@fluidframework/runtime-utils 2.0.0-internal.3.0.0 → 2.0.0-internal.3.1.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 (99) hide show
  1. package/.eslintrc.js +5 -7
  2. package/.mocharc.js +2 -2
  3. package/api-extractor.json +2 -2
  4. package/dist/dataStoreHandleContextUtils.d.ts.map +1 -1
  5. package/dist/dataStoreHandleContextUtils.js +3 -1
  6. package/dist/dataStoreHandleContextUtils.js.map +1 -1
  7. package/dist/dataStoreHelpers.d.ts.map +1 -1
  8. package/dist/dataStoreHelpers.js +23 -7
  9. package/dist/dataStoreHelpers.js.map +1 -1
  10. package/dist/index.d.ts +1 -1
  11. package/dist/index.d.ts.map +1 -1
  12. package/dist/index.js.map +1 -1
  13. package/dist/objectstoragepartition.d.ts.map +1 -1
  14. package/dist/objectstoragepartition.js.map +1 -1
  15. package/dist/objectstorageutils.d.ts.map +1 -1
  16. package/dist/objectstorageutils.js.map +1 -1
  17. package/dist/packageVersion.d.ts +1 -1
  18. package/dist/packageVersion.js +1 -1
  19. package/dist/packageVersion.js.map +1 -1
  20. package/dist/requestParser.d.ts.map +1 -1
  21. package/dist/requestParser.js.map +1 -1
  22. package/dist/runtimeFactoryHelper.d.ts.map +1 -1
  23. package/dist/runtimeFactoryHelper.js +6 -2
  24. package/dist/runtimeFactoryHelper.js.map +1 -1
  25. package/dist/summarizerNode/index.d.ts +1 -1
  26. package/dist/summarizerNode/index.d.ts.map +1 -1
  27. package/dist/summarizerNode/index.js.map +1 -1
  28. package/dist/summarizerNode/summarizerNode.d.ts +4 -5
  29. package/dist/summarizerNode/summarizerNode.d.ts.map +1 -1
  30. package/dist/summarizerNode/summarizerNode.js +33 -13
  31. package/dist/summarizerNode/summarizerNode.js.map +1 -1
  32. package/dist/summarizerNode/summarizerNodeUtils.d.ts +14 -5
  33. package/dist/summarizerNode/summarizerNodeUtils.d.ts.map +1 -1
  34. package/dist/summarizerNode/summarizerNodeUtils.js.map +1 -1
  35. package/dist/summarizerNode/summarizerNodeWithGc.d.ts.map +1 -1
  36. package/dist/summarizerNode/summarizerNodeWithGc.js +23 -13
  37. package/dist/summarizerNode/summarizerNodeWithGc.js.map +1 -1
  38. package/dist/summaryUtils.d.ts.map +1 -1
  39. package/dist/summaryUtils.js +3 -2
  40. package/dist/summaryUtils.js.map +1 -1
  41. package/dist/utils.d.ts.map +1 -1
  42. package/dist/utils.js.map +1 -1
  43. package/lib/dataStoreHandleContextUtils.d.ts.map +1 -1
  44. package/lib/dataStoreHandleContextUtils.js +3 -1
  45. package/lib/dataStoreHandleContextUtils.js.map +1 -1
  46. package/lib/dataStoreHelpers.d.ts.map +1 -1
  47. package/lib/dataStoreHelpers.js +23 -7
  48. package/lib/dataStoreHelpers.js.map +1 -1
  49. package/lib/index.d.ts +1 -1
  50. package/lib/index.d.ts.map +1 -1
  51. package/lib/index.js.map +1 -1
  52. package/lib/objectstoragepartition.d.ts.map +1 -1
  53. package/lib/objectstoragepartition.js.map +1 -1
  54. package/lib/objectstorageutils.d.ts.map +1 -1
  55. package/lib/objectstorageutils.js.map +1 -1
  56. package/lib/packageVersion.d.ts +1 -1
  57. package/lib/packageVersion.js +1 -1
  58. package/lib/packageVersion.js.map +1 -1
  59. package/lib/requestParser.d.ts.map +1 -1
  60. package/lib/requestParser.js.map +1 -1
  61. package/lib/runtimeFactoryHelper.d.ts.map +1 -1
  62. package/lib/runtimeFactoryHelper.js +6 -2
  63. package/lib/runtimeFactoryHelper.js.map +1 -1
  64. package/lib/summarizerNode/index.d.ts +1 -1
  65. package/lib/summarizerNode/index.d.ts.map +1 -1
  66. package/lib/summarizerNode/index.js.map +1 -1
  67. package/lib/summarizerNode/summarizerNode.d.ts +4 -5
  68. package/lib/summarizerNode/summarizerNode.d.ts.map +1 -1
  69. package/lib/summarizerNode/summarizerNode.js +33 -13
  70. package/lib/summarizerNode/summarizerNode.js.map +1 -1
  71. package/lib/summarizerNode/summarizerNodeUtils.d.ts +14 -5
  72. package/lib/summarizerNode/summarizerNodeUtils.d.ts.map +1 -1
  73. package/lib/summarizerNode/summarizerNodeUtils.js.map +1 -1
  74. package/lib/summarizerNode/summarizerNodeWithGc.d.ts.map +1 -1
  75. package/lib/summarizerNode/summarizerNodeWithGc.js +24 -14
  76. package/lib/summarizerNode/summarizerNodeWithGc.js.map +1 -1
  77. package/lib/summaryUtils.d.ts.map +1 -1
  78. package/lib/summaryUtils.js +3 -2
  79. package/lib/summaryUtils.js.map +1 -1
  80. package/lib/utils.d.ts.map +1 -1
  81. package/lib/utils.js.map +1 -1
  82. package/package.json +110 -104
  83. package/prettier.config.cjs +1 -1
  84. package/src/dataStoreHandleContextUtils.ts +23 -16
  85. package/src/dataStoreHelpers.ts +104 -86
  86. package/src/index.ts +2 -1
  87. package/src/objectstoragepartition.ts +13 -13
  88. package/src/objectstorageutils.ts +31 -28
  89. package/src/packageVersion.ts +1 -1
  90. package/src/requestParser.ts +80 -82
  91. package/src/runtimeFactoryHelper.ts +24 -17
  92. package/src/summarizerNode/index.ts +5 -1
  93. package/src/summarizerNode/summarizerNode.ts +602 -549
  94. package/src/summarizerNode/summarizerNodeUtils.ts +163 -150
  95. package/src/summarizerNode/summarizerNodeWithGc.ts +508 -470
  96. package/src/summaryUtils.ts +299 -291
  97. package/src/utils.ts +6 -6
  98. package/tsconfig.esnext.json +6 -6
  99. package/tsconfig.json +8 -12
