@fluidframework/routerlicious-driver 2.0.0-dev.2.3.0.115467 → 2.0.0-dev.4.1.0.148229

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 (170) hide show
  1. package/.eslintrc.js +10 -12
  2. package/.mocharc.js +2 -2
  3. package/README.md +1 -1
  4. package/api-extractor.json +2 -2
  5. package/dist/cache.d.ts +3 -0
  6. package/dist/cache.d.ts.map +1 -1
  7. package/dist/cache.js +6 -4
  8. package/dist/cache.js.map +1 -1
  9. package/dist/createNewUtils.d.ts.map +1 -1
  10. package/dist/createNewUtils.js +4 -2
  11. package/dist/createNewUtils.js.map +1 -1
  12. package/dist/defaultTokenProvider.d.ts.map +1 -1
  13. package/dist/defaultTokenProvider.js.map +1 -1
  14. package/dist/definitions.d.ts.map +1 -1
  15. package/dist/definitions.js.map +1 -1
  16. package/dist/deltaStorageService.d.ts.map +1 -1
  17. package/dist/deltaStorageService.js +4 -1
  18. package/dist/deltaStorageService.js.map +1 -1
  19. package/dist/documentDeltaConnection.d.ts.map +1 -1
  20. package/dist/documentDeltaConnection.js.map +1 -1
  21. package/dist/documentService.d.ts +4 -2
  22. package/dist/documentService.d.ts.map +1 -1
  23. package/dist/documentService.js +28 -41
  24. package/dist/documentService.js.map +1 -1
  25. package/dist/documentServiceFactory.d.ts +0 -1
  26. package/dist/documentServiceFactory.d.ts.map +1 -1
  27. package/dist/documentServiceFactory.js +26 -13
  28. package/dist/documentServiceFactory.js.map +1 -1
  29. package/dist/documentStorageService.d.ts +1 -1
  30. package/dist/documentStorageService.d.ts.map +1 -1
  31. package/dist/documentStorageService.js +8 -6
  32. package/dist/documentStorageService.js.map +1 -1
  33. package/dist/errorUtils.d.ts +11 -3
  34. package/dist/errorUtils.d.ts.map +1 -1
  35. package/dist/errorUtils.js +19 -6
  36. package/dist/errorUtils.js.map +1 -1
  37. package/dist/index.d.ts +2 -1
  38. package/dist/index.d.ts.map +1 -1
  39. package/dist/index.js +4 -1
  40. package/dist/index.js.map +1 -1
  41. package/dist/mapWithExpiration.d.ts +34 -0
  42. package/dist/mapWithExpiration.d.ts.map +1 -0
  43. package/dist/mapWithExpiration.js +105 -0
  44. package/dist/mapWithExpiration.js.map +1 -0
  45. package/dist/nullBlobStorageService.d.ts.map +1 -1
  46. package/dist/nullBlobStorageService.js.map +1 -1
  47. package/dist/packageVersion.d.ts +1 -1
  48. package/dist/packageVersion.js +1 -1
  49. package/dist/packageVersion.js.map +1 -1
  50. package/dist/policies.d.ts.map +1 -1
  51. package/dist/policies.js.map +1 -1
  52. package/dist/restWrapper.d.ts +8 -5
  53. package/dist/restWrapper.d.ts.map +1 -1
  54. package/dist/restWrapper.js +38 -44
  55. package/dist/restWrapper.js.map +1 -1
  56. package/dist/retriableGitManager.d.ts.map +1 -1
  57. package/dist/retriableGitManager.js.map +1 -1
  58. package/dist/shreddedSummaryDocumentStorageService.d.ts +1 -1
  59. package/dist/shreddedSummaryDocumentStorageService.d.ts.map +1 -1
  60. package/dist/shreddedSummaryDocumentStorageService.js +9 -5
  61. package/dist/shreddedSummaryDocumentStorageService.js.map +1 -1
  62. package/dist/tokens.d.ts +24 -7
  63. package/dist/tokens.d.ts.map +1 -1
  64. package/dist/tokens.js.map +1 -1
  65. package/dist/treeUtils.d.ts +51 -0
  66. package/dist/treeUtils.d.ts.map +1 -0
  67. package/dist/treeUtils.js +85 -0
  68. package/dist/treeUtils.js.map +1 -0
  69. package/dist/urlUtils.d.ts.map +1 -1
  70. package/dist/urlUtils.js.map +1 -1
  71. package/dist/wholeSummaryDocumentStorageService.d.ts +1 -1
  72. package/dist/wholeSummaryDocumentStorageService.d.ts.map +1 -1
  73. package/dist/wholeSummaryDocumentStorageService.js +30 -17
  74. package/dist/wholeSummaryDocumentStorageService.js.map +1 -1
  75. package/lib/cache.d.ts +3 -0
  76. package/lib/cache.d.ts.map +1 -1
  77. package/lib/cache.js +6 -4
  78. package/lib/cache.js.map +1 -1
  79. package/lib/createNewUtils.d.ts.map +1 -1
  80. package/lib/createNewUtils.js +4 -2
  81. package/lib/createNewUtils.js.map +1 -1
  82. package/lib/defaultTokenProvider.d.ts.map +1 -1
  83. package/lib/defaultTokenProvider.js.map +1 -1
  84. package/lib/definitions.d.ts.map +1 -1
  85. package/lib/definitions.js.map +1 -1
  86. package/lib/deltaStorageService.d.ts.map +1 -1
  87. package/lib/deltaStorageService.js +4 -1
  88. package/lib/deltaStorageService.js.map +1 -1
  89. package/lib/documentDeltaConnection.d.ts.map +1 -1
  90. package/lib/documentDeltaConnection.js.map +1 -1
  91. package/lib/documentService.d.ts +4 -2
  92. package/lib/documentService.d.ts.map +1 -1
  93. package/lib/documentService.js +30 -24
  94. package/lib/documentService.js.map +1 -1
  95. package/lib/documentServiceFactory.d.ts +0 -1
  96. package/lib/documentServiceFactory.d.ts.map +1 -1
  97. package/lib/documentServiceFactory.js +27 -14
  98. package/lib/documentServiceFactory.js.map +1 -1
  99. package/lib/documentStorageService.d.ts +1 -1
  100. package/lib/documentStorageService.d.ts.map +1 -1
  101. package/lib/documentStorageService.js +9 -7
  102. package/lib/documentStorageService.js.map +1 -1
  103. package/lib/errorUtils.d.ts +11 -3
  104. package/lib/errorUtils.d.ts.map +1 -1
  105. package/lib/errorUtils.js +18 -5
  106. package/lib/errorUtils.js.map +1 -1
  107. package/lib/index.d.ts +2 -1
  108. package/lib/index.d.ts.map +1 -1
  109. package/lib/index.js +3 -1
  110. package/lib/index.js.map +1 -1
  111. package/lib/mapWithExpiration.d.ts +34 -0
  112. package/lib/mapWithExpiration.d.ts.map +1 -0
  113. package/lib/mapWithExpiration.js +101 -0
  114. package/lib/mapWithExpiration.js.map +1 -0
  115. package/lib/nullBlobStorageService.d.ts.map +1 -1
  116. package/lib/nullBlobStorageService.js.map +1 -1
  117. package/lib/packageVersion.d.ts +1 -1
  118. package/lib/packageVersion.js +1 -1
  119. package/lib/packageVersion.js.map +1 -1
  120. package/lib/policies.d.ts.map +1 -1
  121. package/lib/policies.js.map +1 -1
  122. package/lib/restWrapper.d.ts +8 -5
  123. package/lib/restWrapper.d.ts.map +1 -1
  124. package/lib/restWrapper.js +38 -44
  125. package/lib/restWrapper.js.map +1 -1
  126. package/lib/retriableGitManager.d.ts.map +1 -1
  127. package/lib/retriableGitManager.js.map +1 -1
  128. package/lib/shreddedSummaryDocumentStorageService.d.ts +1 -1
  129. package/lib/shreddedSummaryDocumentStorageService.d.ts.map +1 -1
  130. package/lib/shreddedSummaryDocumentStorageService.js +10 -6
  131. package/lib/shreddedSummaryDocumentStorageService.js.map +1 -1
  132. package/lib/tokens.d.ts +24 -7
  133. package/lib/tokens.d.ts.map +1 -1
  134. package/lib/tokens.js.map +1 -1
  135. package/lib/treeUtils.d.ts +51 -0
  136. package/lib/treeUtils.d.ts.map +1 -0
  137. package/lib/treeUtils.js +80 -0
  138. package/lib/treeUtils.js.map +1 -0
  139. package/lib/urlUtils.d.ts.map +1 -1
  140. package/lib/urlUtils.js.map +1 -1
  141. package/lib/wholeSummaryDocumentStorageService.d.ts +1 -1
  142. package/lib/wholeSummaryDocumentStorageService.d.ts.map +1 -1
  143. package/lib/wholeSummaryDocumentStorageService.js +30 -17
  144. package/lib/wholeSummaryDocumentStorageService.js.map +1 -1
  145. package/package.json +55 -52
  146. package/prettier.config.cjs +1 -1
  147. package/src/cache.ts +21 -14
  148. package/src/createNewUtils.ts +24 -22
  149. package/src/defaultTokenProvider.ts +13 -15
  150. package/src/definitions.ts +2 -2
  151. package/src/deltaStorageService.ts +99 -95
  152. package/src/documentDeltaConnection.ts +53 -47
  153. package/src/documentService.ts +260 -241
  154. package/src/documentServiceFactory.ts +268 -237
  155. package/src/documentStorageService.ts +87 -83
  156. package/src/errorUtils.ts +91 -76
  157. package/src/index.ts +7 -1
  158. package/src/mapWithExpiration.ts +124 -0
  159. package/src/nullBlobStorageService.ts +24 -21
  160. package/src/packageVersion.ts +1 -1
  161. package/src/policies.ts +44 -44
  162. package/src/restWrapper.ts +270 -208
  163. package/src/retriableGitManager.ts +152 -151
  164. package/src/shreddedSummaryDocumentStorageService.ts +202 -194
  165. package/src/tokens.ts +69 -44
  166. package/src/treeUtils.ts +107 -0
  167. package/src/urlUtils.ts +26 -23
  168. package/src/wholeSummaryDocumentStorageService.ts +248 -228
  169. package/tsconfig.esnext.json +6 -6
  170. package/tsconfig.json +9 -13
