@proofkit/fmodata 0.1.0-alpha.19 → 0.1.0-alpha.20

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 (74) hide show
  1. package/README.md +198 -0
  2. package/dist/esm/client/builders/default-select.d.ts +4 -1
  3. package/dist/esm/client/builders/default-select.js +3 -2
  4. package/dist/esm/client/builders/default-select.js.map +1 -1
  5. package/dist/esm/client/builders/expand-builder.js.map +1 -1
  6. package/dist/esm/client/builders/query-string-builder.d.ts +1 -0
  7. package/dist/esm/client/builders/query-string-builder.js.map +1 -1
  8. package/dist/esm/client/builders/response-processor.d.ts +2 -0
  9. package/dist/esm/client/builders/response-processor.js +8 -3
  10. package/dist/esm/client/builders/response-processor.js.map +1 -1
  11. package/dist/esm/client/database.d.ts +27 -4
  12. package/dist/esm/client/database.js +17 -4
  13. package/dist/esm/client/database.js.map +1 -1
  14. package/dist/esm/client/delete-builder.d.ts +2 -0
  15. package/dist/esm/client/delete-builder.js +2 -0
  16. package/dist/esm/client/delete-builder.js.map +1 -1
  17. package/dist/esm/client/entity-set.d.ts +8 -7
  18. package/dist/esm/client/entity-set.js +21 -26
  19. package/dist/esm/client/entity-set.js.map +1 -1
  20. package/dist/esm/client/error-parser.js.map +1 -1
  21. package/dist/esm/client/filemaker-odata.d.ts +15 -2
  22. package/dist/esm/client/filemaker-odata.js +25 -2
  23. package/dist/esm/client/filemaker-odata.js.map +1 -1
  24. package/dist/esm/client/insert-builder.d.ts +2 -0
  25. package/dist/esm/client/insert-builder.js +2 -0
  26. package/dist/esm/client/insert-builder.js.map +1 -1
  27. package/dist/esm/client/query/query-builder.d.ts +26 -15
  28. package/dist/esm/client/query/query-builder.js +43 -9
  29. package/dist/esm/client/query/query-builder.js.map +1 -1
  30. package/dist/esm/client/query/response-processor.d.ts +1 -0
  31. package/dist/esm/client/query/types.d.ts +24 -3
  32. package/dist/esm/client/record-builder.d.ts +24 -13
  33. package/dist/esm/client/record-builder.js +50 -17
  34. package/dist/esm/client/record-builder.js.map +1 -1
  35. package/dist/esm/client/update-builder.d.ts +2 -0
  36. package/dist/esm/client/update-builder.js +2 -0
  37. package/dist/esm/client/update-builder.js.map +1 -1
  38. package/dist/esm/client/webhook-builder.d.ts +126 -0
  39. package/dist/esm/client/webhook-builder.js +197 -0
  40. package/dist/esm/client/webhook-builder.js.map +1 -0
  41. package/dist/esm/index.d.ts +1 -0
  42. package/dist/esm/orm/field-builders.d.ts +12 -2
  43. package/dist/esm/orm/field-builders.js +18 -2
  44. package/dist/esm/orm/field-builders.js.map +1 -1
  45. package/dist/esm/orm/table.d.ts +23 -10
  46. package/dist/esm/orm/table.js +17 -30
  47. package/dist/esm/orm/table.js.map +1 -1
  48. package/dist/esm/types.d.ts +32 -2
  49. package/dist/esm/types.js.map +1 -1
  50. package/dist/esm/validation.d.ts +5 -5
  51. package/dist/esm/validation.js +44 -13
  52. package/dist/esm/validation.js.map +1 -1
  53. package/package.json +2 -2
  54. package/src/client/builders/default-select.ts +12 -1
  55. package/src/client/builders/expand-builder.ts +1 -1
  56. package/src/client/builders/query-string-builder.ts +6 -0
  57. package/src/client/builders/response-processor.ts +10 -0
  58. package/src/client/database.ts +54 -12
  59. package/src/client/delete-builder.ts +5 -1
  60. package/src/client/entity-set.ts +72 -44
  61. package/src/client/error-parser.ts +3 -0
  62. package/src/client/filemaker-odata.ts +39 -6
  63. package/src/client/insert-builder.ts +4 -0
  64. package/src/client/query/query-builder.ts +198 -35
  65. package/src/client/query/response-processor.ts +15 -25
  66. package/src/client/query/types.ts +35 -6
  67. package/src/client/record-builder.ts +159 -32
  68. package/src/client/update-builder.ts +4 -1
  69. package/src/client/webhook-builder.ts +285 -0
  70. package/src/index.ts +6 -0
  71. package/src/orm/field-builders.ts +24 -2
  72. package/src/orm/table.ts +40 -48
  73. package/src/types.ts +62 -6
  74. package/src/validation.ts +58 -13
