@fluidframework/container-loader 2.0.0-internal.4.0.6 → 2.0.0-internal.4.1.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.
Files changed (92) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/README.md +38 -0
  3. package/dist/connectionManager.d.ts +2 -1
  4. package/dist/connectionManager.d.ts.map +1 -1
  5. package/dist/connectionManager.js +16 -6
  6. package/dist/connectionManager.js.map +1 -1
  7. package/dist/connectionStateHandler.d.ts.map +1 -1
  8. package/dist/connectionStateHandler.js +7 -0
  9. package/dist/connectionStateHandler.js.map +1 -1
  10. package/dist/container.d.ts +35 -2
  11. package/dist/container.d.ts.map +1 -1
  12. package/dist/container.js +88 -43
  13. package/dist/container.js.map +1 -1
  14. package/dist/containerContext.d.ts +3 -3
  15. package/dist/containerContext.d.ts.map +1 -1
  16. package/dist/containerContext.js +5 -4
  17. package/dist/containerContext.js.map +1 -1
  18. package/dist/containerStorageAdapter.d.ts +27 -2
  19. package/dist/containerStorageAdapter.d.ts.map +1 -1
  20. package/dist/containerStorageAdapter.js +64 -6
  21. package/dist/containerStorageAdapter.js.map +1 -1
  22. package/dist/deltaManager.d.ts +1 -3
  23. package/dist/deltaManager.d.ts.map +1 -1
  24. package/dist/deltaManager.js +3 -8
  25. package/dist/deltaManager.js.map +1 -1
  26. package/dist/index.d.ts +3 -2
  27. package/dist/index.d.ts.map +1 -1
  28. package/dist/index.js +2 -1
  29. package/dist/index.js.map +1 -1
  30. package/dist/loader.d.ts.map +1 -1
  31. package/dist/loader.js +4 -1
  32. package/dist/loader.js.map +1 -1
  33. package/dist/packageVersion.d.ts +1 -1
  34. package/dist/packageVersion.js +1 -1
  35. package/dist/packageVersion.js.map +1 -1
  36. package/dist/protocol.d.ts +1 -0
  37. package/dist/protocol.d.ts.map +1 -1
  38. package/dist/protocol.js +4 -2
  39. package/dist/protocol.js.map +1 -1
  40. package/dist/utils.d.ts.map +1 -1
  41. package/dist/utils.js.map +1 -1
  42. package/lib/connectionManager.d.ts +2 -1
  43. package/lib/connectionManager.d.ts.map +1 -1
  44. package/lib/connectionManager.js +16 -6
  45. package/lib/connectionManager.js.map +1 -1
  46. package/lib/connectionStateHandler.d.ts.map +1 -1
  47. package/lib/connectionStateHandler.js +7 -0
  48. package/lib/connectionStateHandler.js.map +1 -1
  49. package/lib/container.d.ts +35 -2
  50. package/lib/container.d.ts.map +1 -1
  51. package/lib/container.js +90 -45
  52. package/lib/container.js.map +1 -1
  53. package/lib/containerContext.d.ts +3 -3
  54. package/lib/containerContext.d.ts.map +1 -1
  55. package/lib/containerContext.js +5 -4
  56. package/lib/containerContext.js.map +1 -1
  57. package/lib/containerStorageAdapter.d.ts +27 -2
  58. package/lib/containerStorageAdapter.d.ts.map +1 -1
  59. package/lib/containerStorageAdapter.js +62 -6
  60. package/lib/containerStorageAdapter.js.map +1 -1
  61. package/lib/deltaManager.d.ts +1 -3
  62. package/lib/deltaManager.d.ts.map +1 -1
  63. package/lib/deltaManager.js +3 -8
  64. package/lib/deltaManager.js.map +1 -1
  65. package/lib/index.d.ts +3 -2
  66. package/lib/index.d.ts.map +1 -1
  67. package/lib/index.js +1 -1
  68. package/lib/index.js.map +1 -1
  69. package/lib/loader.d.ts.map +1 -1
  70. package/lib/loader.js +4 -1
  71. package/lib/loader.js.map +1 -1
  72. package/lib/packageVersion.d.ts +1 -1
  73. package/lib/packageVersion.js +1 -1
  74. package/lib/packageVersion.js.map +1 -1
  75. package/lib/protocol.d.ts +1 -0
  76. package/lib/protocol.d.ts.map +1 -1
  77. package/lib/protocol.js +3 -1
  78. package/lib/protocol.js.map +1 -1
  79. package/lib/utils.d.ts.map +1 -1
  80. package/lib/utils.js.map +1 -1
  81. package/package.json +17 -13
  82. package/src/connectionManager.ts +17 -7
  83. package/src/connectionStateHandler.ts +12 -0
  84. package/src/container.ts +138 -65
  85. package/src/containerContext.ts +6 -6
  86. package/src/containerStorageAdapter.ts +88 -5
  87. package/src/deltaManager.ts +3 -10
  88. package/src/index.ts +3 -1
  89. package/src/loader.ts +4 -1
  90. package/src/packageVersion.ts +1 -1
  91. package/src/protocol.ts +4 -1
  92. package/src/utils.ts +3 -1