@@ -4,27 +4,24 @@
4
4
  */
5
5
 
6
6
  import type { ITelemetryLogger } from "@fluidframework/common-definitions";
7
+ import { stringToBuffer, Uint8ArrayToString } from "@fluidframework/common-utils";
7
8
  import {
8
- stringToBuffer,
9
- Uint8ArrayToString,
10
- } from "@fluidframework/common-utils";
11
- import {
12
- IDocumentStorageService,
13
- ISummaryContext,
14
- IDocumentStorageServicePolicies,
9
+ IDocumentStorageService,
10
+ ISummaryContext,
11
+ IDocumentStorageServicePolicies,
15
12
  } from "@fluidframework/driver-definitions";
16
13
  import { buildHierarchy } from "@fluidframework/protocol-base";
17
14
  import {
18
- ICreateBlobResponse,
19
- ISnapshotTreeEx,
20
- ISummaryHandle,
21
- ISummaryTree,
22
- IVersion,
15
+ ICreateBlobResponse,
16
+ ISnapshotTreeEx,
17
+ ISummaryHandle,
18
+ ISummaryTree,
19
+ IVersion,
23
20
  } from "@fluidframework/protocol-definitions";
24
21
  import {
25
- GitManager,
26
- ISummaryUploadManager,
27
- SummaryTreeUploadManager,
22
+ GitManager,
23
+ ISummaryUploadManager,
24
+ SummaryTreeUploadManager,
28
25
  } from "@fluidframework/server-services-client";