@@ -0,0 +1,126 @@
1
+ import { FMTable } from '../orm.js';
2
+ import { ExecutionContext, ExecuteMethodOptions } from '../types.js';
3
+ import { FilterExpression } from '../orm/operators.js';
4
+ import { Column } from '../orm/column.js';
5
+ export type Webhook<TableName = string> = {
6
+ webhook: string;
7
+ headers?: Record<string, string>;
8
+ tableName: TableName;
9
+ notifySchemaChanges?: boolean;
10
+ select?: string | Column<any, any, any>[];
11
+ filter?: string | FilterExpression;
12
+ };
13
+ /**
14
+ * Webhook information returned by the API
15
+ */
16
+ export type WebhookInfo = {
17
+ webHookID: number;
18
+ tableName: string;
19
+ url: string;
20
+ headers?: Record<string, string>;
21
+ notifySchemaChanges: boolean;
22
+ select: string;
23
+ filter: string;
24
+ pendingOperations: unknown[];
25
+ };
26
+ /**
27
+ * Response from listing all webhooks
28
+ */
29
+ export type WebhookListResponse = {
30
+ Status: string;
31
+ WebHook: WebhookInfo[];
32
+ };
33
+ /**
34
+ * Response from adding a webhook
35
+ */
36
+ export type WebhookAddResponse = {
37
+ webHookResult: {
38
+ webHookID: number;
39
+ };
40
+ };
41
+ export declare class WebhookManager {
42
+ private readonly databaseName;
43
+ private readonly context;
44
+ constructor(databaseName: string, context: ExecutionContext);
45
+ /**
46
+ * Adds a new webhook to the database.
47
+ * @param webhook - The webhook configuration object
48
+ * @param webhook.webhook - The webhook URL to call
49
+ * @param webhook.tableName - The FMTable instance for the table to monitor
50
+ * @param webhook.headers - Optional custom headers to include in webhook requests
51
+ * @param webhook.notifySchemaChanges - Whether to notify on schema changes
52
+ * @param webhook.select - Optional field selection (string or array of Column references)
53
+ * @param webhook.filter - Optional filter (string or FilterExpression)
54
+ * @returns Promise resolving to the created webhook data with ID
55
+ * @example
56
+ * ```ts
57
+ * const result = await db.webhook.add({
58
+ * webhook: "https://example.com/webhook",
59
+ * tableName: contactsTable,
60
+ * headers: { "X-Custom-Header": "value" },
61
+ * });
62
+ * // result.webHookResult.webHookID contains the new webhook ID
63
+ * ```
64
+ * @example
65
+ * ```ts
66
+ * // Using filter expressions and column arrays (same DX as query builder)
67
+ * const result = await db.webhook.add({
68
+ * webhook: "https://example.com/webhook",
69
+ * tableName: contacts,
70
+ * filter: eq(contacts.name, "John"),
71
+ * select: [contacts.name, contacts.PrimaryKey],
72
+ * });
73
+ * ```
74
+ */
75
+ add(webhook: Webhook<FMTable>, options?: ExecuteMethodOptions): Promise<WebhookAddResponse>;
76
+ /**
77
+ * Deletes a webhook by ID.
78
+ * @param webhookId - The ID of the webhook to delete
79
+ * @returns Promise that resolves when the webhook is deleted
80
+ * @example
81
+ * ```ts
82
+ * await db.webhook.remove(1);
83
+ * ```
84
+ */
85
+ remove(webhookId: string | number, options?: ExecuteMethodOptions): Promise<void>;
86
+ /**
87
+ * Gets a webhook by ID.
88
+ * @param webhookId - The ID of the webhook to retrieve
89
+ * @returns Promise resolving to the webhook data
90
+ * @example
91
+ * ```ts
92
+ * const webhook = await db.webhook.get(1);
93
+ * // webhook.webHookID, webhook.tableName, webhook.url, etc.
94
+ * ```
95
+ */
96
+ get(webhookId: string | number, options?: ExecuteMethodOptions): Promise<WebhookInfo>;
97
+ /**
98
+ * Lists all webhooks.
99
+ * @returns Promise resolving to webhook list response with status and webhooks array
100
+ * @example
101
+ * ```ts
102
+ * const result = await db.webhook.list();
103
+ * // result.Status contains the status
104
+ * // result.WebHook contains the array of webhooks
105
+ * ```
106
+ */
107
+ list(options?: ExecuteMethodOptions): Promise<WebhookListResponse>;
108
+ /**
109
+ * Invokes a webhook by ID, optionally for specific row IDs.
110
+ * @param webhookId - The ID of the webhook to invoke
111
+ * @param options - Optional configuration
112
+ * @param options.rowIDs - Array of row IDs to trigger the webhook for
113
+ * @returns Promise resolving to the invocation result (type unknown until API behavior is confirmed)
114
+ * @example
115
+ * ```ts
116
+ * // Invoke for all rows
117
+ * await db.webhook.invoke(1);
118
+ *
119
+ * // Invoke for specific rows
120
+ * await db.webhook.invoke(1, { rowIDs: [63, 61] });
121
+ * ```
122
+ */
123
+ invoke(webhookId: string | number, options?: {
124
+ rowIDs?: number[];
125
+ }, executeOptions?: ExecuteMethodOptions): Promise<unknown>;
126
+ }
@@ -0,0 +1,197 @@
1
+ import { isColumn } from "../orm/column.js";
2
+ import { FilterExpression } from "../orm/operators.js";
3
+ import { getTableName } from "../orm/table.js";
4
+ import { formatSelectFields } from "./builders/select-utils.js";
5
+ class WebhookManager {
6
+ constructor(databaseName, context) {
7
+ this.databaseName = databaseName;
8
+ this.context = context;
9
+ }
10
+ /**
11
+ * Adds a new webhook to the database.
12
+ * @param webhook - The webhook configuration object
13
+ * @param webhook.webhook - The webhook URL to call
14
+ * @param webhook.tableName - The FMTable instance for the table to monitor
15
+ * @param webhook.headers - Optional custom headers to include in webhook requests
16
+ * @param webhook.notifySchemaChanges - Whether to notify on schema changes
17
+ * @param webhook.select - Optional field selection (string or array of Column references)
18
+ * @param webhook.filter - Optional filter (string or FilterExpression)
19
+ * @returns Promise resolving to the created webhook data with ID
20
+ * @example
21
+ * ```ts
22
+ * const result = await db.webhook.add({
23
+ * webhook: "https://example.com/webhook",
24
+ * tableName: contactsTable,
25
+ * headers: { "X-Custom-Header": "value" },
26
+ * });
27
+ * // result.webHookResult.webHookID contains the new webhook ID
28
+ * ```
29
+ * @example
30
+ * ```ts
31
+ * // Using filter expressions and column arrays (same DX as query builder)
32
+ * const result = await db.webhook.add({
33
+ * webhook: "https://example.com/webhook",
34
+ * tableName: contacts,
35
+ * filter: eq(contacts.name, "John"),
36
+ * select: [contacts.name, contacts.PrimaryKey],
37
+ * });
38
+ * ```
39
+ */
40
+ async add(webhook, options) {
41
+ var _a, _b;
42
+ const tableName = getTableName(webhook.tableName);
43
+ const useEntityIds = (options == null ? void 0 : options.useEntityIds) ?? ((_b = (_a = this.context)._getUseEntityIds) == null ? void 0 : _b.call(_a)) ?? false;
44
+ let filter;
45
+ if (webhook.filter !== void 0) {
46
+ if (webhook.filter instanceof FilterExpression) {
47
+ filter = webhook.filter.toODataFilter(useEntityIds);
48
+ } else {
49
+ filter = webhook.filter;
50
+ }
51
+ }
52
+ let select;
53
+ if (webhook.select !== void 0) {
54
+ if (Array.isArray(webhook.select)) {
55
+ const fieldNames = webhook.select.map((item) => {
56
+ if (isColumn(item)) {
57
+ return item.getFieldIdentifier(useEntityIds);
58
+ }
59
+ return String(item);
60
+ });
61
+ select = formatSelectFields(
62
+ fieldNames,
63
+ webhook.tableName,
64
+ useEntityIds
65
+ );
66
+ } else {
67
+ select = webhook.select;
68
+ }
69
+ }
70
+ const requestBody = {
71
+ webhook: webhook.webhook,
72
+ tableName
73
+ };
74
+ if (webhook.headers !== void 0) {
75
+ requestBody.headers = webhook.headers;
76
+ }
77
+ if (webhook.notifySchemaChanges !== void 0) {
78
+ requestBody.notifySchemaChanges = webhook.notifySchemaChanges;
79
+ }
80
+ if (select !== void 0) {
81
+ requestBody.select = select;
82
+ }
83
+ if (filter !== void 0) {
84
+ requestBody.filter = filter;
85
+ }
86
+ const result = await this.context._makeRequest(
87
+ `/${this.databaseName}/Webhook.Add`,
88
+ {
89
+ method: "POST",
90
+ body: JSON.stringify(requestBody),
91
+ ...options
92
+ }
93
+ );
94
+ if (result.error) {
95
+ throw result.error;
96
+ }
97
+ return result.data;
98
+ }
99
+ /**
100
+ * Deletes a webhook by ID.
101
+ * @param webhookId - The ID of the webhook to delete
102
+ * @returns Promise that resolves when the webhook is deleted
103
+ * @example
104
+ * ```ts
105
+ * await db.webhook.remove(1);
106
+ * ```
107
+ */
108
+ async remove(webhookId, options) {
109
+ const result = await this.context._makeRequest(
110
+ `/${this.databaseName}/Webhook.Delete(${webhookId})`,
111
+ {
112
+ method: "POST",
113
+ ...options
114
+ }
115
+ );
116
+ if (result.error) {
117
+ throw result.error;
118
+ }
119
+ }
120
+ /**
121
+ * Gets a webhook by ID.
122
+ * @param webhookId - The ID of the webhook to retrieve
123
+ * @returns Promise resolving to the webhook data
124
+ * @example
125
+ * ```ts
126
+ * const webhook = await db.webhook.get(1);
127
+ * // webhook.webHookID, webhook.tableName, webhook.url, etc.
128
+ * ```
129
+ */
130
+ async get(webhookId, options) {
131
+ const result = await this.context._makeRequest(
132
+ `/${this.databaseName}/Webhook.Get(${webhookId})`,
133
+ options
134
+ );
135
+ if (result.error) {
136
+ throw result.error;
137
+ }
138
+ return result.data;
139
+ }
140
+ /**
141
+ * Lists all webhooks.
142
+ * @returns Promise resolving to webhook list response with status and webhooks array
143
+ * @example
144
+ * ```ts
145
+ * const result = await db.webhook.list();
146
+ * // result.Status contains the status
147
+ * // result.WebHook contains the array of webhooks
148
+ * ```
149
+ */
150
+ async list(options) {
151
+ const result = await this.context._makeRequest(
152
+ `/${this.databaseName}/Webhook.GetAll`,
153
+ options
154
+ );
155
+ if (result.error) {
156
+ throw result.error;
157
+ }
158
+ return result.data;
159
+ }
160
+ /**
161
+ * Invokes a webhook by ID, optionally for specific row IDs.
162
+ * @param webhookId - The ID of the webhook to invoke
163
+ * @param options - Optional configuration
164
+ * @param options.rowIDs - Array of row IDs to trigger the webhook for
165
+ * @returns Promise resolving to the invocation result (type unknown until API behavior is confirmed)
166
+ * @example
167
+ * ```ts
168
+ * // Invoke for all rows
169
+ * await db.webhook.invoke(1);
170
+ *
171
+ * // Invoke for specific rows
172
+ * await db.webhook.invoke(1, { rowIDs: [63, 61] });
173
+ * ```
174
+ */
175
+ async invoke(webhookId, options, executeOptions) {
176
+ const body = {};
177
+ if ((options == null ? void 0 : options.rowIDs) !== void 0) {
178
+ body.rowIDs = options.rowIDs;
179
+ }
180
+ const result = await this.context._makeRequest(
181
+ `/${this.databaseName}/Webhook.Invoke(${webhookId})`,
182
+ {
183
+ method: "POST",
184
+ body: Object.keys(body).length > 0 ? JSON.stringify(body) : void 0,
185
+ ...executeOptions
186
+ }
187
+ );
188
+ if (result.error) {
189
+ throw result.error;
190
+ }
191
+ return result.data;
192
+ }
193
+ }
194
+ export {
195
+ WebhookManager
196
+ };
197
+ //# sourceMappingURL=webhook-builder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webhook-builder.js","sources":["../../../src/client/webhook-builder.ts"],"sourcesContent":["import { FMTable, getTableName } from \"../orm\";\nimport type { ExecutionContext, ExecuteMethodOptions } from \"../types\";\nimport type { FFetchOptions } from \"@fetchkit/ffetch\";\nimport { FilterExpression } from \"../orm/operators\";\nimport { isColumn, type Column } from \"../orm/column\";\nimport { formatSelectFields } from \"./builders/select-utils\";\n\nexport type Webhook<TableName = string> = {\n webhook: string;\n headers?: Record<string, string>;\n tableName: TableName;\n notifySchemaChanges?: boolean;\n select?: string | Column<any, any, any>[];\n filter?: string | FilterExpression;\n};\n\n/**\n * Webhook information returned by the API\n */\nexport type WebhookInfo = {\n webHookID: number;\n tableName: string;\n url: string;\n headers?: Record<string, string>;\n notifySchemaChanges: boolean;\n select: string;\n filter: string;\n pendingOperations: unknown[];\n};\n\n/**\n * Response from listing all webhooks\n */\nexport type WebhookListResponse = {\n Status: string;\n WebHook: WebhookInfo[];\n};\n\n/**\n * Response from adding a webhook\n */\nexport type WebhookAddResponse = {\n webHookResult: {\n webHookID: number;\n };\n};\n\nexport class WebhookManager {\n constructor(\n private readonly databaseName: string,\n private readonly context: ExecutionContext,\n ) {}\n\n /**\n * Adds a new webhook to the database.\n * @param webhook - The webhook configuration object\n * @param webhook.webhook - The webhook URL to call\n * @param webhook.tableName - The FMTable instance for the table to monitor\n * @param webhook.headers - Optional custom headers to include in webhook requests\n * @param webhook.notifySchemaChanges - Whether to notify on schema changes\n * @param webhook.select - Optional field selection (string or array of Column references)\n * @param webhook.filter - Optional filter (string or FilterExpression)\n * @returns Promise resolving to the created webhook data with ID\n * @example\n * ```ts\n * const result = await db.webhook.add({\n * webhook: \"https://example.com/webhook\",\n * tableName: contactsTable,\n * headers: { \"X-Custom-Header\": \"value\" },\n * });\n * // result.webHookResult.webHookID contains the new webhook ID\n * ```\n * @example\n * ```ts\n * // Using filter expressions and column arrays (same DX as query builder)\n * const result = await db.webhook.add({\n * webhook: \"https://example.com/webhook\",\n * tableName: contacts,\n * filter: eq(contacts.name, \"John\"),\n * select: [contacts.name, contacts.PrimaryKey],\n * });\n * ```\n */\n async add(\n webhook: Webhook<FMTable>,\n options?: ExecuteMethodOptions,\n ): Promise<WebhookAddResponse> {\n // Extract the string table name from the FMTable instance\n const tableName = getTableName(webhook.tableName);\n\n // Get useEntityIds setting (check options first, then context, default to false)\n const useEntityIds =\n options?.useEntityIds ?? this.context._getUseEntityIds?.() ?? false;\n\n // Transform filter if it's a FilterExpression\n let filter: string | undefined;\n if (webhook.filter !== undefined) {\n if (webhook.filter instanceof FilterExpression) {\n filter = webhook.filter.toODataFilter(useEntityIds);\n } else {\n filter = webhook.filter;\n }\n }\n\n // Transform select if it's an array of Columns\n let select: string | undefined;\n if (webhook.select !== undefined) {\n if (Array.isArray(webhook.select)) {\n // Extract field identifiers from columns or use strings as-is\n const fieldNames = webhook.select.map((item) => {\n if (isColumn(item)) {\n return item.getFieldIdentifier(useEntityIds);\n }\n return String(item);\n });\n // Use formatSelectFields to properly format the select string\n select = formatSelectFields(\n fieldNames,\n webhook.tableName,\n useEntityIds,\n );\n } else {\n // Already a string, use as-is\n select = webhook.select;\n }\n }\n\n // Create request body with string table name and transformed filter/select\n const requestBody: {\n webhook: string;\n headers?: Record<string, string>;\n tableName: string;\n notifySchemaChanges?: boolean;\n select?: string;\n filter?: string;\n } = {\n webhook: webhook.webhook,\n tableName,\n };\n\n if (webhook.headers !== undefined) {\n requestBody.headers = webhook.headers;\n }\n if (webhook.notifySchemaChanges !== undefined) {\n requestBody.notifySchemaChanges = webhook.notifySchemaChanges;\n }\n if (select !== undefined) {\n requestBody.select = select;\n }\n if (filter !== undefined) {\n requestBody.filter = filter;\n }\n\n const result = await this.context._makeRequest<WebhookAddResponse>(\n `/${this.databaseName}/Webhook.Add`,\n {\n method: \"POST\",\n body: JSON.stringify(requestBody),\n ...options,\n },\n );\n\n if (result.error) {\n throw result.error;\n }\n\n return result.data;\n }\n\n /**\n * Deletes a webhook by ID.\n * @param webhookId - The ID of the webhook to delete\n * @returns Promise that resolves when the webhook is deleted\n * @example\n * ```ts\n * await db.webhook.remove(1);\n * ```\n */\n async remove(\n webhookId: string | number,\n options?: ExecuteMethodOptions,\n ): Promise<void> {\n const result = await this.context._makeRequest(\n `/${this.databaseName}/Webhook.Delete(${webhookId})`,\n {\n method: \"POST\",\n ...options,\n },\n );\n\n if (result.error) {\n throw result.error;\n }\n }\n\n /**\n * Gets a webhook by ID.\n * @param webhookId - The ID of the webhook to retrieve\n * @returns Promise resolving to the webhook data\n * @example\n * ```ts\n * const webhook = await db.webhook.get(1);\n * // webhook.webHookID, webhook.tableName, webhook.url, etc.\n * ```\n */\n async get(\n webhookId: string | number,\n options?: ExecuteMethodOptions,\n ): Promise<WebhookInfo> {\n const result = await this.context._makeRequest<WebhookInfo>(\n `/${this.databaseName}/Webhook.Get(${webhookId})`,\n options,\n );\n\n if (result.error) {\n throw result.error;\n }\n\n return result.data;\n }\n\n /**\n * Lists all webhooks.\n * @returns Promise resolving to webhook list response with status and webhooks array\n * @example\n * ```ts\n * const result = await db.webhook.list();\n * // result.Status contains the status\n * // result.WebHook contains the array of webhooks\n * ```\n */\n async list(options?: ExecuteMethodOptions): Promise<WebhookListResponse> {\n const result = await this.context._makeRequest<WebhookListResponse>(\n `/${this.databaseName}/Webhook.GetAll`,\n options,\n );\n\n if (result.error) {\n throw result.error;\n }\n\n return result.data;\n }\n\n /**\n * Invokes a webhook by ID, optionally for specific row IDs.\n * @param webhookId - The ID of the webhook to invoke\n * @param options - Optional configuration\n * @param options.rowIDs - Array of row IDs to trigger the webhook for\n * @returns Promise resolving to the invocation result (type unknown until API behavior is confirmed)\n * @example\n * ```ts\n * // Invoke for all rows\n * await db.webhook.invoke(1);\n *\n * // Invoke for specific rows\n * await db.webhook.invoke(1, { rowIDs: [63, 61] });\n * ```\n */\n async invoke(\n webhookId: string | number,\n options?: { rowIDs?: number[] },\n executeOptions?: ExecuteMethodOptions,\n ): Promise<unknown> {\n const body: { rowIDs?: number[] } = {};\n if (options?.rowIDs !== undefined) {\n body.rowIDs = options.rowIDs;\n }\n\n const result = await this.context._makeRequest<unknown>(\n `/${this.databaseName}/Webhook.Invoke(${webhookId})`,\n {\n method: \"POST\",\n body: Object.keys(body).length > 0 ? JSON.stringify(body) : undefined,\n ...executeOptions,\n },\n );\n\n if (result.error) {\n throw result.error;\n }\n\n return result.data;\n }\n}\n"],"names":[],"mappings":"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"}
@@ -3,6 +3,7 @@ export { textField, numberField, dateField, timeField, timestampField, container
3
3
  export type { Database } from './client/database.js';
4
4
  export type { EntitySet } from './client/entity-set.js';
5
5
  export type { SchemaManager, Field, StringField, NumericField, DateField, TimeField, TimestampField, ContainerField, } from './client/schema-manager.js';
6
+ export type { Webhook, WebhookInfo, WebhookListResponse, WebhookAddResponse, } from './client/webhook-builder.js';
6
7
  export type { Result, BatchResult, BatchItemResult, InferSchemaType, ODataRecordMetadata, Metadata, FetchHandler, ExecuteMethodOptions, ExecuteOptions, } from './types.js';
7
8
  export { TimeoutError, AbortError, NetworkError, RetryLimitError, CircuitOpenError, } from '@fetchkit/ffetch';
8
9
  export type { FFetchOptions } from '@fetchkit/ffetch';
@@ -24,12 +24,13 @@ export declare class FieldBuilder<TOutput = any, TInput = TOutput, TDbType = TOu
24
24
  private _outputValidator?;
25
25
  private _inputValidator?;
26
26
  private _fieldType;
27
+ private _comment?;
27
28
  constructor(fieldType: string);
28
29
  /**
29
30
  * Mark this field as the primary key for the table.
30
- * Primary keys are automatically read-only.
31
+ * Primary keys are automatically read-only and non-nullable.
31
32
  */
32
- primaryKey(): FieldBuilder<TOutput, TInput, TDbType, true>;
33
+ primaryKey(): FieldBuilder<NonNullable<TOutput>, NonNullable<TInput>, NonNullable<TDbType>, true>;
33
34
  /**
34
35
  * Mark this field as non-nullable.
35
36
  * Updates the type to exclude null/undefined.
@@ -63,6 +64,14 @@ export declare class FieldBuilder<TOutput = any, TInput = TOutput, TDbType = TOu
63
64
  * // You pass true/false, FileMaker gets 1/0
64
65
  */
65
66
  writeValidator<I>(validator: StandardSchemaV1<I, TDbType>): FieldBuilder<TOutput, I, TDbType, TReadOnly>;
67
+ /**
68
+ * Add a comment to this field for metadata purposes.
69
+ * This helps future developers understand the purpose of the field.
70
+ *
71
+ * @example
72
+ * textField().comment("Account name of the user who last modified each record")
73
+ */
74
+ comment(comment: string): FieldBuilder<TOutput, TInput, TDbType, TReadOnly>;
66
75
  /**
67
76
  * Get the metadata configuration for this field.
68
77
  * @internal Used by fmTableOccurrence to extract field configuration
@@ -75,6 +84,7 @@ export declare class FieldBuilder<TOutput = any, TInput = TOutput, TDbType = TOu
75
84
  entityId: `FMFID:${string}` | undefined;
76
85
  outputValidator: StandardSchemaV1<any, TOutput> | undefined;
77
86
  inputValidator: StandardSchemaV1<TInput, any> | undefined;
87
+ comment: string | undefined;
78
88
  };
79
89
  /**
80
90
  * Clone this builder to allow immutable chaining.
@@ -10,15 +10,17 @@ class FieldBuilder {
10
10
  __publicField(this, "_outputValidator");
11
11
  __publicField(this, "_inputValidator");
12
12
  __publicField(this, "_fieldType");
13
+ __publicField(this, "_comment");
13
14
  this._fieldType = fieldType;
14
15
  }
15
16
  /**
16
17
  * Mark this field as the primary key for the table.
17
- * Primary keys are automatically read-only.
18
+ * Primary keys are automatically read-only and non-nullable.
18
19
  */
19
20
  primaryKey() {
20
21
  const builder = this._clone();
21
22
  builder._primaryKey = true;
23
+ builder._notNull = true;
22
24
  builder._readOnly = true;
23
25
  return builder;
24
26
  }
@@ -75,6 +77,18 @@ class FieldBuilder {
75
77
  builder._inputValidator = validator;
76
78
  return builder;
77
79
  }
80
+ /**
81
+ * Add a comment to this field for metadata purposes.
82
+ * This helps future developers understand the purpose of the field.
83
+ *
84
+ * @example
85
+ * textField().comment("Account name of the user who last modified each record")
86
+ */
87
+ comment(comment) {
88
+ const builder = this._clone();
89
+ builder._comment = comment;
90
+ return builder;
91
+ }
78
92
  /**
79
93
  * Get the metadata configuration for this field.
80
94
  * @internal Used by fmTableOccurrence to extract field configuration
@@ -87,7 +101,8 @@ class FieldBuilder {
87
101
  readOnly: this._readOnly,
88
102
  entityId: this._entityId,
89
103
  outputValidator: this._outputValidator,
90
- inputValidator: this._inputValidator
104
+ inputValidator: this._inputValidator,
105
+ comment: this._comment
91
106
  };
92
107
  }
93
108
  /**
@@ -104,6 +119,7 @@ class FieldBuilder {
104
119
  builder._entityId = this._entityId;
105
120
  builder._outputValidator = this._outputValidator;
106
121
  builder._inputValidator = this._inputValidator;
122
+ builder._comment = this._comment;
107
123
  return builder;
108
124
  }
109
125
  }
@@ -1 +1 @@
1
- {"version":3,"file":"field-builders.js","sources":["../../../src/orm/field-builders.ts"],"sourcesContent":["import type { StandardSchemaV1 } from \"@standard-schema/spec\";\n\n/**\n * Branded type for container field's database type.\n * This allows TypeScript to distinguish container fields from regular string fields\n * at the type level, enabling compile-time exclusion from select operations.\n */\nexport type ContainerDbType = string & { readonly __container: true };\n\n/**\n * FieldBuilder provides a fluent API for defining table fields with type-safe metadata.\n * Supports chaining methods to configure primary keys, nullability, read-only status, entity IDs, and validators.\n *\n * @template TOutput - The output type after applying outputValidator (what you get when reading)\n * @template TInput - The input type after applying inputValidator (what you pass when writing)\n * @template TDbType - The database type (what FileMaker stores/expects)\n * @template TReadOnly - Whether this field is read-only (for type-level exclusion from insert/update)\n */\nexport class FieldBuilder<\n TOutput = any,\n TInput = TOutput,\n TDbType = TOutput,\n TReadOnly extends boolean = false,\n> {\n private _primaryKey = false;\n private _notNull = false;\n private _readOnly = false;\n private _entityId?: `FMFID:${string}`;\n private _outputValidator?: StandardSchemaV1<any, TOutput>;\n private _inputValidator?: StandardSchemaV1<TInput, any>;\n private _fieldType: string;\n\n constructor(fieldType: string) {\n this._fieldType = fieldType;\n }\n\n /**\n * Mark this field as the primary key for the table.\n * Primary keys are automatically read-only.\n */\n primaryKey(): FieldBuilder<TOutput, TInput, TDbType, true> {\n const builder = this._clone() as any;\n builder._primaryKey = true;\n builder._readOnly = true; // Primary keys are automatically read-only\n return builder;\n }\n\n /**\n * Mark this field as non-nullable.\n * Updates the type to exclude null/undefined.\n */\n notNull(): FieldBuilder<\n NonNullable<TOutput>,\n NonNullable<TInput>,\n NonNullable<TDbType>,\n TReadOnly\n > {\n const builder = this._clone() as any;\n builder._notNull = true;\n return builder;\n }\n\n /**\n * Mark this field as read-only.\n * Read-only fields are excluded from insert and update operations.\n */\n readOnly(): FieldBuilder<TOutput, TInput, TDbType, true> {\n const builder = this._clone() as any;\n builder._readOnly = true;\n return builder;\n }\n\n /**\n * Assign a FileMaker field ID (FMFID) to this field.\n * When useEntityIds is enabled, this ID will be used in API requests instead of the field name.\n */\n entityId(\n id: `FMFID:${string}`,\n ): FieldBuilder<TOutput, TInput, TDbType, TReadOnly> {\n const builder = this._clone();\n builder._entityId = id;\n return builder;\n }\n\n /**\n * Set a validator for the output (reading from database).\n * The output validator transforms/validates data coming FROM the database in list or get operations.\n *\n * @example\n * numberField().readValidator(z.coerce.boolean())\n * // FileMaker returns 0/1, you get true/false\n */\n readValidator<O, VInput = TDbType>(\n validator: StandardSchemaV1<VInput, O>,\n ): FieldBuilder<O, TInput, TDbType, TReadOnly> {\n const builder = this._clone() as any;\n builder._outputValidator = validator;\n return builder;\n }\n\n /**\n * Set a validator for the input (writing to database).\n * The input validator transforms/validates data going TO the database in insert, update, and filter operations.\n *\n * @example\n * numberField().writeValidator(z.boolean().transform(v => v ? 1 : 0))\n * // You pass true/false, FileMaker gets 1/0\n */\n writeValidator<I>(\n validator: StandardSchemaV1<I, TDbType>,\n ): FieldBuilder<TOutput, I, TDbType, TReadOnly> {\n const builder = this._clone() as any;\n builder._inputValidator = validator;\n return builder;\n }\n\n /**\n * Get the metadata configuration for this field.\n * @internal Used by fmTableOccurrence to extract field configuration\n */\n _getConfig() {\n return {\n fieldType: this._fieldType,\n primaryKey: this._primaryKey,\n notNull: this._notNull,\n readOnly: this._readOnly,\n entityId: this._entityId,\n outputValidator: this._outputValidator,\n inputValidator: this._inputValidator,\n };\n }\n\n /**\n * Clone this builder to allow immutable chaining.\n * @private\n */\n private _clone(): FieldBuilder<TOutput, TInput, TDbType, TReadOnly> {\n const builder = new FieldBuilder<TOutput, TInput, TDbType, TReadOnly>(\n this._fieldType,\n );\n builder._primaryKey = this._primaryKey;\n builder._notNull = this._notNull;\n builder._readOnly = this._readOnly;\n builder._entityId = this._entityId;\n builder._outputValidator = this._outputValidator;\n builder._inputValidator = this._inputValidator;\n return builder;\n }\n}\n\n/**\n * Create a text field (Edm.String in FileMaker OData).\n * By default, text fields are nullable.\n *\n * @example\n * textField() // string | null\n * textField().notNull() // string\n * textField().entityId(\"FMFID:1\") // with entity ID\n */\nexport function textField(): FieldBuilder<\n string | null,\n string | null,\n string | null,\n false\n> {\n return new FieldBuilder<string | null, string | null, string | null, false>(\n \"text\",\n );\n}\n\n/**\n * Create a number field (Edm.Decimal in FileMaker OData).\n * By default, number fields are nullable.\n *\n * @example\n * numberField() // number | null\n * numberField().notNull() // number\n * numberField().outputValidator(z.coerce.boolean()) // transform to boolean on read\n */\nexport function numberField(): FieldBuilder<\n number | null,\n number | null,\n number | null,\n false\n> {\n return new FieldBuilder<number | null, number | null, number | null, false>(\n \"number\",\n );\n}\n\n/**\n * Create a date field (Edm.Date in FileMaker OData).\n * By default, date fields are nullable and represented as ISO date strings (YYYY-MM-DD).\n *\n * @example\n * dateField() // string | null (ISO date format)\n * dateField().notNull() // string\n */\nexport function dateField(): FieldBuilder<\n string | null,\n string | null,\n string | null,\n false\n> {\n return new FieldBuilder<string | null, string | null, string | null, false>(\n \"date\",\n );\n}\n\n/**\n * Create a time field (Edm.TimeOfDay in FileMaker OData).\n * By default, time fields are nullable and represented as ISO time strings (HH:mm:ss).\n *\n * @example\n * timeField() // string | null (ISO time format)\n * timeField().notNull() // string\n */\nexport function timeField(): FieldBuilder<\n string | null,\n string | null,\n string | null,\n false\n> {\n return new FieldBuilder<string | null, string | null, string | null, false>(\n \"time\",\n );\n}\n\n/**\n * Create a timestamp field (Edm.DateTimeOffset in FileMaker OData).\n * By default, timestamp fields are nullable and represented as ISO 8601 strings.\n *\n * @example\n * timestampField() // string | null (ISO 8601 format)\n * timestampField().notNull() // string\n * timestampField().readOnly() // typical for CreationTimestamp\n */\nexport function timestampField(): FieldBuilder<\n string | null,\n string | null,\n string | null,\n false\n> {\n return new FieldBuilder<string | null, string | null, string | null, false>(\n \"timestamp\",\n );\n}\n\n/**\n * Create a container field (Edm.Stream in FileMaker OData).\n * Container fields store binary data and are represented as base64 strings in the API.\n * By default, container fields are nullable.\n *\n * Note: Container fields cannot be selected via .select() - they can only be accessed\n * via .getSingleField() due to FileMaker OData API limitations.\n *\n * @example\n * containerField() // string | null (base64 encoded)\n * containerField().notNull() // string\n */\nexport function containerField(): FieldBuilder<\n string | null,\n string | null,\n ContainerDbType | null,\n false\n> {\n return new FieldBuilder<\n string | null,\n string | null,\n ContainerDbType | null,\n false\n >(\"container\");\n}\n\n/**\n * Create a calculated field (read-only field computed by FileMaker).\n * Calculated fields are automatically marked as read-only.\n *\n * @example\n * calcField() // string | null\n * calcField().notNull() // string\n */\nexport function calcField(): FieldBuilder<\n string | null,\n string | null,\n string | null,\n true\n> {\n const builder = new FieldBuilder<\n string | null,\n string | null,\n string | null,\n false\n >(\"calculated\");\n return builder.readOnly();\n}\n"],"names":[],"mappings":";;;AAkBO,MAAM,aAKX;AAAA,EASA,YAAY,WAAmB;AARvB,uCAAc;AACd,oCAAW;AACX,qCAAY;AACZ;AACA;AACA;AACA;AAGN,SAAK,aAAa;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOpB,aAA2D;AACnD,UAAA,UAAU,KAAK,OAAO;AAC5B,YAAQ,cAAc;AACtB,YAAQ,YAAY;AACb,WAAA;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOT,UAKE;AACM,UAAA,UAAU,KAAK,OAAO;AAC5B,YAAQ,WAAW;AACZ,WAAA;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOT,WAAyD;AACjD,UAAA,UAAU,KAAK,OAAO;AAC5B,YAAQ,YAAY;AACb,WAAA;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOT,SACE,IACmD;AAC7C,UAAA,UAAU,KAAK,OAAO;AAC5B,YAAQ,YAAY;AACb,WAAA;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWT,cACE,WAC6C;AACvC,UAAA,UAAU,KAAK,OAAO;AAC5B,YAAQ,mBAAmB;AACpB,WAAA;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWT,eACE,WAC8C;AACxC,UAAA,UAAU,KAAK,OAAO;AAC5B,YAAQ,kBAAkB;AACnB,WAAA;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOT,aAAa;AACJ,WAAA;AAAA,MACL,WAAW,KAAK;AAAA,MAChB,YAAY,KAAK;AAAA,MACjB,SAAS,KAAK;AAAA,MACd,UAAU,KAAK;AAAA,MACf,UAAU,KAAK;AAAA,MACf,iBAAiB,KAAK;AAAA,MACtB,gBAAgB,KAAK;AAAA,IACvB;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOM,SAA4D;AAClE,UAAM,UAAU,IAAI;AAAA,MAClB,KAAK;AAAA,IACP;AACA,YAAQ,cAAc,KAAK;AAC3B,YAAQ,WAAW,KAAK;AACxB,YAAQ,YAAY,KAAK;AACzB,YAAQ,YAAY,KAAK;AACzB,YAAQ,mBAAmB,KAAK;AAChC,YAAQ,kBAAkB,KAAK;AACxB,WAAA;AAAA,EAAA;AAEX;AAWO,SAAS,YAKd;AACA,SAAO,IAAI;AAAA,IACT;AAAA,EACF;AACF;AAWO,SAAS,cAKd;AACA,SAAO,IAAI;AAAA,IACT;AAAA,EACF;AACF;AAUO,SAAS,YAKd;AACA,SAAO,IAAI;AAAA,IACT;AAAA,EACF;AACF;AAUO,SAAS,YAKd;AACA,SAAO,IAAI;AAAA,IACT;AAAA,EACF;AACF;AAWO,SAAS,iBAKd;AACA,SAAO,IAAI;AAAA,IACT;AAAA,EACF;AACF;AAcO,SAAS,iBAKd;AACO,SAAA,IAAI,aAKT,WAAW;AACf;AAUO,SAAS,YAKd;AACM,QAAA,UAAU,IAAI,aAKlB,YAAY;AACd,SAAO,QAAQ,SAAS;AAC1B;"}
1
+ {"version":3,"file":"field-builders.js","sources":["../../../src/orm/field-builders.ts"],"sourcesContent":["import type { StandardSchemaV1 } from \"@standard-schema/spec\";\n\n/**\n * Branded type for container field's database type.\n * This allows TypeScript to distinguish container fields from regular string fields\n * at the type level, enabling compile-time exclusion from select operations.\n */\nexport type ContainerDbType = string & { readonly __container: true };\n\n/**\n * FieldBuilder provides a fluent API for defining table fields with type-safe metadata.\n * Supports chaining methods to configure primary keys, nullability, read-only status, entity IDs, and validators.\n *\n * @template TOutput - The output type after applying outputValidator (what you get when reading)\n * @template TInput - The input type after applying inputValidator (what you pass when writing)\n * @template TDbType - The database type (what FileMaker stores/expects)\n * @template TReadOnly - Whether this field is read-only (for type-level exclusion from insert/update)\n */\nexport class FieldBuilder<\n TOutput = any,\n TInput = TOutput,\n TDbType = TOutput,\n TReadOnly extends boolean = false,\n> {\n private _primaryKey = false;\n private _notNull = false;\n private _readOnly = false;\n private _entityId?: `FMFID:${string}`;\n private _outputValidator?: StandardSchemaV1<any, TOutput>;\n private _inputValidator?: StandardSchemaV1<TInput, any>;\n private _fieldType: string;\n private _comment?: string;\n\n constructor(fieldType: string) {\n this._fieldType = fieldType;\n }\n\n /**\n * Mark this field as the primary key for the table.\n * Primary keys are automatically read-only and non-nullable.\n */\n primaryKey(): FieldBuilder<\n NonNullable<TOutput>,\n NonNullable<TInput>,\n NonNullable<TDbType>,\n true\n > {\n const builder = this._clone() as any;\n builder._primaryKey = true;\n builder._notNull = true; // Primary keys are automatically non-nullable\n builder._readOnly = true; // Primary keys are automatically read-only\n return builder;\n }\n\n /**\n * Mark this field as non-nullable.\n * Updates the type to exclude null/undefined.\n */\n notNull(): FieldBuilder<\n NonNullable<TOutput>,\n NonNullable<TInput>,\n NonNullable<TDbType>,\n TReadOnly\n > {\n const builder = this._clone() as any;\n builder._notNull = true;\n return builder;\n }\n\n /**\n * Mark this field as read-only.\n * Read-only fields are excluded from insert and update operations.\n */\n readOnly(): FieldBuilder<TOutput, TInput, TDbType, true> {\n const builder = this._clone() as any;\n builder._readOnly = true;\n return builder;\n }\n\n /**\n * Assign a FileMaker field ID (FMFID) to this field.\n * When useEntityIds is enabled, this ID will be used in API requests instead of the field name.\n */\n entityId(\n id: `FMFID:${string}`,\n ): FieldBuilder<TOutput, TInput, TDbType, TReadOnly> {\n const builder = this._clone();\n builder._entityId = id;\n return builder;\n }\n\n /**\n * Set a validator for the output (reading from database).\n * The output validator transforms/validates data coming FROM the database in list or get operations.\n *\n * @example\n * numberField().readValidator(z.coerce.boolean())\n * // FileMaker returns 0/1, you get true/false\n */\n readValidator<O, VInput = TDbType>(\n validator: StandardSchemaV1<VInput, O>,\n ): FieldBuilder<O, TInput, TDbType, TReadOnly> {\n const builder = this._clone() as any;\n builder._outputValidator = validator;\n return builder;\n }\n\n /**\n * Set a validator for the input (writing to database).\n * The input validator transforms/validates data going TO the database in insert, update, and filter operations.\n *\n * @example\n * numberField().writeValidator(z.boolean().transform(v => v ? 1 : 0))\n * // You pass true/false, FileMaker gets 1/0\n */\n writeValidator<I>(\n validator: StandardSchemaV1<I, TDbType>,\n ): FieldBuilder<TOutput, I, TDbType, TReadOnly> {\n const builder = this._clone() as any;\n builder._inputValidator = validator;\n return builder;\n }\n\n /**\n * Add a comment to this field for metadata purposes.\n * This helps future developers understand the purpose of the field.\n *\n * @example\n * textField().comment(\"Account name of the user who last modified each record\")\n */\n comment(comment: string): FieldBuilder<TOutput, TInput, TDbType, TReadOnly> {\n const builder = this._clone();\n builder._comment = comment;\n return builder;\n }\n\n /**\n * Get the metadata configuration for this field.\n * @internal Used by fmTableOccurrence to extract field configuration\n */\n _getConfig() {\n return {\n fieldType: this._fieldType,\n primaryKey: this._primaryKey,\n notNull: this._notNull,\n readOnly: this._readOnly,\n entityId: this._entityId,\n outputValidator: this._outputValidator,\n inputValidator: this._inputValidator,\n comment: this._comment,\n };\n }\n\n /**\n * Clone this builder to allow immutable chaining.\n * @private\n */\n private _clone(): FieldBuilder<TOutput, TInput, TDbType, TReadOnly> {\n const builder = new FieldBuilder<TOutput, TInput, TDbType, TReadOnly>(\n this._fieldType,\n );\n builder._primaryKey = this._primaryKey;\n builder._notNull = this._notNull;\n builder._readOnly = this._readOnly;\n builder._entityId = this._entityId;\n builder._outputValidator = this._outputValidator;\n builder._inputValidator = this._inputValidator;\n builder._comment = this._comment;\n return builder;\n }\n}\n\n/**\n * Create a text field (Edm.String in FileMaker OData).\n * By default, text fields are nullable.\n *\n * @example\n * textField() // string | null\n * textField().notNull() // string\n * textField().entityId(\"FMFID:1\") // with entity ID\n */\nexport function textField(): FieldBuilder<\n string | null,\n string | null,\n string | null,\n false\n> {\n return new FieldBuilder<string | null, string | null, string | null, false>(\n \"text\",\n );\n}\n\n/**\n * Create a number field (Edm.Decimal in FileMaker OData).\n * By default, number fields are nullable.\n *\n * @example\n * numberField() // number | null\n * numberField().notNull() // number\n * numberField().outputValidator(z.coerce.boolean()) // transform to boolean on read\n */\nexport function numberField(): FieldBuilder<\n number | null,\n number | null,\n number | null,\n false\n> {\n return new FieldBuilder<number | null, number | null, number | null, false>(\n \"number\",\n );\n}\n\n/**\n * Create a date field (Edm.Date in FileMaker OData).\n * By default, date fields are nullable and represented as ISO date strings (YYYY-MM-DD).\n *\n * @example\n * dateField() // string | null (ISO date format)\n * dateField().notNull() // string\n */\nexport function dateField(): FieldBuilder<\n string | null,\n string | null,\n string | null,\n false\n> {\n return new FieldBuilder<string | null, string | null, string | null, false>(\n \"date\",\n );\n}\n\n/**\n * Create a time field (Edm.TimeOfDay in FileMaker OData).\n * By default, time fields are nullable and represented as ISO time strings (HH:mm:ss).\n *\n * @example\n * timeField() // string | null (ISO time format)\n * timeField().notNull() // string\n */\nexport function timeField(): FieldBuilder<\n string | null,\n string | null,\n string | null,\n false\n> {\n return new FieldBuilder<string | null, string | null, string | null, false>(\n \"time\",\n );\n}\n\n/**\n * Create a timestamp field (Edm.DateTimeOffset in FileMaker OData).\n * By default, timestamp fields are nullable and represented as ISO 8601 strings.\n *\n * @example\n * timestampField() // string | null (ISO 8601 format)\n * timestampField().notNull() // string\n * timestampField().readOnly() // typical for CreationTimestamp\n */\nexport function timestampField(): FieldBuilder<\n string | null,\n string | null,\n string | null,\n false\n> {\n return new FieldBuilder<string | null, string | null, string | null, false>(\n \"timestamp\",\n );\n}\n\n/**\n * Create a container field (Edm.Stream in FileMaker OData).\n * Container fields store binary data and are represented as base64 strings in the API.\n * By default, container fields are nullable.\n *\n * Note: Container fields cannot be selected via .select() - they can only be accessed\n * via .getSingleField() due to FileMaker OData API limitations.\n *\n * @example\n * containerField() // string | null (base64 encoded)\n * containerField().notNull() // string\n */\nexport function containerField(): FieldBuilder<\n string | null,\n string | null,\n ContainerDbType | null,\n false\n> {\n return new FieldBuilder<\n string | null,\n string | null,\n ContainerDbType | null,\n false\n >(\"container\");\n}\n\n/**\n * Create a calculated field (read-only field computed by FileMaker).\n * Calculated fields are automatically marked as read-only.\n *\n * @example\n * calcField() // string | null\n * calcField().notNull() // string\n */\nexport function calcField(): FieldBuilder<\n string | null,\n string | null,\n string | null,\n true\n> {\n const builder = new FieldBuilder<\n string | null,\n string | null,\n string | null,\n false\n >(\"calculated\");\n return builder.readOnly();\n}\n"],"names":[],"mappings":";;;AAkBO,MAAM,aAKX;AAAA,EAUA,YAAY,WAAmB;AATvB,uCAAc;AACd,oCAAW;AACX,qCAAY;AACZ;AACA;AACA;AACA;AACA;AAGN,SAAK,aAAa;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOpB,aAKE;AACM,UAAA,UAAU,KAAK,OAAO;AAC5B,YAAQ,cAAc;AACtB,YAAQ,WAAW;AACnB,YAAQ,YAAY;AACb,WAAA;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOT,UAKE;AACM,UAAA,UAAU,KAAK,OAAO;AAC5B,YAAQ,WAAW;AACZ,WAAA;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOT,WAAyD;AACjD,UAAA,UAAU,KAAK,OAAO;AAC5B,YAAQ,YAAY;AACb,WAAA;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOT,SACE,IACmD;AAC7C,UAAA,UAAU,KAAK,OAAO;AAC5B,YAAQ,YAAY;AACb,WAAA;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWT,cACE,WAC6C;AACvC,UAAA,UAAU,KAAK,OAAO;AAC5B,YAAQ,mBAAmB;AACpB,WAAA;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWT,eACE,WAC8C;AACxC,UAAA,UAAU,KAAK,OAAO;AAC5B,YAAQ,kBAAkB;AACnB,WAAA;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUT,QAAQ,SAAoE;AACpE,UAAA,UAAU,KAAK,OAAO;AAC5B,YAAQ,WAAW;AACZ,WAAA;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOT,aAAa;AACJ,WAAA;AAAA,MACL,WAAW,KAAK;AAAA,MAChB,YAAY,KAAK;AAAA,MACjB,SAAS,KAAK;AAAA,MACd,UAAU,KAAK;AAAA,MACf,UAAU,KAAK;AAAA,MACf,iBAAiB,KAAK;AAAA,MACtB,gBAAgB,KAAK;AAAA,MACrB,SAAS,KAAK;AAAA,IAChB;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOM,SAA4D;AAClE,UAAM,UAAU,IAAI;AAAA,MAClB,KAAK;AAAA,IACP;AACA,YAAQ,cAAc,KAAK;AAC3B,YAAQ,WAAW,KAAK;AACxB,YAAQ,YAAY,KAAK;AACzB,YAAQ,YAAY,KAAK;AACzB,YAAQ,mBAAmB,KAAK;AAChC,YAAQ,kBAAkB,KAAK;AAC/B,YAAQ,WAAW,KAAK;AACjB,WAAA;AAAA,EAAA;AAEX;AAWO,SAAS,YAKd;AACA,SAAO,IAAI;AAAA,IACT;AAAA,EACF;AACF;AAWO,SAAS,cAKd;AACA,SAAO,IAAI;AAAA,IACT;AAAA,EACF;AACF;AAUO,SAAS,YAKd;AACA,SAAO,IAAI;AAAA,IACT;AAAA,EACF;AACF;AAUO,SAAS,YAKd;AACA,SAAO,IAAI;AAAA,IACT;AAAA,EACF;AACF;AAWO,SAAS,iBAKd;AACA,SAAO,IAAI;AAAA,IACT;AAAA,EACF;AACF;AAcO,SAAS,iBAKd;AACO,SAAA,IAAI,aAKT,WAAW;AACf;AAUO,SAAS,YAKd;AACM,QAAA,UAAU,IAAI,aAKlB,YAAY;AACd,SAAO,QAAQ,SAAS;AAC1B;"}
@@ -56,6 +56,7 @@ declare const FMTableNavigationPaths: unique symbol;
56
56
  declare const FMTableDefaultSelect: unique symbol;
57
57
  declare const FMTableBaseTableConfig: unique symbol;
58
58
  declare const FMTableUseEntityIds: unique symbol;
59
+ declare const FMTableComment: unique symbol;
59
60
  /**
60
61
  * Base table class with Symbol-based internal properties.
61
62
  * This follows the Drizzle ORM pattern where internal configuration
@@ -75,6 +76,7 @@ export declare class FMTable<TFields extends Record<string, FieldBuilder<any, an
75
76
  NavigationPaths: symbol;
76
77
  DefaultSelect: symbol;
77
78
  BaseTableConfig: symbol;
79
+ Comment: symbol;
78
80
  };
79
81
  /** @internal */
80
82
  [FMTableName]: TName;
@@ -83,7 +85,9 @@ export declare class FMTable<TFields extends Record<string, FieldBuilder<any, an
83
85
  /** @internal */
84
86
  [FMTableUseEntityIds]?: boolean;
85
87
  /** @internal */
86
- [FMTableSchema]: StandardSchemaV1<any, InferSchemaFromFields<TFields>>;
88
+ [FMTableComment]?: string;
89
+ /** @internal */
90
+ [FMTableSchema]: Partial<Record<keyof TFields, StandardSchemaV1>>;
87
91
  /** @internal */
88
92
  [FMTableFields]: TFields;
89
93
  /** @internal */
@@ -92,8 +96,8 @@ export declare class FMTable<TFields extends Record<string, FieldBuilder<any, an
92
96
  [FMTableDefaultSelect]: "all" | "schema" | Record<string, Column<any, any, TName>>;
93
97
  /** @internal */
94
98
  [FMTableBaseTableConfig]: {
95
- schema: Record<keyof TFields, StandardSchemaV1>;
96
- inputSchema?: Record<keyof TFields, StandardSchemaV1>;
99
+ schema: Partial<Record<keyof TFields, StandardSchemaV1>>;
100
+ inputSchema?: Partial<Record<keyof TFields, StandardSchemaV1>>;
97
101
  idField?: keyof TFields;
98
102
  required: readonly (keyof TFields)[];
99
103
  readOnly: readonly (keyof TFields)[];
@@ -104,13 +108,14 @@ export declare class FMTable<TFields extends Record<string, FieldBuilder<any, an
104
108
  name: TName;
105
109
  entityId?: `FMTID:${string}`;
106
110
  useEntityIds?: boolean;
107
- schema: StandardSchemaV1<any, InferSchemaFromFields<TFields>>;
111
+ comment?: string;
112
+ schema: Partial<Record<keyof TFields, StandardSchemaV1>>;
108
113
  fields: TFields;
109
114
  navigationPaths: TNavigationPaths;
110
115
  defaultSelect: "all" | "schema" | Record<string, Column<any, any, TName>>;
111
116
  baseTableConfig: {
112
- schema: Record<keyof TFields, StandardSchemaV1>;
113
- inputSchema?: Record<keyof TFields, StandardSchemaV1>;
117
+ schema: Partial<Record<keyof TFields, StandardSchemaV1>>;
118
+ inputSchema?: Partial<Record<keyof TFields, StandardSchemaV1>>;
114
119
  idField?: keyof TFields;
115
120
  required: readonly (keyof TFields)[];
116
121
  readOnly: readonly (keyof TFields)[];
@@ -157,6 +162,8 @@ export type FMTableWithColumns<TFields extends Record<string, FieldBuilder<any,
157
162
  export interface FMTableOccurrenceOptions<TFields extends Record<string, FieldBuilder<any, any, any, any>>, TName extends string> {
158
163
  /** The entity ID (FMTID) for this table occurrence */
159
164
  entityId?: `FMTID:${string}`;
165
+ /** The comment for this table */
166
+ comment?: string;
160
167
  /**
161
168
  * Default select behavior:
162
169
  * - "all": Select all fields (including related tables)
@@ -264,9 +271,9 @@ export declare function getTableEntityId<T extends FMTable<any, any>>(table: T):
264
271
  /**
265
272
  * Get the schema validator from an FMTable instance.
266
273
  * @param table - FMTable instance
267
- * @returns The StandardSchemaV1 validator
274
+ * @returns The StandardSchemaV1 validator record (partial - only fields with validators)
268
275
  */
269
- export declare function getTableSchema<T extends FMTable<any, any>>(table: T): StandardSchemaV1;
276
+ export declare function getTableSchema<T extends FMTable<any, any>>(table: T): Partial<Record<keyof T[typeof FMTableFields], StandardSchemaV1>>;
270
277
  /**
271
278
  * Get the fields from an FMTable instance.
272
279
  * @param table - FMTable instance
@@ -292,8 +299,8 @@ export declare function getDefaultSelect<T extends FMTable<any, any>>(table: T):
292
299
  * @returns Base table configuration object
293
300
  */
294
301
  export declare function getBaseTableConfig<T extends FMTable<any, any>>(table: T): {
295
- schema: Record<string | number | symbol, StandardSchemaV1<unknown, unknown>>;
296
- inputSchema?: Record<string | number | symbol, StandardSchemaV1<unknown, unknown>> | undefined;
302
+ schema: Partial<Record<string | number | symbol, StandardSchemaV1<unknown, unknown>>>;
303
+ inputSchema?: Partial<Record<string | number | symbol, StandardSchemaV1<unknown, unknown>>> | undefined;
297
304
  idField?: string | number | symbol | undefined;
298
305
  required: readonly (string | number | symbol)[];
299
306
  readOnly: readonly (string | number | symbol)[];
@@ -327,6 +334,12 @@ export declare function getFieldName<T extends FMTable<any, any>>(table: T, fiel
327
334
  * @returns The FMTID string or the table name
328
335
  */
329
336
  export declare function getTableId<T extends FMTable<any, any>>(table: T): string;
337
+ /**
338
+ * Get the comment from an FMTable instance.
339
+ * @param table - FMTable instance
340
+ * @returns The comment string or undefined if not set
341
+ */
342
+ export declare function getTableComment<T extends FMTable<any, any>>(table: T): string | undefined;
330
343
  /**
331
344
  * Get all columns from a table as an object.
332
345
  * Useful for selecting all fields except some using destructuring.