mp-js-api 0.0.30 → 0.0.32

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.
@@ -9,6 +9,11 @@ exports.toCapitalSnakeCase = toCapitalSnakeCase;
9
9
  exports.caseConverter = caseConverter;
10
10
  exports.convertToCamelCase = convertToCamelCase;
11
11
  exports.convertToSnakeCase = convertToSnakeCase;
12
+ exports.toPascalCase = toPascalCase;
13
+ exports.fromPascalCase = fromPascalCase;
14
+ exports.pascalCaseConverter = pascalCaseConverter;
15
+ exports.convertToPascalCase = convertToPascalCase;
16
+ exports.convertFromPascalCase = convertFromPascalCase;
12
17
  function stringifyURLParams(mpOptions = {}) {
13
18
  return escapeSql(Object.entries(mpOptions).reduce((acc, [key, value]) => {
14
19
  if (!acc) {
@@ -114,3 +119,58 @@ function convertToCamelCase(obj, capitalIds = true) {
114
119
  function convertToSnakeCase(obj, capitalIds = true) {
115
120
  return caseConverter(obj, { type: 'toSnake', capitalIds });
116
121
  }
122
+ /**
123
+ * Converts a camelCase string to PascalCase.
124
+ * Example: "authorUserId" → "AuthorUserId"
125
+ */
126
+ function toPascalCase(str) {
127
+ if (!str)
128
+ return str;
129
+ return str.charAt(0).toUpperCase() + str.slice(1);
130
+ }
131
+ /**
132
+ * Converts a PascalCase string to camelCase.
133
+ * Example: "AuthorUserId" → "authorUserId"
134
+ */
135
+ function fromPascalCase(str) {
136
+ if (!str)
137
+ return str;
138
+ return str.charAt(0).toLowerCase() + str.slice(1);
139
+ }
140
+ /**
141
+ * Recursively converts object keys between camelCase and PascalCase.
142
+ * Used for /communications, /messages, /texts, /procs endpoints.
143
+ */
144
+ function pascalCaseConverter(obj, direction) {
145
+ const caseFn = direction === 'toPascal' ? toPascalCase : fromPascalCase;
146
+ if (Array.isArray(obj)) {
147
+ return obj.map(val => pascalCaseConverter(val, direction));
148
+ }
149
+ if (obj !== null && typeof obj === 'object') {
150
+ const result = {};
151
+ for (const key in obj) {
152
+ if (Object.prototype.hasOwnProperty.call(obj, key)) {
153
+ const newKey = caseFn(key);
154
+ result[newKey] = pascalCaseConverter(obj[key], direction);
155
+ }
156
+ }
157
+ return result;
158
+ }
159
+ return obj;
160
+ }
161
+ /**
162
+ * Converts camelCase object keys to PascalCase.
163
+ * Used for outgoing requests to /communications, /messages, /texts endpoints.
164
+ * Example: { authorUserId: 1 } → { AuthorUserId: 1 }
165
+ */
166
+ function convertToPascalCase(obj) {
167
+ return pascalCaseConverter(obj, 'toPascal');
168
+ }
169
+ /**
170
+ * Converts PascalCase object keys to camelCase.
171
+ * Used for incoming responses from /communications, /messages, /texts, /procs endpoints.
172
+ * Example: { AuthorUserId: 1 } → { authorUserId: 1 }
173
+ */
174
+ function convertFromPascalCase(obj) {
175
+ return pascalCaseConverter(obj, 'fromPascal');
176
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mp-js-api",
3
- "version": "0.0.30",
3
+ "version": "0.0.32",
4
4
  "description": "Node MinistryPlatform API",
5
5
  "main": "dist/index.js",
6
6
  "scripts": {
package/src/api.ts CHANGED
@@ -1,6 +1,10 @@
1
1
  import axios, { AxiosError, AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios';
2
2
  import { URLSearchParams } from 'url';
3
- import { convertToCamelCase, convertToSnakeCase, escapeApostrophes, stringifyURLParams, toCapitalSnakeCase } from './utils/converters';
3
+ import { convertToCamelCase, convertToSnakeCase, convertToPascalCase, convertFromPascalCase, escapeApostrophes, stringifyURLParams, toCapitalSnakeCase } from './utils/converters';
4
+ import { Communication, CommunicationInfo } from './endpoints/communications';
5
+ import { MessageInfo } from './endpoints/messages';
6
+ import { TextInfo } from './endpoints/texts';
7
+ import { ProcedureInfo } from './endpoints/procedures';
4
8
 
5
9
 
6
10
  export type APIGetOneInstance = <T extends Record<string, any>>({ id, path, mpQuery, config }: APIGetParameter & { id: number; }) => Promise<T | undefined | { error: ErrorDetails; }>;
@@ -10,6 +14,15 @@ export type APICreateManyInstance = <T extends Record<string, any>>({ path, mpQu
10
14
  export type APICreateFileInstance = <T extends Record<string, any>>({ path, mpQuery, data, config }: APICreateFileParameter) => Promise<T | { error: ErrorDetails; }>;
11
15
  export type APIUpdateInstance = <T extends Record<string, any>>({ path, mpQuery, data, config }: APIUpdateParameter) => Promise<T[] | { error: ErrorDetails; }>;
12
16
 
17
+ // Communications API types
18
+ export type APISendCommunicationInstance = (data: CommunicationInfo, config?: AxiosRequestConfig) => Promise<Communication | { error: ErrorDetails; }>;
19
+ export type APISendMessageInstance = (data: MessageInfo, config?: AxiosRequestConfig) => Promise<Communication | { error: ErrorDetails; }>;
20
+ export type APISendTextInstance = (data: TextInfo, config?: AxiosRequestConfig) => Promise<Communication | { error: ErrorDetails; }>;
21
+
22
+ // Procedures API types
23
+ export type APIGetProceduresInstance = (search?: string, config?: AxiosRequestConfig) => Promise<ProcedureInfo[] | { error: ErrorDetails; }>;
24
+ export type APIExecuteProcedureInstance = <T = Record<string, any>>(procedureName: string, input?: Record<string, any>, config?: AxiosRequestConfig) => Promise<T[][] | { error: ErrorDetails; }>;
25
+
13
26
 
14
27
  export interface MPApiBase {
15
28
  getOne: APIGetOneInstance;
@@ -23,6 +36,13 @@ export interface MPApiBase {
23
36
  post: AxiosInstance['post'];
24
37
  put: AxiosInstance['put'];
25
38
  getError: (error: AxiosError) => ErrorDetails;
39
+ // Communications API
40
+ sendCommunication: APISendCommunicationInstance;
41
+ sendMessage: APISendMessageInstance;
42
+ sendText: APISendTextInstance;
43
+ // Procedures API
44
+ getProcedures: APIGetProceduresInstance;
45
+ executeProcedure: APIExecuteProcedureInstance;
26
46
  }
27
47
 
28
48
  export interface ErrorDetails {
@@ -226,6 +246,65 @@ export const createApiBase = ({ auth }: { auth: { username: string; password: st
226
246
  };
227
247
  };
228
248
 
249
+ // Communications API: POST /communications
250
+ const sendCommunication: APISendCommunicationInstance = async (data, config) => {
251
+ try {
252
+ const payload = convertToPascalCase(data);
253
+ const res = await post<Communication>('/communications', payload, config);
254
+ return convertFromPascalCase<Communication>(res.data);
255
+ } catch (err) {
256
+ return { error: getError(err as AxiosError) };
257
+ }
258
+ };
259
+
260
+ // Messages API: POST /messages
261
+ const sendMessage: APISendMessageInstance = async (data, config) => {
262
+ try {
263
+ const payload = convertToPascalCase(data);
264
+ const res = await post<Communication>('/messages', payload, config);
265
+ return convertFromPascalCase<Communication>(res.data);
266
+ } catch (err) {
267
+ return { error: getError(err as AxiosError) };
268
+ }
269
+ };
270
+
271
+ // Texts API: POST /texts
272
+ const sendText: APISendTextInstance = async (data, config) => {
273
+ try {
274
+ const payload = convertToPascalCase(data);
275
+ const res = await post<Communication>('/texts', payload, config);
276
+ return convertFromPascalCase<Communication>(res.data);
277
+ } catch (err) {
278
+ return { error: getError(err as AxiosError) };
279
+ }
280
+ };
281
+
282
+ // Procedures API: GET /procs
283
+ const getProcedures: APIGetProceduresInstance = async (search, config) => {
284
+ try {
285
+ const url = search ? `/procs?$search=${encodeURIComponent(search)}` : '/procs';
286
+ const res = await get<ProcedureInfo[]>(url, config);
287
+ return res.data.map(proc => convertFromPascalCase<ProcedureInfo>(proc));
288
+ } catch (err) {
289
+ return { error: getError(err as AxiosError) };
290
+ }
291
+ };
292
+
293
+ // Procedures API: POST /procs/{procedure}
294
+ const executeProcedure: APIExecuteProcedureInstance = async <T = Record<string, any>>(
295
+ procedureName: string,
296
+ input?: Record<string, any>,
297
+ config?: AxiosRequestConfig
298
+ ) => {
299
+ try {
300
+ const url = `/procs/${encodeURIComponent(procedureName)}`;
301
+ const res = await post<T[][]>(url, input, config);
302
+ return res.data;
303
+ } catch (err) {
304
+ return { error: getError(err as AxiosError) };
305
+ }
306
+ };
307
+
229
308
  return {
230
309
  get,
231
310
  put,
@@ -237,7 +316,12 @@ export const createApiBase = ({ auth }: { auth: { username: string; password: st
237
316
  updateMany,
238
317
  createFile,
239
318
  updateFile,
240
- getError
319
+ getError,
320
+ sendCommunication,
321
+ sendMessage,
322
+ sendText,
323
+ getProcedures,
324
+ executeProcedure,
241
325
  };
242
326
  };
243
327
 
@@ -0,0 +1,125 @@
1
+ /**
2
+ * Communication type enum.
3
+ * Determines the delivery method for the communication.
4
+ */
5
+ export type CommunicationType = 'Unknown' | 'Email' | 'SMS' | 'RssFeed' | 'GlobalMFA';
6
+
7
+ /**
8
+ * Communication status enum.
9
+ * Represents the current state of a communication.
10
+ */
11
+ export type CommunicationStatus = 'Unknown' | 'Draft' | 'InReview' | 'ReadyToSend' | 'Sent';
12
+
13
+ /**
14
+ * Texting compliance level enum.
15
+ * Controls how bulk opt-out messages are filtered.
16
+ */
17
+ export type TextingComplianceLevel = 'None' | 'SingleOptIn' | 'DoubleOptIn';
18
+
19
+ /**
20
+ * CommunicationInfo - Request payload for POST /communications.
21
+ * Uses camelCase internally; converted to PascalCase for API.
22
+ *
23
+ * API expects: AuthorUserId, FromContactId, CommunicationType, Contacts, etc.
24
+ */
25
+ export interface CommunicationInfo {
26
+ /** User ID who authored the communication. */
27
+ authorUserId: number;
28
+ /** Subject line of email or SMS/MMS message content. */
29
+ subject: string;
30
+ /** Body content of the communication (HTML supported for email). */
31
+ body?: string;
32
+ /** Contact ID of the sender. */
33
+ fromContactId: number;
34
+ /** Contact ID for replies. */
35
+ replyToContactId: number;
36
+ /** Delivery type: 'Email' or 'SMS'. */
37
+ communicationType: CommunicationType;
38
+ /** Array of recipient Contact IDs. */
39
+ contacts: number[];
40
+ /** ISO datetime to send. Future date = scheduled. */
41
+ startDate?: string;
42
+ /** Whether this is a bulk email. */
43
+ isBulkEmail?: boolean;
44
+ /** Send to household heads instead of contacts. */
45
+ sendToContactParents?: boolean;
46
+ /** Outbound SMS phone number ID (required for SMS). */
47
+ textPhoneNumberId?: number;
48
+ /** Exclude contacts who opted out of bulk messages. */
49
+ excludeOptedOutOfBulkMessages?: boolean;
50
+ /** Texting compliance filter level (SMS only). */
51
+ textingComplianceLevel?: TextingComplianceLevel;
52
+ /** Timezone for date/time rendering in messages. */
53
+ timeZoneName?: string;
54
+ /** Locale for value formatting in messages. */
55
+ cultureName?: string;
56
+ /** Alternate email type ID. */
57
+ alternateEmailTypeId?: number;
58
+ /** Related publication ID. */
59
+ publicationId?: number;
60
+ }
61
+
62
+ /**
63
+ * Communication - Response model from /communications endpoints.
64
+ * Uses camelCase internally; API returns PascalCase.
65
+ *
66
+ * API returns: CommunicationId, AuthorUserId, AuthorName, Subject, etc.
67
+ */
68
+ export interface Communication {
69
+ /** Unique identifier of the communication. */
70
+ communicationId: number;
71
+ /** User ID who authored the communication. */
72
+ authorUserId: number;
73
+ /** Display name of the author (readonly). */
74
+ authorName: string;
75
+ /** Subject line or SMS content. */
76
+ subject: string;
77
+ /** Body content. */
78
+ body?: string;
79
+ /** Start/send date. */
80
+ startDate: string;
81
+ /** Expiration date. */
82
+ expirationDate?: string;
83
+ /** Current status. */
84
+ status?: CommunicationStatus;
85
+ /** Sender contact ID. */
86
+ fromContactId: number;
87
+ /** Sender display name (readonly). */
88
+ fromName: string;
89
+ /** Sender email address (readonly). */
90
+ fromAddress: string;
91
+ /** Reply-to contact ID. */
92
+ replyToContactId: number;
93
+ /** Reply-to display name (readonly). */
94
+ replyToName: string;
95
+ /** Reply-to email address (readonly). */
96
+ replyToAddress: string;
97
+ /** Associated task ID. */
98
+ taskId?: number;
99
+ /** Selection ID for recipients. */
100
+ selectionId?: number;
101
+ /** Single recipient contact ID override. */
102
+ recipientContactId?: number;
103
+ /** Recipient display name (readonly). */
104
+ recipientName?: string;
105
+ /** Send to household heads. */
106
+ sendToContactParents?: boolean;
107
+ /** Exclude opted-out contacts. */
108
+ excludeOptedOutOfBulkMessages?: boolean;
109
+ /** Texting compliance level. */
110
+ textingComplianceLevel?: TextingComplianceLevel;
111
+ /** Timezone for rendering. */
112
+ timeZoneName?: string;
113
+ /** Locale for formatting. */
114
+ cultureName?: string;
115
+ /** Outbound SMS phone number ID. */
116
+ textPhoneNumberId?: number;
117
+ /** Outbound SMS phone number (readonly). */
118
+ textPhoneNumber?: string;
119
+ /** Communication delivery type. */
120
+ communicationType: CommunicationType;
121
+ /** Alternate email type ID. */
122
+ alternateEmailTypeId?: number;
123
+ /** Related publication ID. */
124
+ publicationId?: number;
125
+ }
@@ -0,0 +1,34 @@
1
+ /**
2
+ * MessageAddress - Email address with display name.
3
+ * Used for FromAddress, ToAddresses, and ReplyToAddress.
4
+ *
5
+ * API expects/returns: DisplayName, Address (PascalCase)
6
+ */
7
+ export interface MessageAddress {
8
+ /** Display name shown in email client. */
9
+ displayName: string;
10
+ /** Email address. */
11
+ address: string;
12
+ }
13
+
14
+ /**
15
+ * MessageInfo - Request payload for POST /messages.
16
+ * Sends emails directly by email address (bypasses MP contacts).
17
+ * Uses camelCase internally; converted to PascalCase for API.
18
+ *
19
+ * API expects: FromAddress, ToAddresses, ReplyToAddress, Subject, Body, StartDate
20
+ */
21
+ export interface MessageInfo {
22
+ /** Sender email address and display name. */
23
+ fromAddress: MessageAddress;
24
+ /** Array of recipient email addresses. */
25
+ toAddresses: MessageAddress[];
26
+ /** Reply-to email address (optional). */
27
+ replyToAddress?: MessageAddress;
28
+ /** Email subject line. */
29
+ subject: string;
30
+ /** Email body content (HTML supported). */
31
+ body: string;
32
+ /** ISO datetime to send. Future date = scheduled. */
33
+ startDate?: string;
34
+ }
@@ -0,0 +1,87 @@
1
+ /**
2
+ * Parameter direction enum.
3
+ * Indicates whether a parameter is input, output, or both.
4
+ */
5
+ export type ParameterDirection = 'Input' | 'Output' | 'InputOutput' | 'ReturnValue';
6
+
7
+ /**
8
+ * Parameter data type enum.
9
+ * All supported SQL data types for stored procedure parameters.
10
+ */
11
+ export type ParameterDataType =
12
+ | 'Unknown'
13
+ | 'String'
14
+ | 'Text'
15
+ | 'Xml'
16
+ | 'Byte'
17
+ | 'Integer16'
18
+ | 'Integer32'
19
+ | 'Integer64'
20
+ | 'Decimal'
21
+ | 'Real'
22
+ | 'Boolean'
23
+ | 'Date'
24
+ | 'Time'
25
+ | 'DateTime'
26
+ | 'Timestamp'
27
+ | 'Binary'
28
+ | 'Password'
29
+ | 'Money'
30
+ | 'Guid'
31
+ | 'Phone'
32
+ | 'Email'
33
+ | 'Variant'
34
+ | 'Separator'
35
+ | 'Image'
36
+ | 'Counter'
37
+ | 'TableName'
38
+ | 'GlobalFilter'
39
+ | 'TimeZone'
40
+ | 'Locale'
41
+ | 'LargeString'
42
+ | 'Url'
43
+ | 'Strings'
44
+ | 'Integers'
45
+ | 'Color'
46
+ | 'SecretKey';
47
+
48
+ /**
49
+ * ParameterInfo - Metadata about a stored procedure parameter.
50
+ * Uses camelCase internally; API returns PascalCase.
51
+ *
52
+ * API returns: Name, Direction, DataType, Size
53
+ */
54
+ export interface ParameterInfo {
55
+ /** Parameter name (e.g., "@ContactId"). */
56
+ name: string;
57
+ /** Parameter direction (Input, Output, etc.). */
58
+ direction: ParameterDirection;
59
+ /** SQL data type. */
60
+ dataType: ParameterDataType;
61
+ /** Maximum length/size. */
62
+ size: number;
63
+ }
64
+
65
+ /**
66
+ * ProcedureInfo - Metadata about a stored procedure.
67
+ * Returned from GET /procs endpoint.
68
+ * Uses camelCase internally; API returns PascalCase.
69
+ *
70
+ * API returns: Name, Parameters
71
+ */
72
+ export interface ProcedureInfo {
73
+ /** Procedure name (e.g., "api_Custom_GetContacts"). */
74
+ name: string;
75
+ /** Array of parameter definitions. */
76
+ parameters: ParameterInfo[];
77
+ }
78
+
79
+ /**
80
+ * ProcedureInput - Input parameters for executing a stored procedure.
81
+ * Keys should match parameter names with @ prefix.
82
+ *
83
+ * Example: { "@SelectionID": 26918, "@StartDate": "2024-01-01" }
84
+ */
85
+ export interface ProcedureInput {
86
+ [parameterName: string]: string | number | boolean | null;
87
+ }
@@ -0,0 +1,17 @@
1
+ /**
2
+ * TextInfo - Request payload for POST /texts.
3
+ * Sends SMS/MMS messages to phone numbers.
4
+ * Uses camelCase internally; converted to PascalCase for API.
5
+ *
6
+ * API expects: FromPhoneNumberId, ToPhoneNumbers, Message, StartDate
7
+ */
8
+ export interface TextInfo {
9
+ /** MP phone number ID for outbound messages. */
10
+ fromPhoneNumberId: number;
11
+ /** Array of recipient phone numbers in E.164 format (e.g., "+15551234567"). */
12
+ toPhoneNumbers: string[];
13
+ /** Message content (SMS character limits apply). */
14
+ message: string;
15
+ /** ISO datetime to send. Future date = scheduled. */
16
+ startDate?: string;
17
+ }
package/src/index.ts CHANGED
@@ -1,7 +1,11 @@
1
- import { AxiosInstance } from 'axios';
1
+ import { AxiosInstance, AxiosRequestConfig } from 'axios';
2
2
  import { createApiBase, MPApiBase, ErrorDetails, MPGetQuery, MPCreateQuery, MPUpdateQuery, DateTimeIsoString } from './api';
3
- import { convertToCamelCase, convertToSnakeCase, escapeSql, stringifyURLParams } from './utils/converters';
3
+ import { convertToCamelCase, convertToSnakeCase, convertToPascalCase, convertFromPascalCase, escapeSql, stringifyURLParams } from './utils/converters';
4
4
  import { Contact, ContactRecord } from './tables/contacts';
5
+ import { Communication, CommunicationInfo, CommunicationType, CommunicationStatus, TextingComplianceLevel } from './endpoints/communications';
6
+ import { MessageInfo, MessageAddress } from './endpoints/messages';
7
+ import { TextInfo } from './endpoints/texts';
8
+ import { ProcedureInfo, ParameterInfo, ParameterDirection, ParameterDataType, ProcedureInput } from './endpoints/procedures';
5
9
  import { Event, EventRecord } from './tables/events';
6
10
  import { Group, GroupRecord } from './tables/groups';
7
11
  import { Address, AddressRecord } from './tables/addresses';
@@ -64,6 +68,20 @@ export type CreateFilePayload = WithRequired<
64
68
  'Description' | 'IsDefaultImage'
65
69
  >;
66
70
 
71
+ // Communications API payload types
72
+ export type CreateCommunicationPayload = WithRequired<
73
+ CommunicationInfo,
74
+ 'authorUserId' | 'subject' | 'fromContactId' | 'replyToContactId' | 'communicationType' | 'contacts'
75
+ >;
76
+ export type CreateMessagePayload = WithRequired<
77
+ MessageInfo,
78
+ 'fromAddress' | 'toAddresses' | 'subject' | 'body'
79
+ >;
80
+ export type CreateTextPayload = WithRequired<
81
+ TextInfo,
82
+ 'fromPhoneNumberId' | 'toPhoneNumbers' | 'message'
83
+ >;
84
+
67
85
 
68
86
  export interface ContactDetails extends Contact, Participant, Household {
69
87
  householdID: number;
@@ -244,12 +262,41 @@ export type MPInstance = {
244
262
  : Promise<AttachedFile | { error: ErrorDetails; }>;
245
263
  updateFiles(table: string, fileId: number, data: WithRequired<Partial<AttachedFile>, 'FileId'>[])
246
264
  : Promise<AttachedFile[] | { error: ErrorDetails; }>;
265
+
266
+ // Communications API
267
+ sendCommunication(
268
+ data: CreateCommunicationPayload,
269
+ config?: AxiosRequestConfig
270
+ ): Promise<Communication | { error: ErrorDetails; }>;
271
+ sendMessage(
272
+ data: CreateMessagePayload,
273
+ config?: AxiosRequestConfig
274
+ ): Promise<Communication | { error: ErrorDetails; }>;
275
+ sendText(
276
+ data: CreateTextPayload,
277
+ config?: AxiosRequestConfig
278
+ ): Promise<Communication | { error: ErrorDetails; }>;
279
+
280
+ // Procedures API
281
+ getProcedures(
282
+ search?: string,
283
+ config?: AxiosRequestConfig
284
+ ): Promise<ProcedureInfo[] | { error: ErrorDetails; }>;
285
+ executeProcedure<T = Record<string, any>>(
286
+ procedureName: string,
287
+ input?: ProcedureInput,
288
+ config?: AxiosRequestConfig
289
+ ): Promise<T[][] | { error: ErrorDetails; }>;
247
290
  };
248
291
 
249
292
 
250
293
  export const createMPInstance = ({ auth }: { auth: { username: string; password: string; }; }): MPInstance => {
251
294
 
252
- const { getOne, getMany, createOne, createMany, updateMany, createFile, updateFile, get, post, put } = createApiBase({ auth });
295
+ const {
296
+ getOne, getMany, createOne, createMany, updateMany, createFile, updateFile,
297
+ get, post, put,
298
+ sendCommunication, sendMessage, sendText, getProcedures, executeProcedure
299
+ } = createApiBase({ auth });
253
300
 
254
301
  return {
255
302
  get,
@@ -494,10 +541,20 @@ export const createMPInstance = ({ auth }: { auth: { username: string; password:
494
541
  { path: `/files/${table}/${fileId}`, data }
495
542
  );
496
543
  },
544
+
545
+ // Communications API
546
+ sendCommunication,
547
+ sendMessage,
548
+ sendText,
549
+
550
+ // Procedures API
551
+ getProcedures,
552
+ executeProcedure,
497
553
  };
498
554
  };
499
555
 
500
556
  export {
557
+ // Tables
501
558
  Contact,
502
559
  Participant,
503
560
  Event,
@@ -513,10 +570,31 @@ export {
513
570
  ContactEmailAddress,
514
571
  ContactWithEmailAddress,
515
572
  ContactWithEmailAddresses,
573
+
574
+ // Communications endpoint types
575
+ Communication,
576
+ CommunicationInfo,
577
+ CommunicationType,
578
+ CommunicationStatus,
579
+ TextingComplianceLevel,
580
+ MessageInfo,
581
+ MessageAddress,
582
+ TextInfo,
583
+
584
+ // Procedures endpoint types
585
+ ProcedureInfo,
586
+ ParameterInfo,
587
+ ParameterDirection,
588
+ ParameterDataType,
589
+ ProcedureInput,
590
+
591
+ // Utilities
516
592
  ErrorDetails,
517
593
  DateTimeIsoString,
518
594
  convertToCamelCase,
519
595
  convertToSnakeCase,
596
+ convertToPascalCase,
597
+ convertFromPascalCase,
520
598
  stringifyURLParams,
521
599
  escapeSql
522
600
  };
@@ -54,6 +54,7 @@ export type EventRecord = {
54
54
  Allow_Email: boolean;
55
55
  Show_Building_Room_Info: boolean;
56
56
  Convert_Default_Contacts: boolean;
57
+ Online_Attendance: boolean;
57
58
  }
58
59
 
59
60
  export type Event = {
@@ -112,5 +113,6 @@ export type Event = {
112
113
  allowEmail: boolean;
113
114
  showBuildingRoomInfo: boolean;
114
115
  convertDefaultContacts: boolean;
116
+ onlineAttendance: boolean;
115
117
  }
116
118
 
@@ -114,3 +114,67 @@ export function convertToCamelCase<T extends Record<string, any> = Record<string
114
114
  export function convertToSnakeCase<T extends Record<string, any> = Record<string, any>, D extends Record<string, any> = Record<string, any>>(obj: Partial<D>, capitalIds = true): T {
115
115
  return caseConverter(obj, { type: 'toSnake', capitalIds });
116
116
  }
117
+
118
+ /**
119
+ * Converts a camelCase string to PascalCase.
120
+ * Example: "authorUserId" → "AuthorUserId"
121
+ */
122
+ export function toPascalCase(str: string): string {
123
+ if (!str) return str;
124
+ return str.charAt(0).toUpperCase() + str.slice(1);
125
+ }
126
+
127
+ /**
128
+ * Converts a PascalCase string to camelCase.
129
+ * Example: "AuthorUserId" → "authorUserId"
130
+ */
131
+ export function fromPascalCase(str: string): string {
132
+ if (!str) return str;
133
+ return str.charAt(0).toLowerCase() + str.slice(1);
134
+ }
135
+
136
+ /**
137
+ * Recursively converts object keys between camelCase and PascalCase.
138
+ * Used for /communications, /messages, /texts, /procs endpoints.
139
+ */
140
+ export function pascalCaseConverter<T>(
141
+ obj: T,
142
+ direction: 'toPascal' | 'fromPascal'
143
+ ): T {
144
+ const caseFn = direction === 'toPascal' ? toPascalCase : fromPascalCase;
145
+
146
+ if (Array.isArray(obj)) {
147
+ return obj.map(val => pascalCaseConverter(val, direction)) as T;
148
+ }
149
+
150
+ if (obj !== null && typeof obj === 'object') {
151
+ const result: Record<string, unknown> = {};
152
+ for (const key in obj) {
153
+ if (Object.prototype.hasOwnProperty.call(obj, key)) {
154
+ const newKey = caseFn(key);
155
+ result[newKey] = pascalCaseConverter((obj as Record<string, unknown>)[key], direction);
156
+ }
157
+ }
158
+ return result as T;
159
+ }
160
+
161
+ return obj;
162
+ }
163
+
164
+ /**
165
+ * Converts camelCase object keys to PascalCase.
166
+ * Used for outgoing requests to /communications, /messages, /texts endpoints.
167
+ * Example: { authorUserId: 1 } → { AuthorUserId: 1 }
168
+ */
169
+ export function convertToPascalCase<T extends Record<string, any>>(obj: T): T {
170
+ return pascalCaseConverter(obj, 'toPascal');
171
+ }
172
+
173
+ /**
174
+ * Converts PascalCase object keys to camelCase.
175
+ * Used for incoming responses from /communications, /messages, /texts, /procs endpoints.
176
+ * Example: { AuthorUserId: 1 } → { authorUserId: 1 }
177
+ */
178
+ export function convertFromPascalCase<T extends Record<string, any>>(obj: T): T {
179
+ return pascalCaseConverter(obj, 'fromPascal');
180
+ }