@fluidframework/routerlicious-driver 2.3.0-288113 → 2.3.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.
Files changed (87) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/dist/createNewUtils.d.ts.map +1 -1
  3. package/dist/createNewUtils.js +3 -1
  4. package/dist/createNewUtils.js.map +1 -1
  5. package/dist/deltaStorageService.js +1 -1
  6. package/dist/deltaStorageService.js.map +1 -1
  7. package/dist/documentService.d.ts +6 -11
  8. package/dist/documentService.d.ts.map +1 -1
  9. package/dist/documentService.js +16 -61
  10. package/dist/documentService.js.map +1 -1
  11. package/dist/documentServiceFactory.d.ts +1 -0
  12. package/dist/documentServiceFactory.d.ts.map +1 -1
  13. package/dist/documentServiceFactory.js +33 -42
  14. package/dist/documentServiceFactory.js.map +1 -1
  15. package/dist/packageVersion.d.ts +1 -1
  16. package/dist/packageVersion.d.ts.map +1 -1
  17. package/dist/packageVersion.js +1 -1
  18. package/dist/packageVersion.js.map +1 -1
  19. package/dist/r11sSnapshotParser.d.ts.map +1 -1
  20. package/dist/r11sSnapshotParser.js +2 -4
  21. package/dist/r11sSnapshotParser.js.map +1 -1
  22. package/dist/sessionInfoManager.d.ts +55 -0
  23. package/dist/sessionInfoManager.d.ts.map +1 -0
  24. package/dist/sessionInfoManager.js +100 -0
  25. package/dist/sessionInfoManager.js.map +1 -0
  26. package/dist/shreddedSummaryDocumentStorageService.d.ts.map +1 -1
  27. package/dist/shreddedSummaryDocumentStorageService.js +3 -4
  28. package/dist/shreddedSummaryDocumentStorageService.js.map +1 -1
  29. package/dist/summaryTreeUploadManager.d.ts.map +1 -1
  30. package/dist/summaryTreeUploadManager.js +3 -3
  31. package/dist/summaryTreeUploadManager.js.map +1 -1
  32. package/dist/urlUtils.d.ts.map +1 -1
  33. package/dist/urlUtils.js +0 -2
  34. package/dist/urlUtils.js.map +1 -1
  35. package/dist/wholeSummaryDocumentStorageService.d.ts.map +1 -1
  36. package/dist/wholeSummaryDocumentStorageService.js +3 -4
  37. package/dist/wholeSummaryDocumentStorageService.js.map +1 -1
  38. package/lib/createNewUtils.d.ts.map +1 -1
  39. package/lib/createNewUtils.js +3 -1
  40. package/lib/createNewUtils.js.map +1 -1
  41. package/lib/deltaStorageService.js +1 -1
  42. package/lib/deltaStorageService.js.map +1 -1
  43. package/lib/documentService.d.ts +6 -11
  44. package/lib/documentService.d.ts.map +1 -1
  45. package/lib/documentService.js +16 -61
  46. package/lib/documentService.js.map +1 -1
  47. package/lib/documentServiceFactory.d.ts +1 -0
  48. package/lib/documentServiceFactory.d.ts.map +1 -1
  49. package/lib/documentServiceFactory.js +19 -28
  50. package/lib/documentServiceFactory.js.map +1 -1
  51. package/lib/packageVersion.d.ts +1 -1
  52. package/lib/packageVersion.d.ts.map +1 -1
  53. package/lib/packageVersion.js +1 -1
  54. package/lib/packageVersion.js.map +1 -1
  55. package/lib/r11sSnapshotParser.d.ts.map +1 -1
  56. package/lib/r11sSnapshotParser.js +2 -4
  57. package/lib/r11sSnapshotParser.js.map +1 -1
  58. package/lib/sessionInfoManager.d.ts +55 -0
  59. package/lib/sessionInfoManager.d.ts.map +1 -0
  60. package/lib/sessionInfoManager.js +96 -0
  61. package/lib/sessionInfoManager.js.map +1 -0
  62. package/lib/shreddedSummaryDocumentStorageService.d.ts.map +1 -1
  63. package/lib/shreddedSummaryDocumentStorageService.js +3 -4
  64. package/lib/shreddedSummaryDocumentStorageService.js.map +1 -1
  65. package/lib/summaryTreeUploadManager.d.ts.map +1 -1
  66. package/lib/summaryTreeUploadManager.js +3 -3
  67. package/lib/summaryTreeUploadManager.js.map +1 -1
  68. package/lib/tsdoc-metadata.json +1 -1
  69. package/lib/urlUtils.d.ts.map +1 -1
  70. package/lib/urlUtils.js +0 -2
  71. package/lib/urlUtils.js.map +1 -1
  72. package/lib/wholeSummaryDocumentStorageService.d.ts.map +1 -1
  73. package/lib/wholeSummaryDocumentStorageService.js +3 -4
  74. package/lib/wholeSummaryDocumentStorageService.js.map +1 -1
  75. package/package.json +16 -15
  76. package/src/createNewUtils.ts +4 -1
  77. package/src/deltaStorageService.ts +1 -1
  78. package/src/documentService.ts +19 -75
  79. package/src/documentServiceFactory.ts +25 -38
  80. package/src/packageVersion.ts +1 -1
  81. package/src/r11sSnapshotParser.ts +3 -5
  82. package/src/sessionInfoManager.ts +148 -0
  83. package/src/shreddedSummaryDocumentStorageService.ts +3 -4
  84. package/src/summaryTreeUploadManager.ts +4 -4
  85. package/src/urlUtils.ts +2 -4
  86. package/src/wholeSummaryDocumentStorageService.ts +3 -4
  87. package/tsconfig.json +1 -0
