@proofkit/fmdapi 5.0.0-beta.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.
Files changed (49) hide show
  1. package/LICENSE.md +21 -0
  2. package/README.md +110 -0
  3. package/dist/esm/adapters/core.d.ts +55 -0
  4. package/dist/esm/adapters/fetch-base-types.d.ts +7 -0
  5. package/dist/esm/adapters/fetch-base.d.ts +60 -0
  6. package/dist/esm/adapters/fetch-base.js +256 -0
  7. package/dist/esm/adapters/fetch-base.js.map +1 -0
  8. package/dist/esm/adapters/fetch.d.ts +27 -0
  9. package/dist/esm/adapters/fetch.js +79 -0
  10. package/dist/esm/adapters/fetch.js.map +1 -0
  11. package/dist/esm/adapters/otto.d.ts +26 -0
  12. package/dist/esm/adapters/otto.js +29 -0
  13. package/dist/esm/adapters/otto.js.map +1 -0
  14. package/dist/esm/client-types.d.ts +226 -0
  15. package/dist/esm/client-types.js +41 -0
  16. package/dist/esm/client-types.js.map +1 -0
  17. package/dist/esm/client.d.ts +133 -0
  18. package/dist/esm/client.js +295 -0
  19. package/dist/esm/client.js.map +1 -0
  20. package/dist/esm/index.d.ts +8 -0
  21. package/dist/esm/index.js +16 -0
  22. package/dist/esm/index.js.map +1 -0
  23. package/dist/esm/tokenStore/file.d.ts +3 -0
  24. package/dist/esm/tokenStore/index.d.ts +3 -0
  25. package/dist/esm/tokenStore/memory.d.ts +3 -0
  26. package/dist/esm/tokenStore/memory.js +21 -0
  27. package/dist/esm/tokenStore/memory.js.map +1 -0
  28. package/dist/esm/tokenStore/types.d.ts +8 -0
  29. package/dist/esm/tokenStore/upstash.d.ts +6 -0
  30. package/dist/esm/utils.d.ts +8 -0
  31. package/dist/esm/utils.js +16 -0
  32. package/dist/esm/utils.js.map +1 -0
  33. package/package.json +99 -0
  34. package/src/adapters/core.ts +62 -0
  35. package/src/adapters/fetch-base-types.ts +5 -0
  36. package/src/adapters/fetch-base.ts +339 -0
  37. package/src/adapters/fetch.ts +95 -0
  38. package/src/adapters/otto.ts +59 -0
  39. package/src/client-types.ts +296 -0
  40. package/src/client.ts +534 -0
  41. package/src/index.ts +11 -0
  42. package/src/tokenStore/file.ts +33 -0
  43. package/src/tokenStore/index.ts +3 -0
  44. package/src/tokenStore/memory.ts +20 -0
  45. package/src/tokenStore/types.ts +7 -0
  46. package/src/tokenStore/upstash.ts +31 -0
  47. package/src/utils.ts +29 -0
  48. package/stubs/fmschema.config.stub.js +17 -0
  49. package/stubs/fmschema.config.stub.mjs +17 -0
