@fluidframework/container-loader 2.0.0-internal.3.0.5 → 2.0.0-internal.3.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (148) hide show
  1. package/.eslintrc.js +18 -21
  2. package/.mocharc.js +2 -2
  3. package/README.md +45 -43
  4. package/api-extractor.json +2 -2
  5. package/closeAndGetPendingLocalState.md +51 -0
  6. package/dist/audience.d.ts.map +1 -1
  7. package/dist/audience.js.map +1 -1
  8. package/dist/catchUpMonitor.d.ts.map +1 -1
  9. package/dist/catchUpMonitor.js.map +1 -1
  10. package/dist/collabWindowTracker.d.ts.map +1 -1
  11. package/dist/collabWindowTracker.js.map +1 -1
  12. package/dist/connectionManager.d.ts +2 -2
  13. package/dist/connectionManager.d.ts.map +1 -1
  14. package/dist/connectionManager.js +51 -24
  15. package/dist/connectionManager.js.map +1 -1
  16. package/dist/connectionState.d.ts.map +1 -1
  17. package/dist/connectionState.js.map +1 -1
  18. package/dist/connectionStateHandler.d.ts.map +1 -1
  19. package/dist/connectionStateHandler.js +35 -16
  20. package/dist/connectionStateHandler.js.map +1 -1
  21. package/dist/container.d.ts +1 -10
  22. package/dist/container.d.ts.map +1 -1
  23. package/dist/container.js +89 -44
  24. package/dist/container.js.map +1 -1
  25. package/dist/containerContext.d.ts.map +1 -1
  26. package/dist/containerContext.js +6 -2
  27. package/dist/containerContext.js.map +1 -1
  28. package/dist/containerStorageAdapter.d.ts.map +1 -1
  29. package/dist/containerStorageAdapter.js +2 -4
  30. package/dist/containerStorageAdapter.js.map +1 -1
  31. package/dist/contracts.d.ts.map +1 -1
  32. package/dist/contracts.js.map +1 -1
  33. package/dist/deltaManager.d.ts +3 -3
  34. package/dist/deltaManager.d.ts.map +1 -1
  35. package/dist/deltaManager.js +56 -27
  36. package/dist/deltaManager.js.map +1 -1
  37. package/dist/deltaManagerProxy.d.ts.map +1 -1
  38. package/dist/deltaManagerProxy.js.map +1 -1
  39. package/dist/deltaQueue.d.ts.map +1 -1
  40. package/dist/deltaQueue.js +4 -2
  41. package/dist/deltaQueue.js.map +1 -1
  42. package/dist/index.d.ts +1 -1
  43. package/dist/index.d.ts.map +1 -1
  44. package/dist/index.js.map +1 -1
  45. package/dist/loader.d.ts +3 -3
  46. package/dist/loader.d.ts.map +1 -1
  47. package/dist/loader.js +18 -15
  48. package/dist/loader.js.map +1 -1
  49. package/dist/packageVersion.d.ts +1 -1
  50. package/dist/packageVersion.js +1 -1
  51. package/dist/packageVersion.js.map +1 -1
  52. package/dist/protocol.d.ts.map +1 -1
  53. package/dist/protocol.js +2 -1
  54. package/dist/protocol.js.map +1 -1
  55. package/dist/protocolTreeDocumentStorageService.d.ts.map +1 -1
  56. package/dist/protocolTreeDocumentStorageService.js.map +1 -1
  57. package/dist/quorum.d.ts.map +1 -1
  58. package/dist/quorum.js.map +1 -1
  59. package/dist/retriableDocumentStorageService.d.ts.map +1 -1
  60. package/dist/retriableDocumentStorageService.js +6 -2
  61. package/dist/retriableDocumentStorageService.js.map +1 -1
  62. package/dist/utils.d.ts.map +1 -1
  63. package/dist/utils.js +6 -4
  64. package/dist/utils.js.map +1 -1
  65. package/lib/audience.d.ts.map +1 -1
  66. package/lib/audience.js.map +1 -1
  67. package/lib/catchUpMonitor.d.ts.map +1 -1
  68. package/lib/catchUpMonitor.js.map +1 -1
  69. package/lib/collabWindowTracker.d.ts.map +1 -1
  70. package/lib/collabWindowTracker.js.map +1 -1
  71. package/lib/connectionManager.d.ts +2 -2
  72. package/lib/connectionManager.d.ts.map +1 -1
  73. package/lib/connectionManager.js +53 -26
  74. package/lib/connectionManager.js.map +1 -1
  75. package/lib/connectionState.d.ts.map +1 -1
  76. package/lib/connectionState.js.map +1 -1
  77. package/lib/connectionStateHandler.d.ts.map +1 -1
  78. package/lib/connectionStateHandler.js +35 -16
  79. package/lib/connectionStateHandler.js.map +1 -1
  80. package/lib/container.d.ts +1 -10
  81. package/lib/container.d.ts.map +1 -1
  82. package/lib/container.js +93 -48
  83. package/lib/container.js.map +1 -1
  84. package/lib/containerContext.d.ts.map +1 -1
  85. package/lib/containerContext.js +6 -2
  86. package/lib/containerContext.js.map +1 -1
  87. package/lib/containerStorageAdapter.d.ts.map +1 -1
  88. package/lib/containerStorageAdapter.js +2 -4
  89. package/lib/containerStorageAdapter.js.map +1 -1
  90. package/lib/contracts.d.ts.map +1 -1
  91. package/lib/contracts.js.map +1 -1
  92. package/lib/deltaManager.d.ts +3 -3
  93. package/lib/deltaManager.d.ts.map +1 -1
  94. package/lib/deltaManager.js +58 -29
  95. package/lib/deltaManager.js.map +1 -1
  96. package/lib/deltaManagerProxy.d.ts.map +1 -1
  97. package/lib/deltaManagerProxy.js.map +1 -1
  98. package/lib/deltaQueue.d.ts.map +1 -1
  99. package/lib/deltaQueue.js +4 -2
  100. package/lib/deltaQueue.js.map +1 -1
  101. package/lib/index.d.ts +1 -1
  102. package/lib/index.d.ts.map +1 -1
  103. package/lib/index.js.map +1 -1
  104. package/lib/loader.d.ts +3 -3
  105. package/lib/loader.d.ts.map +1 -1
  106. package/lib/loader.js +18 -15
  107. package/lib/loader.js.map +1 -1
  108. package/lib/packageVersion.d.ts +1 -1
  109. package/lib/packageVersion.js +1 -1
  110. package/lib/packageVersion.js.map +1 -1
  111. package/lib/protocol.d.ts.map +1 -1
  112. package/lib/protocol.js +2 -1
  113. package/lib/protocol.js.map +1 -1
  114. package/lib/protocolTreeDocumentStorageService.d.ts.map +1 -1
  115. package/lib/protocolTreeDocumentStorageService.js.map +1 -1
  116. package/lib/quorum.d.ts.map +1 -1
  117. package/lib/quorum.js.map +1 -1
  118. package/lib/retriableDocumentStorageService.d.ts.map +1 -1
  119. package/lib/retriableDocumentStorageService.js +6 -2
  120. package/lib/retriableDocumentStorageService.js.map +1 -1
  121. package/lib/utils.d.ts.map +1 -1
  122. package/lib/utils.js +6 -4
  123. package/lib/utils.js.map +1 -1
  124. package/package.json +115 -114
  125. package/prettier.config.cjs +1 -1
  126. package/src/audience.ts +51 -46
  127. package/src/catchUpMonitor.ts +39 -37
  128. package/src/collabWindowTracker.ts +75 -70
  129. package/src/connectionManager.ts +1006 -944
  130. package/src/connectionState.ts +19 -19
  131. package/src/connectionStateHandler.ts +544 -465
  132. package/src/container.ts +2056 -1909
  133. package/src/containerContext.ts +350 -340
  134. package/src/containerStorageAdapter.ts +163 -153
  135. package/src/contracts.ts +155 -153
  136. package/src/deltaManager.ts +1069 -992
  137. package/src/deltaManagerProxy.ts +143 -137
  138. package/src/deltaQueue.ts +155 -151
  139. package/src/index.ts +14 -17
  140. package/src/loader.ts +428 -430
  141. package/src/packageVersion.ts +1 -1
  142. package/src/protocol.ts +93 -87
  143. package/src/protocolTreeDocumentStorageService.ts +30 -33
  144. package/src/quorum.ts +34 -34
  145. package/src/retriableDocumentStorageService.ts +118 -102
  146. package/src/utils.ts +89 -82
  147. package/tsconfig.esnext.json +6 -6
  148. package/tsconfig.json +8 -12
