@openfn/language-msgraph 0.3.4 → 0.4.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/ast.json +129 -0
- package/dist/index.cjs +145 -51
- package/dist/index.js +137 -51
- package/package.json +3 -2
- package/types/Adaptor.d.ts +42 -1
- package/types/Utils.d.ts +24 -7
package/ast.json
CHANGED
|
@@ -326,6 +326,135 @@
|
|
|
326
326
|
]
|
|
327
327
|
},
|
|
328
328
|
"valid": true
|
|
329
|
+
},
|
|
330
|
+
{
|
|
331
|
+
"name": "uploadFile",
|
|
332
|
+
"params": [
|
|
333
|
+
"resource",
|
|
334
|
+
"data",
|
|
335
|
+
"callback"
|
|
336
|
+
],
|
|
337
|
+
"docs": {
|
|
338
|
+
"description": "Upload a file to a drive",
|
|
339
|
+
"tags": [
|
|
340
|
+
{
|
|
341
|
+
"title": "public",
|
|
342
|
+
"description": null,
|
|
343
|
+
"type": null
|
|
344
|
+
},
|
|
345
|
+
{
|
|
346
|
+
"title": "example",
|
|
347
|
+
"description": "uploadFile(\n state => ({\n driveId: state.driveId,\n folderId: state.folderId,\n fileName: `Tracker.xlsx`,\n }),\n state => state.buffer\n);",
|
|
348
|
+
"caption": "Upload Excel file to a drive using `driveId` and `parantItemId`"
|
|
349
|
+
},
|
|
350
|
+
{
|
|
351
|
+
"title": "example",
|
|
352
|
+
"description": "uploadFile(\n state => ({\n siteId: state.siteId,\n folderId: state.folderId,\n fileName: `Report.xlsx`,\n }),\n state => state.buffer\n);",
|
|
353
|
+
"caption": "Upload Excel file to a SharePoint drive using `siteId` and `parantItemId`"
|
|
354
|
+
},
|
|
355
|
+
{
|
|
356
|
+
"title": "function",
|
|
357
|
+
"description": null,
|
|
358
|
+
"name": null
|
|
359
|
+
},
|
|
360
|
+
{
|
|
361
|
+
"title": "param",
|
|
362
|
+
"description": "Resource Object",
|
|
363
|
+
"type": {
|
|
364
|
+
"type": "NameExpression",
|
|
365
|
+
"name": "Object"
|
|
366
|
+
},
|
|
367
|
+
"name": "resource"
|
|
368
|
+
},
|
|
369
|
+
{
|
|
370
|
+
"title": "param",
|
|
371
|
+
"description": "Drive Id",
|
|
372
|
+
"type": {
|
|
373
|
+
"type": "OptionalType",
|
|
374
|
+
"expression": {
|
|
375
|
+
"type": "NameExpression",
|
|
376
|
+
"name": "String"
|
|
377
|
+
}
|
|
378
|
+
},
|
|
379
|
+
"name": "resource.driveId"
|
|
380
|
+
},
|
|
381
|
+
{
|
|
382
|
+
"title": "param",
|
|
383
|
+
"description": "Site Id",
|
|
384
|
+
"type": {
|
|
385
|
+
"type": "OptionalType",
|
|
386
|
+
"expression": {
|
|
387
|
+
"type": "NameExpression",
|
|
388
|
+
"name": "String"
|
|
389
|
+
}
|
|
390
|
+
},
|
|
391
|
+
"name": "resource.driveId"
|
|
392
|
+
},
|
|
393
|
+
{
|
|
394
|
+
"title": "param",
|
|
395
|
+
"description": "Parent folder id",
|
|
396
|
+
"type": {
|
|
397
|
+
"type": "OptionalType",
|
|
398
|
+
"expression": {
|
|
399
|
+
"type": "NameExpression",
|
|
400
|
+
"name": "String"
|
|
401
|
+
}
|
|
402
|
+
},
|
|
403
|
+
"name": "resource.folderId"
|
|
404
|
+
},
|
|
405
|
+
{
|
|
406
|
+
"title": "param",
|
|
407
|
+
"description": "Resource content-type",
|
|
408
|
+
"type": {
|
|
409
|
+
"type": "OptionalType",
|
|
410
|
+
"expression": {
|
|
411
|
+
"type": "NameExpression",
|
|
412
|
+
"name": "String"
|
|
413
|
+
}
|
|
414
|
+
},
|
|
415
|
+
"name": "resource.contentType"
|
|
416
|
+
},
|
|
417
|
+
{
|
|
418
|
+
"title": "param",
|
|
419
|
+
"description": "Specify conflict behavior if file with the same name exists. Can be \"rename | fail | replace\"",
|
|
420
|
+
"type": {
|
|
421
|
+
"type": "OptionalType",
|
|
422
|
+
"expression": {
|
|
423
|
+
"type": "NameExpression",
|
|
424
|
+
"name": "String"
|
|
425
|
+
}
|
|
426
|
+
},
|
|
427
|
+
"name": "resource.onConflict"
|
|
428
|
+
},
|
|
429
|
+
{
|
|
430
|
+
"title": "param",
|
|
431
|
+
"description": "A buffer containing the file.",
|
|
432
|
+
"type": {
|
|
433
|
+
"type": "NameExpression",
|
|
434
|
+
"name": "Object"
|
|
435
|
+
},
|
|
436
|
+
"name": "data"
|
|
437
|
+
},
|
|
438
|
+
{
|
|
439
|
+
"title": "param",
|
|
440
|
+
"description": "Optional callback function",
|
|
441
|
+
"type": {
|
|
442
|
+
"type": "NameExpression",
|
|
443
|
+
"name": "Function"
|
|
444
|
+
},
|
|
445
|
+
"name": "callback"
|
|
446
|
+
},
|
|
447
|
+
{
|
|
448
|
+
"title": "returns",
|
|
449
|
+
"description": null,
|
|
450
|
+
"type": {
|
|
451
|
+
"type": "NameExpression",
|
|
452
|
+
"name": "Operation"
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
]
|
|
456
|
+
},
|
|
457
|
+
"valid": false
|
|
329
458
|
}
|
|
330
459
|
],
|
|
331
460
|
"exports": [],
|
package/dist/index.cjs
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
var __create = Object.create;
|
|
1
2
|
var __defProp = Object.defineProperty;
|
|
2
3
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
4
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
4
6
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
7
|
var __export = (target, all) => {
|
|
6
8
|
for (var name in all)
|
|
@@ -14,6 +16,10 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
14
16
|
}
|
|
15
17
|
return to;
|
|
16
18
|
};
|
|
19
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
20
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
21
|
+
mod
|
|
22
|
+
));
|
|
17
23
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
18
24
|
|
|
19
25
|
// src/index.js
|
|
@@ -37,7 +43,9 @@ __export(src_exports, {
|
|
|
37
43
|
merge: () => import_language_common3.merge,
|
|
38
44
|
parseCsv: () => import_language_common3.parseCsv,
|
|
39
45
|
request: () => request,
|
|
40
|
-
|
|
46
|
+
sheetToBuffer: () => sheetToBuffer,
|
|
47
|
+
sourceValue: () => import_language_common3.sourceValue,
|
|
48
|
+
uploadFile: () => uploadFile
|
|
41
49
|
});
|
|
42
50
|
module.exports = __toCommonJS(src_exports);
|
|
43
51
|
|
|
@@ -61,15 +69,19 @@ __export(Adaptor_exports, {
|
|
|
61
69
|
merge: () => import_language_common3.merge,
|
|
62
70
|
parseCsv: () => import_language_common3.parseCsv,
|
|
63
71
|
request: () => request,
|
|
64
|
-
|
|
72
|
+
sheetToBuffer: () => sheetToBuffer,
|
|
73
|
+
sourceValue: () => import_language_common3.sourceValue,
|
|
74
|
+
uploadFile: () => uploadFile
|
|
65
75
|
});
|
|
66
76
|
var import_language_common2 = require("@openfn/language-common");
|
|
67
|
-
var
|
|
77
|
+
var import_util2 = require("@openfn/language-common/util");
|
|
68
78
|
|
|
69
79
|
// src/Utils.js
|
|
80
|
+
var import_xlsx = __toESM(require("xlsx"), 1);
|
|
70
81
|
var import_undici = require("undici");
|
|
71
82
|
var import_node_stream = require("stream");
|
|
72
83
|
var import_language_common = require("@openfn/language-common");
|
|
84
|
+
var import_util = require("@openfn/language-common/util");
|
|
73
85
|
function assertDrive(state, driveName) {
|
|
74
86
|
if (!state.drives[driveName]) {
|
|
75
87
|
const errorString = [
|
|
@@ -80,7 +92,7 @@ function assertDrive(state, driveName) {
|
|
|
80
92
|
throw new Error(errorString);
|
|
81
93
|
}
|
|
82
94
|
}
|
|
83
|
-
function
|
|
95
|
+
function setUrl(resource, apiVersion) {
|
|
84
96
|
if (isValidHttpUrl(resource))
|
|
85
97
|
return resource;
|
|
86
98
|
const pathSuffix = apiVersion ? `${apiVersion}/${resource}` : `v1.0/${resource}`;
|
|
@@ -95,9 +107,6 @@ function isValidHttpUrl(string) {
|
|
|
95
107
|
}
|
|
96
108
|
return url.protocol === "http:" || url.protocol === "https:";
|
|
97
109
|
}
|
|
98
|
-
function getAuth(token) {
|
|
99
|
-
return token ? { headers: { Authorization: `Bearer ${token}` } } : null;
|
|
100
|
-
}
|
|
101
110
|
var isStream = (value) => {
|
|
102
111
|
if (value && typeof value == "object") {
|
|
103
112
|
if (value instanceof import_node_stream.Readable || value instanceof import_node_stream.Writable) {
|
|
@@ -138,21 +147,22 @@ function handleResponseError(response, data, method) {
|
|
|
138
147
|
throw new Error(errorString);
|
|
139
148
|
}
|
|
140
149
|
}
|
|
141
|
-
var
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
};
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
150
|
+
var defaultOptions = {
|
|
151
|
+
method: "GET",
|
|
152
|
+
headers: {
|
|
153
|
+
"Content-Type": "application/json"
|
|
154
|
+
},
|
|
155
|
+
accessToken: ""
|
|
156
|
+
};
|
|
157
|
+
var request = async (path, params) => {
|
|
158
|
+
let url = path;
|
|
159
|
+
const options = { ...defaultOptions, ...params };
|
|
160
|
+
const { parseAs, query, method, accessToken } = options;
|
|
161
|
+
delete options.parseAs;
|
|
162
|
+
delete options.accessToken;
|
|
163
|
+
options.headers["Authorization"] = makeAuthHeader(accessToken);
|
|
164
|
+
if (method === "GET" && query) {
|
|
165
|
+
url = `${path}?${new URLSearchParams(query).toString()}`;
|
|
156
166
|
}
|
|
157
167
|
const response = await (0, import_undici.fetch)(url, options);
|
|
158
168
|
const contentType = response.headers.get("Content-Type");
|
|
@@ -168,6 +178,41 @@ var request = async (urlString, params = {}, method = "GET") => {
|
|
|
168
178
|
handleResponseError(response, data, method);
|
|
169
179
|
return data;
|
|
170
180
|
};
|
|
181
|
+
function makeAuthHeader(accessToken) {
|
|
182
|
+
return accessToken ? `Bearer ${accessToken}` : null;
|
|
183
|
+
}
|
|
184
|
+
var defaultSheetOptions = {
|
|
185
|
+
bookType: "xlsx",
|
|
186
|
+
wsName: "Sheet"
|
|
187
|
+
};
|
|
188
|
+
function sheetToBuffer(rows, options, callback) {
|
|
189
|
+
return (state) => {
|
|
190
|
+
const resolvedRows = (0, import_language_common.asData)(rows, state);
|
|
191
|
+
const [resolvedOptions] = (0, import_util.expandReferences)(state, options);
|
|
192
|
+
const { wsName, bookType } = {
|
|
193
|
+
...defaultSheetOptions,
|
|
194
|
+
...resolvedOptions
|
|
195
|
+
};
|
|
196
|
+
const workbook = import_xlsx.default.utils.book_new();
|
|
197
|
+
const worksheet = import_xlsx.default.utils.json_to_sheet(resolvedRows);
|
|
198
|
+
import_xlsx.default.utils.book_append_sheet(workbook, worksheet, wsName);
|
|
199
|
+
const buffer = import_xlsx.default.write(workbook, { type: "buffer", bookType });
|
|
200
|
+
console.log(`Creating sheet buffer with bookType '${bookType}'`);
|
|
201
|
+
const nextState = { ...state, buffer };
|
|
202
|
+
if (callback)
|
|
203
|
+
return callback(nextState);
|
|
204
|
+
return nextState;
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
function assertResources(resources) {
|
|
208
|
+
const { driveId, siteId, folderId } = resources;
|
|
209
|
+
if (driveId && siteId)
|
|
210
|
+
throw new Error('Use either "driveId" or "siteId" not both');
|
|
211
|
+
if (!driveId && !siteId)
|
|
212
|
+
throw new Error('"siteId" or "driveId" is required');
|
|
213
|
+
if (!folderId)
|
|
214
|
+
throw new Error("Parent Item Id is required");
|
|
215
|
+
}
|
|
171
216
|
|
|
172
217
|
// src/Adaptor.js
|
|
173
218
|
var import_language_common3 = require("@openfn/language-common");
|
|
@@ -178,8 +223,13 @@ function execute(...operations) {
|
|
|
178
223
|
drives: {}
|
|
179
224
|
};
|
|
180
225
|
const cleanup = (finalState) => {
|
|
181
|
-
|
|
182
|
-
|
|
226
|
+
if (finalState == null ? void 0 : finalState.buffer) {
|
|
227
|
+
delete finalState.buffer;
|
|
228
|
+
}
|
|
229
|
+
if (finalState == null ? void 0 : finalState.drives) {
|
|
230
|
+
delete finalState.drives;
|
|
231
|
+
}
|
|
232
|
+
return finalState;
|
|
183
233
|
};
|
|
184
234
|
return (state) => {
|
|
185
235
|
return (0, import_language_common2.execute)(...operations)({
|
|
@@ -193,19 +243,19 @@ function execute(...operations) {
|
|
|
193
243
|
}
|
|
194
244
|
function create(resource, data, callback) {
|
|
195
245
|
return (state) => {
|
|
196
|
-
const [resolvedResource, resolvedData] = (0,
|
|
246
|
+
const [resolvedResource, resolvedData] = (0, import_util2.expandReferences)(
|
|
197
247
|
state,
|
|
198
248
|
resource,
|
|
199
249
|
data
|
|
200
250
|
);
|
|
201
251
|
const { accessToken, apiVersion } = state.configuration;
|
|
202
|
-
const url =
|
|
203
|
-
const auth = getAuth(accessToken);
|
|
252
|
+
const url = setUrl({ apiVersion, resolvedResource });
|
|
204
253
|
const options = {
|
|
205
|
-
|
|
206
|
-
|
|
254
|
+
accessToken,
|
|
255
|
+
body: JSON.stringify(resolvedData),
|
|
256
|
+
method: "POST"
|
|
207
257
|
};
|
|
208
|
-
return request(url, options
|
|
258
|
+
return request(url, options).then(
|
|
209
259
|
(response) => handleResponse(response, state, callback)
|
|
210
260
|
);
|
|
211
261
|
};
|
|
@@ -213,10 +263,9 @@ function create(resource, data, callback) {
|
|
|
213
263
|
function get(path, query, callback = false) {
|
|
214
264
|
return (state) => {
|
|
215
265
|
const { accessToken, apiVersion } = state.configuration;
|
|
216
|
-
const [resolvedPath, resolvedQuery] = (0,
|
|
217
|
-
const url =
|
|
218
|
-
|
|
219
|
-
return request(url, { ...resolvedQuery, ...auth }).then(
|
|
266
|
+
const [resolvedPath, resolvedQuery] = (0, import_util2.expandReferences)(state, path, query);
|
|
267
|
+
const url = setUrl(resolvedPath, apiVersion);
|
|
268
|
+
return request(url, { query: resolvedQuery, accessToken }).then(
|
|
220
269
|
(response) => handleResponse(response, state, callback)
|
|
221
270
|
);
|
|
222
271
|
};
|
|
@@ -224,7 +273,7 @@ function get(path, query, callback = false) {
|
|
|
224
273
|
function getDrive(specifier, name = "default", callback = (s) => s) {
|
|
225
274
|
return (state) => {
|
|
226
275
|
const { accessToken, apiVersion } = state.configuration;
|
|
227
|
-
const [resolvedSpecifier, resolvedName] = (0,
|
|
276
|
+
const [resolvedSpecifier, resolvedName] = (0, import_util2.expandReferences)(
|
|
228
277
|
state,
|
|
229
278
|
specifier,
|
|
230
279
|
name
|
|
@@ -236,9 +285,8 @@ function getDrive(specifier, name = "default", callback = (s) => s) {
|
|
|
236
285
|
} else {
|
|
237
286
|
resource = `${owner}/${id}/drive`;
|
|
238
287
|
}
|
|
239
|
-
const url =
|
|
240
|
-
|
|
241
|
-
return request(url, { ...auth }).then((response) => {
|
|
288
|
+
const url = setUrl(resource, apiVersion);
|
|
289
|
+
return request(url, { accessToken }).then((response) => {
|
|
242
290
|
state.drives[resolvedName] = response;
|
|
243
291
|
return callback(state);
|
|
244
292
|
});
|
|
@@ -246,17 +294,17 @@ function getDrive(specifier, name = "default", callback = (s) => s) {
|
|
|
246
294
|
}
|
|
247
295
|
function getFolder(pathOrId, options, callback = (s) => s) {
|
|
248
296
|
return async (state) => {
|
|
249
|
-
const
|
|
297
|
+
const defaultOptions2 = {
|
|
250
298
|
driveName: "default",
|
|
251
299
|
metadata: false
|
|
252
300
|
};
|
|
253
301
|
const { accessToken, apiVersion } = state.configuration;
|
|
254
|
-
const [resolvedPathOrId, resolvedOptions] = (0,
|
|
302
|
+
const [resolvedPathOrId, resolvedOptions] = (0, import_util2.expandReferences)(
|
|
255
303
|
state,
|
|
256
304
|
pathOrId,
|
|
257
305
|
options
|
|
258
306
|
);
|
|
259
|
-
const { driveName, metadata } = { ...
|
|
307
|
+
const { driveName, metadata } = { ...defaultOptions2, ...resolvedOptions };
|
|
260
308
|
assertDrive(state, driveName);
|
|
261
309
|
const { id: driveId } = state.drives[driveName];
|
|
262
310
|
let resource;
|
|
@@ -270,27 +318,26 @@ function getFolder(pathOrId, options, callback = (s) => s) {
|
|
|
270
318
|
if (!metadata) {
|
|
271
319
|
resource += resolvedPathOrId.startsWith("/") ? ":/children" : "/children";
|
|
272
320
|
}
|
|
273
|
-
const url =
|
|
274
|
-
|
|
275
|
-
return request(url, { ...auth }).then(
|
|
321
|
+
const url = setUrl(resource, apiVersion);
|
|
322
|
+
return request(url, { accessToken }).then(
|
|
276
323
|
(response) => handleResponse(response, state, callback)
|
|
277
324
|
);
|
|
278
325
|
};
|
|
279
326
|
}
|
|
280
327
|
function getFile(pathOrId, options, callback = (s) => s) {
|
|
281
|
-
const
|
|
328
|
+
const defaultOptions2 = {
|
|
282
329
|
driveName: "default",
|
|
283
330
|
metadata: false
|
|
284
331
|
};
|
|
285
332
|
return async (state) => {
|
|
286
333
|
const { accessToken, apiVersion } = state.configuration;
|
|
287
|
-
const [resolvedPathOrId, resolvedOptions] = (0,
|
|
334
|
+
const [resolvedPathOrId, resolvedOptions] = (0, import_util2.expandReferences)(
|
|
288
335
|
state,
|
|
289
336
|
pathOrId,
|
|
290
337
|
options
|
|
291
338
|
);
|
|
292
339
|
const { driveName, metadata } = {
|
|
293
|
-
...
|
|
340
|
+
...defaultOptions2,
|
|
294
341
|
...resolvedOptions
|
|
295
342
|
};
|
|
296
343
|
assertDrive(state, driveName);
|
|
@@ -306,15 +353,60 @@ function getFile(pathOrId, options, callback = (s) => s) {
|
|
|
306
353
|
if (!metadata) {
|
|
307
354
|
resource += resolvedPathOrId.startsWith("/") ? ":/content" : "/content";
|
|
308
355
|
}
|
|
309
|
-
const url =
|
|
310
|
-
const auth = getAuth(accessToken);
|
|
356
|
+
const url = setUrl(resource, apiVersion);
|
|
311
357
|
const response = await request(url, {
|
|
312
|
-
|
|
358
|
+
accessToken,
|
|
313
359
|
parseAs: metadata ? "json" : "text"
|
|
314
360
|
});
|
|
315
361
|
return handleResponse(response, state, callback);
|
|
316
362
|
};
|
|
317
363
|
}
|
|
364
|
+
var defaultResource = {
|
|
365
|
+
contentType: "application/octet-stream",
|
|
366
|
+
driveId: "",
|
|
367
|
+
folderId: "",
|
|
368
|
+
fileName: "sheet.xls",
|
|
369
|
+
onConflict: "replace"
|
|
370
|
+
};
|
|
371
|
+
function uploadFile(resource, data, callback) {
|
|
372
|
+
return async (state) => {
|
|
373
|
+
const { accessToken, apiVersion } = state.configuration;
|
|
374
|
+
const [resolvedResource, resolvedData] = (0, import_util2.expandReferences)(
|
|
375
|
+
state,
|
|
376
|
+
resource,
|
|
377
|
+
data
|
|
378
|
+
);
|
|
379
|
+
const { contentType, driveId, siteId, folderId, onConflict, fileName } = {
|
|
380
|
+
...defaultResource,
|
|
381
|
+
...resolvedResource
|
|
382
|
+
};
|
|
383
|
+
assertResources({ driveId, siteId, folderId });
|
|
384
|
+
const path = driveId && `drives/${driveId}/items/${folderId}:/${fileName}:/createUploadSession` || siteId && `sites/${siteId}/drive/items/${folderId}:/${fileName}:/createUploadSession`;
|
|
385
|
+
const uploadSession = await request(setUrl(path, apiVersion), {
|
|
386
|
+
method: "POST",
|
|
387
|
+
accessToken,
|
|
388
|
+
headers: {
|
|
389
|
+
"Content-Type": "application/json"
|
|
390
|
+
},
|
|
391
|
+
body: JSON.stringify({
|
|
392
|
+
"@microsoft.graph.conflictBehavior": onConflict,
|
|
393
|
+
name: fileName
|
|
394
|
+
})
|
|
395
|
+
});
|
|
396
|
+
const uploadUrl = uploadSession.uploadUrl;
|
|
397
|
+
console.log(`Uploading file...`);
|
|
398
|
+
return request(uploadUrl, {
|
|
399
|
+
method: "PUT",
|
|
400
|
+
accessToken,
|
|
401
|
+
headers: {
|
|
402
|
+
"Content-Type": contentType,
|
|
403
|
+
"Content-Length": `${resolvedData.length}`,
|
|
404
|
+
"Content-Range": `bytes 0-${resolvedData.length - 1}/${resolvedData.length}`
|
|
405
|
+
},
|
|
406
|
+
body: resolvedData
|
|
407
|
+
}).then((response) => handleResponse(response, state, callback));
|
|
408
|
+
};
|
|
409
|
+
}
|
|
318
410
|
|
|
319
411
|
// src/index.js
|
|
320
412
|
var src_default = Adaptor_exports;
|
|
@@ -337,5 +429,7 @@ var src_default = Adaptor_exports;
|
|
|
337
429
|
merge,
|
|
338
430
|
parseCsv,
|
|
339
431
|
request,
|
|
340
|
-
|
|
432
|
+
sheetToBuffer,
|
|
433
|
+
sourceValue,
|
|
434
|
+
uploadFile
|
|
341
435
|
});
|
package/dist/index.js
CHANGED
|
@@ -24,15 +24,19 @@ __export(Adaptor_exports, {
|
|
|
24
24
|
merge: () => merge,
|
|
25
25
|
parseCsv: () => parseCsv,
|
|
26
26
|
request: () => request,
|
|
27
|
-
|
|
27
|
+
sheetToBuffer: () => sheetToBuffer,
|
|
28
|
+
sourceValue: () => sourceValue,
|
|
29
|
+
uploadFile: () => uploadFile
|
|
28
30
|
});
|
|
29
31
|
import { execute as commonExecute } from "@openfn/language-common";
|
|
30
|
-
import { expandReferences } from "@openfn/language-common/util";
|
|
32
|
+
import { expandReferences as expandReferences2 } from "@openfn/language-common/util";
|
|
31
33
|
|
|
32
34
|
// src/Utils.js
|
|
35
|
+
import xlsx from "xlsx";
|
|
33
36
|
import { fetch } from "undici";
|
|
34
37
|
import { Readable, Writable } from "stream";
|
|
35
|
-
import { composeNextState } from "@openfn/language-common";
|
|
38
|
+
import { composeNextState, asData } from "@openfn/language-common";
|
|
39
|
+
import { expandReferences } from "@openfn/language-common/util";
|
|
36
40
|
function assertDrive(state, driveName) {
|
|
37
41
|
if (!state.drives[driveName]) {
|
|
38
42
|
const errorString = [
|
|
@@ -43,7 +47,7 @@ function assertDrive(state, driveName) {
|
|
|
43
47
|
throw new Error(errorString);
|
|
44
48
|
}
|
|
45
49
|
}
|
|
46
|
-
function
|
|
50
|
+
function setUrl(resource, apiVersion) {
|
|
47
51
|
if (isValidHttpUrl(resource))
|
|
48
52
|
return resource;
|
|
49
53
|
const pathSuffix = apiVersion ? `${apiVersion}/${resource}` : `v1.0/${resource}`;
|
|
@@ -58,9 +62,6 @@ function isValidHttpUrl(string) {
|
|
|
58
62
|
}
|
|
59
63
|
return url.protocol === "http:" || url.protocol === "https:";
|
|
60
64
|
}
|
|
61
|
-
function getAuth(token) {
|
|
62
|
-
return token ? { headers: { Authorization: `Bearer ${token}` } } : null;
|
|
63
|
-
}
|
|
64
65
|
var isStream = (value) => {
|
|
65
66
|
if (value && typeof value == "object") {
|
|
66
67
|
if (value instanceof Readable || value instanceof Writable) {
|
|
@@ -101,21 +102,22 @@ function handleResponseError(response, data, method) {
|
|
|
101
102
|
throw new Error(errorString);
|
|
102
103
|
}
|
|
103
104
|
}
|
|
104
|
-
var
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
};
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
105
|
+
var defaultOptions = {
|
|
106
|
+
method: "GET",
|
|
107
|
+
headers: {
|
|
108
|
+
"Content-Type": "application/json"
|
|
109
|
+
},
|
|
110
|
+
accessToken: ""
|
|
111
|
+
};
|
|
112
|
+
var request = async (path, params) => {
|
|
113
|
+
let url = path;
|
|
114
|
+
const options = { ...defaultOptions, ...params };
|
|
115
|
+
const { parseAs, query, method, accessToken } = options;
|
|
116
|
+
delete options.parseAs;
|
|
117
|
+
delete options.accessToken;
|
|
118
|
+
options.headers["Authorization"] = makeAuthHeader(accessToken);
|
|
119
|
+
if (method === "GET" && query) {
|
|
120
|
+
url = `${path}?${new URLSearchParams(query).toString()}`;
|
|
119
121
|
}
|
|
120
122
|
const response = await fetch(url, options);
|
|
121
123
|
const contentType = response.headers.get("Content-Type");
|
|
@@ -131,6 +133,41 @@ var request = async (urlString, params = {}, method = "GET") => {
|
|
|
131
133
|
handleResponseError(response, data, method);
|
|
132
134
|
return data;
|
|
133
135
|
};
|
|
136
|
+
function makeAuthHeader(accessToken) {
|
|
137
|
+
return accessToken ? `Bearer ${accessToken}` : null;
|
|
138
|
+
}
|
|
139
|
+
var defaultSheetOptions = {
|
|
140
|
+
bookType: "xlsx",
|
|
141
|
+
wsName: "Sheet"
|
|
142
|
+
};
|
|
143
|
+
function sheetToBuffer(rows, options, callback) {
|
|
144
|
+
return (state) => {
|
|
145
|
+
const resolvedRows = asData(rows, state);
|
|
146
|
+
const [resolvedOptions] = expandReferences(state, options);
|
|
147
|
+
const { wsName, bookType } = {
|
|
148
|
+
...defaultSheetOptions,
|
|
149
|
+
...resolvedOptions
|
|
150
|
+
};
|
|
151
|
+
const workbook = xlsx.utils.book_new();
|
|
152
|
+
const worksheet = xlsx.utils.json_to_sheet(resolvedRows);
|
|
153
|
+
xlsx.utils.book_append_sheet(workbook, worksheet, wsName);
|
|
154
|
+
const buffer = xlsx.write(workbook, { type: "buffer", bookType });
|
|
155
|
+
console.log(`Creating sheet buffer with bookType '${bookType}'`);
|
|
156
|
+
const nextState = { ...state, buffer };
|
|
157
|
+
if (callback)
|
|
158
|
+
return callback(nextState);
|
|
159
|
+
return nextState;
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
function assertResources(resources) {
|
|
163
|
+
const { driveId, siteId, folderId } = resources;
|
|
164
|
+
if (driveId && siteId)
|
|
165
|
+
throw new Error('Use either "driveId" or "siteId" not both');
|
|
166
|
+
if (!driveId && !siteId)
|
|
167
|
+
throw new Error('"siteId" or "driveId" is required');
|
|
168
|
+
if (!folderId)
|
|
169
|
+
throw new Error("Parent Item Id is required");
|
|
170
|
+
}
|
|
134
171
|
|
|
135
172
|
// src/Adaptor.js
|
|
136
173
|
import {
|
|
@@ -153,8 +190,13 @@ function execute(...operations) {
|
|
|
153
190
|
drives: {}
|
|
154
191
|
};
|
|
155
192
|
const cleanup = (finalState) => {
|
|
156
|
-
|
|
157
|
-
|
|
193
|
+
if (finalState == null ? void 0 : finalState.buffer) {
|
|
194
|
+
delete finalState.buffer;
|
|
195
|
+
}
|
|
196
|
+
if (finalState == null ? void 0 : finalState.drives) {
|
|
197
|
+
delete finalState.drives;
|
|
198
|
+
}
|
|
199
|
+
return finalState;
|
|
158
200
|
};
|
|
159
201
|
return (state) => {
|
|
160
202
|
return commonExecute(...operations)({
|
|
@@ -168,19 +210,19 @@ function execute(...operations) {
|
|
|
168
210
|
}
|
|
169
211
|
function create(resource, data, callback) {
|
|
170
212
|
return (state) => {
|
|
171
|
-
const [resolvedResource, resolvedData] =
|
|
213
|
+
const [resolvedResource, resolvedData] = expandReferences2(
|
|
172
214
|
state,
|
|
173
215
|
resource,
|
|
174
216
|
data
|
|
175
217
|
);
|
|
176
218
|
const { accessToken, apiVersion } = state.configuration;
|
|
177
|
-
const url =
|
|
178
|
-
const auth = getAuth(accessToken);
|
|
219
|
+
const url = setUrl({ apiVersion, resolvedResource });
|
|
179
220
|
const options = {
|
|
180
|
-
|
|
181
|
-
|
|
221
|
+
accessToken,
|
|
222
|
+
body: JSON.stringify(resolvedData),
|
|
223
|
+
method: "POST"
|
|
182
224
|
};
|
|
183
|
-
return request(url, options
|
|
225
|
+
return request(url, options).then(
|
|
184
226
|
(response) => handleResponse(response, state, callback)
|
|
185
227
|
);
|
|
186
228
|
};
|
|
@@ -188,10 +230,9 @@ function create(resource, data, callback) {
|
|
|
188
230
|
function get(path, query, callback = false) {
|
|
189
231
|
return (state) => {
|
|
190
232
|
const { accessToken, apiVersion } = state.configuration;
|
|
191
|
-
const [resolvedPath, resolvedQuery] =
|
|
192
|
-
const url =
|
|
193
|
-
|
|
194
|
-
return request(url, { ...resolvedQuery, ...auth }).then(
|
|
233
|
+
const [resolvedPath, resolvedQuery] = expandReferences2(state, path, query);
|
|
234
|
+
const url = setUrl(resolvedPath, apiVersion);
|
|
235
|
+
return request(url, { query: resolvedQuery, accessToken }).then(
|
|
195
236
|
(response) => handleResponse(response, state, callback)
|
|
196
237
|
);
|
|
197
238
|
};
|
|
@@ -199,7 +240,7 @@ function get(path, query, callback = false) {
|
|
|
199
240
|
function getDrive(specifier, name = "default", callback = (s) => s) {
|
|
200
241
|
return (state) => {
|
|
201
242
|
const { accessToken, apiVersion } = state.configuration;
|
|
202
|
-
const [resolvedSpecifier, resolvedName] =
|
|
243
|
+
const [resolvedSpecifier, resolvedName] = expandReferences2(
|
|
203
244
|
state,
|
|
204
245
|
specifier,
|
|
205
246
|
name
|
|
@@ -211,9 +252,8 @@ function getDrive(specifier, name = "default", callback = (s) => s) {
|
|
|
211
252
|
} else {
|
|
212
253
|
resource = `${owner}/${id}/drive`;
|
|
213
254
|
}
|
|
214
|
-
const url =
|
|
215
|
-
|
|
216
|
-
return request(url, { ...auth }).then((response) => {
|
|
255
|
+
const url = setUrl(resource, apiVersion);
|
|
256
|
+
return request(url, { accessToken }).then((response) => {
|
|
217
257
|
state.drives[resolvedName] = response;
|
|
218
258
|
return callback(state);
|
|
219
259
|
});
|
|
@@ -221,17 +261,17 @@ function getDrive(specifier, name = "default", callback = (s) => s) {
|
|
|
221
261
|
}
|
|
222
262
|
function getFolder(pathOrId, options, callback = (s) => s) {
|
|
223
263
|
return async (state) => {
|
|
224
|
-
const
|
|
264
|
+
const defaultOptions2 = {
|
|
225
265
|
driveName: "default",
|
|
226
266
|
metadata: false
|
|
227
267
|
};
|
|
228
268
|
const { accessToken, apiVersion } = state.configuration;
|
|
229
|
-
const [resolvedPathOrId, resolvedOptions] =
|
|
269
|
+
const [resolvedPathOrId, resolvedOptions] = expandReferences2(
|
|
230
270
|
state,
|
|
231
271
|
pathOrId,
|
|
232
272
|
options
|
|
233
273
|
);
|
|
234
|
-
const { driveName, metadata } = { ...
|
|
274
|
+
const { driveName, metadata } = { ...defaultOptions2, ...resolvedOptions };
|
|
235
275
|
assertDrive(state, driveName);
|
|
236
276
|
const { id: driveId } = state.drives[driveName];
|
|
237
277
|
let resource;
|
|
@@ -245,27 +285,26 @@ function getFolder(pathOrId, options, callback = (s) => s) {
|
|
|
245
285
|
if (!metadata) {
|
|
246
286
|
resource += resolvedPathOrId.startsWith("/") ? ":/children" : "/children";
|
|
247
287
|
}
|
|
248
|
-
const url =
|
|
249
|
-
|
|
250
|
-
return request(url, { ...auth }).then(
|
|
288
|
+
const url = setUrl(resource, apiVersion);
|
|
289
|
+
return request(url, { accessToken }).then(
|
|
251
290
|
(response) => handleResponse(response, state, callback)
|
|
252
291
|
);
|
|
253
292
|
};
|
|
254
293
|
}
|
|
255
294
|
function getFile(pathOrId, options, callback = (s) => s) {
|
|
256
|
-
const
|
|
295
|
+
const defaultOptions2 = {
|
|
257
296
|
driveName: "default",
|
|
258
297
|
metadata: false
|
|
259
298
|
};
|
|
260
299
|
return async (state) => {
|
|
261
300
|
const { accessToken, apiVersion } = state.configuration;
|
|
262
|
-
const [resolvedPathOrId, resolvedOptions] =
|
|
301
|
+
const [resolvedPathOrId, resolvedOptions] = expandReferences2(
|
|
263
302
|
state,
|
|
264
303
|
pathOrId,
|
|
265
304
|
options
|
|
266
305
|
);
|
|
267
306
|
const { driveName, metadata } = {
|
|
268
|
-
...
|
|
307
|
+
...defaultOptions2,
|
|
269
308
|
...resolvedOptions
|
|
270
309
|
};
|
|
271
310
|
assertDrive(state, driveName);
|
|
@@ -281,15 +320,60 @@ function getFile(pathOrId, options, callback = (s) => s) {
|
|
|
281
320
|
if (!metadata) {
|
|
282
321
|
resource += resolvedPathOrId.startsWith("/") ? ":/content" : "/content";
|
|
283
322
|
}
|
|
284
|
-
const url =
|
|
285
|
-
const auth = getAuth(accessToken);
|
|
323
|
+
const url = setUrl(resource, apiVersion);
|
|
286
324
|
const response = await request(url, {
|
|
287
|
-
|
|
325
|
+
accessToken,
|
|
288
326
|
parseAs: metadata ? "json" : "text"
|
|
289
327
|
});
|
|
290
328
|
return handleResponse(response, state, callback);
|
|
291
329
|
};
|
|
292
330
|
}
|
|
331
|
+
var defaultResource = {
|
|
332
|
+
contentType: "application/octet-stream",
|
|
333
|
+
driveId: "",
|
|
334
|
+
folderId: "",
|
|
335
|
+
fileName: "sheet.xls",
|
|
336
|
+
onConflict: "replace"
|
|
337
|
+
};
|
|
338
|
+
function uploadFile(resource, data, callback) {
|
|
339
|
+
return async (state) => {
|
|
340
|
+
const { accessToken, apiVersion } = state.configuration;
|
|
341
|
+
const [resolvedResource, resolvedData] = expandReferences2(
|
|
342
|
+
state,
|
|
343
|
+
resource,
|
|
344
|
+
data
|
|
345
|
+
);
|
|
346
|
+
const { contentType, driveId, siteId, folderId, onConflict, fileName } = {
|
|
347
|
+
...defaultResource,
|
|
348
|
+
...resolvedResource
|
|
349
|
+
};
|
|
350
|
+
assertResources({ driveId, siteId, folderId });
|
|
351
|
+
const path = driveId && `drives/${driveId}/items/${folderId}:/${fileName}:/createUploadSession` || siteId && `sites/${siteId}/drive/items/${folderId}:/${fileName}:/createUploadSession`;
|
|
352
|
+
const uploadSession = await request(setUrl(path, apiVersion), {
|
|
353
|
+
method: "POST",
|
|
354
|
+
accessToken,
|
|
355
|
+
headers: {
|
|
356
|
+
"Content-Type": "application/json"
|
|
357
|
+
},
|
|
358
|
+
body: JSON.stringify({
|
|
359
|
+
"@microsoft.graph.conflictBehavior": onConflict,
|
|
360
|
+
name: fileName
|
|
361
|
+
})
|
|
362
|
+
});
|
|
363
|
+
const uploadUrl = uploadSession.uploadUrl;
|
|
364
|
+
console.log(`Uploading file...`);
|
|
365
|
+
return request(uploadUrl, {
|
|
366
|
+
method: "PUT",
|
|
367
|
+
accessToken,
|
|
368
|
+
headers: {
|
|
369
|
+
"Content-Type": contentType,
|
|
370
|
+
"Content-Length": `${resolvedData.length}`,
|
|
371
|
+
"Content-Range": `bytes 0-${resolvedData.length - 1}/${resolvedData.length}`
|
|
372
|
+
},
|
|
373
|
+
body: resolvedData
|
|
374
|
+
}).then((response) => handleResponse(response, state, callback));
|
|
375
|
+
};
|
|
376
|
+
}
|
|
293
377
|
|
|
294
378
|
// src/index.js
|
|
295
379
|
var src_default = Adaptor_exports;
|
|
@@ -312,5 +396,7 @@ export {
|
|
|
312
396
|
merge,
|
|
313
397
|
parseCsv,
|
|
314
398
|
request,
|
|
315
|
-
|
|
399
|
+
sheetToBuffer,
|
|
400
|
+
sourceValue,
|
|
401
|
+
uploadFile
|
|
316
402
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openfn/language-msgraph",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "Microsoft Graph Language Pack for OpenFn",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -20,7 +20,8 @@
|
|
|
20
20
|
],
|
|
21
21
|
"dependencies": {
|
|
22
22
|
"undici": "^5.22.1",
|
|
23
|
-
"
|
|
23
|
+
"xlsx": "https://cdn.sheetjs.com/xlsx-0.20.0/xlsx-0.20.0.tgz",
|
|
24
|
+
"@openfn/language-common": "1.11.1"
|
|
24
25
|
},
|
|
25
26
|
"devDependencies": {
|
|
26
27
|
"@openfn/buildtools": "^1.0.2",
|
package/types/Adaptor.d.ts
CHANGED
|
@@ -79,5 +79,46 @@ export function getFolder(pathOrId: string, options: object, callback?: Function
|
|
|
79
79
|
* @return {Operation}
|
|
80
80
|
*/
|
|
81
81
|
export function getFile(pathOrId: string, options: object, callback?: Function): Operation;
|
|
82
|
-
|
|
82
|
+
/**
|
|
83
|
+
* Upload a file to a drive
|
|
84
|
+
* @public
|
|
85
|
+
* @example
|
|
86
|
+
* <caption>Upload Excel file to a drive using `driveId` and `parantItemId`</caption>
|
|
87
|
+
* uploadFile(
|
|
88
|
+
* state => ({
|
|
89
|
+
* driveId: state.driveId,
|
|
90
|
+
* folderId: state.folderId,
|
|
91
|
+
* fileName: `Tracker.xlsx`,
|
|
92
|
+
* }),
|
|
93
|
+
* state => state.buffer
|
|
94
|
+
* );
|
|
95
|
+
* @example
|
|
96
|
+
* <caption>Upload Excel file to a SharePoint drive using `siteId` and `parantItemId`</caption>
|
|
97
|
+
* uploadFile(
|
|
98
|
+
* state => ({
|
|
99
|
+
* siteId: state.siteId,
|
|
100
|
+
* folderId: state.folderId,
|
|
101
|
+
* fileName: `Report.xlsx`,
|
|
102
|
+
* }),
|
|
103
|
+
* state => state.buffer
|
|
104
|
+
* );
|
|
105
|
+
* @function
|
|
106
|
+
* @param {Object} resource - Resource Object
|
|
107
|
+
* @param {String} [resource.driveId] - Drive Id
|
|
108
|
+
* @param {String} [resource.driveId] - Site Id
|
|
109
|
+
* @param {String} [resource.folderId] - Parent folder id
|
|
110
|
+
* @param {String} [resource.contentType] - Resource content-type
|
|
111
|
+
* @param {String} [resource.onConflict] - Specify conflict behavior if file with the same name exists. Can be "rename | fail | replace"
|
|
112
|
+
* @param {Object} data - A buffer containing the file.
|
|
113
|
+
* @param {Function} callback - Optional callback function
|
|
114
|
+
* @returns {Operation}
|
|
115
|
+
*/
|
|
116
|
+
export function uploadFile(resource: {
|
|
117
|
+
driveId?: string;
|
|
118
|
+
driveId?: string;
|
|
119
|
+
folderId?: string;
|
|
120
|
+
contentType?: string;
|
|
121
|
+
onConflict?: string;
|
|
122
|
+
}, data: any, callback: Function): Operation;
|
|
123
|
+
export { request, sheetToBuffer } from "./Utils";
|
|
83
124
|
export { dataPath, dataValue, dateFns, each, field, fields, fn, lastReferenceValue, merge, sourceValue, parseCsv } from "@openfn/language-common";
|
package/types/Utils.d.ts
CHANGED
|
@@ -1,10 +1,27 @@
|
|
|
1
1
|
export function assertDrive(state: any, driveName: any): void;
|
|
2
|
-
export function
|
|
3
|
-
export function getAuth(token: any): {
|
|
4
|
-
headers: {
|
|
5
|
-
Authorization: string;
|
|
6
|
-
};
|
|
7
|
-
};
|
|
2
|
+
export function setUrl(resource: any, apiVersion: any): any;
|
|
8
3
|
export function handleResponse(response: any, state: any, callback: any): any;
|
|
9
4
|
export function handleResponseError(response: any, data: any, method: any): void;
|
|
10
|
-
|
|
5
|
+
/**
|
|
6
|
+
* The function `sheetToBuffer` takes in rows, options and optional callback, It creates a workbook
|
|
7
|
+
* and worksheet using the rows, appends the worksheet to the workbook, and returns the workbook as a
|
|
8
|
+
* buffer.
|
|
9
|
+
* @public
|
|
10
|
+
* @example
|
|
11
|
+
* <caption>Create a buffer containing excel file with `xlsx` output format </caption>
|
|
12
|
+
* sheetToBuffer('$.data[*]', {
|
|
13
|
+
* wsName: 'Invalid Grant Codes',
|
|
14
|
+
* bookType: 'xlsx',
|
|
15
|
+
* });
|
|
16
|
+
* @param rows - The `rows` parameter is an array of objects representing the data to be written to the
|
|
17
|
+
* Excel sheet. Each object in the array represents a row in the sheet, and the keys of the object
|
|
18
|
+
* represent the column headers. The values of the object represent the data in each cell of the row.
|
|
19
|
+
* @param options - The `options` parameter is an object that contains additional configuration options
|
|
20
|
+
* @param {String} [options.wsName] - Worksheet name i.e 32 Characters
|
|
21
|
+
* @param {String} [options.bookType] - File format of the exported file, Default is 'xlsx'. See {@link https://docs.sheetjs.com/docs/api/write-options/#supported-output-formats here}
|
|
22
|
+
* for the function. It can have the following properties:
|
|
23
|
+
* @returns a buffer containing the Excel file in `state.buffer`.
|
|
24
|
+
*/
|
|
25
|
+
export function sheetToBuffer(rows: any, options: any, callback: any): (state: any) => any;
|
|
26
|
+
export function assertResources(resources: any): void;
|
|
27
|
+
export function request(path: any, params: any): Promise<unknown>;
|