@proofkit/better-auth 0.3.1-beta.0 → 0.4.0-beta.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 { logger } from \"better-auth\";\nimport { getAdapter, getAuthTables } from \"better-auth/db\";\nimport chalk from \"chalk\";\nimport fs from \"fs-extra\";\nimport prompts from \"prompts\";\nimport type { AdapterOptions } from \"../adapter\";\nimport { getConfig } from \"../better-auth-cli/utils/get-config\";\nimport { executeMigration, planMigration, prettyPrintMigrationPlan } from \"../migrate\";\nimport { createRawFetch } from \"../odata\";\nimport \"dotenv/config\";\n\nasync function main() {\n const program = new Command();\n\n program\n .command(\"migrate\", { isDefault: true })\n .option(\"--cwd <path>\", \"Path to the current working directory\", process.cwd())\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(\"This generator is only compatible with the FileMaker adapter.\");\n return;\n }\n\n const betterAuthSchema = getAuthTables(config);\n\n const adapterConfig = (adapter.options as AdapterOptions).config;\n const { fetch } = createRawFetch({\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 logging: \"verbose\", // Enable logging for CLI operations\n });\n\n const migrationPlan = await planMigration(fetch, betterAuthSchema, adapterConfig.odata.database);\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(chalk.gray(\"💡 Tip: You can use the --yes flag to skip this confirmation.\"));\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":";;;;;;;;;;;AAaA,eAAe,OAAO;AACd,QAAA,UAAU,IAAI,QAAQ;AAE5B,UACG,QAAQ,WAAW,EAAE,WAAW,MAAM,EACtC,OAAO,gBAAgB,yCAAyC,QAAQ,IAAI,CAAC,EAC7E,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;AAC9B,aAAO,MAAM,+DAA+D;AAC5E;AAAA,IAAA;AAGI,UAAA,mBAAmB,cAAc,MAAM;AAEvC,UAAA,gBAAiB,QAAQ,QAA2B;AACpD,UAAA,EAAE,MAAM,IAAI,eAAe;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,MAC1B,SAAS;AAAA;AAAA,IAAA,CACV;AAED,UAAM,gBAAgB,MAAM,cAAc,OAAO,kBAAkB,cAAc,MAAM,QAAQ;AAE3F,QAAA,cAAc,WAAW,GAAG;AAC9B,aAAO,KAAK,8CAA8C;AAC1D;AAAA,IAAA;AAGE,QAAA,CAAC,QAAQ,KAAK;AAChB,+BAAyB,aAAa;AAElC,UAAA,cAAc,SAAS,GAAG;AAC5B,gBAAQ,IAAI,MAAM,KAAK,+DAA+D,CAAC;AAAA,MAAA;AAGzF,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 type { Database, FFetchOptions } from \"@proofkit/fmodata\";\nimport { FMServerConnection } from \"@proofkit/fmodata\";\nimport { logger } from \"better-auth\";\nimport { getAdapter, getSchema } from \"better-auth/db\";\nimport chalk from \"chalk\";\nimport fs from \"fs-extra\";\nimport prompts from \"prompts\";\nimport { getConfig } from \"../better-auth-cli/utils/get-config\";\nimport { executeMigration, planMigration, prettyPrintMigrationPlan } from \"../migrate\";\nimport \"dotenv/config\";\n\nasync function main() {\n const program = new Command();\n\n program\n .command(\"migrate\", { isDefault: true })\n .option(\"--cwd <path>\", \"Path to the current working directory\", process.cwd())\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(\"This generator is only compatible with the FileMaker adapter.\");\n return;\n }\n\n const betterAuthSchema = getSchema(config);\n\n // Extract Database from the adapter factory or resolved adapter.\n // config.database is the FileMakerAdapter factory function (has .database set on it).\n // adapter is the resolved adapter after getAdapter() calls the factory (also has .database).\n // Try both: adapter first (post-call), then config.database (pre-call / factory function).\n const configDb =\n (adapter as unknown as { database?: Database }).database ??\n (config.database as unknown as { database?: Database } | undefined)?.database;\n if (!configDb || typeof configDb !== \"object\" || !(\"schema\" in configDb)) {\n logger.error(\n \"Could not extract Database instance from adapter. Ensure your auth.ts uses FileMakerAdapter with an fmodata Database.\",\n );\n process.exit(1);\n }\n let db: Database = configDb;\n\n // Extract database name and server URL for display.\n // Try the public getter first (_getDatabaseName), fall back to the private field (databaseName).\n const dbObj = configDb as unknown as {\n _getDatabaseName?: string;\n databaseName?: string;\n context?: { _getBaseUrl?: () => string; _fetchClientOptions?: unknown };\n };\n const dbName: string = dbObj._getDatabaseName ?? dbObj.databaseName ?? \"\";\n const baseUrl: string | undefined = dbObj.context?._getBaseUrl?.();\n const serverUrl = baseUrl ? new URL(baseUrl).origin : undefined;\n\n // If CLI credential overrides are provided, construct a new connection\n if (options.username && options.password) {\n if (!dbName) {\n logger.error(\"Could not determine database filename from adapter config.\");\n process.exit(1);\n }\n\n if (!baseUrl) {\n logger.error(\n \"Could not determine server URL from adapter config. Ensure your auth.ts uses FMServerConnection.\",\n );\n process.exit(1);\n }\n\n const fetchClientOptions = dbObj.context?._fetchClientOptions as FFetchOptions | undefined;\n const connection = new FMServerConnection({\n serverUrl: serverUrl as string,\n auth: {\n username: options.username,\n password: options.password,\n },\n fetchClientOptions,\n });\n\n db = connection.database(dbName);\n }\n\n let migrationPlan: Awaited<ReturnType<typeof planMigration>>;\n try {\n migrationPlan = await planMigration(db, betterAuthSchema);\n } catch (err) {\n logger.error(`Failed to read database schema: ${err instanceof Error ? err.message : err}`);\n process.exit(1);\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, { serverUrl, fileName: dbName });\n\n if (migrationPlan.length > 0) {\n console.log(chalk.gray(\"💡 Tip: You can use the --yes flag to skip this confirmation.\"));\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 try {\n await executeMigration(db, migrationPlan);\n logger.info(\"Migration applied successfully.\");\n } catch {\n process.exit(1);\n }\n });\n await program.parseAsync(process.argv);\n process.exit(0);\n}\n\nmain().catch((err) => {\n logger.error(err.message ?? err);\n process.exit(1);\n});\n"],"names":[],"mappings":"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"}
@@ -1,85 +1,27 @@
1
- import { BetterAuthDbSchema } from 'better-auth/db';
2
- import { Metadata } from 'fm-odata-client';
3
- import { default as z } from 'zod/v4';
4
- import { createRawFetch } from './odata.js';
5
- export declare function getMetadata(fetch: ReturnType<typeof createRawFetch>["fetch"], databaseName: string): Promise<Metadata | null>;
6
- export declare function planMigration(fetch: ReturnType<typeof createRawFetch>["fetch"], betterAuthSchema: BetterAuthDbSchema, databaseName: string): Promise<MigrationPlan>;
7
- export declare function executeMigration(fetch: ReturnType<typeof createRawFetch>["fetch"], migrationPlan: MigrationPlan): Promise<void>;
8
- declare const migrationPlanSchema: z.ZodArray<z.ZodObject<{
9
- tableName: z.ZodString;
10
- operation: z.ZodEnum<{
11
- update: "update";
12
- create: "create";
13
- }>;
14
- fields: z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
15
- name: z.ZodString;
16
- nullable: z.ZodOptional<z.ZodBoolean>;
17
- primary: z.ZodOptional<z.ZodBoolean>;
18
- unique: z.ZodOptional<z.ZodBoolean>;
19
- global: z.ZodOptional<z.ZodBoolean>;
20
- repetitions: z.ZodOptional<z.ZodNumber>;
21
- type: z.ZodLiteral<"varchar">;
22
- maxLength: z.ZodOptional<z.ZodNumber>;
23
- default: z.ZodOptional<z.ZodEnum<{
24
- USER: "USER";
25
- USERNAME: "USERNAME";
26
- CURRENT_USER: "CURRENT_USER";
27
- }>>;
28
- }, z.core.$strip>, z.ZodObject<{
29
- name: z.ZodString;
30
- nullable: z.ZodOptional<z.ZodBoolean>;
31
- primary: z.ZodOptional<z.ZodBoolean>;
32
- unique: z.ZodOptional<z.ZodBoolean>;
33
- global: z.ZodOptional<z.ZodBoolean>;
34
- repetitions: z.ZodOptional<z.ZodNumber>;
35
- type: z.ZodLiteral<"numeric">;
36
- }, z.core.$strip>, z.ZodObject<{
37
- name: z.ZodString;
38
- nullable: z.ZodOptional<z.ZodBoolean>;
39
- primary: z.ZodOptional<z.ZodBoolean>;
40
- unique: z.ZodOptional<z.ZodBoolean>;
41
- global: z.ZodOptional<z.ZodBoolean>;
42
- repetitions: z.ZodOptional<z.ZodNumber>;
43
- type: z.ZodLiteral<"date">;
44
- default: z.ZodOptional<z.ZodEnum<{
45
- CURRENT_DATE: "CURRENT_DATE";
46
- CURDATE: "CURDATE";
47
- }>>;
48
- }, z.core.$strip>, z.ZodObject<{
49
- name: z.ZodString;
50
- nullable: z.ZodOptional<z.ZodBoolean>;
51
- primary: z.ZodOptional<z.ZodBoolean>;
52
- unique: z.ZodOptional<z.ZodBoolean>;
53
- global: z.ZodOptional<z.ZodBoolean>;
54
- repetitions: z.ZodOptional<z.ZodNumber>;
55
- type: z.ZodLiteral<"time">;
56
- default: z.ZodOptional<z.ZodEnum<{
57
- CURRENT_TIME: "CURRENT_TIME";
58
- CURTIME: "CURTIME";
59
- }>>;
60
- }, z.core.$strip>, z.ZodObject<{
61
- name: z.ZodString;
62
- nullable: z.ZodOptional<z.ZodBoolean>;
63
- primary: z.ZodOptional<z.ZodBoolean>;
64
- unique: z.ZodOptional<z.ZodBoolean>;
65
- global: z.ZodOptional<z.ZodBoolean>;
66
- repetitions: z.ZodOptional<z.ZodNumber>;
67
- type: z.ZodLiteral<"timestamp">;
68
- default: z.ZodOptional<z.ZodEnum<{
69
- CURRENT_TIMESTAMP: "CURRENT_TIMESTAMP";
70
- CURTIMESTAMP: "CURTIMESTAMP";
71
- }>>;
72
- }, z.core.$strip>, z.ZodObject<{
73
- name: z.ZodString;
74
- nullable: z.ZodOptional<z.ZodBoolean>;
75
- primary: z.ZodOptional<z.ZodBoolean>;
76
- unique: z.ZodOptional<z.ZodBoolean>;
77
- global: z.ZodOptional<z.ZodBoolean>;
78
- repetitions: z.ZodOptional<z.ZodNumber>;
79
- type: z.ZodLiteral<"container">;
80
- externalSecurePath: z.ZodOptional<z.ZodString>;
81
- }, z.core.$strip>], "type">>;
82
- }, z.core.$strip>>;
83
- export type MigrationPlan = z.infer<typeof migrationPlanSchema>;
84
- export declare function prettyPrintMigrationPlan(migrationPlan: MigrationPlan): void;
1
+ import { Database, Metadata } from '../../fmodata/src.js';
2
+ import { DBFieldAttribute } from 'better-auth/db';
3
+ type BetterAuthSchema = Record<string, {
4
+ fields: Record<string, DBFieldAttribute>;
5
+ order: number;
6
+ }>;
7
+ export declare function getMetadata(db: Database): Promise<Metadata>;
8
+ export declare function planMigration(db: Database, betterAuthSchema: BetterAuthSchema): Promise<MigrationPlan>;
9
+ export declare function executeMigration(db: Database, migrationPlan: MigrationPlan): Promise<void>;
10
+ interface FmField {
11
+ name: string;
12
+ type: "string" | "numeric" | "timestamp";
13
+ primary?: boolean;
14
+ unique?: boolean;
15
+ }
16
+ declare const migrationStepTypes: readonly ["create", "update"];
17
+ interface MigrationStep {
18
+ tableName: string;
19
+ operation: (typeof migrationStepTypes)[number];
20
+ fields: FmField[];
21
+ }
22
+ export type MigrationPlan = MigrationStep[];
23
+ export declare function prettyPrintMigrationPlan(migrationPlan: MigrationPlan, target?: {
24
+ serverUrl?: string;
25
+ fileName?: string;
26
+ }): void;
85
27
  export {};
