@proofkit/fmdapi 5.0.3-beta.0 → 5.0.3-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/dist/esm/adapters/core.d.ts +4 -4
  2. package/dist/esm/adapters/fetch-base-types.d.ts +4 -4
  3. package/dist/esm/adapters/fetch-base.d.ts +2 -2
  4. package/dist/esm/adapters/fetch-base.js +36 -49
  5. package/dist/esm/adapters/fetch-base.js.map +1 -1
  6. package/dist/esm/adapters/fetch.d.ts +5 -5
  7. package/dist/esm/adapters/fetch.js +11 -10
  8. package/dist/esm/adapters/fetch.js.map +1 -1
  9. package/dist/esm/adapters/otto.d.ts +2 -2
  10. package/dist/esm/adapters/otto.js +3 -5
  11. package/dist/esm/adapters/otto.js.map +1 -1
  12. package/dist/esm/client-types.d.ts +41 -41
  13. package/dist/esm/client-types.js +1 -6
  14. package/dist/esm/client-types.js.map +1 -1
  15. package/dist/esm/client.d.ts +27 -43
  16. package/dist/esm/client.js +75 -80
  17. package/dist/esm/client.js.map +1 -1
  18. package/dist/esm/index.d.ts +4 -6
  19. package/dist/esm/index.js +5 -5
  20. package/dist/esm/tokenStore/index.d.ts +1 -1
  21. package/dist/esm/tokenStore/types.d.ts +2 -2
  22. package/dist/esm/tokenStore/upstash.d.ts +1 -1
  23. package/dist/esm/utils.d.ts +7 -7
  24. package/dist/esm/utils.js +6 -4
  25. package/dist/esm/utils.js.map +1 -1
  26. package/package.json +11 -13
  27. package/src/adapters/core.ts +6 -9
  28. package/src/adapters/fetch-base-types.ts +5 -3
  29. package/src/adapters/fetch-base.ts +53 -78
  30. package/src/adapters/fetch.ts +19 -24
  31. package/src/adapters/otto.ts +8 -8
  32. package/src/client-types.ts +59 -83
  33. package/src/client.ts +131 -167
  34. package/src/index.ts +4 -9
  35. package/src/tokenStore/file.ts +2 -4
  36. package/src/tokenStore/index.ts +1 -1
  37. package/src/tokenStore/types.ts +2 -2
  38. package/src/tokenStore/upstash.ts +2 -5
  39. package/src/utils.ts +16 -23
@@ -1,9 +1,9 @@
1
- import { CreateParams, CreateResponse, DeleteParams, DeleteResponse, FieldData, GetParams, GetResponse, ListParamsRaw, LayoutMetadataResponse, Query, UpdateParams, UpdateResponse, ScriptResponse } from '../client-types.js';
2
- export type BaseRequest = {
1
+ import { CreateParams, CreateResponse, DeleteParams, DeleteResponse, FieldData, GetParams, GetResponse, LayoutMetadataResponse, ListParamsRaw, Query, ScriptResponse, UpdateParams, UpdateResponse } from '../client-types.js';
2
+ export interface BaseRequest {
3
3
  layout: string;
4
4
  fetch?: RequestInit;
5
5
  timeout?: number;
6
- };
6
+ }
7
7
  export type ListOptions = BaseRequest & {
8
8
  data: ListParamsRaw;
9
9
  };
@@ -14,7 +14,7 @@ export type GetOptions = BaseRequest & {
14
14
  };
15
15
  export type FindOptions = BaseRequest & {
16
16
  data: ListParamsRaw & {
17
- query: Array<Query>;
17
+ query: Query[];
18
18
  };
19
19
  };
