@fluidframework/presence 2.41.0-338186 → 2.41.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (163) hide show
  1. package/README.md +6 -10
  2. package/dist/alpha.d.ts +18 -14
  3. package/dist/baseTypes.d.ts +1 -1
  4. package/dist/baseTypes.js.map +1 -1
  5. package/dist/beta.d.ts +53 -0
  6. package/dist/broadcastControls.d.ts +2 -2
  7. package/dist/broadcastControls.js.map +1 -1
  8. package/dist/datastorePresenceManagerFactory.d.ts +4 -1
  9. package/dist/datastorePresenceManagerFactory.d.ts.map +1 -1
  10. package/dist/datastorePresenceManagerFactory.js +23 -3
  11. package/dist/datastorePresenceManagerFactory.js.map +1 -1
  12. package/dist/experimentalAccess.d.ts +12 -4
  13. package/dist/experimentalAccess.d.ts.map +1 -1
  14. package/dist/experimentalAccess.js +24 -17
  15. package/dist/experimentalAccess.js.map +1 -1
  16. package/dist/exposedInternalTypes.d.ts +1 -1
  17. package/dist/exposedInternalTypes.js +1 -1
  18. package/dist/exposedInternalTypes.js.map +1 -1
  19. package/dist/index.d.ts +2 -2
  20. package/dist/index.d.ts.map +1 -1
  21. package/dist/index.js +2 -1
  22. package/dist/index.js.map +1 -1
  23. package/dist/internalTypes.d.ts +25 -6
  24. package/dist/internalTypes.d.ts.map +1 -1
  25. package/dist/internalTypes.js.map +1 -1
  26. package/dist/internalUtils.d.ts +9 -4
  27. package/dist/internalUtils.d.ts.map +1 -1
  28. package/dist/internalUtils.js +5 -0
  29. package/dist/internalUtils.js.map +1 -1
  30. package/dist/latestMapValueManager.d.ts +8 -8
  31. package/dist/latestMapValueManager.js +1 -1
  32. package/dist/latestMapValueManager.js.map +1 -1
  33. package/dist/latestValueManager.d.ts +4 -4
  34. package/dist/latestValueManager.js +1 -1
  35. package/dist/latestValueManager.js.map +1 -1
  36. package/dist/latestValueTypes.d.ts +3 -3
  37. package/dist/latestValueTypes.js.map +1 -1
  38. package/dist/notificationsManager.d.ts +1 -1
  39. package/dist/notificationsManager.d.ts.map +1 -1
  40. package/dist/notificationsManager.js.map +1 -1
  41. package/dist/package.json +5 -4
  42. package/dist/presence.d.ts +19 -8
  43. package/dist/presence.d.ts.map +1 -1
  44. package/dist/presence.js +1 -1
  45. package/dist/presence.js.map +1 -1
  46. package/dist/presenceDatastoreManager.d.ts +6 -37
  47. package/dist/presenceDatastoreManager.d.ts.map +1 -1
  48. package/dist/presenceDatastoreManager.js +33 -31
  49. package/dist/presenceDatastoreManager.js.map +1 -1
  50. package/dist/presenceManager.d.ts +5 -5
  51. package/dist/presenceManager.d.ts.map +1 -1
  52. package/dist/presenceManager.js +12 -10
  53. package/dist/presenceManager.js.map +1 -1
  54. package/dist/presenceStates.d.ts +1 -1
  55. package/dist/presenceStates.d.ts.map +1 -1
  56. package/dist/presenceStates.js.map +1 -1
  57. package/dist/protocol.d.ts +74 -0
  58. package/dist/protocol.d.ts.map +1 -0
  59. package/dist/protocol.js +16 -0
  60. package/dist/protocol.js.map +1 -0
  61. package/dist/stateDatastore.d.ts +1 -1
  62. package/dist/stateDatastore.d.ts.map +1 -1
  63. package/dist/stateDatastore.js.map +1 -1
  64. package/dist/stateFactory.d.ts +1 -1
  65. package/dist/stateFactory.js +1 -1
  66. package/dist/stateFactory.js.map +1 -1
  67. package/dist/systemWorkspace.js.map +1 -1
  68. package/dist/types.d.ts +9 -8
  69. package/dist/types.d.ts.map +1 -1
  70. package/dist/types.js.map +1 -1
  71. package/lib/alpha.d.ts +18 -14
  72. package/lib/baseTypes.d.ts +1 -1
  73. package/lib/baseTypes.js.map +1 -1
  74. package/lib/beta.d.ts +53 -0
  75. package/lib/broadcastControls.d.ts +2 -2
  76. package/lib/broadcastControls.js.map +1 -1
  77. package/lib/datastorePresenceManagerFactory.d.ts +4 -1
  78. package/lib/datastorePresenceManagerFactory.d.ts.map +1 -1
  79. package/lib/datastorePresenceManagerFactory.js +23 -3
  80. package/lib/datastorePresenceManagerFactory.js.map +1 -1
  81. package/lib/experimentalAccess.d.ts +12 -4
  82. package/lib/experimentalAccess.d.ts.map +1 -1
  83. package/lib/experimentalAccess.js +22 -15
  84. package/lib/experimentalAccess.js.map +1 -1
  85. package/lib/exposedInternalTypes.d.ts +1 -1
  86. package/lib/exposedInternalTypes.js +1 -1
  87. package/lib/exposedInternalTypes.js.map +1 -1
  88. package/lib/index.d.ts +2 -2
  89. package/lib/index.d.ts.map +1 -1
  90. package/lib/index.js +1 -1
  91. package/lib/index.js.map +1 -1
  92. package/lib/internalTypes.d.ts +25 -6
  93. package/lib/internalTypes.d.ts.map +1 -1
  94. package/lib/internalTypes.js.map +1 -1
  95. package/lib/internalUtils.d.ts +9 -4
  96. package/lib/internalUtils.d.ts.map +1 -1
  97. package/lib/internalUtils.js +5 -0
  98. package/lib/internalUtils.js.map +1 -1
  99. package/lib/latestMapValueManager.d.ts +8 -8
  100. package/lib/latestMapValueManager.js +1 -1
  101. package/lib/latestMapValueManager.js.map +1 -1
  102. package/lib/latestValueManager.d.ts +4 -4
  103. package/lib/latestValueManager.js +1 -1
  104. package/lib/latestValueManager.js.map +1 -1
  105. package/lib/latestValueTypes.d.ts +3 -3
  106. package/lib/latestValueTypes.js.map +1 -1
  107. package/lib/notificationsManager.d.ts +1 -1
  108. package/lib/notificationsManager.d.ts.map +1 -1
  109. package/lib/notificationsManager.js.map +1 -1
  110. package/lib/presence.d.ts +19 -8
  111. package/lib/presence.d.ts.map +1 -1
  112. package/lib/presence.js +1 -1
  113. package/lib/presence.js.map +1 -1
  114. package/lib/presenceDatastoreManager.d.ts +6 -37
  115. package/lib/presenceDatastoreManager.d.ts.map +1 -1
  116. package/lib/presenceDatastoreManager.js +32 -30
  117. package/lib/presenceDatastoreManager.js.map +1 -1
  118. package/lib/presenceManager.d.ts +5 -5
  119. package/lib/presenceManager.d.ts.map +1 -1
  120. package/lib/presenceManager.js +12 -10
  121. package/lib/presenceManager.js.map +1 -1
  122. package/lib/presenceStates.d.ts +1 -1
  123. package/lib/presenceStates.d.ts.map +1 -1
  124. package/lib/presenceStates.js.map +1 -1
  125. package/lib/protocol.d.ts +74 -0
  126. package/lib/protocol.d.ts.map +1 -0
  127. package/lib/protocol.js +13 -0
  128. package/lib/protocol.js.map +1 -0
  129. package/lib/stateDatastore.d.ts +1 -1
  130. package/lib/stateDatastore.d.ts.map +1 -1
  131. package/lib/stateDatastore.js.map +1 -1
  132. package/lib/stateFactory.d.ts +1 -1
  133. package/lib/stateFactory.js +1 -1
  134. package/lib/stateFactory.js.map +1 -1
  135. package/lib/systemWorkspace.js.map +1 -1
  136. package/lib/types.d.ts +9 -8
  137. package/lib/types.d.ts.map +1 -1
  138. package/lib/types.js.map +1 -1
  139. package/package.json +30 -23
  140. package/dist/container-definitions/containerExtensions.d.ts +0 -137
  141. package/dist/container-definitions/containerExtensions.d.ts.map +0 -1
  142. package/dist/container-definitions/containerExtensions.js +0 -7
  143. package/dist/container-definitions/containerExtensions.js.map +0 -1
  144. package/dist/container-definitions/index.d.ts +0 -7
  145. package/dist/container-definitions/index.d.ts.map +0 -1
  146. package/dist/container-definitions/index.js +0 -7
  147. package/dist/container-definitions/index.js.map +0 -1
  148. package/dist/container-definitions/runtime.d.ts +0 -12
  149. package/dist/container-definitions/runtime.d.ts.map +0 -1
  150. package/dist/container-definitions/runtime.js +0 -7
  151. package/dist/container-definitions/runtime.js.map +0 -1
  152. package/lib/container-definitions/containerExtensions.d.ts +0 -137
  153. package/lib/container-definitions/containerExtensions.d.ts.map +0 -1
  154. package/lib/container-definitions/containerExtensions.js +0 -6
  155. package/lib/container-definitions/containerExtensions.js.map +0 -1
  156. package/lib/container-definitions/index.d.ts +0 -7
  157. package/lib/container-definitions/index.d.ts.map +0 -1
  158. package/lib/container-definitions/index.js +0 -6
  159. package/lib/container-definitions/index.js.map +0 -1
  160. package/lib/container-definitions/runtime.d.ts +0 -12
  161. package/lib/container-definitions/runtime.d.ts.map +0 -1
  162. package/lib/container-definitions/runtime.js +0 -6
  163. package/lib/container-definitions/runtime.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"presence.d.ts","sourceRoot":"","sources":["../src/presence.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iCAAiC,CAAC;AAClE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,+BAA+B,CAAC;AAE/D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AACzD,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,wBAAwB,CAAC;AACvE,OAAO,KAAK,EACX,sBAAsB,EACtB,4BAA4B,EAC5B,eAAe,EACf,qBAAqB,EACrB,gBAAgB,EAChB,MAAM,YAAY,CAAC;AAEpB;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,UAAU,GAAG,SAAS,GAAG;IAAE,QAAQ,CAAC,UAAU,EAAE,YAAY,CAAA;CAAE,CAAC;AAE3E;;;;GAIG;AACH,eAAO,MAAM,cAAc;IAC1B;;OAEG;;IAGH;;OAEG;;CAEM,CAAC;AAEX;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,cAAc,GAAG,CAAC,OAAO,cAAc,CAAC,CAAC,MAAM,OAAO,cAAc,CAAC,CAAC;AAElF;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,WAAW,QAAQ,CAAC,kBAAkB,SAAS,UAAU,GAAG,UAAU;IAC3E;;OAEG;IACH,QAAQ,CAAC,UAAU,EAAE,kBAAkB,CAAC;IAExC;;;;;;;;;OASG;IACH,eAAe,IAAI,kBAAkB,CAAC;IAEtC;;;;;OAKG;IACH,mBAAmB,IAAI,cAAc,CAAC;CACtC;AAED;;;;;GAKG;AACH,MAAM,MAAM,gBAAgB,CAAC,kBAAkB,SAAS,UAAU,IACjE,MAAM,SAAS,kBAAkB,GAAG,KAAK,GAAG,QAAQ,CAAC,kBAAkB,CAAC,CAAC;AAE1E;;;GAGG;AACH,MAAM,WAAW,eAAe;IAC/B;;;;OAIG;IACH,iBAAiB,EAAE,CAAC,QAAQ,EAAE,QAAQ,KAAK,IAAI,CAAC;IAEhD;;;;OAIG;IACH,oBAAoB,EAAE,CAAC,QAAQ,EAAE,QAAQ,KAAK,IAAI,CAAC;CACnD;AAED;;;GAGG;AACH,MAAM,WAAW,cAAc;IAC9B;;;;;;;;;;;OAWG;IACH,kBAAkB,EAAE,CACnB,gBAAgB,EAAE,gBAAgB,EAClC,IAAI,EAAE,QAAQ,GAAG,eAAe,GAAG,SAAS,KACxC,IAAI,CAAC;CACV;AAED;;;;;GAKG;AACH,MAAM,WAAW,QAAQ;IACxB;;OAEG;IACH,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC,cAAc,CAAC,CAAC;IAE5C,QAAQ,CAAC,SAAS,EAAE;QACnB;;WAEG;QACH,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC,eAAe,CAAC,CAAC;QAE7C;;;;;;WAMG;QACH,YAAY,IAAI,WAAW,CAAC,QAAQ,CAAC,CAAC;QAEtC;;;;WAIG;QACH,WAAW,CAAC,QAAQ,EAAE,kBAAkB,GAAG,UAAU,GAAG,QAAQ,CAAC;QAEjE;;;;WAIG;QACH,SAAS,IAAI,QAAQ,CAAC;KACtB,CAAC;IAEF,QAAQ,CAAC,MAAM,EAAE;QAChB;;;;;;;WAOG;QACH,YAAY,CAAC,YAAY,SAAS,qBAAqB,EACtD,gBAAgB,EAAE,gBAAgB,EAClC,eAAe,EAAE,YAAY,EAC7B,QAAQ,CAAC,EAAE,wBAAwB,GACjC,eAAe,CAAC,YAAY,CAAC,CAAC;KACjC,CAAC;IAEF,QAAQ,CAAC,aAAa,EAAE;QACvB;;;;;;WAMG;QACH,YAAY,CAAC,mBAAmB,SAAS,4BAA4B,EACpE,eAAe,EAAE,gBAAgB,EACjC,sBAAsB,EAAE,mBAAmB,GACzC,sBAAsB,CAAC,mBAAmB,CAAC,CAAC;KAC/C,CAAC;CACF"}
