@adobe/helix-onedrive-support 10.8.5 → 11.0.1

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/.eslintrc.cjs CHANGED
@@ -19,7 +19,7 @@ module.exports = {
19
19
  },
20
20
  parserOptions: {
21
21
  sourceType: 'module',
22
- ecmaVersion: 2020,
22
+ ecmaVersion: 2022,
23
23
  },
24
24
  rules: {
25
25
  'import/extensions': [2, 'ignorePackages'],
package/CHANGELOG.md CHANGED
@@ -1,3 +1,22 @@
1
+ ## [11.0.1](https://github.com/adobe/helix-onedrive-support/compare/v11.0.0...v11.0.1) (2023-10-18)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * log errors once ([#453](https://github.com/adobe/helix-onedrive-support/issues/453)) ([018c1c2](https://github.com/adobe/helix-onedrive-support/commit/018c1c22a3257805fa126b56ad8e59afd7e1fc0f))
7
+
8
+ # [11.0.0](https://github.com/adobe/helix-onedrive-support/compare/v10.8.5...v11.0.0) (2023-10-14)
9
+
10
+
11
+ * fix(excel)!: store session in workbook (#450) ([f7e3abc](https://github.com/adobe/helix-onedrive-support/commit/f7e3abc433d6a1209b3abec58cefedc8066701b3)), closes [#450](https://github.com/adobe/helix-onedrive-support/issues/450)
12
+
13
+
14
+ ### BREAKING CHANGES
15
+
16
+ * semantics of setting sessions changed
17
+
18
+ * fix: add getSessionId
19
+
1
20
  ## [10.8.5](https://github.com/adobe/helix-onedrive-support/compare/v10.8.4...v10.8.5) (2023-10-08)
2
21
 
3
22
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adobe/helix-onedrive-support",
3
- "version": "10.8.5",
3
+ "version": "11.0.1",
4
4
  "description": "Helix OneDrive Support",
5
5
  "main": "src/index.js",
6
6
  "exports": {
@@ -30,13 +30,13 @@
30
30
  "@adobe/fetch": "4.1.0",
31
31
  "@adobe/helix-shared-tokencache": "1.3.11",
32
32
  "@azure/msal-node": "2.2.0",
33
- "jose": "4.15.2"
33
+ "jose": "4.15.4"
34
34
  },
35
35
  "devDependencies": {
36
36
  "@adobe/eslint-config-helix": "2.0.3",
37
37
  "@semantic-release/changelog": "6.0.3",
38
38
  "@semantic-release/git": "10.0.1",
39
- "@aws-sdk/client-s3": "3.427.0",
39
+ "@aws-sdk/client-s3": "3.428.0",
40
40
  "ajv": "8.12.0",
41
41
  "c8": "8.0.1",
42
42
  "codecov": "3.8.3",
@@ -48,11 +48,11 @@
48
48
  "install": "0.13.0",
49
49
  "jsdoc-to-markdown": "8.0.0",
50
50
  "jsdoc-tsimport-plugin": "1.0.5",
51
- "junit-report-builder": "3.0.1",
52
- "lint-staged": "14.0.1",
51
+ "junit-report-builder": "3.1.0",
52
+ "lint-staged": "15.0.1",
53
53
  "mocha": "10.2.0",
54
54
  "mocha-multi-reporters": "1.5.1",
55
- "nock": "13.3.3",
55
+ "nock": "13.3.4",
56
56
  "npm": "10.2.0",
57
57
  "semantic-release": "22.0.5"
58
58
  },
package/src/OneDrive.js CHANGED
@@ -116,12 +116,30 @@ export class OneDrive {
116
116
  return this._log;
117
117
  }
118
118
 
119
- get workbookSessionId() {
120
- return this._sessionId;
121
- }
119
+ async #handleBadResponse(resp, rateLimit) {
120
+ const { log } = this;
121
+
122
+ let text;
123
+ let err;
124
+
125
+ try {
126
+ text = await resp.text();
127
+ /* c8 ignore next 4 */
128
+ } catch (e) {
129
+ log.warn(`Unable to fetch response text: ${e.message}`);
130
+ throw StatusCodeError.fromError(e);
131
+ }
122
132
 
123
- setWorkbookSessionId(workbookSessionId) {
124
- this._sessionId = workbookSessionId;
133
+ try {
134
+ err = StatusCodeError.fromErrorResponse(JSON.parse(text), resp.status, rateLimit);
135
+ } catch (e) {
136
+ if (text.startsWith('<!DOCTYPE html>')) {
137
+ log.warn('Graph API returned html response', text);
138
+ text = 'Something went wrong: HTML error from graph api.';
139
+ }
140
+ err = new StatusCodeError(text, resp.status, null, rateLimit);
141
+ }
142
+ throw err;
125
143
  }
126
144
 
127
145
  /**
@@ -134,51 +152,40 @@ export class OneDrive {
134
152
  }
135
153
  opts.headers.authorization = `Bearer ${accessToken}`;
136
154
 
137
- if (this._sessionId) {
138
- opts.headers['Workbook-Session-Id'] = this._sessionId;
139
- }
140
155
  const { log, auth: { logFields, tenant } } = this;
141
156
  const url = `https://graph.microsoft.com/v1.0${relUrl}`;
142
157
  const method = opts.method || 'GET';
158
+ let resp;
143
159
 
144
160
  try {
145
161
  const { fetch } = this.fetchContext;
146
- const resp = await fetch(url, opts);
162
+ resp = await fetch(url, opts);
147
163
  log.info(`OneDrive API [tenant:${tenant}] ${logFields}: ${method} ${relUrl} ${resp.status}`);
164
+ } catch (e) {
165
+ log.info(`OneDrive API [tenant:${tenant}] ${logFields}: ${method} ${relUrl} ${e.message}`);
166
+ throw StatusCodeError.fromError(e);
167
+ }
148
168
 
149
- const rateLimit = RateLimit.fromHeaders(resp.headers);
150
- if (rateLimit) {
151
- log.warn({ sharepointRateLimit: { tenant, ...rateLimit.toJSON() } });
152
- }
169
+ const rateLimit = RateLimit.fromHeaders(resp.headers);
170
+ if (rateLimit) {
171
+ log.warn({ sharepointRateLimit: { tenant, ...rateLimit.toJSON() } });
172
+ }
153
173
 
154
- if (!resp.ok) {
155
- let text = await resp.text();
156
- let err;
157
- try {
158
- // try to parse json
159
- err = StatusCodeError.fromErrorResponse(JSON.parse(text), resp.status, rateLimit);
160
- } catch {
161
- if (text.startsWith('<!DOCTYPE html>')) {
162
- log.warn('onedrive returned html response', text);
163
- text = 'Something went wrong: HTML error from graph api.';
164
- }
165
- err = new StatusCodeError(text, resp.status, null, rateLimit);
166
- }
167
- throw err;
168
- }
174
+ if (!resp.ok) {
175
+ return this.#handleBadResponse(resp, rateLimit);
176
+ }
177
+
178
+ try {
169
179
  // check content type before trying to parse a response body as JSON
170
180
  const contentType = resp.headers.get('content-type');
171
181
  const json = contentType && contentType.startsWith('application/json');
172
182
 
173
183
  // await result in order to be able to catch any error
174
184
  return await (rawResponseBody || !json ? resp.buffer() : resp.json());
185
+ /* c8 ignore next 4 */
175
186
  } catch (e) {
176
- let err = e;
177
- if (!(e instanceof StatusCodeError)) {
178
- err = StatusCodeError.fromError(e);
179
- }
180
- log.info(`OneDrive API [tenant:${tenant}] ${logFields}: ${method} ${relUrl} ${e.statusCode}`);
181
- throw err;
187
+ log.warn(`Unable to fetch response buffer or json: ${e.message}`);
188
+ throw StatusCodeError.fromError(e);
182
189
  }
183
190
  }