@@ -5,28 +5,28 @@
5
5
 
6
6
  import { TelemetryEventPropertyType } from "@fluidframework/common-definitions";
7
7
  import {
8
- bufferToString,
9
- fromBase64ToUtf8,
10
- IsoBuffer,
11
- Uint8ArrayToString,
12
- unreachableCase,
8
+ bufferToString,
9
+ fromBase64ToUtf8,
10
+ IsoBuffer,
11
+ Uint8ArrayToString,
12
+ unreachableCase,
13
13
  } from "@fluidframework/common-utils";
14
14
  import { AttachmentTreeEntry, BlobTreeEntry, TreeTreeEntry } from "@fluidframework/protocol-base";
15
15
  import {
16
- ITree,
17
- SummaryType,
18
- ISummaryTree,
19
- SummaryObject,
20
- ISummaryBlob,
21
- TreeEntry,
22
- ITreeEntry,
23
- ISnapshotTree,
16
+ ITree,
17
+ SummaryType,
18
+ ISummaryTree,
19
+ SummaryObject,
20
+ ISummaryBlob,
21
+ TreeEntry,
22
+ ITreeEntry,
23
+ ISnapshotTree,
24
24
  } from "@fluidframework/protocol-definitions";
25
25
  import {
26
- ISummaryStats,
27
- ISummarizeResult,
28
- ISummaryTreeWithStats,
29
- ITelemetryContext,
26
+ ISummaryStats,
27
+ ISummarizeResult,
28
+ ISummaryTreeWithStats,
29
+ ITelemetryContext,
30
30
  } from "@fluidframework/runtime-definitions";
