@fluidframework/container-loader 2.0.0-internal.7.1.0 → 2.0.0-internal.7.2.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 (98) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/api-report/container-loader.api.md +13 -2
  3. package/dist/connectionManager.d.ts +1 -1
  4. package/dist/connectionManager.d.ts.map +1 -1
  5. package/dist/connectionManager.js +9 -4
  6. package/dist/connectionManager.js.map +1 -1
  7. package/dist/container.d.ts +6 -5
  8. package/dist/container.d.ts.map +1 -1
  9. package/dist/container.js +21 -19
  10. package/dist/container.js.map +1 -1
  11. package/dist/containerContext.d.ts +2 -2
  12. package/dist/containerContext.d.ts.map +1 -1
  13. package/dist/containerContext.js.map +1 -1
  14. package/dist/containerStorageAdapter.d.ts +1 -1
  15. package/dist/containerStorageAdapter.d.ts.map +1 -1
  16. package/dist/containerStorageAdapter.js +3 -3
  17. package/dist/containerStorageAdapter.js.map +1 -1
  18. package/dist/contracts.d.ts +1 -1
  19. package/dist/contracts.d.ts.map +1 -1
  20. package/dist/contracts.js.map +1 -1
  21. package/dist/deltaManager.d.ts +1 -1
  22. package/dist/deltaManager.d.ts.map +1 -1
  23. package/dist/deltaManager.js +3 -8
  24. package/dist/deltaManager.js.map +1 -1
  25. package/dist/index.d.ts +1 -0
  26. package/dist/index.d.ts.map +1 -1
  27. package/dist/index.js +3 -1
  28. package/dist/index.js.map +1 -1
  29. package/dist/loader.d.ts +4 -4
  30. package/dist/loader.js +7 -7
  31. package/dist/loader.js.map +1 -1
  32. package/dist/packageVersion.d.ts +1 -1
  33. package/dist/packageVersion.js +1 -1
  34. package/dist/packageVersion.js.map +1 -1
  35. package/dist/retriableDocumentStorageService.d.ts +3 -2
  36. package/dist/retriableDocumentStorageService.d.ts.map +1 -1
  37. package/dist/retriableDocumentStorageService.js +18 -11
  38. package/dist/retriableDocumentStorageService.js.map +1 -1
  39. package/dist/utils.d.ts +23 -1
  40. package/dist/utils.d.ts.map +1 -1
  41. package/dist/utils.js +11 -3
  42. package/dist/utils.js.map +1 -1
  43. package/lib/connectionManager.d.ts +1 -1
  44. package/lib/connectionManager.d.ts.map +1 -1
  45. package/lib/connectionManager.js +9 -4
  46. package/lib/connectionManager.js.map +1 -1
  47. package/lib/container.d.ts +6 -5
  48. package/lib/container.d.ts.map +1 -1
  49. package/lib/container.js +21 -19
  50. package/lib/container.js.map +1 -1
  51. package/lib/containerContext.d.ts +2 -2
  52. package/lib/containerContext.d.ts.map +1 -1
  53. package/lib/containerContext.js.map +1 -1
  54. package/lib/containerStorageAdapter.d.ts +1 -1
  55. package/lib/containerStorageAdapter.d.ts.map +1 -1
  56. package/lib/containerStorageAdapter.js +3 -3
  57. package/lib/containerStorageAdapter.js.map +1 -1
  58. package/lib/contracts.d.ts +1 -1
  59. package/lib/contracts.d.ts.map +1 -1
  60. package/lib/contracts.js.map +1 -1
  61. package/lib/deltaManager.d.ts +1 -1
  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 +1 -0
  66. package/lib/index.d.ts.map +1 -1
  67. package/lib/index.js +1 -0
  68. package/lib/index.js.map +1 -1
  69. package/lib/loader.d.ts +4 -4
  70. package/lib/loader.js +8 -8
  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/retriableDocumentStorageService.d.ts +3 -2
  76. package/lib/retriableDocumentStorageService.d.ts.map +1 -1
  77. package/lib/retriableDocumentStorageService.js +18 -11
  78. package/lib/retriableDocumentStorageService.js.map +1 -1
  79. package/lib/utils.d.ts +23 -1
  80. package/lib/utils.d.ts.map +1 -1
  81. package/lib/utils.js +9 -1
  82. package/lib/utils.js.map +1 -1
  83. package/package.json +16 -17
  84. package/src/connectionManager.ts +13 -5
  85. package/src/container.ts +34 -24
  86. package/src/containerContext.ts +1 -1
  87. package/src/containerStorageAdapter.ts +3 -3
  88. package/src/contracts.ts +1 -1
  89. package/src/deltaManager.ts +6 -23
  90. package/src/index.ts +1 -0
  91. package/src/loader.ts +8 -8
  92. package/src/packageVersion.ts +1 -1
  93. package/src/retriableDocumentStorageService.ts +29 -15
  94. package/src/utils.ts +23 -1
  95. package/dist/container-loader-alpha.d.ts +0 -297
  96. package/dist/container-loader-beta.d.ts +0 -297
  97. package/dist/container-loader-public.d.ts +0 -297
  98. package/dist/container-loader.d.ts +0 -297
@@ -5,5 +5,5 @@
5
5
  * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY
6
6
  */
7
7
  export const pkgName = "@fluidframework/container-loader";
8
- export const pkgVersion = "2.0.0-internal.7.1.0";
8
+ export const pkgVersion = "2.0.0-internal.7.2.0";
9
9
  //# sourceMappingURL=packageVersion.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"packageVersion.js","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,CAAC,MAAM,OAAO,GAAG,kCAAkC,CAAC;AAC1D,MAAM,CAAC,MAAM,UAAU,GAAG,sBAAsB,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n *\n * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY\n */\n\nexport const pkgName = \"@fluidframework/container-loader\";\nexport const pkgVersion = \"2.0.0-internal.7.1.0\";\n"]}
