@proofkit/better-auth 0.2.0 → 0.2.1

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,6 +1,7 @@
1
1
  import { createAdapter } from "better-auth/adapters";
2
2
  import { createFmOdataFetch } from "./odata/index.js";
3
3
  import { z, prettifyError } from "zod/v4";
4
+ import { logger } from "better-auth";
4
5
  const configSchema = z.object({
5
6
  debugLogs: z.unknown().optional(),
6
7
  usePlural: z.boolean().optional(),
@@ -31,10 +32,16 @@ function parseWhere(where) {
31
32
  }
32
33
  function formatValue(value) {
33
34
  if (value === null) return "null";
34
- if (typeof value === "string") return `'${value.replace(/'/g, "''")}'`;
35
35
  if (typeof value === "boolean") return value ? "true" : "false";
36
- if (value instanceof Date) return `'${value.toISOString()}'`;
36
+ if (value instanceof Date) return value.toISOString();
37
37
  if (Array.isArray(value)) return `(${value.map(formatValue).join(",")})`;
38
+ if (typeof value === "string") {
39
+ const isoDateRegex = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d{3})?Z?$/;
40
+ if (isoDateRegex.test(value)) {
41
+ return value;
42
+ }
43
+ return `'${value.replace(/'/g, "''")}'`;
44
+ }
38
45
  return (value == null ? void 0 : value.toString()) ?? "";
39
46
  }
40
47
  const opMap = {
@@ -92,8 +99,8 @@ const FileMakerAdapter = (_config = defaultConfig) => {
92
99
  }
93
100
  const config = parsed.data;
94
101
  const fetch = createFmOdataFetch({
95
- ...config.odata
96
- // logging: config.debugLogs ? true : "none",
102
+ ...config.odata,
103
+ logging: config.debugLogs ? "verbose" : "none"
97
104
  });
98
105
  return createAdapter({
99
106
  config: {
@@ -111,11 +118,28 @@ const FileMakerAdapter = (_config = defaultConfig) => {
111
118
  // Whether the database supports booleans. (Default: true)
112
119
  supportsNumericIds: false
113
120
  // Whether the database supports auto-incrementing numeric IDs. (Default: true)
121
+ // customTransformInput: ({ data, fieldAttributes }) => {
122
+ // if (fieldAttributes.type === "date") {
123
+ // const rawData = data as string;
124
+ // const fmDate = dayjs(rawData).format("YYYY+MM+DD");
125
+ // const isoDate = dayjs(rawData).format("YYYY-MM-DD");
126
+ // const newData = rawData
127
+ // .replace(isoDate, fmDate)
128
+ // .replace("T", " ")
129
+ // .replace("Z", "");
130
+ // console.log(`replaced ${isoDate} with ${fmDate}`);
131
+ // return newData;
132
+ // }
133
+ // return data;
134
+ // },
114
135
  },
115
136
  adapter: ({ options }) => {
116
137
  return {
117
138
  options: { config },
118
139
  create: async ({ data, model, select }) => {
140
+ if (model === "session") {
141
+ console.log("session", data);
142
+ }
119
143
  const result = await fetch(`/${model}`, {
120
144
  method: "POST",
121
145
  body: data,
@@ -128,10 +152,12 @@ const FileMakerAdapter = (_config = defaultConfig) => {
128
152
  },
129
153
  count: async ({ model, where }) => {
130
154
  var _a;
155
+ const filter = parseWhere(where);
156
+ logger.debug("$filter", filter);
131
157
  const result = await fetch(`/${model}/$count`, {
132
158
  method: "GET",
133
159
  query: {
134
- $filter: parseWhere(where)
160
+ $filter: filter
135
161
  },
136
162
  output: z.object({ value: z.number() })
137
163
  });
@@ -142,10 +168,12 @@ const FileMakerAdapter = (_config = defaultConfig) => {
142
168
  },
143
169
  findOne: async ({ model, where }) => {
144
170
  var _a, _b;
171
+ const filter = parseWhere(where);
172
+ logger.debug("$filter", filter);
145
173
  const result = await fetch(`/${model}`, {
146
174
  method: "GET",
147
175
  query: {
148
- ...where.length > 0 ? { $filter: parseWhere(where) } : {},
176
+ ...filter.length > 0 ? { $filter: filter } : {},
149
177
  $top: 1
150
178
  },
151
179
  output: z.object({ value: z.array(z.any()) })
@@ -158,6 +186,7 @@ const FileMakerAdapter = (_config = defaultConfig) => {
158
186
  findMany: async ({ model, where, limit, offset, sortBy }) => {
159
187
  var _a;
160
188
  const filter = parseWhere(where);
189
+ logger.debug("$filter", filter);
161
190
  const rows = await fetch(`/${model}`, {
162
191
  method: "GET",
163
192
  query: {
@@ -174,12 +203,14 @@ const FileMakerAdapter = (_config = defaultConfig) => {
174
203
  return ((_a = rows.data) == null ? void 0 : _a.value) ?? [];
175
204
  },
176
205
  delete: async ({ model, where }) => {
206
+ const filter = parseWhere(where);
207
+ logger.debug("$filter", filter);
208
+ console.log("delete", model, where, filter);
177
209
  const result = await fetch(`/${model}`, {
178
210
  method: "DELETE",
179
211
  query: {
180
- ...where.length > 0 ? { $filter: parseWhere(where) } : {},
181
- $top: 1,
182
- $select: [`"id"`]
212
+ ...where.length > 0 ? { $filter: filter } : {},
213
+ $top: 1
183
214
  }
184
215
  });
185
216
  if (result.error) {
@@ -187,12 +218,15 @@ const FileMakerAdapter = (_config = defaultConfig) => {
187
218
  }
188
219
  },
189
220
  deleteMany: async ({ model, where }) => {
221
+ const filter = parseWhere(where);
222
+ logger.debug(
223
+ where.map((o) => `typeof ${o.value} is ${typeof o.value}`).join("\n")
224
+ );
225
+ logger.debug("$filter", filter);
190
226
  const result = await fetch(`/${model}/$count`, {
191
227
  method: "DELETE",
192
228
  query: {
193
- ...where.length > 0 ? { $filter: parseWhere(where) } : {},
194
- $top: 1,
195
- $select: [`"id"`]
229
+ ...where.length > 0 ? { $filter: filter } : {}
196
230
  },
197
231
  output: z.coerce.number()
198
232
  });
@@ -1 +1 @@
1
- {"version":3,"file":"adapter.js","sources":["../../src/adapter.ts"],"sourcesContent":["import {\n CleanedWhere,\n createAdapter,\n type AdapterDebugLogs,\n} from \"better-auth/adapters\";\nimport { createFmOdataFetch, type FmOdataConfig } from \"./odata\";\nimport { prettifyError, z } from \"zod/v4\";\n\nconst configSchema = z.object({\n debugLogs: z.unknown().optional(),\n usePlural: z.boolean().optional(),\n odata: z.object({\n serverUrl: z.url(),\n auth: z.union([\n z.object({ username: z.string(), password: z.string() }),\n z.object({ apiKey: z.string() }),\n ]),\n database: z.string().endsWith(\".fmp12\"),\n }),\n});\n\ninterface FileMakerAdapterConfig {\n /**\n * Helps you debug issues with the adapter.\n */\n debugLogs?: AdapterDebugLogs;\n /**\n * If the table names in the schema are plural.\n */\n usePlural?: boolean;\n\n /**\n * Connection details for the FileMaker server.\n */\n odata: z.infer<typeof configSchema>[\"odata\"];\n}\n\nexport type AdapterOptions = {\n config: FileMakerAdapterConfig;\n};\n\nconst defaultConfig: Required<FileMakerAdapterConfig> = {\n debugLogs: false,\n usePlural: false,\n odata: {\n serverUrl: \"\",\n auth: { username: \"\", password: \"\" },\n database: \"\",\n },\n};\n\n/**\n * Parse the where clause to an OData filter string.\n * @param where - The where clause to parse.\n * @returns The OData filter string.\n * @internal\n */\nexport function parseWhere(where?: CleanedWhere[]): string {\n if (!where || where.length === 0) return \"\";\n\n // Helper to quote field names with special chars or if field is 'id'\n function quoteField(field: string, value?: any) {\n // Never quote for null or date values (per test expectations)\n if (value === null || value instanceof Date) return field;\n // Always quote if field is 'id' or has space or underscore\n if (field === \"id\" || /[\\s_]/.test(field)) return `\"${field}\"`;\n return field;\n }\n\n // Helper to format values for OData\n function formatValue(value: any): string {\n if (value === null) return \"null\";\n if (typeof value === \"string\") return `'${value.replace(/'/g, \"''\")}'`;\n if (typeof value === \"boolean\") return value ? \"true\" : \"false\";\n if (value instanceof Date) return `'${value.toISOString()}'`;\n if (Array.isArray(value)) return `(${value.map(formatValue).join(\",\")})`;\n return value?.toString() ?? \"\";\n }\n\n // Map our operators to OData\n const opMap: Record<string, string> = {\n eq: \"eq\",\n ne: \"ne\",\n lt: \"lt\",\n lte: \"le\",\n gt: \"gt\",\n gte: \"ge\",\n };\n\n // Build each clause\n const clauses: string[] = [];\n for (let i = 0; i < where.length; i++) {\n const cond = where[i];\n if (!cond) continue;\n const field = quoteField(cond.field, cond.value);\n let clause = \"\";\n switch (cond.operator) {\n case \"eq\":\n case \"ne\":\n case \"lt\":\n case \"lte\":\n case \"gt\":\n case \"gte\":\n clause = `${field} ${opMap[cond.operator!]} ${formatValue(cond.value)}`;\n break;\n case \"in\":\n if (Array.isArray(cond.value)) {\n clause = cond.value\n .map((v) => `${field} eq ${formatValue(v)}`)\n .join(\" or \");\n clause = `(${clause})`;\n }\n break;\n case \"contains\":\n clause = `contains(${field}, ${formatValue(cond.value)})`;\n break;\n case \"starts_with\":\n clause = `startswith(${field}, ${formatValue(cond.value)})`;\n break;\n case \"ends_with\":\n clause = `endswith(${field}, ${formatValue(cond.value)})`;\n break;\n default:\n clause = `${field} eq ${formatValue(cond.value)}`;\n }\n clauses.push(clause);\n // Add connector if not last\n if (i < where.length - 1) {\n clauses.push((cond.connector || \"and\").toLowerCase());\n }\n }\n return clauses.join(\" \");\n}\n\nexport const FileMakerAdapter = (\n _config: FileMakerAdapterConfig = defaultConfig,\n) => {\n const parsed = configSchema.loose().safeParse(_config);\n\n if (!parsed.success) {\n throw new Error(`Invalid configuration: ${prettifyError(parsed.error)}`);\n }\n const config = parsed.data;\n\n const fetch = createFmOdataFetch({\n ...config.odata,\n // logging: config.debugLogs ? true : \"none\",\n });\n\n return createAdapter({\n config: {\n adapterId: \"filemaker\",\n adapterName: \"FileMaker\",\n usePlural: config.usePlural ?? false, // Whether the table names in the schema are plural.\n debugLogs: config.debugLogs ?? false, // Whether to enable debug logs.\n supportsJSON: false, // Whether the database supports JSON. (Default: false)\n supportsDates: false, // Whether the database supports dates. (Default: true)\n supportsBooleans: false, // Whether the database supports booleans. (Default: true)\n supportsNumericIds: false, // Whether the database supports auto-incrementing numeric IDs. (Default: true)\n },\n adapter: ({ options }) => {\n return {\n options: { config },\n create: async ({ data, model, select }) => {\n const result = await fetch(`/${model}`, {\n method: \"POST\",\n body: data,\n output: z.looseObject({ id: z.string() }),\n });\n\n if (result.error) {\n throw new Error(\"Failed to create record\");\n }\n\n return result.data as any;\n },\n count: async ({ model, where }) => {\n const result = await fetch(`/${model}/$count`, {\n method: \"GET\",\n query: {\n $filter: parseWhere(where),\n },\n output: z.object({ value: z.number() }),\n });\n if (!result.data) {\n throw new Error(\"Failed to count records\");\n }\n return result.data?.value ?? 0;\n },\n findOne: async ({ model, where }) => {\n const result = await fetch(`/${model}`, {\n method: \"GET\",\n query: {\n ...(where.length > 0 ? { $filter: parseWhere(where) } : {}),\n $top: 1,\n },\n output: z.object({ value: z.array(z.any()) }),\n });\n if (result.error) {\n throw new Error(\"Failed to find record\");\n }\n return result.data?.value?.[0] ?? null;\n },\n findMany: async ({ model, where, limit, offset, sortBy }) => {\n const filter = parseWhere(where);\n\n const rows = await fetch(`/${model}`, {\n method: \"GET\",\n query: {\n ...(filter.length > 0 ? { $filter: filter } : {}),\n $top: limit,\n $skip: offset,\n ...(sortBy\n ? { $orderby: `\"${sortBy.field}\" ${sortBy.direction ?? \"asc\"}` }\n : {}),\n },\n output: z.object({ value: z.array(z.any()) }),\n });\n if (rows.error) {\n throw new Error(\"Failed to find records\");\n }\n return rows.data?.value ?? [];\n },\n delete: async ({ model, where }) => {\n const result = await fetch(`/${model}`, {\n method: \"DELETE\",\n query: {\n ...(where.length > 0 ? { $filter: parseWhere(where) } : {}),\n $top: 1,\n $select: [`\"id\"`],\n },\n });\n if (result.error) {\n throw new Error(\"Failed to delete record\");\n }\n },\n deleteMany: async ({ model, where }) => {\n const result = await fetch(`/${model}/$count`, {\n method: \"DELETE\",\n query: {\n ...(where.length > 0 ? { $filter: parseWhere(where) } : {}),\n $top: 1,\n $select: [`\"id\"`],\n },\n output: z.coerce.number(),\n });\n if (result.error) {\n throw new Error(\"Failed to delete record\");\n }\n return result.data ?? 0;\n },\n update: async ({ model, where, update }) => {\n const result = await fetch(`/${model}`, {\n method: \"PATCH\",\n query: {\n ...(where.length > 0 ? { $filter: parseWhere(where) } : {}),\n $top: 1,\n $select: [`\"id\"`],\n },\n body: update,\n output: z.object({ value: z.array(z.any()) }),\n });\n return result.data?.value?.[0] ?? null;\n },\n updateMany: async ({ model, where, update }) => {\n const filter = parseWhere(where);\n const result = await fetch(`/${model}`, {\n method: \"PATCH\",\n query: {\n ...(where.length > 0 ? { $filter: filter } : {}),\n },\n body: update,\n });\n return result.data as any;\n },\n };\n },\n });\n};\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"adapter.js","sources":["../../src/adapter.ts"],"sourcesContent":["import {\n CleanedWhere,\n createAdapter,\n type AdapterDebugLogs,\n} from \"better-auth/adapters\";\nimport { createFmOdataFetch, type FmOdataConfig } from \"./odata\";\nimport { prettifyError, z } from \"zod/v4\";\nimport dayjs from \"dayjs\";\nimport { logger } from \"better-auth\";\n\nconst configSchema = z.object({\n debugLogs: z.unknown().optional(),\n usePlural: z.boolean().optional(),\n odata: z.object({\n serverUrl: z.url(),\n auth: z.union([\n z.object({ username: z.string(), password: z.string() }),\n z.object({ apiKey: z.string() }),\n ]),\n database: z.string().endsWith(\".fmp12\"),\n }),\n});\n\ninterface FileMakerAdapterConfig {\n /**\n * Helps you debug issues with the adapter.\n */\n debugLogs?: AdapterDebugLogs;\n /**\n * If the table names in the schema are plural.\n */\n usePlural?: boolean;\n\n /**\n * Connection details for the FileMaker server.\n */\n odata: z.infer<typeof configSchema>[\"odata\"];\n}\n\nexport type AdapterOptions = {\n config: FileMakerAdapterConfig;\n};\n\nconst defaultConfig: Required<FileMakerAdapterConfig> = {\n debugLogs: false,\n usePlural: false,\n odata: {\n serverUrl: \"\",\n auth: { username: \"\", password: \"\" },\n database: \"\",\n },\n};\n\n/**\n * Parse the where clause to an OData filter string.\n * @param where - The where clause to parse.\n * @returns The OData filter string.\n * @internal\n */\nexport function parseWhere(where?: CleanedWhere[]): string {\n if (!where || where.length === 0) return \"\";\n\n // Helper to quote field names with special chars or if field is 'id'\n function quoteField(field: string, value?: any) {\n // Never quote for null or date values (per test expectations)\n if (value === null || value instanceof Date) return field;\n // Always quote if field is 'id' or has space or underscore\n if (field === \"id\" || /[\\s_]/.test(field)) return `\"${field}\"`;\n return field;\n }\n\n // Helper to format values for OData\n function formatValue(value: any): string {\n if (value === null) return \"null\";\n if (typeof value === \"boolean\") return value ? \"true\" : \"false\";\n if (value instanceof Date) return value.toISOString();\n if (Array.isArray(value)) return `(${value.map(formatValue).join(\",\")})`;\n\n // Handle strings - check if it's an ISO date string first\n if (typeof value === \"string\") {\n // Check if it's an ISO date string (YYYY-MM-DDTHH:mm:ss.sssZ format)\n const isoDateRegex = /^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(\\.\\d{3})?Z?$/;\n if (isoDateRegex.test(value)) {\n return value; // Return ISO date strings without quotes\n }\n return `'${value.replace(/'/g, \"''\")}'`; // Regular strings get quotes\n }\n\n return value?.toString() ?? \"\";\n }\n\n // Map our operators to OData\n const opMap: Record<string, string> = {\n eq: \"eq\",\n ne: \"ne\",\n lt: \"lt\",\n lte: \"le\",\n gt: \"gt\",\n gte: \"ge\",\n };\n\n // Build each clause\n const clauses: string[] = [];\n for (let i = 0; i < where.length; i++) {\n const cond = where[i];\n if (!cond) continue;\n const field = quoteField(cond.field, cond.value);\n let clause = \"\";\n switch (cond.operator) {\n case \"eq\":\n case \"ne\":\n case \"lt\":\n case \"lte\":\n case \"gt\":\n case \"gte\":\n clause = `${field} ${opMap[cond.operator!]} ${formatValue(cond.value)}`;\n break;\n case \"in\":\n if (Array.isArray(cond.value)) {\n clause = cond.value\n .map((v) => `${field} eq ${formatValue(v)}`)\n .join(\" or \");\n clause = `(${clause})`;\n }\n break;\n case \"contains\":\n clause = `contains(${field}, ${formatValue(cond.value)})`;\n break;\n case \"starts_with\":\n clause = `startswith(${field}, ${formatValue(cond.value)})`;\n break;\n case \"ends_with\":\n clause = `endswith(${field}, ${formatValue(cond.value)})`;\n break;\n default:\n clause = `${field} eq ${formatValue(cond.value)}`;\n }\n clauses.push(clause);\n // Add connector if not last\n if (i < where.length - 1) {\n clauses.push((cond.connector || \"and\").toLowerCase());\n }\n }\n return clauses.join(\" \");\n}\n\nexport const FileMakerAdapter = (\n _config: FileMakerAdapterConfig = defaultConfig,\n) => {\n const parsed = configSchema.loose().safeParse(_config);\n\n if (!parsed.success) {\n throw new Error(`Invalid configuration: ${prettifyError(parsed.error)}`);\n }\n const config = parsed.data;\n\n const fetch = createFmOdataFetch({\n ...config.odata,\n logging: config.debugLogs ? \"verbose\" : \"none\",\n });\n\n return createAdapter({\n config: {\n adapterId: \"filemaker\",\n adapterName: \"FileMaker\",\n usePlural: config.usePlural ?? false, // Whether the table names in the schema are plural.\n debugLogs: config.debugLogs ?? false, // Whether to enable debug logs.\n supportsJSON: false, // Whether the database supports JSON. (Default: false)\n supportsDates: false, // Whether the database supports dates. (Default: true)\n supportsBooleans: false, // Whether the database supports booleans. (Default: true)\n supportsNumericIds: false, // Whether the database supports auto-incrementing numeric IDs. (Default: true)\n // customTransformInput: ({ data, fieldAttributes }) => {\n // if (fieldAttributes.type === \"date\") {\n // const rawData = data as string;\n // const fmDate = dayjs(rawData).format(\"YYYY+MM+DD\");\n // const isoDate = dayjs(rawData).format(\"YYYY-MM-DD\");\n\n // const newData = rawData\n // .replace(isoDate, fmDate)\n // .replace(\"T\", \" \")\n // .replace(\"Z\", \"\");\n\n // console.log(`replaced ${isoDate} with ${fmDate}`);\n // return newData;\n // }\n\n // return data;\n // },\n },\n adapter: ({ options }) => {\n return {\n options: { config },\n create: async ({ data, model, select }) => {\n if (model === \"session\") {\n console.log(\"session\", data);\n }\n\n const result = await fetch(`/${model}`, {\n method: \"POST\",\n body: data,\n output: z.looseObject({ id: z.string() }),\n });\n\n if (result.error) {\n throw new Error(\"Failed to create record\");\n }\n\n return result.data as any;\n },\n count: async ({ model, where }) => {\n const filter = parseWhere(where);\n logger.debug(\"$filter\", filter);\n const result = await fetch(`/${model}/$count`, {\n method: \"GET\",\n query: {\n $filter: filter,\n },\n output: z.object({ value: z.number() }),\n });\n if (!result.data) {\n throw new Error(\"Failed to count records\");\n }\n return result.data?.value ?? 0;\n },\n findOne: async ({ model, where }) => {\n const filter = parseWhere(where);\n logger.debug(\"$filter\", filter);\n const result = await fetch(`/${model}`, {\n method: \"GET\",\n query: {\n ...(filter.length > 0 ? { $filter: filter } : {}),\n $top: 1,\n },\n output: z.object({ value: z.array(z.any()) }),\n });\n if (result.error) {\n throw new Error(\"Failed to find record\");\n }\n return result.data?.value?.[0] ?? null;\n },\n findMany: async ({ model, where, limit, offset, sortBy }) => {\n const filter = parseWhere(where);\n logger.debug(\"$filter\", filter);\n\n const rows = await fetch(`/${model}`, {\n method: \"GET\",\n query: {\n ...(filter.length > 0 ? { $filter: filter } : {}),\n $top: limit,\n $skip: offset,\n ...(sortBy\n ? { $orderby: `\"${sortBy.field}\" ${sortBy.direction ?? \"asc\"}` }\n : {}),\n },\n output: z.object({ value: z.array(z.any()) }),\n });\n if (rows.error) {\n throw new Error(\"Failed to find records\");\n }\n return rows.data?.value ?? [];\n },\n delete: async ({ model, where }) => {\n const filter = parseWhere(where);\n logger.debug(\"$filter\", filter);\n console.log(\"delete\", model, where, filter);\n const result = await fetch(`/${model}`, {\n method: \"DELETE\",\n query: {\n ...(where.length > 0 ? { $filter: filter } : {}),\n $top: 1,\n },\n });\n if (result.error) {\n throw new Error(\"Failed to delete record\");\n }\n },\n deleteMany: async ({ model, where }) => {\n const filter = parseWhere(where);\n logger.debug(\n where\n .map((o) => `typeof ${o.value} is ${typeof o.value}`)\n .join(\"\\n\"),\n );\n logger.debug(\"$filter\", filter);\n\n const result = await fetch(`/${model}/$count`, {\n method: \"DELETE\",\n query: {\n ...(where.length > 0 ? { $filter: filter } : {}),\n },\n output: z.coerce.number(),\n });\n if (result.error) {\n throw new Error(\"Failed to delete record\");\n }\n return result.data ?? 0;\n },\n update: async ({ model, where, update }) => {\n const result = await fetch(`/${model}`, {\n method: \"PATCH\",\n query: {\n ...(where.length > 0 ? { $filter: parseWhere(where) } : {}),\n $top: 1,\n $select: [`\"id\"`],\n },\n body: update,\n output: z.object({ value: z.array(z.any()) }),\n });\n return result.data?.value?.[0] ?? null;\n },\n updateMany: async ({ model, where, update }) => {\n const filter = parseWhere(where);\n const result = await fetch(`/${model}`, {\n method: \"PATCH\",\n query: {\n ...(where.length > 0 ? { $filter: filter } : {}),\n },\n body: update,\n });\n return result.data as any;\n },\n };\n },\n });\n};\n"],"names":[],"mappings":";;;;AAUA,MAAM,eAAe,EAAE,OAAO;AAAA,EAC5B,WAAW,EAAE,QAAQ,EAAE,SAAS;AAAA,EAChC,WAAW,EAAE,QAAQ,EAAE,SAAS;AAAA,EAChC,OAAO,EAAE,OAAO;AAAA,IACd,WAAW,EAAE,IAAI;AAAA,IACjB,MAAM,EAAE,MAAM;AAAA,MACZ,EAAE,OAAO,EAAE,UAAU,EAAE,OAAO,GAAG,UAAU,EAAE,OAAO,GAAG;AAAA,MACvD,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAA,EAAU,CAAA;AAAA,IAAA,CAChC;AAAA,IACD,UAAU,EAAE,OAAO,EAAE,SAAS,QAAQ;AAAA,EACvC,CAAA;AACH,CAAC;AAsBD,MAAM,gBAAkD;AAAA,EACtD,WAAW;AAAA,EACX,WAAW;AAAA,EACX,OAAO;AAAA,IACL,WAAW;AAAA,IACX,MAAM,EAAE,UAAU,IAAI,UAAU,GAAG;AAAA,IACnC,UAAU;AAAA,EAAA;AAEd;AAQO,SAAS,WAAW,OAAgC;AACzD,MAAI,CAAC,SAAS,MAAM,WAAW,EAAU,QAAA;AAGhC,WAAA,WAAW,OAAe,OAAa;AAE9C,QAAI,UAAU,QAAQ,iBAAiB,KAAa,QAAA;AAEhD,QAAA,UAAU,QAAQ,QAAQ,KAAK,KAAK,EAAG,QAAO,IAAI,KAAK;AACpD,WAAA;AAAA,EAAA;AAIT,WAAS,YAAY,OAAoB;AACnC,QAAA,UAAU,KAAa,QAAA;AAC3B,QAAI,OAAO,UAAU,UAAW,QAAO,QAAQ,SAAS;AACxD,QAAI,iBAAiB,KAAa,QAAA,MAAM,YAAY;AACpD,QAAI,MAAM,QAAQ,KAAK,EAAU,QAAA,IAAI,MAAM,IAAI,WAAW,EAAE,KAAK,GAAG,CAAC;AAGjE,QAAA,OAAO,UAAU,UAAU;AAE7B,YAAM,eAAe;AACjB,UAAA,aAAa,KAAK,KAAK,GAAG;AACrB,eAAA;AAAA,MAAA;AAET,aAAO,IAAI,MAAM,QAAQ,MAAM,IAAI,CAAC;AAAA,IAAA;AAG/B,YAAA,+BAAO,eAAc;AAAA,EAAA;AAI9B,QAAM,QAAgC;AAAA,IACpC,IAAI;AAAA,IACJ,IAAI;AAAA,IACJ,IAAI;AAAA,IACJ,KAAK;AAAA,IACL,IAAI;AAAA,IACJ,KAAK;AAAA,EACP;AAGA,QAAM,UAAoB,CAAC;AAC3B,WAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;AAC/B,UAAA,OAAO,MAAM,CAAC;AACpB,QAAI,CAAC,KAAM;AACX,UAAM,QAAQ,WAAW,KAAK,OAAO,KAAK,KAAK;AAC/C,QAAI,SAAS;AACb,YAAQ,KAAK,UAAU;AAAA,MACrB,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AACM,iBAAA,GAAG,KAAK,IAAI,MAAM,KAAK,QAAS,CAAC,IAAI,YAAY,KAAK,KAAK,CAAC;AACrE;AAAA,MACF,KAAK;AACH,YAAI,MAAM,QAAQ,KAAK,KAAK,GAAG;AAC7B,mBAAS,KAAK,MACX,IAAI,CAAC,MAAM,GAAG,KAAK,OAAO,YAAY,CAAC,CAAC,EAAE,EAC1C,KAAK,MAAM;AACd,mBAAS,IAAI,MAAM;AAAA,QAAA;AAErB;AAAA,MACF,KAAK;AACH,iBAAS,YAAY,KAAK,KAAK,YAAY,KAAK,KAAK,CAAC;AACtD;AAAA,MACF,KAAK;AACH,iBAAS,cAAc,KAAK,KAAK,YAAY,KAAK,KAAK,CAAC;AACxD;AAAA,MACF,KAAK;AACH,iBAAS,YAAY,KAAK,KAAK,YAAY,KAAK,KAAK,CAAC;AACtD;AAAA,MACF;AACE,iBAAS,GAAG,KAAK,OAAO,YAAY,KAAK,KAAK,CAAC;AAAA,IAAA;AAEnD,YAAQ,KAAK,MAAM;AAEf,QAAA,IAAI,MAAM,SAAS,GAAG;AACxB,cAAQ,MAAM,KAAK,aAAa,OAAO,aAAa;AAAA,IAAA;AAAA,EACtD;AAEK,SAAA,QAAQ,KAAK,GAAG;AACzB;AAEa,MAAA,mBAAmB,CAC9B,UAAkC,kBAC/B;AACH,QAAM,SAAS,aAAa,MAAM,EAAE,UAAU,OAAO;AAEjD,MAAA,CAAC,OAAO,SAAS;AACnB,UAAM,IAAI,MAAM,0BAA0B,cAAc,OAAO,KAAK,CAAC,EAAE;AAAA,EAAA;AAEzE,QAAM,SAAS,OAAO;AAEtB,QAAM,QAAQ,mBAAmB;AAAA,IAC/B,GAAG,OAAO;AAAA,IACV,SAAS,OAAO,YAAY,YAAY;AAAA,EAAA,CACzC;AAED,SAAO,cAAc;AAAA,IACnB,QAAQ;AAAA,MACN,WAAW;AAAA,MACX,aAAa;AAAA,MACb,WAAW,OAAO,aAAa;AAAA;AAAA,MAC/B,WAAW,OAAO,aAAa;AAAA;AAAA,MAC/B,cAAc;AAAA;AAAA,MACd,eAAe;AAAA;AAAA,MACf,kBAAkB;AAAA;AAAA,MAClB,oBAAoB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAkBtB;AAAA,IACA,SAAS,CAAC,EAAE,cAAc;AACjB,aAAA;AAAA,QACL,SAAS,EAAE,OAAO;AAAA,QAClB,QAAQ,OAAO,EAAE,MAAM,OAAO,aAAa;AACzC,cAAI,UAAU,WAAW;AACf,oBAAA,IAAI,WAAW,IAAI;AAAA,UAAA;AAG7B,gBAAM,SAAS,MAAM,MAAM,IAAI,KAAK,IAAI;AAAA,YACtC,QAAQ;AAAA,YACR,MAAM;AAAA,YACN,QAAQ,EAAE,YAAY,EAAE,IAAI,EAAE,SAAU,CAAA;AAAA,UAAA,CACzC;AAED,cAAI,OAAO,OAAO;AACV,kBAAA,IAAI,MAAM,yBAAyB;AAAA,UAAA;AAG3C,iBAAO,OAAO;AAAA,QAChB;AAAA,QACA,OAAO,OAAO,EAAE,OAAO,YAAY;;AAC3B,gBAAA,SAAS,WAAW,KAAK;AACxB,iBAAA,MAAM,WAAW,MAAM;AAC9B,gBAAM,SAAS,MAAM,MAAM,IAAI,KAAK,WAAW;AAAA,YAC7C,QAAQ;AAAA,YACR,OAAO;AAAA,cACL,SAAS;AAAA,YACX;AAAA,YACA,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,SAAU,CAAA;AAAA,UAAA,CACvC;AACG,cAAA,CAAC,OAAO,MAAM;AACV,kBAAA,IAAI,MAAM,yBAAyB;AAAA,UAAA;AAEpC,mBAAA,YAAO,SAAP,mBAAa,UAAS;AAAA,QAC/B;AAAA,QACA,SAAS,OAAO,EAAE,OAAO,YAAY;;AAC7B,gBAAA,SAAS,WAAW,KAAK;AACxB,iBAAA,MAAM,WAAW,MAAM;AAC9B,gBAAM,SAAS,MAAM,MAAM,IAAI,KAAK,IAAI;AAAA,YACtC,QAAQ;AAAA,YACR,OAAO;AAAA,cACL,GAAI,OAAO,SAAS,IAAI,EAAE,SAAS,OAAA,IAAW,CAAC;AAAA,cAC/C,MAAM;AAAA,YACR;AAAA,YACA,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,IAAA,CAAK,EAAG,CAAA;AAAA,UAAA,CAC7C;AACD,cAAI,OAAO,OAAO;AACV,kBAAA,IAAI,MAAM,uBAAuB;AAAA,UAAA;AAEzC,mBAAO,kBAAO,SAAP,mBAAa,UAAb,mBAAqB,OAAM;AAAA,QACpC;AAAA,QACA,UAAU,OAAO,EAAE,OAAO,OAAO,OAAO,QAAQ,aAAa;;AACrD,gBAAA,SAAS,WAAW,KAAK;AACxB,iBAAA,MAAM,WAAW,MAAM;AAE9B,gBAAM,OAAO,MAAM,MAAM,IAAI,KAAK,IAAI;AAAA,YACpC,QAAQ;AAAA,YACR,OAAO;AAAA,cACL,GAAI,OAAO,SAAS,IAAI,EAAE,SAAS,OAAA,IAAW,CAAC;AAAA,cAC/C,MAAM;AAAA,cACN,OAAO;AAAA,cACP,GAAI,SACA,EAAE,UAAU,IAAI,OAAO,KAAK,KAAK,OAAO,aAAa,KAAK,GAAA,IAC1D,CAAA;AAAA,YACN;AAAA,YACA,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,IAAA,CAAK,EAAG,CAAA;AAAA,UAAA,CAC7C;AACD,cAAI,KAAK,OAAO;AACR,kBAAA,IAAI,MAAM,wBAAwB;AAAA,UAAA;AAEnC,mBAAA,UAAK,SAAL,mBAAW,UAAS,CAAC;AAAA,QAC9B;AAAA,QACA,QAAQ,OAAO,EAAE,OAAO,YAAY;AAC5B,gBAAA,SAAS,WAAW,KAAK;AACxB,iBAAA,MAAM,WAAW,MAAM;AAC9B,kBAAQ,IAAI,UAAU,OAAO,OAAO,MAAM;AAC1C,gBAAM,SAAS,MAAM,MAAM,IAAI,KAAK,IAAI;AAAA,YACtC,QAAQ;AAAA,YACR,OAAO;AAAA,cACL,GAAI,MAAM,SAAS,IAAI,EAAE,SAAS,OAAA,IAAW,CAAC;AAAA,cAC9C,MAAM;AAAA,YAAA;AAAA,UACR,CACD;AACD,cAAI,OAAO,OAAO;AACV,kBAAA,IAAI,MAAM,yBAAyB;AAAA,UAAA;AAAA,QAE7C;AAAA,QACA,YAAY,OAAO,EAAE,OAAO,YAAY;AAChC,gBAAA,SAAS,WAAW,KAAK;AACxB,iBAAA;AAAA,YACL,MACG,IAAI,CAAC,MAAM,UAAU,EAAE,KAAK,OAAO,OAAO,EAAE,KAAK,EAAE,EACnD,KAAK,IAAI;AAAA,UACd;AACO,iBAAA,MAAM,WAAW,MAAM;AAE9B,gBAAM,SAAS,MAAM,MAAM,IAAI,KAAK,WAAW;AAAA,YAC7C,QAAQ;AAAA,YACR,OAAO;AAAA,cACL,GAAI,MAAM,SAAS,IAAI,EAAE,SAAS,OAAA,IAAW,CAAA;AAAA,YAC/C;AAAA,YACA,QAAQ,EAAE,OAAO,OAAO;AAAA,UAAA,CACzB;AACD,cAAI,OAAO,OAAO;AACV,kBAAA,IAAI,MAAM,yBAAyB;AAAA,UAAA;AAE3C,iBAAO,OAAO,QAAQ;AAAA,QACxB;AAAA,QACA,QAAQ,OAAO,EAAE,OAAO,OAAO,aAAa;;AAC1C,gBAAM,SAAS,MAAM,MAAM,IAAI,KAAK,IAAI;AAAA,YACtC,QAAQ;AAAA,YACR,OAAO;AAAA,cACL,GAAI,MAAM,SAAS,IAAI,EAAE,SAAS,WAAW,KAAK,EAAE,IAAI,CAAC;AAAA,cACzD,MAAM;AAAA,cACN,SAAS,CAAC,MAAM;AAAA,YAClB;AAAA,YACA,MAAM;AAAA,YACN,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,IAAA,CAAK,EAAG,CAAA;AAAA,UAAA,CAC7C;AACD,mBAAO,kBAAO,SAAP,mBAAa,UAAb,mBAAqB,OAAM;AAAA,QACpC;AAAA,QACA,YAAY,OAAO,EAAE,OAAO,OAAO,aAAa;AACxC,gBAAA,SAAS,WAAW,KAAK;AAC/B,gBAAM,SAAS,MAAM,MAAM,IAAI,KAAK,IAAI;AAAA,YACtC,QAAQ;AAAA,YACR,OAAO;AAAA,cACL,GAAI,MAAM,SAAS,IAAI,EAAE,SAAS,OAAA,IAAW,CAAA;AAAA,YAC/C;AAAA,YACA,MAAM;AAAA,UAAA,CACP;AACD,iBAAO,OAAO;AAAA,QAAA;AAAA,MAElB;AAAA,IAAA;AAAA,EACF,CACD;AACH;"}
@@ -1,5 +1,6 @@
1
1
  import { createSchema, createFetch } from "@better-fetch/fetch";
2
2
  import { logger } from "@better-fetch/logger";
3
+ import { logger as logger$1 } from "better-auth";
3
4
  import { ok, err } from "neverthrow";
4
5
  import { z } from "zod/v4";
5
6
  const schema = createSchema({
@@ -57,11 +58,11 @@ function createFmOdataFetch(args) {
57
58
  verbose: args.logging === "verbose",
58
59
  enabled: args.logging === "verbose" || !!args.logging,
59
60
  console: {
60
- fail: (...args2) => console.error(...args2),
61
- success: (...args2) => console.log(...args2),
62
- log: (...args2) => console.log(...args2),
63
- error: (...args2) => console.error(...args2),
64
- warn: (...args2) => console.warn(...args2)
61
+ fail: (...args2) => logger$1.error("better-fetch", ...args2),
62
+ success: (...args2) => logger$1.info("better-fetch", ...args2),
63
+ log: (...args2) => logger$1.info("better-fetch", ...args2),
64
+ error: (...args2) => logger$1.error("better-fetch", ...args2),
65
+ warn: (...args2) => logger$1.warn("better-fetch", ...args2)
65
66
  }
66
67
  })
67
68
  ]
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../../../src/odata/index.ts"],"sourcesContent":["import { createFetch, createSchema } from \"@better-fetch/fetch\";\nimport { logger } from \"@better-fetch/logger\";\nimport { err, ok, Result } from \"neverthrow\";\nimport { z } from \"zod/v4\";\n\nexport type BasicAuthCredentials = {\n username: string;\n password: string;\n};\nexport type OttoAPIKeyAuth = {\n apiKey: string;\n};\nexport type ODataAuth = BasicAuthCredentials | OttoAPIKeyAuth;\n\nexport function isBasicAuth(auth: ODataAuth): auth is BasicAuthCredentials {\n return (\n typeof (auth as BasicAuthCredentials).username === \"string\" &&\n typeof (auth as BasicAuthCredentials).password === \"string\"\n );\n}\n\nexport function isOttoAPIKeyAuth(auth: ODataAuth): auth is OttoAPIKeyAuth {\n return typeof (auth as OttoAPIKeyAuth).apiKey === \"string\";\n}\n\nexport type FmOdataConfig = {\n serverUrl: string;\n auth: ODataAuth;\n database: string;\n logging?: true | \"verbose\" | \"none\";\n};\n\nconst schema = createSchema({\n /**\n * Create a new table\n */\n \"@post/FileMaker_Tables\": {\n input: z.object({ tableName: z.string(), fields: z.array(z.any()) }),\n },\n /**\n * Add fields to a table\n */\n \"@patch/FileMaker_Tables/:tableName\": {\n params: z.object({ tableName: z.string() }),\n input: z.object({ fields: z.array(z.any()) }),\n },\n /**\n * Delete a table\n */\n \"@delete/FileMaker_Tables/:tableName\": {\n params: z.object({ tableName: z.string() }),\n },\n /**\n * Delete a field from a table\n */\n \"@delete/FileMaker_Tables/:tableName/:fieldName\": {\n params: z.object({ tableName: z.string(), fieldName: z.string() }),\n },\n});\n\nexport function createFmOdataFetch(args: FmOdataConfig) {\n const result = validateUrl(args.serverUrl);\n\n if (result.isErr()) {\n throw new Error(\"Invalid server URL\");\n }\n let baseURL = result.value.origin;\n if (\"apiKey\" in args.auth) {\n baseURL += `/otto`;\n }\n baseURL += `/fmi/odata/v4/${args.database}`;\n\n return createFetch({\n baseURL,\n auth:\n \"apiKey\" in args.auth\n ? { type: \"Bearer\", token: args.auth.apiKey }\n : {\n type: \"Basic\",\n username: args.auth.username,\n password: args.auth.password,\n },\n onError: (error) => {\n console.error(\"url\", error.request.url.toString());\n console.log(error.error);\n console.log(\"error.request.body\", JSON.stringify(error.request.body));\n },\n schema,\n plugins: [\n logger({\n verbose: args.logging === \"verbose\",\n enabled: args.logging === \"verbose\" || !!args.logging,\n console: {\n fail: (...args) => console.error(...args),\n success: (...args) => console.log(...args),\n log: (...args) => console.log(...args),\n error: (...args) => console.error(...args),\n warn: (...args) => console.warn(...args),\n },\n }),\n ],\n });\n}\n\nexport function validateUrl(input: string): Result<URL, unknown> {\n try {\n const url = new URL(input);\n return ok(url);\n } catch (error) {\n return err(error);\n }\n}\n"],"names":["args"],"mappings":";;;;AAgCA,MAAM,SAAS,aAAa;AAAA;AAAA;AAAA;AAAA,EAI1B,0BAA0B;AAAA,IACxB,OAAO,EAAE,OAAO,EAAE,WAAW,EAAE,UAAU,QAAQ,EAAE,MAAM,EAAE,IAAK,CAAA,EAAG,CAAA;AAAA,EACrE;AAAA;AAAA;AAAA;AAAA,EAIA,sCAAsC;AAAA,IACpC,QAAQ,EAAE,OAAO,EAAE,WAAW,EAAE,OAAA,GAAU;AAAA,IAC1C,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAA,CAAK,EAAG,CAAA;AAAA,EAC9C;AAAA;AAAA;AAAA;AAAA,EAIA,uCAAuC;AAAA,IACrC,QAAQ,EAAE,OAAO,EAAE,WAAW,EAAE,SAAU,CAAA;AAAA,EAC5C;AAAA;AAAA;AAAA;AAAA,EAIA,kDAAkD;AAAA,IAChD,QAAQ,EAAE,OAAO,EAAE,WAAW,EAAE,OAAO,GAAG,WAAW,EAAE,SAAU,CAAA;AAAA,EAAA;AAErE,CAAC;AAEM,SAAS,mBAAmB,MAAqB;AAChD,QAAA,SAAS,YAAY,KAAK,SAAS;AAErC,MAAA,OAAO,SAAS;AACZ,UAAA,IAAI,MAAM,oBAAoB;AAAA,EAAA;AAElC,MAAA,UAAU,OAAO,MAAM;AACvB,MAAA,YAAY,KAAK,MAAM;AACd,eAAA;AAAA,EAAA;AAEF,aAAA,iBAAiB,KAAK,QAAQ;AAEzC,SAAO,YAAY;AAAA,IACjB;AAAA,IACA,MACE,YAAY,KAAK,OACb,EAAE,MAAM,UAAU,OAAO,KAAK,KAAK,OAAA,IACnC;AAAA,MACE,MAAM;AAAA,MACN,UAAU,KAAK,KAAK;AAAA,MACpB,UAAU,KAAK,KAAK;AAAA,IACtB;AAAA,IACN,SAAS,CAAC,UAAU;AAClB,cAAQ,MAAM,OAAO,MAAM,QAAQ,IAAI,UAAU;AACzC,cAAA,IAAI,MAAM,KAAK;AACvB,cAAQ,IAAI,sBAAsB,KAAK,UAAU,MAAM,QAAQ,IAAI,CAAC;AAAA,IACtE;AAAA,IACA;AAAA,IACA,SAAS;AAAA,MACP,OAAO;AAAA,QACL,SAAS,KAAK,YAAY;AAAA,QAC1B,SAAS,KAAK,YAAY,aAAa,CAAC,CAAC,KAAK;AAAA,QAC9C,SAAS;AAAA,UACP,MAAM,IAAIA,UAAS,QAAQ,MAAM,GAAGA,KAAI;AAAA,UACxC,SAAS,IAAIA,UAAS,QAAQ,IAAI,GAAGA,KAAI;AAAA,UACzC,KAAK,IAAIA,UAAS,QAAQ,IAAI,GAAGA,KAAI;AAAA,UACrC,OAAO,IAAIA,UAAS,QAAQ,MAAM,GAAGA,KAAI;AAAA,UACzC,MAAM,IAAIA,UAAS,QAAQ,KAAK,GAAGA,KAAI;AAAA,QAAA;AAAA,MAE1C,CAAA;AAAA,IAAA;AAAA,EACH,CACD;AACH;AAEO,SAAS,YAAY,OAAqC;AAC3D,MAAA;AACI,UAAA,MAAM,IAAI,IAAI,KAAK;AACzB,WAAO,GAAG,GAAG;AAAA,WACN,OAAO;AACd,WAAO,IAAI,KAAK;AAAA,EAAA;AAEpB;"}
1
+ {"version":3,"file":"index.js","sources":["../../../src/odata/index.ts"],"sourcesContent":["import { createFetch, createSchema } from \"@better-fetch/fetch\";\nimport { logger } from \"@better-fetch/logger\";\nimport { logger as betterAuthLogger } from \"better-auth\";\nimport { err, ok, Result } from \"neverthrow\";\nimport { z } from \"zod/v4\";\n\nexport type BasicAuthCredentials = {\n username: string;\n password: string;\n};\nexport type OttoAPIKeyAuth = {\n apiKey: string;\n};\nexport type ODataAuth = BasicAuthCredentials | OttoAPIKeyAuth;\n\nexport function isBasicAuth(auth: ODataAuth): auth is BasicAuthCredentials {\n return (\n typeof (auth as BasicAuthCredentials).username === \"string\" &&\n typeof (auth as BasicAuthCredentials).password === \"string\"\n );\n}\n\nexport function isOttoAPIKeyAuth(auth: ODataAuth): auth is OttoAPIKeyAuth {\n return typeof (auth as OttoAPIKeyAuth).apiKey === \"string\";\n}\n\nexport type FmOdataConfig = {\n serverUrl: string;\n auth: ODataAuth;\n database: string;\n logging?: true | \"verbose\" | \"none\";\n};\n\nconst schema = createSchema({\n /**\n * Create a new table\n */\n \"@post/FileMaker_Tables\": {\n input: z.object({ tableName: z.string(), fields: z.array(z.any()) }),\n },\n /**\n * Add fields to a table\n */\n \"@patch/FileMaker_Tables/:tableName\": {\n params: z.object({ tableName: z.string() }),\n input: z.object({ fields: z.array(z.any()) }),\n },\n /**\n * Delete a table\n */\n \"@delete/FileMaker_Tables/:tableName\": {\n params: z.object({ tableName: z.string() }),\n },\n /**\n * Delete a field from a table\n */\n \"@delete/FileMaker_Tables/:tableName/:fieldName\": {\n params: z.object({ tableName: z.string(), fieldName: z.string() }),\n },\n});\n\nexport function createFmOdataFetch(args: FmOdataConfig) {\n const result = validateUrl(args.serverUrl);\n\n if (result.isErr()) {\n throw new Error(\"Invalid server URL\");\n }\n let baseURL = result.value.origin;\n if (\"apiKey\" in args.auth) {\n baseURL += `/otto`;\n }\n baseURL += `/fmi/odata/v4/${args.database}`;\n\n return createFetch({\n baseURL,\n auth:\n \"apiKey\" in args.auth\n ? { type: \"Bearer\", token: args.auth.apiKey }\n : {\n type: \"Basic\",\n username: args.auth.username,\n password: args.auth.password,\n },\n onError: (error) => {\n console.error(\"url\", error.request.url.toString());\n console.log(error.error);\n console.log(\"error.request.body\", JSON.stringify(error.request.body));\n },\n schema,\n plugins: [\n logger({\n verbose: args.logging === \"verbose\",\n enabled: args.logging === \"verbose\" || !!args.logging,\n console: {\n fail: (...args) => betterAuthLogger.error(\"better-fetch\", ...args),\n success: (...args) => betterAuthLogger.info(\"better-fetch\", ...args),\n log: (...args) => betterAuthLogger.info(\"better-fetch\", ...args),\n error: (...args) => betterAuthLogger.error(\"better-fetch\", ...args),\n warn: (...args) => betterAuthLogger.warn(\"better-fetch\", ...args),\n },\n }),\n ],\n });\n}\n\nexport function validateUrl(input: string): Result<URL, unknown> {\n try {\n const url = new URL(input);\n return ok(url);\n } catch (error) {\n return err(error);\n }\n}\n"],"names":["args","betterAuthLogger"],"mappings":";;;;;AAiCA,MAAM,SAAS,aAAa;AAAA;AAAA;AAAA;AAAA,EAI1B,0BAA0B;AAAA,IACxB,OAAO,EAAE,OAAO,EAAE,WAAW,EAAE,UAAU,QAAQ,EAAE,MAAM,EAAE,IAAK,CAAA,EAAG,CAAA;AAAA,EACrE;AAAA;AAAA;AAAA;AAAA,EAIA,sCAAsC;AAAA,IACpC,QAAQ,EAAE,OAAO,EAAE,WAAW,EAAE,OAAA,GAAU;AAAA,IAC1C,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAA,CAAK,EAAG,CAAA;AAAA,EAC9C;AAAA;AAAA;AAAA;AAAA,EAIA,uCAAuC;AAAA,IACrC,QAAQ,EAAE,OAAO,EAAE,WAAW,EAAE,SAAU,CAAA;AAAA,EAC5C;AAAA;AAAA;AAAA;AAAA,EAIA,kDAAkD;AAAA,IAChD,QAAQ,EAAE,OAAO,EAAE,WAAW,EAAE,OAAO,GAAG,WAAW,EAAE,SAAU,CAAA;AAAA,EAAA;AAErE,CAAC;AAEM,SAAS,mBAAmB,MAAqB;AAChD,QAAA,SAAS,YAAY,KAAK,SAAS;AAErC,MAAA,OAAO,SAAS;AACZ,UAAA,IAAI,MAAM,oBAAoB;AAAA,EAAA;AAElC,MAAA,UAAU,OAAO,MAAM;AACvB,MAAA,YAAY,KAAK,MAAM;AACd,eAAA;AAAA,EAAA;AAEF,aAAA,iBAAiB,KAAK,QAAQ;AAEzC,SAAO,YAAY;AAAA,IACjB;AAAA,IACA,MACE,YAAY,KAAK,OACb,EAAE,MAAM,UAAU,OAAO,KAAK,KAAK,OAAA,IACnC;AAAA,MACE,MAAM;AAAA,MACN,UAAU,KAAK,KAAK;AAAA,MACpB,UAAU,KAAK,KAAK;AAAA,IACtB;AAAA,IACN,SAAS,CAAC,UAAU;AAClB,cAAQ,MAAM,OAAO,MAAM,QAAQ,IAAI,UAAU;AACzC,cAAA,IAAI,MAAM,KAAK;AACvB,cAAQ,IAAI,sBAAsB,KAAK,UAAU,MAAM,QAAQ,IAAI,CAAC;AAAA,IACtE;AAAA,IACA;AAAA,IACA,SAAS;AAAA,MACP,OAAO;AAAA,QACL,SAAS,KAAK,YAAY;AAAA,QAC1B,SAAS,KAAK,YAAY,aAAa,CAAC,CAAC,KAAK;AAAA,QAC9C,SAAS;AAAA,UACP,MAAM,IAAIA,UAASC,SAAiB,MAAM,gBAAgB,GAAGD,KAAI;AAAA,UACjE,SAAS,IAAIA,UAASC,SAAiB,KAAK,gBAAgB,GAAGD,KAAI;AAAA,UACnE,KAAK,IAAIA,UAASC,SAAiB,KAAK,gBAAgB,GAAGD,KAAI;AAAA,UAC/D,OAAO,IAAIA,UAASC,SAAiB,MAAM,gBAAgB,GAAGD,KAAI;AAAA,UAClE,MAAM,IAAIA,UAASC,SAAiB,KAAK,gBAAgB,GAAGD,KAAI;AAAA,QAAA;AAAA,MAEnE,CAAA;AAAA,IAAA;AAAA,EACH,CACD;AACH;AAEO,SAAS,YAAY,OAAqC;AAC3D,MAAA;AACI,UAAA,MAAM,IAAI,IAAI,KAAK;AACzB,WAAO,GAAG,GAAG;AAAA,WACN,OAAO;AACd,WAAO,IAAI,KAAK;AAAA,EAAA;AAEpB;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@proofkit/better-auth",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "description": "FileMaker adapter for Better Auth",
5
5
  "type": "module",
6
6
  "main": "dist/esm/index.js",
@@ -46,6 +46,7 @@
46
46
  "c12": "^3.0.4",
47
47
  "chalk": "5.4.1",
48
48
  "commander": "^14.0.0",
49
+ "dayjs": "^1.11.13",
49
50
  "dotenv": "^16.5.0",
50
51
  "fs-extra": "^11.3.0",
51
52
  "neverthrow": "^8.2.0",
package/src/adapter.ts CHANGED
@@ -5,6 +5,8 @@ import {
5
5
  } from "better-auth/adapters";
6
6
  import { createFmOdataFetch, type FmOdataConfig } from "./odata";
7
7
  import { prettifyError, z } from "zod/v4";
8
+ import dayjs from "dayjs";
9
+ import { logger } from "better-auth";
8
10
 
9
11
  const configSchema = z.object({
10
12
  debugLogs: z.unknown().optional(),
@@ -70,10 +72,20 @@ export function parseWhere(where?: CleanedWhere[]): string {
70
72
  // Helper to format values for OData
71
73
  function formatValue(value: any): string {
72
74
  if (value === null) return "null";
73
- if (typeof value === "string") return `'${value.replace(/'/g, "''")}'`;
74
75
  if (typeof value === "boolean") return value ? "true" : "false";
75
- if (value instanceof Date) return `'${value.toISOString()}'`;
76
+ if (value instanceof Date) return value.toISOString();
76
77
  if (Array.isArray(value)) return `(${value.map(formatValue).join(",")})`;
78
+
79
+ // Handle strings - check if it's an ISO date string first
80
+ if (typeof value === "string") {
81
+ // Check if it's an ISO date string (YYYY-MM-DDTHH:mm:ss.sssZ format)
82
+ const isoDateRegex = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d{3})?Z?$/;
83
+ if (isoDateRegex.test(value)) {
84
+ return value; // Return ISO date strings without quotes
85
+ }
86
+ return `'${value.replace(/'/g, "''")}'`; // Regular strings get quotes
87
+ }
88
+
77
89
  return value?.toString() ?? "";
78
90
  }
79
91
 
@@ -144,7 +156,7 @@ export const FileMakerAdapter = (
144
156
 
145
157
  const fetch = createFmOdataFetch({
146
158
  ...config.odata,
147
- // logging: config.debugLogs ? true : "none",
159
+ logging: config.debugLogs ? "verbose" : "none",
148
160
  });
149
161
 
150
162
  return createAdapter({
@@ -157,11 +169,32 @@ export const FileMakerAdapter = (
157
169
  supportsDates: false, // Whether the database supports dates. (Default: true)
158
170
  supportsBooleans: false, // Whether the database supports booleans. (Default: true)
159
171
  supportsNumericIds: false, // Whether the database supports auto-incrementing numeric IDs. (Default: true)
172
+ // customTransformInput: ({ data, fieldAttributes }) => {
173
+ // if (fieldAttributes.type === "date") {
174
+ // const rawData = data as string;
175
+ // const fmDate = dayjs(rawData).format("YYYY+MM+DD");
176
+ // const isoDate = dayjs(rawData).format("YYYY-MM-DD");
177
+
178
+ // const newData = rawData
179
+ // .replace(isoDate, fmDate)
180
+ // .replace("T", " ")
181
+ // .replace("Z", "");
182
+
183
+ // console.log(`replaced ${isoDate} with ${fmDate}`);
184
+ // return newData;
185
+ // }
186
+
187
+ // return data;
188
+ // },
160
189
  },
161
190
  adapter: ({ options }) => {
162
191
  return {
163
192
  options: { config },
164
193
  create: async ({ data, model, select }) => {
194
+ if (model === "session") {
195
+ console.log("session", data);
196
+ }
197
+
165
198
  const result = await fetch(`/${model}`, {
166
199
  method: "POST",
167
200
  body: data,
@@ -175,10 +208,12 @@ export const FileMakerAdapter = (
175
208
  return result.data as any;
176
209
  },
177
210
  count: async ({ model, where }) => {
211
+ const filter = parseWhere(where);
212
+ logger.debug("$filter", filter);
178
213
  const result = await fetch(`/${model}/$count`, {
179
214
  method: "GET",
180
215
  query: {
181
- $filter: parseWhere(where),
216
+ $filter: filter,
182
217
  },
183
218
  output: z.object({ value: z.number() }),
184
219
  });
@@ -188,10 +223,12 @@ export const FileMakerAdapter = (
188
223
  return result.data?.value ?? 0;
189
224
  },
190
225
  findOne: async ({ model, where }) => {
226
+ const filter = parseWhere(where);
227
+ logger.debug("$filter", filter);
191
228
  const result = await fetch(`/${model}`, {
192
229
  method: "GET",
193
230
  query: {
194
- ...(where.length > 0 ? { $filter: parseWhere(where) } : {}),
231
+ ...(filter.length > 0 ? { $filter: filter } : {}),
195
232
  $top: 1,
196
233
  },
197
234
  output: z.object({ value: z.array(z.any()) }),
@@ -203,6 +240,7 @@ export const FileMakerAdapter = (
203
240
  },
204
241
  findMany: async ({ model, where, limit, offset, sortBy }) => {
205
242
  const filter = parseWhere(where);
243
+ logger.debug("$filter", filter);
206
244
 
207
245
  const rows = await fetch(`/${model}`, {
208
246
  method: "GET",
@@ -222,12 +260,14 @@ export const FileMakerAdapter = (
222
260
  return rows.data?.value ?? [];
223
261
  },
224
262
  delete: async ({ model, where }) => {
263
+ const filter = parseWhere(where);
264
+ logger.debug("$filter", filter);
265
+ console.log("delete", model, where, filter);
225
266
  const result = await fetch(`/${model}`, {
226
267
  method: "DELETE",
227
268
  query: {
228
- ...(where.length > 0 ? { $filter: parseWhere(where) } : {}),
269
+ ...(where.length > 0 ? { $filter: filter } : {}),
229
270
  $top: 1,
230
- $select: [`"id"`],
231
271
  },
232
272
  });
233
273
  if (result.error) {
@@ -235,12 +275,18 @@ export const FileMakerAdapter = (
235
275
  }
236
276
  },
237
277
  deleteMany: async ({ model, where }) => {
278
+ const filter = parseWhere(where);
279
+ logger.debug(
280
+ where
281
+ .map((o) => `typeof ${o.value} is ${typeof o.value}`)
282
+ .join("\n"),
283
+ );
284
+ logger.debug("$filter", filter);
285
+
238
286
  const result = await fetch(`/${model}/$count`, {
239
287
  method: "DELETE",
240
288
  query: {
241
- ...(where.length > 0 ? { $filter: parseWhere(where) } : {}),
242
- $top: 1,
243
- $select: [`"id"`],
289
+ ...(where.length > 0 ? { $filter: filter } : {}),
244
290
  },
245
291
  output: z.coerce.number(),
246
292
  });
@@ -1,5 +1,6 @@
1
1
  import { createFetch, createSchema } from "@better-fetch/fetch";
2
2
  import { logger } from "@better-fetch/logger";
3
+ import { logger as betterAuthLogger } from "better-auth";
3
4
  import { err, ok, Result } from "neverthrow";
4
5
  import { z } from "zod/v4";
5
6
 
@@ -91,11 +92,11 @@ export function createFmOdataFetch(args: FmOdataConfig) {
91
92
  verbose: args.logging === "verbose",
92
93
  enabled: args.logging === "verbose" || !!args.logging,
93
94
  console: {
94
- fail: (...args) => console.error(...args),
95
- success: (...args) => console.log(...args),
96
- log: (...args) => console.log(...args),
97
- error: (...args) => console.error(...args),
98
- warn: (...args) => console.warn(...args),
95
+ fail: (...args) => betterAuthLogger.error("better-fetch", ...args),
96
+ success: (...args) => betterAuthLogger.info("better-fetch", ...args),
97
+ log: (...args) => betterAuthLogger.info("better-fetch", ...args),
98
+ error: (...args) => betterAuthLogger.error("better-fetch", ...args),
99
+ warn: (...args) => betterAuthLogger.warn("better-fetch", ...args),
99
100
  },
100
101
  }),
101
102
  ],