@proofkit/better-auth 0.2.0-beta.0 → 0.2.0
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 +5 -2
- package/dist/esm/adapter.js.map +1 -1
- package/dist/esm/odata/index.js +0 -1
- package/dist/esm/odata/index.js.map +1 -1
- package/package.json +1 -1
- package/src/adapter.ts +14 -11
- package/src/odata/index.ts +0 -1
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
|
@@ -5,8 +5,11 @@ const configSchema = z.object({
|
|
|
5
5
|
debugLogs: z.unknown().optional(),
|
|
6
6
|
usePlural: z.boolean().optional(),
|
|
7
7
|
odata: z.object({
|
|
8
|
-
serverUrl: z.
|
|
9
|
-
auth: z.
|
|
8
|
+
serverUrl: z.url(),
|
|
9
|
+
auth: z.union([
|
|
10
|
+
z.object({ username: z.string(), password: z.string() }),
|
|
11
|
+
z.object({ apiKey: z.string() })
|
|
12
|
+
]),
|
|
10
13
|
database: z.string().endsWith(".fmp12")
|
|
11
14
|
})
|
|
12
15
|
});
|
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":";;;AA4BA,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,OAAO;AAAA,IACpB,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,OAAO,GAAG,UAAU,EAAE,OAAO,EAAA,CAAG;AAAA,IAC7D,UAAU,EAAE,OAAO,EAAE,SAAS,QAAQ;AAAA,EACvC,CAAA;AACH,CAAC;AAED,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;AACvB,QAAA,OAAO,UAAU,SAAU,QAAO,IAAI,MAAM,QAAQ,MAAM,IAAI,CAAC;AACnE,QAAI,OAAO,UAAU,UAAW,QAAO,QAAQ,SAAS;AACxD,QAAI,iBAAiB,KAAM,QAAO,IAAI,MAAM,YAAa,CAAA;AACzD,QAAI,MAAM,QAAQ,KAAK,EAAU,QAAA,IAAI,MAAM,IAAI,WAAW,EAAE,KAAK,GAAG,CAAC;AAC9D,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;AAAA,EAAA,CAEX;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,IACtB;AAAA,IACA,SAAS,CAAC,EAAE,cAAc;AACjB,aAAA;AAAA,QACL,SAAS,EAAE,OAAO;AAAA,QAClB,QAAQ,OAAO,EAAE,MAAM,OAAO,aAAa;AACzC,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;;AACjC,gBAAM,SAAS,MAAM,MAAM,IAAI,KAAK,WAAW;AAAA,YAC7C,QAAQ;AAAA,YACR,OAAO;AAAA,cACL,SAAS,WAAW,KAAK;AAAA,YAC3B;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;;AACnC,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,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;AAE/B,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;AAClC,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,YAAA;AAAA,UAClB,CACD;AACD,cAAI,OAAO,OAAO;AACV,kBAAA,IAAI,MAAM,yBAAyB;AAAA,UAAA;AAAA,QAE7C;AAAA,QACA,YAAY,OAAO,EAAE,OAAO,YAAY;AACtC,gBAAM,SAAS,MAAM,MAAM,IAAI,KAAK,WAAW;AAAA,YAC7C,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,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
|
+
{"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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"}
|
package/dist/esm/odata/index.js
CHANGED
|
@@ -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
|
|
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;"}
|
package/package.json
CHANGED
package/src/adapter.ts
CHANGED
|
@@ -6,6 +6,19 @@ import {
|
|
|
6
6
|
import { createFmOdataFetch, type FmOdataConfig } from "./odata";
|
|
7
7
|
import { prettifyError, z } from "zod/v4";
|
|
8
8
|
|
|
9
|
+
const configSchema = z.object({
|
|
10
|
+
debugLogs: z.unknown().optional(),
|
|
11
|
+
usePlural: z.boolean().optional(),
|
|
12
|
+
odata: z.object({
|
|
13
|
+
serverUrl: z.url(),
|
|
14
|
+
auth: z.union([
|
|
15
|
+
z.object({ username: z.string(), password: z.string() }),
|
|
16
|
+
z.object({ apiKey: z.string() }),
|
|
17
|
+
]),
|
|
18
|
+
database: z.string().endsWith(".fmp12"),
|
|
19
|
+
}),
|
|
20
|
+
});
|
|
21
|
+
|
|
9
22
|
interface FileMakerAdapterConfig {
|
|
10
23
|
/**
|
|
11
24
|
* Helps you debug issues with the adapter.
|
|
@@ -19,23 +32,13 @@ interface FileMakerAdapterConfig {
|
|
|
19
32
|
/**
|
|
20
33
|
* Connection details for the FileMaker server.
|
|
21
34
|
*/
|
|
22
|
-
odata:
|
|
35
|
+
odata: z.infer<typeof configSchema>["odata"];
|
|
23
36
|
}
|
|
24
37
|
|
|
25
38
|
export type AdapterOptions = {
|
|
26
39
|
config: FileMakerAdapterConfig;
|
|
27
40
|
};
|
|
28
41
|
|
|
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
42
|
const defaultConfig: Required<FileMakerAdapterConfig> = {
|
|
40
43
|
debugLogs: false,
|
|
41
44
|
usePlural: false,
|