31
31
 
32
32
  /**
@@ -35,153 +35,167 @@ import {
35
35
  * @param stats - stats to merge
36
36
  */
37
37
  export function mergeStats(...stats: ISummaryStats[]): ISummaryStats {
38
- const results = {
39
- treeNodeCount: 0,
40
- blobNodeCount: 0,
41
- handleNodeCount: 0,
42
- totalBlobSize: 0,
43
- unreferencedBlobSize: 0,
44
- };
45
- for (const stat of stats) {
46
- results.treeNodeCount += stat.treeNodeCount;
47
- results.blobNodeCount += stat.blobNodeCount;
48
- results.handleNodeCount += stat.handleNodeCount;
49
- results.totalBlobSize += stat.totalBlobSize;
50
- results.unreferencedBlobSize += stat.unreferencedBlobSize;
51
- }
52
- return results;
38
+ const results = {
39
+ treeNodeCount: 0,
40
+ blobNodeCount: 0,
41
+ handleNodeCount: 0,
42
+ totalBlobSize: 0,
43
+ unreferencedBlobSize: 0,
44
+ };
45
+ for (const stat of stats) {
46
+ results.treeNodeCount += stat.treeNodeCount;
47
+ results.blobNodeCount += stat.blobNodeCount;
48
+ results.handleNodeCount += stat.handleNodeCount;
49
+ results.totalBlobSize += stat.totalBlobSize;
50
+ results.unreferencedBlobSize += stat.unreferencedBlobSize;
51
+ }
52
+ return results;
53
53
  }
54
54
 
55
55
  export function utf8ByteLength(str: string): number {
56
- // returns the byte length of an utf8 string
57
- let s = str.length;
58
- for (let i = str.length - 1; i >= 0; i--) {
59
- const code = str.charCodeAt(i);
60
- if (code > 0x7f && code <= 0x7ff) {
61
- s++;
62
- } else if (code > 0x7ff && code <= 0xffff) {
63
- s += 2;
64
- }
65
- if (code >= 0xDC00 && code <= 0xDFFF) {
66
- i--; // trail surrogate
67
- }
68
- }
69
- return s;
56
+ // returns the byte length of an utf8 string
57
+ let s = str.length;
58
+ for (let i = str.length - 1; i >= 0; i--) {
59
+ const code = str.charCodeAt(i);
60
+ if (code > 0x7f && code <= 0x7ff) {
61
+ s++;
62
+ } else if (code > 0x7ff && code <= 0xffff) {
63
+ s += 2;
64
+ }
65
+ if (code >= 0xdc00 && code <= 0xdfff) {
66
+ i--; // trail surrogate
67
+ }
68
+ }
69
+ return s;
70
70
  }
71
71
 
72
72
  export function getBlobSize(content: ISummaryBlob["content"]): number {
73
- return typeof content === "string" ? utf8ByteLength(content) : content.byteLength;
73
+ return typeof content === "string" ? utf8ByteLength(content) : content.byteLength;
74
74
  }
75
75
 
