@fluidframework/routerlicious-driver 0.54.2 → 0.56.0-49831

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.
Files changed (49) hide show
  1. package/.eslintrc.js +1 -1
  2. package/dist/documentServiceFactory.js +1 -1
  3. package/dist/documentServiceFactory.js.map +1 -1
  4. package/dist/errorUtils.js +3 -3
  5. package/dist/errorUtils.js.map +1 -1
  6. package/dist/nullBlobStorageService.d.ts +1 -1
  7. package/dist/nullBlobStorageService.d.ts.map +1 -1
  8. package/dist/nullBlobStorageService.js.map +1 -1
  9. package/dist/packageVersion.d.ts +1 -1
  10. package/dist/packageVersion.d.ts.map +1 -1
  11. package/dist/packageVersion.js +1 -1
  12. package/dist/packageVersion.js.map +1 -1
  13. package/dist/policies.d.ts +1 -1
  14. package/dist/policies.js.map +1 -1
  15. package/dist/restWrapper.d.ts +3 -2
  16. package/dist/restWrapper.d.ts.map +1 -1
  17. package/dist/restWrapper.js +48 -36
  18. package/dist/restWrapper.js.map +1 -1
  19. package/dist/shreddedSummaryDocumentStorageService.d.ts +1 -1
  20. package/dist/shreddedSummaryDocumentStorageService.d.ts.map +1 -1
  21. package/dist/shreddedSummaryDocumentStorageService.js.map +1 -1
  22. package/lib/documentServiceFactory.js +1 -1
  23. package/lib/documentServiceFactory.js.map +1 -1
  24. package/lib/errorUtils.js +3 -3
  25. package/lib/errorUtils.js.map +1 -1
  26. package/lib/nullBlobStorageService.d.ts +1 -1
  27. package/lib/nullBlobStorageService.d.ts.map +1 -1
  28. package/lib/nullBlobStorageService.js.map +1 -1
  29. package/lib/packageVersion.d.ts +1 -1
  30. package/lib/packageVersion.d.ts.map +1 -1
  31. package/lib/packageVersion.js +1 -1
  32. package/lib/packageVersion.js.map +1 -1
  33. package/lib/policies.d.ts +1 -1
  34. package/lib/policies.js.map +1 -1
  35. package/lib/restWrapper.d.ts +3 -2
  36. package/lib/restWrapper.d.ts.map +1 -1
  37. package/lib/restWrapper.js +46 -35
  38. package/lib/restWrapper.js.map +1 -1
  39. package/lib/shreddedSummaryDocumentStorageService.d.ts +1 -1
  40. package/lib/shreddedSummaryDocumentStorageService.d.ts.map +1 -1
  41. package/lib/shreddedSummaryDocumentStorageService.js.map +1 -1
  42. package/package.json +22 -17
  43. package/src/documentServiceFactory.ts +1 -1
  44. package/src/errorUtils.ts +3 -3
  45. package/src/nullBlobStorageService.ts +1 -1
  46. package/src/packageVersion.ts +1 -1
  47. package/src/policies.ts +1 -1
  48. package/src/restWrapper.ts +66 -41
  49. package/src/shreddedSummaryDocumentStorageService.ts +1 -1
@@ -11,7 +11,12 @@ import {
11
11
  RestLessClient,
12
12
  RestWrapper,
13
13
  } from "@fluidframework/server-services-client";
14
- import Axios, { AxiosError, AxiosRequestConfig } from "axios";
14
+ import {
15
+ default as nodeFetch,
16
+ RequestInfo as FetchRequestInfo,
17
+ RequestInit as FetchRequestInit,
18
+ } from "node-fetch";
19
+ import type { AxiosRequestConfig } from "axios";
15
20
  import safeStringify from "json-stringify-safe";
16
21
  import { v4 as uuid } from "uuid";
17
22
  import { throwR11sNetworkError } from "./errorUtils";
@@ -19,12 +24,31 @@ import { ITokenProvider } from "./tokens";
19
24
 
20
25
  type AuthorizationHeaderGetter = (refresh?: boolean) => Promise<string | undefined>;
21
26
 
