@proofkit/fmodata 0.1.0-alpha.8 → 0.1.0-beta.23

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 (163) hide show
  1. package/LICENSE.md +21 -0
  2. package/README.md +651 -449
  3. package/dist/esm/client/batch-builder.d.ts +10 -9
  4. package/dist/esm/client/batch-builder.js +119 -56
  5. package/dist/esm/client/batch-builder.js.map +1 -1
  6. package/dist/esm/client/batch-request.js +16 -21
  7. package/dist/esm/client/batch-request.js.map +1 -1
  8. package/dist/esm/client/builders/default-select.d.ts +10 -0
  9. package/dist/esm/client/builders/default-select.js +41 -0
  10. package/dist/esm/client/builders/default-select.js.map +1 -0
  11. package/dist/esm/client/builders/expand-builder.d.ts +45 -0
  12. package/dist/esm/client/builders/expand-builder.js +185 -0
  13. package/dist/esm/client/builders/expand-builder.js.map +1 -0
  14. package/dist/esm/client/builders/index.d.ts +9 -0
  15. package/dist/esm/client/builders/query-string-builder.d.ts +18 -0
  16. package/dist/esm/client/builders/query-string-builder.js +21 -0
  17. package/dist/esm/client/builders/query-string-builder.js.map +1 -0
  18. package/dist/esm/client/builders/response-processor.d.ts +43 -0
  19. package/dist/esm/client/builders/response-processor.js +175 -0
  20. package/dist/esm/client/builders/response-processor.js.map +1 -0
  21. package/dist/esm/client/builders/select-mixin.d.ts +25 -0
  22. package/dist/esm/client/builders/select-mixin.js +28 -0
  23. package/dist/esm/client/builders/select-mixin.js.map +1 -0
  24. package/dist/esm/client/builders/select-utils.d.ts +18 -0
  25. package/dist/esm/client/builders/select-utils.js +30 -0
  26. package/dist/esm/client/builders/select-utils.js.map +1 -0
  27. package/dist/esm/client/builders/shared-types.d.ts +40 -0
  28. package/dist/esm/client/builders/table-utils.d.ts +35 -0
  29. package/dist/esm/client/builders/table-utils.js +44 -0
  30. package/dist/esm/client/builders/table-utils.js.map +1 -0
  31. package/dist/esm/client/database.d.ts +34 -22
  32. package/dist/esm/client/database.js +48 -84
  33. package/dist/esm/client/database.js.map +1 -1
  34. package/dist/esm/client/delete-builder.d.ts +25 -30
  35. package/dist/esm/client/delete-builder.js +45 -30
  36. package/dist/esm/client/delete-builder.js.map +1 -1
  37. package/dist/esm/client/entity-set.d.ts +35 -43
  38. package/dist/esm/client/entity-set.js +110 -52
  39. package/dist/esm/client/entity-set.js.map +1 -1
  40. package/dist/esm/client/error-parser.d.ts +12 -0
  41. package/dist/esm/client/error-parser.js +25 -0
  42. package/dist/esm/client/error-parser.js.map +1 -0
  43. package/dist/esm/client/filemaker-odata.d.ts +26 -7
  44. package/dist/esm/client/filemaker-odata.js +65 -42
  45. package/dist/esm/client/filemaker-odata.js.map +1 -1
  46. package/dist/esm/client/insert-builder.d.ts +19 -24
  47. package/dist/esm/client/insert-builder.js +94 -58
  48. package/dist/esm/client/insert-builder.js.map +1 -1
  49. package/dist/esm/client/query/expand-builder.d.ts +35 -0
  50. package/dist/esm/client/query/index.d.ts +4 -0
  51. package/dist/esm/client/query/query-builder.d.ts +132 -0
  52. package/dist/esm/client/query/query-builder.js +456 -0
  53. package/dist/esm/client/query/query-builder.js.map +1 -0
  54. package/dist/esm/client/query/response-processor.d.ts +25 -0
  55. package/dist/esm/client/query/types.d.ts +77 -0
  56. package/dist/esm/client/query/url-builder.d.ts +71 -0
  57. package/dist/esm/client/query/url-builder.js +100 -0
  58. package/dist/esm/client/query/url-builder.js.map +1 -0
  59. package/dist/esm/client/query-builder.d.ts +2 -115
  60. package/dist/esm/client/record-builder.d.ts +108 -36
  61. package/dist/esm/client/record-builder.js +284 -119
  62. package/dist/esm/client/record-builder.js.map +1 -1
  63. package/dist/esm/client/response-processor.d.ts +4 -9
  64. package/dist/esm/client/sanitize-json.d.ts +35 -0
  65. package/dist/esm/client/sanitize-json.js +27 -0
  66. package/dist/esm/client/sanitize-json.js.map +1 -0
  67. package/dist/esm/client/schema-manager.d.ts +5 -5
  68. package/dist/esm/client/schema-manager.js +45 -31
  69. package/dist/esm/client/schema-manager.js.map +1 -1
  70. package/dist/esm/client/update-builder.d.ts +34 -40
  71. package/dist/esm/client/update-builder.js +99 -58
  72. package/dist/esm/client/update-builder.js.map +1 -1
  73. package/dist/esm/client/webhook-builder.d.ts +126 -0
  74. package/dist/esm/client/webhook-builder.js +189 -0
  75. package/dist/esm/client/webhook-builder.js.map +1 -0
  76. package/dist/esm/errors.d.ts +19 -2
  77. package/dist/esm/errors.js +39 -4
  78. package/dist/esm/errors.js.map +1 -1
  79. package/dist/esm/index.d.ts +10 -8
  80. package/dist/esm/index.js +40 -10
  81. package/dist/esm/index.js.map +1 -1
  82. package/dist/esm/logger.d.ts +47 -0
  83. package/dist/esm/logger.js +69 -0
  84. package/dist/esm/logger.js.map +1 -0
  85. package/dist/esm/logger.test.d.ts +1 -0
  86. package/dist/esm/orm/column.d.ts +62 -0
  87. package/dist/esm/orm/column.js +63 -0
  88. package/dist/esm/orm/column.js.map +1 -0
  89. package/dist/esm/orm/field-builders.d.ts +164 -0
  90. package/dist/esm/orm/field-builders.js +158 -0
  91. package/dist/esm/orm/field-builders.js.map +1 -0
  92. package/dist/esm/orm/index.d.ts +5 -0
  93. package/dist/esm/orm/operators.d.ts +173 -0
  94. package/dist/esm/orm/operators.js +260 -0
  95. package/dist/esm/orm/operators.js.map +1 -0
  96. package/dist/esm/orm/table.d.ts +355 -0
  97. package/dist/esm/orm/table.js +202 -0
  98. package/dist/esm/orm/table.js.map +1 -0
  99. package/dist/esm/transform.d.ts +20 -21
  100. package/dist/esm/transform.js +44 -45
  101. package/dist/esm/transform.js.map +1 -1
  102. package/dist/esm/types.d.ts +96 -30
  103. package/dist/esm/types.js +7 -0
  104. package/dist/esm/types.js.map +1 -0
  105. package/dist/esm/validation.d.ts +22 -12
  106. package/dist/esm/validation.js +132 -85
  107. package/dist/esm/validation.js.map +1 -1
  108. package/package.json +28 -20
  109. package/src/client/batch-builder.ts +153 -89
  110. package/src/client/batch-request.ts +25 -41
  111. package/src/client/builders/default-select.ts +75 -0
  112. package/src/client/builders/expand-builder.ts +246 -0
  113. package/src/client/builders/index.ts +11 -0
  114. package/src/client/builders/query-string-builder.ts +46 -0
  115. package/src/client/builders/response-processor.ts +279 -0
  116. package/src/client/builders/select-mixin.ts +65 -0
  117. package/src/client/builders/select-utils.ts +59 -0
  118. package/src/client/builders/shared-types.ts +45 -0
  119. package/src/client/builders/table-utils.ts +83 -0
  120. package/src/client/database.ts +89 -183
  121. package/src/client/delete-builder.ts +74 -84
  122. package/src/client/entity-set.ts +266 -293
  123. package/src/client/error-parser.ts +41 -0
  124. package/src/client/filemaker-odata.ts +98 -66
  125. package/src/client/insert-builder.ts +157 -118
  126. package/src/client/query/expand-builder.ts +160 -0
  127. package/src/client/query/index.ts +14 -0
  128. package/src/client/query/query-builder.ts +729 -0
  129. package/src/client/query/response-processor.ts +226 -0
  130. package/src/client/query/types.ts +126 -0
  131. package/src/client/query/url-builder.ts +151 -0
  132. package/src/client/query-builder.ts +10 -1455
  133. package/src/client/record-builder.ts +575 -240
  134. package/src/client/response-processor.ts +15 -42
  135. package/src/client/sanitize-json.ts +64 -0
  136. package/src/client/schema-manager.ts +61 -76
  137. package/src/client/update-builder.ts +161 -143
  138. package/src/client/webhook-builder.ts +265 -0
  139. package/src/errors.ts +49 -16
  140. package/src/index.ts +99 -54
  141. package/src/logger.test.ts +34 -0
  142. package/src/logger.ts +116 -0
  143. package/src/orm/column.ts +106 -0
  144. package/src/orm/field-builders.ts +250 -0
  145. package/src/orm/index.ts +61 -0
  146. package/src/orm/operators.ts +473 -0
  147. package/src/orm/table.ts +741 -0
  148. package/src/transform.ts +90 -70
  149. package/src/types.ts +154 -113
  150. package/src/validation.ts +200 -115
  151. package/dist/esm/client/base-table.d.ts +0 -125
  152. package/dist/esm/client/base-table.js +0 -57
  153. package/dist/esm/client/base-table.js.map +0 -1
  154. package/dist/esm/client/query-builder.js +0 -896
  155. package/dist/esm/client/query-builder.js.map +0 -1
  156. package/dist/esm/client/table-occurrence.d.ts +0 -72
  157. package/dist/esm/client/table-occurrence.js +0 -74
  158. package/dist/esm/client/table-occurrence.js.map +0 -1
  159. package/dist/esm/filter-types.d.ts +0 -76
  160. package/src/client/base-table.ts +0 -166
  161. package/src/client/query-builder.ts.bak +0 -1457
  162. package/src/client/table-occurrence.ts +0 -175
  163. package/src/filter-types.ts +0 -97