1
+ {"version":3,"file":"presence.d.ts","sourceRoot":"","sources":["../src/presence.ts"],"names":[],"mappings":"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"}
package/lib/presence.js CHANGED
@@ -5,7 +5,7 @@
5
5
  /**
6
6
  * The connection status of the {@link Attendee}.
7
7
  *
8
- * @alpha
8
+ * @beta
9
9
  */
10
10
  export const AttendeeStatus = {
11
11
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"presence.js","sourceRoot":"","sources":["../src/presence.ts"],"names":[],"mappings":"AAAA;;;GAGG;AA6BH;;;;GAIG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG;IAC7B;;OAEG;IACH,SAAS,EAAE,WAAW;IAEtB;;OAEG;IACH,YAAY,EAAE,cAAc;CACnB,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport type { Listenable } from \"@fluidframework/core-interfaces\";\nimport type { SessionId } from \"@fluidframework/id-compressor\";\n\nimport type { ClientConnectionId } from \"./baseTypes.js\";\nimport type { BroadcastControlSettings } from \"./broadcastControls.js\";\nimport type {\n\tNotificationsWorkspace,\n\tNotificationsWorkspaceSchema,\n\tStatesWorkspace,\n\tStatesWorkspaceSchema,\n\tWorkspaceAddress,\n} from \"./types.js\";\n\n/**\n * A Fluid client session identifier.\n *\n * @remarks\n * Each client once connected to a session is given a unique identifier for the\n * duration of the session. If a client disconnects and reconnects, it will\n * retain its identifier. Prefer use of {@link Attendee} as a way to\n * identify clients in a session. {@link Attendee.attendeeId} will provide\n * the session ID.\n *\n * @alpha\n */\nexport type AttendeeId = SessionId & { readonly AttendeeId: \"AttendeeId\" };\n\n/**\n * The connection status of the {@link Attendee}.\n *\n * @alpha\n */\nexport const AttendeeStatus = {\n\t/**\n\t * The {@link Attendee} is connected to the Fluid service.\n\t */\n\tConnected: \"Connected\",\n\n\t/**\n\t * The {@link Attendee} is not connected to the Fluid service.\n\t */\n\tDisconnected: \"Disconnected\",\n} as const;\n\n/**\n * Represents the connection status of an {@link Attendee}.\n *\n * This type can be either `'Connected'` or `'Disconnected'`, indicating whether\n * the attendee is currently connected to the Fluid service.\n *\n * When `'Disconnected'`:\n * - State changes are kept locally and communicated to others upon reconnect.\n * - Notification requests are discarded (silently).\n *\n * @alpha\n */\nexport type AttendeeStatus = (typeof AttendeeStatus)[keyof typeof AttendeeStatus];\n\n/**\n * A client within a Fluid session (period of container connectivity to service).\n *\n * @remarks\n * Note: This is very preliminary attendee representation.\n *\n * {@link Attendee} should be used as key to distinguish between different\n * clients as they join, rejoin, and disconnect from a session. While a\n * client's {@link ClientConnectionId} from {@link Attendee.getConnectionStatus}\n * may change over time, `Attendee` will be fixed.\n *\n * @privateRemarks\n * As this is evolved, pay attention to how this relates to Audience, Service\n * Audience, and Quorum representations of clients and users.\n *\n * @sealed\n * @alpha\n */\nexport interface Attendee<SpecificAttendeeId extends AttendeeId = AttendeeId> {\n\t/**\n\t * The session ID of the client that is stable over all connections.\n\t */\n\treadonly attendeeId: SpecificAttendeeId;\n\n\t/**\n\t * Get current client connection ID.\n\t *\n\t * @returns Current client connection ID.\n\t *\n\t * @remarks\n\t * Connection ID will change on reconnect.\n\t *\n\t * If {@link Attendee.getConnectionStatus} is {@link (AttendeeStatus:variable).Disconnected}, this will represent the last known connection ID.\n\t */\n\tgetConnectionId(): ClientConnectionId;\n\n\t/**\n\t * Get connection status of attendee.\n\t *\n\t * @returns Connection status of attendee.\n\t *\n\t */\n\tgetConnectionStatus(): AttendeeStatus;\n}\n\n/**\n * Utility type limiting to a specific attendee. (A attendee with\n * a specific session ID - not just any session ID.)\n *\n * @internal\n */\nexport type SpecificAttendee<SpecificAttendeeId extends AttendeeId> =\n\tstring extends SpecificAttendeeId ? never : Attendee<SpecificAttendeeId>;\n\n/**\n * @sealed\n * @alpha\n */\nexport interface AttendeesEvents {\n\t/**\n\t * Raised when new client joins session.\n\t *\n\t * @eventProperty\n\t */\n\tattendeeConnected: (attendee: Attendee) => void;\n\n\t/**\n\t * Raised when client appears disconnected from session.\n\t *\n\t * @eventProperty\n\t */\n\tattendeeDisconnected: (attendee: Attendee) => void;\n}\n\n/**\n * @sealed\n * @alpha\n */\nexport interface PresenceEvents {\n\t/**\n\t * Raised when a workspace is activated within the session.\n\t *\n\t * \"Activated\" means that a workspace is being used by a client and this\n\t * client is seeing information for the first time.\n\t *\n\t * @remarks\n\t * Local workspaces may be passively acquired/registered when this event\n\t * is raised. For a notifications workspace, that lazy registration must\n\t * be done before the event handler returns to ensure no notifications\n\t * are missed.\n\t */\n\tworkspaceActivated: (\n\t\tworkspaceAddress: WorkspaceAddress,\n\t\ttype: \"States\" | \"Notifications\" | \"Unknown\",\n\t) => void;\n}\n\n/**\n * Presence represents known clients within a session and their custom states and notifications.\n *\n * @sealed\n * @alpha\n */\nexport interface Presence {\n\t/**\n\t * Events for Presence.\n\t */\n\treadonly events: Listenable<PresenceEvents>;\n\n\treadonly attendees: {\n\t\t/**\n\t\t * Events for {@link Attendee}s.\n\t\t */\n\t\treadonly events: Listenable<AttendeesEvents>;\n\n\t\t/**\n\t\t * Get all {@link Attendee}s in the session.\n\t\t *\n\t\t * @remarks\n\t\t * Attendee states are dynamic and will change as clients join and leave\n\t\t * the session.\n\t\t */\n\t\tgetAttendees(): ReadonlySet<Attendee>;\n\n\t\t/**\n\t\t * Lookup a specific {@link Attendee} in the session.\n\t\t *\n\t\t * @param clientId - Client connection or session ID\n\t\t */\n\t\tgetAttendee(clientId: ClientConnectionId | AttendeeId): Attendee;\n\n\t\t/**\n\t\t * Get this client's {@link Attendee}.\n\t\t *\n\t\t * @returns This client's attendee.\n\t\t */\n\t\tgetMyself(): Attendee;\n\t};\n\n\treadonly states: {\n\t\t/**\n\t\t * Acquires a StatesWorkspace from store or adds new one.\n\t\t *\n\t\t * @param workspaceAddress - Address of the requested StatesWorkspace\n\t\t * @param requestedStates - Requested states for the workspace\n\t\t * @param controls - Optional settings for default broadcast controls\n\t\t * @returns A StatesWorkspace\n\t\t */\n\t\tgetWorkspace<StatesSchema extends StatesWorkspaceSchema>(\n\t\t\tworkspaceAddress: WorkspaceAddress,\n\t\t\trequestedStates: StatesSchema,\n\t\t\tcontrols?: BroadcastControlSettings,\n\t\t): StatesWorkspace<StatesSchema>;\n\t};\n\n\treadonly notifications: {\n\t\t/**\n\t\t * Acquires a Notifications workspace from store or adds new one.\n\t\t *\n\t\t * @param workspaceAddress - Address of the requested Notifications Workspace\n\t\t * @param requestedNotifications - Requested notifications for the workspace\n\t\t * @returns A Notifications workspace\n\t\t */\n\t\tgetWorkspace<NotificationsSchema extends NotificationsWorkspaceSchema>(\n\t\t\tnotificationsId: WorkspaceAddress,\n\t\t\trequestedNotifications: NotificationsSchema,\n\t\t): NotificationsWorkspace<NotificationsSchema>;\n\t};\n}\n"]}
1
+ {"version":3,"file":"presence.js","sourceRoot":"","sources":["../src/presence.ts"],"names":[],"mappings":"AAAA;;;GAGG;AA6BH;;;;GAIG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG;IAC7B;;OAEG;IACH,SAAS,EAAE,WAAW;IAEtB;;OAEG;IACH,YAAY,EAAE,cAAc;CACnB,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport type { Listenable } from \"@fluidframework/core-interfaces\";\nimport type { SessionId } from \"@fluidframework/id-compressor\";\n\nimport type { ClientConnectionId } from \"./baseTypes.js\";\nimport type { BroadcastControlSettings } from \"./broadcastControls.js\";\nimport type {\n\tNotificationsWorkspace,\n\tNotificationsWorkspaceSchema,\n\tStatesWorkspace,\n\tStatesWorkspaceSchema,\n\tWorkspaceAddress,\n} from \"./types.js\";\n\n/**\n * A Fluid client session identifier.\n *\n * @remarks\n * Each client once connected to a session is given a unique identifier for the\n * duration of the session. If a client disconnects and reconnects, it will\n * retain its identifier. Prefer use of {@link Attendee} as a way to\n * identify clients in a session. {@link Attendee.attendeeId} will provide\n * the session ID.\n *\n * @beta\n */\nexport type AttendeeId = SessionId & { readonly AttendeeId: \"AttendeeId\" };\n\n/**\n * The connection status of the {@link Attendee}.\n *\n * @beta\n */\nexport const AttendeeStatus = {\n\t/**\n\t * The {@link Attendee} is connected to the Fluid service.\n\t */\n\tConnected: \"Connected\",\n\n\t/**\n\t * The {@link Attendee} is not connected to the Fluid service.\n\t */\n\tDisconnected: \"Disconnected\",\n} as const;\n\n/**\n * Represents the connection status of an {@link Attendee}.\n *\n * This type can be either `'Connected'` or `'Disconnected'`, indicating whether\n * the attendee is currently connected to the Fluid service.\n *\n * When `'Disconnected'`:\n * - State changes are kept locally and communicated to others upon reconnect.\n * - Notification requests are discarded (silently).\n *\n * @beta\n */\nexport type AttendeeStatus = (typeof AttendeeStatus)[keyof typeof AttendeeStatus];\n\n/**\n * A client within a Fluid session (period of container connectivity to service).\n *\n * @remarks\n * Note: This is very preliminary attendee representation.\n *\n * {@link Attendee} should be used as key to distinguish between different\n * clients as they join, rejoin, and disconnect from a session. While a\n * client's {@link ClientConnectionId} from {@link Attendee.getConnectionStatus}\n * may change over time, `Attendee` will be fixed.\n *\n * @privateRemarks\n * As this is evolved, pay attention to how this relates to Audience, Service\n * Audience, and Quorum representations of clients and users.\n *\n * @sealed\n * @beta\n */\nexport interface Attendee<SpecificAttendeeId extends AttendeeId = AttendeeId> {\n\t/**\n\t * The session ID of the client that is stable over all connections.\n\t */\n\treadonly attendeeId: SpecificAttendeeId;\n\n\t/**\n\t * Get current client connection ID.\n\t *\n\t * @returns Current client connection ID.\n\t *\n\t * @remarks\n\t * Connection ID will change on reconnect.\n\t *\n\t * If {@link Attendee.getConnectionStatus} is {@link (AttendeeStatus:variable).Disconnected}, this will represent the last known connection ID.\n\t */\n\tgetConnectionId(): ClientConnectionId;\n\n\t/**\n\t * Get connection status of attendee.\n\t *\n\t * @returns Connection status of attendee.\n\t *\n\t */\n\tgetConnectionStatus(): AttendeeStatus;\n}\n\n/**\n * Utility type limiting to a specific attendee. (A attendee with\n * a specific session ID - not just any session ID.)\n *\n * @internal\n */\nexport type SpecificAttendee<SpecificAttendeeId extends AttendeeId> =\n\tstring extends SpecificAttendeeId ? never : Attendee<SpecificAttendeeId>;\n\n/**\n * @sealed\n * @beta\n */\nexport interface AttendeesEvents {\n\t/**\n\t * Raised when new client joins session.\n\t *\n\t * @eventProperty\n\t */\n\tattendeeConnected: (attendee: Attendee) => void;\n\n\t/**\n\t * Raised when client appears disconnected from session.\n\t *\n\t * @eventProperty\n\t */\n\tattendeeDisconnected: (attendee: Attendee) => void;\n}\n\n/**\n * @sealed\n * @beta\n */\nexport interface PresenceEvents {\n\t/**\n\t * Raised when a workspace is activated within the session.\n\t *\n\t * \"Activated\" means that a workspace is being used by a client and this\n\t * client is seeing information for the first time.\n\t *\n\t * @remarks\n\t * Local workspaces may be passively acquired/registered when this event\n\t * is raised. For a notifications workspace, that lazy registration must\n\t * be done before the event handler returns to ensure no notifications\n\t * are missed.\n\t */\n\tworkspaceActivated: (\n\t\tworkspaceAddress: WorkspaceAddress,\n\t\ttype: \"States\" | \"Notifications\" | \"Unknown\",\n\t) => void;\n}\n\n/**\n * Presence represents known clients within a session and their custom states.\n *\n * @sealed\n * @beta\n */\nexport interface Presence {\n\t/**\n\t * Events for Presence.\n\t */\n\treadonly events: Listenable<PresenceEvents>;\n\n\treadonly attendees: {\n\t\t/**\n\t\t * Events for {@link Attendee}s.\n\t\t */\n\t\treadonly events: Listenable<AttendeesEvents>;\n\n\t\t/**\n\t\t * Get all {@link Attendee}s in the session.\n\t\t *\n\t\t * @remarks\n\t\t * Attendee states are dynamic and will change as clients join and leave\n\t\t * the session.\n\t\t */\n\t\tgetAttendees(): ReadonlySet<Attendee>;\n\n\t\t/**\n\t\t * Lookup a specific {@link Attendee} in the session.\n\t\t *\n\t\t * @param clientId - Client connection or session ID\n\t\t */\n\t\tgetAttendee(clientId: ClientConnectionId | AttendeeId): Attendee;\n\n\t\t/**\n\t\t * Get this client's {@link Attendee}.\n\t\t *\n\t\t * @returns This client's attendee.\n\t\t */\n\t\tgetMyself(): Attendee;\n\t};\n\n\treadonly states: {\n\t\t/**\n\t\t * Acquires a StatesWorkspace from store or adds new one.\n\t\t *\n\t\t * @param workspaceAddress - Address of the requested StatesWorkspace\n\t\t * @param requestedStates - Requested states for the workspace\n\t\t * @param controls - Optional settings for default broadcast controls\n\t\t * @returns A StatesWorkspace\n\t\t */\n\t\tgetWorkspace<StatesSchema extends StatesWorkspaceSchema>(\n\t\t\tworkspaceAddress: WorkspaceAddress,\n\t\t\trequestedStates: StatesSchema,\n\t\t\tcontrols?: BroadcastControlSettings,\n\t\t): StatesWorkspace<StatesSchema>;\n\t};\n}\n\n/**\n * Presence represents known clients within a session and their custom states and notifications.\n *\n * @remarks\n * To access this alpha API, cast any `{@link Presence}` to `PresenceWithNotifications`.\n *\n * @sealed\n * @alpha\n */\nexport interface PresenceWithNotifications extends Presence {\n\treadonly notifications: {\n\t\t/**\n\t\t * Acquires a Notifications workspace from store or adds new one.\n\t\t *\n\t\t * @param workspaceAddress - Address of the requested Notifications Workspace\n\t\t * @param requestedNotifications - Requested notifications for the workspace\n\t\t * @returns A Notifications workspace\n\t\t */\n\t\tgetWorkspace<NotificationsSchema extends NotificationsWorkspaceSchema>(\n\t\t\tnotificationsId: WorkspaceAddress,\n\t\t\trequestedNotifications: NotificationsSchema,\n\t\t): NotificationsWorkspace<NotificationsSchema>;\n\t};\n}\n"]}
@@ -2,53 +2,22 @@
2
2
  * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
