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.
- package/.claude/settings.local.json +13 -0
- package/dev/Swagger UI.html +6662 -0
- package/dist/api.d.ts +24 -0
- package/dist/api.d.ts.map +1 -1
- package/dist/api.js +61 -1
- package/dist/endpoints/communications.d.ts +122 -0
- package/dist/endpoints/communications.d.ts.map +1 -0
- package/dist/endpoints/communications.js +2 -0
- package/dist/endpoints/messages.d.ts +34 -0
- package/dist/endpoints/messages.d.ts.map +1 -0
- package/dist/endpoints/messages.js +2 -0
- package/dist/endpoints/procedures.d.ts +49 -0
- package/dist/endpoints/procedures.d.ts.map +1 -0
- package/dist/endpoints/procedures.js +2 -0
- package/dist/endpoints/texts.d.ts +18 -0
- package/dist/endpoints/texts.d.ts.map +1 -0
- package/dist/endpoints/texts.js +2 -0
- package/dist/index.d.ts +25 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +11 -2
- package/dist/tables/events.d.ts +2 -0
- package/dist/tables/events.d.ts.map +1 -1
- package/dist/utils/converters.d.ts +27 -0
- package/dist/utils/converters.d.ts.map +1 -1
- package/dist/utils/converters.js +60 -0
- package/package.json +1 -1
- package/src/api.ts +86 -2
- package/src/endpoints/communications.ts +125 -0
- package/src/endpoints/messages.ts +34 -0
- package/src/endpoints/procedures.ts +87 -0
- package/src/endpoints/texts.ts +17 -0
- package/src/index.ts +81 -3
- package/src/tables/events.ts +2 -0
- package/src/utils/converters.ts +64 -0
- package/tasks/todo.md +617 -0
package/tasks/todo.md
ADDED
|
@@ -0,0 +1,617 @@
|
|
|
1
|
+
# MinistryPlatform Communications API & Stored Procedures Implementation Plan
|
|
2
|
+
|
|
3
|
+
## API Endpoints Summary (from Swagger)
|
|
4
|
+
|
|
5
|
+
| Endpoint | Method | Description |
|
|
6
|
+
|----------|--------|-------------|
|
|
7
|
+
| `POST /communications` | POST | Creates new communication and immediately renders/schedules for delivery |
|
|
8
|
+
| `GET /communications/{communicationId}` | GET | Returns communication by ID |
|
|
9
|
+
| `DELETE /communications/{communicationId}` | DELETE | Deletes communication by ID |
|
|
10
|
+
| `POST /messages` | POST | Creates emails from provided info and schedules for delivery |
|
|
11
|
+
| `POST /texts` | POST | Creates SMS/MMS messages and schedules for delivery |
|
|
12
|
+
| `GET /procs` | GET | Returns list of available procedures with metadata |
|
|
13
|
+
| `GET /procs/{procedure}` | GET | Executes stored procedure with query string params |
|
|
14
|
+
| `POST /procs/{procedure}` | POST | Executes stored procedure with body params |
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## 1. Communications Endpoint (`POST /communications`)
|
|
19
|
+
|
|
20
|
+
### Request Format
|
|
21
|
+
Supports both JSON and multipart/form-data (for attachments).
|
|
22
|
+
|
|
23
|
+
**CommunicationInfo Request Body:**
|
|
24
|
+
```typescript
|
|
25
|
+
interface CommunicationInfo {
|
|
26
|
+
AuthorUserId: number; // Required - User ID who authored
|
|
27
|
+
Subject: string; // Required - Email subject or SMS content
|
|
28
|
+
Body: string; // Email body content (HTML supported)
|
|
29
|
+
FromContactId: number; // Required - Contact ID of sender
|
|
30
|
+
ReplyToContactId: number; // Required - Contact ID for replies
|
|
31
|
+
CommunicationType: CommunicationType; // Required - 'Email' | 'SMS'
|
|
32
|
+
Contacts: number[]; // Required - Array of recipient Contact IDs
|
|
33
|
+
StartDate?: string; // ISO date - when to send (future = scheduled)
|
|
34
|
+
IsBulkEmail?: boolean; // Default false
|
|
35
|
+
SendToContactParents?: boolean; // Send to household heads
|
|
36
|
+
TextPhoneNumberId?: number; // Required for SMS - outbound phone ID
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
type CommunicationType = 'Unknown' | 'Email' | 'SMS' | 'RssFeed' | 'GlobalMFA';
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
**Example Request:**
|
|
43
|
+
```json
|
|
44
|
+
{
|
|
45
|
+
"AuthorUserId": 4,
|
|
46
|
+
"Body": "Test Body",
|
|
47
|
+
"FromContactId": 2,
|
|
48
|
+
"ReplyToContactId": 2,
|
|
49
|
+
"CommunicationType": "Email",
|
|
50
|
+
"Contacts": [200145, 200109, 200536],
|
|
51
|
+
"IsBulkEmail": false,
|
|
52
|
+
"SendToContactParents": false,
|
|
53
|
+
"Subject": "Test Subject",
|
|
54
|
+
"StartDate": "2017-01-01T00:00:00",
|
|
55
|
+
"TextPhoneNumberId": 1
|
|
56
|
+
}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### Response Model (Communication)
|
|
60
|
+
```typescript
|
|
61
|
+
interface Communication {
|
|
62
|
+
CommunicationId: number; // Unique identifier
|
|
63
|
+
AuthorUserId: number; // User ID who authored
|
|
64
|
+
AuthorName: string; // Display name of author (readonly)
|
|
65
|
+
Subject: string; // Subject line / SMS content
|
|
66
|
+
Body?: string; // Body content
|
|
67
|
+
StartDate: string; // ISO datetime
|
|
68
|
+
ExpirationDate?: string; // Optional expiration
|
|
69
|
+
Status?: CommunicationStatus; // Current status
|
|
70
|
+
FromContactId: number; // Sender contact ID
|
|
71
|
+
FromName: string; // Sender display name (readonly)
|
|
72
|
+
FromAddress: string; // Sender email (readonly)
|
|
73
|
+
ReplyToContactId: number; // Reply-to contact ID
|
|
74
|
+
ReplyToName: string; // Reply-to name (readonly)
|
|
75
|
+
ReplyToAddress: string; // Reply-to email (readonly)
|
|
76
|
+
TaskId?: number; // Associated task ID
|
|
77
|
+
SelectionId?: number; // Selection ID for recipients
|
|
78
|
+
RecipientContactId?: number; // Single recipient override
|
|
79
|
+
RecipientName?: string; // Recipient name (readonly)
|
|
80
|
+
SendToContactParents?: boolean; // Send to household heads
|
|
81
|
+
ExcludeOptedOutOfBulkMessages?: boolean; // Exclude opted-out
|
|
82
|
+
TextingComplianceLevel?: TextingComplianceLevel;
|
|
83
|
+
TimeZoneName?: string; // Timezone for date rendering
|
|
84
|
+
CultureName?: string; // Locale for formatting
|
|
85
|
+
TextPhoneNumberId?: number; // Outbound SMS phone ID
|
|
86
|
+
TextPhoneNumber?: string; // Outbound phone (readonly)
|
|
87
|
+
CommunicationType: CommunicationType;
|
|
88
|
+
AlternateEmailTypeId?: number; // Alternate email type
|
|
89
|
+
PublicationId?: number; // Related publication
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
type CommunicationStatus = 'Unknown' | 'Draft' | 'InReview' | 'ReadyToSend' | 'Sent';
|
|
93
|
+
type TextingComplianceLevel = 'None' | 'SingleOptIn' | 'DoubleOptIn';
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
## 2. Messages Endpoint (`POST /messages`)
|
|
99
|
+
|
|
100
|
+
### Request Format
|
|
101
|
+
Supports multipart/form-data for attachments.
|
|
102
|
+
|
|
103
|
+
**MessageInfo Request Body:**
|
|
104
|
+
```typescript
|
|
105
|
+
interface MessageInfo {
|
|
106
|
+
FromAddress: MessageAddress; // Required - Sender info
|
|
107
|
+
ToAddresses: MessageAddress[]; // Required - Recipients
|
|
108
|
+
ReplyToAddress?: MessageAddress; // Reply-to info
|
|
109
|
+
Subject: string; // Required - Email subject
|
|
110
|
+
Body: string; // Required - Email body (HTML)
|
|
111
|
+
StartDate?: string; // ISO date for scheduling
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
interface MessageAddress {
|
|
115
|
+
DisplayName: string; // Display name
|
|
116
|
+
Address: string; // Email address
|
|
117
|
+
}
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
**Example Request:**
|
|
121
|
+
```json
|
|
122
|
+
{
|
|
123
|
+
"FromAddress": { "DisplayName": "From Name", "Address": "from@test.com" },
|
|
124
|
+
"ToAddresses": [
|
|
125
|
+
{ "DisplayName": "To Address 1", "Address": "to1@test.com" },
|
|
126
|
+
{ "DisplayName": "To Address 2", "Address": "to2@test.com" }
|
|
127
|
+
],
|
|
128
|
+
"ReplyToAddress": { "DisplayName": "Reply Address", "Address": "reply@test.com" },
|
|
129
|
+
"Subject": "Test Subject",
|
|
130
|
+
"Body": "Test Body"
|
|
131
|
+
}
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
### Response
|
|
135
|
+
Returns `Communication` object (same as `/communications` endpoint).
|
|
136
|
+
|
|
137
|
+
---
|
|
138
|
+
|
|
139
|
+
## 3. Texts Endpoint (`POST /texts`)
|
|
140
|
+
|
|
141
|
+
### Request Format
|
|
142
|
+
Supports multipart/form-data for MMS attachments.
|
|
143
|
+
|
|
144
|
+
**TextInfo Request Body:**
|
|
145
|
+
```typescript
|
|
146
|
+
interface TextInfo {
|
|
147
|
+
FromPhoneNumberId: number; // Required - MP phone number ID
|
|
148
|
+
ToPhoneNumbers: string[]; // Required - E.164 format (+1XXXXXXXXXX)
|
|
149
|
+
Message: string; // Required - SMS/MMS content
|
|
150
|
+
StartDate?: string; // ISO date for scheduling
|
|
151
|
+
}
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
**Example Request:**
|
|
155
|
+
```json
|
|
156
|
+
{
|
|
157
|
+
"FromPhoneNumberId": 1,
|
|
158
|
+
"Message": "Test Body",
|
|
159
|
+
"StartDate": "2017-01-01T00:00:00",
|
|
160
|
+
"ToPhoneNumbers": [
|
|
161
|
+
"+13362702467",
|
|
162
|
+
"+16781231234"
|
|
163
|
+
]
|
|
164
|
+
}
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
### Response
|
|
168
|
+
Returns `Communication` object (same as `/communications` endpoint).
|
|
169
|
+
|
|
170
|
+
---
|
|
171
|
+
|
|
172
|
+
## 4. Procedures Endpoints
|
|
173
|
+
|
|
174
|
+
### `GET /procs` - List Available Procedures
|
|
175
|
+
|
|
176
|
+
**Query Parameters:**
|
|
177
|
+
- `$search` (string, optional) - Filter procedures by name
|
|
178
|
+
|
|
179
|
+
**Response:**
|
|
180
|
+
```typescript
|
|
181
|
+
interface ProcedureInfo {
|
|
182
|
+
Name: string; // Procedure name (e.g., "api_MyProc")
|
|
183
|
+
Parameters: ParameterInfo[]; // Parameter definitions
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
interface ParameterInfo {
|
|
187
|
+
Name: string; // Parameter name (e.g., "@ContactId")
|
|
188
|
+
Direction: ParameterDirection; // Input, Output, etc.
|
|
189
|
+
DataType: ParameterDataType; // String, Integer32, etc.
|
|
190
|
+
Size: number; // Max length
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
type ParameterDirection = 'Input' | 'Output' | 'InputOutput' | 'ReturnValue';
|
|
194
|
+
type ParameterDataType =
|
|
195
|
+
| 'Unknown' | 'String' | 'Text' | 'Xml' | 'Byte'
|
|
196
|
+
| 'Integer16' | 'Integer32' | 'Integer64'
|
|
197
|
+
| 'Decimal' | 'Real' | 'Boolean'
|
|
198
|
+
| 'Date' | 'Time' | 'DateTime' | 'Timestamp'
|
|
199
|
+
| 'Binary' | 'Password' | 'Money' | 'Guid'
|
|
200
|
+
| 'Phone' | 'Email' | 'Variant' | 'Separator'
|
|
201
|
+
| 'Image' | 'Counter' | 'TableName' | 'GlobalFilter'
|
|
202
|
+
| 'TimeZone' | 'Locale' | 'LargeString' | 'Url'
|
|
203
|
+
| 'Strings' | 'Integers' | 'Color' | 'SecretKey';
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
### `GET /procs/{procedure}` - Execute with Query Params
|
|
207
|
+
|
|
208
|
+
**Path Parameters:**
|
|
209
|
+
- `procedure` (string, required) - Procedure name
|
|
210
|
+
|
|
211
|
+
**Query Parameters:**
|
|
212
|
+
- Any procedure parameters as query string (e.g., `?@ContactId=123`)
|
|
213
|
+
|
|
214
|
+
### `POST /procs/{procedure}` - Execute with Body
|
|
215
|
+
|
|
216
|
+
**Path Parameters:**
|
|
217
|
+
- `procedure` (string, required) - Procedure name
|
|
218
|
+
|
|
219
|
+
**Request Body:**
|
|
220
|
+
```typescript
|
|
221
|
+
// Key-value pairs matching procedure parameters
|
|
222
|
+
interface ProcedureInput {
|
|
223
|
+
[parameterName: string]: any; // e.g., { "@SelectionID": 26918 }
|
|
224
|
+
}
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
**Response:**
|
|
228
|
+
Returns array of result sets (each is array of objects):
|
|
229
|
+
```typescript
|
|
230
|
+
type ProcedureResult = object[][];
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
---
|
|
234
|
+
|
|
235
|
+
## Implementation Plan
|
|
236
|
+
|
|
237
|
+
### Phase 1: Core Types (`src/types/`)
|
|
238
|
+
|
|
239
|
+
> **IMPORTANT:** These endpoints use **PascalCase** in the API (not Snake_Case like `/tables/`).
|
|
240
|
+
> We use camelCase internally (consistent with library), and convert to PascalCase before sending.
|
|
241
|
+
> Need to add `convertToPascalCase()` utility in `src/utils/converters.ts`.
|
|
242
|
+
|
|
243
|
+
#### 1.1 Create `src/types/communications.ts`
|
|
244
|
+
```typescript
|
|
245
|
+
// CommunicationInfo - Request payload (camelCase for library usage)
|
|
246
|
+
// API expects: AuthorUserId, FromContactId, etc. (PascalCase)
|
|
247
|
+
export interface CommunicationInfo {
|
|
248
|
+
authorUserId: number;
|
|
249
|
+
subject: string;
|
|
250
|
+
body?: string;
|
|
251
|
+
fromContactId: number;
|
|
252
|
+
replyToContactId: number;
|
|
253
|
+
communicationType: CommunicationType;
|
|
254
|
+
contacts: number[];
|
|
255
|
+
startDate?: string;
|
|
256
|
+
isBulkEmail?: boolean;
|
|
257
|
+
sendToContactParents?: boolean;
|
|
258
|
+
textPhoneNumberId?: number;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
// Communication - Response model (camelCase for library usage)
|
|
262
|
+
// API returns: CommunicationId, AuthorUserId, etc. (PascalCase)
|
|
263
|
+
export interface Communication {
|
|
264
|
+
communicationId: number;
|
|
265
|
+
authorUserId: number;
|
|
266
|
+
authorName: string;
|
|
267
|
+
subject: string;
|
|
268
|
+
body?: string;
|
|
269
|
+
startDate: string;
|
|
270
|
+
expirationDate?: string;
|
|
271
|
+
status?: CommunicationStatus;
|
|
272
|
+
fromContactId: number;
|
|
273
|
+
fromName: string;
|
|
274
|
+
fromAddress: string;
|
|
275
|
+
replyToContactId: number;
|
|
276
|
+
replyToName: string;
|
|
277
|
+
replyToAddress: string;
|
|
278
|
+
taskId?: number;
|
|
279
|
+
selectionId?: number;
|
|
280
|
+
recipientContactId?: number;
|
|
281
|
+
recipientName?: string;
|
|
282
|
+
sendToContactParents?: boolean;
|
|
283
|
+
excludeOptedOutOfBulkMessages?: boolean;
|
|
284
|
+
textingComplianceLevel?: TextingComplianceLevel;
|
|
285
|
+
timeZoneName?: string;
|
|
286
|
+
cultureName?: string;
|
|
287
|
+
textPhoneNumberId?: number;
|
|
288
|
+
textPhoneNumber?: string;
|
|
289
|
+
communicationType: CommunicationType;
|
|
290
|
+
alternateEmailTypeId?: number;
|
|
291
|
+
publicationId?: number;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
export type CommunicationType = 'Unknown' | 'Email' | 'SMS' | 'RssFeed' | 'GlobalMFA';
|
|
295
|
+
export type CommunicationStatus = 'Unknown' | 'Draft' | 'InReview' | 'ReadyToSend' | 'Sent';
|
|
296
|
+
export type TextingComplianceLevel = 'None' | 'SingleOptIn' | 'DoubleOptIn';
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
#### 1.2 Create `src/types/messages.ts`
|
|
300
|
+
```typescript
|
|
301
|
+
// MessageAddress - nested object (camelCase for library usage)
|
|
302
|
+
// API expects: DisplayName, Address (PascalCase)
|
|
303
|
+
export interface MessageAddress {
|
|
304
|
+
displayName: string;
|
|
305
|
+
address: string;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
// MessageInfo - Request payload (camelCase for library usage)
|
|
309
|
+
// API expects: FromAddress, ToAddresses, etc. (PascalCase)
|
|
310
|
+
export interface MessageInfo {
|
|
311
|
+
fromAddress: MessageAddress;
|
|
312
|
+
toAddresses: MessageAddress[];
|
|
313
|
+
replyToAddress?: MessageAddress;
|
|
314
|
+
subject: string;
|
|
315
|
+
body: string;
|
|
316
|
+
startDate?: string;
|
|
317
|
+
}
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
#### 1.3 Create `src/types/texts.ts`
|
|
321
|
+
```typescript
|
|
322
|
+
// TextInfo - Request payload (camelCase for library usage)
|
|
323
|
+
// API expects: FromPhoneNumberId, ToPhoneNumbers, Message (PascalCase)
|
|
324
|
+
export interface TextInfo {
|
|
325
|
+
fromPhoneNumberId: number;
|
|
326
|
+
toPhoneNumbers: string[];
|
|
327
|
+
message: string;
|
|
328
|
+
startDate?: string;
|
|
329
|
+
}
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
#### 1.4 Create `src/types/procedures.ts`
|
|
333
|
+
```typescript
|
|
334
|
+
// ProcedureInfo - Response from GET /procs (camelCase for library usage)
|
|
335
|
+
// API returns: Name, Parameters (PascalCase)
|
|
336
|
+
export interface ProcedureInfo {
|
|
337
|
+
name: string;
|
|
338
|
+
parameters: ParameterInfo[];
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
export interface ParameterInfo {
|
|
342
|
+
name: string;
|
|
343
|
+
direction: ParameterDirection;
|
|
344
|
+
dataType: ParameterDataType;
|
|
345
|
+
size: number;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
export type ParameterDirection = 'Input' | 'Output' | 'InputOutput' | 'ReturnValue';
|
|
349
|
+
export type ParameterDataType =
|
|
350
|
+
| 'Unknown' | 'String' | 'Text' | 'Xml' | 'Byte'
|
|
351
|
+
| 'Integer16' | 'Integer32' | 'Integer64'
|
|
352
|
+
| 'Decimal' | 'Real' | 'Boolean'
|
|
353
|
+
| 'Date' | 'Time' | 'DateTime' | 'Timestamp'
|
|
354
|
+
| 'Binary' | 'Password' | 'Money' | 'Guid'
|
|
355
|
+
| 'Phone' | 'Email' | 'Variant' | 'Separator'
|
|
356
|
+
| 'Image' | 'Counter' | 'TableName' | 'GlobalFilter'
|
|
357
|
+
| 'TimeZone' | 'Locale' | 'LargeString' | 'Url'
|
|
358
|
+
| 'Strings' | 'Integers' | 'Color' | 'SecretKey';
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
#### 1.5 Add to `src/utils/converters.ts`
|
|
362
|
+
```typescript
|
|
363
|
+
/**
|
|
364
|
+
* Converts camelCase object keys to PascalCase.
|
|
365
|
+
* Used for /communications, /messages, /texts endpoints.
|
|
366
|
+
* Example: { authorUserId: 1 } → { AuthorUserId: 1 }
|
|
367
|
+
*/
|
|
368
|
+
export function convertToPascalCase<T>(obj: Record<string, any>): T {
|
|
369
|
+
// Implementation: capitalize first letter of each key
|
|
370
|
+
// Handle nested objects and arrays recursively
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
/**
|
|
374
|
+
* Converts PascalCase object keys to camelCase.
|
|
375
|
+
* Used for responses from /communications, /messages, /texts, /procs endpoints.
|
|
376
|
+
* Example: { AuthorUserId: 1 } → { authorUserId: 1 }
|
|
377
|
+
*/
|
|
378
|
+
export function convertFromPascalCase<T>(obj: Record<string, any>): T {
|
|
379
|
+
// Implementation: lowercase first letter of each key
|
|
380
|
+
// Handle nested objects and arrays recursively
|
|
381
|
+
}
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
---
|
|
385
|
+
|
|
386
|
+
### Phase 2: API Methods (`src/api.ts`)
|
|
387
|
+
|
|
388
|
+
#### 2.1 Add New Type Definitions
|
|
389
|
+
```typescript
|
|
390
|
+
export type APISendCommunicationInstance = (
|
|
391
|
+
params: APISendCommunicationParameter
|
|
392
|
+
) => Promise<Communication | { error: ErrorDetails }>;
|
|
393
|
+
|
|
394
|
+
export type APISendMessageInstance = (
|
|
395
|
+
params: APISendMessageParameter
|
|
396
|
+
) => Promise<Communication | { error: ErrorDetails }>;
|
|
397
|
+
|
|
398
|
+
export type APISendTextInstance = (
|
|
399
|
+
params: APISendTextParameter
|
|
400
|
+
) => Promise<Communication | { error: ErrorDetails }>;
|
|
401
|
+
|
|
402
|
+
export type APIExecuteProcedureInstance = <T extends Record<string, any>>(
|
|
403
|
+
params: APIExecuteProcedureParameter
|
|
404
|
+
) => Promise<T[][] | { error: ErrorDetails }>;
|
|
405
|
+
|
|
406
|
+
export type APIGetProceduresInstance = (
|
|
407
|
+
search?: string
|
|
408
|
+
) => Promise<ProcedureInfo[] | { error: ErrorDetails }>;
|
|
409
|
+
```
|
|
410
|
+
|
|
411
|
+
#### 2.2 Add Core Methods
|
|
412
|
+
```typescript
|
|
413
|
+
// POST /communications
|
|
414
|
+
const sendCommunication = async ({ data, config }) => {
|
|
415
|
+
const url = '/communications';
|
|
416
|
+
const payload = convertToPascalCase(data); // camelCase → PascalCase
|
|
417
|
+
const res = await post(url, payload, config);
|
|
418
|
+
return convertFromPascalCase(res.data); // PascalCase → camelCase
|
|
419
|
+
};
|
|
420
|
+
|
|
421
|
+
// POST /messages
|
|
422
|
+
const sendMessage = async ({ data, config }) => {
|
|
423
|
+
const url = '/messages';
|
|
424
|
+
const payload = convertToPascalCase(data); // camelCase → PascalCase
|
|
425
|
+
const res = await post(url, payload, config);
|
|
426
|
+
return convertFromPascalCase(res.data); // PascalCase → camelCase
|
|
427
|
+
};
|
|
428
|
+
|
|
429
|
+
// POST /texts
|
|
430
|
+
const sendText = async ({ data, config }) => {
|
|
431
|
+
const url = '/texts';
|
|
432
|
+
const payload = convertToPascalCase(data); // camelCase → PascalCase
|
|
433
|
+
const res = await post(url, payload, config);
|
|
434
|
+
return convertFromPascalCase(res.data); // PascalCase → camelCase
|
|
435
|
+
};
|
|
436
|
+
|
|
437
|
+
// GET /procs
|
|
438
|
+
const getProcedures = async (search?: string) => {
|
|
439
|
+
const url = search ? `/procs?$search=${search}` : '/procs';
|
|
440
|
+
const res = await get(url);
|
|
441
|
+
return res.data.map(p => convertFromPascalCase(p)); // PascalCase → camelCase
|
|
442
|
+
};
|
|
443
|
+
|
|
444
|
+
// POST /procs/{procedure}
|
|
445
|
+
const executeProcedure = async <T>({ procedureName, input, config }) => {
|
|
446
|
+
const url = `/procs/${procedureName}`;
|
|
447
|
+
// Note: input params use @ParamName format, no conversion needed
|
|
448
|
+
const res = await post(url, input, config);
|
|
449
|
+
return res.data; // Returns T[][] - results may need conversion depending on proc
|
|
450
|
+
};
|
|
451
|
+
```
|
|
452
|
+
|
|
453
|
+
---
|
|
454
|
+
|
|
455
|
+
### Phase 3: Public API (`src/index.ts`)
|
|
456
|
+
|
|
457
|
+
#### 3.1 Update MPInstance Interface
|
|
458
|
+
```typescript
|
|
459
|
+
export type MPInstance = {
|
|
460
|
+
// ... existing methods ...
|
|
461
|
+
|
|
462
|
+
// Communications
|
|
463
|
+
sendCommunication(
|
|
464
|
+
data: CreateCommunicationPayload
|
|
465
|
+
): Promise<Communication | { error: ErrorDetails }>;
|
|
466
|
+
|
|
467
|
+
// Messages (by email address)
|
|
468
|
+
sendMessage(
|
|
469
|
+
data: CreateMessagePayload
|
|
470
|
+
): Promise<Communication | { error: ErrorDetails }>;
|
|
471
|
+
|
|
472
|
+
// Texts (by phone number)
|
|
473
|
+
sendText(
|
|
474
|
+
data: CreateTextPayload
|
|
475
|
+
): Promise<Communication | { error: ErrorDetails }>;
|
|
476
|
+
|
|
477
|
+
// Procedures
|
|
478
|
+
getProcedures(
|
|
479
|
+
search?: string
|
|
480
|
+
): Promise<ProcedureInfo[] | { error: ErrorDetails }>;
|
|
481
|
+
|
|
482
|
+
executeProcedure<T extends Record<string, any>>(
|
|
483
|
+
procedureName: string,
|
|
484
|
+
input?: Record<string, any>
|
|
485
|
+
): Promise<T[][] | { error: ErrorDetails }>;
|
|
486
|
+
};
|
|
487
|
+
```
|
|
488
|
+
|
|
489
|
+
#### 3.2 Create Payload Types
|
|
490
|
+
```typescript
|
|
491
|
+
// camelCase internally, converted to PascalCase before API call
|
|
492
|
+
export type CreateCommunicationPayload = WithRequired<
|
|
493
|
+
CommunicationInfo,
|
|
494
|
+
'authorUserId' | 'subject' | 'fromContactId' | 'replyToContactId' | 'communicationType' | 'contacts'
|
|
495
|
+
>;
|
|
496
|
+
|
|
497
|
+
export type CreateMessagePayload = WithRequired<
|
|
498
|
+
MessageInfo,
|
|
499
|
+
'fromAddress' | 'toAddresses' | 'subject' | 'body'
|
|
500
|
+
>;
|
|
501
|
+
|
|
502
|
+
export type CreateTextPayload = WithRequired<
|
|
503
|
+
TextInfo,
|
|
504
|
+
'fromPhoneNumberId' | 'toPhoneNumbers' | 'message'
|
|
505
|
+
>;
|
|
506
|
+
```
|
|
507
|
+
|
|
508
|
+
#### 3.3 Add Exports
|
|
509
|
+
```typescript
|
|
510
|
+
export {
|
|
511
|
+
// ... existing exports ...
|
|
512
|
+
Communication,
|
|
513
|
+
CommunicationInfo,
|
|
514
|
+
CommunicationType,
|
|
515
|
+
CommunicationStatus,
|
|
516
|
+
MessageInfo,
|
|
517
|
+
MessageAddress,
|
|
518
|
+
TextInfo,
|
|
519
|
+
ProcedureInfo,
|
|
520
|
+
ParameterInfo,
|
|
521
|
+
ParameterDirection,
|
|
522
|
+
ParameterDataType,
|
|
523
|
+
};
|
|
524
|
+
```
|
|
525
|
+
|
|
526
|
+
---
|
|
527
|
+
|
|
528
|
+
## File Changes Summary
|
|
529
|
+
|
|
530
|
+
| File | Action | Description |
|
|
531
|
+
|------|--------|-------------|
|
|
532
|
+
| `src/types/communications.ts` | **Create** | Communication types and enums |
|
|
533
|
+
| `src/types/messages.ts` | **Create** | Message and MessageAddress types |
|
|
534
|
+
| `src/types/texts.ts` | **Create** | TextInfo types |
|
|
535
|
+
| `src/types/procedures.ts` | **Create** | Procedure and Parameter types |
|
|
536
|
+
| `src/utils/converters.ts` | **Modify** | Add `convertToPascalCase()` and `convertFromPascalCase()` |
|
|
537
|
+
| `src/api.ts` | **Modify** | Add 5 new methods |
|
|
538
|
+
| `src/index.ts` | **Modify** | Export new methods and types |
|
|
539
|
+
|
|
540
|
+
---
|
|
541
|
+
|
|
542
|
+
## Implementation Notes
|
|
543
|
+
|
|
544
|
+
### Case Conversion
|
|
545
|
+
The Communications/Messages/Texts/Procs endpoints use **PascalCase** in request/response bodies (not Snake_Case like `/tables/`).
|
|
546
|
+
|
|
547
|
+
| Endpoint Type | API Format | Library Format | Conversion |
|
|
548
|
+
|---------------|------------|----------------|------------|
|
|
549
|
+
| `/tables/*` | Snake_Case | camelCase | `convertToSnakeCase()` / `convertToCamelCase()` |
|
|
550
|
+
| `/communications`, `/messages`, `/texts`, `/procs` | PascalCase | camelCase | `convertToPascalCase()` / `convertFromPascalCase()` |
|
|
551
|
+
|
|
552
|
+
**Implementation:** Add two new utility functions to `src/utils/converters.ts`:
|
|
553
|
+
- `convertToPascalCase()` - for outgoing requests
|
|
554
|
+
- `convertFromPascalCase()` - for incoming responses (same as existing `convertToCamelCase()` for first letter)
|
|
555
|
+
|
|
556
|
+
### Multipart Form Data Support
|
|
557
|
+
All three communication endpoints support file attachments via multipart/form-data. For the initial implementation, we can support JSON-only requests. File attachment support can be added later if needed.
|
|
558
|
+
|
|
559
|
+
### Scheduling
|
|
560
|
+
Setting `StartDate` to a future date schedules the communication for later delivery. If omitted or set to current time, sends immediately.
|
|
561
|
+
|
|
562
|
+
---
|
|
563
|
+
|
|
564
|
+
## Usage Examples
|
|
565
|
+
|
|
566
|
+
### Send Email via Communications API
|
|
567
|
+
```typescript
|
|
568
|
+
const mp = createMPInstance({ auth });
|
|
569
|
+
|
|
570
|
+
const result = await mp.sendCommunication({
|
|
571
|
+
authorUserId: 4,
|
|
572
|
+
fromContactId: 100,
|
|
573
|
+
replyToContactId: 100,
|
|
574
|
+
subject: 'Event Reminder',
|
|
575
|
+
body: '<h1>Reminder</h1><p>Service starts tomorrow!</p>',
|
|
576
|
+
communicationType: 'Email',
|
|
577
|
+
contacts: [1001, 1002, 1003],
|
|
578
|
+
startDate: '2024-01-15T09:00:00' // Schedule for Jan 15
|
|
579
|
+
});
|
|
580
|
+
```
|
|
581
|
+
|
|
582
|
+
### Send Email via Messages API
|
|
583
|
+
```typescript
|
|
584
|
+
const result = await mp.sendMessage({
|
|
585
|
+
fromAddress: { displayName: 'Church Admin', address: 'admin@church.org' },
|
|
586
|
+
toAddresses: [
|
|
587
|
+
{ displayName: 'John Doe', address: 'john@email.com' }
|
|
588
|
+
],
|
|
589
|
+
replyToAddress: { displayName: 'Support', address: 'support@church.org' },
|
|
590
|
+
subject: 'Welcome!',
|
|
591
|
+
body: '<h1>Welcome to our church!</h1>'
|
|
592
|
+
});
|
|
593
|
+
```
|
|
594
|
+
|
|
595
|
+
### Send SMS via Texts API
|
|
596
|
+
```typescript
|
|
597
|
+
const result = await mp.sendText({
|
|
598
|
+
fromPhoneNumberId: 1, // Your MP phone number ID
|
|
599
|
+
toPhoneNumbers: ['+15551234567', '+15559876543'],
|
|
600
|
+
message: 'Service starts in 30 minutes!'
|
|
601
|
+
});
|
|
602
|
+
```
|
|
603
|
+
|
|
604
|
+
### Execute Stored Procedure
|
|
605
|
+
```typescript
|
|
606
|
+
// List available procedures
|
|
607
|
+
const procs = await mp.getProcedures('api_');
|
|
608
|
+
|
|
609
|
+
// Execute procedure with parameters
|
|
610
|
+
const result = await mp.executeProcedure<ContactResult>(
|
|
611
|
+
'api_Custom_GetActiveMembers',
|
|
612
|
+
{ '@MinistryID': 5, '@StartDate': '2024-01-01' }
|
|
613
|
+
);
|
|
614
|
+
|
|
615
|
+
// Result is array of result sets
|
|
616
|
+
const contacts = result[0]; // First result set
|
|
617
|
+
```
|