@@ -0,0 +1,148 @@
1
+ /*!
2
+ * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
+ * Licensed under the MIT License.
4
+ */
5
+
6
+ import { assert } from "@fluidframework/core-utils/internal";
7
+ import { getW3CData } from "@fluidframework/driver-base/internal";
8
+ import { IResolvedUrl } from "@fluidframework/driver-definitions/internal";
9
+ import { ISession } from "@fluidframework/server-services-client";
10
+ import {
11
+ PerformanceEvent,
12
+ ITelemetryLoggerExt,
13
+ } from "@fluidframework/telemetry-utils/internal";
14
+
15
+ import { RouterliciousOrdererRestWrapper } from "./restWrapper.js";
16
+ import { getDiscoveredFluidResolvedUrl } from "./urlUtils.js";
17
+
18
+ /**
19
+ * Amount of time between discoveries within which we don't need to rediscover on re-connect.
20
+ * Currently, R11s defines session length at 10 minutes. To avoid any weird unknown edge-cases though,
21
+ * we set the limit to 5 minutes here.
22
+ * In the future, we likely want to retrieve this information from service's "inactive session" definition.
23
+ */
24
+ export const RediscoverAfterTimeSinceDiscoveryMs = 5 * 60000; // 5 minutes
25
+
26
+ interface IGetSessionInfoParams {
27
+ resolvedUrl: IResolvedUrl;
28
+ documentId: string;
29
+ tenantId: string;
30
+ ordererRestWrapper: RouterliciousOrdererRestWrapper;
31
+ logger: ITelemetryLoggerExt;
32
+ }
33
+
34
+ export interface IGetSessionInfoResponse {
35
+ refreshed: boolean;
36
+ resolvedUrl: IResolvedUrl;
37
+ }
38
+
39
+ export class SessionInfoManager {
40
+ /**
41
+ * Stored session info
42
+ * Key: URL for given session (see "getDiscoverSessionUrl")
43
+ * Value: session info stored as an IResolvedUrl
44
+ */
45
+ private readonly sessionInfoMap: Map<string, IResolvedUrl> = new Map();
46
+
47
+ /**
48
+ * Stored dates of when a session was last discovered/refreshed
49
+ * Key: URL for given session (see "getDiscoverSessionUrl")
50
+ * Value: date last discovered
51
+ */
52
+ private readonly sessionLastDiscoveredMap: Map<string, number> = new Map();
53
+
54
+ constructor(private readonly enableDiscovery: boolean) {}
55
+
56
+ /**
57
+ * Start tracking info for a given session
58
+ */
59
+ public async initializeSessionInfo(
60
+ params: IGetSessionInfoParams & { session: ISession | undefined },
61
+ ): Promise<IResolvedUrl> {
62
+ const { resolvedUrl, session } = params;
63
+
64
+ const url = getDiscoverSessionUrl(params);
65
+ assert(
66
+ this.sessionInfoMap.has(url) === this.sessionLastDiscoveredMap.has(url),
67
+ 0xa2d /* Session map state mismatch */,
68
+ );
69
+
70
+ if (session !== undefined) {
71
+ this.sessionInfoMap.set(url, getDiscoveredFluidResolvedUrl(resolvedUrl, session));
72
+ this.sessionLastDiscoveredMap.set(url, Date.now());
73
+ } else if (!this.sessionInfoMap.has(url)) {
74
+ this.sessionInfoMap.set(url, resolvedUrl);
75
+ // Force a refresh
76
+ this.sessionLastDiscoveredMap.set(url, 0);
77
+ }
78
+
79
+ return (await this.getSessionInfo(params)).resolvedUrl;
80
+ }
81
+
82
+ /**
83
+ * Retrieve, and potentially refresh, info of a given session
84
+ */
85
+ public async getSessionInfo(
86
+ params: IGetSessionInfoParams,
87
+ ): Promise<IGetSessionInfoResponse> {
88
+ const url = getDiscoverSessionUrl(params);
89
+ assert(
90
+ this.sessionInfoMap.has(url) && this.sessionLastDiscoveredMap.has(url),
91
+ 0xa2e /* Unexpected discover session URL */,
92
+ );
93
+
94
+ let refreshed = false;
95
+ const shouldRediscover =
96
+ Date.now() - this.sessionLastDiscoveredMap.get(url)! >
97
+ RediscoverAfterTimeSinceDiscoveryMs;
98
+ if (this.enableDiscovery && shouldRediscover) {
99
+ await this.fetchAndUpdateSessionInfo(params).catch((error) => {
100
+ // Undo discovery time set on failure, so that next check refreshes.
101
+ this.sessionLastDiscoveredMap.set(url, 0);
102
+ throw error;
103
+ });
104
+ refreshed = true;
105
+ }
106
+ return {
107
+ refreshed,
108
+ // ! Shallow copy is important as some mechanisms may rely on object comparison
109
+ resolvedUrl: { ...this.sessionInfoMap.get(url)! },
110
+ };
111
+ }
112
+
113
+ private async fetchAndUpdateSessionInfo(params: IGetSessionInfoParams): Promise<void> {
114
+ const { documentId, ordererRestWrapper, logger, resolvedUrl } = params;
115
+
116
+ const url = getDiscoverSessionUrl(params);
117
+ const discoveredSession = await PerformanceEvent.timedExecAsync(
118
+ logger,
119
+ {
120
+ eventName: "DiscoverSession",
121
+ docId: documentId,
122
+ },
123
+ async (event) => {
124
+ // The service responds with the current document session associated with the container.
125
+ const response = await ordererRestWrapper.get<ISession>(url);
126
+ event.end({
127
+ ...response.propsToLog,
128
+ ...getW3CData(response.requestUrl, "xmlhttprequest"),
129
+ });
130
+ return response.content;
131
+ },
132
+ );
133
+ this.sessionInfoMap.set(
134
+ url,
135
+ getDiscoveredFluidResolvedUrl(resolvedUrl, discoveredSession),
136
+ );
137
+ this.sessionLastDiscoveredMap.set(url, Date.now());
138
+ }
139
+ }
140
+
141
+ function getDiscoverSessionUrl(params: {
142
+ resolvedUrl: IResolvedUrl;
143
+ tenantId: string;
144
+ documentId: string;
145
+ }): string {
146
+ const { resolvedUrl, tenantId, documentId } = params;
147
+ return `${resolvedUrl.endpoints.ordererUrl}/documents/${tenantId}/session/${documentId}`;
148
+ }
@@ -98,14 +98,13 @@ export class ShreddedSummaryDocumentStorageService implements IDocumentStorageSe
98
98
 