3
  * Licensed under the MIT License.
4
4
  */
5
+ import type { InboundExtensionMessage } from "@fluidframework/container-runtime-definitions/internal";
5
6
  import type { IEmitter } from "@fluidframework/core-interfaces/internal";
6
- import type { IInboundSignalMessage } from "@fluidframework/runtime-definitions/internal";
7
7
  import type { ITelemetryLoggerExt } from "@fluidframework/telemetry-utils/internal";
8
8
  import type { ClientConnectionId } from "./baseTypes.js";
9
9
  import type { BroadcastControlSettings } from "./broadcastControls.js";
10
10
  import type { IEphemeralRuntime } from "./internalTypes.js";
11
- import type { AttendeeId, Attendee, Presence, PresenceEvents } from "./presence.js";
12
- import type { ClientUpdateEntry, PresenceStatesInternal } from "./presenceStates.js";
11
+ import type { AttendeeId, Attendee, PresenceWithNotifications as Presence, PresenceEvents } from "./presence.js";
12
+ import type { PresenceStatesInternal } from "./presenceStates.js";
13
+ import type { SignalMessages } from "./protocol.js";
13
14
  import type { SystemWorkspaceDatastore } from "./systemWorkspace.js";
14
15
  import type { AnyWorkspace, NotificationsWorkspace, NotificationsWorkspaceSchema, StatesWorkspace, StatesWorkspaceSchema, WorkspaceAddress } from "./types.js";
