@fluidframework/replay-driver 3.0.2 → 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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # @fluidframework/replay-driver
2
2
 
3
+ ## 3.1.0
4
+
5
+ Dependency updates only.
6
+
3
7
  ## 3.0.0
4
8
 
5
9
  ### Minor Changes
package/README.md CHANGED
@@ -3,8 +3,7 @@
3
3
  This is an implementation of a driver which provides a DocumentService which uses the DocumentService provided to it to fetch ops and then replay those ops
4
4
  to mimic the web socket connection.
5
5
 
6
- <!-- AUTO-GENERATED-CONTENT:START (LIBRARY_README_HEADER) -->
7
-
6
+ <!-- markdown-magic:begin {"transform":"library-readme-header","headingLevel":2} -->
8
7
  <!-- prettier-ignore-start -->
9
8
  <!-- NOTE: This section is automatically generated using @fluid-tools/markdown-magic. Do not update these generated contents directly. -->
10
9
 
@@ -29,11 +28,9 @@ npm i @fluidframework/replay-driver
29
28
  Read the **@fluidframework/replay-driver** API documentation at <https://fluidframework.com/docs/apis/replay-driver>.
30
29
 
31
30
  <!-- prettier-ignore-end -->
31
+ <!-- markdown-magic:end -->
32
32
 
33
- <!-- AUTO-GENERATED-CONTENT:END -->
34
-
35
- <!-- AUTO-GENERATED-CONTENT:START (README_FOOTER) -->
36
-
33
+ <!-- markdown-magic:begin {"transform":"readme-footer","headingLevel":2} -->
37
34
  <!-- prettier-ignore-start -->
38
35
  <!-- NOTE: This section is automatically generated using @fluid-tools/markdown-magic. Do not update these generated contents directly. -->
39
36
 
@@ -50,29 +47,29 @@ To request support for a configuration that is not listed, file an issue.
50
47
  The product team will evaluate your request.
51
48
  In the issue, specify the current status of the configuration:
52
49
 
53
- - The configuration works but needs official support.
54
- - The configuration does not work and requires changes.
50
+ - The configuration works but needs official support.
51
+ - The configuration does not work and requires changes.
55
52
 
56
53
  ### Supported Runtimes
57
54
 