184
191
 
@@ -28,7 +28,7 @@ export declare interface Workbook {
28
28
  * Create the worksheet with given name in the workbook.
29
29
  * @param {string} sheetName sheet name
30
30
  * @returns Worksheet
31
- *
31
+ *
32
32
  */
33
33
  createWorksheet(sheetName: string): Worksheet;
34
34
 
@@ -109,9 +109,15 @@ export declare interface Workbook {
109
109
  */
110
110
  refreshSession(): Promise<void>;
111
111
 
112
+ /**
113
+ * Returns the sessionId of the workbook
114
+ * @returns {string} sessionId or null
115
+ */
116
+ getSessionId(): string;
117
+
112
118
  /**
113
119
  * Sets the sessionId of the workbook
114
- * @param sessionId
120
+ * @param {string} sessionId session id
115
121
  */
116
122
  setSessionId(sessionId: string): void;
117
123
  }
@@ -23,65 +23,87 @@ export class Workbook extends NamedItemContainer {
23
23
  this._log = log;
24
24
  }
25
25
 
26
- async getData() {
27
- const result = await this._oneDrive.doFetch(this._uri);
28
- return result.value;
29
- }
30
-
31
- async getWorksheetNames() {
32
- this.log.debug(`get worksheet names from ${this._uri}/worksheets`);
33
- const result = await this._oneDrive.doFetch(`${this._uri}/worksheets`);
34
- return result.value.map((v) => v.name);
35
- }
36
-
37
- worksheet(name) {
38
- return new Worksheet(this._oneDrive, `${this._uri}/worksheets`, name, this._log);
39
- }
40
-
41
26
  async createSession() {
42
- const sessionId = this._oneDrive.workbookSessionId;
43
- if (sessionId) {
44
- return sessionId;
45
- } else {
46
- const uri = `${this.uri}/createSession`;
47
- const result = await this._oneDrive.doFetch(uri, false, {
48
- method: 'POST',
49
- });
50
- this._oneDrive.setWorkbookSessionId(result.id);
51
- return result.id;
27
+ if (this._sessionId) {
28
+ throw new StatusCodeError('This workbook is already associated with a session', 400);
52
29
  }
30
+ const uri = `${this.uri}/createSession`;
31
+ const result = await this._oneDrive.doFetch(uri, false, {
32
+ method: 'POST',
33
+ });
34
+ this._sessionId = result.id;
35
+ return this._sessionId;
53
36
  }
54
37
 
55
38
  async closeSession() {
56
- if (this._oneDrive.workbookSessionId) {
39
+ if (this._sessionId) {
57
40
  const uri = `${this.uri}/closeSession`;
58
41
  await this._oneDrive.doFetch(uri, false, {
59
42
  method: 'POST',
43
+ headers: {
44
+ 'Workbook-Session-Id': this._sessionId,
45
+ },
60
46
  });
61
- this._oneDrive.setWorkbookSessionId(null);
62
- } else {
63
- throw new StatusCodeError('Please create a session first!', 400);
47
+ this._sessionId = null;
48
+ return;
64
49
  }
50
+ throw new StatusCodeError('No session associated with workbook', 400);
65
51
  }
66
52
 
67
53
  async refreshSession() {
68
- if (this._oneDrive.workbookSessionId) {
54
+ if (this._sessionId) {
69
55
  const uri = `${this.uri}/refreshSession`;
70
56
  await this._oneDrive.doFetch(uri, false, {
71
57
  method: 'POST',
58
+ headers: {
59
+ 'Workbook-Session-Id': this._sessionId,
60
+ },
72
61
  });
73
- } else {
74
- throw new StatusCodeError('Please create a session first!', 400);
62
+ return;
75
63
  }
64
+ throw new StatusCodeError('No session associated with workbook', 400);
65
+ }
66
+
67
+ getSessionId() {
68
+ return this._sessionId;
76
69
  }
77
70
 
78
71
  setSessionId(sessionId) {
79
- this._oneDrive.setWorkbookSessionId(sessionId);
72
+ if (this._sessionId) {
73
+ throw new StatusCodeError('This workbook is already associated with a session', 400);
74
+ }
75
+ this._sessionId = sessionId;
76
+ }
77
+
78
+ async doFetch(relUrl, rawResponseBody, options) {
79
+ const opts = { ...options };
80
+ if (!opts.headers) {
81
+ opts.headers = {};
82
+ }
83
+ if (this._sessionId) {
84
+ opts.headers['Workbook-Session-Id'] = this._sessionId;
85
+ }
86
+ return this._oneDrive.doFetch(relUrl, rawResponseBody, opts);
87
+ }
88
+
89
+ async getData() {
90
+ const result = await this.doFetch(this._uri);
91
+ return result.value;
92
+ }
93
+
94
+ async getWorksheetNames() {
95
+ this.log.debug(`get worksheet names from ${this._uri}/worksheets`);
96
+ const result = await this.doFetch(`${this._uri}/worksheets`);
97
+ return result.value.map((v) => v.name);
98
+ }
99
+
100
+ worksheet(name) {
101
+ return new Worksheet(this, `${this._uri}/worksheets`, name, this._log);
80
102
  }
81
103
 
82
104
  async createWorksheet(sheetName) {
83
105
  const uri = `${this.uri}/worksheets`;
84
- await this._oneDrive.doFetch(uri, false, {
106
+ await this.doFetch(uri, false, {
85
107
  method: 'POST',
86
108
  body: { name: sheetName },
87
109
  headers: { 'content-type': 'application/json' },
@@ -91,7 +113,7 @@ export class Workbook extends NamedItemContainer {
91
113
 
92
114
  async deleteWorksheet(sheetName) {
93
115
  const uri = `${this.uri}/worksheets/${sheetName}`;
94
- await this._oneDrive.doFetch(uri, false, {
116
+ await this.doFetch(uri, false, {
95
117
  method: 'DELETE',
96
118
  headers: { 'content-type': 'application/json' },
97
119
  });
@@ -99,12 +121,12 @@ export class Workbook extends NamedItemContainer {
99
121
 
100
122
  async getTableNames() {
101
123
  this.log.debug(`get table names from ${this._uri}/tables`);
102
- const result = await this._oneDrive.doFetch(`${this._uri}/tables`);
124
+ const result = await this.doFetch(`${this._uri}/tables`);
103
125
  return result.value.map((v) => v.name);
104
126
  }
105
127
 
106
128
  table(name) {
107
- return new Table(this._oneDrive, `${this._uri}/tables`, name, this._log);
129
+ return new Table(this, `${this._uri}/tables`, name, this._log);
108
130
  }
109
131
 
110
132
  async addTable(address, hasHeaders, name) {
@@ -114,7 +136,7 @@ export class Workbook extends NamedItemContainer {
114
136
  throw new StatusCodeError(`Table name already exists: ${name}`, 409);
115
137
  }
116
138
  }
117
- const result = await this._oneDrive.doFetch(`${this.uri}/tables/add`, false, {
139
+ const result = await this.doFetch(`${this.uri}/tables/add`, false, {
118
140
  method: 'POST',
119
141
  body: {
120
142
  address,