nylas 7.11.0 → 7.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/lib/cjs/apiClient.js +17 -9
- package/lib/cjs/resources/auth.js +2 -2
- package/lib/cjs/resources/drafts.js +2 -2
- package/lib/cjs/resources/messages.js +26 -11
- package/lib/cjs/utils.js +60 -9
- package/lib/cjs/version.js +1 -1
- package/lib/esm/apiClient.js +17 -9
- package/lib/esm/resources/auth.js +1 -1
- package/lib/esm/resources/drafts.js +3 -3
- package/lib/esm/resources/messages.js +27 -12
- package/lib/esm/utils.js +58 -9
- package/lib/esm/version.js +1 -1
- package/lib/types/apiClient.d.ts +1 -1
- package/lib/types/models/drafts.d.ts +6 -1
- package/lib/types/models/response.d.ts +33 -0
- package/lib/types/resources/messages.d.ts +1 -1
- package/lib/types/utils.d.ts +15 -0
- package/lib/types/version.d.ts +1 -1
- package/package.json +5 -4
package/lib/cjs/apiClient.js
CHANGED
|
@@ -156,10 +156,6 @@ class APIClient {
|
|
|
156
156
|
}
|
|
157
157
|
if (optionParams.form) {
|
|
158
158
|
requestOptions.body = optionParams.form;
|
|
159
|
-
requestOptions.headers = {
|
|
160
|
-
...requestOptions.headers,
|
|
161
|
-
...optionParams.form.getHeaders(),
|
|
162
|
-
};
|
|
163
159
|
}
|
|
164
160
|
return requestOptions;
|
|
165
161
|
}
|
|
@@ -178,11 +174,19 @@ class APIClient {
|
|
|
178
174
|
const flowId = headers[exports.FLOW_ID_HEADER];
|
|
179
175
|
const text = await response.text();
|
|
180
176
|
try {
|
|
181
|
-
const
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
177
|
+
const parsed = JSON.parse(text);
|
|
178
|
+
const payload = (0, utils_js_1.objKeysToCamelCase)({
|
|
179
|
+
...parsed,
|
|
180
|
+
flowId,
|
|
181
|
+
// deprecated: headers will be removed in a future release. This is for backwards compatibility.
|
|
182
|
+
headers,
|
|
183
|
+
}, ['metadata']);
|
|
184
|
+
// Attach rawHeaders as a non-enumerable property to avoid breaking deep equality
|
|
185
|
+
Object.defineProperty(payload, 'rawHeaders', {
|
|
186
|
+
value: headers,
|
|
187
|
+
enumerable: false,
|
|
188
|
+
});
|
|
189
|
+
return payload;
|
|
186
190
|
}
|
|
187
191
|
catch (e) {
|
|
188
192
|
throw new Error(`Could not parse response from the server: ${text}`);
|
|
@@ -198,6 +202,10 @@ class APIClient {
|
|
|
198
202
|
}
|
|
199
203
|
async requestStream(options) {
|
|
200
204
|
const response = await this.sendRequest(options);
|
|
205
|
+
// TODO: See if we can fix this in a backwards compatible way
|
|
206
|
+
if (!response.body) {
|
|
207
|
+
throw new Error('No response body');
|
|
208
|
+
}
|
|
201
209
|
return response.body;
|
|
202
210
|
}
|
|
203
211
|
}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.Auth = void 0;
|
|
4
4
|
const uuid_1 = require("uuid");
|
|
5
|
-
const
|
|
5
|
+
const node_crypto_1 = require("node:crypto");
|
|
6
6
|
const resource_js_1 = require("./resource.js");
|
|
7
7
|
const utils_js_1 = require("../utils.js");
|
|
8
8
|
/**
|
|
@@ -166,7 +166,7 @@ class Auth extends resource_js_1.Resource {
|
|
|
166
166
|
return url;
|
|
167
167
|
}
|
|
168
168
|
hashPKCESecret(secret) {
|
|
169
|
-
const hash = (0,
|
|
169
|
+
const hash = (0, node_crypto_1.createHash)('sha256').update(secret).digest('hex');
|
|
170
170
|
return Buffer.from(hash).toString('base64').replace(/=+$/, '');
|
|
171
171
|
}
|
|
172
172
|
getTokenInfo(params) {
|
|
@@ -55,7 +55,7 @@ class Drafts extends resource_js_1.Resource {
|
|
|
55
55
|
});
|
|
56
56
|
}
|
|
57
57
|
else if (requestBody.attachments) {
|
|
58
|
-
const processedAttachments = await (0, utils_js_1.
|
|
58
|
+
const processedAttachments = await (0, utils_js_1.encodeAttachmentContent)(requestBody.attachments);
|
|
59
59
|
requestBody = {
|
|
60
60
|
...requestBody,
|
|
61
61
|
attachments: processedAttachments,
|
|
@@ -88,7 +88,7 @@ class Drafts extends resource_js_1.Resource {
|
|
|
88
88
|
});
|
|
89
89
|
}
|
|
90
90
|
else if (requestBody.attachments) {
|
|
91
|
-
const processedAttachments = await (0, utils_js_1.
|
|
91
|
+
const processedAttachments = await (0, utils_js_1.encodeAttachmentContent)(requestBody.attachments);
|
|
92
92
|
requestBody = {
|
|
93
93
|
...requestBody,
|
|
94
94
|
attachments: processedAttachments,
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.Messages = void 0;
|
|
4
|
+
const formdata_node_1 = require("formdata-node");
|
|
4
5
|
const utils_js_1 = require("../utils.js");
|
|
5
6
|
const resource_js_1 = require("./resource.js");
|
|
6
7
|
const smartCompose_js_1 = require("./smartCompose.js");
|
|
@@ -96,7 +97,7 @@ class Messages extends resource_js_1.Resource {
|
|
|
96
97
|
}
|
|
97
98
|
else {
|
|
98
99
|
if (requestBody.attachments) {
|
|
99
|
-
const processedAttachments = await (0, utils_js_1.
|
|
100
|
+
const processedAttachments = await (0, utils_js_1.encodeAttachmentContent)(requestBody.attachments);
|
|
100
101
|
requestOptions.body = {
|
|
101
102
|
...requestBody,
|
|
102
103
|
attachments: processedAttachments,
|
|
@@ -155,10 +156,7 @@ class Messages extends resource_js_1.Resource {
|
|
|
155
156
|
});
|
|
156
157
|
}
|
|
157
158
|
static _buildFormRequest(requestBody) {
|
|
158
|
-
|
|
159
|
-
const FD = require('form-data');
|
|
160
|
-
const FormDataConstructor = FD.default || FD;
|
|
161
|
-
const form = new FormDataConstructor();
|
|
159
|
+
const form = new formdata_node_1.FormData();
|
|
162
160
|
// Split out the message payload from the attachments
|
|
163
161
|
const messagePayload = {
|
|
164
162
|
...requestBody,
|
|
@@ -166,13 +164,30 @@ class Messages extends resource_js_1.Resource {
|
|
|
166
164
|
};
|
|
167
165
|
form.append('message', JSON.stringify((0, utils_js_1.objKeysToSnakeCase)(messagePayload)));
|
|
168
166
|
// Add a separate form field for each attachment
|
|
169
|
-
requestBody.attachments
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
167
|
+
if (requestBody.attachments && requestBody.attachments.length > 0) {
|
|
168
|
+
requestBody.attachments.map((attachment, index) => {
|
|
169
|
+
const contentId = attachment.contentId || `file${index}`;
|
|
170
|
+
// Handle different content types for formdata-node
|
|
171
|
+
if (typeof attachment.content === 'string') {
|
|
172
|
+
// Base64 string - create a Blob
|
|
173
|
+
const buffer = Buffer.from(attachment.content, 'base64');
|
|
174
|
+
const blob = new formdata_node_1.Blob([buffer], { type: attachment.contentType });
|
|
175
|
+
form.append(contentId, blob, attachment.filename);
|
|
176
|
+
}
|
|
177
|
+
else if (Buffer.isBuffer(attachment.content)) {
|
|
178
|
+
// Buffer - create a Blob
|
|
179
|
+
const blob = new formdata_node_1.Blob([attachment.content], {
|
|
180
|
+
type: attachment.contentType,
|
|
181
|
+
});
|
|
182
|
+
form.append(contentId, blob, attachment.filename);
|
|
183
|
+
}
|
|
184
|
+
else {
|
|
185
|
+
// ReadableStream - create a proper file-like object according to formdata-node docs
|
|
186
|
+
const file = (0, utils_js_1.attachmentStreamToFile)(attachment);
|
|
187
|
+
form.append(contentId, file, attachment.filename);
|
|
188
|
+
}
|
|
174
189
|
});
|
|
175
|
-
}
|
|
190
|
+
}
|
|
176
191
|
return form;
|
|
177
192
|
}
|
|
178
193
|
}
|
package/lib/cjs/utils.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.createFileRequestBuilder = createFileRequestBuilder;
|
|
4
|
+
exports.attachmentStreamToFile = attachmentStreamToFile;
|
|
5
|
+
exports.encodeAttachmentContent = encodeAttachmentContent;
|
|
4
6
|
exports.encodeAttachmentStreams = encodeAttachmentStreams;
|
|
5
7
|
exports.objKeysToCamelCase = objKeysToCamelCase;
|
|
6
8
|
exports.objKeysToSnakeCase = objKeysToSnakeCase;
|
|
@@ -8,10 +10,10 @@ exports.safePath = safePath;
|
|
|
8
10
|
exports.makePathParams = makePathParams;
|
|
9
11
|
exports.calculateTotalPayloadSize = calculateTotalPayloadSize;
|
|
10
12
|
const change_case_1 = require("change-case");
|
|
11
|
-
const fs = require("fs");
|
|
12
|
-
const path = require("path");
|
|
13
|
+
const fs = require("node:fs");
|
|
14
|
+
const path = require("node:path");
|
|
13
15
|
const mime = require("mime-types");
|
|
14
|
-
const
|
|
16
|
+
const node_stream_1 = require("node:stream");
|
|
15
17
|
function createFileRequestBuilder(filePath) {
|
|
16
18
|
const stats = fs.statSync(filePath);
|
|
17
19
|
const filename = path.basename(filePath);
|
|
@@ -45,18 +47,67 @@ function streamToBase64(stream) {
|
|
|
45
47
|
});
|
|
46
48
|
}
|
|
47
49
|
/**
|
|
48
|
-
*
|
|
50
|
+
* Converts a ReadableStream to a File-like object that can be used with FormData.
|
|
51
|
+
* @param attachment The attachment containing the stream and metadata.
|
|
52
|
+
* @param mimeType The MIME type for the file (optional).
|
|
53
|
+
* @returns A File-like object that properly handles the stream.
|
|
54
|
+
*/
|
|
55
|
+
function attachmentStreamToFile(attachment, mimeType) {
|
|
56
|
+
if (mimeType != null && typeof mimeType !== 'string') {
|
|
57
|
+
throw new Error('Invalid mimetype, expected string.');
|
|
58
|
+
}
|
|
59
|
+
const content = attachment.content;
|
|
60
|
+
if (typeof content === 'string' || Buffer.isBuffer(content)) {
|
|
61
|
+
throw new Error('Invalid attachment content, expected ReadableStream.');
|
|
62
|
+
}
|
|
63
|
+
// Create a file-shaped object that FormData can handle properly
|
|
64
|
+
const fileObject = {
|
|
65
|
+
type: mimeType || attachment.contentType,
|
|
66
|
+
name: attachment.filename,
|
|
67
|
+
[Symbol.toStringTag]: 'File',
|
|
68
|
+
stream() {
|
|
69
|
+
return content;
|
|
70
|
+
},
|
|
71
|
+
};
|
|
72
|
+
// Add size if available
|
|
73
|
+
if (attachment.size !== undefined) {
|
|
74
|
+
fileObject.size = attachment.size;
|
|
75
|
+
}
|
|
76
|
+
return fileObject;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Encodes the content of each attachment to base64.
|
|
80
|
+
* Handles ReadableStream, Buffer, and string content types.
|
|
49
81
|
* @param attachments The attachments to encode.
|
|
50
82
|
* @returns The attachments with their content encoded to base64.
|
|
51
83
|
*/
|
|
52
|
-
async function
|
|
84
|
+
async function encodeAttachmentContent(attachments) {
|
|
53
85
|
return await Promise.all(attachments.map(async (attachment) => {
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
86
|
+
let base64EncodedContent;
|
|
87
|
+
if (attachment.content instanceof node_stream_1.Readable) {
|
|
88
|
+
// ReadableStream -> base64
|
|
89
|
+
base64EncodedContent = await streamToBase64(attachment.content);
|
|
90
|
+
}
|
|
91
|
+
else if (Buffer.isBuffer(attachment.content)) {
|
|
92
|
+
// Buffer -> base64
|
|
93
|
+
base64EncodedContent = attachment.content.toString('base64');
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
// string (assumed to already be base64)
|
|
97
|
+
base64EncodedContent = attachment.content;
|
|
98
|
+
}
|
|
99
|
+
return { ...attachment, content: base64EncodedContent };
|
|
58
100
|
}));
|
|
59
101
|
}
|
|
102
|
+
/**
|
|
103
|
+
* @deprecated Use encodeAttachmentContent instead. This alias is provided for backwards compatibility.
|
|
104
|
+
* Encodes the content of each attachment stream to base64.
|
|
105
|
+
* @param attachments The attachments to encode.
|
|
106
|
+
* @returns The attachments with their content encoded to base64.
|
|
107
|
+
*/
|
|
108
|
+
async function encodeAttachmentStreams(attachments) {
|
|
109
|
+
return encodeAttachmentContent(attachments);
|
|
110
|
+
}
|
|
60
111
|
/**
|
|
61
112
|
* Applies the casing function and ensures numeric parts are preceded by underscores in snake_case.
|
|
62
113
|
* @param casingFunction The original casing function.
|
package/lib/cjs/version.js
CHANGED
package/lib/esm/apiClient.js
CHANGED
|
@@ -153,10 +153,6 @@ export default class APIClient {
|
|
|
153
153
|
}
|
|
154
154
|
if (optionParams.form) {
|
|
155
155
|
requestOptions.body = optionParams.form;
|
|
156
|
-
requestOptions.headers = {
|
|
157
|
-
...requestOptions.headers,
|
|
158
|
-
...optionParams.form.getHeaders(),
|
|
159
|
-
};
|
|
160
156
|
}
|
|
161
157
|
return requestOptions;
|
|
162
158
|
}
|
|
@@ -175,11 +171,19 @@ export default class APIClient {
|
|
|
175
171
|
const flowId = headers[FLOW_ID_HEADER];
|
|
176
172
|
const text = await response.text();
|
|
177
173
|
try {
|
|
178
|
-
const
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
174
|
+
const parsed = JSON.parse(text);
|
|
175
|
+
const payload = objKeysToCamelCase({
|
|
176
|
+
...parsed,
|
|
177
|
+
flowId,
|
|
178
|
+
// deprecated: headers will be removed in a future release. This is for backwards compatibility.
|
|
179
|
+
headers,
|
|
180
|
+
}, ['metadata']);
|
|
181
|
+
// Attach rawHeaders as a non-enumerable property to avoid breaking deep equality
|
|
182
|
+
Object.defineProperty(payload, 'rawHeaders', {
|
|
183
|
+
value: headers,
|
|
184
|
+
enumerable: false,
|
|
185
|
+
});
|
|
186
|
+
return payload;
|
|
183
187
|
}
|
|
184
188
|
catch (e) {
|
|
185
189
|
throw new Error(`Could not parse response from the server: ${text}`);
|
|
@@ -195,6 +199,10 @@ export default class APIClient {
|
|
|
195
199
|
}
|
|
196
200
|
async requestStream(options) {
|
|
197
201
|
const response = await this.sendRequest(options);
|
|
202
|
+
// TODO: See if we can fix this in a backwards compatible way
|
|
203
|
+
if (!response.body) {
|
|
204
|
+
throw new Error('No response body');
|
|
205
|
+
}
|
|
198
206
|
return response.body;
|
|
199
207
|
}
|
|
200
208
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Messages } from './messages.js';
|
|
2
2
|
import { Resource } from './resource.js';
|
|
3
|
-
import {
|
|
3
|
+
import { encodeAttachmentContent, calculateTotalPayloadSize, } from '../utils.js';
|
|
4
4
|
import { makePathParams } from '../utils.js';
|
|
5
5
|
/**
|
|
6
6
|
* Nylas Drafts API
|
|
@@ -52,7 +52,7 @@ export class Drafts extends Resource {
|
|
|
52
52
|
});
|
|
53
53
|
}
|
|
54
54
|
else if (requestBody.attachments) {
|
|
55
|
-
const processedAttachments = await
|
|
55
|
+
const processedAttachments = await encodeAttachmentContent(requestBody.attachments);
|
|
56
56
|
requestBody = {
|
|
57
57
|
...requestBody,
|
|
58
58
|
attachments: processedAttachments,
|
|
@@ -85,7 +85,7 @@ export class Drafts extends Resource {
|
|
|
85
85
|
});
|
|
86
86
|
}
|
|
87
87
|
else if (requestBody.attachments) {
|
|
88
|
-
const processedAttachments = await
|
|
88
|
+
const processedAttachments = await encodeAttachmentContent(requestBody.attachments);
|
|
89
89
|
requestBody = {
|
|
90
90
|
...requestBody,
|
|
91
91
|
attachments: processedAttachments,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Blob, FormData } from 'formdata-node';
|
|
2
|
+
import { attachmentStreamToFile, calculateTotalPayloadSize, encodeAttachmentContent, makePathParams, objKeysToSnakeCase, } from '../utils.js';
|
|
2
3
|
import { Resource } from './resource.js';
|
|
3
4
|
import { SmartCompose } from './smartCompose.js';
|
|
4
5
|
/**
|
|
@@ -93,7 +94,7 @@ export class Messages extends Resource {
|
|
|
93
94
|
}
|
|
94
95
|
else {
|
|
95
96
|
if (requestBody.attachments) {
|
|
96
|
-
const processedAttachments = await
|
|
97
|
+
const processedAttachments = await encodeAttachmentContent(requestBody.attachments);
|
|
97
98
|
requestOptions.body = {
|
|
98
99
|
...requestBody,
|
|
99
100
|
attachments: processedAttachments,
|
|
@@ -152,10 +153,7 @@ export class Messages extends Resource {
|
|
|
152
153
|
});
|
|
153
154
|
}
|
|
154
155
|
static _buildFormRequest(requestBody) {
|
|
155
|
-
|
|
156
|
-
const FD = require('form-data');
|
|
157
|
-
const FormDataConstructor = FD.default || FD;
|
|
158
|
-
const form = new FormDataConstructor();
|
|
156
|
+
const form = new FormData();
|
|
159
157
|
// Split out the message payload from the attachments
|
|
160
158
|
const messagePayload = {
|
|
161
159
|
...requestBody,
|
|
@@ -163,13 +161,30 @@ export class Messages extends Resource {
|
|
|
163
161
|
};
|
|
164
162
|
form.append('message', JSON.stringify(objKeysToSnakeCase(messagePayload)));
|
|
165
163
|
// Add a separate form field for each attachment
|
|
166
|
-
requestBody.attachments
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
164
|
+
if (requestBody.attachments && requestBody.attachments.length > 0) {
|
|
165
|
+
requestBody.attachments.map((attachment, index) => {
|
|
166
|
+
const contentId = attachment.contentId || `file${index}`;
|
|
167
|
+
// Handle different content types for formdata-node
|
|
168
|
+
if (typeof attachment.content === 'string') {
|
|
169
|
+
// Base64 string - create a Blob
|
|
170
|
+
const buffer = Buffer.from(attachment.content, 'base64');
|
|
171
|
+
const blob = new Blob([buffer], { type: attachment.contentType });
|
|
172
|
+
form.append(contentId, blob, attachment.filename);
|
|
173
|
+
}
|
|
174
|
+
else if (Buffer.isBuffer(attachment.content)) {
|
|
175
|
+
// Buffer - create a Blob
|
|
176
|
+
const blob = new Blob([attachment.content], {
|
|
177
|
+
type: attachment.contentType,
|
|
178
|
+
});
|
|
179
|
+
form.append(contentId, blob, attachment.filename);
|
|
180
|
+
}
|
|
181
|
+
else {
|
|
182
|
+
// ReadableStream - create a proper file-like object according to formdata-node docs
|
|
183
|
+
const file = attachmentStreamToFile(attachment);
|
|
184
|
+
form.append(contentId, file, attachment.filename);
|
|
185
|
+
}
|
|
171
186
|
});
|
|
172
|
-
}
|
|
187
|
+
}
|
|
173
188
|
return form;
|
|
174
189
|
}
|
|
175
190
|
}
|
package/lib/esm/utils.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { camelCase, snakeCase } from 'change-case';
|
|
2
|
-
import * as fs from 'fs';
|
|
3
|
-
import * as path from 'path';
|
|
2
|
+
import * as fs from 'node:fs';
|
|
3
|
+
import * as path from 'node:path';
|
|
4
4
|
import * as mime from 'mime-types';
|
|
5
|
-
import { Readable } from 'stream';
|
|
5
|
+
import { Readable } from 'node:stream';
|
|
6
6
|
export function createFileRequestBuilder(filePath) {
|
|
7
7
|
const stats = fs.statSync(filePath);
|
|
8
8
|
const filename = path.basename(filePath);
|
|
@@ -36,18 +36,67 @@ function streamToBase64(stream) {
|
|
|
36
36
|
});
|
|
37
37
|
}
|
|
38
38
|
/**
|
|
39
|
-
*
|
|
39
|
+
* Converts a ReadableStream to a File-like object that can be used with FormData.
|
|
40
|
+
* @param attachment The attachment containing the stream and metadata.
|
|
41
|
+
* @param mimeType The MIME type for the file (optional).
|
|
42
|
+
* @returns A File-like object that properly handles the stream.
|
|
43
|
+
*/
|
|
44
|
+
export function attachmentStreamToFile(attachment, mimeType) {
|
|
45
|
+
if (mimeType != null && typeof mimeType !== 'string') {
|
|
46
|
+
throw new Error('Invalid mimetype, expected string.');
|
|
47
|
+
}
|
|
48
|
+
const content = attachment.content;
|
|
49
|
+
if (typeof content === 'string' || Buffer.isBuffer(content)) {
|
|
50
|
+
throw new Error('Invalid attachment content, expected ReadableStream.');
|
|
51
|
+
}
|
|
52
|
+
// Create a file-shaped object that FormData can handle properly
|
|
53
|
+
const fileObject = {
|
|
54
|
+
type: mimeType || attachment.contentType,
|
|
55
|
+
name: attachment.filename,
|
|
56
|
+
[Symbol.toStringTag]: 'File',
|
|
57
|
+
stream() {
|
|
58
|
+
return content;
|
|
59
|
+
},
|
|
60
|
+
};
|
|
61
|
+
// Add size if available
|
|
62
|
+
if (attachment.size !== undefined) {
|
|
63
|
+
fileObject.size = attachment.size;
|
|
64
|
+
}
|
|
65
|
+
return fileObject;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Encodes the content of each attachment to base64.
|
|
69
|
+
* Handles ReadableStream, Buffer, and string content types.
|
|
40
70
|
* @param attachments The attachments to encode.
|
|
41
71
|
* @returns The attachments with their content encoded to base64.
|
|
42
72
|
*/
|
|
43
|
-
export async function
|
|
73
|
+
export async function encodeAttachmentContent(attachments) {
|
|
44
74
|
return await Promise.all(attachments.map(async (attachment) => {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
75
|
+
let base64EncodedContent;
|
|
76
|
+
if (attachment.content instanceof Readable) {
|
|
77
|
+
// ReadableStream -> base64
|
|
78
|
+
base64EncodedContent = await streamToBase64(attachment.content);
|
|
79
|
+
}
|
|
80
|
+
else if (Buffer.isBuffer(attachment.content)) {
|
|
81
|
+
// Buffer -> base64
|
|
82
|
+
base64EncodedContent = attachment.content.toString('base64');
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
// string (assumed to already be base64)
|
|
86
|
+
base64EncodedContent = attachment.content;
|
|
87
|
+
}
|
|
88
|
+
return { ...attachment, content: base64EncodedContent };
|
|
49
89
|
}));
|
|
50
90
|
}
|
|
91
|
+
/**
|
|
92
|
+
* @deprecated Use encodeAttachmentContent instead. This alias is provided for backwards compatibility.
|
|
93
|
+
* Encodes the content of each attachment stream to base64.
|
|
94
|
+
* @param attachments The attachments to encode.
|
|
95
|
+
* @returns The attachments with their content encoded to base64.
|
|
96
|
+
*/
|
|
97
|
+
export async function encodeAttachmentStreams(attachments) {
|
|
98
|
+
return encodeAttachmentContent(attachments);
|
|
99
|
+
}
|
|
51
100
|
/**
|
|
52
101
|
* Applies the casing function and ensures numeric parts are preceded by underscores in snake_case.
|
|
53
102
|
* @param casingFunction The original casing function.
|
package/lib/esm/version.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// This file is generated by scripts/exportVersion.js
|
|
2
|
-
export const SDK_VERSION = '7.
|
|
2
|
+
export const SDK_VERSION = '7.13.0';
|
package/lib/types/apiClient.d.ts
CHANGED
|
@@ -69,6 +69,11 @@ export interface CreateDraftRequest {
|
|
|
69
69
|
* An array of custom headers to add to the message.
|
|
70
70
|
*/
|
|
71
71
|
customHeaders?: CustomHeader[];
|
|
72
|
+
/**
|
|
73
|
+
* When true, the message body is sent as plain text and the MIME data doesn't include the HTML version of the message.
|
|
74
|
+
* When false, the message body is sent as HTML. Defaults to false.
|
|
75
|
+
*/
|
|
76
|
+
isPlaintext?: boolean;
|
|
72
77
|
}
|
|
73
78
|
/**
|
|
74
79
|
* Interface representing a request to send a message.
|
|
@@ -96,7 +101,7 @@ export interface Draft extends BaseMessage, Omit<CreateDraftRequest, 'attachment
|
|
|
96
101
|
/**
|
|
97
102
|
* Interface representing a request to update a draft.
|
|
98
103
|
*/
|
|
99
|
-
export type UpdateDraftRequest = Partial<CreateDraftRequest> & {
|
|
104
|
+
export type UpdateDraftRequest = Omit<Partial<CreateDraftRequest>, 'isPlaintext'> & {
|
|
100
105
|
/**
|
|
101
106
|
* Return drafts that are unread.
|
|
102
107
|
*/
|
|
@@ -3,6 +3,20 @@
|
|
|
3
3
|
*/
|
|
4
4
|
export interface NylasBaseResponse {
|
|
5
5
|
requestId: string;
|
|
6
|
+
/**
|
|
7
|
+
* The flow ID
|
|
8
|
+
* Provide this to Nylas support to help trace requests and responses
|
|
9
|
+
*/
|
|
10
|
+
flowId?: string;
|
|
11
|
+
/**
|
|
12
|
+
* The response headers with camelCased keys (backwards compatible)
|
|
13
|
+
* @deprecated Use rawHeaders instead
|
|
14
|
+
*/
|
|
15
|
+
headers?: Record<string, string>;
|
|
16
|
+
/**
|
|
17
|
+
* The raw response headers with original dashed lowercase keys
|
|
18
|
+
*/
|
|
19
|
+
rawHeaders?: Record<string, string>;
|
|
6
20
|
}
|
|
7
21
|
/**
|
|
8
22
|
* Interface representation of a Nylas response object
|
|
@@ -23,8 +37,13 @@ export interface NylasResponse<T> {
|
|
|
23
37
|
flowId?: string;
|
|
24
38
|
/**
|
|
25
39
|
* The response headers
|
|
40
|
+
* @deprecated Use rawHeaders instead
|
|
26
41
|
*/
|
|
27
42
|
headers?: Record<string, string>;
|
|
43
|
+
/**
|
|
44
|
+
* The raw response headers with original dashed lowercase keys
|
|
45
|
+
*/
|
|
46
|
+
rawHeaders?: Record<string, string>;
|
|
28
47
|
}
|
|
29
48
|
/**
|
|
30
49
|
* Interface representation of a Nylas response object that contains a list of objects.
|
|
@@ -42,6 +61,20 @@ export interface NylasListResponse<T> {
|
|
|
42
61
|
* The cursor to use to get the next page of data.
|
|
43
62
|
*/
|
|
44
63
|
nextCursor?: string;
|
|
64
|
+
/**
|
|
65
|
+
* The flow ID
|
|
66
|
+
* Provide this to Nylas support to help trace requests and responses
|
|
67
|
+
*/
|
|
68
|
+
flowId?: string;
|
|
69
|
+
/**
|
|
70
|
+
* The response headers with camelCased keys (backwards compatible)
|
|
71
|
+
* @deprecated Use rawHeaders instead
|
|
72
|
+
*/
|
|
73
|
+
headers?: Record<string, string>;
|
|
74
|
+
/**
|
|
75
|
+
* The raw response headers with original dashed lowercase keys
|
|
76
|
+
*/
|
|
77
|
+
rawHeaders?: Record<string, string>;
|
|
45
78
|
}
|
|
46
79
|
/**
|
|
47
80
|
* Helper type for pagination
|
package/lib/types/utils.d.ts
CHANGED
|
@@ -1,6 +1,21 @@
|
|
|
1
1
|
import { CreateAttachmentRequest } from './models/attachments.js';
|
|
2
2
|
export declare function createFileRequestBuilder(filePath: string): CreateAttachmentRequest;
|
|
3
3
|
/**
|
|
4
|
+
* Converts a ReadableStream to a File-like object that can be used with FormData.
|
|
5
|
+
* @param attachment The attachment containing the stream and metadata.
|
|
6
|
+
* @param mimeType The MIME type for the file (optional).
|
|
7
|
+
* @returns A File-like object that properly handles the stream.
|
|
8
|
+
*/
|
|
9
|
+
export declare function attachmentStreamToFile(attachment: CreateAttachmentRequest, mimeType?: string): any;
|
|
10
|
+
/**
|
|
11
|
+
* Encodes the content of each attachment to base64.
|
|
12
|
+
* Handles ReadableStream, Buffer, and string content types.
|
|
13
|
+
* @param attachments The attachments to encode.
|
|
14
|
+
* @returns The attachments with their content encoded to base64.
|
|
15
|
+
*/
|
|
16
|
+
export declare function encodeAttachmentContent(attachments: CreateAttachmentRequest[]): Promise<CreateAttachmentRequest[]>;
|
|
17
|
+
/**
|
|
18
|
+
* @deprecated Use encodeAttachmentContent instead. This alias is provided for backwards compatibility.
|
|
4
19
|
* Encodes the content of each attachment stream to base64.
|
|
5
20
|
* @param attachments The attachments to encode.
|
|
6
21
|
* @returns The attachments with their content encoded to base64.
|
package/lib/types/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const SDK_VERSION = "7.
|
|
1
|
+
export declare const SDK_VERSION = "7.13.0";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nylas",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.13.0",
|
|
4
4
|
"description": "A NodeJS wrapper for the Nylas REST API for email, contacts, and calendar.",
|
|
5
5
|
"main": "lib/cjs/nylas.js",
|
|
6
6
|
"types": "lib/types/nylas.d.ts",
|
|
@@ -40,9 +40,10 @@
|
|
|
40
40
|
"license": "MIT",
|
|
41
41
|
"dependencies": {
|
|
42
42
|
"change-case": "^4.1.2",
|
|
43
|
-
"form-data": "^4.
|
|
43
|
+
"form-data-encoder": "^4.1.0",
|
|
44
|
+
"formdata-node": "^6.0.3",
|
|
44
45
|
"mime-types": "^2.1.35",
|
|
45
|
-
"node-fetch": "^
|
|
46
|
+
"node-fetch": "^3.3.2",
|
|
46
47
|
"uuid": "^8.3.2"
|
|
47
48
|
},
|
|
48
49
|
"devDependencies": {
|
|
@@ -50,7 +51,6 @@
|
|
|
50
51
|
"@types/jest": "^29.5.2",
|
|
51
52
|
"@types/mime-types": "^2.1.2",
|
|
52
53
|
"@types/node": "^22.15.21",
|
|
53
|
-
"@types/node-fetch": "^2.6.4",
|
|
54
54
|
"@types/uuid": "^8.3.4",
|
|
55
55
|
"@typescript-eslint/eslint-plugin": "^2.25.0",
|
|
56
56
|
"@typescript-eslint/parser": "^2.25.0",
|
|
@@ -60,6 +60,7 @@
|
|
|
60
60
|
"eslint-plugin-import": "^2.28.1",
|
|
61
61
|
"eslint-plugin-prettier": "^3.0.1",
|
|
62
62
|
"jest": "^29.6.1",
|
|
63
|
+
"jest-fetch-mock": "^3.0.3",
|
|
63
64
|
"prettier": "^3.5.3",
|
|
64
65
|
"ts-jest": "^29.1.1",
|
|
65
66
|
"typedoc": "^0.28.4",
|