15
- import type { IExtensionMessage } from "@fluidframework/presence/internal/container-definitions/internal";
16
16
  interface AnyWorkspaceEntry<TSchema extends StatesWorkspaceSchema> {
17
17
  public: AnyWorkspace<TSchema>;
18
18
  internal: PresenceStatesInternal;
19
19
  }
20
- interface SystemDatastore {
21
- "system:presence": SystemWorkspaceDatastore;
22
- }
23
20
  type InternalWorkspaceAddress = `${"s" | "n"}:${WorkspaceAddress}`;
24
- interface GeneralDatastoreMessageContent {
25
- [WorkspaceAddress: string]: {
26
- [StateValueManagerKey: string]: {
27
- [AttendeeId: AttendeeId]: ClientUpdateEntry;
28
- };
29
- };
30
- }
31
- type DatastoreMessageContent = SystemDatastore & GeneralDatastoreMessageContent;
32
- declare const datastoreUpdateMessageType = "Pres:DatastoreUpdate";
33
- interface DatastoreUpdateMessage extends IInboundSignalMessage {
34
- type: typeof datastoreUpdateMessageType;
35
- content: {
36
- sendTimestamp: number;
37
- avgLatency: number;
38
- isComplete?: true;
39
- data: DatastoreMessageContent;
40
- };
41
- }
42
- declare const joinMessageType = "Pres:ClientJoin";
43
- interface ClientJoinMessage extends IInboundSignalMessage {
44
- type: typeof joinMessageType;
45
- content: {
46
- updateProviders: ClientConnectionId[];
47
- sendTimestamp: number;
48
- avgLatency: number;
49
- data: DatastoreMessageContent;
50
- };
51
- }
52
21
  /**
53
22
  * @internal
54
23
  */
@@ -56,7 +25,7 @@ export interface PresenceDatastoreManager {
56
25
  joinSession(clientId: ClientConnectionId): void;
57
26
  getWorkspace<TSchema extends StatesWorkspaceSchema>(internalWorkspaceAddress: `s:${WorkspaceAddress}`, requestedContent: TSchema, controls?: BroadcastControlSettings): StatesWorkspace<TSchema>;
58
27
  getWorkspace<TSchema extends NotificationsWorkspaceSchema>(internalWorkspaceAddress: `n:${WorkspaceAddress}`, requestedContent: TSchema): NotificationsWorkspace<TSchema>;
59
- processSignal(message: IExtensionMessage, local: boolean): void;
28
+ processSignal(message: InboundExtensionMessage<SignalMessages>, local: boolean, optional: boolean): void;
60
29
  }
61
30
  /**
62
31
  * Manages singleton datastore for all Presence.
@@ -91,7 +60,7 @@ export declare class PresenceDatastoreManagerImpl implements PresenceDatastoreMa
91
60
  */
92
61
  private sendQueuedMessage;
93
62
  private broadcastAllKnownState;
94
- processSignal(message: IInboundSignalMessage | DatastoreUpdateMessage | ClientJoinMessage, local: boolean): void;
63
+ processSignal(message: InboundExtensionMessage<SignalMessages>, local: boolean, optional: boolean): void;
95
64
  /**
96
65
  * Handles responding to another client joining the session.
97
66
  *
@@ -1 +1 @@
1
- {"version":3,"file":"presenceDatastoreManager.d.ts","sourceRoot":"","sources":["../src/presenceDatastoreManager.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"presenceDatastoreManager.d.ts","sourceRoot":"","sources":["../src/presenceDatastoreManager.ts"],"names":[],"mappings":"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"}
@@ -5,15 +5,15 @@
5
5
  import { assert } from "@fluidframework/core-utils/internal";
6
6
  import { objectEntries } from "./internalUtils.js";
7
7
  import { createPresenceStates, mergeUntrackedDatastore, mergeValueDirectory, } from "./presenceStates.js";
8
+ import { datastoreUpdateMessageType, joinMessageType } from "./protocol.js";
8
9
  import { TimerManager } from "./timerManager.js";
9
- const datastoreUpdateMessageType = "Pres:DatastoreUpdate";
10
10
  const internalWorkspaceTypes = {
11
11
  s: "States",
12
12
  n: "Notifications",
13
13
  };
14
- const joinMessageType = "Pres:ClientJoin";
14
+ const knownMessageTypes = new Set([joinMessageType, datastoreUpdateMessageType]);
15
15
  function isPresenceMessage(message) {
16
- return message.type.startsWith("Pres:");
16
+ return knownMessageTypes.has(message.type);
17
17
  }
18
18
  function mergeGeneralDatastoreMessageContent(base, newData) {
19
19
  // This function-local "datastore" will hold the merged message data.
@@ -67,11 +67,14 @@ export class PresenceDatastoreManagerImpl {
67
67
  if (updateProviders.length > 3) {
68
68
  updateProviders.length = 3;
69
69
  }
70
- this.runtime.submitSignal(joinMessageType, {
71
- sendTimestamp: Date.now(),
72
- avgLatency: this.averageLatency,
73
- data: this.datastore,
74
- updateProviders,
70
+ this.runtime.submitSignal({
71
+ type: joinMessageType,
72
+ content: {
73
+ sendTimestamp: Date.now(),
74
+ avgLatency: this.averageLatency,
75
+ data: this.datastore,
76
+ updateProviders,
77
+ },
75
78
  });
76
79
  }
77
80
  getWorkspace(internalWorkspaceAddress, requestedContent, controls) {
@@ -85,7 +88,7 @@ export class PresenceDatastoreManagerImpl {
85
88
  }
86
89
  const localUpdate = (states, options) => {
87
90
  // Check for connectivity before sending updates.
88
- if (!this.runtime.connected) {
91
+ if (!this.runtime.isConnected()) {
89
92
  return;
90
93
  }
91
94
  const updates = {};
@@ -148,13 +151,13 @@ export class PresenceDatastoreManagerImpl {
148
151
  return;
149
152
  }
150
153
  // Check for connectivity before sending updates.
151
- if (!this.runtime.connected) {
154
+ if (!this.runtime.isConnected()) {
152
155
  // Clear the queued data since we're disconnected. We don't want messages
153
156
  // to queue infinitely while disconnected.
154
157
  this.queuedData = undefined;
155
158
  return;
156
159
  }
157
- const clientConnectionId = this.runtime.clientId;
160
+ const clientConnectionId = this.runtime.getClientId();
158
161
  assert(clientConnectionId !== undefined, 0xa59 /* Client connected without clientId */);
159
162
  const currentClientToSessionValueState =
160
163
  // When connected, `clientToSessionId` must always have current connection entry.
@@ -178,28 +181,25 @@ export class PresenceDatastoreManagerImpl {
178
181
  },
179
182
  };
180
183
  this.queuedData = undefined;
181
- this.runtime.submitSignal(datastoreUpdateMessageType, newMessage);
184
+ this.runtime.submitSignal({ type: datastoreUpdateMessageType, content: newMessage });
182
185
  }