29
26
  import { PerformanceEvent } from "@fluidframework/telemetry-utils";
30
27
  import { IRouterliciousDriverPolicies } from "./policies";
@@ -40,183 +37,194 @@ const isNode = typeof window === "undefined";
40
37
  * Downloads summaries piece-by-piece on-demand, or up-front when prefetch is enabled.
41
38
  */
42
39
  export class ShreddedSummaryDocumentStorageService implements IDocumentStorageService {
43
- // The values of this cache is useless. We only need the keys. So we are always putting
44
- // empty strings as values.
45
- protected readonly blobsShaCache = new Map<string, string>();
46
- private readonly blobCache: ICache<ArrayBufferLike> | undefined;
47
- private readonly snapshotTreeCache: ICache<ISnapshotTreeVersion> | undefined;
48
-
49
- public get repositoryUrl(): string {
50
- return "";
51
- }
52
-
53
- private async getSummaryUploadManager(): Promise<ISummaryUploadManager> {
54
- const manager = await this.getStorageManager();
55
- return new SummaryTreeUploadManager(
56
- new RetriableGitManager(manager, this.logger),
57
- this.blobsShaCache,
58
- this.getPreviousFullSnapshot.bind(this),
59
- );
60
- }
61
-
62
- constructor(
63
- protected readonly id: string,
64
- protected readonly manager: GitManager,
65
- protected readonly logger: ITelemetryLogger,
66
- public readonly policies: IDocumentStorageServicePolicies = {},
67
- driverPolicies?: IRouterliciousDriverPolicies,
68
- blobCache?: ICache<ArrayBufferLike>,
69
- snapshotTreeCache?: ICache<ISnapshotTreeVersion>,
70
- private readonly getStorageManager: (disableCache?: boolean) => Promise<GitManager> = async () => this.manager,
71
- ) {
72
- if (driverPolicies?.enableRestLess === true || isNode) {
73
- this.blobCache = blobCache ?? new InMemoryCache();
74
- this.snapshotTreeCache = snapshotTreeCache ?? new InMemoryCache();
75
- }
76
- }
77
-
78
- public async getVersions(versionId: string | null, count: number): Promise<IVersion[]> {
79
- const id = versionId ? versionId : this.id;
80
- const commits = await PerformanceEvent.timedExecAsync(
81
- this.logger,
82
- {
83
- eventName: "getVersions",
84
- versionId: id,
85
- count,
86
- },
87
- async () => {
88
- const manager = await this.getStorageManager();
89
- return manager.getCommits(id, count);
90
- },
91
- );
92
- return commits.map((commit) => ({
93
- date: commit.commit.author.date,
94
- id: commit.sha,
95
- treeId: commit.commit.tree.sha,
96
- }));
97
- }
98
-
99
- public async getSnapshotTree(version?: IVersion): Promise<ISnapshotTreeEx | null> {
100
- let requestVersion = version;
101
- if (!requestVersion) {
102
- const versions = await this.getVersions(this.id, 1);
103
- if (versions.length === 0) {
104
- return null;
105
- }
106
-
107
- requestVersion = versions[0];
108
- }
109
-
110
- const cachedSnapshotTree = await this.snapshotTreeCache?.get(this.getCacheKey(requestVersion.treeId));
111
- if (cachedSnapshotTree) {
112
- return cachedSnapshotTree.snapshotTree as ISnapshotTreeEx;
113
- }
114
-
115
- const rawTree = await PerformanceEvent.timedExecAsync(
116
- this.logger,
117
- {
118
- eventName: "getSnapshotTree",
119
- treeId: requestVersion.treeId,
120
- },
121
- async (event) => {
122
- const manager = await this.getStorageManager();
123
- const response = await manager.getTree(requestVersion!.treeId);
124
- event.end({
125
- size: response.tree.length,
126
- });
127
- return response;
128
- },
129
- );
130
- const tree = buildHierarchy(rawTree, this.blobsShaCache, true);
131
- await this.snapshotTreeCache?.put(
132
- this.getCacheKey(tree.id),
133
- { id: requestVersion.id, snapshotTree: tree },
134
- );
135
- return tree;
136
- }
137
-
138
- public async readBlob(blobId: string): Promise<ArrayBufferLike> {
139
- const cachedBlob = await this.blobCache?.get(this.getCacheKey(blobId));
140
- if (cachedBlob) {
141
- return cachedBlob;
142
- }
143
-
144
- const value = await PerformanceEvent.timedExecAsync(
145
- this.logger,
146
- {
147
- eventName: "readBlob",
148
- blobId,
149
- },
150
- async (event) => {
151
- const manager = await this.getStorageManager();
152
- const response = await manager.getBlob(blobId);
153
- event.end({
154
- size: response.size,
155
- });
156
- return response;
157
- },
158
- );
159
- this.blobsShaCache.set(value.sha, "");
160
- const bufferContent = stringToBuffer(value.content, value.encoding);
161
- await this.blobCache?.put(this.getCacheKey(value.sha), bufferContent);
162
- return bufferContent;
163
- }
164
-
165
- public async uploadSummaryWithContext(summary: ISummaryTree, context: ISummaryContext): Promise<string> {
166
- const summaryHandle = await PerformanceEvent.timedExecAsync(
167
- this.logger,
168
- {
169
- eventName: "uploadSummaryWithContext",
170
- proposalHandle: context.proposalHandle,
171
- ackHandle: context.ackHandle,
172
- referenceSequenceNumber: context.referenceSequenceNumber,
173
- },
174
- async () => {
175
- const summaryUploadManager = await this.getSummaryUploadManager();
176
- return summaryUploadManager.writeSummaryTree(summary, context.ackHandle ?? "", "channel");
177
- },
178
- );
179
- return summaryHandle;
180
- }
181
-
182
- public async downloadSummary(handle: ISummaryHandle): Promise<ISummaryTree> {
183
- throw new Error("NOT IMPLEMENTED!");
184
- }
185
-
186
- public async createBlob(file: ArrayBufferLike): Promise<ICreateBlobResponse> {
187
- const uint8ArrayFile = new Uint8Array(file);
188
- return PerformanceEvent.timedExecAsync(
189
- this.logger,
190
- {
191
- eventName: "createBlob",
192
- size: uint8ArrayFile.length,
193
- },
194
- async (event) => {
195
- const manager = await this.getStorageManager();
196
- const response = await manager.createBlob(
197
- Uint8ArrayToString(
198
- uint8ArrayFile, "base64"),
199
- "base64").then((r) => ({ id: r.sha, url: r.url }));
200
- event.end({
201
- blobId: response.id,
202
- });
203
- return response;
204
- },
205
- );
206
- }
207
-
208
- private async getPreviousFullSnapshot(parentHandle: string): Promise<ISnapshotTreeEx | null | undefined> {
209
- return parentHandle
210
- ? this.getVersions(parentHandle, 1)
211
- .then(async (versions) => {
212
- // Clear the cache as the getSnapshotTree call will fill the cache.
213
- this.blobsShaCache.clear();
214
- return this.getSnapshotTree(versions[0]);
215
- })
216
- : undefined;
217
- }
218
-
219
- private getCacheKey(blobId: string): string {
220
- return `${this.id}:${blobId}`;
221
- }
40
+ // The values of this cache is useless. We only need the keys. So we are always putting
41
+ // empty strings as values.
42
+ protected readonly blobsShaCache = new Map<string, string>();
43
+ private readonly blobCache: ICache<ArrayBufferLike> | undefined;
44
+ private readonly snapshotTreeCache: ICache<ISnapshotTreeVersion> | undefined;
45
+
46
+ public get repositoryUrl(): string {
47
+ return "";
48
+ }
49
+
50
+ private async getSummaryUploadManager(): Promise<ISummaryUploadManager> {
51
+ const manager = await this.getStorageManager();
52
+ return new SummaryTreeUploadManager(
53
+ new RetriableGitManager(manager, this.logger),
54
+ this.blobsShaCache,
55
+ this.getPreviousFullSnapshot.bind(this),
56
+ );
57
+ }
58
+
59
+ constructor(
60
+ protected readonly id: string,
61
+ protected readonly manager: GitManager,
62
+ protected readonly logger: ITelemetryLogger,
63
+ public readonly policies: IDocumentStorageServicePolicies,
64
+ driverPolicies?: IRouterliciousDriverPolicies,
65
+ blobCache?: ICache<ArrayBufferLike>,
66
+ snapshotTreeCache?: ICache<ISnapshotTreeVersion>,
67
+ private readonly getStorageManager: (
68
+ disableCache?: boolean,
69
+ ) => Promise<GitManager> = async () => this.manager,
70
+ ) {
71
+ if (driverPolicies?.enableRestLess === true || isNode) {
72
+ this.blobCache = blobCache ?? new InMemoryCache();
73
+ this.snapshotTreeCache = snapshotTreeCache ?? new InMemoryCache();
74
+ }
75
+ }
76
+
77
+ public async getVersions(versionId: string | null, count: number): Promise<IVersion[]> {
78
+ const id = versionId ? versionId : this.id;
79
+ const commits = await PerformanceEvent.timedExecAsync(
80
+ this.logger,
81
+ {
82
+ eventName: "getVersions",
83
+ versionId: id,
84
+ count,
85
+ },
86
+ async () => {
87
+ const manager = await this.getStorageManager();
88
+ return manager.getCommits(id, count);
89
+ },
90
+ );
91
+ return commits.map((commit) => ({
92
+ date: commit.commit.author.date,
93
+ id: commit.sha,
94
+ treeId: commit.commit.tree.sha,
95
+ }));
96
+ }
97
+
98
+ public async getSnapshotTree(version?: IVersion): Promise<ISnapshotTreeEx | null> {
99
+ let requestVersion = version;
100
+ if (!requestVersion) {
101
+ const versions = await this.getVersions(this.id, 1);
102
+ if (versions.length === 0) {
103
+ return null;
104
+ }
105
+
106
+ requestVersion = versions[0];
107
+ }
108
+
109
+ const cachedSnapshotTree = await this.snapshotTreeCache?.get(
110
+ this.getCacheKey(requestVersion.treeId),
111
+ );
112
+ if (cachedSnapshotTree) {
113
+ return cachedSnapshotTree.snapshotTree as ISnapshotTreeEx;
114
+ }
115
+
116
+ const rawTree = await PerformanceEvent.timedExecAsync(
117
+ this.logger,
118
+ {
119
+ eventName: "getSnapshotTree",
120
+ treeId: requestVersion.treeId,
121
+ },
122
+ async (event) => {
123
+ const manager = await this.getStorageManager();
124
+ const response = await manager.getTree(requestVersion!.treeId);
125
+ event.end({
126
+ size: response.tree.length,
127
+ });
128
+ return response;
129
+ },
130
+ );
131
+ const tree = buildHierarchy(rawTree, this.blobsShaCache, true);
132
+ await this.snapshotTreeCache?.put(this.getCacheKey(tree.id), {
133
+ id: requestVersion.id,
134
+ snapshotTree: tree,
135
+ });
136
+ return tree;
137
+ }
138
+
139
+ public async readBlob(blobId: string): Promise<ArrayBufferLike> {
140
+ const cachedBlob = await this.blobCache?.get(this.getCacheKey(blobId));
141
+ if (cachedBlob) {
142
+ return cachedBlob;
143
+ }
144
+
145
+ const value = await PerformanceEvent.timedExecAsync(
146
+ this.logger,
147
+ {
148
+ eventName: "readBlob",
149
+ blobId,
150
+ },
151
+ async (event) => {
152
+ const manager = await this.getStorageManager();
153
+ const response = await manager.getBlob(blobId);
154
+ event.end({
155
+ size: response.size,
156
+ });
157
+ return response;
158
+ },
159
+ );
160
+ this.blobsShaCache.set(value.sha, "");
161
+ const bufferContent = stringToBuffer(value.content, value.encoding);
162
+ await this.blobCache?.put(this.getCacheKey(value.sha), bufferContent);
163
+ return bufferContent;
164
+ }
165
+
166
+ public async uploadSummaryWithContext(
167
+ summary: ISummaryTree,
168
+ context: ISummaryContext,
169
+ ): Promise<string> {
170
+ const summaryHandle = await PerformanceEvent.timedExecAsync(
171
+ this.logger,
172
+ {
173
+ eventName: "uploadSummaryWithContext",
174
+ proposalHandle: context.proposalHandle,
175
+ ackHandle: context.ackHandle,
176
+ referenceSequenceNumber: context.referenceSequenceNumber,
177
+ },
178
+ async () => {
179
+ const summaryUploadManager = await this.getSummaryUploadManager();
180
+ return summaryUploadManager.writeSummaryTree(
181
+ summary,
182
+ context.ackHandle ?? "",
183
+ "channel",
184
+ );
185
+ },
186
+ );
187
+ return summaryHandle;
188
+ }
189
+
190
+ public async downloadSummary(handle: ISummaryHandle): Promise<ISummaryTree> {
191
+ throw new Error("NOT IMPLEMENTED!");
192
+ }
193
+
194
+ public async createBlob(file: ArrayBufferLike): Promise<ICreateBlobResponse> {
195
+ const uint8ArrayFile = new Uint8Array(file);
196
+ return PerformanceEvent.timedExecAsync(
197
+ this.logger,
198
+ {
199
+ eventName: "createBlob",
200
+ size: uint8ArrayFile.length,
201
+ },
202
+ async (event) => {
203
+ const manager = await this.getStorageManager();
204
+ const response = await manager
205
+ .createBlob(Uint8ArrayToString(uint8ArrayFile, "base64"), "base64")
206
+ .then((r) => ({ id: r.sha, url: r.url }));
207
+ event.end({
208
+ blobId: response.id,
209
+ });
210
+ return response;
211
+ },
212
+ );
213
+ }
214
+
215
+ private async getPreviousFullSnapshot(
216
+ parentHandle: string,
217
+ ): Promise<ISnapshotTreeEx | null | undefined> {
218
+ return parentHandle
219
+ ? this.getVersions(parentHandle, 1).then(async (versions) => {
220
+ // Clear the cache as the getSnapshotTree call will fill the cache.
221
+ this.blobsShaCache.clear();
222
+ return this.getSnapshotTree(versions[0]);
223
+ })
224
+ : undefined;
225
+ }
226
+
227
+ private getCacheKey(blobId: string): string {
228
+ return `${this.id}:${blobId}`;
229
+ }
222
230
  }