20
20
  export type CreateOptions = BaseRequest & {
@@ -1,7 +1,7 @@
1
- export type BaseFetchAdapterOptions = {
1
+ export interface BaseFetchAdapterOptions {
2
2
  server: string;
3
3
  db: string;
4
- };
5
- export type GetTokenArguments = {
4
+ }
5
+ export interface GetTokenArguments {
6
6
  refresh?: boolean;
7
- };
7
+ }
@@ -4,12 +4,12 @@ import { BaseFetchAdapterOptions, GetTokenArguments } from './fetch-base-types.j
4
4
  export declare class BaseFetchAdapter implements Adapter {
5
5
  protected server: string;
6
6
  protected db: string;
7
- private refreshToken;
7
+ private readonly refreshToken;
8
8
  baseUrl: URL;
9
9
  constructor(options: BaseFetchAdapterOptions & {
10
10
  refreshToken?: boolean;
11
11
  });
12
- protected getToken: (args?: GetTokenArguments) => Promise<string>;
12
+ protected getToken: (_args?: GetTokenArguments) => Promise<string>;
13
13
  protected request: (params: {
14
14
  url: string;
15
15
  body?: object | FormData;
@@ -8,33 +8,22 @@ class BaseFetchAdapter {
8
8
  __publicField(this, "db");
9
9
  __publicField(this, "refreshToken");
10
10
  __publicField(this, "baseUrl");
11
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
12
- __publicField(this, "getToken", async (args) => {
13
- throw new Error("getToken method not implemented by Fetch Adapter");
11
+ __publicField(this, "getToken", (_args) => {
12
+ return Promise.reject(new Error("getToken method not implemented by Fetch Adapter"));
14
13
  });
15
14
  __publicField(this, "request", async (params) => {
16
15
  var _a, _b;
17
- const {
18
- query,
19
- body,
20
- method = "GET",
21
- retry = false,
22
- fetchOptions = {}
23
- } = params;
16
+ const { query, body, method = "GET", retry = false, fetchOptions = {} } = params;
24
17
  const url = new URL(`${this.baseUrl}${params.url}`);
25
18
  if (query) {
26
19
  const { _sort, ...rest } = query;
27
- const searchParams = new URLSearchParams(rest);
20
+ const filteredRest = Object.fromEntries(Object.entries(rest).filter(([, v]) => v !== void 0 && v !== null));
21
+ const searchParams = new URLSearchParams(filteredRest);
28
22
  if (query.portalRanges && typeof query.portalRanges === "object") {
29
- for (const [portalName, value] of Object.entries(
30
- query.portalRanges
31
- )) {
23
+ for (const [portalName, value] of Object.entries(query.portalRanges)) {
32
24
  if (value) {
33
25
  if (value.offset && value.offset > 0) {
34
- searchParams.set(
35
- `_offset.${portalName}`,
36
- value.offset.toString()
37
- );
26
+ searchParams.set(`_offset.${portalName}`, value.offset.toString());
38
27
  }
39
28
  if (value.limit) {
40
29
  searchParams.set(`_limit.${portalName}`, value.limit.toString());
@@ -49,46 +38,47 @@ class BaseFetchAdapter {
49
38
  url.search = searchParams.toString();
50
39
  }
51
40
  if (body && "portalRanges" in body) {
52
- for (const [portalName, value] of Object.entries(
53
- body.portalRanges
54
- )) {
41
+ for (const [portalName, value] of Object.entries(body.portalRanges)) {
55
42
  if (value) {
56
43
  if (value.offset && value.offset > 0) {
57
- url.searchParams.set(
58
- `_offset.${portalName}`,
59
- value.offset.toString()
60
- );
44
+ url.searchParams.set(`_offset.${portalName}`, value.offset.toString());
61
45
  }
62
46
  if (value.limit) {
63
- url.searchParams.set(
64
- `_limit.${portalName}`,
65
- value.limit.toString()
66
- );
47
+ url.searchParams.set(`_limit.${portalName}`, value.limit.toString());
67
48
  }
68
49
  }
69
50
  }
70
- delete body.portalRanges;
51
+ body.portalRanges = void 0;
71
52
  }
72
53
  const controller = new AbortController();
73
54
  let timeout = null;
74
- if (params.timeout)
55
+ if (params.timeout) {
75
56
  timeout = setTimeout(() => controller.abort(), params.timeout);
57
+ }
76
58
  const token = await this.getToken({ refresh: retry });
77
59
  const headers = new Headers(fetchOptions == null ? void 0 : fetchOptions.headers);
78
60
  headers.set("Authorization", `Bearer ${token}`);
79
61
  if (!(body instanceof FormData)) {
80
62
  headers.set("Content-Type", "application/json");
81
63
  }
64
+ let requestBody;
65
+ if (body instanceof FormData) {
66
+ requestBody = body;
67
+ } else if (body) {
68
+ requestBody = JSON.stringify(body);
69
+ } else {
70
+ requestBody = void 0;
71
+ }
82
72
  const res = await fetch(url.toString(), {
83
73
  ...fetchOptions,
84
74
  method,
85
- body: body instanceof FormData ? body : body ? JSON.stringify(body) : void 0,
75
+ body: requestBody,
86
76
  headers,
87
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
88
- // @ts-ignore
89
77
  signal: controller.signal
90
78
  });
91
- if (timeout) clearTimeout(timeout);
79
+ if (timeout) {
80
+ clearTimeout(timeout);
81
+ }
92
82
  let respData;
93
83
  try {
94
84
  respData = await res.json();
@@ -98,16 +88,11 @@ class BaseFetchAdapter {
98
88
  if (!res.ok) {
99
89
  if (((_a = respData == null ? void 0 : respData.messages) == null ? void 0 : _a[0].code) === "952" && !retry && this.refreshToken) {
100
90
  return this.request({ ...params, retry: true });
101
- } else {
102
- throw new FileMakerError(
103
- ((_b = respData == null ? void 0 : respData.messages) == null ? void 0 : _b[0].code) ?? "500",
104
- `Filemaker Data API failed with (${res.status}): ${JSON.stringify(
105
- respData,
106
- null,
107
- 2
108
- )}`
109
- );
110
91
  }
92
+ throw new FileMakerError(
93
+ ((_b = respData == null ? void 0 : respData.messages) == null ? void 0 : _b[0].code) ?? "500",
94
+ `Filemaker Data API failed with (${res.status}): ${JSON.stringify(respData, null, 2)}`
95
+ );
111
96
  }
112
97
  return respData.response;
113
98
  });
@@ -218,7 +203,9 @@ class BaseFetchAdapter {
218
203
  });
219
204
  __publicField(this, "containerUpload", async (opts) => {
220
205
  let url = `/layouts/${opts.layout}/records/${opts.data.recordId}/containers/${opts.data.containerFieldName}`;
221
- if (opts.data.repetition) url += `/${opts.data.repetition}`;
206
+ if (opts.data.repetition) {
207
+ url += `/${opts.data.repetition}`;
208
+ }
222
209
  const formData = new FormData();
223
210
  formData.append("upload", opts.data.file);
224
211
  await this.request({
@@ -244,10 +231,10 @@ class BaseFetchAdapter {
244
231
  this.server = options.server;
245
232
  this.db = options.db;
246
233
  this.refreshToken = options.refreshToken ?? false;
247
- this.baseUrl = new URL(
248
- `${this.server}/fmi/data/vLatest/databases/${this.db}`
249
- );
250
- if (this.db === "") throw new Error("Database name is required");
234
+ this.baseUrl = new URL(`${this.server}/fmi/data/vLatest/databases/${this.db}`);
235
+ if (this.db === "") {
236
+ throw new Error("Database name is required");
237
+ }
251
238
  }
252
239
  }
253
240
  export {
@@ -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 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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"}
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 { BaseFetchAdapterOptions, GetTokenArguments } from \"./fetch-base-types.js\";\n\nexport class BaseFetchAdapter implements Adapter {\n protected server: string;\n protected db: string;\n private readonly 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(`${this.server}/fmi/data/vLatest/databases/${this.db}`);\n\n if (this.db === \"\") {\n throw new Error(\"Database name is required\");\n }\n }\n\n protected getToken = (_args?: GetTokenArguments): Promise<string> => {\n // method must be implemented in subclass\n return Promise.reject(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 { query, body, method = \"GET\", retry = false, fetchOptions = {} } = params;\n\n const url = new URL(`${this.baseUrl}${params.url}`);\n\n if (query) {\n const { _sort, ...rest } = query;\n // Filter out undefined/null values before creating URLSearchParams\n const filteredRest = Object.fromEntries(Object.entries(rest).filter(([, v]) => v !== undefined && v !== null));\n const searchParams = new URLSearchParams(filteredRest as Record<string, string>);\n if (query.portalRanges && typeof query.portalRanges === \"object\") {\n for (const [portalName, value] of Object.entries(query.portalRanges as PortalRanges)) {\n if (value) {\n if (value.offset && value.offset > 0) {\n searchParams.set(`_offset.${portalName}`, value.offset.toString());\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(body.portalRanges as PortalRanges)) {\n if (value) {\n if (value.offset && value.offset > 0) {\n url.searchParams.set(`_offset.${portalName}`, value.offset.toString());\n }\n if (value.limit) {\n url.searchParams.set(`_limit.${portalName}`, value.limit.toString());\n }\n }\n }\n body.portalRanges = undefined;\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\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 let requestBody: string | FormData | undefined;\n if (body instanceof FormData) {\n requestBody = body;\n } else if (body) {\n requestBody = JSON.stringify(body);\n } else {\n requestBody = undefined;\n }\n\n const res = await fetch(url.toString(), {\n ...fetchOptions,\n method,\n body: requestBody,\n headers,\n signal: controller.signal,\n });\n\n if (timeout) {\n clearTimeout(timeout);\n }\n\n let respData: RawFMResponse;\n try {\n respData = await res.json();\n } catch {\n respData = {};\n }\n\n if (!res.ok) {\n if (respData?.messages?.[0].code === \"952\" && !retry && this.refreshToken) {\n // token expired, get new token and retry once\n return this.request({ ...params, retry: true });\n }\n throw new FileMakerError(\n respData?.messages?.[0].code ?? \"500\",\n `Filemaker Data API failed with (${res.status}): ${JSON.stringify(respData, null, 2)}`,\n );\n }\n\n return respData.response;\n };\n\n 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 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 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 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 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 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 layoutMetadata = async (opts: LayoutMetadataOptions): 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 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 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 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 containerUpload = async (opts: ContainerUploadOptions) => {\n let url = `/layouts/${opts.layout}/records/${opts.data.recordId}/containers/${opts.data.containerFieldName}`;\n if (opts.data.repetition) {\n url += `/${opts.data.repetition}`;\n }\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 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,6 +1,6 @@
1
1
  import { TokenStoreDefinitions } from '../tokenStore/types.js';
2
- import { BaseFetchAdapterOptions, GetTokenArguments } from './fetch-base-types.js';
3
2
  import { BaseFetchAdapter } from './fetch-base.js';
3
+ import { BaseFetchAdapterOptions, GetTokenArguments } from './fetch-base-types.js';
4
4
  export interface FetchAdapterOptions extends BaseFetchAdapterOptions {
5
5
  auth: {
6
6
  username: string;
@@ -9,10 +9,10 @@ export interface FetchAdapterOptions extends BaseFetchAdapterOptions {
9
9
  tokenStore?: TokenStoreDefinitions;
10
10
  }
11
11
  export declare class FetchAdapter extends BaseFetchAdapter {
12
- private username;
13
- private password;
14
- private tokenStore;
15
- private getTokenKey;
12
+ private readonly username;
13
+ private readonly password;
14
+ private readonly tokenStore;
15
+ private readonly getTokenKey;
16
16
  constructor(args: FetchAdapterOptions);
17
17
  /**
18
18
  * Gets a FileMaker Data API token for authentication.
@@ -31,20 +31,17 @@ class FetchAdapter extends BaseFetchAdapter {
31
31
  method: "POST",
32
32
  headers: {
33
33
  "Content-Type": "application/json",
34
- Authorization: `Basic ${Buffer.from(
35
- `${this.username}:${this.password}`
36
- ).toString("base64")}`
34
+ Authorization: `Basic ${Buffer.from(`${this.username}:${this.password}`).toString("base64")}`
37
35
  }
38
36
  });
39
37
  if (!res.ok) {
40
38
  const data = await res.json();
41
- throw new FileMakerError(
42
- data.messages[0].code,
43
- data.messages[0].message
44
- );
39
+ throw new FileMakerError(data.messages[0].code, data.messages[0].message);
45
40
  }
46
41
  token = res.headers.get("X-FM-Data-Access-Token");
47
- if (!token) throw new Error("Could not get token");
42
+ if (!token) {
43
+ throw new Error("Could not get token");
44
+ }
48
45
  this.tokenStore.setToken(this.getTokenKey(), token);
49
46
  }
50
47
  return token;
@@ -69,8 +66,12 @@ class FetchAdapter extends BaseFetchAdapter {
69
66
  this.password = args.auth.password;
70
67
  this.tokenStore = args.tokenStore ?? memoryStore();
71
68
  this.getTokenKey = ((_a = args.tokenStore) == null ? void 0 : _a.getKey) ?? (() => `${args.server}/${args.db}`);
72
- if (this.username === "") throw new Error("Username is required");
73
- if (this.password === "") throw new Error("Password is required");
69
+ if (this.username === "") {
70
+ throw new Error("Username is required");
71
+ }
72
+ if (this.password === "") {
73
+ throw new Error("Password is required");
74
+ }
74
75
  }
75
76
  }
76
77
  export {
@@ -1 +1 @@
1
- {"version":3,"file":"fetch.js","sources":["../../../src/adapters/fetch.ts"],"sourcesContent":["import { FileMakerError } from \"../client-types.js\";\nimport memoryStore from \"../tokenStore/memory.js\";\nimport type { TokenStoreDefinitions } from \"../tokenStore/types.js\";\nimport type {\n BaseFetchAdapterOptions,\n GetTokenArguments,\n} from \"./fetch-base-types.js\";\nimport { BaseFetchAdapter } from \"./fetch-base.js\";\n\nexport interface FetchAdapterOptions extends BaseFetchAdapterOptions {\n auth: {\n username: string;\n password: string;\n };\n tokenStore?: TokenStoreDefinitions;\n}\n\nexport class FetchAdapter extends BaseFetchAdapter {\n private username: string;\n private password: string;\n private tokenStore: Omit<TokenStoreDefinitions, \"getKey\">;\n private getTokenKey: Required<TokenStoreDefinitions>[\"getKey\"];\n\n constructor(args: FetchAdapterOptions) {\n super({ ...args, refreshToken: true });\n this.username = args.auth.username;\n this.password = args.auth.password;\n this.tokenStore = args.tokenStore ?? memoryStore();\n this.getTokenKey =\n args.tokenStore?.getKey ?? (() => `${args.server}/${args.db}`);\n\n if (this.username === \"\") throw new Error(\"Username is required\");\n if (this.password === \"\") throw new Error(\"Password is required\");\n }\n\n /**\n * Gets a FileMaker Data API token for authentication.\n *\n * This token is **NOT** guaranteed to be valid, since it expires 15 minutes after the last use. Pass `refresh=true` to forcibly get a fresh token\n *\n * @param args.refresh - If true, forces getting a new token instead of using cached token\n * @internal This method is intended for internal use, you should not need to use it in most cases.\n */\n public override getToken = async (\n args?: GetTokenArguments,\n ): Promise<string> => {\n const { refresh = false } = args ?? {};\n let token: string | null = null;\n if (!refresh) {\n token = await this.tokenStore.getToken(this.getTokenKey());\n }\n\n if (!token) {\n const res = await fetch(`${this.baseUrl}/sessions`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Basic ${Buffer.from(\n `${this.username}:${this.password}`,\n ).toString(\"base64\")}`,\n },\n });\n\n if (!res.ok) {\n const data = await res.json();\n throw new FileMakerError(\n data.messages[0].code,\n data.messages[0].message,\n );\n }\n token = res.headers.get(\"X-FM-Data-Access-Token\");\n if (!token) throw new Error(\"Could not get token\");\n this.tokenStore.setToken(this.getTokenKey(), token);\n }\n\n return token;\n };\n\n public disconnect = async (): Promise<void> => {\n const token = await this.tokenStore.getToken(this.getTokenKey());\n if (token) {\n await this.request({\n url: `/sessions/${token}`,\n method: \"DELETE\",\n fetchOptions: {\n headers: {\n Authorization: `Bearer ${token}`,\n \"Content-Type\": \"application/json\",\n },\n },\n });\n this.tokenStore.clearToken(this.getTokenKey());\n }\n };\n}\n"],"names":[],"mappings":";;;;;;AAiBO,MAAM,qBAAqB,iBAAiB;AAAA,EAMjD,YAAY,MAA2B;;AACrC,UAAM,EAAE,GAAG,MAAM,cAAc,MAAM;AAN/B;AACA;AACA;AACA;AAsBQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,oCAAW,OACzB,SACoB;AACpB,YAAM,EAAE,UAAU,MAAM,IAAI,QAAQ,CAAC;AACrC,UAAI,QAAuB;AAC3B,UAAI,CAAC,SAAS;AACZ,gBAAQ,MAAM,KAAK,WAAW,SAAS,KAAK,aAAa;AAAA,MAAA;AAG3D,UAAI,CAAC,OAAO;AACV,cAAM,MAAM,MAAM,MAAM,GAAG,KAAK,OAAO,aAAa;AAAA,UAClD,QAAQ;AAAA,UACR,SAAS;AAAA,YACP,gBAAgB;AAAA,YAChB,eAAe,SAAS,OAAO;AAAA,cAC7B,GAAG,KAAK,QAAQ,IAAI,KAAK,QAAQ;AAAA,YAAA,EACjC,SAAS,QAAQ,CAAC;AAAA,UAAA;AAAA,QACtB,CACD;AAEG,YAAA,CAAC,IAAI,IAAI;AACL,gBAAA,OAAO,MAAM,IAAI,KAAK;AAC5B,gBAAM,IAAI;AAAA,YACR,KAAK,SAAS,CAAC,EAAE;AAAA,YACjB,KAAK,SAAS,CAAC,EAAE;AAAA,UACnB;AAAA,QAAA;AAEM,gBAAA,IAAI,QAAQ,IAAI,wBAAwB;AAChD,YAAI,CAAC,MAAa,OAAA,IAAI,MAAM,qBAAqB;AACjD,aAAK,WAAW,SAAS,KAAK,YAAA,GAAe,KAAK;AAAA,MAAA;AAG7C,aAAA;AAAA,IACT;AAEO,sCAAa,YAA2B;AAC7C,YAAM,QAAQ,MAAM,KAAK,WAAW,SAAS,KAAK,aAAa;AAC/D,UAAI,OAAO;AACT,cAAM,KAAK,QAAQ;AAAA,UACjB,KAAK,aAAa,KAAK;AAAA,UACvB,QAAQ;AAAA,UACR,cAAc;AAAA,YACZ,SAAS;AAAA,cACP,eAAe,UAAU,KAAK;AAAA,cAC9B,gBAAgB;AAAA,YAAA;AAAA,UAClB;AAAA,QACF,CACD;AACD,aAAK,WAAW,WAAW,KAAK,YAAA,CAAa;AAAA,MAAA;AAAA,IAEjD;AApEO,SAAA,WAAW,KAAK,KAAK;AACrB,SAAA,WAAW,KAAK,KAAK;AACrB,SAAA,aAAa,KAAK,cAAc,YAAY;AAC5C,SAAA,gBACH,UAAK,eAAL,mBAAiB,YAAW,MAAM,GAAG,KAAK,MAAM,IAAI,KAAK,EAAE;AAE7D,QAAI,KAAK,aAAa,GAAU,OAAA,IAAI,MAAM,sBAAsB;AAChE,QAAI,KAAK,aAAa,GAAU,OAAA,IAAI,MAAM,sBAAsB;AAAA,EAAA;AA8DpE;"}
1
+ {"version":3,"file":"fetch.js","sources":["../../../src/adapters/fetch.ts"],"sourcesContent":["import { FileMakerError } from \"../client-types.js\";\nimport memoryStore from \"../tokenStore/memory.js\";\nimport type { TokenStoreDefinitions } from \"../tokenStore/types.js\";\nimport { BaseFetchAdapter } from \"./fetch-base.js\";\nimport type { BaseFetchAdapterOptions, GetTokenArguments } from \"./fetch-base-types.js\";\n\nexport interface FetchAdapterOptions extends BaseFetchAdapterOptions {\n auth: {\n username: string;\n password: string;\n };\n tokenStore?: TokenStoreDefinitions;\n}\n\nexport class FetchAdapter extends BaseFetchAdapter {\n private readonly username: string;\n private readonly password: string;\n private readonly tokenStore: Omit<TokenStoreDefinitions, \"getKey\">;\n private readonly getTokenKey: Required<TokenStoreDefinitions>[\"getKey\"];\n\n constructor(args: FetchAdapterOptions) {\n super({ ...args, refreshToken: true });\n this.username = args.auth.username;\n this.password = args.auth.password;\n this.tokenStore = args.tokenStore ?? memoryStore();\n this.getTokenKey = args.tokenStore?.getKey ?? (() => `${args.server}/${args.db}`);\n\n if (this.username === \"\") {\n throw new Error(\"Username is required\");\n }\n if (this.password === \"\") {\n throw new Error(\"Password is required\");\n }\n }\n\n /**\n * Gets a FileMaker Data API token for authentication.\n *\n * This token is **NOT** guaranteed to be valid, since it expires 15 minutes after the last use. Pass `refresh=true` to forcibly get a fresh token\n *\n * @param args.refresh - If true, forces getting a new token instead of using cached token\n * @internal This method is intended for internal use, you should not need to use it in most cases.\n */\n override getToken = async (args?: GetTokenArguments): Promise<string> => {\n const { refresh = false } = args ?? {};\n let token: string | null = null;\n if (!refresh) {\n token = await this.tokenStore.getToken(this.getTokenKey());\n }\n\n if (!token) {\n const res = await fetch(`${this.baseUrl}/sessions`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Basic ${Buffer.from(`${this.username}:${this.password}`).toString(\"base64\")}`,\n },\n });\n\n if (!res.ok) {\n const data = await res.json();\n throw new FileMakerError(data.messages[0].code, data.messages[0].message);\n }\n token = res.headers.get(\"X-FM-Data-Access-Token\");\n if (!token) {\n throw new Error(\"Could not get token\");\n }\n this.tokenStore.setToken(this.getTokenKey(), token);\n }\n\n return token;\n };\n\n disconnect = async (): Promise<void> => {\n const token = await this.tokenStore.getToken(this.getTokenKey());\n if (token) {\n await this.request({\n url: `/sessions/${token}`,\n method: \"DELETE\",\n fetchOptions: {\n headers: {\n Authorization: `Bearer ${token}`,\n \"Content-Type\": \"application/json\",\n },\n },\n });\n this.tokenStore.clearToken(this.getTokenKey());\n }\n };\n}\n"],"names":[],"mappings":";;;;;;AAcO,MAAM,qBAAqB,iBAAiB;AAAA,EAMjD,YAAY,MAA2B;;AACrC,UAAM,EAAE,GAAG,MAAM,cAAc,MAAM;AANtB;AACA;AACA;AACA;AAyBR;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,oCAAW,OAAO,SAA8C;AACvE,YAAM,EAAE,UAAU,MAAM,IAAI,QAAQ,CAAC;AACrC,UAAI,QAAuB;AAC3B,UAAI,CAAC,SAAS;AACZ,gBAAQ,MAAM,KAAK,WAAW,SAAS,KAAK,aAAa;AAAA,MAAA;AAG3D,UAAI,CAAC,OAAO;AACV,cAAM,MAAM,MAAM,MAAM,GAAG,KAAK,OAAO,aAAa;AAAA,UAClD,QAAQ;AAAA,UACR,SAAS;AAAA,YACP,gBAAgB;AAAA,YAChB,eAAe,SAAS,OAAO,KAAK,GAAG,KAAK,QAAQ,IAAI,KAAK,QAAQ,EAAE,EAAE,SAAS,QAAQ,CAAC;AAAA,UAAA;AAAA,QAC7F,CACD;AAEG,YAAA,CAAC,IAAI,IAAI;AACL,gBAAA,OAAO,MAAM,IAAI,KAAK;AACtB,gBAAA,IAAI,eAAe,KAAK,SAAS,CAAC,EAAE,MAAM,KAAK,SAAS,CAAC,EAAE,OAAO;AAAA,QAAA;AAElE,gBAAA,IAAI,QAAQ,IAAI,wBAAwB;AAChD,YAAI,CAAC,OAAO;AACJ,gBAAA,IAAI,MAAM,qBAAqB;AAAA,QAAA;AAEvC,aAAK,WAAW,SAAS,KAAK,YAAA,GAAe,KAAK;AAAA,MAAA;AAG7C,aAAA;AAAA,IACT;AAEA,sCAAa,YAA2B;AACtC,YAAM,QAAQ,MAAM,KAAK,WAAW,SAAS,KAAK,aAAa;AAC/D,UAAI,OAAO;AACT,cAAM,KAAK,QAAQ;AAAA,UACjB,KAAK,aAAa,KAAK;AAAA,UACvB,QAAQ;AAAA,UACR,cAAc;AAAA,YACZ,SAAS;AAAA,cACP,eAAe,UAAU,KAAK;AAAA,cAC9B,gBAAgB;AAAA,YAAA;AAAA,UAClB;AAAA,QACF,CACD;AACD,aAAK,WAAW,WAAW,KAAK,YAAA,CAAa;AAAA,MAAA;AAAA,IAEjD;AAlEO,SAAA,WAAW,KAAK,KAAK;AACrB,SAAA,WAAW,KAAK,KAAK;AACrB,SAAA,aAAa,KAAK,cAAc,YAAY;AAC5C,SAAA,gBAAc,UAAK,eAAL,mBAAiB,YAAW,MAAM,GAAG,KAAK,MAAM,IAAI,KAAK,EAAE;AAE1E,QAAA,KAAK,aAAa,IAAI;AAClB,YAAA,IAAI,MAAM,sBAAsB;AAAA,IAAA;AAEpC,QAAA,KAAK,aAAa,IAAI;AAClB,YAAA,IAAI,MAAM,sBAAsB;AAAA,IAAA;AAAA,EACxC;AAyDJ;"}
@@ -18,8 +18,8 @@ export type OttoAdapterOptions = BaseFetchAdapterOptions & {
18
18
  auth: OttoAuth;
19
19
  };
20
20
  export declare class OttoAdapter extends BaseFetchAdapter {
21
- private apiKey;
22
- private port;
21
+ private readonly apiKey;
22
+ private readonly port;
23
23
  constructor(options: OttoAdapterOptions);
24
24
  protected getToken: () => Promise<string>;
25
25
  }
@@ -7,8 +7,8 @@ class OttoAdapter extends BaseFetchAdapter {
7
7
  super({ ...options, refreshToken: false });
8
8
  __publicField(this, "apiKey");
9
9
  __publicField(this, "port");
10
- __publicField(this, "getToken", async () => {
11
- return this.apiKey;
10
+ __publicField(this, "getToken", () => {
11
+ return Promise.resolve(this.apiKey);
12
12
  });
13
13
  this.apiKey = options.auth.apiKey;
14
14
  this.port = options.auth.ottoPort;
@@ -17,9 +17,7 @@ class OttoAdapter extends BaseFetchAdapter {
17
17
  } else if (this.apiKey.startsWith("dk_")) {
18
18
  this.baseUrl.pathname = `otto/${this.baseUrl.pathname.replace(/^\/+|\/+$/g, "")}`;
19
19
  } else {
20
- throw new Error(
21
- "Invalid Otto API key format. Must start with 'KEY_' (Otto v3) or 'dk_' (OttoFMS)"
22
- );
20
+ throw new Error("Invalid Otto API key format. Must start with 'KEY_' (Otto v3) or 'dk_' (OttoFMS)");
23
21
  }
24
22
  }
25
23
  }
@@ -1 +1 @@
1
- {"version":3,"file":"otto.js","sources":["../../../src/adapters/otto.ts"],"sourcesContent":["import { BaseFetchAdapter } from \"./fetch-base.js\";\nimport type { BaseFetchAdapterOptions } from \"./fetch-base-types.js\";\n\nexport type Otto3APIKey = `KEY_${string}`;\nexport type OttoFMSAPIKey = `dk_${string}`;\nexport type OttoAPIKey = Otto3APIKey | OttoFMSAPIKey;\n\nexport function isOtto3APIKey(key: string): key is Otto3APIKey {\n return key.startsWith(\"KEY_\");\n}\nexport function isOttoFMSAPIKey(key: string): key is OttoFMSAPIKey {\n return key.startsWith(\"dk_\");\n}\nexport function isOttoAPIKey(key: string): key is OttoAPIKey {\n return isOtto3APIKey(key) || isOttoFMSAPIKey(key);\n}\n\nexport function isOttoAuth(auth: unknown): auth is OttoAuth {\n if (typeof auth !== \"object\" || auth === null) return false;\n return \"apiKey\" in auth;\n}\n\ntype OttoAuth =\n | {\n apiKey: Otto3APIKey;\n ottoPort?: number;\n }\n | { apiKey: OttoFMSAPIKey; ottoPort?: never };\n\nexport type OttoAdapterOptions = BaseFetchAdapterOptions & {\n auth: OttoAuth;\n};\n\nexport class OttoAdapter extends BaseFetchAdapter {\n private apiKey: OttoAPIKey | Otto3APIKey;\n private port: number | undefined;\n\n constructor(options: OttoAdapterOptions) {\n super({ ...options, refreshToken: false });\n this.apiKey = options.auth.apiKey;\n this.port = options.auth.ottoPort;\n\n if (this.apiKey.startsWith(\"KEY_\")) {\n // otto v3 uses port 3030\n this.baseUrl.port = (this.port ?? 3030).toString();\n } else if (this.apiKey.startsWith(\"dk_\")) {\n // otto v4 uses default port, but with /otto prefix\n this.baseUrl.pathname = `otto/${this.baseUrl.pathname.replace(/^\\/+|\\/+$/g, \"\")}`;\n } else {\n throw new Error(\n \"Invalid Otto API key format. Must start with 'KEY_' (Otto v3) or 'dk_' (OttoFMS)\",\n );\n }\n }\n\n protected override getToken = async (): Promise<string> => {\n return this.apiKey;\n };\n}\n"],"names":[],"mappings":";;;;AAiCO,MAAM,oBAAoB,iBAAiB;AAAA,EAIhD,YAAY,SAA6B;AACvC,UAAM,EAAE,GAAG,SAAS,cAAc,OAAO;AAJnC;AACA;AAoBW,oCAAW,YAA6B;AACzD,aAAO,KAAK;AAAA,IACd;AAlBO,SAAA,SAAS,QAAQ,KAAK;AACtB,SAAA,OAAO,QAAQ,KAAK;AAEzB,QAAI,KAAK,OAAO,WAAW,MAAM,GAAG;AAElC,WAAK,QAAQ,QAAQ,KAAK,QAAQ,MAAM,SAAS;AAAA,IACxC,WAAA,KAAK,OAAO,WAAW,KAAK,GAAG;AAEnC,WAAA,QAAQ,WAAW,QAAQ,KAAK,QAAQ,SAAS,QAAQ,cAAc,EAAE,CAAC;AAAA,IAAA,OAC1E;AACL,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,IAAA;AAAA,EACF;AAMJ;"}
1
+ {"version":3,"file":"otto.js","sources":["../../../src/adapters/otto.ts"],"sourcesContent":["import { BaseFetchAdapter } from \"./fetch-base.js\";\nimport type { BaseFetchAdapterOptions } from \"./fetch-base-types.js\";\n\nexport type Otto3APIKey = `KEY_${string}`;\nexport type OttoFMSAPIKey = `dk_${string}`;\nexport type OttoAPIKey = Otto3APIKey | OttoFMSAPIKey;\n\nexport function isOtto3APIKey(key: string): key is Otto3APIKey {\n return key.startsWith(\"KEY_\");\n}\nexport function isOttoFMSAPIKey(key: string): key is OttoFMSAPIKey {\n return key.startsWith(\"dk_\");\n}\nexport function isOttoAPIKey(key: string): key is OttoAPIKey {\n return isOtto3APIKey(key) || isOttoFMSAPIKey(key);\n}\n\nexport function isOttoAuth(auth: unknown): auth is OttoAuth {\n if (typeof auth !== \"object\" || auth === null) {\n return false;\n }\n return \"apiKey\" in auth;\n}\n\ntype OttoAuth =\n | {\n apiKey: Otto3APIKey;\n ottoPort?: number;\n }\n | { apiKey: OttoFMSAPIKey; ottoPort?: never };\n\nexport type OttoAdapterOptions = BaseFetchAdapterOptions & {\n auth: OttoAuth;\n};\n\nexport class OttoAdapter extends BaseFetchAdapter {\n private readonly apiKey: OttoAPIKey | Otto3APIKey;\n private readonly port: number | undefined;\n\n constructor(options: OttoAdapterOptions) {\n super({ ...options, refreshToken: false });\n this.apiKey = options.auth.apiKey;\n this.port = options.auth.ottoPort;\n\n if (this.apiKey.startsWith(\"KEY_\")) {\n // otto v3 uses port 3030\n this.baseUrl.port = (this.port ?? 3030).toString();\n } else if (this.apiKey.startsWith(\"dk_\")) {\n // otto v4 uses default port, but with /otto prefix\n this.baseUrl.pathname = `otto/${this.baseUrl.pathname.replace(/^\\/+|\\/+$/g, \"\")}`;\n } else {\n throw new Error(\"Invalid Otto API key format. Must start with 'KEY_' (Otto v3) or 'dk_' (OttoFMS)\");\n }\n }\n\n protected override getToken = (): Promise<string> => {\n return Promise.resolve(this.apiKey);\n };\n}\n"],"names":[],"mappings":";;;;AAmCO,MAAM,oBAAoB,iBAAiB;AAAA,EAIhD,YAAY,SAA6B;AACvC,UAAM,EAAE,GAAG,SAAS,cAAc,OAAO;AAJ1B;AACA;AAkBE,oCAAW,MAAuB;AAC5C,aAAA,QAAQ,QAAQ,KAAK,MAAM;AAAA,IACpC;AAhBO,SAAA,SAAS,QAAQ,KAAK;AACtB,SAAA,OAAO,QAAQ,KAAK;AAEzB,QAAI,KAAK,OAAO,WAAW,MAAM,GAAG;AAElC,WAAK,QAAQ,QAAQ,KAAK,QAAQ,MAAM,SAAS;AAAA,IACxC,WAAA,KAAK,OAAO,WAAW,KAAK,GAAG;AAEnC,WAAA,QAAQ,WAAW,QAAQ,KAAK,QAAQ,SAAS,QAAQ,cAAc,EAAE,CAAC;AAAA,IAAA,OAC1E;AACC,YAAA,IAAI,MAAM,kFAAkF;AAAA,IAAA;AAAA,EACpG;AAMJ;"}
@@ -3,11 +3,11 @@ export declare const ZFieldValue: z.ZodUnion<readonly [z.ZodString, z.ZodNumber,
3
3
  export type FieldValue = z.infer<typeof ZFieldValue>;
4
4
  export declare const ZFieldData: z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodNull, z.ZodUnknown]>>;
5
5
  export type FieldData = Record<string, unknown>;
6
- export type GenericPortalData = {
6
+ export interface GenericPortalData {
7
7
  [key: string]: {
8
8
  [x: string]: string | number | null | unknown;
9
9
  };
10
- };
10
+ }
11
11
  export type PortalsWithIds<U extends GenericPortalData = GenericPortalData> = {
12
12
  [key in keyof U]: Array<U[key] & {
13
13
  recordId: string;
@@ -20,13 +20,13 @@ export type UpdatePortalsWithIds<U extends GenericPortalData = GenericPortalData
20
20
  modId?: string;
21
21
  }>;
22
22
  };
23
- export type FMRecord<T extends FieldData = FieldData, U extends GenericPortalData = GenericPortalData> = {
23
+ export interface FMRecord<T extends FieldData = FieldData, U extends GenericPortalData = GenericPortalData> {
24
24
  fieldData: T;
25
25
  recordId: string;
26
26
  modId: string;
27
27
  portalData: PortalsWithIds<U>;
28
- };
29
- export type ScriptParams = {
28
+ }
29
+ export interface ScriptParams {
30
30
  script?: string;
31
31
  "script.param"?: string;
32
32
  "script.prerequest"?: string;
@@ -34,7 +34,7 @@ export type ScriptParams = {
34
34
  "script.presort"?: string;
35
35
  "script.presort.param"?: string;
36
36
  timeout?: number;
37
- };
37
+ }
38
38
  declare const ZScriptResponse: z.ZodObject<{
39
39
  scriptResult: z.ZodOptional<z.ZodString>;
40
40
  scriptError: z.ZodOptional<z.ZodString>;
@@ -68,36 +68,36 @@ export type UpdateResponse = ScriptResponse & {
68
68
  };
69
69
  export type DeleteParams = ScriptParams;
70
70
  export type DeleteResponse = ScriptResponse;
71
- export type RangeParams = {
71
+ export interface RangeParams {
72
72
  offset?: number;
73
73
  limit?: number;
74
- };
75
- export type RangeParamsRaw = {
74
+ }
75
+ export interface RangeParamsRaw {
76
76
  _offset?: number;
77
77
  _limit?: number;
78
- };
78
+ }
79
79
  export type PortalRanges<U extends GenericPortalData = GenericPortalData> = Partial<{
80
80
  [key in keyof U]: RangeParams;
81
81
  }>;
82
- export type PortalRangesParams<U extends GenericPortalData = GenericPortalData> = {
82
+ export interface PortalRangesParams<U extends GenericPortalData = GenericPortalData> {
83
83
  portalRanges?: PortalRanges<U>;
84
- };
84
+ }
85
85
  export type GetParams<U extends GenericPortalData = GenericPortalData> = ScriptParams & PortalRangesParams<U> & {
86
86
  "layout.response"?: string;
87
87
  dateformats?: "US" | "file_locale" | "ISO8601";
88
88
  };
89
- export type Sort<T extends FieldData = FieldData> = {
89
+ export interface Sort<T extends FieldData = FieldData> {
90
90
  fieldName: keyof T;
91
91
  sortOrder?: "ascend" | "descend" | (string & {});
92
- };
92
+ }
93
93
  export type ListParams<T extends FieldData = FieldData, U extends GenericPortalData = GenericPortalData> = GetParams<U> & RangeParams & {
94
- sort?: Sort<T> | Array<Sort<T>>;
94
+ sort?: Sort<T> | Sort<T>[];
95
95
  };
96
96
  export type ListParamsRaw<T extends FieldData = FieldData, U extends GenericPortalData = GenericPortalData> = GetParams<U> & RangeParamsRaw & {
97
- _sort?: Array<Sort<T>>;
97
+ _sort?: Sort<T>[];
98
98
  };
99
99
  export type GetResponse<T extends FieldData = FieldData, U extends GenericPortalData = GenericPortalData> = ScriptResponse & {
100
- data: Array<FMRecord<T, U>>;
100
+ data: FMRecord<T, U>[];
101
101
  dataInfo: DataInfo;
102
102
  };
103
103
  export type GetResponseOne<T extends FieldData = FieldData, U extends GenericPortalData = GenericPortalData> = ScriptResponse & {
@@ -114,25 +114,25 @@ export type Query<T extends FieldData = FieldData, U extends GenericPortalData =
114
114
  }> & {
115
115
  omit?: "true";
116
116
  };
117
- export type LayoutMetadataResponse = {
117
+ export interface LayoutMetadataResponse {
118
118
  fieldMetaData: FieldMetaData[];
119
119
  portalMetaData: {
120
120
  [key: string]: FieldMetaData[];
121
121
  };
122
122
  valueLists?: ValueList[];
123
- };
124
- export type ProductInfoMetadataResponse = {
123
+ }
124
+ export interface ProductInfoMetadataResponse {
125
125
  name: string;
126
126
  dateFormat: string;
127
127
  timeFormat: string;
128
128
  timeStampFormat: string;
129
- };
130
- export type DatabaseMetadataResponse = {
129
+ }
130
+ export interface DatabaseMetadataResponse {
131
131
  databases: Array<{
132
132
  name: string;
133
133
  }>;
134
- };
135
- export type FieldMetaData = {
134
+ }
135
+ export interface FieldMetaData {
136
136
  name: string;
137
137
  type: "normal" | "calculation" | "summary";
138
138
  displayType: "editText" | "popupList" | "popupMenu" | "checkBox" | "calendar" | "radioButtons" | "secureText";
@@ -147,28 +147,28 @@ export type FieldMetaData = {
147
147
  repetitions: number;
148
148
  timeOfDay: boolean;
149
149
  valueList?: string;
150
- };
151
- type ValueList = {
150
+ }
151
+ interface ValueList {
152
152
  name: string;
153
153
  type: "customList" | "byField";
154
154
  values: Array<{
155
155
  value: string;
156
156
  displayValue: string;
157
157
  }>;
158
- };
158
+ }
159
159
  /**
160
160
  * Represents the data returned by a call to the Data API `layouts` endpoint.
161
161
  */
162
- export type AllLayoutsMetadataResponse = {
162
+ export interface AllLayoutsMetadataResponse {
163
163
  /**
164
164
  * A list of `Layout` or `LayoutsFolder` objects.
165
165
  */
166
166
  layouts: LayoutOrFolder[];
167
- };
167
+ }
168
168
  /**
169
169
  * Represents a FileMaker layout.
170
170
  */
171
- export type Layout = {
171
+ export interface Layout {
172
172
  /**
173
173
  * The name of the layout
174
174
  */
@@ -178,11 +178,11 @@ export type Layout = {
178
178
  * the layout is associated with.
179
179
  */
180
180
  table: string;
181
- };
181
+ }
182
182
  /**
183
183
  * Represents a folder of `Layout` or `LayoutsFolder` objects.
184
184
  */
185
- export type LayoutsFolder = {
185
+ export interface LayoutsFolder {
186
186
  /**
187
187
  * The name of the folder
188
188
  */
@@ -192,33 +192,33 @@ export type LayoutsFolder = {
192
192
  * A list of the Layout or LayoutsFolder objects in the folder.
193
193
  */
194
194
  folderLayoutNames?: LayoutOrFolder[];
195
- };
195
+ }
196
196
  export type LayoutOrFolder = Layout | LayoutsFolder;
197
197
  /**
198
198
  * Represents the data returned by a call to the Data API `scripts` endpoint.
199
199
  */
200
- export type ScriptsMetadataResponse = {
200
+ export interface ScriptsMetadataResponse {
201
201
  /**
202
202
  * A list of `Layout` or `LayoutsFolder` objects.
203
203
  */
204
204
  scripts: ScriptOrFolder[];
205
- };
206
- type Script = {
205
+ }
206
+ interface Script {
207
207
  name: string;
208
208
  isFolder: false;
209
- };
210
- type ScriptFolder = {
209
+ }
210
+ interface ScriptFolder {
211
211
  name: string;
212
212
  isFolder: true;
213
213
  folderScriptNames: ScriptOrFolder[];
214
- };
214
+ }
215
215
  export type ScriptOrFolder = Script | ScriptFolder;
216
- export type RawFMResponse<T = unknown> = {
216
+ export interface RawFMResponse<T = unknown> {
217
217
  response?: T;
218
218
  messages?: [{
219
219
  code: string;
220
220
  }];
221
- };
221
+ }
222
222
  export declare class FileMakerError extends Error {
223
223
  readonly code: string;
224
224
  constructor(code: string, message: string);
@@ -2,12 +2,7 @@ var __defProp = Object.defineProperty;
2
2
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
3
3
  var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
4
4
  import { z } from "zod/v4";
5
- const ZFieldValue = z.union([
6
- z.string(),
7
- z.number(),
8
- z.null(),
9
- z.unknown()
10
- ]);
5
+ const ZFieldValue = z.union([z.string(), z.number(), z.null(), z.unknown()]);
11
6
  const ZFieldData = z.record(z.string(), ZFieldValue);
12
7
  z.object({
13
8
  scriptResult: z.string().optional(),