@wordpress/core-data 7.39.1-next.v.0 → 7.39.1-next.v.202602091733.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (98) hide show
  1. package/build/awareness/awareness-state.cjs +267 -0
  2. package/build/awareness/awareness-state.cjs.map +7 -0
  3. package/build/awareness/base-awareness.cjs +14 -11
  4. package/build/awareness/base-awareness.cjs.map +2 -2
  5. package/build/awareness/config.cjs +5 -2
  6. package/build/awareness/config.cjs.map +2 -2
  7. package/build/awareness/post-editor-awareness.cjs +9 -9
  8. package/build/awareness/post-editor-awareness.cjs.map +2 -2
  9. package/build/awareness/typed-awareness.cjs +56 -0
  10. package/build/awareness/typed-awareness.cjs.map +7 -0
  11. package/build/awareness/types.cjs.map +1 -1
  12. package/build/awareness/utils.cjs +43 -14
  13. package/build/awareness/utils.cjs.map +2 -2
  14. package/build/entities.cjs +1 -1
  15. package/build/entities.cjs.map +1 -1
  16. package/build/hooks/use-post-editor-awareness-state.cjs +11 -11
  17. package/build/hooks/use-post-editor-awareness-state.cjs.map +2 -2
  18. package/build/index.cjs +2 -0
  19. package/build/index.cjs.map +2 -2
  20. package/build/private-apis.cjs +3 -1
  21. package/build/private-apis.cjs.map +2 -2
  22. package/build/sync.cjs +18 -6
  23. package/build/sync.cjs.map +3 -3
  24. package/build/utils/crdt-blocks.cjs +3 -2
  25. package/build/utils/crdt-blocks.cjs.map +3 -3
  26. package/build/utils/crdt-user-selections.cjs +2 -1
  27. package/build/utils/crdt-user-selections.cjs.map +3 -3
  28. package/build/utils/crdt.cjs.map +2 -2
  29. package/build-module/awareness/awareness-state.mjs +242 -0
  30. package/build-module/awareness/awareness-state.mjs.map +7 -0
  31. package/build-module/awareness/base-awareness.mjs +14 -11
  32. package/build-module/awareness/base-awareness.mjs.map +2 -2
  33. package/build-module/awareness/config.mjs +3 -1
  34. package/build-module/awareness/config.mjs.map +2 -2
  35. package/build-module/awareness/post-editor-awareness.mjs +9 -9
  36. package/build-module/awareness/post-editor-awareness.mjs.map +2 -2
  37. package/build-module/awareness/typed-awareness.mjs +31 -0
  38. package/build-module/awareness/typed-awareness.mjs.map +7 -0
  39. package/build-module/awareness/utils.mjs +38 -12
  40. package/build-module/awareness/utils.mjs.map +2 -2
  41. package/build-module/entities.mjs +1 -1
  42. package/build-module/entities.mjs.map +1 -1
  43. package/build-module/hooks/use-post-editor-awareness-state.mjs +10 -10
  44. package/build-module/hooks/use-post-editor-awareness-state.mjs.map +2 -2
  45. package/build-module/index.mjs +1 -0
  46. package/build-module/index.mjs.map +2 -2
  47. package/build-module/private-apis.mjs +3 -1
  48. package/build-module/private-apis.mjs.map +2 -2
  49. package/build-module/sync.mjs +9 -3
  50. package/build-module/sync.mjs.map +2 -2
  51. package/build-module/utils/crdt-blocks.mjs +2 -1
  52. package/build-module/utils/crdt-blocks.mjs.map +2 -2
  53. package/build-module/utils/crdt-user-selections.mjs +2 -1
  54. package/build-module/utils/crdt-user-selections.mjs.map +2 -2
  55. package/build-module/utils/crdt.mjs.map +2 -2
  56. package/build-types/awareness/awareness-state.d.ts +125 -0
  57. package/build-types/awareness/awareness-state.d.ts.map +1 -0
  58. package/build-types/awareness/base-awareness.d.ts +9 -6
  59. package/build-types/awareness/base-awareness.d.ts.map +1 -1
  60. package/build-types/awareness/config.d.ts +4 -0
  61. package/build-types/awareness/config.d.ts.map +1 -1
  62. package/build-types/awareness/post-editor-awareness.d.ts +4 -4
  63. package/build-types/awareness/post-editor-awareness.d.ts.map +1 -1
  64. package/build-types/awareness/typed-awareness.d.ts +25 -0
  65. package/build-types/awareness/typed-awareness.d.ts.map +1 -0
  66. package/build-types/awareness/types.d.ts +19 -10
  67. package/build-types/awareness/types.d.ts.map +1 -1
  68. package/build-types/awareness/utils.d.ts +14 -11
  69. package/build-types/awareness/utils.d.ts.map +1 -1
  70. package/build-types/hooks/use-post-editor-awareness-state.d.ts +6 -6
  71. package/build-types/hooks/use-post-editor-awareness-state.d.ts.map +1 -1
  72. package/build-types/index.d.ts +1 -0
  73. package/build-types/index.d.ts.map +1 -1
  74. package/build-types/private-apis.d.ts.map +1 -1
  75. package/build-types/sync.d.ts +3 -2
  76. package/build-types/sync.d.ts.map +1 -1
  77. package/build-types/utils/crdt-blocks.d.ts.map +1 -1
  78. package/build-types/utils/crdt-user-selections.d.ts +1 -1
  79. package/build-types/utils/crdt-user-selections.d.ts.map +1 -1
  80. package/build-types/utils/crdt.d.ts +1 -2
  81. package/build-types/utils/crdt.d.ts.map +1 -1
  82. package/package.json +18 -18
  83. package/src/awareness/awareness-state.ts +342 -0
  84. package/src/awareness/base-awareness.ts +14 -11
  85. package/src/awareness/config.ts +5 -0
  86. package/src/awareness/post-editor-awareness.ts +11 -11
  87. package/src/awareness/typed-awareness.ts +44 -0
  88. package/src/awareness/types.ts +25 -11
  89. package/src/awareness/utils.ts +67 -27
  90. package/src/entities.js +1 -1
  91. package/src/hooks/use-post-editor-awareness-state.ts +21 -20
  92. package/src/index.js +1 -0
  93. package/src/private-apis.js +2 -0
  94. package/src/sync.ts +14 -3
  95. package/src/utils/crdt-blocks.ts +2 -1
  96. package/src/utils/crdt-user-selections.ts +3 -2
  97. package/src/utils/crdt.ts +1 -2
  98. package/src/utils/test/crdt.ts +5 -5