package/src/tokens.ts CHANGED
@@ -6,23 +6,28 @@
6
6
  import { ITokenClaims } from "@fluidframework/protocol-definitions";
7
7
 
8
8
  /**
9
- * The ITokenService abstracts the discovery of claims contained within a token
9
+ * Abstracts the discovery of claims contained within a token.
10
10
  */
11
11
  export interface ITokenService {
12
- extractClaims(token: string): ITokenClaims;
12
+ /**
13
+ * Extracts the {@link @fluidframework/protocol-definitions#ITokenClaims | token claims} from the provided
14
+ * {@link https://jwt.io/introduction/ | JSON Web Token (JWT)} string representation.
15
+ */
16
+ extractClaims(token: string): ITokenClaims;
13
17
  }
14
18
 
15
19
  export interface ITokenResponse {
16
- /**
17
- * {@link https://jwt.io/introduction/ | JSON Web Token (JWT)} value.
18
- */
19
- jwt: string;
20
+ /**
21
+ * {@link https://jwt.io/introduction/ | JSON Web Token (JWT)} value.
22
+ */
23
+ jwt: string;
20
24
 
21
- /**
22
- * Flag indicating whether token was obtained from local cache.
23
- * Undefined indicates that the source of the token could not be determined.
24
- */
25
- fromCache?: boolean;
25
+ /**
26
+ * A flag indicating whether token was obtained from local cache.
27
+ *
28
+ * @remarks `undefined` indicates that the source of the token could not be determined.
29
+ */
30
+ fromCache?: boolean;
26
31
  }
