fireberry-api-client 1.0.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js ADDED
@@ -0,0 +1,1586 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropNames = Object.getOwnPropertyNames;
3
+ var __esm = (fn, res) => function __init() {
4
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
5
+ };
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+
11
+ // src/constants/excludedFields.ts
12
+ var excludedFields_exports = {};
13
+ __export(excludedFields_exports, {
14
+ EXCLUDED_FIELDS_FOR_STAR_QUERY: () => EXCLUDED_FIELDS_FOR_STAR_QUERY,
15
+ getExcludedFieldsForStarQuery: () => getExcludedFieldsForStarQuery,
16
+ isExcludedFromStarQuery: () => isExcludedFromStarQuery
17
+ });
18
+ function isExcludedFromStarQuery(objectType, fieldName) {
19
+ const objectTypeStr = String(objectType);
20
+ const excludedFields = EXCLUDED_FIELDS_FOR_STAR_QUERY[objectTypeStr];
21
+ return excludedFields ? excludedFields.includes(fieldName) : false;
22
+ }
23
+ function getExcludedFieldsForStarQuery(objectType) {
24
+ const objectTypeStr = String(objectType);
25
+ return EXCLUDED_FIELDS_FOR_STAR_QUERY[objectTypeStr] || [];
26
+ }
27
+ var EXCLUDED_FIELDS_FOR_STAR_QUERY;
28
+ var init_excludedFields = __esm({
29
+ "src/constants/excludedFields.ts"() {
30
+ EXCLUDED_FIELDS_FOR_STAR_QUERY = {
31
+ "7": ["deletedon", "deletedby"],
32
+ // Note
33
+ "8": ["deletedon", "deletedby"],
34
+ // Competitor
35
+ "114": ["deletedon", "deletedby"],
36
+ // Calendar Resource
37
+ "115": ["deletedon", "deletedby"],
38
+ // Customer Journey
39
+ "116": ["deletedon", "deletedby"],
40
+ // Profile
41
+ "117": ["deletedon", "deletedby"]
42
+ // Landing Page
43
+ };
44
+ }
45
+ });
46
+
47
+ // src/errors.ts
48
+ var FireberryErrorCode = /* @__PURE__ */ ((FireberryErrorCode2) => {
49
+ FireberryErrorCode2["UNKNOWN"] = "UNKNOWN";
50
+ FireberryErrorCode2["NETWORK_ERROR"] = "NETWORK_ERROR";
51
+ FireberryErrorCode2["TIMEOUT"] = "TIMEOUT";
52
+ FireberryErrorCode2["AUTHENTICATION_FAILED"] = "AUTHENTICATION_FAILED";
53
+ FireberryErrorCode2["AUTHORIZATION_FAILED"] = "AUTHORIZATION_FAILED";
54
+ FireberryErrorCode2["NOT_FOUND"] = "NOT_FOUND";
55
+ FireberryErrorCode2["RATE_LIMITED"] = "RATE_LIMITED";
56
+ FireberryErrorCode2["INVALID_REQUEST"] = "INVALID_REQUEST";
57
+ FireberryErrorCode2["SERVER_ERROR"] = "SERVER_ERROR";
58
+ FireberryErrorCode2["ABORTED"] = "ABORTED";
59
+ FireberryErrorCode2["INVALID_RESPONSE"] = "INVALID_RESPONSE";
60
+ return FireberryErrorCode2;
61
+ })(FireberryErrorCode || {});
62
+ var FireberryError = class _FireberryError extends Error {
63
+ /** Error code */
64
+ code;
65
+ /** HTTP status code if applicable */
66
+ statusCode;
67
+ /** Original error that caused this error */
68
+ cause;
69
+ /** Additional context data */
70
+ context;
71
+ constructor(message, options) {
72
+ super(message);
73
+ this.name = "FireberryError";
74
+ this.code = options.code;
75
+ this.statusCode = options.statusCode;
76
+ this.cause = options.cause;
77
+ this.context = options.context;
78
+ if (Error.captureStackTrace) {
79
+ Error.captureStackTrace(this, _FireberryError);
80
+ }
81
+ }
82
+ /**
83
+ * Creates a string representation of the error
84
+ */
85
+ toString() {
86
+ let str = `${this.name} [${this.code}]: ${this.message}`;
87
+ if (this.statusCode) {
88
+ str += ` (HTTP ${this.statusCode})`;
89
+ }
90
+ return str;
91
+ }
92
+ /**
93
+ * Converts the error to a plain object for logging/serialization
94
+ */
95
+ toJSON() {
96
+ return {
97
+ name: this.name,
98
+ message: this.message,
99
+ code: this.code,
100
+ statusCode: this.statusCode,
101
+ context: this.context,
102
+ stack: this.stack
103
+ };
104
+ }
105
+ };
106
+ function createErrorFromResponse(response, body) {
107
+ const status = response.status;
108
+ let code;
109
+ let message;
110
+ switch (status) {
111
+ case 400:
112
+ code = "INVALID_REQUEST" /* INVALID_REQUEST */;
113
+ message = "Invalid request parameters";
114
+ break;
115
+ case 401:
116
+ code = "AUTHENTICATION_FAILED" /* AUTHENTICATION_FAILED */;
117
+ message = "Authentication failed - invalid or missing API key";
118
+ break;
119
+ case 403:
120
+ code = "AUTHORIZATION_FAILED" /* AUTHORIZATION_FAILED */;
121
+ message = "Authorization failed - insufficient permissions";
122
+ break;
123
+ case 404:
124
+ code = "NOT_FOUND" /* NOT_FOUND */;
125
+ message = "Resource not found";
126
+ break;
127
+ case 429:
128
+ code = "RATE_LIMITED" /* RATE_LIMITED */;
129
+ message = "Rate limit exceeded - too many requests";
130
+ break;
131
+ default:
132
+ if (status >= 500) {
133
+ code = "SERVER_ERROR" /* SERVER_ERROR */;
134
+ message = `Server error (${status})`;
135
+ } else {
136
+ code = "UNKNOWN" /* UNKNOWN */;
137
+ message = `HTTP error ${status}`;
138
+ }
139
+ }
140
+ if (body && typeof body === "object") {
141
+ const bodyObj = body;
142
+ if (typeof bodyObj.message === "string") {
143
+ message = bodyObj.message;
144
+ } else if (typeof bodyObj.error === "string") {
145
+ message = bodyObj.error;
146
+ }
147
+ }
148
+ return new FireberryError(message, {
149
+ code,
150
+ statusCode: status,
151
+ context: { body }
152
+ });
153
+ }
154
+ function createNetworkError(error) {
155
+ if (error.name === "AbortError") {
156
+ return new FireberryError("Request was aborted", {
157
+ code: "ABORTED" /* ABORTED */,
158
+ cause: error
159
+ });
160
+ }
161
+ if (error.name === "TimeoutError" || error.message.includes("timeout")) {
162
+ return new FireberryError("Request timed out", {
163
+ code: "TIMEOUT" /* TIMEOUT */,
164
+ cause: error
165
+ });
166
+ }
167
+ return new FireberryError(`Network error: ${error.message}`, {
168
+ code: "NETWORK_ERROR" /* NETWORK_ERROR */,
169
+ cause: error
170
+ });
171
+ }
172
+
173
+ // src/utils/helpers.ts
174
+ function wait(ms) {
175
+ return new Promise((resolve) => {
176
+ setTimeout(resolve, ms);
177
+ });
178
+ }
179
+ function chunkArray(array, size) {
180
+ const result = [];
181
+ for (let i = 0; i < array.length; i += size) {
182
+ result.push(array.slice(i, i + size));
183
+ }
184
+ return result;
185
+ }
186
+
187
+ // src/utils/queryBuilder.ts
188
+ function escapeQueryValue(value) {
189
+ if (!value) {
190
+ return "";
191
+ }
192
+ let escaped = value.replace(/\\/g, "\\\\");
193
+ escaped = escaped.replace(/\(/g, "\\(");
194
+ escaped = escaped.replace(/\)/g, "\\)");
195
+ escaped = escaped.replace(/\bor\b/gi, "\\or");
196
+ escaped = escaped.replace(/\band\b/gi, "\\and");
197
+ return escaped;
198
+ }
199
+ function sanitizeQuery(query) {
200
+ if (!query) {
201
+ return "";
202
+ }
203
+ query = query.replace(
204
+ /\(\s*([a-zA-Z0-9_]+)\s+(is-null|is-not-null)\s*\)/g,
205
+ "($1 __SPECIAL_OPERATOR__$2)"
206
+ );
207
+ query = query.replace(
208
+ /\(\s*([a-zA-Z0-9_]+)\s+(start-with|not-start-with)\s+([^)]+)\s*\)/g,
209
+ "($1 __TEXT_OPERATOR__$2 $3)"
210
+ );
211
+ query = query.replace(
212
+ /\(\s*([a-zA-Z0-9_]+(?:field|Field|system|System)[0-9]*)\s+(?!__SPECIAL_OPERATOR__|__TEXT_OPERATOR__)([^()<>=!]+)\s*\)/g,
213
+ "($1 = $2)"
214
+ );
215
+ query = query.replace(
216
+ /\(\s*([a-zA-Z0-9_]+)\s+(?!__SPECIAL_OPERATOR__|__TEXT_OPERATOR__|<=|>=|!=|<|>|=\s)([^()<>]+)\s*\)/g,
217
+ "($1 = $2)"
218
+ );
219
+ query = query.replace(/__SPECIAL_OPERATOR__/g, "");
220
+ query = query.replace(/__TEXT_OPERATOR__/g, "");
221
+ query = query.replace(/\(\s*(?:<=|>=|!=|<|>|=)\s*\)/g, "");
222
+ query = query.replace(/\(\s*(?:start-with|not-start-with)\s*\)/gi, "");
223
+ query = query.replace(/\(\s*(?:and|or)\s*\)/gi, "");
224
+ query = query.replace(/\(\s*\)/g, "");
225
+ query = query.replace(/^\s*(and|or)\s*/gi, "");
226
+ query = query.replace(/\s*(and|or)\s*$/gi, "");
227
+ const nestedPattern = /\(\s*\(([^()]+)\)\s*\)/g;
228
+ while (nestedPattern.test(query)) {
229
+ query = query.replace(nestedPattern, "($1)");
230
+ }
231
+ query = query.replace(/\s+/g, " ");
232
+ return query.trim();
233
+ }
234
+ var QueryBuilder = class {
235
+ conditions = [];
236
+ joinOperators = [];
237
+ currentField = null;
238
+ selectedFields = [];
239
+ objectTypeId = null;
240
+ sortByField = null;
241
+ sortDirection = "desc";
242
+ limitValue = null;
243
+ pageNumber = 1;
244
+ showRealValueFlag = true;
245
+ client = null;
246
+ /**
247
+ * Creates a new QueryBuilder
248
+ * @param client - Optional FireberryClient for executing queries
249
+ */
250
+ constructor(client) {
251
+ this.client = client ?? null;
252
+ }
253
+ /**
254
+ * Sets the object type for the query
255
+ * @param objectType - Object type ID (e.g., '1' for Account)
256
+ */
257
+ objectType(objectType) {
258
+ this.objectTypeId = String(objectType);
259
+ return this;
260
+ }
261
+ /**
262
+ * Adds fields to select
263
+ * @param fields - Field names to select
264
+ */
265
+ select(...fields) {
266
+ this.selectedFields.push(...fields);
267
+ return this;
268
+ }
269
+ /**
270
+ * Starts a new WHERE condition
271
+ * @param field - Field name to filter on
272
+ */
273
+ where(field) {
274
+ this.currentField = field;
275
+ return this.createConditionBuilder();
276
+ }
277
+ /**
278
+ * Adds an AND logical operator
279
+ */
280
+ and() {
281
+ if (this.conditions.length > 0) {
282
+ this.joinOperators.push("and");
283
+ }
284
+ return this;
285
+ }
286
+ /**
287
+ * Adds an OR logical operator
288
+ */
289
+ or() {
290
+ if (this.conditions.length > 0) {
291
+ this.joinOperators.push("or");
292
+ }
293
+ return this;
294
+ }
295
+ /**
296
+ * Sets the sort field and direction
297
+ * @param field - Field to sort by
298
+ * @param direction - Sort direction ('asc' or 'desc')
299
+ */
300
+ sortBy(field, direction = "desc") {
301
+ this.sortByField = field;
302
+ this.sortDirection = direction;
303
+ return this;
304
+ }
305
+ /**
306
+ * Sets the maximum number of records to return
307
+ * @param count - Maximum record count
308
+ */
309
+ limit(count) {
310
+ this.limitValue = count;
311
+ return this;
312
+ }
313
+ /**
314
+ * Sets the page number for pagination
315
+ * @param page - Page number (1-based)
316
+ */
317
+ page(page) {
318
+ this.pageNumber = page;
319
+ return this;
320
+ }
321
+ /**
322
+ * Controls whether to show real values (labels) for dropdown fields
323
+ * @param show - Whether to show real values (default: true)
324
+ */
325
+ showRealValue(show) {
326
+ this.showRealValueFlag = show;
327
+ return this;
328
+ }
329
+ /**
330
+ * Builds the query string from conditions
331
+ * @returns The built query string
332
+ */
333
+ build() {
334
+ if (this.conditions.length === 0) {
335
+ return "";
336
+ }
337
+ const parts = [];
338
+ for (let i = 0; i < this.conditions.length; i++) {
339
+ const condition = this.conditions[i];
340
+ let conditionStr;
341
+ if (condition.operator === "is-null" || condition.operator === "is-not-null") {
342
+ conditionStr = `(${condition.field} ${condition.operator})`;
343
+ } else {
344
+ const escapedValue = escapeQueryValue(condition.value || "");
345
+ conditionStr = `(${condition.field} ${condition.operator} ${escapedValue})`;
346
+ }
347
+ parts.push(conditionStr);
348
+ if (i < this.joinOperators.length) {
349
+ parts.push(this.joinOperators[i]);
350
+ }
351
+ }
352
+ return parts.join(" ");
353
+ }
354
+ /**
355
+ * Returns the selected fields array
356
+ * Useful for inspecting the query configuration
357
+ */
358
+ getFields() {
359
+ return [...this.selectedFields];
360
+ }
361
+ /**
362
+ * Converts the query builder state to a payload compatible with @fireberry/sdk
363
+ *
364
+ * @returns Object with `fields` (comma-separated string) and `query` (filter string)
365
+ *
366
+ * @example
367
+ * ```typescript
368
+ * import FireberryClientSDK from '@fireberry/sdk/client';
369
+ * import { QueryBuilder } from 'fireberry-api-client';
370
+ *
371
+ * const sdk = new FireberryClientSDK();
372
+ * await sdk.initializeContext();
373
+ *
374
+ * const payload = new QueryBuilder()
375
+ * .select('accountid', 'accountname')
376
+ * .where('statuscode').equals('1')
377
+ * .toSDKPayload();
378
+ *
379
+ * // Use with SDK
380
+ * const results = await sdk.api.query(1, payload);
381
+ * ```
382
+ */
383
+ toSDKPayload() {
384
+ const payload = {
385
+ fields: this.selectedFields.length > 0 ? this.selectedFields.join(",") : "*",
386
+ query: this.build()
387
+ };
388
+ if (this.limitValue !== null) {
389
+ payload.page_size = this.limitValue;
390
+ }
391
+ if (this.pageNumber > 1) {
392
+ payload.page_number = this.pageNumber;
393
+ }
394
+ return payload;
395
+ }
396
+ /**
397
+ * Executes the query (requires client to be set)
398
+ * @param signal - Optional AbortSignal for cancellation
399
+ * @returns Query results
400
+ */
401
+ async execute(signal) {
402
+ if (!this.client) {
403
+ throw new Error("QueryBuilder requires a client to execute queries. Pass a FireberryClient to the constructor.");
404
+ }
405
+ if (!this.objectTypeId) {
406
+ throw new Error("Object type is required. Use .objectType() before executing.");
407
+ }
408
+ const queryOptions = {
409
+ objectType: this.objectTypeId,
410
+ fields: this.selectedFields.length > 0 ? this.selectedFields : ["*"],
411
+ query: this.build(),
412
+ showRealValue: this.showRealValueFlag
413
+ };
414
+ if (this.sortByField) {
415
+ queryOptions.sortBy = this.sortByField;
416
+ queryOptions.sortType = this.sortDirection;
417
+ }
418
+ if (this.limitValue !== null) {
419
+ queryOptions.limit = this.limitValue;
420
+ }
421
+ if (this.pageNumber > 1) {
422
+ queryOptions.page = this.pageNumber;
423
+ }
424
+ if (signal) {
425
+ queryOptions.signal = signal;
426
+ }
427
+ return this.client.query(queryOptions);
428
+ }
429
+ /**
430
+ * Creates a condition builder for the current field
431
+ */
432
+ createConditionBuilder() {
433
+ const field = this.currentField;
434
+ return {
435
+ equals: (value) => {
436
+ this.addCondition(field, "=", String(value));
437
+ return this;
438
+ },
439
+ notEquals: (value) => {
440
+ this.addCondition(field, "!=", String(value));
441
+ return this;
442
+ },
443
+ lessThan: (value) => {
444
+ this.addCondition(field, "<", String(value));
445
+ return this;
446
+ },
447
+ greaterThan: (value) => {
448
+ this.addCondition(field, ">", String(value));
449
+ return this;
450
+ },
451
+ lessThanOrEqual: (value) => {
452
+ this.addCondition(field, "<=", String(value));
453
+ return this;
454
+ },
455
+ greaterThanOrEqual: (value) => {
456
+ this.addCondition(field, ">=", String(value));
457
+ return this;
458
+ },
459
+ contains: (value) => {
460
+ this.addCondition(field, "start-with", `%${value}`);
461
+ return this;
462
+ },
463
+ notContains: (value) => {
464
+ this.addCondition(field, "not-start-with", `%${value}`);
465
+ return this;
466
+ },
467
+ startsWith: (value) => {
468
+ this.addCondition(field, "start-with", value);
469
+ return this;
470
+ },
471
+ notStartsWith: (value) => {
472
+ this.addCondition(field, "not-start-with", value);
473
+ return this;
474
+ },
475
+ isNull: () => {
476
+ this.addCondition(field, "is-null");
477
+ return this;
478
+ },
479
+ isNotNull: () => {
480
+ this.addCondition(field, "is-not-null");
481
+ return this;
482
+ }
483
+ };
484
+ }
485
+ /**
486
+ * Adds a condition to the query
487
+ */
488
+ addCondition(field, operator, value) {
489
+ this.conditions.push({ field, operator, value });
490
+ this.currentField = null;
491
+ }
492
+ };
493
+
494
+ // src/constants/fieldTypes.ts
495
+ var FIELD_TYPE_IDS = {
496
+ DROPDOWN: "b4919f2e-2996-48e4-a03c-ba39fb64386c",
497
+ LOOKUP: "a8fcdf65-91bc-46fd-82f6-1234758345a1",
498
+ EMAIL: "c713d2f7-8fa9-43c3-8062-f07486eaf567",
499
+ TEXT: "a1e7ed6f-5083-477b-b44c-9943a6181359",
500
+ URL: "c820d32f-44df-4c2a-9c1e-18734e864fd5",
501
+ LONG_TEXT: "80108f9d-1e75-40fa-9fa9-02be4ddc1da1",
502
+ DATETIME: "ce972d02-5013-46d4-9d1d-f09df1ac346a",
503
+ DATE: "83bf530c-e04c-462b-9ffc-a46f750fc072",
504
+ HTML: "ed2ad39d-32fc-4585-8f5b-2e93463f050a",
505
+ TELEPHONE: "3f62f67a-1cee-403a-bec6-aa02a9804edb",
506
+ NUMERIC: "6a34bfe3-fece-4da1-9136-a7b1e5ae3319"
507
+ };
508
+ var FIELD_TYPE_MAPPINGS = {
509
+ [FIELD_TYPE_IDS.DROPDOWN]: "Dropdown",
510
+ [FIELD_TYPE_IDS.EMAIL]: "Email",
511
+ [FIELD_TYPE_IDS.TEXT]: "Text",
512
+ [FIELD_TYPE_IDS.LOOKUP]: "Lookup",
513
+ [FIELD_TYPE_IDS.URL]: "URL",
514
+ [FIELD_TYPE_IDS.LONG_TEXT]: "Long Text",
515
+ [FIELD_TYPE_IDS.DATETIME]: "DateTime",
516
+ [FIELD_TYPE_IDS.DATE]: "Date",
517
+ [FIELD_TYPE_IDS.HTML]: "HTML",
518
+ [FIELD_TYPE_IDS.TELEPHONE]: "Telephone",
519
+ [FIELD_TYPE_IDS.NUMERIC]: "Number"
520
+ };
521
+
522
+ // src/api/metadata.ts
523
+ var MetadataAPI = class {
524
+ constructor(client) {
525
+ this.client = client;
526
+ }
527
+ /**
528
+ * Gets all available objects/entity types from Fireberry
529
+ *
530
+ * @param signal - Optional AbortSignal for cancellation
531
+ * @returns List of all objects
532
+ *
533
+ * @example
534
+ * ```typescript
535
+ * const result = await client.metadata.getObjects();
536
+ * console.log(result.objects); // [{ objectType: 1, name: 'Account', ... }, ...]
537
+ * ```
538
+ */
539
+ async getObjects(signal) {
540
+ const cached = this.client.getCached("objects");
541
+ if (cached) {
542
+ return cached;
543
+ }
544
+ const response = await this.client.request({
545
+ method: "GET",
546
+ endpoint: "/metadata/records",
547
+ signal
548
+ });
549
+ const result = {
550
+ objects: response.data || [],
551
+ total: response.data?.length || 0,
552
+ success: true
553
+ };
554
+ this.client.setCache("objects", result);
555
+ return result;
556
+ }
557
+ /**
558
+ * Gets all fields for a specific object type
559
+ *
560
+ * @param objectType - The object type ID (e.g., '1' for Account)
561
+ * @param signal - Optional AbortSignal for cancellation
562
+ * @returns List of fields with metadata
563
+ *
564
+ * @example
565
+ * ```typescript
566
+ * const result = await client.metadata.getFields('1');
567
+ * console.log(result.fields); // [{ fieldName: 'accountid', label: 'Account ID', ... }, ...]
568
+ * ```
569
+ */
570
+ async getFields(objectType, signal) {
571
+ const objectTypeStr = String(objectType);
572
+ const cached = this.client.getCached("fields", objectTypeStr);
573
+ if (cached) {
574
+ return cached;
575
+ }
576
+ const response = await this.client.request({
577
+ method: "GET",
578
+ endpoint: `/metadata/records/${objectTypeStr}/fields`,
579
+ signal
580
+ });
581
+ const fields = (response.data || []).map((field) => ({
582
+ ...field,
583
+ fieldType: FIELD_TYPE_MAPPINGS[field.systemFieldTypeId] || field.systemFieldTypeId
584
+ }));
585
+ const result = {
586
+ objectTypeId: objectTypeStr,
587
+ fields,
588
+ total: fields.length,
589
+ success: true
590
+ };
591
+ this.client.setCache("fields", objectTypeStr, result);
592
+ return result;
593
+ }
594
+ /**
595
+ * Gets all possible values for a dropdown field
596
+ *
597
+ * @param objectType - The object type ID
598
+ * @param fieldName - The field name
599
+ * @param signal - Optional AbortSignal for cancellation
600
+ * @returns List of dropdown values
601
+ *
602
+ * @example
603
+ * ```typescript
604
+ * const result = await client.metadata.getFieldValues('1', 'statuscode');
605
+ * console.log(result.values); // [{ name: 'Active', value: '1' }, { name: 'Inactive', value: '2' }]
606
+ * ```
607
+ */
608
+ async getFieldValues(objectType, fieldName, signal) {
609
+ const objectTypeStr = String(objectType);
610
+ const cached = this.client.getCached(
611
+ "fieldValues",
612
+ objectTypeStr,
613
+ fieldName
614
+ );
615
+ if (cached) {
616
+ return cached;
617
+ }
618
+ const response = await this.client.request({
619
+ method: "GET",
620
+ endpoint: `/metadata/records/${objectTypeStr}/fields/${fieldName}/values`,
621
+ signal
622
+ });
623
+ const result = {
624
+ objectTypeId: objectTypeStr,
625
+ fieldName,
626
+ values: response.data?.values || [],
627
+ total: response.data?.values?.length || 0,
628
+ success: true
629
+ };
630
+ this.client.setCache("fieldValues", objectTypeStr, fieldName, result);
631
+ return result;
632
+ }
633
+ };
634
+
635
+ // src/constants/objectIds.ts
636
+ var OBJECT_ID_MAP = {
637
+ 1: "accountid",
638
+ 2: "contactid",
639
+ 3: "leadid",
640
+ 4: "opportunityid",
641
+ 5: "casesid",
642
+ 6: "activityid",
643
+ 7: "noteid",
644
+ 8: "competitorid",
645
+ 9: "crmuserid",
646
+ 10: "taskid",
647
+ 13: "crmorderid",
648
+ 14: "productid",
649
+ 17: "crmorderitemid",
650
+ 20: "emailtemplateid",
651
+ 23: "businessunitid",
652
+ 27: "printtemplateid",
653
+ 28: "contractid",
654
+ 33: "accountproductid",
655
+ 46: "projectid",
656
+ 67: "campaignid",
657
+ 76: "articleid",
658
+ 86: "invoiceid",
659
+ 101: "attendanceclockid",
660
+ 102: "activitylogid",
661
+ 104: "conversationid",
662
+ 114: "calendarresourceid"
663
+ };
664
+ function getObjectIdFieldName(objectTypeId) {
665
+ const objectTypeNum = typeof objectTypeId === "string" ? parseInt(objectTypeId, 10) : objectTypeId;
666
+ if (OBJECT_ID_MAP[objectTypeNum]) {
667
+ return OBJECT_ID_MAP[objectTypeNum];
668
+ }
669
+ if (objectTypeNum >= 1e3) {
670
+ return `customobject${objectTypeNum}id`;
671
+ }
672
+ return "id";
673
+ }
674
+
675
+ // src/api/records.ts
676
+ var RecordsAPI = class {
677
+ constructor(client) {
678
+ this.client = client;
679
+ }
680
+ /**
681
+ * Creates a new record in Fireberry
682
+ *
683
+ * @param objectType - The object type ID (e.g., '1' for Account)
684
+ * @param data - Record data to create
685
+ * @param options - Optional settings
686
+ * @returns Created record data
687
+ *
688
+ * @example
689
+ * ```typescript
690
+ * const result = await client.records.create('1', {
691
+ * accountname: 'New Account',
692
+ * emailaddress1: 'contact@example.com',
693
+ * });
694
+ * ```
695
+ */
696
+ async create(objectType, data, options) {
697
+ const response = await this.client.request({
698
+ method: "POST",
699
+ endpoint: `/api/v2/record/${objectType}`,
700
+ body: data,
701
+ signal: options?.signal
702
+ });
703
+ return response.record;
704
+ }
705
+ /**
706
+ * Updates an existing record in Fireberry
707
+ *
708
+ * @param objectType - The object type ID
709
+ * @param recordId - The record ID to update
710
+ * @param data - Record data to update
711
+ * @param options - Optional settings
712
+ * @returns Updated record data
713
+ *
714
+ * @example
715
+ * ```typescript
716
+ * const result = await client.records.update('1', 'abc123', {
717
+ * accountname: 'Updated Account Name',
718
+ * });
719
+ * ```
720
+ */
721
+ async update(objectType, recordId, data, options) {
722
+ const response = await this.client.request({
723
+ method: "PUT",
724
+ endpoint: `/api/v2/record/${objectType}/${recordId}`,
725
+ body: data,
726
+ signal: options?.signal
727
+ });
728
+ return response.record;
729
+ }
730
+ /**
731
+ * Deletes a record from Fireberry
732
+ *
733
+ * @param objectType - The object type ID
734
+ * @param recordId - The record ID to delete
735
+ * @param options - Optional settings
736
+ * @returns Success status
737
+ *
738
+ * @example
739
+ * ```typescript
740
+ * await client.records.delete('1', 'abc123');
741
+ * ```
742
+ */
743
+ async delete(objectType, recordId, options) {
744
+ await this.client.request({
745
+ method: "DELETE",
746
+ endpoint: `/api/record/${objectType}/${recordId}`,
747
+ signal: options?.signal
748
+ });
749
+ return {
750
+ success: true,
751
+ id: recordId
752
+ };
753
+ }
754
+ /**
755
+ * Upserts a record (creates if not exists, updates if exists)
756
+ *
757
+ * @param objectType - The object type ID
758
+ * @param keyFields - Fields to use for matching existing records
759
+ * @param data - Record data to upsert
760
+ * @param options - Optional settings
761
+ * @returns Upsert result with operation type and record data
762
+ *
763
+ * @example
764
+ * ```typescript
765
+ * const result = await client.records.upsert('1', ['emailaddress1'], {
766
+ * accountname: 'Acme Corp',
767
+ * emailaddress1: 'contact@acme.com',
768
+ * });
769
+ * console.log(result.operationType); // 'create' or 'update'
770
+ * ```
771
+ */
772
+ async upsert(objectType, keyFields, data, options) {
773
+ const objectTypeStr = String(objectType);
774
+ const upsertKeyValues = {};
775
+ for (const key of keyFields) {
776
+ if (!(key in data)) {
777
+ throw new Error(`Missing value for upsert key field: ${key}`);
778
+ }
779
+ upsertKeyValues[key] = data[key];
780
+ }
781
+ const queryConditions = keyFields.map((key) => `(${key} = ${data[key]})`);
782
+ const queryString = queryConditions.join(" and ");
783
+ const queryResult = await this.client.query({
784
+ objectType: objectTypeStr,
785
+ fields: "*",
786
+ query: queryString,
787
+ limit: 1,
788
+ showRealValue: true,
789
+ signal: options?.signal
790
+ });
791
+ const existingRecords = queryResult.records;
792
+ if (existingRecords.length > 0) {
793
+ const existingRecord = existingRecords[0];
794
+ const idFieldName = getObjectIdFieldName(objectTypeStr);
795
+ const recordId = String(existingRecord[idFieldName]);
796
+ const updatedRecord = await this.update(objectTypeStr, recordId, data, options);
797
+ return {
798
+ success: true,
799
+ operationType: "update",
800
+ upsertKeys: keyFields,
801
+ upsertKeyValues,
802
+ oldRecord: existingRecord,
803
+ newRecord: updatedRecord
804
+ };
805
+ } else {
806
+ const createdRecord = await this.create(objectTypeStr, data, options);
807
+ return {
808
+ success: true,
809
+ operationType: "create",
810
+ upsertKeys: keyFields,
811
+ upsertKeyValues,
812
+ oldRecord: null,
813
+ newRecord: createdRecord
814
+ };
815
+ }
816
+ }
817
+ };
818
+
819
+ // src/api/batch.ts
820
+ var BATCH_SIZE = 20;
821
+ var BatchAPI = class {
822
+ constructor(client) {
823
+ this.client = client;
824
+ }
825
+ /**
826
+ * Creates multiple records in batch
827
+ * Automatically chunks into batches of 20 records
828
+ *
829
+ * @param objectType - The object type ID
830
+ * @param records - Array of records to create
831
+ * @param options - Optional settings
832
+ * @returns Batch result with all created records
833
+ *
834
+ * @example
835
+ * ```typescript
836
+ * const result = await client.batch.create('1', [
837
+ * { accountname: 'Account 1' },
838
+ * { accountname: 'Account 2' },
839
+ * ]);
840
+ * console.log(result.count); // 2
841
+ * ```
842
+ */
843
+ async create(objectType, records, options) {
844
+ const objectTypeStr = String(objectType);
845
+ const batches = chunkArray(records, BATCH_SIZE);
846
+ const allResponses = [];
847
+ for (const batch of batches) {
848
+ if (options?.signal?.aborted) {
849
+ break;
850
+ }
851
+ const response = await this.client.request({
852
+ method: "POST",
853
+ endpoint: `/api/v3/record/${objectTypeStr}/batch/create`,
854
+ body: { data: batch },
855
+ signal: options?.signal
856
+ });
857
+ if (response.data) {
858
+ if (Array.isArray(response.data)) {
859
+ allResponses.push(...response.data);
860
+ } else {
861
+ allResponses.push(response.data);
862
+ }
863
+ }
864
+ }
865
+ return {
866
+ success: true,
867
+ data: allResponses,
868
+ count: allResponses.length
869
+ };
870
+ }
871
+ /**
872
+ * Updates multiple records in batch
873
+ * Automatically chunks into batches of 20 records
874
+ *
875
+ * @param objectType - The object type ID
876
+ * @param records - Array of records with ID and data to update
877
+ * @param options - Optional settings
878
+ * @returns Batch result with all updated records
879
+ *
880
+ * @example
881
+ * ```typescript
882
+ * const result = await client.batch.update('1', [
883
+ * { id: 'abc123', record: { accountname: 'Updated 1' } },
884
+ * { id: 'def456', record: { accountname: 'Updated 2' } },
885
+ * ]);
886
+ * ```
887
+ */
888
+ async update(objectType, records, options) {
889
+ const objectTypeStr = String(objectType);
890
+ const batches = chunkArray(records, BATCH_SIZE);
891
+ const allResponses = [];
892
+ for (const batch of batches) {
893
+ if (options?.signal?.aborted) {
894
+ break;
895
+ }
896
+ const response = await this.client.request({
897
+ method: "POST",
898
+ endpoint: `/api/v3/record/${objectTypeStr}/batch/update`,
899
+ body: { data: batch },
900
+ signal: options?.signal
901
+ });
902
+ if (response.data) {
903
+ if (Array.isArray(response.data)) {
904
+ allResponses.push(...response.data);
905
+ } else {
906
+ allResponses.push(response.data);
907
+ }
908
+ }
909
+ }
910
+ return {
911
+ success: true,
912
+ data: allResponses,
913
+ count: allResponses.length
914
+ };
915
+ }
916
+ /**
917
+ * Deletes multiple records in batch
918
+ * Automatically chunks into batches of 20 records
919
+ *
920
+ * @param objectType - The object type ID
921
+ * @param recordIds - Array of record IDs to delete
922
+ * @param options - Optional settings
923
+ * @returns Batch delete result with deleted IDs
924
+ *
925
+ * @example
926
+ * ```typescript
927
+ * const result = await client.batch.delete('1', ['abc123', 'def456']);
928
+ * console.log(result.ids); // ['abc123', 'def456']
929
+ * ```
930
+ */
931
+ async delete(objectType, recordIds, options) {
932
+ const objectTypeStr = String(objectType);
933
+ const batches = chunkArray(recordIds, BATCH_SIZE);
934
+ const allDeletedIds = [];
935
+ for (const batch of batches) {
936
+ if (options?.signal?.aborted) {
937
+ break;
938
+ }
939
+ await this.client.request({
940
+ method: "POST",
941
+ endpoint: `/api/v3/record/${objectTypeStr}/batch/delete`,
942
+ body: { data: batch },
943
+ signal: options?.signal
944
+ });
945
+ allDeletedIds.push(...batch);
946
+ }
947
+ return {
948
+ success: true,
949
+ ids: allDeletedIds,
950
+ count: allDeletedIds.length
951
+ };
952
+ }
953
+ };
954
+
955
+ // src/api/fields.ts
956
+ var FIELD_TYPE_ENDPOINTS = {
957
+ text: "text",
958
+ email: "email",
959
+ url: "url",
960
+ phone: "phone",
961
+ number: "number",
962
+ textarea: "textarea",
963
+ html: "html",
964
+ date: "date",
965
+ datetime: "datetime",
966
+ lookup: "lookup",
967
+ summary: "summary",
968
+ formula: "formula",
969
+ picklist: "picklist"
970
+ };
971
+ var FieldsAPI = class {
972
+ constructor(client) {
973
+ this.client = client;
974
+ }
975
+ /**
976
+ * Creates a new custom field in a Fireberry object
977
+ *
978
+ * @param objectType - The object type ID
979
+ * @param options - Field creation options
980
+ * @returns Created field result
981
+ *
982
+ * @example
983
+ * ```typescript
984
+ * // Create a text field
985
+ * const result = await client.fields.create('1', {
986
+ * type: 'text',
987
+ * fieldName: 'pcf_custom_field',
988
+ * label: 'Custom Field',
989
+ * maxLength: 100,
990
+ * });
991
+ *
992
+ * // Create a picklist field
993
+ * const result = await client.fields.create('1', {
994
+ * type: 'picklist',
995
+ * fieldName: 'pcf_status',
996
+ * label: 'Status',
997
+ * values: [
998
+ * { name: 'Active', value: '1' },
999
+ * { name: 'Inactive', value: '2' },
1000
+ * ],
1001
+ * });
1002
+ *
1003
+ * // Create a lookup field
1004
+ * const result = await client.fields.create('2', {
1005
+ * type: 'lookup',
1006
+ * fieldName: 'pcf_related_account',
1007
+ * label: 'Related Account',
1008
+ * relatedObjectId: '1',
1009
+ * });
1010
+ * ```
1011
+ */
1012
+ async create(objectType, options) {
1013
+ const objectTypeStr = String(objectType);
1014
+ const { type, fieldName, label, defaultValue, follow, autoComplete } = options;
1015
+ const fieldData = {
1016
+ fieldName,
1017
+ label
1018
+ };
1019
+ if (defaultValue !== void 0) {
1020
+ fieldData.defaultValue = defaultValue;
1021
+ }
1022
+ if (follow !== void 0) {
1023
+ fieldData.follow = follow;
1024
+ }
1025
+ if (autoComplete !== void 0 && ["text", "email", "url", "phone", "number"].includes(type)) {
1026
+ fieldData.autoComplete = autoComplete;
1027
+ }
1028
+ switch (type) {
1029
+ case "text":
1030
+ case "email":
1031
+ case "url": {
1032
+ const opts = options;
1033
+ if (opts.maxLength !== void 0 && opts.maxLength > 0) {
1034
+ fieldData.maxLength = opts.maxLength;
1035
+ }
1036
+ break;
1037
+ }
1038
+ case "number": {
1039
+ const opts = options;
1040
+ if (opts.precision !== void 0) {
1041
+ fieldData.precision = opts.precision;
1042
+ }
1043
+ break;
1044
+ }
1045
+ case "lookup": {
1046
+ const opts = options;
1047
+ fieldData.relatedObjectId = opts.relatedObjectId;
1048
+ break;
1049
+ }
1050
+ case "picklist": {
1051
+ const opts = options;
1052
+ fieldData.values = opts.values;
1053
+ break;
1054
+ }
1055
+ case "summary": {
1056
+ const opts = options;
1057
+ fieldData.summaryType = opts.summaryType;
1058
+ fieldData.relatedObjectId = opts.relatedObjectId;
1059
+ if (opts.summaryField) {
1060
+ fieldData.summaryField = opts.summaryField;
1061
+ }
1062
+ break;
1063
+ }
1064
+ case "formula": {
1065
+ const opts = options;
1066
+ fieldData.formula = opts.formula;
1067
+ fieldData.fieldType = opts.formulaFieldType;
1068
+ if (opts.formulaFieldType === "number" && opts.formulaPrecision !== void 0) {
1069
+ fieldData.precision = opts.formulaPrecision;
1070
+ }
1071
+ break;
1072
+ }
1073
+ }
1074
+ const endpoint = FIELD_TYPE_ENDPOINTS[type];
1075
+ if (!endpoint) {
1076
+ throw new Error(`Unsupported field type: ${type}`);
1077
+ }
1078
+ const response = await this.client.request({
1079
+ method: "POST",
1080
+ endpoint: `/api/v2/system-field/${objectTypeStr}/${endpoint}`,
1081
+ body: fieldData
1082
+ });
1083
+ return {
1084
+ objectTypeId: objectTypeStr,
1085
+ fieldType: type,
1086
+ fieldData: response,
1087
+ success: true
1088
+ };
1089
+ }
1090
+ };
1091
+
1092
+ // src/api/files.ts
1093
+ var FilesAPI = class {
1094
+ constructor(client) {
1095
+ this.client = client;
1096
+ }
1097
+ /**
1098
+ * Uploads a file attachment to a Fireberry record
1099
+ *
1100
+ * @param objectType - The object type ID
1101
+ * @param recordId - The record ID to attach the file to
1102
+ * @param options - File upload options
1103
+ * @param signal - Optional AbortSignal for cancellation
1104
+ * @returns Upload result
1105
+ *
1106
+ * @example
1107
+ * ```typescript
1108
+ * import { readFileSync } from 'fs';
1109
+ *
1110
+ * const fileBuffer = readFileSync('document.pdf');
1111
+ * const result = await client.files.upload('1', 'abc123', {
1112
+ * buffer: fileBuffer,
1113
+ * filename: 'document.pdf',
1114
+ * mimeType: 'application/pdf',
1115
+ * });
1116
+ * ```
1117
+ */
1118
+ async upload(objectType, recordId, options, signal) {
1119
+ const objectTypeStr = String(objectType);
1120
+ const { buffer, filename, mimeType } = options;
1121
+ const config = this.client.getConfig();
1122
+ const url = `${config.baseUrl}/api/v2/record/${objectTypeStr}/${recordId}/files`;
1123
+ const boundary = `----FormBoundary${Date.now()}`;
1124
+ const formParts = [];
1125
+ const fileHeader = [
1126
+ `--${boundary}`,
1127
+ `Content-Disposition: form-data; name="file"; filename="${filename}"`,
1128
+ `Content-Type: ${mimeType}`,
1129
+ "",
1130
+ ""
1131
+ ].join("\r\n");
1132
+ formParts.push(Buffer.from(fileHeader));
1133
+ formParts.push(buffer);
1134
+ formParts.push(Buffer.from(`\r
1135
+ --${boundary}--\r
1136
+ `));
1137
+ const body = Buffer.concat(formParts);
1138
+ try {
1139
+ const response = await fetch(url, {
1140
+ method: "POST",
1141
+ headers: {
1142
+ Accept: "application/json",
1143
+ "Content-Type": `multipart/form-data; boundary=${boundary}`,
1144
+ tokenid: config.apiKey
1145
+ },
1146
+ body,
1147
+ signal
1148
+ });
1149
+ if (!response.ok) {
1150
+ throw new FireberryError(`File upload failed: ${response.statusText}`, {
1151
+ code: "INVALID_REQUEST" /* INVALID_REQUEST */,
1152
+ statusCode: response.status
1153
+ });
1154
+ }
1155
+ const responseData = await response.json();
1156
+ return {
1157
+ success: true,
1158
+ objectType: objectTypeStr,
1159
+ recordId,
1160
+ fileName: filename,
1161
+ mimeType,
1162
+ fileSize: buffer.length,
1163
+ response: responseData
1164
+ };
1165
+ } catch (error) {
1166
+ if (error instanceof FireberryError) {
1167
+ throw error;
1168
+ }
1169
+ throw new FireberryError(`File upload failed: ${error.message}`, {
1170
+ code: "NETWORK_ERROR" /* NETWORK_ERROR */,
1171
+ cause: error
1172
+ });
1173
+ }
1174
+ }
1175
+ };
1176
+
1177
+ // src/client.ts
1178
+ var FireberryClient = class {
1179
+ config;
1180
+ cacheStore;
1181
+ /** Metadata API operations */
1182
+ metadata;
1183
+ /** Records CRUD operations */
1184
+ records;
1185
+ /** Batch operations */
1186
+ batch;
1187
+ /** Field management operations */
1188
+ fields;
1189
+ /** File operations */
1190
+ files;
1191
+ /**
1192
+ * Creates a new FireberryClient instance
1193
+ */
1194
+ constructor(config) {
1195
+ this.config = {
1196
+ apiKey: config.apiKey,
1197
+ baseUrl: config.baseUrl || "https://api.fireberry.com",
1198
+ timeout: config.timeout || 3e4,
1199
+ retryOn429: config.retryOn429 ?? true,
1200
+ maxRetries: config.maxRetries || 120,
1201
+ retryDelay: config.retryDelay || 1e3,
1202
+ cacheMetadata: config.cacheMetadata || false,
1203
+ cacheTTL: config.cacheTTL || 3e5
1204
+ // 5 minutes default
1205
+ };
1206
+ this.cacheStore = {
1207
+ fields: /* @__PURE__ */ new Map(),
1208
+ fieldValues: /* @__PURE__ */ new Map()
1209
+ };
1210
+ this.metadata = new MetadataAPI(this);
1211
+ this.records = new RecordsAPI(this);
1212
+ this.batch = new BatchAPI(this);
1213
+ this.fields = new FieldsAPI(this);
1214
+ this.files = new FilesAPI(this);
1215
+ }
1216
+ /**
1217
+ * Gets the client configuration
1218
+ */
1219
+ getConfig() {
1220
+ return this.config;
1221
+ }
1222
+ /**
1223
+ * Cache control methods
1224
+ */
1225
+ cache = {
1226
+ clear: () => {
1227
+ this.cacheStore.objects = void 0;
1228
+ this.cacheStore.fields.clear();
1229
+ this.cacheStore.fieldValues.clear();
1230
+ },
1231
+ clearObjects: () => {
1232
+ this.cacheStore.objects = void 0;
1233
+ },
1234
+ clearFields: (objectType) => {
1235
+ this.cacheStore.fields.delete(objectType);
1236
+ },
1237
+ clearFieldValues: (objectType, fieldName) => {
1238
+ if (fieldName) {
1239
+ this.cacheStore.fieldValues.delete(`${objectType}:${fieldName}`);
1240
+ } else {
1241
+ for (const key of this.cacheStore.fieldValues.keys()) {
1242
+ if (key.startsWith(`${objectType}:`)) {
1243
+ this.cacheStore.fieldValues.delete(key);
1244
+ }
1245
+ }
1246
+ }
1247
+ }
1248
+ };
1249
+ getCached(type, objectType, fieldName) {
1250
+ if (!this.config.cacheMetadata) {
1251
+ return void 0;
1252
+ }
1253
+ const now = Date.now();
1254
+ if (type === "objects") {
1255
+ const cached = this.cacheStore.objects;
1256
+ if (cached && now - cached.timestamp < this.config.cacheTTL) {
1257
+ return cached.data;
1258
+ }
1259
+ } else if (type === "fields" && objectType) {
1260
+ const cached = this.cacheStore.fields.get(objectType);
1261
+ if (cached && now - cached.timestamp < this.config.cacheTTL) {
1262
+ return cached.data;
1263
+ }
1264
+ } else if (type === "fieldValues" && objectType && fieldName) {
1265
+ const key = `${objectType}:${fieldName}`;
1266
+ const cached = this.cacheStore.fieldValues.get(key);
1267
+ if (cached && now - cached.timestamp < this.config.cacheTTL) {
1268
+ return cached.data;
1269
+ }
1270
+ }
1271
+ return void 0;
1272
+ }
1273
+ setCache(type, objectTypeOrData, fieldNameOrData, data) {
1274
+ if (!this.config.cacheMetadata) {
1275
+ return;
1276
+ }
1277
+ const now = Date.now();
1278
+ if (type === "objects") {
1279
+ this.cacheStore.objects = { data: objectTypeOrData, timestamp: now };
1280
+ } else if (type === "fields" && typeof objectTypeOrData === "string") {
1281
+ this.cacheStore.fields.set(objectTypeOrData, {
1282
+ data: fieldNameOrData,
1283
+ timestamp: now
1284
+ });
1285
+ } else if (type === "fieldValues" && typeof objectTypeOrData === "string" && typeof fieldNameOrData === "string") {
1286
+ const key = `${objectTypeOrData}:${fieldNameOrData}`;
1287
+ this.cacheStore.fieldValues.set(key, { data, timestamp: now });
1288
+ }
1289
+ }
1290
+ /**
1291
+ * Creates a new QueryBuilder instance
1292
+ */
1293
+ queryBuilder() {
1294
+ return new QueryBuilder(this);
1295
+ }
1296
+ /**
1297
+ * Executes a query against the Fireberry API
1298
+ */
1299
+ async query(options) {
1300
+ const {
1301
+ objectType,
1302
+ fields,
1303
+ query,
1304
+ sortBy = "modifiedon",
1305
+ sortType = "desc",
1306
+ limit,
1307
+ page = 1,
1308
+ pageSize = 500,
1309
+ showRealValue = true,
1310
+ autoPage = true,
1311
+ signal
1312
+ } = options;
1313
+ let fieldsStr;
1314
+ if (Array.isArray(fields)) {
1315
+ fieldsStr = fields.join(",");
1316
+ } else if (typeof fields === "string") {
1317
+ fieldsStr = fields;
1318
+ } else {
1319
+ fieldsStr = "*";
1320
+ }
1321
+ if (fieldsStr === "*") {
1322
+ fieldsStr = await this.expandStarFields(objectType, signal);
1323
+ }
1324
+ if (autoPage) {
1325
+ return this.queryAllPages({
1326
+ objectType,
1327
+ fields: fieldsStr,
1328
+ query,
1329
+ sortBy,
1330
+ sortType,
1331
+ showRealValue,
1332
+ limit,
1333
+ signal
1334
+ });
1335
+ }
1336
+ const body = {
1337
+ objecttype: objectType,
1338
+ fields: fieldsStr,
1339
+ query: query || "",
1340
+ sort_by: sortBy,
1341
+ sort_type: sortType,
1342
+ page_size: Math.min(pageSize, limit || 500),
1343
+ page_number: page,
1344
+ show_real_value: showRealValue ? 1 : 0
1345
+ };
1346
+ const response = await this.request({
1347
+ method: "POST",
1348
+ endpoint: "/api/query",
1349
+ body,
1350
+ signal
1351
+ });
1352
+ const records = response.data?.Data || [];
1353
+ return {
1354
+ records,
1355
+ total: records.length,
1356
+ success: true
1357
+ };
1358
+ }
1359
+ /**
1360
+ * Fetches all pages of a query
1361
+ */
1362
+ async queryAllPages(options) {
1363
+ const { objectType, fields, query, sortBy, sortType, showRealValue, limit, signal } = options;
1364
+ const maxPageSize = 500;
1365
+ const allRecords = [];
1366
+ let currentPage = 1;
1367
+ let hasMore = true;
1368
+ while (hasMore) {
1369
+ if (signal?.aborted) {
1370
+ break;
1371
+ }
1372
+ const body = {
1373
+ objecttype: objectType,
1374
+ fields,
1375
+ query: query || "",
1376
+ sort_by: sortBy,
1377
+ sort_type: sortType,
1378
+ page_size: maxPageSize,
1379
+ page_number: currentPage,
1380
+ show_real_value: showRealValue ? 1 : 0
1381
+ };
1382
+ const response = await this.request({
1383
+ method: "POST",
1384
+ endpoint: "/api/query",
1385
+ body,
1386
+ signal
1387
+ });
1388
+ const pageData = response.data?.Data || [];
1389
+ allRecords.push(...pageData);
1390
+ if (limit && allRecords.length >= limit) {
1391
+ allRecords.splice(limit);
1392
+ break;
1393
+ }
1394
+ if (pageData.length < maxPageSize) {
1395
+ hasMore = false;
1396
+ } else {
1397
+ currentPage++;
1398
+ }
1399
+ }
1400
+ return {
1401
+ records: allRecords,
1402
+ total: allRecords.length,
1403
+ success: true
1404
+ };
1405
+ }
1406
+ /**
1407
+ * Expands '*' fields to actual field names, excluding problematic fields for specific object types
1408
+ */
1409
+ async expandStarFields(objectType, signal) {
1410
+ const { getExcludedFieldsForStarQuery: getExcludedFieldsForStarQuery2 } = await Promise.resolve().then(() => (init_excludedFields(), excludedFields_exports));
1411
+ const excludedFields = getExcludedFieldsForStarQuery2(objectType);
1412
+ if (excludedFields.length === 0) {
1413
+ return "*";
1414
+ }
1415
+ const fieldsResult = await this.metadata.getFields(objectType, signal);
1416
+ const allFieldNames = fieldsResult.fields.map((f) => f.fieldName);
1417
+ const filteredFields = allFieldNames.filter(
1418
+ (fieldName) => !excludedFields.includes(fieldName)
1419
+ );
1420
+ return filteredFields.join(",");
1421
+ }
1422
+ /**
1423
+ * Makes a raw API request to the Fireberry API
1424
+ */
1425
+ async request(options) {
1426
+ const {
1427
+ method,
1428
+ endpoint,
1429
+ query: queryParams,
1430
+ body,
1431
+ headers: customHeaders,
1432
+ signal
1433
+ } = options;
1434
+ let url = `${this.config.baseUrl}${endpoint}`;
1435
+ if (queryParams && Object.keys(queryParams).length > 0) {
1436
+ const params = new URLSearchParams();
1437
+ for (const [key, value] of Object.entries(queryParams)) {
1438
+ if (value !== void 0 && value !== null) {
1439
+ params.set(key, String(value));
1440
+ }
1441
+ }
1442
+ url += `?${params.toString()}`;
1443
+ }
1444
+ const headers = {
1445
+ Accept: "application/json",
1446
+ tokenid: this.config.apiKey,
1447
+ ...customHeaders
1448
+ };
1449
+ if (body) {
1450
+ headers["Content-Type"] = "application/json";
1451
+ }
1452
+ const fetchOptions = {
1453
+ method,
1454
+ headers,
1455
+ signal
1456
+ };
1457
+ if (body) {
1458
+ fetchOptions.body = JSON.stringify(body);
1459
+ }
1460
+ return this.executeWithRetry(url, fetchOptions);
1461
+ }
1462
+ /**
1463
+ * Executes a fetch request with retry logic for 429 errors
1464
+ */
1465
+ async executeWithRetry(url, options, retryCount = 0) {
1466
+ try {
1467
+ const timeoutController = new AbortController();
1468
+ const timeoutId = setTimeout(() => {
1469
+ timeoutController.abort();
1470
+ }, this.config.timeout);
1471
+ const combinedSignal = options.signal ? this.combineSignals([options.signal, timeoutController.signal]) : timeoutController.signal;
1472
+ const response = await fetch(url, {
1473
+ ...options,
1474
+ signal: combinedSignal
1475
+ });
1476
+ clearTimeout(timeoutId);
1477
+ if (response.status === 429 && this.config.retryOn429) {
1478
+ if (retryCount < this.config.maxRetries) {
1479
+ await wait(this.config.retryDelay);
1480
+ return this.executeWithRetry(url, options, retryCount + 1);
1481
+ }
1482
+ throw new FireberryError("Rate limit exceeded after max retries", {
1483
+ code: "RATE_LIMITED" /* RATE_LIMITED */,
1484
+ statusCode: 429,
1485
+ context: { retryCount }
1486
+ });
1487
+ }
1488
+ let body;
1489
+ const contentType = response.headers.get("content-type");
1490
+ if (contentType?.includes("application/json")) {
1491
+ body = await response.json();
1492
+ } else {
1493
+ body = await response.text();
1494
+ }
1495
+ if (!response.ok) {
1496
+ throw createErrorFromResponse(response, body);
1497
+ }
1498
+ return body;
1499
+ } catch (error) {
1500
+ if (error instanceof Error && error.name === "AbortError") {
1501
+ throw createNetworkError(error);
1502
+ }
1503
+ if (error instanceof FireberryError) {
1504
+ throw error;
1505
+ }
1506
+ throw createNetworkError(error);
1507
+ }
1508
+ }
1509
+ /**
1510
+ * Combines multiple abort signals into one
1511
+ */
1512
+ combineSignals(signals) {
1513
+ const controller = new AbortController();
1514
+ for (const signal of signals) {
1515
+ if (signal.aborted) {
1516
+ controller.abort();
1517
+ break;
1518
+ }
1519
+ signal.addEventListener("abort", () => controller.abort(), { once: true });
1520
+ }
1521
+ return controller.signal;
1522
+ }
1523
+ };
1524
+
1525
+ // src/constants/objectNames.ts
1526
+ var OBJECT_NAME_MAP = {
1527
+ 1: "accountname",
1528
+ // Account
1529
+ 2: "fullname",
1530
+ // Contact
1531
+ 3: "fullname",
1532
+ // Lead
1533
+ 4: "name",
1534
+ // Opportunity
1535
+ 5: "title",
1536
+ // Case
1537
+ 6: "subject",
1538
+ // Activity
1539
+ 7: "subject",
1540
+ // Note
1541
+ 8: "name",
1542
+ // Competitor
1543
+ 9: "fullname",
1544
+ // CRM User
1545
+ 10: "subject",
1546
+ // Task
1547
+ 13: "name",
1548
+ // CRM Order
1549
+ 14: "productname",
1550
+ // Product
1551
+ 17: "productname",
1552
+ // CRM Order Item
1553
+ 20: "name",
1554
+ // Email Template
1555
+ 23: "name",
1556
+ // Business Unit
1557
+ 27: "name",
1558
+ // Print Template
1559
+ 28: "name",
1560
+ // Contract
1561
+ 33: "productname",
1562
+ // Account Product
1563
+ 46: "name",
1564
+ // Project
1565
+ 67: "name",
1566
+ // Campaign
1567
+ 76: "title",
1568
+ // Article
1569
+ 86: "name",
1570
+ // Invoice
1571
+ 101: "name",
1572
+ // Attendance Clock
1573
+ 102: "subject",
1574
+ // Activity Log
1575
+ 104: "subject",
1576
+ // Conversation
1577
+ 114: "name"
1578
+ // Calendar Resource
1579
+ };
1580
+
1581
+ // src/constants/index.ts
1582
+ init_excludedFields();
1583
+
1584
+ export { EXCLUDED_FIELDS_FOR_STAR_QUERY, FIELD_TYPE_IDS, FIELD_TYPE_MAPPINGS, FireberryClient, FireberryError, FireberryErrorCode, OBJECT_ID_MAP, OBJECT_NAME_MAP, QueryBuilder, escapeQueryValue, sanitizeQuery };
1585
+ //# sourceMappingURL=index.js.map
1586
+ //# sourceMappingURL=index.js.map