@@ -0,0 +1,267 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // packages/core-data/src/awareness/awareness-state.ts
21
+ var awareness_state_exports = {};
22
+ __export(awareness_state_exports, {
23
+ AwarenessState: () => AwarenessState
24
+ });
25
+ module.exports = __toCommonJS(awareness_state_exports);
26
+ var import_config = require("./config.cjs");
27
+ var import_typed_awareness = require("./typed-awareness.cjs");
28
+ var import_utils = require("./utils.cjs");
29
+ var AwarenessWithEqualityChecks = class extends import_typed_awareness.TypedAwareness {
30
+ /** OVERRIDDEN METHODS */
31
+ /**
32
+ * Set a local state field on an awareness document. Calling this method may
33
+ * trigger rerenders of any subscribed components.
34
+ *
35
+ * Equality checks are provided by the abstract `equalityFieldChecks` property.
36
+ * @param field - The field to set.
37
+ * @param value - The value to set.
38
+ */
39
+ setLocalStateField(field, value) {
40
+ if (this.isFieldEqual(
41
+ field,
42
+ value,
43
+ this.getLocalStateField(field) ?? void 0
44
+ )) {
45
+ return;
46
+ }
47
+ super.setLocalStateField(field, value);
48
+ }
49
+ /** CUSTOM METHODS */
50
+ /**
51
+ * Determine if a field value has changed using the provided equality checks.
52
+ * @param field - The field to check.
53
+ * @param value1 - The first value to compare.
54
+ * @param value2 - The second value to compare.
55
+ */
56
+ isFieldEqual(field, value1, value2) {
57
+ if (["clientId", "isConnected", "isMe"].includes(field)) {
58
+ return value1 === value2;
59
+ }
60
+ if (field in this.equalityFieldChecks) {
61
+ const fn = this.equalityFieldChecks[field];
62
+ return fn(value1, value2);
63
+ }
64
+ throw new Error(
65
+ `No equality check implemented for awareness state field "${field.toString()}".`
66
+ );
67
+ }
68
+ /**
69
+ * Determine if two states are equal by comparing each field using the
70
+ * provided equality checks.
71
+ * @param state1 - The first state to compare.
72
+ * @param state2 - The second state to compare.
73
+ */
74
+ isStateEqual(state1, state2) {
75
+ return [
76
+ .../* @__PURE__ */ new Set([
77
+ ...(0, import_utils.getTypedKeys)(state1),
78
+ ...(0, import_utils.getTypedKeys)(state2)
79
+ ])
80
+ ].every((field) => {
81
+ const value1 = state1[field];
82
+ const value2 = state2[field];
83
+ return this.isFieldEqual(field, value1, value2);
84
+ });
85
+ }
86
+ };
87
+ var AwarenessState = class extends AwarenessWithEqualityChecks {
88
+ /** CUSTOM PROPERTIES */
89
+ /**
90
+ * Whether the setUp method has been called, to avoid running it multiple
91
+ * times.
92
+ */
93
+ hasSetupRun = false;
94
+ /**
95
+ * We keep track of all seen states during the current session for two reasons:
96
+ *
97
+ * 1. So that we can represent recently disconnected collaborators in our UI, even
98
+ * after they have been removed from the awareness document.
99
+ * 2. So that we can provide debug information about all collaborators seen during
100
+ * the session.
101
+ */
102
+ disconnectedCollaborators = /* @__PURE__ */ new Set();
103
+ seenStates = /* @__PURE__ */ new Map();
104
+ /**
105
+ * Hold a snapshot of the previous awareness state allows us to compare the
106
+ * state values and avoid unnecessary updates to subscribers.
107
+ */
108
+ previousSnapshot = /* @__PURE__ */ new Map();
109
+ stateSubscriptions = [];
110
+ /**
111
+ * In some cases, we may want to throttle setting local state fields to avoid
112
+ * overwhelming the awareness document with rapid updates. At the same time, we
113
+ * want to ensure that when we read our own state locally, we get the latest
114
+ * value -- even if it hasn't yet been set on the awareness instance.
115
+ */
116
+ myThrottledState = {};
117
+ throttleTimeouts = /* @__PURE__ */ new Map();
118
+ /** CUSTOM METHODS */
119
+ /**
120
+ * Set up the awareness state. This method is idempotent and will only run
121
+ * once. Subclasses should override `onSetUp()` instead of this method to
122
+ * add their own setup logic.
123
+ *
124
+ * This is defined as a readonly arrow function property to prevent
125
+ * subclasses from overriding it.
126
+ */
127
+ setUp = () => {
128
+ if (this.hasSetupRun) {
129
+ return;
130
+ }
131
+ this.hasSetupRun = true;
132
+ this.onSetUp();
133
+ this.on(
134
+ "change",
135
+ ({ added, removed, updated }) => {
136
+ [...added, ...updated].forEach((id) => {
137
+ this.disconnectedCollaborators.delete(id);
138
+ });
139
+ removed.forEach((id) => {
140
+ this.disconnectedCollaborators.add(id);
141
+ setTimeout(() => {
142
+ this.disconnectedCollaborators.delete(id);
143
+ this.updateSubscribers(
144
+ true
145
+ /* force update */
146
+ );
147
+ }, import_config.REMOVAL_DELAY_IN_MS);
148
+ });
149
+ this.updateSubscribers();
150
+ }
151
+ );
152
+ };
153
+ /**
154
+ * Get the most recent state from the last processed change event.
155
+ *
156
+ * @return An array of EnhancedState< State >.
157
+ */
158
+ getCurrentState() {
159
+ return Array.from(this.previousSnapshot.values());
160
+ }
161
+ /**
162
+ * Get all seen states in this session to enable debug reporting.
163
+ */
164
+ getSeenStates() {
165
+ return this.seenStates;
166
+ }
167
+ /**
168
+ * Allow external code to subscribe to awareness state changes.
169
+ * @param callback - The callback to subscribe to.
170
+ */
171
+ onStateChange(callback) {
172
+ this.stateSubscriptions.push(callback);
173
+ return () => {
174
+ this.stateSubscriptions = this.stateSubscriptions.filter(
175
+ (cb) => cb !== callback
176
+ );
177
+ };
178
+ }
179
+ /**
180
+ * Set a local state field on an awareness document with throttle. See caveats
181
+ * of this.setLocalStateField.
182
+ * @param field - The field to set.
183
+ * @param value - The value to set.
184
+ * @param wait - The wait time in milliseconds.
185
+ */
186
+ setThrottledLocalStateField(field, value, wait) {
187
+ this.setLocalStateField(field, value);
188
+ this.throttleTimeouts.set(
189
+ field,
190
+ setTimeout(() => {
191
+ this.throttleTimeouts.delete(field);
192
+ if (this.myThrottledState[field]) {
193
+ this.setLocalStateField(
194
+ field,
195
+ this.myThrottledState[field]
196
+ );
197
+ delete this.myThrottledState[field];
198
+ }
199
+ }, wait)
200
+ );
201
+ }
202
+ /**
203
+ * Set the current collaborator's connection status as awareness state.
204
+ * @param isConnected - The connection status.
205
+ */
206
+ setConnectionStatus(isConnected) {
207
+ if (isConnected) {
208
+ this.disconnectedCollaborators.delete(this.clientID);
209
+ } else {
210
+ this.disconnectedCollaborators.add(this.clientID);
211
+ }
212
+ this.updateSubscribers(
213
+ true
214
+ /* force update */
215
+ );
216
+ }
217
+ /**
218
+ * Update all subscribed listeners with the latest awareness state.
219
+ * @param forceUpdate - Whether to force an update.
220
+ */
221
+ updateSubscribers(forceUpdate = false) {
222
+ if (!this.stateSubscriptions.length) {
223
+ return;
224
+ }
225
+ const states = this.getStates();
226
+ this.seenStates = new Map([
227
+ ...this.seenStates.entries(),
228
+ ...states.entries()
229
+ ]);
230
+ const updatedStates = new Map(
231
+ [...this.disconnectedCollaborators, ...states.keys()].filter((clientId) => {
232
+ return Object.keys(this.seenStates.get(clientId) ?? {}).length > 0;
233
+ }).map((clientId) => {
234
+ const rawState = this.seenStates.get(clientId);
235
+ const isConnected = !this.disconnectedCollaborators.has(clientId);
236
+ const isMe = clientId === this.clientID;
237
+ const myState = isMe ? this.myThrottledState : {};
238
+ const state = {
239
+ ...rawState,
240
+ ...myState,
241
+ clientId,
242
+ isConnected,
243
+ isMe
244
+ };
245
+ return [clientId, state];
246
+ })
247
+ );
248
+ if (!forceUpdate) {
249
+ if ((0, import_utils.areMapsEqual)(
250
+ this.previousSnapshot,
251
+ updatedStates,
252
+ this.isStateEqual.bind(this)
253
+ )) {
254
+ return;
255
+ }
256
+ }
257
+ this.previousSnapshot = updatedStates;
258
+ this.stateSubscriptions.forEach((callback) => {
259
+ callback(Array.from(updatedStates.values()));
260
+ });
261
+ }
262
+ };
263
+ // Annotate the CommonJS export names for ESM import in node:
264
+ 0 && (module.exports = {
265
+ AwarenessState
266
+ });
267
+ //# sourceMappingURL=awareness-state.cjs.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/awareness/awareness-state.ts"],
4
+ "sourcesContent": ["/**\n * Internal dependencies\n */\nimport { REMOVAL_DELAY_IN_MS } from './config';\nimport { TypedAwareness } from './typed-awareness';\nimport type { EnhancedState, EqualityFieldCheck } from './types';\nimport { getTypedKeys, areMapsEqual } from './utils';\n\ntype AwarenessClientID = number;\n\ninterface AwarenessStateChange {\n\tadded: AwarenessClientID[];\n\tupdated: AwarenessClientID[];\n\tremoved: AwarenessClientID[];\n}\n\nabstract class AwarenessWithEqualityChecks<\n\tState extends object,\n> extends TypedAwareness< State > {\n\t/** OVERRIDDEN METHODS */\n\n\t/**\n\t * Set a local state field on an awareness document. Calling this method may\n\t * trigger rerenders of any subscribed components.\n\t *\n\t * Equality checks are provided by the abstract `equalityFieldChecks` property.\n\t * @param field - The field to set.\n\t * @param value - The value to set.\n\t */\n\tpublic setLocalStateField< FieldName extends string & keyof State >(\n\t\tfield: FieldName,\n\t\tvalue: State[ FieldName ]\n\t): void {\n\t\tif (\n\t\t\tthis.isFieldEqual(\n\t\t\t\tfield,\n\t\t\t\tvalue,\n\t\t\t\tthis.getLocalStateField( field ) ?? undefined\n\t\t\t)\n\t\t) {\n\t\t\treturn;\n\t\t}\n\n\t\tsuper.setLocalStateField( field, value );\n\t}\n\n\t/** ABSTRACT PROPERTIES */\n\n\t/**\n\t * Extending classes must implement equality checks for each awareness state\n\t * field they manage.\n\t */\n\tprotected abstract equalityFieldChecks: {\n\t\t[ FieldName in keyof State ]: EqualityFieldCheck< State, FieldName >;\n\t};\n\n\t/** CUSTOM METHODS */\n\n\t/**\n\t * Determine if a field value has changed using the provided equality checks.\n\t * @param field - The field to check.\n\t * @param value1 - The first value to compare.\n\t * @param value2 - The second value to compare.\n\t */\n\tprotected isFieldEqual< FieldName extends keyof State >(\n\t\tfield: FieldName,\n\t\tvalue1?: State[ FieldName ],\n\t\tvalue2?: State[ FieldName ]\n\t): boolean {\n\t\tif (\n\t\t\t[ 'clientId', 'isConnected', 'isMe' ].includes( field as string )\n\t\t) {\n\t\t\treturn value1 === value2;\n\t\t}\n\n\t\tif ( field in this.equalityFieldChecks ) {\n\t\t\tconst fn = this.equalityFieldChecks[ field ];\n\t\t\treturn fn( value1, value2 );\n\t\t}\n\n\t\tthrow new Error(\n\t\t\t`No equality check implemented for awareness state field \"${ field.toString() }\".`\n\t\t);\n\t}\n\n\t/**\n\t * Determine if two states are equal by comparing each field using the\n\t * provided equality checks.\n\t * @param state1 - The first state to compare.\n\t * @param state2 - The second state to compare.\n\t */\n\tprotected isStateEqual( state1: State, state2: State ): boolean {\n\t\treturn [\n\t\t\t...new Set< keyof State >( [\n\t\t\t\t...getTypedKeys( state1 ),\n\t\t\t\t...getTypedKeys( state2 ),\n\t\t\t] ),\n\t\t].every( ( field ) => {\n\t\t\tconst value1 = state1[ field ];\n\t\t\tconst value2 = state2[ field ];\n\n\t\t\treturn this.isFieldEqual( field, value1, value2 );\n\t\t} );\n\t}\n}\n\n/**\n * Abstract class to manage awareness and allow external code to subscribe to\n * state updates.\n */\nexport abstract class AwarenessState<\n\tState extends object = {},\n> extends AwarenessWithEqualityChecks< State > {\n\t/** CUSTOM PROPERTIES */\n\n\t/**\n\t * Whether the setUp method has been called, to avoid running it multiple\n\t * times.\n\t */\n\tprivate hasSetupRun = false;\n\n\t/**\n\t * We keep track of all seen states during the current session for two reasons:\n\t *\n\t * 1. So that we can represent recently disconnected collaborators in our UI, even\n\t * after they have been removed from the awareness document.\n\t * 2. So that we can provide debug information about all collaborators seen during\n\t * the session.\n\t */\n\tprivate disconnectedCollaborators: Set< number > = new Set();\n\tprivate seenStates: Map< number, State > = new Map();\n\n\t/**\n\t * Hold a snapshot of the previous awareness state allows us to compare the\n\t * state values and avoid unnecessary updates to subscribers.\n\t */\n\tprivate previousSnapshot = new Map< number, EnhancedState< State > >();\n\tprivate stateSubscriptions: Array<\n\t\t( newState: EnhancedState< State >[] ) => void\n\t> = [];\n\n\t/**\n\t * In some cases, we may want to throttle setting local state fields to avoid\n\t * overwhelming the awareness document with rapid updates. At the same time, we\n\t * want to ensure that when we read our own state locally, we get the latest\n\t * value -- even if it hasn't yet been set on the awareness instance.\n\t */\n\tprivate myThrottledState: Partial< State > = {};\n\tprivate throttleTimeouts: Map< string, NodeJS.Timeout > = new Map();\n\n\t/** CUSTOM METHODS */\n\n\t/**\n\t * Set up the awareness state. This method is idempotent and will only run\n\t * once. Subclasses should override `onSetUp()` instead of this method to\n\t * add their own setup logic.\n\t *\n\t * This is defined as a readonly arrow function property to prevent\n\t * subclasses from overriding it.\n\t */\n\tpublic readonly setUp = (): void => {\n\t\tif ( this.hasSetupRun ) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.hasSetupRun = true;\n\n\t\tthis.onSetUp();\n\n\t\tthis.on(\n\t\t\t'change',\n\t\t\t( { added, removed, updated }: AwarenessStateChange ) => {\n\t\t\t\t[ ...added, ...updated ].forEach( ( id ) => {\n\t\t\t\t\tthis.disconnectedCollaborators.delete( id );\n\t\t\t\t} );\n\n\t\t\t\tremoved.forEach( ( id ) => {\n\t\t\t\t\tthis.disconnectedCollaborators.add( id );\n\n\t\t\t\t\tsetTimeout( () => {\n\t\t\t\t\t\tthis.disconnectedCollaborators.delete( id );\n\t\t\t\t\t\tthis.updateSubscribers( true /* force update */ );\n\t\t\t\t\t}, REMOVAL_DELAY_IN_MS );\n\t\t\t\t} );\n\n\t\t\t\t// Do not force-update the store here, since this change handler can be\n\t\t\t\t// called even when there are no actual state changes.\n\t\t\t\tthis.updateSubscribers();\n\t\t\t}\n\t\t);\n\t};\n\n\t/**\n\t * Hook method for subclasses to add their own setup logic. This is called\n\t * once after the base class setup completes. All subclasses must implement\n\t * this method. If extending a class that already implements `onSetUp()`,\n\t * call `super.onSetUp()` to ensure parent setup runs.\n\t */\n\tprotected abstract onSetUp(): void;\n\n\t/**\n\t * Get the most recent state from the last processed change event.\n\t *\n\t * @return An array of EnhancedState< State >.\n\t */\n\tpublic getCurrentState(): EnhancedState< State >[] {\n\t\treturn Array.from( this.previousSnapshot.values() );\n\t}\n\n\t/**\n\t * Get all seen states in this session to enable debug reporting.\n\t */\n\tpublic getSeenStates(): Map< number, State > {\n\t\treturn this.seenStates;\n\t}\n\n\t/**\n\t * Allow external code to subscribe to awareness state changes.\n\t * @param callback - The callback to subscribe to.\n\t */\n\tpublic onStateChange(\n\t\tcallback: ( newState: EnhancedState< State >[] ) => void\n\t): () => void {\n\t\tthis.stateSubscriptions.push( callback );\n\n\t\treturn () => {\n\t\t\tthis.stateSubscriptions = this.stateSubscriptions.filter(\n\t\t\t\t( cb ) => cb !== callback\n\t\t\t);\n\t\t};\n\t}\n\n\t/**\n\t * Set a local state field on an awareness document with throttle. See caveats\n\t * of this.setLocalStateField.\n\t * @param field - The field to set.\n\t * @param value - The value to set.\n\t * @param wait - The wait time in milliseconds.\n\t */\n\tpublic setThrottledLocalStateField<\n\t\tFieldName extends string & keyof State,\n\t>( field: FieldName, value: State[ FieldName ], wait: number ): void {\n\t\tthis.setLocalStateField( field, value );\n\n\t\tthis.throttleTimeouts.set(\n\t\t\tfield,\n\t\t\tsetTimeout( () => {\n\t\t\t\tthis.throttleTimeouts.delete( field );\n\t\t\t\tif ( this.myThrottledState[ field ] ) {\n\t\t\t\t\tthis.setLocalStateField(\n\t\t\t\t\t\tfield,\n\t\t\t\t\t\tthis.myThrottledState[ field ]\n\t\t\t\t\t);\n\n\t\t\t\t\tdelete this.myThrottledState[ field ];\n\t\t\t\t}\n\t\t\t}, wait )\n\t\t);\n\t}\n\n\t/**\n\t * Set the current collaborator's connection status as awareness state.\n\t * @param isConnected - The connection status.\n\t */\n\tpublic setConnectionStatus( isConnected: boolean ): void {\n\t\tif ( isConnected ) {\n\t\t\tthis.disconnectedCollaborators.delete( this.clientID );\n\t\t} else {\n\t\t\tthis.disconnectedCollaborators.add( this.clientID );\n\t\t}\n\n\t\tthis.updateSubscribers( true /* force update */ );\n\t}\n\n\t/**\n\t * Update all subscribed listeners with the latest awareness state.\n\t * @param forceUpdate - Whether to force an update.\n\t */\n\tprotected updateSubscribers( forceUpdate = false ): void {\n\t\tif ( ! this.stateSubscriptions.length ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst states = this.getStates();\n\n\t\tthis.seenStates = new Map< number, State >( [\n\t\t\t...this.seenStates.entries(),\n\t\t\t...states.entries(),\n\t\t] );\n\n\t\tconst updatedStates = new Map< number, EnhancedState< State > >(\n\t\t\t[ ...this.disconnectedCollaborators, ...states.keys() ]\n\t\t\t\t.filter( ( clientId ) => {\n\t\t\t\t\t// Exclude any collaborators with empty awareness state. This can happen from\n\t\t\t\t\t// the Yjs inspector.\n\t\t\t\t\treturn (\n\t\t\t\t\t\tObject.keys( this.seenStates.get( clientId ) ?? {} )\n\t\t\t\t\t\t\t.length > 0\n\t\t\t\t\t);\n\t\t\t\t} )\n\t\t\t\t.map( ( clientId ) => {\n\t\t\t\t\t// The filter above ensures that seenStates has the clientId.\n\t\t\t\t\tconst rawState: State = this.seenStates.get( clientId )!;\n\n\t\t\t\t\tconst isConnected =\n\t\t\t\t\t\t! this.disconnectedCollaborators.has( clientId );\n\t\t\t\t\tconst isMe = clientId === this.clientID;\n\t\t\t\t\tconst myState: Partial< State > = isMe\n\t\t\t\t\t\t? this.myThrottledState\n\t\t\t\t\t\t: {};\n\t\t\t\t\tconst state: EnhancedState< State > = {\n\t\t\t\t\t\t...rawState,\n\t\t\t\t\t\t...myState,\n\t\t\t\t\t\tclientId,\n\t\t\t\t\t\tisConnected,\n\t\t\t\t\t\tisMe,\n\t\t\t\t\t};\n\n\t\t\t\t\treturn [ clientId, state ];\n\t\t\t\t} )\n\t\t);\n\n\t\tif ( ! forceUpdate ) {\n\t\t\tif (\n\t\t\t\tareMapsEqual(\n\t\t\t\t\tthis.previousSnapshot,\n\t\t\t\t\tupdatedStates,\n\t\t\t\t\tthis.isStateEqual.bind( this )\n\t\t\t\t)\n\t\t\t) {\n\t\t\t\t// Awareness state unchanged, do not update subscribers.\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\n\t\t// Update subscribers.\n\t\tthis.previousSnapshot = updatedStates;\n\t\tthis.stateSubscriptions.forEach( ( callback ) => {\n\t\t\tcallback( Array.from( updatedStates.values() ) );\n\t\t} );\n\t}\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -26,28 +26,31 @@ __export(base_awareness_exports, {
26
26
  });