@@ -0,0 +1,295 @@
1
+ import { FileMakerError } from "./client-types.js";
2
+ function asNumber(input) {
3
+ return typeof input === "string" ? parseInt(input) : input;
4
+ }
5
+ function DataApi(options) {
6
+ if ("zodValidators" in options) {
7
+ throw new Error(
8
+ "zodValidators is no longer supported. Use schema instead, or re-run the typegen command"
9
+ );
10
+ }
11
+ const schema = options.schema;
12
+ const layout = options.layout;
13
+ const {
14
+ create,
15
+ delete: _adapterDelete,
16
+ find,
17
+ get,
18
+ list,
19
+ update,
20
+ layoutMetadata,
21
+ containerUpload,
22
+ ...otherMethods
23
+ } = options.adapter;
24
+ async function _list(args) {
25
+ const { fetch, timeout, ...params } = args ?? {};
26
+ if ("limit" in params && params.limit !== void 0)
27
+ delete Object.assign(params, { _limit: params.limit })["limit"];
28
+ if ("offset" in params && params.offset !== void 0) {
29
+ if (params.offset <= 1) delete params.offset;
30
+ else delete Object.assign(params, { _offset: params.offset })["offset"];
31
+ }
32
+ if ("sort" in params && params.sort !== void 0)
33
+ delete Object.assign(params, {
34
+ _sort: Array.isArray(params.sort) ? params.sort : [params.sort]
35
+ })["sort"];
36
+ const result = await list({
37
+ layout,
38
+ data: params,
39
+ fetch,
40
+ timeout
41
+ });
42
+ if (result.dataInfo.foundCount > result.dataInfo.returnedCount) {
43
+ if ((args == null ? void 0 : args.limit) === void 0 && (args == null ? void 0 : args.offset) === void 0) {
44
+ console.warn(
45
+ `🚨 @proofkit/fmdapi: Loaded only ${result.dataInfo.returnedCount} of the ${result.dataInfo.foundCount} records from your "${layout}" layout. Use the "listAll" method to automatically paginate through all records, or specify a "limit" and "offset" to handle pagination yourself.`
46
+ );
47
+ }
48
+ }
49
+ return await runSchemaValidationAndTransform(
50
+ schema,
51
+ result
52
+ );
53
+ }
54
+ async function listAll(args) {
55
+ let runningData = [];
56
+ const limit = (args == null ? void 0 : args.limit) ?? 100;
57
+ let offset = (args == null ? void 0 : args.offset) ?? 1;
58
+ while (true) {
59
+ const data = await _list({
60
+ ...args,
61
+ offset
62
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
63
+ });
64
+ runningData = [...runningData, ...data.data];
65
+ if (runningData.length >= data.dataInfo.foundCount) break;
66
+ offset = offset + limit;
67
+ }
68
+ return runningData;
69
+ }
70
+ async function _create(args) {
71
+ const { fetch, timeout, ...params } = args ?? {};
72
+ return await create({
73
+ layout,
74
+ data: params,
75
+ fetch,
76
+ timeout
77
+ });
78
+ }
79
+ async function _get(args) {
80
+ args.recordId = asNumber(args.recordId);
81
+ const { recordId, fetch, timeout, ...params } = args;
82
+ const result = await get({
83
+ layout,
84
+ data: { ...params, recordId },
85
+ fetch,
86
+ timeout
87
+ });
88
+ return await runSchemaValidationAndTransform(
89
+ schema,
90
+ result
91
+ );
92
+ }
93
+ async function _update(args) {
94
+ args.recordId = asNumber(args.recordId);
95
+ const { recordId, fetch, timeout, ...params } = args;
96
+ return await update({
97
+ layout,
98
+ data: { ...params, recordId },
99
+ fetch,
100
+ timeout
101
+ });
102
+ }
103
+ async function deleteRecord(args) {
104
+ args.recordId = asNumber(args.recordId);
105
+ const { recordId, fetch, timeout, ...params } = args;
106
+ return _adapterDelete({
107
+ layout,
108
+ data: { ...params, recordId },
109
+ fetch,
110
+ timeout
111
+ });
112
+ }
113
+ async function _find(args) {
114
+ const {
115
+ query: queryInput,
116
+ ignoreEmptyResult = false,
117
+ timeout,
118
+ fetch,
119
+ ...params
120
+ } = args;
121
+ const query = !Array.isArray(queryInput) ? [queryInput] : queryInput;
122
+ if ("offset" in params && params.offset !== void 0) {
123
+ if (params.offset <= 1) delete params.offset;
124
+ }
125
+ if ("dateformats" in params && params.dateformats !== void 0) {
126
+ params.dateformats = (params.dateformats === "US" ? 0 : params.dateformats === "file_locale" ? 1 : params.dateformats === "ISO8601" ? 2 : 0).toString();
127
+ }
128
+ const result = await find({
129
+ data: { ...params, query },
130
+ layout,
131
+ fetch,
132
+ timeout
133
+ }).catch((e) => {
134
+ if (ignoreEmptyResult && e instanceof FileMakerError && e.code === "401")
135
+ return { data: [], dataInfo: { foundCount: 0, returnedCount: 0 } };
136
+ throw e;
137
+ });
138
+ if (result.dataInfo.foundCount > result.dataInfo.returnedCount) {
139
+ if ((args == null ? void 0 : args.limit) === void 0 && (args == null ? void 0 : args.offset) === void 0) {
140
+ console.warn(
141
+ `🚨 @proofkit/fmdapi: Loaded only ${result.dataInfo.returnedCount} of the ${result.dataInfo.foundCount} records from your "${layout}" layout. Use the "findAll" method to automatically paginate through all records, or specify a "limit" and "offset" to handle pagination yourself.`
142
+ );
143
+ }
144
+ }
145
+ return await runSchemaValidationAndTransform(schema, result);
146
+ }
147
+ async function findOne(args) {
148
+ const result = await _find(args);
149
+ if (result.data.length !== 1)
150
+ throw new Error(
151
+ `${result.data.length} records found; expecting exactly 1`
152
+ );
153
+ const transformedResult = await runSchemaValidationAndTransform(
154
+ schema,
155
+ result
156
+ );
157
+ if (!transformedResult.data[0]) throw new Error("No data found");
158
+ return { ...transformedResult, data: transformedResult.data[0] };
159
+ }
160
+ async function findFirst(args) {
161
+ const result = await _find(args);
162
+ const transformedResult = await runSchemaValidationAndTransform(
163
+ schema,
164
+ result
165
+ );
166
+ if (!transformedResult.data[0]) throw new Error("No data found");
167
+ return { ...transformedResult, data: transformedResult.data[0] };
168
+ }
169
+ async function maybeFindFirst(args) {
170
+ const result = await _find({ ...args, ignoreEmptyResult: true });
171
+ const transformedResult = await runSchemaValidationAndTransform(
172
+ schema,
173
+ result
174
+ );
175
+ if (!transformedResult.data[0]) return null;
176
+ return { ...transformedResult, data: transformedResult.data[0] };
177
+ }
178
+ async function findAll(args) {
179
+ let runningData = [];
180
+ const limit = args.limit ?? 100;
181
+ let offset = args.offset ?? 1;
182
+ while (true) {
183
+ const data = await _find({
184
+ ...args,
185
+ offset,
186
+ ignoreEmptyResult: true
187
+ });
188
+ runningData = [...runningData, ...data.data];
189
+ if (runningData.length === 0 || runningData.length >= data.dataInfo.foundCount)
190
+ break;
191
+ offset = offset + limit;
192
+ }
193
+ return runningData;
194
+ }
195
+ async function _layoutMetadata(args) {
196
+ const { ...restArgs } = args ?? {};
197
+ const params = restArgs;
198
+ return await layoutMetadata({
199
+ layout,
200
+ fetch: params.fetch,
201
+ // Now should correctly resolve to undefined if not present
202
+ timeout: params.timeout
203
+ // Now should correctly resolve to undefined if not present
204
+ });
205
+ }
206
+ async function _containerUpload(args) {
207
+ const { ...params } = args;
208
+ return await containerUpload({
209
+ layout,
210
+ data: {
211
+ ...params,
212
+ containerFieldName: params.containerFieldName,
213
+ repetition: params.containerFieldRepetition
214
+ },
215
+ fetch: params.fetch,
216
+ timeout: params.timeout
217
+ });
218
+ }
219
+ async function runSchemaValidationAndTransform(schema2, result) {
220
+ const fieldDataIssues = [];
221
+ const portalDataIssues = [];
222
+ if (!schema2) return result;
223
+ const transformedData = [];
224
+ for (const record of result.data) {
225
+ let fieldResult = schema2.fieldData["~standard"].validate(
226
+ record.fieldData
227
+ );
228
+ if (fieldResult instanceof Promise) fieldResult = await fieldResult;
229
+ if ("value" in fieldResult) {
230
+ record.fieldData = fieldResult.value;
231
+ } else {
232
+ fieldDataIssues.push(...fieldResult.issues);
233
+ }
234
+ if (schema2.portalData) {
235
+ for (const [portalName, portalRecords] of Object.entries(
236
+ record.portalData
237
+ )) {
238
+ const validatedPortalRecords = [];
239
+ for (const portalRecord of portalRecords) {
240
+ let portalResult = schema2.portalData["~standard"].validate({
241
+ [portalName]: portalRecord
242
+ });
243
+ if (portalResult instanceof Promise)
244
+ portalResult = await portalResult;
245
+ if ("value" in portalResult) {
246
+ validatedPortalRecords.push({
247
+ ...portalResult.value[portalName],
248
+ recordId: portalRecord.recordId,
249
+ modId: portalRecord.modId
250
+ });
251
+ } else {
252
+ portalDataIssues.push(...portalResult.issues);
253
+ }
254
+ }
255
+ record.portalData[portalName] = validatedPortalRecords;
256
+ }
257
+ }
258
+ transformedData.push(record);
259
+ }
260
+ result.data = transformedData;
261
+ if (fieldDataIssues.length > 0 || portalDataIssues.length > 0) {
262
+ console.error(
263
+ `🚨 @proofkit/fmdapi: Validation issues for layout "${layout}". Run the typegen command again to generate the latest field definitions from your layout.`,
264
+ {
265
+ fieldDataIssues,
266
+ portalDataIssues
267
+ }
268
+ );
269
+ throw new Error("Schema validation issues");
270
+ }
271
+ return result;
272
+ }
273
+ return {
274
+ ...otherMethods,
275
+ layout: options.layout,
276
+ list: _list,
277
+ listAll,
278
+ create: _create,
279
+ get: _get,
280
+ update: _update,
281
+ delete: deleteRecord,
282
+ find: _find,
283
+ findOne,
284
+ findFirst,
285
+ maybeFindFirst,
286
+ findAll,
287
+ layoutMetadata: _layoutMetadata,
288
+ containerUpload: _containerUpload
289
+ };
290
+ }
291
+ export {
292
+ DataApi,
293
+ DataApi as default
294
+ };
295
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sources":["../../src/client.ts"],"sourcesContent":["import type { Adapter } from \"./adapters/core.js\";\nimport type {\n CreateParams,\n CreateResponse,\n DeleteParams,\n DeleteResponse,\n FMRecord,\n FieldData,\n GenericPortalData,\n GetParams,\n GetResponse,\n GetResponseOne,\n ListParams,\n PortalsWithIds,\n Query,\n UpdateParams,\n UpdateResponse,\n} from \"./client-types.js\";\nimport { FileMakerError } from \"./index.js\";\nimport type { StandardSchemaV1 } from \"@standard-schema/spec\";\n\nfunction asNumber(input: string | number): number {\n return typeof input === \"string\" ? parseInt(input) : input;\n}\n\nexport type ClientObjectProps = {\n /**\n * The layout to use by default for all requests. Can be overrridden on each request.\n */\n layout: string;\n schema?: {\n /**\n * The schema for the field data.\n */\n fieldData: StandardSchemaV1<FieldData>;\n /**\n * The schema for the portal data.\n */\n portalData?: StandardSchemaV1<GenericPortalData>;\n };\n};\n\ntype FetchOptions = {\n fetch?: RequestInit;\n};\n\nfunction DataApi<\n Fd extends FieldData = FieldData,\n Pd extends GenericPortalData = GenericPortalData,\n Opts extends ClientObjectProps = ClientObjectProps,\n Adp extends Adapter = Adapter,\n>(options: Opts & { adapter: Adp }) {\n type InferredFieldData = Opts[\"schema\"] extends object\n ? StandardSchemaV1.InferOutput<Opts[\"schema\"][\"fieldData\"]>\n : Fd;\n type InferredPortalData = Opts[\"schema\"] extends object\n ? Opts[\"schema\"][\"portalData\"] extends object\n ? StandardSchemaV1.InferOutput<Opts[\"schema\"][\"portalData\"]>\n : Pd\n : Pd;\n\n if (\"zodValidators\" in options) {\n throw new Error(\n \"zodValidators is no longer supported. Use schema instead, or re-run the typegen command\",\n );\n }\n\n const schema = options.schema;\n const layout = options.layout;\n const {\n create,\n delete: _adapterDelete,\n find,\n get,\n list,\n update,\n layoutMetadata,\n containerUpload,\n ...otherMethods\n } = options.adapter;\n\n type CreateArgs<\n T extends InferredFieldData = InferredFieldData,\n U extends InferredPortalData = InferredPortalData,\n > = CreateParams<U> & {\n fieldData: Partial<T>;\n };\n type GetArgs<U extends InferredPortalData = InferredPortalData> =\n GetParams<U> & {\n recordId: number | string;\n };\n type UpdateArgs<\n T extends InferredFieldData = InferredFieldData,\n U extends InferredPortalData = InferredPortalData,\n > = UpdateParams<U> & {\n fieldData: Partial<T>;\n recordId: number | string;\n };\n type ContainerUploadArgs<T extends InferredFieldData = InferredFieldData> = {\n containerFieldName: keyof T;\n containerFieldRepetition?: string | number;\n file: Blob;\n recordId: number | string;\n modId?: number;\n timeout?: number;\n };\n type DeleteArgs = DeleteParams & {\n recordId: number | string;\n };\n type IgnoreEmptyResult = {\n /**\n * If true, a find that returns no results will retun an empty array instead of throwing an error.\n * @default false\n */\n ignoreEmptyResult?: boolean;\n };\n type FindArgs<\n T extends FieldData = InferredFieldData,\n U extends InferredPortalData = InferredPortalData,\n > = ListParams<T, U> & {\n query: Query<T> | Array<Query<T>>;\n timeout?: number;\n };\n\n /**\n * List all records from a given layout, no find criteria applied.\n */\n async function _list(): Promise<\n GetResponse<InferredFieldData, InferredPortalData>\n >;\n async function _list(\n args: ListParams<InferredFieldData, InferredPortalData> & FetchOptions,\n ): Promise<GetResponse<InferredFieldData, InferredPortalData>>;\n async function _list(\n args?: ListParams<InferredFieldData, InferredPortalData> & FetchOptions,\n ): Promise<GetResponse<InferredFieldData, InferredPortalData>> {\n const { fetch, timeout, ...params } = args ?? {};\n\n // rename and refactor limit, offset, and sort keys for this request\n if (\"limit\" in params && params.limit !== undefined)\n delete Object.assign(params, { _limit: params.limit })[\"limit\"];\n if (\"offset\" in params && params.offset !== undefined) {\n if (params.offset <= 1) delete params.offset;\n else delete Object.assign(params, { _offset: params.offset })[\"offset\"];\n }\n if (\"sort\" in params && params.sort !== undefined)\n delete Object.assign(params, {\n _sort: Array.isArray(params.sort) ? params.sort : [params.sort],\n })[\"sort\"];\n\n const result = await list({\n layout,\n data: params,\n fetch,\n timeout,\n });\n\n if (result.dataInfo.foundCount > result.dataInfo.returnedCount) {\n // more records found than returned\n if (args?.limit === undefined && args?.offset === undefined) {\n // and the user didn't specify a limit or offset, so we should warn them\n console.warn(\n `🚨 @proofkit/fmdapi: Loaded only ${result.dataInfo.returnedCount} of the ${result.dataInfo.foundCount} records from your \"${layout}\" layout. Use the \"listAll\" method to automatically paginate through all records, or specify a \"limit\" and \"offset\" to handle pagination yourself.`,\n );\n }\n }\n\n return await runSchemaValidationAndTransform(\n schema,\n result as GetResponse<InferredFieldData, InferredPortalData>,\n );\n }\n\n /**\n * Paginate through all records from a given layout, no find criteria applied.\n * ⚠️ WARNING: Use this method with caution, as it can be slow with large datasets\n */\n async function listAll<\n T extends FieldData = InferredFieldData,\n U extends InferredPortalData = InferredPortalData,\n >(): Promise<FMRecord<T, U>[]>;\n async function listAll<\n T extends FieldData = InferredFieldData,\n U extends InferredPortalData = InferredPortalData,\n >(args: ListParams<T, U> & FetchOptions): Promise<FMRecord<T, U>[]>;\n async function listAll<\n T extends FieldData = InferredFieldData,\n U extends InferredPortalData = InferredPortalData,\n >(args?: ListParams<T, U> & FetchOptions): Promise<FMRecord<T, U>[]> {\n let runningData: GetResponse<T, U>[\"data\"] = [];\n const limit = args?.limit ?? 100;\n let offset = args?.offset ?? 1;\n\n // eslint-disable-next-line no-constant-condition\n while (true) {\n const data = (await _list({\n ...args,\n offset,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n } as any)) as unknown as GetResponse<T, U>;\n runningData = [...runningData, ...data.data];\n if (runningData.length >= data.dataInfo.foundCount) break;\n offset = offset + limit;\n }\n return runningData;\n }\n\n /**\n * Create a new record in a given layout\n */\n async function _create<\n T extends InferredFieldData = InferredFieldData,\n U extends InferredPortalData = InferredPortalData,\n >(args: CreateArgs<T, U> & FetchOptions): Promise<CreateResponse> {\n const { fetch, timeout, ...params } = args ?? {};\n return await create({\n layout,\n data: params,\n fetch,\n timeout,\n });\n }\n\n /**\n * Get a single record by Internal RecordId\n */\n async function _get(\n args: GetArgs<InferredPortalData> & FetchOptions,\n ): Promise<GetResponse<InferredFieldData, InferredPortalData>> {\n args.recordId = asNumber(args.recordId);\n const { recordId, fetch, timeout, ...params } = args;\n\n const result = await get({\n layout,\n data: { ...params, recordId },\n fetch,\n timeout,\n });\n return await runSchemaValidationAndTransform(\n schema,\n result as GetResponse<InferredFieldData, InferredPortalData>,\n );\n }\n\n /**\n * Update a single record by internal RecordId\n */\n async function _update(\n args: UpdateArgs<InferredFieldData, InferredPortalData> & FetchOptions,\n ): Promise<UpdateResponse> {\n args.recordId = asNumber(args.recordId);\n const { recordId, fetch, timeout, ...params } = args;\n return await update({\n layout,\n data: { ...params, recordId },\n fetch,\n timeout,\n });\n }\n\n /**\n * Delete a single record by internal RecordId\n */\n async function deleteRecord(\n args: DeleteArgs & FetchOptions,\n ): Promise<DeleteResponse> {\n args.recordId = asNumber(args.recordId);\n const { recordId, fetch, timeout, ...params } = args;\n\n return _adapterDelete({\n layout,\n data: { ...params, recordId },\n fetch,\n timeout,\n });\n }\n\n /**\n * Find records in a given layout\n */\n async function _find(\n args: FindArgs<InferredFieldData, InferredPortalData> &\n IgnoreEmptyResult &\n FetchOptions,\n ): Promise<GetResponse<InferredFieldData, InferredPortalData>> {\n const {\n query: queryInput,\n ignoreEmptyResult = false,\n timeout,\n fetch,\n ...params\n } = args;\n const query = !Array.isArray(queryInput) ? [queryInput] : queryInput;\n\n // rename and refactor limit, offset, and sort keys for this request\n if (\"offset\" in params && params.offset !== undefined) {\n if (params.offset <= 1) delete params.offset;\n }\n if (\"dateformats\" in params && params.dateformats !== undefined) {\n // reassign dateformats to match FileMaker's expected values\n // @ts-expect-error FM wants a string, so this is fine\n params.dateformats = (\n params.dateformats === \"US\"\n ? 0\n : params.dateformats === \"file_locale\"\n ? 1\n : params.dateformats === \"ISO8601\"\n ? 2\n : 0\n ).toString();\n }\n const result = (await find({\n data: { ...params, query },\n layout,\n fetch,\n timeout,\n }).catch((e: unknown) => {\n if (ignoreEmptyResult && e instanceof FileMakerError && e.code === \"401\")\n return { data: [], dataInfo: { foundCount: 0, returnedCount: 0 } };\n throw e;\n })) as GetResponse<InferredFieldData, InferredPortalData>;\n\n if (result.dataInfo.foundCount > result.dataInfo.returnedCount) {\n // more records found than returned\n if (args?.limit === undefined && args?.offset === undefined) {\n console.warn(\n `🚨 @proofkit/fmdapi: Loaded only ${result.dataInfo.returnedCount} of the ${result.dataInfo.foundCount} records from your \"${layout}\" layout. Use the \"findAll\" method to automatically paginate through all records, or specify a \"limit\" and \"offset\" to handle pagination yourself.`,\n );\n }\n }\n\n return await runSchemaValidationAndTransform(schema, result);\n }\n\n /**\n * Helper method for `find`. Will only return the first result or throw error if there is more than 1 result.\n */\n async function findOne(\n args: FindArgs<InferredFieldData, InferredPortalData> & FetchOptions,\n ): Promise<GetResponseOne<InferredFieldData, InferredPortalData>> {\n const result = await _find(args);\n if (result.data.length !== 1)\n throw new Error(\n `${result.data.length} records found; expecting exactly 1`,\n );\n const transformedResult = await runSchemaValidationAndTransform(\n schema,\n result,\n );\n if (!transformedResult.data[0]) throw new Error(\"No data found\");\n return { ...transformedResult, data: transformedResult.data[0] };\n }\n\n /**\n * Helper method for `find`. Will only return the first result instead of an array.\n */\n async function findFirst(\n args: FindArgs<InferredFieldData, InferredPortalData> &\n IgnoreEmptyResult &\n FetchOptions,\n ): Promise<GetResponseOne<InferredFieldData, InferredPortalData>> {\n const result = await _find(args);\n const transformedResult = await runSchemaValidationAndTransform(\n schema,\n result,\n );\n\n if (!transformedResult.data[0]) throw new Error(\"No data found\");\n return { ...transformedResult, data: transformedResult.data[0] };\n }\n\n /**\n * Helper method for `find`. Will return the first result or null if no results are found.\n */\n async function maybeFindFirst(\n args: FindArgs<InferredFieldData, InferredPortalData> &\n IgnoreEmptyResult &\n FetchOptions,\n ): Promise<GetResponseOne<InferredFieldData, InferredPortalData> | null> {\n const result = await _find({ ...args, ignoreEmptyResult: true });\n const transformedResult = await runSchemaValidationAndTransform(\n schema,\n result,\n );\n if (!transformedResult.data[0]) return null;\n return { ...transformedResult, data: transformedResult.data[0] };\n }\n\n /**\n * Helper method for `find` to page through all found results.\n * ⚠️ WARNING: Use with caution as this can be a slow operation with large datasets\n */\n async function findAll(\n args: FindArgs<InferredFieldData, InferredPortalData> & FetchOptions,\n ): Promise<FMRecord<InferredFieldData, InferredPortalData>[]> {\n let runningData: GetResponse<\n InferredFieldData,\n InferredPortalData\n >[\"data\"] = [];\n const limit = args.limit ?? 100;\n let offset = args.offset ?? 1;\n // eslint-disable-next-line no-constant-condition\n while (true) {\n const data = await _find({\n ...args,\n offset,\n ignoreEmptyResult: true,\n });\n runningData = [...runningData, ...data.data];\n if (\n runningData.length === 0 ||\n runningData.length >= data.dataInfo.foundCount\n )\n break;\n offset = offset + limit;\n }\n return runningData;\n }\n\n async function _layoutMetadata(args?: { timeout?: number } & FetchOptions) {\n const { ...restArgs } = args ?? {};\n // Explicitly define the type for params based on FetchOptions\n const params: FetchOptions & { timeout?: number } = restArgs;\n\n return await layoutMetadata({\n layout,\n fetch: params.fetch, // Now should correctly resolve to undefined if not present\n timeout: params.timeout, // Now should correctly resolve to undefined if not present\n });\n }\n\n async function _containerUpload<\n T extends InferredFieldData = InferredFieldData,\n >(args: ContainerUploadArgs<T> & FetchOptions) {\n const { ...params } = args;\n return await containerUpload({\n layout,\n data: {\n ...params,\n containerFieldName: params.containerFieldName as string,\n repetition: params.containerFieldRepetition,\n },\n fetch: params.fetch,\n timeout: params.timeout,\n });\n }\n\n async function runSchemaValidationAndTransform(\n schema: ClientObjectProps[\"schema\"],\n result: GetResponse<InferredFieldData, InferredPortalData>,\n ): Promise<GetResponse<InferredFieldData, InferredPortalData>> {\n const fieldDataIssues: StandardSchemaV1.Issue[] = [];\n const portalDataIssues: StandardSchemaV1.Issue[] = [];\n\n if (!schema) return result;\n const transformedData: FMRecord<InferredFieldData, InferredPortalData>[] =\n [];\n for (const record of result.data) {\n let fieldResult = schema.fieldData[\"~standard\"].validate(\n record.fieldData,\n );\n if (fieldResult instanceof Promise) fieldResult = await fieldResult;\n if (\"value\" in fieldResult) {\n record.fieldData = fieldResult.value as InferredFieldData;\n } else {\n fieldDataIssues.push(...fieldResult.issues);\n }\n\n if (schema.portalData) {\n for (const [portalName, portalRecords] of Object.entries(\n record.portalData,\n )) {\n const validatedPortalRecords: PortalsWithIds<GenericPortalData>[] =\n [];\n for (const portalRecord of portalRecords) {\n let portalResult = schema.portalData[\"~standard\"].validate({\n [portalName]: portalRecord,\n });\n if (portalResult instanceof Promise)\n portalResult = await portalResult;\n if (\"value\" in portalResult) {\n validatedPortalRecords.push({\n ...portalResult.value[portalName],\n recordId: portalRecord.recordId,\n modId: portalRecord.modId,\n });\n } else {\n portalDataIssues.push(...portalResult.issues);\n }\n }\n // @ts-expect-error We know portalName is a valid key, but can't figure out the right assertions\n record.portalData[portalName] = validatedPortalRecords;\n }\n }\n\n transformedData.push(record);\n }\n result.data = transformedData;\n\n if (fieldDataIssues.length > 0 || portalDataIssues.length > 0) {\n console.error(\n `🚨 @proofkit/fmdapi: Validation issues for layout \"${layout}\". Run the typegen command again to generate the latest field definitions from your layout.`,\n {\n fieldDataIssues,\n portalDataIssues,\n },\n );\n throw new Error(\"Schema validation issues\");\n }\n\n return result;\n }\n\n return {\n ...otherMethods,\n layout: options.layout as Opts[\"layout\"],\n list: _list,\n listAll,\n create: _create,\n get: _get,\n update: _update,\n delete: deleteRecord,\n find: _find,\n findOne,\n findFirst,\n maybeFindFirst,\n findAll,\n layoutMetadata: _layoutMetadata,\n containerUpload: _containerUpload,\n };\n}\n\nexport default DataApi;\nexport { DataApi };\n"],"names":["schema"],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ import { FileMakerError } from './client-types.js';
2
+ import { DataApi } from './client.js';
3
+ export { DataApi, FileMakerError };
4
+ export * from './utils.js';
5
+ export * as clientTypes from './client-types.js';
6
+ export { FetchAdapter } from './adapters/fetch.js';
7
+ export { OttoAdapter, type OttoAPIKey } from './adapters/otto.js';
8
+ export default DataApi;
@@ -0,0 +1,16 @@
1
+ import * as clientTypes from "./client-types.js";
2
+ import { FileMakerError } from "./client-types.js";
3
+ import DataApi from "./client.js";
4
+ import { removeFMTableNames } from "./utils.js";
5
+ import { FetchAdapter } from "./adapters/fetch.js";
6
+ import { OttoAdapter } from "./adapters/otto.js";
7
+ export {
8
+ DataApi,
9
+ FetchAdapter,
10
+ FileMakerError,
11
+ OttoAdapter,
12
+ clientTypes,
13
+ DataApi as default,
14
+ removeFMTableNames
15
+ };
16
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;"}
@@ -0,0 +1,3 @@
1
+ import { TokenStoreDefinitions } from './types.js';
2
+ export declare const fileTokenStore: (fileName?: string) => TokenStoreDefinitions;
3
+ export default fileTokenStore;
@@ -0,0 +1,3 @@
1
+ export { default as upstashTokenStore } from './upstash.js';
2
+ export { default as fileStore } from './file.js';
3
+ export { default as memoryStore } from './memory.js';
@@ -0,0 +1,3 @@
1
+ import { TokenStoreDefinitions } from './types.js';
2
+ export declare function memoryStore(): TokenStoreDefinitions;
3
+ export default memoryStore;
@@ -0,0 +1,21 @@
1
+ function memoryStore() {
2
+ const data = {};
3
+ return {
4
+ getToken: (key) => {
5
+ try {
6
+ return data[key] ?? null;
7
+ } catch {
8
+ return null;
9
+ }
10
+ },
11
+ clearToken: (key) => delete data[key],
12
+ setToken: (key, value) => {
13
+ data[key] = value;
14
+ }
15
+ };
16
+ }
17
+ export {
18
+ memoryStore as default,
19
+ memoryStore
20
+ };
21
+ //# sourceMappingURL=memory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memory.js","sources":["../../../src/tokenStore/memory.ts"],"sourcesContent":["import type { TokenStoreDefinitions } from \"./types.js\";\n\nexport function memoryStore(): TokenStoreDefinitions {\n const data: Record<string, string> = {};\n return {\n getToken: (key: string): string | null => {\n try {\n return data[key] ?? null;\n } catch {\n return null;\n }\n },\n clearToken: (key: string) => delete data[key],\n setToken: (key: string, value: string): void => {\n data[key] = value;\n },\n };\n}\n\nexport default memoryStore;\n"],"names":[],"mappings":"AAEO,SAAS,cAAqC;AACnD,QAAM,OAA+B,CAAC;AAC/B,SAAA;AAAA,IACL,UAAU,CAAC,QAA+B;AACpC,UAAA;AACK,eAAA,KAAK,GAAG,KAAK;AAAA,MAAA,QACd;AACC,eAAA;AAAA,MAAA;AAAA,IAEX;AAAA,IACA,YAAY,CAAC,QAAgB,OAAO,KAAK,GAAG;AAAA,IAC5C,UAAU,CAAC,KAAa,UAAwB;AAC9C,WAAK,GAAG,IAAI;AAAA,IAAA;AAAA,EAEhB;AACF;"}
@@ -0,0 +1,8 @@
1
+ type MaybePromise<T> = Promise<T> | T;
2
+ export type TokenStoreDefinitions = {
3
+ getKey?: () => string;
4
+ getToken: (key: string) => MaybePromise<string | null>;
5
+ setToken: (key: string, value: string) => void;
6
+ clearToken: (key: string) => void;
7
+ };
8
+ export {};
@@ -0,0 +1,6 @@
1
+ import { TokenStoreDefinitions } from './types.js';
2
+ import { RedisConfigNodejs } from '@upstash/redis';
3
+ export declare function upstashTokenStore(config: RedisConfigNodejs, options?: {
4
+ prefix?: string;
5
+ }): TokenStoreDefinitions;
6
+ export default upstashTokenStore;
@@ -0,0 +1,8 @@
1
+ import { S, L, U } from 'ts-toolbelt';
2
+ type TransformedFields<T extends Record<string, any>> = U.Merge<{
3
+ [Field in keyof T]: {
4
+ [Key in Field extends string ? L.Last<S.Split<Field, "::">> : Field]: T[Field];
5
+ };
6
+ }[keyof T]>;
7
+ export declare function removeFMTableNames<T extends Record<string, any>>(obj: T): TransformedFields<T>;
8
+ export {};
@@ -0,0 +1,16 @@
1
+ function removeFMTableNames(obj) {
2
+ const newObj = {};
3
+ for (const key in obj) {
4
+ if (key.includes("::")) {
5
+ const newKey = key.split("::")[1];
6
+ newObj[newKey] = obj[key];
7
+ } else {
8
+ newObj[key] = obj[key];
9
+ }
10
+ }
11
+ return newObj;
12
+ }
13
+ export {
14
+ removeFMTableNames
15
+ };
16
+ //# sourceMappingURL=utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.js","sources":["../../src/utils.ts"],"sourcesContent":["import type { S, L, U } from \"ts-toolbelt\";\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype TransformedFields<T extends Record<string, any>> = U.Merge<\n {\n [Field in keyof T]: {\n [Key in Field extends string\n ? L.Last<S.Split<Field, \"::\">>\n : Field]: T[Field];\n };\n }[keyof T]\n>;\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport function removeFMTableNames<T extends Record<string, any>>(\n obj: T,\n): TransformedFields<T> {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const newObj: any = {};\n for (const key in obj) {\n if (key.includes(\"::\")) {\n const newKey = key.split(\"::\")[1];\n newObj[newKey as keyof TransformedFields<T>] = obj[key];\n } else {\n newObj[key] = obj[key];\n }\n }\n return newObj;\n}\n"],"names":[],"mappings":"AAcO,SAAS,mBACd,KACsB;AAEtB,QAAM,SAAc,CAAC;AACrB,aAAW,OAAO,KAAK;AACjB,QAAA,IAAI,SAAS,IAAI,GAAG;AACtB,YAAM,SAAS,IAAI,MAAM,IAAI,EAAE,CAAC;AACzB,aAAA,MAAoC,IAAI,IAAI,GAAG;AAAA,IAAA,OACjD;AACE,aAAA,GAAG,IAAI,IAAI,GAAG;AAAA,IAAA;AAAA,EACvB;AAEK,SAAA;AACT;"}
package/package.json ADDED
@@ -0,0 +1,99 @@
1
+ {
2
+ "name": "@proofkit/fmdapi",
3
+ "version": "5.0.0-beta.0",
4
+ "description": "FileMaker Data API client",
5
+ "repository": "git@github.com:proofgeist/fm-dapi.git",
6
+ "author": "Eric <37158449+eluce2@users.noreply.github.com>",
7
+ "license": "MIT",
8
+ "private": false,
9
+ "type": "module",
10
+ "main": "./dist/esm/index.js",
11
+ "types": "./dist/esm/index.d.ts",
12
+ "exports": {
13
+ ".": {
14
+ "import": {
15
+ "types": "./dist/esm/index.d.ts",
16
+ "default": "./dist/esm/index.js"
17
+ }
18
+ },
19
+ "./utils/*": {
20
+ "import": {
21
+ "types": "./dist/esm/utils.d.ts",
22
+ "default": "./dist/esm/utils.js"
23
+ }
24
+ },
25
+ "./tokenStore/*": {
26
+ "import": {
27
+ "types": "./dist/esm/tokenStore/*.d.ts",
28
+ "default": "./dist/esm/tokenStore/*.js"
29
+ }
30
+ },
31
+ "./adapters/*": {
32
+ "import": {
33
+ "types": "./dist/esm/adapters/*.d.ts",
34
+ "default": "./dist/esm/adapters/*.js"
35
+ }
36
+ },
37
+ "./package.json": "./package.json"
38
+ },
39
+ "dependencies": {
40
+ "@standard-schema/spec": "^1.0.0",
41
+ "@tanstack/vite-config": "^0.2.0",
42
+ "chalk": "4.1.2",
43
+ "commander": "^9.5.0",
44
+ "dotenv": "^16.4.7",
45
+ "fs-extra": "^11.3.0",
46
+ "ts-morph": "^25.0.1",
47
+ "vite": "^6.3.4",
48
+ "zod": "4.0.0-beta.20250505T012514"
49
+ },
50
+ "devDependencies": {
51
+ "@types/fs-extra": "^11.0.4",
52
+ "@types/node": "^22.15.3",
53
+ "@typescript-eslint/eslint-plugin": "^8.29.0",
54
+ "@typescript-eslint/parser": "^8.29.0",
55
+ "@upstash/redis": "^1.34.6",
56
+ "eslint": "^9.23.0",
57
+ "eslint-plugin-react": "^7.37.4",
58
+ "knip": "^5.52.0",
59
+ "prettier": "^3.5.3",
60
+ "publint": "^0.3.12",
61
+ "ts-toolbelt": "^9.6.0",
62
+ "typescript": "^5.8.3",
63
+ "vitest": "^3.1.1"
64
+ },
65
+ "engines": {
66
+ "node": ">=18.0.0"
67
+ },
68
+ "files": [
69
+ "src",
70
+ "dist",
71
+ "dist-browser",
72
+ "tokenStore",
73
+ "utils",
74
+ "stubs"
75
+ ],
76
+ "keywords": [
77
+ "filemaker",
78
+ "fms",
79
+ "fm",
80
+ "data api",
81
+ "dapi",
82
+ "fmrest",
83
+ "fmdapi",
84
+ "proofgeist",
85
+ "fm-dapi"
86
+ ],
87
+ "scripts": {
88
+ "build": "tsc && vite build && publint --strict",
89
+ "build:watch": "tsc && vite build --watch",
90
+ "check-format": "prettier --check .",
91
+ "format": "prettier --write .",
92
+ "dev": "tsc --watch",
93
+ "ci": "pnpm build && pnpm check-format && pnpm publint --strict && pnpm test",
94
+ "test": "op inject -i op.env -o .env.local -f && vitest run",
95
+ "changeset": "changeset",
96
+ "release": "pnpm build && changeset publish --access public",
97
+ "knip": "knip"
98
+ }
99
+ }
@@ -0,0 +1,62 @@
1
+ import type {
2
+ CreateParams,
3
+ CreateResponse,
4
+ DeleteParams,
5
+ DeleteResponse,
6
+ FieldData,
7
+ GetParams,
8
+ GetResponse,
9
+ ListParamsRaw,
10
+ LayoutMetadataResponse,
11
+ Query,
12
+ UpdateParams,
13
+ UpdateResponse,
14
+ } from "../client-types.js";
15
+
16
+ export type BaseRequest = {
17
+ layout: string;
18
+ fetch?: RequestInit;
19
+ timeout?: number;
20
+ };
21
+
22
+ export type ListOptions = BaseRequest & { data: ListParamsRaw };
23
+ export type GetOptions = BaseRequest & {
24
+ data: GetParams & { recordId: number };
25
+ };
26
+ export type FindOptions = BaseRequest & {
27
+ data: ListParamsRaw & { query: Array<Query> };
28
+ };
29
+ export type CreateOptions = BaseRequest & {
30
+ data: CreateParams & { fieldData: Partial<FieldData> };
31
+ };
32
+ export type UpdateOptions = BaseRequest & {
33
+ data: UpdateParams & { recordId: number; fieldData: Partial<FieldData> };
34
+ };
35
+ export type DeleteOptions = BaseRequest & {
36
+ data: DeleteParams & { recordId: number };
37
+ };
38
+ export type ContainerUploadOptions = BaseRequest & {
39
+ data: {
40
+ containerFieldName: string;
41
+ repetition?: string | number;
42
+ file: Blob;
43
+ recordId: string | number;
44
+ modId?: number;
45
+ };
46
+ };
47
+
48
+ export type LayoutMetadataOptions = BaseRequest;
49
+
50
+ export interface Adapter {
51
+ list: (opts: ListOptions) => Promise<GetResponse>;
52
+ get: (opts: GetOptions) => Promise<GetResponse>;
53
+ find: (opts: FindOptions) => Promise<GetResponse>;
54
+ create: (opts: CreateOptions) => Promise<CreateResponse>;
55
+ update: (opts: UpdateOptions) => Promise<UpdateResponse>;
56
+ delete: (opts: DeleteOptions) => Promise<DeleteResponse>;
57
+ containerUpload: (opts: ContainerUploadOptions) => Promise<void>;
58
+
59
+ layoutMetadata: (
60
+ opts: LayoutMetadataOptions,
61
+ ) => Promise<LayoutMetadataResponse>;
62
+ }
@@ -0,0 +1,5 @@
1
+ export type BaseFetchAdapterOptions = {
2
+ server: string;
3
+ db: string;
4
+ };
5
+ export type GetTokenArguments = { refresh?: boolean };