@@ -0,0 +1,41 @@
1
+ import { type FMODataErrorType, HTTPError, ODataError, SchemaLockedError } from "../errors";
2
+ import { safeJsonParse } from "./sanitize-json";
3
+
4
+ /**
5
+ * Parses an error response and returns an appropriate error object.
6
+ * This helper is used by builder processResponse methods to handle error responses
7
+ * consistently, particularly important for batch operations where errors need to be
8
+ * properly parsed from the response body.
9
+ *
10
+ * @param response - The Response object (may be from batch or direct request)
11
+ * @param url - The URL that was requested (for error context)
12
+ * @returns An appropriate error object (ODataError, SchemaLockedError, or HTTPError)
13
+ */
14
+ export async function parseErrorResponse(response: Response, url: string): Promise<FMODataErrorType> {
15
+ // Try to parse error body if it's JSON
16
+ let errorBody: { error?: { code?: string | number; message?: string } } | undefined;
17
+
18
+ try {
19
+ if (response.headers.get("content-type")?.includes("application/json")) {
20
+ errorBody = await safeJsonParse<typeof errorBody>(response);
21
+ }
22
+ } catch {
23
+ // Ignore JSON parse errors - we'll fall back to HTTPError
24
+ }
25
+
26
+ // Check if it's an OData error response
27
+ if (errorBody?.error) {
28
+ const errorCode = errorBody.error.code;
29
+ const errorMessage = errorBody.error.message || response.statusText;
30
+
31
+ // Check for schema locked error (code 303)
32
+ if (errorCode === "303" || errorCode === 303) {
33
+ return new SchemaLockedError(url, errorMessage, errorBody.error);
34
+ }
35
+
36
+ return new ODataError(url, errorMessage, String(errorCode), errorBody.error);
37
+ }
38
+
39
+ // Fall back to generic HTTPError
40
+ return new HTTPError(url, response.status, response.statusText, errorBody);
41
+ }
@@ -1,26 +1,35 @@
1
1
  import createClient, {
2
- FFetchOptions,
3
- TimeoutError,
4
2
  AbortError,
3
+ CircuitOpenError,
4
+ type FFetchOptions,
5
5
  NetworkError,
6
6
  RetryLimitError,
7
- CircuitOpenError,
7
+ TimeoutError,
8
8
  } from "@fetchkit/ffetch";