27
27
  module.exports = __toCommonJS(base_awareness_exports);
28
28
  var import_data = require("@wordpress/data");
29
- var import_sync = require("@wordpress/sync");
29
+ var import_awareness_state = require("./awareness-state.cjs");
30
30
  var import_name = require("../name.cjs");
31
31
  var import_utils = require("./utils.cjs");
32
- var BaseAwarenessState = class extends import_sync.AwarenessState {
32
+ var BaseAwarenessState = class extends import_awareness_state.AwarenessState {
33
33
  onSetUp() {
34
- void this.setCurrentUserInfo();
34
+ void this.setCurrentCollaboratorInfo();
35
35
  }
36
36
  /**
37
- * Set the current user info in the local state.
37
+ * Set the current collaborator info in the local state.
38
38
  */
39
- async setCurrentUserInfo() {
39
+ async setCurrentCollaboratorInfo() {
40
40
  const states = this.getStates();
41
- const otherUserColors = Array.from(states.entries()).filter(
42
- ([clientId, state]) => state.userInfo && clientId !== this.clientID
43
- ).map(([, state]) => state.userInfo.color).filter(Boolean);
41
+ const otherCollaboratorColors = Array.from(states.entries()).filter(
42
+ ([clientId, state]) => state.collaboratorInfo && clientId !== this.clientID
43
+ ).map(([, state]) => state.collaboratorInfo.color).filter(Boolean);
44
44
  const currentUser = await (0, import_data.resolveSelect)(import_name.STORE_NAME).getCurrentUser();
45
- const userInfo = (0, import_utils.generateUserInfo)(currentUser, otherUserColors);
46
- this.setLocalStateField("userInfo", userInfo);
45
+ const collaboratorInfo = (0, import_utils.generateCollaboratorInfo)(
46
+ currentUser,
47
+ otherCollaboratorColors
48
+ );
49
+ this.setLocalStateField("collaboratorInfo", collaboratorInfo);
47
50
  }
48
51
  };
49
52
  var baseEqualityFieldChecks = {
50
- userInfo: import_utils.areUserInfosEqual
53
+ collaboratorInfo: import_utils.areCollaboratorInfosEqual
51
54
  };
52
55
  var BaseAwareness = class extends BaseAwarenessState {
53
56
  equalityFieldChecks = baseEqualityFieldChecks;
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/awareness/base-awareness.ts"],
4
- "sourcesContent": ["/**\n * WordPress dependencies\n */\nimport { resolveSelect } from '@wordpress/data';\nimport { AwarenessState } from '@wordpress/sync';\n\n/**\n * Internal dependencies\n */\nimport { STORE_NAME as coreStore } from '../name';\nimport { generateUserInfo, areUserInfosEqual } from './utils';\n\nimport type { BaseState } from './types';\n\nexport abstract class BaseAwarenessState<\n\tState extends BaseState,\n> extends AwarenessState< State > {\n\tprotected onSetUp(): void {\n\t\tvoid this.setCurrentUserInfo();\n\t}\n\n\t/**\n\t * Set the current user info in the local state.\n\t */\n\tprivate async setCurrentUserInfo(): Promise< void > {\n\t\tconst states = this.getStates();\n\t\tconst otherUserColors = Array.from( states.entries() )\n\t\t\t.filter(\n\t\t\t\t( [ clientId, state ] ) =>\n\t\t\t\t\tstate.userInfo && clientId !== this.clientID\n\t\t\t)\n\t\t\t.map( ( [ , state ] ) => state.userInfo.color )\n\t\t\t.filter( Boolean );\n\n\t\t// Get current user info and set it in local state.\n\t\tconst currentUser = await resolveSelect( coreStore ).getCurrentUser();\n\t\tconst userInfo = generateUserInfo( currentUser, otherUserColors );\n\t\tthis.setLocalStateField( 'userInfo', userInfo );\n\t}\n}\n\nexport const baseEqualityFieldChecks = {\n\tuserInfo: areUserInfosEqual,\n};\n\nexport class BaseAwareness extends BaseAwarenessState< BaseState > {\n\tprotected equalityFieldChecks = baseEqualityFieldChecks;\n}\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA,kBAA8B;AAC9B,kBAA+B;AAK/B,kBAAwC;AACxC,mBAAoD;AAI7C,IAAe,qBAAf,cAEG,2BAAwB;AAAA,EACvB,UAAgB;AACzB,SAAK,KAAK,mBAAmB;AAAA,EAC9B;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,qBAAsC;AACnD,UAAM,SAAS,KAAK,UAAU;AAC9B,UAAM,kBAAkB,MAAM,KAAM,OAAO,QAAQ,CAAE,EACnD;AAAA,MACA,CAAE,CAAE,UAAU,KAAM,MACnB,MAAM,YAAY,aAAa,KAAK;AAAA,IACtC,EACC,IAAK,CAAE,CAAE,EAAE,KAAM,MAAO,MAAM,SAAS,KAAM,EAC7C,OAAQ,OAAQ;AAGlB,UAAM,cAAc,UAAM,2BAAe,YAAAA,UAAU,EAAE,eAAe;AACpE,UAAM,eAAW,+BAAkB,aAAa,eAAgB;AAChE,SAAK,mBAAoB,YAAY,QAAS;AAAA,EAC/C;AACD;AAEO,IAAM,0BAA0B;AAAA,EACtC,UAAU;AACX;AAEO,IAAM,gBAAN,cAA4B,mBAAgC;AAAA,EACxD,sBAAsB;AACjC;",
4
+ "sourcesContent": ["/**\n * WordPress dependencies\n */\nimport { resolveSelect } from '@wordpress/data';\n\n/**\n * Internal dependencies\n */\nimport { AwarenessState } from './awareness-state';\nimport { STORE_NAME as coreStore } from '../name';\nimport { generateCollaboratorInfo, areCollaboratorInfosEqual } from './utils';\n\nimport type { BaseState } from './types';\n\nexport abstract class BaseAwarenessState<\n\tState extends BaseState,\n> extends AwarenessState< State > {\n\tprotected onSetUp(): void {\n\t\tvoid this.setCurrentCollaboratorInfo();\n\t}\n\n\t/**\n\t * Set the current collaborator info in the local state.\n\t */\n\tprivate async setCurrentCollaboratorInfo(): Promise< void > {\n\t\tconst states = this.getStates();\n\t\tconst otherCollaboratorColors = Array.from( states.entries() )\n\t\t\t.filter(\n\t\t\t\t( [ clientId, state ] ) =>\n\t\t\t\t\tstate.collaboratorInfo && clientId !== this.clientID\n\t\t\t)\n\t\t\t.map( ( [ , state ] ) => state.collaboratorInfo.color )\n\t\t\t.filter( Boolean );\n\n\t\t// Get current user info and set it in local state.\n\t\tconst currentUser = await resolveSelect( coreStore ).getCurrentUser();\n\t\tconst collaboratorInfo = generateCollaboratorInfo(\n\t\t\tcurrentUser,\n\t\t\totherCollaboratorColors\n\t\t);\n\t\tthis.setLocalStateField( 'collaboratorInfo', collaboratorInfo );\n\t}\n}\n\nexport const baseEqualityFieldChecks = {\n\tcollaboratorInfo: areCollaboratorInfosEqual,\n};\n\nexport class BaseAwareness extends BaseAwarenessState< BaseState > {\n\tprotected equalityFieldChecks = baseEqualityFieldChecks;\n}\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA,kBAA8B;AAK9B,6BAA+B;AAC/B,kBAAwC;AACxC,mBAAoE;AAI7D,IAAe,qBAAf,cAEG,sCAAwB;AAAA,EACvB,UAAgB;AACzB,SAAK,KAAK,2BAA2B;AAAA,EACtC;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,6BAA8C;AAC3D,UAAM,SAAS,KAAK,UAAU;AAC9B,UAAM,0BAA0B,MAAM,KAAM,OAAO,QAAQ,CAAE,EAC3D;AAAA,MACA,CAAE,CAAE,UAAU,KAAM,MACnB,MAAM,oBAAoB,aAAa,KAAK;AAAA,IAC9C,EACC,IAAK,CAAE,CAAE,EAAE,KAAM,MAAO,MAAM,iBAAiB,KAAM,EACrD,OAAQ,OAAQ;AAGlB,UAAM,cAAc,UAAM,2BAAe,YAAAA,UAAU,EAAE,eAAe;AACpE,UAAM,uBAAmB;AAAA,MACxB;AAAA,MACA;AAAA,IACD;AACA,SAAK,mBAAoB,oBAAoB,gBAAiB;AAAA,EAC/D;AACD;AAEO,IAAM,0BAA0B;AAAA,EACtC,kBAAkB;AACnB;AAEO,IAAM,gBAAN,cAA4B,mBAAgC;AAAA,EACxD,sBAAsB;AACjC;",
6
6
  "names": ["coreStore"]
7
7
  }
@@ -21,14 +21,17 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
21
21
  var config_exports = {};
22
22
  __export(config_exports, {
23
23
  AWARENESS_CURSOR_UPDATE_THROTTLE_IN_MS: () => AWARENESS_CURSOR_UPDATE_THROTTLE_IN_MS,
24
- LOCAL_CURSOR_UPDATE_DEBOUNCE_IN_MS: () => LOCAL_CURSOR_UPDATE_DEBOUNCE_IN_MS
24
+ LOCAL_CURSOR_UPDATE_DEBOUNCE_IN_MS: () => LOCAL_CURSOR_UPDATE_DEBOUNCE_IN_MS,
25
+ REMOVAL_DELAY_IN_MS: () => REMOVAL_DELAY_IN_MS
25
26
  });
26
27
  module.exports = __toCommonJS(config_exports);
27
28
  var AWARENESS_CURSOR_UPDATE_THROTTLE_IN_MS = 100;
28
29
  var LOCAL_CURSOR_UPDATE_DEBOUNCE_IN_MS = 5;
30
+ var REMOVAL_DELAY_IN_MS = 5e3;
29
31
  // Annotate the CommonJS export names for ESM import in node:
30
32
  0 && (module.exports = {
31
33
  AWARENESS_CURSOR_UPDATE_THROTTLE_IN_MS,
32
- LOCAL_CURSOR_UPDATE_DEBOUNCE_IN_MS
34
+ LOCAL_CURSOR_UPDATE_DEBOUNCE_IN_MS,
35
+ REMOVAL_DELAY_IN_MS
33
36
  });
34
37
  //# sourceMappingURL=config.cjs.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/awareness/config.ts"],
4
- "sourcesContent": ["/**\n * Delay in milliseconds before throttling the cursor position updates.\n */\nexport const AWARENESS_CURSOR_UPDATE_THROTTLE_IN_MS = 100;\n\n/**\n * Delay in milliseconds before updating the cursor position.\n */\nexport const LOCAL_CURSOR_UPDATE_DEBOUNCE_IN_MS = 5;\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGO,IAAM,yCAAyC;AAK/C,IAAM,qCAAqC;",
4
+ "sourcesContent": ["/**\n * Delay in milliseconds before throttling the cursor position updates.\n */\nexport const AWARENESS_CURSOR_UPDATE_THROTTLE_IN_MS = 100;\n\n/**\n * Delay in milliseconds before updating the cursor position.\n */\nexport const LOCAL_CURSOR_UPDATE_DEBOUNCE_IN_MS = 5;\n\n/**\n * Delay in milliseconds before removing a collaborator from presence indicators.\n */\nexport const REMOVAL_DELAY_IN_MS = 5000;\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGO,IAAM,yCAAyC;AAK/C,IAAM,qCAAqC;AAK3C,IAAM,sBAAsB;",
6
6
  "names": []
7
7
  }
@@ -43,12 +43,12 @@ var PostEditorAwareness = class extends import_base_awareness.BaseAwarenessState
43
43
  };
44
44
  onSetUp() {
45
45
  super.onSetUp();
46
- this.subscribeToUserSelectionChanges();
46
+ this.subscribeToCollaboratorSelectionChanges();
47
47
  }
48
48
  /**
49
- * Subscribe to user selection changes and update the selection state.
49
+ * Subscribe to collaborator selection changes and update the selection state.
50
50
  */
51
- subscribeToUserSelectionChanges() {
51
+ subscribeToCollaboratorSelectionChanges() {
52
52
  const {
53
53
  getSelectionStart,
54
54
  getSelectionEnd,
@@ -89,7 +89,7 @@ var PostEditorAwareness = class extends import_base_awareness.BaseAwarenessState
89
89
  });
90
90
  }
91
91
  /**
92
- * Update the entity record with the current user's selection.
92
+ * Update the entity record with the current collaborator's selection.
93
93
  *
94
94
  * @param selectionStart - The start position of the selection.
95
95
  * @param selectionEnd - The end position of the selection.
@@ -156,13 +156,13 @@ var PostEditorAwareness = class extends import_base_awareness.BaseAwarenessState
156
156
  value.toJSON()
157
157
  ])
158
158
  );
159
- const userMapData = new Map(
159
+ const collaboratorMapData = new Map(
160
160
  Array.from(this.getSeenStates().entries()).map(
161
- ([clientId, userState]) => [
161
+ ([clientId, collaboratorState]) => [
162
162
  String(clientId),
163
163
  {
164
- name: userState.userInfo.name,
165
- wpUserId: userState.userInfo.id
164
+ name: collaboratorState.collaboratorInfo.name,
165
+ wpUserId: collaboratorState.collaboratorInfo.id
166
166
  }
167
167
  ]
168
168
  )
@@ -192,7 +192,7 @@ var PostEditorAwareness = class extends import_base_awareness.BaseAwarenessState
192
192
  return {
193
193
  doc: docData,
194
194
  clients: serializableClientItems,
195
- userMap: Object.fromEntries(userMapData)
195
+ collaboratorMap: Object.fromEntries(collaboratorMapData)
196
196
  };
197
197
  }
198
198
  };
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/awareness/post-editor-awareness.ts"],
4
- "sourcesContent": ["/**\n * WordPress dependencies\n */\nimport { dispatch, select, subscribe } from '@wordpress/data';\nimport { Y } from '@wordpress/sync';\n// @ts-ignore No exported types for block editor store selectors.\nimport { store as blockEditorStore } from '@wordpress/block-editor';\n\n/**\n * Internal dependencies\n */\nimport { BaseAwarenessState, baseEqualityFieldChecks } from './base-awareness';\nimport {\n\tAWARENESS_CURSOR_UPDATE_THROTTLE_IN_MS,\n\tLOCAL_CURSOR_UPDATE_DEBOUNCE_IN_MS,\n} from './config';\nimport { STORE_NAME as coreStore } from '../name';\nimport {\n\tareSelectionsStatesEqual,\n\tgetSelectionState,\n} from '../utils/crdt-user-selections';\n\nimport type { SelectionCursor, WPBlockSelection } from '../types';\nimport type {\n\tDebugUserData,\n\tEditorState,\n\tPostEditorState,\n\tSerializableYItem,\n\tYDocDebugData,\n} from './types';\n\nexport class PostEditorAwareness extends BaseAwarenessState< PostEditorState > {\n\tprotected equalityFieldChecks = {\n\t\t...baseEqualityFieldChecks,\n\t\teditorState: this.areEditorStatesEqual,\n\t};\n\n\tpublic constructor(\n\t\tdoc: Y.Doc,\n\t\tprivate kind: string,\n\t\tprivate name: string,\n\t\tprivate postId: number\n\t) {\n\t\tsuper( doc );\n\t}\n\n\tprotected onSetUp(): void {\n\t\tsuper.onSetUp();\n\n\t\tthis.subscribeToUserSelectionChanges();\n\t}\n\n\t/**\n\t * Subscribe to user selection changes and update the selection state.\n\t */\n\tprivate subscribeToUserSelectionChanges(): void {\n\t\tconst {\n\t\t\tgetSelectionStart,\n\t\t\tgetSelectionEnd,\n\t\t\tgetSelectedBlocksInitialCaretPosition,\n\t\t} = select( blockEditorStore );\n\n\t\t// Keep track of the current selection in the outer scope so we can compare\n\t\t// in the subscription.\n\t\tlet selectionStart = getSelectionStart();\n\t\tlet selectionEnd = getSelectionEnd();\n\t\tlet localCursorTimeout: NodeJS.Timeout | null = null;\n\n\t\tsubscribe( () => {\n\t\t\tconst newSelectionStart = getSelectionStart();\n\t\t\tconst newSelectionEnd = getSelectionEnd();\n\n\t\t\tif (\n\t\t\t\tnewSelectionStart === selectionStart &&\n\t\t\t\tnewSelectionEnd === selectionEnd\n\t\t\t) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tselectionStart = newSelectionStart;\n\t\t\tselectionEnd = newSelectionEnd;\n\n\t\t\t// Typically selection position is only persisted after typing in a block, which\n\t\t\t// can cause selection position to be reset by other users making block updates.\n\t\t\t// Ensure we update the controlled selection right away, persisting our cursor position locally.\n\t\t\tconst initialPosition = getSelectedBlocksInitialCaretPosition();\n\t\t\tvoid this.updateSelectionInEntityRecord(\n\t\t\t\tselectionStart,\n\t\t\t\tselectionEnd,\n\t\t\t\tinitialPosition\n\t\t\t);\n\n\t\t\t// We receive two selection changes in quick succession\n\t\t\t// from local selection events:\n\t\t\t// { clientId: \"123...\", attributeKey: \"content\", offset: undefined }\n\t\t\t// { clientId: \"123...\", attributeKey: \"content\", offset: 554 }\n\t\t\t// Add a short debounce to avoid sending the first selection change.\n\t\t\tif ( localCursorTimeout ) {\n\t\t\t\tclearTimeout( localCursorTimeout );\n\t\t\t}\n\n\t\t\tlocalCursorTimeout = setTimeout( () => {\n\t\t\t\tconst selectionState = getSelectionState(\n\t\t\t\t\tselectionStart,\n\t\t\t\t\tselectionEnd,\n\t\t\t\t\tthis.doc\n\t\t\t\t);\n\n\t\t\t\tthis.setThrottledLocalStateField(\n\t\t\t\t\t'editorState',\n\t\t\t\t\t{ selection: selectionState },\n\t\t\t\t\tAWARENESS_CURSOR_UPDATE_THROTTLE_IN_MS\n\t\t\t\t);\n\t\t\t}, LOCAL_CURSOR_UPDATE_DEBOUNCE_IN_MS );\n\t\t} );\n\t}\n\n\t/**\n\t * Update the entity record with the current user's selection.\n\t *\n\t * @param selectionStart - The start position of the selection.\n\t * @param selectionEnd - The end position of the selection.\n\t * @param initialPosition - The initial position of the selection.\n\t */\n\tprivate async updateSelectionInEntityRecord(\n\t\tselectionStart: WPBlockSelection,\n\t\tselectionEnd: WPBlockSelection,\n\t\tinitialPosition: number | null\n\t): Promise< void > {\n\t\t// Send an entityRecord `selection` update if we have a selection.\n\t\t//\n\t\t// Normally WordPress updates the `selection` property of the post when changes are made to blocks.\n\t\t// In a multi-user setup, block changes can occur from other users. When an entity is updated from another\n\t\t// user's changes, useBlockSync() in Gutenberg will reset the user's selection to the last saved selection.\n\t\t//\n\t\t// Manually adding an edit for each movement ensures that other user's changes to the document will\n\t\t// not cause the local user's selection to reset to the last local change location.\n\t\tconst edits = {\n\t\t\tselection: { selectionStart, selectionEnd, initialPosition },\n\t\t};\n\n\t\tconst options = {\n\t\t\tundoIgnore: true,\n\t\t};\n\n\t\t// @ts-ignore Types are not provided when using store name instead of store instance.\n\t\tdispatch( coreStore ).editEntityRecord(\n\t\t\tthis.kind,\n\t\t\tthis.name,\n\t\t\tthis.postId,\n\t\t\tedits,\n\t\t\toptions\n\t\t);\n\t}\n\n\t/**\n\t * Check if two editor states are equal.\n\t *\n\t * @param state1 - The first editor state.\n\t * @param state2 - The second editor state.\n\t * @return True if the editor states are equal, false otherwise.\n\t */\n\tprivate areEditorStatesEqual(\n\t\tstate1?: EditorState,\n\t\tstate2?: EditorState\n\t): boolean {\n\t\tif ( ! state1 || ! state2 ) {\n\t\t\treturn state1 === state2;\n\t\t}\n\n\t\treturn areSelectionsStatesEqual( state1.selection, state2.selection );\n\t}\n\n\t/**\n\t * Get the absolute position index from a selection cursor.\n\t *\n\t * @param selection - The selection cursor.\n\t * @return The absolute position index, or null if not found.\n\t */\n\tpublic getAbsolutePositionIndex(\n\t\tselection: SelectionCursor\n\t): number | null {\n\t\treturn (\n\t\t\tY.createAbsolutePositionFromRelativePosition(\n\t\t\t\tselection.cursorPosition.relativePosition,\n\t\t\t\tthis.doc\n\t\t\t)?.index ?? null\n\t\t);\n\t}\n\n\t/**\n\t * Type guard to check if a struct is a Y.Item (not Y.GC)\n\t * @param struct - The struct to check.\n\t * @return True if the struct is a Y.Item, false otherwise.\n\t */\n\tprivate isYItem( struct: Y.Item | Y.GC ): struct is Y.Item {\n\t\treturn 'content' in struct;\n\t}\n\n\t/**\n\t * Get data for debugging, using the awareness state.\n\t *\n\t * @return {YDocDebugData} The debug data.\n\t */\n\tpublic getDebugData(): YDocDebugData {\n\t\tconst ydoc = this.doc;\n\n\t\t// Manually extract doc data to avoid deprecated toJSON method\n\t\tconst docData: Record< string, unknown > = Object.fromEntries(\n\t\t\tArray.from( ydoc.share, ( [ key, value ] ) => [\n\t\t\t\tkey,\n\t\t\t\tvalue.toJSON(),\n\t\t\t] )\n\t\t);\n\n\t\t// Build userMap from awareness store (all users seen this session)\n\t\tconst userMapData = new Map< string, DebugUserData >(\n\t\t\tArray.from( this.getSeenStates().entries() ).map(\n\t\t\t\t( [ clientId, userState ] ) => [\n\t\t\t\t\tString( clientId ),\n\t\t\t\t\t{\n\t\t\t\t\t\tname: userState.userInfo.name,\n\t\t\t\t\t\twpUserId: userState.userInfo.id,\n\t\t\t\t\t},\n\t\t\t\t]\n\t\t\t)\n\t\t);\n\n\t\t// Serialize Yjs client items to avoid deep nesting\n\t\tconst serializableClientItems: Record<\n\t\t\tnumber,\n\t\t\tArray< SerializableYItem >\n\t\t> = {};\n\n\t\tydoc.store.clients.forEach( ( structs, clientId ) => {\n\t\t\t// Filter for Y.Item only (skip Y.GC garbage collection structs)\n\t\t\tconst items = structs.filter( this.isYItem );\n\n\t\t\tserializableClientItems[ clientId ] = items.map( ( item ) => {\n\t\t\t\tconst { left, right, ...rest } = item;\n\n\t\t\t\treturn {\n\t\t\t\t\t...rest,\n\t\t\t\t\tleft: left\n\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\tid: left.id,\n\t\t\t\t\t\t\t\tlength: left.length,\n\t\t\t\t\t\t\t\torigin: left.origin,\n\t\t\t\t\t\t\t\tcontent: left.content,\n\t\t\t\t\t\t }\n\t\t\t\t\t\t: null,\n\t\t\t\t\tright: right\n\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\tid: right.id,\n\t\t\t\t\t\t\t\tlength: right.length,\n\t\t\t\t\t\t\t\torigin: right.origin,\n\t\t\t\t\t\t\t\tcontent: right.content,\n\t\t\t\t\t\t }\n\t\t\t\t\t\t: null,\n\t\t\t\t};\n\t\t\t} );\n\t\t} );\n\n\t\treturn {\n\t\t\tdoc: docData,\n\t\t\tclients: serializableClientItems,\n\t\t\tuserMap: Object.fromEntries( userMapData ),\n\t\t};\n\t}\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["/**\n * WordPress dependencies\n */\nimport { dispatch, select, subscribe } from '@wordpress/data';\nimport { Y } from '@wordpress/sync';\n// @ts-ignore No exported types for block editor store selectors.\nimport { store as blockEditorStore } from '@wordpress/block-editor';\n\n/**\n * Internal dependencies\n */\nimport { BaseAwarenessState, baseEqualityFieldChecks } from './base-awareness';\nimport {\n\tAWARENESS_CURSOR_UPDATE_THROTTLE_IN_MS,\n\tLOCAL_CURSOR_UPDATE_DEBOUNCE_IN_MS,\n} from './config';\nimport { STORE_NAME as coreStore } from '../name';\nimport {\n\tareSelectionsStatesEqual,\n\tgetSelectionState,\n} from '../utils/crdt-user-selections';\n\nimport type { SelectionCursor, WPBlockSelection } from '../types';\nimport type {\n\tDebugCollaboratorData,\n\tEditorState,\n\tPostEditorState,\n\tSerializableYItem,\n\tYDocDebugData,\n} from './types';\n\nexport class PostEditorAwareness extends BaseAwarenessState< PostEditorState > {\n\tprotected equalityFieldChecks = {\n\t\t...baseEqualityFieldChecks,\n\t\teditorState: this.areEditorStatesEqual,\n\t};\n\n\tpublic constructor(\n\t\tdoc: Y.Doc,\n\t\tprivate kind: string,\n\t\tprivate name: string,\n\t\tprivate postId: number\n\t) {\n\t\tsuper( doc );\n\t}\n\n\tprotected onSetUp(): void {\n\t\tsuper.onSetUp();\n\n\t\tthis.subscribeToCollaboratorSelectionChanges();\n\t}\n\n\t/**\n\t * Subscribe to collaborator selection changes and update the selection state.\n\t */\n\tprivate subscribeToCollaboratorSelectionChanges(): void {\n\t\tconst {\n\t\t\tgetSelectionStart,\n\t\t\tgetSelectionEnd,\n\t\t\tgetSelectedBlocksInitialCaretPosition,\n\t\t} = select( blockEditorStore );\n\n\t\t// Keep track of the current selection in the outer scope so we can compare\n\t\t// in the subscription.\n\t\tlet selectionStart = getSelectionStart();\n\t\tlet selectionEnd = getSelectionEnd();\n\t\tlet localCursorTimeout: NodeJS.Timeout | null = null;\n\n\t\tsubscribe( () => {\n\t\t\tconst newSelectionStart = getSelectionStart();\n\t\t\tconst newSelectionEnd = getSelectionEnd();\n\n\t\t\tif (\n\t\t\t\tnewSelectionStart === selectionStart &&\n\t\t\t\tnewSelectionEnd === selectionEnd\n\t\t\t) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tselectionStart = newSelectionStart;\n\t\t\tselectionEnd = newSelectionEnd;\n\n\t\t\t// Typically selection position is only persisted after typing in a block, which\n\t\t\t// can cause selection position to be reset by other users making block updates.\n\t\t\t// Ensure we update the controlled selection right away, persisting our cursor position locally.\n\t\t\tconst initialPosition = getSelectedBlocksInitialCaretPosition();\n\t\t\tvoid this.updateSelectionInEntityRecord(\n\t\t\t\tselectionStart,\n\t\t\t\tselectionEnd,\n\t\t\t\tinitialPosition\n\t\t\t);\n\n\t\t\t// We receive two selection changes in quick succession\n\t\t\t// from local selection events:\n\t\t\t// { clientId: \"123...\", attributeKey: \"content\", offset: undefined }\n\t\t\t// { clientId: \"123...\", attributeKey: \"content\", offset: 554 }\n\t\t\t// Add a short debounce to avoid sending the first selection change.\n\t\t\tif ( localCursorTimeout ) {\n\t\t\t\tclearTimeout( localCursorTimeout );\n\t\t\t}\n\n\t\t\tlocalCursorTimeout = setTimeout( () => {\n\t\t\t\tconst selectionState = getSelectionState(\n\t\t\t\t\tselectionStart,\n\t\t\t\t\tselectionEnd,\n\t\t\t\t\tthis.doc\n\t\t\t\t);\n\n\t\t\t\tthis.setThrottledLocalStateField(\n\t\t\t\t\t'editorState',\n\t\t\t\t\t{ selection: selectionState },\n\t\t\t\t\tAWARENESS_CURSOR_UPDATE_THROTTLE_IN_MS\n\t\t\t\t);\n\t\t\t}, LOCAL_CURSOR_UPDATE_DEBOUNCE_IN_MS );\n\t\t} );\n\t}\n\n\t/**\n\t * Update the entity record with the current collaborator's selection.\n\t *\n\t * @param selectionStart - The start position of the selection.\n\t * @param selectionEnd - The end position of the selection.\n\t * @param initialPosition - The initial position of the selection.\n\t */\n\tprivate async updateSelectionInEntityRecord(\n\t\tselectionStart: WPBlockSelection,\n\t\tselectionEnd: WPBlockSelection,\n\t\tinitialPosition: number | null\n\t): Promise< void > {\n\t\t// Send an entityRecord `selection` update if we have a selection.\n\t\t//\n\t\t// Normally WordPress updates the `selection` property of the post when changes are made to blocks.\n\t\t// In a multi-user setup, block changes can occur from other users. When an entity is updated from another\n\t\t// user's changes, useBlockSync() in Gutenberg will reset the user's selection to the last saved selection.\n\t\t//\n\t\t// Manually adding an edit for each movement ensures that other user's changes to the document will\n\t\t// not cause the local user's selection to reset to the last local change location.\n\t\tconst edits = {\n\t\t\tselection: { selectionStart, selectionEnd, initialPosition },\n\t\t};\n\n\t\tconst options = {\n\t\t\tundoIgnore: true,\n\t\t};\n\n\t\t// @ts-ignore Types are not provided when using store name instead of store instance.\n\t\tdispatch( coreStore ).editEntityRecord(\n\t\t\tthis.kind,\n\t\t\tthis.name,\n\t\t\tthis.postId,\n\t\t\tedits,\n\t\t\toptions\n\t\t);\n\t}\n\n\t/**\n\t * Check if two editor states are equal.\n\t *\n\t * @param state1 - The first editor state.\n\t * @param state2 - The second editor state.\n\t * @return True if the editor states are equal, false otherwise.\n\t */\n\tprivate areEditorStatesEqual(\n\t\tstate1?: EditorState,\n\t\tstate2?: EditorState\n\t): boolean {\n\t\tif ( ! state1 || ! state2 ) {\n\t\t\treturn state1 === state2;\n\t\t}\n\n\t\treturn areSelectionsStatesEqual( state1.selection, state2.selection );\n\t}\n\n\t/**\n\t * Get the absolute position index from a selection cursor.\n\t *\n\t * @param selection - The selection cursor.\n\t * @return The absolute position index, or null if not found.\n\t */\n\tpublic getAbsolutePositionIndex(\n\t\tselection: SelectionCursor\n\t): number | null {\n\t\treturn (\n\t\t\tY.createAbsolutePositionFromRelativePosition(\n\t\t\t\tselection.cursorPosition.relativePosition,\n\t\t\t\tthis.doc\n\t\t\t)?.index ?? null\n\t\t);\n\t}\n\n\t/**\n\t * Type guard to check if a struct is a Y.Item (not Y.GC)\n\t * @param struct - The struct to check.\n\t * @return True if the struct is a Y.Item, false otherwise.\n\t */\n\tprivate isYItem( struct: Y.Item | Y.GC ): struct is Y.Item {\n\t\treturn 'content' in struct;\n\t}\n\n\t/**\n\t * Get data for debugging, using the awareness state.\n\t *\n\t * @return {YDocDebugData} The debug data.\n\t */\n\tpublic getDebugData(): YDocDebugData {\n\t\tconst ydoc = this.doc;\n\n\t\t// Manually extract doc data to avoid deprecated toJSON method\n\t\tconst docData: Record< string, unknown > = Object.fromEntries(\n\t\t\tArray.from( ydoc.share, ( [ key, value ] ) => [\n\t\t\t\tkey,\n\t\t\t\tvalue.toJSON(),\n\t\t\t] )\n\t\t);\n\n\t\t// Build collaboratorMap from awareness store (all collaborators seen this session)\n\t\tconst collaboratorMapData = new Map< string, DebugCollaboratorData >(\n\t\t\tArray.from( this.getSeenStates().entries() ).map(\n\t\t\t\t( [ clientId, collaboratorState ] ) => [\n\t\t\t\t\tString( clientId ),\n\t\t\t\t\t{\n\t\t\t\t\t\tname: collaboratorState.collaboratorInfo.name,\n\t\t\t\t\t\twpUserId: collaboratorState.collaboratorInfo.id,\n\t\t\t\t\t},\n\t\t\t\t]\n\t\t\t)\n\t\t);\n\n\t\t// Serialize Yjs client items to avoid deep nesting\n\t\tconst serializableClientItems: Record<\n\t\t\tnumber,\n\t\t\tArray< SerializableYItem >\n\t\t> = {};\n\n\t\tydoc.store.clients.forEach( ( structs, clientId ) => {\n\t\t\t// Filter for Y.Item only (skip Y.GC garbage collection structs)\n\t\t\tconst items = structs.filter( this.isYItem );\n\n\t\t\tserializableClientItems[ clientId ] = items.map( ( item ) => {\n\t\t\t\tconst { left, right, ...rest } = item;\n\n\t\t\t\treturn {\n\t\t\t\t\t...rest,\n\t\t\t\t\tleft: left\n\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\tid: left.id,\n\t\t\t\t\t\t\t\tlength: left.length,\n\t\t\t\t\t\t\t\torigin: left.origin,\n\t\t\t\t\t\t\t\tcontent: left.content,\n\t\t\t\t\t\t }\n\t\t\t\t\t\t: null,\n\t\t\t\t\tright: right\n\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\tid: right.id,\n\t\t\t\t\t\t\t\tlength: right.length,\n\t\t\t\t\t\t\t\torigin: right.origin,\n\t\t\t\t\t\t\t\tcontent: right.content,\n\t\t\t\t\t\t }\n\t\t\t\t\t\t: null,\n\t\t\t\t};\n\t\t\t} );\n\t\t} );\n\n\t\treturn {\n\t\t\tdoc: docData,\n\t\t\tclients: serializableClientItems,\n\t\t\tcollaboratorMap: Object.fromEntries( collaboratorMapData ),\n\t\t};\n\t}\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["blockEditorStore", "coreStore"]
7
7
  }
@@ -0,0 +1,56 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // packages/core-data/src/awareness/typed-awareness.ts
21
+ var typed_awareness_exports = {};
22
+ __export(typed_awareness_exports, {
23
+ TypedAwareness: () => TypedAwareness
24
+ });
25
+ module.exports = __toCommonJS(typed_awareness_exports);
26
+ var import_sync = require("@wordpress/sync");
27
+ var import_utils = require("./utils.cjs");
28
+ var TypedAwareness = class extends import_sync.Awareness {
29
+ /**
30
+ * Get the states from an awareness document.
31
+ */
32
+ getStates() {
33
+ return super.getStates();
34
+ }
35
+ /**
36
+ * Get a local state field from an awareness document.
37
+ * @param field
38
+ */
39
+ getLocalStateField(field) {
40
+ const state = this.getLocalState();
41
+ return (0, import_utils.getRecordValue)(state, field);
42
+ }
43
+ /**
44
+ * Set a local state field on an awareness document.
45
+ * @param field
46
+ * @param value
47
+ */
48
+ setLocalStateField(field, value) {
49
+ super.setLocalStateField(field, value);
50
+ }
51
+ };
52
+ // Annotate the CommonJS export names for ESM import in node:
53
+ 0 && (module.exports = {
54
+ TypedAwareness
55
+ });
56
+ //# sourceMappingURL=typed-awareness.cjs.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/awareness/typed-awareness.ts"],
4
+ "sourcesContent": ["/**\n * External dependencies\n */\nimport { Awareness } from '@wordpress/sync';\n\n/**\n * Internal dependencies\n */\nimport { getRecordValue } from './utils';\n\n/**\n * Extended Awareness class with typed state accessors.\n */\nexport class TypedAwareness< State extends object > extends Awareness {\n\t/**\n\t * Get the states from an awareness document.\n\t */\n\tpublic getStates(): Map< number, State > {\n\t\treturn super.getStates() as Map< number, State >;\n\t}\n\n\t/**\n\t * Get a local state field from an awareness document.\n\t * @param field\n\t */\n\tpublic getLocalStateField< FieldName extends keyof State >(\n\t\tfield: FieldName\n\t): State[ FieldName ] | null {\n\t\tconst state: State | null = this.getLocalState() as State | null;\n\t\treturn getRecordValue< State, FieldName >( state, field );\n\t}\n\n\t/**\n\t * Set a local state field on an awareness document.\n\t * @param field\n\t * @param value\n\t */\n\tpublic setLocalStateField< FieldName extends string & keyof State >(\n\t\tfield: FieldName,\n\t\tvalue: State[ FieldName ]\n\t): void {\n\t\tsuper.setLocalStateField( field, value );\n\t}\n}\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA,kBAA0B;AAK1B,mBAA+B;AAKxB,IAAM,iBAAN,cAAqD,sBAAU;AAAA;AAAA;AAAA;AAAA,EAI9D,YAAkC;AACxC,WAAO,MAAM,UAAU;AAAA,EACxB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMO,mBACN,OAC4B;AAC5B,UAAM,QAAsB,KAAK,cAAc;AAC/C,eAAO,6BAAoC,OAAO,KAAM;AAAA,EACzD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOO,mBACN,OACA,OACO;AACP,UAAM,mBAAoB,OAAO,KAAM;AAAA,EACxC;AACD;",
6
+ "names": []
7
+ }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/awareness/types.ts"],
4
- "sourcesContent": ["/**\n * WordPress dependencies\n */\nimport type { EnhancedState, Y } from '@wordpress/sync';\n\n/**\n * Internal dependencies\n */\nimport type { SelectionState } from '../types';\nimport type { User } from '../entity-types';\n\nexport type UserInfo = Pick<\n\tUser< 'view' >,\n\t'id' | 'name' | 'slug' | 'avatar_urls'\n> & {\n\tbrowserType: string;\n\tcolor: string;\n\tenteredAt: number;\n};\n\n/**\n * This base state represents the presence of the user. We expect it to be\n * extended to include additional state describing the user's current activity.\n * This state must be serializable and compact.\n */\nexport interface BaseState {\n\tuserInfo: UserInfo;\n}\n\n/**\n * The editor state includes information about the user's current selection.\n */\nexport interface EditorState {\n\tselection: SelectionState;\n}\n\n/**\n * The post editor state extends the base state with information used to render\n * presence indicators in the post editor.\n */\nexport interface PostEditorState extends BaseState {\n\teditorState?: EditorState;\n}\n\n/**\n * An enhanced post editor awareness state includes additional metadata about\n * the user and their connection.\n */\nexport type PostEditorAwarenessState = EnhancedState< PostEditorState >;\n\n// WordPress user info for debug export (subset of UserInfo)\nexport type DebugUserData = Pick< UserInfo, 'name' > & {\n\twpUserId: UserInfo[ 'id' ];\n};\n\nexport interface YDocDebugData {\n\tdoc: Record< string, unknown >;\n\tclients: Record< number, Array< SerializableYItem > >;\n\tuserMap: Record< string, DebugUserData >;\n}\n\n// Type for serializable left/right item references to avoid deep nesting\nexport type SerializableYItemRef = Pick<\n\tY.Item,\n\t'id' | 'length' | 'origin' | 'content'\n>;\n\n// Serializable Y.Item - only includes data properties with shallow left/right references\nexport type SerializableYItem = Pick<\n\tY.Item,\n\t| 'id'\n\t| 'length'\n\t| 'origin'\n\t| 'rightOrigin'\n\t| 'parent'\n\t| 'parentSub'\n\t| 'redone'\n\t| 'content'\n\t| 'info'\n> & {\n\tleft: SerializableYItemRef | null;\n\tright: SerializableYItemRef | null;\n};\n"],
4
+ "sourcesContent": ["/**\n * WordPress dependencies\n */\nimport type { Y } from '@wordpress/sync';\n\n/**\n * Internal dependencies\n */\nimport type { SelectionState } from '../types';\nimport type { User } from '../entity-types';\n\nexport type CollaboratorInfo = Pick<\n\tUser< 'view' >,\n\t'id' | 'name' | 'slug' | 'avatar_urls'\n> & {\n\tbrowserType: string;\n\tcolor: string;\n\tenteredAt: number;\n};\n\n/**\n * This base state represents the presence of the collaborator. We expect it to be\n * extended to include additional state describing the collaborator's current activity.\n * This state must be serializable and compact.\n */\nexport interface BaseState {\n\tcollaboratorInfo: CollaboratorInfo;\n}\n\n/**\n * The editor state includes information about the collaborator's current selection.\n */\nexport interface EditorState {\n\tselection: SelectionState;\n}\n\n/**\n * The post editor state extends the base state with information used to render\n * presence indicators in the post editor.\n */\nexport interface PostEditorState extends BaseState {\n\teditorState?: EditorState;\n}\n\n/**\n * An enhanced state includes additional metadata about the collaborator's connection.\n */\nexport type EnhancedState< State > = State & {\n\tclientId: number;\n\tisConnected: boolean;\n\tisMe: boolean;\n};\n\n/**\n * An enhanced post editor awareness state includes additional metadata about\n * the collaborator and their connection.\n */\nexport type PostEditorAwarenessState = EnhancedState< PostEditorState >;\n\n// WordPress collaborator info for debug export (subset of CollaboratorInfo)\nexport type DebugCollaboratorData = Pick< CollaboratorInfo, 'name' > & {\n\twpUserId: CollaboratorInfo[ 'id' ];\n};\n\nexport interface YDocDebugData {\n\tdoc: Record< string, unknown >;\n\tclients: Record< number, Array< SerializableYItem > >;\n\tcollaboratorMap: Record< string, DebugCollaboratorData >;\n}\n\n// Type for serializable left/right item references to avoid deep nesting\nexport type SerializableYItemRef = Pick<\n\tY.Item,\n\t'id' | 'length' | 'origin' | 'content'\n>;\n\n// Serializable Y.Item - only includes data properties with shallow left/right references\nexport type SerializableYItem = Pick<\n\tY.Item,\n\t| 'id'\n\t| 'length'\n\t| 'origin'\n\t| 'rightOrigin'\n\t| 'parent'\n\t| 'parentSub'\n\t| 'redone'\n\t| 'content'\n\t| 'info'\n> & {\n\tleft: SerializableYItemRef | null;\n\tright: SerializableYItemRef | null;\n};\n\nexport type EqualityFieldCheck< State, FieldName extends keyof State > = (\n\tvalue1?: State[ FieldName ],\n\tvalue2?: State[ FieldName ]\n) => boolean;\n"],
5
5
  "mappings": ";;;;;;;;;;;;;;;;AAAA;AAAA;",
6
6
  "names": []
7
7
  }