1
+ {"version":3,"file":"packageVersion.js","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,CAAC,MAAM,OAAO,GAAG,kCAAkC,CAAC;AAC1D,MAAM,CAAC,MAAM,UAAU,GAAG,sBAAsB,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n *\n * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY\n */\n\nexport const pkgName = \"@fluidframework/container-loader\";\nexport const pkgVersion = \"2.0.0-internal.7.2.0\";\n"]}
@@ -7,10 +7,11 @@ import { ICreateBlobResponse, ISnapshotTree, ISummaryHandle, ISummaryTree, IVers
7
7
  import { IDisposable } from "@fluidframework/core-interfaces";
8
8
  import { ITelemetryLoggerExt } from "@fluidframework/telemetry-utils";
9
9
  export declare class RetriableDocumentStorageService implements IDocumentStorageService, IDisposable {
10
- private readonly internalStorageService;
10
+ private readonly internalStorageServiceP;
11
11
  private readonly logger;
12
12
  private _disposed;
13
- constructor(internalStorageService: IDocumentStorageService, logger: ITelemetryLoggerExt);
13
+ private internalStorageService;
14
+ constructor(internalStorageServiceP: Promise<IDocumentStorageService>, logger: ITelemetryLoggerExt);
14
15
  get policies(): IDocumentStorageServicePolicies | undefined;
15
16
  get disposed(): boolean;
16
17
  dispose(): void;
@@ -1 +1 @@
1
- {"version":3,"file":"retriableDocumentStorageService.d.ts","sourceRoot":"","sources":["../src/retriableDocumentStorageService.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EACN,WAAW,EACX,uBAAuB,EACvB,+BAA+B,EAC/B,eAAe,EACf,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EACN,mBAAmB,EACnB,aAAa,EACb,cAAc,EACd,YAAY,EACZ,QAAQ,EACR,MAAM,sCAAsC,CAAC;AAC9C,OAAO,EAAE,WAAW,EAAE,MAAM,iCAAiC,CAAC;AAC9D,OAAO,EAAgB,mBAAmB,EAAE,MAAM,iCAAiC,CAAC;AAGpF,qBAAa,+BAAgC,YAAW,uBAAuB,EAAE,WAAW;IAG1F,OAAO,CAAC,QAAQ,CAAC,sBAAsB;IACvC,OAAO,CAAC,QAAQ,CAAC,MAAM;IAHxB,OAAO,CAAC,SAAS,CAAS;gBAER,sBAAsB,EAAE,uBAAuB,EAC/C,MAAM,EAAE,mBAAmB;IAG7C,IAAW,QAAQ,IAAI,+BAA+B,GAAG,SAAS,CAEjE;IACD,IAAW,QAAQ,YAElB;IACM,OAAO;IAId,IAAW,aAAa,IAAI,MAAM,CAEjC;IAEY,eAAe,CAC3B,OAAO,CAAC,EAAE,QAAQ,EAClB,YAAY,CAAC,EAAE,MAAM,GACnB,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC;IAOnB,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC;IAO9C,WAAW,CACvB,SAAS,EAAE,MAAM,GAAG,IAAI,EACxB,KAAK,EAAE,MAAM,EACb,YAAY,CAAC,EAAE,MAAM,EACrB,WAAW,CAAC,EAAE,WAAW,GACvB,OAAO,CAAC,QAAQ,EAAE,CAAC;IAaT,wBAAwB,CACpC,OAAO,EAAE,YAAY,EACrB,OAAO,EAAE,eAAe,GACtB,OAAO,CAAC,MAAM,CAAC;IAyBL,eAAe,CAAC,MAAM,EAAE,cAAc,GAAG,OAAO,CAAC,YAAY,CAAC;IAO9D,UAAU,CAAC,IAAI,EAAE,eAAe,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAO5E,OAAO,CAAC,oBAAoB;YAiBd,YAAY;CAM1B"}
1
+ {"version":3,"file":"retriableDocumentStorageService.d.ts","sourceRoot":"","sources":["../src/retriableDocumentStorageService.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EACN,WAAW,EACX,uBAAuB,EACvB,+BAA+B,EAC/B,eAAe,EACf,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EACN,mBAAmB,EACnB,aAAa,EACb,cAAc,EACd,YAAY,EACZ,QAAQ,EACR,MAAM,sCAAsC,CAAC;AAC9C,OAAO,EAAE,WAAW,EAAE,MAAM,iCAAiC,CAAC;AAC9D,OAAO,EAAgB,mBAAmB,EAAE,MAAM,iCAAiC,CAAC;AAGpF,qBAAa,+BAAgC,YAAW,uBAAuB,EAAE,WAAW;IAI1F,OAAO,CAAC,QAAQ,CAAC,uBAAuB;IACxC,OAAO,CAAC,QAAQ,CAAC,MAAM;IAJxB,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,sBAAsB,CAAsC;gBAElD,uBAAuB,EAAE,OAAO,CAAC,uBAAuB,CAAC,EACzD,MAAM,EAAE,mBAAmB;IAK7C,IAAW,QAAQ,IAAI,+BAA+B,GAAG,SAAS,CAKjE;IACD,IAAW,QAAQ,YAElB;IACM,OAAO;IAId,IAAW,aAAa,IAAI,MAAM,CAKjC;IAEY,eAAe,CAC3B,OAAO,CAAC,EAAE,QAAQ,EAClB,YAAY,CAAC,EAAE,MAAM,GACnB,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC;IAUnB,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC;IAO9C,WAAW,CACvB,SAAS,EAAE,MAAM,GAAG,IAAI,EACxB,KAAK,EAAE,MAAM,EACb,YAAY,CAAC,EAAE,MAAM,EACrB,WAAW,CAAC,EAAE,WAAW,GACvB,OAAO,CAAC,QAAQ,EAAE,CAAC;IAUT,wBAAwB,CACpC,OAAO,EAAE,YAAY,EACrB,OAAO,EAAE,eAAe,GACtB,OAAO,CAAC,MAAM,CAAC;IA8BL,eAAe,CAAC,MAAM,EAAE,cAAc,GAAG,OAAO,CAAC,YAAY,CAAC;IAO9D,UAAU,CAAC,IAAI,EAAE,eAAe,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAO5E,OAAO,CAAC,oBAAoB;YAiBd,YAAY;CAM1B"}
@@ -6,13 +6,17 @@ import { assert } from "@fluidframework/core-utils";
6
6
  import { GenericError } from "@fluidframework/telemetry-utils";
7
7
  import { runWithRetry } from "@fluidframework/driver-utils";
8
8
  export class RetriableDocumentStorageService {
9
- constructor(internalStorageService, logger) {
10
- this.internalStorageService = internalStorageService;
9
+ constructor(internalStorageServiceP, logger) {
10
+ this.internalStorageServiceP = internalStorageServiceP;
11
11
  this.logger = logger;
12
12
  this._disposed = false;
13
+ this.internalStorageServiceP.then((s) => (this.internalStorageService = s)).catch(() => { });
13
14
  }
14
15
  get policies() {
15
- return this.internalStorageService.policies;
16
+ if (this.internalStorageService) {
17
+ return this.internalStorageService.policies;
18
+ }
19
+ throw new Error("storage service not yet instantiated");
16
20
  }
17
21
  get disposed() {
18
22
  return this._disposed;
@@ -21,16 +25,19 @@ export class RetriableDocumentStorageService {
21
25
  this._disposed = true;
22
26
  }
23
27
  get repositoryUrl() {
24
- return this.internalStorageService.repositoryUrl;
28
+ if (this.internalStorageService) {
29
+ return this.internalStorageService.repositoryUrl;
30
+ }
31
+ throw new Error("storage service not yet instantiated");
25
32
  }
26
33
  async getSnapshotTree(version, scenarioName) {
27
- return this.runWithRetry(async () => this.internalStorageService.getSnapshotTree(version, scenarioName), "storage_getSnapshotTree");
34
+ return this.runWithRetry(async () => this.internalStorageServiceP.then(async (s) => s.getSnapshotTree(version, scenarioName)), "storage_getSnapshotTree");
28
35
  }
29
36
  async readBlob(id) {
30
- return this.runWithRetry(async () => this.internalStorageService.readBlob(id), "storage_readBlob");
37
+ return this.runWithRetry(async () => this.internalStorageServiceP.then(async (s) => s.readBlob(id)), "storage_readBlob");
31
38
  }
32
39
  async getVersions(versionId, count, scenarioName, fetchSource) {
33
- return this.runWithRetry(async () => this.internalStorageService.getVersions(versionId, count, scenarioName, fetchSource), "storage_getVersions");
40
+ return this.runWithRetry(async () => this.internalStorageServiceP.then(async (s) => s.getVersions(versionId, count, scenarioName, fetchSource)), "storage_getVersions");
34
41
  }
35
42
  async uploadSummaryWithContext(summary, context) {
36
43
  // Not using retry loop here. Couple reasons:
@@ -44,16 +51,16 @@ export class RetriableDocumentStorageService {
44
51
  // But retry loop is required for creation flow (Container.attach)
45
52
  assert((context.referenceSequenceNumber === 0) === (context.ackHandle === undefined), 0x251 /* "creation summary has to have seq=0 && handle === undefined" */);
46
53
  if (context.referenceSequenceNumber !== 0) {
47
- return this.internalStorageService.uploadSummaryWithContext(summary, context);
54
+ return this.internalStorageServiceP.then(async (s) => s.uploadSummaryWithContext(summary, context));
48
55
  }
49
56
  // Creation flow with attachment blobs - need to do retries!
50
- return this.runWithRetry(async () => this.internalStorageService.uploadSummaryWithContext(summary, context), "storage_uploadSummaryWithContext");
57
+ return this.runWithRetry(async () => this.internalStorageServiceP.then(async (s) => s.uploadSummaryWithContext(summary, context)), "storage_uploadSummaryWithContext");
51
58
  }
52
59
  async downloadSummary(handle) {
53
- return this.runWithRetry(async () => this.internalStorageService.downloadSummary(handle), "storage_downloadSummary");
60
+ return this.runWithRetry(async () => this.internalStorageServiceP.then(async (s) => s.downloadSummary(handle)), "storage_downloadSummary");
54
61
  }
55
62
  async createBlob(file) {
56
- return this.runWithRetry(async () => this.internalStorageService.createBlob(file), "storage_createBlob");
63
+ return this.runWithRetry(async () => this.internalStorageServiceP.then(async (s) => s.createBlob(file)), "storage_createBlob");
57
64
  }
58
65
  checkStorageDisposed(callName, error) {
59
66
  if (this._disposed) {
@@ -1 +1 @@
1
- {"version":3,"file":"retriableDocumentStorageService.js","sourceRoot":"","sources":["../src/retriableDocumentStorageService.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { assert } from \"@fluidframework/core-utils\";\nimport {\n\tFetchSource,\n\tIDocumentStorageService,\n\tIDocumentStorageServicePolicies,\n\tISummaryContext,\n} from \"@fluidframework/driver-definitions\";\nimport {\n\tICreateBlobResponse,\n\tISnapshotTree,\n\tISummaryHandle,\n\tISummaryTree,\n\tIVersion,\n} from \"@fluidframework/protocol-definitions\";\nimport { IDisposable } from \"@fluidframework/core-interfaces\";\nimport { GenericError, ITelemetryLoggerExt } from \"@fluidframework/telemetry-utils\";\nimport { runWithRetry } from \"@fluidframework/driver-utils\";\n\nexport class RetriableDocumentStorageService implements IDocumentStorageService, IDisposable {\n\tprivate _disposed = false;\n\tconstructor(\n\t\tprivate readonly internalStorageService: IDocumentStorageService,\n\t\tprivate readonly logger: ITelemetryLoggerExt,\n\t) {}\n\n\tpublic get policies(): IDocumentStorageServicePolicies | undefined {\n\t\treturn this.internalStorageService.policies;\n\t}\n\tpublic get disposed() {\n\t\treturn this._disposed;\n\t}\n\tpublic dispose() {\n\t\tthis._disposed = true;\n\t}\n\n\tpublic get repositoryUrl(): string {\n\t\treturn this.internalStorageService.repositoryUrl;\n\t}\n\n\tpublic async getSnapshotTree(\n\t\tversion?: IVersion,\n\t\tscenarioName?: string,\n\t): Promise<ISnapshotTree | null> {\n\t\treturn this.runWithRetry(\n\t\t\tasync () => this.internalStorageService.getSnapshotTree(version, scenarioName),\n\t\t\t\"storage_getSnapshotTree\",\n\t\t);\n\t}\n\n\tpublic async readBlob(id: string): Promise<ArrayBufferLike> {\n\t\treturn this.runWithRetry(\n\t\t\tasync () => this.internalStorageService.readBlob(id),\n\t\t\t\"storage_readBlob\",\n\t\t);\n\t}\n\n\tpublic async getVersions(\n\t\tversionId: string | null,\n\t\tcount: number,\n\t\tscenarioName?: string,\n\t\tfetchSource?: FetchSource,\n\t): Promise<IVersion[]> {\n\t\treturn this.runWithRetry(\n\t\t\tasync () =>\n\t\t\t\tthis.internalStorageService.getVersions(\n\t\t\t\t\tversionId,\n\t\t\t\t\tcount,\n\t\t\t\t\tscenarioName,\n\t\t\t\t\tfetchSource,\n\t\t\t\t),\n\t\t\t\"storage_getVersions\",\n\t\t);\n\t}\n\n\tpublic async uploadSummaryWithContext(\n\t\tsummary: ISummaryTree,\n\t\tcontext: ISummaryContext,\n\t): Promise<string> {\n\t\t// Not using retry loop here. Couple reasons:\n\t\t// 1. If client lost connectivity, then retry loop will result in uploading stale summary\n\t\t// by stale summarizer after connectivity comes back. It will cause failures for this client and for\n\t\t// real (new) summarizer. This problem in particular should be solved in future by supplying abort handle\n\t\t// on all APIs and caller (ContainerRuntime.submitSummary) aborting call on loss of connectivity\n\t\t// 2. Similar, if we get 429 with retryAfter = 10 minutes, it's likely not the right call to retry summary\n\t\t// upload in 10 minutes - it's better to keep processing ops and retry later. Though caller needs to take\n\t\t// retryAfter into account!\n\t\t// But retry loop is required for creation flow (Container.attach)\n\t\tassert(\n\t\t\t(context.referenceSequenceNumber === 0) === (context.ackHandle === undefined),\n\t\t\t0x251 /* \"creation summary has to have seq=0 && handle === undefined\" */,\n\t\t);\n\t\tif (context.referenceSequenceNumber !== 0) {\n\t\t\treturn this.internalStorageService.uploadSummaryWithContext(summary, context);\n\t\t}\n\n\t\t// Creation flow with attachment blobs - need to do retries!\n\t\treturn this.runWithRetry(\n\t\t\tasync () => this.internalStorageService.uploadSummaryWithContext(summary, context),\n\t\t\t\"storage_uploadSummaryWithContext\",\n\t\t);\n\t}\n\n\tpublic async downloadSummary(handle: ISummaryHandle): Promise<ISummaryTree> {\n\t\treturn this.runWithRetry(\n\t\t\tasync () => this.internalStorageService.downloadSummary(handle),\n\t\t\t\"storage_downloadSummary\",\n\t\t);\n\t}\n\n\tpublic async createBlob(file: ArrayBufferLike): Promise<ICreateBlobResponse> {\n\t\treturn this.runWithRetry(\n\t\t\tasync () => this.internalStorageService.createBlob(file),\n\t\t\t\"storage_createBlob\",\n\t\t);\n\t}\n\n\tprivate checkStorageDisposed(callName: string, error: unknown) {\n\t\tif (this._disposed) {\n\t\t\tthis.logger.sendTelemetryEvent(\n\t\t\t\t{\n\t\t\t\t\teventName: `${callName}_abortedStorageDisposed`,\n\t\t\t\t\tfetchCallName: callName, // fetchCallName matches logs in runWithRetry.ts\n\t\t\t\t},\n\t\t\t\terror,\n\t\t\t);\n\t\t\t// pre-0.58 error message: storageServiceDisposedCannotRetry\n\t\t\tthrow new GenericError(\"Storage Service is disposed. Cannot retry\", {\n\t\t\t\tcanRetry: false,\n\t\t\t});\n\t\t}\n\t\treturn;\n\t}\n\n\tprivate async runWithRetry<T>(api: () => Promise<T>, callName: string): Promise<T> {\n\t\treturn runWithRetry(api, callName, this.logger, {\n\t\t\tonRetry: (_delayInMs: number, error: unknown) =>\n\t\t\t\tthis.checkStorageDisposed(callName, error),\n\t\t});\n\t}\n}\n"]}
1
+ {"version":3,"file":"retriableDocumentStorageService.js","sourceRoot":"","sources":["../src/retriableDocumentStorageService.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { assert } from \"@fluidframework/core-utils\";\nimport {\n\tFetchSource,\n\tIDocumentStorageService,\n\tIDocumentStorageServicePolicies,\n\tISummaryContext,\n} from \"@fluidframework/driver-definitions\";\nimport {\n\tICreateBlobResponse,\n\tISnapshotTree,\n\tISummaryHandle,\n\tISummaryTree,\n\tIVersion,\n} from \"@fluidframework/protocol-definitions\";\nimport { IDisposable } from \"@fluidframework/core-interfaces\";\nimport { GenericError, ITelemetryLoggerExt } from \"@fluidframework/telemetry-utils\";\nimport { runWithRetry } from \"@fluidframework/driver-utils\";\n\nexport class RetriableDocumentStorageService implements IDocumentStorageService, IDisposable {\n\tprivate _disposed = false;\n\tprivate internalStorageService: IDocumentStorageService | undefined;\n\tconstructor(\n\t\tprivate readonly internalStorageServiceP: Promise<IDocumentStorageService>,\n\t\tprivate readonly logger: ITelemetryLoggerExt,\n\t) {\n\t\tthis.internalStorageServiceP.then((s) => (this.internalStorageService = s)).catch(() => {});\n\t}\n\n\tpublic get policies(): IDocumentStorageServicePolicies | undefined {\n\t\tif (this.internalStorageService) {\n\t\t\treturn this.internalStorageService.policies;\n\t\t}\n\t\tthrow new Error(\"storage service not yet instantiated\");\n\t}\n\tpublic get disposed() {\n\t\treturn this._disposed;\n\t}\n\tpublic dispose() {\n\t\tthis._disposed = true;\n\t}\n\n\tpublic get repositoryUrl(): string {\n\t\tif (this.internalStorageService) {\n\t\t\treturn this.internalStorageService.repositoryUrl;\n\t\t}\n\t\tthrow new Error(\"storage service not yet instantiated\");\n\t}\n\n\tpublic async getSnapshotTree(\n\t\tversion?: IVersion,\n\t\tscenarioName?: string,\n\t): Promise<ISnapshotTree | null> {\n\t\treturn this.runWithRetry(\n\t\t\tasync () =>\n\t\t\t\tthis.internalStorageServiceP.then(async (s) =>\n\t\t\t\t\ts.getSnapshotTree(version, scenarioName),\n\t\t\t\t),\n\t\t\t\"storage_getSnapshotTree\",\n\t\t);\n\t}\n\n\tpublic async readBlob(id: string): Promise<ArrayBufferLike> {\n\t\treturn this.runWithRetry(\n\t\t\tasync () => this.internalStorageServiceP.then(async (s) => s.readBlob(id)),\n\t\t\t\"storage_readBlob\",\n\t\t);\n\t}\n\n\tpublic async getVersions(\n\t\tversionId: string | null,\n\t\tcount: number,\n\t\tscenarioName?: string,\n\t\tfetchSource?: FetchSource,\n\t): Promise<IVersion[]> {\n\t\treturn this.runWithRetry(\n\t\t\tasync () =>\n\t\t\t\tthis.internalStorageServiceP.then(async (s) =>\n\t\t\t\t\ts.getVersions(versionId, count, scenarioName, fetchSource),\n\t\t\t\t),\n\t\t\t\"storage_getVersions\",\n\t\t);\n\t}\n\n\tpublic async uploadSummaryWithContext(\n\t\tsummary: ISummaryTree,\n\t\tcontext: ISummaryContext,\n\t): Promise<string> {\n\t\t// Not using retry loop here. Couple reasons:\n\t\t// 1. If client lost connectivity, then retry loop will result in uploading stale summary\n\t\t// by stale summarizer after connectivity comes back. It will cause failures for this client and for\n\t\t// real (new) summarizer. This problem in particular should be solved in future by supplying abort handle\n\t\t// on all APIs and caller (ContainerRuntime.submitSummary) aborting call on loss of connectivity\n\t\t// 2. Similar, if we get 429 with retryAfter = 10 minutes, it's likely not the right call to retry summary\n\t\t// upload in 10 minutes - it's better to keep processing ops and retry later. Though caller needs to take\n\t\t// retryAfter into account!\n\t\t// But retry loop is required for creation flow (Container.attach)\n\t\tassert(\n\t\t\t(context.referenceSequenceNumber === 0) === (context.ackHandle === undefined),\n\t\t\t0x251 /* \"creation summary has to have seq=0 && handle === undefined\" */,\n\t\t);\n\t\tif (context.referenceSequenceNumber !== 0) {\n\t\t\treturn this.internalStorageServiceP.then(async (s) =>\n\t\t\t\ts.uploadSummaryWithContext(summary, context),\n\t\t\t);\n\t\t}\n\n\t\t// Creation flow with attachment blobs - need to do retries!\n\t\treturn this.runWithRetry(\n\t\t\tasync () =>\n\t\t\t\tthis.internalStorageServiceP.then(async (s) =>\n\t\t\t\t\ts.uploadSummaryWithContext(summary, context),\n\t\t\t\t),\n\t\t\t\"storage_uploadSummaryWithContext\",\n\t\t);\n\t}\n\n\tpublic async downloadSummary(handle: ISummaryHandle): Promise<ISummaryTree> {\n\t\treturn this.runWithRetry(\n\t\t\tasync () => this.internalStorageServiceP.then(async (s) => s.downloadSummary(handle)),\n\t\t\t\"storage_downloadSummary\",\n\t\t);\n\t}\n\n\tpublic async createBlob(file: ArrayBufferLike): Promise<ICreateBlobResponse> {\n\t\treturn this.runWithRetry(\n\t\t\tasync () => this.internalStorageServiceP.then(async (s) => s.createBlob(file)),\n\t\t\t\"storage_createBlob\",\n\t\t);\n\t}\n\n\tprivate checkStorageDisposed(callName: string, error: unknown) {\n\t\tif (this._disposed) {\n\t\t\tthis.logger.sendTelemetryEvent(\n\t\t\t\t{\n\t\t\t\t\teventName: `${callName}_abortedStorageDisposed`,\n\t\t\t\t\tfetchCallName: callName, // fetchCallName matches logs in runWithRetry.ts\n\t\t\t\t},\n\t\t\t\terror,\n\t\t\t);\n\t\t\t// pre-0.58 error message: storageServiceDisposedCannotRetry\n\t\t\tthrow new GenericError(\"Storage Service is disposed. Cannot retry\", {\n\t\t\t\tcanRetry: false,\n\t\t\t});\n\t\t}\n\t\treturn;\n\t}\n\n\tprivate async runWithRetry<T>(api: () => Promise<T>, callName: string): Promise<T> {\n\t\treturn runWithRetry(api, callName, this.logger, {\n\t\t\tonRetry: (_delayInMs: number, error: unknown) =>\n\t\t\t\tthis.checkStorageDisposed(callName, error),\n\t\t});\n\t}\n}\n"]}
package/lib/utils.d.ts CHANGED
@@ -12,9 +12,23 @@ export interface ISnapshotTreeWithBlobContents extends ISnapshotTree {
12
12
  [path: string]: ISnapshotTreeWithBlobContents;
13
13
  };
14
14
  }
15
+ /**
16
+ * Interface to represent the parsed parts of IResolvedUrl.url to help
17
+ * in getting info about different parts of the url.
18
+ * May not be compatible or relevant for any Url Resolver
19
+ */
15
20
  export interface IParsedUrl {
21
+ /**
22
+ * It is combination of tenantid/docId part of the url.
23
+ */
16
24
  id: string;
25
+ /**
26
+ * It is the deep link path in the url.
27
+ */
17
28
  path: string;
29
+ /**
30
+ * Query string part of the url.
31
+ */
18
32
  query: string;
19
33
  /**
20
34
  * Null means do not use snapshots, undefined means load latest snapshot
@@ -23,7 +37,15 @@ export interface IParsedUrl {
23
37
  */
24
38
  version: string | null | undefined;
25
39
  }
26
- export declare function parseUrl(url: string): IParsedUrl | undefined;
40
+ /**
41
+ * Utility api to parse the IResolvedUrl.url into specific parts like querystring, path to get
42
+ * deep link info etc.
43
+ * Warning - This function may not be compatible with any Url Resolver's resolved url. It works
44
+ * with urls of type: protocol://<string>/.../..?<querystring>
45
+ * @param url - This is the IResolvedUrl.url part of the resolved url.
46
+ * @returns The IParsedUrl representing the input URL, or undefined if the format was not supported
47
+ */
48
+ export declare function tryParseCompatibleResolvedUrl(url: string): IParsedUrl | undefined;
27
49
  /**
28
50
  * Combine the app summary and protocol summary in 1 tree.
29
51
  * @param appSummary - Summary of the app.
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAMH,OAAO,EAAE,YAAY,EAAE,aAAa,EAAe,MAAM,sCAAsC,CAAC;AAEhG,OAAO,EACN,6BAA6B,EAC7B,mCAAmC,EAEnC,MAAM,8BAA8B,CAAC;AAKtC,MAAM,WAAW,6BAA8B,SAAQ,aAAa;IACnE,aAAa,EAAE;QAAE,CAAC,IAAI,EAAE,MAAM,GAAG,eAAe,CAAA;KAAE,CAAC;IACnD,KAAK,EAAE;QAAE,CAAC,IAAI,EAAE,MAAM,GAAG,6BAA6B,CAAA;KAAE,CAAC;CACzD;AAED,MAAM,WAAW,UAAU;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd;;;;OAIG;IACH,OAAO,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;CACnC;AAED,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS,CAW5D;AAED;;;;;GAKG;AACH,wBAAgB,4BAA4B,CAC3C,UAAU,EAAE,YAAY,EACxB,eAAe,EAAE,YAAY,GAC3B,6BAA6B,CAiB/B;AA0DD;;;;GAIG;AACH,wBAAgB,0CAA0C,CACzD,mBAAmB,EAAE,YAAY,EACjC,cAAc,EAAE,YAAY,GAC1B,6BAA6B,CAW/B;AAID,eAAO,MAAM,sCAAsC,8BACvB,YAAY,KACrC,6BAYF,CAAC;AAEF,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,aAAa,GAAG,aAAa,CAE9E;AAED,wBAAgB,qCAAqC,CACpD,KAAK,EAAE,GAAG,GACR,KAAK,IAAI,mCAAmC,CAM9C"}
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAMH,OAAO,EAAE,YAAY,EAAE,aAAa,EAAe,MAAM,sCAAsC,CAAC;AAEhG,OAAO,EACN,6BAA6B,EAC7B,mCAAmC,EAEnC,MAAM,8BAA8B,CAAC;AAKtC,MAAM,WAAW,6BAA8B,SAAQ,aAAa;IACnE,aAAa,EAAE;QAAE,CAAC,IAAI,EAAE,MAAM,GAAG,eAAe,CAAA;KAAE,CAAC;IACnD,KAAK,EAAE;QAAE,CAAC,IAAI,EAAE,MAAM,GAAG,6BAA6B,CAAA;KAAE,CAAC;CACzD;AAED;;;;GAIG;AACH,MAAM,WAAW,UAAU;IAC1B;;OAEG;IACH,EAAE,EAAE,MAAM,CAAC;IACX;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC;IACb;;OAEG;IACH,KAAK,EAAE,MAAM,CAAC;IACd;;;;OAIG;IACH,OAAO,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;CACnC;AAED;;;;;;;GAOG;AACH,wBAAgB,6BAA6B,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS,CAWjF;AAED;;;;;GAKG;AACH,wBAAgB,4BAA4B,CAC3C,UAAU,EAAE,YAAY,EACxB,eAAe,EAAE,YAAY,GAC3B,6BAA6B,CAiB/B;AA0DD;;;;GAIG;AACH,wBAAgB,0CAA0C,CACzD,mBAAmB,EAAE,YAAY,EACjC,cAAc,EAAE,YAAY,GAC1B,6BAA6B,CAW/B;AAID,eAAO,MAAM,sCAAsC,8BACvB,YAAY,KACrC,6BAYF,CAAC;AAEF,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,aAAa,GAAG,aAAa,CAE9E;AAED,wBAAgB,qCAAqC,CACpD,KAAK,EAAE,GAAG,GACR,KAAK,IAAI,mCAAmC,CAM9C"}
package/lib/utils.js CHANGED
@@ -10,7 +10,15 @@ import { SummaryType } from "@fluidframework/protocol-definitions";
10
10
  import { LoggingError } from "@fluidframework/telemetry-utils";
11
11
  import { isCombinedAppAndProtocolSummary, } from "@fluidframework/driver-utils";
12
12
  import { DriverErrorTypes } from "@fluidframework/driver-definitions";
13
- export function parseUrl(url) {
13
+ /**
14
+ * Utility api to parse the IResolvedUrl.url into specific parts like querystring, path to get
15
+ * deep link info etc.
16
+ * Warning - This function may not be compatible with any Url Resolver's resolved url. It works
17
+ * with urls of type: protocol://<string>/.../..?<querystring>
18
+ * @param url - This is the IResolvedUrl.url part of the resolved url.
19
+ * @returns The IParsedUrl representing the input URL, or undefined if the format was not supported
20
+ */
21
+ export function tryParseCompatibleResolvedUrl(url) {
14
22
  const parsed = parse(url, true);
15
23
  if (typeof parsed.pathname !== "string") {
16
24
  throw new LoggingError("Failed to parse pathname");
package/lib/utils.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { parse } from \"url\";\nimport { v4 as uuid } from \"uuid\";\nimport { stringToBuffer, Uint8ArrayToArrayBuffer } from \"@fluid-internal/client-utils\";\nimport { assert, unreachableCase } from \"@fluidframework/core-utils\";\nimport { ISummaryTree, ISnapshotTree, SummaryType } from \"@fluidframework/protocol-definitions\";\nimport { LoggingError } from \"@fluidframework/telemetry-utils\";\nimport {\n\tCombinedAppAndProtocolSummary,\n\tDeltaStreamConnectionForbiddenError,\n\tisCombinedAppAndProtocolSummary,\n} from \"@fluidframework/driver-utils\";\nimport { DriverErrorTypes } from \"@fluidframework/driver-definitions\";\n\n// This is used when we rehydrate a container from the snapshot. Here we put the blob contents\n// in separate property: blobContents.\nexport interface ISnapshotTreeWithBlobContents extends ISnapshotTree {\n\tblobsContents: { [path: string]: ArrayBufferLike };\n\ttrees: { [path: string]: ISnapshotTreeWithBlobContents };\n}\n\nexport interface IParsedUrl {\n\tid: string;\n\tpath: string;\n\tquery: string;\n\t/**\n\t * Null means do not use snapshots, undefined means load latest snapshot\n\t * otherwise it's version ID passed to IDocumentStorageService.getVersions() to figure out what snapshot to use.\n\t * If needed, can add undefined which is treated by Container.load() as load latest snapshot.\n\t */\n\tversion: string | null | undefined;\n}\n\nexport function parseUrl(url: string): IParsedUrl | undefined {\n\tconst parsed = parse(url, true);\n\tif (typeof parsed.pathname !== \"string\") {\n\t\tthrow new LoggingError(\"Failed to parse pathname\");\n\t}\n\tconst query = parsed.search ?? \"\";\n\tconst regex = /^\\/([^/]*\\/[^/]*)(\\/?.*)$/;\n\tconst match = regex.exec(parsed.pathname);\n\treturn match?.length === 3\n\t\t? { id: match[1], path: match[2], query, version: parsed.query.version as string }\n\t\t: undefined;\n}\n\n/**\n * Combine the app summary and protocol summary in 1 tree.\n * @param appSummary - Summary of the app.\n * @param protocolSummary - Summary of the protocol.\n * @internal\n */\nexport function combineAppAndProtocolSummary(\n\tappSummary: ISummaryTree,\n\tprotocolSummary: ISummaryTree,\n): CombinedAppAndProtocolSummary {\n\tassert(\n\t\t!isCombinedAppAndProtocolSummary(appSummary),\n\t\t0x5a8 /* app summary is already a combined tree! */,\n\t);\n\tassert(\n\t\t!isCombinedAppAndProtocolSummary(protocolSummary),\n\t\t0x5a9 /* protocol summary is already a combined tree! */,\n\t);\n\tconst createNewSummary: CombinedAppAndProtocolSummary = {\n\t\ttype: SummaryType.Tree,\n\t\ttree: {\n\t\t\t\".protocol\": protocolSummary,\n\t\t\t\".app\": appSummary,\n\t\t},\n\t};\n\treturn createNewSummary;\n}\n\n/**\n * Converts summary tree (for upload) to snapshot tree (for download).\n * Summary tree blobs contain contents, but snapshot tree blobs normally\n * contain IDs pointing to storage. This will create 2 blob entries in the\n * snapshot tree for each blob in the summary tree. One will be the regular\n * path pointing to a uniquely generated ID. Then there will be another\n * entry with the path as that uniquely generated ID, and value as the\n * blob contents as a base-64 string.\n * @param summary - summary to convert\n */\nfunction convertSummaryToSnapshotWithEmbeddedBlobContents(\n\tsummary: ISummaryTree,\n): ISnapshotTreeWithBlobContents {\n\tconst treeNode: ISnapshotTreeWithBlobContents = {\n\t\tblobs: {},\n\t\tblobsContents: {},\n\t\ttrees: {},\n\t\tid: uuid(),\n\t\tunreferenced: summary.unreferenced,\n\t};\n\tconst keys = Object.keys(summary.tree);\n\tfor (const key of keys) {\n\t\tconst summaryObject = summary.tree[key];\n\n\t\tswitch (summaryObject.type) {\n\t\t\tcase SummaryType.Tree: {\n\t\t\t\ttreeNode.trees[key] =\n\t\t\t\t\tconvertSummaryToSnapshotWithEmbeddedBlobContents(summaryObject);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase SummaryType.Attachment:\n\t\t\t\ttreeNode.blobs[key] = summaryObject.id;\n\t\t\t\tbreak;\n\t\t\tcase SummaryType.Blob: {\n\t\t\t\tconst blobId = uuid();\n\t\t\t\ttreeNode.blobs[key] = blobId;\n\t\t\t\tconst contentBuffer =\n\t\t\t\t\ttypeof summaryObject.content === \"string\"\n\t\t\t\t\t\t? stringToBuffer(summaryObject.content, \"utf8\")\n\t\t\t\t\t\t: Uint8ArrayToArrayBuffer(summaryObject.content);\n\t\t\t\ttreeNode.blobsContents[blobId] = contentBuffer;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase SummaryType.Handle:\n\t\t\t\tthrow new LoggingError(\n\t\t\t\t\t\"No handles should be there in summary in detached container!!\",\n\t\t\t\t);\n\t\t\t\tbreak;\n\t\t\tdefault: {\n\t\t\t\tunreachableCase(summaryObject, `Unknown tree type ${(summaryObject as any).type}`);\n\t\t\t}\n\t\t}\n\t}\n\treturn treeNode;\n}\n\n/**\n * Combine and convert protocol and app summary tree to format which is readable by container while rehydrating.\n * @param protocolSummaryTree - Protocol Summary Tree\n * @param appSummaryTree - App Summary Tree\n */\nexport function convertProtocolAndAppSummaryToSnapshotTree(\n\tprotocolSummaryTree: ISummaryTree,\n\tappSummaryTree: ISummaryTree,\n): ISnapshotTreeWithBlobContents {\n\t// Shallow copy is fine, since we are doing a deep clone below.\n\tconst combinedSummary: ISummaryTree = {\n\t\ttype: SummaryType.Tree,\n\t\ttree: { ...appSummaryTree.tree },\n\t};\n\n\tcombinedSummary.tree[\".protocol\"] = protocolSummaryTree;\n\tconst snapshotTreeWithBlobContents =\n\t\tconvertSummaryToSnapshotWithEmbeddedBlobContents(combinedSummary);\n\treturn snapshotTreeWithBlobContents;\n}\n\n// This function converts the snapshot taken in detached container(by serialize api) to snapshotTree with which\n// a detached container can be rehydrated.\nexport const getSnapshotTreeFromSerializedContainer = (\n\tdetachedContainerSnapshot: ISummaryTree,\n): ISnapshotTreeWithBlobContents => {\n\tassert(\n\t\tisCombinedAppAndProtocolSummary(detachedContainerSnapshot),\n\t\t0x1e0 /* \"Protocol and App summary trees should be present\" */,\n\t);\n\tconst protocolSummaryTree = detachedContainerSnapshot.tree[\".protocol\"];\n\tconst appSummaryTree = detachedContainerSnapshot.tree[\".app\"];\n\tconst snapshotTreeWithBlobContents = convertProtocolAndAppSummaryToSnapshotTree(\n\t\tprotocolSummaryTree,\n\t\tappSummaryTree,\n\t);\n\treturn snapshotTreeWithBlobContents;\n};\n\nexport function getProtocolSnapshotTree(snapshot: ISnapshotTree): ISnapshotTree {\n\treturn \".protocol\" in snapshot.trees ? snapshot.trees[\".protocol\"] : snapshot;\n}\n\nexport function isDeltaStreamConnectionForbiddenError(\n\terror: any,\n): error is DeltaStreamConnectionForbiddenError {\n\treturn (\n\t\ttypeof error === \"object\" &&\n\t\terror !== null &&\n\t\terror?.errorType === DriverErrorTypes.deltaStreamConnectionForbidden\n\t);\n}\n"]}
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { parse } from \"url\";\nimport { v4 as uuid } from \"uuid\";\nimport { stringToBuffer, Uint8ArrayToArrayBuffer } from \"@fluid-internal/client-utils\";\nimport { assert, unreachableCase } from \"@fluidframework/core-utils\";\nimport { ISummaryTree, ISnapshotTree, SummaryType } from \"@fluidframework/protocol-definitions\";\nimport { LoggingError } from \"@fluidframework/telemetry-utils\";\nimport {\n\tCombinedAppAndProtocolSummary,\n\tDeltaStreamConnectionForbiddenError,\n\tisCombinedAppAndProtocolSummary,\n} from \"@fluidframework/driver-utils\";\nimport { DriverErrorTypes } from \"@fluidframework/driver-definitions\";\n\n// This is used when we rehydrate a container from the snapshot. Here we put the blob contents\n// in separate property: blobContents.\nexport interface ISnapshotTreeWithBlobContents extends ISnapshotTree {\n\tblobsContents: { [path: string]: ArrayBufferLike };\n\ttrees: { [path: string]: ISnapshotTreeWithBlobContents };\n}\n\n/**\n * Interface to represent the parsed parts of IResolvedUrl.url to help\n * in getting info about different parts of the url.\n * May not be compatible or relevant for any Url Resolver\n */\nexport interface IParsedUrl {\n\t/**\n\t * It is combination of tenantid/docId part of the url.\n\t */\n\tid: string;\n\t/**\n\t * It is the deep link path in the url.\n\t */\n\tpath: string;\n\t/**\n\t * Query string part of the url.\n\t */\n\tquery: string;\n\t/**\n\t * Null means do not use snapshots, undefined means load latest snapshot\n\t * otherwise it's version ID passed to IDocumentStorageService.getVersions() to figure out what snapshot to use.\n\t * If needed, can add undefined which is treated by Container.load() as load latest snapshot.\n\t */\n\tversion: string | null | undefined;\n}\n\n/**\n * Utility api to parse the IResolvedUrl.url into specific parts like querystring, path to get\n * deep link info etc.\n * Warning - This function may not be compatible with any Url Resolver's resolved url. It works\n * with urls of type: protocol://<string>/.../..?<querystring>\n * @param url - This is the IResolvedUrl.url part of the resolved url.\n * @returns The IParsedUrl representing the input URL, or undefined if the format was not supported\n */\nexport function tryParseCompatibleResolvedUrl(url: string): IParsedUrl | undefined {\n\tconst parsed = parse(url, true);\n\tif (typeof parsed.pathname !== \"string\") {\n\t\tthrow new LoggingError(\"Failed to parse pathname\");\n\t}\n\tconst query = parsed.search ?? \"\";\n\tconst regex = /^\\/([^/]*\\/[^/]*)(\\/?.*)$/;\n\tconst match = regex.exec(parsed.pathname);\n\treturn match?.length === 3\n\t\t? { id: match[1], path: match[2], query, version: parsed.query.version as string }\n\t\t: undefined;\n}\n\n/**\n * Combine the app summary and protocol summary in 1 tree.\n * @param appSummary - Summary of the app.\n * @param protocolSummary - Summary of the protocol.\n * @internal\n */\nexport function combineAppAndProtocolSummary(\n\tappSummary: ISummaryTree,\n\tprotocolSummary: ISummaryTree,\n): CombinedAppAndProtocolSummary {\n\tassert(\n\t\t!isCombinedAppAndProtocolSummary(appSummary),\n\t\t0x5a8 /* app summary is already a combined tree! */,\n\t);\n\tassert(\n\t\t!isCombinedAppAndProtocolSummary(protocolSummary),\n\t\t0x5a9 /* protocol summary is already a combined tree! */,\n\t);\n\tconst createNewSummary: CombinedAppAndProtocolSummary = {\n\t\ttype: SummaryType.Tree,\n\t\ttree: {\n\t\t\t\".protocol\": protocolSummary,\n\t\t\t\".app\": appSummary,\n\t\t},\n\t};\n\treturn createNewSummary;\n}\n\n/**\n * Converts summary tree (for upload) to snapshot tree (for download).\n * Summary tree blobs contain contents, but snapshot tree blobs normally\n * contain IDs pointing to storage. This will create 2 blob entries in the\n * snapshot tree for each blob in the summary tree. One will be the regular\n * path pointing to a uniquely generated ID. Then there will be another\n * entry with the path as that uniquely generated ID, and value as the\n * blob contents as a base-64 string.\n * @param summary - summary to convert\n */\nfunction convertSummaryToSnapshotWithEmbeddedBlobContents(\n\tsummary: ISummaryTree,\n): ISnapshotTreeWithBlobContents {\n\tconst treeNode: ISnapshotTreeWithBlobContents = {\n\t\tblobs: {},\n\t\tblobsContents: {},\n\t\ttrees: {},\n\t\tid: uuid(),\n\t\tunreferenced: summary.unreferenced,\n\t};\n\tconst keys = Object.keys(summary.tree);\n\tfor (const key of keys) {\n\t\tconst summaryObject = summary.tree[key];\n\n\t\tswitch (summaryObject.type) {\n\t\t\tcase SummaryType.Tree: {\n\t\t\t\ttreeNode.trees[key] =\n\t\t\t\t\tconvertSummaryToSnapshotWithEmbeddedBlobContents(summaryObject);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase SummaryType.Attachment:\n\t\t\t\ttreeNode.blobs[key] = summaryObject.id;\n\t\t\t\tbreak;\n\t\t\tcase SummaryType.Blob: {\n\t\t\t\tconst blobId = uuid();\n\t\t\t\ttreeNode.blobs[key] = blobId;\n\t\t\t\tconst contentBuffer =\n\t\t\t\t\ttypeof summaryObject.content === \"string\"\n\t\t\t\t\t\t? stringToBuffer(summaryObject.content, \"utf8\")\n\t\t\t\t\t\t: Uint8ArrayToArrayBuffer(summaryObject.content);\n\t\t\t\ttreeNode.blobsContents[blobId] = contentBuffer;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase SummaryType.Handle:\n\t\t\t\tthrow new LoggingError(\n\t\t\t\t\t\"No handles should be there in summary in detached container!!\",\n\t\t\t\t);\n\t\t\t\tbreak;\n\t\t\tdefault: {\n\t\t\t\tunreachableCase(summaryObject, `Unknown tree type ${(summaryObject as any).type}`);\n\t\t\t}\n\t\t}\n\t}\n\treturn treeNode;\n}\n\n/**\n * Combine and convert protocol and app summary tree to format which is readable by container while rehydrating.\n * @param protocolSummaryTree - Protocol Summary Tree\n * @param appSummaryTree - App Summary Tree\n */\nexport function convertProtocolAndAppSummaryToSnapshotTree(\n\tprotocolSummaryTree: ISummaryTree,\n\tappSummaryTree: ISummaryTree,\n): ISnapshotTreeWithBlobContents {\n\t// Shallow copy is fine, since we are doing a deep clone below.\n\tconst combinedSummary: ISummaryTree = {\n\t\ttype: SummaryType.Tree,\n\t\ttree: { ...appSummaryTree.tree },\n\t};\n\n\tcombinedSummary.tree[\".protocol\"] = protocolSummaryTree;\n\tconst snapshotTreeWithBlobContents =\n\t\tconvertSummaryToSnapshotWithEmbeddedBlobContents(combinedSummary);\n\treturn snapshotTreeWithBlobContents;\n}\n\n// This function converts the snapshot taken in detached container(by serialize api) to snapshotTree with which\n// a detached container can be rehydrated.\nexport const getSnapshotTreeFromSerializedContainer = (\n\tdetachedContainerSnapshot: ISummaryTree,\n): ISnapshotTreeWithBlobContents => {\n\tassert(\n\t\tisCombinedAppAndProtocolSummary(detachedContainerSnapshot),\n\t\t0x1e0 /* \"Protocol and App summary trees should be present\" */,\n\t);\n\tconst protocolSummaryTree = detachedContainerSnapshot.tree[\".protocol\"];\n\tconst appSummaryTree = detachedContainerSnapshot.tree[\".app\"];\n\tconst snapshotTreeWithBlobContents = convertProtocolAndAppSummaryToSnapshotTree(\n\t\tprotocolSummaryTree,\n\t\tappSummaryTree,\n\t);\n\treturn snapshotTreeWithBlobContents;\n};\n\nexport function getProtocolSnapshotTree(snapshot: ISnapshotTree): ISnapshotTree {\n\treturn \".protocol\" in snapshot.trees ? snapshot.trees[\".protocol\"] : snapshot;\n}\n\nexport function isDeltaStreamConnectionForbiddenError(\n\terror: any,\n): error is DeltaStreamConnectionForbiddenError {\n\treturn (\n\t\ttypeof error === \"object\" &&\n\t\terror !== null &&\n\t\terror?.errorType === DriverErrorTypes.deltaStreamConnectionForbidden\n\t);\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fluidframework/container-loader",
3
- "version": "2.0.0-internal.7.1.0",
3
+ "version": "2.0.0-internal.7.2.0",
4
4
  "description": "Fluid container loader",
5
5
  "homepage": "https://fluidframework.com",
6
6
  "repository": {
@@ -35,16 +35,16 @@
35
35
  "temp-directory": "nyc/.nyc_output"
36
36
  },
37
37
  "dependencies": {
38
- "@fluid-internal/client-utils": ">=2.0.0-internal.7.1.0 <2.0.0-internal.7.2.0",
39
- "@fluidframework/container-definitions": ">=2.0.0-internal.7.1.0 <2.0.0-internal.7.2.0",
40
- "@fluidframework/core-interfaces": ">=2.0.0-internal.7.1.0 <2.0.0-internal.7.2.0",
41
- "@fluidframework/core-utils": ">=2.0.0-internal.7.1.0 <2.0.0-internal.7.2.0",
42
- "@fluidframework/driver-definitions": ">=2.0.0-internal.7.1.0 <2.0.0-internal.7.2.0",
43
- "@fluidframework/driver-utils": ">=2.0.0-internal.7.1.0 <2.0.0-internal.7.2.0",
38
+ "@fluid-internal/client-utils": ">=2.0.0-internal.7.2.0 <2.0.0-internal.7.3.0",
39
+ "@fluidframework/container-definitions": ">=2.0.0-internal.7.2.0 <2.0.0-internal.7.3.0",
40
+ "@fluidframework/core-interfaces": ">=2.0.0-internal.7.2.0 <2.0.0-internal.7.3.0",
41
+ "@fluidframework/core-utils": ">=2.0.0-internal.7.2.0 <2.0.0-internal.7.3.0",
42
+ "@fluidframework/driver-definitions": ">=2.0.0-internal.7.2.0 <2.0.0-internal.7.3.0",
43
+ "@fluidframework/driver-utils": ">=2.0.0-internal.7.2.0 <2.0.0-internal.7.3.0",
44
44
  "@fluidframework/protocol-base": "^2.0.1",
45
45
  "@fluidframework/protocol-definitions": "^3.0.0",
46
- "@fluidframework/telemetry-utils": ">=2.0.0-internal.7.1.0 <2.0.0-internal.7.2.0",
47
- "debug": "^4.1.1",
46
+ "@fluidframework/telemetry-utils": ">=2.0.0-internal.7.2.0 <2.0.0-internal.7.3.0",
47
+ "debug": "^4.3.4",
48
48
  "double-ended-queue": "^2.1.0-0",
49
49
  "events": "^3.1.0",
50
50
  "lodash": "^4.17.21",
@@ -52,13 +52,13 @@
52
52
  "uuid": "^9.0.0"
53
53
  },
54
54
  "devDependencies": {
55
- "@fluid-internal/test-loader-utils": ">=2.0.0-internal.7.1.0 <2.0.0-internal.7.2.0",
56
- "@fluid-tools/build-cli": "^0.25.0",
57
- "@fluidframework/build-common": "^2.0.1",
58
- "@fluidframework/build-tools": "^0.25.0",
59
- "@fluidframework/container-loader-previous": "npm:@fluidframework/container-loader@2.0.0-internal.7.0.0",
55
+ "@fluid-internal/test-loader-utils": ">=2.0.0-internal.7.2.0 <2.0.0-internal.7.3.0",
56
+ "@fluid-tools/build-cli": "^0.26.1",
57
+ "@fluidframework/build-common": "^2.0.3",
58
+ "@fluidframework/build-tools": "^0.26.1",
59
+ "@fluidframework/container-loader-previous": "npm:@fluidframework/container-loader@2.0.0-internal.7.1.0",
60
60
  "@fluidframework/eslint-config-fluid": "^3.0.0",
61
- "@fluidframework/mocha-test-setup": ">=2.0.0-internal.7.1.0 <2.0.0-internal.7.2.0",
61
+ "@fluidframework/mocha-test-setup": ">=2.0.0-internal.7.2.0 <2.0.0-internal.7.3.0",
62
62
  "@microsoft/api-extractor": "^7.37.0",
63
63
  "@types/double-ended-queue": "^2.1.0",
64
64
  "@types/events": "^3.0.0",
@@ -67,7 +67,6 @@
67
67
  "@types/node": "^16.18.38",
68
68
  "@types/sinon": "^7.0.13",
69
69
  "c8": "^7.7.1",
70
- "copyfiles": "^2.4.1",
71
70
  "cross-env": "^7.0.3",
72
71
  "eslint": "~8.50.0",
73
72
  "mocha": "^10.2.0",
@@ -91,7 +90,7 @@
91
90
  "build:genver": "gen-version",
92
91
  "build:test": "tsc --project ./src/test/tsconfig.json",
93
92
  "ci:build:docs": "api-extractor run",
94
- "clean": "rimraf --glob 'dist' 'lib' '*.tsbuildinfo' '*.build.log' '_api-extractor-temp' 'nyc'",
93
+ "clean": "rimraf --glob dist lib \"*.tsbuildinfo\" \"*.build.log\" _api-extractor-temp nyc",
95
94
  "eslint": "eslint --format stylish src",
96
95
  "eslint:fix": "eslint --format stylish src --fix --fix-type problem,suggestion,layout",
97
96
  "format": "npm run prettier:fix",
@@ -3,7 +3,7 @@
3
3
  * Licensed under the MIT License.
4
4
  */
5
5
 
6
- import { IDisposable, ITelemetryProperties } from "@fluidframework/core-interfaces";
6
+ import { IDisposable, ITelemetryProperties, LogLevel } from "@fluidframework/core-interfaces";
7
7
  import { assert } from "@fluidframework/core-utils";
8
8
  import { performance, TypedEventEmitter } from "@fluid-internal/client-utils";
9
9
  import {
@@ -585,6 +585,14 @@ export class ConnectionManager implements IConnectionManager {
585
585
  this.logger.sendTelemetryEvent({ eventName: "ReceivedClosedConnection" });
586
586
  connection = undefined;
587
587
  }
588
+ this.logger.sendTelemetryEvent(
589
+ {
590
+ eventName: "ConnectionReceived",
591
+ connected: connection !== undefined && connection.disposed === false,
592
+ },
593
+ undefined,
594
+ LogLevel.verbose,
595
+ );
588
596
  } catch (origError: any) {
589
597
  if (isDeltaStreamConnectionForbiddenError(origError)) {
590
598
  connection = new NoDeltaStream(origError.storageOnlyReason, {
@@ -674,8 +682,8 @@ export class ConnectionManager implements IConnectionManager {
674
682
  );
675
683
  }
676
684
 
677
- // Check for abort signal after while loop as well
678
- if (abortSignal.aborted === true) {
685
+ // Check for abort signal after while loop as well or we've been disposed
686
+ if (abortSignal.aborted === true || this._disposed) {
679
687
  connection.dispose();
680
688
  this.logger.sendTelemetryEvent({
681
689
  eventName: "ConnectionAttemptCancelled",
@@ -1051,9 +1059,9 @@ export class ConnectionManager implements IConnectionManager {
1051
1059
  };
1052
1060
  }
1053
1061
 
1054
- public submitSignal(content: any) {
1062
+ public submitSignal(content: any, targetClientId?: string) {
1055
1063
  if (this.connection !== undefined) {
1056
- this.connection.submitSignal(content);
1064
+ this.connection.submitSignal(content, targetClientId);
1057
1065
  } else {
1058
1066
  this.logger.sendErrorEvent({ eventName: "submitSignalDisconnected" });
1059
1067
  }
package/src/container.ts CHANGED
@@ -40,6 +40,7 @@ import {
40
40
  IRuntime,
41
41
  ReadOnlyInfo,
42
42
  isFluidCodeDetails,
43
+ IGetPendingLocalStateProps,
43
44
  } from "@fluidframework/container-definitions";
44
45
  import {
45
46
  IDocumentService,
@@ -134,6 +135,8 @@ const savedContainerEvent = "saved";
134
135
 
135
136
  const packageNotFactoryError = "Code package does not implement IRuntimeFactory";
136
137
 
138
+ const hasBlobsSummaryTree = ".hasAttachmentBlobs";
139
+
137
140
  /**
138
141
  * @internal
139
142
  */
@@ -473,7 +476,11 @@ export class Container
473
476
  container.mc.logger,
474
477
  { eventName: "RehydrateDetachedFromSnapshot" },
475
478
  async (_event) => {
476
- const deserializedSummary = JSON.parse(snapshot) as ISummaryTree;
479
+ const deserializedSummary = JSON.parse(snapshot);
480
+ if (!isCombinedAppAndProtocolSummary(deserializedSummary, hasBlobsSummaryTree)) {
481
+ throw new UsageError("Cannot rehydrate detached container. Incorrect format");
482
+ }
483
+
477
484
  await container.rehydrateDetachedFromSnapshot(deserializedSummary);
478
485
  return container;
479
486
  },
@@ -580,6 +587,7 @@ export class Container
580
587
  private readonly savedOps: ISequencedDocumentMessage[] = [];
581
588
  private baseSnapshot?: ISnapshotTree;
582
589
  private baseSnapshotBlobs?: ISerializableBlobContents;
590
+ private readonly _containerId: string;
583
591
 
584
592
  private lastVisible: number | undefined;
585
593
  private readonly visibilityEventHandler: (() => void) | undefined;
@@ -815,6 +823,8 @@ export class Container
815
823
  const clientType = `${interactive ? "interactive" : "noninteractive"}${
816
824
  type !== undefined && type !== "" ? `/${type}` : ""
817
825
  }`;
826
+
827
+ this._containerId = uuid();
818
828
  // Need to use the property getter for docId because for detached flow we don't have the docId initially.
819
829
  // We assign the id later so property getter is used.
820
830
  this.subLogger = createChildLogger({
@@ -822,7 +832,7 @@ export class Container
822
832
  properties: {
823
833
  all: {
824
834
  clientType, // Differentiating summarizer container from main container
825
- containerId: uuid(),
835
+ containerId: this._containerId,
826
836
  docId: () => this.resolvedUrl?.id,
827
837
  containerAttachState: () => this._attachState,
828
838
  containerLifecycleState: () => this._lifecycleState,
@@ -1103,12 +1113,17 @@ export class Container
1103
1113
  }
1104
1114
  }
1105
1115
 
1106
- public async closeAndGetPendingLocalState(): Promise<string> {
1116
+ public async closeAndGetPendingLocalState(
1117
+ stopBlobAttachingSignal?: AbortSignal,
1118
+ ): Promise<string> {
1107
1119
  // runtime matches pending ops to successful ones by clientId and client seq num, so we need to close the
1108
1120
  // container at the same time we get pending state, otherwise this container could reconnect and resubmit with
1109
1121
  // a new clientId and a future container using stale pending state without the new clientId would resubmit them
1110
1122
  this.disconnectInternal({ text: "closeAndGetPendingLocalState" }); // TODO https://dev.azure.com/fluidframework/internal/_workitems/edit/5127
1111
- const pendingState = await this.getPendingLocalStateCore({ notifyImminentClosure: true });
1123
+ const pendingState = await this.getPendingLocalStateCore({
1124
+ notifyImminentClosure: true,
1125
+ stopBlobAttachingSignal,
1126
+ });
1112
1127
  this.close();
1113
1128
  return pendingState;
1114
1129
  }
@@ -1117,7 +1132,7 @@ export class Container
1117
1132
  return this.getPendingLocalStateCore({ notifyImminentClosure: false });
1118
1133
  }
1119
1134
 
1120
- private async getPendingLocalStateCore(props: { notifyImminentClosure: boolean }) {
1135
+ private async getPendingLocalStateCore(props: IGetPendingLocalStateProps) {
1121
1136
  return PerformanceEvent.timedExecAsync(
1122
1137
  this.mc.logger,
1123
1138
  {
@@ -1178,7 +1193,7 @@ export class Container
1178
1193
  const combinedSummary = combineAppAndProtocolSummary(appSummary, protocolSummary);
1179
1194
 
1180
1195
  if (this.detachedBlobStorage && this.detachedBlobStorage.size > 0) {
1181
- combinedSummary.tree[".hasAttachmentBlobs"] = {
1196
+ combinedSummary.tree[hasBlobsSummaryTree] = {
1182
1197
  type: SummaryType.Blob,
1183
1198
  content: "true",
1184
1199
  };
@@ -1264,7 +1279,7 @@ export class Container
1264
1279
  }, // progress
1265
1280
  );
1266
1281
  }
1267
- await this.storageAdapter.connectToService(this.service);
1282
+ this.storageAdapter.connectToService(this.service);
1268
1283
 
1269
1284
  if (hasAttachmentBlobs) {
1270
1285
  // upload blobs to storage
@@ -1574,14 +1589,7 @@ export class Container
1574
1589
  this.connectToDeltaStream(connectionArgs);
1575
1590
  }
1576
1591
 
1577
- if (!pendingLocalState) {
1578
- await this.storageAdapter.connectToService(this.service);
1579
- } else {
1580
- // if we have pendingLocalState we can load without storage; don't wait for connection
1581
- this.storageAdapter.connectToService(this.service).catch((error) => {
1582
- this.close(error);
1583
- });
1584
- }
1592
+ this.storageAdapter.connectToService(this.service);
1585
1593
 
1586
1594
  this._attachState = AttachState.Attached;
1587
1595
 
@@ -1815,12 +1823,13 @@ export class Container
1815
1823
  }
1816
1824
 
1817
1825
  private async rehydrateDetachedFromSnapshot(detachedContainerSnapshot: ISummaryTree) {
1818
- if (detachedContainerSnapshot.tree[".hasAttachmentBlobs"] !== undefined) {
1826
+ if (detachedContainerSnapshot.tree[hasBlobsSummaryTree] !== undefined) {
1819
1827
  assert(
1820
1828
  !!this.detachedBlobStorage && this.detachedBlobStorage.size > 0,
1821
1829
  0x250 /* "serialized container with attachment blobs must be rehydrated with detached blob storage" */,
1822
1830
  );
1823
- delete detachedContainerSnapshot.tree[".hasAttachmentBlobs"];
1831
+ // eslint-disable-next-line @typescript-eslint/no-dynamic-delete
1832
+ delete detachedContainerSnapshot.tree[hasBlobsSummaryTree];
1824
1833
  }
1825
1834
 
1826
1835
  const snapshotTree = getSnapshotTreeFromSerializedContainer(detachedContainerSnapshot);
@@ -2007,6 +2016,7 @@ export class Container
2007
2016
  client.details.environment = [
2008
2017
  client.details.environment,
2009
2018
  ` loaderVersion:${pkgVersion}`,
2019
+ ` containerId:${this._containerId}`,
2010
2020
  ].join(";");
2011
2021
  return client;
2012
2022
  }
@@ -2335,8 +2345,8 @@ export class Container
2335
2345
  this.emit("op", message);
2336
2346
  }
2337
2347
 
2338
- private submitSignal(message: any) {
2339
- this._deltaManager.submitSignal(JSON.stringify(message));
2348
+ private submitSignal(content: any, targetClientId?: string) {
2349
+ this._deltaManager.submitSignal(JSON.stringify(content), targetClientId);
2340
2350
  }
2341
2351
 
2342
2352
  private processSignal(message: ISignalMessage) {
@@ -2430,7 +2440,7 @@ export class Container
2430
2440
  this.submitSummaryMessage(summaryOp, referenceSequenceNumber),
2431
2441
  (batch: IBatchMessage[], referenceSequenceNumber?: number) =>
2432
2442
  this.submitBatch(batch, referenceSequenceNumber),
2433
- (message) => this.submitSignal(message),
2443
+ (content, targetClientId) => this.submitSignal(content, targetClientId),
2434
2444
  (error?: ICriticalContainerError) => this.dispose(error),
2435
2445
  (error?: ICriticalContainerError) => this.close(error),
2436
2446
  this.updateDirtyContainerState,
@@ -2513,7 +2523,7 @@ export class Container
2513
2523
 
2514
2524
  /**
2515
2525
  * IContainer interface that includes experimental features still under development.
2516
- * @experimental
2526
+ * @alpha
2517
2527
  */
2518
2528
  export interface IContainerExperimental extends IContainer {
2519
2529
  /**
@@ -2521,7 +2531,7 @@ export interface IContainerExperimental extends IContainer {
2521
2531
  * submission and potential document corruption. The blob returned MUST be deleted if and when this
2522
2532
  * container emits a "connected" event.
2523
2533
  * @returns serialized blob that can be passed to Loader.resolve()
2524
- * @experimental misuse of this API can result in duplicate op submission and potential document corruption
2534
+ * @alpha misuse of this API can result in duplicate op submission and potential document corruption
2525
2535
  * {@link https://github.com/microsoft/FluidFramework/blob/main/packages/loader/container-loader/closeAndGetPendingLocalState.md}
2526
2536
  */
2527
2537
  getPendingLocalState?(): Promise<string>;
@@ -2529,8 +2539,8 @@ export interface IContainerExperimental extends IContainer {
2529
2539
  /**
2530
2540
  * Closes the container and returns serialized local state intended to be
2531
2541
  * given to a newly loaded container.
2532
- * @experimental
2542
+ * @alpha
2533
2543
  * {@link https://github.com/microsoft/FluidFramework/blob/main/packages/loader/container-loader/closeAndGetPendingLocalState.md}
2534
2544
  */
2535
- closeAndGetPendingLocalState?(): Promise<string>;
2545
+ closeAndGetPendingLocalState?(stopBlobAttachingSignal?: AbortSignal): Promise<string>;
2536
2546
  }
@@ -85,7 +85,7 @@ export class ContainerContext implements IContainerContext {
85
85
  batch: IBatchMessage[],
86
86
  referenceSequenceNumber?: number,
87
87
  ) => number,
88
- public readonly submitSignalFn: (contents: any) => void,
88
+ public readonly submitSignalFn: (content: any, targetClientId?: string) => void,
89
89
  public readonly disposeFn: (error?: ICriticalContainerError) => void,
90
90
  public readonly closeFn: (error?: ICriticalContainerError) => void,
91
91
  public readonly updateDirtyContainerState: (dirty: boolean) => void,
@@ -79,14 +79,14 @@ export class ContainerStorageAdapter implements IDocumentStorageService, IDispos
79
79
  this.disposed = true;
80
80
  }
81
81
 
82
- public async connectToService(service: IDocumentService): Promise<void> {
82
+ public connectToService(service: IDocumentService): void {
83
83
  if (!(this._storageService instanceof BlobOnlyStorage)) {
84
84
  return;
85
85
  }
86
86
 
87
- const storageService = await service.connectToStorage();
87
+ const storageServiceP = service.connectToStorage();
88
88
  const retriableStorage = (this._storageService = new RetriableDocumentStorageService(
89
- storageService,
89
+ storageServiceP,
90
90
  this.logger,
91
91
  ));
92
92
 
package/src/contracts.ts CHANGED
@@ -100,7 +100,7 @@ export interface IConnectionManager {
100
100
  * Submits signal to relay service.
101
101
  * Called only when active connection is present.
102
102
  */
103
- submitSignal(content: any): void;
103
+ submitSignal(content: any, targetClientId?: string): void;
104
104
 
105
105
  /**
106
106
  * Submits messages to relay service.