@fluidframework/presence 2.74.0 → 2.81.0-374083

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 (73) hide show
  1. package/dist/alpha.d.ts +1 -0
  2. package/dist/beta.d.ts +1 -0
  3. package/dist/exposedInternalTypes.d.ts +1 -1
  4. package/dist/exposedInternalTypes.d.ts.map +1 -1
  5. package/dist/exposedInternalTypes.js.map +1 -1
  6. package/dist/getPresence.js +2 -2
  7. package/dist/getPresence.js.map +1 -1
  8. package/dist/index.d.ts +1 -1
  9. package/dist/index.d.ts.map +1 -1
  10. package/dist/index.js.map +1 -1
  11. package/dist/internalTypes.d.ts +6 -0
  12. package/dist/internalTypes.d.ts.map +1 -1
  13. package/dist/internalTypes.js.map +1 -1
  14. package/dist/latestMapValueManager.d.ts +33 -14
  15. package/dist/latestMapValueManager.d.ts.map +1 -1
  16. package/dist/latestMapValueManager.js +33 -16
  17. package/dist/latestMapValueManager.js.map +1 -1
  18. package/dist/legacy.alpha.d.ts +1 -0
  19. package/dist/packageVersion.d.ts +1 -1
  20. package/dist/packageVersion.d.ts.map +1 -1
  21. package/dist/packageVersion.js +1 -1
  22. package/dist/packageVersion.js.map +1 -1
  23. package/dist/presenceDatastoreManager.d.ts +7 -11
  24. package/dist/presenceDatastoreManager.d.ts.map +1 -1
  25. package/dist/presenceDatastoreManager.js +15 -65
  26. package/dist/presenceDatastoreManager.js.map +1 -1
  27. package/dist/presenceManager.d.ts.map +1 -1
  28. package/dist/presenceManager.js +68 -23
  29. package/dist/presenceManager.js.map +1 -1
  30. package/dist/stateDatastore.d.ts +2 -2
  31. package/dist/stateDatastore.d.ts.map +1 -1
  32. package/dist/stateDatastore.js.map +1 -1
  33. package/dist/systemWorkspace.d.ts +2 -1
  34. package/dist/systemWorkspace.d.ts.map +1 -1
  35. package/dist/systemWorkspace.js +95 -42
  36. package/dist/systemWorkspace.js.map +1 -1
  37. package/lib/alpha.d.ts +1 -0
  38. package/lib/beta.d.ts +1 -0
  39. package/lib/exposedInternalTypes.d.ts +1 -1
  40. package/lib/exposedInternalTypes.d.ts.map +1 -1
  41. package/lib/exposedInternalTypes.js.map +1 -1
  42. package/lib/getPresence.js +2 -2
  43. package/lib/getPresence.js.map +1 -1
  44. package/lib/index.d.ts +1 -1
  45. package/lib/index.d.ts.map +1 -1
  46. package/lib/index.js.map +1 -1
  47. package/lib/internalTypes.d.ts +6 -0
  48. package/lib/internalTypes.d.ts.map +1 -1
  49. package/lib/internalTypes.js.map +1 -1
  50. package/lib/latestMapValueManager.d.ts +33 -14
  51. package/lib/latestMapValueManager.d.ts.map +1 -1
  52. package/lib/latestMapValueManager.js +33 -16
  53. package/lib/latestMapValueManager.js.map +1 -1
  54. package/lib/legacy.alpha.d.ts +1 -0
  55. package/lib/packageVersion.d.ts +1 -1
  56. package/lib/packageVersion.d.ts.map +1 -1
  57. package/lib/packageVersion.js +1 -1
  58. package/lib/packageVersion.js.map +1 -1
  59. package/lib/presenceDatastoreManager.d.ts +7 -11
  60. package/lib/presenceDatastoreManager.d.ts.map +1 -1
  61. package/lib/presenceDatastoreManager.js +15 -65
  62. package/lib/presenceDatastoreManager.js.map +1 -1
  63. package/lib/presenceManager.d.ts.map +1 -1
  64. package/lib/presenceManager.js +64 -19
  65. package/lib/presenceManager.js.map +1 -1
  66. package/lib/stateDatastore.d.ts +2 -2
  67. package/lib/stateDatastore.d.ts.map +1 -1
  68. package/lib/stateDatastore.js.map +1 -1
  69. package/lib/systemWorkspace.d.ts +2 -1
  70. package/lib/systemWorkspace.d.ts.map +1 -1
  71. package/lib/systemWorkspace.js +95 -42
  72. package/lib/systemWorkspace.js.map +1 -1
  73. package/package.json +26 -26
@@ -10,14 +10,15 @@ const internalUtils_js_1 = require("./internalUtils.js");
10
10
  const presence_js_1 = require("./presence.js");
11
11
  const timerManager_js_1 = require("./timerManager.js");