76
76
  function calculateStatsCore(summaryObject: SummaryObject, stats: ISummaryStats): void {
77
- switch (summaryObject.type) {
78
- case SummaryType.Tree: {
79
- stats.treeNodeCount++;
80
- for (const value of Object.values(summaryObject.tree)) {
81
- calculateStatsCore(value, stats);
82
- }
83
- return;
84
- }
85
- case SummaryType.Handle: {
86
- stats.handleNodeCount++;
87
- return;
88
- }
89
- case SummaryType.Blob: {
90
- stats.blobNodeCount++;
91
- stats.totalBlobSize += getBlobSize(summaryObject.content);
92
- return;
93
- }
94
- default: return;
95
- }
77
+ switch (summaryObject.type) {
78
+ case SummaryType.Tree: {
79
+ stats.treeNodeCount++;
80
+ for (const value of Object.values(summaryObject.tree)) {
81
+ calculateStatsCore(value, stats);
82
+ }
83
+ return;
84
+ }
85
+ case SummaryType.Handle: {
86
+ stats.handleNodeCount++;
87
+ return;
88
+ }
89
+ case SummaryType.Blob: {
90
+ stats.blobNodeCount++;
91
+ stats.totalBlobSize += getBlobSize(summaryObject.content);
92
+ return;
93
+ }
94
+ default:
95
+ return;
96
+ }
96
97
  }
97
98
 
98
99
  export function calculateStats(summary: SummaryObject): ISummaryStats {
99
- const stats = mergeStats();
100
- calculateStatsCore(summary, stats);
101
- return stats;
100
+ const stats = mergeStats();
101
+ calculateStatsCore(summary, stats);
102
+ return stats;
102
103
  }
103
104
 
