@proofkit/better-auth 0.2.1 → 0.2.2

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.
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../../../src/cli/index.ts"],"sourcesContent":["#!/usr/bin/env node --no-warnings\nimport { Command } from \"@commander-js/extra-typings\";\nimport fs from \"fs-extra\";\n\nimport {\n executeMigration,\n planMigration,\n prettyPrintMigrationPlan,\n} from \"../migrate\";\nimport { getAdapter, getAuthTables } from \"better-auth/db\";\nimport { getConfig } from \"../better-auth-cli/utils/get-config\";\nimport { logger } from \"better-auth\";\nimport { BasicAuth, Connection, Database } from \"fm-odata-client\";\nimport prompts from \"prompts\";\nimport chalk from \"chalk\";\nimport { AdapterOptions } from \"../adapter\";\nimport { createFmOdataFetch } from \"../odata\";\n\nasync function main() {\n const program = new Command();\n\n program\n .command(\"migrate\", { isDefault: true })\n .option(\n \"--cwd <path>\",\n \"Path to the current working directory\",\n process.cwd(),\n )\n .option(\"--config <path>\", \"Path to the config file\")\n .option(\"-u, --username <username>\", \"Full Access Username\")\n .option(\"-p, --password <password>\", \"Full Access Password\")\n .option(\"-y, --yes\", \"Skip confirmation\", false)\n\n .action(async (options) => {\n const cwd = options.cwd;\n if (!fs.existsSync(cwd)) {\n logger.error(`The directory \"${cwd}\" does not exist.`);\n process.exit(1);\n }\n\n const config = await getConfig({\n cwd,\n configPath: options.config,\n });\n if (!config) {\n logger.error(\n \"No configuration file found. Add a `auth.ts` file to your project or pass the path to the configuration file using the `--config` flag.\",\n );\n return;\n }\n\n const adapter = await getAdapter(config).catch((e) => {\n logger.error(e.message);\n process.exit(1);\n });\n\n if (adapter.id !== \"filemaker\") {\n logger.error(\n \"This generator is only compatible with the FileMaker adapter.\",\n );\n return;\n }\n\n const betterAuthSchema = getAuthTables(config);\n\n const adapterConfig = (adapter.options as AdapterOptions).config;\n const fetch = createFmOdataFetch({\n ...adapterConfig.odata,\n auth:\n // If the username and password are provided in the CLI, use them to authenticate instead of what's in the config file.\n options.username && options.password\n ? {\n username: options.username,\n password: options.password,\n }\n : adapterConfig.odata.auth,\n });\n\n const migrationPlan = await planMigration(\n fetch,\n betterAuthSchema,\n adapterConfig.odata.database,\n );\n\n if (migrationPlan.length === 0) {\n logger.info(\"No changes to apply. Database is up to date.\");\n return;\n }\n\n if (!options.yes) {\n prettyPrintMigrationPlan(migrationPlan);\n\n if (migrationPlan.length > 0) {\n console.log(\n chalk.gray(\n \"💡 Tip: You can use the --yes flag to skip this confirmation.\",\n ),\n );\n }\n\n const { confirm } = await prompts({\n type: \"confirm\",\n name: \"confirm\",\n message: \"Apply the above changes to your database?\",\n });\n if (!confirm) {\n logger.error(\"Schema changes not applied.\");\n return;\n }\n }\n\n await executeMigration(fetch, migrationPlan);\n\n logger.info(\"Migration applied successfully.\");\n });\n await program.parseAsync(process.argv);\n process.exit(0);\n}\n\nmain().catch(console.error);\n"],"names":[],"mappings":";;;;;;;;;;AAkBA,eAAe,OAAO;AACd,QAAA,UAAU,IAAI,QAAQ;AAE5B,UACG,QAAQ,WAAW,EAAE,WAAW,KAAM,CAAA,EACtC;AAAA,IACC;AAAA,IACA;AAAA,IACA,QAAQ,IAAI;AAAA,EAAA,EAEb,OAAO,mBAAmB,yBAAyB,EACnD,OAAO,6BAA6B,sBAAsB,EAC1D,OAAO,6BAA6B,sBAAsB,EAC1D,OAAO,aAAa,qBAAqB,KAAK,EAE9C,OAAO,OAAO,YAAY;AACzB,UAAM,MAAM,QAAQ;AACpB,QAAI,CAAC,GAAG,WAAW,GAAG,GAAG;AAChB,aAAA,MAAM,kBAAkB,GAAG,mBAAmB;AACrD,cAAQ,KAAK,CAAC;AAAA,IAAA;AAGV,UAAA,SAAS,MAAM,UAAU;AAAA,MAC7B;AAAA,MACA,YAAY,QAAQ;AAAA,IAAA,CACrB;AACD,QAAI,CAAC,QAAQ;AACJ,aAAA;AAAA,QACL;AAAA,MACF;AACA;AAAA,IAAA;AAGF,UAAM,UAAU,MAAM,WAAW,MAAM,EAAE,MAAM,CAAC,MAAM;AAC7C,aAAA,MAAM,EAAE,OAAO;AACtB,cAAQ,KAAK,CAAC;AAAA,IAAA,CACf;AAEG,QAAA,QAAQ,OAAO,aAAa;AACvB,aAAA;AAAA,QACL;AAAA,MACF;AACA;AAAA,IAAA;AAGI,UAAA,mBAAmB,cAAc,MAAM;AAEvC,UAAA,gBAAiB,QAAQ,QAA2B;AAC1D,UAAM,QAAQ,mBAAmB;AAAA,MAC/B,GAAG,cAAc;AAAA,MACjB;AAAA;AAAA,QAEE,QAAQ,YAAY,QAAQ,WACxB;AAAA,UACE,UAAU,QAAQ;AAAA,UAClB,UAAU,QAAQ;AAAA,QAAA,IAEpB,cAAc,MAAM;AAAA;AAAA,IAAA,CAC3B;AAED,UAAM,gBAAgB,MAAM;AAAA,MAC1B;AAAA,MACA;AAAA,MACA,cAAc,MAAM;AAAA,IACtB;AAEI,QAAA,cAAc,WAAW,GAAG;AAC9B,aAAO,KAAK,8CAA8C;AAC1D;AAAA,IAAA;AAGE,QAAA,CAAC,QAAQ,KAAK;AAChB,+BAAyB,aAAa;AAElC,UAAA,cAAc,SAAS,GAAG;AACpB,gBAAA;AAAA,UACN,MAAM;AAAA,YACJ;AAAA,UAAA;AAAA,QAEJ;AAAA,MAAA;AAGF,YAAM,EAAE,YAAY,MAAM,QAAQ;AAAA,QAChC,MAAM;AAAA,QACN,MAAM;AAAA,QACN,SAAS;AAAA,MAAA,CACV;AACD,UAAI,CAAC,SAAS;AACZ,eAAO,MAAM,6BAA6B;AAC1C;AAAA,MAAA;AAAA,IACF;AAGI,UAAA,iBAAiB,OAAO,aAAa;AAE3C,WAAO,KAAK,iCAAiC;AAAA,EAAA,CAC9C;AACG,QAAA,QAAQ,WAAW,QAAQ,IAAI;AACrC,UAAQ,KAAK,CAAC;AAChB;AAEA,OAAO,MAAM,QAAQ,KAAK;"}
1
+ {"version":3,"file":"index.js","sources":["../../../src/cli/index.ts"],"sourcesContent":["#!/usr/bin/env node --no-warnings\nimport { Command } from \"@commander-js/extra-typings\";\nimport fs from \"fs-extra\";\n\nimport {\n executeMigration,\n planMigration,\n prettyPrintMigrationPlan,\n} from \"../migrate\";\nimport { getAdapter, getAuthTables } from \"better-auth/db\";\nimport { getConfig } from \"../better-auth-cli/utils/get-config\";\nimport { logger } from \"better-auth\";\nimport prompts from \"prompts\";\nimport chalk from \"chalk\";\nimport { AdapterOptions } from \"../adapter\";\nimport { createFmOdataFetch } from \"../odata\";\n\nasync function main() {\n const program = new Command();\n\n program\n .command(\"migrate\", { isDefault: true })\n .option(\n \"--cwd <path>\",\n \"Path to the current working directory\",\n process.cwd(),\n )\n .option(\"--config <path>\", \"Path to the config file\")\n .option(\"-u, --username <username>\", \"Full Access Username\")\n .option(\"-p, --password <password>\", \"Full Access Password\")\n .option(\"-y, --yes\", \"Skip confirmation\", false)\n\n .action(async (options) => {\n const cwd = options.cwd;\n if (!fs.existsSync(cwd)) {\n logger.error(`The directory \"${cwd}\" does not exist.`);\n process.exit(1);\n }\n\n const config = await getConfig({\n cwd,\n configPath: options.config,\n });\n if (!config) {\n logger.error(\n \"No configuration file found. Add a `auth.ts` file to your project or pass the path to the configuration file using the `--config` flag.\",\n );\n return;\n }\n\n const adapter = await getAdapter(config).catch((e) => {\n logger.error(e.message);\n process.exit(1);\n });\n\n if (adapter.id !== \"filemaker\") {\n logger.error(\n \"This generator is only compatible with the FileMaker adapter.\",\n );\n return;\n }\n\n const betterAuthSchema = getAuthTables(config);\n\n const adapterConfig = (adapter.options as AdapterOptions).config;\n const fetch = createFmOdataFetch({\n ...adapterConfig.odata,\n auth:\n // If the username and password are provided in the CLI, use them to authenticate instead of what's in the config file.\n options.username && options.password\n ? {\n username: options.username,\n password: options.password,\n }\n : adapterConfig.odata.auth,\n });\n\n const migrationPlan = await planMigration(\n fetch,\n betterAuthSchema,\n adapterConfig.odata.database,\n );\n\n if (migrationPlan.length === 0) {\n logger.info(\"No changes to apply. Database is up to date.\");\n return;\n }\n\n if (!options.yes) {\n prettyPrintMigrationPlan(migrationPlan);\n\n if (migrationPlan.length > 0) {\n console.log(\n chalk.gray(\n \"💡 Tip: You can use the --yes flag to skip this confirmation.\",\n ),\n );\n }\n\n const { confirm } = await prompts({\n type: \"confirm\",\n name: \"confirm\",\n message: \"Apply the above changes to your database?\",\n });\n if (!confirm) {\n logger.error(\"Schema changes not applied.\");\n return;\n }\n }\n\n await executeMigration(fetch, migrationPlan);\n\n logger.info(\"Migration applied successfully.\");\n });\n await program.parseAsync(process.argv);\n process.exit(0);\n}\n\nmain().catch(console.error);\n"],"names":[],"mappings":";;;;;;;;;;AAiBA,eAAe,OAAO;AACd,QAAA,UAAU,IAAI,QAAQ;AAE5B,UACG,QAAQ,WAAW,EAAE,WAAW,KAAM,CAAA,EACtC;AAAA,IACC;AAAA,IACA;AAAA,IACA,QAAQ,IAAI;AAAA,EAAA,EAEb,OAAO,mBAAmB,yBAAyB,EACnD,OAAO,6BAA6B,sBAAsB,EAC1D,OAAO,6BAA6B,sBAAsB,EAC1D,OAAO,aAAa,qBAAqB,KAAK,EAE9C,OAAO,OAAO,YAAY;AACzB,UAAM,MAAM,QAAQ;AACpB,QAAI,CAAC,GAAG,WAAW,GAAG,GAAG;AAChB,aAAA,MAAM,kBAAkB,GAAG,mBAAmB;AACrD,cAAQ,KAAK,CAAC;AAAA,IAAA;AAGV,UAAA,SAAS,MAAM,UAAU;AAAA,MAC7B;AAAA,MACA,YAAY,QAAQ;AAAA,IAAA,CACrB;AACD,QAAI,CAAC,QAAQ;AACJ,aAAA;AAAA,QACL;AAAA,MACF;AACA;AAAA,IAAA;AAGF,UAAM,UAAU,MAAM,WAAW,MAAM,EAAE,MAAM,CAAC,MAAM;AAC7C,aAAA,MAAM,EAAE,OAAO;AACtB,cAAQ,KAAK,CAAC;AAAA,IAAA,CACf;AAEG,QAAA,QAAQ,OAAO,aAAa;AACvB,aAAA;AAAA,QACL;AAAA,MACF;AACA;AAAA,IAAA;AAGI,UAAA,mBAAmB,cAAc,MAAM;AAEvC,UAAA,gBAAiB,QAAQ,QAA2B;AAC1D,UAAM,QAAQ,mBAAmB;AAAA,MAC/B,GAAG,cAAc;AAAA,MACjB;AAAA;AAAA,QAEE,QAAQ,YAAY,QAAQ,WACxB;AAAA,UACE,UAAU,QAAQ;AAAA,UAClB,UAAU,QAAQ;AAAA,QAAA,IAEpB,cAAc,MAAM;AAAA;AAAA,IAAA,CAC3B;AAED,UAAM,gBAAgB,MAAM;AAAA,MAC1B;AAAA,MACA;AAAA,MACA,cAAc,MAAM;AAAA,IACtB;AAEI,QAAA,cAAc,WAAW,GAAG;AAC9B,aAAO,KAAK,8CAA8C;AAC1D;AAAA,IAAA;AAGE,QAAA,CAAC,QAAQ,KAAK;AAChB,+BAAyB,aAAa;AAElC,UAAA,cAAc,SAAS,GAAG;AACpB,gBAAA;AAAA,UACN,MAAM;AAAA,YACJ;AAAA,UAAA;AAAA,QAEJ;AAAA,MAAA;AAGF,YAAM,EAAE,YAAY,MAAM,QAAQ;AAAA,QAChC,MAAM;AAAA,QACN,MAAM;AAAA,QACN,SAAS;AAAA,MAAA,CACV;AACD,UAAI,CAAC,SAAS;AACZ,eAAO,MAAM,6BAA6B;AAC1C;AAAA,MAAA;AAAA,IACF;AAGI,UAAA,iBAAiB,OAAO,aAAa;AAE3C,WAAO,KAAK,iCAAiC;AAAA,EAAA,CAC9C;AACG,QAAA,QAAQ,WAAW,QAAQ,IAAI;AACrC,UAAQ,KAAK,CAAC;AAChB;AAEA,OAAO,MAAM,QAAQ,KAAK;"}
@@ -18,7 +18,7 @@ export declare const migrationPlanSchema: z.ZodArray<z.ZodObject<{
18
18
  unique: z.ZodOptional<z.ZodBoolean>;
19
19
  global: z.ZodOptional<z.ZodBoolean>;
20
20
  repetitions: z.ZodOptional<z.ZodNumber>;
21
- type: z.ZodLiteral<"string">;
21
+ type: z.ZodLiteral<"varchar">;
22
22
  maxLength: z.ZodOptional<z.ZodNumber>;
23
23
  default: z.ZodOptional<z.ZodEnum<{
24
24
  USER: "USER";
@@ -31,7 +31,7 @@ async function planMigration(fetch, betterAuthSchema, databaseName) {
31
31
  ([fieldKey, fieldValue]) => typeof fieldValue === "object" && fieldValue !== null && "$Type" in fieldValue
32
32
  ).map(([fieldKey, fieldValue]) => ({
33
33
  name: fieldKey,
34
- type: fieldValue.$Type === "Edm.String" ? "string" : fieldValue.$Type === "Edm.DateTimeOffset" ? "timestamp" : fieldValue.$Type === "Edm.Decimal" || fieldValue.$Type === "Edm.Int32" || fieldValue.$Type === "Edm.Int64" ? "numeric" : "string"
34
+ type: fieldValue.$Type === "Edm.String" ? "varchar" : fieldValue.$Type === "Edm.DateTimeOffset" ? "timestamp" : fieldValue.$Type === "Edm.Decimal" || fieldValue.$Type === "Edm.Int32" || fieldValue.$Type === "Edm.Int64" ? "numeric" : "varchar"
35
35
  }));
36
36
  acc[entitySetName] = fields;
37
37
  return acc;
@@ -47,7 +47,7 @@ async function planMigration(fetch, betterAuthSchema, databaseName) {
47
47
  const fields = Object.entries(baTable.fields).map(
48
48
  ([key, field]) => ({
49
49
  name: field.fieldName ?? key,
50
- type: field.type === "boolean" || field.type.includes("number") ? "numeric" : field.type === "date" ? "timestamp" : "string"
50
+ type: field.type === "boolean" || field.type.includes("number") ? "numeric" : field.type === "date" ? "timestamp" : "varchar"
51
51
  })
52
52
  );
53
53
  const tableExists = Object.prototype.hasOwnProperty.call(
@@ -61,7 +61,7 @@ async function planMigration(fetch, betterAuthSchema, databaseName) {
61
61
  fields: [
62
62
  {
63
63
  name: "id",
64
- type: "string",
64
+ type: "varchar",
65
65
  primary: true,
66
66
  unique: true
67
67
  },
@@ -128,7 +128,7 @@ const genericFieldSchema = z.object({
128
128
  repetitions: z.number().optional()
129
129
  });
130
130
  const stringFieldSchema = genericFieldSchema.extend({
131
- type: z.literal("string"),
131
+ type: z.literal("varchar"),
132
132
  maxLength: z.number().optional(),
133
133
  default: z.enum(["USER", "USERNAME", "CURRENT_USER"]).optional()
134
134
  });
@@ -1 +1 @@
1
- {"version":3,"file":"migrate.js","sources":["../../src/migrate.ts"],"sourcesContent":["import { type BetterAuthDbSchema } from \"better-auth/db\";\nimport { type Metadata, type Field as FmField } from \"fm-odata-client\";\nimport chalk from \"chalk\";\nimport z from \"zod/v4\";\nimport { createFmOdataFetch } from \"./odata\";\n\nexport async function getMetadata(\n fetch: ReturnType<typeof createFmOdataFetch>,\n databaseName: string,\n) {\n const result = await fetch(\"/$metadata\", {\n method: \"GET\",\n headers: { accept: \"application/json\" },\n output: z.looseObject({\n $Version: z.string(),\n \"@ServerVersion\": z.string(),\n }),\n });\n return result.data?.[databaseName] as Metadata;\n}\n\nexport async function planMigration(\n fetch: ReturnType<typeof createFmOdataFetch>,\n betterAuthSchema: BetterAuthDbSchema,\n databaseName: string,\n): Promise<MigrationPlan> {\n const metadata = await getMetadata(fetch, databaseName);\n\n // Build a map from entity set name to entity type key\n let entitySetToType: Record<string, string> = {};\n if (metadata) {\n for (const [key, value] of Object.entries(metadata)) {\n if (value.$Kind === \"EntitySet\" && value.$Type) {\n // $Type is like 'betterauth_test.fmp12.proofkit_user_'\n const typeKey = value.$Type.split(\".\").pop(); // e.g., 'proofkit_user_'\n entitySetToType[key] = typeKey || key;\n }\n }\n }\n\n const existingTables = metadata\n ? Object.entries(entitySetToType).reduce(\n (acc, [entitySetName, entityTypeKey]) => {\n const entityType = metadata[entityTypeKey];\n if (!entityType) return acc;\n const fields = Object.entries(entityType)\n .filter(\n ([fieldKey, fieldValue]) =>\n typeof fieldValue === \"object\" &&\n fieldValue !== null &&\n \"$Type\" in fieldValue,\n )\n .map(([fieldKey, fieldValue]) => ({\n name: fieldKey,\n type:\n fieldValue.$Type === \"Edm.String\"\n ? \"string\"\n : fieldValue.$Type === \"Edm.DateTimeOffset\"\n ? \"timestamp\"\n : fieldValue.$Type === \"Edm.Decimal\" ||\n fieldValue.$Type === \"Edm.Int32\" ||\n fieldValue.$Type === \"Edm.Int64\"\n ? \"numeric\"\n : \"string\",\n }));\n acc[entitySetName] = fields;\n return acc;\n },\n {} as Record<string, { name: string; type: string }[]>,\n )\n : {};\n\n const baTables = Object.entries(betterAuthSchema)\n .sort((a, b) => (a[1].order ?? 0) - (b[1].order ?? 0))\n .map(([key, value]) => ({\n ...value,\n keyName: key,\n }));\n\n const migrationPlan: MigrationPlan = [];\n\n for (const baTable of baTables) {\n const fields: FmField[] = Object.entries(baTable.fields).map(\n ([key, field]) => ({\n name: field.fieldName ?? key,\n type:\n field.type === \"boolean\" || field.type.includes(\"number\")\n ? \"numeric\"\n : field.type === \"date\"\n ? \"timestamp\"\n : \"string\",\n }),\n );\n\n // get existing table or create it\n const tableExists = Object.prototype.hasOwnProperty.call(\n existingTables,\n baTable.modelName,\n );\n\n if (!tableExists) {\n migrationPlan.push({\n tableName: baTable.modelName,\n operation: \"create\",\n fields: [\n {\n name: \"id\",\n type: \"string\",\n primary: true,\n unique: true,\n },\n ...fields,\n ],\n });\n } else {\n const existingFields = (existingTables[baTable.modelName] || []).map(\n (f) => f.name,\n );\n const existingFieldMap = (existingTables[baTable.modelName] || []).reduce(\n (acc, f) => {\n acc[f.name] = f.type;\n return acc;\n },\n {} as Record<string, string>,\n );\n // Warn about type mismatches (optional, not in plan)\n fields.forEach((field) => {\n if (\n existingFields.includes(field.name) &&\n existingFieldMap[field.name] !== field.type\n ) {\n console.warn(\n `⚠️ WARNING: Field '${field.name}' in table '${baTable.modelName}' exists but has type '${existingFieldMap[field.name]}' (expected '${field.type}'). Change the field type in FileMaker to avoid potential errors.`,\n );\n }\n });\n const fieldsToAdd = fields.filter(\n (f) => !existingFields.includes(f.name),\n );\n if (fieldsToAdd.length > 0) {\n migrationPlan.push({\n tableName: baTable.modelName,\n operation: \"update\",\n fields: fieldsToAdd,\n });\n }\n }\n }\n\n return migrationPlan;\n}\n\nexport async function executeMigration(\n fetch: ReturnType<typeof createFmOdataFetch>,\n migrationPlan: MigrationPlan,\n) {\n for (const step of migrationPlan) {\n if (step.operation === \"create\") {\n console.log(\"Creating table:\", step.tableName);\n await fetch(\"@post/FileMaker_Tables\", {\n body: {\n tableName: step.tableName,\n fields: step.fields,\n },\n });\n } else if (step.operation === \"update\") {\n console.log(\"Adding fields to table:\", step.tableName);\n await fetch(\"@post/FileMaker_Tables/:tableName\", {\n params: { tableName: step.tableName },\n body: { fields: step.fields },\n });\n }\n }\n}\n\nconst genericFieldSchema = z.object({\n name: z.string(),\n nullable: z.boolean().optional(),\n primary: z.boolean().optional(),\n unique: z.boolean().optional(),\n global: z.boolean().optional(),\n repetitions: z.number().optional(),\n});\n\nconst stringFieldSchema = genericFieldSchema.extend({\n type: z.literal(\"string\"),\n maxLength: z.number().optional(),\n default: z.enum([\"USER\", \"USERNAME\", \"CURRENT_USER\"]).optional(),\n});\n\nconst numericFieldSchema = genericFieldSchema.extend({\n type: z.literal(\"numeric\"),\n});\n\nconst dateFieldSchema = genericFieldSchema.extend({\n type: z.literal(\"date\"),\n default: z.enum([\"CURRENT_DATE\", \"CURDATE\"]).optional(),\n});\n\nconst timeFieldSchema = genericFieldSchema.extend({\n type: z.literal(\"time\"),\n default: z.enum([\"CURRENT_TIME\", \"CURTIME\"]).optional(),\n});\n\nconst timestampFieldSchema = genericFieldSchema.extend({\n type: z.literal(\"timestamp\"),\n default: z.enum([\"CURRENT_TIMESTAMP\", \"CURTIMESTAMP\"]).optional(),\n});\n\nconst containerFieldSchema = genericFieldSchema.extend({\n type: z.literal(\"container\"),\n externalSecurePath: z.string().optional(),\n});\n\nconst fieldSchema = z.discriminatedUnion(\"type\", [\n stringFieldSchema,\n numericFieldSchema,\n dateFieldSchema,\n timeFieldSchema,\n timestampFieldSchema,\n containerFieldSchema,\n]);\n\nexport const migrationPlanSchema = z\n .object({\n tableName: z.string(),\n operation: z.enum([\"create\", \"update\"]),\n fields: z.array(fieldSchema),\n })\n .array();\n\nexport type MigrationPlan = z.infer<typeof migrationPlanSchema>;\n\nexport function prettyPrintMigrationPlan(migrationPlan: MigrationPlan) {\n if (!migrationPlan.length) {\n console.log(\"No changes to apply. Database is up to date.\");\n return;\n }\n console.log(chalk.bold.green(\"Migration plan:\"));\n for (const step of migrationPlan) {\n const emoji = step.operation === \"create\" ? \"✅\" : \"✏️\";\n console.log(\n `\\n${emoji} ${step.operation === \"create\" ? chalk.bold.green(\"Create table\") : chalk.bold.yellow(\"Update table\")}: ${step.tableName}`,\n );\n if (step.fields.length) {\n for (const field of step.fields) {\n let fieldDesc = ` - ${field.name} (${field.type}`;\n if (field.primary) fieldDesc += \", primary\";\n if (field.unique) fieldDesc += \", unique\";\n fieldDesc += \")\";\n console.log(fieldDesc);\n }\n } else {\n console.log(\" (No fields to add)\");\n }\n }\n console.log(\"\");\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"migrate.js","sources":["../../src/migrate.ts"],"sourcesContent":["import { type BetterAuthDbSchema } from \"better-auth/db\";\nimport { type Metadata } from \"fm-odata-client\";\nimport chalk from \"chalk\";\nimport z from \"zod/v4\";\nimport { createFmOdataFetch } from \"./odata\";\n\nexport async function getMetadata(\n fetch: ReturnType<typeof createFmOdataFetch>,\n databaseName: string,\n) {\n const result = await fetch(\"/$metadata\", {\n method: \"GET\",\n headers: { accept: \"application/json\" },\n output: z.looseObject({\n $Version: z.string(),\n \"@ServerVersion\": z.string(),\n }),\n });\n return result.data?.[databaseName] as Metadata;\n}\n\nexport async function planMigration(\n fetch: ReturnType<typeof createFmOdataFetch>,\n betterAuthSchema: BetterAuthDbSchema,\n databaseName: string,\n): Promise<MigrationPlan> {\n const metadata = await getMetadata(fetch, databaseName);\n\n // Build a map from entity set name to entity type key\n let entitySetToType: Record<string, string> = {};\n if (metadata) {\n for (const [key, value] of Object.entries(metadata)) {\n if (value.$Kind === \"EntitySet\" && value.$Type) {\n // $Type is like 'betterauth_test.fmp12.proofkit_user_'\n const typeKey = value.$Type.split(\".\").pop(); // e.g., 'proofkit_user_'\n entitySetToType[key] = typeKey || key;\n }\n }\n }\n\n const existingTables = metadata\n ? Object.entries(entitySetToType).reduce(\n (acc, [entitySetName, entityTypeKey]) => {\n const entityType = metadata[entityTypeKey];\n if (!entityType) return acc;\n const fields = Object.entries(entityType)\n .filter(\n ([fieldKey, fieldValue]) =>\n typeof fieldValue === \"object\" &&\n fieldValue !== null &&\n \"$Type\" in fieldValue,\n )\n .map(([fieldKey, fieldValue]) => ({\n name: fieldKey,\n type:\n fieldValue.$Type === \"Edm.String\"\n ? \"varchar\"\n : fieldValue.$Type === \"Edm.DateTimeOffset\"\n ? \"timestamp\"\n : fieldValue.$Type === \"Edm.Decimal\" ||\n fieldValue.$Type === \"Edm.Int32\" ||\n fieldValue.$Type === \"Edm.Int64\"\n ? \"numeric\"\n : \"varchar\",\n }));\n acc[entitySetName] = fields;\n return acc;\n },\n {} as Record<string, { name: string; type: string }[]>,\n )\n : {};\n\n const baTables = Object.entries(betterAuthSchema)\n .sort((a, b) => (a[1].order ?? 0) - (b[1].order ?? 0))\n .map(([key, value]) => ({\n ...value,\n keyName: key,\n }));\n\n const migrationPlan: MigrationPlan = [];\n\n for (const baTable of baTables) {\n const fields: FmField[] = Object.entries(baTable.fields).map(\n ([key, field]) => ({\n name: field.fieldName ?? key,\n type:\n field.type === \"boolean\" || field.type.includes(\"number\")\n ? \"numeric\"\n : field.type === \"date\"\n ? \"timestamp\"\n : \"varchar\",\n }),\n );\n\n // get existing table or create it\n const tableExists = Object.prototype.hasOwnProperty.call(\n existingTables,\n baTable.modelName,\n );\n\n if (!tableExists) {\n migrationPlan.push({\n tableName: baTable.modelName,\n operation: \"create\",\n fields: [\n {\n name: \"id\",\n type: \"varchar\",\n primary: true,\n unique: true,\n },\n ...fields,\n ],\n });\n } else {\n const existingFields = (existingTables[baTable.modelName] || []).map(\n (f) => f.name,\n );\n const existingFieldMap = (existingTables[baTable.modelName] || []).reduce(\n (acc, f) => {\n acc[f.name] = f.type;\n return acc;\n },\n {} as Record<string, string>,\n );\n // Warn about type mismatches (optional, not in plan)\n fields.forEach((field) => {\n if (\n existingFields.includes(field.name) &&\n existingFieldMap[field.name] !== field.type\n ) {\n console.warn(\n `⚠️ WARNING: Field '${field.name}' in table '${baTable.modelName}' exists but has type '${existingFieldMap[field.name]}' (expected '${field.type}'). Change the field type in FileMaker to avoid potential errors.`,\n );\n }\n });\n const fieldsToAdd = fields.filter(\n (f) => !existingFields.includes(f.name),\n );\n if (fieldsToAdd.length > 0) {\n migrationPlan.push({\n tableName: baTable.modelName,\n operation: \"update\",\n fields: fieldsToAdd,\n });\n }\n }\n }\n\n return migrationPlan;\n}\n\nexport async function executeMigration(\n fetch: ReturnType<typeof createFmOdataFetch>,\n migrationPlan: MigrationPlan,\n) {\n for (const step of migrationPlan) {\n if (step.operation === \"create\") {\n console.log(\"Creating table:\", step.tableName);\n await fetch(\"@post/FileMaker_Tables\", {\n body: {\n tableName: step.tableName,\n fields: step.fields,\n },\n });\n } else if (step.operation === \"update\") {\n console.log(\"Adding fields to table:\", step.tableName);\n await fetch(\"@post/FileMaker_Tables/:tableName\", {\n params: { tableName: step.tableName },\n body: { fields: step.fields },\n });\n }\n }\n}\n\nconst genericFieldSchema = z.object({\n name: z.string(),\n nullable: z.boolean().optional(),\n primary: z.boolean().optional(),\n unique: z.boolean().optional(),\n global: z.boolean().optional(),\n repetitions: z.number().optional(),\n});\n\nconst stringFieldSchema = genericFieldSchema.extend({\n type: z.literal(\"varchar\"),\n maxLength: z.number().optional(),\n default: z.enum([\"USER\", \"USERNAME\", \"CURRENT_USER\"]).optional(),\n});\n\nconst numericFieldSchema = genericFieldSchema.extend({\n type: z.literal(\"numeric\"),\n});\n\nconst dateFieldSchema = genericFieldSchema.extend({\n type: z.literal(\"date\"),\n default: z.enum([\"CURRENT_DATE\", \"CURDATE\"]).optional(),\n});\n\nconst timeFieldSchema = genericFieldSchema.extend({\n type: z.literal(\"time\"),\n default: z.enum([\"CURRENT_TIME\", \"CURTIME\"]).optional(),\n});\n\nconst timestampFieldSchema = genericFieldSchema.extend({\n type: z.literal(\"timestamp\"),\n default: z.enum([\"CURRENT_TIMESTAMP\", \"CURTIMESTAMP\"]).optional(),\n});\n\nconst containerFieldSchema = genericFieldSchema.extend({\n type: z.literal(\"container\"),\n externalSecurePath: z.string().optional(),\n});\n\nconst fieldSchema = z.discriminatedUnion(\"type\", [\n stringFieldSchema,\n numericFieldSchema,\n dateFieldSchema,\n timeFieldSchema,\n timestampFieldSchema,\n containerFieldSchema,\n]);\n\ntype FmField = z.infer<typeof fieldSchema>;\n\nexport const migrationPlanSchema = z\n .object({\n tableName: z.string(),\n operation: z.enum([\"create\", \"update\"]),\n fields: z.array(fieldSchema),\n })\n .array();\n\nexport type MigrationPlan = z.infer<typeof migrationPlanSchema>;\n\nexport function prettyPrintMigrationPlan(migrationPlan: MigrationPlan) {\n if (!migrationPlan.length) {\n console.log(\"No changes to apply. Database is up to date.\");\n return;\n }\n console.log(chalk.bold.green(\"Migration plan:\"));\n for (const step of migrationPlan) {\n const emoji = step.operation === \"create\" ? \"✅\" : \"✏️\";\n console.log(\n `\\n${emoji} ${step.operation === \"create\" ? chalk.bold.green(\"Create table\") : chalk.bold.yellow(\"Update table\")}: ${step.tableName}`,\n );\n if (step.fields.length) {\n for (const field of step.fields) {\n let fieldDesc = ` - ${field.name} (${field.type}`;\n if (field.primary) fieldDesc += \", primary\";\n if (field.unique) fieldDesc += \", unique\";\n fieldDesc += \")\";\n console.log(fieldDesc);\n }\n } else {\n console.log(\" (No fields to add)\");\n }\n }\n console.log(\"\");\n}\n"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@proofkit/better-auth",
3
- "version": "0.2.1",
3
+ "version": "0.2.2",
4
4
  "description": "FileMaker adapter for Better Auth",
5
5
  "type": "module",
6
6
  "main": "dist/esm/index.js",
package/src/cli/index.ts CHANGED
@@ -10,7 +10,6 @@ import {
10
10
  import { getAdapter, getAuthTables } from "better-auth/db";
11
11
  import { getConfig } from "../better-auth-cli/utils/get-config";
12
12
  import { logger } from "better-auth";
13
- import { BasicAuth, Connection, Database } from "fm-odata-client";
14
13
  import prompts from "prompts";
15
14
  import chalk from "chalk";
16
15
  import { AdapterOptions } from "../adapter";
package/src/migrate.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { type BetterAuthDbSchema } from "better-auth/db";
2
- import { type Metadata, type Field as FmField } from "fm-odata-client";
2
+ import { type Metadata } from "fm-odata-client";
3
3
  import chalk from "chalk";
4
4
  import z from "zod/v4";
5
5
  import { createFmOdataFetch } from "./odata";
@@ -54,14 +54,14 @@ export async function planMigration(
54
54
  name: fieldKey,
55
55
  type:
56
56
  fieldValue.$Type === "Edm.String"
57
- ? "string"
57
+ ? "varchar"
58
58
  : fieldValue.$Type === "Edm.DateTimeOffset"
59
59
  ? "timestamp"
60
60
  : fieldValue.$Type === "Edm.Decimal" ||
61
61
  fieldValue.$Type === "Edm.Int32" ||
62
62
  fieldValue.$Type === "Edm.Int64"
63
63
  ? "numeric"
64
- : "string",
64
+ : "varchar",
65
65
  }));
66
66
  acc[entitySetName] = fields;
67
67
  return acc;
@@ -88,7 +88,7 @@ export async function planMigration(
88
88
  ? "numeric"
89
89
  : field.type === "date"
90
90
  ? "timestamp"
91
- : "string",
91
+ : "varchar",
92
92
  }),
93
93
  );
94
94
 
@@ -105,7 +105,7 @@ export async function planMigration(
105
105
  fields: [
106
106
  {
107
107
  name: "id",
108
- type: "string",
108
+ type: "varchar",
109
109
  primary: true,
110
110
  unique: true,
111
111
  },
@@ -183,7 +183,7 @@ const genericFieldSchema = z.object({
183
183
  });
184
184
 
185
185
  const stringFieldSchema = genericFieldSchema.extend({
186
- type: z.literal("string"),
186
+ type: z.literal("varchar"),
187
187
  maxLength: z.number().optional(),
188
188
  default: z.enum(["USER", "USERNAME", "CURRENT_USER"]).optional(),
189
189
  });
@@ -221,6 +221,8 @@ const fieldSchema = z.discriminatedUnion("type", [
221
221
  containerFieldSchema,
222
222
  ]);
223
223
 
224
+ type FmField = z.infer<typeof fieldSchema>;
225
+
224
226
  export const migrationPlanSchema = z
225
227
  .object({
226
228
  tableName: z.string(),