package/package.json CHANGED
@@ -1,116 +1,117 @@
1
1
  {
2
- "name": "@fluidframework/container-loader",
3
- "version": "2.0.0-internal.3.0.5",
4
- "description": "Fluid container loader",
5
- "homepage": "https://fluidframework.com",
6
- "repository": {
7
- "type": "git",
8
- "url": "https://github.com/microsoft/FluidFramework.git",
9
- "directory": "packages/loader/container-loader"
10
- },
11
- "license": "MIT",
12
- "author": "Microsoft and contributors",
13
- "sideEffects": false,
14
- "main": "dist/index.js",
15
- "module": "lib/index.js",
16
- "types": "dist/index.d.ts",
17
- "scripts": {
18
- "build": "npm run build:genver && concurrently npm:build:compile npm:lint && npm run build:docs",
19
- "build:commonjs": "npm run tsc && npm run typetests:gen && npm run build:test",
20
- "build:compile": "concurrently npm:build:commonjs npm:build:esnext",
21
- "build:docs": "api-extractor run --local --typescript-compiler-folder ../../../node_modules/typescript && copyfiles -u 1 ./_api-extractor-temp/doc-models/* ../../../_api-extractor-temp/",
22
- "build:esnext": "tsc --project ./tsconfig.esnext.json",
23
- "build:full": "npm run build",
24
- "build:full:compile": "npm run build:compile",
25
- "build:genver": "gen-version",
26
- "build:test": "tsc --project ./src/test/tsconfig.json",
27
- "ci:build:docs": "api-extractor run --typescript-compiler-folder ../../../node_modules/typescript && copyfiles -u 1 ./_api-extractor-temp/* ../../../_api-extractor-temp/",
28
- "clean": "rimraf dist lib *.tsbuildinfo *.build.log",
29
- "eslint": "eslint --format stylish src",
30
- "eslint:fix": "eslint --format stylish src --fix --fix-type problem,suggestion,layout",
31
- "format": "npm run prettier:fix",
32
- "lint": "npm run eslint",
33
- "lint:fix": "npm run eslint:fix",
34
- "prettier": "prettier --check . --ignore-path ../../../.prettierignore",
35
- "prettier:fix": "prettier --write . --ignore-path ../../../.prettierignore",
36
- "test": "npm run test:mocha",
37
- "test:coverage": "nyc npm test -- --reporter xunit --reporter-option output=nyc/junit-report.xml",
38
- "test:mocha": "mocha --ignore 'dist/test/types/*' --recursive dist/test -r node_modules/@fluidframework/mocha-test-setup --unhandled-rejections=strict",
39
- "test:mocha:verbose": "cross-env FLUID_TEST_VERBOSE=1 npm run test:mocha",
40
- "tsc": "tsc",
41
- "tsc:watch": "tsc --watch",
42
- "typetests:gen": "flub generate typetests --generate --dir .",
43
- "typetests:prepare": "flub generate typetests --prepare --dir . --pin"
44
- },
45
- "nyc": {
46
- "all": true,
47
- "cache-dir": "nyc/.cache",
48
- "exclude": [
49
- "src/test/**/*.ts",
50
- "dist/test/**/*.js"
51
- ],
52
- "exclude-after-remap": false,
53
- "include": [
54
- "src/**/*.ts",
55
- "dist/**/*.js"
56
- ],
57
- "report-dir": "nyc/report",
58
- "reporter": [
59
- "cobertura",
60
- "html",
61
- "text"
62
- ],
63
- "temp-directory": "nyc/.nyc_output"
64
- },
65
- "dependencies": {
66
- "@fluidframework/common-definitions": "^0.20.1",
67
- "@fluidframework/common-utils": "^1.0.0",
68
- "@fluidframework/container-definitions": ">=2.0.0-internal.3.0.5 <2.0.0-internal.4.0.0",
69
- "@fluidframework/container-utils": ">=2.0.0-internal.3.0.5 <2.0.0-internal.4.0.0",
70
- "@fluidframework/core-interfaces": ">=2.0.0-internal.3.0.5 <2.0.0-internal.4.0.0",
71
- "@fluidframework/driver-definitions": ">=2.0.0-internal.3.0.5 <2.0.0-internal.4.0.0",
72
- "@fluidframework/driver-utils": ">=2.0.0-internal.3.0.5 <2.0.0-internal.4.0.0",
73
- "@fluidframework/protocol-base": "^0.1038.2000",
74
- "@fluidframework/protocol-definitions": "^1.1.0",
75
- "@fluidframework/telemetry-utils": ">=2.0.0-internal.3.0.5 <2.0.0-internal.4.0.0",
76
- "abort-controller": "^3.0.0",
77
- "double-ended-queue": "^2.1.0-0",
78
- "events": "^3.1.0",
79
- "lodash": "^4.17.21",
80
- "url": "^0.11.0",
81
- "uuid": "^8.3.1"
82
- },
83
- "devDependencies": {
84
- "@fluid-tools/build-cli": "^0.8.0",
85
- "@fluidframework/build-common": "^1.1.0",
86
- "@fluidframework/build-tools": "^0.8.0",
87
- "@fluidframework/container-loader-previous": "npm:@fluidframework/container-loader@2.0.0-internal.3.0.0",
88
- "@fluidframework/eslint-config-fluid": "^2.0.0",
89
- "@fluidframework/mocha-test-setup": ">=2.0.0-internal.3.0.5 <2.0.0-internal.4.0.0",
90
- "@fluidframework/test-loader-utils": ">=2.0.0-internal.3.0.5 <2.0.0-internal.4.0.0",
91
- "@microsoft/api-extractor": "^7.22.2",
92
- "@rushstack/eslint-config": "^2.5.1",
93
- "@types/double-ended-queue": "^2.1.0",
94
- "@types/events": "^3.0.0",
95
- "@types/lodash": "^4.14.118",
96
- "@types/mocha": "^9.1.1",
97
- "@types/node": "^14.18.36",
98
- "@types/sinon": "^7.0.13",
99
- "concurrently": "^6.2.0",
100
- "copyfiles": "^2.4.1",
101
- "cross-env": "^7.0.2",
102
- "eslint": "~8.6.0",
103
- "mocha": "^10.0.0",
104
- "nyc": "^15.0.0",
105
- "prettier": "~2.6.2",
106
- "rimraf": "^2.6.2",
107
- "sinon": "^7.4.2",
108
- "typescript": "~4.5.5"
109
- },
110
- "typeValidation": {
111
- "version": "2.0.0-internal.3.0.1",
112
- "previousVersionStyle": "previousPatch",
113
- "baselineRange": "2.0.0-internal.3.0.0",
114
- "broken": {}
115
- }
2
+ "name": "@fluidframework/container-loader",
3
+ "version": "2.0.0-internal.3.1.1",
4
+ "description": "Fluid container loader",
5
+ "homepage": "https://fluidframework.com",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "https://github.com/microsoft/FluidFramework.git",
9
+ "directory": "packages/loader/container-loader"
10
+ },
11
+ "license": "MIT",
12
+ "author": "Microsoft and contributors",
13
+ "sideEffects": false,
14
+ "main": "dist/index.js",
15
+ "module": "lib/index.js",
16
+ "types": "dist/index.d.ts",
17
+ "scripts": {
18
+ "build": "npm run build:genver && concurrently npm:build:compile npm:lint && npm run build:docs",
19
+ "build:commonjs": "npm run tsc && npm run typetests:gen && npm run build:test",
20
+ "build:compile": "concurrently npm:build:commonjs npm:build:esnext",
21
+ "build:docs": "api-extractor run --local --typescript-compiler-folder ../../../node_modules/typescript && copyfiles -u 1 ./_api-extractor-temp/doc-models/* ../../../_api-extractor-temp/",
22
+ "build:esnext": "tsc --project ./tsconfig.esnext.json",
23
+ "build:full": "npm run build",
24
+ "build:full:compile": "npm run build:compile",
25
+ "build:genver": "gen-version",
26
+ "build:test": "tsc --project ./src/test/tsconfig.json",
27
+ "ci:build:docs": "api-extractor run --typescript-compiler-folder ../../../node_modules/typescript && copyfiles -u 1 ./_api-extractor-temp/* ../../../_api-extractor-temp/",
28
+ "clean": "rimraf dist lib *.tsbuildinfo *.build.log",
29
+ "eslint": "eslint --format stylish src",
30
+ "eslint:fix": "eslint --format stylish src --fix --fix-type problem,suggestion,layout",
31
+ "format": "npm run prettier:fix",
32
+ "lint": "npm run prettier && npm run eslint",
33
+ "lint:fix": "npm run prettier:fix && npm run eslint:fix",
34
+ "prettier": "prettier --check . --ignore-path ../../../.prettierignore",
35
+ "prettier:fix": "prettier --write . --ignore-path ../../../.prettierignore",
36
+ "test": "npm run test:mocha",
37
+ "test:coverage": "nyc npm test -- --reporter xunit --reporter-option output=nyc/junit-report.xml",
38
+ "test:mocha": "mocha --ignore 'dist/test/types/*' --recursive dist/test -r node_modules/@fluidframework/mocha-test-setup --unhandled-rejections=strict",
39
+ "test:mocha:verbose": "cross-env FLUID_TEST_VERBOSE=1 npm run test:mocha",
40
+ "tsc": "tsc",
41
+ "tsc:watch": "tsc --watch",
42
+ "typetests:gen": "flub generate typetests --generate --dir .",
43
+ "typetests:prepare": "flub generate typetests --prepare --dir . --pin"
44
+ },
45
+ "nyc": {
46
+ "all": true,
47
+ "cache-dir": "nyc/.cache",
48
+ "exclude": [
49
+ "src/test/**/*.ts",
50
+ "dist/test/**/*.js"
51
+ ],
52
+ "exclude-after-remap": false,
53
+ "include": [
54
+ "src/**/*.ts",
55
+ "dist/**/*.js"
56
+ ],
57
+ "report-dir": "nyc/report",
58
+ "reporter": [
59
+ "cobertura",
60
+ "html",
61
+ "text"
62
+ ],
63
+ "temp-directory": "nyc/.nyc_output"
64
+ },
65
+ "dependencies": {
66
+ "@fluidframework/common-definitions": "^0.20.1",
67
+ "@fluidframework/common-utils": "^1.0.0",
68
+ "@fluidframework/container-definitions": ">=2.0.0-internal.3.1.1 <2.0.0-internal.4.0.0",
69
+ "@fluidframework/container-utils": ">=2.0.0-internal.3.1.1 <2.0.0-internal.4.0.0",
70
+ "@fluidframework/core-interfaces": ">=2.0.0-internal.3.1.1 <2.0.0-internal.4.0.0",
71
+ "@fluidframework/driver-definitions": ">=2.0.0-internal.3.1.1 <2.0.0-internal.4.0.0",
72
+ "@fluidframework/driver-utils": ">=2.0.0-internal.3.1.1 <2.0.0-internal.4.0.0",
73
+ "@fluidframework/protocol-base": "^0.1038.2000",
74
+ "@fluidframework/protocol-definitions": "^1.1.0",
75
+ "@fluidframework/telemetry-utils": ">=2.0.0-internal.3.1.1 <2.0.0-internal.4.0.0",
76
+ "abort-controller": "^3.0.0",
77
+ "double-ended-queue": "^2.1.0-0",
78
+ "events": "^3.1.0",
79
+ "lodash": "^4.17.21",
80
+ "url": "^0.11.0",
81
+ "uuid": "^8.3.1"
82
+ },
83
+ "devDependencies": {
84
+ "@fluid-tools/build-cli": "^0.9.0",
85
+ "@fluidframework/build-common": "^1.1.0",
86
+ "@fluidframework/build-tools": "^0.9.0",
87
+ "@fluidframework/container-loader-previous": "npm:@fluidframework/container-loader@2.0.0-internal.3.0.1",
88
+ "@fluidframework/eslint-config-fluid": "^2.0.0",
89
+ "@fluidframework/mocha-test-setup": ">=2.0.0-internal.3.1.1 <2.0.0-internal.4.0.0",
90
+ "@fluidframework/test-loader-utils": ">=2.0.0-internal.3.1.1 <2.0.0-internal.4.0.0",
91
+ "@microsoft/api-extractor": "^7.22.2",
92
+ "@rushstack/eslint-config": "^2.5.1",
93
+ "@types/double-ended-queue": "^2.1.0",
94
+ "@types/events": "^3.0.0",
95
+ "@types/lodash": "^4.14.118",
96
+ "@types/mocha": "^9.1.1",
97
+ "@types/node": "^14.18.36",
98
+ "@types/sinon": "^7.0.13",
99
+ "concurrently": "^6.2.0",
100
+ "copyfiles": "^2.4.1",
101
+ "cross-env": "^7.0.2",
102
+ "eslint": "~8.6.0",
103
+ "mocha": "^10.0.0",
104
+ "nyc": "^15.0.0",
105
+ "prettier": "~2.6.2",
106
+ "rimraf": "^2.6.2",
107
+ "sinon": "^7.4.2",
108
+ "typescript": "~4.5.5"
109
+ },
110
+ "typeValidation": {
111
+ "version": "2.0.0-internal.3.1.1",
112
+ "previousVersionStyle": "~previousMinor",
113
+ "baselineRange": ">=2.0.0-internal.3.0.0 <2.0.0-internal.3.1.0",
114
+ "baselineVersion": "2.0.0-internal.3.0.1",
115
+ "broken": {}
116
+ }
116
117
  }