183
186
  broadcastAllKnownState() {
184
- this.runtime.submitSignal(datastoreUpdateMessageType, {
185
- sendTimestamp: Date.now(),
186
- avgLatency: this.averageLatency,
187
- isComplete: true,
188
- data: this.datastore,
187
+ this.runtime.submitSignal({
188
+ type: datastoreUpdateMessageType,
189
+ content: {
190
+ sendTimestamp: Date.now(),
191
+ avgLatency: this.averageLatency,
192
+ isComplete: true,
193
+ data: this.datastore,
194
+ },
189
195
  });
190
196
  this.refreshBroadcastRequested = false;
191
197
  }
192
- processSignal(
193
- // Note: IInboundSignalMessage is used here in place of IExtensionMessage
194
- // as IExtensionMessage's strictly JSON `content` creates type compatibility
195
- // issues with `AttendeeId` keys and really unknown value content.
196
- // IExtensionMessage is a subset of IInboundSignalMessage so this is safe.
197
- // Change types of DatastoreUpdateMessage | ClientJoinMessage to
198
- // IExtensionMessage<> derivatives to see the issues.
199
- message, local) {
198
+ processSignal(message, local, optional) {
200
199
  const received = Date.now();
201
200
  assert(message.clientId !== null, 0xa3a /* Map received signal without clientId */);
202
201
  if (!isPresenceMessage(message)) {
202
+ assert(optional, "Unrecognized message type in critical message");
203
203
  return;
204
204
  }
205
205
  if (local) {
@@ -220,14 +220,13 @@ export class PresenceDatastoreManagerImpl {
220
220
  // It is possible for some signals to come in while client is not connected due
221
221
  // to how work is scheduled. If we are not connected, we can't respond to the
222
222
  // join request. We will make our own Join request once we are connected.
223
- if (this.runtime.connected) {
223
+ if (this.runtime.isConnected()) {
224
224
  this.prepareJoinResponse(message.content.updateProviders, message.clientId);
225
225
  }
226
226
  // It is okay to continue processing the contained updates even if we are not
227
227
  // connected.
228
228
  }
229
229
  else {
230
- assert(message.type === datastoreUpdateMessageType, 0xa3b /* Unexpected message type */);
231
230
  if (message.content.isComplete) {
232
231
  this.refreshBroadcastRequested = false;
233
232
  }
@@ -251,7 +250,10 @@ export class PresenceDatastoreManagerImpl {
251
250
  this.events.emit("workspaceActivated", publicWorkspaceAddress, internalWorkspaceType);
252
251
  }
253
252
  const postUpdateActions = [];
254
- for (const [workspaceAddress, remoteDatastore] of Object.entries(message.content.data)) {
253
+ // While the system workspace is processed here too, it is declared as
254
+ // conforming to the general schema. So drop its override.
255
+ const data = message.content.data;
256
+ for (const [workspaceAddress, remoteDatastore] of Object.entries(data)) {
255
257
  // Direct to the appropriate Presence Workspace, if present.
256
258
  const workspace = this.workspaces.get(workspaceAddress);
257
259
  if (workspace) {
@@ -287,7 +289,7 @@ export class PresenceDatastoreManagerImpl {
287
289
  // We must be connected to receive this message, so clientId should be defined.
288
290
  // If it isn't then, not really a problem; just won't be in provider or quorum list.
289
291
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
290
- const clientId = this.runtime.clientId;
292
+ const clientId = this.runtime.getClientId();
291
293
  // const requestor = message.clientId;
292
294
  if (updateProviders.includes(clientId)) {
293
295
  // Send all current state to the new client
@@ -330,7 +332,7 @@ export class PresenceDatastoreManagerImpl {
330
332
  setTimeout(() => {
331
333
  // Make sure a broadcast is still needed and we are currently connected.
332
334
  // If not connected, nothing we can do.
333
- if (this.refreshBroadcastRequested && this.runtime.connected) {
335
+ if (this.refreshBroadcastRequested && this.runtime.isConnected()) {
334
336
  this.broadcastAllKnownState();
335
337
  this.logger?.sendTelemetryEvent({
336
338
  eventName: "JoinResponse",
@@ -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 { IEmitter } from \"@fluidframework/core-interfaces/internal\";\nimport { assert } from \"@fluidframework/core-utils/internal\";\nimport type { IInboundSignalMessage } from \"@fluidframework/runtime-definitions/internal\";\nimport type { ITelemetryLoggerExt } from \"@fluidframework/telemetry-utils/internal\";\n\nimport type { ClientConnectionId } from \"./baseTypes.js\";\nimport type { BroadcastControlSettings } from \"./broadcastControls.js\";\nimport type { IEphemeralRuntime, PostUpdateAction } from \"./internalTypes.js\";\nimport { objectEntries } from \"./internalUtils.js\";\nimport type { AttendeeId, Attendee, Presence, PresenceEvents } 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 { 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\nimport type { IExtensionMessage } from \"@fluidframework/presence/internal/container-definitions/internal\";\n\ninterface AnyWorkspaceEntry<TSchema extends StatesWorkspaceSchema> {\n\tpublic: AnyWorkspace<TSchema>;\n\tinternal: PresenceStatesInternal;\n}\n\ninterface SystemDatastore {\n\t\"system:presence\": SystemWorkspaceDatastore;\n}\n\ntype InternalWorkspaceAddress = `${\"s\" | \"n\"}:${WorkspaceAddress}`;\n\ntype PresenceDatastore = SystemDatastore & {\n\t[WorkspaceAddress: string]: ValueElementMap<StatesWorkspaceSchema>;\n};\n\ninterface GeneralDatastoreMessageContent {\n\t[WorkspaceAddress: string]: {\n\t\t[StateValueManagerKey: string]: {\n\t\t\t[AttendeeId: AttendeeId]: ClientUpdateEntry;\n\t\t};\n\t};\n}\n\ntype DatastoreMessageContent = SystemDatastore & GeneralDatastoreMessageContent;\n\nconst datastoreUpdateMessageType = \"Pres:DatastoreUpdate\";\n\nconst internalWorkspaceTypes: Readonly<Record<string, \"States\" | \"Notifications\">> = {\n\ts: \"States\",\n\tn: \"Notifications\",\n} as const;\n\ninterface DatastoreUpdateMessage extends IInboundSignalMessage {\n\ttype: typeof datastoreUpdateMessageType;\n\tcontent: {\n\t\tsendTimestamp: number;\n\t\tavgLatency: number;\n\t\tisComplete?: true;\n\t\tdata: DatastoreMessageContent;\n\t};\n}\n\nconst joinMessageType = \"Pres:ClientJoin\";\ninterface ClientJoinMessage extends IInboundSignalMessage {\n\ttype: typeof joinMessageType;\n\tcontent: {\n\t\tupdateProviders: ClientConnectionId[];\n\t\tsendTimestamp: number;\n\t\tavgLatency: number;\n\t\tdata: DatastoreMessageContent;\n\t};\n}\n\nfunction isPresenceMessage(\n\tmessage: IInboundSignalMessage,\n): message is DatastoreUpdateMessage | ClientJoinMessage {\n\treturn message.type.startsWith(\"Pres:\");\n}\n/**\n * @internal\n */\nexport interface PresenceDatastoreManager {\n\tjoinSession(clientId: ClientConnectionId): 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(message: IExtensionMessage, local: boolean): 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 Object.entries(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 * 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 refreshBroadcastRequested = false;\n\tprivate readonly timer = new TimerManager();\n\tprivate readonly workspaces = new Map<string, AnyWorkspaceEntry<StatesWorkspaceSchema>>();\n\n\tpublic constructor(\n\t\tprivate readonly attendeeId: AttendeeId,\n\t\tprivate readonly runtime: IEphemeralRuntime,\n\t\tprivate readonly lookupClient: (clientId: AttendeeId) => Attendee,\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}\n\n\tpublic joinSession(clientId: ClientConnectionId): void {\n\t\t// Broadcast join message to all clients\n\t\tconst updateProviders = [...this.runtime.getQuorum().getMembers().keys()].filter(\n\t\t\t(quorumClientId) => quorumClientId !== clientId,\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}\n\t\tthis.runtime.submitSignal(joinMessageType, {\n\t\t\tsendTimestamp: Date.now(),\n\t\t\tavgLatency: this.averageLatency,\n\t\t\tdata: this.datastore,\n\t\t\tupdateProviders,\n\t\t} satisfies ClientJoinMessage[\"content\"]);\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.connected) {\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\tlookupClient: this.lookupClient,\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 undefined when no messages are queued.\n\t */\n\tprivate queuedData: GeneralDatastoreMessageContent | 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,\n\t\toptions: RuntimeLocalUpdateOptions,\n\t): void {\n\t\t// Merging the message with any queued messages effectively queues the message.\n\t\t// It is OK to queue all incoming messages as long as when we send, we send the queued data.\n\t\tthis.queuedData = mergeGeneralDatastoreMessageContent(this.queuedData, data);\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.timer.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.timer.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 === allowableUpdateLatency, 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.timer.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.timer.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.connected) {\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\tconst clientConnectionId = this.runtime.clientId;\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\t// eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n\t\t\tthis.datastore[\"system:presence\"].clientToSessionId[clientConnectionId]!;\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 DatastoreUpdateMessage[\"content\"];\n\t\tthis.queuedData = undefined;\n\t\tthis.runtime.submitSignal(datastoreUpdateMessageType, newMessage);\n\t}\n\n\tprivate broadcastAllKnownState(): void {\n\t\tthis.runtime.submitSignal(datastoreUpdateMessageType, {\n\t\t\tsendTimestamp: Date.now(),\n\t\t\tavgLatency: this.averageLatency,\n\t\t\tisComplete: true,\n\t\t\tdata: this.datastore,\n\t\t} satisfies DatastoreUpdateMessage[\"content\"]);\n\t\tthis.refreshBroadcastRequested = false;\n\t}\n\n\tpublic processSignal(\n\t\t// Note: IInboundSignalMessage is used here in place of IExtensionMessage\n\t\t// as IExtensionMessage's strictly JSON `content` creates type compatibility\n\t\t// issues with `AttendeeId` keys and really unknown value content.\n\t\t// IExtensionMessage is a subset of IInboundSignalMessage so this is safe.\n\t\t// Change types of DatastoreUpdateMessage | ClientJoinMessage to\n\t\t// IExtensionMessage<> derivatives to see the issues.\n\t\tmessage: IInboundSignalMessage | DatastoreUpdateMessage | ClientJoinMessage,\n\t\tlocal: 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\treturn;\n\t\t}\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 timeModifier =\n\t\t\treceived -\n\t\t\t(this.averageLatency + message.content.avgLatency + message.content.sendTimestamp);\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.connected) {\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\tassert(message.type === datastoreUpdateMessageType, 0xa3b /* Unexpected message type */);\n\t\t\tif (message.content.isComplete) {\n\t\t\t\tthis.refreshBroadcastRequested = false;\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 Object.entries(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\tconst postUpdateActions: PostUpdateAction[] = [];\n\t\tfor (const [workspaceAddress, remoteDatastore] of Object.entries(message.content.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 * 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\tthis.refreshBroadcastRequested = true;\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 quorum list.\n\t\t// eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n\t\tconst clientId = this.runtime.clientId!;\n\t\t// const requestor = message.clientId;\n\t\tif (updateProviders.includes(clientId)) {\n\t\t\t// Send all current state to the new client\n\t\t\tthis.broadcastAllKnownState();\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\trequestor,\n\t\t\t\t\trole: \"primary\",\n\t\t\t\t},\n\t\t\t});\n\t\t} else {\n\t\t\t// Schedule a broadcast to the new client after a delay only to send if\n\t\t\t// another broadcast hasn't been seen in the meantime. The delay is based\n\t\t\t// on the position in the quorum list. It doesn't have to be a stable\n\t\t\t// list across all clients. We need something to provide suggested order\n\t\t\t// to prevent a flood of broadcasts.\n\t\t\tlet relativeResponseOrder;\n\t\t\tconst quorumMembers = this.runtime.getQuorum().getMembers();\n\t\t\tconst self = quorumMembers.get(clientId);\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 { sequenceNumber } of quorumMembers.values()) {\n\t\t\t\t\tif (sequenceNumber < self.sequenceNumber) {\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\trelativeResponseOrder = quorumMembers.size + Math.random() * 10;\n\t\t\t}\n\t\t\t// These numbers have been chosen arbitrarily to start with.\n\t\t\t// 20 is minimum wait time, 20 is the additional wait time per provider\n\t\t\t// given an chance before us with named providers given more time.\n\t\t\tconst waitTime = 20 + 20 * (3 * updateProviders.length + relativeResponseOrder);\n\t\t\tsetTimeout(() => {\n\t\t\t\t// Make sure a broadcast is still needed and we are currently connected.\n\t\t\t\t// If not connected, nothing we can do.\n\t\t\t\tif (this.refreshBroadcastRequested && this.runtime.connected) {\n\t\t\t\t\tthis.broadcastAllKnownState();\n\t\t\t\t\tthis.logger?.sendTelemetryEvent({\n\t\t\t\t\t\teventName: \"JoinResponse\",\n\t\t\t\t\t\tdetails: {\n\t\t\t\t\t\t\ttype: \"broadcastAll\",\n\t\t\t\t\t\t\trequestor,\n\t\t\t\t\t\t\trole: \"secondary\",\n\t\t\t\t\t\t\torder: relativeResponseOrder,\n\t\t\t\t\t\t},\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}, waitTime);\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 { 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 { IEphemeralRuntime, PostUpdateAction } from \"./internalTypes.js\";\nimport { objectEntries } from \"./internalUtils.js\";\nimport type {\n\tAttendeeId,\n\tAttendee,\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\tGeneralDatastoreMessageContent,\n\tInboundClientJoinMessage,\n\tInboundDatastoreUpdateMessage,\n\tOutboundDatastoreUpdateMessage,\n\tSignalMessages,\n\tSystemDatastore,\n} from \"./protocol.js\";\nimport { datastoreUpdateMessageType, joinMessageType } 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\ntype PresenceDatastore = SystemDatastore & {\n\t[WorkspaceAddress: string]: ValueElementMap<StatesWorkspaceSchema>;\n};\n\ntype InternalWorkspaceAddress = `${\"s\" | \"n\"}:${WorkspaceAddress}`;\n\nconst internalWorkspaceTypes: Readonly<Record<string, \"States\" | \"Notifications\">> = {\n\ts: \"States\",\n\tn: \"Notifications\",\n} as const;\n\nconst knownMessageTypes = new Set([joinMessageType, datastoreUpdateMessageType]);\nfunction isPresenceMessage(\n\tmessage: InboundExtensionMessage<SignalMessages>,\n): message is InboundDatastoreUpdateMessage | InboundClientJoinMessage {\n\treturn knownMessageTypes.has(message.type);\n}\n\n/**\n * @internal\n */\nexport interface PresenceDatastoreManager {\n\tjoinSession(clientId: ClientConnectionId): 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 Object.entries(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 * 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 refreshBroadcastRequested = false;\n\tprivate readonly timer = new TimerManager();\n\tprivate readonly workspaces = new Map<string, AnyWorkspaceEntry<StatesWorkspaceSchema>>();\n\n\tpublic constructor(\n\t\tprivate readonly attendeeId: AttendeeId,\n\t\tprivate readonly runtime: IEphemeralRuntime,\n\t\tprivate readonly lookupClient: (clientId: AttendeeId) => Attendee,\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}\n\n\tpublic joinSession(clientId: ClientConnectionId): void {\n\t\t// Broadcast join message to all clients\n\t\tconst updateProviders = [...this.runtime.getQuorum().getMembers().keys()].filter(\n\t\t\t(quorumClientId) => quorumClientId !== clientId,\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}\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.datastore,\n\t\t\t\tupdateProviders,\n\t\t\t},\n\t\t});\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.isConnected()) {\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\tlookupClient: this.lookupClient,\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 undefined when no messages are queued.\n\t */\n\tprivate queuedData: GeneralDatastoreMessageContent | 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,\n\t\toptions: RuntimeLocalUpdateOptions,\n\t): void {\n\t\t// Merging the message with any queued messages effectively queues the message.\n\t\t// It is OK to queue all incoming messages as long as when we send, we send the queued data.\n\t\tthis.queuedData = mergeGeneralDatastoreMessageContent(this.queuedData, data);\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.timer.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.timer.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 === allowableUpdateLatency, 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.timer.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.timer.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.isConnected()) {\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\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\t// eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n\t\t\tthis.datastore[\"system:presence\"].clientToSessionId[clientConnectionId]!;\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\tprivate broadcastAllKnownState(): void {\n\t\tthis.runtime.submitSignal({\n\t\t\ttype: datastoreUpdateMessageType,\n\t\t\tcontent: {\n\t\t\t\tsendTimestamp: Date.now(),\n\t\t\t\tavgLatency: this.averageLatency,\n\t\t\t\tisComplete: true,\n\t\t\t\tdata: this.datastore,\n\t\t\t},\n\t\t});\n\t\tthis.refreshBroadcastRequested = false;\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\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 timeModifier =\n\t\t\treceived -\n\t\t\t(this.averageLatency + message.content.avgLatency + message.content.sendTimestamp);\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.isConnected()) {\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\tif (message.content.isComplete) {\n\t\t\t\tthis.refreshBroadcastRequested = false;\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 Object.entries(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\tconst postUpdateActions: PostUpdateAction[] = [];\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 Object.entries(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 * 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\tthis.refreshBroadcastRequested = true;\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 quorum list.\n\t\t// eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n\t\tconst clientId = this.runtime.getClientId()!;\n\t\t// const requestor = message.clientId;\n\t\tif (updateProviders.includes(clientId)) {\n\t\t\t// Send all current state to the new client\n\t\t\tthis.broadcastAllKnownState();\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\trequestor,\n\t\t\t\t\trole: \"primary\",\n\t\t\t\t},\n\t\t\t});\n\t\t} else {\n\t\t\t// Schedule a broadcast to the new client after a delay only to send if\n\t\t\t// another broadcast hasn't been seen in the meantime. The delay is based\n\t\t\t// on the position in the quorum list. It doesn't have to be a stable\n\t\t\t// list across all clients. We need something to provide suggested order\n\t\t\t// to prevent a flood of broadcasts.\n\t\t\tlet relativeResponseOrder;\n\t\t\tconst quorumMembers = this.runtime.getQuorum().getMembers();\n\t\t\tconst self = quorumMembers.get(clientId);\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 { sequenceNumber } of quorumMembers.values()) {\n\t\t\t\t\tif (sequenceNumber < self.sequenceNumber) {\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\trelativeResponseOrder = quorumMembers.size + Math.random() * 10;\n\t\t\t}\n\t\t\t// These numbers have been chosen arbitrarily to start with.\n\t\t\t// 20 is minimum wait time, 20 is the additional wait time per provider\n\t\t\t// given an chance before us with named providers given more time.\n\t\t\tconst waitTime = 20 + 20 * (3 * updateProviders.length + relativeResponseOrder);\n\t\t\tsetTimeout(() => {\n\t\t\t\t// Make sure a broadcast is still needed and we are currently connected.\n\t\t\t\t// If not connected, nothing we can do.\n\t\t\t\tif (this.refreshBroadcastRequested && this.runtime.isConnected()) {\n\t\t\t\t\tthis.broadcastAllKnownState();\n\t\t\t\t\tthis.logger?.sendTelemetryEvent({\n\t\t\t\t\t\teventName: \"JoinResponse\",\n\t\t\t\t\t\tdetails: {\n\t\t\t\t\t\t\ttype: \"broadcastAll\",\n\t\t\t\t\t\t\trequestor,\n\t\t\t\t\t\t\trole: \"secondary\",\n\t\t\t\t\t\t\torder: relativeResponseOrder,\n\t\t\t\t\t\t},\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}, waitTime);\n\t\t}\n\t}\n}\n"]}
@@ -2,15 +2,15 @@
2
2
  * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
3
  * Licensed under the MIT License.
4
4
  */
5
- import type { IEphemeralRuntime } from "./internalTypes.js";
6
- import type { AttendeeId, Presence } from "./presence.js";
7
- import type { IContainerExtension } from "@fluidframework/presence/internal/container-definitions/internal";
5
+ import type { ContainerExtension } from "@fluidframework/container-runtime-definitions/internal";
6
+ import type { ExtensionRuntimeProperties, IEphemeralRuntime } from "./internalTypes.js";
7
+ import type { AttendeeId, PresenceWithNotifications as Presence } from "./presence.js";
8
8
  /**
9
- * Portion of the container extension requirements ({@link IContainerExtension}) that are delegated to presence manager.
9
+ * Portion of the container extension requirements ({@link ContainerExtension}) that are delegated to presence manager.
10
10
  *
11
11
  * @internal
12
12
  */
13
- export type PresenceExtensionInterface = Required<Pick<IContainerExtension<never>, "processSignal">>;
13
+ export type PresenceExtensionInterface = Required<Pick<ContainerExtension<ExtensionRuntimeProperties>, "processSignal">>;
14
14
  /**
15
15
  * Instantiates Presence Manager
16
16
  *
@@ -1 +1 @@
1
- {"version":3,"file":"presenceManager.d.ts","sourceRoot":"","sources":["../src/presenceManager.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAaH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAC5D,OAAO,KAAK,EAAmB,UAAU,EAAE,QAAQ,EAAkB,MAAM,eAAe,CAAC;AAa3F,OAAO,KAAK,EACX,mBAAmB,EAEnB,MAAM,kEAAkE,CAAC;AAE1E;;;;GAIG;AACH,MAAM,MAAM,0BAA0B,GAAG,QAAQ,CAChD,IAAI,CAAC,mBAAmB,CAAC,KAAK,CAAC,EAAE,eAAe,CAAC,CACjD,CAAC;AAiIF;;;;GAIG;AACH,wBAAgB,qBAAqB,CACpC,OAAO,EAAE,iBAAiB,EAC1B,UAAU,GAAE,UAA4C,GACtD,QAAQ,GAAG,0BAA0B,CAEvC"}
1
+ {"version":3,"file":"presenceManager.d.ts","sourceRoot":"","sources":["../src/presenceManager.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EACX,kBAAkB,EAElB,MAAM,wDAAwD,CAAC;AAWhE,OAAO,KAAK,EAAE,0BAA0B,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AACxF,OAAO,KAAK,EAEX,UAAU,EACV,yBAAyB,IAAI,QAAQ,EAErC,MAAM,eAAe,CAAC;AAcvB;;;;GAIG;AACH,MAAM,MAAM,0BAA0B,GAAG,QAAQ,CAChD,IAAI,CAAC,kBAAkB,CAAC,0BAA0B,CAAC,EAAE,eAAe,CAAC,CACrE,CAAC;AA0IF;;;;GAIG;AACH,wBAAgB,qBAAqB,CACpC,OAAO,EAAE,iBAAiB,EAC1B,UAAU,GAAE,UAA4C,GACtD,QAAQ,GAAG,0BAA0B,CAEvC"}
@@ -27,10 +27,11 @@ class PresenceManager {
27
27
  }
28
28
  [this.datastoreManager, this.systemWorkspace] = setupSubComponents(attendeeId, runtime, this.events, this.mc?.logger, this);
29
29
  this.attendees = this.systemWorkspace;
30
- runtime.on("connected", this.onConnect.bind(this));
31
- runtime.on("disconnected", () => {
32
- if (runtime.clientId !== undefined) {
33
- this.removeClientConnectionId(runtime.clientId);
30
+ runtime.events.on("connected", this.onConnect.bind(this));
31
+ runtime.events.on("disconnected", () => {
32
+ const currentClientId = runtime.getClientId();
33
+ if (currentClientId !== undefined) {
34
+ this.removeClientConnectionId(currentClientId);
34
35
  }
35
36
  });
36
37
  runtime.getAudience().on("removeMember", this.removeClientConnectionId.bind(this));
@@ -40,8 +41,8 @@ class PresenceManager {
40
41
  // delayed we expect that "connected" event has passed.
41
42
  // Note: In some manual testing, this does not appear to be enough to
42
43
  // always trigger an initial connect.
43
- const clientId = runtime.clientId;
44
- if (clientId !== undefined && runtime.connected) {
44
+ const clientId = runtime.getClientId();
45
+ if (clientId !== undefined && runtime.isConnected()) {
45
46
  this.onConnect(clientId);
46
47
  }
47
48
  }
@@ -55,12 +56,13 @@ class PresenceManager {
55
56
  /**
56
57
  * Check for Presence message and process it.
57
58
  *
58
- * @param address - Address of the message
59
- * @param message - Message to be processed
59
+ * @param addressChain - Address chain of the message
60
+ * @param message - Unverified message to be processed
60
61
  * @param local - Whether the message originated locally (`true`) or remotely (`false`)
61
62
  */
62
- processSignal(address, message, local) {
63
- this.datastoreManager.processSignal(message, local);
63
+ processSignal(addressChain, message, local) {
64
+ this.datastoreManager.processSignal(message, local,
65
+ /* optional */ addressChain[0] === "?");
64
66
  }
65
67
  }
66
68
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"presenceManager.js","sourceRoot":"","sources":["../src/presenceManager.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 { createEmitter } from \"@fluid-internal/client-utils\";\nimport type { IEmitter, Listenable } from \"@fluidframework/core-interfaces/internal\";\nimport { createSessionId } from \"@fluidframework/id-compressor/internal\";\nimport type {\n\tITelemetryLoggerExt,\n\tMonitoringContext,\n} from \"@fluidframework/telemetry-utils/internal\";\nimport { createChildMonitoringContext } from \"@fluidframework/telemetry-utils/internal\";\n\nimport type { ClientConnectionId } from \"./baseTypes.js\";\nimport type { BroadcastControlSettings } from \"./broadcastControls.js\";\nimport type { IEphemeralRuntime } from \"./internalTypes.js\";\nimport type { AttendeesEvents, AttendeeId, Presence, PresenceEvents } from \"./presence.js\";\nimport type { PresenceDatastoreManager } from \"./presenceDatastoreManager.js\";\nimport { PresenceDatastoreManagerImpl } from \"./presenceDatastoreManager.js\";\nimport type { SystemWorkspace, SystemWorkspaceDatastore } from \"./systemWorkspace.js\";\nimport { createSystemWorkspace } from \"./systemWorkspace.js\";\nimport type {\n\tNotificationsWorkspace,\n\tNotificationsWorkspaceSchema,\n\tStatesWorkspace,\n\tStatesWorkspaceSchema,\n\tWorkspaceAddress,\n} from \"./types.js\";\n\nimport type {\n\tIContainerExtension,\n\tIExtensionMessage,\n} from \"@fluidframework/presence/internal/container-definitions/internal\";\n\n/**\n * Portion of the container extension requirements ({@link IContainerExtension}) that are delegated to presence manager.\n *\n * @internal\n */\nexport type PresenceExtensionInterface = Required<\n\tPick<IContainerExtension<never>, \"processSignal\">\n>;\n\n/**\n * The Presence manager\n */\nclass PresenceManager implements Presence, PresenceExtensionInterface {\n\tprivate readonly datastoreManager: PresenceDatastoreManager;\n\tprivate readonly systemWorkspace: SystemWorkspace;\n\n\tpublic readonly events = createEmitter<PresenceEvents & AttendeesEvents>();\n\n\tpublic readonly attendees: Presence[\"attendees\"];\n\n\tpublic readonly states = {\n\t\tgetWorkspace: <TSchema extends StatesWorkspaceSchema>(\n\t\t\tworkspaceAddress: WorkspaceAddress,\n\t\t\trequestedContent: TSchema,\n\t\t\tsettings?: BroadcastControlSettings,\n\t\t): StatesWorkspace<TSchema> =>\n\t\t\tthis.datastoreManager.getWorkspace(`s:${workspaceAddress}`, requestedContent, settings),\n\t};\n\tpublic readonly notifications = {\n\t\tgetWorkspace: <TSchema extends NotificationsWorkspaceSchema>(\n\t\t\tworkspaceAddress: WorkspaceAddress,\n\t\t\trequestedContent: TSchema,\n\t\t): NotificationsWorkspace<TSchema> =>\n\t\t\tthis.datastoreManager.getWorkspace(`n:${workspaceAddress}`, requestedContent),\n\t};\n\n\tprivate readonly mc: MonitoringContext | undefined = undefined;\n\n\tpublic constructor(runtime: IEphemeralRuntime, attendeeId: AttendeeId) {\n\t\tconst logger = runtime.logger;\n\t\tif (logger) {\n\t\t\tthis.mc = createChildMonitoringContext({ logger, namespace: \"Presence\" });\n\t\t\tthis.mc.logger.sendTelemetryEvent({ eventName: \"PresenceInstantiated\" });\n\t\t}\n\n\t\t[this.datastoreManager, this.systemWorkspace] = setupSubComponents(\n\t\t\tattendeeId,\n\t\t\truntime,\n\t\t\tthis.events,\n\t\t\tthis.mc?.logger,\n\t\t\tthis,\n\t\t);\n\t\tthis.attendees = this.systemWorkspace;\n\n\t\truntime.on(\"connected\", this.onConnect.bind(this));\n\n\t\truntime.on(\"disconnected\", () => {\n\t\t\tif (runtime.clientId !== undefined) {\n\t\t\t\tthis.removeClientConnectionId(runtime.clientId);\n\t\t\t}\n\t\t});\n\n\t\truntime.getAudience().on(\"removeMember\", this.removeClientConnectionId.bind(this));\n\n\t\t// Check if already connected at the time of construction.\n\t\t// If constructed during data store load, the runtime may already be connected\n\t\t// and the \"connected\" event will be raised during completion. With construction\n\t\t// delayed we expect that \"connected\" event has passed.\n\t\t// Note: In some manual testing, this does not appear to be enough to\n\t\t// always trigger an initial connect.\n\t\tconst clientId = runtime.clientId;\n\t\tif (clientId !== undefined && runtime.connected) {\n\t\t\tthis.onConnect(clientId);\n\t\t}\n\t}\n\n\tprivate onConnect(clientConnectionId: ClientConnectionId): void {\n\t\tthis.systemWorkspace.onConnectionAdded(clientConnectionId);\n\t\tthis.datastoreManager.joinSession(clientConnectionId);\n\t}\n\n\tprivate removeClientConnectionId(clientConnectionId: ClientConnectionId): void {\n\t\tthis.systemWorkspace.removeClientConnectionId(clientConnectionId);\n\t}\n\t/**\n\t * Check for Presence message and process it.\n\t *\n\t * @param address - Address of the message\n\t * @param message - Message to be processed\n\t * @param local - Whether the message originated locally (`true`) or remotely (`false`)\n\t */\n\tpublic processSignal(address: string, message: IExtensionMessage, local: boolean): void {\n\t\tthis.datastoreManager.processSignal(message, local);\n\t}\n}\n\n/**\n * Helper for Presence Manager setup\n *\n * Presence Manager is outermost layer of the presence system and has two main\n * sub-components:\n * 1. PresenceDatastoreManager: Manages the unified general data for states and\n * registry for workspaces.\n * 2. SystemWorkspace: Custom internal workspace for system states including\n * attendee management. It is registered with the PresenceDatastoreManager.\n */\nfunction setupSubComponents(\n\tattendeeId: AttendeeId,\n\truntime: IEphemeralRuntime,\n\tevents: Listenable<PresenceEvents & AttendeesEvents> &\n\t\tIEmitter<PresenceEvents & AttendeesEvents>,\n\tlogger: ITelemetryLoggerExt | undefined,\n\tpresence: Presence,\n): [PresenceDatastoreManager, SystemWorkspace] {\n\tconst systemWorkspaceDatastore: SystemWorkspaceDatastore = {\n\t\tclientToSessionId: {},\n\t};\n\tconst systemWorkspaceConfig = createSystemWorkspace(\n\t\tattendeeId,\n\t\tsystemWorkspaceDatastore,\n\t\tevents,\n\t\truntime.getAudience(),\n\t);\n\tconst datastoreManager = new PresenceDatastoreManagerImpl(\n\t\tattendeeId,\n\t\truntime,\n\t\tsystemWorkspaceConfig.workspace.getAttendee.bind(systemWorkspaceConfig.workspace),\n\t\tlogger,\n\t\tevents,\n\t\tpresence,\n\t\tsystemWorkspaceDatastore,\n\t\tsystemWorkspaceConfig.statesEntry,\n\t);\n\treturn [datastoreManager, systemWorkspaceConfig.workspace];\n}\n\n/**\n * Instantiates Presence Manager\n *\n * @internal\n */\nexport function createPresenceManager(\n\truntime: IEphemeralRuntime,\n\tattendeeId: AttendeeId = createSessionId() as AttendeeId,\n): Presence & PresenceExtensionInterface {\n\treturn new PresenceManager(runtime, attendeeId);\n}\n"]}
1
+ {"version":3,"file":"presenceManager.js","sourceRoot":"","sources":["../src/presenceManager.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 { createEmitter } from \"@fluid-internal/client-utils\";\nimport type {\n\tContainerExtension,\n\tInboundExtensionMessage,\n} from \"@fluidframework/container-runtime-definitions/internal\";\nimport type { IEmitter, Listenable } from \"@fluidframework/core-interfaces/internal\";\nimport { createSessionId } from \"@fluidframework/id-compressor/internal\";\nimport type {\n\tITelemetryLoggerExt,\n\tMonitoringContext,\n} from \"@fluidframework/telemetry-utils/internal\";\nimport { createChildMonitoringContext } from \"@fluidframework/telemetry-utils/internal\";\n\nimport type { ClientConnectionId } from \"./baseTypes.js\";\nimport type { BroadcastControlSettings } from \"./broadcastControls.js\";\nimport type { ExtensionRuntimeProperties, IEphemeralRuntime } from \"./internalTypes.js\";\nimport type {\n\tAttendeesEvents,\n\tAttendeeId,\n\tPresenceWithNotifications as Presence,\n\tPresenceEvents,\n} from \"./presence.js\";\nimport type { PresenceDatastoreManager } from \"./presenceDatastoreManager.js\";\nimport { PresenceDatastoreManagerImpl } from \"./presenceDatastoreManager.js\";\nimport type { SignalMessages } from \"./protocol.js\";\nimport type { SystemWorkspace, SystemWorkspaceDatastore } from \"./systemWorkspace.js\";\nimport { createSystemWorkspace } from \"./systemWorkspace.js\";\nimport type {\n\tNotificationsWorkspace,\n\tNotificationsWorkspaceSchema,\n\tStatesWorkspace,\n\tStatesWorkspaceSchema,\n\tWorkspaceAddress,\n} from \"./types.js\";\n\n/**\n * Portion of the container extension requirements ({@link ContainerExtension}) that are delegated to presence manager.\n *\n * @internal\n */\nexport type PresenceExtensionInterface = Required<\n\tPick<ContainerExtension<ExtensionRuntimeProperties>, \"processSignal\">\n>;\n\n/**\n * The Presence manager\n */\nclass PresenceManager implements Presence, PresenceExtensionInterface {\n\tprivate readonly datastoreManager: PresenceDatastoreManager;\n\tprivate readonly systemWorkspace: SystemWorkspace;\n\n\tpublic readonly events = createEmitter<PresenceEvents & AttendeesEvents>();\n\n\tpublic readonly attendees: Presence[\"attendees\"];\n\n\tpublic readonly states = {\n\t\tgetWorkspace: <TSchema extends StatesWorkspaceSchema>(\n\t\t\tworkspaceAddress: WorkspaceAddress,\n\t\t\trequestedContent: TSchema,\n\t\t\tsettings?: BroadcastControlSettings,\n\t\t): StatesWorkspace<TSchema> =>\n\t\t\tthis.datastoreManager.getWorkspace(`s:${workspaceAddress}`, requestedContent, settings),\n\t};\n\tpublic readonly notifications = {\n\t\tgetWorkspace: <TSchema extends NotificationsWorkspaceSchema>(\n\t\t\tworkspaceAddress: WorkspaceAddress,\n\t\t\trequestedContent: TSchema,\n\t\t): NotificationsWorkspace<TSchema> =>\n\t\t\tthis.datastoreManager.getWorkspace(`n:${workspaceAddress}`, requestedContent),\n\t};\n\n\tprivate readonly mc: MonitoringContext | undefined = undefined;\n\n\tpublic constructor(runtime: IEphemeralRuntime, attendeeId: AttendeeId) {\n\t\tconst logger = runtime.logger;\n\t\tif (logger) {\n\t\t\tthis.mc = createChildMonitoringContext({ logger, namespace: \"Presence\" });\n\t\t\tthis.mc.logger.sendTelemetryEvent({ eventName: \"PresenceInstantiated\" });\n\t\t}\n\n\t\t[this.datastoreManager, this.systemWorkspace] = setupSubComponents(\n\t\t\tattendeeId,\n\t\t\truntime,\n\t\t\tthis.events,\n\t\t\tthis.mc?.logger,\n\t\t\tthis,\n\t\t);\n\t\tthis.attendees = this.systemWorkspace;\n\n\t\truntime.events.on(\"connected\", this.onConnect.bind(this));\n\n\t\truntime.events.on(\"disconnected\", () => {\n\t\t\tconst currentClientId = runtime.getClientId();\n\t\t\tif (currentClientId !== undefined) {\n\t\t\t\tthis.removeClientConnectionId(currentClientId);\n\t\t\t}\n\t\t});\n\n\t\truntime.getAudience().on(\"removeMember\", this.removeClientConnectionId.bind(this));\n\n\t\t// Check if already connected at the time of construction.\n\t\t// If constructed during data store load, the runtime may already be connected\n\t\t// and the \"connected\" event will be raised during completion. With construction\n\t\t// delayed we expect that \"connected\" event has passed.\n\t\t// Note: In some manual testing, this does not appear to be enough to\n\t\t// always trigger an initial connect.\n\t\tconst clientId = runtime.getClientId();\n\t\tif (clientId !== undefined && runtime.isConnected()) {\n\t\t\tthis.onConnect(clientId);\n\t\t}\n\t}\n\n\tprivate onConnect(clientConnectionId: ClientConnectionId): void {\n\t\tthis.systemWorkspace.onConnectionAdded(clientConnectionId);\n\t\tthis.datastoreManager.joinSession(clientConnectionId);\n\t}\n\n\tprivate removeClientConnectionId(clientConnectionId: ClientConnectionId): void {\n\t\tthis.systemWorkspace.removeClientConnectionId(clientConnectionId);\n\t}\n\t/**\n\t * Check for Presence message and process it.\n\t *\n\t * @param addressChain - Address chain of the message\n\t * @param message - Unverified message to be processed\n\t * @param local - Whether the message originated locally (`true`) or remotely (`false`)\n\t */\n\tpublic processSignal(\n\t\taddressChain: string[],\n\t\tmessage: InboundExtensionMessage<SignalMessages>,\n\t\tlocal: boolean,\n\t): void {\n\t\tthis.datastoreManager.processSignal(\n\t\t\tmessage,\n\t\t\tlocal,\n\t\t\t/* optional */ addressChain[0] === \"?\",\n\t\t);\n\t}\n}\n\n/**\n * Helper for Presence Manager setup\n *\n * Presence Manager is outermost layer of the presence system and has two main\n * sub-components:\n * 1. PresenceDatastoreManager: Manages the unified general data for states and\n * registry for workspaces.\n * 2. SystemWorkspace: Custom internal workspace for system states including\n * attendee management. It is registered with the PresenceDatastoreManager.\n */\nfunction setupSubComponents(\n\tattendeeId: AttendeeId,\n\truntime: IEphemeralRuntime,\n\tevents: Listenable<PresenceEvents & AttendeesEvents> &\n\t\tIEmitter<PresenceEvents & AttendeesEvents>,\n\tlogger: ITelemetryLoggerExt | undefined,\n\tpresence: Presence,\n): [PresenceDatastoreManager, SystemWorkspace] {\n\tconst systemWorkspaceDatastore: SystemWorkspaceDatastore = {\n\t\tclientToSessionId: {},\n\t};\n\tconst systemWorkspaceConfig = createSystemWorkspace(\n\t\tattendeeId,\n\t\tsystemWorkspaceDatastore,\n\t\tevents,\n\t\truntime.getAudience(),\n\t);\n\tconst datastoreManager = new PresenceDatastoreManagerImpl(\n\t\tattendeeId,\n\t\truntime,\n\t\tsystemWorkspaceConfig.workspace.getAttendee.bind(systemWorkspaceConfig.workspace),\n\t\tlogger,\n\t\tevents,\n\t\tpresence,\n\t\tsystemWorkspaceDatastore,\n\t\tsystemWorkspaceConfig.statesEntry,\n\t);\n\treturn [datastoreManager, systemWorkspaceConfig.workspace];\n}\n\n/**\n * Instantiates Presence Manager\n *\n * @internal\n */\nexport function createPresenceManager(\n\truntime: IEphemeralRuntime,\n\tattendeeId: AttendeeId = createSessionId() as AttendeeId,\n): Presence & PresenceExtensionInterface {\n\treturn new PresenceManager(runtime, attendeeId);\n}\n"]}
@@ -6,7 +6,7 @@ import type { ClientConnectionId } from "./baseTypes.js";
6
6
  import type { BroadcastControlSettings } from "./broadcastControls.js";
7
7
  import type { InternalTypes } from "./exposedInternalTypes.js";
8
8
  import type { ClientRecord, PostUpdateAction } from "./internalTypes.js";
9
- import type { AttendeeId, Attendee, Presence } from "./presence.js";
9
+ import type { AttendeeId, Attendee, PresenceWithNotifications as Presence } from "./presence.js";
10
10
  import type { AnyWorkspace, StatesWorkspaceSchema } from "./types.js";
11
11
  /**
12
12
  * Extracts `Part` from {@link InternalTypes.ManagerFactory} return type
@@ -1 +1 @@
1
- {"version":3,"file":"presenceStates.d.ts","sourceRoot":"","sources":["../src/presenceStates.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"presenceStates.d.ts","sourceRoot":"","sources":["../src/presenceStates.ts"],"names":[],"mappings":"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"}