@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,265 @@
1
+ import { type FMTable, getTableName } from "../orm";
2
+ import { type Column, isColumn } from "../orm/column";
3
+ import { FilterExpression } from "../orm/operators";
4
+ import type { ExecuteMethodOptions, ExecutionContext } from "../types";
5
+ import { formatSelectFields } from "./builders/select-utils";
6
+
7
+ export interface Webhook<TableName = string> {
8
+ webhook: string;
9
+ headers?: Record<string, string>;
10
+ tableName: TableName;
11
+ notifySchemaChanges?: boolean;
12
+ // biome-ignore lint/suspicious/noExplicitAny: Generic constraint accepting any Column configuration
13
+ select?: string | Column<any, any, any>[];
14
+ filter?: string | FilterExpression;
15
+ }
16
+
17
+ /**
18
+ * Webhook information returned by the API
19
+ */
20
+ export interface WebhookInfo {
21
+ webHookID: number;
22
+ tableName: string;
23
+ url: string;
24
+ headers?: Record<string, string>;
25
+ notifySchemaChanges: boolean;
26
+ select: string;
27
+ filter: string;
28
+ pendingOperations: unknown[];
29
+ }
30
+
31
+ /**
32
+ * Response from listing all webhooks
33
+ */
34
+ export interface WebhookListResponse {
35
+ Status: string;
36
+ WebHook: WebhookInfo[];
37
+ }
38
+
39
+ /**
40
+ * Response from adding a webhook
41
+ */
42
+ export interface WebhookAddResponse {
43
+ webHookResult: {
44
+ webHookID: number;
45
+ };
46
+ }
47
+
48
+ export class WebhookManager {
49
+ private readonly databaseName: string;
50
+ private readonly context: ExecutionContext;
51
+
52
+ constructor(databaseName: string, context: ExecutionContext) {
53
+ this.databaseName = databaseName;
54
+ this.context = context;
55
+ }
56
+
57
+ /**
58
+ * Adds a new webhook to the database.
59
+ * @param webhook - The webhook configuration object
60
+ * @param webhook.webhook - The webhook URL to call
61
+ * @param webhook.tableName - The FMTable instance for the table to monitor
62
+ * @param webhook.headers - Optional custom headers to include in webhook requests
63
+ * @param webhook.notifySchemaChanges - Whether to notify on schema changes
64
+ * @param webhook.select - Optional field selection (string or array of Column references)
65
+ * @param webhook.filter - Optional filter (string or FilterExpression)
66
+ * @returns Promise resolving to the created webhook data with ID
67
+ * @example
68
+ * ```ts
69
+ * const result = await db.webhook.add({
70
+ * webhook: "https://example.com/webhook",
71
+ * tableName: contactsTable,
72
+ * headers: { "X-Custom-Header": "value" },
73
+ * });
74
+ * // result.webHookResult.webHookID contains the new webhook ID
75
+ * ```
76
+ * @example
77
+ * ```ts
78
+ * // Using filter expressions and column arrays (same DX as query builder)
79
+ * const result = await db.webhook.add({
80
+ * webhook: "https://example.com/webhook",
81
+ * tableName: contacts,
82
+ * filter: eq(contacts.name, "John"),
83
+ * select: [contacts.name, contacts.PrimaryKey],
84
+ * });
85
+ * ```
86
+ */
87
+ async add(webhook: Webhook<FMTable>, options?: ExecuteMethodOptions): Promise<WebhookAddResponse> {
88
+ // Extract the string table name from the FMTable instance
89
+ const tableName = getTableName(webhook.tableName);
90
+
91
+ // Get useEntityIds setting (check options first, then context, default to false)
92
+ const useEntityIds = options?.useEntityIds ?? this.context._getUseEntityIds?.() ?? false;
93
+
94
+ // Transform filter if it's a FilterExpression
95
+ let filter: string | undefined;
96
+ if (webhook.filter !== undefined) {
97
+ if (webhook.filter instanceof FilterExpression) {
98
+ filter = webhook.filter.toODataFilter(useEntityIds);
99
+ } else {
100
+ filter = webhook.filter;
101
+ }
102
+ }
103
+
104
+ // Transform select if it's an array of Columns
105
+ let select: string | undefined;
106
+ if (webhook.select !== undefined) {
107
+ if (Array.isArray(webhook.select)) {
108
+ // Extract field identifiers from columns or use strings as-is
109
+ const fieldNames = webhook.select.map((item) => {
110
+ if (isColumn(item)) {
111
+ return item.getFieldIdentifier(useEntityIds);
112
+ }
113
+ return String(item);
114
+ });
115
+ // Use formatSelectFields to properly format the select string
116
+ select = formatSelectFields(fieldNames, webhook.tableName, useEntityIds);
117
+ } else {
118
+ // Already a string, use as-is
119
+ select = webhook.select;
120
+ }
121
+ }
122
+
123
+ // Create request body with string table name and transformed filter/select
124
+ const requestBody: {
125
+ webhook: string;
126
+ headers?: Record<string, string>;
127
+ tableName: string;
128
+ notifySchemaChanges?: boolean;
129
+ select?: string;
130
+ filter?: string;
131
+ } = {
132
+ webhook: webhook.webhook,
133
+ tableName,
134
+ };
135
+
136
+ if (webhook.headers !== undefined) {
137
+ requestBody.headers = webhook.headers;
138
+ }
139
+ if (webhook.notifySchemaChanges !== undefined) {
140
+ requestBody.notifySchemaChanges = webhook.notifySchemaChanges;
141
+ }
142
+ if (select !== undefined) {
143
+ requestBody.select = select;
144
+ }
145
+ if (filter !== undefined) {
146
+ requestBody.filter = filter;
147
+ }
148
+
149
+ const result = await this.context._makeRequest<WebhookAddResponse>(`/${this.databaseName}/Webhook.Add`, {
150
+ method: "POST",
151
+ body: JSON.stringify(requestBody),
152
+ ...options,
153
+ });
154
+
155
+ if (result.error) {
156
+ throw result.error;
157
+ }
158
+
159
+ return result.data;
160
+ }
161
+
162
+ /**
163
+ * Deletes a webhook by ID.
164
+ * @param webhookId - The ID of the webhook to delete
165
+ * @returns Promise that resolves when the webhook is deleted
166
+ * @example
167
+ * ```ts
168
+ * await db.webhook.remove(1);
169
+ * ```
170
+ */
171
+ async remove(webhookId: number, options?: ExecuteMethodOptions): Promise<void> {
172
+ const result = await this.context._makeRequest(`/${this.databaseName}/Webhook.Delete(${webhookId})`, {
173
+ method: "POST",
174
+ ...options,
175
+ });
176
+
177
+ if (result.error) {
178
+ throw result.error;
179
+ }
180
+ }
181
+
182
+ /**
183
+ * Gets a webhook by ID.
184
+ * @param webhookId - The ID of the webhook to retrieve
185
+ * @returns Promise resolving to the webhook data
186
+ * @example
187
+ * ```ts
188
+ * const webhook = await db.webhook.get(1);
189
+ * // webhook.webHookID, webhook.tableName, webhook.url, etc.
190
+ * ```
191
+ */
192
+ async get(webhookId: number, options?: ExecuteMethodOptions): Promise<WebhookInfo> {
193
+ const result = await this.context._makeRequest<WebhookInfo>(
194
+ `/${this.databaseName}/Webhook.Get(${webhookId})`,
195
+ options,
196
+ );
197
+
198
+ if (result.error) {
199
+ throw result.error;
200
+ }
201
+
202
+ return result.data;
203
+ }
204
+
205
+ /**
206
+ * Lists all webhooks.
207
+ * @returns Promise resolving to webhook list response with status and webhooks array
208
+ * @example
209
+ * ```ts
210
+ * const result = await db.webhook.list();
211
+ * // result.Status contains the status
212
+ * // result.WebHook contains the array of webhooks
213
+ * ```
214
+ */
215
+ async list(options?: ExecuteMethodOptions): Promise<WebhookListResponse> {
216
+ const result = await this.context._makeRequest<WebhookListResponse>(
217
+ `/${this.databaseName}/Webhook.GetAll`,
218
+ options,
219
+ );
220
+
221
+ if (result.error) {
222
+ throw result.error;
223
+ }
224
+
225
+ return result.data;
226
+ }
227
+
228
+ /**
229
+ * Invokes a webhook by ID, optionally for specific row IDs.
230
+ * @param webhookId - The ID of the webhook to invoke
231
+ * @param options - Optional configuration
232
+ * @param options.rowIDs - Array of row IDs to trigger the webhook for
233
+ * @returns Promise resolving to the invocation result (type unknown until API behavior is confirmed)
234
+ * @example
235
+ * ```ts
236
+ * // Invoke for all rows
237
+ * await db.webhook.invoke(1);
238
+ *
239
+ * // Invoke for specific rows
240
+ * await db.webhook.invoke(1, { rowIDs: [63, 61] });
241
+ * ```
242
+ */
243
+ async invoke(
244
+ webhookId: number,
245
+ options?: { rowIDs?: number[] },
246
+ executeOptions?: ExecuteMethodOptions,
247
+ ): Promise<unknown> {
248
+ const body: { rowIDs?: number[] } = {};
249
+ if (options?.rowIDs !== undefined) {
250
+ body.rowIDs = options.rowIDs;
251
+ }
252
+
253
+ const result = await this.context._makeRequest<unknown>(`/${this.databaseName}/Webhook.Invoke(${webhookId})`, {
254
+ method: "POST",
255
+ body: Object.keys(body).length > 0 ? JSON.stringify(body) : undefined,
256
+ ...executeOptions,
257
+ });
258
+
259
+ if (result.error) {
260
+ throw result.error;
261
+ }
262
+
263
+ return result.data;
264
+ }
265
+ }
package/src/errors.ts CHANGED
@@ -23,8 +23,10 @@ export class HTTPError extends FMODataError {
23
23
  readonly url: string;
24
24
  readonly status: number;
25
25
  readonly statusText: string;
26
+ // biome-ignore lint/suspicious/noExplicitAny: Dynamic response type from OData API
26
27
  readonly response?: any;
27
28
 
29
+ // biome-ignore lint/suspicious/noExplicitAny: Dynamic response type from OData API
28
30
  constructor(url: string, status: number, statusText: string, response?: any) {
29
31
  super(`HTTP ${status} ${statusText} for ${url}`);
30
32
  this.url = url;
@@ -63,8 +65,10 @@ export class ODataError extends FMODataError {
63
65
  readonly kind = "ODataError" as const;
64
66
  readonly url: string;
65
67
  readonly code?: string;
68
+ // biome-ignore lint/suspicious/noExplicitAny: Dynamic error details from OData API
66
69
  readonly details?: any;
67
70
 
71
+ // biome-ignore lint/suspicious/noExplicitAny: Dynamic error details from OData API
68
72
  constructor(url: string, message: string, code?: string, details?: any) {
69
73
  super(`OData error: ${message}`);
70
74
  this.url = url;
@@ -77,8 +81,10 @@ export class SchemaLockedError extends FMODataError {
77
81
  readonly kind = "SchemaLockedError" as const;
78
82
  readonly url: string;
79
83
  readonly code: string;
84
+ // biome-ignore lint/suspicious/noExplicitAny: Dynamic error details from OData API
80
85
  readonly details?: any;
81
86
 
87
+ // biome-ignore lint/suspicious/noExplicitAny: Dynamic error details from OData API
82
88
  constructor(url: string, message: string, details?: any) {
83
89
  super(`OData error: ${message}`);
84
90
  this.url = url;
@@ -106,10 +112,7 @@ export class ValidationError extends FMODataError {
106
112
  cause?: Error["cause"];
107
113
  },
108
114
  ) {
109
- super(
110
- message,
111
- options?.cause !== undefined ? { cause: options.cause } : undefined,
112
- );
115
+ super(message, options?.cause !== undefined ? { cause: options.cause } : undefined);
113
116
  this.field = options?.field;
114
117
  this.issues = issues;
115
118
  this.value = options?.value;
@@ -119,8 +122,10 @@ export class ValidationError extends FMODataError {
119
122
  export class ResponseStructureError extends FMODataError {
120
123
  readonly kind = "ResponseStructureError" as const;
121
124
  readonly expected: string;
125
+ // biome-ignore lint/suspicious/noExplicitAny: Dynamic response type from OData API
122
126
  readonly received: any;
123
127
 
128
+ // biome-ignore lint/suspicious/noExplicitAny: Dynamic response type from OData API
124
129
  constructor(expected: string, received: any) {
125
130
  super(`Invalid response structure: expected ${expected}`);
126
131
  this.expected = expected;
@@ -151,6 +156,30 @@ export class InvalidLocationHeaderError extends FMODataError {
151
156
  }
152
157
  }
153
158
 
159
+ export class ResponseParseError extends FMODataError {
160
+ readonly kind = "ResponseParseError" as const;
161
+ readonly url: string;
162
+ readonly rawText?: string;
163
+
164
+ constructor(url: string, message: string, options?: { rawText?: string; cause?: Error }) {
165
+ super(message, options?.cause ? { cause: options.cause } : undefined);
166
+ this.url = url;
167
+ this.rawText = options?.rawText;
168
+ }
169
+ }
170
+
171
+ export class BatchTruncatedError extends FMODataError {
172
+ readonly kind = "BatchTruncatedError" as const;
173
+ readonly operationIndex: number;
174
+ readonly failedAtIndex: number;
175
+
176
+ constructor(operationIndex: number, failedAtIndex: number) {
177
+ super(`Operation ${operationIndex} was not executed because operation ${failedAtIndex} failed`);
178
+ this.operationIndex = operationIndex;
179
+ this.failedAtIndex = failedAtIndex;
180
+ }
181
+ }
182
+
154
183
  // ============================================
155
184
  // Type Guards
156
185
  // ============================================
@@ -167,24 +196,26 @@ export function isODataError(error: unknown): error is ODataError {
167
196
  return error instanceof ODataError;
168
197
  }
169
198
 
170
- export function isSchemaLockedError(
171
- error: unknown,
172
- ): error is SchemaLockedError {
199
+ export function isSchemaLockedError(error: unknown): error is SchemaLockedError {
173
200
  return error instanceof SchemaLockedError;
174
201
  }
175
202
 
176
- export function isResponseStructureError(
177
- error: unknown,
178
- ): error is ResponseStructureError {
203
+ export function isResponseStructureError(error: unknown): error is ResponseStructureError {
179
204
  return error instanceof ResponseStructureError;
180
205
  }
181
206
 
182
- export function isRecordCountMismatchError(
183
- error: unknown,
184
- ): error is RecordCountMismatchError {
207
+ export function isRecordCountMismatchError(error: unknown): error is RecordCountMismatchError {
185
208
  return error instanceof RecordCountMismatchError;
186
209
  }
187
210
 
211
+ export function isResponseParseError(error: unknown): error is ResponseParseError {
212
+ return error instanceof ResponseParseError;
213
+ }
214
+
215
+ export function isBatchTruncatedError(error: unknown): error is BatchTruncatedError {
216
+ return error instanceof BatchTruncatedError;
217
+ }
218
+
188
219
  export function isFMODataError(error: unknown): error is FMODataError {
189
220
  return error instanceof FMODataError;
190
221
  }
@@ -195,11 +226,11 @@ export function isFMODataError(error: unknown): error is FMODataError {
195
226
 
196
227
  // Re-export ffetch errors (they'll be imported from @fetchkit/ffetch)
197
228
  export type {
198
- TimeoutError,
199
229
  AbortError,
230
+ CircuitOpenError,
200
231
  NetworkError,
201
232
  RetryLimitError,
202
- CircuitOpenError,
233
+ TimeoutError,
203
234
  } from "@fetchkit/ffetch";
204
235
 
205
236
  export type FMODataErrorType =
@@ -214,4 +245,6 @@ export type FMODataErrorType =
214
245
  | ValidationError
215
246
  | ResponseStructureError
216
247
  | RecordCountMismatchError
217
- | InvalidLocationHeaderError;
248
+ | InvalidLocationHeaderError
249
+ | ResponseParseError
250
+ | BatchTruncatedError;
package/src/index.ts CHANGED
@@ -1,74 +1,119 @@
1
1
  // Barrel file - exports all public API from the client folder
2
- export { BaseTable, defineBaseTable } from "./client/base-table";
2
+ /** biome-ignore-all lint/performance/noBarrelFile: Re-exporting all public API from the client folder */
3
+
4
+ export type { FFetchOptions } from "@fetchkit/ffetch";
5
+ // Re-export ffetch errors and types
3
6
  export {
4
- TableOccurrence,
5
- createTableOccurrence,
6
- defineTableOccurrence,
7
- } from "./client/table-occurrence";
8
- export { FMServerConnection } from "./client/filemaker-odata";
7
+ AbortError,
8
+ CircuitOpenError,
9
+ NetworkError,
10
+ RetryLimitError,
11
+ TimeoutError,
12
+ } from "@fetchkit/ffetch";
9
13
 
10
- // Type-only exports for TypeScript declaration file portability
11
- // Users get these instances from the builder pattern, not by direct instantiation
14
+ // Type-only exports - for type annotations only, not direct instantiation
12
15
  export type { Database } from "./client/database";
13
16
  export type { EntitySet } from "./client/entity-set";
17
+ // Main API - use these functions to create tables and occurrences
18
+ export { FMServerConnection } from "./client/filemaker-odata";
14
19
  export type {
15
- SchemaManager,
20
+ ContainerField,
21
+ DateField,
16
22
  Field,
17
- StringField,
18
23
  NumericField,
19
- DateField,
24
+ SchemaManager,
25
+ StringField,
20
26
  TimeField,
21
27
  TimestampField,
22
- ContainerField,
23
28
  } from "./client/schema-manager";
24
-
25
- // Utility types for type annotations
26
- export type {
27
- Result,
28
- InferSchemaType,
29
- InsertData,
30
- UpdateData,
31
- ODataRecordMetadata,
32
- Metadata,
33
- } from "./types";
34
-
35
- // Filter types
36
29
  export type {
37
- Filter,
38
- TypedFilter,
39
- FieldFilter,
40
- StringOperators,
41
- NumberOperators,
42
- BooleanOperators,
43
- DateOperators,
44
- LogicalFilter,
45
- } from "./filter-types";
46
-
47
- // Re-export ffetch errors
48
- export {
49
- TimeoutError,
50
- AbortError,
51
- NetworkError,
52
- RetryLimitError,
53
- CircuitOpenError,
54
- } from "@fetchkit/ffetch";
55
-
30
+ Webhook,
31
+ WebhookAddResponse,
32
+ WebhookInfo,
33
+ WebhookListResponse,
34
+ } from "./client/webhook-builder";
35
+ export type { FMODataErrorType } from "./errors";
56
36
  // Export our errors
57
37
  export {
38
+ BatchTruncatedError,
58
39
  FMODataError,
59
40
  HTTPError,
60
- ODataError,
61
- SchemaLockedError,
62
- ValidationError,
63
- ResponseStructureError,
64
- RecordCountMismatchError,
41
+ isBatchTruncatedError,
42
+ isFMODataError,
65
43
  isHTTPError,
66
- isValidationError,
67
44
  isODataError,
68
- isSchemaLockedError,
69
- isResponseStructureError,
70
45
  isRecordCountMismatchError,
71
- isFMODataError,
46
+ isResponseParseError,
47
+ isResponseStructureError,
48
+ isSchemaLockedError,
49
+ isValidationError,
50
+ ODataError,
51
+ RecordCountMismatchError,
52
+ ResponseParseError,
53
+ ResponseStructureError,
54
+ SchemaLockedError,
55
+ ValidationError,
72
56
  } from "./errors";
73
-
74
- export type { FMODataErrorType } from "./errors";
57
+ export type { Logger } from "./logger";
58
+ // NEW ORM API - Drizzle-inspired field builders and operators
59
+ export {
60
+ and,
61
+ asc,
62
+ // Column references
63
+ type Column,
64
+ calcField,
65
+ containerField,
66
+ contains,
67
+ dateField,
68
+ desc,
69
+ endsWith,
70
+ eq,
71
+ type FieldBuilder,
72
+ // Filter operators
73
+ type FilterExpression,
74
+ FMTable,
75
+ type FMTableWithColumns as TableOccurrenceResult,
76
+ // Table definition
77
+ fmTableOccurrence,
78
+ // Table helper functions
79
+ // getTableFields,
80
+ // getDefaultSelect,
81
+ // getBaseTableConfig,
82
+ // getFieldId,
83
+ // getFieldName,
84
+ // getTableId,
85
+ getTableColumns,
86
+ gt,
87
+ gte,
88
+ type InferTableSchema,
89
+ inArray,
90
+ isColumn,
91
+ isNotNull,
92
+ isNull,
93
+ lt,
94
+ lte,
95
+ ne,
96
+ not,
97
+ notInArray,
98
+ numberField,
99
+ // OrderBy operators
100
+ type OrderByExpression,
101
+ or,
102
+ startsWith,
103
+ // Field builders
104
+ textField,
105
+ timeField,
106
+ timestampField,
107
+ } from "./orm/index";
108
+ // Utility types for type annotations
109
+ export type {
110
+ BatchItemResult,
111
+ BatchResult,
112
+ ExecuteMethodOptions,
113
+ ExecuteOptions,
114
+ FetchHandler,
115
+ InferSchemaType,
116
+ Metadata,
117
+ ODataRecordMetadata,
118
+ Result,
119
+ } from "./types";
@@ -0,0 +1,34 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import type { LogLevel } from "./logger";
3
+ import { shouldPublishLog } from "./logger";
4
+
5
+ describe("shouldPublishLog", () => {
6
+ const testCases: {
7
+ currentLogLevel: LogLevel;
8
+ logLevel: LogLevel;
9
+ expected: boolean;
10
+ }[] = [
11
+ { currentLogLevel: "debug", logLevel: "debug", expected: true },
12
+ { currentLogLevel: "debug", logLevel: "info", expected: true },
13
+ { currentLogLevel: "debug", logLevel: "warn", expected: true },
14
+ { currentLogLevel: "debug", logLevel: "error", expected: true },
15
+ { currentLogLevel: "info", logLevel: "debug", expected: false },
16
+ { currentLogLevel: "info", logLevel: "info", expected: true },
17
+ { currentLogLevel: "info", logLevel: "warn", expected: true },
18
+ { currentLogLevel: "info", logLevel: "error", expected: true },
19
+ { currentLogLevel: "warn", logLevel: "debug", expected: false },
20
+ { currentLogLevel: "warn", logLevel: "info", expected: false },
21
+ { currentLogLevel: "warn", logLevel: "warn", expected: true },
22
+ { currentLogLevel: "warn", logLevel: "error", expected: true },
23
+ { currentLogLevel: "error", logLevel: "debug", expected: false },
24
+ { currentLogLevel: "error", logLevel: "info", expected: false },
25
+ { currentLogLevel: "error", logLevel: "warn", expected: false },
26
+ { currentLogLevel: "error", logLevel: "error", expected: true },
27
+ ];
28
+
29
+ for (const { currentLogLevel, logLevel, expected } of testCases) {
30
+ it(`should return "${expected}" when currentLogLevel is "${currentLogLevel}" and logLevel is "${logLevel}"`, () => {
31
+ expect(shouldPublishLog(currentLogLevel, logLevel)).toBe(expected);
32
+ });
33
+ }
34
+ });