@@ -4,5 +4,5 @@
4
4
  */
5
5
 
6
6
  module.exports = {
7
- ...require("@fluidframework/build-common/prettier.config.cjs"),
7
+ ...require("@fluidframework/build-common/prettier.config.cjs"),
8
8
  };
package/src/audience.ts CHANGED
@@ -11,55 +11,60 @@ import { IClient } from "@fluidframework/protocol-definitions";
11
11
  * Audience represents all clients connected to the op stream.
12
12
  */
13
13
  export class Audience extends EventEmitter implements IAudienceOwner {
14
- private readonly members = new Map<string, IClient>();
14
+ private readonly members = new Map<string, IClient>();
15
15
 
16
- public on(event: "addMember" | "removeMember", listener: (clientId: string, client: IClient) => void): this;
17
- public on(event: string, listener: (...args: any[]) => void): this {
18
- return super.on(event, listener);
19
- }
16
+ public on(
17
+ event: "addMember" | "removeMember",
18
+ listener: (clientId: string, client: IClient) => void,
19
+ ): this;
20
+ public on(event: string, listener: (...args: any[]) => void): this {
21
+ return super.on(event, listener);
22
+ }
20
23
 
21
- /**
22
- * Adds a new client to the audience
23
- */
24
- public addMember(clientId: string, details: IClient) {
25
- // Given that signal delivery is unreliable process, we might observe same client being added twice
26
- // In such case we should see exactly same payload (IClient), and should not raise event twice!
27
- if (this.members.has(clientId)) {
28
- const client = this.members.get(clientId);
29
- assert(JSON.stringify(client) === JSON.stringify(details), 0x4b2 /* new client has different payload from existing one */);
30
- }
31
- else {
32
- this.members.set(clientId, details);
33
- this.emit("addMember", clientId, details);
34
- }
35
- }
24
+ /**
25
+ * Adds a new client to the audience
26
+ */
27
+ public addMember(clientId: string, details: IClient) {
28
+ // Given that signal delivery is unreliable process, we might observe same client being added twice
29
+ // In such case we should see exactly same payload (IClient), and should not raise event twice!
30
+ if (this.members.has(clientId)) {
31
+ const client = this.members.get(clientId);
32
+ assert(
33
+ JSON.stringify(client) === JSON.stringify(details),
34
+ 0x4b2 /* new client has different payload from existing one */,
35
+ );
36
+ } else {
37
+ this.members.set(clientId, details);
38
+ this.emit("addMember", clientId, details);
39
+ }
40
+ }
36
41
 
37
- /**
38
- * Removes a client from the audience. Only emits an event if a client is actually removed
39
- * @returns if a client was removed from the audience
40
- */
41
- public removeMember(clientId: string): boolean {
42
- const removedClient = this.members.get(clientId);
43
- if (removedClient !== undefined) {
44
- this.members.delete(clientId);
45
- this.emit("removeMember", clientId, removedClient);
46
- return true;
47
- } else {
48
- return false;
49
- }
50
- }
42
+ /**
43
+ * Removes a client from the audience. Only emits an event if a client is actually removed
44
+ * @returns if a client was removed from the audience
45
+ */
46
+ public removeMember(clientId: string): boolean {
47
+ const removedClient = this.members.get(clientId);
48
+ if (removedClient !== undefined) {
49
+ this.members.delete(clientId);
50
+ this.emit("removeMember", clientId, removedClient);
51
+ return true;
52
+ } else {
53
+ return false;
54
+ }
55
+ }
51
56
 
52
- /**
53
- * Retrieves all the members in the audience
54
- */
55
- public getMembers(): Map<string, IClient> {
56
- return new Map(this.members);
57
- }
57
+ /**
58
+ * Retrieves all the members in the audience
59
+ */
60
+ public getMembers(): Map<string, IClient> {
61
+ return new Map(this.members);
62
+ }
58
63
 
59
- /**
60
- * Retrieves a specific member of the audience
61
- */
62
- public getMember(clientId: string): IClient | undefined {
63
- return this.members.get(clientId);
64
- }
64
+ /**
65
+ * Retrieves a specific member of the audience
66
+ */
67
+ public getMember(clientId: string): IClient | undefined {
68
+ return this.members.get(clientId);
69
+ }
65
70
  }