@@ -1,34 +1,37 @@
1
+ import { isODataError, isFMODataError } from "@proofkit/fmodata";
1
2
  import chalk from "chalk";
2
- import z from "zod/v4";
3
- async function getMetadata(fetch, databaseName) {
4
- var _a;
5
- console.log("getting metadata...");
6
- const result = await fetch("/$metadata", {
7
- method: "GET",
8
- headers: { accept: "application/json" },
9
- output: z.looseObject({
10
- $Version: z.string(),
11
- "@ServerVersion": z.string()
12
- }).or(z.null()).catch(null)
13
- });
14
- if (result.error) {
15
- console.error("Failed to get metadata:", result.error);
16
- return null;
3
+ function normalizeBetterAuthFieldType(fieldType) {
4
+ if (typeof fieldType === "string") {
5
+ return fieldType;
17
6
  }
18
- return ((_a = result.data) == null ? void 0 : _a[databaseName]) ?? null;
7
+ if (Array.isArray(fieldType)) {
8
+ return fieldType.map(String).join("|");
9
+ }
10
+ return String(fieldType);
11
+ }
12
+ async function getMetadata(db) {
13
+ const metadata = await db.getMetadata({ format: "json" });
14
+ return metadata;
15
+ }
16
+ function mapFieldType(t) {
17
+ if (t.includes("boolean") || t.includes("number")) {
18
+ return "numeric";
19
+ }
20
+ if (t.includes("date")) {
21
+ return "timestamp";
22
+ }
23
+ return "string";
19
24
  }
20
- async function planMigration(fetch, betterAuthSchema, databaseName) {
21
- const metadata = await getMetadata(fetch, databaseName);
25
+ async function planMigration(db, betterAuthSchema) {
26
+ const metadata = await getMetadata(db);
22
27
  const entitySetToType = {};
23
- if (metadata) {
24
- for (const [key, value] of Object.entries(metadata)) {
25
- if (value.$Kind === "EntitySet" && value.$Type) {
26
- const typeKey = value.$Type.split(".").pop();
27
- entitySetToType[key] = typeKey || key;
28
- }
28
+ for (const [key, value] of Object.entries(metadata)) {
29
+ if (value.$Kind === "EntitySet" && value.$Type) {
30
+ const typeKey = value.$Type.split(".").pop();
31
+ entitySetToType[key] = typeKey || key;
29
32
  }
30
33
  }
31
- const existingTables = metadata ? Object.entries(entitySetToType).reduce(
34
+ const existingTables = Object.entries(entitySetToType).reduce(
32
35
  (acc, [entitySetName, entityTypeKey]) => {
33
36
  const entityType = metadata[entityTypeKey];
34
37
  if (!entityType) {
@@ -37,9 +40,9 @@ async function planMigration(fetch, betterAuthSchema, databaseName) {
37
40
  const fields = Object.entries(entityType).filter(
38
41
  ([_fieldKey, fieldValue]) => typeof fieldValue === "object" && fieldValue !== null && "$Type" in fieldValue
39
42
  ).map(([fieldKey, fieldValue]) => {
40
- let type = "varchar";
43
+ let type = "string";
41
44
  if (fieldValue.$Type === "Edm.String") {
42
- type = "varchar";
45
+ type = "string";
43
46
  } else if (fieldValue.$Type === "Edm.DateTimeOffset") {
44
47
  type = "timestamp";
45
48
  } else if (fieldValue.$Type === "Edm.Decimal" || fieldValue.$Type === "Edm.Int32" || fieldValue.$Type === "Edm.Int64") {
@@ -54,20 +57,16 @@ async function planMigration(fetch, betterAuthSchema, databaseName) {
54
57
  return acc;
55
58
  },
56
59
  {}
57
- ) : {};
60
+ );
58
61
  const baTables = Object.entries(betterAuthSchema).sort((a, b) => (a[1].order ?? 0) - (b[1].order ?? 0)).map(([key, value]) => ({
59
62
  ...value,
60
- keyName: key
63
+ modelName: key
61
64
  }));
62
65
  const migrationPlan = [];
63
66
  for (const baTable of baTables) {
64
67
  const fields = Object.entries(baTable.fields).map(([key, field]) => {
65
- let type = "varchar";
66
- if (field.type === "boolean" || field.type.includes("number")) {
67
- type = "numeric";
68
- } else if (field.type === "date") {
69
- type = "timestamp";
70
- }
68
+ const t = normalizeBetterAuthFieldType(field.type);
69
+ const type = mapFieldType(t);
71
70
  return {
72
71
  name: field.fieldName ?? key,
73
72
  type
@@ -105,7 +104,7 @@ async function planMigration(fetch, betterAuthSchema, databaseName) {
105
104
  fields: [
106
105
  {
107
106
  name: "id",
108
- type: "varchar",
107
+ type: "string",
109
108
  primary: true,
110
109
  unique: true
111
110
  },
@@ -116,85 +115,78 @@ async function planMigration(fetch, betterAuthSchema, databaseName) {
116
115
  }
117
116
  return migrationPlan;
118
117
  }
119
- async function executeMigration(fetch, migrationPlan) {
118
+ async function executeMigration(db, migrationPlan) {
120
119
  for (const step of migrationPlan) {
120
+ const fmodataFields = step.fields.map((f) => ({
121
+ name: f.name,
122
+ type: f.type,
123
+ ...f.primary ? { primary: true } : {},
124
+ ...f.unique ? { unique: true } : {}
125
+ }));
121
126
  if (step.operation === "create") {
122
127
  console.log("Creating table:", step.tableName);
123
- const result = await fetch("/FileMaker_Tables", {
124
- method: "POST",
125
- body: {
126
- tableName: step.tableName,
127
- fields: step.fields
128
- }
129
- });
130
- if (result.error) {
131
- console.error(`Failed to create table ${step.tableName}:`, result.error);
132
- throw new Error(`Migration failed: ${result.error}`);
128
+ try {
129
+ await db.schema.createTable(step.tableName, fmodataFields);
130
+ } catch (error) {
131
+ throw migrationError("create", step.tableName, error);
133
132
  }
134
133
  } else if (step.operation === "update") {
135
134
  console.log("Adding fields to table:", step.tableName);
136
- const result = await fetch(`/FileMaker_Tables/${step.tableName}`, {
137
- method: "PATCH",
138
- body: { fields: step.fields }
139
- });
140
- if (result.error) {
141
- console.error(`Failed to update table ${step.tableName}:`, result.error);
142
- throw new Error(`Migration failed: ${result.error}`);
135
+ try {
136
+ await db.schema.addFields(step.tableName, fmodataFields);
137
+ } catch (error) {
138
+ throw migrationError("update", step.tableName, error);
143
139
  }
144
140
  }
145
141
  }
146
142
  }
147
- const genericFieldSchema = z.object({
148
- name: z.string(),
149
- nullable: z.boolean().optional(),
150
- primary: z.boolean().optional(),
151
- unique: z.boolean().optional(),
152
- global: z.boolean().optional(),
153
- repetitions: z.number().optional()
154
- });
155
- const stringFieldSchema = genericFieldSchema.extend({
156
- type: z.literal("varchar"),
157
- maxLength: z.number().optional(),
158
- default: z.enum(["USER", "USERNAME", "CURRENT_USER"]).optional()
159
- });
160
- const numericFieldSchema = genericFieldSchema.extend({
161
- type: z.literal("numeric")
162
- });
163
- const dateFieldSchema = genericFieldSchema.extend({
164
- type: z.literal("date"),
165
- default: z.enum(["CURRENT_DATE", "CURDATE"]).optional()
166
- });
167
- const timeFieldSchema = genericFieldSchema.extend({
168
- type: z.literal("time"),
169
- default: z.enum(["CURRENT_TIME", "CURTIME"]).optional()
170
- });
171
- const timestampFieldSchema = genericFieldSchema.extend({
172
- type: z.literal("timestamp"),
173
- default: z.enum(["CURRENT_TIMESTAMP", "CURTIMESTAMP"]).optional()
174
- });
175
- const containerFieldSchema = genericFieldSchema.extend({
176
- type: z.literal("container"),
177
- externalSecurePath: z.string().optional()
178
- });
179
- const fieldSchema = z.discriminatedUnion("type", [
180
- stringFieldSchema,
181
- numericFieldSchema,
182
- dateFieldSchema,
183
- timeFieldSchema,
184
- timestampFieldSchema,
185
- containerFieldSchema
186
- ]);
187
- z.object({
188
- tableName: z.string(),
189
- operation: z.enum(["create", "update"]),
190
- fields: z.array(fieldSchema)
191
- }).array();
192
- function prettyPrintMigrationPlan(migrationPlan) {
143
+ function formatError(error) {
144
+ if (isODataError(error)) {
145
+ const code = error.code ? ` (${error.code})` : "";
146
+ return `${error.message}${code}`;
147
+ }
148
+ if (isFMODataError(error)) {
149
+ return error.message;
150
+ }
151
+ if (error instanceof Error) {
152
+ return error.message;
153
+ }
154
+ return String(error);
155
+ }
156
+ function migrationError(operation, tableName, error) {
157
+ const action = operation === "create" ? "create table" : "update table";
158
+ const base = `Failed to ${action} "${tableName}"`;
159
+ if (isODataError(error) && error.code === "207") {
160
+ console.error(
161
+ chalk.red(`
162
+ ${base}: Cannot modify schema.`),
163
+ chalk.yellow("\nThe account used does not have schema modification privileges."),
164
+ chalk.gray(
165
+ "\nUse --username and --password to provide Full Access credentials, or grant schema modification privileges to the current account."
166
+ )
167
+ );
168
+ } else {
169
+ console.error(chalk.red(`
170
+ ${base}:`), formatError(error));
171
+ }
172
+ return new Error(`Migration failed: ${formatError(error)}`);
173
+ }
174
+ function prettyPrintMigrationPlan(migrationPlan, target) {
193
175
  if (!migrationPlan.length) {
194
176
  console.log("No changes to apply. Database is up to date.");
195
177
  return;
196
178
  }
197
179
  console.log(chalk.bold.green("Migration plan:"));
180
+ if ((target == null ? void 0 : target.serverUrl) || (target == null ? void 0 : target.fileName)) {
181
+ const parts = [];
182
+ if (target.fileName) {
183
+ parts.push(chalk.cyan(target.fileName));
184
+ }
185
+ if (target.serverUrl) {
186
+ parts.push(chalk.gray(target.serverUrl));
187
+ }
188
+ console.log(` Target: ${parts.join(" @ ")}`);
189
+ }
198
190
  for (const step of migrationPlan) {
199
191
  const emoji = step.operation === "create" ? "✅" : "✏️";
200
192
  console.log(
@@ -1 +1 @@
1
- {"version":3,"file":"migrate.js","sources":["../../src/migrate.ts"],"sourcesContent":["import type { BetterAuthDbSchema } from \"better-auth/db\";\nimport chalk from \"chalk\";\nimport type { Metadata } from \"fm-odata-client\";\nimport z from \"zod/v4\";\nimport type { createRawFetch } from \"./odata\";\n\nexport async function getMetadata(fetch: ReturnType<typeof createRawFetch>[\"fetch\"], databaseName: string) {\n console.log(\"getting metadata...\");\n const result = await fetch(\"/$metadata\", {\n method: \"GET\",\n headers: { accept: \"application/json\" },\n output: z\n .looseObject({\n $Version: z.string(),\n \"@ServerVersion\": z.string(),\n })\n .or(z.null())\n .catch(null),\n });\n\n if (result.error) {\n console.error(\"Failed to get metadata:\", result.error);\n return null;\n }\n\n return (result.data?.[databaseName] ?? null) as Metadata | null;\n}\n\nexport async function planMigration(\n fetch: ReturnType<typeof createRawFetch>[\"fetch\"],\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 const 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) {\n return acc;\n }\n const fields = Object.entries(entityType)\n .filter(\n ([_fieldKey, fieldValue]) =>\n typeof fieldValue === \"object\" && fieldValue !== null && \"$Type\" in fieldValue,\n )\n .map(([fieldKey, fieldValue]) => {\n let type = \"varchar\";\n if (fieldValue.$Type === \"Edm.String\") {\n type = \"varchar\";\n } else if (fieldValue.$Type === \"Edm.DateTimeOffset\") {\n type = \"timestamp\";\n } else if (\n fieldValue.$Type === \"Edm.Decimal\" ||\n fieldValue.$Type === \"Edm.Int32\" ||\n fieldValue.$Type === \"Edm.Int64\"\n ) {\n type = \"numeric\";\n }\n return {\n name: fieldKey,\n type,\n };\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(([key, field]) => {\n let type: \"varchar\" | \"numeric\" | \"timestamp\" = \"varchar\";\n if (field.type === \"boolean\" || field.type.includes(\"number\")) {\n type = \"numeric\";\n } else if (field.type === \"date\") {\n type = \"timestamp\";\n }\n return {\n name: field.fieldName ?? key,\n type,\n };\n });\n\n // get existing table or create it\n const tableExists = baTable.modelName in existingTables;\n\n if (tableExists) {\n const existingFields = (existingTables[baTable.modelName] || []).map((f) => f.name);\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 for (const field of fields) {\n if (existingFields.includes(field.name) && existingFieldMap[field.name] !== field.type) {\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((f) => !existingFields.includes(f.name));\n if (fieldsToAdd.length > 0) {\n migrationPlan.push({\n tableName: baTable.modelName,\n operation: \"update\",\n fields: fieldsToAdd,\n });\n }\n } else {\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 }\n }\n\n return migrationPlan;\n}\n\nexport async function executeMigration(\n fetch: ReturnType<typeof createRawFetch>[\"fetch\"],\n migrationPlan: MigrationPlan,\n) {\n for (const step of migrationPlan) {\n if (step.operation === \"create\") {\n console.log(\"Creating table:\", step.tableName);\n const result = await fetch(\"/FileMaker_Tables\", {\n method: \"POST\",\n body: {\n tableName: step.tableName,\n fields: step.fields,\n },\n });\n\n if (result.error) {\n console.error(`Failed to create table ${step.tableName}:`, result.error);\n throw new Error(`Migration failed: ${result.error}`);\n }\n } else if (step.operation === \"update\") {\n console.log(\"Adding fields to table:\", step.tableName);\n const result = await fetch(`/FileMaker_Tables/${step.tableName}`, {\n method: \"PATCH\",\n body: { fields: step.fields },\n });\n\n if (result.error) {\n console.error(`Failed to update table ${step.tableName}:`, result.error);\n throw new Error(`Migration failed: ${result.error}`);\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\nconst 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) {\n fieldDesc += \", primary\";\n }\n if (field.unique) {\n fieldDesc += \", unique\";\n }\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 { Database, Field, Metadata } from \"@proofkit/fmodata\";\nimport { isFMODataError, isODataError } from \"@proofkit/fmodata\";\nimport type { DBFieldAttribute } from \"better-auth/db\";\nimport chalk from \"chalk\";\n\n/** Schema type returned by better-auth's getSchema function */\ntype BetterAuthSchema = Record<string, { fields: Record<string, DBFieldAttribute>; order: number }>;\n\nfunction normalizeBetterAuthFieldType(fieldType: unknown): string {\n if (typeof fieldType === \"string\") {\n return fieldType;\n }\n if (Array.isArray(fieldType)) {\n return fieldType.map(String).join(\"|\");\n }\n return String(fieldType);\n}\n\nexport async function getMetadata(db: Database): Promise<Metadata> {\n const metadata = await db.getMetadata({ format: \"json\" });\n return metadata;\n}\n\n/** Map a better-auth field type string to an fmodata Field type */\nfunction mapFieldType(t: string): \"string\" | \"numeric\" | \"timestamp\" {\n if (t.includes(\"boolean\") || t.includes(\"number\")) {\n return \"numeric\";\n }\n if (t.includes(\"date\")) {\n return \"timestamp\";\n }\n return \"string\";\n}\n\nexport async function planMigration(db: Database, betterAuthSchema: BetterAuthSchema): Promise<MigrationPlan> {\n const metadata = await getMetadata(db);\n\n // Build a map from entity set name to entity type key\n const entitySetToType: Record<string, string> = {};\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 const existingTables = Object.entries(entitySetToType).reduce(\n (acc, [entitySetName, entityTypeKey]) => {\n const entityType = metadata[entityTypeKey];\n if (!entityType) {\n return acc;\n }\n const fields = Object.entries(entityType)\n .filter(\n ([_fieldKey, fieldValue]) => typeof fieldValue === \"object\" && fieldValue !== null && \"$Type\" in fieldValue,\n )\n .map(([fieldKey, fieldValue]) => {\n let type = \"string\";\n if (fieldValue.$Type === \"Edm.String\") {\n type = \"string\";\n } else if (fieldValue.$Type === \"Edm.DateTimeOffset\") {\n type = \"timestamp\";\n } else if (\n fieldValue.$Type === \"Edm.Decimal\" ||\n fieldValue.$Type === \"Edm.Int32\" ||\n fieldValue.$Type === \"Edm.Int64\"\n ) {\n type = \"numeric\";\n }\n return {\n name: fieldKey,\n type,\n };\n });\n acc[entitySetName] = fields;\n return acc;\n },\n {} as Record<string, { name: string; type: string }[]>,\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 modelName: key,\n }));\n\n const migrationPlan: MigrationPlan = [];\n\n for (const baTable of baTables) {\n const fields: FmField[] = Object.entries(baTable.fields).map(([key, field]) => {\n const t = normalizeBetterAuthFieldType(field.type);\n const type = mapFieldType(t);\n return {\n name: field.fieldName ?? key,\n type,\n };\n });\n\n const tableExists = baTable.modelName in existingTables;\n\n if (tableExists) {\n const existingFields = (existingTables[baTable.modelName] || []).map((f) => f.name);\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 for (const field of fields) {\n if (existingFields.includes(field.name) && existingFieldMap[field.name] !== field.type) {\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((f) => !existingFields.includes(f.name));\n if (fieldsToAdd.length > 0) {\n migrationPlan.push({\n tableName: baTable.modelName,\n operation: \"update\",\n fields: fieldsToAdd,\n });\n }\n } else {\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 }\n }\n\n return migrationPlan;\n}\n\nexport async function executeMigration(db: Database, migrationPlan: MigrationPlan) {\n for (const step of migrationPlan) {\n // Convert plan fields to fmodata Field type\n const fmodataFields: Field[] = step.fields.map((f) => ({\n name: f.name,\n type: f.type,\n ...(f.primary ? { primary: true } : {}),\n ...(f.unique ? { unique: true } : {}),\n }));\n\n if (step.operation === \"create\") {\n console.log(\"Creating table:\", step.tableName);\n try {\n await db.schema.createTable(step.tableName, fmodataFields);\n } catch (error) {\n throw migrationError(\"create\", step.tableName, error);\n }\n } else if (step.operation === \"update\") {\n console.log(\"Adding fields to table:\", step.tableName);\n try {\n await db.schema.addFields(step.tableName, fmodataFields);\n } catch (error) {\n throw migrationError(\"update\", step.tableName, error);\n }\n }\n }\n}\n\ninterface FmField {\n name: string;\n type: \"string\" | \"numeric\" | \"timestamp\";\n primary?: boolean;\n unique?: boolean;\n}\n\nconst migrationStepTypes = [\"create\", \"update\"] as const;\ninterface MigrationStep {\n tableName: string;\n operation: (typeof migrationStepTypes)[number];\n fields: FmField[];\n}\n\nexport type MigrationPlan = MigrationStep[];\n\nfunction formatError(error: unknown): string {\n if (isODataError(error)) {\n const code = error.code ? ` (${error.code})` : \"\";\n return `${error.message}${code}`;\n }\n if (isFMODataError(error)) {\n return error.message;\n }\n if (error instanceof Error) {\n return error.message;\n }\n return String(error);\n}\n\nfunction migrationError(operation: string, tableName: string, error: unknown): Error {\n const action = operation === \"create\" ? \"create table\" : \"update table\";\n const base = `Failed to ${action} \"${tableName}\"`;\n\n if (isODataError(error) && error.code === \"207\") {\n console.error(\n chalk.red(`\\n${base}: Cannot modify schema.`),\n chalk.yellow(\"\\nThe account used does not have schema modification privileges.\"),\n chalk.gray(\n \"\\nUse --username and --password to provide Full Access credentials, or grant schema modification privileges to the current account.\",\n ),\n );\n } else {\n console.error(chalk.red(`\\n${base}:`), formatError(error));\n }\n return new Error(`Migration failed: ${formatError(error)}`);\n}\n\nexport function prettyPrintMigrationPlan(\n migrationPlan: MigrationPlan,\n target?: { serverUrl?: string; fileName?: string },\n) {\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 if (target?.serverUrl || target?.fileName) {\n const parts: string[] = [];\n if (target.fileName) {\n parts.push(chalk.cyan(target.fileName));\n }\n if (target.serverUrl) {\n parts.push(chalk.gray(target.serverUrl));\n }\n console.log(` Target: ${parts.join(\" @ \")}`);\n }\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) {\n fieldDesc += \", primary\";\n }\n if (field.unique) {\n fieldDesc += \", unique\";\n }\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.3.1-beta.0",
3
+ "version": "0.4.0-beta.2",
4
4
  "description": "FileMaker adapter for Better Auth",
5
5
  "type": "module",
6
6
  "main": "dist/esm/index.js",
@@ -36,34 +36,33 @@
36
36
  "url": "git+https://github.com/proofgeist/proofkit.git"
37
37
  },
38
38
  "dependencies": {
39
- "@babel/preset-react": "^7.27.1",
40
- "@babel/preset-typescript": "^7.27.1",
39
+ "@babel/preset-react": "^7.28.5",
40
+ "@babel/preset-typescript": "^7.28.5",
41
41
  "@commander-js/extra-typings": "^14.0.0",
42
- "@tanstack/vite-config": "^0.2.0",
43
- "better-auth": "^1.2.10",
44
- "c12": "^3.0.4",
42
+ "@tanstack/vite-config": "^0.2.1",
43
+ "better-auth": "^1.4.11",
44
+ "c12": "^3.3.3",
45
45
  "chalk": "5.4.1",
46
- "commander": "^14.0.0",
47
- "dotenv": "^16.5.0",
48
- "fs-extra": "^11.3.0",
49
- "neverthrow": "^8.2.0",
50
- "odata-query": "^8.0.4",
46
+ "commander": "^14.0.2",
47
+ "dotenv": "^16.6.1",
48
+ "fs-extra": "^11.3.3",
51
49
  "prompts": "^2.4.2",
52
- "vite": "^6.3.4",
53
- "zod": "^4.1.13"
50
+ "vite": "^6.4.1",
51
+ "@proofkit/fmodata": "0.1.0-beta.25"
54
52
  },
55
53
  "devDependencies": {
56
54
  "@types/fs-extra": "^11.0.4",
57
55
  "@types/prompts": "^2.4.9",
58
56
  "@vitest/ui": "^3.2.4",
59
- "fm-odata-client": "^3.0.1",
60
- "publint": "^0.3.12",
57
+ "publint": "^0.3.16",
61
58
  "typescript": "^5.9.3",
62
- "vitest": "^4.0.7"
59
+ "vitest": "^4.0.17"
63
60
  },
64
61
  "scripts": {
65
62
  "dev": "pnpm build:watch",
66
63
  "test": "vitest run",
64
+ "test:e2e": "doppler run -c test_betterauth -- vitest run tests/e2e",
65
+ "typecheck": "tsc --noEmit",
67
66
  "build": "vite build && publint --strict",
68
67
  "build:watch": "vite build --watch",
69
68
  "ci": "pnpm run build && pnpm run test",