99
99
  public async getSnapshotTree(version?: IVersion): Promise<ISnapshotTreeEx | null> {
100
100
  let requestVersion = version;
101
- if (requestVersion === undefined) {
101
+ if (!requestVersion) {
102
102
  const versions = await this.getVersions(this.id, 1);
103
- const firstVersion = versions[0];
104
- if (firstVersion === undefined) {
103
+ if (versions.length === 0) {
105
104
  return null;
106
105
  }
107
106
 
108
- requestVersion = firstVersion;
107
+ requestVersion = versions[0];
109
108
  }
110
109
 
111
110
  const cachedSnapshotTree = await this.snapshotTreeCache?.get(
@@ -41,7 +41,8 @@ export class SummaryTreeUploadManager implements ISummaryUploadManager {
41
41
  previousFullSnapshot: ISnapshotTreeEx | undefined,
42
42
  ): Promise<string> {
43
43
  const entries = await Promise.all(
44
- Object.entries(summaryTree.tree).map(async ([key, entry]) => {
44
+ Object.keys(summaryTree.tree).map(async (key) => {
45
+ const entry = summaryTree.tree[key];
45
46
  const pathHandle = await this.writeSummaryTreeObject(entry, previousFullSnapshot);
46
47
  const treeEntry: IGitCreateTreeEntry = {
47
48
  mode: getGitMode(entry),
@@ -122,8 +123,8 @@ export class SummaryTreeUploadManager implements ISummaryUploadManager {
122
123
  /** Previous snapshot, subtree relative to this path part */
123
124
  previousSnapshot: ISnapshotTreeEx,
124
125
  ): string {
126
+ assert(path.length > 0, 0x0b3 /* "Expected at least 1 path part" */);
125
127
  const key = path[0];
126
- assert(path.length > 0 && key !== undefined, 0x0b3 /* "Expected at least 1 path part" */);
127
128
  if (path.length === 1) {
128
129
  switch (handleType) {
129
130
  case SummaryType.Blob: {
@@ -146,7 +147,6 @@ export class SummaryTreeUploadManager implements ISummaryUploadManager {
146
147
  throw Error(`Unexpected handle summary object type: "${handleType}".`);
147
148
  }
148
149
  }
149
- // TODO why are we non null asserting here?
150
- return this.getIdFromPathCore(handleType, path.slice(1), previousSnapshot.trees[key]!);
150
+ return this.getIdFromPathCore(handleType, path.slice(1), previousSnapshot.trees[key]);
151
151
  }
152
152
  }
package/src/urlUtils.ts CHANGED
@@ -20,13 +20,11 @@ export const getDiscoveredFluidResolvedUrl = (
20
20
  session: ISession,
21
21
  ): IResolvedUrl => {
22
22
  const discoveredOrdererUrl = new URL(session.ordererUrl);
23
- // TODO why are we non null asserting here?
24
- const deltaStorageUrl = new URL(resolvedUrl.endpoints.deltaStorageUrl!);
23
+ const deltaStorageUrl = new URL(resolvedUrl.endpoints.deltaStorageUrl);
25
24
  deltaStorageUrl.host = discoveredOrdererUrl.host;
26
25
 
27
26
  const discoveredStorageUrl = new URL(session.historianUrl);
28
- // TODO why are we non null asserting here?
29
- const storageUrl = new URL(resolvedUrl.endpoints.storageUrl!);
27
+ const storageUrl = new URL(resolvedUrl.endpoints.storageUrl);
30
28
  storageUrl.host = discoveredStorageUrl.host;
31
29
 
32
30
  const parsedUrl = new URL(resolvedUrl.url);
@@ -161,14 +161,13 @@ export class WholeSummaryDocumentStorageService implements IDocumentStorageServi
161
161
  // eslint-disable-next-line @rushstack/no-new-null
162
162
  public async getSnapshotTree(version?: IVersion): Promise<ISnapshotTree | null> {
163
163
  let requestVersion = version;
164
- if (requestVersion === undefined) {
164
+ if (!requestVersion) {
165
165
  const versions = await this.getVersions(this.id, 1);
166
- const firstVersion = versions[0];
167
- if (firstVersion === undefined) {
166
+ if (versions.length === 0) {
168
167
  return null;
169
168
  }
170
169
 
171
- requestVersion = firstVersion;
170
+ requestVersion = versions[0];
172
171
  }
173
172
 
174
173
  let normalizedWholeSnapshot = await this.snapshotTreeCache.get(
package/tsconfig.json CHANGED
@@ -6,5 +6,6 @@
6
6
  "rootDir": "./src",
7
7
  "outDir": "./lib",
8
8
  "exactOptionalPropertyTypes": false,
9
+ "noUncheckedIndexedAccess": false,
9
10
  },
10
11
  }