104
- export function addBlobToSummary(summary: ISummaryTreeWithStats, key: string, content: string | Uint8Array): void {
105
- const blob: ISummaryBlob = {
106
- type: SummaryType.Blob,
107
- content,
108
- };
109
- summary.summary.tree[key] = blob;
110
- summary.stats.blobNodeCount++;
111
- summary.stats.totalBlobSize += getBlobSize(content);
105
+ export function addBlobToSummary(
106
+ summary: ISummaryTreeWithStats,
107
+ key: string,
108
+ content: string | Uint8Array,
109
+ ): void {
110
+ const blob: ISummaryBlob = {
111
+ type: SummaryType.Blob,
112
+ content,
113
+ };
114
+ summary.summary.tree[key] = blob;
115
+ summary.stats.blobNodeCount++;
116
+ summary.stats.totalBlobSize += getBlobSize(content);
112
117
  }
113
118
 
114
- export function addTreeToSummary(summary: ISummaryTreeWithStats, key: string, summarizeResult: ISummarizeResult): void {
115
- summary.summary.tree[key] = summarizeResult.summary;
116
- summary.stats = mergeStats(summary.stats, summarizeResult.stats);
119
+ export function addTreeToSummary(
120
+ summary: ISummaryTreeWithStats,
121
+ key: string,
122
+ summarizeResult: ISummarizeResult,
123
+ ): void {
124
+ summary.summary.tree[key] = summarizeResult.summary;
125
+ summary.stats = mergeStats(summary.stats, summarizeResult.stats);
117
126
  }
118
127
 
119
128
  export function addSummarizeResultToSummary(
120
- summary: ISummaryTreeWithStats,
121
- key: string,
122
- summarizeResult: ISummarizeResult,
129
+ summary: ISummaryTreeWithStats,
130
+ key: string,
131
+ summarizeResult: ISummarizeResult,
123
132
  ): void {
124
- summary.summary.tree[key] = summarizeResult.summary;
125
- summary.stats = mergeStats(summary.stats, summarizeResult.stats);
133
+ summary.summary.tree[key] = summarizeResult.summary;
134
+ summary.stats = mergeStats(summary.stats, summarizeResult.stats);
126
135
  }
127
136
 
128
137
  export class SummaryTreeBuilder implements ISummaryTreeWithStats {
129
- private attachmentCounter: number = 0;
130
-
131
- public get summary(): ISummaryTree {
132
- return {
133
- type: SummaryType.Tree,
134
- tree: { ...this.summaryTree },
135
- };
136
- }
137
-
138
- public get stats(): Readonly<ISummaryStats> {
139
- return { ...this.summaryStats };
140
- }
141
-
142
- constructor() {
143
- this.summaryStats = mergeStats();
144
- this.summaryStats.treeNodeCount++;
145
- }
146
-
147
- private readonly summaryTree: { [path: string]: SummaryObject; } = {};
148
- private summaryStats: ISummaryStats;
149
-
150
- public addBlob(key: string, content: string | Uint8Array): void {
151
- // Prevent cloning by directly referencing underlying private properties
152
- addBlobToSummary({
153
- summary: {
154
- type: SummaryType.Tree,
155
- tree: this.summaryTree,
156
- },
157
- stats: this.summaryStats,
158
- }, key, content);
159
- }
160
-
161
- public addHandle(
162
- key: string,
163
- handleType: SummaryType.Tree | SummaryType.Blob | SummaryType.Attachment,
164
- handle: string): void {
165
- this.summaryTree[key] = {
166
- type: SummaryType.Handle,
167
- handleType,
168
- handle,
169
- };
170
- this.summaryStats.handleNodeCount++;
171
- }
172
-
173
- public addWithStats(key: string, summarizeResult: ISummarizeResult): void {
174
- this.summaryTree[key] = summarizeResult.summary;
175
- this.summaryStats = mergeStats(this.summaryStats, summarizeResult.stats);
176
- }
177
-
178
- public addAttachment(id: string) {
179
- this.summaryTree[this.attachmentCounter++] = { id, type: SummaryType.Attachment };
180
- }
181
-
182
- public getSummaryTree(): ISummaryTreeWithStats {
183
- return { summary: this.summary, stats: this.stats };
184
- }
138
+ private attachmentCounter: number = 0;
139
+
140
+ public get summary(): ISummaryTree {
141
+ return {
142
+ type: SummaryType.Tree,
143
+ tree: { ...this.summaryTree },
144
+ };
145
+ }
146
+
147
+ public get stats(): Readonly<ISummaryStats> {
148
+ return { ...this.summaryStats };
149
+ }
150
+
151
+ constructor() {
152
+ this.summaryStats = mergeStats();
153
+ this.summaryStats.treeNodeCount++;
154
+ }
155
+
156
+ private readonly summaryTree: { [path: string]: SummaryObject } = {};
157
+ private summaryStats: ISummaryStats;
158
+
159
+ public addBlob(key: string, content: string | Uint8Array): void {
160
+ // Prevent cloning by directly referencing underlying private properties
161
+ addBlobToSummary(
162
+ {
163
+ summary: {
164
+ type: SummaryType.Tree,
165
+ tree: this.summaryTree,
166
+ },
167
+ stats: this.summaryStats,
168
+ },
169
+ key,
170
+ content,
171
+ );
172
+ }
173
+
174
+ public addHandle(
175
+ key: string,
176
+ handleType: SummaryType.Tree | SummaryType.Blob | SummaryType.Attachment,
177
+ handle: string,
178
+ ): void {
179
+ this.summaryTree[key] = {
180
+ type: SummaryType.Handle,
181
+ handleType,
182
+ handle,
183
+ };
184
+ this.summaryStats.handleNodeCount++;
185
+ }
186
+
187
+ public addWithStats(key: string, summarizeResult: ISummarizeResult): void {
188
+ this.summaryTree[key] = summarizeResult.summary;
189
+ this.summaryStats = mergeStats(this.summaryStats, summarizeResult.stats);
190
+ }
191
+
192
+ public addAttachment(id: string) {
193
+ this.summaryTree[this.attachmentCounter++] = { id, type: SummaryType.Attachment };
194
+ }
195
+
196
+ public getSummaryTree(): ISummaryTreeWithStats {
197
+ return { summary: this.summary, stats: this.stats };
198
+ }
185
199
  }
186
200
 
187
201
  /**
@@ -190,45 +204,44 @@ export class SummaryTreeBuilder implements ISummaryTreeWithStats {
190
204
  * @param fullTree - true to never use handles, even if id is specified
191
205
  */
192
206
  export function convertToSummaryTreeWithStats(
193
- snapshot: ITree,
194
- fullTree: boolean = false,
207
+ snapshot: ITree,
208
+ fullTree: boolean = false,
195
209
  ): ISummaryTreeWithStats {
196
- const builder = new SummaryTreeBuilder();
197
- for (const entry of snapshot.entries) {
198
- switch (entry.type) {
199
- case TreeEntry.Blob: {
200
- const blob = entry.value;
201
- const content = blob.encoding === "base64"
202
- ? IsoBuffer.from(blob.contents, "base64")
203
- : blob.contents;
204
- builder.addBlob(entry.path, content);
205
- break;
206
- }
207
-
208
- case TreeEntry.Tree: {
209
- const subtree = convertToSummaryTree(
210
- entry.value,
211
- fullTree);
212
- builder.addWithStats(entry.path, subtree);
213
-
214
- break;
215
- }
216
-
217
- case TreeEntry.Attachment: {
218
- const id = entry.value.id;
219
- builder.addAttachment(id);
220
-
221
- break;
222
- }
223
-
224
- default:
225
- throw new Error("Unexpected TreeEntry type");
226
- }
227
- }
228
-
229
- const summaryTree = builder.getSummaryTree();
230
- summaryTree.summary.unreferenced = snapshot.unreferenced;
231
- return summaryTree;
210
+ const builder = new SummaryTreeBuilder();
211
+ for (const entry of snapshot.entries) {
212
+ switch (entry.type) {
213
+ case TreeEntry.Blob: {
214
+ const blob = entry.value;
215
+ const content =
216
+ blob.encoding === "base64"
217
+ ? IsoBuffer.from(blob.contents, "base64")
218
+ : blob.contents;
219
+ builder.addBlob(entry.path, content);
220
+ break;
221
+ }
222
+
223
+ case TreeEntry.Tree: {
224
+ const subtree = convertToSummaryTree(entry.value, fullTree);
225
+ builder.addWithStats(entry.path, subtree);
226
+
227
+ break;
228
+ }
229
+
230
+ case TreeEntry.Attachment: {
231
+ const id = entry.value.id;
232
+ builder.addAttachment(id);
233
+
234
+ break;
235
+ }
236
+
237
+ default:
238
+ throw new Error("Unexpected TreeEntry type");
239
+ }
240
+ }
241
+
242
+ const summaryTree = builder.getSummaryTree();
243
+ summaryTree.summary.unreferenced = snapshot.unreferenced;
244
+ return summaryTree;
232
245
  }
233
246
 
234
247
  /**
@@ -236,25 +249,22 @@ export function convertToSummaryTreeWithStats(
236
249
  * @param snapshot - snapshot in ITree format
237
250
  * @param fullTree - true to never use handles, even if id is specified
238
251
  */
239
- export function convertToSummaryTree(
240
- snapshot: ITree,
241
- fullTree: boolean = false,
242
- ): ISummarizeResult {
243
- // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
244
- if (snapshot.id && !fullTree) {
245
- const stats = mergeStats();
246
- stats.handleNodeCount++;
247
- return {
248
- summary: {
249
- handle: snapshot.id,
250
- handleType: SummaryType.Tree,
251
- type: SummaryType.Handle,
252
- },
253
- stats,
254
- };
255
- } else {
256
- return convertToSummaryTreeWithStats(snapshot, fullTree);
257
- }
252
+ export function convertToSummaryTree(snapshot: ITree, fullTree: boolean = false): ISummarizeResult {
253
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
254
+ if (snapshot.id && !fullTree) {
255
+ const stats = mergeStats();
256
+ stats.handleNodeCount++;
257
+ return {
258
+ summary: {
259
+ handle: snapshot.id,
260
+ handleType: SummaryType.Tree,
261
+ type: SummaryType.Handle,
262
+ },
263
+ stats,
264
+ };
265
+ } else {
266
+ return convertToSummaryTreeWithStats(snapshot, fullTree);
267
+ }
258
268
  }
259
269
 
260
270
  /**
@@ -262,35 +272,33 @@ export function convertToSummaryTree(
262
272
  * was taken by serialize api in detached container.
263
273
  * @param snapshot - snapshot in ISnapshotTree format
264
274
  */
265
- export function convertSnapshotTreeToSummaryTree(
266
- snapshot: ISnapshotTree,
267
- ): ISummaryTreeWithStats {
268
- const builder = new SummaryTreeBuilder();
269
- for (const [path, id] of Object.entries(snapshot.blobs)) {
270
- let decoded: string | undefined;
271
- if ((snapshot as any).blobsContents !== undefined) {
272
- const content: ArrayBufferLike = (snapshot as any).blobsContents[id];
273
- if (content !== undefined) {
274
- decoded = bufferToString(content, "utf-8");
275
- }
276
- // 0.44 back-compat We still put contents in same blob for back-compat so need to add blob
277
- // only for blobPath -> blobId mapping and not for blobId -> blob value contents.
278
- } else if (snapshot.blobs[id] !== undefined) {
279
- decoded = fromBase64ToUtf8(snapshot.blobs[id]);
280
- }
281
- if (decoded !== undefined) {
282
- builder.addBlob(path, decoded);
283
- }
284
- }
285
-
286
- for (const [key, tree] of Object.entries(snapshot.trees)) {
287
- const subtree = convertSnapshotTreeToSummaryTree(tree);
288
- builder.addWithStats(key, subtree);
289
- }
290
-
291
- const summaryTree = builder.getSummaryTree();
292
- summaryTree.summary.unreferenced = snapshot.unreferenced;
293
- return summaryTree;
275
+ export function convertSnapshotTreeToSummaryTree(snapshot: ISnapshotTree): ISummaryTreeWithStats {
276
+ const builder = new SummaryTreeBuilder();
277
+ for (const [path, id] of Object.entries(snapshot.blobs)) {
278
+ let decoded: string | undefined;
279
+ if ((snapshot as any).blobsContents !== undefined) {
280
+ const content: ArrayBufferLike = (snapshot as any).blobsContents[id];
281
+ if (content !== undefined) {
282
+ decoded = bufferToString(content, "utf-8");
283
+ }
284
+ // 0.44 back-compat We still put contents in same blob for back-compat so need to add blob
285
+ // only for blobPath -> blobId mapping and not for blobId -> blob value contents.
286
+ } else if (snapshot.blobs[id] !== undefined) {
287
+ decoded = fromBase64ToUtf8(snapshot.blobs[id]);
288
+ }
289
+ if (decoded !== undefined) {
290
+ builder.addBlob(path, decoded);
291
+ }
292
+ }
293
+
294
+ for (const [key, tree] of Object.entries(snapshot.trees)) {
295
+ const subtree = convertSnapshotTreeToSummaryTree(tree);
296
+ builder.addWithStats(key, subtree);
297
+ }
298
+
299
+ const summaryTree = builder.getSummaryTree();
300
+ summaryTree.summary.unreferenced = snapshot.unreferenced;
301
+ return summaryTree;
294
302
  }
295
303
 
296
304
  /**
@@ -298,71 +306,71 @@ export function convertSnapshotTreeToSummaryTree(
298
306
  * @param summaryTree - summary tree in ISummaryTree format
299
307
  */
300
308
  export function convertSummaryTreeToITree(summaryTree: ISummaryTree): ITree {
301
- const entries: ITreeEntry[] = [];
302
- for (const [key, value] of Object.entries(summaryTree.tree)) {
303
- switch (value.type) {
304
- case SummaryType.Blob: {
305
- let parsedContent: string;
306
- let encoding: "utf-8" | "base64" = "utf-8";
307
- if (typeof value.content === "string") {
308
- parsedContent = value.content;
309
- } else {
310
- parsedContent = Uint8ArrayToString(value.content, "base64");
311
- encoding = "base64";
312
- }
313
- entries.push(new BlobTreeEntry(key, parsedContent, encoding));
314
- break;
315
- }
316
-
317
- case SummaryType.Tree: {
318
- entries.push(new TreeTreeEntry(key, convertSummaryTreeToITree(value)));
319
- break;
320
- }
321
-
322
- case SummaryType.Attachment: {
323
- entries.push(new AttachmentTreeEntry(key, value.id));
324
- break;
325
- }
326
-
327
- case SummaryType.Handle: {
328
- throw new Error("Should not have Handle type in summary tree");
329
- }
330
-
331
- default:
332
- unreachableCase(value, "Unexpected summary tree type");
333
- }
334
- }
335
- return {
336
- entries,
337
- unreferenced: summaryTree.unreferenced,
338
- };
309
+ const entries: ITreeEntry[] = [];
310
+ for (const [key, value] of Object.entries(summaryTree.tree)) {
311
+ switch (value.type) {
312
+ case SummaryType.Blob: {
313
+ let parsedContent: string;
314
+ let encoding: "utf-8" | "base64" = "utf-8";
315
+ if (typeof value.content === "string") {
316
+ parsedContent = value.content;
317
+ } else {
318
+ parsedContent = Uint8ArrayToString(value.content, "base64");
319
+ encoding = "base64";
320
+ }
321
+ entries.push(new BlobTreeEntry(key, parsedContent, encoding));
322
+ break;
323
+ }
324
+
325
+ case SummaryType.Tree: {
326
+ entries.push(new TreeTreeEntry(key, convertSummaryTreeToITree(value)));
327
+ break;
328
+ }
329
+
330
+ case SummaryType.Attachment: {
331
+ entries.push(new AttachmentTreeEntry(key, value.id));
332
+ break;
333
+ }
334
+
335
+ case SummaryType.Handle: {
336
+ throw new Error("Should not have Handle type in summary tree");
337
+ }
338
+
339
+ default:
340
+ unreachableCase(value, "Unexpected summary tree type");
341
+ }
342
+ }
343
+ return {
344
+ entries,
345
+ unreferenced: summaryTree.unreferenced,
346
+ };
339
347
  }
340
348
 
341
349
  export class TelemetryContext implements ITelemetryContext {
342
- private readonly telemetry = new Map<string, TelemetryEventPropertyType>();
343
-
344
- /**
345
- * {@inheritDoc @fluidframework/runtime-definitions#ITelemetryContext.set}
346
- */
347
- set(prefix: string, property: string, value: TelemetryEventPropertyType): void {
348
- this.telemetry.set(`${prefix}${property}`, value);
349
- }
350
-
351
- /**
352
- * {@inheritDoc @fluidframework/runtime-definitions#ITelemetryContext.get}
353
- */
354
- get(prefix: string, property: string): TelemetryEventPropertyType {
355
- return this.telemetry.get(`${prefix}${property}`);
356
- }
357
-
358
- /**
359
- * {@inheritDoc @fluidframework/runtime-definitions#ITelemetryContext.serialize}
360
- */
361
- serialize(): string {
362
- const jsonObject = {};
363
- this.telemetry.forEach((value, key) => {
364
- jsonObject[key] = value;
365
- });
366
- return JSON.stringify(jsonObject);
367
- }
350
+ private readonly telemetry = new Map<string, TelemetryEventPropertyType>();
351
+
352
+ /**
353
+ * {@inheritDoc @fluidframework/runtime-definitions#ITelemetryContext.set}
354
+ */
355
+ set(prefix: string, property: string, value: TelemetryEventPropertyType): void {
356
+ this.telemetry.set(`${prefix}${property}`, value);
357
+ }
358
+
359
+ /**
360
+ * {@inheritDoc @fluidframework/runtime-definitions#ITelemetryContext.get}
361
+ */
362
+ get(prefix: string, property: string): TelemetryEventPropertyType {
363
+ return this.telemetry.get(`${prefix}${property}`);
364
+ }
365
+
366
+ /**
367
+ * {@inheritDoc @fluidframework/runtime-definitions#ITelemetryContext.serialize}
368
+ */
369
+ serialize(): string {
370
+ const jsonObject = {};
371
+ this.telemetry.forEach((value, key) => {
372
+ jsonObject[key] = value;
373
+ });
374
+ return JSON.stringify(jsonObject);
375
+ }
368
376
  }