58
- - Fluid Framework supports Node.js versions 22 and 24 while they receive [upstream support](https://nodejs.org/en/about/previous-releases).
59
- - Fluid Framework will stop support for version 22 [when upstream support ends on 2027-04-30](https://github.com/nodejs/release#release-schedule).
60
- - Fluid Framework does not support Node.js with the `--no-experimental-fetch` flag.
61
- - Fluid Framework supports modern browsers that support the ES2022 standard library.
55
+ - Fluid Framework supports Node.js versions 22 and 24 while they receive [upstream support](https://nodejs.org/en/about/previous-releases).
56
+ - Fluid Framework will stop support for version 22 [when upstream support ends on 2027-04-30](https://github.com/nodejs/release#release-schedule).
57
+ - Fluid Framework does not support Node.js with the `--no-experimental-fetch` flag.
58
+ - Fluid Framework supports modern browsers that support the ES2022 standard library.
62
59
 
63
60
  ### Supported Tools
64
61
 
65
- - [TypeScript 6.0](https://typescriptdocs.com/release-notes/TypeScript%206.0):
66
- - Fluid Framework supports all [`strict`](https://www.typescriptlang.org/tsconfig) options.
67
- - Set the build targets (`lib`, `target`) to `ES2022` or later.
68
- - Enable [`strictNullChecks`](https://www.typescriptlang.org/tsconfig).
69
- - Fluid Framework does not support [configuration options deprecated in TypeScript 6.0](https://typescriptdocs.com/release-notes/TypeScript%206.0#breaking-changes-and-deprecations-in-typescript-6-0).
70
- - Fluid Framework does not fully support `exactOptionalPropertyTypes`.
71
- If you enable this option, do not use `in`, `Reflect.has`, `Object.hasOwn`, or `Object.prototype.hasOwnProperty` to narrow members of Fluid Framework types.
72
- These methods can incorrectly exclude `undefined` from the possible values.
73
- - [webpack](https://webpack.js.org/) 5
74
- - We do not require a specific bundler.
75
- Other bundlers that handle ES Modules can work, but we actively test only webpack.
62
+ - [TypeScript 6.0](https://typescriptdocs.com/release-notes/TypeScript%206.0):
63
+ - Fluid Framework supports all [`strict`](https://www.typescriptlang.org/tsconfig) options.
64
+ - Set the build targets (`lib`, `target`) to `ES2022` or later.
65
+ - Enable [`strictNullChecks`](https://www.typescriptlang.org/tsconfig).
66
+ - Fluid Framework does not support [configuration options deprecated in TypeScript 6.0](https://typescriptdocs.com/release-notes/TypeScript%206.0#breaking-changes-and-deprecations-in-typescript-6-0).
67
+ - Fluid Framework does not fully support `exactOptionalPropertyTypes`.
68
+ If you enable this option, do not use `in`, `Reflect.has`, `Object.hasOwn`, or `Object.prototype.hasOwnProperty` to narrow members of Fluid Framework types.
69
+ These methods can incorrectly exclude `undefined` from the possible values.
70
+ - [webpack](https://webpack.js.org/) 5
71
+ - We do not require a specific bundler.
72
+ Other bundlers that handle ES Modules can work, but we actively test only webpack.
76
73
 
77
74
  ### Module Resolution
78
75
 
@@ -83,25 +80,25 @@ Do not use `Node10` module resolution.
83
80
 
84
81
  ### Module Formats
85
82
 
86
- - ES Modules:
87
- Use ES Modules to consume Fluid Framework client packages, including in Node.js.
88
- - CommonJS:
89
- Fluid Framework does not officially support CommonJS in version 3.0 or later.
83
+ - ES Modules:
84
+ Use ES Modules to consume Fluid Framework client packages, including in Node.js.
85
+ - CommonJS:
86
+ Fluid Framework does not officially support CommonJS in version 3.0 or later.
90
87
 
91
88
  ## Contribution Guidelines
92
89
 
93
90
  You can [contribute](https://github.com/microsoft/FluidFramework/blob/main/CONTRIBUTING.md) to Fluid Framework in these ways:
94
91
 
95
- - Answer questions in [GitHub Discussions](https://github.com/microsoft/FluidFramework/discussions).
96
- - [Submit bug reports](https://github.com/microsoft/FluidFramework/issues) and help verify fixes.
97
- - Review [source code changes](https://github.com/microsoft/FluidFramework/pulls).
98
- - [Contribute bug fixes](https://github.com/microsoft/FluidFramework/blob/main/CONTRIBUTING.md).
92
+ - Answer questions in [GitHub Discussions](https://github.com/microsoft/FluidFramework/discussions).
93
+ - [Submit bug reports](https://github.com/microsoft/FluidFramework/issues) and help verify fixes.
94
+ - Review [source code changes](https://github.com/microsoft/FluidFramework/pulls).
95
+ - [Contribute bug fixes](https://github.com/microsoft/FluidFramework/blob/main/CONTRIBUTING.md).
99
96
 
100
97
  For detailed instructions, read the [repo documentation](https://github.com/microsoft/FluidFramework/blob/main/docs/content/Home.md).
101
98
 
102
99
  This project follows the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
103
100
  For more information, read the [Code of Conduct frequently asked questions](https://opensource.microsoft.com/codeofconduct/faq/).
104
- For questions or comments, contact [opencode@microsoft.com](mailto:opencode@microsoft.com).
101
+ For questions or comments, contact <opencode@microsoft.com>.
105
102
 
106
103
  This project may contain Microsoft trademarks or logos for Microsoft projects, products, or services.
107
104
  Use of these trademarks or logos must follow Microsoft’s [Trademark & Brand Guidelines](https://www.microsoft.com/trademarks).
@@ -122,5 +119,4 @@ Use of these trademarks or logos must follow Microsoft's [Trademark & Brand Guid
122
119
  Use of Microsoft trademarks or logos in modified versions of this project must not cause confusion or imply Microsoft sponsorship.
123
120
 
124
121
  <!-- prettier-ignore-end -->
125
-
126
- <!-- AUTO-GENERATED-CONTENT:END -->
122
+ <!-- markdown-magic:end -->
@@ -1 +1 @@
1
- {"version":3,"file":"replayDocumentDeltaConnection.d.ts","sourceRoot":"","sources":["../src/replayDocumentDeltaConnection.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"replayDocumentDeltaConnection.d.ts","sourceRoot":"","sources":["../src/replayDocumentDeltaConnection.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AACjE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iCAAiC,CAAC;AAEnE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AACzE,OAAO,KAAK,EACX,oBAAoB,EACpB,UAAU,EACV,wBAAwB,EACxB,8BAA8B,EAC9B,4BAA4B,EAC5B,gBAAgB,EAChB,gBAAgB,EAChB,yBAAyB,EACzB,aAAa,EACb,cAAc,EACd,aAAa,EACb,YAAY,EACZ,QAAQ,EACR,MAAM,6CAA6C,CAAC;AAGrD,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAIzD,qBAAa,sBAAuB,SAAQ,gBAAgB;aAgB1C,UAAU,EAAE,MAAM;aAClB,QAAQ,EAAE,MAAM;aAChB,UAAU,CAAC,EAAE,OAAO;IAjBrC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,aAAa,CAAM;IAC3C,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,gBAAgB,CAAM;IAE9C,OAAO,CAAC,cAAc,CAAqB;IAC3C,OAAO,CAAC,aAAa,CAAK;IAG1B;;;;;;OAMG;gBAEc,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,EAChB,UAAU,CAAC,EAAE,OAAO,YAAA;IASxB,WAAW,CAAC,eAAe,EAAE,gBAAgB,GAAG,OAAO,CAAC,OAAO,CAAC;IAIhE,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC;IAIzE,eAAe,CAAC,OAAO,CAAC,EAAE,QAAQ,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC;IAIlE,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC;IAIlD,qBAAqB,IAAI,OAAO,CAAC,MAAM,CAAC;IAI9C,OAAO,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAO9C,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,aAAa,CAAC,EAAE,MAAM,GAAG,OAAO;IAc/D,WAAW,CAAC,UAAU,EAAE,yBAAyB,EAAE,GAAG,MAAM;IAsBtD,MAAM,CAClB,OAAO,EAAE,CAAC,EAAE,EAAE,yBAAyB,EAAE,KAAK,IAAI,EAClD,UAAU,EAAE,yBAAyB,EAAE,GACrC,OAAO,CAAC,IAAI,CAAC;CAuEhB;AAED,qBAAa,6BACZ,SAAQ,iBAAiB,CAAC,8BAA8B,CACxD,YAAW,wBAAwB,EAAE,WAAW;IAuF7B,OAAO,EAAE,UAAU;IArFtC;;;OAGG;WACW,MAAM,CACnB,sBAAsB,EAAE,4BAA4B,EACpD,UAAU,EAAE,gBAAgB,GAC1B,wBAAwB;IAwB3B,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,qBAAqB,CAAY;IAEzD,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,oBAAoB,CAAa;IAEzD,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAU5B;IAEF,IAAW,QAAQ,IAAI,MAAM,CAE5B;IAED,IAAW,IAAI,IAAI,cAAc,CAEhC;IAED,IAAW,MAAM,IAAI,YAAY,CAEhC;IAED,IAAW,QAAQ,IAAI,OAAO,CAE7B;IAED,IAAW,OAAO,IAAI,MAAM,CAE3B;IAED,IAAW,eAAe,IAAI,yBAAyB,EAAE,CAExD;IAED,IAAW,cAAc,IAAI,cAAc,EAAE,CAE5C;IAED,IAAW,cAAc,IAAI,aAAa,EAAE,CAE3C;IAED,IAAW,oBAAoB,IAAI,oBAAoB,CAEtD;IAED,SAAgB,cAAc,SAAsD;gBAEjE,OAAO,EAAE,UAAU;IAI/B,MAAM,CAAC,eAAe,EAAE,gBAAgB,EAAE,GAAG,IAAI;IAO3C,YAAY,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAE1D,OAAO,CAAC,SAAS,CAAS;IAC1B,IAAW,QAAQ,IAAI,OAAO,CAE7B;IACM,OAAO,IAAI,IAAI;IAItB;;OAEG;YACW,eAAe;CA+C7B"}
@@ -92,11 +92,15 @@ class ReplayControllerStatic extends replayController_js_1.ReplayController {
92
92
  }
93
93
  async replay(emitter, fetchedOps) {
94
94
  let current = this.skipToIndex(fetchedOps);
95
- return new Promise((resolve) => {
95
+ return new Promise((resolve, reject) => {
96
96
  const replayNextOps = () => {
97
97
  // Emit the ops from replay to the end every "deltainterval" milliseconds
98
98
  // to simulate the socket stream
99
99
  const currentOp = fetchedOps[current];
100
+ if (currentOp === undefined) {
101
+ reject(new Error(`No op found at replay index ${current}`));
102
+ return;
103
+ }
100
104
  const playbackOps = [currentOp];
101
105
  let nextInterval = ReplayControllerStatic.DelayInterval;
102
106
  current += 1;
@@ -106,6 +110,10 @@ class ReplayControllerStatic extends replayController_js_1.ReplayController {
106
110
  // Emit more ops that is in the ReplayResolution window
107
111
  while (current < fetchedOps.length) {
108
112
  const op = fetchedOps[current];
113
+ if (op === undefined) {
114
+ reject(new Error(`No op found at replay index ${current}`));
115
+ return;
116
+ }
109
117
  if (op.timestamp === undefined) {
110
118
  // Missing timestamp, just delay the standard amount of time
111
119
  break;
@@ -262,7 +270,11 @@ class ReplayDocumentDeltaConnection extends client_utils_1.TypedEventEmitter {
262
270
  replayPromiseChain = replayPromiseChain.then(async () => controller.replay((ops) => this.emit("op", ReplayDocumentId, ops), messages));
263
271
  const messages = result.value;
264
272
  currentOp += messages.length;
265
- done = controller.isDoneFetch(currentOp, messages[messages.length - 1].timestamp);
273
+ const lastMessage = messages[messages.length - 1];
274
+ if (lastMessage === undefined) {
275
+ throw new Error("Delta storage returned an empty batch of messages");
276
+ }
277
+ done = controller.isDoneFetch(currentOp, lastMessage.timestamp);
266
278
  } while (!done);
267
279
  abortController.abort();
268
280
  } while (!done);
@@ -1 +1 @@
1
- {"version":3,"file":"replayDocumentDeltaConnection.js","sourceRoot":"","sources":["../src/replayDocumentDeltaConnection.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 { TypedEventEmitter } from \"@fluid-internal/client-utils\";\nimport type { IDisposable } from \"@fluidframework/core-interfaces\";\nimport { delay } from \"@fluidframework/core-utils/internal\";\nimport type { ConnectionMode } from \"@fluidframework/driver-definitions\";\nimport type {\n\tIClientConfiguration,\n\tIConnected,\n\tIDocumentDeltaConnection,\n\tIDocumentDeltaConnectionEvents,\n\tIDocumentDeltaStorageService,\n\tIDocumentMessage,\n\tIDocumentService,\n\tISequencedDocumentMessage,\n\tISignalClient,\n\tISignalMessage,\n\tISnapshotTree,\n\tITokenClaims,\n\tIVersion,\n} from \"@fluidframework/driver-definitions/internal\";\nimport { ScopeType } from \"@fluidframework/driver-definitions/internal\";\n\nimport { ReplayController } from \"./replayController.js\";\n\nconst ReplayDocumentId = \"documentId\";\n\nexport class ReplayControllerStatic extends ReplayController {\n\tprivate static readonly DelayInterval = 50;\n\tprivate static readonly ReplayResolution = 15;\n\n\tprivate firstTimeStamp: number | undefined;\n\tprivate replayCurrent = 0;\n\t// Simulated delay interval for emitting the ops\n\n\t/**\n\t * Helper class\n\t *\n\t * @param replayFrom - First op to be played on socket.\n\t * @param replayTo - Last op number to be played on socket.\n\t * @param unitIsTime - True is user want to play ops that are within a replay resolution window.\n\t */\n\tpublic constructor(\n\t\tpublic readonly replayFrom: number,\n\t\tpublic readonly replayTo: number,\n\t\tpublic readonly unitIsTime?: boolean,\n\t) {\n\t\tsuper();\n\t\tif (unitIsTime !== true) {\n\t\t\t// There is no code in here to start with snapshot, thus we have to start with op #0.\n\t\t\tthis.replayTo = 0;\n\t\t}\n\t}\n\n\tpublic async initStorage(documentService: IDocumentService): Promise<boolean> {\n\t\treturn true;\n\t}\n\n\tpublic async getVersions(versionId: string | null, count: number): Promise<IVersion[]> {\n\t\treturn [];\n\t}\n\n\tpublic async getSnapshotTree(version?: IVersion): Promise<ISnapshotTree | null> {\n\t\treturn version ? Promise.reject(new Error(\"Invalid operation\")) : null;\n\t}\n\n\tpublic async readBlob(blobId: string): Promise<ArrayBufferLike> {\n\t\tthrow new Error(\"Invalid operation\");\n\t}\n\n\tpublic async getStartingOpSequence(): Promise<number> {\n\t\treturn 0;\n\t}\n\n\tpublic fetchTo(currentOp: number): number | undefined {\n\t\tif (!(this.unitIsTime !== true && this.replayTo >= 0)) {\n\t\t\treturn undefined;\n\t\t}\n\t\treturn this.replayTo;\n\t}\n\n\tpublic isDoneFetch(currentOp: number, lastTimeStamp?: number): boolean {\n\t\tif (this.replayTo >= 0) {\n\t\t\tif (this.unitIsTime === true) {\n\t\t\t\treturn (\n\t\t\t\t\tlastTimeStamp !== undefined &&\n\t\t\t\t\tthis.firstTimeStamp !== undefined &&\n\t\t\t\t\tlastTimeStamp - this.firstTimeStamp >= this.replayTo\n\t\t\t\t);\n\t\t\t}\n\t\t\treturn currentOp >= this.replayTo;\n\t\t}\n\t\treturn lastTimeStamp === undefined; // No more ops\n\t}\n\n\tpublic skipToIndex(fetchedOps: ISequencedDocumentMessage[]): number {\n\t\tif (this.replayFrom <= 0) {\n\t\t\treturn 0;\n\t\t}\n\t\tif (this.unitIsTime === true) {\n\t\t\tfor (const [i, { timestamp }] of fetchedOps.entries()) {\n\t\t\t\tif (timestamp !== undefined) {\n\t\t\t\t\t// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing -- using ??= could change behavior if value is falsy\n\t\t\t\t\tif (this.firstTimeStamp === undefined) {\n\t\t\t\t\t\tthis.firstTimeStamp = timestamp;\n\t\t\t\t\t}\n\t\t\t\t\tif (timestamp - this.firstTimeStamp >= this.replayFrom) {\n\t\t\t\t\t\treturn i;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (this.replayFrom > this.replayCurrent) {\n\t\t\treturn this.replayFrom - this.replayCurrent;\n\t\t}\n\t\treturn 0;\n\t}\n\n\tpublic async replay(\n\t\temitter: (op: ISequencedDocumentMessage[]) => void,\n\t\tfetchedOps: ISequencedDocumentMessage[],\n\t): Promise<void> {\n\t\tlet current = this.skipToIndex(fetchedOps);\n\n\t\treturn new Promise((resolve) => {\n\t\t\tconst replayNextOps = (): void => {\n\t\t\t\t// Emit the ops from replay to the end every \"deltainterval\" milliseconds\n\t\t\t\t// to simulate the socket stream\n\t\t\t\tconst currentOp = fetchedOps[current];\n\t\t\t\tconst playbackOps = [currentOp];\n\t\t\t\tlet nextInterval = ReplayControllerStatic.DelayInterval;\n\t\t\t\tcurrent += 1;\n\n\t\t\t\tif (this.unitIsTime === true) {\n\t\t\t\t\tconst currentTimeStamp = currentOp.timestamp;\n\t\t\t\t\tif (currentTimeStamp !== undefined) {\n\t\t\t\t\t\t// Emit more ops that is in the ReplayResolution window\n\n\t\t\t\t\t\twhile (current < fetchedOps.length) {\n\t\t\t\t\t\t\tconst op = fetchedOps[current];\n\t\t\t\t\t\t\tif (op.timestamp === undefined) {\n\t\t\t\t\t\t\t\t// Missing timestamp, just delay the standard amount of time\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tconst timeDiff = op.timestamp - currentTimeStamp;\n\t\t\t\t\t\t\tif (timeDiff >= ReplayControllerStatic.ReplayResolution) {\n\t\t\t\t\t\t\t\t// Time exceeded the resolution window, break out the loop\n\t\t\t\t\t\t\t\t// and delay for the time difference.\n\t\t\t\t\t\t\t\tnextInterval = timeDiff;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (timeDiff < 0) {\n\t\t\t\t\t\t\t\t// Time have regressed, just delay the standard amount of time\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// The op is within the ReplayResolution emit it now\n\t\t\t\t\t\t\tplaybackOps.push(op);\n\t\t\t\t\t\t\tcurrent += 1;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\tthis.firstTimeStamp !== undefined &&\n\t\t\t\t\t\t\tthis.replayTo >= 0 &&\n\t\t\t\t\t\t\tcurrentTimeStamp + nextInterval - this.firstTimeStamp > this.replayTo\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\tnextInterval = -1;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tscheduleNext(nextInterval);\n\t\t\t\temitter(playbackOps);\n\t\t\t};\n\t\t\tconst scheduleNext = (nextInterval: number): void => {\n\t\t\t\tif (nextInterval >= 0 && current < fetchedOps.length) {\n\t\t\t\t\tsetTimeout(replayNextOps, nextInterval);\n\t\t\t\t} else {\n\t\t\t\t\tthis.replayCurrent += current;\n\t\t\t\t\tresolve();\n\t\t\t\t}\n\t\t\t};\n\t\t\tscheduleNext(ReplayControllerStatic.DelayInterval);\n\t\t});\n\t}\n}\n\nexport class ReplayDocumentDeltaConnection\n\textends TypedEventEmitter<IDocumentDeltaConnectionEvents>\n\timplements IDocumentDeltaConnection, IDisposable\n{\n\t/**\n\t * Creates a new delta connection and mimics the delta connection to replay ops on it.\n\t * @param documentService - The document service to be used to get underlying endpoints.\n\t */\n\tpublic static create(\n\t\tdocumentStorageService: IDocumentDeltaStorageService,\n\t\tcontroller: ReplayController,\n\t): IDocumentDeltaConnection {\n\t\tconst connection: IConnected = {\n\t\t\tclaims: ReplayDocumentDeltaConnection.claims,\n\t\t\tclientId: \"PseudoClientId\",\n\t\t\texisting: true,\n\t\t\tinitialMessages: [],\n\t\t\tinitialSignals: [],\n\t\t\tinitialClients: [],\n\t\t\tmaxMessageSize: ReplayDocumentDeltaConnection.ReplayMaxMessageSize,\n\t\t\tmode: \"read\",\n\t\t\tserviceConfiguration: {\n\t\t\t\tblockSize: 64436,\n\t\t\t\tmaxMessageSize: ReplayDocumentDeltaConnection.ReplayMaxMessageSize,\n\t\t\t},\n\t\t\tsupportedVersions: [ReplayDocumentDeltaConnection.replayProtocolVersion],\n\t\t\tversion: ReplayDocumentDeltaConnection.replayProtocolVersion,\n\t\t};\n\t\tconst deltaConnection = new ReplayDocumentDeltaConnection(connection);\n\t\t// eslint-disable-next-line @typescript-eslint/no-floating-promises\n\t\tdeltaConnection.fetchAndEmitOps(documentStorageService, controller);\n\n\t\treturn deltaConnection;\n\t}\n\n\tprivate static readonly replayProtocolVersion = \"^0.1.0\";\n\t// Since the replay service never actually sends messages the size below is arbitrary\n\tprivate static readonly ReplayMaxMessageSize = 16 * 1024;\n\n\tprivate static readonly claims: ITokenClaims = {\n\t\tdocumentId: ReplayDocumentId,\n\t\tscopes: [ScopeType.DocRead],\n\t\ttenantId: \"\",\n\t\tuser: {\n\t\t\tid: \"\",\n\t\t},\n\t\tiat: Math.round(Date.now() / 1000),\n\t\texp: Math.round(Date.now() / 1000) + 60 * 60, // 1 hour expiration\n\t\tver: \"1.0\",\n\t};\n\n\tpublic get clientId(): string {\n\t\treturn this.details.clientId;\n\t}\n\n\tpublic get mode(): ConnectionMode {\n\t\treturn this.details.mode;\n\t}\n\n\tpublic get claims(): ITokenClaims {\n\t\treturn this.details.claims;\n\t}\n\n\tpublic get existing(): boolean {\n\t\treturn this.details.existing;\n\t}\n\n\tpublic get version(): string {\n\t\treturn this.details.version;\n\t}\n\n\tpublic get initialMessages(): ISequencedDocumentMessage[] {\n\t\treturn this.details.initialMessages;\n\t}\n\n\tpublic get initialSignals(): ISignalMessage[] {\n\t\treturn this.details.initialSignals;\n\t}\n\n\tpublic get initialClients(): ISignalClient[] {\n\t\treturn this.details.initialClients;\n\t}\n\n\tpublic get serviceConfiguration(): IClientConfiguration {\n\t\treturn this.details.serviceConfiguration;\n\t}\n\n\tpublic readonly maxMessageSize = ReplayDocumentDeltaConnection.ReplayMaxMessageSize;\n\n\tconstructor(public details: IConnected) {\n\t\tsuper();\n\t}\n\n\tpublic submit(documentMessage: IDocumentMessage[]): void {\n\t\t// ReplayDocumentDeltaConnection.submit() can't be called - client never sees its own join on,\n\t\t// and thus can never move to sending ops.\n\t\tthrow new Error(\"ReplayDocumentDeltaConnection.submit() can't be called\");\n\t}\n\n\t// eslint-disable-next-line @typescript-eslint/no-misused-promises\n\tpublic async submitSignal(message: unknown): Promise<void> {}\n\n\tprivate _disposed = false;\n\tpublic get disposed(): boolean {\n\t\treturn this._disposed;\n\t}\n\tpublic dispose(): void {\n\t\tthis._disposed = true;\n\t}\n\n\t/**\n\t * This gets the specified ops from the delta storage endpoint and replays them in the replayer.\n\t */\n\tprivate async fetchAndEmitOps(\n\t\tdocumentStorageService: IDocumentDeltaStorageService,\n\t\tcontroller: ReplayController,\n\t): Promise<void> {\n\t\tlet done;\n\t\tlet replayPromiseChain = Promise.resolve();\n\n\t\tlet currentOp = await controller.getStartingOpSequence();\n\n\t\tdo {\n\t\t\tconst fetchTo = controller.fetchTo(currentOp);\n\n\t\t\tconst abortController = new AbortController();\n\t\t\tconst stream = documentStorageService.fetchMessages(\n\t\t\t\tcurrentOp + 1,\n\t\t\t\tfetchTo,\n\t\t\t\tabortController.signal,\n\t\t\t);\n\t\t\tdo {\n\t\t\t\tconst result = await stream.read();\n\n\t\t\t\tif (result.done) {\n\t\t\t\t\t// No more ops. But, they can show up later, either because document was just created,\n\t\t\t\t\t// or because another client keeps submitting new ops.\n\t\t\t\t\tdone = controller.isDoneFetch(currentOp, undefined);\n\t\t\t\t\tif (!done) {\n\t\t\t\t\t\tawait delay(2000);\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\treplayPromiseChain = replayPromiseChain.then(async () =>\n\t\t\t\t\tcontroller.replay((ops) => this.emit(\"op\", ReplayDocumentId, ops), messages),\n\t\t\t\t);\n\n\t\t\t\tconst messages = result.value;\n\t\t\t\tcurrentOp += messages.length;\n\t\t\t\tdone = controller.isDoneFetch(currentOp, messages[messages.length - 1].timestamp);\n\t\t\t} while (!done);\n\n\t\t\tabortController.abort();\n\t\t} while (!done);\n\t\treturn replayPromiseChain;\n\t}\n}\n"]}
1
+ {"version":3,"file":"replayDocumentDeltaConnection.js","sourceRoot":"","sources":["../src/replayDocumentDeltaConnection.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 { TypedEventEmitter } from \"@fluid-internal/client-utils\";\nimport type { IDisposable } from \"@fluidframework/core-interfaces\";\nimport { delay } from \"@fluidframework/core-utils/internal\";\nimport type { ConnectionMode } from \"@fluidframework/driver-definitions\";\nimport type {\n\tIClientConfiguration,\n\tIConnected,\n\tIDocumentDeltaConnection,\n\tIDocumentDeltaConnectionEvents,\n\tIDocumentDeltaStorageService,\n\tIDocumentMessage,\n\tIDocumentService,\n\tISequencedDocumentMessage,\n\tISignalClient,\n\tISignalMessage,\n\tISnapshotTree,\n\tITokenClaims,\n\tIVersion,\n} from \"@fluidframework/driver-definitions/internal\";\nimport { ScopeType } from \"@fluidframework/driver-definitions/internal\";\n\nimport { ReplayController } from \"./replayController.js\";\n\nconst ReplayDocumentId = \"documentId\";\n\nexport class ReplayControllerStatic extends ReplayController {\n\tprivate static readonly DelayInterval = 50;\n\tprivate static readonly ReplayResolution = 15;\n\n\tprivate firstTimeStamp: number | undefined;\n\tprivate replayCurrent = 0;\n\t// Simulated delay interval for emitting the ops\n\n\t/**\n\t * Helper class\n\t *\n\t * @param replayFrom - First op to be played on socket.\n\t * @param replayTo - Last op number to be played on socket.\n\t * @param unitIsTime - True is user want to play ops that are within a replay resolution window.\n\t */\n\tpublic constructor(\n\t\tpublic readonly replayFrom: number,\n\t\tpublic readonly replayTo: number,\n\t\tpublic readonly unitIsTime?: boolean,\n\t) {\n\t\tsuper();\n\t\tif (unitIsTime !== true) {\n\t\t\t// There is no code in here to start with snapshot, thus we have to start with op #0.\n\t\t\tthis.replayTo = 0;\n\t\t}\n\t}\n\n\tpublic async initStorage(documentService: IDocumentService): Promise<boolean> {\n\t\treturn true;\n\t}\n\n\tpublic async getVersions(versionId: string | null, count: number): Promise<IVersion[]> {\n\t\treturn [];\n\t}\n\n\tpublic async getSnapshotTree(version?: IVersion): Promise<ISnapshotTree | null> {\n\t\treturn version ? Promise.reject(new Error(\"Invalid operation\")) : null;\n\t}\n\n\tpublic async readBlob(blobId: string): Promise<ArrayBufferLike> {\n\t\tthrow new Error(\"Invalid operation\");\n\t}\n\n\tpublic async getStartingOpSequence(): Promise<number> {\n\t\treturn 0;\n\t}\n\n\tpublic fetchTo(currentOp: number): number | undefined {\n\t\tif (!(this.unitIsTime !== true && this.replayTo >= 0)) {\n\t\t\treturn undefined;\n\t\t}\n\t\treturn this.replayTo;\n\t}\n\n\tpublic isDoneFetch(currentOp: number, lastTimeStamp?: number): boolean {\n\t\tif (this.replayTo >= 0) {\n\t\t\tif (this.unitIsTime === true) {\n\t\t\t\treturn (\n\t\t\t\t\tlastTimeStamp !== undefined &&\n\t\t\t\t\tthis.firstTimeStamp !== undefined &&\n\t\t\t\t\tlastTimeStamp - this.firstTimeStamp >= this.replayTo\n\t\t\t\t);\n\t\t\t}\n\t\t\treturn currentOp >= this.replayTo;\n\t\t}\n\t\treturn lastTimeStamp === undefined; // No more ops\n\t}\n\n\tpublic skipToIndex(fetchedOps: ISequencedDocumentMessage[]): number {\n\t\tif (this.replayFrom <= 0) {\n\t\t\treturn 0;\n\t\t}\n\t\tif (this.unitIsTime === true) {\n\t\t\tfor (const [i, { timestamp }] of fetchedOps.entries()) {\n\t\t\t\tif (timestamp !== undefined) {\n\t\t\t\t\t// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing -- using ??= could change behavior if value is falsy\n\t\t\t\t\tif (this.firstTimeStamp === undefined) {\n\t\t\t\t\t\tthis.firstTimeStamp = timestamp;\n\t\t\t\t\t}\n\t\t\t\t\tif (timestamp - this.firstTimeStamp >= this.replayFrom) {\n\t\t\t\t\t\treturn i;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (this.replayFrom > this.replayCurrent) {\n\t\t\treturn this.replayFrom - this.replayCurrent;\n\t\t}\n\t\treturn 0;\n\t}\n\n\tpublic async replay(\n\t\temitter: (op: ISequencedDocumentMessage[]) => void,\n\t\tfetchedOps: ISequencedDocumentMessage[],\n\t): Promise<void> {\n\t\tlet current = this.skipToIndex(fetchedOps);\n\n\t\treturn new Promise((resolve, reject) => {\n\t\t\tconst replayNextOps = (): void => {\n\t\t\t\t// Emit the ops from replay to the end every \"deltainterval\" milliseconds\n\t\t\t\t// to simulate the socket stream\n\t\t\t\tconst currentOp = fetchedOps[current];\n\t\t\t\tif (currentOp === undefined) {\n\t\t\t\t\treject(new Error(`No op found at replay index ${current}`));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst playbackOps = [currentOp];\n\t\t\t\tlet nextInterval = ReplayControllerStatic.DelayInterval;\n\t\t\t\tcurrent += 1;\n\n\t\t\t\tif (this.unitIsTime === true) {\n\t\t\t\t\tconst currentTimeStamp = currentOp.timestamp;\n\t\t\t\t\tif (currentTimeStamp !== undefined) {\n\t\t\t\t\t\t// Emit more ops that is in the ReplayResolution window\n\n\t\t\t\t\t\twhile (current < fetchedOps.length) {\n\t\t\t\t\t\t\tconst op = fetchedOps[current];\n\t\t\t\t\t\t\tif (op === undefined) {\n\t\t\t\t\t\t\t\treject(new Error(`No op found at replay index ${current}`));\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (op.timestamp === undefined) {\n\t\t\t\t\t\t\t\t// Missing timestamp, just delay the standard amount of time\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tconst timeDiff = op.timestamp - currentTimeStamp;\n\t\t\t\t\t\t\tif (timeDiff >= ReplayControllerStatic.ReplayResolution) {\n\t\t\t\t\t\t\t\t// Time exceeded the resolution window, break out the loop\n\t\t\t\t\t\t\t\t// and delay for the time difference.\n\t\t\t\t\t\t\t\tnextInterval = timeDiff;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (timeDiff < 0) {\n\t\t\t\t\t\t\t\t// Time have regressed, just delay the standard amount of time\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// The op is within the ReplayResolution emit it now\n\t\t\t\t\t\t\tplaybackOps.push(op);\n\t\t\t\t\t\t\tcurrent += 1;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\tthis.firstTimeStamp !== undefined &&\n\t\t\t\t\t\t\tthis.replayTo >= 0 &&\n\t\t\t\t\t\t\tcurrentTimeStamp + nextInterval - this.firstTimeStamp > this.replayTo\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\tnextInterval = -1;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tscheduleNext(nextInterval);\n\t\t\t\temitter(playbackOps);\n\t\t\t};\n\t\t\tconst scheduleNext = (nextInterval: number): void => {\n\t\t\t\tif (nextInterval >= 0 && current < fetchedOps.length) {\n\t\t\t\t\tsetTimeout(replayNextOps, nextInterval);\n\t\t\t\t} else {\n\t\t\t\t\tthis.replayCurrent += current;\n\t\t\t\t\tresolve();\n\t\t\t\t}\n\t\t\t};\n\t\t\tscheduleNext(ReplayControllerStatic.DelayInterval);\n\t\t});\n\t}\n}\n\nexport class ReplayDocumentDeltaConnection\n\textends TypedEventEmitter<IDocumentDeltaConnectionEvents>\n\timplements IDocumentDeltaConnection, IDisposable\n{\n\t/**\n\t * Creates a new delta connection and mimics the delta connection to replay ops on it.\n\t * @param documentService - The document service to be used to get underlying endpoints.\n\t */\n\tpublic static create(\n\t\tdocumentStorageService: IDocumentDeltaStorageService,\n\t\tcontroller: ReplayController,\n\t): IDocumentDeltaConnection {\n\t\tconst connection: IConnected = {\n\t\t\tclaims: ReplayDocumentDeltaConnection.claims,\n\t\t\tclientId: \"PseudoClientId\",\n\t\t\texisting: true,\n\t\t\tinitialMessages: [],\n\t\t\tinitialSignals: [],\n\t\t\tinitialClients: [],\n\t\t\tmaxMessageSize: ReplayDocumentDeltaConnection.ReplayMaxMessageSize,\n\t\t\tmode: \"read\",\n\t\t\tserviceConfiguration: {\n\t\t\t\tblockSize: 64436,\n\t\t\t\tmaxMessageSize: ReplayDocumentDeltaConnection.ReplayMaxMessageSize,\n\t\t\t},\n\t\t\tsupportedVersions: [ReplayDocumentDeltaConnection.replayProtocolVersion],\n\t\t\tversion: ReplayDocumentDeltaConnection.replayProtocolVersion,\n\t\t};\n\t\tconst deltaConnection = new ReplayDocumentDeltaConnection(connection);\n\t\t// eslint-disable-next-line @typescript-eslint/no-floating-promises\n\t\tdeltaConnection.fetchAndEmitOps(documentStorageService, controller);\n\n\t\treturn deltaConnection;\n\t}\n\n\tprivate static readonly replayProtocolVersion = \"^0.1.0\";\n\t// Since the replay service never actually sends messages the size below is arbitrary\n\tprivate static readonly ReplayMaxMessageSize = 16 * 1024;\n\n\tprivate static readonly claims: ITokenClaims = {\n\t\tdocumentId: ReplayDocumentId,\n\t\tscopes: [ScopeType.DocRead],\n\t\ttenantId: \"\",\n\t\tuser: {\n\t\t\tid: \"\",\n\t\t},\n\t\tiat: Math.round(Date.now() / 1000),\n\t\texp: Math.round(Date.now() / 1000) + 60 * 60, // 1 hour expiration\n\t\tver: \"1.0\",\n\t};\n\n\tpublic get clientId(): string {\n\t\treturn this.details.clientId;\n\t}\n\n\tpublic get mode(): ConnectionMode {\n\t\treturn this.details.mode;\n\t}\n\n\tpublic get claims(): ITokenClaims {\n\t\treturn this.details.claims;\n\t}\n\n\tpublic get existing(): boolean {\n\t\treturn this.details.existing;\n\t}\n\n\tpublic get version(): string {\n\t\treturn this.details.version;\n\t}\n\n\tpublic get initialMessages(): ISequencedDocumentMessage[] {\n\t\treturn this.details.initialMessages;\n\t}\n\n\tpublic get initialSignals(): ISignalMessage[] {\n\t\treturn this.details.initialSignals;\n\t}\n\n\tpublic get initialClients(): ISignalClient[] {\n\t\treturn this.details.initialClients;\n\t}\n\n\tpublic get serviceConfiguration(): IClientConfiguration {\n\t\treturn this.details.serviceConfiguration;\n\t}\n\n\tpublic readonly maxMessageSize = ReplayDocumentDeltaConnection.ReplayMaxMessageSize;\n\n\tconstructor(public details: IConnected) {\n\t\tsuper();\n\t}\n\n\tpublic submit(documentMessage: IDocumentMessage[]): void {\n\t\t// ReplayDocumentDeltaConnection.submit() can't be called - client never sees its own join on,\n\t\t// and thus can never move to sending ops.\n\t\tthrow new Error(\"ReplayDocumentDeltaConnection.submit() can't be called\");\n\t}\n\n\t// eslint-disable-next-line @typescript-eslint/no-misused-promises\n\tpublic async submitSignal(message: unknown): Promise<void> {}\n\n\tprivate _disposed = false;\n\tpublic get disposed(): boolean {\n\t\treturn this._disposed;\n\t}\n\tpublic dispose(): void {\n\t\tthis._disposed = true;\n\t}\n\n\t/**\n\t * This gets the specified ops from the delta storage endpoint and replays them in the replayer.\n\t */\n\tprivate async fetchAndEmitOps(\n\t\tdocumentStorageService: IDocumentDeltaStorageService,\n\t\tcontroller: ReplayController,\n\t): Promise<void> {\n\t\tlet done;\n\t\tlet replayPromiseChain = Promise.resolve();\n\n\t\tlet currentOp = await controller.getStartingOpSequence();\n\n\t\tdo {\n\t\t\tconst fetchTo = controller.fetchTo(currentOp);\n\n\t\t\tconst abortController = new AbortController();\n\t\t\tconst stream = documentStorageService.fetchMessages(\n\t\t\t\tcurrentOp + 1,\n\t\t\t\tfetchTo,\n\t\t\t\tabortController.signal,\n\t\t\t);\n\t\t\tdo {\n\t\t\t\tconst result = await stream.read();\n\n\t\t\t\tif (result.done) {\n\t\t\t\t\t// No more ops. But, they can show up later, either because document was just created,\n\t\t\t\t\t// or because another client keeps submitting new ops.\n\t\t\t\t\tdone = controller.isDoneFetch(currentOp, undefined);\n\t\t\t\t\tif (!done) {\n\t\t\t\t\t\tawait delay(2000);\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\treplayPromiseChain = replayPromiseChain.then(async () =>\n\t\t\t\t\tcontroller.replay((ops) => this.emit(\"op\", ReplayDocumentId, ops), messages),\n\t\t\t\t);\n\n\t\t\t\tconst messages = result.value;\n\t\t\t\tcurrentOp += messages.length;\n\t\t\t\tconst lastMessage = messages[messages.length - 1];\n\t\t\t\tif (lastMessage === undefined) {\n\t\t\t\t\tthrow new Error(\"Delta storage returned an empty batch of messages\");\n\t\t\t\t}\n\t\t\t\tdone = controller.isDoneFetch(currentOp, lastMessage.timestamp);\n\t\t\t} while (!done);\n\n\t\t\tabortController.abort();\n\t\t} while (!done);\n\t\treturn replayPromiseChain;\n\t}\n}\n"]}
package/eslint.config.mts CHANGED
@@ -10,7 +10,6 @@ const config: Linter.Config[] = [
10
10
  ...recommended,
11
11
  {
12
12
  rules: {
13
- "@fluid-internal/fluid/no-unchecked-record-access": "warn",
14
13
  "@rushstack/no-new-null": "off",
15
14
  "@typescript-eslint/strict-boolean-expressions": "off",
16
15
  "unicorn/no-null": "off",
@@ -1 +1 @@
1
- {"version":3,"file":"replayDocumentDeltaConnection.d.ts","sourceRoot":"","sources":["../src/replayDocumentDeltaConnection.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"replayDocumentDeltaConnection.d.ts","sourceRoot":"","sources":["../src/replayDocumentDeltaConnection.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AACjE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iCAAiC,CAAC;AAEnE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AACzE,OAAO,KAAK,EACX,oBAAoB,EACpB,UAAU,EACV,wBAAwB,EACxB,8BAA8B,EAC9B,4BAA4B,EAC5B,gBAAgB,EAChB,gBAAgB,EAChB,yBAAyB,EACzB,aAAa,EACb,cAAc,EACd,aAAa,EACb,YAAY,EACZ,QAAQ,EACR,MAAM,6CAA6C,CAAC;AAGrD,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAIzD,qBAAa,sBAAuB,SAAQ,gBAAgB;aAgB1C,UAAU,EAAE,MAAM;aAClB,QAAQ,EAAE,MAAM;aAChB,UAAU,CAAC,EAAE,OAAO;IAjBrC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,aAAa,CAAM;IAC3C,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,gBAAgB,CAAM;IAE9C,OAAO,CAAC,cAAc,CAAqB;IAC3C,OAAO,CAAC,aAAa,CAAK;IAG1B;;;;;;OAMG;gBAEc,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,EAChB,UAAU,CAAC,EAAE,OAAO,YAAA;IASxB,WAAW,CAAC,eAAe,EAAE,gBAAgB,GAAG,OAAO,CAAC,OAAO,CAAC;IAIhE,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC;IAIzE,eAAe,CAAC,OAAO,CAAC,EAAE,QAAQ,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC;IAIlE,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC;IAIlD,qBAAqB,IAAI,OAAO,CAAC,MAAM,CAAC;IAI9C,OAAO,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAO9C,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,aAAa,CAAC,EAAE,MAAM,GAAG,OAAO;IAc/D,WAAW,CAAC,UAAU,EAAE,yBAAyB,EAAE,GAAG,MAAM;IAsBtD,MAAM,CAClB,OAAO,EAAE,CAAC,EAAE,EAAE,yBAAyB,EAAE,KAAK,IAAI,EAClD,UAAU,EAAE,yBAAyB,EAAE,GACrC,OAAO,CAAC,IAAI,CAAC;CAuEhB;AAED,qBAAa,6BACZ,SAAQ,iBAAiB,CAAC,8BAA8B,CACxD,YAAW,wBAAwB,EAAE,WAAW;IAuF7B,OAAO,EAAE,UAAU;IArFtC;;;OAGG;WACW,MAAM,CACnB,sBAAsB,EAAE,4BAA4B,EACpD,UAAU,EAAE,gBAAgB,GAC1B,wBAAwB;IAwB3B,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,qBAAqB,CAAY;IAEzD,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,oBAAoB,CAAa;IAEzD,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAU5B;IAEF,IAAW,QAAQ,IAAI,MAAM,CAE5B;IAED,IAAW,IAAI,IAAI,cAAc,CAEhC;IAED,IAAW,MAAM,IAAI,YAAY,CAEhC;IAED,IAAW,QAAQ,IAAI,OAAO,CAE7B;IAED,IAAW,OAAO,IAAI,MAAM,CAE3B;IAED,IAAW,eAAe,IAAI,yBAAyB,EAAE,CAExD;IAED,IAAW,cAAc,IAAI,cAAc,EAAE,CAE5C;IAED,IAAW,cAAc,IAAI,aAAa,EAAE,CAE3C;IAED,IAAW,oBAAoB,IAAI,oBAAoB,CAEtD;IAED,SAAgB,cAAc,SAAsD;gBAEjE,OAAO,EAAE,UAAU;IAI/B,MAAM,CAAC,eAAe,EAAE,gBAAgB,EAAE,GAAG,IAAI;IAO3C,YAAY,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAE1D,OAAO,CAAC,SAAS,CAAS;IAC1B,IAAW,QAAQ,IAAI,OAAO,CAE7B;IACM,OAAO,IAAI,IAAI;IAItB;;OAEG;YACW,eAAe;CA+C7B"}
@@ -89,11 +89,15 @@ export class ReplayControllerStatic extends ReplayController {
89
89
  }
90
90
  async replay(emitter, fetchedOps) {
91
91
  let current = this.skipToIndex(fetchedOps);
92
- return new Promise((resolve) => {
92
+ return new Promise((resolve, reject) => {
93
93
  const replayNextOps = () => {
94
94
  // Emit the ops from replay to the end every "deltainterval" milliseconds
95
95
  // to simulate the socket stream
96
96
  const currentOp = fetchedOps[current];
97
+ if (currentOp === undefined) {
98
+ reject(new Error(`No op found at replay index ${current}`));
99
+ return;
100
+ }
97
101
  const playbackOps = [currentOp];
98
102
  let nextInterval = ReplayControllerStatic.DelayInterval;
99
103
  current += 1;
@@ -103,6 +107,10 @@ export class ReplayControllerStatic extends ReplayController {
103
107
  // Emit more ops that is in the ReplayResolution window
104
108
  while (current < fetchedOps.length) {
105
109
  const op = fetchedOps[current];
110
+ if (op === undefined) {
111
+ reject(new Error(`No op found at replay index ${current}`));
112
+ return;
113
+ }
106
114
  if (op.timestamp === undefined) {
107
115
  // Missing timestamp, just delay the standard amount of time
108
116
  break;
@@ -258,7 +266,11 @@ export class ReplayDocumentDeltaConnection extends TypedEventEmitter {
258
266
  replayPromiseChain = replayPromiseChain.then(async () => controller.replay((ops) => this.emit("op", ReplayDocumentId, ops), messages));
259
267
  const messages = result.value;
260
268
  currentOp += messages.length;
261
- done = controller.isDoneFetch(currentOp, messages[messages.length - 1].timestamp);
269
+ const lastMessage = messages[messages.length - 1];
270
+ if (lastMessage === undefined) {
271
+ throw new Error("Delta storage returned an empty batch of messages");
272
+ }
273
+ done = controller.isDoneFetch(currentOp, lastMessage.timestamp);
262
274
  } while (!done);
263
275
  abortController.abort();
264
276
  } while (!done);
@@ -1 +1 @@
1
- {"version":3,"file":"replayDocumentDeltaConnection.js","sourceRoot":"","sources":["../src/replayDocumentDeltaConnection.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 { TypedEventEmitter } from \"@fluid-internal/client-utils\";\nimport type { IDisposable } from \"@fluidframework/core-interfaces\";\nimport { delay } from \"@fluidframework/core-utils/internal\";\nimport type { ConnectionMode } from \"@fluidframework/driver-definitions\";\nimport type {\n\tIClientConfiguration,\n\tIConnected,\n\tIDocumentDeltaConnection,\n\tIDocumentDeltaConnectionEvents,\n\tIDocumentDeltaStorageService,\n\tIDocumentMessage,\n\tIDocumentService,\n\tISequencedDocumentMessage,\n\tISignalClient,\n\tISignalMessage,\n\tISnapshotTree,\n\tITokenClaims,\n\tIVersion,\n} from \"@fluidframework/driver-definitions/internal\";\nimport { ScopeType } from \"@fluidframework/driver-definitions/internal\";\n\nimport { ReplayController } from \"./replayController.js\";\n\nconst ReplayDocumentId = \"documentId\";\n\nexport class ReplayControllerStatic extends ReplayController {\n\tprivate static readonly DelayInterval = 50;\n\tprivate static readonly ReplayResolution = 15;\n\n\tprivate firstTimeStamp: number | undefined;\n\tprivate replayCurrent = 0;\n\t// Simulated delay interval for emitting the ops\n\n\t/**\n\t * Helper class\n\t *\n\t * @param replayFrom - First op to be played on socket.\n\t * @param replayTo - Last op number to be played on socket.\n\t * @param unitIsTime - True is user want to play ops that are within a replay resolution window.\n\t */\n\tpublic constructor(\n\t\tpublic readonly replayFrom: number,\n\t\tpublic readonly replayTo: number,\n\t\tpublic readonly unitIsTime?: boolean,\n\t) {\n\t\tsuper();\n\t\tif (unitIsTime !== true) {\n\t\t\t// There is no code in here to start with snapshot, thus we have to start with op #0.\n\t\t\tthis.replayTo = 0;\n\t\t}\n\t}\n\n\tpublic async initStorage(documentService: IDocumentService): Promise<boolean> {\n\t\treturn true;\n\t}\n\n\tpublic async getVersions(versionId: string | null, count: number): Promise<IVersion[]> {\n\t\treturn [];\n\t}\n\n\tpublic async getSnapshotTree(version?: IVersion): Promise<ISnapshotTree | null> {\n\t\treturn version ? Promise.reject(new Error(\"Invalid operation\")) : null;\n\t}\n\n\tpublic async readBlob(blobId: string): Promise<ArrayBufferLike> {\n\t\tthrow new Error(\"Invalid operation\");\n\t}\n\n\tpublic async getStartingOpSequence(): Promise<number> {\n\t\treturn 0;\n\t}\n\n\tpublic fetchTo(currentOp: number): number | undefined {\n\t\tif (!(this.unitIsTime !== true && this.replayTo >= 0)) {\n\t\t\treturn undefined;\n\t\t}\n\t\treturn this.replayTo;\n\t}\n\n\tpublic isDoneFetch(currentOp: number, lastTimeStamp?: number): boolean {\n\t\tif (this.replayTo >= 0) {\n\t\t\tif (this.unitIsTime === true) {\n\t\t\t\treturn (\n\t\t\t\t\tlastTimeStamp !== undefined &&\n\t\t\t\t\tthis.firstTimeStamp !== undefined &&\n\t\t\t\t\tlastTimeStamp - this.firstTimeStamp >= this.replayTo\n\t\t\t\t);\n\t\t\t}\n\t\t\treturn currentOp >= this.replayTo;\n\t\t}\n\t\treturn lastTimeStamp === undefined; // No more ops\n\t}\n\n\tpublic skipToIndex(fetchedOps: ISequencedDocumentMessage[]): number {\n\t\tif (this.replayFrom <= 0) {\n\t\t\treturn 0;\n\t\t}\n\t\tif (this.unitIsTime === true) {\n\t\t\tfor (const [i, { timestamp }] of fetchedOps.entries()) {\n\t\t\t\tif (timestamp !== undefined) {\n\t\t\t\t\t// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing -- using ??= could change behavior if value is falsy\n\t\t\t\t\tif (this.firstTimeStamp === undefined) {\n\t\t\t\t\t\tthis.firstTimeStamp = timestamp;\n\t\t\t\t\t}\n\t\t\t\t\tif (timestamp - this.firstTimeStamp >= this.replayFrom) {\n\t\t\t\t\t\treturn i;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (this.replayFrom > this.replayCurrent) {\n\t\t\treturn this.replayFrom - this.replayCurrent;\n\t\t}\n\t\treturn 0;\n\t}\n\n\tpublic async replay(\n\t\temitter: (op: ISequencedDocumentMessage[]) => void,\n\t\tfetchedOps: ISequencedDocumentMessage[],\n\t): Promise<void> {\n\t\tlet current = this.skipToIndex(fetchedOps);\n\n\t\treturn new Promise((resolve) => {\n\t\t\tconst replayNextOps = (): void => {\n\t\t\t\t// Emit the ops from replay to the end every \"deltainterval\" milliseconds\n\t\t\t\t// to simulate the socket stream\n\t\t\t\tconst currentOp = fetchedOps[current];\n\t\t\t\tconst playbackOps = [currentOp];\n\t\t\t\tlet nextInterval = ReplayControllerStatic.DelayInterval;\n\t\t\t\tcurrent += 1;\n\n\t\t\t\tif (this.unitIsTime === true) {\n\t\t\t\t\tconst currentTimeStamp = currentOp.timestamp;\n\t\t\t\t\tif (currentTimeStamp !== undefined) {\n\t\t\t\t\t\t// Emit more ops that is in the ReplayResolution window\n\n\t\t\t\t\t\twhile (current < fetchedOps.length) {\n\t\t\t\t\t\t\tconst op = fetchedOps[current];\n\t\t\t\t\t\t\tif (op.timestamp === undefined) {\n\t\t\t\t\t\t\t\t// Missing timestamp, just delay the standard amount of time\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tconst timeDiff = op.timestamp - currentTimeStamp;\n\t\t\t\t\t\t\tif (timeDiff >= ReplayControllerStatic.ReplayResolution) {\n\t\t\t\t\t\t\t\t// Time exceeded the resolution window, break out the loop\n\t\t\t\t\t\t\t\t// and delay for the time difference.\n\t\t\t\t\t\t\t\tnextInterval = timeDiff;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (timeDiff < 0) {\n\t\t\t\t\t\t\t\t// Time have regressed, just delay the standard amount of time\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// The op is within the ReplayResolution emit it now\n\t\t\t\t\t\t\tplaybackOps.push(op);\n\t\t\t\t\t\t\tcurrent += 1;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\tthis.firstTimeStamp !== undefined &&\n\t\t\t\t\t\t\tthis.replayTo >= 0 &&\n\t\t\t\t\t\t\tcurrentTimeStamp + nextInterval - this.firstTimeStamp > this.replayTo\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\tnextInterval = -1;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tscheduleNext(nextInterval);\n\t\t\t\temitter(playbackOps);\n\t\t\t};\n\t\t\tconst scheduleNext = (nextInterval: number): void => {\n\t\t\t\tif (nextInterval >= 0 && current < fetchedOps.length) {\n\t\t\t\t\tsetTimeout(replayNextOps, nextInterval);\n\t\t\t\t} else {\n\t\t\t\t\tthis.replayCurrent += current;\n\t\t\t\t\tresolve();\n\t\t\t\t}\n\t\t\t};\n\t\t\tscheduleNext(ReplayControllerStatic.DelayInterval);\n\t\t});\n\t}\n}\n\nexport class ReplayDocumentDeltaConnection\n\textends TypedEventEmitter<IDocumentDeltaConnectionEvents>\n\timplements IDocumentDeltaConnection, IDisposable\n{\n\t/**\n\t * Creates a new delta connection and mimics the delta connection to replay ops on it.\n\t * @param documentService - The document service to be used to get underlying endpoints.\n\t */\n\tpublic static create(\n\t\tdocumentStorageService: IDocumentDeltaStorageService,\n\t\tcontroller: ReplayController,\n\t): IDocumentDeltaConnection {\n\t\tconst connection: IConnected = {\n\t\t\tclaims: ReplayDocumentDeltaConnection.claims,\n\t\t\tclientId: \"PseudoClientId\",\n\t\t\texisting: true,\n\t\t\tinitialMessages: [],\n\t\t\tinitialSignals: [],\n\t\t\tinitialClients: [],\n\t\t\tmaxMessageSize: ReplayDocumentDeltaConnection.ReplayMaxMessageSize,\n\t\t\tmode: \"read\",\n\t\t\tserviceConfiguration: {\n\t\t\t\tblockSize: 64436,\n\t\t\t\tmaxMessageSize: ReplayDocumentDeltaConnection.ReplayMaxMessageSize,\n\t\t\t},\n\t\t\tsupportedVersions: [ReplayDocumentDeltaConnection.replayProtocolVersion],\n\t\t\tversion: ReplayDocumentDeltaConnection.replayProtocolVersion,\n\t\t};\n\t\tconst deltaConnection = new ReplayDocumentDeltaConnection(connection);\n\t\t// eslint-disable-next-line @typescript-eslint/no-floating-promises\n\t\tdeltaConnection.fetchAndEmitOps(documentStorageService, controller);\n\n\t\treturn deltaConnection;\n\t}\n\n\tprivate static readonly replayProtocolVersion = \"^0.1.0\";\n\t// Since the replay service never actually sends messages the size below is arbitrary\n\tprivate static readonly ReplayMaxMessageSize = 16 * 1024;\n\n\tprivate static readonly claims: ITokenClaims = {\n\t\tdocumentId: ReplayDocumentId,\n\t\tscopes: [ScopeType.DocRead],\n\t\ttenantId: \"\",\n\t\tuser: {\n\t\t\tid: \"\",\n\t\t},\n\t\tiat: Math.round(Date.now() / 1000),\n\t\texp: Math.round(Date.now() / 1000) + 60 * 60, // 1 hour expiration\n\t\tver: \"1.0\",\n\t};\n\n\tpublic get clientId(): string {\n\t\treturn this.details.clientId;\n\t}\n\n\tpublic get mode(): ConnectionMode {\n\t\treturn this.details.mode;\n\t}\n\n\tpublic get claims(): ITokenClaims {\n\t\treturn this.details.claims;\n\t}\n\n\tpublic get existing(): boolean {\n\t\treturn this.details.existing;\n\t}\n\n\tpublic get version(): string {\n\t\treturn this.details.version;\n\t}\n\n\tpublic get initialMessages(): ISequencedDocumentMessage[] {\n\t\treturn this.details.initialMessages;\n\t}\n\n\tpublic get initialSignals(): ISignalMessage[] {\n\t\treturn this.details.initialSignals;\n\t}\n\n\tpublic get initialClients(): ISignalClient[] {\n\t\treturn this.details.initialClients;\n\t}\n\n\tpublic get serviceConfiguration(): IClientConfiguration {\n\t\treturn this.details.serviceConfiguration;\n\t}\n\n\tpublic readonly maxMessageSize = ReplayDocumentDeltaConnection.ReplayMaxMessageSize;\n\n\tconstructor(public details: IConnected) {\n\t\tsuper();\n\t}\n\n\tpublic submit(documentMessage: IDocumentMessage[]): void {\n\t\t// ReplayDocumentDeltaConnection.submit() can't be called - client never sees its own join on,\n\t\t// and thus can never move to sending ops.\n\t\tthrow new Error(\"ReplayDocumentDeltaConnection.submit() can't be called\");\n\t}\n\n\t// eslint-disable-next-line @typescript-eslint/no-misused-promises\n\tpublic async submitSignal(message: unknown): Promise<void> {}\n\n\tprivate _disposed = false;\n\tpublic get disposed(): boolean {\n\t\treturn this._disposed;\n\t}\n\tpublic dispose(): void {\n\t\tthis._disposed = true;\n\t}\n\n\t/**\n\t * This gets the specified ops from the delta storage endpoint and replays them in the replayer.\n\t */\n\tprivate async fetchAndEmitOps(\n\t\tdocumentStorageService: IDocumentDeltaStorageService,\n\t\tcontroller: ReplayController,\n\t): Promise<void> {\n\t\tlet done;\n\t\tlet replayPromiseChain = Promise.resolve();\n\n\t\tlet currentOp = await controller.getStartingOpSequence();\n\n\t\tdo {\n\t\t\tconst fetchTo = controller.fetchTo(currentOp);\n\n\t\t\tconst abortController = new AbortController();\n\t\t\tconst stream = documentStorageService.fetchMessages(\n\t\t\t\tcurrentOp + 1,\n\t\t\t\tfetchTo,\n\t\t\t\tabortController.signal,\n\t\t\t);\n\t\t\tdo {\n\t\t\t\tconst result = await stream.read();\n\n\t\t\t\tif (result.done) {\n\t\t\t\t\t// No more ops. But, they can show up later, either because document was just created,\n\t\t\t\t\t// or because another client keeps submitting new ops.\n\t\t\t\t\tdone = controller.isDoneFetch(currentOp, undefined);\n\t\t\t\t\tif (!done) {\n\t\t\t\t\t\tawait delay(2000);\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\treplayPromiseChain = replayPromiseChain.then(async () =>\n\t\t\t\t\tcontroller.replay((ops) => this.emit(\"op\", ReplayDocumentId, ops), messages),\n\t\t\t\t);\n\n\t\t\t\tconst messages = result.value;\n\t\t\t\tcurrentOp += messages.length;\n\t\t\t\tdone = controller.isDoneFetch(currentOp, messages[messages.length - 1].timestamp);\n\t\t\t} while (!done);\n\n\t\t\tabortController.abort();\n\t\t} while (!done);\n\t\treturn replayPromiseChain;\n\t}\n}\n"]}
1
+ {"version":3,"file":"replayDocumentDeltaConnection.js","sourceRoot":"","sources":["../src/replayDocumentDeltaConnection.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 { TypedEventEmitter } from \"@fluid-internal/client-utils\";\nimport type { IDisposable } from \"@fluidframework/core-interfaces\";\nimport { delay } from \"@fluidframework/core-utils/internal\";\nimport type { ConnectionMode } from \"@fluidframework/driver-definitions\";\nimport type {\n\tIClientConfiguration,\n\tIConnected,\n\tIDocumentDeltaConnection,\n\tIDocumentDeltaConnectionEvents,\n\tIDocumentDeltaStorageService,\n\tIDocumentMessage,\n\tIDocumentService,\n\tISequencedDocumentMessage,\n\tISignalClient,\n\tISignalMessage,\n\tISnapshotTree,\n\tITokenClaims,\n\tIVersion,\n} from \"@fluidframework/driver-definitions/internal\";\nimport { ScopeType } from \"@fluidframework/driver-definitions/internal\";\n\nimport { ReplayController } from \"./replayController.js\";\n\nconst ReplayDocumentId = \"documentId\";\n\nexport class ReplayControllerStatic extends ReplayController {\n\tprivate static readonly DelayInterval = 50;\n\tprivate static readonly ReplayResolution = 15;\n\n\tprivate firstTimeStamp: number | undefined;\n\tprivate replayCurrent = 0;\n\t// Simulated delay interval for emitting the ops\n\n\t/**\n\t * Helper class\n\t *\n\t * @param replayFrom - First op to be played on socket.\n\t * @param replayTo - Last op number to be played on socket.\n\t * @param unitIsTime - True is user want to play ops that are within a replay resolution window.\n\t */\n\tpublic constructor(\n\t\tpublic readonly replayFrom: number,\n\t\tpublic readonly replayTo: number,\n\t\tpublic readonly unitIsTime?: boolean,\n\t) {\n\t\tsuper();\n\t\tif (unitIsTime !== true) {\n\t\t\t// There is no code in here to start with snapshot, thus we have to start with op #0.\n\t\t\tthis.replayTo = 0;\n\t\t}\n\t}\n\n\tpublic async initStorage(documentService: IDocumentService): Promise<boolean> {\n\t\treturn true;\n\t}\n\n\tpublic async getVersions(versionId: string | null, count: number): Promise<IVersion[]> {\n\t\treturn [];\n\t}\n\n\tpublic async getSnapshotTree(version?: IVersion): Promise<ISnapshotTree | null> {\n\t\treturn version ? Promise.reject(new Error(\"Invalid operation\")) : null;\n\t}\n\n\tpublic async readBlob(blobId: string): Promise<ArrayBufferLike> {\n\t\tthrow new Error(\"Invalid operation\");\n\t}\n\n\tpublic async getStartingOpSequence(): Promise<number> {\n\t\treturn 0;\n\t}\n\n\tpublic fetchTo(currentOp: number): number | undefined {\n\t\tif (!(this.unitIsTime !== true && this.replayTo >= 0)) {\n\t\t\treturn undefined;\n\t\t}\n\t\treturn this.replayTo;\n\t}\n\n\tpublic isDoneFetch(currentOp: number, lastTimeStamp?: number): boolean {\n\t\tif (this.replayTo >= 0) {\n\t\t\tif (this.unitIsTime === true) {\n\t\t\t\treturn (\n\t\t\t\t\tlastTimeStamp !== undefined &&\n\t\t\t\t\tthis.firstTimeStamp !== undefined &&\n\t\t\t\t\tlastTimeStamp - this.firstTimeStamp >= this.replayTo\n\t\t\t\t);\n\t\t\t}\n\t\t\treturn currentOp >= this.replayTo;\n\t\t}\n\t\treturn lastTimeStamp === undefined; // No more ops\n\t}\n\n\tpublic skipToIndex(fetchedOps: ISequencedDocumentMessage[]): number {\n\t\tif (this.replayFrom <= 0) {\n\t\t\treturn 0;\n\t\t}\n\t\tif (this.unitIsTime === true) {\n\t\t\tfor (const [i, { timestamp }] of fetchedOps.entries()) {\n\t\t\t\tif (timestamp !== undefined) {\n\t\t\t\t\t// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing -- using ??= could change behavior if value is falsy\n\t\t\t\t\tif (this.firstTimeStamp === undefined) {\n\t\t\t\t\t\tthis.firstTimeStamp = timestamp;\n\t\t\t\t\t}\n\t\t\t\t\tif (timestamp - this.firstTimeStamp >= this.replayFrom) {\n\t\t\t\t\t\treturn i;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (this.replayFrom > this.replayCurrent) {\n\t\t\treturn this.replayFrom - this.replayCurrent;\n\t\t}\n\t\treturn 0;\n\t}\n\n\tpublic async replay(\n\t\temitter: (op: ISequencedDocumentMessage[]) => void,\n\t\tfetchedOps: ISequencedDocumentMessage[],\n\t): Promise<void> {\n\t\tlet current = this.skipToIndex(fetchedOps);\n\n\t\treturn new Promise((resolve, reject) => {\n\t\t\tconst replayNextOps = (): void => {\n\t\t\t\t// Emit the ops from replay to the end every \"deltainterval\" milliseconds\n\t\t\t\t// to simulate the socket stream\n\t\t\t\tconst currentOp = fetchedOps[current];\n\t\t\t\tif (currentOp === undefined) {\n\t\t\t\t\treject(new Error(`No op found at replay index ${current}`));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst playbackOps = [currentOp];\n\t\t\t\tlet nextInterval = ReplayControllerStatic.DelayInterval;\n\t\t\t\tcurrent += 1;\n\n\t\t\t\tif (this.unitIsTime === true) {\n\t\t\t\t\tconst currentTimeStamp = currentOp.timestamp;\n\t\t\t\t\tif (currentTimeStamp !== undefined) {\n\t\t\t\t\t\t// Emit more ops that is in the ReplayResolution window\n\n\t\t\t\t\t\twhile (current < fetchedOps.length) {\n\t\t\t\t\t\t\tconst op = fetchedOps[current];\n\t\t\t\t\t\t\tif (op === undefined) {\n\t\t\t\t\t\t\t\treject(new Error(`No op found at replay index ${current}`));\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (op.timestamp === undefined) {\n\t\t\t\t\t\t\t\t// Missing timestamp, just delay the standard amount of time\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tconst timeDiff = op.timestamp - currentTimeStamp;\n\t\t\t\t\t\t\tif (timeDiff >= ReplayControllerStatic.ReplayResolution) {\n\t\t\t\t\t\t\t\t// Time exceeded the resolution window, break out the loop\n\t\t\t\t\t\t\t\t// and delay for the time difference.\n\t\t\t\t\t\t\t\tnextInterval = timeDiff;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (timeDiff < 0) {\n\t\t\t\t\t\t\t\t// Time have regressed, just delay the standard amount of time\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// The op is within the ReplayResolution emit it now\n\t\t\t\t\t\t\tplaybackOps.push(op);\n\t\t\t\t\t\t\tcurrent += 1;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\tthis.firstTimeStamp !== undefined &&\n\t\t\t\t\t\t\tthis.replayTo >= 0 &&\n\t\t\t\t\t\t\tcurrentTimeStamp + nextInterval - this.firstTimeStamp > this.replayTo\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\tnextInterval = -1;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tscheduleNext(nextInterval);\n\t\t\t\temitter(playbackOps);\n\t\t\t};\n\t\t\tconst scheduleNext = (nextInterval: number): void => {\n\t\t\t\tif (nextInterval >= 0 && current < fetchedOps.length) {\n\t\t\t\t\tsetTimeout(replayNextOps, nextInterval);\n\t\t\t\t} else {\n\t\t\t\t\tthis.replayCurrent += current;\n\t\t\t\t\tresolve();\n\t\t\t\t}\n\t\t\t};\n\t\t\tscheduleNext(ReplayControllerStatic.DelayInterval);\n\t\t});\n\t}\n}\n\nexport class ReplayDocumentDeltaConnection\n\textends TypedEventEmitter<IDocumentDeltaConnectionEvents>\n\timplements IDocumentDeltaConnection, IDisposable\n{\n\t/**\n\t * Creates a new delta connection and mimics the delta connection to replay ops on it.\n\t * @param documentService - The document service to be used to get underlying endpoints.\n\t */\n\tpublic static create(\n\t\tdocumentStorageService: IDocumentDeltaStorageService,\n\t\tcontroller: ReplayController,\n\t): IDocumentDeltaConnection {\n\t\tconst connection: IConnected = {\n\t\t\tclaims: ReplayDocumentDeltaConnection.claims,\n\t\t\tclientId: \"PseudoClientId\",\n\t\t\texisting: true,\n\t\t\tinitialMessages: [],\n\t\t\tinitialSignals: [],\n\t\t\tinitialClients: [],\n\t\t\tmaxMessageSize: ReplayDocumentDeltaConnection.ReplayMaxMessageSize,\n\t\t\tmode: \"read\",\n\t\t\tserviceConfiguration: {\n\t\t\t\tblockSize: 64436,\n\t\t\t\tmaxMessageSize: ReplayDocumentDeltaConnection.ReplayMaxMessageSize,\n\t\t\t},\n\t\t\tsupportedVersions: [ReplayDocumentDeltaConnection.replayProtocolVersion],\n\t\t\tversion: ReplayDocumentDeltaConnection.replayProtocolVersion,\n\t\t};\n\t\tconst deltaConnection = new ReplayDocumentDeltaConnection(connection);\n\t\t// eslint-disable-next-line @typescript-eslint/no-floating-promises\n\t\tdeltaConnection.fetchAndEmitOps(documentStorageService, controller);\n\n\t\treturn deltaConnection;\n\t}\n\n\tprivate static readonly replayProtocolVersion = \"^0.1.0\";\n\t// Since the replay service never actually sends messages the size below is arbitrary\n\tprivate static readonly ReplayMaxMessageSize = 16 * 1024;\n\n\tprivate static readonly claims: ITokenClaims = {\n\t\tdocumentId: ReplayDocumentId,\n\t\tscopes: [ScopeType.DocRead],\n\t\ttenantId: \"\",\n\t\tuser: {\n\t\t\tid: \"\",\n\t\t},\n\t\tiat: Math.round(Date.now() / 1000),\n\t\texp: Math.round(Date.now() / 1000) + 60 * 60, // 1 hour expiration\n\t\tver: \"1.0\",\n\t};\n\n\tpublic get clientId(): string {\n\t\treturn this.details.clientId;\n\t}\n\n\tpublic get mode(): ConnectionMode {\n\t\treturn this.details.mode;\n\t}\n\n\tpublic get claims(): ITokenClaims {\n\t\treturn this.details.claims;\n\t}\n\n\tpublic get existing(): boolean {\n\t\treturn this.details.existing;\n\t}\n\n\tpublic get version(): string {\n\t\treturn this.details.version;\n\t}\n\n\tpublic get initialMessages(): ISequencedDocumentMessage[] {\n\t\treturn this.details.initialMessages;\n\t}\n\n\tpublic get initialSignals(): ISignalMessage[] {\n\t\treturn this.details.initialSignals;\n\t}\n\n\tpublic get initialClients(): ISignalClient[] {\n\t\treturn this.details.initialClients;\n\t}\n\n\tpublic get serviceConfiguration(): IClientConfiguration {\n\t\treturn this.details.serviceConfiguration;\n\t}\n\n\tpublic readonly maxMessageSize = ReplayDocumentDeltaConnection.ReplayMaxMessageSize;\n\n\tconstructor(public details: IConnected) {\n\t\tsuper();\n\t}\n\n\tpublic submit(documentMessage: IDocumentMessage[]): void {\n\t\t// ReplayDocumentDeltaConnection.submit() can't be called - client never sees its own join on,\n\t\t// and thus can never move to sending ops.\n\t\tthrow new Error(\"ReplayDocumentDeltaConnection.submit() can't be called\");\n\t}\n\n\t// eslint-disable-next-line @typescript-eslint/no-misused-promises\n\tpublic async submitSignal(message: unknown): Promise<void> {}\n\n\tprivate _disposed = false;\n\tpublic get disposed(): boolean {\n\t\treturn this._disposed;\n\t}\n\tpublic dispose(): void {\n\t\tthis._disposed = true;\n\t}\n\n\t/**\n\t * This gets the specified ops from the delta storage endpoint and replays them in the replayer.\n\t */\n\tprivate async fetchAndEmitOps(\n\t\tdocumentStorageService: IDocumentDeltaStorageService,\n\t\tcontroller: ReplayController,\n\t): Promise<void> {\n\t\tlet done;\n\t\tlet replayPromiseChain = Promise.resolve();\n\n\t\tlet currentOp = await controller.getStartingOpSequence();\n\n\t\tdo {\n\t\t\tconst fetchTo = controller.fetchTo(currentOp);\n\n\t\t\tconst abortController = new AbortController();\n\t\t\tconst stream = documentStorageService.fetchMessages(\n\t\t\t\tcurrentOp + 1,\n\t\t\t\tfetchTo,\n\t\t\t\tabortController.signal,\n\t\t\t);\n\t\t\tdo {\n\t\t\t\tconst result = await stream.read();\n\n\t\t\t\tif (result.done) {\n\t\t\t\t\t// No more ops. But, they can show up later, either because document was just created,\n\t\t\t\t\t// or because another client keeps submitting new ops.\n\t\t\t\t\tdone = controller.isDoneFetch(currentOp, undefined);\n\t\t\t\t\tif (!done) {\n\t\t\t\t\t\tawait delay(2000);\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\treplayPromiseChain = replayPromiseChain.then(async () =>\n\t\t\t\t\tcontroller.replay((ops) => this.emit(\"op\", ReplayDocumentId, ops), messages),\n\t\t\t\t);\n\n\t\t\t\tconst messages = result.value;\n\t\t\t\tcurrentOp += messages.length;\n\t\t\t\tconst lastMessage = messages[messages.length - 1];\n\t\t\t\tif (lastMessage === undefined) {\n\t\t\t\t\tthrow new Error(\"Delta storage returned an empty batch of messages\");\n\t\t\t\t}\n\t\t\t\tdone = controller.isDoneFetch(currentOp, lastMessage.timestamp);\n\t\t\t} while (!done);\n\n\t\t\tabortController.abort();\n\t\t} while (!done);\n\t\treturn replayPromiseChain;\n\t}\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fluidframework/replay-driver",
3
- "version": "3.0.2",
3
+ "version": "3.1.0",
4
4
  "description": "Document replay version of Socket.IO implementation",
5
5
  "homepage": "https://fluidframework.com",
6
6
  "repository": {
@@ -26,12 +26,12 @@
26
26
  }
27
27
  },
28
28
  "dependencies": {
29
- "@fluid-internal/client-utils": "~3.0.2",
30
- "@fluidframework/core-interfaces": "~3.0.2",
31
- "@fluidframework/core-utils": "~3.0.2",
32
- "@fluidframework/driver-definitions": "~3.0.2",
33
- "@fluidframework/driver-utils": "~3.0.2",
34
- "@fluidframework/telemetry-utils": "~3.0.2"
29
+ "@fluid-internal/client-utils": "~3.1.0",
30
+ "@fluidframework/core-interfaces": "~3.1.0",
31
+ "@fluidframework/core-utils": "~3.1.0",
32
+ "@fluidframework/driver-definitions": "~3.1.0",
33
+ "@fluidframework/driver-utils": "~3.1.0",
34
+ "@fluidframework/telemetry-utils": "~3.1.0"
35
35
  },
36
36
  "devDependencies": {
37
37
  "@arethetypeswrong/cli": "^0.18.5",
@@ -124,11 +124,15 @@ export class ReplayControllerStatic extends ReplayController {
124
124
  ): Promise<void> {
125
125
  let current = this.skipToIndex(fetchedOps);
126
126
 
127
- return new Promise((resolve) => {
127
+ return new Promise((resolve, reject) => {
128
128
  const replayNextOps = (): void => {
129
129
  // Emit the ops from replay to the end every "deltainterval" milliseconds
130
130
  // to simulate the socket stream
131
131
  const currentOp = fetchedOps[current];
132
+ if (currentOp === undefined) {
133
+ reject(new Error(`No op found at replay index ${current}`));
134
+ return;
135
+ }
132
136
  const playbackOps = [currentOp];
133
137
  let nextInterval = ReplayControllerStatic.DelayInterval;
134
138
  current += 1;
@@ -140,6 +144,10 @@ export class ReplayControllerStatic extends ReplayController {
140
144
 
141
145
  while (current < fetchedOps.length) {
142
146
  const op = fetchedOps[current];
147
+ if (op === undefined) {
148
+ reject(new Error(`No op found at replay index ${current}`));
149
+ return;
150
+ }
143
151
  if (op.timestamp === undefined) {
144
152
  // Missing timestamp, just delay the standard amount of time
145
153
  break;
@@ -335,7 +343,11 @@ export class ReplayDocumentDeltaConnection
335
343
 
336
344
  const messages = result.value;
337
345
  currentOp += messages.length;
338
- done = controller.isDoneFetch(currentOp, messages[messages.length - 1].timestamp);
346
+ const lastMessage = messages[messages.length - 1];
347
+ if (lastMessage === undefined) {
348
+ throw new Error("Delta storage returned an empty batch of messages");
349
+ }
350
+ done = controller.isDoneFetch(currentOp, lastMessage.timestamp);
339
351
  } while (!done);
340
352
 
341
353
  abortController.abort();
package/tsconfig.json CHANGED
@@ -5,7 +5,5 @@
5
5
  "compilerOptions": {
6
6
  "rootDir": "./src",
7
7
  "outDir": "./lib",
8
- // TODO: AB#34164 Enable noUncheckedIndexedAccess for packages/drivers/replay-driver
9
- "noUncheckedIndexedAccess": false,
10
8
  },
11
9
  }