@@ -19,41 +19,43 @@ export type ICatchUpMonitor = IDisposable;
19
19
  * that were known at the time the monitor was created.
20
20
  */
21
21
  export class CatchUpMonitor implements ICatchUpMonitor {
22
- private readonly targetSeqNumber: number;
23
- private caughtUp: boolean = false;
24
-
25
- private readonly opHandler = (message: Pick<ISequencedDocumentMessage, "sequenceNumber">) => {
26
- if (!this.caughtUp && message.sequenceNumber >= this.targetSeqNumber) {
27
- this.caughtUp = true;
28
- this.listener();
29
- }
30
- };
31
-
32
- /**
33
- * Create the CatchUpMonitor, setting the target sequence number to wait for based on DeltaManager's current state.
34
- */
35
- constructor(
36
- private readonly deltaManager: IDeltaManager<any, any>,
37
- private readonly listener: CaughtUpListener,
38
- ) {
39
- this.targetSeqNumber = this.deltaManager.lastKnownSeqNumber;
40
-
41
- assert(this.targetSeqNumber >= this.deltaManager.lastSequenceNumber,
42
- 0x37c /* Cannot wait for seqNumber below last processed sequence number */);
43
-
44
- this.deltaManager.on("op", this.opHandler);
45
-
46
- // Simulate the last processed op to set caughtUp in case we already are
47
- this.opHandler({ sequenceNumber: this.deltaManager.lastSequenceNumber });
48
- }
49
-
50
- public disposed: boolean = false;
51
- public dispose() {
52
- if (this.disposed) {
53
- return;
54
- }
55
- this.disposed = true;
56
-
57
- this.deltaManager.off("op", this.opHandler);
58
- }
22
+ private readonly targetSeqNumber: number;
23
+ private caughtUp: boolean = false;
24
+
25
+ private readonly opHandler = (message: Pick<ISequencedDocumentMessage, "sequenceNumber">) => {
26
+ if (!this.caughtUp && message.sequenceNumber >= this.targetSeqNumber) {
27
+ this.caughtUp = true;
28
+ this.listener();
29
+ }
30
+ };
31
+
32
+ /**
33
+ * Create the CatchUpMonitor, setting the target sequence number to wait for based on DeltaManager's current state.
34
+ */
35
+ constructor(
36
+ private readonly deltaManager: IDeltaManager<any, any>,
37
+ private readonly listener: CaughtUpListener,
38
+ ) {
39
+ this.targetSeqNumber = this.deltaManager.lastKnownSeqNumber;
40
+
41
+ assert(
42
+ this.targetSeqNumber >= this.deltaManager.lastSequenceNumber,
43
+ 0x37c /* Cannot wait for seqNumber below last processed sequence number */,
44
+ );
45
+
46
+ this.deltaManager.on("op", this.opHandler);
47
+
48
+ // Simulate the last processed op to set caughtUp in case we already are
49
+ this.opHandler({ sequenceNumber: this.deltaManager.lastSequenceNumber });
50
+ }
51
+
52
+ public disposed: boolean = false;
53
+ public dispose() {
54
+ if (this.disposed) {
55
+ return;
56
+ }
57
+ this.disposed = true;
58
+
59
+ this.deltaManager.off("op", this.opHandler);
60
+ }
59
61
  }