@@ -21,7 +21,6 @@ import {
21
21
  IProvideFluidCodeDetailsComparer,
22
22
  ICodeDetailsLoader,
23
23
  IFluidModuleWithDetails,
24
- ISnapshotTreeWithBlobContents,
25
24
  IBatchMessage,
26
25
  } from "@fluidframework/container-definitions";
27
26
  import { IRequest, IResponse, FluidObject } from "@fluidframework/core-interfaces";
@@ -221,7 +220,7 @@ export class ContainerContext implements IContainerContext {
221
220
  public readonly scope: FluidObject,
222
221
  private readonly codeLoader: ICodeDetailsLoader,
223
222
  private readonly _codeDetails: IFluidCodeDetails,
224
- private _baseSnapshot: ISnapshotTree | undefined,
223
+ private readonly _baseSnapshot: ISnapshotTree | undefined,
225
224
  public readonly deltaManager: IDeltaManager<ISequencedDocumentMessage, IDocumentMessage>,
226
225
  quorum: IQuorum,
227
226
  public readonly loader: ILoader,
@@ -375,10 +374,8 @@ export class ContainerContext implements IContainerContext {
375
374
  return true;
376
375
  }
377
376
 
378
- public notifyAttaching(snapshot: ISnapshotTreeWithBlobContents) {
379
- this._baseSnapshot = snapshot;
380
- this.runtime.notifyAttaching?.(snapshot);
381
- this.runtime.setAttachState(AttachState.Attaching);
377
+ public async notifyOpReplay(message: ISequencedDocumentMessage): Promise<void> {
378
+ return this.runtime.notifyOpReplay?.(message);
382
379
  }
383
380
 
384
381
  // #region private
@@ -406,6 +403,9 @@ export class ContainerContext implements IContainerContext {
406
403
  }
407
404
 
408
405
  private attachListener() {
406
+ this.container.once("attaching", () => {
407
+ this.runtime.setAttachState(AttachState.Attaching);
408
+ });
409
409
  this.container.once("attached", () => {
410
410
  this.runtime.setAttachState(AttachState.Attached);
411
411
  });
@@ -4,7 +4,7 @@
4
4
  */
5
5
 
6
6
  import { IDisposable, ITelemetryLogger } from "@fluidframework/common-definitions";
7
- import { assert } from "@fluidframework/common-utils";
7
+ import { assert, bufferToString, stringToBuffer } from "@fluidframework/common-utils";
8
8
  import { ISnapshotTreeWithBlobContents } from "@fluidframework/container-definitions";
9
9
  import {
10
10
  FetchSource,
@@ -25,12 +25,20 @@ import { IDetachedBlobStorage } from "./loader";
25
25
  import { ProtocolTreeStorageService } from "./protocolTreeDocumentStorageService";
26
26
  import { RetriableDocumentStorageService } from "./retriableDocumentStorageService";
27
27
 
28
+ /**
29
+ * Stringified blobs from a summary/snapshot tree.
30
+ * @deprecated this is an internal interface and will not longer be exported in future versions
31
+ * @internal
32
+ */
33
+ export interface ISerializableBlobContents {
34
+ [id: string]: string;
35
+ }
36
+
28
37
  /**
29
38
  * This class wraps the actual storage and make sure no wrong apis are called according to
30
39
  * container attach state.
31
40
  */
32
41
  export class ContainerStorageAdapter implements IDocumentStorageService, IDisposable {
33
- private readonly blobContents: { [id: string]: ArrayBufferLike } = {};
34
42
  private _storageService: IDocumentStorageService & Partial<IDisposable>;
35
43
 
36
44
  private _summarizeProtocolTree: boolean | undefined;
@@ -53,6 +61,10 @@ export class ContainerStorageAdapter implements IDocumentStorageService, IDispos
53
61
  public constructor(
54
62
  detachedBlobStorage: IDetachedBlobStorage | undefined,
55
63
  private readonly logger: ITelemetryLogger,
64
+ /**
65
+ * ArrayBufferLikes or utf8 encoded strings, containing blobs from a snapshot
66
+ */
67
+ private readonly blobContents: { [id: string]: ArrayBufferLike | string } = {},
56
68
  private readonly addProtocolSummaryIfMissing: (summaryTree: ISummaryTree) => ISummaryTree,
57
69
  forceEnableSummarizeProtocolTree: boolean | undefined,
58
70
  ) {
@@ -128,9 +140,13 @@ export class ContainerStorageAdapter implements IDocumentStorageService, IDispos
128
140
  }
129
141
 
130
142
  public async readBlob(id: string): Promise<ArrayBufferLike> {
131
- const blob = this.blobContents[id];
132
- if (blob !== undefined) {
133
- return blob;
143
+ const maybeBlob = this.blobContents[id];
144
+ if (maybeBlob !== undefined) {
145
+ if (typeof maybeBlob === "string") {
146
+ const blob = stringToBuffer(maybeBlob, "utf8");
147
+ return blob;
148
+ }
149
+ return maybeBlob;
134
150
  }
135
151
  return this._storageService.readBlob(id);
136
152
  }
@@ -212,3 +228,70 @@ class BlobOnlyStorage implements IDocumentStorageService {
212
228
  }
213
229
  }
214
230
  }
231
+
232
+ // runtime will write a tree to the summary containing only "attachment" type entries
233
+ // which reference attachment blobs by ID. However, some drivers do not support this type
234
+ // and will convert them to "blob" type entries. We want to avoid saving these to reduce
235
+ // the size of stashed change blobs.
236
+ const blobsTreeName = ".blobs";
237
+
238
+ /**
239
+ * Get blob contents of a snapshot tree from storage (or, ideally, cache)
240
+ */
241
+ export async function getBlobContentsFromTree(
242
+ snapshot: ISnapshotTree,
243
+ storage: IDocumentStorageService,
244
+ ): Promise<ISerializableBlobContents> {
245
+ const blobs = {};
246
+ await getBlobContentsFromTreeCore(snapshot, blobs, storage);
247
+ return blobs;
248
+ }
249
+
250
+ async function getBlobContentsFromTreeCore(
251
+ tree: ISnapshotTree,
252
+ blobs: ISerializableBlobContents,
253
+ storage: IDocumentStorageService,
254
+ root = true,
255
+ ) {
256
+ const treePs: Promise<any>[] = [];
257
+ for (const [key, subTree] of Object.entries(tree.trees)) {
258
+ if (!root || key !== blobsTreeName) {
259
+ treePs.push(getBlobContentsFromTreeCore(subTree, blobs, storage, false));
260
+ }
261
+ }
262
+ for (const id of Object.values(tree.blobs)) {
263
+ const blob = await storage.readBlob(id);
264
+ // ArrayBufferLike will not survive JSON.stringify()
265
+ blobs[id] = bufferToString(blob, "utf8");
266
+ }
267
+ return Promise.all(treePs);
268
+ }
269
+
270
+ /**
271
+ * Extract blob contents from a snapshot tree with blob contents
272
+ */
273
+ export function getBlobContentsFromTreeWithBlobContents(
274
+ snapshot: ISnapshotTreeWithBlobContents,
275
+ ): ISerializableBlobContents {
276
+ const blobs = {};
277
+ getBlobContentsFromTreeWithBlobContentsCore(snapshot, blobs);
278
+ return blobs;
279
+ }
280
+
281
+ function getBlobContentsFromTreeWithBlobContentsCore(
282
+ tree: ISnapshotTreeWithBlobContents,
283
+ blobs: ISerializableBlobContents,
284
+ root = true,
285
+ ) {
286
+ for (const [key, subTree] of Object.entries(tree.trees)) {
287
+ if (!root || key !== blobsTreeName) {
288
+ getBlobContentsFromTreeWithBlobContentsCore(subTree, blobs, false);
289
+ }
290
+ }
291
+ for (const id of Object.values(tree.blobs)) {
292
+ const blob = tree.blobsContents[id];
293
+ assert(blob !== undefined, 0x2ec /* "Blob must be present in blobsContents" */);
294
+ // ArrayBufferLike will not survive JSON.stringify()
295
+ blobs[id] = bufferToString(blob, "utf8");
296
+ }
297
+ }
@@ -41,8 +41,9 @@ import {
41
41
  extractSafePropertiesFromMessage,
42
42
  DataProcessingError,
43
43
  } from "@fluidframework/container-utils";
44
- import { DeltaQueue } from "./deltaQueue";
45
44
  import { IConnectionManagerFactoryArgs, IConnectionManager } from "./contracts";
45
+ import { DeltaQueue } from "./deltaQueue";
46
+ import { OnlyValidTermValue } from "./protocol";
46
47
 
47
48
  export interface IConnectionArgs {
48
49
  mode?: ConnectionMode;
@@ -123,7 +124,6 @@ export class DeltaManager<TConnectionManager extends IConnectionManager>
123
124
  private lastObservedSeqNumber: number = 0;
124
125
  private lastProcessedSequenceNumber: number = 0;
125
126
  private lastProcessedMessage: ISequencedDocumentMessage | undefined;
126
- private baseTerm: number = 0;
127
127
 
128
128
  /** count number of noops sent by the client which may not be acked */
129
129
  private noOpCount: number = 0;
@@ -187,10 +187,6 @@ export class DeltaManager<TConnectionManager extends IConnectionManager>
187
187
  return this.lastObservedSeqNumber;
188
188
  }
189
189
 
190
- public get referenceTerm(): number {
191
- return this.baseTerm;
192
- }
193
-
194
190
  public get minimumSequenceNumber(): number {
195
191
  return this.minSequenceNumber;
196
192
  }
@@ -465,13 +461,11 @@ export class DeltaManager<TConnectionManager extends IConnectionManager>
465
461
  public async attachOpHandler(
466
462
  minSequenceNumber: number,
467
463
  sequenceNumber: number,
468
- term: number,
469
464
  handler: IDeltaHandlerStrategy,
470
465
  prefetchType: "cached" | "all" | "none" = "none",
471
466
  ) {
472
467
  this.initSequenceNumber = sequenceNumber;
473
468
  this.lastProcessedSequenceNumber = sequenceNumber;
474
- this.baseTerm = term;
475
469
  this.minSequenceNumber = minSequenceNumber;
476
470
  this.lastQueuedSequenceNumber = sequenceNumber;
477
471
  this.lastObservedSeqNumber = sequenceNumber;
@@ -986,9 +980,8 @@ export class DeltaManager<TConnectionManager extends IConnectionManager>
986
980
 
987
981
  // Back-compat for older server with no term
988
982
  if (message.term === undefined) {
989
- message.term = 1;
983
+ message.term = OnlyValidTermValue;
990
984
  }
991
- this.baseTerm = message.term;
992
985
 
993
986
  if (this.handler === undefined) {
994
987
  throw new Error("Attempted to process an inbound message without a handler attached");
package/src/index.ts CHANGED
@@ -5,11 +5,12 @@
5
5
 
6
6
  export { ConnectionState } from "./connectionState";
7
7
  export {
8
- IContainerLoadOptions,
9
8
  IContainerConfig,
9
+ IContainerLoadOptions,
10
10
  IPendingContainerState,
11
11
  waitContainerToCatchUp,
12
12
  } from "./container";
13
+ export { ISerializableBlobContents } from "./containerStorageAdapter";
13
14
  export {
14
15
  ICodeDetailsLoader,
15
16
  IDetachedBlobStorage,
@@ -18,5 +19,6 @@ export {
18
19
  ILoaderProps,
19
20
  ILoaderServices,
20
21
  Loader,
22
+ requestResolvedObjectFromContainer,
21
23
  } from "./loader";
22
24
  export { IProtocolHandler, ProtocolHandlerBuilder } from "./protocol";
package/src/loader.ts CHANGED
@@ -273,7 +273,10 @@ export async function requestResolvedObjectFromContainer(
273
273
  throw new Error(`Invalid URL ${container.resolvedUrl.url}`);
274
274
  }
275
275
 
276
- return container.request({
276
+ const entryPoint: FluidObject<IFluidRouter> | undefined = await container.getEntryPoint?.();
277
+ const router = entryPoint?.IFluidRouter ?? container.IFluidRouter;
278
+
279
+ return router.request({
277
280
  url: `${parsedUrl.path}${parsedUrl.query}`,
278
281
  headers,
279
282
  });
@@ -6,4 +6,4 @@
6
6
  */
7
7
 
8
8
  export const pkgName = "@fluidframework/container-loader";
9
- export const pkgVersion = "2.0.0-internal.4.0.6";
9
+ export const pkgVersion = "2.0.0-internal.4.1.1";
package/src/protocol.ts CHANGED
@@ -20,6 +20,9 @@ import {
20
20
  } from "@fluidframework/protocol-definitions";
21
21
  import { canBeCoalescedByService } from "@fluidframework/driver-utils";
22
22
 
23
+ // "term" was an experimental feature that is being removed. The only safe value to use is 1.
24
+ export const OnlyValidTermValue = 1 as const;
25
+
23
26
  // ADO: #1986: Start using enum from protocol-base.
24
27
  export enum SignalType {
25
28
  ClientJoin = "join", // same value as MessageType.ClientJoin,
@@ -51,7 +54,7 @@ export class ProtocolHandler extends ProtocolOpHandler implements IProtocolHandl
51
54
  super(
52
55
  attributes.minimumSequenceNumber,
53
56
  attributes.sequenceNumber,
54
- attributes.term,
57
+ OnlyValidTermValue,
55
58
  quorumSnapshot.members,
56
59
  quorumSnapshot.proposals,
57
60
  quorumSnapshot.values,
package/src/utils.ts CHANGED
@@ -126,7 +126,9 @@ export function convertProtocolAndAppSummaryToSnapshotTree(
126
126
 
127
127
  // This function converts the snapshot taken in detached container(by serialize api) to snapshotTree with which
128
128
  // a detached container can be rehydrated.
129
- export const getSnapshotTreeFromSerializedContainer = (detachedContainerSnapshot: ISummaryTree) => {
129
+ export const getSnapshotTreeFromSerializedContainer = (
130
+ detachedContainerSnapshot: ISummaryTree,
131
+ ): ISnapshotTreeWithBlobContents => {
130
132
  assert(
131
133
  isCombinedAppAndProtocolSummary(detachedContainerSnapshot),
132
134
  0x1e0 /* "Protocol and App summary trees should be present" */,