plenna_utilities 1.11.0 → 1.13.0
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.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/src/airTable/index.d.ts +16 -0
- package/dist/src/airTable/index.js +56 -1
- package/dist/src/customerio/index.d.ts +2 -0
- package/dist/src/customerio/index.js +26 -0
- package/dist/src/google/index.d.ts +53 -1
- package/dist/src/google/index.js +69 -1
- package/dist/src/respira/index.d.ts +65 -0
- package/dist/src/respira/index.js +42 -0
- package/package.json +3 -1
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -30,3 +30,4 @@ __exportStar(require("./src/airTable"), exports);
|
|
|
30
30
|
__exportStar(require("./src/alerts/presenter"), exports);
|
|
31
31
|
__exportStar(require("./src/common/domain/shared"), exports);
|
|
32
32
|
__exportStar(require("./src/AI/bedrock"), exports);
|
|
33
|
+
__exportStar(require("./src/respira"), exports);
|
|
@@ -1,5 +1,21 @@
|
|
|
1
|
+
import { type FieldSet, type Records } from 'airtable';
|
|
2
|
+
export type { FieldSet } from 'airtable';
|
|
3
|
+
export type { Records } from 'airtable';
|
|
1
4
|
export declare class AirTable {
|
|
2
5
|
private readonly webhook;
|
|
3
6
|
constructor(webhook: string);
|
|
4
7
|
sendToAirTable(payload: Record<string, unknown>): Promise<boolean>;
|
|
5
8
|
}
|
|
9
|
+
export declare class AirtableAPI {
|
|
10
|
+
private readonly apiKey;
|
|
11
|
+
private readonly baseId;
|
|
12
|
+
private readonly tableName;
|
|
13
|
+
constructor(apiKey: string, baseId: string, tableName: string);
|
|
14
|
+
getRecords(valuesToSearch: string[], fieldToSearch: string, maxRecords: number, view?: string, options?: {
|
|
15
|
+
fields?: string[];
|
|
16
|
+
}): Promise<Array<Records<FieldSet>[number]>>;
|
|
17
|
+
updateRecords(records: Array<{
|
|
18
|
+
id: string;
|
|
19
|
+
fields: Record<string, unknown>;
|
|
20
|
+
}>): Promise<void>;
|
|
21
|
+
}
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
2
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.AirTable = void 0;
|
|
6
|
+
exports.AirtableAPI = exports.AirTable = void 0;
|
|
7
|
+
const airtable_1 = __importDefault(require("airtable"));
|
|
4
8
|
class AirTable {
|
|
5
9
|
webhook;
|
|
6
10
|
constructor(webhook) {
|
|
@@ -25,3 +29,54 @@ class AirTable {
|
|
|
25
29
|
}
|
|
26
30
|
}
|
|
27
31
|
exports.AirTable = AirTable;
|
|
32
|
+
class AirtableAPI {
|
|
33
|
+
apiKey;
|
|
34
|
+
baseId;
|
|
35
|
+
tableName;
|
|
36
|
+
constructor(apiKey, baseId, tableName) {
|
|
37
|
+
this.apiKey = apiKey;
|
|
38
|
+
this.baseId = baseId;
|
|
39
|
+
this.tableName = tableName;
|
|
40
|
+
}
|
|
41
|
+
async getRecords(valuesToSearch, fieldToSearch, maxRecords, view, options) {
|
|
42
|
+
return await new Promise((resolve, reject) => {
|
|
43
|
+
const base = new airtable_1.default({ apiKey: this.apiKey }).base(this.baseId);
|
|
44
|
+
const allRecords = [];
|
|
45
|
+
const filterByFormula = valuesToSearch.length === 1
|
|
46
|
+
? `{${fieldToSearch}} = '${valuesToSearch[0]}'`
|
|
47
|
+
: `OR(${valuesToSearch.map(v => `{${fieldToSearch}} = '${v}'`).join(', ')})`;
|
|
48
|
+
base(this.tableName)
|
|
49
|
+
.select({ filterByFormula, maxRecords, view: view ?? 'Grid view', ...options })
|
|
50
|
+
.eachPage((records, fetchNextPage) => {
|
|
51
|
+
console.log('records: ', records);
|
|
52
|
+
allRecords.push(...records);
|
|
53
|
+
fetchNextPage();
|
|
54
|
+
}, (err) => {
|
|
55
|
+
if (err !== null) {
|
|
56
|
+
console.error('❌ Error de Airtable:', err);
|
|
57
|
+
reject(err);
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
resolve(allRecords);
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
async updateRecords(records) {
|
|
65
|
+
const base = new airtable_1.default({ apiKey: this.apiKey }).base(this.baseId);
|
|
66
|
+
const chunkSize = 10;
|
|
67
|
+
for (let i = 0; i < records.length; i += chunkSize) {
|
|
68
|
+
const batch = records.slice(i, i + chunkSize).map((record) => (record));
|
|
69
|
+
console.log(`Actualizando batch ${i / chunkSize + 1}...`);
|
|
70
|
+
try {
|
|
71
|
+
await base(this.tableName).update(batch);
|
|
72
|
+
console.log(`✅ Update completado del batch ${i / chunkSize + 1}`);
|
|
73
|
+
}
|
|
74
|
+
catch (error) {
|
|
75
|
+
console.error('❌ Error de Airtable:', error);
|
|
76
|
+
throw error;
|
|
77
|
+
}
|
|
78
|
+
await new Promise((resolve) => setTimeout(resolve, 200));
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
exports.AirtableAPI = AirtableAPI;
|
|
@@ -6,4 +6,6 @@ export declare class CustomerIo {
|
|
|
6
6
|
constructor(key: string);
|
|
7
7
|
sendPushNotification(requestOptions: PushRequestOptions): Promise<boolean>;
|
|
8
8
|
sendEmail(requestOptions: EmailRequestOptions): Promise<boolean>;
|
|
9
|
+
sendPushNotificationWithResponse(requestOptions: PushRequestOptions): Promise<Record<string, unknown>>;
|
|
10
|
+
sendEmailWithResponse(requestOptions: EmailRequestOptions): Promise<Record<string, unknown>>;
|
|
9
11
|
}
|
|
@@ -33,5 +33,31 @@ class CustomerIo {
|
|
|
33
33
|
return false;
|
|
34
34
|
}
|
|
35
35
|
}
|
|
36
|
+
async sendPushNotificationWithResponse(requestOptions) {
|
|
37
|
+
try {
|
|
38
|
+
const request = new customerio_node_1.SendPushRequest(requestOptions);
|
|
39
|
+
const api = new customerio_node_1.APIClient(this.key, { region: customerio_node_1.RegionUS });
|
|
40
|
+
const response = await api.sendPush(request);
|
|
41
|
+
console.log('Sent push notification success: ', response);
|
|
42
|
+
return response;
|
|
43
|
+
}
|
|
44
|
+
catch (error) {
|
|
45
|
+
console.error('Failed to send push notification: ', error);
|
|
46
|
+
return { error };
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
async sendEmailWithResponse(requestOptions) {
|
|
50
|
+
try {
|
|
51
|
+
const request = new customerio_node_1.SendEmailRequest(requestOptions);
|
|
52
|
+
const api = new customerio_node_1.APIClient(this.key, { region: customerio_node_1.RegionUS });
|
|
53
|
+
const response = await api.sendEmail(request);
|
|
54
|
+
console.log('Sent email success: ', response);
|
|
55
|
+
return response;
|
|
56
|
+
}
|
|
57
|
+
catch (error) {
|
|
58
|
+
console.error('Failed to send email: ', error);
|
|
59
|
+
return { error };
|
|
60
|
+
}
|
|
61
|
+
}
|
|
36
62
|
}
|
|
37
63
|
exports.CustomerIo = CustomerIo;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { docs_v1 } from '@googleapis/docs';
|
|
2
|
+
import { calendar_v3 } from '@googleapis/calendar';
|
|
2
3
|
import { GoogleAuth, type JWTInput } from 'google-auth-library';
|
|
3
4
|
import { type JSONClient } from 'google-auth-library/build/src/auth/googleauth';
|
|
4
5
|
import { type IPlennaGoogleBase } from './requestBuilder';
|
|
@@ -14,6 +15,50 @@ interface deleteDocumentResponse {
|
|
|
14
15
|
success: boolean;
|
|
15
16
|
documentId?: string;
|
|
16
17
|
}
|
|
18
|
+
interface createCalendarEventResponse {
|
|
19
|
+
success: boolean;
|
|
20
|
+
event?: calendar_v3.Schema$Event;
|
|
21
|
+
}
|
|
22
|
+
interface deleteCalendarEventResponse {
|
|
23
|
+
success: boolean;
|
|
24
|
+
eventId?: string;
|
|
25
|
+
}
|
|
26
|
+
interface updateCalendarEventResponse {
|
|
27
|
+
success: boolean;
|
|
28
|
+
event?: calendar_v3.Schema$Event;
|
|
29
|
+
}
|
|
30
|
+
export interface IRescheduleEvent {
|
|
31
|
+
start: {
|
|
32
|
+
dateTime?: string;
|
|
33
|
+
date?: string;
|
|
34
|
+
timeZone?: string;
|
|
35
|
+
};
|
|
36
|
+
end: {
|
|
37
|
+
dateTime?: string;
|
|
38
|
+
date?: string;
|
|
39
|
+
timeZone?: string;
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
export interface ICalendarEventInsertParameters {
|
|
43
|
+
calendarId: string;
|
|
44
|
+
conferenceDataVersion: number;
|
|
45
|
+
maxAttendees: number;
|
|
46
|
+
sendNotifications: boolean;
|
|
47
|
+
sendUpdates: 'all' | 'externalOnly' | 'none';
|
|
48
|
+
supportsAttachments: boolean;
|
|
49
|
+
}
|
|
50
|
+
export interface ICalendarEventPatchParameters {
|
|
51
|
+
calendarId: string;
|
|
52
|
+
eventId: string;
|
|
53
|
+
alwaysIncludeEmail?: boolean;
|
|
54
|
+
conferenceDataVersion?: number;
|
|
55
|
+
maxAttendees?: number;
|
|
56
|
+
sendNotifications?: boolean;
|
|
57
|
+
sendUpdates?: 'all' | 'externalOnly' | 'none';
|
|
58
|
+
supportsAttachments?: boolean;
|
|
59
|
+
}
|
|
60
|
+
export interface ICalendarEvent extends calendar_v3.Schema$Event {
|
|
61
|
+
}
|
|
17
62
|
export interface ISchemaRequest extends docs_v1.Schema$Request {
|
|
18
63
|
}
|
|
19
64
|
export interface IInsertText extends docs_v1.Schema$InsertTextRequest {
|
|
@@ -24,8 +69,12 @@ export interface ICredentials extends JWTInput {
|
|
|
24
69
|
}
|
|
25
70
|
export declare class PlennaGoogleService {
|
|
26
71
|
private readonly credentials;
|
|
27
|
-
|
|
72
|
+
private readonly opts?;
|
|
73
|
+
constructor(credentials: ICredentials, opts?: {
|
|
74
|
+
subject?: string;
|
|
75
|
+
});
|
|
28
76
|
authorization(): GoogleAuth<JSONClient>;
|
|
77
|
+
calendarAuthorization(): GoogleAuth<JSONClient>;
|
|
29
78
|
getDocument(documentId: string): Promise<docs_v1.Schema$Document | undefined>;
|
|
30
79
|
cloneDocument(documentId: string, folderId: string): Promise<cloneDocumentResponse>;
|
|
31
80
|
buildPayload(template?: Array<Partial<IPlennaGoogleBase>>): ISchemaRequest[];
|
|
@@ -34,5 +83,8 @@ export declare class PlennaGoogleService {
|
|
|
34
83
|
exportDocumentAsUrl(fileId: string): Promise<string | undefined>;
|
|
35
84
|
exportDocumentAsFile(fileId: string): Promise<ArrayBuffer | undefined>;
|
|
36
85
|
deleteDocument(fileId: string): Promise<deleteDocumentResponse>;
|
|
86
|
+
createCalendarEvent(parameterOptions: ICalendarEventInsertParameters, event: ICalendarEvent): Promise<createCalendarEventResponse>;
|
|
87
|
+
deleteCalendarEvent(eventId: string, calendarId?: string): Promise<deleteCalendarEventResponse>;
|
|
88
|
+
updateCalendarEvent(parameterOptions: ICalendarEventPatchParameters, updates: Partial<ICalendarEvent>): Promise<updateCalendarEventResponse>;
|
|
37
89
|
}
|
|
38
90
|
export {};
|
package/dist/src/google/index.js
CHANGED
|
@@ -3,11 +3,14 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.PlennaGoogleService = void 0;
|
|
4
4
|
const docs_1 = require("@googleapis/docs");
|
|
5
5
|
const drive_1 = require("@googleapis/drive");
|
|
6
|
+
const calendar_1 = require("@googleapis/calendar");
|
|
6
7
|
const google_auth_library_1 = require("google-auth-library");
|
|
7
8
|
const requestBuilder_1 = require("./requestBuilder");
|
|
8
9
|
class PlennaGoogleService {
|
|
9
10
|
credentials;
|
|
10
|
-
|
|
11
|
+
opts;
|
|
12
|
+
constructor(credentials, opts) {
|
|
13
|
+
this.opts = opts ?? null;
|
|
11
14
|
this.credentials = credentials;
|
|
12
15
|
}
|
|
13
16
|
authorization() {
|
|
@@ -19,6 +22,17 @@ class PlennaGoogleService {
|
|
|
19
22
|
]
|
|
20
23
|
});
|
|
21
24
|
}
|
|
25
|
+
calendarAuthorization() {
|
|
26
|
+
return new google_auth_library_1.GoogleAuth({
|
|
27
|
+
credentials: this.credentials,
|
|
28
|
+
scopes: [
|
|
29
|
+
'https://www.googleapis.com/auth/calendar'
|
|
30
|
+
],
|
|
31
|
+
clientOptions: {
|
|
32
|
+
subject: this.opts?.subject ?? ''
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
}
|
|
22
36
|
async getDocument(documentId) {
|
|
23
37
|
const authClient = this.authorization();
|
|
24
38
|
const client = new docs_1.docs_v1.Docs({ auth: authClient });
|
|
@@ -114,5 +128,59 @@ class PlennaGoogleService {
|
|
|
114
128
|
return { success: false };
|
|
115
129
|
}
|
|
116
130
|
}
|
|
131
|
+
async createCalendarEvent(parameterOptions, event) {
|
|
132
|
+
const authClient = this.calendarAuthorization();
|
|
133
|
+
const calendar = new calendar_1.calendar_v3.Calendar({ auth: authClient });
|
|
134
|
+
try {
|
|
135
|
+
const response = await calendar.events.insert({
|
|
136
|
+
...parameterOptions,
|
|
137
|
+
requestBody: event
|
|
138
|
+
}, { headers: await authClient.getRequestHeaders() });
|
|
139
|
+
return {
|
|
140
|
+
success: true,
|
|
141
|
+
event: response.data
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
catch (error) {
|
|
145
|
+
console.log(error);
|
|
146
|
+
return { success: false };
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
async deleteCalendarEvent(eventId, calendarId = 'primary') {
|
|
150
|
+
const authClient = this.calendarAuthorization();
|
|
151
|
+
const calendar = new calendar_1.calendar_v3.Calendar({ auth: authClient });
|
|
152
|
+
try {
|
|
153
|
+
await calendar.events.delete({
|
|
154
|
+
calendarId,
|
|
155
|
+
eventId
|
|
156
|
+
}, { headers: await authClient.getRequestHeaders() });
|
|
157
|
+
return {
|
|
158
|
+
success: true,
|
|
159
|
+
eventId
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
catch (error) {
|
|
163
|
+
console.log(error);
|
|
164
|
+
return { success: false };
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
async updateCalendarEvent(parameterOptions, updates) {
|
|
168
|
+
const authClient = this.authorization();
|
|
169
|
+
const calendar = new calendar_1.calendar_v3.Calendar({ auth: authClient });
|
|
170
|
+
try {
|
|
171
|
+
const response = await calendar.events.patch({
|
|
172
|
+
...parameterOptions,
|
|
173
|
+
requestBody: updates
|
|
174
|
+
}, { headers: await authClient.getRequestHeaders() });
|
|
175
|
+
return {
|
|
176
|
+
success: true,
|
|
177
|
+
event: response.data
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
catch (error) {
|
|
181
|
+
console.log(error);
|
|
182
|
+
return { success: false };
|
|
183
|
+
}
|
|
184
|
+
}
|
|
117
185
|
}
|
|
118
186
|
exports.PlennaGoogleService = PlennaGoogleService;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
export interface IWhatsAppMessage {
|
|
2
|
+
phone: string;
|
|
3
|
+
name?: string;
|
|
4
|
+
email?: string;
|
|
5
|
+
ri_body_param_1?: string;
|
|
6
|
+
ri_body_param_2?: string;
|
|
7
|
+
ri_body_param_3?: string;
|
|
8
|
+
ri_body_param_4?: string;
|
|
9
|
+
ri_body_param_5?: string;
|
|
10
|
+
ri_body_param_6?: string;
|
|
11
|
+
ri_body_param_7?: string;
|
|
12
|
+
ri_body_param_8?: string;
|
|
13
|
+
ri_body_param_9?: string;
|
|
14
|
+
ri_body_param_10?: string;
|
|
15
|
+
ri_body_param_11?: string;
|
|
16
|
+
ri_body_param_12?: string;
|
|
17
|
+
ri_body_param_13?: string;
|
|
18
|
+
ri_body_param_14?: string;
|
|
19
|
+
ri_body_param_15?: string;
|
|
20
|
+
ri_body_param_16?: string;
|
|
21
|
+
ri_body_param_17?: string;
|
|
22
|
+
ri_body_param_18?: string;
|
|
23
|
+
ri_body_param_19?: string;
|
|
24
|
+
ri_body_param_20?: string;
|
|
25
|
+
ri_footer_param_1?: string;
|
|
26
|
+
ri_footer_param_2?: string;
|
|
27
|
+
ri_footer_param_3?: string;
|
|
28
|
+
ri_footer_param_4?: string;
|
|
29
|
+
ri_footer_param_5?: string;
|
|
30
|
+
ri_header_type?: string;
|
|
31
|
+
ri_header_text?: string;
|
|
32
|
+
ri_header_link?: string;
|
|
33
|
+
delivery_date?: string;
|
|
34
|
+
delivery_time?: string;
|
|
35
|
+
iana_timezone?: string;
|
|
36
|
+
tags?: string;
|
|
37
|
+
}
|
|
38
|
+
export interface ISendWhatsAppMessagesOptions {
|
|
39
|
+
template_name: string;
|
|
40
|
+
language: string;
|
|
41
|
+
omit_ticket_creation: string;
|
|
42
|
+
ticket_id?: number;
|
|
43
|
+
tags?: string;
|
|
44
|
+
add_to_queue?: boolean;
|
|
45
|
+
origin?: string;
|
|
46
|
+
subdomain?: string;
|
|
47
|
+
messages: IWhatsAppMessage[];
|
|
48
|
+
}
|
|
49
|
+
export interface IWhatsAppMessageDetailQuery {
|
|
50
|
+
id_single_notification: string;
|
|
51
|
+
phone?: string;
|
|
52
|
+
template_name?: string;
|
|
53
|
+
sunco_notification_id?: string;
|
|
54
|
+
origin?: string;
|
|
55
|
+
delivery_date_from?: string;
|
|
56
|
+
delivery_date_to?: string;
|
|
57
|
+
}
|
|
58
|
+
export declare class RespiraInternet {
|
|
59
|
+
private readonly apiKey;
|
|
60
|
+
private readonly username;
|
|
61
|
+
private readonly apiUrl;
|
|
62
|
+
constructor(apiKey: string, username: string, apiUrl: string);
|
|
63
|
+
sendWhatsAppMessages(options: ISendWhatsAppMessagesOptions): Promise<Response>;
|
|
64
|
+
getWhatsAppMessageDetail(query: IWhatsAppMessageDetailQuery): Promise<Response>;
|
|
65
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.RespiraInternet = void 0;
|
|
4
|
+
class RespiraInternet {
|
|
5
|
+
apiKey;
|
|
6
|
+
username;
|
|
7
|
+
apiUrl;
|
|
8
|
+
constructor(apiKey, username, apiUrl) {
|
|
9
|
+
this.apiKey = apiKey;
|
|
10
|
+
this.username = username;
|
|
11
|
+
this.apiUrl = apiUrl;
|
|
12
|
+
}
|
|
13
|
+
sendWhatsAppMessages(options) {
|
|
14
|
+
const auth = Buffer.from(`${this.username}:${this.apiKey}`).toString('base64');
|
|
15
|
+
return fetch(`${this.apiUrl}/messages/`, {
|
|
16
|
+
method: 'POST',
|
|
17
|
+
headers: {
|
|
18
|
+
Authorization: `Basic ${auth}`,
|
|
19
|
+
'Content-Type': 'application/json'
|
|
20
|
+
},
|
|
21
|
+
body: JSON.stringify(options)
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
getWhatsAppMessageDetail(query) {
|
|
25
|
+
const params = {};
|
|
26
|
+
Object.entries(query).forEach(([key, value]) => {
|
|
27
|
+
if (value !== undefined) {
|
|
28
|
+
params[key] = value;
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
const queryString = new URLSearchParams(params).toString();
|
|
32
|
+
const auth = Buffer.from(`${this.username}:${this.apiKey}`).toString('base64');
|
|
33
|
+
return fetch(`${this.apiUrl}/messages?${queryString}`, {
|
|
34
|
+
method: 'GET',
|
|
35
|
+
headers: {
|
|
36
|
+
Authorization: `Basic ${auth}`,
|
|
37
|
+
'Content-Type': 'application/json'
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
exports.RespiraInternet = RespiraInternet;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "plenna_utilities",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.13.0",
|
|
4
4
|
"description": "plenna's utils for backend projects",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -39,10 +39,12 @@
|
|
|
39
39
|
"@aws-sdk/client-bedrock-runtime": "^3.600.0",
|
|
40
40
|
"@aws-sdk/client-s3": "^3.600.0",
|
|
41
41
|
"@aws-sdk/s3-request-presigner": "^3.600.0",
|
|
42
|
+
"@googleapis/calendar": "^14.2.0",
|
|
42
43
|
"@googleapis/docs": "^3.0.2",
|
|
43
44
|
"@googleapis/drive": "^8.10.0",
|
|
44
45
|
"@googleapis/sheets": "^8.0.0",
|
|
45
46
|
"@slack/web-api": "^6.9.1",
|
|
47
|
+
"airtable": "^0.12.2",
|
|
46
48
|
"customerio-node": "^4.1.1",
|
|
47
49
|
"dotenv": "^16.4.5",
|
|
48
50
|
"google-auth-library": "^9.11.0",
|