9
+ import { get } from "es-toolkit/compat";
10
+ import { HTTPError, ODataError, ResponseParseError, SchemaLockedError } from "../errors";
11
+ import { createLogger, type InternalLogger, type Logger } from "../logger";
9
12
  import type { Auth, ExecutionContext, Result } from "../types";
10
- import { HTTPError, ODataError, SchemaLockedError } from "../errors";
13
+ import { getAcceptHeader } from "../types";
11
14
  import { Database } from "./database";
12
- import { TableOccurrence } from "./table-occurrence";
15
+ import { safeJsonParse } from "./sanitize-json";
16
+
17
+ const TRAILING_SLASH_REGEX = /\/+$/;
13
18
 
14
19
  export class FMServerConnection implements ExecutionContext {
15
- private fetchClient: ReturnType<typeof createClient>;
16
- private serverUrl: string;
17
- private auth: Auth;
18
- private useEntityIds: boolean = false;
20
+ private readonly fetchClient: ReturnType<typeof createClient>;
21
+ private readonly serverUrl: string;
22
+ private readonly auth: Auth;
23
+ private useEntityIds = false;
24
+ private includeSpecialColumns = false;
25
+ private readonly logger: InternalLogger;
19
26
  constructor(config: {
20
27
  serverUrl: string;
21
28
  auth: Auth;
22
29
  fetchClientOptions?: FFetchOptions;
30
+ logger?: Logger;
23
31
  }) {
32
+ this.logger = createLogger(config.logger);
24
33
  this.fetchClient = createClient({
25
34
  retries: 0,
26
35
  ...config.fetchClientOptions,
@@ -31,8 +40,8 @@ export class FMServerConnection implements ExecutionContext {
31
40
  url.protocol = "https:";
32
41
  }
33
42
  // Remove any trailing slash from pathname
34
- url.pathname = url.pathname.replace(/\/+$/, "");
35
- this.serverUrl = url.toString().replace(/\/+$/, "");
43
+ url.pathname = url.pathname.replace(TRAILING_SLASH_REGEX, "");
44
+ this.serverUrl = url.toString().replace(TRAILING_SLASH_REGEX, "");
36
45
  this.auth = config.auth;
37
46
  }
38
47
 
@@ -52,12 +61,36 @@ export class FMServerConnection implements ExecutionContext {
52
61
  return this.useEntityIds;
53
62
  }
54
63
 
64
+ /**
65
+ * @internal
66
+ * Sets whether to include special columns (ROWID and ROWMODID) in requests
67
+ */
68
+ _setIncludeSpecialColumns(includeSpecialColumns: boolean): void {
69
+ this.includeSpecialColumns = includeSpecialColumns;
70
+ }
71
+
72
+ /**
73
+ * @internal
74
+ * Gets whether to include special columns (ROWID and ROWMODID) in requests
75
+ */
76
+ _getIncludeSpecialColumns(): boolean {
77
+ return this.includeSpecialColumns;
78
+ }
79
+
55
80
  /**
56
81
  * @internal
57
82
  * Gets the base URL for OData requests
58
83
  */
59
84
  _getBaseUrl(): string {
60
- return `${this.serverUrl}${"apiKey" in this.auth ? `/otto` : ""}/fmi/odata/v4`;
85
+ return `${this.serverUrl}${"apiKey" in this.auth ? "/otto" : ""}/fmi/odata/v4`;
86
+ }
87
+
88
+ /**
89
+ * @internal
90
+ * Gets the logger instance
91
+ */
92
+ _getLogger(): InternalLogger {
93
+ return this.logger;
61
94
  }
62
95
 
63
96
  /**
@@ -65,13 +98,32 @@ export class FMServerConnection implements ExecutionContext {
65
98
  */
66
99
  async _makeRequest<T>(
67
100
  url: string,
68
- options?: RequestInit & FFetchOptions & { useEntityIds?: boolean },
101
+ options?: RequestInit &
102
+ FFetchOptions & {
103
+ useEntityIds?: boolean;
104
+ includeSpecialColumns?: boolean;
105
+ },
69
106
  ): Promise<Result<T>> {
70
- const baseUrl = `${this.serverUrl}${"apiKey" in this.auth ? `/otto` : ""}/fmi/odata/v4`;
107
+ const logger = this._getLogger();
108
+ const baseUrl = `${this.serverUrl}${"apiKey" in this.auth ? "/otto" : ""}/fmi/odata/v4`;
71
109
  const fullUrl = baseUrl + url;
72
110
 
73
111
  // Use per-request override if provided, otherwise use the database-level setting
74
112
  const useEntityIds = options?.useEntityIds ?? this.useEntityIds;
113
+ const includeSpecialColumns = options?.includeSpecialColumns ?? this.includeSpecialColumns;
114
+
115
+ // Get includeODataAnnotations from options (it's passed through from execute options)
116
+ // biome-ignore lint/suspicious/noExplicitAny: Type assertion for optional property access
117
+ const includeODataAnnotations = (options as any)?.includeODataAnnotations;
118
+
119
+ // Build Prefer header as comma-separated list when multiple preferences are set
120
+ const preferValues: string[] = [];
121
+ if (useEntityIds) {
122
+ preferValues.push("fmodata.entity-ids");
123
+ }
124
+ if (includeSpecialColumns) {
125
+ preferValues.push("fmodata.include-specialcolumns");
126
+ }
75
127
 
76
128
  const headers = {
77
129
  Authorization:
@@ -79,25 +131,23 @@ export class FMServerConnection implements ExecutionContext {
79
131
  ? `Bearer ${this.auth.apiKey}`
80
132
  : `Basic ${btoa(`${this.auth.username}:${this.auth.password}`)}`,
81
133
  "Content-Type": "application/json",
82
- Accept: "application/json",
83
- ...(useEntityIds ? { Prefer: "fmodata.entity-ids" } : {}),
134
+ Accept: getAcceptHeader(includeODataAnnotations),
135
+ ...(preferValues.length > 0 ? { Prefer: preferValues.join(", ") } : {}),
84
136
  ...(options?.headers || {}),
85
137
  };
86
138
 
139
+ // Prepare loggableHeaders by omitting the Authorization key
140
+ const { Authorization, ...loggableHeaders } = headers;
141
+ logger.debug("Request headers:", loggableHeaders);
142
+
87
143
  // TEMPORARY WORKAROUND: Hopefully this feature will be fixed in the ffetch library
88
144
  // Extract fetchHandler and headers separately, only for tests where we're overriding the fetch handler per-request
89
145
  const fetchHandler = options?.fetchHandler;
90
- const {
91
- headers: _headers,
92
- fetchHandler: _fetchHandler,
93
- ...restOptions
94
- } = options || {};
146
+ const { headers: _headers, fetchHandler: _fetchHandler, ...restOptions } = options || {};
95
147
 
96
148
  // If fetchHandler is provided, create a temporary client with it
97
149
  // Otherwise use the existing client
98
- const clientToUse = fetchHandler
99
- ? createClient({ retries: 0, fetchHandler })
100
- : this.fetchClient;
150
+ const clientToUse = fetchHandler ? createClient({ retries: 0, fetchHandler }) : this.fetchClient;
101
151
 
102
152
  try {
103
153
  const finalOptions = {
@@ -105,22 +155,16 @@ export class FMServerConnection implements ExecutionContext {
105
155
  headers,
106
156
  };
107
157
 
108
- // For batch requests, use native fetch to avoid any potential serialization issues with ffetch
109
- const resp = url.includes("/$batch")
110
- ? await fetch(fullUrl, {
111
- method: finalOptions.method,
112
- headers: finalOptions.headers,
113
- body: finalOptions.body,
114
- })
115
- : await clientToUse(fullUrl, finalOptions);
158
+ const resp = await clientToUse(fullUrl, finalOptions);
159
+ logger.debug(`${finalOptions.method ?? "GET"} ${resp.status} ${fullUrl}`);
116
160
 
117
161
  // Handle HTTP errors
118
162
  if (!resp.ok) {
119
163
  // Try to parse error body if it's JSON
120
- let errorBody;
164
+ let errorBody: { error?: { code?: string | number; message?: string } } | undefined;
121
165
  try {
122
166
  if (resp.headers.get("content-type")?.includes("application/json")) {
123
- errorBody = await resp.json();
167
+ errorBody = await safeJsonParse<typeof errorBody>(resp);
124
168
  }
125
169
  } catch {
126
170
  // Ignore JSON parse errors
@@ -135,33 +179,19 @@ export class FMServerConnection implements ExecutionContext {
135
179
  if (errorCode === "303" || errorCode === 303) {
136
180
  return {
137
181
  data: undefined,
138
- error: new SchemaLockedError(
139
- fullUrl,
140
- errorMessage,
141
- errorBody.error,
142
- ),
182
+ error: new SchemaLockedError(fullUrl, errorMessage, errorBody.error),
143
183
  };
144
184
  }
145
185
 
146
186
  return {
147
187
  data: undefined,
148
- error: new ODataError(
149
- fullUrl,
150
- errorMessage,
151
- errorCode,
152
- errorBody.error,
153
- ),
188
+ error: new ODataError(fullUrl, errorMessage, String(errorCode), errorBody.error),
154
189
  };
155
190
  }
156
191
 
157
192
  return {
158
193
  data: undefined,
159
- error: new HTTPError(
160
- fullUrl,
161
- resp.status,
162
- resp.statusText,
163
- errorBody,
164
- ),
194
+ error: new HTTPError(fullUrl, resp.status, resp.statusText, errorBody),
165
195
  };
166
196
  }
167
197
 
@@ -169,15 +199,14 @@ export class FMServerConnection implements ExecutionContext {
169
199
  // FileMaker may return this with 204 No Content or 200 OK
170
200
  const affectedRows = resp.headers.get("fmodata.affected_rows");
171
201
  if (affectedRows !== null) {
172
- return { data: parseInt(affectedRows, 10) as T, error: undefined };
202
+ return { data: Number.parseInt(affectedRows, 10) as T, error: undefined };
173
203
  }
174
204
 
175
205
  // Handle 204 No Content with no body
176
206
  if (resp.status === 204) {
177
207
  // Check for Location header (used for insert with return=minimal)
178
208
  // Use optional chaining for safety with mocks that might not have proper headers
179
- const locationHeader =
180
- resp.headers?.get?.("Location") || resp.headers?.get?.("location");
209
+ const locationHeader = resp.headers?.get?.("Location") || resp.headers?.get?.("location");
181
210
  if (locationHeader) {
182
211
  // Return the location header so InsertBuilder can extract ROWID
183
212
  return { data: { _location: locationHeader } as T, error: undefined };
@@ -187,12 +216,12 @@ export class FMServerConnection implements ExecutionContext {
187
216
 
188
217
  // Parse response
189
218
  if (resp.headers.get("content-type")?.includes("application/json")) {
190
- const data = await resp.json();
219
+ const data = await safeJsonParse<T & { error?: { code?: string | number; message?: string } }>(resp);
191
220
 
192
221
  // Check for embedded OData errors
193
- if (data.error) {
194
- const errorCode = data.error.code;
195
- const errorMessage = data.error.message || "Unknown OData error";
222
+ if (get(data, "error", null)) {
223
+ const errorCode = get(data, "error.code", null);
224
+ const errorMessage = get(data, "error.message", "Unknown OData error");
196
225
 
197
226
  // Check for schema locked error (code 303)
198
227
  if (errorCode === "303" || errorCode === 303) {
@@ -204,7 +233,7 @@ export class FMServerConnection implements ExecutionContext {
204
233
 
205
234
  return {
206
235
  data: undefined,
207
- error: new ODataError(fullUrl, errorMessage, errorCode, data.error),
236
+ error: new ODataError(fullUrl, errorMessage, String(errorCode), data.error),
208
237
  };
209
238
  }
210
239
 
@@ -224,6 +253,11 @@ export class FMServerConnection implements ExecutionContext {
224
253
  return { data: undefined, error: err };
225
254
  }
226
255
 
256
+ // Handle JSON parse errors (ResponseParseError from safeJsonParse)
257
+ if (err instanceof ResponseParseError) {
258
+ return { data: undefined, error: err };
259
+ }
260
+
227
261
  // Unknown error - wrap it as NetworkError
228
262
  return {
229
263
  data: undefined,
@@ -232,16 +266,14 @@ export class FMServerConnection implements ExecutionContext {
232
266
  }
233
267
  }
234
268
 
235
- database<
236
- const Occurrences extends readonly TableOccurrence<any, any, any, any>[],
237
- >(
269
+ database<IncludeSpecialColumns extends boolean = false>(
238
270
  name: string,
239
271
  config?: {
240
- occurrences?: Occurrences | undefined;
241
272
  useEntityIds?: boolean;
273
+ includeSpecialColumns?: IncludeSpecialColumns;
242
274
  },
243
- ): Database<Occurrences> {
244
- return new Database(name, this, config);
275
+ ): Database<IncludeSpecialColumns> {
276
+ return new Database<IncludeSpecialColumns>(name, this, config);
245
277
  }
246
278
 
247
279
  /**
@@ -251,7 +283,7 @@ export class FMServerConnection implements ExecutionContext {
251
283
  async listDatabaseNames(): Promise<string[]> {
252
284
  const result = await this._makeRequest<{
253
285
  value?: Array<{ name: string }>;
254
- }>("/");
286
+ }>("/$metadata", { headers: { Accept: "application/json" } });
255
287
  if (result.error) {
256
288
  throw result.error;
257
289
  }