@proofkit/fmdapi 5.0.1-beta.3 → 5.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/esm/adapters/core.d.ts +6 -1
- package/dist/esm/adapters/fetch-base.d.ts +1 -5
- package/dist/esm/adapters/fetch-base.js.map +1 -1
- package/dist/esm/client.d.ts +10 -2
- package/dist/esm/client.js +9 -1
- package/dist/esm/client.js.map +1 -1
- package/package.json +6 -6
- package/src/adapters/core.ts +8 -1
- package/src/adapters/fetch-base.ts +1 -5
- package/src/client.ts +12 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { CreateParams, CreateResponse, DeleteParams, DeleteResponse, FieldData, GetParams, GetResponse, ListParamsRaw, LayoutMetadataResponse, Query, UpdateParams, UpdateResponse } from '../client-types.js';
|
|
1
|
+
import { CreateParams, CreateResponse, DeleteParams, DeleteResponse, FieldData, GetParams, GetResponse, ListParamsRaw, LayoutMetadataResponse, Query, UpdateParams, UpdateResponse, ScriptResponse } from '../client-types.js';
|
|
2
2
|
export type BaseRequest = {
|
|
3
3
|
layout: string;
|
|
4
4
|
fetch?: RequestInit;
|
|
@@ -42,6 +42,10 @@ export type ContainerUploadOptions = BaseRequest & {
|
|
|
42
42
|
modId?: number;
|
|
43
43
|
};
|
|
44
44
|
};
|
|
45
|
+
export type ExecuteScriptOptions = BaseRequest & {
|
|
46
|
+
script: string;
|
|
47
|
+
scriptParam?: string;
|
|
48
|
+
};
|
|
45
49
|
export type LayoutMetadataOptions = BaseRequest;
|
|
46
50
|
export interface Adapter {
|
|
47
51
|
list: (opts: ListOptions) => Promise<GetResponse>;
|
|
@@ -52,4 +56,5 @@ export interface Adapter {
|
|
|
52
56
|
delete: (opts: DeleteOptions) => Promise<DeleteResponse>;
|
|
53
57
|
containerUpload: (opts: ContainerUploadOptions) => Promise<void>;
|
|
54
58
|
layoutMetadata: (opts: LayoutMetadataOptions) => Promise<LayoutMetadataResponse>;
|
|
59
|
+
executeScript: (opts: ExecuteScriptOptions) => Promise<ScriptResponse>;
|
|
55
60
|
}
|
|
@@ -1,10 +1,6 @@
|
|
|
1
1
|
import { AllLayoutsMetadataResponse, CreateResponse, DeleteResponse, GetResponse, LayoutMetadataResponse, PortalRanges, ScriptsMetadataResponse, UpdateResponse } from '../client-types.js';
|
|
2
|
-
import { Adapter, BaseRequest, ContainerUploadOptions, CreateOptions, DeleteOptions, FindOptions, GetOptions, LayoutMetadataOptions, ListOptions, UpdateOptions } from './core.js';
|
|
2
|
+
import { Adapter, BaseRequest, ContainerUploadOptions, CreateOptions, DeleteOptions, ExecuteScriptOptions, FindOptions, GetOptions, LayoutMetadataOptions, ListOptions, UpdateOptions } from './core.js';
|
|
3
3
|
import { BaseFetchAdapterOptions, GetTokenArguments } from './fetch-base-types.js';
|
|
4
|
-
export type ExecuteScriptOptions = BaseRequest & {
|
|
5
|
-
script: string;
|
|
6
|
-
scriptParam?: string;
|
|
7
|
-
};
|
|
8
4
|
export declare class BaseFetchAdapter implements Adapter {
|
|
9
5
|
protected server: string;
|
|
10
6
|
protected db: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fetch-base.js","sources":["../../../src/adapters/fetch-base.ts"],"sourcesContent":["import type {\n AllLayoutsMetadataResponse,\n CreateResponse,\n DeleteResponse,\n GetResponse,\n LayoutMetadataResponse,\n PortalRanges,\n RawFMResponse,\n ScriptResponse,\n ScriptsMetadataResponse,\n UpdateResponse,\n} from \"../client-types.js\";\nimport { FileMakerError } from \"../client-types.js\";\nimport type {\n Adapter,\n BaseRequest,\n ContainerUploadOptions,\n CreateOptions,\n DeleteOptions,\n FindOptions,\n GetOptions,\n LayoutMetadataOptions,\n ListOptions,\n UpdateOptions,\n} from \"./core.js\";\nimport type {\n BaseFetchAdapterOptions,\n GetTokenArguments,\n} from \"./fetch-base-types.js\";\n\nexport type ExecuteScriptOptions = BaseRequest & {\n script: string;\n scriptParam?: string;\n};\n\nexport class BaseFetchAdapter implements Adapter {\n protected server: string;\n protected db: string;\n private refreshToken: boolean;\n baseUrl: URL;\n\n constructor(options: BaseFetchAdapterOptions & { refreshToken?: boolean }) {\n this.server = options.server;\n this.db = options.db;\n this.refreshToken = options.refreshToken ?? false;\n this.baseUrl = new URL(\n `${this.server}/fmi/data/vLatest/databases/${this.db}`,\n );\n\n if (this.db === \"\") throw new Error(\"Database name is required\");\n }\n\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n protected getToken = async (args?: GetTokenArguments): Promise<string> => {\n // method must be implemented in subclass\n throw new Error(\"getToken method not implemented by Fetch Adapter\");\n };\n\n protected request = async (params: {\n url: string;\n body?: object | FormData;\n query?: Record<string, string>;\n method?: string;\n retry?: boolean;\n portalRanges?: PortalRanges;\n timeout?: number;\n fetchOptions?: RequestInit;\n }): Promise<unknown> => {\n const {\n query,\n body,\n method = \"GET\",\n retry = false,\n fetchOptions = {},\n } = params;\n\n const url = new URL(`${this.baseUrl}${params.url}`);\n\n if (query) {\n const { _sort, ...rest } = query;\n const searchParams = new URLSearchParams(rest);\n if (query.portalRanges && typeof query.portalRanges === \"object\") {\n for (const [portalName, value] of Object.entries(\n query.portalRanges as PortalRanges,\n )) {\n if (value) {\n if (value.offset && value.offset > 0) {\n searchParams.set(\n `_offset.${portalName}`,\n value.offset.toString(),\n );\n }\n if (value.limit) {\n searchParams.set(`_limit.${portalName}`, value.limit.toString());\n }\n }\n }\n }\n if (_sort) {\n searchParams.set(\"_sort\", JSON.stringify(_sort));\n }\n searchParams.delete(\"portalRanges\");\n url.search = searchParams.toString();\n }\n\n if (body && \"portalRanges\" in body) {\n for (const [portalName, value] of Object.entries(\n body.portalRanges as PortalRanges,\n )) {\n if (value) {\n if (value.offset && value.offset > 0) {\n url.searchParams.set(\n `_offset.${portalName}`,\n value.offset.toString(),\n );\n }\n if (value.limit) {\n url.searchParams.set(\n `_limit.${portalName}`,\n value.limit.toString(),\n );\n }\n }\n }\n delete body.portalRanges;\n }\n\n const controller = new AbortController();\n let timeout: NodeJS.Timeout | null = null;\n if (params.timeout)\n timeout = setTimeout(() => controller.abort(), params.timeout);\n\n const token = await this.getToken({ refresh: retry });\n\n const headers = new Headers(fetchOptions?.headers);\n headers.set(\"Authorization\", `Bearer ${token}`);\n\n // Only set Content-Type for JSON bodies\n if (!(body instanceof FormData)) {\n headers.set(\"Content-Type\", \"application/json\");\n }\n\n const res = await fetch(url.toString(), {\n ...fetchOptions,\n method,\n body:\n body instanceof FormData\n ? body\n : body\n ? JSON.stringify(body)\n : undefined,\n headers,\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore\n signal: controller.signal,\n });\n\n if (timeout) clearTimeout(timeout);\n\n let respData: RawFMResponse;\n try {\n respData = await res.json();\n } catch {\n respData = {};\n }\n\n if (!res.ok) {\n if (\n respData?.messages?.[0].code === \"952\" &&\n !retry &&\n this.refreshToken\n ) {\n // token expired, get new token and retry once\n return this.request({ ...params, retry: true });\n } else {\n throw new FileMakerError(\n respData?.messages?.[0].code ?? \"500\",\n `Filemaker Data API failed with (${res.status}): ${JSON.stringify(\n respData,\n null,\n 2,\n )}`,\n );\n }\n }\n\n return respData.response;\n };\n\n public list = async (opts: ListOptions): Promise<GetResponse> => {\n const { data, layout } = opts;\n\n const resp = await this.request({\n url: `/layouts/${layout}/records`,\n query: data as Record<string, string>,\n fetchOptions: opts.fetch,\n timeout: opts.timeout,\n });\n return resp as GetResponse;\n };\n\n public get = async (opts: GetOptions): Promise<GetResponse> => {\n const { data, layout } = opts;\n const resp = await this.request({\n url: `/layouts/${layout}/records/${data.recordId}`,\n fetchOptions: opts.fetch,\n timeout: opts.timeout,\n });\n return resp as GetResponse;\n };\n\n public find = async (opts: FindOptions): Promise<GetResponse> => {\n const { data, layout } = opts;\n const resp = await this.request({\n url: `/layouts/${layout}/_find`,\n body: data,\n method: \"POST\",\n fetchOptions: opts.fetch,\n timeout: opts.timeout,\n });\n return resp as GetResponse;\n };\n\n public create = async (opts: CreateOptions): Promise<CreateResponse> => {\n const { data, layout } = opts;\n const resp = await this.request({\n url: `/layouts/${layout}/records`,\n body: data,\n method: \"POST\",\n fetchOptions: opts.fetch,\n timeout: opts.timeout,\n });\n return resp as CreateResponse;\n };\n\n public update = async (opts: UpdateOptions): Promise<UpdateResponse> => {\n const {\n data: { recordId, ...data },\n layout,\n } = opts;\n const resp = await this.request({\n url: `/layouts/${layout}/records/${recordId}`,\n body: data,\n method: \"PATCH\",\n fetchOptions: opts.fetch,\n timeout: opts.timeout,\n });\n return resp as UpdateResponse;\n };\n\n public delete = async (opts: DeleteOptions): Promise<DeleteResponse> => {\n const { data, layout } = opts;\n const resp = await this.request({\n url: `/layouts/${layout}/records/${data.recordId}`,\n method: \"DELETE\",\n fetchOptions: opts.fetch,\n timeout: opts.timeout,\n });\n return resp as DeleteResponse;\n };\n\n public layoutMetadata = async (\n opts: LayoutMetadataOptions,\n ): Promise<LayoutMetadataResponse> => {\n return (await this.request({\n url: `/layouts/${opts.layout}`,\n fetchOptions: opts.fetch,\n timeout: opts.timeout,\n })) as LayoutMetadataResponse;\n };\n\n /**\n * Execute a script within the database\n */\n public executeScript = async (opts: ExecuteScriptOptions) => {\n const { script, scriptParam, layout } = opts;\n const resp = await this.request({\n url: `/layouts/${layout}/script/${script}`,\n query: scriptParam ? { \"script.param\": scriptParam } : undefined,\n fetchOptions: opts.fetch,\n timeout: opts.timeout,\n });\n return resp as ScriptResponse;\n };\n\n /**\n * Returns a list of available layouts on the database.\n */\n public layouts = async (opts?: Omit<BaseRequest, \"layout\">) => {\n return (await this.request({\n url: \"/layouts\",\n fetchOptions: opts?.fetch,\n timeout: opts?.timeout,\n })) as AllLayoutsMetadataResponse;\n };\n\n /**\n * Returns a list of available scripts on the database.\n */\n public scripts = async (opts?: Omit<BaseRequest, \"layout\">) => {\n return (await this.request({\n url: \"/scripts\",\n fetchOptions: opts?.fetch,\n timeout: opts?.timeout,\n })) as ScriptsMetadataResponse;\n };\n\n public containerUpload = async (opts: ContainerUploadOptions) => {\n let url = `/layouts/${opts.layout}/records/${opts.data.recordId}/containers/${opts.data.containerFieldName}`;\n if (opts.data.repetition) url += `/${opts.data.repetition}`;\n const formData = new FormData();\n formData.append(\"upload\", opts.data.file);\n\n await this.request({\n url,\n method: \"POST\",\n body: formData,\n timeout: opts.timeout,\n fetchOptions: opts.fetch,\n });\n };\n\n /**\n * Set global fields for the current session\n */\n public globals = async (\n opts: Omit<BaseRequest, \"layout\"> & {\n globalFields: Record<string, string | number>;\n },\n ) => {\n return (await this.request({\n url: \"/globals\",\n method: \"PATCH\",\n body: { globalFields: opts.globalFields },\n fetchOptions: opts?.fetch,\n timeout: opts?.timeout,\n })) as Record<string, never>;\n };\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"fetch-base.js","sources":["../../../src/adapters/fetch-base.ts"],"sourcesContent":["import type {\n AllLayoutsMetadataResponse,\n CreateResponse,\n DeleteResponse,\n GetResponse,\n LayoutMetadataResponse,\n PortalRanges,\n RawFMResponse,\n ScriptResponse,\n ScriptsMetadataResponse,\n UpdateResponse,\n} from \"../client-types.js\";\nimport { FileMakerError } from \"../client-types.js\";\nimport type {\n Adapter,\n BaseRequest,\n ContainerUploadOptions,\n CreateOptions,\n DeleteOptions,\n ExecuteScriptOptions,\n FindOptions,\n GetOptions,\n LayoutMetadataOptions,\n ListOptions,\n UpdateOptions,\n} from \"./core.js\";\nimport type {\n BaseFetchAdapterOptions,\n GetTokenArguments,\n} from \"./fetch-base-types.js\";\n\nexport class BaseFetchAdapter implements Adapter {\n protected server: string;\n protected db: string;\n private refreshToken: boolean;\n baseUrl: URL;\n\n constructor(options: BaseFetchAdapterOptions & { refreshToken?: boolean }) {\n this.server = options.server;\n this.db = options.db;\n this.refreshToken = options.refreshToken ?? false;\n this.baseUrl = new URL(\n `${this.server}/fmi/data/vLatest/databases/${this.db}`,\n );\n\n if (this.db === \"\") throw new Error(\"Database name is required\");\n }\n\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n protected getToken = async (args?: GetTokenArguments): Promise<string> => {\n // method must be implemented in subclass\n throw new Error(\"getToken method not implemented by Fetch Adapter\");\n };\n\n protected request = async (params: {\n url: string;\n body?: object | FormData;\n query?: Record<string, string>;\n method?: string;\n retry?: boolean;\n portalRanges?: PortalRanges;\n timeout?: number;\n fetchOptions?: RequestInit;\n }): Promise<unknown> => {\n const {\n query,\n body,\n method = \"GET\",\n retry = false,\n fetchOptions = {},\n } = params;\n\n const url = new URL(`${this.baseUrl}${params.url}`);\n\n if (query) {\n const { _sort, ...rest } = query;\n const searchParams = new URLSearchParams(rest);\n if (query.portalRanges && typeof query.portalRanges === \"object\") {\n for (const [portalName, value] of Object.entries(\n query.portalRanges as PortalRanges,\n )) {\n if (value) {\n if (value.offset && value.offset > 0) {\n searchParams.set(\n `_offset.${portalName}`,\n value.offset.toString(),\n );\n }\n if (value.limit) {\n searchParams.set(`_limit.${portalName}`, value.limit.toString());\n }\n }\n }\n }\n if (_sort) {\n searchParams.set(\"_sort\", JSON.stringify(_sort));\n }\n searchParams.delete(\"portalRanges\");\n url.search = searchParams.toString();\n }\n\n if (body && \"portalRanges\" in body) {\n for (const [portalName, value] of Object.entries(\n body.portalRanges as PortalRanges,\n )) {\n if (value) {\n if (value.offset && value.offset > 0) {\n url.searchParams.set(\n `_offset.${portalName}`,\n value.offset.toString(),\n );\n }\n if (value.limit) {\n url.searchParams.set(\n `_limit.${portalName}`,\n value.limit.toString(),\n );\n }\n }\n }\n delete body.portalRanges;\n }\n\n const controller = new AbortController();\n let timeout: NodeJS.Timeout | null = null;\n if (params.timeout)\n timeout = setTimeout(() => controller.abort(), params.timeout);\n\n const token = await this.getToken({ refresh: retry });\n\n const headers = new Headers(fetchOptions?.headers);\n headers.set(\"Authorization\", `Bearer ${token}`);\n\n // Only set Content-Type for JSON bodies\n if (!(body instanceof FormData)) {\n headers.set(\"Content-Type\", \"application/json\");\n }\n\n const res = await fetch(url.toString(), {\n ...fetchOptions,\n method,\n body:\n body instanceof FormData\n ? body\n : body\n ? JSON.stringify(body)\n : undefined,\n headers,\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore\n signal: controller.signal,\n });\n\n if (timeout) clearTimeout(timeout);\n\n let respData: RawFMResponse;\n try {\n respData = await res.json();\n } catch {\n respData = {};\n }\n\n if (!res.ok) {\n if (\n respData?.messages?.[0].code === \"952\" &&\n !retry &&\n this.refreshToken\n ) {\n // token expired, get new token and retry once\n return this.request({ ...params, retry: true });\n } else {\n throw new FileMakerError(\n respData?.messages?.[0].code ?? \"500\",\n `Filemaker Data API failed with (${res.status}): ${JSON.stringify(\n respData,\n null,\n 2,\n )}`,\n );\n }\n }\n\n return respData.response;\n };\n\n public list = async (opts: ListOptions): Promise<GetResponse> => {\n const { data, layout } = opts;\n\n const resp = await this.request({\n url: `/layouts/${layout}/records`,\n query: data as Record<string, string>,\n fetchOptions: opts.fetch,\n timeout: opts.timeout,\n });\n return resp as GetResponse;\n };\n\n public get = async (opts: GetOptions): Promise<GetResponse> => {\n const { data, layout } = opts;\n const resp = await this.request({\n url: `/layouts/${layout}/records/${data.recordId}`,\n fetchOptions: opts.fetch,\n timeout: opts.timeout,\n });\n return resp as GetResponse;\n };\n\n public find = async (opts: FindOptions): Promise<GetResponse> => {\n const { data, layout } = opts;\n const resp = await this.request({\n url: `/layouts/${layout}/_find`,\n body: data,\n method: \"POST\",\n fetchOptions: opts.fetch,\n timeout: opts.timeout,\n });\n return resp as GetResponse;\n };\n\n public create = async (opts: CreateOptions): Promise<CreateResponse> => {\n const { data, layout } = opts;\n const resp = await this.request({\n url: `/layouts/${layout}/records`,\n body: data,\n method: \"POST\",\n fetchOptions: opts.fetch,\n timeout: opts.timeout,\n });\n return resp as CreateResponse;\n };\n\n public update = async (opts: UpdateOptions): Promise<UpdateResponse> => {\n const {\n data: { recordId, ...data },\n layout,\n } = opts;\n const resp = await this.request({\n url: `/layouts/${layout}/records/${recordId}`,\n body: data,\n method: \"PATCH\",\n fetchOptions: opts.fetch,\n timeout: opts.timeout,\n });\n return resp as UpdateResponse;\n };\n\n public delete = async (opts: DeleteOptions): Promise<DeleteResponse> => {\n const { data, layout } = opts;\n const resp = await this.request({\n url: `/layouts/${layout}/records/${data.recordId}`,\n method: \"DELETE\",\n fetchOptions: opts.fetch,\n timeout: opts.timeout,\n });\n return resp as DeleteResponse;\n };\n\n public layoutMetadata = async (\n opts: LayoutMetadataOptions,\n ): Promise<LayoutMetadataResponse> => {\n return (await this.request({\n url: `/layouts/${opts.layout}`,\n fetchOptions: opts.fetch,\n timeout: opts.timeout,\n })) as LayoutMetadataResponse;\n };\n\n /**\n * Execute a script within the database\n */\n public executeScript = async (opts: ExecuteScriptOptions) => {\n const { script, scriptParam, layout } = opts;\n const resp = await this.request({\n url: `/layouts/${layout}/script/${script}`,\n query: scriptParam ? { \"script.param\": scriptParam } : undefined,\n fetchOptions: opts.fetch,\n timeout: opts.timeout,\n });\n return resp as ScriptResponse;\n };\n\n /**\n * Returns a list of available layouts on the database.\n */\n public layouts = async (opts?: Omit<BaseRequest, \"layout\">) => {\n return (await this.request({\n url: \"/layouts\",\n fetchOptions: opts?.fetch,\n timeout: opts?.timeout,\n })) as AllLayoutsMetadataResponse;\n };\n\n /**\n * Returns a list of available scripts on the database.\n */\n public scripts = async (opts?: Omit<BaseRequest, \"layout\">) => {\n return (await this.request({\n url: \"/scripts\",\n fetchOptions: opts?.fetch,\n timeout: opts?.timeout,\n })) as ScriptsMetadataResponse;\n };\n\n public containerUpload = async (opts: ContainerUploadOptions) => {\n let url = `/layouts/${opts.layout}/records/${opts.data.recordId}/containers/${opts.data.containerFieldName}`;\n if (opts.data.repetition) url += `/${opts.data.repetition}`;\n const formData = new FormData();\n formData.append(\"upload\", opts.data.file);\n\n await this.request({\n url,\n method: \"POST\",\n body: formData,\n timeout: opts.timeout,\n fetchOptions: opts.fetch,\n });\n };\n\n /**\n * Set global fields for the current session\n */\n public globals = async (\n opts: Omit<BaseRequest, \"layout\"> & {\n globalFields: Record<string, string | number>;\n },\n ) => {\n return (await this.request({\n url: \"/globals\",\n method: \"PATCH\",\n body: { globalFields: opts.globalFields },\n fetchOptions: opts?.fetch,\n timeout: opts?.timeout,\n })) as Record<string, never>;\n };\n}\n"],"names":[],"mappings":"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"}
|
package/dist/esm/client.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Adapter } from './adapters/core.js';
|
|
1
|
+
import { Adapter, ExecuteScriptOptions } from './adapters/core.js';
|
|
2
2
|
import { CreateResponse, DeleteResponse, FMRecord, FieldData, GenericPortalData, GetResponse, GetResponseOne, ListParams, Query, UpdateResponse } from './client-types.js';
|
|
3
3
|
import { StandardSchemaV1 } from '@standard-schema/spec';
|
|
4
4
|
export type ClientObjectProps = {
|
|
@@ -22,7 +22,7 @@ type FetchOptions = {
|
|
|
22
22
|
};
|
|
23
23
|
declare function DataApi<Fd extends FieldData = FieldData, Pd extends GenericPortalData = GenericPortalData, Opts extends ClientObjectProps = ClientObjectProps, Adp extends Adapter = Adapter>(options: Opts & {
|
|
24
24
|
adapter: Adp;
|
|
25
|
-
}): Omit<Adp, "create" | "delete" | "find" | "get" | "list" | "update" | "layoutMetadata" | "containerUpload"> & {
|
|
25
|
+
}): Omit<Adp, "create" | "delete" | "find" | "get" | "list" | "update" | "layoutMetadata" | "containerUpload" | "executeScript"> & {
|
|
26
26
|
layout: Opts["layout"];
|
|
27
27
|
list: {
|
|
28
28
|
(): Promise<GetResponse<Opts["schema"] extends object ? StandardSchemaV1.InferOutput<Opts["schema"]["fieldData"]> : Fd, Opts["schema"] extends object ? Opts["schema"]["portalData"] extends object ? { [K in keyof Opts["schema"]["portalData"]]: StandardSchemaV1.InferOutput<Opts["schema"]["portalData"][K]>; } : Pd : Pd>>;
|
|
@@ -128,6 +128,14 @@ declare function DataApi<Fd extends FieldData = FieldData, Pd extends GenericPor
|
|
|
128
128
|
modId?: number;
|
|
129
129
|
timeout?: number;
|
|
130
130
|
} & FetchOptions) => Promise<void>;
|
|
131
|
+
executeScript: (args: Omit<ExecuteScriptOptions, "layout"> & FetchOptions) => Promise<{
|
|
132
|
+
scriptResult?: string | undefined;
|
|
133
|
+
scriptError?: string | undefined;
|
|
134
|
+
"scriptResult.prerequest"?: string | undefined;
|
|
135
|
+
"scriptError.prerequest"?: string | undefined;
|
|
136
|
+
"scriptResult.presort"?: string | undefined;
|
|
137
|
+
"scriptError.presort"?: string | undefined;
|
|
138
|
+
}>;
|
|
131
139
|
};
|
|
132
140
|
export default DataApi;
|
|
133
141
|
export { DataApi };
|
package/dist/esm/client.js
CHANGED
|
@@ -19,6 +19,7 @@ function DataApi(options) {
|
|
|
19
19
|
update,
|
|
20
20
|
layoutMetadata,
|
|
21
21
|
containerUpload,
|
|
22
|
+
executeScript,
|
|
22
23
|
...otherMethods
|
|
23
24
|
} = options.adapter;
|
|
24
25
|
async function _list(args) {
|
|
@@ -271,6 +272,12 @@ function DataApi(options) {
|
|
|
271
272
|
}
|
|
272
273
|
return result;
|
|
273
274
|
}
|
|
275
|
+
async function _executeScript(args) {
|
|
276
|
+
return await executeScript({
|
|
277
|
+
...args,
|
|
278
|
+
layout
|
|
279
|
+
});
|
|
280
|
+
}
|
|
274
281
|
return {
|
|
275
282
|
...otherMethods,
|
|
276
283
|
layout: options.layout,
|
|
@@ -286,7 +293,8 @@ function DataApi(options) {
|
|
|
286
293
|
maybeFindFirst,
|
|
287
294
|
findAll,
|
|
288
295
|
layoutMetadata: _layoutMetadata,
|
|
289
|
-
containerUpload: _containerUpload
|
|
296
|
+
containerUpload: _containerUpload,
|
|
297
|
+
executeScript: _executeScript
|
|
290
298
|
};
|
|
291
299
|
}
|
|
292
300
|
export {
|
package/dist/esm/client.js.map
CHANGED
|
@@ -1 +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?: Record<string, StandardSchemaV1<FieldData>>;\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 ? {\n [K in keyof Opts[\"schema\"][\"portalData\"]]: StandardSchemaV1.InferOutput<\n Opts[\"schema\"][\"portalData\"][K]\n >;\n }\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 =\n schema.portalData[portalName]?.[\"~standard\"].validate(\n portalRecord,\n );\n if (portalResult instanceof Promise)\n portalResult = await portalResult;\n if (portalResult && \"value\" in portalResult) {\n validatedPortalRecords.push({\n ...portalResult.value,\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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"}
|
|
1
|
+
{"version":3,"file":"client.js","sources":["../../src/client.ts"],"sourcesContent":["import type { Adapter, ExecuteScriptOptions } 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?: Record<string, StandardSchemaV1<FieldData>>;\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 ? {\n [K in keyof Opts[\"schema\"][\"portalData\"]]: StandardSchemaV1.InferOutput<\n Opts[\"schema\"][\"portalData\"][K]\n >;\n }\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 executeScript,\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 type ExecuteScriptArgs = Omit<ExecuteScriptOptions, \"layout\">;\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 =\n schema.portalData[portalName]?.[\"~standard\"].validate(\n portalRecord,\n );\n if (portalResult instanceof Promise)\n portalResult = await portalResult;\n if (portalResult && \"value\" in portalResult) {\n validatedPortalRecords.push({\n ...portalResult.value,\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 async function _executeScript(args: ExecuteScriptArgs & FetchOptions) {\n return await executeScript({\n ...args,\n layout,\n });\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 executeScript: _executeScript,\n };\n}\n\nexport default DataApi;\nexport { DataApi };\n"],"names":["schema"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@proofkit/fmdapi",
|
|
3
|
-
"version": "5.0.
|
|
3
|
+
"version": "5.0.2",
|
|
4
4
|
"description": "FileMaker Data API client",
|
|
5
5
|
"repository": "git@github.com:proofgeist/fm-dapi.git",
|
|
6
6
|
"author": "Eric <37158449+eluce2@users.noreply.github.com>",
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
"@tanstack/vite-config": "^0.2.0",
|
|
42
42
|
"chalk": "5.4.1",
|
|
43
43
|
"commander": "^14.0.0",
|
|
44
|
-
"dotenv": "^16.
|
|
44
|
+
"dotenv": "^16.5.0",
|
|
45
45
|
"fs-extra": "^11.3.0",
|
|
46
46
|
"ts-morph": "^26.0.0",
|
|
47
47
|
"vite": "^6.3.4",
|
|
@@ -49,18 +49,18 @@
|
|
|
49
49
|
},
|
|
50
50
|
"devDependencies": {
|
|
51
51
|
"@types/fs-extra": "^11.0.4",
|
|
52
|
-
"@types/node": "^22.
|
|
52
|
+
"@types/node": "^22.17.1",
|
|
53
53
|
"@typescript-eslint/eslint-plugin": "^8.29.0",
|
|
54
54
|
"@typescript-eslint/parser": "^8.29.0",
|
|
55
55
|
"@upstash/redis": "^1.34.6",
|
|
56
56
|
"eslint": "^9.23.0",
|
|
57
57
|
"eslint-plugin-react": "^7.37.4",
|
|
58
|
-
"knip": "^5.
|
|
58
|
+
"knip": "^5.56.0",
|
|
59
59
|
"prettier": "^3.5.3",
|
|
60
60
|
"publint": "^0.3.12",
|
|
61
61
|
"ts-toolbelt": "^9.6.0",
|
|
62
|
-
"typescript": "^5.
|
|
63
|
-
"vitest": "^3.2.
|
|
62
|
+
"typescript": "^5.9.2",
|
|
63
|
+
"vitest": "^3.2.4"
|
|
64
64
|
},
|
|
65
65
|
"engines": {
|
|
66
66
|
"node": ">=18.0.0"
|
package/src/adapters/core.ts
CHANGED
|
@@ -11,6 +11,8 @@ import type {
|
|
|
11
11
|
Query,
|
|
12
12
|
UpdateParams,
|
|
13
13
|
UpdateResponse,
|
|
14
|
+
ScriptParams,
|
|
15
|
+
ScriptResponse,
|
|
14
16
|
} from "../client-types.js";
|
|
15
17
|
|
|
16
18
|
export type BaseRequest = {
|
|
@@ -44,7 +46,10 @@ export type ContainerUploadOptions = BaseRequest & {
|
|
|
44
46
|
modId?: number;
|
|
45
47
|
};
|
|
46
48
|
};
|
|
47
|
-
|
|
49
|
+
export type ExecuteScriptOptions = BaseRequest & {
|
|
50
|
+
script: string;
|
|
51
|
+
scriptParam?: string;
|
|
52
|
+
};
|
|
48
53
|
export type LayoutMetadataOptions = BaseRequest;
|
|
49
54
|
|
|
50
55
|
export interface Adapter {
|
|
@@ -59,4 +64,6 @@ export interface Adapter {
|
|
|
59
64
|
layoutMetadata: (
|
|
60
65
|
opts: LayoutMetadataOptions,
|
|
61
66
|
) => Promise<LayoutMetadataResponse>;
|
|
67
|
+
|
|
68
|
+
executeScript: (opts: ExecuteScriptOptions) => Promise<ScriptResponse>;
|
|
62
69
|
}
|
|
@@ -17,6 +17,7 @@ import type {
|
|
|
17
17
|
ContainerUploadOptions,
|
|
18
18
|
CreateOptions,
|
|
19
19
|
DeleteOptions,
|
|
20
|
+
ExecuteScriptOptions,
|
|
20
21
|
FindOptions,
|
|
21
22
|
GetOptions,
|
|
22
23
|
LayoutMetadataOptions,
|
|
@@ -28,11 +29,6 @@ import type {
|
|
|
28
29
|
GetTokenArguments,
|
|
29
30
|
} from "./fetch-base-types.js";
|
|
30
31
|
|
|
31
|
-
export type ExecuteScriptOptions = BaseRequest & {
|
|
32
|
-
script: string;
|
|
33
|
-
scriptParam?: string;
|
|
34
|
-
};
|
|
35
|
-
|
|
36
32
|
export class BaseFetchAdapter implements Adapter {
|
|
37
33
|
protected server: string;
|
|
38
34
|
protected db: string;
|
package/src/client.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Adapter } from "./adapters/core.js";
|
|
1
|
+
import type { Adapter, ExecuteScriptOptions } from "./adapters/core.js";
|
|
2
2
|
import type {
|
|
3
3
|
CreateParams,
|
|
4
4
|
CreateResponse,
|
|
@@ -80,6 +80,7 @@ function DataApi<
|
|
|
80
80
|
update,
|
|
81
81
|
layoutMetadata,
|
|
82
82
|
containerUpload,
|
|
83
|
+
executeScript,
|
|
83
84
|
...otherMethods
|
|
84
85
|
} = options.adapter;
|
|
85
86
|
|
|
@@ -126,6 +127,8 @@ function DataApi<
|
|
|
126
127
|
timeout?: number;
|
|
127
128
|
};
|
|
128
129
|
|
|
130
|
+
type ExecuteScriptArgs = Omit<ExecuteScriptOptions, "layout">;
|
|
131
|
+
|
|
129
132
|
/**
|
|
130
133
|
* List all records from a given layout, no find criteria applied.
|
|
131
134
|
*/
|
|
@@ -516,6 +519,13 @@ function DataApi<
|
|
|
516
519
|
return result;
|
|
517
520
|
}
|
|
518
521
|
|
|
522
|
+
async function _executeScript(args: ExecuteScriptArgs & FetchOptions) {
|
|
523
|
+
return await executeScript({
|
|
524
|
+
...args,
|
|
525
|
+
layout,
|
|
526
|
+
});
|
|
527
|
+
}
|
|
528
|
+
|
|
519
529
|
return {
|
|
520
530
|
...otherMethods,
|
|
521
531
|
layout: options.layout as Opts["layout"],
|
|
@@ -532,6 +542,7 @@ function DataApi<
|
|
|
532
542
|
findAll,
|
|
533
543
|
layoutMetadata: _layoutMetadata,
|
|
534
544
|
containerUpload: _containerUpload,
|
|
545
|
+
executeScript: _executeScript,
|
|
535
546
|
};
|
|
536
547
|
}
|
|
537
548
|
|