12
12
  class SessionClient {
13
- constructor(attendeeId, connectionId = undefined) {
13
+ constructor(attendeeId,
14
+ /**
15
+ * Order is used to track the most recent client connection
16
+ * during a session.
17
+ */
18
+ order = 0, connectionId = undefined) {
14
19
  this.attendeeId = attendeeId;
20
+ this.order = order;
15
21
  this.connectionId = connectionId;
16
- /**
17
- * Order is used to track the most recent client connection
18
- * during a session.
19
- */
20
- this.order = 0;
21
22
  this.connectionStatus = presence_js_1.AttendeeStatus.Disconnected;
22
23
  }
23
24
  getConnectionId() {
@@ -75,12 +76,13 @@ class SystemWorkspaceImpl {
75
76
  const postUpdateActions = [];
76
77
  for (const [clientConnectionId, value] of Object.entries((0, internalUtils_js_1.revealOpaqueJson)(remoteDatastore.clientToSessionId))) {
77
78
  const attendeeId = value.value;
78
- const { attendee, isJoining } = this.ensureAttendee(attendeeId, clientConnectionId,
79
- /* order */ value.rev,
80
- // If the attendee is present in audience OR if the attendee update is from the sending remote client itself,
81
- // then the attendee is considered connected.
82
- /* isConnected */ senderConnectionId === clientConnectionId ||
83
- audienceMembers.has(clientConnectionId));
79
+ const { attendee, isJoining } = this.ensureAttendee({
80
+ attendeeId,
81
+ clientConnectionId,
82
+ order: value.rev,
83
+ isSender: senderConnectionId === clientConnectionId,
84
+ isInAudience: audienceMembers.has(clientConnectionId),
85
+ });
84
86
  // If the attendee is joining the session, add them to the list of joining attendees to be announced later.
85
87
  if (isJoining) {
86
88
  postUpdateActions.push(() => this.events.emit("attendeeConnected", attendee));
@@ -95,32 +97,57 @@ class SystemWorkspaceImpl {
95
97
  }
96
98
  return postUpdateActions;
97
99
  }
98
- onConnectionAdded(clientConnectionId) {
100
+ onConnectionAdded(clientConnectionId, audienceOutOfDate) {
99
101
  (0, internal_1.assert)(this.selfAttendee.getConnectionStatus() === presence_js_1.AttendeeStatus.Disconnected, 0xaad /* Local client should be 'Disconnected' before adding new connection. */);
100
- this.datastore.clientToSessionId[clientConnectionId] = {
101
- rev: this.selfAttendee.order++,
102
- timestamp: Date.now(),
103
- value: this.selfAttendee.attendeeId,
104
- };
105
- // Mark 'Connected' remote attendees connections as stale
106
- for (const staleConnectionClient of this.attendees.values()) {
107
- if (staleConnectionClient.getConnectionStatus() === presence_js_1.AttendeeStatus.Connected) {
108
- this.staleConnectionClients.add(staleConnectionClient);
109
- }
102
+ const selfInAudience = this.audience.getMember(clientConnectionId) !== undefined;
103
+ (0, internal_1.assert)(selfInAudience || audienceOutOfDate, 0xcc0 /* Local client must be in audience for presence to handle added connection. */);
104
+ if (!(clientConnectionId in this.datastore.clientToSessionId)) {
105
+ this.datastore.clientToSessionId[clientConnectionId] = {
106
+ rev: this.selfAttendee.order++,
107
+ timestamp: Date.now(),
108
+ value: this.selfAttendee.attendeeId,
109
+ };
110
110
  }
111
- // Update the self attendee
111
+ // Update the self attendee connection information, but not connection
112
+ // status yet. Connection status is updated once self is in audience -
113
+ // see later. It is only once our connection is known to audience that
114
+ // audience can be used to track other attendees' connection statuses
115
+ // and we seek to present a consistent view locally.
112
116
  this.selfAttendee.connectionId = clientConnectionId;
113
- this.selfAttendee.setConnected();
114
117
  this.attendees.set(clientConnectionId, this.selfAttendee);
115
- this.staleConnectionTimer.setTimeout(() => {
116
- for (const client of this.staleConnectionClients) {
117
- client.setDisconnected();
118
+ if (selfInAudience) {
119
+ // Mark 'Connected' remote attendees connections as stale
120
+ // Performance note: This will visit attendees multiple times as the
121
+ // attendee map has attendeeIds and connectionIds entries that point to
122
+ // the same attendee. But the getConnectionStatus check is cheap and
123
+ // staleConnectionClients.add will handle duplicates.
124
+ this.staleConnectionClients.clear();
125
+ for (const staleConnectionClient of this.attendees.values()) {
126
+ if (staleConnectionClient.getConnectionStatus() === presence_js_1.AttendeeStatus.Connected) {
127
+ this.staleConnectionClients.add(staleConnectionClient);
128
+ }
118
129
  }
119
- for (const client of this.staleConnectionClients) {
120
- this.events.emit("attendeeDisconnected", client);
130
+ this.staleConnectionTimer.setTimeout(this.resolveStaleConnections.bind(this), 30_000);
131
+ this.selfAttendee.setConnected();
132
+ // TODO: AB#56686: self-Attendee never announced as Connected - Emit this event once there are tests in place
133
+ // this.events.emit("attendeeConnected", this.selfAttendee);
134
+ }
135
+ }
136
+ resolveStaleConnections() {
137
+ const consideredDisconnected = [];
138
+ for (const client of this.staleConnectionClients) {
139
+ // Confirm that audience no longer has connection. It is possible
140
+ // but unlikely that no one mentioned the attendee in this period
141
+ // and that they were never disconnected.
142
+ if (this.audience.getMember(client.getConnectionId()) === undefined) {
143
+ consideredDisconnected.push(client);
144
+ client.setDisconnected();
121
145
  }
122
- this.staleConnectionClients.clear();
123
- }, 30_000);
146
+ }
147
+ for (const client of consideredDisconnected) {
148
+ this.events.emit("attendeeDisconnected", client);
149
+ }
150
+ this.staleConnectionClients.clear();
124
151
  }
125
152
  removeClientConnectionId(clientConnectionId) {
126
153
  const attendee = this.attendees.get(clientConnectionId);
@@ -131,6 +158,14 @@ class SystemWorkspaceImpl {
131
158
  if (attendee === this.selfAttendee) {
132
159
  this.staleConnectionTimer.clearTimeout();
133
160
  }
161
+ else {
162
+ // When self is not connected, audience may go through a refresh that
163
+ // removes members and adds them back. Defer any removals until self
164
+ // is connected implying audience is stable.
165
+ if (this.selfAttendee.getConnectionStatus() !== presence_js_1.AttendeeStatus.Connected) {
166
+ return;
167
+ }
168
+ }
134
169
  // If the last known connectionID is different from the connection ID being removed, the attendee has reconnected,
135
170
  // therefore we should not change the attendee connection status or emit a disconnect event.
136
171
  const attendeeReconnected = attendee.getConnectionId() !== clientConnectionId;
@@ -163,29 +198,47 @@ class SystemWorkspaceImpl {
163
198
  * in the attendee map. If not present, SessionClient is created and added
164
199
  * to map. If present, make sure the current connection ID is updated.
165
200
  */
166
- ensureAttendee(attendeeId, clientConnectionId, order, isConnected) {
201
+ ensureAttendee({ attendeeId, clientConnectionId, order, isSender, isInAudience, }) {
167
202
  let attendee = this.attendees.get(attendeeId);
203
+ let isConnected = false;
168
204
  let isJoining = false;
169
205
  if (attendee === undefined) {
170
206
  // New attendee. Create SessionClient and add session ID based
171
207
  // entry to map.
172
- attendee = new SessionClient(attendeeId, clientConnectionId);
208
+ attendee = new SessionClient(attendeeId, order, clientConnectionId);
173
209
  this.attendees.set(attendeeId, attendee);
174
- if (isConnected) {
210
+ // If the attendee update is from the sending remote client itself
211
+ // OR if the attendee is present in audience,
212
+ // then the attendee is considered connected. (Otherwise, leave
213
+ // state as disconnected - default.)
214
+ if (isSender || isInAudience) {
215
+ isConnected = true;
175
216
  attendee.setConnected();
176
217
  isJoining = true;
177
218
  }
178
219
  }
179
- else if (order > attendee.order) {
180
- // The given association is newer than the one we have.
181
- // Update the order and current connection ID.
182
- attendee.order = order;
183
- // Known attendee is joining the session if they are currently disconnected
184
- if (attendee.getConnectionStatus() === presence_js_1.AttendeeStatus.Disconnected && isConnected) {
220
+ else {
221
+ // Known attendee is considered connected if
222
+ isConnected =
223
+ // this information is at least up to date with current knowledge
224
+ order >= attendee.order &&
225
+ // AND in the audience OR
226
+ (isInAudience ||
227
+ // not in audience, but client is the sender and has newer
228
+ // info. (Assume that audience is out of date and attendee
229
+ // is joining.)
230
+ (isSender && order > attendee.order));
231
+ if (order > attendee.order) {
232
+ // The given association is newer than the one we have.
233
+ // Update the order and current connection ID.
234
+ attendee.order = order;
235
+ attendee.connectionId = clientConnectionId;
236
+ }
237
+ // Known attendee is joining the session if they are currently disconnected.
238
+ if (isConnected && attendee.getConnectionStatus() === presence_js_1.AttendeeStatus.Disconnected) {
185
239
  attendee.setConnected();
186
240
  isJoining = true;
187
241
  }
188
- attendee.connectionId = clientConnectionId;
189
242
  }
190
243
  if (isConnected) {
191
244
  // If the attendee is connected, remove them from the stale connection set
@@ -1 +1 @@
1
- {"version":3,"file":"systemWorkspace.js","sourceRoot":"","sources":["../src/systemWorkspace.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport type { IAudience } from \"@fluidframework/container-definitions\";\nimport type { IEmitter, Listenable } from \"@fluidframework/core-interfaces/internal\";\nimport { assert } from \"@fluidframework/core-utils/internal\";\n\nimport type { ClientConnectionId } from \"./baseTypes.js\";\nimport type { InternalTypes } from \"./exposedInternalTypes.js\";\nimport type { PostUpdateAction } from \"./internalTypes.js\";\nimport { revealOpaqueJson } from \"./internalUtils.js\";\nimport type { Attendee, AttendeesEvents, AttendeeId, Presence } from \"./presence.js\";\nimport { AttendeeStatus } from \"./presence.js\";\nimport type { PresenceStatesInternal } from \"./presenceStates.js\";\nimport { TimerManager } from \"./timerManager.js\";\nimport type { AnyWorkspace, StatesWorkspaceSchema } from \"./types.js\";\n\n/**\n * `ConnectionValueState` is known value state for `clientToSessionId` data.\n *\n * @remarks\n * It is {@link InternalTypes.ValueRequiredState} with a known value type.\n */\ninterface ConnectionValueState extends InternalTypes.ValueStateMetadata {\n\tvalue: AttendeeId;\n}\n\n/**\n * The system workspace's datastore structure.\n */\nexport interface SystemWorkspaceDatastore {\n\tclientToSessionId: {\n\t\t[ConnectionId: ClientConnectionId]: ConnectionValueState;\n\t};\n}\n\nclass SessionClient implements Attendee {\n\t/**\n\t * Order is used to track the most recent client connection\n\t * during a session.\n\t */\n\tpublic order: number = 0;\n\n\tprivate connectionStatus: AttendeeStatus = AttendeeStatus.Disconnected;\n\n\tpublic constructor(\n\t\tpublic readonly attendeeId: AttendeeId,\n\t\tpublic connectionId: ClientConnectionId | undefined = undefined,\n\t) {}\n\n\tpublic getConnectionId(): ClientConnectionId {\n\t\tif (this.connectionId === undefined) {\n\t\t\tthrow new Error(\"Client has never been connected\");\n\t\t}\n\t\treturn this.connectionId;\n\t}\n\n\tpublic getConnectionStatus(): AttendeeStatus {\n\t\treturn this.connectionStatus;\n\t}\n\n\tpublic setConnected(): void {\n\t\tthis.connectionStatus = AttendeeStatus.Connected;\n\t}\n\n\tpublic setDisconnected(): void {\n\t\tthis.connectionStatus = AttendeeStatus.Disconnected;\n\t}\n}\n\n/**\n * Internal workspace that manages metadata for session attendees.\n */\nexport interface SystemWorkspace\n\t// Portion of Presence that is handled by SystemWorkspace along with\n\t// responsibility for emitting \"attendeeConnected\" events.\n\textends Exclude<Presence[\"attendees\"], never> {\n\t/**\n\t * Must be called when the current client acquires a new connection.\n\t *\n\t * @param clientConnectionId - The new client connection ID.\n\t */\n\tonConnectionAdded(clientConnectionId: ClientConnectionId): void;\n\n\t/**\n\t * Removes the client connection ID from the system workspace.\n\t *\n\t * @param clientConnectionId - The client connection ID to remove.\n\t */\n\tremoveClientConnectionId(clientConnectionId: ClientConnectionId): void;\n}\n\nclass SystemWorkspaceImpl implements PresenceStatesInternal, SystemWorkspace {\n\tprivate readonly selfAttendee: SessionClient;\n\t/**\n\t * `attendees` is this client's understanding of the attendees in the\n\t * session. The map covers entries for both session ids and connection\n\t * ids, which are never expected to collide, but if they did for same\n\t * client that would be fine.\n\t * An entry is for session ID if the value's `attendeeId` matches the key.\n\t */\n\tprivate readonly attendees = new Map<ClientConnectionId | AttendeeId, SessionClient>();\n\n\t// When local client disconnects, we lose the connectivity status updates for remote attendees in the session.\n\t// Upon reconnect, we mark all other attendees connections as stale and update their status to disconnected after 30 seconds of inactivity.\n\tprivate readonly staleConnectionClients = new Set<SessionClient>();\n\n\tprivate readonly staleConnectionTimer = new TimerManager();\n\n\tpublic constructor(\n\t\tattendeeId: AttendeeId,\n\t\tprivate readonly datastore: SystemWorkspaceDatastore,\n\t\tpublic readonly events: Listenable<AttendeesEvents> & IEmitter<AttendeesEvents>,\n\t\tprivate readonly audience: IAudience,\n\t) {\n\t\tthis.selfAttendee = new SessionClient(attendeeId);\n\t\tthis.attendees.set(attendeeId, this.selfAttendee);\n\t}\n\n\tpublic ensureContent<TSchemaAdditional extends StatesWorkspaceSchema>(\n\t\t_content: TSchemaAdditional,\n\t): never {\n\t\tthrow new Error(\"Method not implemented.\");\n\t}\n\n\tpublic processUpdate(\n\t\t_received: number,\n\t\t_timeModifier: number,\n\t\t/**\n\t\t * Remote datastore typed to match {@link PresenceStatesInternal.processUpdate}'s\n\t\t * `ValueUpdateRecord` type that uses {@link InternalTypes.ValueRequiredState}\n\t\t * and expects an Opaque JSON type. (We get away with a non-`unknown` value type\n\t\t * per TypeScript's method parameter bivariance.) Proper type would be\n\t\t * {@link ConnectionValueState} directly.\n\t\t * {@link ClientConnectionId} use for index is also a deviation, but conveniently\n\t\t * the accurate {@link AttendeeId} type is just a branded string, and\n\t\t * {@link ClientConnectionId} is just `string`.\n\t\t */\n\t\tremoteDatastore: {\n\t\t\tclientToSessionId: {\n\t\t\t\t[ConnectionId: ClientConnectionId]: InternalTypes.ValueRequiredState<\n\t\t\t\t\tConnectionValueState[\"value\"]\n\t\t\t\t>;\n\t\t\t};\n\t\t},\n\t\tsenderConnectionId: ClientConnectionId,\n\t): PostUpdateAction[] {\n\t\tconst audienceMembers = this.audience.getMembers();\n\t\tconst postUpdateActions: PostUpdateAction[] = [];\n\t\tfor (const [clientConnectionId, value] of Object.entries(\n\t\t\trevealOpaqueJson(remoteDatastore.clientToSessionId),\n\t\t)) {\n\t\t\tconst attendeeId = value.value;\n\t\t\tconst { attendee, isJoining } = this.ensureAttendee(\n\t\t\t\tattendeeId,\n\t\t\t\tclientConnectionId,\n\t\t\t\t/* order */ value.rev,\n\t\t\t\t// If the attendee is present in audience OR if the attendee update is from the sending remote client itself,\n\t\t\t\t// then the attendee is considered connected.\n\t\t\t\t/* isConnected */ senderConnectionId === clientConnectionId ||\n\t\t\t\t\taudienceMembers.has(clientConnectionId),\n\t\t\t);\n\t\t\t// If the attendee is joining the session, add them to the list of joining attendees to be announced later.\n\t\t\tif (isJoining) {\n\t\t\t\tpostUpdateActions.push(() => this.events.emit(\"attendeeConnected\", attendee));\n\t\t\t}\n\n\t\t\tconst knownSessionId = this.datastore.clientToSessionId[clientConnectionId];\n\t\t\tif (knownSessionId === undefined) {\n\t\t\t\tthis.datastore.clientToSessionId[clientConnectionId] = value;\n\t\t\t} else {\n\t\t\t\tassert(knownSessionId.value === value.value, 0xa5a /* Mismatched SessionId */);\n\t\t\t}\n\t\t}\n\n\t\treturn postUpdateActions;\n\t}\n\n\tpublic onConnectionAdded(clientConnectionId: ClientConnectionId): void {\n\t\tassert(\n\t\t\tthis.selfAttendee.getConnectionStatus() === AttendeeStatus.Disconnected,\n\t\t\t0xaad /* Local client should be 'Disconnected' before adding new connection. */,\n\t\t);\n\n\t\tthis.datastore.clientToSessionId[clientConnectionId] = {\n\t\t\trev: this.selfAttendee.order++,\n\t\t\ttimestamp: Date.now(),\n\t\t\tvalue: this.selfAttendee.attendeeId,\n\t\t};\n\n\t\t// Mark 'Connected' remote attendees connections as stale\n\t\tfor (const staleConnectionClient of this.attendees.values()) {\n\t\t\tif (staleConnectionClient.getConnectionStatus() === AttendeeStatus.Connected) {\n\t\t\t\tthis.staleConnectionClients.add(staleConnectionClient);\n\t\t\t}\n\t\t}\n\n\t\t// Update the self attendee\n\t\tthis.selfAttendee.connectionId = clientConnectionId;\n\t\tthis.selfAttendee.setConnected();\n\t\tthis.attendees.set(clientConnectionId, this.selfAttendee);\n\n\t\tthis.staleConnectionTimer.setTimeout(() => {\n\t\t\tfor (const client of this.staleConnectionClients) {\n\t\t\t\tclient.setDisconnected();\n\t\t\t}\n\t\t\tfor (const client of this.staleConnectionClients) {\n\t\t\t\tthis.events.emit(\"attendeeDisconnected\", client);\n\t\t\t}\n\t\t\tthis.staleConnectionClients.clear();\n\t\t}, 30_000);\n\t}\n\n\tpublic removeClientConnectionId(clientConnectionId: ClientConnectionId): void {\n\t\tconst attendee = this.attendees.get(clientConnectionId);\n\t\tif (!attendee) {\n\t\t\treturn;\n\t\t}\n\n\t\t// If the local connection is being removed, clear the stale connection timer\n\t\tif (attendee === this.selfAttendee) {\n\t\t\tthis.staleConnectionTimer.clearTimeout();\n\t\t}\n\n\t\t// If the last known connectionID is different from the connection ID being removed, the attendee has reconnected,\n\t\t// therefore we should not change the attendee connection status or emit a disconnect event.\n\t\tconst attendeeReconnected = attendee.getConnectionId() !== clientConnectionId;\n\t\tconst connected = attendee.getConnectionStatus() === AttendeeStatus.Connected;\n\t\tif (!attendeeReconnected && connected) {\n\t\t\tattendee.setDisconnected();\n\t\t\tthis.events.emit(\"attendeeDisconnected\", attendee);\n\t\t\tthis.staleConnectionClients.delete(attendee);\n\t\t}\n\t}\n\n\tpublic getAttendees(): ReadonlySet<Attendee> {\n\t\treturn new Set(this.attendees.values());\n\t}\n\n\tpublic getAttendee(clientId: ClientConnectionId | AttendeeId): Attendee {\n\t\tconst attendee = this.attendees.get(clientId);\n\t\tif (attendee) {\n\t\t\treturn attendee;\n\t\t}\n\n\t\t// TODO: Restore option to add attendee on demand to handle internal\n\t\t// lookup cases that must come from internal data.\n\t\t// There aren't any resiliency mechanisms in place to handle a missed\n\t\t// ClientJoin right now.\n\t\tthrow new Error(\"Attendee not found\");\n\t}\n\n\tpublic getMyself(): Attendee {\n\t\treturn this.selfAttendee;\n\t}\n\n\t/**\n\t * Make sure the given client session and connection ID pair are represented\n\t * in the attendee map. If not present, SessionClient is created and added\n\t * to map. If present, make sure the current connection ID is updated.\n\t */\n\tprivate ensureAttendee(\n\t\tattendeeId: AttendeeId,\n\t\tclientConnectionId: ClientConnectionId,\n\t\torder: number,\n\t\tisConnected: boolean,\n\t): { attendee: SessionClient; isJoining: boolean } {\n\t\tlet attendee = this.attendees.get(attendeeId);\n\t\tlet isJoining = false;\n\n\t\tif (attendee === undefined) {\n\t\t\t// New attendee. Create SessionClient and add session ID based\n\t\t\t// entry to map.\n\t\t\tattendee = new SessionClient(attendeeId, clientConnectionId);\n\t\t\tthis.attendees.set(attendeeId, attendee);\n\t\t\tif (isConnected) {\n\t\t\t\tattendee.setConnected();\n\t\t\t\tisJoining = true;\n\t\t\t}\n\t\t} else if (order > attendee.order) {\n\t\t\t// The given association is newer than the one we have.\n\t\t\t// Update the order and current connection ID.\n\t\t\tattendee.order = order;\n\t\t\t// Known attendee is joining the session if they are currently disconnected\n\t\t\tif (attendee.getConnectionStatus() === AttendeeStatus.Disconnected && isConnected) {\n\t\t\t\tattendee.setConnected();\n\t\t\t\tisJoining = true;\n\t\t\t}\n\t\t\tattendee.connectionId = clientConnectionId;\n\t\t}\n\n\t\tif (isConnected) {\n\t\t\t// If the attendee is connected, remove them from the stale connection set\n\t\t\tthis.staleConnectionClients.delete(attendee);\n\t\t}\n\n\t\t// Always update entry for the connection ID. (Okay if already set.)\n\t\tthis.attendees.set(clientConnectionId, attendee);\n\n\t\treturn { attendee, isJoining };\n\t}\n}\n\n/**\n * Instantiates the system workspace.\n */\nexport function createSystemWorkspace(\n\tattendeeId: AttendeeId,\n\tdatastore: SystemWorkspaceDatastore,\n\tevents: Listenable<AttendeesEvents> & IEmitter<AttendeesEvents>,\n\taudience: IAudience,\n): {\n\tworkspace: SystemWorkspace;\n\tstatesEntry: {\n\t\tinternal: PresenceStatesInternal;\n\t\tpublic: AnyWorkspace<StatesWorkspaceSchema>;\n\t};\n} {\n\tconst workspace = new SystemWorkspaceImpl(attendeeId, datastore, events, audience);\n\treturn {\n\t\tworkspace,\n\t\tstatesEntry: {\n\t\t\tinternal: workspace,\n\t\t\tpublic: undefined as unknown as AnyWorkspace<StatesWorkspaceSchema>,\n\t\t},\n\t};\n}\n"]}
1
+ {"version":3,"file":"systemWorkspace.js","sourceRoot":"","sources":["../src/systemWorkspace.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport type { IAudience } from \"@fluidframework/container-definitions\";\nimport type { IEmitter, Listenable } from \"@fluidframework/core-interfaces/internal\";\nimport { assert } from \"@fluidframework/core-utils/internal\";\n\nimport type { ClientConnectionId } from \"./baseTypes.js\";\nimport type { InternalTypes } from \"./exposedInternalTypes.js\";\nimport type { PostUpdateAction } from \"./internalTypes.js\";\nimport { revealOpaqueJson } from \"./internalUtils.js\";\nimport type { Attendee, AttendeesEvents, AttendeeId, Presence } from \"./presence.js\";\nimport { AttendeeStatus } from \"./presence.js\";\nimport type { PresenceStatesInternal } from \"./presenceStates.js\";\nimport { TimerManager } from \"./timerManager.js\";\nimport type { AnyWorkspace, StatesWorkspaceSchema } from \"./types.js\";\n\n/**\n * `ConnectionValueState` is known value state for `clientToSessionId` data.\n *\n * @remarks\n * It is {@link InternalTypes.ValueRequiredState} with a known value type.\n */\ninterface ConnectionValueState extends InternalTypes.ValueStateMetadata {\n\tvalue: AttendeeId;\n}\n\n/**\n * The system workspace's datastore structure.\n */\nexport interface SystemWorkspaceDatastore {\n\tclientToSessionId: {\n\t\t[ConnectionId: ClientConnectionId]: ConnectionValueState;\n\t};\n}\n\nclass SessionClient implements Attendee {\n\tprivate connectionStatus: AttendeeStatus = AttendeeStatus.Disconnected;\n\n\tpublic constructor(\n\t\tpublic readonly attendeeId: AttendeeId,\n\t\t/**\n\t\t * Order is used to track the most recent client connection\n\t\t * during a session.\n\t\t */\n\t\tpublic order: number = 0,\n\t\tpublic connectionId: ClientConnectionId | undefined = undefined,\n\t) {}\n\n\tpublic getConnectionId(): ClientConnectionId {\n\t\tif (this.connectionId === undefined) {\n\t\t\tthrow new Error(\"Client has never been connected\");\n\t\t}\n\t\treturn this.connectionId;\n\t}\n\n\tpublic getConnectionStatus(): AttendeeStatus {\n\t\treturn this.connectionStatus;\n\t}\n\n\tpublic setConnected(): void {\n\t\tthis.connectionStatus = AttendeeStatus.Connected;\n\t}\n\n\tpublic setDisconnected(): void {\n\t\tthis.connectionStatus = AttendeeStatus.Disconnected;\n\t}\n}\n\n/**\n * Internal workspace that manages metadata for session attendees.\n */\nexport interface SystemWorkspace\n\t// Portion of Presence that is handled by SystemWorkspace along with\n\t// responsibility for emitting \"attendeeConnected\" events.\n\textends Exclude<Presence[\"attendees\"], never> {\n\t/**\n\t * Must be called when the current client acquires a new connection.\n\t *\n\t * @param clientConnectionId - The new client connection ID.\n\t * @param audienceOutOfDate - When true, audience cannot be used as authoritative.\n\t */\n\tonConnectionAdded(clientConnectionId: ClientConnectionId, audienceOutOfDate: boolean): void;\n\n\t/**\n\t * Removes the client connection ID from the system workspace.\n\t *\n\t * @param clientConnectionId - The client connection ID to remove.\n\t */\n\tremoveClientConnectionId(clientConnectionId: ClientConnectionId): void;\n}\n\nclass SystemWorkspaceImpl implements PresenceStatesInternal, SystemWorkspace {\n\tprivate readonly selfAttendee: SessionClient;\n\t/**\n\t * `attendees` is this client's understanding of the attendees in the\n\t * session. The map covers entries for both session ids and connection\n\t * ids, which are never expected to collide, but if they did for same\n\t * client that would be fine.\n\t * An entry is for session ID if the value's `attendeeId` matches the key.\n\t */\n\tprivate readonly attendees = new Map<ClientConnectionId | AttendeeId, SessionClient>();\n\n\t// When local client disconnects, we lose the connectivity status updates for remote attendees in the session.\n\t// Upon reconnect, we mark all other attendees connections as stale and update their status to disconnected after 30 seconds of inactivity.\n\tprivate readonly staleConnectionClients = new Set<SessionClient>();\n\n\tprivate readonly staleConnectionTimer = new TimerManager();\n\n\tpublic constructor(\n\t\tattendeeId: AttendeeId,\n\t\tprivate readonly datastore: SystemWorkspaceDatastore,\n\t\tpublic readonly events: Listenable<AttendeesEvents> & IEmitter<AttendeesEvents>,\n\t\tprivate readonly audience: IAudience,\n\t) {\n\t\tthis.selfAttendee = new SessionClient(attendeeId);\n\t\tthis.attendees.set(attendeeId, this.selfAttendee);\n\t}\n\n\tpublic ensureContent<TSchemaAdditional extends StatesWorkspaceSchema>(\n\t\t_content: TSchemaAdditional,\n\t): never {\n\t\tthrow new Error(\"Method not implemented.\");\n\t}\n\n\tpublic processUpdate(\n\t\t_received: number,\n\t\t_timeModifier: number,\n\t\t/**\n\t\t * Remote datastore typed to match {@link PresenceStatesInternal.processUpdate}'s\n\t\t * `ValueUpdateRecord` type that uses {@link InternalTypes.ValueRequiredState}\n\t\t * and expects an Opaque JSON type. (We get away with a non-`unknown` value type\n\t\t * per TypeScript's method parameter bivariance.) Proper type would be\n\t\t * {@link ConnectionValueState} directly.\n\t\t * {@link ClientConnectionId} use for index is also a deviation, but conveniently\n\t\t * the accurate {@link AttendeeId} type is just a branded string, and\n\t\t * {@link ClientConnectionId} is just `string`.\n\t\t */\n\t\tremoteDatastore: {\n\t\t\tclientToSessionId: {\n\t\t\t\t[ConnectionId: ClientConnectionId]: InternalTypes.ValueRequiredState<\n\t\t\t\t\tConnectionValueState[\"value\"]\n\t\t\t\t>;\n\t\t\t};\n\t\t},\n\t\tsenderConnectionId: ClientConnectionId,\n\t): PostUpdateAction[] {\n\t\tconst audienceMembers = this.audience.getMembers();\n\t\tconst postUpdateActions: PostUpdateAction[] = [];\n\t\tfor (const [clientConnectionId, value] of Object.entries(\n\t\t\trevealOpaqueJson(remoteDatastore.clientToSessionId),\n\t\t)) {\n\t\t\tconst attendeeId = value.value;\n\t\t\tconst { attendee, isJoining } = this.ensureAttendee({\n\t\t\t\tattendeeId,\n\t\t\t\tclientConnectionId,\n\t\t\t\torder: value.rev,\n\t\t\t\tisSender: senderConnectionId === clientConnectionId,\n\t\t\t\tisInAudience: audienceMembers.has(clientConnectionId),\n\t\t\t});\n\t\t\t// If the attendee is joining the session, add them to the list of joining attendees to be announced later.\n\t\t\tif (isJoining) {\n\t\t\t\tpostUpdateActions.push(() => this.events.emit(\"attendeeConnected\", attendee));\n\t\t\t}\n\n\t\t\tconst knownSessionId = this.datastore.clientToSessionId[clientConnectionId];\n\t\t\tif (knownSessionId === undefined) {\n\t\t\t\tthis.datastore.clientToSessionId[clientConnectionId] = value;\n\t\t\t} else {\n\t\t\t\tassert(knownSessionId.value === value.value, 0xa5a /* Mismatched SessionId */);\n\t\t\t}\n\t\t}\n\n\t\treturn postUpdateActions;\n\t}\n\n\tpublic onConnectionAdded(\n\t\tclientConnectionId: ClientConnectionId,\n\t\taudienceOutOfDate: boolean,\n\t): void {\n\t\tassert(\n\t\t\tthis.selfAttendee.getConnectionStatus() === AttendeeStatus.Disconnected,\n\t\t\t0xaad /* Local client should be 'Disconnected' before adding new connection. */,\n\t\t);\n\n\t\tconst selfInAudience = this.audience.getMember(clientConnectionId) !== undefined;\n\t\tassert(\n\t\t\tselfInAudience || audienceOutOfDate,\n\t\t\t0xcc0 /* Local client must be in audience for presence to handle added connection. */,\n\t\t);\n\n\t\tif (!(clientConnectionId in this.datastore.clientToSessionId)) {\n\t\t\tthis.datastore.clientToSessionId[clientConnectionId] = {\n\t\t\t\trev: this.selfAttendee.order++,\n\t\t\t\ttimestamp: Date.now(),\n\t\t\t\tvalue: this.selfAttendee.attendeeId,\n\t\t\t};\n\t\t}\n\n\t\t// Update the self attendee connection information, but not connection\n\t\t// status yet. Connection status is updated once self is in audience -\n\t\t// see later. It is only once our connection is known to audience that\n\t\t// audience can be used to track other attendees' connection statuses\n\t\t// and we seek to present a consistent view locally.\n\t\tthis.selfAttendee.connectionId = clientConnectionId;\n\t\tthis.attendees.set(clientConnectionId, this.selfAttendee);\n\n\t\tif (selfInAudience) {\n\t\t\t// Mark 'Connected' remote attendees connections as stale\n\t\t\t// Performance note: This will visit attendees multiple times as the\n\t\t\t// attendee map has attendeeIds and connectionIds entries that point to\n\t\t\t// the same attendee. But the getConnectionStatus check is cheap and\n\t\t\t// staleConnectionClients.add will handle duplicates.\n\t\t\tthis.staleConnectionClients.clear();\n\t\t\tfor (const staleConnectionClient of this.attendees.values()) {\n\t\t\t\tif (staleConnectionClient.getConnectionStatus() === AttendeeStatus.Connected) {\n\t\t\t\t\tthis.staleConnectionClients.add(staleConnectionClient);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthis.staleConnectionTimer.setTimeout(this.resolveStaleConnections.bind(this), 30_000);\n\n\t\t\tthis.selfAttendee.setConnected();\n\t\t\t// TODO: AB#56686: self-Attendee never announced as Connected - Emit this event once there are tests in place\n\t\t\t// this.events.emit(\"attendeeConnected\", this.selfAttendee);\n\t\t}\n\t}\n\n\tprivate resolveStaleConnections(): void {\n\t\tconst consideredDisconnected = [];\n\t\tfor (const client of this.staleConnectionClients) {\n\t\t\t// Confirm that audience no longer has connection. It is possible\n\t\t\t// but unlikely that no one mentioned the attendee in this period\n\t\t\t// and that they were never disconnected.\n\t\t\tif (this.audience.getMember(client.getConnectionId()) === undefined) {\n\t\t\t\tconsideredDisconnected.push(client);\n\t\t\t\tclient.setDisconnected();\n\t\t\t}\n\t\t}\n\t\tfor (const client of consideredDisconnected) {\n\t\t\tthis.events.emit(\"attendeeDisconnected\", client);\n\t\t}\n\t\tthis.staleConnectionClients.clear();\n\t}\n\n\tpublic removeClientConnectionId(clientConnectionId: ClientConnectionId): void {\n\t\tconst attendee = this.attendees.get(clientConnectionId);\n\t\tif (!attendee) {\n\t\t\treturn;\n\t\t}\n\n\t\t// If the local connection is being removed, clear the stale connection timer\n\t\tif (attendee === this.selfAttendee) {\n\t\t\tthis.staleConnectionTimer.clearTimeout();\n\t\t} else {\n\t\t\t// When self is not connected, audience may go through a refresh that\n\t\t\t// removes members and adds them back. Defer any removals until self\n\t\t\t// is connected implying audience is stable.\n\t\t\tif (this.selfAttendee.getConnectionStatus() !== AttendeeStatus.Connected) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\n\t\t// If the last known connectionID is different from the connection ID being removed, the attendee has reconnected,\n\t\t// therefore we should not change the attendee connection status or emit a disconnect event.\n\t\tconst attendeeReconnected = attendee.getConnectionId() !== clientConnectionId;\n\t\tconst connected = attendee.getConnectionStatus() === AttendeeStatus.Connected;\n\t\tif (!attendeeReconnected && connected) {\n\t\t\tattendee.setDisconnected();\n\t\t\tthis.events.emit(\"attendeeDisconnected\", attendee);\n\t\t\tthis.staleConnectionClients.delete(attendee);\n\t\t}\n\t}\n\n\tpublic getAttendees(): ReadonlySet<Attendee> {\n\t\treturn new Set(this.attendees.values());\n\t}\n\n\tpublic getAttendee(clientId: ClientConnectionId | AttendeeId): Attendee {\n\t\tconst attendee = this.attendees.get(clientId);\n\t\tif (attendee) {\n\t\t\treturn attendee;\n\t\t}\n\n\t\t// TODO: Restore option to add attendee on demand to handle internal\n\t\t// lookup cases that must come from internal data.\n\t\t// There aren't any resiliency mechanisms in place to handle a missed\n\t\t// ClientJoin right now.\n\t\tthrow new Error(\"Attendee not found\");\n\t}\n\n\tpublic getMyself(): Attendee {\n\t\treturn this.selfAttendee;\n\t}\n\n\t/**\n\t * Make sure the given client session and connection ID pair are represented\n\t * in the attendee map. If not present, SessionClient is created and added\n\t * to map. If present, make sure the current connection ID is updated.\n\t */\n\tprivate ensureAttendee({\n\t\tattendeeId,\n\t\tclientConnectionId,\n\t\torder,\n\t\tisSender,\n\t\tisInAudience,\n\t}: {\n\t\tattendeeId: AttendeeId;\n\t\tclientConnectionId: ClientConnectionId;\n\t\torder: number;\n\t\tisSender: boolean;\n\t\tisInAudience: boolean;\n\t}): { attendee: SessionClient; isJoining: boolean } {\n\t\tlet attendee = this.attendees.get(attendeeId);\n\t\tlet isConnected = false;\n\t\tlet isJoining = false;\n\n\t\tif (attendee === undefined) {\n\t\t\t// New attendee. Create SessionClient and add session ID based\n\t\t\t// entry to map.\n\t\t\tattendee = new SessionClient(attendeeId, order, clientConnectionId);\n\t\t\tthis.attendees.set(attendeeId, attendee);\n\t\t\t// If the attendee update is from the sending remote client itself\n\t\t\t// OR if the attendee is present in audience,\n\t\t\t// then the attendee is considered connected. (Otherwise, leave\n\t\t\t// state as disconnected - default.)\n\t\t\tif (isSender || isInAudience) {\n\t\t\t\tisConnected = true;\n\t\t\t\tattendee.setConnected();\n\t\t\t\tisJoining = true;\n\t\t\t}\n\t\t} else {\n\t\t\t// Known attendee is considered connected if\n\t\t\tisConnected =\n\t\t\t\t// this information is at least up to date with current knowledge\n\t\t\t\torder >= attendee.order &&\n\t\t\t\t// AND in the audience OR\n\t\t\t\t(isInAudience ||\n\t\t\t\t\t// not in audience, but client is the sender and has newer\n\t\t\t\t\t// info. (Assume that audience is out of date and attendee\n\t\t\t\t\t// is joining.)\n\t\t\t\t\t(isSender && order > attendee.order));\n\n\t\t\tif (order > attendee.order) {\n\t\t\t\t// The given association is newer than the one we have.\n\t\t\t\t// Update the order and current connection ID.\n\t\t\t\tattendee.order = order;\n\t\t\t\tattendee.connectionId = clientConnectionId;\n\t\t\t}\n\n\t\t\t// Known attendee is joining the session if they are currently disconnected.\n\t\t\tif (isConnected && attendee.getConnectionStatus() === AttendeeStatus.Disconnected) {\n\t\t\t\tattendee.setConnected();\n\t\t\t\tisJoining = true;\n\t\t\t}\n\t\t}\n\n\t\tif (isConnected) {\n\t\t\t// If the attendee is connected, remove them from the stale connection set\n\t\t\tthis.staleConnectionClients.delete(attendee);\n\t\t}\n\n\t\t// Always update entry for the connection ID. (Okay if already set.)\n\t\tthis.attendees.set(clientConnectionId, attendee);\n\n\t\treturn { attendee, isJoining };\n\t}\n}\n\n/**\n * Instantiates the system workspace.\n */\nexport function createSystemWorkspace(\n\tattendeeId: AttendeeId,\n\tdatastore: SystemWorkspaceDatastore,\n\tevents: Listenable<AttendeesEvents> & IEmitter<AttendeesEvents>,\n\taudience: IAudience,\n): {\n\tworkspace: SystemWorkspace;\n\tstatesEntry: {\n\t\tinternal: PresenceStatesInternal;\n\t\tpublic: AnyWorkspace<StatesWorkspaceSchema>;\n\t};\n} {\n\tconst workspace = new SystemWorkspaceImpl(attendeeId, datastore, events, audience);\n\treturn {\n\t\tworkspace,\n\t\tstatesEntry: {\n\t\t\tinternal: workspace,\n\t\t\tpublic: undefined as unknown as AnyWorkspace<StatesWorkspaceSchema>,\n\t\t},\n\t};\n}\n"]}
package/lib/alpha.d.ts CHANGED
@@ -27,6 +27,7 @@ export {
27
27
  BroadcastControls,
28
28
  ClientConnectionId,
29
29
  InternalTypes,
30
+ KeySchemaValidator,
30
31
  Latest,
31
32
  LatestArguments,
32
33
  LatestArgumentsRaw,
package/lib/beta.d.ts CHANGED
@@ -27,6 +27,7 @@ export {
27
27
  BroadcastControls,
28
28
  ClientConnectionId,
29
29
  InternalTypes,
30
+ KeySchemaValidator,
30
31
  Latest,
31
32
  LatestArguments,
32
33
  LatestArgumentsRaw,
@@ -72,7 +72,7 @@ export declare namespace InternalTypes {
72
72
  *
73
73
  * @system
74
74
  */
75
- interface MapValueState<T, Keys extends string | number> {
75
+ interface MapValueState<T, Keys extends string> {
76
76
  rev: number;
77
77
  items: {
78
78
  [name in Keys]: ValueOptionalState<T>;
@@ -1 +1 @@
1
- {"version":3,"file":"exposedInternalTypes.d.ts","sourceRoot":"","sources":["../src/exposedInternalTypes.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,8DAA8D,CAAC;AAE3G;;;;;;GAMG;AAEH,yBAAiB,aAAa,CAAC;IAC9B;;;;OAIG;IACH,UAAiB,kBAAkB;QAClC,GAAG,EAAE,MAAM,CAAC;QACZ,SAAS,EAAE,MAAM,CAAC;KAClB;IAED;;;;;;;;OAQG;IACH,UAAiB,kBAAkB,CAAC,MAAM,CAAE,SAAQ,kBAAkB;QACrE,KAAK,CAAC,EAAE,sBAAsB,CAAC,MAAM,CAAC,CAAC;KAMvC;IAED;;;;;;;;;;;;;;OAcG;IACH,UAAiB,kBAAkB,CAAC,MAAM,CAAE,SAAQ,kBAAkB;QACrE,KAAK,EAAE,sBAAsB,CAAC,MAAM,CAAC,CAAC;KAMtC;IAED;;;;OAIG;IACH,UAAiB,cAAc,CAAC,CAAC;QAChC,GAAG,EAAE,MAAM,CAAC;QACZ,KAAK,EAAE;YAIN,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,kBAAkB,CAAC,CAAC,CAAC,GAAG,cAAc,CAAC,CAAC,CAAC,CAAC;SACnE,CAAC;KACF;IAED;;;;OAIG;IACH,KAAY,qBAAqB,CAAC,CAAC,IAAI,kBAAkB,CAAC,CAAC,CAAC,GAAG,cAAc,CAAC,CAAC,CAAC,CAAC;IAEjF;;;;OAIG;IACH,UAAiB,aAAa,CAAC,CAAC,EAAE,IAAI,SAAS,MAAM,GAAG,MAAM;QAC7D,GAAG,EAAE,MAAM,CAAC;QACZ,KAAK,EAAE;aAIL,IAAI,IAAI,IAAI,GAAG,kBAAkB,CAAC,CAAC,CAAC;SACrC,CAAC;KACF;IAED;;;;OAIG;IACH,MAAqB,oBAAoB,CAAC,IAAI,EAAE,MAAM,SAAS,qBAAqB,CAAC,GAAG,CAAC;QACxF,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAAqC;KAC1E;IAED;;;;;OAKG;IACH,MAAqB,eAAe,CAAC,CAAC;QACrC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAgB;KAC3C;IAED;;;;;;;;;OASG;IACH,KAAY,UAAU,CAAC,CAAC,IAAI,CAAC,GAAG,eAAe,CAAC,CAAC,CAAC,CAAC;IAEnD;;;;OAIG;IACH,KAAY,cAAc,CACzB,IAAI,SAAS,MAAM,EACnB,MAAM,SAAS,qBAAqB,CAAC,GAAG,CAAC,EACzC,QAAQ,IACL;QAAE,YAAY,EAAE,KAAK,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,CAAA;KAAE,GAAG,CAAC,CACpD,GAAG,EAAE,IAAI,EACT,eAAe,EAAE,oBAAoB,CAAC,IAAI,EAAE,MAAM,CAAC,KAC/C;QACJ,WAAW,CAAC,EAAE;YAAE,KAAK,EAAE,MAAM,CAAC;YAAC,wBAAwB,EAAE,MAAM,GAAG,SAAS,CAAA;SAAE,CAAC;QAC9E,OAAO,EAAE,UAAU,CAAC,QAAQ,CAAC,CAAC;KAC9B,CAAC,CAAC;IAEH;;;;OAIG;IACH,UAAiB,gBAAgB;QAChC,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,EAAE,OAAO,EAAE,CAAC;KAChB;CACD"}
1
+ {"version":3,"file":"exposedInternalTypes.d.ts","sourceRoot":"","sources":["../src/exposedInternalTypes.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,8DAA8D,CAAC;AAE3G;;;;;;GAMG;AAEH,yBAAiB,aAAa,CAAC;IAC9B;;;;OAIG;IACH,UAAiB,kBAAkB;QAClC,GAAG,EAAE,MAAM,CAAC;QACZ,SAAS,EAAE,MAAM,CAAC;KAClB;IAED;;;;;;;;OAQG;IACH,UAAiB,kBAAkB,CAAC,MAAM,CAAE,SAAQ,kBAAkB;QACrE,KAAK,CAAC,EAAE,sBAAsB,CAAC,MAAM,CAAC,CAAC;KAMvC;IAED;;;;;;;;;;;;;;OAcG;IACH,UAAiB,kBAAkB,CAAC,MAAM,CAAE,SAAQ,kBAAkB;QACrE,KAAK,EAAE,sBAAsB,CAAC,MAAM,CAAC,CAAC;KAMtC;IAED;;;;OAIG;IACH,UAAiB,cAAc,CAAC,CAAC;QAChC,GAAG,EAAE,MAAM,CAAC;QACZ,KAAK,EAAE;YAIN,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,kBAAkB,CAAC,CAAC,CAAC,GAAG,cAAc,CAAC,CAAC,CAAC,CAAC;SACnE,CAAC;KACF;IAED;;;;OAIG;IACH,KAAY,qBAAqB,CAAC,CAAC,IAAI,kBAAkB,CAAC,CAAC,CAAC,GAAG,cAAc,CAAC,CAAC,CAAC,CAAC;IAEjF;;;;OAIG;IACH,UAAiB,aAAa,CAAC,CAAC,EAAE,IAAI,SAAS,MAAM;QACpD,GAAG,EAAE,MAAM,CAAC;QACZ,KAAK,EAAE;aAIL,IAAI,IAAI,IAAI,GAAG,kBAAkB,CAAC,CAAC,CAAC;SACrC,CAAC;KACF;IAED;;;;OAIG;IACH,MAAqB,oBAAoB,CAAC,IAAI,EAAE,MAAM,SAAS,qBAAqB,CAAC,GAAG,CAAC;QACxF,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAAqC;KAC1E;IAED;;;;;OAKG;IACH,MAAqB,eAAe,CAAC,CAAC;QACrC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAgB;KAC3C;IAED;;;;;;;;;OASG;IACH,KAAY,UAAU,CAAC,CAAC,IAAI,CAAC,GAAG,eAAe,CAAC,CAAC,CAAC,CAAC;IAEnD;;;;OAIG;IACH,KAAY,cAAc,CACzB,IAAI,SAAS,MAAM,EACnB,MAAM,SAAS,qBAAqB,CAAC,GAAG,CAAC,EACzC,QAAQ,IACL;QAAE,YAAY,EAAE,KAAK,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,CAAA;KAAE,GAAG,CAAC,CACpD,GAAG,EAAE,IAAI,EACT,eAAe,EAAE,oBAAoB,CAAC,IAAI,EAAE,MAAM,CAAC,KAC/C;QACJ,WAAW,CAAC,EAAE;YAAE,KAAK,EAAE,MAAM,CAAC;YAAC,wBAAwB,EAAE,MAAM,GAAG,SAAS,CAAA;SAAE,CAAC;QAC9E,OAAO,EAAE,UAAU,CAAC,QAAQ,CAAC,CAAC;KAC9B,CAAC,CAAC;IAEH;;;;OAIG;IACH,UAAiB,gBAAgB;QAChC,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,EAAE,OAAO,EAAE,CAAC;KAChB;CACD"}
@@ -1 +1 @@
1
- {"version":3,"file":"exposedInternalTypes.js","sourceRoot":"","sources":["../src/exposedInternalTypes.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH;;;;;;GAMG;AACH,2DAA2D;AAC3D,MAAM,KAAW,aAAa,CAmJ7B;AAnJD,WAAiB,aAAa;AAmJ9B,CAAC,EAnJgB,aAAa,KAAb,aAAa,QAmJ7B","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport type { OpaqueJsonDeserialized } from \"@fluidframework/core-interfaces/internal/exposedUtilityTypes\";\n\n/**\n * Collection of value types that are not intended to be used/imported\n * directly outside of this package.\n *\n * @beta\n * @system\n */\n// eslint-disable-next-line @typescript-eslint/no-namespace\nexport namespace InternalTypes {\n\t/**\n\t * Metadata for a value state.\n\t *\n\t * @system\n\t */\n\texport interface ValueStateMetadata {\n\t\trev: number;\n\t\ttimestamp: number;\n\t}\n\n\t/**\n\t * Represents a state that may have a value.\n\t * And it includes standard metadata.\n\t *\n\t * @remarks\n\t * See {@link InternalTypes.ValueRequiredState}.\n\t *\n\t * @system\n\t */\n\texport interface ValueOptionalState<TValue> extends ValueStateMetadata {\n\t\tvalue?: OpaqueJsonDeserialized<TValue>;\n\n\t\t// Uncomment this property and rebuild to check more thoroughly\n\t\t// for incompatibilities between this non-validatable state\n\t\t// and ValidatableOptionalState.\n\t\t// validatedValue?: never;\n\t}\n\n\t/**\n\t * Represents a state that must have a value.\n\t * And it includes standard metadata.\n\t *\n\t * @remarks\n\t * The value is wrapped in `OpaqueJsonDeserialized` as uses are expected\n\t * to involve generic or unknown types that will be filtered. It is here\n\t * mostly as a convenience to the many such uses that would otherwise\n\t * need to specify some wrapper themselves.\n\t *\n\t * For known cases, construct a custom interface that extends\n\t * {@link InternalTypes.ValueStateMetadata}.\n\t *\n\t * @system\n\t */\n\texport interface ValueRequiredState<TValue> extends ValueStateMetadata {\n\t\tvalue: OpaqueJsonDeserialized<TValue>;\n\n\t\t// Uncomment this property and rebuild to check more thoroughly\n\t\t// for incompatibilities between this non-validatable state\n\t\t// and ValidatableOptionalState.\n\t\t// validatedValue?: never;\n\t}\n\n\t/**\n\t * A directory of values, where each value may be an optional state or another directory.\n\t *\n\t * @system\n\t */\n\texport interface ValueDirectory<T> {\n\t\trev: number;\n\t\titems: {\n\t\t\t// Caution: any particular item may or may not exist\n\t\t\t// Typescript does not support absent keys without forcing type to also be undefined.\n\t\t\t// See https://github.com/microsoft/TypeScript/issues/42810.\n\t\t\t[name: string | number]: ValueOptionalState<T> | ValueDirectory<T>;\n\t\t};\n\t}\n\n\t/**\n\t * Convenience type for a required state or a directory of values.\n\t *\n\t * @system\n\t */\n\texport type ValueDirectoryOrState<T> = ValueRequiredState<T> | ValueDirectory<T>;\n\n\t/**\n\t * Collection of optional values in a \"map\" structure.\n\t *\n\t * @system\n\t */\n\texport interface MapValueState<T, Keys extends string | number> {\n\t\trev: number;\n\t\titems: {\n\t\t\t// Caution: any particular item may or may not exist\n\t\t\t// Typescript does not support absent keys without forcing type to also be undefined.\n\t\t\t// See https://github.com/microsoft/TypeScript/issues/42810.\n\t\t\t[name in Keys]: ValueOptionalState<T>;\n\t\t};\n\t}\n\n\t/**\n\t * Opaque type representing internal state datastore.\n\t *\n\t * @system\n\t */\n\texport declare class StateDatastoreHandle<TKey, TValue extends ValueDirectoryOrState<any>> {\n\t\tprivate readonly StateDatastoreHandle: StateDatastoreHandle<TKey, TValue>;\n\t}\n\n\t/**\n\t * Brand to ensure state values internal type safety without revealing\n\t * internals that are subject to change.\n\t *\n\t * @system\n\t */\n\texport declare class StateValueBrand<T> {\n\t\tprivate readonly StateValue: StateValue<T>;\n\t}\n\n\t/**\n\t * This type provides no additional functionality over the type it wraps.\n\t * It is used to ensure type safety within package.\n\t * Users may find it convenient to just use the type it wraps directly.\n\t *\n\t * @privateRemarks\n\t * Checkout filtering omitting unknown from T (`Omit<T,unknown> &`).\n\t *\n\t * @system\n\t */\n\texport type StateValue<T> = T & StateValueBrand<T>;\n\n\t/**\n\t * Package internal function declaration for state and notification instantiation.\n\t *\n\t * @system\n\t */\n\texport type ManagerFactory<\n\t\tTKey extends string,\n\t\tTValue extends ValueDirectoryOrState<any>,\n\t\tTManager,\n\t> = { instanceBase: new (...args: any[]) => any } & ((\n\t\tkey: TKey,\n\t\tdatastoreHandle: StateDatastoreHandle<TKey, TValue>,\n\t) => {\n\t\tinitialData?: { value: TValue; allowableUpdateLatencyMs: number | undefined };\n\t\tmanager: StateValue<TManager>;\n\t});\n\n\t/**\n\t * Structure of a generic notification \"value\".\n\t *\n\t * @system\n\t */\n\texport interface NotificationType {\n\t\tname: string;\n\t\targs: unknown[];\n\t}\n}\n"]}
1
+ {"version":3,"file":"exposedInternalTypes.js","sourceRoot":"","sources":["../src/exposedInternalTypes.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH;;;;;;GAMG;AACH,2DAA2D;AAC3D,MAAM,KAAW,aAAa,CAmJ7B;AAnJD,WAAiB,aAAa;AAmJ9B,CAAC,EAnJgB,aAAa,KAAb,aAAa,QAmJ7B","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport type { OpaqueJsonDeserialized } from \"@fluidframework/core-interfaces/internal/exposedUtilityTypes\";\n\n/**\n * Collection of value types that are not intended to be used/imported\n * directly outside of this package.\n *\n * @beta\n * @system\n */\n// eslint-disable-next-line @typescript-eslint/no-namespace\nexport namespace InternalTypes {\n\t/**\n\t * Metadata for a value state.\n\t *\n\t * @system\n\t */\n\texport interface ValueStateMetadata {\n\t\trev: number;\n\t\ttimestamp: number;\n\t}\n\n\t/**\n\t * Represents a state that may have a value.\n\t * And it includes standard metadata.\n\t *\n\t * @remarks\n\t * See {@link InternalTypes.ValueRequiredState}.\n\t *\n\t * @system\n\t */\n\texport interface ValueOptionalState<TValue> extends ValueStateMetadata {\n\t\tvalue?: OpaqueJsonDeserialized<TValue>;\n\n\t\t// Uncomment this property and rebuild to check more thoroughly\n\t\t// for incompatibilities between this non-validatable state\n\t\t// and ValidatableOptionalState.\n\t\t// validatedValue?: never;\n\t}\n\n\t/**\n\t * Represents a state that must have a value.\n\t * And it includes standard metadata.\n\t *\n\t * @remarks\n\t * The value is wrapped in `OpaqueJsonDeserialized` as uses are expected\n\t * to involve generic or unknown types that will be filtered. It is here\n\t * mostly as a convenience to the many such uses that would otherwise\n\t * need to specify some wrapper themselves.\n\t *\n\t * For known cases, construct a custom interface that extends\n\t * {@link InternalTypes.ValueStateMetadata}.\n\t *\n\t * @system\n\t */\n\texport interface ValueRequiredState<TValue> extends ValueStateMetadata {\n\t\tvalue: OpaqueJsonDeserialized<TValue>;\n\n\t\t// Uncomment this property and rebuild to check more thoroughly\n\t\t// for incompatibilities between this non-validatable state\n\t\t// and ValidatableOptionalState.\n\t\t// validatedValue?: never;\n\t}\n\n\t/**\n\t * A directory of values, where each value may be an optional state or another directory.\n\t *\n\t * @system\n\t */\n\texport interface ValueDirectory<T> {\n\t\trev: number;\n\t\titems: {\n\t\t\t// Caution: any particular item may or may not exist\n\t\t\t// Typescript does not support absent keys without forcing type to also be undefined.\n\t\t\t// See https://github.com/microsoft/TypeScript/issues/42810.\n\t\t\t[name: string | number]: ValueOptionalState<T> | ValueDirectory<T>;\n\t\t};\n\t}\n\n\t/**\n\t * Convenience type for a required state or a directory of values.\n\t *\n\t * @system\n\t */\n\texport type ValueDirectoryOrState<T> = ValueRequiredState<T> | ValueDirectory<T>;\n\n\t/**\n\t * Collection of optional values in a \"map\" structure.\n\t *\n\t * @system\n\t */\n\texport interface MapValueState<T, Keys extends string> {\n\t\trev: number;\n\t\titems: {\n\t\t\t// Caution: any particular item may or may not exist\n\t\t\t// Typescript does not support absent keys without forcing type to also be undefined.\n\t\t\t// See https://github.com/microsoft/TypeScript/issues/42810.\n\t\t\t[name in Keys]: ValueOptionalState<T>;\n\t\t};\n\t}\n\n\t/**\n\t * Opaque type representing internal state datastore.\n\t *\n\t * @system\n\t */\n\texport declare class StateDatastoreHandle<TKey, TValue extends ValueDirectoryOrState<any>> {\n\t\tprivate readonly StateDatastoreHandle: StateDatastoreHandle<TKey, TValue>;\n\t}\n\n\t/**\n\t * Brand to ensure state values internal type safety without revealing\n\t * internals that are subject to change.\n\t *\n\t * @system\n\t */\n\texport declare class StateValueBrand<T> {\n\t\tprivate readonly StateValue: StateValue<T>;\n\t}\n\n\t/**\n\t * This type provides no additional functionality over the type it wraps.\n\t * It is used to ensure type safety within package.\n\t * Users may find it convenient to just use the type it wraps directly.\n\t *\n\t * @privateRemarks\n\t * Checkout filtering omitting unknown from T (`Omit<T,unknown> &`).\n\t *\n\t * @system\n\t */\n\texport type StateValue<T> = T & StateValueBrand<T>;\n\n\t/**\n\t * Package internal function declaration for state and notification instantiation.\n\t *\n\t * @system\n\t */\n\texport type ManagerFactory<\n\t\tTKey extends string,\n\t\tTValue extends ValueDirectoryOrState<any>,\n\t\tTManager,\n\t> = { instanceBase: new (...args: any[]) => any } & ((\n\t\tkey: TKey,\n\t\tdatastoreHandle: StateDatastoreHandle<TKey, TValue>,\n\t) => {\n\t\tinitialData?: { value: TValue; allowableUpdateLatencyMs: number | undefined };\n\t\tmanager: StateValue<TManager>;\n\t});\n\n\t/**\n\t * Structure of a generic notification \"value\".\n\t *\n\t * @system\n\t */\n\texport interface NotificationType {\n\t\tname: string;\n\t\targs: unknown[];\n\t}\n}\n"]}
@@ -45,7 +45,7 @@ class ContainerPresenceManager {
45
45
  assertCompatibilityInvariants(newCompatibilityRequest);
46
46
  // There have not yet been any changes that would require action to upgrade.
47
47
  // But also mixed runtime versions are not yet expected.
48
- fail("Presence is only expected to be accessed with a single version.");
48
+ fail(0xcb1 /* Presence is only expected to be accessed with a single version. */);
49
49
  }
50
50
  onNewUse() {
51
51
  // No-op
@@ -66,7 +66,7 @@ const ContainerPresenceFactory = {
66
66
  assertCompatibilityInvariants(existingInstantiation.compatibility);
67
67
  // There have not yet been any changes that would require action to upgrade.
68
68
  // But also mixed runtime versions are not yet expected.
69
- fail("Presence is only expected to be accessed with a single version.");
69
+ fail(0xcb2 /* Presence is only expected to be accessed with a single version. */);
70
70
  },
71
71
  instantiateExtension(host) {
72
72
  return new ContainerPresenceManager(host);
@@ -1 +1 @@
1
- {"version":3,"file":"getPresence.js","sourceRoot":"","sources":["../src/getPresence.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 { ILayerCompatSupportRequirements } from \"@fluid-internal/client-utils\";\nimport type {\n\tContainerExtension,\n\tContainerExtensionFactory,\n\tExtensionInstantiationResult,\n\tExtensionRuntimeProperties as GenericExtensionRuntimeProperties,\n\tInboundExtensionMessage,\n} from \"@fluidframework/container-runtime-definitions/internal\";\nimport { assert, fail } from \"@fluidframework/core-utils/internal\";\nimport type { IFluidContainer } from \"@fluidframework/fluid-static\";\nimport { isInternalFluidContainer } from \"@fluidframework/fluid-static/internal\";\nimport type {\n\tExtensionCompatibilityDetails,\n\tFluidDataStoreContextInternal,\n\tIFluidDataStoreContext,\n} from \"@fluidframework/runtime-definitions/internal\";\n\nimport type { ExtensionHost, ExtensionRuntimeProperties } from \"./internalTypes.js\";\nimport { pkgVersion } from \"./packageVersion.js\";\nimport type { Presence, PresenceWithNotifications } from \"./presence.js\";\nimport type { PresenceExtensionInterface } from \"./presenceManager.js\";\nimport { createPresenceManager } from \"./presenceManager.js\";\nimport type { SignalMessages } from \"./protocol.js\";\n\nconst presenceCompatibility = {\n\tgeneration: 1,\n\tversion: pkgVersion,\n\tcapabilities: new Set([]),\n} as const satisfies ExtensionCompatibilityDetails;\n\n/**\n * Minimal compatible package version.\n * If an existing presence extension is registered with this version or higher,\n * it can be used instead of instantiating new instance from this version of\n * the package (assuming also capabilities are compatible).\n */\nconst minimalCompatiblePackageVersion = \"2.71.0\";\n\nfunction assertCompatibilityInvariants(compatibility: ExtensionCompatibilityDetails): void {\n\tassert(\n\t\tcompatibility.generation === presenceCompatibility.generation,\n\t\t0xc97 /* Presence compatibility generation mismatch. */,\n\t);\n\tassert(\n\t\tcompatibility.version.startsWith(\"2.\"),\n\t\t0xc98 /* Registered version is not major version 2. */,\n\t);\n\tassert(\n\t\tNumber.parseFloat(compatibility.version.slice(2)) <\n\t\t\tNumber.parseFloat(presenceCompatibility.version.slice(2)),\n\t\t0xc99 /* Registered version is not less than the current version. */,\n\t);\n\tassert(\n\t\tpresenceCompatibility.capabilities.size === 0,\n\t\t0xc9a /* Presence capabilities should be empty. */,\n\t);\n}\n\n/**\n * Common Presence manager for a container\n */\nclass ContainerPresenceManager\n\timplements\n\t\tContainerExtension<ExtensionRuntimeProperties>,\n\t\tReturnType<\n\t\t\tContainerExtensionFactory<\n\t\t\t\tPresenceWithNotifications,\n\t\t\t\tExtensionRuntimeProperties\n\t\t\t>[\"instantiateExtension\"]\n\t\t>\n{\n\t// ContainerExtensionFactory return elements\n\tpublic readonly compatibility = presenceCompatibility;\n\tpublic readonly interface: PresenceWithNotifications;\n\tpublic readonly extension = this;\n\n\tprivate readonly manager: PresenceExtensionInterface;\n\n\tpublic constructor(host: ExtensionHost) {\n\t\tthis.interface = this.manager = createPresenceManager({\n\t\t\t...host,\n\t\t\tsubmitSignal: (message) => {\n\t\t\t\thost.submitAddressedSignal([], message);\n\t\t\t},\n\t\t});\n\t}\n\n\tpublic handleVersionOrCapabilitiesMismatch<_TRequestedInterface>(\n\t\tourExistingInstantiation: Readonly<\n\t\t\tExtensionInstantiationResult<PresenceWithNotifications, ExtensionRuntimeProperties, []>\n\t\t>,\n\t\tnewCompatibilityRequest: ExtensionCompatibilityDetails,\n\t): never {\n\t\tassert(\n\t\t\tourExistingInstantiation.compatibility === presenceCompatibility,\n\t\t\t0xc9b /* Presence extension called without own compatibility details */,\n\t\t);\n\t\tassertCompatibilityInvariants(newCompatibilityRequest);\n\t\t// There have not yet been any changes that would require action to upgrade.\n\t\t// But also mixed runtime versions are not yet expected.\n\t\tfail(\"Presence is only expected to be accessed with a single version.\");\n\t}\n\n\tpublic onNewUse(): void {\n\t\t// No-op\n\t}\n\n\tpublic processSignal(\n\t\taddressChain: string[],\n\t\tmessage: InboundExtensionMessage<SignalMessages>,\n\t\tlocal: boolean,\n\t): void {\n\t\tthis.manager.processSignal(addressChain, message, local);\n\t}\n}\n\nconst extensionId = \"dis:bb89f4c0-80fd-4f0c-8469-4f2848ee7f4a\";\n\nconst ContainerPresenceFactory = {\n\thostRequirements: {\n\t\tminSupportedGeneration: 1,\n\t\trequiredFeatures: [],\n\t} as const satisfies ILayerCompatSupportRequirements,\n\n\tinstanceExpectations: { ...presenceCompatibility, version: minimalCompatiblePackageVersion },\n\n\tresolvePriorInstantiation(\n\t\texistingInstantiation: ExtensionInstantiationResult<\n\t\t\tunknown,\n\t\t\tGenericExtensionRuntimeProperties,\n\t\t\tunknown[]\n\t\t>,\n\t): never {\n\t\t// Validate assumptions about existing instance\n\t\tassertCompatibilityInvariants(existingInstantiation.compatibility);\n\t\t// There have not yet been any changes that would require action to upgrade.\n\t\t// But also mixed runtime versions are not yet expected.\n\t\tfail(\"Presence is only expected to be accessed with a single version.\");\n\t},\n\n\tinstantiateExtension(host: ExtensionHost): ContainerPresenceManager {\n\t\treturn new ContainerPresenceManager(host);\n\t},\n\n\t[Symbol.hasInstance]: (instance: unknown): instance is ContainerPresenceManager => {\n\t\treturn instance instanceof ContainerPresenceManager;\n\t},\n} as const satisfies ContainerExtensionFactory<\n\tPresenceWithNotifications,\n\tExtensionRuntimeProperties\n>;\n\n/**\n * Acquire a {@link Presence} from a Fluid Container\n * @param fluidContainer - Fluid Container to acquire the map from\n * @returns the {@link Presence}\n *\n * @beta\n */\nexport const getPresence: (fluidContainer: IFluidContainer) => Presence = getPresenceAlpha;\n\n/**\n * Acquire a {@link PresenceWithNotifications} from a Fluid Container\n * @param fluidContainer - Fluid Container to acquire the map from\n * @returns the {@link PresenceWithNotifications}\n *\n * @alpha\n */\nexport function getPresenceAlpha(fluidContainer: IFluidContainer): PresenceWithNotifications {\n\tassert(\n\t\tisInternalFluidContainer(fluidContainer),\n\t\t0xa2f /* IFluidContainer was not recognized. Only Containers generated by the Fluid Framework are supported. */,\n\t);\n\tconst presence = fluidContainer.acquireExtension(extensionId, ContainerPresenceFactory);\n\treturn presence;\n}\n\nfunction assertContextHasExtensionProvider(\n\tcontext: IFluidDataStoreContext,\n): asserts context is FluidDataStoreContextInternal {\n\tassert(\n\t\t\"getExtension\" in context,\n\t\t0xc9c /* Data store context does not implement ContainerExtensionProvider */,\n\t);\n}\n\n/**\n * Get {@link Presence} from a Fluid Data Store Context\n *\n * @legacy @alpha\n */\nexport function getPresenceFromDataStoreContext(context: IFluidDataStoreContext): Presence {\n\tassertContextHasExtensionProvider(context);\n\treturn context.getExtension(extensionId, ContainerPresenceFactory);\n}\n"]}
1
+ {"version":3,"file":"getPresence.js","sourceRoot":"","sources":["../src/getPresence.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 { ILayerCompatSupportRequirements } from \"@fluid-internal/client-utils\";\nimport type {\n\tContainerExtension,\n\tContainerExtensionFactory,\n\tExtensionInstantiationResult,\n\tExtensionRuntimeProperties as GenericExtensionRuntimeProperties,\n\tInboundExtensionMessage,\n} from \"@fluidframework/container-runtime-definitions/internal\";\nimport { assert, fail } from \"@fluidframework/core-utils/internal\";\nimport type { IFluidContainer } from \"@fluidframework/fluid-static\";\nimport { isInternalFluidContainer } from \"@fluidframework/fluid-static/internal\";\nimport type {\n\tExtensionCompatibilityDetails,\n\tFluidDataStoreContextInternal,\n\tIFluidDataStoreContext,\n} from \"@fluidframework/runtime-definitions/internal\";\n\nimport type { ExtensionHost, ExtensionRuntimeProperties } from \"./internalTypes.js\";\nimport { pkgVersion } from \"./packageVersion.js\";\nimport type { Presence, PresenceWithNotifications } from \"./presence.js\";\nimport type { PresenceExtensionInterface } from \"./presenceManager.js\";\nimport { createPresenceManager } from \"./presenceManager.js\";\nimport type { SignalMessages } from \"./protocol.js\";\n\nconst presenceCompatibility = {\n\tgeneration: 1,\n\tversion: pkgVersion,\n\tcapabilities: new Set([]),\n} as const satisfies ExtensionCompatibilityDetails;\n\n/**\n * Minimal compatible package version.\n * If an existing presence extension is registered with this version or higher,\n * it can be used instead of instantiating new instance from this version of\n * the package (assuming also capabilities are compatible).\n */\nconst minimalCompatiblePackageVersion = \"2.71.0\";\n\nfunction assertCompatibilityInvariants(compatibility: ExtensionCompatibilityDetails): void {\n\tassert(\n\t\tcompatibility.generation === presenceCompatibility.generation,\n\t\t0xc97 /* Presence compatibility generation mismatch. */,\n\t);\n\tassert(\n\t\tcompatibility.version.startsWith(\"2.\"),\n\t\t0xc98 /* Registered version is not major version 2. */,\n\t);\n\tassert(\n\t\tNumber.parseFloat(compatibility.version.slice(2)) <\n\t\t\tNumber.parseFloat(presenceCompatibility.version.slice(2)),\n\t\t0xc99 /* Registered version is not less than the current version. */,\n\t);\n\tassert(\n\t\tpresenceCompatibility.capabilities.size === 0,\n\t\t0xc9a /* Presence capabilities should be empty. */,\n\t);\n}\n\n/**\n * Common Presence manager for a container\n */\nclass ContainerPresenceManager\n\timplements\n\t\tContainerExtension<ExtensionRuntimeProperties>,\n\t\tReturnType<\n\t\t\tContainerExtensionFactory<\n\t\t\t\tPresenceWithNotifications,\n\t\t\t\tExtensionRuntimeProperties\n\t\t\t>[\"instantiateExtension\"]\n\t\t>\n{\n\t// ContainerExtensionFactory return elements\n\tpublic readonly compatibility = presenceCompatibility;\n\tpublic readonly interface: PresenceWithNotifications;\n\tpublic readonly extension = this;\n\n\tprivate readonly manager: PresenceExtensionInterface;\n\n\tpublic constructor(host: ExtensionHost) {\n\t\tthis.interface = this.manager = createPresenceManager({\n\t\t\t...host,\n\t\t\tsubmitSignal: (message) => {\n\t\t\t\thost.submitAddressedSignal([], message);\n\t\t\t},\n\t\t});\n\t}\n\n\tpublic handleVersionOrCapabilitiesMismatch<_TRequestedInterface>(\n\t\tourExistingInstantiation: Readonly<\n\t\t\tExtensionInstantiationResult<PresenceWithNotifications, ExtensionRuntimeProperties, []>\n\t\t>,\n\t\tnewCompatibilityRequest: ExtensionCompatibilityDetails,\n\t): never {\n\t\tassert(\n\t\t\tourExistingInstantiation.compatibility === presenceCompatibility,\n\t\t\t0xc9b /* Presence extension called without own compatibility details */,\n\t\t);\n\t\tassertCompatibilityInvariants(newCompatibilityRequest);\n\t\t// There have not yet been any changes that would require action to upgrade.\n\t\t// But also mixed runtime versions are not yet expected.\n\t\tfail(0xcb1 /* Presence is only expected to be accessed with a single version. */);\n\t}\n\n\tpublic onNewUse(): void {\n\t\t// No-op\n\t}\n\n\tpublic processSignal(\n\t\taddressChain: string[],\n\t\tmessage: InboundExtensionMessage<SignalMessages>,\n\t\tlocal: boolean,\n\t): void {\n\t\tthis.manager.processSignal(addressChain, message, local);\n\t}\n}\n\nconst extensionId = \"dis:bb89f4c0-80fd-4f0c-8469-4f2848ee7f4a\";\n\nconst ContainerPresenceFactory = {\n\thostRequirements: {\n\t\tminSupportedGeneration: 1,\n\t\trequiredFeatures: [],\n\t} as const satisfies ILayerCompatSupportRequirements,\n\n\tinstanceExpectations: { ...presenceCompatibility, version: minimalCompatiblePackageVersion },\n\n\tresolvePriorInstantiation(\n\t\texistingInstantiation: ExtensionInstantiationResult<\n\t\t\tunknown,\n\t\t\tGenericExtensionRuntimeProperties,\n\t\t\tunknown[]\n\t\t>,\n\t): never {\n\t\t// Validate assumptions about existing instance\n\t\tassertCompatibilityInvariants(existingInstantiation.compatibility);\n\t\t// There have not yet been any changes that would require action to upgrade.\n\t\t// But also mixed runtime versions are not yet expected.\n\t\tfail(0xcb2 /* Presence is only expected to be accessed with a single version. */);\n\t},\n\n\tinstantiateExtension(host: ExtensionHost): ContainerPresenceManager {\n\t\treturn new ContainerPresenceManager(host);\n\t},\n\n\t[Symbol.hasInstance]: (instance: unknown): instance is ContainerPresenceManager => {\n\t\treturn instance instanceof ContainerPresenceManager;\n\t},\n} as const satisfies ContainerExtensionFactory<\n\tPresenceWithNotifications,\n\tExtensionRuntimeProperties\n>;\n\n/**\n * Acquire a {@link Presence} from a Fluid Container\n * @param fluidContainer - Fluid Container to acquire the map from\n * @returns the {@link Presence}\n *\n * @beta\n */\nexport const getPresence: (fluidContainer: IFluidContainer) => Presence = getPresenceAlpha;\n\n/**\n * Acquire a {@link PresenceWithNotifications} from a Fluid Container\n * @param fluidContainer - Fluid Container to acquire the map from\n * @returns the {@link PresenceWithNotifications}\n *\n * @alpha\n */\nexport function getPresenceAlpha(fluidContainer: IFluidContainer): PresenceWithNotifications {\n\tassert(\n\t\tisInternalFluidContainer(fluidContainer),\n\t\t0xa2f /* IFluidContainer was not recognized. Only Containers generated by the Fluid Framework are supported. */,\n\t);\n\tconst presence = fluidContainer.acquireExtension(extensionId, ContainerPresenceFactory);\n\treturn presence;\n}\n\nfunction assertContextHasExtensionProvider(\n\tcontext: IFluidDataStoreContext,\n): asserts context is FluidDataStoreContextInternal {\n\tassert(\n\t\t\"getExtension\" in context,\n\t\t0xc9c /* Data store context does not implement ContainerExtensionProvider */,\n\t);\n}\n\n/**\n * Get {@link Presence} from a Fluid Data Store Context\n *\n * @legacy @alpha\n */\nexport function getPresenceFromDataStoreContext(context: IFluidDataStoreContext): Presence {\n\tassertContextHasExtensionProvider(context);\n\treturn context.getExtension(extensionId, ContainerPresenceFactory);\n}\n"]}
package/lib/index.d.ts CHANGED
@@ -14,7 +14,7 @@ export type { NotificationsWorkspace, NotificationsWorkspaceSchema, StatesWorksp
14
14
  export { type Attendee, type AttendeesEvents, type AttendeeId, AttendeeStatus, type Presence, type PresenceEvents, type PresenceWithNotifications, } from "./presence.js";
15
15
  export type { BroadcastControls, BroadcastControlSettings, } from "./broadcastControls.js";
16
16
  export { getPresence, getPresenceAlpha, getPresenceFromDataStoreContext, } from "./getPresence.js";
17
- export type { LatestMap, LatestMapArguments, LatestMapArgumentsRaw, LatestMapClientData, LatestMapEvents, LatestMapFactory, LatestMapItemRemovedClientData, LatestMapItemUpdatedClientData, LatestMapRaw, LatestMapRawEvents, StateMap, } from "./latestMapValueManager.js";
17
+ export type { KeySchemaValidator, LatestMap, LatestMapArguments, LatestMapArgumentsRaw, LatestMapClientData, LatestMapEvents, LatestMapFactory, LatestMapItemRemovedClientData, LatestMapItemUpdatedClientData, LatestMapRaw, LatestMapRawEvents, StateMap, } from "./latestMapValueManager.js";
18
18
  export type { Latest, LatestArguments, LatestArgumentsRaw, LatestEvents, LatestFactory, LatestRaw, LatestRawEvents, } from "./latestValueManager.js";
19
19
  export type { Accessor, LatestClientData, LatestData, LatestMetadata, ProxiedValueAccessor, RawValueAccessor, StateSchemaValidator, ValueAccessor, } from "./latestValueTypes.js";
20
20
  export { type NotificationEmitter, type NotificationListenable, type NotificationSubscriptions, Notifications, type NotificationsManager, type NotificationsManagerEvents, } from "./notificationsManager.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;;;;GAMG;AAEH,YAAY,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAEzD,YAAY,EACX,sBAAsB,EACtB,4BAA4B,EAC5B,eAAe,EACf,sBAAsB,EACtB,qBAAqB,EACrB,oBAAoB,EACpB,gBAAgB,GAChB,MAAM,YAAY,CAAC;AAEpB,OAAO,EACN,KAAK,QAAQ,EACb,KAAK,eAAe,EACpB,KAAK,UAAU,EACf,cAAc,EACd,KAAK,QAAQ,EACb,KAAK,cAAc,EACnB,KAAK,yBAAyB,GAC9B,MAAM,eAAe,CAAC;AAEvB,YAAY,EACX,iBAAiB,EACjB,wBAAwB,GACxB,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EACN,WAAW,EACX,gBAAgB,EAChB,+BAA+B,GAC/B,MAAM,kBAAkB,CAAC;AAE1B,YAAY,EACX,SAAS,EACT,kBAAkB,EAClB,qBAAqB,EACrB,mBAAmB,EACnB,eAAe,EACf,gBAAgB,EAChB,8BAA8B,EAC9B,8BAA8B,EAC9B,YAAY,EACZ,kBAAkB,EAClB,QAAQ,GACR,MAAM,4BAA4B,CAAC;AACpC,YAAY,EACX,MAAM,EACN,eAAe,EACf,kBAAkB,EAClB,YAAY,EACZ,aAAa,EACb,SAAS,EACT,eAAe,GACf,MAAM,yBAAyB,CAAC;AACjC,YAAY,EACX,QAAQ,EACR,gBAAgB,EAChB,UAAU,EACV,cAAc,EACd,oBAAoB,EACpB,gBAAgB,EAChB,oBAAoB,EACpB,aAAa,GACb,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EACN,KAAK,mBAAmB,EACxB,KAAK,sBAAsB,EAC3B,KAAK,yBAAyB,EAC9B,aAAa,EACb,KAAK,oBAAoB,EACzB,KAAK,0BAA0B,GAC/B,MAAM,2BAA2B,CAAC;AAEnC,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEjD,YAAY,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC/D,YAAY,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;;;;GAMG;AAEH,YAAY,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAEzD,YAAY,EACX,sBAAsB,EACtB,4BAA4B,EAC5B,eAAe,EACf,sBAAsB,EACtB,qBAAqB,EACrB,oBAAoB,EACpB,gBAAgB,GAChB,MAAM,YAAY,CAAC;AAEpB,OAAO,EACN,KAAK,QAAQ,EACb,KAAK,eAAe,EACpB,KAAK,UAAU,EACf,cAAc,EACd,KAAK,QAAQ,EACb,KAAK,cAAc,EACnB,KAAK,yBAAyB,GAC9B,MAAM,eAAe,CAAC;AAEvB,YAAY,EACX,iBAAiB,EACjB,wBAAwB,GACxB,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EACN,WAAW,EACX,gBAAgB,EAChB,+BAA+B,GAC/B,MAAM,kBAAkB,CAAC;AAE1B,YAAY,EACX,kBAAkB,EAClB,SAAS,EACT,kBAAkB,EAClB,qBAAqB,EACrB,mBAAmB,EACnB,eAAe,EACf,gBAAgB,EAChB,8BAA8B,EAC9B,8BAA8B,EAC9B,YAAY,EACZ,kBAAkB,EAClB,QAAQ,GACR,MAAM,4BAA4B,CAAC;AACpC,YAAY,EACX,MAAM,EACN,eAAe,EACf,kBAAkB,EAClB,YAAY,EACZ,aAAa,EACb,SAAS,EACT,eAAe,GACf,MAAM,yBAAyB,CAAC;AACjC,YAAY,EACX,QAAQ,EACR,gBAAgB,EAChB,UAAU,EACV,cAAc,EACd,oBAAoB,EACpB,gBAAgB,EAChB,oBAAoB,EACpB,aAAa,GACb,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EACN,KAAK,mBAAmB,EACxB,KAAK,sBAAsB,EAC3B,KAAK,yBAAyB,EAC9B,aAAa,EACb,KAAK,oBAAoB,EACzB,KAAK,0BAA0B,GAC/B,MAAM,2BAA2B,CAAC;AAEnC,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEjD,YAAY,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC/D,YAAY,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC"}
package/lib/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAsBH,OAAO,EAIN,cAAc,GAId,MAAM,eAAe,CAAC;AAOvB,OAAO,EACN,WAAW,EACX,gBAAgB,EAChB,+BAA+B,GAC/B,MAAM,kBAAkB,CAAC;AAmC1B,OAAO,EAIN,aAAa,GAGb,MAAM,2BAA2B,CAAC;AAEnC,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\n/**\n * Package for client presence within a connected session.\n *\n * See {@link https://github.com/microsoft/FluidFramework/tree/main/packages/framework/presence#readme | README.md } for an overview of the package.\n *\n * @packageDocumentation\n */\n\nexport type { ClientConnectionId } from \"./baseTypes.js\";\n\nexport type {\n\tNotificationsWorkspace,\n\tNotificationsWorkspaceSchema,\n\tStatesWorkspace,\n\tStatesWorkspaceEntries,\n\tStatesWorkspaceSchema,\n\tStatesWorkspaceEntry,\n\tWorkspaceAddress,\n} from \"./types.js\";\n\nexport {\n\ttype Attendee,\n\ttype AttendeesEvents,\n\ttype AttendeeId,\n\tAttendeeStatus,\n\ttype Presence,\n\ttype PresenceEvents,\n\ttype PresenceWithNotifications,\n} from \"./presence.js\";\n\nexport type {\n\tBroadcastControls,\n\tBroadcastControlSettings,\n} from \"./broadcastControls.js\";\n\nexport {\n\tgetPresence,\n\tgetPresenceAlpha,\n\tgetPresenceFromDataStoreContext,\n} from \"./getPresence.js\";\n\nexport type {\n\tLatestMap,\n\tLatestMapArguments,\n\tLatestMapArgumentsRaw,\n\tLatestMapClientData,\n\tLatestMapEvents,\n\tLatestMapFactory,\n\tLatestMapItemRemovedClientData,\n\tLatestMapItemUpdatedClientData,\n\tLatestMapRaw,\n\tLatestMapRawEvents,\n\tStateMap,\n} from \"./latestMapValueManager.js\";\nexport type {\n\tLatest,\n\tLatestArguments,\n\tLatestArgumentsRaw,\n\tLatestEvents,\n\tLatestFactory,\n\tLatestRaw,\n\tLatestRawEvents,\n} from \"./latestValueManager.js\";\nexport type {\n\tAccessor,\n\tLatestClientData,\n\tLatestData,\n\tLatestMetadata,\n\tProxiedValueAccessor,\n\tRawValueAccessor,\n\tStateSchemaValidator,\n\tValueAccessor,\n} from \"./latestValueTypes.js\";\n\nexport {\n\ttype NotificationEmitter,\n\ttype NotificationListenable,\n\ttype NotificationSubscriptions,\n\tNotifications,\n\ttype NotificationsManager,\n\ttype NotificationsManagerEvents,\n} from \"./notificationsManager.js\";\n\nexport { StateFactory } from \"./stateFactory.js\";\n\nexport type { InternalTypes } from \"./exposedInternalTypes.js\";\nexport type { InternalUtilityTypes } from \"./exposedUtilityTypes.js\";\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAsBH,OAAO,EAIN,cAAc,GAId,MAAM,eAAe,CAAC;AAOvB,OAAO,EACN,WAAW,EACX,gBAAgB,EAChB,+BAA+B,GAC/B,MAAM,kBAAkB,CAAC;AAoC1B,OAAO,EAIN,aAAa,GAGb,MAAM,2BAA2B,CAAC;AAEnC,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\n/**\n * Package for client presence within a connected session.\n *\n * See {@link https://github.com/microsoft/FluidFramework/tree/main/packages/framework/presence#readme | README.md } for an overview of the package.\n *\n * @packageDocumentation\n */\n\nexport type { ClientConnectionId } from \"./baseTypes.js\";\n\nexport type {\n\tNotificationsWorkspace,\n\tNotificationsWorkspaceSchema,\n\tStatesWorkspace,\n\tStatesWorkspaceEntries,\n\tStatesWorkspaceSchema,\n\tStatesWorkspaceEntry,\n\tWorkspaceAddress,\n} from \"./types.js\";\n\nexport {\n\ttype Attendee,\n\ttype AttendeesEvents,\n\ttype AttendeeId,\n\tAttendeeStatus,\n\ttype Presence,\n\ttype PresenceEvents,\n\ttype PresenceWithNotifications,\n} from \"./presence.js\";\n\nexport type {\n\tBroadcastControls,\n\tBroadcastControlSettings,\n} from \"./broadcastControls.js\";\n\nexport {\n\tgetPresence,\n\tgetPresenceAlpha,\n\tgetPresenceFromDataStoreContext,\n} from \"./getPresence.js\";\n\nexport type {\n\tKeySchemaValidator,\n\tLatestMap,\n\tLatestMapArguments,\n\tLatestMapArgumentsRaw,\n\tLatestMapClientData,\n\tLatestMapEvents,\n\tLatestMapFactory,\n\tLatestMapItemRemovedClientData,\n\tLatestMapItemUpdatedClientData,\n\tLatestMapRaw,\n\tLatestMapRawEvents,\n\tStateMap,\n} from \"./latestMapValueManager.js\";\nexport type {\n\tLatest,\n\tLatestArguments,\n\tLatestArgumentsRaw,\n\tLatestEvents,\n\tLatestFactory,\n\tLatestRaw,\n\tLatestRawEvents,\n} from \"./latestValueManager.js\";\nexport type {\n\tAccessor,\n\tLatestClientData,\n\tLatestData,\n\tLatestMetadata,\n\tProxiedValueAccessor,\n\tRawValueAccessor,\n\tStateSchemaValidator,\n\tValueAccessor,\n} from \"./latestValueTypes.js\";\n\nexport {\n\ttype NotificationEmitter,\n\ttype NotificationListenable,\n\ttype NotificationSubscriptions,\n\tNotifications,\n\ttype NotificationsManager,\n\ttype NotificationsManagerEvents,\n} from \"./notificationsManager.js\";\n\nexport { StateFactory } from \"./stateFactory.js\";\n\nexport type { InternalTypes } from \"./exposedInternalTypes.js\";\nexport type { InternalUtilityTypes } from \"./exposedUtilityTypes.js\";\n"]}
@@ -50,6 +50,12 @@ export type IEphemeralRuntime = Omit<ExtensionHost, "logger" | "submitAddressedS
50
50
  */
51
51
  export interface ValueManager<TValue, TValueState extends InternalTypes.ValueDirectoryOrState<TValue> = InternalTypes.ValueDirectoryOrState<TValue>> {
52
52
  readonly value?: TValueState;
53
+ /**
54
+ * Process an update of `value` for remote attendee.
55
+ * @param attendee - The attendee whose `value` is being updated
56
+ * @param received - The revision number received
57
+ * @param value - The new `value` state
58
+ */
53
59
  update(attendee: Attendee, received: number, value: TValueState): PostUpdateAction[];
54
60
  }
55
61
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"internalTypes.d.ts","sourceRoot":"","sources":["../src/internalTypes.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,aAAa,IAAI,sBAAsB,EAAE,MAAM,wDAAwD,CAAC;AACtH,OAAO,KAAK,EACX,oBAAoB,EACpB,sBAAsB,EACtB,MAAM,0CAA0C,CAAC;AAElD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAC1D,OAAO,KAAK,EACX,8BAA8B,EAC9B,yBAAyB,EACzB,8BAA8B,EAC9B,cAAc,EACd,MAAM,eAAe,CAAC;AAEvB;;GAEG;AACH,MAAM,WAAW,0BAA0B;IAC1C,cAAc,EAAE,cAAc,CAAC;CAC/B;AACD;;GAEG;AACH,MAAM,MAAM,aAAa,GAAG,sBAAsB,CAAC,0BAA0B,CAAC,CAAC;AAE/E;;;;;GAKG;AACH,MAAM,WAAW,YAAY,CAAC,MAAM,SAAS,gCAAgC,CAAC,OAAO,CAAC;IAIrF,CAAC,UAAU,EAAE,UAAU,GAAG,MAAM,CAAC;CACjC;AAED;;;;;;GAMG;AACH,MAAM,MAAM,iBAAiB,GAAG,IAAI,CAAC,aAAa,EAAE,QAAQ,GAAG,uBAAuB,CAAC,GAEtF,OAAO,CAAC,IAAI,CAAC,aAAa,EAAE,QAAQ,CAAC,CAAC,GAAG;IACxC;;;;;OAKG;IACH,YAAY,EAAE,CACb,OAAO,EACJ,8BAA8B,GAC9B,yBAAyB,GACzB,8BAA8B,KAC7B,IAAI,CAAC;CACV,CAAC;AAEH;;;;;GAKG;AACH,MAAM,WAAW,YAAY,CAC5B,MAAM,EACN,WAAW,SACV,aAAa,CAAC,qBAAqB,CAAC,MAAM,CAAC,GAAG,aAAa,CAAC,qBAAqB,CAAC,MAAM,CAAC;IAG1F,QAAQ,CAAC,KAAK,CAAC,EAAE,WAAW,CAAC;IAC7B,MAAM,CAAC,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,GAAG,gBAAgB,EAAE,CAAC;CACrF;AAED;;GAEG;AACH,MAAM,MAAM,gBAAgB,GAAG,MAAM,IAAI,CAAC;AAE1C;;GAEG;AACH,UAAU,mBAAmB,CAAC,MAAM;IACnC;;;;;;OAMG;IACH,cAAc,CAAC,EAAE,sBAAsB,CAAC,MAAM,CAAC,GAAG,SAAS,CAAC;CAE5D;AAED;;;GAGG;AACH,MAAM,WAAW,wBAAwB,CAAC,MAAM,CAC/C,SAAQ,IAAI,CAAC,aAAa,CAAC,kBAAkB,CAAC,MAAM,CAAC,EAAE,MAAM,mBAAmB,CAAC,MAAM,CAAC,CAAC,EACxF,mBAAmB,CAAC,MAAM,CAAC;CAAG;AAEhC;;;GAGG;AACH,MAAM,WAAW,wBAAwB,CAAC,MAAM,CAC/C,SAAQ,IAAI,CAAC,aAAa,CAAC,kBAAkB,CAAC,MAAM,CAAC,EAAE,MAAM,mBAAmB,CAAC,MAAM,CAAC,CAAC,EACxF,mBAAmB,CAAC,MAAM,CAAC;CAAG;AAEhC;;;;;;GAMG;AACH,MAAM,WAAW,yBAAyB,CAAC,CAAC;IAC3C,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE;QAIN,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,wBAAwB,CAAC,CAAC,CAAC,GAAG,yBAAyB,CAAC,CAAC,CAAC,CAAC;KACpF,CAAC;CACF;AAED;;;;;GAKG;AACH,MAAM,MAAM,gCAAgC,CAAC,CAAC,IAC3C,wBAAwB,CAAC,CAAC,CAAC,GAC3B,yBAAyB,CAAC,CAAC,CAAC,CAAC;AAEhC;;;;;;;;;;GAUG;AACH,MAAM,MAAM,yBAAyB,CACpC,CAAC,SACE,aAAa,CAAC,cAAc,CAAC,OAAO,CAAC,GACrC,aAAa,CAAC,kBAAkB,CAAC,OAAO,CAAC,GACzC,aAAa,CAAC,kBAAkB,CAAC,OAAO,CAAC,IACzC,CAAC,SAAS,aAAa,CAAC,cAAc,CAAC,MAAM,MAAM,CAAC,GACrD,oBAAoB,CAAC,UAAU,CAC/B,CAAC,EACD,aAAa,CAAC,cAAc,CAAC,CAAC,CAAC,EAE/B,yBAAyB,CAAC,MAAM,CAAC,EAEjC,oBAAoB,CAAC,mBAAmB,CACvC,IAAI,CAAC,CAAC,EAAE,OAAO,CAAC,GAAG;IAClB,KAAK,EAAE;SACL,MAAM,IAAI,MAAM,CAAC,CAAC,OAAO,CAAC,GAAG,yBAAyB,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC;KAC3E,CAAC;CACF,CACD,CACD,GACA,CAAC,SACE,aAAa,CAAC,kBAAkB,CAAC,MAAM,MAAM,CAAC,GAC9C,aAAa,CAAC,kBAAkB,CAAC,MAAM,MAAM,CAAC,GAChD,oBAAoB,CAAC,mBAAmB,CACxC,IAAI,CAAC,CAAC,EAAE,MAAM,mBAAmB,CAAC,MAAM,CAAC,CAAC,GAAG,mBAAmB,CAAC,MAAM,CAAC,CACxE,GACA,KAAK,CAAC"}
1
+ {"version":3,"file":"internalTypes.d.ts","sourceRoot":"","sources":["../src/internalTypes.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"internalTypes.js","sourceRoot":"","sources":["../src/internalTypes.ts"],"names":[],"mappings":"AAAA;;;GAGG","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport type { ExtensionHost as ContainerExtensionHost } from \"@fluidframework/container-runtime-definitions/internal\";\nimport type {\n\tInternalUtilityTypes,\n\tOpaqueJsonDeserialized,\n} from \"@fluidframework/core-interfaces/internal\";\n\nimport type { InternalTypes } from \"./exposedInternalTypes.js\";\nimport type { AttendeeId, Attendee } from \"./presence.js\";\nimport type {\n\tOutboundAcknowledgementMessage,\n\tOutboundClientJoinMessage,\n\tOutboundDatastoreUpdateMessage,\n\tSignalMessages,\n} from \"./protocol.js\";\n\n/**\n * Presence {@link ContainerExtension} version of {@link @fluidframework/container-runtime-definitions#ExtensionRuntimeProperties}\n */\nexport interface ExtensionRuntimeProperties {\n\tSignalMessages: SignalMessages;\n}\n/**\n * Presence specific ExtensionHost\n */\nexport type ExtensionHost = ContainerExtensionHost<ExtensionRuntimeProperties>;\n\n/**\n * Basic structure of set of {@link Attendee} records within Presence datastore\n *\n * @remarks\n * This is commonly exists per named state in State Managers.\n */\nexport interface ClientRecord<TValue extends ValidatableValueDirectoryOrState<unknown>> {\n\t// Caution: any particular item may or may not exist\n\t// Typescript does not support absent keys without forcing type to also be undefined.\n\t// See https://github.com/microsoft/TypeScript/issues/42810.\n\t[AttendeeId: AttendeeId]: TValue;\n}\n\n/**\n * This interface is a subset of ExtensionHost (and mostly of\n * FluidDataStoreRuntime) that is needed by the Presence States.\n *\n * @privateRemarks\n * Replace with non-DataStore based interface.\n */\nexport type IEphemeralRuntime = Omit<ExtensionHost, \"logger\" | \"submitAddressedSignal\"> &\n\t// Apart from tests, there is always a logger. So this could be promoted to required.\n\tPartial<Pick<ExtensionHost, \"logger\">> & {\n\t\t/**\n\t\t * Submits the signal to be sent to other clients.\n\t\t * @param type - Type of the signal.\n\t\t * @param content - Content of the signal. Should be a JSON serializable object or primitive.\n\t\t * @param targetClientId - When specified, the signal is only sent to the provided client id.\n\t\t */\n\t\tsubmitSignal: (\n\t\t\tmessage:\n\t\t\t\t| OutboundAcknowledgementMessage\n\t\t\t\t| OutboundClientJoinMessage\n\t\t\t\t| OutboundDatastoreUpdateMessage,\n\t\t) => void;\n\t};\n\n/**\n * Contract for State Managers as used by a States Workspace (`PresenceStatesImpl`)\n *\n * @remarks\n * See uses of `unbrandIVM`.\n */\nexport interface ValueManager<\n\tTValue,\n\tTValueState extends\n\t\tInternalTypes.ValueDirectoryOrState<TValue> = InternalTypes.ValueDirectoryOrState<TValue>,\n> {\n\t// State objects should provide value - implement Required<ValueManager<...>>\n\treadonly value?: TValueState;\n\tupdate(attendee: Attendee, received: number, value: TValueState): PostUpdateAction[];\n}\n\n/**\n * A function to be called at the end of an update frame\n */\nexport type PostUpdateAction = () => void;\n\n/**\n * Metadata for a value that may have been validated by a {@link StateSchemaValidator} function.\n */\ninterface ValidatableMetadata<TValue> {\n\t/**\n\t * Contains a validated value or undefined if `value` is invalid.\n\t *\n\t * This property will not be present if the data has not been validated.\n\t * If it is present and `undefined`, the value has been checked and found to be invalid.\n\t * Otherwise it will be the validated value.\n\t */\n\tvalidatedValue?: OpaqueJsonDeserialized<TValue> | undefined;\n\t// typeCheck: \"do you have me?\";\n}\n\n/**\n * Represents data with optional value that may have been validated by a\n * {@link StateSchemaValidator} function.\n */\nexport interface ValidatableOptionalState<TValue>\n\textends Omit<InternalTypes.ValueOptionalState<TValue>, keyof ValidatableMetadata<TValue>>,\n\t\tValidatableMetadata<TValue> {}\n\n/**\n * Represents data with required value that may have been validated by a\n * {@link StateSchemaValidator} function.\n */\nexport interface ValidatableRequiredState<TValue>\n\textends Omit<InternalTypes.ValueRequiredState<TValue>, keyof ValidatableMetadata<TValue>>,\n\t\tValidatableMetadata<TValue> {}\n\n/**\n * A directory of validatable values, where each value may be an optional\n * state or another directory.\n *\n * @remarks\n * The is the validatable version of {@link InternalTypes.ValueDirectory}.\n */\nexport interface ValidatableValueDirectory<T> {\n\trev: number;\n\titems: {\n\t\t// Caution: any particular item may or may not exist\n\t\t// Typescript does not support absent keys without forcing type to also be undefined.\n\t\t// See https://github.com/microsoft/TypeScript/issues/42810.\n\t\t[name: string | number]: ValidatableOptionalState<T> | ValidatableValueDirectory<T>;\n\t};\n}\n\n/**\n * Convenience type for a validatable required state or a directory of values.\n *\n * @remarks\n * This is the validatable version of {@link InternalTypes.ValueDirectoryOrState}.\n */\nexport type ValidatableValueDirectoryOrState<T> =\n\t| ValidatableRequiredState<T>\n\t| ValidatableValueDirectory<T>;\n\n/**\n * Transforms basic value datastore / protocol type into equivalent type\n * with validation support.\n *\n * @remarks\n * Use when some more specific or parameterized type equivalent of\n * `InternalTypes.Value(Directory|RequiredState|OptionalState)` is needed.\n *\n * Basically, wherever a `*ValueState` appears it is extended with\n * {@link ValidatableMetadata} to support validation.\n */\nexport type ValidatableValueStructure<\n\tT extends\n\t\t| InternalTypes.ValueDirectory<unknown>\n\t\t| InternalTypes.ValueRequiredState<unknown>\n\t\t| InternalTypes.ValueOptionalState<unknown>,\n> = T extends InternalTypes.ValueDirectory<infer TValue>\n\t? InternalUtilityTypes.IfSameType<\n\t\t\tT,\n\t\t\tInternalTypes.ValueDirectory<T>,\n\t\t\t// Use canonical type for exact match\n\t\t\tValidatableValueDirectory<TValue>,\n\t\t\t// Inexact match => recurse\n\t\t\tInternalUtilityTypes.FlattenIntersection<\n\t\t\t\tOmit<T, \"items\"> & {\n\t\t\t\t\titems: {\n\t\t\t\t\t\t[KItems in keyof T[\"items\"]]: ValidatableValueStructure<T[\"items\"][KItems]>;\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t>\n\t\t>\n\t: T extends\n\t\t\t\t| InternalTypes.ValueRequiredState<infer TValue>\n\t\t\t\t| InternalTypes.ValueOptionalState<infer TValue>\n\t\t? InternalUtilityTypes.FlattenIntersection<\n\t\t\t\tOmit<T, keyof ValidatableMetadata<TValue>> & ValidatableMetadata<TValue>\n\t\t\t>\n\t\t: never;\n"]}
1
+ {"version":3,"file":"internalTypes.js","sourceRoot":"","sources":["../src/internalTypes.ts"],"names":[],"mappings":"AAAA;;;GAGG","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport type { ExtensionHost as ContainerExtensionHost } from \"@fluidframework/container-runtime-definitions/internal\";\nimport type {\n\tInternalUtilityTypes,\n\tOpaqueJsonDeserialized,\n} from \"@fluidframework/core-interfaces/internal\";\n\nimport type { InternalTypes } from \"./exposedInternalTypes.js\";\nimport type { AttendeeId, Attendee } from \"./presence.js\";\nimport type {\n\tOutboundAcknowledgementMessage,\n\tOutboundClientJoinMessage,\n\tOutboundDatastoreUpdateMessage,\n\tSignalMessages,\n} from \"./protocol.js\";\n\n/**\n * Presence {@link ContainerExtension} version of {@link @fluidframework/container-runtime-definitions#ExtensionRuntimeProperties}\n */\nexport interface ExtensionRuntimeProperties {\n\tSignalMessages: SignalMessages;\n}\n/**\n * Presence specific ExtensionHost\n */\nexport type ExtensionHost = ContainerExtensionHost<ExtensionRuntimeProperties>;\n\n/**\n * Basic structure of set of {@link Attendee} records within Presence datastore\n *\n * @remarks\n * This is commonly exists per named state in State Managers.\n */\nexport interface ClientRecord<TValue extends ValidatableValueDirectoryOrState<unknown>> {\n\t// Caution: any particular item may or may not exist\n\t// Typescript does not support absent keys without forcing type to also be undefined.\n\t// See https://github.com/microsoft/TypeScript/issues/42810.\n\t[AttendeeId: AttendeeId]: TValue;\n}\n\n/**\n * This interface is a subset of ExtensionHost (and mostly of\n * FluidDataStoreRuntime) that is needed by the Presence States.\n *\n * @privateRemarks\n * Replace with non-DataStore based interface.\n */\nexport type IEphemeralRuntime = Omit<ExtensionHost, \"logger\" | \"submitAddressedSignal\"> &\n\t// Apart from tests, there is always a logger. So this could be promoted to required.\n\tPartial<Pick<ExtensionHost, \"logger\">> & {\n\t\t/**\n\t\t * Submits the signal to be sent to other clients.\n\t\t * @param type - Type of the signal.\n\t\t * @param content - Content of the signal. Should be a JSON serializable object or primitive.\n\t\t * @param targetClientId - When specified, the signal is only sent to the provided client id.\n\t\t */\n\t\tsubmitSignal: (\n\t\t\tmessage:\n\t\t\t\t| OutboundAcknowledgementMessage\n\t\t\t\t| OutboundClientJoinMessage\n\t\t\t\t| OutboundDatastoreUpdateMessage,\n\t\t) => void;\n\t};\n\n/**\n * Contract for State Managers as used by a States Workspace (`PresenceStatesImpl`)\n *\n * @remarks\n * See uses of `unbrandIVM`.\n */\nexport interface ValueManager<\n\tTValue,\n\tTValueState extends\n\t\tInternalTypes.ValueDirectoryOrState<TValue> = InternalTypes.ValueDirectoryOrState<TValue>,\n> {\n\t// State objects should provide value - implement Required<ValueManager<...>>\n\treadonly value?: TValueState;\n\n\t/**\n\t * Process an update of `value` for remote attendee.\n\t * @param attendee - The attendee whose `value` is being updated\n\t * @param received - The revision number received\n\t * @param value - The new `value` state\n\t */\n\tupdate(attendee: Attendee, received: number, value: TValueState): PostUpdateAction[];\n}\n\n/**\n * A function to be called at the end of an update frame\n */\nexport type PostUpdateAction = () => void;\n\n/**\n * Metadata for a value that may have been validated by a {@link StateSchemaValidator} function.\n */\ninterface ValidatableMetadata<TValue> {\n\t/**\n\t * Contains a validated value or undefined if `value` is invalid.\n\t *\n\t * This property will not be present if the data has not been validated.\n\t * If it is present and `undefined`, the value has been checked and found to be invalid.\n\t * Otherwise it will be the validated value.\n\t */\n\tvalidatedValue?: OpaqueJsonDeserialized<TValue> | undefined;\n\t// typeCheck: \"do you have me?\";\n}\n\n/**\n * Represents data with optional value that may have been validated by a\n * {@link StateSchemaValidator} function.\n */\nexport interface ValidatableOptionalState<TValue>\n\textends Omit<InternalTypes.ValueOptionalState<TValue>, keyof ValidatableMetadata<TValue>>,\n\t\tValidatableMetadata<TValue> {}\n\n/**\n * Represents data with required value that may have been validated by a\n * {@link StateSchemaValidator} function.\n */\nexport interface ValidatableRequiredState<TValue>\n\textends Omit<InternalTypes.ValueRequiredState<TValue>, keyof ValidatableMetadata<TValue>>,\n\t\tValidatableMetadata<TValue> {}\n\n/**\n * A directory of validatable values, where each value may be an optional\n * state or another directory.\n *\n * @remarks\n * The is the validatable version of {@link InternalTypes.ValueDirectory}.\n */\nexport interface ValidatableValueDirectory<T> {\n\trev: number;\n\titems: {\n\t\t// Caution: any particular item may or may not exist\n\t\t// Typescript does not support absent keys without forcing type to also be undefined.\n\t\t// See https://github.com/microsoft/TypeScript/issues/42810.\n\t\t[name: string | number]: ValidatableOptionalState<T> | ValidatableValueDirectory<T>;\n\t};\n}\n\n/**\n * Convenience type for a validatable required state or a directory of values.\n *\n * @remarks\n * This is the validatable version of {@link InternalTypes.ValueDirectoryOrState}.\n */\nexport type ValidatableValueDirectoryOrState<T> =\n\t| ValidatableRequiredState<T>\n\t| ValidatableValueDirectory<T>;\n\n/**\n * Transforms basic value datastore / protocol type into equivalent type\n * with validation support.\n *\n * @remarks\n * Use when some more specific or parameterized type equivalent of\n * `InternalTypes.Value(Directory|RequiredState|OptionalState)` is needed.\n *\n * Basically, wherever a `*ValueState` appears it is extended with\n * {@link ValidatableMetadata} to support validation.\n */\nexport type ValidatableValueStructure<\n\tT extends\n\t\t| InternalTypes.ValueDirectory<unknown>\n\t\t| InternalTypes.ValueRequiredState<unknown>\n\t\t| InternalTypes.ValueOptionalState<unknown>,\n> = T extends InternalTypes.ValueDirectory<infer TValue>\n\t? InternalUtilityTypes.IfSameType<\n\t\t\tT,\n\t\t\tInternalTypes.ValueDirectory<T>,\n\t\t\t// Use canonical type for exact match\n\t\t\tValidatableValueDirectory<TValue>,\n\t\t\t// Inexact match => recurse\n\t\t\tInternalUtilityTypes.FlattenIntersection<\n\t\t\t\tOmit<T, \"items\"> & {\n\t\t\t\t\titems: {\n\t\t\t\t\t\t[KItems in keyof T[\"items\"]]: ValidatableValueStructure<T[\"items\"][KItems]>;\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t>\n\t\t>\n\t: T extends\n\t\t\t\t| InternalTypes.ValueRequiredState<infer TValue>\n\t\t\t\t| InternalTypes.ValueOptionalState<infer TValue>\n\t\t? InternalUtilityTypes.FlattenIntersection<\n\t\t\t\tOmit<T, keyof ValidatableMetadata<TValue>> & ValidatableMetadata<TValue>\n\t\t\t>\n\t\t: never;\n"]}