@proofkit/better-auth 0.2.0-beta.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.
- package/dist/esm/adapter.d.ts +16 -2
- package/dist/esm/adapter.js +51 -14
- package/dist/esm/adapter.js.map +1 -1
- package/dist/esm/odata/index.js +6 -6
- package/dist/esm/odata/index.js.map +1 -1
- package/package.json +2 -1
- package/src/adapter.ts +70 -21
- package/src/odata/index.ts +6 -6
package/dist/esm/adapter.d.ts
CHANGED
|
@@ -1,9 +1,23 @@
|
|
|
1
1
|
import { CleanedWhere, AdapterDebugLogs } from 'better-auth/adapters';
|
|
2
|
-
import {
|
|
2
|
+
import { z } from 'zod/v4';
|
|
3
|
+
declare const configSchema: z.ZodObject<{
|
|
4
|
+
debugLogs: z.ZodOptional<z.ZodUnknown>;
|
|
5
|
+
usePlural: z.ZodOptional<z.ZodBoolean>;
|
|
6
|
+
odata: z.ZodObject<{
|
|
7
|
+
serverUrl: z.ZodURL;
|
|
8
|
+
auth: z.ZodUnion<readonly [z.ZodObject<{
|
|
9
|
+
username: z.ZodString;
|
|
10
|
+
password: z.ZodString;
|
|
11
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
12
|
+
apiKey: z.ZodString;
|
|
13
|
+
}, z.core.$strip>]>;
|
|
14
|
+
database: z.ZodString;
|
|
15
|
+
}, z.core.$strip>;
|
|
16
|
+
}, z.core.$strip>;
|
|
3
17
|
interface FileMakerAdapterConfig {
|
|
4
18
|
debugLogs?: AdapterDebugLogs;
|
|
5
19
|
usePlural?: boolean;
|
|
6
|
-
odata:
|
|
20
|
+
odata: z.infer<typeof configSchema>["odata"];
|
|
7
21
|
}
|
|
8
22
|
export type AdapterOptions = {
|
|
9
23
|
config: FileMakerAdapterConfig;
|
package/dist/esm/adapter.js
CHANGED
|
@@ -1,12 +1,16 @@
|
|
|
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(),
|
|
7
8
|
odata: z.object({
|
|
8
|
-
serverUrl: z.
|
|
9
|
-
auth: z.
|
|
9
|
+
serverUrl: z.url(),
|
|
10
|
+
auth: z.union([
|
|
11
|
+
z.object({ username: z.string(), password: z.string() }),
|
|
12
|
+
z.object({ apiKey: z.string() })
|
|
13
|
+
]),
|
|
10
14
|
database: z.string().endsWith(".fmp12")
|
|
11
15
|
})
|
|
12
16
|
});
|
|
@@ -28,10 +32,16 @@ function parseWhere(where) {
|
|
|
28
32
|
}
|
|
29
33
|
function formatValue(value) {
|
|
30
34
|
if (value === null) return "null";
|
|
31
|
-
if (typeof value === "string") return `'${value.replace(/'/g, "''")}'`;
|
|
32
35
|
if (typeof value === "boolean") return value ? "true" : "false";
|
|
33
|
-
if (value instanceof Date) return
|
|
36
|
+
if (value instanceof Date) return value.toISOString();
|
|
34
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
|
+
}
|
|
35
45
|
return (value == null ? void 0 : value.toString()) ?? "";
|
|
36
46
|
}
|
|
37
47
|
const opMap = {
|
|
@@ -89,8 +99,8 @@ const FileMakerAdapter = (_config = defaultConfig) => {
|
|
|
89
99
|
}
|
|
90
100
|
const config = parsed.data;
|
|
91
101
|
const fetch = createFmOdataFetch({
|
|
92
|
-
...config.odata
|
|
93
|
-
|
|
102
|
+
...config.odata,
|
|
103
|
+
logging: config.debugLogs ? "verbose" : "none"
|
|
94
104
|
});
|
|
95
105
|
return createAdapter({
|
|
96
106
|
config: {
|
|
@@ -108,11 +118,28 @@ const FileMakerAdapter = (_config = defaultConfig) => {
|
|
|
108
118
|
// Whether the database supports booleans. (Default: true)
|
|
109
119
|
supportsNumericIds: false
|
|
110
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
|
+
// },
|
|
111
135
|
},
|
|
112
136
|
adapter: ({ options }) => {
|
|
113
137
|
return {
|
|
114
138
|
options: { config },
|
|
115
139
|
create: async ({ data, model, select }) => {
|
|
140
|
+
if (model === "session") {
|
|
141
|
+
console.log("session", data);
|
|
142
|
+
}
|
|
116
143
|
const result = await fetch(`/${model}`, {
|
|
117
144
|
method: "POST",
|
|
118
145
|
body: data,
|
|
@@ -125,10 +152,12 @@ const FileMakerAdapter = (_config = defaultConfig) => {
|
|
|
125
152
|
},
|
|
126
153
|
count: async ({ model, where }) => {
|
|
127
154
|
var _a;
|
|
155
|
+
const filter = parseWhere(where);
|
|
156
|
+
logger.debug("$filter", filter);
|
|
128
157
|
const result = await fetch(`/${model}/$count`, {
|
|
129
158
|
method: "GET",
|
|
130
159
|
query: {
|
|
131
|
-
$filter:
|
|
160
|
+
$filter: filter
|
|
132
161
|
},
|
|
133
162
|
output: z.object({ value: z.number() })
|
|
134
163
|
});
|
|
@@ -139,10 +168,12 @@ const FileMakerAdapter = (_config = defaultConfig) => {
|
|
|
139
168
|
},
|
|
140
169
|
findOne: async ({ model, where }) => {
|
|
141
170
|
var _a, _b;
|
|
171
|
+
const filter = parseWhere(where);
|
|
172
|
+
logger.debug("$filter", filter);
|
|
142
173
|
const result = await fetch(`/${model}`, {
|
|
143
174
|
method: "GET",
|
|
144
175
|
query: {
|
|
145
|
-
...
|
|
176
|
+
...filter.length > 0 ? { $filter: filter } : {},
|
|
146
177
|
$top: 1
|
|
147
178
|
},
|
|
148
179
|
output: z.object({ value: z.array(z.any()) })
|
|
@@ -155,6 +186,7 @@ const FileMakerAdapter = (_config = defaultConfig) => {
|
|
|
155
186
|
findMany: async ({ model, where, limit, offset, sortBy }) => {
|
|
156
187
|
var _a;
|
|
157
188
|
const filter = parseWhere(where);
|
|
189
|
+
logger.debug("$filter", filter);
|
|
158
190
|
const rows = await fetch(`/${model}`, {
|
|
159
191
|
method: "GET",
|
|
160
192
|
query: {
|
|
@@ -171,12 +203,14 @@ const FileMakerAdapter = (_config = defaultConfig) => {
|
|
|
171
203
|
return ((_a = rows.data) == null ? void 0 : _a.value) ?? [];
|
|
172
204
|
},
|
|
173
205
|
delete: async ({ model, where }) => {
|
|
206
|
+
const filter = parseWhere(where);
|
|
207
|
+
logger.debug("$filter", filter);
|
|
208
|
+
console.log("delete", model, where, filter);
|
|
174
209
|
const result = await fetch(`/${model}`, {
|
|
175
210
|
method: "DELETE",
|
|
176
211
|
query: {
|
|
177
|
-
...where.length > 0 ? { $filter:
|
|
178
|
-
$top: 1
|
|
179
|
-
$select: [`"id"`]
|
|
212
|
+
...where.length > 0 ? { $filter: filter } : {},
|
|
213
|
+
$top: 1
|
|
180
214
|
}
|
|
181
215
|
});
|
|
182
216
|
if (result.error) {
|
|
@@ -184,12 +218,15 @@ const FileMakerAdapter = (_config = defaultConfig) => {
|
|
|
184
218
|
}
|
|
185
219
|
},
|
|
186
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);
|
|
187
226
|
const result = await fetch(`/${model}/$count`, {
|
|
188
227
|
method: "DELETE",
|
|
189
228
|
query: {
|
|
190
|
-
...where.length > 0 ? { $filter:
|
|
191
|
-
$top: 1,
|
|
192
|
-
$select: [`"id"`]
|
|
229
|
+
...where.length > 0 ? { $filter: filter } : {}
|
|
193
230
|
},
|
|
194
231
|
output: z.coerce.number()
|
|
195
232
|
});
|
package/dist/esm/adapter.js.map
CHANGED
|
@@ -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\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: FmOdataConfig;\n}\n\nexport type AdapterOptions = {\n config: FileMakerAdapterConfig;\n};\n\nconst configSchema = z.object({\n debugLogs: z.unknown().optional(),\n usePlural: z.boolean().optional(),\n odata: z.object({\n serverUrl: z.string(),\n auth: z.object({ username: z.string(), password: z.string() }),\n database: z.string().endsWith(\".fmp12\"),\n }),\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":"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"}
|
package/dist/esm/odata/index.js
CHANGED
|
@@ -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) =>
|
|
61
|
-
success: (...args2) =>
|
|
62
|
-
log: (...args2) =>
|
|
63
|
-
error: (...args2) =>
|
|
64
|
-
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
|
]
|
|
@@ -72,7 +73,6 @@ function validateUrl(input) {
|
|
|
72
73
|
const url = new URL(input);
|
|
73
74
|
return ok(url);
|
|
74
75
|
} catch (error) {
|
|
75
|
-
console.error(error);
|
|
76
76
|
return err(error);
|
|
77
77
|
}
|
|
78
78
|
}
|
|
@@ -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) =>
|
|
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.
|
|
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,21 @@ 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";
|
|
10
|
+
|
|
11
|
+
const configSchema = z.object({
|
|
12
|
+
debugLogs: z.unknown().optional(),
|
|
13
|
+
usePlural: z.boolean().optional(),
|
|
14
|
+
odata: z.object({
|
|
15
|
+
serverUrl: z.url(),
|
|
16
|
+
auth: z.union([
|
|
17
|
+
z.object({ username: z.string(), password: z.string() }),
|
|
18
|
+
z.object({ apiKey: z.string() }),
|
|
19
|
+
]),
|
|
20
|
+
database: z.string().endsWith(".fmp12"),
|
|
21
|
+
}),
|
|
22
|
+
});
|
|
8
23
|
|
|
9
24
|
interface FileMakerAdapterConfig {
|
|
10
25
|
/**
|
|
@@ -19,23 +34,13 @@ interface FileMakerAdapterConfig {
|
|
|
19
34
|
/**
|
|
20
35
|
* Connection details for the FileMaker server.
|
|
21
36
|
*/
|
|
22
|
-
odata:
|
|
37
|
+
odata: z.infer<typeof configSchema>["odata"];
|
|
23
38
|
}
|
|
24
39
|
|
|
25
40
|
export type AdapterOptions = {
|
|
26
41
|
config: FileMakerAdapterConfig;
|
|
27
42
|
};
|
|
28
43
|
|
|
29
|
-
const configSchema = z.object({
|
|
30
|
-
debugLogs: z.unknown().optional(),
|
|
31
|
-
usePlural: z.boolean().optional(),
|
|
32
|
-
odata: z.object({
|
|
33
|
-
serverUrl: z.string(),
|
|
34
|
-
auth: z.object({ username: z.string(), password: z.string() }),
|
|
35
|
-
database: z.string().endsWith(".fmp12"),
|
|
36
|
-
}),
|
|
37
|
-
});
|
|
38
|
-
|
|
39
44
|
const defaultConfig: Required<FileMakerAdapterConfig> = {
|
|
40
45
|
debugLogs: false,
|
|
41
46
|
usePlural: false,
|
|
@@ -67,10 +72,20 @@ export function parseWhere(where?: CleanedWhere[]): string {
|
|
|
67
72
|
// Helper to format values for OData
|
|
68
73
|
function formatValue(value: any): string {
|
|
69
74
|
if (value === null) return "null";
|
|
70
|
-
if (typeof value === "string") return `'${value.replace(/'/g, "''")}'`;
|
|
71
75
|
if (typeof value === "boolean") return value ? "true" : "false";
|
|
72
|
-
if (value instanceof Date) return
|
|
76
|
+
if (value instanceof Date) return value.toISOString();
|
|
73
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
|
+
|
|
74
89
|
return value?.toString() ?? "";
|
|
75
90
|
}
|
|
76
91
|
|
|
@@ -141,7 +156,7 @@ export const FileMakerAdapter = (
|
|
|
141
156
|
|
|
142
157
|
const fetch = createFmOdataFetch({
|
|
143
158
|
...config.odata,
|
|
144
|
-
|
|
159
|
+
logging: config.debugLogs ? "verbose" : "none",
|
|
145
160
|
});
|
|
146
161
|
|
|
147
162
|
return createAdapter({
|
|
@@ -154,11 +169,32 @@ export const FileMakerAdapter = (
|
|
|
154
169
|
supportsDates: false, // Whether the database supports dates. (Default: true)
|
|
155
170
|
supportsBooleans: false, // Whether the database supports booleans. (Default: true)
|
|
156
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
|
+
// },
|
|
157
189
|
},
|
|
158
190
|
adapter: ({ options }) => {
|
|
159
191
|
return {
|
|
160
192
|
options: { config },
|
|
161
193
|
create: async ({ data, model, select }) => {
|
|
194
|
+
if (model === "session") {
|
|
195
|
+
console.log("session", data);
|
|
196
|
+
}
|
|
197
|
+
|
|
162
198
|
const result = await fetch(`/${model}`, {
|
|
163
199
|
method: "POST",
|
|
164
200
|
body: data,
|
|
@@ -172,10 +208,12 @@ export const FileMakerAdapter = (
|
|
|
172
208
|
return result.data as any;
|
|
173
209
|
},
|
|
174
210
|
count: async ({ model, where }) => {
|
|
211
|
+
const filter = parseWhere(where);
|
|
212
|
+
logger.debug("$filter", filter);
|
|
175
213
|
const result = await fetch(`/${model}/$count`, {
|
|
176
214
|
method: "GET",
|
|
177
215
|
query: {
|
|
178
|
-
$filter:
|
|
216
|
+
$filter: filter,
|
|
179
217
|
},
|
|
180
218
|
output: z.object({ value: z.number() }),
|
|
181
219
|
});
|
|
@@ -185,10 +223,12 @@ export const FileMakerAdapter = (
|
|
|
185
223
|
return result.data?.value ?? 0;
|
|
186
224
|
},
|
|
187
225
|
findOne: async ({ model, where }) => {
|
|
226
|
+
const filter = parseWhere(where);
|
|
227
|
+
logger.debug("$filter", filter);
|
|
188
228
|
const result = await fetch(`/${model}`, {
|
|
189
229
|
method: "GET",
|
|
190
230
|
query: {
|
|
191
|
-
...(
|
|
231
|
+
...(filter.length > 0 ? { $filter: filter } : {}),
|
|
192
232
|
$top: 1,
|
|
193
233
|
},
|
|
194
234
|
output: z.object({ value: z.array(z.any()) }),
|
|
@@ -200,6 +240,7 @@ export const FileMakerAdapter = (
|
|
|
200
240
|
},
|
|
201
241
|
findMany: async ({ model, where, limit, offset, sortBy }) => {
|
|
202
242
|
const filter = parseWhere(where);
|
|
243
|
+
logger.debug("$filter", filter);
|
|
203
244
|
|
|
204
245
|
const rows = await fetch(`/${model}`, {
|
|
205
246
|
method: "GET",
|
|
@@ -219,12 +260,14 @@ export const FileMakerAdapter = (
|
|
|
219
260
|
return rows.data?.value ?? [];
|
|
220
261
|
},
|
|
221
262
|
delete: async ({ model, where }) => {
|
|
263
|
+
const filter = parseWhere(where);
|
|
264
|
+
logger.debug("$filter", filter);
|
|
265
|
+
console.log("delete", model, where, filter);
|
|
222
266
|
const result = await fetch(`/${model}`, {
|
|
223
267
|
method: "DELETE",
|
|
224
268
|
query: {
|
|
225
|
-
...(where.length > 0 ? { $filter:
|
|
269
|
+
...(where.length > 0 ? { $filter: filter } : {}),
|
|
226
270
|
$top: 1,
|
|
227
|
-
$select: [`"id"`],
|
|
228
271
|
},
|
|
229
272
|
});
|
|
230
273
|
if (result.error) {
|
|
@@ -232,12 +275,18 @@ export const FileMakerAdapter = (
|
|
|
232
275
|
}
|
|
233
276
|
},
|
|
234
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
|
+
|
|
235
286
|
const result = await fetch(`/${model}/$count`, {
|
|
236
287
|
method: "DELETE",
|
|
237
288
|
query: {
|
|
238
|
-
...(where.length > 0 ? { $filter:
|
|
239
|
-
$top: 1,
|
|
240
|
-
$select: [`"id"`],
|
|
289
|
+
...(where.length > 0 ? { $filter: filter } : {}),
|
|
241
290
|
},
|
|
242
291
|
output: z.coerce.number(),
|
|
243
292
|
});
|
package/src/odata/index.ts
CHANGED
|
@@ -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) =>
|
|
95
|
-
success: (...args) =>
|
|
96
|
-
log: (...args) =>
|
|
97
|
-
error: (...args) =>
|
|
98
|
-
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
|
],
|
|
@@ -107,7 +108,6 @@ export function validateUrl(input: string): Result<URL, unknown> {
|
|
|
107
108
|
const url = new URL(input);
|
|
108
109
|
return ok(url);
|
|
109
110
|
} catch (error) {
|
|
110
|
-
console.error(error);
|
|
111
111
|
return err(error);
|
|
112
112
|
}
|
|
113
113
|
}
|