@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 +4 -0
- package/README.md +30 -34
- package/dist/replayDocumentDeltaConnection.d.ts.map +1 -1
- package/dist/replayDocumentDeltaConnection.js +14 -2
- package/dist/replayDocumentDeltaConnection.js.map +1 -1
- package/eslint.config.mts +0 -1
- package/lib/replayDocumentDeltaConnection.d.ts.map +1 -1
- package/lib/replayDocumentDeltaConnection.js +14 -2
- package/lib/replayDocumentDeltaConnection.js.map +1 -1
- package/package.json +7 -7
- package/src/replayDocumentDeltaConnection.ts +14 -2
- package/tsconfig.json +0 -2
package/CHANGELOG.md
CHANGED
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
|
-
<!--
|
|
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
|
-
<!--
|
|
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
|
-
-
|
|
54
|
-
-
|
|
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
|
-
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
-
|
|
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
|
-
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
-
|
|
74
|
-
|
|
75
|
-
|
|
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
|
-
-
|
|
87
|
-
|
|
88
|
-
-
|
|
89
|
-
|
|
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
|
-
-
|
|
96
|
-
-
|
|
97
|
-
-
|
|
98
|
-
-
|
|
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
|
|
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":"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;
|
|
1
|
+
{"version":3,"file":"replayDocumentDeltaConnection.d.ts","sourceRoot":"","sources":["../src/replayDocumentDeltaConnection.ts"],"names":[],"mappings":"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"}
|
|
@@ -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
|
-
|
|
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
|
@@ -1 +1 @@
|
|
|
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;
|
|
1
|
+
{"version":3,"file":"replayDocumentDeltaConnection.d.ts","sourceRoot":"","sources":["../src/replayDocumentDeltaConnection.ts"],"names":[],"mappings":"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"}
|
|
@@ -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
|
-
|
|
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":"AAAA;;;GAGG;AAEH,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AAEjE,OAAO,EAAE,KAAK,EAAE,MAAM,qCAAqC,CAAC;AAiB5D,OAAO,EAAE,SAAS,EAAE,MAAM,6CAA6C,CAAC;AAExE,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAEzD,MAAM,gBAAgB,GAAG,YAAY,CAAC;AAEtC,MAAM,OAAO,sBAAuB,SAAQ,gBAAgB;IAgB1C;IACA;IACA;IAjBT,MAAM,CAAU,aAAa,GAAG,EAAE,CAAC;IACnC,MAAM,CAAU,gBAAgB,GAAG,EAAE,CAAC;IAEtC,cAAc,CAAqB;IACnC,aAAa,GAAG,CAAC,CAAC;IAC1B,gDAAgD;IAEhD;;;;;;OAMG;IACH,YACiB,UAAkB,EAClB,QAAgB,EAChB,UAAoB;QAEpC,KAAK,EAAE,CAAC;QAJQ,eAAU,GAAV,UAAU,CAAQ;QAClB,aAAQ,GAAR,QAAQ,CAAQ;QAChB,eAAU,GAAV,UAAU,CAAU;QAGpC,IAAI,UAAU,KAAK,IAAI,EAAE,CAAC;YACzB,qFAAqF;YACrF,IAAI,CAAC,QAAQ,GAAG,CAAC,CAAC;QACnB,CAAC;IACF,CAAC;IAEM,KAAK,CAAC,WAAW,CAAC,eAAiC;QACzD,OAAO,IAAI,CAAC;IACb,CAAC;IAEM,KAAK,CAAC,WAAW,CAAC,SAAwB,EAAE,KAAa;QAC/D,OAAO,EAAE,CAAC;IACX,CAAC;IAEM,KAAK,CAAC,eAAe,CAAC,OAAkB;QAC9C,OAAO,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,mBAAmB,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IACxE,CAAC;IAEM,KAAK,CAAC,QAAQ,CAAC,MAAc;QACnC,MAAM,IAAI,KAAK,CAAC,mBAAmB,CAAC,CAAC;IACtC,CAAC;IAEM,KAAK,CAAC,qBAAqB;QACjC,OAAO,CAAC,CAAC;IACV,CAAC;IAEM,OAAO,CAAC,SAAiB;QAC/B,IAAI,CAAC,CAAC,IAAI,CAAC,UAAU,KAAK,IAAI,IAAI,IAAI,CAAC,QAAQ,IAAI,CAAC,CAAC,EAAE,CAAC;YACvD,OAAO,SAAS,CAAC;QAClB,CAAC;QACD,OAAO,IAAI,CAAC,QAAQ,CAAC;IACtB,CAAC;IAEM,WAAW,CAAC,SAAiB,EAAE,aAAsB;QAC3D,IAAI,IAAI,CAAC,QAAQ,IAAI,CAAC,EAAE,CAAC;YACxB,IAAI,IAAI,CAAC,UAAU,KAAK,IAAI,EAAE,CAAC;gBAC9B,OAAO,CACN,aAAa,KAAK,SAAS;oBAC3B,IAAI,CAAC,cAAc,KAAK,SAAS;oBACjC,aAAa,GAAG,IAAI,CAAC,cAAc,IAAI,IAAI,CAAC,QAAQ,CACpD,CAAC;YACH,CAAC;YACD,OAAO,SAAS,IAAI,IAAI,CAAC,QAAQ,CAAC;QACnC,CAAC;QACD,OAAO,aAAa,KAAK,SAAS,CAAC,CAAC,cAAc;IACnD,CAAC;IAEM,WAAW,CAAC,UAAuC;QACzD,IAAI,IAAI,CAAC,UAAU,IAAI,CAAC,EAAE,CAAC;YAC1B,OAAO,CAAC,CAAC;QACV,CAAC;QACD,IAAI,IAAI,CAAC,UAAU,KAAK,IAAI,EAAE,CAAC;YAC9B,KAAK,MAAM,CAAC,CAAC,EAAE,EAAE,SAAS,EAAE,CAAC,IAAI,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC;gBACvD,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;oBAC7B,6HAA6H;oBAC7H,IAAI,IAAI,CAAC,cAAc,KAAK,SAAS,EAAE,CAAC;wBACvC,IAAI,CAAC,cAAc,GAAG,SAAS,CAAC;oBACjC,CAAC;oBACD,IAAI,SAAS,GAAG,IAAI,CAAC,cAAc,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;wBACxD,OAAO,CAAC,CAAC;oBACV,CAAC;gBACF,CAAC;YACF,CAAC;QACF,CAAC;aAAM,IAAI,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,aAAa,EAAE,CAAC;YACjD,OAAO,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,aAAa,CAAC;QAC7C,CAAC;QACD,OAAO,CAAC,CAAC;IACV,CAAC;IAEM,KAAK,CAAC,MAAM,CAClB,OAAkD,EAClD,UAAuC;QAEvC,IAAI,OAAO,GAAG,IAAI,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC;QAE3C,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACtC,MAAM,aAAa,GAAG,GAAS,EAAE;gBAChC,yEAAyE;gBACzE,gCAAgC;gBAChC,MAAM,SAAS,GAAG,UAAU,CAAC,OAAO,CAAC,CAAC;gBACtC,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;oBAC7B,MAAM,CAAC,IAAI,KAAK,CAAC,+BAA+B,OAAO,EAAE,CAAC,CAAC,CAAC;oBAC5D,OAAO;gBACR,CAAC;gBACD,MAAM,WAAW,GAAG,CAAC,SAAS,CAAC,CAAC;gBAChC,IAAI,YAAY,GAAG,sBAAsB,CAAC,aAAa,CAAC;gBACxD,OAAO,IAAI,CAAC,CAAC;gBAEb,IAAI,IAAI,CAAC,UAAU,KAAK,IAAI,EAAE,CAAC;oBAC9B,MAAM,gBAAgB,GAAG,SAAS,CAAC,SAAS,CAAC;oBAC7C,IAAI,gBAAgB,KAAK,SAAS,EAAE,CAAC;wBACpC,uDAAuD;wBAEvD,OAAO,OAAO,GAAG,UAAU,CAAC,MAAM,EAAE,CAAC;4BACpC,MAAM,EAAE,GAAG,UAAU,CAAC,OAAO,CAAC,CAAC;4BAC/B,IAAI,EAAE,KAAK,SAAS,EAAE,CAAC;gCACtB,MAAM,CAAC,IAAI,KAAK,CAAC,+BAA+B,OAAO,EAAE,CAAC,CAAC,CAAC;gCAC5D,OAAO;4BACR,CAAC;4BACD,IAAI,EAAE,CAAC,SAAS,KAAK,SAAS,EAAE,CAAC;gCAChC,4DAA4D;gCAC5D,MAAM;4BACP,CAAC;4BACD,MAAM,QAAQ,GAAG,EAAE,CAAC,SAAS,GAAG,gBAAgB,CAAC;4BACjD,IAAI,QAAQ,IAAI,sBAAsB,CAAC,gBAAgB,EAAE,CAAC;gCACzD,0DAA0D;gCAC1D,qCAAqC;gCACrC,YAAY,GAAG,QAAQ,CAAC;gCACxB,MAAM;4BACP,CAAC;4BACD,IAAI,QAAQ,GAAG,CAAC,EAAE,CAAC;gCAClB,8DAA8D;gCAC9D,MAAM;4BACP,CAAC;4BAED,oDAAoD;4BACpD,WAAW,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;4BACrB,OAAO,IAAI,CAAC,CAAC;wBACd,CAAC;wBAED,IACC,IAAI,CAAC,cAAc,KAAK,SAAS;4BACjC,IAAI,CAAC,QAAQ,IAAI,CAAC;4BAClB,gBAAgB,GAAG,YAAY,GAAG,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC,QAAQ,EACpE,CAAC;4BACF,YAAY,GAAG,CAAC,CAAC,CAAC;wBACnB,CAAC;oBACF,CAAC;gBACF,CAAC;gBACD,YAAY,CAAC,YAAY,CAAC,CAAC;gBAC3B,OAAO,CAAC,WAAW,CAAC,CAAC;YACtB,CAAC,CAAC;YACF,MAAM,YAAY,GAAG,CAAC,YAAoB,EAAQ,EAAE;gBACnD,IAAI,YAAY,IAAI,CAAC,IAAI,OAAO,GAAG,UAAU,CAAC,MAAM,EAAE,CAAC;oBACtD,UAAU,CAAC,aAAa,EAAE,YAAY,CAAC,CAAC;gBACzC,CAAC;qBAAM,CAAC;oBACP,IAAI,CAAC,aAAa,IAAI,OAAO,CAAC;oBAC9B,OAAO,EAAE,CAAC;gBACX,CAAC;YACF,CAAC,CAAC;YACF,YAAY,CAAC,sBAAsB,CAAC,aAAa,CAAC,CAAC;QACpD,CAAC,CAAC,CAAC;IACJ,CAAC;;AAGF,MAAM,OAAO,6BACZ,SAAQ,iBAAiD;IAwFtC;IArFnB;;;OAGG;IACI,MAAM,CAAC,MAAM,CACnB,sBAAoD,EACpD,UAA4B;QAE5B,MAAM,UAAU,GAAe;YAC9B,MAAM,EAAE,6BAA6B,CAAC,MAAM;YAC5C,QAAQ,EAAE,gBAAgB;YAC1B,QAAQ,EAAE,IAAI;YACd,eAAe,EAAE,EAAE;YACnB,cAAc,EAAE,EAAE;YAClB,cAAc,EAAE,EAAE;YAClB,cAAc,EAAE,6BAA6B,CAAC,oBAAoB;YAClE,IAAI,EAAE,MAAM;YACZ,oBAAoB,EAAE;gBACrB,SAAS,EAAE,KAAK;gBAChB,cAAc,EAAE,6BAA6B,CAAC,oBAAoB;aAClE;YACD,iBAAiB,EAAE,CAAC,6BAA6B,CAAC,qBAAqB,CAAC;YACxE,OAAO,EAAE,6BAA6B,CAAC,qBAAqB;SAC5D,CAAC;QACF,MAAM,eAAe,GAAG,IAAI,6BAA6B,CAAC,UAAU,CAAC,CAAC;QACtE,mEAAmE;QACnE,eAAe,CAAC,eAAe,CAAC,sBAAsB,EAAE,UAAU,CAAC,CAAC;QAEpE,OAAO,eAAe,CAAC;IACxB,CAAC;IAEO,MAAM,CAAU,qBAAqB,GAAG,QAAQ,CAAC;IACzD,qFAAqF;IAC7E,MAAM,CAAU,oBAAoB,GAAG,EAAE,GAAG,IAAI,CAAC;IAEjD,MAAM,CAAU,MAAM,GAAiB;QAC9C,UAAU,EAAE,gBAAgB;QAC5B,MAAM,EAAE,CAAC,SAAS,CAAC,OAAO,CAAC;QAC3B,QAAQ,EAAE,EAAE;QACZ,IAAI,EAAE;YACL,EAAE,EAAE,EAAE;SACN;QACD,GAAG,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC;QAClC,GAAG,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,oBAAoB;QAClE,GAAG,EAAE,KAAK;KACV,CAAC;IAEF,IAAW,QAAQ;QAClB,OAAO,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC;IAC9B,CAAC;IAED,IAAW,IAAI;QACd,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC;IAC1B,CAAC;IAED,IAAW,MAAM;QAChB,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC;IAC5B,CAAC;IAED,IAAW,QAAQ;QAClB,OAAO,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC;IAC9B,CAAC;IAED,IAAW,OAAO;QACjB,OAAO,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC;IAC7B,CAAC;IAED,IAAW,eAAe;QACzB,OAAO,IAAI,CAAC,OAAO,CAAC,eAAe,CAAC;IACrC,CAAC;IAED,IAAW,cAAc;QACxB,OAAO,IAAI,CAAC,OAAO,CAAC,cAAc,CAAC;IACpC,CAAC;IAED,IAAW,cAAc;QACxB,OAAO,IAAI,CAAC,OAAO,CAAC,cAAc,CAAC;IACpC,CAAC;IAED,IAAW,oBAAoB;QAC9B,OAAO,IAAI,CAAC,OAAO,CAAC,oBAAoB,CAAC;IAC1C,CAAC;IAEe,cAAc,GAAG,6BAA6B,CAAC,oBAAoB,CAAC;IAEpF,YAAmB,OAAmB;QACrC,KAAK,EAAE,CAAC;QADU,YAAO,GAAP,OAAO,CAAY;IAEtC,CAAC;IAEM,MAAM,CAAC,eAAmC;QAChD,8FAA8F;QAC9F,0CAA0C;QAC1C,MAAM,IAAI,KAAK,CAAC,wDAAwD,CAAC,CAAC;IAC3E,CAAC;IAED,kEAAkE;IAC3D,KAAK,CAAC,YAAY,CAAC,OAAgB,IAAkB,CAAC;IAErD,SAAS,GAAG,KAAK,CAAC;IAC1B,IAAW,QAAQ;QAClB,OAAO,IAAI,CAAC,SAAS,CAAC;IACvB,CAAC;IACM,OAAO;QACb,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;IACvB,CAAC;IAED;;OAEG;IACK,KAAK,CAAC,eAAe,CAC5B,sBAAoD,EACpD,UAA4B;QAE5B,IAAI,IAAI,CAAC;QACT,IAAI,kBAAkB,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC;QAE3C,IAAI,SAAS,GAAG,MAAM,UAAU,CAAC,qBAAqB,EAAE,CAAC;QAEzD,GAAG,CAAC;YACH,MAAM,OAAO,GAAG,UAAU,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;YAE9C,MAAM,eAAe,GAAG,IAAI,eAAe,EAAE,CAAC;YAC9C,MAAM,MAAM,GAAG,sBAAsB,CAAC,aAAa,CAClD,SAAS,GAAG,CAAC,EACb,OAAO,EACP,eAAe,CAAC,MAAM,CACtB,CAAC;YACF,GAAG,CAAC;gBACH,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC;gBAEnC,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC;oBACjB,sFAAsF;oBACtF,sDAAsD;oBACtD,IAAI,GAAG,UAAU,CAAC,WAAW,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;oBACpD,IAAI,CAAC,IAAI,EAAE,CAAC;wBACX,MAAM,KAAK,CAAC,IAAI,CAAC,CAAC;oBACnB,CAAC;oBACD,MAAM;gBACP,CAAC;gBACD,kBAAkB,GAAG,kBAAkB,CAAC,IAAI,CAAC,KAAK,IAAI,EAAE,CACvD,UAAU,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,gBAAgB,EAAE,GAAG,CAAC,EAAE,QAAQ,CAAC,CAC5E,CAAC;gBAEF,MAAM,QAAQ,GAAG,MAAM,CAAC,KAAK,CAAC;gBAC9B,SAAS,IAAI,QAAQ,CAAC,MAAM,CAAC;gBAC7B,MAAM,WAAW,GAAG,QAAQ,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;gBAClD,IAAI,WAAW,KAAK,SAAS,EAAE,CAAC;oBAC/B,MAAM,IAAI,KAAK,CAAC,mDAAmD,CAAC,CAAC;gBACtE,CAAC;gBACD,IAAI,GAAG,UAAU,CAAC,WAAW,CAAC,SAAS,EAAE,WAAW,CAAC,SAAS,CAAC,CAAC;YACjE,CAAC,QAAQ,CAAC,IAAI,EAAE;YAEhB,eAAe,CAAC,KAAK,EAAE,CAAC;QACzB,CAAC,QAAQ,CAAC,IAAI,EAAE;QAChB,OAAO,kBAAkB,CAAC;IAC3B,CAAC","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
|
|
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
|
|
30
|
-
"@fluidframework/core-interfaces": "~3.0
|
|
31
|
-
"@fluidframework/core-utils": "~3.0
|
|
32
|
-
"@fluidframework/driver-definitions": "~3.0
|
|
33
|
-
"@fluidframework/driver-utils": "~3.0
|
|
34
|
-
"@fluidframework/telemetry-utils": "~3.0
|
|
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
|
-
|
|
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();
|