@@ -30,82 +30,87 @@ const defaultNoopCountFrequency = 50;
30
30
  // 2. If there are more than 50 ops received without sending any ops, send noop to keep collab window small.
31
31
  // Note that system ops (including noops themselves) are excluded, so it's 1 noop per 50 real ops.
32
32
  export class CollabWindowTracker {
33
- private opsCountSinceNoop = 0;
34
- private readonly timer: Timer | undefined;
33
+ private opsCountSinceNoop = 0;
34
+ private readonly timer: Timer | undefined;
35
35
 
36
- constructor(
37
- private readonly submit: (type: MessageType) => void,
38
- NoopTimeFrequency: number = defaultNoopTimeFrequency,
39
- private readonly NoopCountFrequency: number = defaultNoopCountFrequency,
40
- ) {
41
- if (NoopTimeFrequency !== Infinity) {
42
- this.timer = new Timer(NoopTimeFrequency, () => {
43
- // Can get here due to this.stopSequenceNumberUpdate() not resetting timer.
44
- // Also timer callback can fire even after timer cancellation if it was queued before cancellation.
45
- if (this.opsCountSinceNoop !== 0) {
46
- this.submitNoop(false /* immediate */);
47
- }
48
- });
49
- }
50
- }
36
+ constructor(
37
+ private readonly submit: (type: MessageType) => void,
38
+ NoopTimeFrequency: number = defaultNoopTimeFrequency,
39
+ private readonly NoopCountFrequency: number = defaultNoopCountFrequency,
40
+ ) {
41
+ if (NoopTimeFrequency !== Infinity) {
42
+ this.timer = new Timer(NoopTimeFrequency, () => {
43
+ // Can get here due to this.stopSequenceNumberUpdate() not resetting timer.
44
+ // Also timer callback can fire even after timer cancellation if it was queued before cancellation.
45
+ if (this.opsCountSinceNoop !== 0) {
46
+ this.submitNoop(false /* immediate */);
47
+ }
48
+ });
49
+ }
50
+ }
51
51
 
52
- /**
53
- * Schedules as ack to the server to update the reference sequence number
54
- */
55
- public scheduleSequenceNumberUpdate(message: ISequencedDocumentMessage, immediateNoOp: boolean): void {
56
- // While processing a message, an immediate no-op can be requested.
57
- // i.e. to expedite approve or commit phase of quorum.
58
- if (immediateNoOp) {
59
- this.submitNoop(true /* immediate */);
60
- return;
61
- }
52
+ /**
53
+ * Schedules as ack to the server to update the reference sequence number
54
+ */
55
+ public scheduleSequenceNumberUpdate(
56
+ message: ISequencedDocumentMessage,
57
+ immediateNoOp: boolean,
58
+ ): void {
59
+ // While processing a message, an immediate no-op can be requested.
60
+ // i.e. to expedite approve or commit phase of quorum.
61
+ if (immediateNoOp) {
62
+ this.submitNoop(true /* immediate */);
63
+ return;
64
+ }
62
65
 
63
- // We don't acknowledge no-ops to avoid acknowledgement cycles (i.e. ack the MSN
64
- // update, which updates the MSN, then ack the update, etc...).
65
- // Intent here is for runtime (and DDSes) not to keep too much tracking state / memory
66
- // due to runtime ops from other clients.
67
- if (!isRuntimeMessage(message)) {
68
- return;
69
- }
66
+ // We don't acknowledge no-ops to avoid acknowledgement cycles (i.e. ack the MSN
67
+ // update, which updates the MSN, then ack the update, etc...).
68
+ // Intent here is for runtime (and DDSes) not to keep too much tracking state / memory
69
+ // due to runtime ops from other clients.
70
+ if (!isRuntimeMessage(message)) {
71
+ return;
72
+ }
70
73
 
71
- this.opsCountSinceNoop++;
72
- if (this.opsCountSinceNoop === this.NoopCountFrequency) {
73
- // Ensure we only send noop after a batch of many ops is processed
74
- // eslint-disable-next-line @typescript-eslint/no-floating-promises
75
- Promise.resolve().then(() => {
76
- if (this.opsCountSinceNoop >= this.NoopCountFrequency) {
77
- this.submitNoop(false /* immediate */);
78
- // reset count now that all ops are processed
79
- this.opsCountSinceNoop = 0;
80
- }
81
- return;
82
- });
83
- }
74
+ this.opsCountSinceNoop++;
75
+ if (this.opsCountSinceNoop === this.NoopCountFrequency) {
76
+ // Ensure we only send noop after a batch of many ops is processed
77
+ // eslint-disable-next-line @typescript-eslint/no-floating-promises
78
+ Promise.resolve().then(() => {
79
+ if (this.opsCountSinceNoop >= this.NoopCountFrequency) {
80
+ this.submitNoop(false /* immediate */);
81
+ // reset count now that all ops are processed
82
+ this.opsCountSinceNoop = 0;
83
+ }
84
+ return;
85
+ });
86
+ }
84
87
 
85
- if (this.timer !== undefined) {
86
- if (this.opsCountSinceNoop === 1) {
87
- this.timer.restart();
88
- }
88
+ if (this.timer !== undefined) {
89
+ if (this.opsCountSinceNoop === 1) {
90
+ this.timer.restart();
91
+ }
89
92
 
90
- assert(this.timer.hasTimer, 0x242 /* "has timer" */);
91
- }
92
- }
93
+ assert(this.timer.hasTimer, 0x242 /* "has timer" */);
94
+ }
95
+ }
93
96
 
94
- private submitNoop(immediate: boolean) {
95
- // Anything other than null is immediate noop
96
- // ADO:1385: Remove cast and use MessageType once definition changes propagate
97
- this.submit(immediate ? (MessageType2.Accept as unknown as MessageType) : MessageType.NoOp);
98
- assert(this.opsCountSinceNoop === 0,
99
- 0x243 /* "stopSequenceNumberUpdate should be called as result of sending any op!" */);
100
- }
97
+ private submitNoop(immediate: boolean) {
98
+ // Anything other than null is immediate noop
99
+ // ADO:1385: Remove cast and use MessageType once definition changes propagate
100
+ this.submit(immediate ? (MessageType2.Accept as unknown as MessageType) : MessageType.NoOp);
101
+ assert(
102
+ this.opsCountSinceNoop === 0,
103
+ 0x243 /* "stopSequenceNumberUpdate should be called as result of sending any op!" */,
104
+ );
105
+ }
101
106
 
102
- public stopSequenceNumberUpdate(): void {
103
- this.opsCountSinceNoop = 0;
104
- // Ideally, we cancel timer here. But that will result in too often set/reset cycle if this client
105
- // keeps sending ops. In most cases it's actually better to let it expire (at most - 4 times per second)
106
- // for nothing, then have a ton of set/reset cycles.
107
- // Note that Timer.restart() is smart and will not change timer expiration if we keep extending timer
108
- // expiration - it will restart the timer instead when it fires with adjusted expiration.
109
- // this.timer.clear();
110
- }
107
+ public stopSequenceNumberUpdate(): void {
108
+ this.opsCountSinceNoop = 0;
109
+ // Ideally, we cancel timer here. But that will result in too often set/reset cycle if this client
110
+ // keeps sending ops. In most cases it's actually better to let it expire (at most - 4 times per second)
111
+ // for nothing, then have a ton of set/reset cycles.
112
+ // Note that Timer.restart() is smart and will not change timer expiration if we keep extending timer
113
+ // expiration - it will restart the timer instead when it fires with adjusted expiration.
114
+ // this.timer.clear();
115
+ }
111
116
  }