27
32
 
28
33
  /**
@@ -30,39 +35,59 @@ export interface ITokenResponse {
30
35
  * The hosting application is responsible for providing an implementation.
31
36
  */
32
37
  export interface ITokenProvider {
33
- /**
34
- * Fetches the orderer token from host.
35
- * @param tenantId - Tenant ID.
36
- * @param documentId - Optional. Document ID is only required for document-scoped requests.
37
- * @param refresh - Optional flag indicating whether token fetch must bypass local cache.
38
- * @returns TokenResponse object representing token value along with flag indicating
39
- * whether token came from cache.
40
- */
41
- fetchOrdererToken(tenantId: string, documentId?: string, refresh?: boolean): Promise<ITokenResponse>;
38
+ /**
39
+ * Fetches the orderer token from host.
40
+ *
41
+ * @param tenantId - Tenant ID.
42
+ * @param documentId - Optional. Document ID is only required for document-scoped requests.
43
+ * @param refresh - Optional flag indicating whether token fetch must bypass local cache.
44
+ * This likely indicates that some previous request failed authorization due to an expired token,
45
+ * and so a fresh token is required.
46
+ *
47
+ * Default: `false`.
48
+ *
49
+ * NOTE: This parameter will be made required in the future.
50
+ */
51
+ fetchOrdererToken(
52
+ tenantId: string,
53
+ documentId?: string,
54
+ refresh?: boolean,
55
+ ): Promise<ITokenResponse>;
42
56
 
43
- /**
44
- * Fetches the storage token from host.
45
- * @param tenantId - Tenant ID.
46
- * @param documentId - Document ID.
47
- * @param refresh - Optional flag indicating whether token fetch must bypass local cache.
48
- * @returns TokenResponse object representing token value along with flag indicating
49
- * whether token came from cache.
50
- */
51
- fetchStorageToken(tenantId: string, documentId: string, refresh?: boolean): Promise<ITokenResponse>;
57
+ /**
58
+ * Fetches the storage token from host.
59
+ *
60
+ * @param tenantId - Tenant ID.
61
+ * @param documentId - Document ID.
62
+ * @param refresh - Optional flag indicating whether token fetch must bypass local cache.
63
+ * This likely indicates that some previous request failed authorization due to an expired token,
64
+ * and so a fresh token is required.
65
+ *
66
+ * Default: `false`.
67
+ *
68
+ * NOTE: This parameter will be made required in the future.
69
+ */
70
+ fetchStorageToken(
71
+ tenantId: string,
72
+ documentId: string,
73
+ refresh?: boolean,
74
+ ): Promise<ITokenResponse>;
52
75
 
53
- /**
54
- * A callback triggered directly after creating the document. In this callback the client has the opportunity, to
55
- * verify against an authorization service, if the user who claims to create the document is the same user who
56
- * created it.
57
- *
58
- * @remarks Notes:
59
- * * Using the callback may have performance impact on the document creation process.
60
- * * Any exceptions thrown in the callback would fail the creation workflow
61
- * (see {@link RouterliciousDocumentServiceFactory.createContainer} for more details).
62
- *
63
- * @param documentId - Document ID.
64
- * @param creationToken - A special token that doesn't provide any kind of access, but it has the user's payload
65
- * and document id. It can be used to validate the identity of the document creator.
66
- */
67
- documentPostCreateCallback?(documentId: string, creationToken: string): Promise<void>;
76
+ /**
77
+ * A callback triggered directly after creating the document. In this callback the client has the opportunity, to
78
+ * verify against an authorization service, if the user who claims to create the document is the same user who
79
+ * created it.
80
+ *
81
+ * @remarks Notes:
82
+ *
83
+ * * Using the callback may have performance impact on the document creation process.
84
+ *
85
+ * * Any exceptions thrown in the callback would fail the creation workflow
86
+ * (see {@link RouterliciousDocumentServiceFactory.createContainer} for more details).
87
+ *
88
+ * @param documentId - Document ID.
89
+ * @param creationToken - A special token that doesn't provide any kind of access, but it has the user's payload
90
+ * and document id. It can be used to validate the identity of the document creator.
91
+ */
92
+ documentPostCreateCallback?(documentId: string, creationToken: string): Promise<void>;
68
93
  }
