@fluidframework/presence 2.73.0 → 2.74.0-365691
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/dist/packageVersion.d.ts +1 -1
- package/dist/packageVersion.d.ts.map +1 -1
- package/dist/packageVersion.js +1 -1
- package/dist/packageVersion.js.map +1 -1
- package/dist/presenceDatastoreManager.js +1 -1
- package/dist/presenceDatastoreManager.js.map +1 -1
- package/lib/packageVersion.d.ts +1 -1
- package/lib/packageVersion.d.ts.map +1 -1
- package/lib/packageVersion.js +1 -1
- package/lib/packageVersion.js.map +1 -1
- package/lib/presenceDatastoreManager.js +1 -1
- package/lib/presenceDatastoreManager.js.map +1 -1
- package/package.json +19 -19
package/dist/packageVersion.d.ts
CHANGED
|
@@ -5,5 +5,5 @@
|
|
|
5
5
|
* THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY
|
|
6
6
|
*/
|
|
7
7
|
export declare const pkgName = "@fluidframework/presence";
|
|
8
|
-
export declare const pkgVersion = "2.
|
|
8
|
+
export declare const pkgVersion = "2.74.0-365691";
|
|
9
9
|
//# sourceMappingURL=packageVersion.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"packageVersion.d.ts","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,eAAO,MAAM,OAAO,6BAA6B,CAAC;AAClD,eAAO,MAAM,UAAU,
|
|
1
|
+
{"version":3,"file":"packageVersion.d.ts","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,eAAO,MAAM,OAAO,6BAA6B,CAAC;AAClD,eAAO,MAAM,UAAU,kBAAkB,CAAC"}
|
package/dist/packageVersion.js
CHANGED
|
@@ -8,5 +8,5 @@
|
|
|
8
8
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
9
|
exports.pkgVersion = exports.pkgName = void 0;
|
|
10
10
|
exports.pkgName = "@fluidframework/presence";
|
|
11
|
-
exports.pkgVersion = "2.
|
|
11
|
+
exports.pkgVersion = "2.74.0-365691";
|
|
12
12
|
//# sourceMappingURL=packageVersion.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"packageVersion.js","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;;AAEU,QAAA,OAAO,GAAG,0BAA0B,CAAC;AACrC,QAAA,UAAU,GAAG,
|
|
1
|
+
{"version":3,"file":"packageVersion.js","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;;AAEU,QAAA,OAAO,GAAG,0BAA0B,CAAC;AACrC,QAAA,UAAU,GAAG,eAAe,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n *\n * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY\n */\n\nexport const pkgName = \"@fluidframework/presence\";\nexport const pkgVersion = \"2.74.0-365691\";\n"]}
|
|
@@ -588,7 +588,7 @@ class PresenceDatastoreManagerImpl {
|
|
|
588
588
|
continue;
|
|
589
589
|
}
|
|
590
590
|
// Separate internal type prefix from public workspace address
|
|
591
|
-
const match =
|
|
591
|
+
const match = /^([^:]):([^:]+:.+)$/.exec(workspaceAddress);
|
|
592
592
|
if (match === null) {
|
|
593
593
|
continue;
|
|
594
594
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"presenceDatastoreManager.js","sourceRoot":"","sources":["../src/presenceDatastoreManager.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAKH,kEAA6D;AAa7D,yDAAmD;AAYnD,2DAI6B;AAW7B,+CAIuB;AAEvB,uDAAiD;AAuBjD,MAAM,sBAAsB,GAAyD;IACpF,CAAC,EAAE,QAAQ;IACX,CAAC,EAAE,eAAe;CACT,CAAC;AAEX,MAAM,iBAAiB,GAAG,IAAI,GAAG,CAAC;IACjC,6BAAe;IACf,wCAA0B;IAC1B,wCAA0B;CAC1B,CAAC,CAAC;AACH,SAAS,iBAAiB,CACzB,OAAgD;IAEhD,OAAO,iBAAiB,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;AAC5C,CAAC;AAED;;;;;;GAMG;AACH,SAAgB,gBAAgB,CAC/B,GAA+D;IAE/D,OAAO,OAAO,IAAI,GAAG,CAAC;AACvB,CAAC;AAJD,4CAIC;AAwBD,SAAS,mCAAmC,CAC3C,IAAgD,EAChD,OAAuC;IAEvC,qEAAqE;IACrE,MAAM,cAAc,GAAG,IAAI,IAAI,EAAE,CAAC;IAElC,gEAAgE;IAChE,0EAA0E;IAC1E,KAAK,MAAM,CAAC,aAAa,EAAE,aAAa,CAAC,IAAI,IAAA,gCAAa,EAAC,OAAO,CAAC,EAAE,CAAC;QACrE,8EAA8E;QAC9E,8EAA8E;QAC9E,oCAAoC;QACpC,MAAM,UAAU,GAAG,cAAc,CAAC,aAAa,CAAC,IAAI,EAAE,CAAC;QAEvD,sEAAsE;QACtE,KAAK,MAAM,CAAC,eAAe,EAAE,iBAAiB,CAAC,IAAI,IAAA,gCAAa,EAAC,aAAa,CAAC,EAAE,CAAC;YACjF,KAAK,MAAM,CAAC,UAAU,EAAE,KAAK,CAAC,IAAI,IAAA,gCAAa,EAAC,iBAAiB,CAAC,EAAE,CAAC;gBACpE,MAAM,WAAW,GAAG,CAAC,UAAU,CAAC,eAAe,CAAC,KAAK,EAAE,CAAC,CAAC;gBACzD,MAAM,OAAO,GAAG,WAAW,CAAC,UAAU,CAAC,CAAC;gBACxC,WAAW,CAAC,UAAU,CAAC,GAAG,IAAA,uCAAmB,EAC5C,OAAO,EACP,KAAK,EACL,CAAC,CACD,CAAC;YACH,CAAC;QACF,CAAC;QAED,0FAA0F;QAC1F,8CAA8C;QAC9C,cAAc,CAAC,aAAa,CAAC,GAAG,UAAU,CAAC;IAC5C,CAAC;IACD,OAAO,cAAc,CAAC;AACvB,CAAC;AAED;;;;;;;GAOG;AACU,QAAA,6BAA6B,GAAG;IAC5C;;;;OAIG;IACH,cAAc,EAAE,GAAG;IACnB;;;OAGG;IACH,wBAAwB,EAAE,EAAE;CACnB,CAAC;AAEX;;GAEG;AACH,MAAa,4BAA4B;IAkDxC,YACkB,UAAsB,EACtB,OAA0B,EAC1B,MAAuC,EACvC,MAAgC,EAChC,QAAkB,EACnC,wBAAkD,EAClD,eAAyD;QANxC,eAAU,GAAV,UAAU,CAAY;QACtB,YAAO,GAAP,OAAO,CAAmB;QAC1B,WAAM,GAAN,MAAM,CAAiC;QACvC,WAAM,GAAN,MAAM,CAA0B;QAChC,aAAQ,GAAR,QAAQ,CAAU;QArD5B,mBAAc,GAAG,CAAC,CAAC;QACnB,qBAAgB,GAAG,CAAC,CAAC;QACZ,qBAAgB,GAAG,IAAI,8BAAY,EAAE,CAAC;QACtC,eAAU,GAAG,IAAI,GAAG,EAAoD,CAAC;QAiC1F;;WAEG;QACc,sBAAiB,GAAG,IAAI,GAAG,EAGzC,CAAC;QACJ;;WAEG;QACc,2BAAsB,GAAG,IAAI,8BAAY,EAAE,CAAC;QAgnB7D;;;WAGG;QACc,kCAA6B,GAAG,GAAS,EAAE;YAC3D,wEAAwE;YACxE,uCAAuC;YACvC,IAAI,IAAI,CAAC,OAAO,CAAC,eAAe,EAAE,KAAK,cAAc,IAAI,IAAI,CAAC,iBAAiB,CAAC,IAAI,GAAG,CAAC,EAAE,CAAC;gBAC1F,kEAAkE;gBAClE,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;gBACvB,IAAI,eAAe,GAAG,MAAM,CAAC,iBAAiB,CAAC;gBAC/C,KAAK,MAAM,EAAE,YAAY,EAAE,IAAI,IAAI,CAAC,iBAAiB,CAAC,MAAM,EAAE,EAAE,CAAC;oBAChE,eAAe,GAAG,IAAI,CAAC,GAAG,CAAC,eAAe,EAAE,YAAY,CAAC,CAAC;gBAC3D,CAAC;gBACD,IAAI,eAAe,IAAI,GAAG,EAAE,CAAC;oBAC5B,IAAI,IAAI,CAAC,yBAAyB,EAAE,CAAC;wBACpC,IAAI,CAAC,sBAAsB,EAAE,CAAC;oBAC/B,CAAC;gBACF,CAAC;qBAAM,CAAC;oBACP,oDAAoD;oBACpD,IAAI,CAAC,sBAAsB,CAAC,UAAU,CACrC,IAAI,CAAC,6BAA6B,EAClC,eAAe,GAAG,GAAG,CACrB,CAAC;gBACH,CAAC;YACF,CAAC;QACF,CAAC,CAAC;QA/nBD,yEAAyE;QACzE,IAAI,CAAC,SAAS,GAAG,EAAE,iBAAiB,EAAE,wBAAwB,EAAuB,CAAC;QACtF,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,iBAAiB,EAAE,eAAe,CAAC,CAAC;QACxD,IAAI,CAAC,qBAAqB,GAAG,IAAI,CAAC,OAAO,CAAC,iBAAiB,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC;QACrF,uEAAuE;QACvE,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC,EAAE,CAAC,cAAc,EAAE,CAAC,QAAQ,EAAE,EAAE;YAC1D,IAAI,CAAC,iBAAiB,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QACzC,CAAC,CAAC,CAAC;IACJ,CAAC;IAEO,sBAAsB,CAAC,YAAgC;QAQ9D,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC;QAC5C,MAAM,OAAO,GAAG,QAAQ,CAAC,UAAU,EAAE,CAAC;QACtC,MAAM,GAAG,GAAG,IAAI,GAAG,EAAsB,CAAC;QAC1C,MAAM,OAAO,GAAG,IAAI,GAAG,EAAsB,CAAC;QAC9C,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;QAC9C,IAAI,WAAW,EAAE,CAAC;YACjB,cAAc;YACd,OAAO,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC;QAC9B,CAAC;QACD,gCAAgC;QAChC,KAAK,MAAM,CAAC,EAAE,EAAE,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;YACpC,IAAI,MAAM,CAAC,OAAO,CAAC,YAAY,CAAC,WAAW,EAAE,CAAC;gBAC7C,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;gBACZ,IAAI,MAAM,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;oBAC7B,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;gBACjB,CAAC;YACF,CAAC;QACF,CAAC;QACD,OAAO;YACN,QAAQ;YACR,WAAW;YACX,+BAA+B,EAAE;gBAChC,GAAG;gBACH,OAAO;aACP;SACD,CAAC;IACH,CAAC;IAEM,WAAW,CACjB,YAAgC,EAChC,oBAAoD,SAAS;QAE7D,qEAAqE;QACrE,mEAAmE;QACnE,kEAAkE;QAClE,iEAAiE;QACjE,aAAa;QACb,sEAAsE;QACtE,uEAAuE;QACvE,OAAO;QACP,MAAM,EAAE,QAAQ,EAAE,WAAW,EAAE,+BAA+B,EAAE,GAC/D,IAAI,CAAC,sBAAsB,CAAC,YAAY,CAAC,CAAC;QAE3C,IAAI,+BAA+B,CAAC,GAAG,CAAC,IAAI,KAAK,CAAC,IAAI,iBAAiB,KAAK,SAAS,EAAE,CAAC;YACvF,IAAI,WAAW,EAAE,CAAC;gBACjB,sEAAsE;gBACtE,kCAAkC;gBAClC,IAAI,CAAC,yBAAyB,GAAG,OAAO,CAAC;gBACzC,kEAAkE;gBAClE,2DAA2D;gBAC3D,mEAAmE;gBACnE,+DAA+D;gBAC/D,kEAAkE;gBAClE,8CAA8C;YAC/C,CAAC;iBAAM,CAAC;gBACP,qDAAqD;gBACrD,gEAAgE;gBAChE,IAAI,CAAC,uBAAuB,CAAC,YAAY,EAAE,QAAQ,CAAC,CAAC;gBACrD,OAAO;YACR,CAAC;QACF,CAAC;QAED,wCAAwC;QACxC,kCAAkC;QAClC,gEAAgE;QAChE,MAAM,eAAe,GAAG;YACvB,GAAG,CAAC,+BAA+B,CAAC,OAAO,CAAC,IAAI,GAAG,CAAC;gBACnD,CAAC,CAAC,+BAA+B,CAAC,OAAO;gBACzC,CAAC,CAAC,+BAA+B,CAAC,GAAG,CAAC;SACvC,CAAC;QACF,4DAA4D;QAC5D,+DAA+D;QAC/D,IAAI,eAAe,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAChC,eAAe,CAAC,MAAM,GAAG,CAAC,CAAC;QAC5B,CAAC;aAAM,IAAI,eAAe,CAAC,MAAM,KAAK,CAAC,IAAI,iBAAiB,KAAK,SAAS,EAAE,CAAC;YAC5E,eAAe,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;QACzC,CAAC;QACD,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC;YACzB,IAAI,EAAE,6BAAe;YACrB,OAAO,EAAE;gBACR,aAAa,EAAE,IAAI,CAAC,GAAG,EAAE;gBACzB,UAAU,EAAE,IAAI,CAAC,cAAc;gBAC/B,IAAI,EAAE,IAAI,CAAC,uBAAuB,CAAC,IAAI,CAAC,SAAS,CAAC;gBAClD,eAAe;aACf;SACD,CAAC,CAAC;QACH,IAAI,CAAC,MAAM,EAAE,kBAAkB,CAAC;YAC/B,SAAS,EAAE,eAAe;YAC1B,OAAO,EAAE;gBACR,UAAU,EAAE,IAAI,CAAC,UAAU;gBAC3B,YAAY,EAAE,YAAY;gBAC1B,0DAA0D;gBAC1D,eAAe,EAAE,IAAI,CAAC,SAAS,CAAC,eAAe,CAAC;gBAChD,yEAAyE;gBACzE,WAAW;aACX;SACD,CAAC,CAAC;IACJ,CAAC;IAEO,uBAAuB,CAAC,YAAoB,EAAE,QAAmB;QACxE,IAAI,CAAC,MAAM,EAAE,kBAAkB,CAAC;YAC/B,SAAS,EAAE,cAAc;YACzB,OAAO,EAAE;gBACR,UAAU,EAAE,IAAI,CAAC,UAAU;gBAC3B,YAAY,EAAE,YAAY;aAC1B;SACD,CAAC,CAAC;QACH,mDAAmD;QACnD,gEAAgE;QAChE,4DAA4D;QAC5D,+BAA+B;QAC/B,MAAM,+BAA+B,GAAG,CAAC,aAAiC,EAAQ,EAAE;YACnF,IAAI,aAAa,KAAK,YAAY,EAAE,CAAC;gBACpC,iBAAiB;gBACjB,OAAO;YACR,CAAC;YAED,mEAAmE;YACnE,eAAe;YACf,sEAAsE;YACtE,gCAAgC;YAChC,IAAI,CAAC,kBAAkB,CAAC,YAAY,EAAE,uBAAuB,CAAC,SAAS,CAAC,CAAC;QAC1E,CAAC,CAAC;QACF,QAAQ,CAAC,EAAE,CAAC,WAAW,EAAE,+BAA+B,CAAC,CAAC;QAC1D,IAAI,CAAC,4BAA4B,GAAG,GAAG,EAAE;YACxC,QAAQ,CAAC,GAAG,CAAC,WAAW,EAAE,+BAA+B,CAAC,CAAC;QAC5D,CAAC,CAAC;IACH,CAAC;IAEO,kBAAkB,CACzB,YAAgC,EAChC,iBAAiD;QAEjD,IAAI,CAAC,4BAA4B,EAAE,EAAE,CAAC;QACtC,IAAI,CAAC,4BAA4B,GAAG,SAAS,CAAC;QAC9C,qCAAqC;QACrC,IAAI,IAAI,CAAC,OAAO,CAAC,eAAe,EAAE,KAAK,cAAc,EAAE,CAAC;YACvD,IAAI,CAAC,WAAW,CAAC,YAAY,EAAE,iBAAiB,CAAC,CAAC;QACnD,CAAC;IACF,CAAC;IAEM,cAAc;QACpB,OAAO,IAAI,CAAC,yBAAyB,CAAC;QACtC,IAAI,CAAC,4BAA4B,EAAE,EAAE,CAAC;QACtC,IAAI,CAAC,4BAA4B,GAAG,SAAS,CAAC;IAC/C,CAAC;IAEM,YAAY,CAClB,wBAAkD,EAClD,gBAAyB,EACzB,QAAmC;QAEnC,MAAM,QAAQ,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,wBAAwB,CAAC,CAAC;QAC/D,IAAI,QAAQ,EAAE,CAAC;YACd,OAAO,QAAQ,CAAC,QAAQ,CAAC,aAAa,CAAC,gBAAgB,EAAE,QAAQ,CAAC,CAAC;QACpE,CAAC;QAED,IAAI,kBAAkB,GACrB,IAAI,CAAC,SAAS,CAAC,wBAAwB,CAAC,CAAC;QAC1C,IAAI,kBAAkB,KAAK,SAAS,EAAE,CAAC;YACtC,kBAAkB,GAAG,IAAI,CAAC,SAAS,CAAC,wBAAwB,CAAC,GAAG,EAAE,CAAC;QACpE,CAAC;QAED,MAAM,WAAW,GAAG,CACnB,MAA4C,EAC5C,OAAkC,EAC3B,EAAE;YACT,iDAAiD;YACjD,IAAI,IAAI,CAAC,OAAO,CAAC,eAAe,EAAE,KAAK,cAAc,EAAE,CAAC;gBACvD,OAAO;YACR,CAAC;YAED,MAAM,OAAO,GAA6D,EAAE,CAAC;YAC7E,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;gBACnD,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,KAAK,EAAE,CAAC;YAC7C,CAAC;YAED,IAAI,CAAC,cAAc,CAClB;gBACC,CAAC,wBAAwB,CAAC,EAAE,OAAO;aACnC,EACD,OAAO,CACP,CAAC;QACH,CAAC,CAAC;QAEF,MAAM,KAAK,GAAG,IAAA,wCAAoB,EACjC;YACC,QAAQ,EAAE,IAAI,CAAC,QAAQ;YACvB,UAAU,EAAE,IAAI,CAAC,UAAU;YAC3B,WAAW;SACX,EACD,kBAAkB,EAClB,gBAAgB,EAChB,QAAQ,CACR,CAAC;QAEF,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,wBAAwB,EAAE,KAAK,CAAC,CAAC;QACrD,OAAO,KAAK,CAAC,MAAM,CAAC;IACrB,CAAC;IAQD;;;OAGG;IACK,cAAc,CACrB,IAAgD,EAChD,OAAkC;QAElC,IAAI,IAAI,CAAC,UAAU,KAAK,SAAS,EAAE,CAAC;YACnC,IAAI,CAAC,UAAU;gBACd,IAAI,KAAK,SAAS;oBACjB,CAAC,CAAC,SAAS;oBACX,CAAC,CAAC,+EAA+E;wBAChF,4FAA4F;wBAC5F,mCAAmC,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;QAC/D,CAAC;QAED,MAAM,EAAE,wBAAwB,EAAE,GAAG,OAAO,CAAC;QAC7C,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,MAAM,mBAAmB,GAAG,GAAG,GAAG,wBAAwB,CAAC;QAE3D;QACC,iFAAiF;QACjF,6EAA6E;QAC7E,uFAAuF;QACvF,CAAC,IAAI,CAAC,gBAAgB,CAAC,UAAU,EAAE;YACnC,iFAAiF;YACjF,gEAAgE;YAChE,mBAAmB,IAAI,IAAI,CAAC,gBAAgB,CAAC,UAAU,EACtD,CAAC;YACF,OAAO;QACR,CAAC;QAED,kFAAkF;QAClF,0DAA0D;QAE1D,wGAAwG;QACxG,MAAM,WAAW,GAAG,mBAAmB,GAAG,GAAG,CAAC;QAC9C,MAAM,gBAAgB,GAAG,WAAW,GAAG,CAAC,CAAC;QAEzC,IAAI,gBAAgB,EAAE,CAAC;YACtB,gEAAgE;YAChE,IAAI,CAAC,gBAAgB,CAAC,UAAU,CAAC,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,WAAW,CAAC,CAAC;QAClF,CAAC;aAAM,CAAC;YACP,IAAI,CAAC,iBAAiB,EAAE,CAAC;QAC1B,CAAC;IACF,CAAC;IAED;;OAEG;IACK,iBAAiB;QACxB,IAAI,CAAC,gBAAgB,CAAC,YAAY,EAAE,CAAC;QAErC,IAAI,IAAI,CAAC,UAAU,KAAK,SAAS,EAAE,CAAC;YACnC,OAAO;QACR,CAAC;QAED,iDAAiD;QACjD,IAAI,IAAI,CAAC,OAAO,CAAC,eAAe,EAAE,KAAK,cAAc,EAAE,CAAC;YACvD,yEAAyE;YACzE,0CAA0C;YAC1C,IAAI,CAAC,UAAU,GAAG,SAAS,CAAC;YAC5B,OAAO;QACR,CAAC;QAED,IAAI,IAAI,CAAC,UAAU,KAAK,SAAS,EAAE,CAAC;YACnC,IAAI,CAAC,sBAAsB,EAAE,CAAC;YAC9B,OAAO;QACR,CAAC;QAED,MAAM,kBAAkB,GAAG,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC;QACtD,IAAA,iBAAM,EAAC,kBAAkB,KAAK,SAAS,EAAE,KAAK,CAAC,uCAAuC,CAAC,CAAC;QACxF,MAAM,gCAAgC;QACrC,iFAAiF;QACjF,IAAI,CAAC,SAAS,CAAC,iBAAiB,CAAC,CAAC,iBAAiB,CAAC,kBAAkB,CAAC,CAAC;QACzE,IAAA,iBAAM,EAAC,gCAAgC,KAAK,SAAS,EAAE,kCAAkC,CAAC,CAAC;QAE3F,MAAM,UAAU,GAAG;YAClB,aAAa,EAAE,IAAI,CAAC,GAAG,EAAE;YACzB,UAAU,EAAE,IAAI,CAAC,cAAc;YAC/B,qBAAqB;YACrB,IAAI,EAAE;gBACL,qEAAqE;gBACrE,uEAAuE;gBACvE,sEAAsE;gBACtE,yCAAyC;gBACzC,iBAAiB,EAAE;oBAClB,iBAAiB,EAAE;wBAClB,CAAC,kBAAkB,CAAC,EAAE,EAAE,GAAG,gCAAgC,EAAE;qBAC7D;iBACD;gBACD,GAAG,IAAI,CAAC,UAAU;aAClB;SACmD,CAAC;QACtD,IAAI,CAAC,UAAU,GAAG,SAAS,CAAC;QAC5B,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,EAAE,IAAI,EAAE,wCAA0B,EAAE,OAAO,EAAE,UAAU,EAAE,CAAC,CAAC;IACtF,CAAC;IAED;;;OAGG;IACK,uBAAuB,CAAC,SAA4B;QAC3D,MAAM,cAAc,GAA4B;YAC/C,CAAC,iBAAiB,CAAC,EAAE,SAAS,CAAC,iBAAiB,CAAC;SACjD,CAAC;QAEF,KAAK,MAAM,CAAC,gBAAgB,EAAE,SAAS,CAAC,IAAI,IAAA,gCAAa,EAAC,SAAS,CAAC,EAAE,CAAC;YACtE,6DAA6D;YAC7D,gDAAgD;YAChD,IAAI,gBAAgB,KAAK,iBAAiB;gBAAE,SAAS;YAErD,MAAM,aAAa,GAA4D,EAAE,CAAC;YAElF,KAAK,MAAM,CAAC,SAAS,EAAE,YAAY,CAAC,IAAI,IAAA,gCAAa,EAAC,SAAS,CAAC,EAAE,CAAC;gBAClE,MAAM,iBAAiB,GACtB,EAAE,CAAC;gBAEJ,KAAK,MAAM,CAAC,UAAU,EAAE,SAAS,CAAC,IAAI,IAAA,gCAAa,EAAC,YAAY,CAAC,EAAE,CAAC;oBACnE,iBAAiB,CAAC,UAAU,CAAC,GAAG,IAAI,CAAC,4BAA4B,CAAC,SAAS,CAAC,CAAC;gBAC9E,CAAC;gBAED,aAAa,CAAC,SAAS,CAAC,GAAG,iBAAiB,CAAC;YAC9C,CAAC;YAED,cAAc,CAAC,gBAAgB,CAAC,GAAG,aAAa,CAAC;QAClD,CAAC;QAED,OAAO,cAAc,CAAC;IACvB,CAAC;IAED;;OAEG;IACK,4BAA4B,CAKlC,WAAyC;QAC1C,gDAAgD;QAChD,MAAM,SAAS,GAAG,EAAE,GAAG,WAAW,EAAE,CAAC;QAErC,sDAAsD;QACtD,IAAI,gBAAgB,CAAC,SAAS,CAAC,EAAE,CAAC;YACjC,KAAK,MAAM,CAAC,GAAG,EAAE,IAAI,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC;gBAC3D,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,4BAA4B,CAAC,IAAI,CAAC,CAAC;YAChE,CAAC;YAED,uEAAuE;YACvE,qEAAqE;YACrE,wEAAwE;YACxE,sCAAsC;YACtC,SAAyD,CAAC;YAC1D,OAAO,SAAc,CAAC;QACvB,CAAC;QAED,OAAO,SAAS,CAAC,cAAc,CAAC;QAChC,+DAA+D;QAC/D,kEAAkE;QAClE,wEAAwE;QACxE,sCAAsC;QACtC,SAE4C,CAAC;QAC7C,OAAO,SAAc,CAAC;IACvB,CAAC;IAEO,sBAAsB;QAC7B,MAAM,OAAO,GAA8C;YAC1D,aAAa,EAAE,IAAI,CAAC,GAAG,EAAE;YACzB,UAAU,EAAE,IAAI,CAAC,cAAc;YAC/B,UAAU,EAAE,IAAI;YAChB,IAAI,EAAE,IAAI,CAAC,uBAAuB,CAAC,IAAI,CAAC,SAAS,CAAC;SAClD,CAAC;QAEF,MAAM,iBAAiB,GAAyB,EAAE,CAAC;QACnD,MAAM,mBAAmB,GAAmC,EAAE,CAAC;QAC/D,IAAI,IAAI,CAAC,iBAAiB,CAAC,IAAI,GAAG,CAAC,EAAE,CAAC;YACrC,OAAO,CAAC,eAAe,GAAG,CAAC,GAAG,IAAI,CAAC,iBAAiB,CAAC,IAAI,EAAE,CAAC,CAAC;YAC7D,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;gBACjB,uBAAuB;gBACvB,KAAK,MAAM,CAAC,SAAS,EAAE,EAAE,aAAa,EAAE,CAAC,IAAI,IAAI,CAAC,iBAAiB,CAAC,OAAO,EAAE,EAAE,CAAC;oBAC/E,IAAI,aAAa,KAAK,SAAS,EAAE,CAAC;wBACjC,iBAAiB,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;oBACnC,CAAC;yBAAM,CAAC;wBACP,mBAAmB,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,aAAa,CAAC,CAAC,CAAC;oBACtD,CAAC;gBACF,CAAC;YACF,CAAC;YACD,IAAI,CAAC,iBAAiB,CAAC,KAAK,EAAE,CAAC;QAChC,CAAC;QAED,uEAAuE;QACvE,IAAI,CAAC,sBAAsB,CAAC,YAAY,EAAE,CAAC;QAC3C,IAAI,CAAC,gBAAgB,CAAC,YAAY,EAAE,CAAC;QAErC,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC;YACzB,IAAI,EAAE,wCAA0B;YAChC,OAAO;SACP,CAAC,CAAC;QACH,IAAI,OAAO,CAAC,eAAe,EAAE,CAAC;YAC7B,IAAI,CAAC,MAAM,EAAE,kBAAkB,CAAC;gBAC/B,SAAS,EAAE,cAAc;gBACzB,OAAO,EAAE;oBACR,IAAI,EAAE,cAAc;oBACpB,UAAU,EAAE,IAAI,CAAC,UAAU;oBAC3B,YAAY,EAAE,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE;oBACxC,gBAAgB,EAAE,IAAI,CAAC,SAAS,CAAC,iBAAiB,CAAC;oBACnD,kBAAkB,EAAE,IAAI,CAAC,SAAS,CAAC,mBAAmB,CAAC;iBACvD;aACD,CAAC,CAAC;QACJ,CAAC;QAED,uDAAuD;QACvD,IAAI,CAAC,UAAU,GAAG,SAAS,CAAC;IAC7B,CAAC;IAEM,aAAa,CACnB,OAAgD,EAChD,KAAc,EACd,QAAiB;QAEjB,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAC5B,IAAA,iBAAM,EAAC,OAAO,CAAC,QAAQ,KAAK,IAAI,EAAE,KAAK,CAAC,0CAA0C,CAAC,CAAC;QACpF,IAAI,CAAC,iBAAiB,CAAC,OAAO,CAAC,EAAE,CAAC;YACjC,IAAA,iBAAM,EAAC,QAAQ,EAAE,+CAA+C,CAAC,CAAC;YAClE,OAAO;QACR,CAAC;QAED,IAAI,KAAK,EAAE,CAAC;YACX,MAAM,aAAa,GAAG,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC,aAAa,CAAC;YAC/D,+DAA+D;YAC/D,4DAA4D;YAC5D,iEAAiE;YACjE,cAAc;YACd,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,gBAAgB,GAAG,CAAC,EAAE,GAAG,CAAC,CAAC;YACjE,IAAI,CAAC,cAAc;gBAClB,CAAC,IAAI,CAAC,cAAc,GAAG,CAAC,IAAI,CAAC,gBAAgB,GAAG,CAAC,CAAC,GAAG,aAAa,CAAC;oBACnE,IAAI,CAAC,gBAAgB,CAAC;YACvB,OAAO;QACR,CAAC;QAED,MAAM,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC;QAChD,IAAA,iBAAM,EAAC,YAAY,KAAK,SAAS,EAAE,kCAAkC,CAAC,CAAC;QAEvE,iEAAiE;QACjE,mEAAmE;QACnE,uBAAuB;QACvB,gEAAgE;QAChE,qEAAqE;QACrE,uEAAuE;QACvE,mEAAmE;QACnE,WAAW;QACX,IAAI,IAAI,CAAC,4BAA4B,KAAK,SAAS,EAAE,CAAC;YACrD,IAAI,CAAC,kBAAkB,CAAC,YAAY,EAAE,uBAAuB,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QACjF,CAAC;QAED,MAAM,YAAY,GACjB,QAAQ;YACR,CAAC,IAAI,CAAC,cAAc,GAAG,OAAO,CAAC,OAAO,CAAC,UAAU,GAAG,OAAO,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;QAEpF,MAAM,iBAAiB,GAAuB,EAAE,CAAC;QAEjD,IAAI,OAAO,CAAC,IAAI,KAAK,6BAAe,EAAE,CAAC;YACtC,+EAA+E;YAC/E,6EAA6E;YAC7E,yEAAyE;YACzE,IAAI,IAAI,CAAC,OAAO,CAAC,eAAe,EAAE,KAAK,cAAc,EAAE,CAAC;gBACvD,IAAI,CAAC,mBAAmB,CAAC,OAAO,CAAC,OAAO,CAAC,eAAe,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC;YAC7E,CAAC;YACD,6EAA6E;YAC7E,aAAa;QACd,CAAC;aAAM,CAAC;YACP,wDAAwD;YACxD,MAAM,eAAe,GAAG,OAAO,CAAC,OAAO,CAAC,eAAe,CAAC;YACxD,IAAI,eAAe,EAAE,CAAC;gBACrB,IAAI,0BAA0B,GAAG,KAAK,CAAC;gBACvC,IAAI,eAAe,CAAC,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC;oBAC5C,IAAI,IAAI,CAAC,yBAAyB,EAAE,CAAC;wBACpC,IAAI,IAAI,CAAC,yBAAyB,KAAK,OAAO,EAAE,CAAC;4BAChD,mDAAmD;4BACnD,kDAAkD;4BAClD,uCAAuC;4BACvC,IAAI,CAAC,MAAM,EAAE,kBAAkB,CAAC;gCAC/B,SAAS,EAAE,uBAAuB;gCAClC,OAAO,EAAE;oCACR,UAAU,EAAE,IAAI,CAAC,UAAU;oCAC3B,YAAY,EAAE,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE;iCACxC;6BACD,CAAC,CAAC;wBACJ,CAAC;oBACF,CAAC;yBAAM,CAAC;wBACP,yDAAyD;wBACzD,yDAAyD;wBACzD,2BAA2B;wBAC3B,0BAA0B,GAAG,IAAI,CAAC;oBACnC,CAAC;oBACD,IAAI,CAAC,yBAAyB,GAAG,eAAe,CAAC;gBAClD,CAAC;gBACD,IAAI,IAAI,CAAC,iBAAiB,CAAC,IAAI,GAAG,CAAC,EAAE,CAAC;oBACrC,KAAK,MAAM,WAAW,IAAI,eAAe,EAAE,CAAC;wBAC3C,IAAI,CAAC,iBAAiB,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;oBAC5C,CAAC;oBACD,IAAI,IAAI,CAAC,iBAAiB,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;wBACvC,oDAAoD;wBACpD,IAAI,CAAC,sBAAsB,CAAC,YAAY,EAAE,CAAC;oBAC5C,CAAC;yBAAM,IAAI,0BAA0B,EAAE,CAAC;wBACvC,2DAA2D;wBAC3D,gDAAgD;wBAChD,IAAI,CAAC,sBAAsB,CAAC,YAAY,EAAE,CAAC;wBAC3C,iBAAiB,CAAC,IAAI,CAAC,IAAI,CAAC,6BAA6B,CAAC,CAAC;oBAC5D,CAAC;gBACF,CAAC;YACF,CAAC;YAED,0HAA0H;YAC1H,IAAI,OAAO,CAAC,OAAO,CAAC,iBAAiB,KAAK,SAAS,EAAE,CAAC;gBACrD,IAAA,iBAAM,EACL,IAAI,CAAC,qBAAqB,EAC1B,wFAAwF,CACxF,CAAC;gBACF,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC;oBACzB,IAAI,EAAE,wCAA0B;oBAChC,OAAO,EAAE,EAAE,EAAE,EAAE,OAAO,CAAC,OAAO,CAAC,iBAAiB,EAAE;oBAClD,cAAc,EAAE,OAAO,CAAC,QAAQ;iBAChC,CAAC,CAAC;YACJ,CAAC;QACF,CAAC;QAED,0EAA0E;QAC1E,KAAK,MAAM,CAAC,gBAAgB,CAAC,IAAI,IAAA,gCAAa,EAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;YACtE,4EAA4E;YAC5E,wEAAwE;YACxE,kEAAkE;YAClE,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,gBAAgB,CAAC,IAAI,IAAI,CAAC,SAAS,CAAC,gBAAgB,CAAC,EAAE,CAAC;gBAC/E,SAAS;YACV,CAAC;YAED,8DAA8D;YAC9D,MAAM,KAAK,GAAG,gBAAgB,CAAC,KAAK,CAAC,qBAAqB,CAErB,CAAC;YAEtC,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;gBACpB,SAAS;YACV,CAAC;YAED,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;YACxB,MAAM,sBAAsB,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;YAExC,MAAM,qBAAqB,GAAG,sBAAsB,CAAC,MAAM,CAAC,IAAI,SAAS,CAAC;YAE1E,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,oBAAoB,EAAE,sBAAsB,EAAE,qBAAqB,CAAC,CAAC;QACvF,CAAC;QAED,sEAAsE;QACtE,0DAA0D;QAC1D,MAAM,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,IAA4D,CAAC;QAC1F,KAAK,MAAM,CAAC,gBAAgB,EAAE,eAAe,CAAC,IAAI,IAAA,gCAAa,EAAC,IAAI,CAAC,EAAE,CAAC;YACvE,4DAA4D;YAC5D,MAAM,SAAS,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC;YACxD,IAAI,SAAS,EAAE,CAAC;gBACf,iBAAiB,CAAC,IAAI,CACrB,GAAG,SAAS,CAAC,QAAQ,CAAC,aAAa,CAClC,QAAQ,EACR,YAAY,EACZ,eAAe,EACf,OAAO,CAAC,QAAQ,CAChB,CACD,CAAC;YACH,CAAC;iBAAM,CAAC;gBACP,+EAA+E;gBAC/E,8BAA8B;gBAE9B,0DAA0D;gBAC1D,MAAM,kBAAkB,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,gBAAgB,CAAC,KAAK,EAAE,CAAC,CAAC;gBACrE,KAAK,MAAM,CAAC,GAAG,EAAE,mBAAmB,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,eAAe,CAAC,EAAE,CAAC;oBAC1E,IAAA,2CAAuB,EAAC,GAAG,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,YAAY,CAAC,CAAC;gBACrF,CAAC;YACF,CAAC;QACF,CAAC;QAED,KAAK,MAAM,MAAM,IAAI,iBAAiB,EAAE,CAAC;YACxC,MAAM,EAAE,CAAC;QACV,CAAC;IACF,CAAC;IA8BD;;;;;;;;;;OAUG;IACK,mBAAmB,CAC1B,eAAqC,EACrC,SAA6B;QAE7B,+EAA+E;QAC/E,sFAAsF;QACtF,oEAAoE;QACpE,MAAM,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,WAAW,EAAG,CAAC;QACjD,IAAI,mBAAmB,GAAG,qCAA6B,CAAC,cAAc,CAAC;QACvE,IAAI,qBAAyC,CAAC;QAC9C,IAAI,CAAC,eAAe,CAAC,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC;YAC7C,uEAAuE;YACvE,mEAAmE;YACnE,sEAAsE;YACtE,+DAA+D;YAC/D,yEAAyE;YACzE,MAAM,aAAa,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,CAAC,UAAU,EAAE,CAAC;YAC5D,MAAM,IAAI,GAAG,aAAa,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;YAC7C,IAAI,IAAI,EAAE,CAAC;gBACV,gEAAgE;gBAChE,qBAAqB,GAAG,CAAC,CAAC;gBAC1B,KAAK,MAAM,EAAE,MAAM,EAAE,cAAc,EAAE,IAAI,aAAa,CAAC,MAAM,EAAE,EAAE,CAAC;oBACjE,IACC,cAAc,GAAG,IAAI,CAAC,cAAc;wBACpC,MAAM,CAAC,OAAO,CAAC,YAAY,CAAC,WAAW,EACtC,CAAC;wBACF,qBAAqB,EAAE,CAAC;oBACzB,CAAC;gBACF,CAAC;YACF,CAAC;iBAAM,CAAC;gBACP,mEAAmE;gBACnE,IAAI,yBAAyB,GAAG,CAAC,CAAC;gBAClC,KAAK,MAAM,EAAE,MAAM,EAAE,IAAI,aAAa,CAAC,MAAM,EAAE,EAAE,CAAC;oBACjD,IAAI,MAAM,CAAC,OAAO,CAAC,YAAY,CAAC,WAAW,EAAE,CAAC;wBAC7C,yBAAyB,EAAE,CAAC;oBAC7B,CAAC;gBACF,CAAC;gBACD,qBAAqB,GAAG,yBAAyB,GAAG,IAAI,CAAC,MAAM,EAAE,GAAG,EAAE,CAAC;YACxE,CAAC;YACD,8DAA8D;YAC9D,gDAAgD;YAChD,mBAAmB;gBAClB,qCAA6B,CAAC,wBAAwB;oBACtD,CAAC,CAAC,GAAG,eAAe,CAAC,MAAM,GAAG,qBAAqB,CAAC,CAAC;QACvD,CAAC;QAED,4EAA4E;QAC5E,MAAM,YAAY,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,mBAAmB,CAAC;QACtD,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,SAAS,EAAE;YACrC,YAAY;YACZ,aAAa,EAAE,qBAAqB;SACpC,CAAC,CAAC;QAEH,IAAI,CAAC,IAAI,CAAC,yBAAyB,EAAE,CAAC;YACrC,oEAAoE;YACpE,kEAAkE;YAClE,2DAA2D;YAC3D,MAAM,EAAE,WAAW,EAAE,+BAA+B,EAAE,GACrD,IAAI,CAAC,sBAAsB,CAAC,YAAY,CAAC,CAAC;YAC3C;YACC,0DAA0D;YAC1D,4DAA4D;YAC5D,mCAAmC;YACnC,WAAW;gBACX,IAAI,CAAC,iBAAiB,CAAC,IAAI,IAAI,+BAA+B,CAAC,GAAG,CAAC,IAAI,EACtE,CAAC;gBACF,kDAAkD;gBAClD,2DAA2D;gBAC3D,8DAA8D;gBAC9D,2CAA2C;gBAC3C,IAAI,CAAC,yBAAyB,GAAG,eAAe,CAAC;YAClD,CAAC;QACF,CAAC;QAED,qEAAqE;QACrE,sEAAsE;QACtE,sEAAsE;QACtE,sDAAsD;QACtD,IAAI,IAAI,CAAC,yBAAyB,IAAI,eAAe,CAAC,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC;YAC9E,+DAA+D;YAC/D,mEAAmE;YACnE,wEAAwE;YACxE,oEAAoE;YACpE,IAAI,CAAC,cAAc,CAAC,SAAS,EAAE;gBAC9B,wBAAwB,EAAE,mBAAmB;aAC7C,CAAC,CAAC;QACJ,CAAC;aAAM,CAAC;YACP,gEAAgE;YAChE,4CAA4C;YAC5C,IACC,IAAI,CAAC,sBAAsB,CAAC,UAAU,EAAE;gBACxC,YAAY,GAAG,IAAI,CAAC,sBAAsB,CAAC,UAAU,EACpD,CAAC;gBACF,2BAA2B;gBAC3B,IAAI,CAAC,sBAAsB,CAAC,UAAU,CACrC,IAAI,CAAC,6BAA6B,EAClC,mBAAmB,CACnB,CAAC;YACH,CAAC;QACF,CAAC;IACF,CAAC;CACD;AA5yBD,oEA4yBC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport type { IAudience } from \"@fluidframework/container-definitions\";\nimport type { InboundExtensionMessage } from \"@fluidframework/container-runtime-definitions/internal\";\nimport type { IEmitter } from \"@fluidframework/core-interfaces/internal\";\nimport { assert } from \"@fluidframework/core-utils/internal\";\nimport type { ITelemetryLoggerExt } from \"@fluidframework/telemetry-utils/internal\";\n\nimport type { ClientConnectionId } from \"./baseTypes.js\";\nimport type { BroadcastControlSettings } from \"./broadcastControls.js\";\nimport type { InternalTypes } from \"./exposedInternalTypes.js\";\nimport type {\n\tIEphemeralRuntime,\n\tPostUpdateAction,\n\tValidatableOptionalState,\n\tValidatableValueDirectory,\n\tValidatableValueStructure,\n} from \"./internalTypes.js\";\nimport { objectEntries } from \"./internalUtils.js\";\nimport type {\n\tAttendeeId,\n\tPresenceWithNotifications as Presence,\n\tPresenceEvents,\n} from \"./presence.js\";\nimport type {\n\tClientUpdateEntry,\n\tRuntimeLocalUpdateOptions,\n\tPresenceStatesInternal,\n\tValueElementMap,\n} from \"./presenceStates.js\";\nimport {\n\tcreatePresenceStates,\n\tmergeUntrackedDatastore,\n\tmergeValueDirectory,\n} from \"./presenceStates.js\";\nimport type {\n\tDatastoreMessageContent,\n\tGeneralDatastoreMessageContent,\n\tInboundClientJoinMessage,\n\tInboundDatastoreUpdateMessage,\n\tInternalWorkspaceAddress,\n\tOutboundDatastoreUpdateMessage,\n\tSignalMessages,\n\tSystemDatastore,\n} from \"./protocol.js\";\nimport {\n\tacknowledgementMessageType,\n\tdatastoreUpdateMessageType,\n\tjoinMessageType,\n} from \"./protocol.js\";\nimport type { SystemWorkspaceDatastore } from \"./systemWorkspace.js\";\nimport { TimerManager } from \"./timerManager.js\";\nimport type {\n\tAnyWorkspace,\n\tNotificationsWorkspace,\n\tNotificationsWorkspaceSchema,\n\tStatesWorkspace,\n\tStatesWorkspaceSchema,\n\tWorkspaceAddress,\n} from \"./types.js\";\n\ninterface AnyWorkspaceEntry<TSchema extends StatesWorkspaceSchema> {\n\tpublic: AnyWorkspace<TSchema>;\n\tinternal: PresenceStatesInternal;\n}\n\n/**\n * Datastore structure used for broadcasting to other clients.\n * Validation metadata is stripped before transmission.\n */\ntype PresenceDatastore = SystemDatastore & {\n\t[WorkspaceAddress: InternalWorkspaceAddress]: ValueElementMap<StatesWorkspaceSchema>;\n};\n\nconst internalWorkspaceTypes: Readonly<Record<string, \"States\" | \"Notifications\">> = {\n\ts: \"States\",\n\tn: \"Notifications\",\n} as const;\n\nconst knownMessageTypes = new Set([\n\tjoinMessageType,\n\tdatastoreUpdateMessageType,\n\tacknowledgementMessageType,\n]);\nfunction isPresenceMessage(\n\tmessage: InboundExtensionMessage<SignalMessages>,\n): message is InboundDatastoreUpdateMessage | InboundClientJoinMessage {\n\treturn knownMessageTypes.has(message.type);\n}\n\n/**\n * Type guard to check if a value hierarchy object is a directory (has \"items\"\n * property).\n *\n * @param obj - The object to check\n * @returns True if the object is a {@link ValidatableValueDirectory}\n */\nexport function isValueDirectory<T>(\n\tobj: ValidatableValueDirectory<T> | ValidatableOptionalState<T>,\n): obj is ValidatableValueDirectory<T> {\n\treturn \"items\" in obj;\n}\n\n/**\n * High-level contract for manager of singleton Presence datastore\n */\nexport interface PresenceDatastoreManager {\n\tjoinSession(clientId: ClientConnectionId): void;\n\tonDisconnected(): void;\n\tgetWorkspace<TSchema extends StatesWorkspaceSchema>(\n\t\tinternalWorkspaceAddress: `s:${WorkspaceAddress}`,\n\t\trequestedContent: TSchema,\n\t\tcontrols?: BroadcastControlSettings,\n\t): StatesWorkspace<TSchema>;\n\tgetWorkspace<TSchema extends NotificationsWorkspaceSchema>(\n\t\tinternalWorkspaceAddress: `n:${WorkspaceAddress}`,\n\t\trequestedContent: TSchema,\n\t): NotificationsWorkspace<TSchema>;\n\tprocessSignal(\n\t\tmessage: InboundExtensionMessage<SignalMessages>,\n\t\tlocal: boolean,\n\t\toptional: boolean,\n\t): void;\n}\n\nfunction mergeGeneralDatastoreMessageContent(\n\tbase: GeneralDatastoreMessageContent | undefined,\n\tnewData: GeneralDatastoreMessageContent,\n): GeneralDatastoreMessageContent {\n\t// This function-local \"datastore\" will hold the merged message data.\n\tconst queueDatastore = base ?? {};\n\n\t// Merge the current data with the existing data, if any exists.\n\t// Iterate over the current message data; individual items are workspaces.\n\tfor (const [workspaceName, workspaceData] of objectEntries(newData)) {\n\t\t// Initialize the merged data as the queued datastore entry for the workspace.\n\t\t// Since the key might not exist, create an empty object in that case. It will\n\t\t// be set explicitly after the loop.\n\t\tconst mergedData = queueDatastore[workspaceName] ?? {};\n\n\t\t// Iterate over each value manager and its data, merging it as needed.\n\t\tfor (const [valueManagerKey, valueManagerValue] of objectEntries(workspaceData)) {\n\t\t\tfor (const [attendeeId, value] of objectEntries(valueManagerValue)) {\n\t\t\t\tconst mergeObject = (mergedData[valueManagerKey] ??= {});\n\t\t\t\tconst oldData = mergeObject[attendeeId];\n\t\t\t\tmergeObject[attendeeId] = mergeValueDirectory(\n\t\t\t\t\toldData,\n\t\t\t\t\tvalue,\n\t\t\t\t\t0, // local values do not need a time shift\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\t// Store the merged data in the function-local queue workspace. The whole contents of this\n\t\t// datastore will be sent as the message data.\n\t\tqueueDatastore[workspaceName] = mergedData;\n\t}\n\treturn queueDatastore;\n}\n\n/**\n * Delays used for broadcasting join responses to clients.\n *\n * @remarks\n * Exported for test coordination.\n * These could be made customizable in the future to accommodate different\n * session configurations.\n */\nexport const broadcastJoinResponseDelaysMs = {\n\t/**\n\t * The delay in milliseconds before a join response is sent to any client.\n\t * This is used to accumulate other join response requests and reduce\n\t * network traffic.\n\t */\n\tnamedResponder: 200,\n\t/**\n\t * The additional delay in milliseconds a backup responder waits before sending\n\t * a join response to allow others to respond first.\n\t */\n\tbackupResponderIncrement: 40,\n} as const;\n\n/**\n * Manages singleton datastore for all Presence.\n */\nexport class PresenceDatastoreManagerImpl implements PresenceDatastoreManager {\n\tprivate readonly datastore: PresenceDatastore;\n\tprivate averageLatency = 0;\n\tprivate returnedMessages = 0;\n\tprivate readonly sendMessageTimer = new TimerManager();\n\tprivate readonly workspaces = new Map<string, AnyWorkspaceEntry<StatesWorkspaceSchema>>();\n\tprivate readonly targetedSignalSupport: boolean;\n\n\t/**\n\t * When defined, this client is not recognized in the session.\n\t * Call when no longer caring about that condition. That way listeners are\n\t * cleaned up.\n\t */\n\tprivate stopWaitingForSelfInAudience: undefined | (() => void);\n\n\t/**\n\t * Tracks whether this client has complete snapshot level knowledge and\n\t * how that determination was reached.\n\t * - \"alone\": no other audience members detected at join\n\t * - \"join response\": another client has responded to our join request\n\t * - \"full requests\": all others have requested response from us\n\t *\n\t * @remarks\n\t * Only applies when not using targeted join responses.\n\t *\n\t * Without a complete snapshot, we cannot fully onboard any other clients.\n\t * One exception to this is if this client is the only participant in the\n\t * session. In such a case, there is no one to respond to the join request.\n\t * Another exception is multiple clients attempting to join at the same\n\t * time and thus expecting that someone has full knowledge, yet none have\n\t * received a complete update to think they are qualified to respond.\n\t * Generically if the number of outstanding requestors meets or exceeds the\n\t * count of other audience members, then we can consider the snapshot\n\t * complete (as all will have provided their own complete information in\n\t * their join responses).\n\t */\n\tprivate reasonForCompleteSnapshot?: \"alone\" | \"join response\" | \"full requests\";\n\n\t/**\n\t * Map of outstanding broadcast (join response) requests.\n\t */\n\tprivate readonly broadcastRequests = new Map<\n\t\tClientConnectionId,\n\t\t{ deadlineTime: number; responseOrder?: number | undefined }\n\t>();\n\t/**\n\t * Timer for managing broadcast (join response) request timing.\n\t */\n\tprivate readonly broadcastRequestsTimer = new TimerManager();\n\n\tpublic constructor(\n\t\tprivate readonly attendeeId: AttendeeId,\n\t\tprivate readonly runtime: IEphemeralRuntime,\n\t\tprivate readonly logger: ITelemetryLoggerExt | undefined,\n\t\tprivate readonly events: IEmitter<PresenceEvents>,\n\t\tprivate readonly presence: Presence,\n\t\tsystemWorkspaceDatastore: SystemWorkspaceDatastore,\n\t\tsystemWorkspace: AnyWorkspaceEntry<StatesWorkspaceSchema>,\n\t) {\n\t\t// eslint-disable-next-line @typescript-eslint/consistent-type-assertions\n\t\tthis.datastore = { \"system:presence\": systemWorkspaceDatastore } as PresenceDatastore;\n\t\tthis.workspaces.set(\"system:presence\", systemWorkspace);\n\t\tthis.targetedSignalSupport = this.runtime.supportedFeatures.has(\"submit_signals_v2\");\n\t\t// If audience member is removed, they won't need a broadcast response.\n\t\tthis.runtime.getAudience().on(\"removeMember\", (clientId) => {\n\t\t\tthis.broadcastRequests.delete(clientId);\n\t\t});\n\t}\n\n\tprivate getAudienceInformation(selfClientId: ClientConnectionId): {\n\t\taudience: IAudience;\n\t\tselfPresent: boolean;\n\t\tinteractiveMembersExcludingSelf: {\n\t\t\tall: Set<ClientConnectionId>;\n\t\t\twriters: Set<ClientConnectionId>;\n\t\t};\n\t} {\n\t\tconst audience = this.runtime.getAudience();\n\t\tconst members = audience.getMembers();\n\t\tconst all = new Set<ClientConnectionId>();\n\t\tconst writers = new Set<ClientConnectionId>();\n\t\tconst selfPresent = members.has(selfClientId);\n\t\tif (selfPresent) {\n\t\t\t// Remove self\n\t\t\tmembers.delete(selfClientId);\n\t\t}\n\t\t// Gather interactive client IDs\n\t\tfor (const [id, client] of members) {\n\t\t\tif (client.details.capabilities.interactive) {\n\t\t\t\tall.add(id);\n\t\t\t\tif (client.mode === \"write\") {\n\t\t\t\t\twriters.add(id);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn {\n\t\t\taudience,\n\t\t\tselfPresent,\n\t\t\tinteractiveMembersExcludingSelf: {\n\t\t\t\tall,\n\t\t\t\twriters,\n\t\t\t},\n\t\t};\n\t}\n\n\tpublic joinSession(\n\t\tselfClientId: ClientConnectionId,\n\t\talternateProvider: ClientConnectionId | undefined = undefined,\n\t): void {\n\t\t// Before broadcasting the join message, check that there is at least\n\t\t// one audience member present (self or another). This is useful to\n\t\t// optimize join messages while not using targeted join responses.\n\t\t// (We need at least one other to be able to elect them as update\n\t\t// provider.)\n\t\t// Lack of anyone likely means that this client is very freshly joined\n\t\t// and has not received any Join Signals (type=\"join\") from the service\n\t\t// yet.\n\t\tconst { audience, selfPresent, interactiveMembersExcludingSelf } =\n\t\t\tthis.getAudienceInformation(selfClientId);\n\n\t\tif (interactiveMembersExcludingSelf.all.size === 0 && alternateProvider !== undefined) {\n\t\t\tif (selfPresent) {\n\t\t\t\t// If there aren't any members connected except self, then this client\n\t\t\t\t// must have complete information.\n\t\t\t\tthis.reasonForCompleteSnapshot = \"alone\";\n\t\t\t\t// It would be possible to return at this time and skip ClientJoin\n\t\t\t\t// signal. Instead continue in case audience information is\n\t\t\t\t// inaccurate. This client might temporarily erroneously believe it\n\t\t\t\t// has complete information, but the other(s) should respond to\n\t\t\t\t// ClientJoin soon rectifying that and covering for bad incomplete\n\t\t\t\t// responses this client sent in the meantime.\n\t\t\t} else {\n\t\t\t\t// No one is known. Not even self. Defer judgement on\n\t\t\t\t// complete snapshot until at least self is known to be present.\n\t\t\t\tthis.listenForSelfInAudience(selfClientId, audience);\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\n\t\t// Broadcast join message to all clients\n\t\t// Select primary update providers\n\t\t// Use write members if any, then fallback to read-only members.\n\t\tconst updateProviders = [\n\t\t\t...(interactiveMembersExcludingSelf.writers.size > 0\n\t\t\t\t? interactiveMembersExcludingSelf.writers\n\t\t\t\t: interactiveMembersExcludingSelf.all),\n\t\t];\n\t\t// Limit to three providers to prevent flooding the network.\n\t\t// If none respond, others present will (should) after a delay.\n\t\tif (updateProviders.length > 3) {\n\t\t\tupdateProviders.length = 3;\n\t\t} else if (updateProviders.length === 0 && alternateProvider !== undefined) {\n\t\t\tupdateProviders.push(alternateProvider);\n\t\t}\n\t\tthis.runtime.submitSignal({\n\t\t\ttype: joinMessageType,\n\t\t\tcontent: {\n\t\t\t\tsendTimestamp: Date.now(),\n\t\t\t\tavgLatency: this.averageLatency,\n\t\t\t\tdata: this.stripValidationMetadata(this.datastore),\n\t\t\t\tupdateProviders,\n\t\t\t},\n\t\t});\n\t\tthis.logger?.sendTelemetryEvent({\n\t\t\teventName: \"JoinRequested\",\n\t\t\tdetails: {\n\t\t\t\tattendeeId: this.attendeeId,\n\t\t\t\tconnectionId: selfClientId,\n\t\t\t\t// Empty updateProviders is indicative of join when alone.\n\t\t\t\tupdateProviders: JSON.stringify(updateProviders),\n\t\t\t\t// If false and providers is single entry, then join was probably forced.\n\t\t\t\tselfPresent,\n\t\t\t},\n\t\t});\n\t}\n\n\tprivate listenForSelfInAudience(selfClientId: string, audience: IAudience): void {\n\t\tthis.logger?.sendTelemetryEvent({\n\t\t\teventName: \"JoinDeferred\",\n\t\t\tdetails: {\n\t\t\t\tattendeeId: this.attendeeId,\n\t\t\t\tconnectionId: selfClientId,\n\t\t\t},\n\t\t});\n\t\t// Prepare to join once self audience member joins.\n\t\t// Alternatively, processSignal may force a join when a presence\n\t\t// signal is received even without audience members (assumes\n\t\t// audience signals were lost).\n\t\tconst joinWhenSelfAudienceMemberAdded = (addedClientId: ClientConnectionId): void => {\n\t\t\tif (addedClientId !== selfClientId) {\n\t\t\t\t// Keep listening\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// No need to force here by providing alternate provider as self is\n\t\t\t// now present.\n\t\t\t// Do avoid forcing so that reasonForCompleteSnapshot is set correctly\n\t\t\t// if no others have been added.\n\t\t\tthis.stopWaitingAndJoin(selfClientId, /* alternateProvider */ undefined);\n\t\t};\n\t\taudience.on(\"addMember\", joinWhenSelfAudienceMemberAdded);\n\t\tthis.stopWaitingForSelfInAudience = () => {\n\t\t\taudience.off(\"addMember\", joinWhenSelfAudienceMemberAdded);\n\t\t};\n\t}\n\n\tprivate stopWaitingAndJoin(\n\t\tselfClientId: ClientConnectionId,\n\t\talternateProvider: ClientConnectionId | undefined,\n\t): void {\n\t\tthis.stopWaitingForSelfInAudience?.();\n\t\tthis.stopWaitingForSelfInAudience = undefined;\n\t\t// Confirm not currently disconnected\n\t\tif (this.runtime.getJoinedStatus() !== \"disconnected\") {\n\t\t\tthis.joinSession(selfClientId, alternateProvider);\n\t\t}\n\t}\n\n\tpublic onDisconnected(): void {\n\t\tdelete this.reasonForCompleteSnapshot;\n\t\tthis.stopWaitingForSelfInAudience?.();\n\t\tthis.stopWaitingForSelfInAudience = undefined;\n\t}\n\n\tpublic getWorkspace<TSchema extends StatesWorkspaceSchema>(\n\t\tinternalWorkspaceAddress: InternalWorkspaceAddress,\n\t\trequestedContent: TSchema,\n\t\tcontrols?: BroadcastControlSettings,\n\t): AnyWorkspace<TSchema> {\n\t\tconst existing = this.workspaces.get(internalWorkspaceAddress);\n\t\tif (existing) {\n\t\t\treturn existing.internal.ensureContent(requestedContent, controls);\n\t\t}\n\n\t\tlet workspaceDatastore: ValueElementMap<StatesWorkspaceSchema> | undefined =\n\t\t\tthis.datastore[internalWorkspaceAddress];\n\t\tif (workspaceDatastore === undefined) {\n\t\t\tworkspaceDatastore = this.datastore[internalWorkspaceAddress] = {};\n\t\t}\n\n\t\tconst localUpdate = (\n\t\t\tstates: { [key: string]: ClientUpdateEntry },\n\t\t\toptions: RuntimeLocalUpdateOptions,\n\t\t): void => {\n\t\t\t// Check for connectivity before sending updates.\n\t\t\tif (this.runtime.getJoinedStatus() === \"disconnected\") {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst updates: GeneralDatastoreMessageContent[InternalWorkspaceAddress] = {};\n\t\t\tfor (const [key, value] of Object.entries(states)) {\n\t\t\t\tupdates[key] = { [this.attendeeId]: value };\n\t\t\t}\n\n\t\t\tthis.enqueueMessage(\n\t\t\t\t{\n\t\t\t\t\t[internalWorkspaceAddress]: updates,\n\t\t\t\t},\n\t\t\t\toptions,\n\t\t\t);\n\t\t};\n\n\t\tconst entry = createPresenceStates(\n\t\t\t{\n\t\t\t\tpresence: this.presence,\n\t\t\t\tattendeeId: this.attendeeId,\n\t\t\t\tlocalUpdate,\n\t\t\t},\n\t\t\tworkspaceDatastore,\n\t\t\trequestedContent,\n\t\t\tcontrols,\n\t\t);\n\n\t\tthis.workspaces.set(internalWorkspaceAddress, entry);\n\t\treturn entry.public;\n\t}\n\n\t/**\n\t * The combined contents of all queued updates. Will be `\"sendAll\"` when a\n\t * full broadcast is pending or `undefined` when no messages are queued.\n\t */\n\tprivate queuedData: GeneralDatastoreMessageContent | \"sendAll\" | undefined;\n\n\t/**\n\t * Enqueues a new message to be sent. The message may be queued or may be sent immediately depending on the state of\n\t * the send timer, other messages in the queue, the configured allowed latency, etc.\n\t */\n\tprivate enqueueMessage(\n\t\tdata: GeneralDatastoreMessageContent | \"sendAll\",\n\t\toptions: RuntimeLocalUpdateOptions,\n\t): void {\n\t\tif (this.queuedData !== \"sendAll\") {\n\t\t\tthis.queuedData =\n\t\t\t\tdata === \"sendAll\"\n\t\t\t\t\t? \"sendAll\"\n\t\t\t\t\t: // Merging the message with any queued messages effectively queues the message.\n\t\t\t\t\t\t// It is OK to queue all incoming messages as long as when we send, we send the queued data.\n\t\t\t\t\t\tmergeGeneralDatastoreMessageContent(this.queuedData, data);\n\t\t}\n\n\t\tconst { allowableUpdateLatencyMs } = options;\n\t\tconst now = Date.now();\n\t\tconst thisMessageDeadline = now + allowableUpdateLatencyMs;\n\n\t\tif (\n\t\t\t// If the timer has not expired, we can short-circuit because the timer will fire\n\t\t\t// and cover this update. In other words, queuing this will be fast enough to\n\t\t\t// meet its deadline, because a timer is already scheduled to fire before its deadline.\n\t\t\t!this.sendMessageTimer.hasExpired() &&\n\t\t\t// If the deadline for this message is later than the overall send deadline, then\n\t\t\t// we can exit early since a timer will take care of sending it.\n\t\t\tthisMessageDeadline >= this.sendMessageTimer.expireTime\n\t\t) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Either we need to send this message immediately, or we need to schedule a timer\n\t\t// to fire at the send deadline that will take care of it.\n\n\t\t// Note that timeoutInMs === allowableUpdateLatencyMs, but the calculation is done this way for clarity.\n\t\tconst timeoutInMs = thisMessageDeadline - now;\n\t\tconst scheduleForLater = timeoutInMs > 0;\n\n\t\tif (scheduleForLater) {\n\t\t\t// Schedule the queued messages to be sent at the updateDeadline\n\t\t\tthis.sendMessageTimer.setTimeout(this.sendQueuedMessage.bind(this), timeoutInMs);\n\t\t} else {\n\t\t\tthis.sendQueuedMessage();\n\t\t}\n\t}\n\n\t/**\n\t * Send any queued signal immediately. Does nothing if no message is queued.\n\t */\n\tprivate sendQueuedMessage(): void {\n\t\tthis.sendMessageTimer.clearTimeout();\n\n\t\tif (this.queuedData === undefined) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Check for connectivity before sending updates.\n\t\tif (this.runtime.getJoinedStatus() === \"disconnected\") {\n\t\t\t// Clear the queued data since we're disconnected. We don't want messages\n\t\t\t// to queue infinitely while disconnected.\n\t\t\tthis.queuedData = undefined;\n\t\t\treturn;\n\t\t}\n\n\t\tif (this.queuedData === \"sendAll\") {\n\t\t\tthis.broadcastAllKnownState();\n\t\t\treturn;\n\t\t}\n\n\t\tconst clientConnectionId = this.runtime.getClientId();\n\t\tassert(clientConnectionId !== undefined, 0xa59 /* Client connected without clientId */);\n\t\tconst currentClientToSessionValueState =\n\t\t\t// When connected, `clientToSessionId` must always have current connection entry.\n\t\t\tthis.datastore[\"system:presence\"].clientToSessionId[clientConnectionId];\n\t\tassert(currentClientToSessionValueState !== undefined, \"Client connection update missing\");\n\n\t\tconst newMessage = {\n\t\t\tsendTimestamp: Date.now(),\n\t\t\tavgLatency: this.averageLatency,\n\t\t\t// isComplete: false,\n\t\t\tdata: {\n\t\t\t\t// Always send current connection mapping for some resiliency against\n\t\t\t\t// lost signals. This ensures that client session id found in `updates`\n\t\t\t\t// (which is this client's client session id) is always represented in\n\t\t\t\t// system workspace of recipient clients.\n\t\t\t\t\"system:presence\": {\n\t\t\t\t\tclientToSessionId: {\n\t\t\t\t\t\t[clientConnectionId]: { ...currentClientToSessionValueState },\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t...this.queuedData,\n\t\t\t},\n\t\t} satisfies OutboundDatastoreUpdateMessage[\"content\"];\n\t\tthis.queuedData = undefined;\n\t\tthis.runtime.submitSignal({ type: datastoreUpdateMessageType, content: newMessage });\n\t}\n\n\t/**\n\t * Recursively strips validation metadata (validatedValue) from datastore before broadcasting.\n\t * This ensures that validation metadata doesn't leak into signals sent to other clients.\n\t */\n\tprivate stripValidationMetadata(datastore: PresenceDatastore): DatastoreMessageContent {\n\t\tconst messageContent: DatastoreMessageContent = {\n\t\t\t[\"system:presence\"]: datastore[\"system:presence\"],\n\t\t};\n\n\t\tfor (const [workspaceAddress, workspace] of objectEntries(datastore)) {\n\t\t\t// System workspace has no validation metadata and is already\n\t\t\t// set in messageContent; so, it can be skipped.\n\t\t\tif (workspaceAddress === \"system:presence\") continue;\n\n\t\t\tconst workspaceData: GeneralDatastoreMessageContent[typeof workspaceAddress] = {};\n\n\t\t\tfor (const [stateName, clientRecord] of objectEntries(workspace)) {\n\t\t\t\tconst cleanClientRecord: GeneralDatastoreMessageContent[typeof workspaceAddress][typeof stateName] =\n\t\t\t\t\t{};\n\n\t\t\t\tfor (const [attendeeId, valueData] of objectEntries(clientRecord)) {\n\t\t\t\t\tcleanClientRecord[attendeeId] = this.stripValidationFromValueData(valueData);\n\t\t\t\t}\n\n\t\t\t\tworkspaceData[stateName] = cleanClientRecord;\n\t\t\t}\n\n\t\t\tmessageContent[workspaceAddress] = workspaceData;\n\t\t}\n\n\t\treturn messageContent;\n\t}\n\n\t/**\n\t * Strips validation metadata from individual value data entries.\n\t */\n\tprivate stripValidationFromValueData<\n\t\tT extends\n\t\t\t| InternalTypes.ValueDirectory<unknown>\n\t\t\t| InternalTypes.ValueRequiredState<unknown>\n\t\t\t| InternalTypes.ValueOptionalState<unknown>,\n\t>(valueDataIn: ValidatableValueStructure<T>): T {\n\t\t// Clone the input object since we may mutate it\n\t\tconst valueData = { ...valueDataIn };\n\n\t\t// Handle directory structures (with \"items\" property)\n\t\tif (isValueDirectory(valueData)) {\n\t\t\tfor (const [key, item] of Object.entries(valueData.items)) {\n\t\t\t\tvalueData.items[key] = this.stripValidationFromValueData(item);\n\t\t\t}\n\n\t\t\t// This `satisfies` test is rather weak while ValidatableValueDirectory\n\t\t\t// only has optional properties over InternalTypes.ValueDirectory and\n\t\t\t// thus readily does satisfy. If `validatedValue?: never` is uncommented\n\t\t\t// in Value*State then this will fail.\n\t\t\tvalueData satisfies InternalTypes.ValueDirectory<unknown>;\n\t\t\treturn valueData as T;\n\t\t}\n\n\t\tdelete valueData.validatedValue;\n\t\t// This `satisfies` test is rather weak while Validatable*State\n\t\t// only has optional properties over InternalTypes.Value*State and\n\t\t// thus readily does satisfy. If `validatedValue?: never` is uncommented\n\t\t// in Value*State then this will fail.\n\t\tvalueData satisfies\n\t\t\t| InternalTypes.ValueRequiredState<unknown>\n\t\t\t| InternalTypes.ValueOptionalState<unknown>;\n\t\treturn valueData as T;\n\t}\n\n\tprivate broadcastAllKnownState(): void {\n\t\tconst content: OutboundDatastoreUpdateMessage[\"content\"] = {\n\t\t\tsendTimestamp: Date.now(),\n\t\t\tavgLatency: this.averageLatency,\n\t\t\tisComplete: true,\n\t\t\tdata: this.stripValidationMetadata(this.datastore),\n\t\t};\n\n\t\tconst primaryRequestors: ClientConnectionId[] = [];\n\t\tconst secondaryRequestors: [ClientConnectionId, number][] = [];\n\t\tif (this.broadcastRequests.size > 0) {\n\t\t\tcontent.joinResponseFor = [...this.broadcastRequests.keys()];\n\t\t\tif (this.logger) {\n\t\t\t\t// Build telemetry data\n\t\t\t\tfor (const [requestor, { responseOrder }] of this.broadcastRequests.entries()) {\n\t\t\t\t\tif (responseOrder === undefined) {\n\t\t\t\t\t\tprimaryRequestors.push(requestor);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tsecondaryRequestors.push([requestor, responseOrder]);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis.broadcastRequests.clear();\n\t\t}\n\n\t\t// This broadcast will satisfy all requests; clear any remaining timer.\n\t\tthis.broadcastRequestsTimer.clearTimeout();\n\t\tthis.sendMessageTimer.clearTimeout();\n\n\t\tthis.runtime.submitSignal({\n\t\t\ttype: datastoreUpdateMessageType,\n\t\t\tcontent,\n\t\t});\n\t\tif (content.joinResponseFor) {\n\t\t\tthis.logger?.sendTelemetryEvent({\n\t\t\t\teventName: \"JoinResponse\",\n\t\t\t\tdetails: {\n\t\t\t\t\ttype: \"broadcastAll\",\n\t\t\t\t\tattendeeId: this.attendeeId,\n\t\t\t\t\tconnectionId: this.runtime.getClientId(),\n\t\t\t\t\tprimaryResponses: JSON.stringify(primaryRequestors),\n\t\t\t\t\tsecondaryResponses: JSON.stringify(secondaryRequestors),\n\t\t\t\t},\n\t\t\t});\n\t\t}\n\n\t\t// Sending all must account for anything queued before.\n\t\tthis.queuedData = undefined;\n\t}\n\n\tpublic processSignal(\n\t\tmessage: InboundExtensionMessage<SignalMessages>,\n\t\tlocal: boolean,\n\t\toptional: boolean,\n\t): void {\n\t\tconst received = Date.now();\n\t\tassert(message.clientId !== null, 0xa3a /* Map received signal without clientId */);\n\t\tif (!isPresenceMessage(message)) {\n\t\t\tassert(optional, \"Unrecognized message type in critical message\");\n\t\t\treturn;\n\t\t}\n\n\t\tif (local) {\n\t\t\tconst deliveryDelta = received - message.content.sendTimestamp;\n\t\t\t// Limit returnedMessages count to 256 such that newest message\n\t\t\t// always contributes at least 1/256th to the average. Older\n\t\t\t// messages have more weight, but that diminishes as new messages\n\t\t\t// contribute.\n\t\t\tthis.returnedMessages = Math.min(this.returnedMessages + 1, 256);\n\t\t\tthis.averageLatency =\n\t\t\t\t(this.averageLatency * (this.returnedMessages - 1) + deliveryDelta) /\n\t\t\t\tthis.returnedMessages;\n\t\t\treturn;\n\t\t}\n\n\t\tconst selfClientId = this.runtime.getClientId();\n\t\tassert(selfClientId !== undefined, \"Received signal without clientId\");\n\n\t\t// Check for undesired case of receiving a remote presence signal\n\t\t// without having been alerted to self audience join. (Perhaps join\n\t\t// signal was dropped.)\n\t\t// In practice it is commonly observed that local signals can be\n\t\t// returned ahead of audience join notification. So, it is reasonable\n\t\t// to expect that audience join notification may be delayed until after\n\t\t// other presence signals are received. One is enough to get things\n\t\t// rolling.\n\t\tif (this.stopWaitingForSelfInAudience !== undefined) {\n\t\t\tthis.stopWaitingAndJoin(selfClientId, /* alternateProvider */ message.clientId);\n\t\t}\n\n\t\tconst timeModifier =\n\t\t\treceived -\n\t\t\t(this.averageLatency + message.content.avgLatency + message.content.sendTimestamp);\n\n\t\tconst postUpdateActions: PostUpdateAction[] = [];\n\n\t\tif (message.type === joinMessageType) {\n\t\t\t// It is possible for some signals to come in while client is not connected due\n\t\t\t// to how work is scheduled. If we are not connected, we can't respond to the\n\t\t\t// join request. We will make our own Join request once we are connected.\n\t\t\tif (this.runtime.getJoinedStatus() !== \"disconnected\") {\n\t\t\t\tthis.prepareJoinResponse(message.content.updateProviders, message.clientId);\n\t\t\t}\n\t\t\t// It is okay to continue processing the contained updates even if we are not\n\t\t\t// connected.\n\t\t} else {\n\t\t\t// Update join response requests that are now satisfied.\n\t\t\tconst joinResponseFor = message.content.joinResponseFor;\n\t\t\tif (joinResponseFor) {\n\t\t\t\tlet justGainedCompleteSnapshot = false;\n\t\t\t\tif (joinResponseFor.includes(selfClientId)) {\n\t\t\t\t\tif (this.reasonForCompleteSnapshot) {\n\t\t\t\t\t\tif (this.reasonForCompleteSnapshot === \"alone\") {\n\t\t\t\t\t\t\t// No response was expected. This might happen when\n\t\t\t\t\t\t\t// either cautionary ClientJoin signal is received\n\t\t\t\t\t\t\t// by audience member that was unknown.\n\t\t\t\t\t\t\tthis.logger?.sendTelemetryEvent({\n\t\t\t\t\t\t\t\teventName: \"JoinResponseWhenAlone\",\n\t\t\t\t\t\t\t\tdetails: {\n\t\t\t\t\t\t\t\t\tattendeeId: this.attendeeId,\n\t\t\t\t\t\t\t\t\tconnectionId: this.runtime.getClientId(),\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// If we are the intended recipient of the join response,\n\t\t\t\t\t\t// we can consider our knowledge complete and can respond\n\t\t\t\t\t\t// to others join requests.\n\t\t\t\t\t\tjustGainedCompleteSnapshot = true;\n\t\t\t\t\t}\n\t\t\t\t\tthis.reasonForCompleteSnapshot = \"join response\";\n\t\t\t\t}\n\t\t\t\tif (this.broadcastRequests.size > 0) {\n\t\t\t\t\tfor (const responseFor of joinResponseFor) {\n\t\t\t\t\t\tthis.broadcastRequests.delete(responseFor);\n\t\t\t\t\t}\n\t\t\t\t\tif (this.broadcastRequests.size === 0) {\n\t\t\t\t\t\t// If no more requests are pending, clear any timer.\n\t\t\t\t\t\tthis.broadcastRequestsTimer.clearTimeout();\n\t\t\t\t\t} else if (justGainedCompleteSnapshot) {\n\t\t\t\t\t\t// May or may not be time to respond to remaining requests.\n\t\t\t\t\t\t// Clear the timer and recheck after processing.\n\t\t\t\t\t\tthis.broadcastRequestsTimer.clearTimeout();\n\t\t\t\t\t\tpostUpdateActions.push(this.sendJoinResponseIfStillNeeded);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// If the message requests an acknowledgement, we will send a targeted acknowledgement message back to just the requestor.\n\t\t\tif (message.content.acknowledgementId !== undefined) {\n\t\t\t\tassert(\n\t\t\t\t\tthis.targetedSignalSupport,\n\t\t\t\t\t\"Acknowledgment message was requested while targeted signal capability is not supported\",\n\t\t\t\t);\n\t\t\t\tthis.runtime.submitSignal({\n\t\t\t\t\ttype: acknowledgementMessageType,\n\t\t\t\t\tcontent: { id: message.content.acknowledgementId },\n\t\t\t\t\ttargetClientId: message.clientId,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\t// Handle activation of unregistered workspaces before processing updates.\n\t\tfor (const [workspaceAddress] of objectEntries(message.content.data)) {\n\t\t\t// The first part of OR condition checks if workspace is already registered.\n\t\t\t// The second part checks if the workspace has already been seen before.\n\t\t\t// In either case we can skip emitting 'workspaceActivated' event.\n\t\t\tif (this.workspaces.has(workspaceAddress) || this.datastore[workspaceAddress]) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// Separate internal type prefix from public workspace address\n\t\t\tconst match = workspaceAddress.match(/^([^:]):([^:]+:.+)$/) as\n\t\t\t\t| null\n\t\t\t\t| [string, string, WorkspaceAddress];\n\n\t\t\tif (match === null) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst prefix = match[1];\n\t\t\tconst publicWorkspaceAddress = match[2];\n\n\t\t\tconst internalWorkspaceType = internalWorkspaceTypes[prefix] ?? \"Unknown\";\n\n\t\t\tthis.events.emit(\"workspaceActivated\", publicWorkspaceAddress, internalWorkspaceType);\n\t\t}\n\n\t\t// While the system workspace is processed here too, it is declared as\n\t\t// conforming to the general schema. So drop its override.\n\t\tconst data = message.content.data as Omit<typeof message.content.data, \"system:presence\">;\n\t\tfor (const [workspaceAddress, remoteDatastore] of objectEntries(data)) {\n\t\t\t// Direct to the appropriate Presence Workspace, if present.\n\t\t\tconst workspace = this.workspaces.get(workspaceAddress);\n\t\t\tif (workspace) {\n\t\t\t\tpostUpdateActions.push(\n\t\t\t\t\t...workspace.internal.processUpdate(\n\t\t\t\t\t\treceived,\n\t\t\t\t\t\ttimeModifier,\n\t\t\t\t\t\tremoteDatastore,\n\t\t\t\t\t\tmessage.clientId,\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\t// All broadcast state is kept even if not currently registered, unless a value\n\t\t\t\t// notes itself to be ignored.\n\n\t\t\t\t// Ensure there is a datastore at this address and get it.\n\t\t\t\tconst workspaceDatastore = (this.datastore[workspaceAddress] ??= {});\n\t\t\t\tfor (const [key, remoteAllKnownState] of Object.entries(remoteDatastore)) {\n\t\t\t\t\tmergeUntrackedDatastore(key, remoteAllKnownState, workspaceDatastore, timeModifier);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tfor (const action of postUpdateActions) {\n\t\t\taction();\n\t\t}\n\t}\n\n\t/**\n\t * Broadcasts a join response (complete datastore update message)\n\t * if there is an outstanding join response request.\n\t */\n\tprivate readonly sendJoinResponseIfStillNeeded = (): void => {\n\t\t// Make sure we are currently connected and a broadcast is still needed.\n\t\t// If not connected, nothing we can do.\n\t\tif (this.runtime.getJoinedStatus() !== \"disconnected\" && this.broadcastRequests.size > 0) {\n\t\t\t// Confirm that of remaining requests, now is the time to respond.\n\t\t\tconst now = Date.now();\n\t\t\tlet minResponseTime = Number.POSITIVE_INFINITY;\n\t\t\tfor (const { deadlineTime } of this.broadcastRequests.values()) {\n\t\t\t\tminResponseTime = Math.min(minResponseTime, deadlineTime);\n\t\t\t}\n\t\t\tif (minResponseTime <= now) {\n\t\t\t\tif (this.reasonForCompleteSnapshot) {\n\t\t\t\t\tthis.broadcastAllKnownState();\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// No response needed yet - schedule a later attempt\n\t\t\t\tthis.broadcastRequestsTimer.setTimeout(\n\t\t\t\t\tthis.sendJoinResponseIfStillNeeded,\n\t\t\t\t\tminResponseTime - now,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t};\n\n\t/**\n\t * Handles responding to another client joining the session.\n\t *\n\t * @param updateProviders - list of client connection id's that requestor selected\n\t * to provide response\n\t * @param requestor - `requestor` is only used in telemetry. While it is the requestor's\n\t * client connection id, that is not most important. It is important that this is a\n\t * unique shared id across all clients that might respond as we want to monitor the\n\t * response patterns. The convenience of being client connection id will allow\n\t * correlation with other telemetry where it is often called just `clientId`.\n\t */\n\tprivate prepareJoinResponse(\n\t\tupdateProviders: ClientConnectionId[],\n\t\trequestor: ClientConnectionId,\n\t): void {\n\t\t// We must be connected to receive this message, so clientId should be defined.\n\t\t// If it isn't then, not really a problem; just won't be in provider or audience list.\n\t\t// eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n\t\tconst selfClientId = this.runtime.getClientId()!;\n\t\tlet joinResponseDelayMs = broadcastJoinResponseDelaysMs.namedResponder;\n\t\tlet relativeResponseOrder: number | undefined;\n\t\tif (!updateProviders.includes(selfClientId)) {\n\t\t\t// Schedule a broadcast to the new client after a delay only to send if\n\t\t\t// another broadcast satisfying the request hasn't been seen in the\n\t\t\t// meantime. The delay is based on the position in the quorum list. It\n\t\t\t// doesn't have to be a stable list across all clients. We need\n\t\t\t// something to provide suggested order to prevent a flood of broadcasts.\n\t\t\tconst quorumMembers = this.runtime.getQuorum().getMembers();\n\t\t\tconst self = quorumMembers.get(selfClientId);\n\t\t\tif (self) {\n\t\t\t\t// Compute order quorum join order (indicated by sequenceNumber)\n\t\t\t\trelativeResponseOrder = 0;\n\t\t\t\tfor (const { client, sequenceNumber } of quorumMembers.values()) {\n\t\t\t\t\tif (\n\t\t\t\t\t\tsequenceNumber < self.sequenceNumber &&\n\t\t\t\t\t\tclient.details.capabilities.interactive\n\t\t\t\t\t) {\n\t\t\t\t\t\trelativeResponseOrder++;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// Order past quorum members + arbitrary additional offset up to 10\n\t\t\t\tlet possibleQuorumRespondents = 0;\n\t\t\t\tfor (const { client } of quorumMembers.values()) {\n\t\t\t\t\tif (client.details.capabilities.interactive) {\n\t\t\t\t\t\tpossibleQuorumRespondents++;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\trelativeResponseOrder = possibleQuorumRespondents + Math.random() * 10;\n\t\t\t}\n\t\t\t// When not named to provide update, wait an additional amount\n\t\t\t// of time for those named or others to respond.\n\t\t\tjoinResponseDelayMs +=\n\t\t\t\tbroadcastJoinResponseDelaysMs.backupResponderIncrement *\n\t\t\t\t(3 * updateProviders.length + relativeResponseOrder);\n\t\t}\n\n\t\t// Add the requestor to the list of clients that will receive the broadcast.\n\t\tconst deadlineTime = Date.now() + joinResponseDelayMs;\n\t\tthis.broadcastRequests.set(requestor, {\n\t\t\tdeadlineTime,\n\t\t\tresponseOrder: relativeResponseOrder,\n\t\t});\n\n\t\tif (!this.reasonForCompleteSnapshot) {\n\t\t\t// Check if requestor count meets or exceeds count of other audience\n\t\t\t// members indicating that we effectively have a complete snapshot\n\t\t\t// (once the current message being processed is processed).\n\t\t\tconst { selfPresent, interactiveMembersExcludingSelf } =\n\t\t\t\tthis.getAudienceInformation(selfClientId);\n\t\t\tif (\n\t\t\t\t// Self-present check is done to help ensure that audience\n\t\t\t\t// information is accurate. If self is not present, audience\n\t\t\t\t// information might be incomplete.\n\t\t\t\tselfPresent &&\n\t\t\t\tthis.broadcastRequests.size >= interactiveMembersExcludingSelf.all.size\n\t\t\t) {\n\t\t\t\t// Note that no action is taken here specifically.\n\t\t\t\t// We want action to be queued so that it takes place after\n\t\t\t\t// current message is completely processed. All of the actions\n\t\t\t\t// below should be delayed (not immediate).\n\t\t\t\tthis.reasonForCompleteSnapshot = \"full requests\";\n\t\t\t}\n\t\t}\n\n\t\t// Check if capable of full primary response. If requested to provide\n\t\t// primary response, but do not yet have complete snapshot, we need to\n\t\t// delay a full response, until we think we have complete snapshot. In\n\t\t// the meantime we will send partial updates as usual.\n\t\tif (this.reasonForCompleteSnapshot && updateProviders.includes(selfClientId)) {\n\t\t\t// Use regular message queue to handle timing of the broadcast.\n\t\t\t// Any more immediate broadcasts will accelerate the response time.\n\t\t\t// As a primary responder, it is expected that broadcast will happen and\n\t\t\t// using the regular queue allows other updates to avoid merge work.\n\t\t\tthis.enqueueMessage(\"sendAll\", {\n\t\t\t\tallowableUpdateLatencyMs: joinResponseDelayMs,\n\t\t\t});\n\t\t} else {\n\t\t\t// Check if there isn't already a timer scheduled to send a join\n\t\t\t// response with in this request's deadline.\n\t\t\tif (\n\t\t\t\tthis.broadcastRequestsTimer.hasExpired() ||\n\t\t\t\tdeadlineTime < this.broadcastRequestsTimer.expireTime\n\t\t\t) {\n\t\t\t\t// Set or update the timer.\n\t\t\t\tthis.broadcastRequestsTimer.setTimeout(\n\t\t\t\t\tthis.sendJoinResponseIfStillNeeded,\n\t\t\t\t\tjoinResponseDelayMs,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"presenceDatastoreManager.js","sourceRoot":"","sources":["../src/presenceDatastoreManager.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 type { IAudience } from \"@fluidframework/container-definitions\";\nimport type { InboundExtensionMessage } from \"@fluidframework/container-runtime-definitions/internal\";\nimport type { IEmitter } from \"@fluidframework/core-interfaces/internal\";\nimport { assert } from \"@fluidframework/core-utils/internal\";\nimport type { ITelemetryLoggerExt } from \"@fluidframework/telemetry-utils/internal\";\n\nimport type { ClientConnectionId } from \"./baseTypes.js\";\nimport type { BroadcastControlSettings } from \"./broadcastControls.js\";\nimport type { InternalTypes } from \"./exposedInternalTypes.js\";\nimport type {\n\tIEphemeralRuntime,\n\tPostUpdateAction,\n\tValidatableOptionalState,\n\tValidatableValueDirectory,\n\tValidatableValueStructure,\n} from \"./internalTypes.js\";\nimport { objectEntries } from \"./internalUtils.js\";\nimport type {\n\tAttendeeId,\n\tPresenceWithNotifications as Presence,\n\tPresenceEvents,\n} from \"./presence.js\";\nimport type {\n\tClientUpdateEntry,\n\tRuntimeLocalUpdateOptions,\n\tPresenceStatesInternal,\n\tValueElementMap,\n} from \"./presenceStates.js\";\nimport {\n\tcreatePresenceStates,\n\tmergeUntrackedDatastore,\n\tmergeValueDirectory,\n} from \"./presenceStates.js\";\nimport type {\n\tDatastoreMessageContent,\n\tGeneralDatastoreMessageContent,\n\tInboundClientJoinMessage,\n\tInboundDatastoreUpdateMessage,\n\tInternalWorkspaceAddress,\n\tOutboundDatastoreUpdateMessage,\n\tSignalMessages,\n\tSystemDatastore,\n} from \"./protocol.js\";\nimport {\n\tacknowledgementMessageType,\n\tdatastoreUpdateMessageType,\n\tjoinMessageType,\n} from \"./protocol.js\";\nimport type { SystemWorkspaceDatastore } from \"./systemWorkspace.js\";\nimport { TimerManager } from \"./timerManager.js\";\nimport type {\n\tAnyWorkspace,\n\tNotificationsWorkspace,\n\tNotificationsWorkspaceSchema,\n\tStatesWorkspace,\n\tStatesWorkspaceSchema,\n\tWorkspaceAddress,\n} from \"./types.js\";\n\ninterface AnyWorkspaceEntry<TSchema extends StatesWorkspaceSchema> {\n\tpublic: AnyWorkspace<TSchema>;\n\tinternal: PresenceStatesInternal;\n}\n\n/**\n * Datastore structure used for broadcasting to other clients.\n * Validation metadata is stripped before transmission.\n */\ntype PresenceDatastore = SystemDatastore & {\n\t[WorkspaceAddress: InternalWorkspaceAddress]: ValueElementMap<StatesWorkspaceSchema>;\n};\n\nconst internalWorkspaceTypes: Readonly<Record<string, \"States\" | \"Notifications\">> = {\n\ts: \"States\",\n\tn: \"Notifications\",\n} as const;\n\nconst knownMessageTypes = new Set([\n\tjoinMessageType,\n\tdatastoreUpdateMessageType,\n\tacknowledgementMessageType,\n]);\nfunction isPresenceMessage(\n\tmessage: InboundExtensionMessage<SignalMessages>,\n): message is InboundDatastoreUpdateMessage | InboundClientJoinMessage {\n\treturn knownMessageTypes.has(message.type);\n}\n\n/**\n * Type guard to check if a value hierarchy object is a directory (has \"items\"\n * property).\n *\n * @param obj - The object to check\n * @returns True if the object is a {@link ValidatableValueDirectory}\n */\nexport function isValueDirectory<T>(\n\tobj: ValidatableValueDirectory<T> | ValidatableOptionalState<T>,\n): obj is ValidatableValueDirectory<T> {\n\treturn \"items\" in obj;\n}\n\n/**\n * High-level contract for manager of singleton Presence datastore\n */\nexport interface PresenceDatastoreManager {\n\tjoinSession(clientId: ClientConnectionId): void;\n\tonDisconnected(): void;\n\tgetWorkspace<TSchema extends StatesWorkspaceSchema>(\n\t\tinternalWorkspaceAddress: `s:${WorkspaceAddress}`,\n\t\trequestedContent: TSchema,\n\t\tcontrols?: BroadcastControlSettings,\n\t): StatesWorkspace<TSchema>;\n\tgetWorkspace<TSchema extends NotificationsWorkspaceSchema>(\n\t\tinternalWorkspaceAddress: `n:${WorkspaceAddress}`,\n\t\trequestedContent: TSchema,\n\t): NotificationsWorkspace<TSchema>;\n\tprocessSignal(\n\t\tmessage: InboundExtensionMessage<SignalMessages>,\n\t\tlocal: boolean,\n\t\toptional: boolean,\n\t): void;\n}\n\nfunction mergeGeneralDatastoreMessageContent(\n\tbase: GeneralDatastoreMessageContent | undefined,\n\tnewData: GeneralDatastoreMessageContent,\n): GeneralDatastoreMessageContent {\n\t// This function-local \"datastore\" will hold the merged message data.\n\tconst queueDatastore = base ?? {};\n\n\t// Merge the current data with the existing data, if any exists.\n\t// Iterate over the current message data; individual items are workspaces.\n\tfor (const [workspaceName, workspaceData] of objectEntries(newData)) {\n\t\t// Initialize the merged data as the queued datastore entry for the workspace.\n\t\t// Since the key might not exist, create an empty object in that case. It will\n\t\t// be set explicitly after the loop.\n\t\tconst mergedData = queueDatastore[workspaceName] ?? {};\n\n\t\t// Iterate over each value manager and its data, merging it as needed.\n\t\tfor (const [valueManagerKey, valueManagerValue] of objectEntries(workspaceData)) {\n\t\t\tfor (const [attendeeId, value] of objectEntries(valueManagerValue)) {\n\t\t\t\tconst mergeObject = (mergedData[valueManagerKey] ??= {});\n\t\t\t\tconst oldData = mergeObject[attendeeId];\n\t\t\t\tmergeObject[attendeeId] = mergeValueDirectory(\n\t\t\t\t\toldData,\n\t\t\t\t\tvalue,\n\t\t\t\t\t0, // local values do not need a time shift\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\t// Store the merged data in the function-local queue workspace. The whole contents of this\n\t\t// datastore will be sent as the message data.\n\t\tqueueDatastore[workspaceName] = mergedData;\n\t}\n\treturn queueDatastore;\n}\n\n/**\n * Delays used for broadcasting join responses to clients.\n *\n * @remarks\n * Exported for test coordination.\n * These could be made customizable in the future to accommodate different\n * session configurations.\n */\nexport const broadcastJoinResponseDelaysMs = {\n\t/**\n\t * The delay in milliseconds before a join response is sent to any client.\n\t * This is used to accumulate other join response requests and reduce\n\t * network traffic.\n\t */\n\tnamedResponder: 200,\n\t/**\n\t * The additional delay in milliseconds a backup responder waits before sending\n\t * a join response to allow others to respond first.\n\t */\n\tbackupResponderIncrement: 40,\n} as const;\n\n/**\n * Manages singleton datastore for all Presence.\n */\nexport class PresenceDatastoreManagerImpl implements PresenceDatastoreManager {\n\tprivate readonly datastore: PresenceDatastore;\n\tprivate averageLatency = 0;\n\tprivate returnedMessages = 0;\n\tprivate readonly sendMessageTimer = new TimerManager();\n\tprivate readonly workspaces = new Map<string, AnyWorkspaceEntry<StatesWorkspaceSchema>>();\n\tprivate readonly targetedSignalSupport: boolean;\n\n\t/**\n\t * When defined, this client is not recognized in the session.\n\t * Call when no longer caring about that condition. That way listeners are\n\t * cleaned up.\n\t */\n\tprivate stopWaitingForSelfInAudience: undefined | (() => void);\n\n\t/**\n\t * Tracks whether this client has complete snapshot level knowledge and\n\t * how that determination was reached.\n\t * - \"alone\": no other audience members detected at join\n\t * - \"join response\": another client has responded to our join request\n\t * - \"full requests\": all others have requested response from us\n\t *\n\t * @remarks\n\t * Only applies when not using targeted join responses.\n\t *\n\t * Without a complete snapshot, we cannot fully onboard any other clients.\n\t * One exception to this is if this client is the only participant in the\n\t * session. In such a case, there is no one to respond to the join request.\n\t * Another exception is multiple clients attempting to join at the same\n\t * time and thus expecting that someone has full knowledge, yet none have\n\t * received a complete update to think they are qualified to respond.\n\t * Generically if the number of outstanding requestors meets or exceeds the\n\t * count of other audience members, then we can consider the snapshot\n\t * complete (as all will have provided their own complete information in\n\t * their join responses).\n\t */\n\tprivate reasonForCompleteSnapshot?: \"alone\" | \"join response\" | \"full requests\";\n\n\t/**\n\t * Map of outstanding broadcast (join response) requests.\n\t */\n\tprivate readonly broadcastRequests = new Map<\n\t\tClientConnectionId,\n\t\t{ deadlineTime: number; responseOrder?: number | undefined }\n\t>();\n\t/**\n\t * Timer for managing broadcast (join response) request timing.\n\t */\n\tprivate readonly broadcastRequestsTimer = new TimerManager();\n\n\tpublic constructor(\n\t\tprivate readonly attendeeId: AttendeeId,\n\t\tprivate readonly runtime: IEphemeralRuntime,\n\t\tprivate readonly logger: ITelemetryLoggerExt | undefined,\n\t\tprivate readonly events: IEmitter<PresenceEvents>,\n\t\tprivate readonly presence: Presence,\n\t\tsystemWorkspaceDatastore: SystemWorkspaceDatastore,\n\t\tsystemWorkspace: AnyWorkspaceEntry<StatesWorkspaceSchema>,\n\t) {\n\t\t// eslint-disable-next-line @typescript-eslint/consistent-type-assertions\n\t\tthis.datastore = { \"system:presence\": systemWorkspaceDatastore } as PresenceDatastore;\n\t\tthis.workspaces.set(\"system:presence\", systemWorkspace);\n\t\tthis.targetedSignalSupport = this.runtime.supportedFeatures.has(\"submit_signals_v2\");\n\t\t// If audience member is removed, they won't need a broadcast response.\n\t\tthis.runtime.getAudience().on(\"removeMember\", (clientId) => {\n\t\t\tthis.broadcastRequests.delete(clientId);\n\t\t});\n\t}\n\n\tprivate getAudienceInformation(selfClientId: ClientConnectionId): {\n\t\taudience: IAudience;\n\t\tselfPresent: boolean;\n\t\tinteractiveMembersExcludingSelf: {\n\t\t\tall: Set<ClientConnectionId>;\n\t\t\twriters: Set<ClientConnectionId>;\n\t\t};\n\t} {\n\t\tconst audience = this.runtime.getAudience();\n\t\tconst members = audience.getMembers();\n\t\tconst all = new Set<ClientConnectionId>();\n\t\tconst writers = new Set<ClientConnectionId>();\n\t\tconst selfPresent = members.has(selfClientId);\n\t\tif (selfPresent) {\n\t\t\t// Remove self\n\t\t\tmembers.delete(selfClientId);\n\t\t}\n\t\t// Gather interactive client IDs\n\t\tfor (const [id, client] of members) {\n\t\t\tif (client.details.capabilities.interactive) {\n\t\t\t\tall.add(id);\n\t\t\t\tif (client.mode === \"write\") {\n\t\t\t\t\twriters.add(id);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn {\n\t\t\taudience,\n\t\t\tselfPresent,\n\t\t\tinteractiveMembersExcludingSelf: {\n\t\t\t\tall,\n\t\t\t\twriters,\n\t\t\t},\n\t\t};\n\t}\n\n\tpublic joinSession(\n\t\tselfClientId: ClientConnectionId,\n\t\talternateProvider: ClientConnectionId | undefined = undefined,\n\t): void {\n\t\t// Before broadcasting the join message, check that there is at least\n\t\t// one audience member present (self or another). This is useful to\n\t\t// optimize join messages while not using targeted join responses.\n\t\t// (We need at least one other to be able to elect them as update\n\t\t// provider.)\n\t\t// Lack of anyone likely means that this client is very freshly joined\n\t\t// and has not received any Join Signals (type=\"join\") from the service\n\t\t// yet.\n\t\tconst { audience, selfPresent, interactiveMembersExcludingSelf } =\n\t\t\tthis.getAudienceInformation(selfClientId);\n\n\t\tif (interactiveMembersExcludingSelf.all.size === 0 && alternateProvider !== undefined) {\n\t\t\tif (selfPresent) {\n\t\t\t\t// If there aren't any members connected except self, then this client\n\t\t\t\t// must have complete information.\n\t\t\t\tthis.reasonForCompleteSnapshot = \"alone\";\n\t\t\t\t// It would be possible to return at this time and skip ClientJoin\n\t\t\t\t// signal. Instead continue in case audience information is\n\t\t\t\t// inaccurate. This client might temporarily erroneously believe it\n\t\t\t\t// has complete information, but the other(s) should respond to\n\t\t\t\t// ClientJoin soon rectifying that and covering for bad incomplete\n\t\t\t\t// responses this client sent in the meantime.\n\t\t\t} else {\n\t\t\t\t// No one is known. Not even self. Defer judgement on\n\t\t\t\t// complete snapshot until at least self is known to be present.\n\t\t\t\tthis.listenForSelfInAudience(selfClientId, audience);\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\n\t\t// Broadcast join message to all clients\n\t\t// Select primary update providers\n\t\t// Use write members if any, then fallback to read-only members.\n\t\tconst updateProviders = [\n\t\t\t...(interactiveMembersExcludingSelf.writers.size > 0\n\t\t\t\t? interactiveMembersExcludingSelf.writers\n\t\t\t\t: interactiveMembersExcludingSelf.all),\n\t\t];\n\t\t// Limit to three providers to prevent flooding the network.\n\t\t// If none respond, others present will (should) after a delay.\n\t\tif (updateProviders.length > 3) {\n\t\t\tupdateProviders.length = 3;\n\t\t} else if (updateProviders.length === 0 && alternateProvider !== undefined) {\n\t\t\tupdateProviders.push(alternateProvider);\n\t\t}\n\t\tthis.runtime.submitSignal({\n\t\t\ttype: joinMessageType,\n\t\t\tcontent: {\n\t\t\t\tsendTimestamp: Date.now(),\n\t\t\t\tavgLatency: this.averageLatency,\n\t\t\t\tdata: this.stripValidationMetadata(this.datastore),\n\t\t\t\tupdateProviders,\n\t\t\t},\n\t\t});\n\t\tthis.logger?.sendTelemetryEvent({\n\t\t\teventName: \"JoinRequested\",\n\t\t\tdetails: {\n\t\t\t\tattendeeId: this.attendeeId,\n\t\t\t\tconnectionId: selfClientId,\n\t\t\t\t// Empty updateProviders is indicative of join when alone.\n\t\t\t\tupdateProviders: JSON.stringify(updateProviders),\n\t\t\t\t// If false and providers is single entry, then join was probably forced.\n\t\t\t\tselfPresent,\n\t\t\t},\n\t\t});\n\t}\n\n\tprivate listenForSelfInAudience(selfClientId: string, audience: IAudience): void {\n\t\tthis.logger?.sendTelemetryEvent({\n\t\t\teventName: \"JoinDeferred\",\n\t\t\tdetails: {\n\t\t\t\tattendeeId: this.attendeeId,\n\t\t\t\tconnectionId: selfClientId,\n\t\t\t},\n\t\t});\n\t\t// Prepare to join once self audience member joins.\n\t\t// Alternatively, processSignal may force a join when a presence\n\t\t// signal is received even without audience members (assumes\n\t\t// audience signals were lost).\n\t\tconst joinWhenSelfAudienceMemberAdded = (addedClientId: ClientConnectionId): void => {\n\t\t\tif (addedClientId !== selfClientId) {\n\t\t\t\t// Keep listening\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// No need to force here by providing alternate provider as self is\n\t\t\t// now present.\n\t\t\t// Do avoid forcing so that reasonForCompleteSnapshot is set correctly\n\t\t\t// if no others have been added.\n\t\t\tthis.stopWaitingAndJoin(selfClientId, /* alternateProvider */ undefined);\n\t\t};\n\t\taudience.on(\"addMember\", joinWhenSelfAudienceMemberAdded);\n\t\tthis.stopWaitingForSelfInAudience = () => {\n\t\t\taudience.off(\"addMember\", joinWhenSelfAudienceMemberAdded);\n\t\t};\n\t}\n\n\tprivate stopWaitingAndJoin(\n\t\tselfClientId: ClientConnectionId,\n\t\talternateProvider: ClientConnectionId | undefined,\n\t): void {\n\t\tthis.stopWaitingForSelfInAudience?.();\n\t\tthis.stopWaitingForSelfInAudience = undefined;\n\t\t// Confirm not currently disconnected\n\t\tif (this.runtime.getJoinedStatus() !== \"disconnected\") {\n\t\t\tthis.joinSession(selfClientId, alternateProvider);\n\t\t}\n\t}\n\n\tpublic onDisconnected(): void {\n\t\tdelete this.reasonForCompleteSnapshot;\n\t\tthis.stopWaitingForSelfInAudience?.();\n\t\tthis.stopWaitingForSelfInAudience = undefined;\n\t}\n\n\tpublic getWorkspace<TSchema extends StatesWorkspaceSchema>(\n\t\tinternalWorkspaceAddress: InternalWorkspaceAddress,\n\t\trequestedContent: TSchema,\n\t\tcontrols?: BroadcastControlSettings,\n\t): AnyWorkspace<TSchema> {\n\t\tconst existing = this.workspaces.get(internalWorkspaceAddress);\n\t\tif (existing) {\n\t\t\treturn existing.internal.ensureContent(requestedContent, controls);\n\t\t}\n\n\t\tlet workspaceDatastore: ValueElementMap<StatesWorkspaceSchema> | undefined =\n\t\t\tthis.datastore[internalWorkspaceAddress];\n\t\tif (workspaceDatastore === undefined) {\n\t\t\tworkspaceDatastore = this.datastore[internalWorkspaceAddress] = {};\n\t\t}\n\n\t\tconst localUpdate = (\n\t\t\tstates: { [key: string]: ClientUpdateEntry },\n\t\t\toptions: RuntimeLocalUpdateOptions,\n\t\t): void => {\n\t\t\t// Check for connectivity before sending updates.\n\t\t\tif (this.runtime.getJoinedStatus() === \"disconnected\") {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst updates: GeneralDatastoreMessageContent[InternalWorkspaceAddress] = {};\n\t\t\tfor (const [key, value] of Object.entries(states)) {\n\t\t\t\tupdates[key] = { [this.attendeeId]: value };\n\t\t\t}\n\n\t\t\tthis.enqueueMessage(\n\t\t\t\t{\n\t\t\t\t\t[internalWorkspaceAddress]: updates,\n\t\t\t\t},\n\t\t\t\toptions,\n\t\t\t);\n\t\t};\n\n\t\tconst entry = createPresenceStates(\n\t\t\t{\n\t\t\t\tpresence: this.presence,\n\t\t\t\tattendeeId: this.attendeeId,\n\t\t\t\tlocalUpdate,\n\t\t\t},\n\t\t\tworkspaceDatastore,\n\t\t\trequestedContent,\n\t\t\tcontrols,\n\t\t);\n\n\t\tthis.workspaces.set(internalWorkspaceAddress, entry);\n\t\treturn entry.public;\n\t}\n\n\t/**\n\t * The combined contents of all queued updates. Will be `\"sendAll\"` when a\n\t * full broadcast is pending or `undefined` when no messages are queued.\n\t */\n\tprivate queuedData: GeneralDatastoreMessageContent | \"sendAll\" | undefined;\n\n\t/**\n\t * Enqueues a new message to be sent. The message may be queued or may be sent immediately depending on the state of\n\t * the send timer, other messages in the queue, the configured allowed latency, etc.\n\t */\n\tprivate enqueueMessage(\n\t\tdata: GeneralDatastoreMessageContent | \"sendAll\",\n\t\toptions: RuntimeLocalUpdateOptions,\n\t): void {\n\t\tif (this.queuedData !== \"sendAll\") {\n\t\t\tthis.queuedData =\n\t\t\t\tdata === \"sendAll\"\n\t\t\t\t\t? \"sendAll\"\n\t\t\t\t\t: // Merging the message with any queued messages effectively queues the message.\n\t\t\t\t\t\t// It is OK to queue all incoming messages as long as when we send, we send the queued data.\n\t\t\t\t\t\tmergeGeneralDatastoreMessageContent(this.queuedData, data);\n\t\t}\n\n\t\tconst { allowableUpdateLatencyMs } = options;\n\t\tconst now = Date.now();\n\t\tconst thisMessageDeadline = now + allowableUpdateLatencyMs;\n\n\t\tif (\n\t\t\t// If the timer has not expired, we can short-circuit because the timer will fire\n\t\t\t// and cover this update. In other words, queuing this will be fast enough to\n\t\t\t// meet its deadline, because a timer is already scheduled to fire before its deadline.\n\t\t\t!this.sendMessageTimer.hasExpired() &&\n\t\t\t// If the deadline for this message is later than the overall send deadline, then\n\t\t\t// we can exit early since a timer will take care of sending it.\n\t\t\tthisMessageDeadline >= this.sendMessageTimer.expireTime\n\t\t) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Either we need to send this message immediately, or we need to schedule a timer\n\t\t// to fire at the send deadline that will take care of it.\n\n\t\t// Note that timeoutInMs === allowableUpdateLatencyMs, but the calculation is done this way for clarity.\n\t\tconst timeoutInMs = thisMessageDeadline - now;\n\t\tconst scheduleForLater = timeoutInMs > 0;\n\n\t\tif (scheduleForLater) {\n\t\t\t// Schedule the queued messages to be sent at the updateDeadline\n\t\t\tthis.sendMessageTimer.setTimeout(this.sendQueuedMessage.bind(this), timeoutInMs);\n\t\t} else {\n\t\t\tthis.sendQueuedMessage();\n\t\t}\n\t}\n\n\t/**\n\t * Send any queued signal immediately. Does nothing if no message is queued.\n\t */\n\tprivate sendQueuedMessage(): void {\n\t\tthis.sendMessageTimer.clearTimeout();\n\n\t\tif (this.queuedData === undefined) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Check for connectivity before sending updates.\n\t\tif (this.runtime.getJoinedStatus() === \"disconnected\") {\n\t\t\t// Clear the queued data since we're disconnected. We don't want messages\n\t\t\t// to queue infinitely while disconnected.\n\t\t\tthis.queuedData = undefined;\n\t\t\treturn;\n\t\t}\n\n\t\tif (this.queuedData === \"sendAll\") {\n\t\t\tthis.broadcastAllKnownState();\n\t\t\treturn;\n\t\t}\n\n\t\tconst clientConnectionId = this.runtime.getClientId();\n\t\tassert(clientConnectionId !== undefined, 0xa59 /* Client connected without clientId */);\n\t\tconst currentClientToSessionValueState =\n\t\t\t// When connected, `clientToSessionId` must always have current connection entry.\n\t\t\tthis.datastore[\"system:presence\"].clientToSessionId[clientConnectionId];\n\t\tassert(currentClientToSessionValueState !== undefined, \"Client connection update missing\");\n\n\t\tconst newMessage = {\n\t\t\tsendTimestamp: Date.now(),\n\t\t\tavgLatency: this.averageLatency,\n\t\t\t// isComplete: false,\n\t\t\tdata: {\n\t\t\t\t// Always send current connection mapping for some resiliency against\n\t\t\t\t// lost signals. This ensures that client session id found in `updates`\n\t\t\t\t// (which is this client's client session id) is always represented in\n\t\t\t\t// system workspace of recipient clients.\n\t\t\t\t\"system:presence\": {\n\t\t\t\t\tclientToSessionId: {\n\t\t\t\t\t\t[clientConnectionId]: { ...currentClientToSessionValueState },\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t...this.queuedData,\n\t\t\t},\n\t\t} satisfies OutboundDatastoreUpdateMessage[\"content\"];\n\t\tthis.queuedData = undefined;\n\t\tthis.runtime.submitSignal({ type: datastoreUpdateMessageType, content: newMessage });\n\t}\n\n\t/**\n\t * Recursively strips validation metadata (validatedValue) from datastore before broadcasting.\n\t * This ensures that validation metadata doesn't leak into signals sent to other clients.\n\t */\n\tprivate stripValidationMetadata(datastore: PresenceDatastore): DatastoreMessageContent {\n\t\tconst messageContent: DatastoreMessageContent = {\n\t\t\t[\"system:presence\"]: datastore[\"system:presence\"],\n\t\t};\n\n\t\tfor (const [workspaceAddress, workspace] of objectEntries(datastore)) {\n\t\t\t// System workspace has no validation metadata and is already\n\t\t\t// set in messageContent; so, it can be skipped.\n\t\t\tif (workspaceAddress === \"system:presence\") continue;\n\n\t\t\tconst workspaceData: GeneralDatastoreMessageContent[typeof workspaceAddress] = {};\n\n\t\t\tfor (const [stateName, clientRecord] of objectEntries(workspace)) {\n\t\t\t\tconst cleanClientRecord: GeneralDatastoreMessageContent[typeof workspaceAddress][typeof stateName] =\n\t\t\t\t\t{};\n\n\t\t\t\tfor (const [attendeeId, valueData] of objectEntries(clientRecord)) {\n\t\t\t\t\tcleanClientRecord[attendeeId] = this.stripValidationFromValueData(valueData);\n\t\t\t\t}\n\n\t\t\t\tworkspaceData[stateName] = cleanClientRecord;\n\t\t\t}\n\n\t\t\tmessageContent[workspaceAddress] = workspaceData;\n\t\t}\n\n\t\treturn messageContent;\n\t}\n\n\t/**\n\t * Strips validation metadata from individual value data entries.\n\t */\n\tprivate stripValidationFromValueData<\n\t\tT extends\n\t\t\t| InternalTypes.ValueDirectory<unknown>\n\t\t\t| InternalTypes.ValueRequiredState<unknown>\n\t\t\t| InternalTypes.ValueOptionalState<unknown>,\n\t>(valueDataIn: ValidatableValueStructure<T>): T {\n\t\t// Clone the input object since we may mutate it\n\t\tconst valueData = { ...valueDataIn };\n\n\t\t// Handle directory structures (with \"items\" property)\n\t\tif (isValueDirectory(valueData)) {\n\t\t\tfor (const [key, item] of Object.entries(valueData.items)) {\n\t\t\t\tvalueData.items[key] = this.stripValidationFromValueData(item);\n\t\t\t}\n\n\t\t\t// This `satisfies` test is rather weak while ValidatableValueDirectory\n\t\t\t// only has optional properties over InternalTypes.ValueDirectory and\n\t\t\t// thus readily does satisfy. If `validatedValue?: never` is uncommented\n\t\t\t// in Value*State then this will fail.\n\t\t\tvalueData satisfies InternalTypes.ValueDirectory<unknown>;\n\t\t\treturn valueData as T;\n\t\t}\n\n\t\tdelete valueData.validatedValue;\n\t\t// This `satisfies` test is rather weak while Validatable*State\n\t\t// only has optional properties over InternalTypes.Value*State and\n\t\t// thus readily does satisfy. If `validatedValue?: never` is uncommented\n\t\t// in Value*State then this will fail.\n\t\tvalueData satisfies\n\t\t\t| InternalTypes.ValueRequiredState<unknown>\n\t\t\t| InternalTypes.ValueOptionalState<unknown>;\n\t\treturn valueData as T;\n\t}\n\n\tprivate broadcastAllKnownState(): void {\n\t\tconst content: OutboundDatastoreUpdateMessage[\"content\"] = {\n\t\t\tsendTimestamp: Date.now(),\n\t\t\tavgLatency: this.averageLatency,\n\t\t\tisComplete: true,\n\t\t\tdata: this.stripValidationMetadata(this.datastore),\n\t\t};\n\n\t\tconst primaryRequestors: ClientConnectionId[] = [];\n\t\tconst secondaryRequestors: [ClientConnectionId, number][] = [];\n\t\tif (this.broadcastRequests.size > 0) {\n\t\t\tcontent.joinResponseFor = [...this.broadcastRequests.keys()];\n\t\t\tif (this.logger) {\n\t\t\t\t// Build telemetry data\n\t\t\t\tfor (const [requestor, { responseOrder }] of this.broadcastRequests.entries()) {\n\t\t\t\t\tif (responseOrder === undefined) {\n\t\t\t\t\t\tprimaryRequestors.push(requestor);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tsecondaryRequestors.push([requestor, responseOrder]);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis.broadcastRequests.clear();\n\t\t}\n\n\t\t// This broadcast will satisfy all requests; clear any remaining timer.\n\t\tthis.broadcastRequestsTimer.clearTimeout();\n\t\tthis.sendMessageTimer.clearTimeout();\n\n\t\tthis.runtime.submitSignal({\n\t\t\ttype: datastoreUpdateMessageType,\n\t\t\tcontent,\n\t\t});\n\t\tif (content.joinResponseFor) {\n\t\t\tthis.logger?.sendTelemetryEvent({\n\t\t\t\teventName: \"JoinResponse\",\n\t\t\t\tdetails: {\n\t\t\t\t\ttype: \"broadcastAll\",\n\t\t\t\t\tattendeeId: this.attendeeId,\n\t\t\t\t\tconnectionId: this.runtime.getClientId(),\n\t\t\t\t\tprimaryResponses: JSON.stringify(primaryRequestors),\n\t\t\t\t\tsecondaryResponses: JSON.stringify(secondaryRequestors),\n\t\t\t\t},\n\t\t\t});\n\t\t}\n\n\t\t// Sending all must account for anything queued before.\n\t\tthis.queuedData = undefined;\n\t}\n\n\tpublic processSignal(\n\t\tmessage: InboundExtensionMessage<SignalMessages>,\n\t\tlocal: boolean,\n\t\toptional: boolean,\n\t): void {\n\t\tconst received = Date.now();\n\t\tassert(message.clientId !== null, 0xa3a /* Map received signal without clientId */);\n\t\tif (!isPresenceMessage(message)) {\n\t\t\tassert(optional, \"Unrecognized message type in critical message\");\n\t\t\treturn;\n\t\t}\n\n\t\tif (local) {\n\t\t\tconst deliveryDelta = received - message.content.sendTimestamp;\n\t\t\t// Limit returnedMessages count to 256 such that newest message\n\t\t\t// always contributes at least 1/256th to the average. Older\n\t\t\t// messages have more weight, but that diminishes as new messages\n\t\t\t// contribute.\n\t\t\tthis.returnedMessages = Math.min(this.returnedMessages + 1, 256);\n\t\t\tthis.averageLatency =\n\t\t\t\t(this.averageLatency * (this.returnedMessages - 1) + deliveryDelta) /\n\t\t\t\tthis.returnedMessages;\n\t\t\treturn;\n\t\t}\n\n\t\tconst selfClientId = this.runtime.getClientId();\n\t\tassert(selfClientId !== undefined, \"Received signal without clientId\");\n\n\t\t// Check for undesired case of receiving a remote presence signal\n\t\t// without having been alerted to self audience join. (Perhaps join\n\t\t// signal was dropped.)\n\t\t// In practice it is commonly observed that local signals can be\n\t\t// returned ahead of audience join notification. So, it is reasonable\n\t\t// to expect that audience join notification may be delayed until after\n\t\t// other presence signals are received. One is enough to get things\n\t\t// rolling.\n\t\tif (this.stopWaitingForSelfInAudience !== undefined) {\n\t\t\tthis.stopWaitingAndJoin(selfClientId, /* alternateProvider */ message.clientId);\n\t\t}\n\n\t\tconst timeModifier =\n\t\t\treceived -\n\t\t\t(this.averageLatency + message.content.avgLatency + message.content.sendTimestamp);\n\n\t\tconst postUpdateActions: PostUpdateAction[] = [];\n\n\t\tif (message.type === joinMessageType) {\n\t\t\t// It is possible for some signals to come in while client is not connected due\n\t\t\t// to how work is scheduled. If we are not connected, we can't respond to the\n\t\t\t// join request. We will make our own Join request once we are connected.\n\t\t\tif (this.runtime.getJoinedStatus() !== \"disconnected\") {\n\t\t\t\tthis.prepareJoinResponse(message.content.updateProviders, message.clientId);\n\t\t\t}\n\t\t\t// It is okay to continue processing the contained updates even if we are not\n\t\t\t// connected.\n\t\t} else {\n\t\t\t// Update join response requests that are now satisfied.\n\t\t\tconst joinResponseFor = message.content.joinResponseFor;\n\t\t\tif (joinResponseFor) {\n\t\t\t\tlet justGainedCompleteSnapshot = false;\n\t\t\t\tif (joinResponseFor.includes(selfClientId)) {\n\t\t\t\t\tif (this.reasonForCompleteSnapshot) {\n\t\t\t\t\t\tif (this.reasonForCompleteSnapshot === \"alone\") {\n\t\t\t\t\t\t\t// No response was expected. This might happen when\n\t\t\t\t\t\t\t// either cautionary ClientJoin signal is received\n\t\t\t\t\t\t\t// by audience member that was unknown.\n\t\t\t\t\t\t\tthis.logger?.sendTelemetryEvent({\n\t\t\t\t\t\t\t\teventName: \"JoinResponseWhenAlone\",\n\t\t\t\t\t\t\t\tdetails: {\n\t\t\t\t\t\t\t\t\tattendeeId: this.attendeeId,\n\t\t\t\t\t\t\t\t\tconnectionId: this.runtime.getClientId(),\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// If we are the intended recipient of the join response,\n\t\t\t\t\t\t// we can consider our knowledge complete and can respond\n\t\t\t\t\t\t// to others join requests.\n\t\t\t\t\t\tjustGainedCompleteSnapshot = true;\n\t\t\t\t\t}\n\t\t\t\t\tthis.reasonForCompleteSnapshot = \"join response\";\n\t\t\t\t}\n\t\t\t\tif (this.broadcastRequests.size > 0) {\n\t\t\t\t\tfor (const responseFor of joinResponseFor) {\n\t\t\t\t\t\tthis.broadcastRequests.delete(responseFor);\n\t\t\t\t\t}\n\t\t\t\t\tif (this.broadcastRequests.size === 0) {\n\t\t\t\t\t\t// If no more requests are pending, clear any timer.\n\t\t\t\t\t\tthis.broadcastRequestsTimer.clearTimeout();\n\t\t\t\t\t} else if (justGainedCompleteSnapshot) {\n\t\t\t\t\t\t// May or may not be time to respond to remaining requests.\n\t\t\t\t\t\t// Clear the timer and recheck after processing.\n\t\t\t\t\t\tthis.broadcastRequestsTimer.clearTimeout();\n\t\t\t\t\t\tpostUpdateActions.push(this.sendJoinResponseIfStillNeeded);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// If the message requests an acknowledgement, we will send a targeted acknowledgement message back to just the requestor.\n\t\t\tif (message.content.acknowledgementId !== undefined) {\n\t\t\t\tassert(\n\t\t\t\t\tthis.targetedSignalSupport,\n\t\t\t\t\t\"Acknowledgment message was requested while targeted signal capability is not supported\",\n\t\t\t\t);\n\t\t\t\tthis.runtime.submitSignal({\n\t\t\t\t\ttype: acknowledgementMessageType,\n\t\t\t\t\tcontent: { id: message.content.acknowledgementId },\n\t\t\t\t\ttargetClientId: message.clientId,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\t// Handle activation of unregistered workspaces before processing updates.\n\t\tfor (const [workspaceAddress] of objectEntries(message.content.data)) {\n\t\t\t// The first part of OR condition checks if workspace is already registered.\n\t\t\t// The second part checks if the workspace has already been seen before.\n\t\t\t// In either case we can skip emitting 'workspaceActivated' event.\n\t\t\tif (this.workspaces.has(workspaceAddress) || this.datastore[workspaceAddress]) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// Separate internal type prefix from public workspace address\n\t\t\tconst match = /^([^:]):([^:]+:.+)$/.exec(workspaceAddress) as\n\t\t\t\t| null\n\t\t\t\t| [string, string, WorkspaceAddress];\n\n\t\t\tif (match === null) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst prefix = match[1];\n\t\t\tconst publicWorkspaceAddress = match[2];\n\n\t\t\tconst internalWorkspaceType = internalWorkspaceTypes[prefix] ?? \"Unknown\";\n\n\t\t\tthis.events.emit(\"workspaceActivated\", publicWorkspaceAddress, internalWorkspaceType);\n\t\t}\n\n\t\t// While the system workspace is processed here too, it is declared as\n\t\t// conforming to the general schema. So drop its override.\n\t\tconst data = message.content.data as Omit<typeof message.content.data, \"system:presence\">;\n\t\tfor (const [workspaceAddress, remoteDatastore] of objectEntries(data)) {\n\t\t\t// Direct to the appropriate Presence Workspace, if present.\n\t\t\tconst workspace = this.workspaces.get(workspaceAddress);\n\t\t\tif (workspace) {\n\t\t\t\tpostUpdateActions.push(\n\t\t\t\t\t...workspace.internal.processUpdate(\n\t\t\t\t\t\treceived,\n\t\t\t\t\t\ttimeModifier,\n\t\t\t\t\t\tremoteDatastore,\n\t\t\t\t\t\tmessage.clientId,\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\t// All broadcast state is kept even if not currently registered, unless a value\n\t\t\t\t// notes itself to be ignored.\n\n\t\t\t\t// Ensure there is a datastore at this address and get it.\n\t\t\t\tconst workspaceDatastore = (this.datastore[workspaceAddress] ??= {});\n\t\t\t\tfor (const [key, remoteAllKnownState] of Object.entries(remoteDatastore)) {\n\t\t\t\t\tmergeUntrackedDatastore(key, remoteAllKnownState, workspaceDatastore, timeModifier);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tfor (const action of postUpdateActions) {\n\t\t\taction();\n\t\t}\n\t}\n\n\t/**\n\t * Broadcasts a join response (complete datastore update message)\n\t * if there is an outstanding join response request.\n\t */\n\tprivate readonly sendJoinResponseIfStillNeeded = (): void => {\n\t\t// Make sure we are currently connected and a broadcast is still needed.\n\t\t// If not connected, nothing we can do.\n\t\tif (this.runtime.getJoinedStatus() !== \"disconnected\" && this.broadcastRequests.size > 0) {\n\t\t\t// Confirm that of remaining requests, now is the time to respond.\n\t\t\tconst now = Date.now();\n\t\t\tlet minResponseTime = Number.POSITIVE_INFINITY;\n\t\t\tfor (const { deadlineTime } of this.broadcastRequests.values()) {\n\t\t\t\tminResponseTime = Math.min(minResponseTime, deadlineTime);\n\t\t\t}\n\t\t\tif (minResponseTime <= now) {\n\t\t\t\tif (this.reasonForCompleteSnapshot) {\n\t\t\t\t\tthis.broadcastAllKnownState();\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// No response needed yet - schedule a later attempt\n\t\t\t\tthis.broadcastRequestsTimer.setTimeout(\n\t\t\t\t\tthis.sendJoinResponseIfStillNeeded,\n\t\t\t\t\tminResponseTime - now,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t};\n\n\t/**\n\t * Handles responding to another client joining the session.\n\t *\n\t * @param updateProviders - list of client connection id's that requestor selected\n\t * to provide response\n\t * @param requestor - `requestor` is only used in telemetry. While it is the requestor's\n\t * client connection id, that is not most important. It is important that this is a\n\t * unique shared id across all clients that might respond as we want to monitor the\n\t * response patterns. The convenience of being client connection id will allow\n\t * correlation with other telemetry where it is often called just `clientId`.\n\t */\n\tprivate prepareJoinResponse(\n\t\tupdateProviders: ClientConnectionId[],\n\t\trequestor: ClientConnectionId,\n\t): void {\n\t\t// We must be connected to receive this message, so clientId should be defined.\n\t\t// If it isn't then, not really a problem; just won't be in provider or audience list.\n\t\t// eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n\t\tconst selfClientId = this.runtime.getClientId()!;\n\t\tlet joinResponseDelayMs = broadcastJoinResponseDelaysMs.namedResponder;\n\t\tlet relativeResponseOrder: number | undefined;\n\t\tif (!updateProviders.includes(selfClientId)) {\n\t\t\t// Schedule a broadcast to the new client after a delay only to send if\n\t\t\t// another broadcast satisfying the request hasn't been seen in the\n\t\t\t// meantime. The delay is based on the position in the quorum list. It\n\t\t\t// doesn't have to be a stable list across all clients. We need\n\t\t\t// something to provide suggested order to prevent a flood of broadcasts.\n\t\t\tconst quorumMembers = this.runtime.getQuorum().getMembers();\n\t\t\tconst self = quorumMembers.get(selfClientId);\n\t\t\tif (self) {\n\t\t\t\t// Compute order quorum join order (indicated by sequenceNumber)\n\t\t\t\trelativeResponseOrder = 0;\n\t\t\t\tfor (const { client, sequenceNumber } of quorumMembers.values()) {\n\t\t\t\t\tif (\n\t\t\t\t\t\tsequenceNumber < self.sequenceNumber &&\n\t\t\t\t\t\tclient.details.capabilities.interactive\n\t\t\t\t\t) {\n\t\t\t\t\t\trelativeResponseOrder++;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// Order past quorum members + arbitrary additional offset up to 10\n\t\t\t\tlet possibleQuorumRespondents = 0;\n\t\t\t\tfor (const { client } of quorumMembers.values()) {\n\t\t\t\t\tif (client.details.capabilities.interactive) {\n\t\t\t\t\t\tpossibleQuorumRespondents++;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\trelativeResponseOrder = possibleQuorumRespondents + Math.random() * 10;\n\t\t\t}\n\t\t\t// When not named to provide update, wait an additional amount\n\t\t\t// of time for those named or others to respond.\n\t\t\tjoinResponseDelayMs +=\n\t\t\t\tbroadcastJoinResponseDelaysMs.backupResponderIncrement *\n\t\t\t\t(3 * updateProviders.length + relativeResponseOrder);\n\t\t}\n\n\t\t// Add the requestor to the list of clients that will receive the broadcast.\n\t\tconst deadlineTime = Date.now() + joinResponseDelayMs;\n\t\tthis.broadcastRequests.set(requestor, {\n\t\t\tdeadlineTime,\n\t\t\tresponseOrder: relativeResponseOrder,\n\t\t});\n\n\t\tif (!this.reasonForCompleteSnapshot) {\n\t\t\t// Check if requestor count meets or exceeds count of other audience\n\t\t\t// members indicating that we effectively have a complete snapshot\n\t\t\t// (once the current message being processed is processed).\n\t\t\tconst { selfPresent, interactiveMembersExcludingSelf } =\n\t\t\t\tthis.getAudienceInformation(selfClientId);\n\t\t\tif (\n\t\t\t\t// Self-present check is done to help ensure that audience\n\t\t\t\t// information is accurate. If self is not present, audience\n\t\t\t\t// information might be incomplete.\n\t\t\t\tselfPresent &&\n\t\t\t\tthis.broadcastRequests.size >= interactiveMembersExcludingSelf.all.size\n\t\t\t) {\n\t\t\t\t// Note that no action is taken here specifically.\n\t\t\t\t// We want action to be queued so that it takes place after\n\t\t\t\t// current message is completely processed. All of the actions\n\t\t\t\t// below should be delayed (not immediate).\n\t\t\t\tthis.reasonForCompleteSnapshot = \"full requests\";\n\t\t\t}\n\t\t}\n\n\t\t// Check if capable of full primary response. If requested to provide\n\t\t// primary response, but do not yet have complete snapshot, we need to\n\t\t// delay a full response, until we think we have complete snapshot. In\n\t\t// the meantime we will send partial updates as usual.\n\t\tif (this.reasonForCompleteSnapshot && updateProviders.includes(selfClientId)) {\n\t\t\t// Use regular message queue to handle timing of the broadcast.\n\t\t\t// Any more immediate broadcasts will accelerate the response time.\n\t\t\t// As a primary responder, it is expected that broadcast will happen and\n\t\t\t// using the regular queue allows other updates to avoid merge work.\n\t\t\tthis.enqueueMessage(\"sendAll\", {\n\t\t\t\tallowableUpdateLatencyMs: joinResponseDelayMs,\n\t\t\t});\n\t\t} else {\n\t\t\t// Check if there isn't already a timer scheduled to send a join\n\t\t\t// response with in this request's deadline.\n\t\t\tif (\n\t\t\t\tthis.broadcastRequestsTimer.hasExpired() ||\n\t\t\t\tdeadlineTime < this.broadcastRequestsTimer.expireTime\n\t\t\t) {\n\t\t\t\t// Set or update the timer.\n\t\t\t\tthis.broadcastRequestsTimer.setTimeout(\n\t\t\t\t\tthis.sendJoinResponseIfStillNeeded,\n\t\t\t\t\tjoinResponseDelayMs,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n}\n"]}
|
package/lib/packageVersion.d.ts
CHANGED
|
@@ -5,5 +5,5 @@
|
|
|
5
5
|
* THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY
|
|
6
6
|
*/
|
|
7
7
|
export declare const pkgName = "@fluidframework/presence";
|
|
8
|
-
export declare const pkgVersion = "2.
|
|
8
|
+
export declare const pkgVersion = "2.74.0-365691";
|
|
9
9
|
//# sourceMappingURL=packageVersion.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"packageVersion.d.ts","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,eAAO,MAAM,OAAO,6BAA6B,CAAC;AAClD,eAAO,MAAM,UAAU,
|
|
1
|
+
{"version":3,"file":"packageVersion.d.ts","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,eAAO,MAAM,OAAO,6BAA6B,CAAC;AAClD,eAAO,MAAM,UAAU,kBAAkB,CAAC"}
|
package/lib/packageVersion.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"packageVersion.js","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,CAAC,MAAM,OAAO,GAAG,0BAA0B,CAAC;AAClD,MAAM,CAAC,MAAM,UAAU,GAAG,
|
|
1
|
+
{"version":3,"file":"packageVersion.js","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,CAAC,MAAM,OAAO,GAAG,0BAA0B,CAAC;AAClD,MAAM,CAAC,MAAM,UAAU,GAAG,eAAe,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n *\n * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY\n */\n\nexport const pkgName = \"@fluidframework/presence\";\nexport const pkgVersion = \"2.74.0-365691\";\n"]}
|
|
@@ -584,7 +584,7 @@ export class PresenceDatastoreManagerImpl {
|
|
|
584
584
|
continue;
|
|
585
585
|
}
|
|
586
586
|
// Separate internal type prefix from public workspace address
|
|
587
|
-
const match =
|
|
587
|
+
const match = /^([^:]):([^:]+:.+)$/.exec(workspaceAddress);
|
|
588
588
|
if (match === null) {
|
|
589
589
|
continue;
|
|
590
590
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"presenceDatastoreManager.js","sourceRoot":"","sources":["../src/presenceDatastoreManager.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 type { IAudience } from \"@fluidframework/container-definitions\";\nimport type { InboundExtensionMessage } from \"@fluidframework/container-runtime-definitions/internal\";\nimport type { IEmitter } from \"@fluidframework/core-interfaces/internal\";\nimport { assert } from \"@fluidframework/core-utils/internal\";\nimport type { ITelemetryLoggerExt } from \"@fluidframework/telemetry-utils/internal\";\n\nimport type { ClientConnectionId } from \"./baseTypes.js\";\nimport type { BroadcastControlSettings } from \"./broadcastControls.js\";\nimport type { InternalTypes } from \"./exposedInternalTypes.js\";\nimport type {\n\tIEphemeralRuntime,\n\tPostUpdateAction,\n\tValidatableOptionalState,\n\tValidatableValueDirectory,\n\tValidatableValueStructure,\n} from \"./internalTypes.js\";\nimport { objectEntries } from \"./internalUtils.js\";\nimport type {\n\tAttendeeId,\n\tPresenceWithNotifications as Presence,\n\tPresenceEvents,\n} from \"./presence.js\";\nimport type {\n\tClientUpdateEntry,\n\tRuntimeLocalUpdateOptions,\n\tPresenceStatesInternal,\n\tValueElementMap,\n} from \"./presenceStates.js\";\nimport {\n\tcreatePresenceStates,\n\tmergeUntrackedDatastore,\n\tmergeValueDirectory,\n} from \"./presenceStates.js\";\nimport type {\n\tDatastoreMessageContent,\n\tGeneralDatastoreMessageContent,\n\tInboundClientJoinMessage,\n\tInboundDatastoreUpdateMessage,\n\tInternalWorkspaceAddress,\n\tOutboundDatastoreUpdateMessage,\n\tSignalMessages,\n\tSystemDatastore,\n} from \"./protocol.js\";\nimport {\n\tacknowledgementMessageType,\n\tdatastoreUpdateMessageType,\n\tjoinMessageType,\n} from \"./protocol.js\";\nimport type { SystemWorkspaceDatastore } from \"./systemWorkspace.js\";\nimport { TimerManager } from \"./timerManager.js\";\nimport type {\n\tAnyWorkspace,\n\tNotificationsWorkspace,\n\tNotificationsWorkspaceSchema,\n\tStatesWorkspace,\n\tStatesWorkspaceSchema,\n\tWorkspaceAddress,\n} from \"./types.js\";\n\ninterface AnyWorkspaceEntry<TSchema extends StatesWorkspaceSchema> {\n\tpublic: AnyWorkspace<TSchema>;\n\tinternal: PresenceStatesInternal;\n}\n\n/**\n * Datastore structure used for broadcasting to other clients.\n * Validation metadata is stripped before transmission.\n */\ntype PresenceDatastore = SystemDatastore & {\n\t[WorkspaceAddress: InternalWorkspaceAddress]: ValueElementMap<StatesWorkspaceSchema>;\n};\n\nconst internalWorkspaceTypes: Readonly<Record<string, \"States\" | \"Notifications\">> = {\n\ts: \"States\",\n\tn: \"Notifications\",\n} as const;\n\nconst knownMessageTypes = new Set([\n\tjoinMessageType,\n\tdatastoreUpdateMessageType,\n\tacknowledgementMessageType,\n]);\nfunction isPresenceMessage(\n\tmessage: InboundExtensionMessage<SignalMessages>,\n): message is InboundDatastoreUpdateMessage | InboundClientJoinMessage {\n\treturn knownMessageTypes.has(message.type);\n}\n\n/**\n * Type guard to check if a value hierarchy object is a directory (has \"items\"\n * property).\n *\n * @param obj - The object to check\n * @returns True if the object is a {@link ValidatableValueDirectory}\n */\nexport function isValueDirectory<T>(\n\tobj: ValidatableValueDirectory<T> | ValidatableOptionalState<T>,\n): obj is ValidatableValueDirectory<T> {\n\treturn \"items\" in obj;\n}\n\n/**\n * High-level contract for manager of singleton Presence datastore\n */\nexport interface PresenceDatastoreManager {\n\tjoinSession(clientId: ClientConnectionId): void;\n\tonDisconnected(): void;\n\tgetWorkspace<TSchema extends StatesWorkspaceSchema>(\n\t\tinternalWorkspaceAddress: `s:${WorkspaceAddress}`,\n\t\trequestedContent: TSchema,\n\t\tcontrols?: BroadcastControlSettings,\n\t): StatesWorkspace<TSchema>;\n\tgetWorkspace<TSchema extends NotificationsWorkspaceSchema>(\n\t\tinternalWorkspaceAddress: `n:${WorkspaceAddress}`,\n\t\trequestedContent: TSchema,\n\t): NotificationsWorkspace<TSchema>;\n\tprocessSignal(\n\t\tmessage: InboundExtensionMessage<SignalMessages>,\n\t\tlocal: boolean,\n\t\toptional: boolean,\n\t): void;\n}\n\nfunction mergeGeneralDatastoreMessageContent(\n\tbase: GeneralDatastoreMessageContent | undefined,\n\tnewData: GeneralDatastoreMessageContent,\n): GeneralDatastoreMessageContent {\n\t// This function-local \"datastore\" will hold the merged message data.\n\tconst queueDatastore = base ?? {};\n\n\t// Merge the current data with the existing data, if any exists.\n\t// Iterate over the current message data; individual items are workspaces.\n\tfor (const [workspaceName, workspaceData] of objectEntries(newData)) {\n\t\t// Initialize the merged data as the queued datastore entry for the workspace.\n\t\t// Since the key might not exist, create an empty object in that case. It will\n\t\t// be set explicitly after the loop.\n\t\tconst mergedData = queueDatastore[workspaceName] ?? {};\n\n\t\t// Iterate over each value manager and its data, merging it as needed.\n\t\tfor (const [valueManagerKey, valueManagerValue] of objectEntries(workspaceData)) {\n\t\t\tfor (const [attendeeId, value] of objectEntries(valueManagerValue)) {\n\t\t\t\tconst mergeObject = (mergedData[valueManagerKey] ??= {});\n\t\t\t\tconst oldData = mergeObject[attendeeId];\n\t\t\t\tmergeObject[attendeeId] = mergeValueDirectory(\n\t\t\t\t\toldData,\n\t\t\t\t\tvalue,\n\t\t\t\t\t0, // local values do not need a time shift\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\t// Store the merged data in the function-local queue workspace. The whole contents of this\n\t\t// datastore will be sent as the message data.\n\t\tqueueDatastore[workspaceName] = mergedData;\n\t}\n\treturn queueDatastore;\n}\n\n/**\n * Delays used for broadcasting join responses to clients.\n *\n * @remarks\n * Exported for test coordination.\n * These could be made customizable in the future to accommodate different\n * session configurations.\n */\nexport const broadcastJoinResponseDelaysMs = {\n\t/**\n\t * The delay in milliseconds before a join response is sent to any client.\n\t * This is used to accumulate other join response requests and reduce\n\t * network traffic.\n\t */\n\tnamedResponder: 200,\n\t/**\n\t * The additional delay in milliseconds a backup responder waits before sending\n\t * a join response to allow others to respond first.\n\t */\n\tbackupResponderIncrement: 40,\n} as const;\n\n/**\n * Manages singleton datastore for all Presence.\n */\nexport class PresenceDatastoreManagerImpl implements PresenceDatastoreManager {\n\tprivate readonly datastore: PresenceDatastore;\n\tprivate averageLatency = 0;\n\tprivate returnedMessages = 0;\n\tprivate readonly sendMessageTimer = new TimerManager();\n\tprivate readonly workspaces = new Map<string, AnyWorkspaceEntry<StatesWorkspaceSchema>>();\n\tprivate readonly targetedSignalSupport: boolean;\n\n\t/**\n\t * When defined, this client is not recognized in the session.\n\t * Call when no longer caring about that condition. That way listeners are\n\t * cleaned up.\n\t */\n\tprivate stopWaitingForSelfInAudience: undefined | (() => void);\n\n\t/**\n\t * Tracks whether this client has complete snapshot level knowledge and\n\t * how that determination was reached.\n\t * - \"alone\": no other audience members detected at join\n\t * - \"join response\": another client has responded to our join request\n\t * - \"full requests\": all others have requested response from us\n\t *\n\t * @remarks\n\t * Only applies when not using targeted join responses.\n\t *\n\t * Without a complete snapshot, we cannot fully onboard any other clients.\n\t * One exception to this is if this client is the only participant in the\n\t * session. In such a case, there is no one to respond to the join request.\n\t * Another exception is multiple clients attempting to join at the same\n\t * time and thus expecting that someone has full knowledge, yet none have\n\t * received a complete update to think they are qualified to respond.\n\t * Generically if the number of outstanding requestors meets or exceeds the\n\t * count of other audience members, then we can consider the snapshot\n\t * complete (as all will have provided their own complete information in\n\t * their join responses).\n\t */\n\tprivate reasonForCompleteSnapshot?: \"alone\" | \"join response\" | \"full requests\";\n\n\t/**\n\t * Map of outstanding broadcast (join response) requests.\n\t */\n\tprivate readonly broadcastRequests = new Map<\n\t\tClientConnectionId,\n\t\t{ deadlineTime: number; responseOrder?: number | undefined }\n\t>();\n\t/**\n\t * Timer for managing broadcast (join response) request timing.\n\t */\n\tprivate readonly broadcastRequestsTimer = new TimerManager();\n\n\tpublic constructor(\n\t\tprivate readonly attendeeId: AttendeeId,\n\t\tprivate readonly runtime: IEphemeralRuntime,\n\t\tprivate readonly logger: ITelemetryLoggerExt | undefined,\n\t\tprivate readonly events: IEmitter<PresenceEvents>,\n\t\tprivate readonly presence: Presence,\n\t\tsystemWorkspaceDatastore: SystemWorkspaceDatastore,\n\t\tsystemWorkspace: AnyWorkspaceEntry<StatesWorkspaceSchema>,\n\t) {\n\t\t// eslint-disable-next-line @typescript-eslint/consistent-type-assertions\n\t\tthis.datastore = { \"system:presence\": systemWorkspaceDatastore } as PresenceDatastore;\n\t\tthis.workspaces.set(\"system:presence\", systemWorkspace);\n\t\tthis.targetedSignalSupport = this.runtime.supportedFeatures.has(\"submit_signals_v2\");\n\t\t// If audience member is removed, they won't need a broadcast response.\n\t\tthis.runtime.getAudience().on(\"removeMember\", (clientId) => {\n\t\t\tthis.broadcastRequests.delete(clientId);\n\t\t});\n\t}\n\n\tprivate getAudienceInformation(selfClientId: ClientConnectionId): {\n\t\taudience: IAudience;\n\t\tselfPresent: boolean;\n\t\tinteractiveMembersExcludingSelf: {\n\t\t\tall: Set<ClientConnectionId>;\n\t\t\twriters: Set<ClientConnectionId>;\n\t\t};\n\t} {\n\t\tconst audience = this.runtime.getAudience();\n\t\tconst members = audience.getMembers();\n\t\tconst all = new Set<ClientConnectionId>();\n\t\tconst writers = new Set<ClientConnectionId>();\n\t\tconst selfPresent = members.has(selfClientId);\n\t\tif (selfPresent) {\n\t\t\t// Remove self\n\t\t\tmembers.delete(selfClientId);\n\t\t}\n\t\t// Gather interactive client IDs\n\t\tfor (const [id, client] of members) {\n\t\t\tif (client.details.capabilities.interactive) {\n\t\t\t\tall.add(id);\n\t\t\t\tif (client.mode === \"write\") {\n\t\t\t\t\twriters.add(id);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn {\n\t\t\taudience,\n\t\t\tselfPresent,\n\t\t\tinteractiveMembersExcludingSelf: {\n\t\t\t\tall,\n\t\t\t\twriters,\n\t\t\t},\n\t\t};\n\t}\n\n\tpublic joinSession(\n\t\tselfClientId: ClientConnectionId,\n\t\talternateProvider: ClientConnectionId | undefined = undefined,\n\t): void {\n\t\t// Before broadcasting the join message, check that there is at least\n\t\t// one audience member present (self or another). This is useful to\n\t\t// optimize join messages while not using targeted join responses.\n\t\t// (We need at least one other to be able to elect them as update\n\t\t// provider.)\n\t\t// Lack of anyone likely means that this client is very freshly joined\n\t\t// and has not received any Join Signals (type=\"join\") from the service\n\t\t// yet.\n\t\tconst { audience, selfPresent, interactiveMembersExcludingSelf } =\n\t\t\tthis.getAudienceInformation(selfClientId);\n\n\t\tif (interactiveMembersExcludingSelf.all.size === 0 && alternateProvider !== undefined) {\n\t\t\tif (selfPresent) {\n\t\t\t\t// If there aren't any members connected except self, then this client\n\t\t\t\t// must have complete information.\n\t\t\t\tthis.reasonForCompleteSnapshot = \"alone\";\n\t\t\t\t// It would be possible to return at this time and skip ClientJoin\n\t\t\t\t// signal. Instead continue in case audience information is\n\t\t\t\t// inaccurate. This client might temporarily erroneously believe it\n\t\t\t\t// has complete information, but the other(s) should respond to\n\t\t\t\t// ClientJoin soon rectifying that and covering for bad incomplete\n\t\t\t\t// responses this client sent in the meantime.\n\t\t\t} else {\n\t\t\t\t// No one is known. Not even self. Defer judgement on\n\t\t\t\t// complete snapshot until at least self is known to be present.\n\t\t\t\tthis.listenForSelfInAudience(selfClientId, audience);\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\n\t\t// Broadcast join message to all clients\n\t\t// Select primary update providers\n\t\t// Use write members if any, then fallback to read-only members.\n\t\tconst updateProviders = [\n\t\t\t...(interactiveMembersExcludingSelf.writers.size > 0\n\t\t\t\t? interactiveMembersExcludingSelf.writers\n\t\t\t\t: interactiveMembersExcludingSelf.all),\n\t\t];\n\t\t// Limit to three providers to prevent flooding the network.\n\t\t// If none respond, others present will (should) after a delay.\n\t\tif (updateProviders.length > 3) {\n\t\t\tupdateProviders.length = 3;\n\t\t} else if (updateProviders.length === 0 && alternateProvider !== undefined) {\n\t\t\tupdateProviders.push(alternateProvider);\n\t\t}\n\t\tthis.runtime.submitSignal({\n\t\t\ttype: joinMessageType,\n\t\t\tcontent: {\n\t\t\t\tsendTimestamp: Date.now(),\n\t\t\t\tavgLatency: this.averageLatency,\n\t\t\t\tdata: this.stripValidationMetadata(this.datastore),\n\t\t\t\tupdateProviders,\n\t\t\t},\n\t\t});\n\t\tthis.logger?.sendTelemetryEvent({\n\t\t\teventName: \"JoinRequested\",\n\t\t\tdetails: {\n\t\t\t\tattendeeId: this.attendeeId,\n\t\t\t\tconnectionId: selfClientId,\n\t\t\t\t// Empty updateProviders is indicative of join when alone.\n\t\t\t\tupdateProviders: JSON.stringify(updateProviders),\n\t\t\t\t// If false and providers is single entry, then join was probably forced.\n\t\t\t\tselfPresent,\n\t\t\t},\n\t\t});\n\t}\n\n\tprivate listenForSelfInAudience(selfClientId: string, audience: IAudience): void {\n\t\tthis.logger?.sendTelemetryEvent({\n\t\t\teventName: \"JoinDeferred\",\n\t\t\tdetails: {\n\t\t\t\tattendeeId: this.attendeeId,\n\t\t\t\tconnectionId: selfClientId,\n\t\t\t},\n\t\t});\n\t\t// Prepare to join once self audience member joins.\n\t\t// Alternatively, processSignal may force a join when a presence\n\t\t// signal is received even without audience members (assumes\n\t\t// audience signals were lost).\n\t\tconst joinWhenSelfAudienceMemberAdded = (addedClientId: ClientConnectionId): void => {\n\t\t\tif (addedClientId !== selfClientId) {\n\t\t\t\t// Keep listening\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// No need to force here by providing alternate provider as self is\n\t\t\t// now present.\n\t\t\t// Do avoid forcing so that reasonForCompleteSnapshot is set correctly\n\t\t\t// if no others have been added.\n\t\t\tthis.stopWaitingAndJoin(selfClientId, /* alternateProvider */ undefined);\n\t\t};\n\t\taudience.on(\"addMember\", joinWhenSelfAudienceMemberAdded);\n\t\tthis.stopWaitingForSelfInAudience = () => {\n\t\t\taudience.off(\"addMember\", joinWhenSelfAudienceMemberAdded);\n\t\t};\n\t}\n\n\tprivate stopWaitingAndJoin(\n\t\tselfClientId: ClientConnectionId,\n\t\talternateProvider: ClientConnectionId | undefined,\n\t): void {\n\t\tthis.stopWaitingForSelfInAudience?.();\n\t\tthis.stopWaitingForSelfInAudience = undefined;\n\t\t// Confirm not currently disconnected\n\t\tif (this.runtime.getJoinedStatus() !== \"disconnected\") {\n\t\t\tthis.joinSession(selfClientId, alternateProvider);\n\t\t}\n\t}\n\n\tpublic onDisconnected(): void {\n\t\tdelete this.reasonForCompleteSnapshot;\n\t\tthis.stopWaitingForSelfInAudience?.();\n\t\tthis.stopWaitingForSelfInAudience = undefined;\n\t}\n\n\tpublic getWorkspace<TSchema extends StatesWorkspaceSchema>(\n\t\tinternalWorkspaceAddress: InternalWorkspaceAddress,\n\t\trequestedContent: TSchema,\n\t\tcontrols?: BroadcastControlSettings,\n\t): AnyWorkspace<TSchema> {\n\t\tconst existing = this.workspaces.get(internalWorkspaceAddress);\n\t\tif (existing) {\n\t\t\treturn existing.internal.ensureContent(requestedContent, controls);\n\t\t}\n\n\t\tlet workspaceDatastore: ValueElementMap<StatesWorkspaceSchema> | undefined =\n\t\t\tthis.datastore[internalWorkspaceAddress];\n\t\tif (workspaceDatastore === undefined) {\n\t\t\tworkspaceDatastore = this.datastore[internalWorkspaceAddress] = {};\n\t\t}\n\n\t\tconst localUpdate = (\n\t\t\tstates: { [key: string]: ClientUpdateEntry },\n\t\t\toptions: RuntimeLocalUpdateOptions,\n\t\t): void => {\n\t\t\t// Check for connectivity before sending updates.\n\t\t\tif (this.runtime.getJoinedStatus() === \"disconnected\") {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst updates: GeneralDatastoreMessageContent[InternalWorkspaceAddress] = {};\n\t\t\tfor (const [key, value] of Object.entries(states)) {\n\t\t\t\tupdates[key] = { [this.attendeeId]: value };\n\t\t\t}\n\n\t\t\tthis.enqueueMessage(\n\t\t\t\t{\n\t\t\t\t\t[internalWorkspaceAddress]: updates,\n\t\t\t\t},\n\t\t\t\toptions,\n\t\t\t);\n\t\t};\n\n\t\tconst entry = createPresenceStates(\n\t\t\t{\n\t\t\t\tpresence: this.presence,\n\t\t\t\tattendeeId: this.attendeeId,\n\t\t\t\tlocalUpdate,\n\t\t\t},\n\t\t\tworkspaceDatastore,\n\t\t\trequestedContent,\n\t\t\tcontrols,\n\t\t);\n\n\t\tthis.workspaces.set(internalWorkspaceAddress, entry);\n\t\treturn entry.public;\n\t}\n\n\t/**\n\t * The combined contents of all queued updates. Will be `\"sendAll\"` when a\n\t * full broadcast is pending or `undefined` when no messages are queued.\n\t */\n\tprivate queuedData: GeneralDatastoreMessageContent | \"sendAll\" | undefined;\n\n\t/**\n\t * Enqueues a new message to be sent. The message may be queued or may be sent immediately depending on the state of\n\t * the send timer, other messages in the queue, the configured allowed latency, etc.\n\t */\n\tprivate enqueueMessage(\n\t\tdata: GeneralDatastoreMessageContent | \"sendAll\",\n\t\toptions: RuntimeLocalUpdateOptions,\n\t): void {\n\t\tif (this.queuedData !== \"sendAll\") {\n\t\t\tthis.queuedData =\n\t\t\t\tdata === \"sendAll\"\n\t\t\t\t\t? \"sendAll\"\n\t\t\t\t\t: // Merging the message with any queued messages effectively queues the message.\n\t\t\t\t\t\t// It is OK to queue all incoming messages as long as when we send, we send the queued data.\n\t\t\t\t\t\tmergeGeneralDatastoreMessageContent(this.queuedData, data);\n\t\t}\n\n\t\tconst { allowableUpdateLatencyMs } = options;\n\t\tconst now = Date.now();\n\t\tconst thisMessageDeadline = now + allowableUpdateLatencyMs;\n\n\t\tif (\n\t\t\t// If the timer has not expired, we can short-circuit because the timer will fire\n\t\t\t// and cover this update. In other words, queuing this will be fast enough to\n\t\t\t// meet its deadline, because a timer is already scheduled to fire before its deadline.\n\t\t\t!this.sendMessageTimer.hasExpired() &&\n\t\t\t// If the deadline for this message is later than the overall send deadline, then\n\t\t\t// we can exit early since a timer will take care of sending it.\n\t\t\tthisMessageDeadline >= this.sendMessageTimer.expireTime\n\t\t) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Either we need to send this message immediately, or we need to schedule a timer\n\t\t// to fire at the send deadline that will take care of it.\n\n\t\t// Note that timeoutInMs === allowableUpdateLatencyMs, but the calculation is done this way for clarity.\n\t\tconst timeoutInMs = thisMessageDeadline - now;\n\t\tconst scheduleForLater = timeoutInMs > 0;\n\n\t\tif (scheduleForLater) {\n\t\t\t// Schedule the queued messages to be sent at the updateDeadline\n\t\t\tthis.sendMessageTimer.setTimeout(this.sendQueuedMessage.bind(this), timeoutInMs);\n\t\t} else {\n\t\t\tthis.sendQueuedMessage();\n\t\t}\n\t}\n\n\t/**\n\t * Send any queued signal immediately. Does nothing if no message is queued.\n\t */\n\tprivate sendQueuedMessage(): void {\n\t\tthis.sendMessageTimer.clearTimeout();\n\n\t\tif (this.queuedData === undefined) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Check for connectivity before sending updates.\n\t\tif (this.runtime.getJoinedStatus() === \"disconnected\") {\n\t\t\t// Clear the queued data since we're disconnected. We don't want messages\n\t\t\t// to queue infinitely while disconnected.\n\t\t\tthis.queuedData = undefined;\n\t\t\treturn;\n\t\t}\n\n\t\tif (this.queuedData === \"sendAll\") {\n\t\t\tthis.broadcastAllKnownState();\n\t\t\treturn;\n\t\t}\n\n\t\tconst clientConnectionId = this.runtime.getClientId();\n\t\tassert(clientConnectionId !== undefined, 0xa59 /* Client connected without clientId */);\n\t\tconst currentClientToSessionValueState =\n\t\t\t// When connected, `clientToSessionId` must always have current connection entry.\n\t\t\tthis.datastore[\"system:presence\"].clientToSessionId[clientConnectionId];\n\t\tassert(currentClientToSessionValueState !== undefined, \"Client connection update missing\");\n\n\t\tconst newMessage = {\n\t\t\tsendTimestamp: Date.now(),\n\t\t\tavgLatency: this.averageLatency,\n\t\t\t// isComplete: false,\n\t\t\tdata: {\n\t\t\t\t// Always send current connection mapping for some resiliency against\n\t\t\t\t// lost signals. This ensures that client session id found in `updates`\n\t\t\t\t// (which is this client's client session id) is always represented in\n\t\t\t\t// system workspace of recipient clients.\n\t\t\t\t\"system:presence\": {\n\t\t\t\t\tclientToSessionId: {\n\t\t\t\t\t\t[clientConnectionId]: { ...currentClientToSessionValueState },\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t...this.queuedData,\n\t\t\t},\n\t\t} satisfies OutboundDatastoreUpdateMessage[\"content\"];\n\t\tthis.queuedData = undefined;\n\t\tthis.runtime.submitSignal({ type: datastoreUpdateMessageType, content: newMessage });\n\t}\n\n\t/**\n\t * Recursively strips validation metadata (validatedValue) from datastore before broadcasting.\n\t * This ensures that validation metadata doesn't leak into signals sent to other clients.\n\t */\n\tprivate stripValidationMetadata(datastore: PresenceDatastore): DatastoreMessageContent {\n\t\tconst messageContent: DatastoreMessageContent = {\n\t\t\t[\"system:presence\"]: datastore[\"system:presence\"],\n\t\t};\n\n\t\tfor (const [workspaceAddress, workspace] of objectEntries(datastore)) {\n\t\t\t// System workspace has no validation metadata and is already\n\t\t\t// set in messageContent; so, it can be skipped.\n\t\t\tif (workspaceAddress === \"system:presence\") continue;\n\n\t\t\tconst workspaceData: GeneralDatastoreMessageContent[typeof workspaceAddress] = {};\n\n\t\t\tfor (const [stateName, clientRecord] of objectEntries(workspace)) {\n\t\t\t\tconst cleanClientRecord: GeneralDatastoreMessageContent[typeof workspaceAddress][typeof stateName] =\n\t\t\t\t\t{};\n\n\t\t\t\tfor (const [attendeeId, valueData] of objectEntries(clientRecord)) {\n\t\t\t\t\tcleanClientRecord[attendeeId] = this.stripValidationFromValueData(valueData);\n\t\t\t\t}\n\n\t\t\t\tworkspaceData[stateName] = cleanClientRecord;\n\t\t\t}\n\n\t\t\tmessageContent[workspaceAddress] = workspaceData;\n\t\t}\n\n\t\treturn messageContent;\n\t}\n\n\t/**\n\t * Strips validation metadata from individual value data entries.\n\t */\n\tprivate stripValidationFromValueData<\n\t\tT extends\n\t\t\t| InternalTypes.ValueDirectory<unknown>\n\t\t\t| InternalTypes.ValueRequiredState<unknown>\n\t\t\t| InternalTypes.ValueOptionalState<unknown>,\n\t>(valueDataIn: ValidatableValueStructure<T>): T {\n\t\t// Clone the input object since we may mutate it\n\t\tconst valueData = { ...valueDataIn };\n\n\t\t// Handle directory structures (with \"items\" property)\n\t\tif (isValueDirectory(valueData)) {\n\t\t\tfor (const [key, item] of Object.entries(valueData.items)) {\n\t\t\t\tvalueData.items[key] = this.stripValidationFromValueData(item);\n\t\t\t}\n\n\t\t\t// This `satisfies` test is rather weak while ValidatableValueDirectory\n\t\t\t// only has optional properties over InternalTypes.ValueDirectory and\n\t\t\t// thus readily does satisfy. If `validatedValue?: never` is uncommented\n\t\t\t// in Value*State then this will fail.\n\t\t\tvalueData satisfies InternalTypes.ValueDirectory<unknown>;\n\t\t\treturn valueData as T;\n\t\t}\n\n\t\tdelete valueData.validatedValue;\n\t\t// This `satisfies` test is rather weak while Validatable*State\n\t\t// only has optional properties over InternalTypes.Value*State and\n\t\t// thus readily does satisfy. If `validatedValue?: never` is uncommented\n\t\t// in Value*State then this will fail.\n\t\tvalueData satisfies\n\t\t\t| InternalTypes.ValueRequiredState<unknown>\n\t\t\t| InternalTypes.ValueOptionalState<unknown>;\n\t\treturn valueData as T;\n\t}\n\n\tprivate broadcastAllKnownState(): void {\n\t\tconst content: OutboundDatastoreUpdateMessage[\"content\"] = {\n\t\t\tsendTimestamp: Date.now(),\n\t\t\tavgLatency: this.averageLatency,\n\t\t\tisComplete: true,\n\t\t\tdata: this.stripValidationMetadata(this.datastore),\n\t\t};\n\n\t\tconst primaryRequestors: ClientConnectionId[] = [];\n\t\tconst secondaryRequestors: [ClientConnectionId, number][] = [];\n\t\tif (this.broadcastRequests.size > 0) {\n\t\t\tcontent.joinResponseFor = [...this.broadcastRequests.keys()];\n\t\t\tif (this.logger) {\n\t\t\t\t// Build telemetry data\n\t\t\t\tfor (const [requestor, { responseOrder }] of this.broadcastRequests.entries()) {\n\t\t\t\t\tif (responseOrder === undefined) {\n\t\t\t\t\t\tprimaryRequestors.push(requestor);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tsecondaryRequestors.push([requestor, responseOrder]);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis.broadcastRequests.clear();\n\t\t}\n\n\t\t// This broadcast will satisfy all requests; clear any remaining timer.\n\t\tthis.broadcastRequestsTimer.clearTimeout();\n\t\tthis.sendMessageTimer.clearTimeout();\n\n\t\tthis.runtime.submitSignal({\n\t\t\ttype: datastoreUpdateMessageType,\n\t\t\tcontent,\n\t\t});\n\t\tif (content.joinResponseFor) {\n\t\t\tthis.logger?.sendTelemetryEvent({\n\t\t\t\teventName: \"JoinResponse\",\n\t\t\t\tdetails: {\n\t\t\t\t\ttype: \"broadcastAll\",\n\t\t\t\t\tattendeeId: this.attendeeId,\n\t\t\t\t\tconnectionId: this.runtime.getClientId(),\n\t\t\t\t\tprimaryResponses: JSON.stringify(primaryRequestors),\n\t\t\t\t\tsecondaryResponses: JSON.stringify(secondaryRequestors),\n\t\t\t\t},\n\t\t\t});\n\t\t}\n\n\t\t// Sending all must account for anything queued before.\n\t\tthis.queuedData = undefined;\n\t}\n\n\tpublic processSignal(\n\t\tmessage: InboundExtensionMessage<SignalMessages>,\n\t\tlocal: boolean,\n\t\toptional: boolean,\n\t): void {\n\t\tconst received = Date.now();\n\t\tassert(message.clientId !== null, 0xa3a /* Map received signal without clientId */);\n\t\tif (!isPresenceMessage(message)) {\n\t\t\tassert(optional, \"Unrecognized message type in critical message\");\n\t\t\treturn;\n\t\t}\n\n\t\tif (local) {\n\t\t\tconst deliveryDelta = received - message.content.sendTimestamp;\n\t\t\t// Limit returnedMessages count to 256 such that newest message\n\t\t\t// always contributes at least 1/256th to the average. Older\n\t\t\t// messages have more weight, but that diminishes as new messages\n\t\t\t// contribute.\n\t\t\tthis.returnedMessages = Math.min(this.returnedMessages + 1, 256);\n\t\t\tthis.averageLatency =\n\t\t\t\t(this.averageLatency * (this.returnedMessages - 1) + deliveryDelta) /\n\t\t\t\tthis.returnedMessages;\n\t\t\treturn;\n\t\t}\n\n\t\tconst selfClientId = this.runtime.getClientId();\n\t\tassert(selfClientId !== undefined, \"Received signal without clientId\");\n\n\t\t// Check for undesired case of receiving a remote presence signal\n\t\t// without having been alerted to self audience join. (Perhaps join\n\t\t// signal was dropped.)\n\t\t// In practice it is commonly observed that local signals can be\n\t\t// returned ahead of audience join notification. So, it is reasonable\n\t\t// to expect that audience join notification may be delayed until after\n\t\t// other presence signals are received. One is enough to get things\n\t\t// rolling.\n\t\tif (this.stopWaitingForSelfInAudience !== undefined) {\n\t\t\tthis.stopWaitingAndJoin(selfClientId, /* alternateProvider */ message.clientId);\n\t\t}\n\n\t\tconst timeModifier =\n\t\t\treceived -\n\t\t\t(this.averageLatency + message.content.avgLatency + message.content.sendTimestamp);\n\n\t\tconst postUpdateActions: PostUpdateAction[] = [];\n\n\t\tif (message.type === joinMessageType) {\n\t\t\t// It is possible for some signals to come in while client is not connected due\n\t\t\t// to how work is scheduled. If we are not connected, we can't respond to the\n\t\t\t// join request. We will make our own Join request once we are connected.\n\t\t\tif (this.runtime.getJoinedStatus() !== \"disconnected\") {\n\t\t\t\tthis.prepareJoinResponse(message.content.updateProviders, message.clientId);\n\t\t\t}\n\t\t\t// It is okay to continue processing the contained updates even if we are not\n\t\t\t// connected.\n\t\t} else {\n\t\t\t// Update join response requests that are now satisfied.\n\t\t\tconst joinResponseFor = message.content.joinResponseFor;\n\t\t\tif (joinResponseFor) {\n\t\t\t\tlet justGainedCompleteSnapshot = false;\n\t\t\t\tif (joinResponseFor.includes(selfClientId)) {\n\t\t\t\t\tif (this.reasonForCompleteSnapshot) {\n\t\t\t\t\t\tif (this.reasonForCompleteSnapshot === \"alone\") {\n\t\t\t\t\t\t\t// No response was expected. This might happen when\n\t\t\t\t\t\t\t// either cautionary ClientJoin signal is received\n\t\t\t\t\t\t\t// by audience member that was unknown.\n\t\t\t\t\t\t\tthis.logger?.sendTelemetryEvent({\n\t\t\t\t\t\t\t\teventName: \"JoinResponseWhenAlone\",\n\t\t\t\t\t\t\t\tdetails: {\n\t\t\t\t\t\t\t\t\tattendeeId: this.attendeeId,\n\t\t\t\t\t\t\t\t\tconnectionId: this.runtime.getClientId(),\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// If we are the intended recipient of the join response,\n\t\t\t\t\t\t// we can consider our knowledge complete and can respond\n\t\t\t\t\t\t// to others join requests.\n\t\t\t\t\t\tjustGainedCompleteSnapshot = true;\n\t\t\t\t\t}\n\t\t\t\t\tthis.reasonForCompleteSnapshot = \"join response\";\n\t\t\t\t}\n\t\t\t\tif (this.broadcastRequests.size > 0) {\n\t\t\t\t\tfor (const responseFor of joinResponseFor) {\n\t\t\t\t\t\tthis.broadcastRequests.delete(responseFor);\n\t\t\t\t\t}\n\t\t\t\t\tif (this.broadcastRequests.size === 0) {\n\t\t\t\t\t\t// If no more requests are pending, clear any timer.\n\t\t\t\t\t\tthis.broadcastRequestsTimer.clearTimeout();\n\t\t\t\t\t} else if (justGainedCompleteSnapshot) {\n\t\t\t\t\t\t// May or may not be time to respond to remaining requests.\n\t\t\t\t\t\t// Clear the timer and recheck after processing.\n\t\t\t\t\t\tthis.broadcastRequestsTimer.clearTimeout();\n\t\t\t\t\t\tpostUpdateActions.push(this.sendJoinResponseIfStillNeeded);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// If the message requests an acknowledgement, we will send a targeted acknowledgement message back to just the requestor.\n\t\t\tif (message.content.acknowledgementId !== undefined) {\n\t\t\t\tassert(\n\t\t\t\t\tthis.targetedSignalSupport,\n\t\t\t\t\t\"Acknowledgment message was requested while targeted signal capability is not supported\",\n\t\t\t\t);\n\t\t\t\tthis.runtime.submitSignal({\n\t\t\t\t\ttype: acknowledgementMessageType,\n\t\t\t\t\tcontent: { id: message.content.acknowledgementId },\n\t\t\t\t\ttargetClientId: message.clientId,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\t// Handle activation of unregistered workspaces before processing updates.\n\t\tfor (const [workspaceAddress] of objectEntries(message.content.data)) {\n\t\t\t// The first part of OR condition checks if workspace is already registered.\n\t\t\t// The second part checks if the workspace has already been seen before.\n\t\t\t// In either case we can skip emitting 'workspaceActivated' event.\n\t\t\tif (this.workspaces.has(workspaceAddress) || this.datastore[workspaceAddress]) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// Separate internal type prefix from public workspace address\n\t\t\tconst match = workspaceAddress.match(/^([^:]):([^:]+:.+)$/) as\n\t\t\t\t| null\n\t\t\t\t| [string, string, WorkspaceAddress];\n\n\t\t\tif (match === null) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst prefix = match[1];\n\t\t\tconst publicWorkspaceAddress = match[2];\n\n\t\t\tconst internalWorkspaceType = internalWorkspaceTypes[prefix] ?? \"Unknown\";\n\n\t\t\tthis.events.emit(\"workspaceActivated\", publicWorkspaceAddress, internalWorkspaceType);\n\t\t}\n\n\t\t// While the system workspace is processed here too, it is declared as\n\t\t// conforming to the general schema. So drop its override.\n\t\tconst data = message.content.data as Omit<typeof message.content.data, \"system:presence\">;\n\t\tfor (const [workspaceAddress, remoteDatastore] of objectEntries(data)) {\n\t\t\t// Direct to the appropriate Presence Workspace, if present.\n\t\t\tconst workspace = this.workspaces.get(workspaceAddress);\n\t\t\tif (workspace) {\n\t\t\t\tpostUpdateActions.push(\n\t\t\t\t\t...workspace.internal.processUpdate(\n\t\t\t\t\t\treceived,\n\t\t\t\t\t\ttimeModifier,\n\t\t\t\t\t\tremoteDatastore,\n\t\t\t\t\t\tmessage.clientId,\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\t// All broadcast state is kept even if not currently registered, unless a value\n\t\t\t\t// notes itself to be ignored.\n\n\t\t\t\t// Ensure there is a datastore at this address and get it.\n\t\t\t\tconst workspaceDatastore = (this.datastore[workspaceAddress] ??= {});\n\t\t\t\tfor (const [key, remoteAllKnownState] of Object.entries(remoteDatastore)) {\n\t\t\t\t\tmergeUntrackedDatastore(key, remoteAllKnownState, workspaceDatastore, timeModifier);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tfor (const action of postUpdateActions) {\n\t\t\taction();\n\t\t}\n\t}\n\n\t/**\n\t * Broadcasts a join response (complete datastore update message)\n\t * if there is an outstanding join response request.\n\t */\n\tprivate readonly sendJoinResponseIfStillNeeded = (): void => {\n\t\t// Make sure we are currently connected and a broadcast is still needed.\n\t\t// If not connected, nothing we can do.\n\t\tif (this.runtime.getJoinedStatus() !== \"disconnected\" && this.broadcastRequests.size > 0) {\n\t\t\t// Confirm that of remaining requests, now is the time to respond.\n\t\t\tconst now = Date.now();\n\t\t\tlet minResponseTime = Number.POSITIVE_INFINITY;\n\t\t\tfor (const { deadlineTime } of this.broadcastRequests.values()) {\n\t\t\t\tminResponseTime = Math.min(minResponseTime, deadlineTime);\n\t\t\t}\n\t\t\tif (minResponseTime <= now) {\n\t\t\t\tif (this.reasonForCompleteSnapshot) {\n\t\t\t\t\tthis.broadcastAllKnownState();\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// No response needed yet - schedule a later attempt\n\t\t\t\tthis.broadcastRequestsTimer.setTimeout(\n\t\t\t\t\tthis.sendJoinResponseIfStillNeeded,\n\t\t\t\t\tminResponseTime - now,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t};\n\n\t/**\n\t * Handles responding to another client joining the session.\n\t *\n\t * @param updateProviders - list of client connection id's that requestor selected\n\t * to provide response\n\t * @param requestor - `requestor` is only used in telemetry. While it is the requestor's\n\t * client connection id, that is not most important. It is important that this is a\n\t * unique shared id across all clients that might respond as we want to monitor the\n\t * response patterns. The convenience of being client connection id will allow\n\t * correlation with other telemetry where it is often called just `clientId`.\n\t */\n\tprivate prepareJoinResponse(\n\t\tupdateProviders: ClientConnectionId[],\n\t\trequestor: ClientConnectionId,\n\t): void {\n\t\t// We must be connected to receive this message, so clientId should be defined.\n\t\t// If it isn't then, not really a problem; just won't be in provider or audience list.\n\t\t// eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n\t\tconst selfClientId = this.runtime.getClientId()!;\n\t\tlet joinResponseDelayMs = broadcastJoinResponseDelaysMs.namedResponder;\n\t\tlet relativeResponseOrder: number | undefined;\n\t\tif (!updateProviders.includes(selfClientId)) {\n\t\t\t// Schedule a broadcast to the new client after a delay only to send if\n\t\t\t// another broadcast satisfying the request hasn't been seen in the\n\t\t\t// meantime. The delay is based on the position in the quorum list. It\n\t\t\t// doesn't have to be a stable list across all clients. We need\n\t\t\t// something to provide suggested order to prevent a flood of broadcasts.\n\t\t\tconst quorumMembers = this.runtime.getQuorum().getMembers();\n\t\t\tconst self = quorumMembers.get(selfClientId);\n\t\t\tif (self) {\n\t\t\t\t// Compute order quorum join order (indicated by sequenceNumber)\n\t\t\t\trelativeResponseOrder = 0;\n\t\t\t\tfor (const { client, sequenceNumber } of quorumMembers.values()) {\n\t\t\t\t\tif (\n\t\t\t\t\t\tsequenceNumber < self.sequenceNumber &&\n\t\t\t\t\t\tclient.details.capabilities.interactive\n\t\t\t\t\t) {\n\t\t\t\t\t\trelativeResponseOrder++;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// Order past quorum members + arbitrary additional offset up to 10\n\t\t\t\tlet possibleQuorumRespondents = 0;\n\t\t\t\tfor (const { client } of quorumMembers.values()) {\n\t\t\t\t\tif (client.details.capabilities.interactive) {\n\t\t\t\t\t\tpossibleQuorumRespondents++;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\trelativeResponseOrder = possibleQuorumRespondents + Math.random() * 10;\n\t\t\t}\n\t\t\t// When not named to provide update, wait an additional amount\n\t\t\t// of time for those named or others to respond.\n\t\t\tjoinResponseDelayMs +=\n\t\t\t\tbroadcastJoinResponseDelaysMs.backupResponderIncrement *\n\t\t\t\t(3 * updateProviders.length + relativeResponseOrder);\n\t\t}\n\n\t\t// Add the requestor to the list of clients that will receive the broadcast.\n\t\tconst deadlineTime = Date.now() + joinResponseDelayMs;\n\t\tthis.broadcastRequests.set(requestor, {\n\t\t\tdeadlineTime,\n\t\t\tresponseOrder: relativeResponseOrder,\n\t\t});\n\n\t\tif (!this.reasonForCompleteSnapshot) {\n\t\t\t// Check if requestor count meets or exceeds count of other audience\n\t\t\t// members indicating that we effectively have a complete snapshot\n\t\t\t// (once the current message being processed is processed).\n\t\t\tconst { selfPresent, interactiveMembersExcludingSelf } =\n\t\t\t\tthis.getAudienceInformation(selfClientId);\n\t\t\tif (\n\t\t\t\t// Self-present check is done to help ensure that audience\n\t\t\t\t// information is accurate. If self is not present, audience\n\t\t\t\t// information might be incomplete.\n\t\t\t\tselfPresent &&\n\t\t\t\tthis.broadcastRequests.size >= interactiveMembersExcludingSelf.all.size\n\t\t\t) {\n\t\t\t\t// Note that no action is taken here specifically.\n\t\t\t\t// We want action to be queued so that it takes place after\n\t\t\t\t// current message is completely processed. All of the actions\n\t\t\t\t// below should be delayed (not immediate).\n\t\t\t\tthis.reasonForCompleteSnapshot = \"full requests\";\n\t\t\t}\n\t\t}\n\n\t\t// Check if capable of full primary response. If requested to provide\n\t\t// primary response, but do not yet have complete snapshot, we need to\n\t\t// delay a full response, until we think we have complete snapshot. In\n\t\t// the meantime we will send partial updates as usual.\n\t\tif (this.reasonForCompleteSnapshot && updateProviders.includes(selfClientId)) {\n\t\t\t// Use regular message queue to handle timing of the broadcast.\n\t\t\t// Any more immediate broadcasts will accelerate the response time.\n\t\t\t// As a primary responder, it is expected that broadcast will happen and\n\t\t\t// using the regular queue allows other updates to avoid merge work.\n\t\t\tthis.enqueueMessage(\"sendAll\", {\n\t\t\t\tallowableUpdateLatencyMs: joinResponseDelayMs,\n\t\t\t});\n\t\t} else {\n\t\t\t// Check if there isn't already a timer scheduled to send a join\n\t\t\t// response with in this request's deadline.\n\t\t\tif (\n\t\t\t\tthis.broadcastRequestsTimer.hasExpired() ||\n\t\t\t\tdeadlineTime < this.broadcastRequestsTimer.expireTime\n\t\t\t) {\n\t\t\t\t// Set or update the timer.\n\t\t\t\tthis.broadcastRequestsTimer.setTimeout(\n\t\t\t\t\tthis.sendJoinResponseIfStillNeeded,\n\t\t\t\t\tjoinResponseDelayMs,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"presenceDatastoreManager.js","sourceRoot":"","sources":["../src/presenceDatastoreManager.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 type { IAudience } from \"@fluidframework/container-definitions\";\nimport type { InboundExtensionMessage } from \"@fluidframework/container-runtime-definitions/internal\";\nimport type { IEmitter } from \"@fluidframework/core-interfaces/internal\";\nimport { assert } from \"@fluidframework/core-utils/internal\";\nimport type { ITelemetryLoggerExt } from \"@fluidframework/telemetry-utils/internal\";\n\nimport type { ClientConnectionId } from \"./baseTypes.js\";\nimport type { BroadcastControlSettings } from \"./broadcastControls.js\";\nimport type { InternalTypes } from \"./exposedInternalTypes.js\";\nimport type {\n\tIEphemeralRuntime,\n\tPostUpdateAction,\n\tValidatableOptionalState,\n\tValidatableValueDirectory,\n\tValidatableValueStructure,\n} from \"./internalTypes.js\";\nimport { objectEntries } from \"./internalUtils.js\";\nimport type {\n\tAttendeeId,\n\tPresenceWithNotifications as Presence,\n\tPresenceEvents,\n} from \"./presence.js\";\nimport type {\n\tClientUpdateEntry,\n\tRuntimeLocalUpdateOptions,\n\tPresenceStatesInternal,\n\tValueElementMap,\n} from \"./presenceStates.js\";\nimport {\n\tcreatePresenceStates,\n\tmergeUntrackedDatastore,\n\tmergeValueDirectory,\n} from \"./presenceStates.js\";\nimport type {\n\tDatastoreMessageContent,\n\tGeneralDatastoreMessageContent,\n\tInboundClientJoinMessage,\n\tInboundDatastoreUpdateMessage,\n\tInternalWorkspaceAddress,\n\tOutboundDatastoreUpdateMessage,\n\tSignalMessages,\n\tSystemDatastore,\n} from \"./protocol.js\";\nimport {\n\tacknowledgementMessageType,\n\tdatastoreUpdateMessageType,\n\tjoinMessageType,\n} from \"./protocol.js\";\nimport type { SystemWorkspaceDatastore } from \"./systemWorkspace.js\";\nimport { TimerManager } from \"./timerManager.js\";\nimport type {\n\tAnyWorkspace,\n\tNotificationsWorkspace,\n\tNotificationsWorkspaceSchema,\n\tStatesWorkspace,\n\tStatesWorkspaceSchema,\n\tWorkspaceAddress,\n} from \"./types.js\";\n\ninterface AnyWorkspaceEntry<TSchema extends StatesWorkspaceSchema> {\n\tpublic: AnyWorkspace<TSchema>;\n\tinternal: PresenceStatesInternal;\n}\n\n/**\n * Datastore structure used for broadcasting to other clients.\n * Validation metadata is stripped before transmission.\n */\ntype PresenceDatastore = SystemDatastore & {\n\t[WorkspaceAddress: InternalWorkspaceAddress]: ValueElementMap<StatesWorkspaceSchema>;\n};\n\nconst internalWorkspaceTypes: Readonly<Record<string, \"States\" | \"Notifications\">> = {\n\ts: \"States\",\n\tn: \"Notifications\",\n} as const;\n\nconst knownMessageTypes = new Set([\n\tjoinMessageType,\n\tdatastoreUpdateMessageType,\n\tacknowledgementMessageType,\n]);\nfunction isPresenceMessage(\n\tmessage: InboundExtensionMessage<SignalMessages>,\n): message is InboundDatastoreUpdateMessage | InboundClientJoinMessage {\n\treturn knownMessageTypes.has(message.type);\n}\n\n/**\n * Type guard to check if a value hierarchy object is a directory (has \"items\"\n * property).\n *\n * @param obj - The object to check\n * @returns True if the object is a {@link ValidatableValueDirectory}\n */\nexport function isValueDirectory<T>(\n\tobj: ValidatableValueDirectory<T> | ValidatableOptionalState<T>,\n): obj is ValidatableValueDirectory<T> {\n\treturn \"items\" in obj;\n}\n\n/**\n * High-level contract for manager of singleton Presence datastore\n */\nexport interface PresenceDatastoreManager {\n\tjoinSession(clientId: ClientConnectionId): void;\n\tonDisconnected(): void;\n\tgetWorkspace<TSchema extends StatesWorkspaceSchema>(\n\t\tinternalWorkspaceAddress: `s:${WorkspaceAddress}`,\n\t\trequestedContent: TSchema,\n\t\tcontrols?: BroadcastControlSettings,\n\t): StatesWorkspace<TSchema>;\n\tgetWorkspace<TSchema extends NotificationsWorkspaceSchema>(\n\t\tinternalWorkspaceAddress: `n:${WorkspaceAddress}`,\n\t\trequestedContent: TSchema,\n\t): NotificationsWorkspace<TSchema>;\n\tprocessSignal(\n\t\tmessage: InboundExtensionMessage<SignalMessages>,\n\t\tlocal: boolean,\n\t\toptional: boolean,\n\t): void;\n}\n\nfunction mergeGeneralDatastoreMessageContent(\n\tbase: GeneralDatastoreMessageContent | undefined,\n\tnewData: GeneralDatastoreMessageContent,\n): GeneralDatastoreMessageContent {\n\t// This function-local \"datastore\" will hold the merged message data.\n\tconst queueDatastore = base ?? {};\n\n\t// Merge the current data with the existing data, if any exists.\n\t// Iterate over the current message data; individual items are workspaces.\n\tfor (const [workspaceName, workspaceData] of objectEntries(newData)) {\n\t\t// Initialize the merged data as the queued datastore entry for the workspace.\n\t\t// Since the key might not exist, create an empty object in that case. It will\n\t\t// be set explicitly after the loop.\n\t\tconst mergedData = queueDatastore[workspaceName] ?? {};\n\n\t\t// Iterate over each value manager and its data, merging it as needed.\n\t\tfor (const [valueManagerKey, valueManagerValue] of objectEntries(workspaceData)) {\n\t\t\tfor (const [attendeeId, value] of objectEntries(valueManagerValue)) {\n\t\t\t\tconst mergeObject = (mergedData[valueManagerKey] ??= {});\n\t\t\t\tconst oldData = mergeObject[attendeeId];\n\t\t\t\tmergeObject[attendeeId] = mergeValueDirectory(\n\t\t\t\t\toldData,\n\t\t\t\t\tvalue,\n\t\t\t\t\t0, // local values do not need a time shift\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\t// Store the merged data in the function-local queue workspace. The whole contents of this\n\t\t// datastore will be sent as the message data.\n\t\tqueueDatastore[workspaceName] = mergedData;\n\t}\n\treturn queueDatastore;\n}\n\n/**\n * Delays used for broadcasting join responses to clients.\n *\n * @remarks\n * Exported for test coordination.\n * These could be made customizable in the future to accommodate different\n * session configurations.\n */\nexport const broadcastJoinResponseDelaysMs = {\n\t/**\n\t * The delay in milliseconds before a join response is sent to any client.\n\t * This is used to accumulate other join response requests and reduce\n\t * network traffic.\n\t */\n\tnamedResponder: 200,\n\t/**\n\t * The additional delay in milliseconds a backup responder waits before sending\n\t * a join response to allow others to respond first.\n\t */\n\tbackupResponderIncrement: 40,\n} as const;\n\n/**\n * Manages singleton datastore for all Presence.\n */\nexport class PresenceDatastoreManagerImpl implements PresenceDatastoreManager {\n\tprivate readonly datastore: PresenceDatastore;\n\tprivate averageLatency = 0;\n\tprivate returnedMessages = 0;\n\tprivate readonly sendMessageTimer = new TimerManager();\n\tprivate readonly workspaces = new Map<string, AnyWorkspaceEntry<StatesWorkspaceSchema>>();\n\tprivate readonly targetedSignalSupport: boolean;\n\n\t/**\n\t * When defined, this client is not recognized in the session.\n\t * Call when no longer caring about that condition. That way listeners are\n\t * cleaned up.\n\t */\n\tprivate stopWaitingForSelfInAudience: undefined | (() => void);\n\n\t/**\n\t * Tracks whether this client has complete snapshot level knowledge and\n\t * how that determination was reached.\n\t * - \"alone\": no other audience members detected at join\n\t * - \"join response\": another client has responded to our join request\n\t * - \"full requests\": all others have requested response from us\n\t *\n\t * @remarks\n\t * Only applies when not using targeted join responses.\n\t *\n\t * Without a complete snapshot, we cannot fully onboard any other clients.\n\t * One exception to this is if this client is the only participant in the\n\t * session. In such a case, there is no one to respond to the join request.\n\t * Another exception is multiple clients attempting to join at the same\n\t * time and thus expecting that someone has full knowledge, yet none have\n\t * received a complete update to think they are qualified to respond.\n\t * Generically if the number of outstanding requestors meets or exceeds the\n\t * count of other audience members, then we can consider the snapshot\n\t * complete (as all will have provided their own complete information in\n\t * their join responses).\n\t */\n\tprivate reasonForCompleteSnapshot?: \"alone\" | \"join response\" | \"full requests\";\n\n\t/**\n\t * Map of outstanding broadcast (join response) requests.\n\t */\n\tprivate readonly broadcastRequests = new Map<\n\t\tClientConnectionId,\n\t\t{ deadlineTime: number; responseOrder?: number | undefined }\n\t>();\n\t/**\n\t * Timer for managing broadcast (join response) request timing.\n\t */\n\tprivate readonly broadcastRequestsTimer = new TimerManager();\n\n\tpublic constructor(\n\t\tprivate readonly attendeeId: AttendeeId,\n\t\tprivate readonly runtime: IEphemeralRuntime,\n\t\tprivate readonly logger: ITelemetryLoggerExt | undefined,\n\t\tprivate readonly events: IEmitter<PresenceEvents>,\n\t\tprivate readonly presence: Presence,\n\t\tsystemWorkspaceDatastore: SystemWorkspaceDatastore,\n\t\tsystemWorkspace: AnyWorkspaceEntry<StatesWorkspaceSchema>,\n\t) {\n\t\t// eslint-disable-next-line @typescript-eslint/consistent-type-assertions\n\t\tthis.datastore = { \"system:presence\": systemWorkspaceDatastore } as PresenceDatastore;\n\t\tthis.workspaces.set(\"system:presence\", systemWorkspace);\n\t\tthis.targetedSignalSupport = this.runtime.supportedFeatures.has(\"submit_signals_v2\");\n\t\t// If audience member is removed, they won't need a broadcast response.\n\t\tthis.runtime.getAudience().on(\"removeMember\", (clientId) => {\n\t\t\tthis.broadcastRequests.delete(clientId);\n\t\t});\n\t}\n\n\tprivate getAudienceInformation(selfClientId: ClientConnectionId): {\n\t\taudience: IAudience;\n\t\tselfPresent: boolean;\n\t\tinteractiveMembersExcludingSelf: {\n\t\t\tall: Set<ClientConnectionId>;\n\t\t\twriters: Set<ClientConnectionId>;\n\t\t};\n\t} {\n\t\tconst audience = this.runtime.getAudience();\n\t\tconst members = audience.getMembers();\n\t\tconst all = new Set<ClientConnectionId>();\n\t\tconst writers = new Set<ClientConnectionId>();\n\t\tconst selfPresent = members.has(selfClientId);\n\t\tif (selfPresent) {\n\t\t\t// Remove self\n\t\t\tmembers.delete(selfClientId);\n\t\t}\n\t\t// Gather interactive client IDs\n\t\tfor (const [id, client] of members) {\n\t\t\tif (client.details.capabilities.interactive) {\n\t\t\t\tall.add(id);\n\t\t\t\tif (client.mode === \"write\") {\n\t\t\t\t\twriters.add(id);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn {\n\t\t\taudience,\n\t\t\tselfPresent,\n\t\t\tinteractiveMembersExcludingSelf: {\n\t\t\t\tall,\n\t\t\t\twriters,\n\t\t\t},\n\t\t};\n\t}\n\n\tpublic joinSession(\n\t\tselfClientId: ClientConnectionId,\n\t\talternateProvider: ClientConnectionId | undefined = undefined,\n\t): void {\n\t\t// Before broadcasting the join message, check that there is at least\n\t\t// one audience member present (self or another). This is useful to\n\t\t// optimize join messages while not using targeted join responses.\n\t\t// (We need at least one other to be able to elect them as update\n\t\t// provider.)\n\t\t// Lack of anyone likely means that this client is very freshly joined\n\t\t// and has not received any Join Signals (type=\"join\") from the service\n\t\t// yet.\n\t\tconst { audience, selfPresent, interactiveMembersExcludingSelf } =\n\t\t\tthis.getAudienceInformation(selfClientId);\n\n\t\tif (interactiveMembersExcludingSelf.all.size === 0 && alternateProvider !== undefined) {\n\t\t\tif (selfPresent) {\n\t\t\t\t// If there aren't any members connected except self, then this client\n\t\t\t\t// must have complete information.\n\t\t\t\tthis.reasonForCompleteSnapshot = \"alone\";\n\t\t\t\t// It would be possible to return at this time and skip ClientJoin\n\t\t\t\t// signal. Instead continue in case audience information is\n\t\t\t\t// inaccurate. This client might temporarily erroneously believe it\n\t\t\t\t// has complete information, but the other(s) should respond to\n\t\t\t\t// ClientJoin soon rectifying that and covering for bad incomplete\n\t\t\t\t// responses this client sent in the meantime.\n\t\t\t} else {\n\t\t\t\t// No one is known. Not even self. Defer judgement on\n\t\t\t\t// complete snapshot until at least self is known to be present.\n\t\t\t\tthis.listenForSelfInAudience(selfClientId, audience);\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\n\t\t// Broadcast join message to all clients\n\t\t// Select primary update providers\n\t\t// Use write members if any, then fallback to read-only members.\n\t\tconst updateProviders = [\n\t\t\t...(interactiveMembersExcludingSelf.writers.size > 0\n\t\t\t\t? interactiveMembersExcludingSelf.writers\n\t\t\t\t: interactiveMembersExcludingSelf.all),\n\t\t];\n\t\t// Limit to three providers to prevent flooding the network.\n\t\t// If none respond, others present will (should) after a delay.\n\t\tif (updateProviders.length > 3) {\n\t\t\tupdateProviders.length = 3;\n\t\t} else if (updateProviders.length === 0 && alternateProvider !== undefined) {\n\t\t\tupdateProviders.push(alternateProvider);\n\t\t}\n\t\tthis.runtime.submitSignal({\n\t\t\ttype: joinMessageType,\n\t\t\tcontent: {\n\t\t\t\tsendTimestamp: Date.now(),\n\t\t\t\tavgLatency: this.averageLatency,\n\t\t\t\tdata: this.stripValidationMetadata(this.datastore),\n\t\t\t\tupdateProviders,\n\t\t\t},\n\t\t});\n\t\tthis.logger?.sendTelemetryEvent({\n\t\t\teventName: \"JoinRequested\",\n\t\t\tdetails: {\n\t\t\t\tattendeeId: this.attendeeId,\n\t\t\t\tconnectionId: selfClientId,\n\t\t\t\t// Empty updateProviders is indicative of join when alone.\n\t\t\t\tupdateProviders: JSON.stringify(updateProviders),\n\t\t\t\t// If false and providers is single entry, then join was probably forced.\n\t\t\t\tselfPresent,\n\t\t\t},\n\t\t});\n\t}\n\n\tprivate listenForSelfInAudience(selfClientId: string, audience: IAudience): void {\n\t\tthis.logger?.sendTelemetryEvent({\n\t\t\teventName: \"JoinDeferred\",\n\t\t\tdetails: {\n\t\t\t\tattendeeId: this.attendeeId,\n\t\t\t\tconnectionId: selfClientId,\n\t\t\t},\n\t\t});\n\t\t// Prepare to join once self audience member joins.\n\t\t// Alternatively, processSignal may force a join when a presence\n\t\t// signal is received even without audience members (assumes\n\t\t// audience signals were lost).\n\t\tconst joinWhenSelfAudienceMemberAdded = (addedClientId: ClientConnectionId): void => {\n\t\t\tif (addedClientId !== selfClientId) {\n\t\t\t\t// Keep listening\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// No need to force here by providing alternate provider as self is\n\t\t\t// now present.\n\t\t\t// Do avoid forcing so that reasonForCompleteSnapshot is set correctly\n\t\t\t// if no others have been added.\n\t\t\tthis.stopWaitingAndJoin(selfClientId, /* alternateProvider */ undefined);\n\t\t};\n\t\taudience.on(\"addMember\", joinWhenSelfAudienceMemberAdded);\n\t\tthis.stopWaitingForSelfInAudience = () => {\n\t\t\taudience.off(\"addMember\", joinWhenSelfAudienceMemberAdded);\n\t\t};\n\t}\n\n\tprivate stopWaitingAndJoin(\n\t\tselfClientId: ClientConnectionId,\n\t\talternateProvider: ClientConnectionId | undefined,\n\t): void {\n\t\tthis.stopWaitingForSelfInAudience?.();\n\t\tthis.stopWaitingForSelfInAudience = undefined;\n\t\t// Confirm not currently disconnected\n\t\tif (this.runtime.getJoinedStatus() !== \"disconnected\") {\n\t\t\tthis.joinSession(selfClientId, alternateProvider);\n\t\t}\n\t}\n\n\tpublic onDisconnected(): void {\n\t\tdelete this.reasonForCompleteSnapshot;\n\t\tthis.stopWaitingForSelfInAudience?.();\n\t\tthis.stopWaitingForSelfInAudience = undefined;\n\t}\n\n\tpublic getWorkspace<TSchema extends StatesWorkspaceSchema>(\n\t\tinternalWorkspaceAddress: InternalWorkspaceAddress,\n\t\trequestedContent: TSchema,\n\t\tcontrols?: BroadcastControlSettings,\n\t): AnyWorkspace<TSchema> {\n\t\tconst existing = this.workspaces.get(internalWorkspaceAddress);\n\t\tif (existing) {\n\t\t\treturn existing.internal.ensureContent(requestedContent, controls);\n\t\t}\n\n\t\tlet workspaceDatastore: ValueElementMap<StatesWorkspaceSchema> | undefined =\n\t\t\tthis.datastore[internalWorkspaceAddress];\n\t\tif (workspaceDatastore === undefined) {\n\t\t\tworkspaceDatastore = this.datastore[internalWorkspaceAddress] = {};\n\t\t}\n\n\t\tconst localUpdate = (\n\t\t\tstates: { [key: string]: ClientUpdateEntry },\n\t\t\toptions: RuntimeLocalUpdateOptions,\n\t\t): void => {\n\t\t\t// Check for connectivity before sending updates.\n\t\t\tif (this.runtime.getJoinedStatus() === \"disconnected\") {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst updates: GeneralDatastoreMessageContent[InternalWorkspaceAddress] = {};\n\t\t\tfor (const [key, value] of Object.entries(states)) {\n\t\t\t\tupdates[key] = { [this.attendeeId]: value };\n\t\t\t}\n\n\t\t\tthis.enqueueMessage(\n\t\t\t\t{\n\t\t\t\t\t[internalWorkspaceAddress]: updates,\n\t\t\t\t},\n\t\t\t\toptions,\n\t\t\t);\n\t\t};\n\n\t\tconst entry = createPresenceStates(\n\t\t\t{\n\t\t\t\tpresence: this.presence,\n\t\t\t\tattendeeId: this.attendeeId,\n\t\t\t\tlocalUpdate,\n\t\t\t},\n\t\t\tworkspaceDatastore,\n\t\t\trequestedContent,\n\t\t\tcontrols,\n\t\t);\n\n\t\tthis.workspaces.set(internalWorkspaceAddress, entry);\n\t\treturn entry.public;\n\t}\n\n\t/**\n\t * The combined contents of all queued updates. Will be `\"sendAll\"` when a\n\t * full broadcast is pending or `undefined` when no messages are queued.\n\t */\n\tprivate queuedData: GeneralDatastoreMessageContent | \"sendAll\" | undefined;\n\n\t/**\n\t * Enqueues a new message to be sent. The message may be queued or may be sent immediately depending on the state of\n\t * the send timer, other messages in the queue, the configured allowed latency, etc.\n\t */\n\tprivate enqueueMessage(\n\t\tdata: GeneralDatastoreMessageContent | \"sendAll\",\n\t\toptions: RuntimeLocalUpdateOptions,\n\t): void {\n\t\tif (this.queuedData !== \"sendAll\") {\n\t\t\tthis.queuedData =\n\t\t\t\tdata === \"sendAll\"\n\t\t\t\t\t? \"sendAll\"\n\t\t\t\t\t: // Merging the message with any queued messages effectively queues the message.\n\t\t\t\t\t\t// It is OK to queue all incoming messages as long as when we send, we send the queued data.\n\t\t\t\t\t\tmergeGeneralDatastoreMessageContent(this.queuedData, data);\n\t\t}\n\n\t\tconst { allowableUpdateLatencyMs } = options;\n\t\tconst now = Date.now();\n\t\tconst thisMessageDeadline = now + allowableUpdateLatencyMs;\n\n\t\tif (\n\t\t\t// If the timer has not expired, we can short-circuit because the timer will fire\n\t\t\t// and cover this update. In other words, queuing this will be fast enough to\n\t\t\t// meet its deadline, because a timer is already scheduled to fire before its deadline.\n\t\t\t!this.sendMessageTimer.hasExpired() &&\n\t\t\t// If the deadline for this message is later than the overall send deadline, then\n\t\t\t// we can exit early since a timer will take care of sending it.\n\t\t\tthisMessageDeadline >= this.sendMessageTimer.expireTime\n\t\t) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Either we need to send this message immediately, or we need to schedule a timer\n\t\t// to fire at the send deadline that will take care of it.\n\n\t\t// Note that timeoutInMs === allowableUpdateLatencyMs, but the calculation is done this way for clarity.\n\t\tconst timeoutInMs = thisMessageDeadline - now;\n\t\tconst scheduleForLater = timeoutInMs > 0;\n\n\t\tif (scheduleForLater) {\n\t\t\t// Schedule the queued messages to be sent at the updateDeadline\n\t\t\tthis.sendMessageTimer.setTimeout(this.sendQueuedMessage.bind(this), timeoutInMs);\n\t\t} else {\n\t\t\tthis.sendQueuedMessage();\n\t\t}\n\t}\n\n\t/**\n\t * Send any queued signal immediately. Does nothing if no message is queued.\n\t */\n\tprivate sendQueuedMessage(): void {\n\t\tthis.sendMessageTimer.clearTimeout();\n\n\t\tif (this.queuedData === undefined) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Check for connectivity before sending updates.\n\t\tif (this.runtime.getJoinedStatus() === \"disconnected\") {\n\t\t\t// Clear the queued data since we're disconnected. We don't want messages\n\t\t\t// to queue infinitely while disconnected.\n\t\t\tthis.queuedData = undefined;\n\t\t\treturn;\n\t\t}\n\n\t\tif (this.queuedData === \"sendAll\") {\n\t\t\tthis.broadcastAllKnownState();\n\t\t\treturn;\n\t\t}\n\n\t\tconst clientConnectionId = this.runtime.getClientId();\n\t\tassert(clientConnectionId !== undefined, 0xa59 /* Client connected without clientId */);\n\t\tconst currentClientToSessionValueState =\n\t\t\t// When connected, `clientToSessionId` must always have current connection entry.\n\t\t\tthis.datastore[\"system:presence\"].clientToSessionId[clientConnectionId];\n\t\tassert(currentClientToSessionValueState !== undefined, \"Client connection update missing\");\n\n\t\tconst newMessage = {\n\t\t\tsendTimestamp: Date.now(),\n\t\t\tavgLatency: this.averageLatency,\n\t\t\t// isComplete: false,\n\t\t\tdata: {\n\t\t\t\t// Always send current connection mapping for some resiliency against\n\t\t\t\t// lost signals. This ensures that client session id found in `updates`\n\t\t\t\t// (which is this client's client session id) is always represented in\n\t\t\t\t// system workspace of recipient clients.\n\t\t\t\t\"system:presence\": {\n\t\t\t\t\tclientToSessionId: {\n\t\t\t\t\t\t[clientConnectionId]: { ...currentClientToSessionValueState },\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t...this.queuedData,\n\t\t\t},\n\t\t} satisfies OutboundDatastoreUpdateMessage[\"content\"];\n\t\tthis.queuedData = undefined;\n\t\tthis.runtime.submitSignal({ type: datastoreUpdateMessageType, content: newMessage });\n\t}\n\n\t/**\n\t * Recursively strips validation metadata (validatedValue) from datastore before broadcasting.\n\t * This ensures that validation metadata doesn't leak into signals sent to other clients.\n\t */\n\tprivate stripValidationMetadata(datastore: PresenceDatastore): DatastoreMessageContent {\n\t\tconst messageContent: DatastoreMessageContent = {\n\t\t\t[\"system:presence\"]: datastore[\"system:presence\"],\n\t\t};\n\n\t\tfor (const [workspaceAddress, workspace] of objectEntries(datastore)) {\n\t\t\t// System workspace has no validation metadata and is already\n\t\t\t// set in messageContent; so, it can be skipped.\n\t\t\tif (workspaceAddress === \"system:presence\") continue;\n\n\t\t\tconst workspaceData: GeneralDatastoreMessageContent[typeof workspaceAddress] = {};\n\n\t\t\tfor (const [stateName, clientRecord] of objectEntries(workspace)) {\n\t\t\t\tconst cleanClientRecord: GeneralDatastoreMessageContent[typeof workspaceAddress][typeof stateName] =\n\t\t\t\t\t{};\n\n\t\t\t\tfor (const [attendeeId, valueData] of objectEntries(clientRecord)) {\n\t\t\t\t\tcleanClientRecord[attendeeId] = this.stripValidationFromValueData(valueData);\n\t\t\t\t}\n\n\t\t\t\tworkspaceData[stateName] = cleanClientRecord;\n\t\t\t}\n\n\t\t\tmessageContent[workspaceAddress] = workspaceData;\n\t\t}\n\n\t\treturn messageContent;\n\t}\n\n\t/**\n\t * Strips validation metadata from individual value data entries.\n\t */\n\tprivate stripValidationFromValueData<\n\t\tT extends\n\t\t\t| InternalTypes.ValueDirectory<unknown>\n\t\t\t| InternalTypes.ValueRequiredState<unknown>\n\t\t\t| InternalTypes.ValueOptionalState<unknown>,\n\t>(valueDataIn: ValidatableValueStructure<T>): T {\n\t\t// Clone the input object since we may mutate it\n\t\tconst valueData = { ...valueDataIn };\n\n\t\t// Handle directory structures (with \"items\" property)\n\t\tif (isValueDirectory(valueData)) {\n\t\t\tfor (const [key, item] of Object.entries(valueData.items)) {\n\t\t\t\tvalueData.items[key] = this.stripValidationFromValueData(item);\n\t\t\t}\n\n\t\t\t// This `satisfies` test is rather weak while ValidatableValueDirectory\n\t\t\t// only has optional properties over InternalTypes.ValueDirectory and\n\t\t\t// thus readily does satisfy. If `validatedValue?: never` is uncommented\n\t\t\t// in Value*State then this will fail.\n\t\t\tvalueData satisfies InternalTypes.ValueDirectory<unknown>;\n\t\t\treturn valueData as T;\n\t\t}\n\n\t\tdelete valueData.validatedValue;\n\t\t// This `satisfies` test is rather weak while Validatable*State\n\t\t// only has optional properties over InternalTypes.Value*State and\n\t\t// thus readily does satisfy. If `validatedValue?: never` is uncommented\n\t\t// in Value*State then this will fail.\n\t\tvalueData satisfies\n\t\t\t| InternalTypes.ValueRequiredState<unknown>\n\t\t\t| InternalTypes.ValueOptionalState<unknown>;\n\t\treturn valueData as T;\n\t}\n\n\tprivate broadcastAllKnownState(): void {\n\t\tconst content: OutboundDatastoreUpdateMessage[\"content\"] = {\n\t\t\tsendTimestamp: Date.now(),\n\t\t\tavgLatency: this.averageLatency,\n\t\t\tisComplete: true,\n\t\t\tdata: this.stripValidationMetadata(this.datastore),\n\t\t};\n\n\t\tconst primaryRequestors: ClientConnectionId[] = [];\n\t\tconst secondaryRequestors: [ClientConnectionId, number][] = [];\n\t\tif (this.broadcastRequests.size > 0) {\n\t\t\tcontent.joinResponseFor = [...this.broadcastRequests.keys()];\n\t\t\tif (this.logger) {\n\t\t\t\t// Build telemetry data\n\t\t\t\tfor (const [requestor, { responseOrder }] of this.broadcastRequests.entries()) {\n\t\t\t\t\tif (responseOrder === undefined) {\n\t\t\t\t\t\tprimaryRequestors.push(requestor);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tsecondaryRequestors.push([requestor, responseOrder]);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis.broadcastRequests.clear();\n\t\t}\n\n\t\t// This broadcast will satisfy all requests; clear any remaining timer.\n\t\tthis.broadcastRequestsTimer.clearTimeout();\n\t\tthis.sendMessageTimer.clearTimeout();\n\n\t\tthis.runtime.submitSignal({\n\t\t\ttype: datastoreUpdateMessageType,\n\t\t\tcontent,\n\t\t});\n\t\tif (content.joinResponseFor) {\n\t\t\tthis.logger?.sendTelemetryEvent({\n\t\t\t\teventName: \"JoinResponse\",\n\t\t\t\tdetails: {\n\t\t\t\t\ttype: \"broadcastAll\",\n\t\t\t\t\tattendeeId: this.attendeeId,\n\t\t\t\t\tconnectionId: this.runtime.getClientId(),\n\t\t\t\t\tprimaryResponses: JSON.stringify(primaryRequestors),\n\t\t\t\t\tsecondaryResponses: JSON.stringify(secondaryRequestors),\n\t\t\t\t},\n\t\t\t});\n\t\t}\n\n\t\t// Sending all must account for anything queued before.\n\t\tthis.queuedData = undefined;\n\t}\n\n\tpublic processSignal(\n\t\tmessage: InboundExtensionMessage<SignalMessages>,\n\t\tlocal: boolean,\n\t\toptional: boolean,\n\t): void {\n\t\tconst received = Date.now();\n\t\tassert(message.clientId !== null, 0xa3a /* Map received signal without clientId */);\n\t\tif (!isPresenceMessage(message)) {\n\t\t\tassert(optional, \"Unrecognized message type in critical message\");\n\t\t\treturn;\n\t\t}\n\n\t\tif (local) {\n\t\t\tconst deliveryDelta = received - message.content.sendTimestamp;\n\t\t\t// Limit returnedMessages count to 256 such that newest message\n\t\t\t// always contributes at least 1/256th to the average. Older\n\t\t\t// messages have more weight, but that diminishes as new messages\n\t\t\t// contribute.\n\t\t\tthis.returnedMessages = Math.min(this.returnedMessages + 1, 256);\n\t\t\tthis.averageLatency =\n\t\t\t\t(this.averageLatency * (this.returnedMessages - 1) + deliveryDelta) /\n\t\t\t\tthis.returnedMessages;\n\t\t\treturn;\n\t\t}\n\n\t\tconst selfClientId = this.runtime.getClientId();\n\t\tassert(selfClientId !== undefined, \"Received signal without clientId\");\n\n\t\t// Check for undesired case of receiving a remote presence signal\n\t\t// without having been alerted to self audience join. (Perhaps join\n\t\t// signal was dropped.)\n\t\t// In practice it is commonly observed that local signals can be\n\t\t// returned ahead of audience join notification. So, it is reasonable\n\t\t// to expect that audience join notification may be delayed until after\n\t\t// other presence signals are received. One is enough to get things\n\t\t// rolling.\n\t\tif (this.stopWaitingForSelfInAudience !== undefined) {\n\t\t\tthis.stopWaitingAndJoin(selfClientId, /* alternateProvider */ message.clientId);\n\t\t}\n\n\t\tconst timeModifier =\n\t\t\treceived -\n\t\t\t(this.averageLatency + message.content.avgLatency + message.content.sendTimestamp);\n\n\t\tconst postUpdateActions: PostUpdateAction[] = [];\n\n\t\tif (message.type === joinMessageType) {\n\t\t\t// It is possible for some signals to come in while client is not connected due\n\t\t\t// to how work is scheduled. If we are not connected, we can't respond to the\n\t\t\t// join request. We will make our own Join request once we are connected.\n\t\t\tif (this.runtime.getJoinedStatus() !== \"disconnected\") {\n\t\t\t\tthis.prepareJoinResponse(message.content.updateProviders, message.clientId);\n\t\t\t}\n\t\t\t// It is okay to continue processing the contained updates even if we are not\n\t\t\t// connected.\n\t\t} else {\n\t\t\t// Update join response requests that are now satisfied.\n\t\t\tconst joinResponseFor = message.content.joinResponseFor;\n\t\t\tif (joinResponseFor) {\n\t\t\t\tlet justGainedCompleteSnapshot = false;\n\t\t\t\tif (joinResponseFor.includes(selfClientId)) {\n\t\t\t\t\tif (this.reasonForCompleteSnapshot) {\n\t\t\t\t\t\tif (this.reasonForCompleteSnapshot === \"alone\") {\n\t\t\t\t\t\t\t// No response was expected. This might happen when\n\t\t\t\t\t\t\t// either cautionary ClientJoin signal is received\n\t\t\t\t\t\t\t// by audience member that was unknown.\n\t\t\t\t\t\t\tthis.logger?.sendTelemetryEvent({\n\t\t\t\t\t\t\t\teventName: \"JoinResponseWhenAlone\",\n\t\t\t\t\t\t\t\tdetails: {\n\t\t\t\t\t\t\t\t\tattendeeId: this.attendeeId,\n\t\t\t\t\t\t\t\t\tconnectionId: this.runtime.getClientId(),\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// If we are the intended recipient of the join response,\n\t\t\t\t\t\t// we can consider our knowledge complete and can respond\n\t\t\t\t\t\t// to others join requests.\n\t\t\t\t\t\tjustGainedCompleteSnapshot = true;\n\t\t\t\t\t}\n\t\t\t\t\tthis.reasonForCompleteSnapshot = \"join response\";\n\t\t\t\t}\n\t\t\t\tif (this.broadcastRequests.size > 0) {\n\t\t\t\t\tfor (const responseFor of joinResponseFor) {\n\t\t\t\t\t\tthis.broadcastRequests.delete(responseFor);\n\t\t\t\t\t}\n\t\t\t\t\tif (this.broadcastRequests.size === 0) {\n\t\t\t\t\t\t// If no more requests are pending, clear any timer.\n\t\t\t\t\t\tthis.broadcastRequestsTimer.clearTimeout();\n\t\t\t\t\t} else if (justGainedCompleteSnapshot) {\n\t\t\t\t\t\t// May or may not be time to respond to remaining requests.\n\t\t\t\t\t\t// Clear the timer and recheck after processing.\n\t\t\t\t\t\tthis.broadcastRequestsTimer.clearTimeout();\n\t\t\t\t\t\tpostUpdateActions.push(this.sendJoinResponseIfStillNeeded);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// If the message requests an acknowledgement, we will send a targeted acknowledgement message back to just the requestor.\n\t\t\tif (message.content.acknowledgementId !== undefined) {\n\t\t\t\tassert(\n\t\t\t\t\tthis.targetedSignalSupport,\n\t\t\t\t\t\"Acknowledgment message was requested while targeted signal capability is not supported\",\n\t\t\t\t);\n\t\t\t\tthis.runtime.submitSignal({\n\t\t\t\t\ttype: acknowledgementMessageType,\n\t\t\t\t\tcontent: { id: message.content.acknowledgementId },\n\t\t\t\t\ttargetClientId: message.clientId,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\t// Handle activation of unregistered workspaces before processing updates.\n\t\tfor (const [workspaceAddress] of objectEntries(message.content.data)) {\n\t\t\t// The first part of OR condition checks if workspace is already registered.\n\t\t\t// The second part checks if the workspace has already been seen before.\n\t\t\t// In either case we can skip emitting 'workspaceActivated' event.\n\t\t\tif (this.workspaces.has(workspaceAddress) || this.datastore[workspaceAddress]) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// Separate internal type prefix from public workspace address\n\t\t\tconst match = /^([^:]):([^:]+:.+)$/.exec(workspaceAddress) as\n\t\t\t\t| null\n\t\t\t\t| [string, string, WorkspaceAddress];\n\n\t\t\tif (match === null) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst prefix = match[1];\n\t\t\tconst publicWorkspaceAddress = match[2];\n\n\t\t\tconst internalWorkspaceType = internalWorkspaceTypes[prefix] ?? \"Unknown\";\n\n\t\t\tthis.events.emit(\"workspaceActivated\", publicWorkspaceAddress, internalWorkspaceType);\n\t\t}\n\n\t\t// While the system workspace is processed here too, it is declared as\n\t\t// conforming to the general schema. So drop its override.\n\t\tconst data = message.content.data as Omit<typeof message.content.data, \"system:presence\">;\n\t\tfor (const [workspaceAddress, remoteDatastore] of objectEntries(data)) {\n\t\t\t// Direct to the appropriate Presence Workspace, if present.\n\t\t\tconst workspace = this.workspaces.get(workspaceAddress);\n\t\t\tif (workspace) {\n\t\t\t\tpostUpdateActions.push(\n\t\t\t\t\t...workspace.internal.processUpdate(\n\t\t\t\t\t\treceived,\n\t\t\t\t\t\ttimeModifier,\n\t\t\t\t\t\tremoteDatastore,\n\t\t\t\t\t\tmessage.clientId,\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\t// All broadcast state is kept even if not currently registered, unless a value\n\t\t\t\t// notes itself to be ignored.\n\n\t\t\t\t// Ensure there is a datastore at this address and get it.\n\t\t\t\tconst workspaceDatastore = (this.datastore[workspaceAddress] ??= {});\n\t\t\t\tfor (const [key, remoteAllKnownState] of Object.entries(remoteDatastore)) {\n\t\t\t\t\tmergeUntrackedDatastore(key, remoteAllKnownState, workspaceDatastore, timeModifier);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tfor (const action of postUpdateActions) {\n\t\t\taction();\n\t\t}\n\t}\n\n\t/**\n\t * Broadcasts a join response (complete datastore update message)\n\t * if there is an outstanding join response request.\n\t */\n\tprivate readonly sendJoinResponseIfStillNeeded = (): void => {\n\t\t// Make sure we are currently connected and a broadcast is still needed.\n\t\t// If not connected, nothing we can do.\n\t\tif (this.runtime.getJoinedStatus() !== \"disconnected\" && this.broadcastRequests.size > 0) {\n\t\t\t// Confirm that of remaining requests, now is the time to respond.\n\t\t\tconst now = Date.now();\n\t\t\tlet minResponseTime = Number.POSITIVE_INFINITY;\n\t\t\tfor (const { deadlineTime } of this.broadcastRequests.values()) {\n\t\t\t\tminResponseTime = Math.min(minResponseTime, deadlineTime);\n\t\t\t}\n\t\t\tif (minResponseTime <= now) {\n\t\t\t\tif (this.reasonForCompleteSnapshot) {\n\t\t\t\t\tthis.broadcastAllKnownState();\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// No response needed yet - schedule a later attempt\n\t\t\t\tthis.broadcastRequestsTimer.setTimeout(\n\t\t\t\t\tthis.sendJoinResponseIfStillNeeded,\n\t\t\t\t\tminResponseTime - now,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t};\n\n\t/**\n\t * Handles responding to another client joining the session.\n\t *\n\t * @param updateProviders - list of client connection id's that requestor selected\n\t * to provide response\n\t * @param requestor - `requestor` is only used in telemetry. While it is the requestor's\n\t * client connection id, that is not most important. It is important that this is a\n\t * unique shared id across all clients that might respond as we want to monitor the\n\t * response patterns. The convenience of being client connection id will allow\n\t * correlation with other telemetry where it is often called just `clientId`.\n\t */\n\tprivate prepareJoinResponse(\n\t\tupdateProviders: ClientConnectionId[],\n\t\trequestor: ClientConnectionId,\n\t): void {\n\t\t// We must be connected to receive this message, so clientId should be defined.\n\t\t// If it isn't then, not really a problem; just won't be in provider or audience list.\n\t\t// eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n\t\tconst selfClientId = this.runtime.getClientId()!;\n\t\tlet joinResponseDelayMs = broadcastJoinResponseDelaysMs.namedResponder;\n\t\tlet relativeResponseOrder: number | undefined;\n\t\tif (!updateProviders.includes(selfClientId)) {\n\t\t\t// Schedule a broadcast to the new client after a delay only to send if\n\t\t\t// another broadcast satisfying the request hasn't been seen in the\n\t\t\t// meantime. The delay is based on the position in the quorum list. It\n\t\t\t// doesn't have to be a stable list across all clients. We need\n\t\t\t// something to provide suggested order to prevent a flood of broadcasts.\n\t\t\tconst quorumMembers = this.runtime.getQuorum().getMembers();\n\t\t\tconst self = quorumMembers.get(selfClientId);\n\t\t\tif (self) {\n\t\t\t\t// Compute order quorum join order (indicated by sequenceNumber)\n\t\t\t\trelativeResponseOrder = 0;\n\t\t\t\tfor (const { client, sequenceNumber } of quorumMembers.values()) {\n\t\t\t\t\tif (\n\t\t\t\t\t\tsequenceNumber < self.sequenceNumber &&\n\t\t\t\t\t\tclient.details.capabilities.interactive\n\t\t\t\t\t) {\n\t\t\t\t\t\trelativeResponseOrder++;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// Order past quorum members + arbitrary additional offset up to 10\n\t\t\t\tlet possibleQuorumRespondents = 0;\n\t\t\t\tfor (const { client } of quorumMembers.values()) {\n\t\t\t\t\tif (client.details.capabilities.interactive) {\n\t\t\t\t\t\tpossibleQuorumRespondents++;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\trelativeResponseOrder = possibleQuorumRespondents + Math.random() * 10;\n\t\t\t}\n\t\t\t// When not named to provide update, wait an additional amount\n\t\t\t// of time for those named or others to respond.\n\t\t\tjoinResponseDelayMs +=\n\t\t\t\tbroadcastJoinResponseDelaysMs.backupResponderIncrement *\n\t\t\t\t(3 * updateProviders.length + relativeResponseOrder);\n\t\t}\n\n\t\t// Add the requestor to the list of clients that will receive the broadcast.\n\t\tconst deadlineTime = Date.now() + joinResponseDelayMs;\n\t\tthis.broadcastRequests.set(requestor, {\n\t\t\tdeadlineTime,\n\t\t\tresponseOrder: relativeResponseOrder,\n\t\t});\n\n\t\tif (!this.reasonForCompleteSnapshot) {\n\t\t\t// Check if requestor count meets or exceeds count of other audience\n\t\t\t// members indicating that we effectively have a complete snapshot\n\t\t\t// (once the current message being processed is processed).\n\t\t\tconst { selfPresent, interactiveMembersExcludingSelf } =\n\t\t\t\tthis.getAudienceInformation(selfClientId);\n\t\t\tif (\n\t\t\t\t// Self-present check is done to help ensure that audience\n\t\t\t\t// information is accurate. If self is not present, audience\n\t\t\t\t// information might be incomplete.\n\t\t\t\tselfPresent &&\n\t\t\t\tthis.broadcastRequests.size >= interactiveMembersExcludingSelf.all.size\n\t\t\t) {\n\t\t\t\t// Note that no action is taken here specifically.\n\t\t\t\t// We want action to be queued so that it takes place after\n\t\t\t\t// current message is completely processed. All of the actions\n\t\t\t\t// below should be delayed (not immediate).\n\t\t\t\tthis.reasonForCompleteSnapshot = \"full requests\";\n\t\t\t}\n\t\t}\n\n\t\t// Check if capable of full primary response. If requested to provide\n\t\t// primary response, but do not yet have complete snapshot, we need to\n\t\t// delay a full response, until we think we have complete snapshot. In\n\t\t// the meantime we will send partial updates as usual.\n\t\tif (this.reasonForCompleteSnapshot && updateProviders.includes(selfClientId)) {\n\t\t\t// Use regular message queue to handle timing of the broadcast.\n\t\t\t// Any more immediate broadcasts will accelerate the response time.\n\t\t\t// As a primary responder, it is expected that broadcast will happen and\n\t\t\t// using the regular queue allows other updates to avoid merge work.\n\t\t\tthis.enqueueMessage(\"sendAll\", {\n\t\t\t\tallowableUpdateLatencyMs: joinResponseDelayMs,\n\t\t\t});\n\t\t} else {\n\t\t\t// Check if there isn't already a timer scheduled to send a join\n\t\t\t// response with in this request's deadline.\n\t\t\tif (\n\t\t\t\tthis.broadcastRequestsTimer.hasExpired() ||\n\t\t\t\tdeadlineTime < this.broadcastRequestsTimer.expireTime\n\t\t\t) {\n\t\t\t\t// Set or update the timer.\n\t\t\t\tthis.broadcastRequestsTimer.setTimeout(\n\t\t\t\t\tthis.sendJoinResponseIfStillNeeded,\n\t\t\t\t\tjoinResponseDelayMs,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fluidframework/presence",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.74.0-365691",
|
|
4
4
|
"description": "A component for lightweight data sharing within a single session",
|
|
5
5
|
"homepage": "https://fluidframework.com",
|
|
6
6
|
"repository": {
|
|
@@ -73,31 +73,31 @@
|
|
|
73
73
|
"temp-directory": "nyc/.nyc_output"
|
|
74
74
|
},
|
|
75
75
|
"dependencies": {
|
|
76
|
-
"@fluid-internal/client-utils": "
|
|
77
|
-
"@fluidframework/container-definitions": "
|
|
78
|
-
"@fluidframework/container-runtime-definitions": "
|
|
79
|
-
"@fluidframework/core-interfaces": "
|
|
80
|
-
"@fluidframework/core-utils": "
|
|
81
|
-
"@fluidframework/datastore": "
|
|
82
|
-
"@fluidframework/datastore-definitions": "
|
|
83
|
-
"@fluidframework/fluid-static": "
|
|
84
|
-
"@fluidframework/id-compressor": "
|
|
85
|
-
"@fluidframework/runtime-definitions": "
|
|
86
|
-
"@fluidframework/runtime-utils": "
|
|
87
|
-
"@fluidframework/shared-object-base": "
|
|
88
|
-
"@fluidframework/telemetry-utils": "
|
|
76
|
+
"@fluid-internal/client-utils": "2.74.0-365691",
|
|
77
|
+
"@fluidframework/container-definitions": "2.74.0-365691",
|
|
78
|
+
"@fluidframework/container-runtime-definitions": "2.74.0-365691",
|
|
79
|
+
"@fluidframework/core-interfaces": "2.74.0-365691",
|
|
80
|
+
"@fluidframework/core-utils": "2.74.0-365691",
|
|
81
|
+
"@fluidframework/datastore": "2.74.0-365691",
|
|
82
|
+
"@fluidframework/datastore-definitions": "2.74.0-365691",
|
|
83
|
+
"@fluidframework/fluid-static": "2.74.0-365691",
|
|
84
|
+
"@fluidframework/id-compressor": "2.74.0-365691",
|
|
85
|
+
"@fluidframework/runtime-definitions": "2.74.0-365691",
|
|
86
|
+
"@fluidframework/runtime-utils": "2.74.0-365691",
|
|
87
|
+
"@fluidframework/shared-object-base": "2.74.0-365691",
|
|
88
|
+
"@fluidframework/telemetry-utils": "2.74.0-365691"
|
|
89
89
|
},
|
|
90
90
|
"devDependencies": {
|
|
91
91
|
"@arethetypeswrong/cli": "^0.17.1",
|
|
92
92
|
"@biomejs/biome": "~1.9.3",
|
|
93
|
-
"@fluid-internal/mocha-test-setup": "
|
|
93
|
+
"@fluid-internal/mocha-test-setup": "2.74.0-365691",
|
|
94
94
|
"@fluid-tools/build-cli": "^0.60.0",
|
|
95
95
|
"@fluidframework/build-common": "^2.0.3",
|
|
96
96
|
"@fluidframework/build-tools": "^0.60.0",
|
|
97
|
-
"@fluidframework/driver-definitions": "
|
|
98
|
-
"@fluidframework/eslint-config-fluid": "
|
|
99
|
-
"@fluidframework/test-runtime-utils": "
|
|
100
|
-
"@fluidframework/test-utils": "
|
|
97
|
+
"@fluidframework/driver-definitions": "2.74.0-365691",
|
|
98
|
+
"@fluidframework/eslint-config-fluid": "2.74.0-365691",
|
|
99
|
+
"@fluidframework/test-runtime-utils": "2.74.0-365691",
|
|
100
|
+
"@fluidframework/test-utils": "2.74.0-365691",
|
|
101
101
|
"@microsoft/api-extractor": "7.52.11",
|
|
102
102
|
"@types/mocha": "^10.0.10",
|
|
103
103
|
"@types/node": "^18.19.0",
|