27
+ // Borrowed from @fluidframework/odsp-driver's fetch.ts
28
+ // The only purpose of this helper is to work around the slight misalignments between the
29
+ // Browser's fetch API and the 'node-fetch' package by wrapping the call to the 'node-fetch' API
30
+ // in the browser's types from 'lib.dom.d.ts'.
31
+ export const fetch = async (request: RequestInfo, config?: RequestInit): Promise<Response> =>
32
+ nodeFetch(request as FetchRequestInfo, config as FetchRequestInit) as unknown as Response;
33
+
34
+ const axiosRequestConfigToFetchRequestConfig = (requestConfig: AxiosRequestConfig): [RequestInfo, RequestInit] => {
35
+ const requestInfo: string = requestConfig.baseURL !== undefined
36
+ ? `${requestConfig.baseURL}${requestConfig.url ?? ""}`
37
+ : requestConfig.url ?? "";
38
+ const requestInit: RequestInit = {
39
+ method: requestConfig.method,
40
+ headers: requestConfig.headers,
41
+ body: requestConfig.data,
42
+ };
43
+ return [requestInfo, requestInit];
44
+ };
45
+
22
46
  export class RouterliciousRestWrapper extends RestWrapper {
23
47
  private authorizationHeader: string | undefined;
24
48
  private readonly restLess = new RestLessClient();
25
49
 
26
50
  constructor(
27
- private readonly logger: ITelemetryLogger,
51
+ logger: ITelemetryLogger,
28
52
  private readonly rateLimiter: RateLimiter,
29
53
  private readonly getAuthorizationHeader: AuthorizationHeaderGetter,
30
54
  private readonly useRestLess: boolean,
@@ -45,46 +69,47 @@ export class RouterliciousRestWrapper extends RestWrapper {
45
69
  };
46
70
 
47
71
  const translatedConfig = this.useRestLess ? this.restLess.translate(config) : config;
48
-
49
- try {
50
- const response = await this.rateLimiter.schedule(async () => Axios.request<T>(translatedConfig));
51
- return response.data;
52
- } catch (reason: any) {
53
- if (!reason || !reason?.isAxiosError) {
54
- // Unknown error, treat as critical error and immediately throw as non-retriable
55
- this.logger.sendErrorEvent({
56
- eventName: "CriticalRequestError",
57
- correlationId: config.headers["x-correlation-id"] as string,
58
- }, reason);
59
- throwR11sNetworkError("r11sRequestFailed", `Unknown Error on [${config.method}] to [${config.url}]: ${
60
- safeStringify(reason)
61
- }`);
62
- }
63
-
64
- const axiosError = reason as AxiosError;
65
- if (axiosError.response?.status === statusCode) {
66
- // Axios misinterpreted as error, return as successful response
67
- return axiosError.response.data as T;
68
- }
69
-
70
- if (axiosError.response?.status === 401 && canRetry) {
71
- // Refresh Authorization header and retry once
72
- this.authorizationHeader = await this.getAuthorizationHeader(true);
73
- return this.request<T>(config, statusCode, false);
74
- }
75
-
76
- if (axiosError.response?.status === 429 && axiosError.response.data?.retryAfter > 0) {
77
- // Retry based on retryAfter[Seconds]
78
- return new Promise<T>((resolve, reject) => setTimeout(() => {
79
- this.request<T>(config, statusCode)
80
- .then(resolve)
81
- .catch(reject);
82
- }, axiosError.response!.data.retryAfter * 1000));
83
- }
84
-
85
- // Allow anything else to be handled upstream
86
- throwR11sNetworkError("r11sAxiosError", axiosError.message, axiosError.response?.status);
72
+ const fetchRequestConfig = axiosRequestConfigToFetchRequestConfig(translatedConfig);
73
+
74
+ const response: Response = await this.rateLimiter.schedule(async () => fetch(...fetchRequestConfig)
75
+ .catch(async (error) => {
76
+ // Fetch throws a TypeError on network error
77
+ const isNetworkError = error instanceof TypeError;
78
+ throwR11sNetworkError(
79
+ "r11sFetchError",
80
+ isNetworkError ? `NetworkError: ${error.message}` : safeStringify(error));
81
+ }));
82
+
83
+ const responseBody: any = await response.clone().json().catch(async () => response.text());
84
+
85
+ // Success
86
+ if (response.ok || response.status === statusCode) {
87
+ const result: T = responseBody;
88
+ return result;
89
+ }
90
+ // Failure
91
+ if (response.status === 401 && canRetry) {
92
+ // Refresh Authorization header and retry once
93
+ this.authorizationHeader = await this.getAuthorizationHeader(true);
94
+ return this.request<T>(config, statusCode, false);
87
95
  }
96
+ if (response.status === 429 && responseBody?.retryAfter > 0) {
97
+ // Retry based on retryAfter[Seconds]
98
+ return new Promise<T>((resolve, reject) => setTimeout(() => {
99
+ this.request<T>(config, statusCode)
100
+ .then(resolve)
101
+ .catch(reject);
102
+ }, responseBody.retryAfter * 1000));
103
+ }
104
+
105
+ throwR11sNetworkError(
106
+ "r11sFetchError",
107
+ responseBody !== undefined
108
+ ? typeof responseBody === "string" ? responseBody : safeStringify(responseBody)
109
+ : response.statusText,
110
+ response.status,
111
+ responseBody?.retryAfter,
112
+ );
88
113
  }
89
114
 
90
115
  private generateHeaders(requestHeaders?: Record<string, unknown>): Record<string, unknown> {
@@ -72,7 +72,7 @@ export class ShreddedSummaryDocumentStorageService implements IDocumentStorageSe
72
72
  }
73
73
  }
74
74
 
75
- public async getVersions(versionId: string, count: number): Promise<IVersion[]> {
75
+ public async getVersions(versionId: string | null, count: number): Promise<IVersion[]> {
76
76
  const id = versionId ? versionId : this.id;
77
77
  const commits = await PerformanceEvent.timedExecAsync(
78
78
  this.logger,