@@ -0,0 +1,107 @@
1
+ /*!
2
+ * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
+ * Licensed under the MIT License.
4
+ */
5
+
6
+ import { assert, IsoBuffer } from "@fluidframework/common-utils";
7
+ import {
8
+ SummaryType,
9
+ ISnapshotTree,
10
+ ISummaryTree,
11
+ SummaryObject,
12
+ } from "@fluidframework/protocol-definitions";
13
+
14
+ /**
15
+ * Summary tree assembler props
16
+ */
17
+ export interface ISummaryTreeAssemblerProps {
18
+ /**
19
+ * Indicates that this tree is unreferenced. If this is not present, the tree is considered referenced.
20
+ */
21
+ unreferenced?: true;
22
+ }
23
+
24
+ /**
25
+ * Summary tree assembler (without stats collection).
26
+ */
27
+ export class SummaryTreeAssembler {
28
+ private attachmentCounter: number = 0;
29
+ private readonly summaryTree: { [path: string]: SummaryObject } = {};
30
+
31
+ constructor(private readonly props?: ISummaryTreeAssemblerProps) {}
32
+
33
+ /**
34
+ * Get final summary
35
+ */
36
+ public get summary(): ISummaryTree {
37
+ return {
38
+ type: SummaryType.Tree,
39
+ tree: { ...this.summaryTree },
40
+ unreferenced: this.props?.unreferenced,
41
+ };
42
+ }
43
+
44
+ /**
45
+ * Add blob to summary
46
+ */
47
+ public addBlob(key: string, content: string | Uint8Array): void {
48
+ this.summaryTree[key] = {
49
+ type: SummaryType.Blob,
50
+ content,
51
+ };
52
+ }
53
+
54
+ /**
55
+ * Add handle to summary
56
+ */
57
+ public addHandle(
58
+ key: string,
59
+ handleType: SummaryType.Tree | SummaryType.Blob | SummaryType.Attachment,
60
+ handle: string,
61
+ ): void {
62
+ this.summaryTree[key] = {
63
+ type: SummaryType.Handle,
64
+ handleType,
65
+ handle,
66
+ };
67
+ }
68
+
69
+ /**
70
+ * Add tree to summary
71
+ */
72
+ public addTree(key: string, summary: ISummaryTree): void {
73
+ this.summaryTree[key] = summary;
74
+ }
75
+
76
+ /**
77
+ * Add attachment to summary
78
+ */
79
+ public addAttachment(id: string) {
80
+ this.summaryTree[this.attachmentCounter++] = { id, type: SummaryType.Attachment };
81
+ }
82
+ }
83
+
84
+ /**
85
+ * Helper function that converts ISnapshotTree and blobs to ISummaryTree
86
+ * @param snapshot - Source snapshot tree
87
+ * @param blobs - Blobs cache
88
+ * @returns Converted snapshot in ISummaryTree format
89
+ */
90
+ export function convertSnapshotAndBlobsToSummaryTree(
91
+ snapshot: ISnapshotTree,
92
+ blobs: Map<string, ArrayBuffer>,
93
+ ): ISummaryTree {
94
+ const assembler = new SummaryTreeAssembler({
95
+ unreferenced: snapshot.unreferenced,
96
+ });
97
+ for (const [path, id] of Object.entries(snapshot.blobs)) {
98
+ const blob = blobs.get(id);
99
+ assert(blob !== undefined, 0x2dd /* "Cannot find blob for a given id" */);
100
+ assembler.addBlob(path, IsoBuffer.from(blob).toString("utf-8"));
101
+ }
102
+ for (const [key, tree] of Object.entries(snapshot.trees)) {
103
+ const subtree = convertSnapshotAndBlobsToSummaryTree(tree, blobs);
104
+ assembler.addTree(key, subtree);
105
+ }
106
+ return assembler.summary;
107
+ }