@adobe/helix-onedrive-support 6.0.1 → 6.1.3
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/.mocha-multi.json +6 -0
- package/.nycrc.json +10 -0
- package/CHANGELOG.md +28 -0
- package/package.json +23 -16
- package/src/OneDrive.d.ts +37 -0
- package/src/OneDrive.js +46 -4
- package/src/SharePointSite.js +139 -0
- package/src/StatusCodeError.js +1 -1
package/.nycrc.json
ADDED
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,31 @@
|
|
|
1
|
+
## [6.1.3](https://github.com/adobe/helix-onedrive-support/compare/v6.1.2...v6.1.3) (2022-02-14)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* **deps:** update dependency @adobe/helix-fetch to v3.0.5 ([c260921](https://github.com/adobe/helix-onedrive-support/commit/c260921ccbd51847e64ad0ea15f353efde614311))
|
|
7
|
+
|
|
8
|
+
## [6.1.2](https://github.com/adobe/helix-onedrive-support/compare/v6.1.1...v6.1.2) (2022-02-04)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Bug Fixes
|
|
12
|
+
|
|
13
|
+
* **deps:** update dependency @adobe/helix-fetch to v3.0.3 ([#232](https://github.com/adobe/helix-onedrive-support/issues/232)) ([6102d03](https://github.com/adobe/helix-onedrive-support/commit/6102d03ab45c89d2d1033d67b08bab179e86ea17))
|
|
14
|
+
|
|
15
|
+
## [6.1.1](https://github.com/adobe/helix-onedrive-support/compare/v6.1.0...v6.1.1) (2022-02-03)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
### Bug Fixes
|
|
19
|
+
|
|
20
|
+
* **deps:** update dependency @adobe/helix-fetch to v3.0.2 ([3c3a2f2](https://github.com/adobe/helix-onedrive-support/commit/3c3a2f2c70bc4e69a66b8a2558add6154289eaee))
|
|
21
|
+
|
|
22
|
+
# [6.1.0](https://github.com/adobe/helix-onedrive-support/compare/v6.0.1...v6.1.0) (2022-01-28)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
### Features
|
|
26
|
+
|
|
27
|
+
* add API for SP API ([#227](https://github.com/adobe/helix-onedrive-support/issues/227)) ([6ce5938](https://github.com/adobe/helix-onedrive-support/commit/6ce59387a777d4549964a8fb90b2e0ca2a4fd86e))
|
|
28
|
+
|
|
1
29
|
## [6.0.1](https://github.com/adobe/helix-onedrive-support/compare/v6.0.0...v6.0.1) (2021-10-18)
|
|
2
30
|
|
|
3
31
|
|
package/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adobe/helix-onedrive-support",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.1.3",
|
|
4
4
|
"description": "Helix OneDrive Support",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"types": "src/index.d.ts",
|
|
7
7
|
"scripts": {
|
|
8
|
-
"test": "
|
|
9
|
-
"test-ci": "nyc
|
|
8
|
+
"test": "nyc mocha",
|
|
9
|
+
"test-ci": "nyc mocha && codecov",
|
|
10
10
|
"lint": "./node_modules/.bin/eslint .",
|
|
11
11
|
"semantic-release": "semantic-release",
|
|
12
12
|
"docs": "npx jsdoc2md -c .jsdoc.json --files 'src/*.js' > docs/API.md",
|
|
@@ -23,28 +23,29 @@
|
|
|
23
23
|
},
|
|
24
24
|
"homepage": "https://github.com/adobe/helix-onedrive-support#readme",
|
|
25
25
|
"dependencies": {
|
|
26
|
-
"@adobe/helix-fetch": "3.0.
|
|
26
|
+
"@adobe/helix-fetch": "3.0.5",
|
|
27
27
|
"adal-node": "https://github.com/adobe-rnd/azure-activedirectory-library-for-nodejs.git#adobe"
|
|
28
28
|
},
|
|
29
29
|
"devDependencies": {
|
|
30
|
-
"@adobe/eslint-config-helix": "1.3.
|
|
31
|
-
"@semantic-release/changelog": "6.0.
|
|
32
|
-
"@semantic-release/git": "10.0.
|
|
33
|
-
"ajv": "8.
|
|
30
|
+
"@adobe/eslint-config-helix": "1.3.2",
|
|
31
|
+
"@semantic-release/changelog": "6.0.1",
|
|
32
|
+
"@semantic-release/git": "10.0.1",
|
|
33
|
+
"ajv": "8.10.0",
|
|
34
34
|
"codecov": "3.8.3",
|
|
35
35
|
"commitizen": "4.2.4",
|
|
36
36
|
"cz-conventional-changelog": "3.3.0",
|
|
37
|
-
"dotenv": "
|
|
38
|
-
"eslint": "
|
|
37
|
+
"dotenv": "16.0.0",
|
|
38
|
+
"eslint": "8.9.0",
|
|
39
39
|
"eslint-plugin-header": "3.1.1",
|
|
40
|
-
"eslint-plugin-import": "2.
|
|
41
|
-
"jsdoc-to-markdown": "7.
|
|
40
|
+
"eslint-plugin-import": "2.25.4",
|
|
41
|
+
"jsdoc-to-markdown": "7.1.1",
|
|
42
42
|
"junit-report-builder": "3.0.0",
|
|
43
|
-
"lint-staged": "
|
|
44
|
-
"mocha": "9.
|
|
45
|
-
"
|
|
43
|
+
"lint-staged": "12.3.4",
|
|
44
|
+
"mocha": "9.2.0",
|
|
45
|
+
"mocha-multi-reporters": "1.5.1",
|
|
46
|
+
"nock": "13.2.4",
|
|
46
47
|
"nyc": "15.1.0",
|
|
47
|
-
"semantic-release": "
|
|
48
|
+
"semantic-release": "19.0.2"
|
|
48
49
|
},
|
|
49
50
|
"lint-staged": {
|
|
50
51
|
"*.js": "eslint"
|
|
@@ -56,5 +57,11 @@
|
|
|
56
57
|
"ghooks": {
|
|
57
58
|
"pre-commit": "npx lint-staged"
|
|
58
59
|
}
|
|
60
|
+
},
|
|
61
|
+
"mocha": {
|
|
62
|
+
"spec": "test/**/*.test.js",
|
|
63
|
+
"require": "test/setup-env.js",
|
|
64
|
+
"reporter": "mocha-multi-reporters",
|
|
65
|
+
"reporter-options": "configFile=.mocha-multi.json"
|
|
59
66
|
}
|
|
60
67
|
}
|
package/src/OneDrive.d.ts
CHANGED
|
@@ -60,6 +60,36 @@ export declare interface SubscriptionOptions {
|
|
|
60
60
|
expiresIn?: number;
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
+
export declare interface SharePointSite {
|
|
64
|
+
/**
|
|
65
|
+
* Return a file's properties.
|
|
66
|
+
* @param file file name
|
|
67
|
+
* @returns file properties
|
|
68
|
+
*/
|
|
69
|
+
getFile(file: string): Promise<GraphResult>;
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Return a folder's properties.
|
|
73
|
+
* @param folder folder name
|
|
74
|
+
* @returns folder properties
|
|
75
|
+
*/
|
|
76
|
+
getFolder(folder: string): Promise<GraphResult>;
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Return a file's contents, as a binary buffer.
|
|
80
|
+
* @param file file name
|
|
81
|
+
* @returns file contents
|
|
82
|
+
*/
|
|
83
|
+
getFileContents(file: string): Promise<Buffer>;
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Returns a list of children items in a folder
|
|
87
|
+
* @param folder folder name
|
|
88
|
+
* @returns list of files and folders
|
|
89
|
+
*/
|
|
90
|
+
getFilesAndFolders(folder: string): Promise<GraphResult>;
|
|
91
|
+
}
|
|
92
|
+
|
|
63
93
|
/**
|
|
64
94
|
* Helper class that facilitates accessing one drive.
|
|
65
95
|
*/
|
|
@@ -228,4 +258,11 @@ export declare class OneDrive extends EventEmitter {
|
|
|
228
258
|
* @returns {Promise<Array>} A return object with the values and a `@odata.deltaLink`.
|
|
229
259
|
*/
|
|
230
260
|
fetchChanges(resource: string, token?: string);
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* Returns a site object exposing the SharePoint API (now called Graph API V1).
|
|
264
|
+
* @param siteURL site URL, in the format https://<tenant>.sharepoint.com/sites/<site>
|
|
265
|
+
* @return {Promise<SharePointSite} site object
|
|
266
|
+
*/
|
|
267
|
+
getSite(siteURL: string): Promise<SharePointSite>;
|
|
231
268
|
}
|
package/src/OneDrive.js
CHANGED
|
@@ -20,6 +20,7 @@ const Workbook = require('./Workbook.js');
|
|
|
20
20
|
const StatusCodeError = require('./StatusCodeError.js');
|
|
21
21
|
const { driveItemFromURL, driveItemToURL } = require('./utils.js');
|
|
22
22
|
const { splitByExtension, sanitize, editDistance } = require('./fuzzy-helper.js');
|
|
23
|
+
const SharePointSite = require('./SharePointSite.js');
|
|
23
24
|
|
|
24
25
|
const { fetch, reset } = process.env.HELIX_FETCH_FORCE_HTTP1
|
|
25
26
|
? fetchAPI.context({
|
|
@@ -204,18 +205,26 @@ class OneDrive extends EventEmitter {
|
|
|
204
205
|
if (this.refreshToken) {
|
|
205
206
|
log.debug('acquire token with refresh token.');
|
|
206
207
|
const resp = await context.acquireTokenWithRefreshToken(
|
|
207
|
-
this.refreshToken,
|
|
208
|
+
this.refreshToken,
|
|
209
|
+
this.clientId,
|
|
210
|
+
this.clientSecret,
|
|
211
|
+
AZ_RESOURCE,
|
|
208
212
|
);
|
|
209
213
|
return await this.augmentAndCacheResponse(resp);
|
|
210
214
|
} else if (this.username && this.password) {
|
|
211
215
|
log.debug('acquire token with ROPC.');
|
|
212
216
|
return await context.acquireTokenWithUsernamePassword(
|
|
213
|
-
AZ_RESOURCE,
|
|
217
|
+
AZ_RESOURCE,
|
|
218
|
+
this.username,
|
|
219
|
+
this.password,
|
|
220
|
+
this.clientId,
|
|
214
221
|
);
|
|
215
222
|
} else if (this.clientSecret) {
|
|
216
223
|
log.debug('acquire token with client credentials.');
|
|
217
224
|
return await context.acquireTokenWithClientCredentials(
|
|
218
|
-
AZ_RESOURCE,
|
|
225
|
+
AZ_RESOURCE,
|
|
226
|
+
this.clientId,
|
|
227
|
+
this.clientSecret,
|
|
219
228
|
);
|
|
220
229
|
} else {
|
|
221
230
|
const err = new StatusCodeError('No valid authentication credentials supplied.');
|
|
@@ -259,7 +268,11 @@ class OneDrive extends EventEmitter {
|
|
|
259
268
|
const { log, authContext: context } = this;
|
|
260
269
|
try {
|
|
261
270
|
const resp = await context.acquireTokenWithAuthorizationCode(
|
|
262
|
-
code,
|
|
271
|
+
code,
|
|
272
|
+
redirectUri,
|
|
273
|
+
AZ_RESOURCE,
|
|
274
|
+
this.clientId,
|
|
275
|
+
this.clientSecret,
|
|
263
276
|
);
|
|
264
277
|
return await this.augmentAndCacheResponse(resp);
|
|
265
278
|
} catch (e) {
|
|
@@ -611,6 +624,35 @@ class OneDrive extends EventEmitter {
|
|
|
611
624
|
}
|
|
612
625
|
}
|
|
613
626
|
}
|
|
627
|
+
|
|
628
|
+
async getSite(siteURL) {
|
|
629
|
+
this.log.debug(`getting site: (${siteURL})`);
|
|
630
|
+
|
|
631
|
+
const match = siteURL.match(/^https:\/\/(\S+).sharepoint.com\/sites\/([^/]+)\/(\S+)$/);
|
|
632
|
+
if (!match) {
|
|
633
|
+
throw new Error(`Site URL does not match (*.sharepoint.com/sites/.*): ${match}`);
|
|
634
|
+
}
|
|
635
|
+
const [, owner, site, root] = match;
|
|
636
|
+
|
|
637
|
+
try {
|
|
638
|
+
const accessToken = await this.getAccessToken();
|
|
639
|
+
return new SharePointSite({
|
|
640
|
+
owner,
|
|
641
|
+
site,
|
|
642
|
+
root,
|
|
643
|
+
clientId: this.clientId,
|
|
644
|
+
tenantId: accessToken.tenantId,
|
|
645
|
+
refreshToken: accessToken.refreshToken,
|
|
646
|
+
log: this.log,
|
|
647
|
+
});
|
|
648
|
+
} catch (e) {
|
|
649
|
+
if (e.statusCode === 401) {
|
|
650
|
+
// an inexistant share returns 401, we prefer to just say it wasn't found
|
|
651
|
+
throw new StatusCodeError(e.message, 404, e.details);
|
|
652
|
+
}
|
|
653
|
+
throw e;
|
|
654
|
+
}
|
|
655
|
+
}
|
|
614
656
|
}
|
|
615
657
|
|
|
616
658
|
module.exports = Object.assign(OneDrive, {
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2021 Adobe. All rights reserved.
|
|
3
|
+
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
* you may not use this file except in compliance with the License. You may obtain a copy
|
|
5
|
+
* of the License at http://www.apache.org/licenses/LICENSE-2.0
|
|
6
|
+
*
|
|
7
|
+
* Unless required by applicable law or agreed to in writing, software distributed under
|
|
8
|
+
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
|
|
9
|
+
* OF ANY KIND, either express or implied. See the License for the specific language
|
|
10
|
+
* governing permissions and limitations under the License.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
const fetchAPI = require('@adobe/helix-fetch');
|
|
14
|
+
const StatusCodeError = require('./StatusCodeError.js');
|
|
15
|
+
|
|
16
|
+
/* istanbul ignore next */
|
|
17
|
+
const { fetch } = process.env.HELIX_FETCH_FORCE_HTTP1
|
|
18
|
+
? fetchAPI.context({
|
|
19
|
+
alpnProtocols: [fetchAPI.ALPN_HTTP1_1],
|
|
20
|
+
userAgent: 'helix-fetch', // static user agent for test recordings
|
|
21
|
+
})
|
|
22
|
+
/* istanbul ignore next */
|
|
23
|
+
: fetchAPI;
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Helper class accessing folders and files using the SharePoint V1 API.
|
|
27
|
+
*/
|
|
28
|
+
class SharePointSite {
|
|
29
|
+
constructor(opts) {
|
|
30
|
+
this._owner = opts.owner;
|
|
31
|
+
this._site = opts.site;
|
|
32
|
+
this._clientId = opts.clientId;
|
|
33
|
+
this._tenantId = opts.tenantId;
|
|
34
|
+
this._refreshToken = opts.refreshToken;
|
|
35
|
+
this._root = opts.root || '';
|
|
36
|
+
this._log = opts.log || console;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
async getAccessToken() {
|
|
40
|
+
const { log } = this;
|
|
41
|
+
if (!this._accessToken || Date.now() >= this._expires) {
|
|
42
|
+
const url = `https://login.microsoftonline.com/${this._tenantId}/oauth2/v2.0/token`;
|
|
43
|
+
const resp = await fetch(url, {
|
|
44
|
+
method: 'POST',
|
|
45
|
+
body: new URLSearchParams({
|
|
46
|
+
client_id: this._clientId,
|
|
47
|
+
refresh_token: this._refreshToken,
|
|
48
|
+
grant_type: 'refresh_token',
|
|
49
|
+
scope: `https://${this._owner}.sharepoint.com/Sites.ReadWrite.All`,
|
|
50
|
+
}),
|
|
51
|
+
});
|
|
52
|
+
if (!resp.ok) {
|
|
53
|
+
const text = await resp.text();
|
|
54
|
+
log.error(`Error while getting a SharePoint API token: ${text}}`);
|
|
55
|
+
throw new StatusCodeError(text, resp.status);
|
|
56
|
+
}
|
|
57
|
+
const json = await resp.json();
|
|
58
|
+
this._accessToken = json.access_token;
|
|
59
|
+
this._expires = Date.now() + json.expires_in * 1000;
|
|
60
|
+
}
|
|
61
|
+
return this._accessToken;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
_splitDirAndBase(file) {
|
|
65
|
+
const idx = file.lastIndexOf('/');
|
|
66
|
+
const [dir, base] = (idx < 0)
|
|
67
|
+
? ['', file]
|
|
68
|
+
: [file.substring(0, idx), file.substring(idx + 1)];
|
|
69
|
+
return dir ? [`${this._root}/${dir}`, base] : [this._root, base];
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
_getRelativePath(folder) {
|
|
73
|
+
return folder ? `${this._root}/${folder}` : this._root;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
async getFile(file) {
|
|
77
|
+
const [dir, base] = this._splitDirAndBase(file);
|
|
78
|
+
return this.doFetch(`/GetFolderByServerRelativeUrl('${dir}')/Files('${base}')?$expand=ModifiedBy`);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
async getFolder(folder) {
|
|
82
|
+
const dir = this._getRelativePath(folder);
|
|
83
|
+
return this.doFetch(`/GetFolderByServerRelativeUrl('${dir}')`);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
async getFileContents(file) {
|
|
87
|
+
const [dir, base] = this._splitDirAndBase(file);
|
|
88
|
+
return this.doFetch(`/GetFolderByServerRelativeUrl('${dir}')/Files('${base}')/$value`, true);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
async getFilesAndFolders(folder) {
|
|
92
|
+
const dir = this._getRelativePath(folder);
|
|
93
|
+
return this.doFetch(`/GetFolderByServerRelativeUrl('${dir}')?$expand=Files/ModifiedBy,Folders`);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
async doFetch(relUrl, rawResponseBody = false) {
|
|
97
|
+
const opts = { headers: {} };
|
|
98
|
+
const accessToken = await this.getAccessToken();
|
|
99
|
+
opts.headers.authorization = `Bearer ${accessToken}`;
|
|
100
|
+
if (!rawResponseBody) {
|
|
101
|
+
opts.headers.accept = 'application/json;odata=verbose';
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const url = `https://${this._owner}.sharepoint.com/sites/${this._site}/_api/web${relUrl}`;
|
|
105
|
+
try {
|
|
106
|
+
const resp = await fetch(url, opts);
|
|
107
|
+
if (!resp.ok) {
|
|
108
|
+
const text = await resp.text();
|
|
109
|
+
let err;
|
|
110
|
+
try {
|
|
111
|
+
// try to parse json
|
|
112
|
+
err = StatusCodeError.fromErrorResponse(JSON.parse(text), resp.status);
|
|
113
|
+
} catch {
|
|
114
|
+
err = new StatusCodeError(text, resp.status);
|
|
115
|
+
}
|
|
116
|
+
throw err;
|
|
117
|
+
}
|
|
118
|
+
// check content type before trying to parse a response body as JSON
|
|
119
|
+
const contentType = resp.headers.get('content-type');
|
|
120
|
+
const json = contentType && contentType.startsWith('application/json');
|
|
121
|
+
|
|
122
|
+
// await result in order to be able to catch any error
|
|
123
|
+
return await (rawResponseBody || !json ? resp.buffer() : resp.json());
|
|
124
|
+
} catch (e) {
|
|
125
|
+
/* istanbul ignore else */
|
|
126
|
+
if (e instanceof StatusCodeError) {
|
|
127
|
+
throw e;
|
|
128
|
+
}
|
|
129
|
+
/* istanbul ignore next */
|
|
130
|
+
throw StatusCodeError.fromError(e);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
get log() {
|
|
135
|
+
return this._log;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
module.exports = SharePointSite;
|
package/src/StatusCodeError.js
CHANGED