@apollohg/react-native-rich-text-editor 2.0.0 → 2.0.2

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 (180) hide show
  1. package/README.md +8 -116
  2. package/THIRD_PARTY_NOTICES.md +1 -1
  3. package/android/build.gradle +3 -0
  4. package/android/src/main/java/com/apollohg/editor/EditorEditTextImages.kt +25 -0
  5. package/android/src/main/java/com/apollohg/editor/EditorV2RenderValidation.kt +1 -0
  6. package/android/src/main/java/com/apollohg/editor/ImageResizeOverlayView.kt +101 -33
  7. package/android/src/main/java/com/apollohg/editor/RenderMediaSpans.kt +15 -3
  8. package/android/src/main/java/com/apollohg/editor/RichTextEditorView.kt +14 -0
  9. package/android/src/main/java/com/apollohg/editor/viewer/AndroidProseLayoutEngine.kt +1 -1
  10. package/app.plugin.js +42 -39
  11. package/dist/AtomHost.js +18 -11
  12. package/dist/EditorAddon.js +4 -2
  13. package/dist/EditorAddonNormalization.js +17 -9
  14. package/dist/EditorMentionThemeNormalization.js +6 -3
  15. package/dist/EditorMentionThemeValidation.js +28 -11
  16. package/dist/EditorStyleSheetNormalization.js +85 -38
  17. package/dist/EditorStyleSheetTypes.d.ts +1 -1
  18. package/dist/EditorTheme.d.ts +4 -0
  19. package/dist/EditorTheme.js +5 -3
  20. package/dist/EditorToolbarComponent.d.ts +1 -1
  21. package/dist/EditorToolbarComponent.js +1 -1
  22. package/dist/EditorToolbarRegistry.js +5 -5
  23. package/dist/EditorToolbarTypes.d.ts +12 -12
  24. package/dist/EditorToolbarVisuals.js +1 -1
  25. package/dist/ExternalTextComposition.js +89 -43
  26. package/dist/ImageLoadingPolicy.d.ts +1 -1
  27. package/dist/NativeEditorBoundaryError.d.ts +7 -7
  28. package/dist/NativeEditorBoundaryError.js +9 -5
  29. package/dist/NativeEditorCollaborationTransport.d.ts +7 -7
  30. package/dist/NativeEditorCollaborationTransport.js +28 -15
  31. package/dist/NativeEditorCreateConfig.js +11 -6
  32. package/dist/NativeEditorCreateJson.js +51 -25
  33. package/dist/NativeEditorCreateValidation.js +11 -6
  34. package/dist/NativeEditorDocumentBridge.d.ts +1 -1
  35. package/dist/NativeEditorDocumentBridge.js +32 -18
  36. package/dist/NativeEditorDocumentHandle.d.ts +4 -4
  37. package/dist/NativeEditorDocumentHandle.js +1 -1
  38. package/dist/NativeEditorLocalAwareness.js +25 -13
  39. package/dist/NativeEditorNativeModule.d.ts +8 -1
  40. package/dist/NativeEditorNativeModule.js +7 -5
  41. package/dist/NativeEditorRenderNormalization.js +66 -25
  42. package/dist/NativeEditorResultNormalization.js +53 -29
  43. package/dist/NativeEditorTypes.d.ts +10 -10
  44. package/dist/NativeEditorV2Decimal.js +6 -3
  45. package/dist/NativeProseViewer.js +11 -3
  46. package/dist/ResourceLimits.d.ts +2 -2
  47. package/dist/ResourceLimits.js +7 -2
  48. package/dist/RichTextEditor.js +1 -1
  49. package/dist/RichTextEditorNativeTypes.d.ts +1 -1
  50. package/dist/RichTextEditorNativeView.d.ts +1 -3
  51. package/dist/RichTextEditorSerialization.js +24 -14
  52. package/dist/RichTextEditorTypes.d.ts +1 -1
  53. package/dist/YjsCollaboration.d.ts +7 -7
  54. package/dist/YjsCollaboration.js +42 -26
  55. package/dist/addons.d.ts +4 -4
  56. package/dist/addons.js +3 -3
  57. package/dist/atomInstances.js +6 -3
  58. package/dist/atomUpdates.js +7 -4
  59. package/dist/atoms.js +20 -12
  60. package/dist/attributeValidation.js +55 -24
  61. package/dist/contentExpression.js +80 -42
  62. package/dist/listMarkers.d.ts +1 -1
  63. package/dist/listMarkers.js +1 -1
  64. package/dist/schemaDefinition.d.ts +1 -1
  65. package/dist/schemaDefinition.js +23 -14
  66. package/dist/schemaDocument.js +1 -1
  67. package/dist/schemaDocumentConstruction.js +25 -14
  68. package/dist/schemaNormalization.js +51 -29
  69. package/dist/schemaPresets.d.ts +1 -1
  70. package/dist/schemaPresets.js +9 -4
  71. package/dist/schemaResolution.js +46 -25
  72. package/dist/specs/PreparedProseViewerNativeComponent.d.ts +4 -0
  73. package/dist/useEditorToolbarInteractions.d.ts +2 -2
  74. package/dist/useEditorToolbarInteractions.js +45 -23
  75. package/dist/useEditorToolbarItems.d.ts +1 -1
  76. package/dist/useEditorToolbarItems.js +4 -3
  77. package/dist/useEditorToolbarPresentation.d.ts +3 -3
  78. package/dist/useEditorToolbarPresentation.js +4 -4
  79. package/dist/useEditorToolbarState.d.ts +1 -1
  80. package/dist/useEditorToolbarState.js +1 -1
  81. package/dist/useFocusPreservingFrames.js +11 -8
  82. package/dist/useNativeEditor.d.ts +1 -1
  83. package/dist/useNativeEditor.js +21 -11
  84. package/dist/useRichTextEditorCommands.d.ts +2 -2
  85. package/dist/useRichTextEditorCommands.js +59 -29
  86. package/dist/useRichTextEditorEvents.d.ts +3 -3
  87. package/dist/useRichTextEditorEvents.js +75 -32
  88. package/dist/useRichTextEditorMentions.d.ts +4 -4
  89. package/dist/useRichTextEditorMentions.js +48 -29
  90. package/dist/useRichTextEditorPresentation.d.ts +4 -4
  91. package/dist/useRichTextEditorPresentation.js +25 -23
  92. package/dist/useRichTextEditorState.d.ts +3 -3
  93. package/dist/useRichTextEditorState.js +20 -15
  94. package/dist/useRichTextEditorUpdates.d.ts +1 -1
  95. package/dist/useRichTextEditorUpdates.js +99 -41
  96. package/dist/useViewerAtoms.js +63 -36
  97. package/ios/EditorCore.xcframework/ios-arm64/libeditor_core.a +0 -0
  98. package/ios/EditorCore.xcframework/ios-arm64_x86_64-simulator/libeditor_core.a +0 -0
  99. package/ios/EditorInteractionOverlays.swift +114 -122
  100. package/ios/EditorLayoutManager.swift +13 -3
  101. package/ios/EditorStyleSheet.swift +12 -1
  102. package/ios/EditorTextView+Images.swift +32 -10
  103. package/ios/EditorTextView.swift +1 -1
  104. package/ios/EditorV2Adapter+RenderValidation.swift +2 -2
  105. package/ios/NativeToolbar+ButtonStyle.swift +17 -5
  106. package/ios/NativeToolbar+Diagnostics.swift +15 -0
  107. package/ios/RenderBridge+Atoms.swift +0 -1
  108. package/ios/RenderBridge+Attachments.swift +0 -29
  109. package/ios/RichTextEditorView.swift +4 -12
  110. package/ios/Viewer/CoreTextProseLayoutEngine+AttributedText.swift +3 -2
  111. package/package.json +11 -3
  112. package/react-native.config.js +1 -1
  113. package/rust/android/arm64-v8a/libeditor_core.so +0 -0
  114. package/rust/android/armeabi-v7a/libeditor_core.so +0 -0
  115. package/rust/android/x86/libeditor_core.so +0 -0
  116. package/rust/android/x86_64/libeditor_core.so +0 -0
  117. package/src/AtomHost.tsx +58 -28
  118. package/src/EditorAddon.ts +18 -8
  119. package/src/EditorAddonNormalization.ts +40 -11
  120. package/src/EditorMentionThemeNormalization.ts +15 -4
  121. package/src/EditorMentionThemeValidation.ts +51 -14
  122. package/src/EditorStyleSheet.ts +1 -0
  123. package/src/EditorStyleSheetNormalization.ts +195 -64
  124. package/src/EditorStyleSheetTypes.ts +1 -1
  125. package/src/EditorTheme.ts +13 -5
  126. package/src/EditorToolbarComponent.tsx +2 -1
  127. package/src/EditorToolbarRegistry.tsx +23 -13
  128. package/src/EditorToolbarTypes.tsx +12 -12
  129. package/src/EditorToolbarVisuals.tsx +6 -3
  130. package/src/EditorUpdateRevision.ts +1 -0
  131. package/src/ExternalTextComposition.ts +259 -49
  132. package/src/ImageLoadingPolicy.ts +3 -1
  133. package/src/NativeEditorBoundaryError.ts +38 -11
  134. package/src/NativeEditorCollaborationTransport.ts +108 -27
  135. package/src/NativeEditorCreateConfig.ts +92 -19
  136. package/src/NativeEditorCreateJson.ts +163 -26
  137. package/src/NativeEditorCreateValidation.ts +33 -12
  138. package/src/NativeEditorDocumentBridge.ts +111 -19
  139. package/src/NativeEditorDocumentHandle.ts +9 -4
  140. package/src/NativeEditorLocalAwareness.ts +70 -15
  141. package/src/NativeEditorNativeModule.ts +13 -9
  142. package/src/NativeEditorRenderNormalization.ts +128 -29
  143. package/src/NativeEditorResultNormalization.ts +143 -32
  144. package/src/NativeEditorTypes.ts +12 -11
  145. package/src/NativeEditorV2Decimal.ts +12 -3
  146. package/src/NativeProseViewer.tsx +46 -16
  147. package/src/ResourceLimits.ts +15 -8
  148. package/src/RichTextEditor.tsx +3 -1
  149. package/src/RichTextEditorNativeTypes.tsx +1 -1
  150. package/src/RichTextEditorNativeView.tsx +2 -8
  151. package/src/RichTextEditorSerialization.tsx +70 -24
  152. package/src/RichTextEditorTypes.tsx +1 -1
  153. package/src/YjsCollaboration.ts +143 -47
  154. package/src/addons.ts +12 -8
  155. package/src/atomInstances.ts +25 -5
  156. package/src/atomUpdates.ts +23 -6
  157. package/src/atoms.ts +85 -18
  158. package/src/attributeValidation.ts +97 -33
  159. package/src/contentExpression.ts +218 -63
  160. package/src/listMarkers.ts +1 -1
  161. package/src/schemaDefinition.ts +82 -20
  162. package/src/schemaDocument.ts +15 -1
  163. package/src/schemaDocumentConstruction.ts +80 -16
  164. package/src/schemaNormalization.ts +155 -41
  165. package/src/schemaPresets.ts +37 -31
  166. package/src/schemaResolution.ts +126 -27
  167. package/src/specs/PreparedProseViewerNativeComponent.ts +4 -2
  168. package/src/useEditorToolbarInteractions.tsx +85 -36
  169. package/src/useEditorToolbarItems.tsx +50 -22
  170. package/src/useEditorToolbarPresentation.tsx +81 -58
  171. package/src/useEditorToolbarState.tsx +8 -6
  172. package/src/useFocusPreservingFrames.ts +43 -15
  173. package/src/useNativeEditor.ts +111 -51
  174. package/src/useRichTextEditorCommands.tsx +127 -54
  175. package/src/useRichTextEditorEvents.tsx +144 -42
  176. package/src/useRichTextEditorMentions.tsx +118 -37
  177. package/src/useRichTextEditorPresentation.tsx +128 -114
  178. package/src/useRichTextEditorState.tsx +76 -40
  179. package/src/useRichTextEditorUpdates.tsx +207 -56
  180. package/src/useViewerAtoms.tsx +162 -66
@@ -8,7 +8,7 @@ import { NativeEditorBoundaryError } from './NativeEditorBoundaryError';
8
8
  * Every field is optional; an omitted one uses
9
9
  * {@link DEFAULT_EDITOR_IMAGE_LOADING_POLICY}. Each value must be a positive
10
10
  * integer no greater than the matching
11
- * {@link HARD_EDITOR_IMAGE_LOADING_POLICY} ceiling anything else throws
11
+ * {@link HARD_EDITOR_IMAGE_LOADING_POLICY} ceiling : anything else throws
12
12
  * `NativeEditorBoundaryError` (`IMAGE_POLICY_INVALID`).
13
13
  */
14
14
  export interface EditorImageLoadingPolicy {
@@ -71,6 +71,7 @@ function resolveImagePolicyValue(
71
71
  value: number | undefined
72
72
  ): number {
73
73
  const resolved = value ?? DEFAULT_EDITOR_IMAGE_LOADING_POLICY[name];
74
+
74
75
  if (
75
76
  !Number.isSafeInteger(resolved) ||
76
77
  resolved <= 0 ||
@@ -83,6 +84,7 @@ function resolveImagePolicyValue(
83
84
  resolved
84
85
  );
85
86
  }
87
+
86
88
  return resolved;
87
89
  }
88
90
 
@@ -41,12 +41,12 @@ export const NATIVE_EDITOR_ERROR_DOMAINS = [
41
41
  /**
42
42
  * Which subsystem raised a failure:
43
43
  *
44
- * - `boundary` the value never reached the engine (bad config, oversized input).
45
- * - `document` the document or schema was rejected.
46
- * - `operation` a mutation could not be applied (stale revision, invalid position).
47
- * - `lifecycle` the session was destroyed or is being destroyed.
48
- * - `snapshot` a room snapshot could not be exported or restored.
49
- * - `transport` collaboration transport failure.
44
+ * - `boundary` : the value never reached the engine (bad config, oversized input).
45
+ * - `document` : the document or schema was rejected.
46
+ * - `operation` : a mutation could not be applied (stale revision, invalid position).
47
+ * - `lifecycle` : the session was destroyed or is being destroyed.
48
+ * - `snapshot` : a room snapshot could not be exported or restored.
49
+ * - `transport` : collaboration transport failure.
50
50
  */
51
51
  export type NativeEditorErrorDomain = (typeof NATIVE_EDITOR_ERROR_DOMAINS)[number];
52
52
 
@@ -86,7 +86,7 @@ export interface NativeEditorError {
86
86
  }
87
87
 
88
88
  /**
89
- * A value rejected before it reached the engine an out-of-range resource
89
+ * A value rejected before it reached the engine : an out-of-range resource
90
90
  * limit, an invalid image policy, an oversized input. Thrown synchronously by
91
91
  * the validating helpers in this package.
92
92
  */
@@ -111,9 +111,11 @@ export function parseNativeBoundaryError(value: unknown): NativeEditorBoundaryEr
111
111
  const envelope = value as { error?: Record<string, unknown> };
112
112
  const nativeError = envelope?.error;
113
113
  const code = nativeError?.code;
114
+
114
115
  if (typeof code !== 'string' || typeof nativeError?.message !== 'string') {
115
116
  return null;
116
117
  }
118
+
117
119
  return new NativeEditorBoundaryError(
118
120
  code,
119
121
  nativeError.message,
@@ -126,7 +128,10 @@ export function parseNativeBoundaryError(value: unknown): NativeEditorBoundaryEr
126
128
  }
127
129
 
128
130
  function nullableCanonicalDecimal(value: unknown): string | null | undefined {
129
- if (value == null) return null;
131
+ if (value == null) {
132
+ return null;
133
+ }
134
+
130
135
  return normalizeNativeEditorV2U64(value) ?? undefined;
131
136
  }
132
137
 
@@ -137,12 +142,21 @@ function parseDetails(
137
142
  if (typeof nativeError.details !== 'object' || Array.isArray(nativeError.details)) {
138
143
  return undefined;
139
144
  }
145
+
140
146
  return nativeError.details as Record<string, unknown>;
141
147
  }
142
- if (nativeError.detailsJson == null) return null;
143
- if (typeof nativeError.detailsJson !== 'string') return undefined;
148
+
149
+ if (nativeError.detailsJson == null) {
150
+ return null;
151
+ }
152
+
153
+ if (typeof nativeError.detailsJson !== 'string') {
154
+ return undefined;
155
+ }
156
+
144
157
  try {
145
158
  const details: unknown = JSON.parse(nativeError.detailsJson);
159
+
146
160
  return details != null && typeof details === 'object' && !Array.isArray(details)
147
161
  ? (details as Record<string, unknown>)
148
162
  : undefined;
@@ -183,9 +197,13 @@ function hasValidKnownDetails(code: string, details: Record<string, unknown> | n
183
197
  export function normalizeNativeEditorV2Error(value: unknown): NativeEditorError | null {
184
198
  const envelope = value as { error?: unknown };
185
199
  const nativeError = envelope?.error as Record<string, unknown> | undefined;
186
- if (nativeError == null || typeof nativeError !== 'object') return null;
200
+
201
+ if (nativeError == null || typeof nativeError !== 'object') {
202
+ return null;
203
+ }
187
204
 
188
205
  const { domain, code, message } = nativeError;
206
+
189
207
  if (
190
208
  typeof domain !== 'string' ||
191
209
  !NATIVE_EDITOR_ERROR_DOMAINS.includes(domain as NativeEditorErrorDomain) ||
@@ -200,6 +218,7 @@ export function normalizeNativeEditorV2Error(value: unknown): NativeEditorError
200
218
  const limit = nullableCanonicalDecimal(nativeError.limit);
201
219
  const actual = nullableCanonicalDecimal(nativeError.actual);
202
220
  const details = parseDetails(nativeError);
221
+
203
222
  if (
204
223
  requestId === undefined ||
205
224
  operationIndex === undefined ||
@@ -242,11 +261,17 @@ export function isNativeEditorV2NonRetryableCode(code: string): boolean {
242
261
  /** Base class for every typed error raised from a normalized FFI v2 error record. */
243
262
  export class NativeEditorErrorBase extends Error {
244
263
  readonly domain: NativeEditorErrorDomain;
264
+
245
265
  readonly code: NativeEditorBoundaryErrorCode;
266
+
246
267
  readonly requestId: string | null;
268
+
247
269
  readonly operationIndex: string | null;
270
+
248
271
  readonly limit: string | null;
272
+
249
273
  readonly actual: string | null;
274
+
250
275
  readonly details: Record<string, unknown> | null;
251
276
 
252
277
  constructor(
@@ -340,6 +365,8 @@ export function nativeEditorV2ErrorToException(
340
365
  if (isNativeEditorV2NonRetryableCode(error.code)) {
341
366
  return new NativeEditorNonRetryableError(error);
342
367
  }
368
+
343
369
  const ErrorClass = NATIVE_EDITOR_V2_DOMAIN_ERROR_CLASSES[error.domain];
370
+
344
371
  return new ErrorClass(error);
345
372
  }
@@ -1,5 +1,5 @@
1
1
  import {
2
- NativeEditorErrorBase,
2
+ type NativeEditorErrorBase,
3
3
  nativeEditorV2ErrorToException,
4
4
  normalizeNativeEditorV2Error,
5
5
  } from './NativeEditorBoundaryError';
@@ -40,9 +40,9 @@ export type NativeCollaborationProtocolFrame =
40
40
  /**
41
41
  * What the transport does next after an adapter callback:
42
42
  *
43
- * - `continue` stay in the prelude and await the next frame.
44
- * - `ready` the prelude succeeded; release Yjs traffic.
45
- * - `reject` abandon this attempt.
43
+ * - `continue` : stay in the prelude and await the next frame.
44
+ * - `ready` : the prelude succeeded; release Yjs traffic.
45
+ * - `reject` : abandon this attempt.
46
46
  */
47
47
  export type NativeCollaborationProtocolAdapterAction = 'continue' | 'ready' | 'reject';
48
48
 
@@ -77,7 +77,7 @@ export interface NativeCollaborationProtocolAdapter {
77
77
  timeoutMillis?: number;
78
78
  /** Close codes that park the Rust transport instead of entering automatic retry. */
79
79
  terminalCloseCodes?: readonly number[];
80
- /** Runs once when the socket opens send credentials here. */
80
+ /** Runs once when the socket opens : send credentials here. */
81
81
  onOpen(
82
82
  context: NativeCollaborationProtocolAdapterContext
83
83
  ): NativeCollaborationProtocolAdapterResult | Promise<NativeCollaborationProtocolAdapterResult>;
@@ -90,7 +90,7 @@ export interface NativeCollaborationProtocolAdapter {
90
90
 
91
91
  /** Where the native transport connects, and whether it should. */
92
92
  export interface NativeCollaborationTransportConfig {
93
- /** WebSocket endpoint, `ws:` or `wss:`. Treat it as sensitive it may carry credentials. */
93
+ /** WebSocket endpoint, `ws:` or `wss:`. Treat it as sensitive : it may carry credentials. */
94
94
  url: string;
95
95
  /** Whether to open the connection now. False configures the endpoint without connecting. */
96
96
  connect: boolean;
@@ -98,7 +98,7 @@ export interface NativeCollaborationTransportConfig {
98
98
  protocolAdapter?: NativeCollaborationProtocolAdapter;
99
99
  }
100
100
 
101
- /** Why the transport woke and what it did diagnostic only; no contract depends on these. */
101
+ /** Why the transport woke and what it did : diagnostic only; no contract depends on these. */
102
102
  export interface NativeCollaborationTransportDiagnostics {
103
103
  /** What woke the transport, e.g. a received message or an elapsed timer. */
104
104
  wakeReason: string;
@@ -197,7 +197,8 @@ export function collaborationProtocolAdapterDescriptor(
197
197
  ) {
198
198
  throw invalidV2RequestError('NativeEditorBridge: invalid collaboration protocol adapter');
199
199
  }
200
- const protocols = value.protocols.map((protocol) => {
200
+
201
+ const protocols = value.protocols.map(protocol => {
201
202
  if (
202
203
  typeof protocol !== 'string' ||
203
204
  protocol.length === 0 ||
@@ -208,14 +209,18 @@ export function collaborationProtocolAdapterDescriptor(
208
209
  'NativeEditorBridge: invalid collaboration WebSocket subprotocol'
209
210
  );
210
211
  }
212
+
211
213
  return protocol;
212
214
  });
215
+
213
216
  if (new Set(protocols).size !== protocols.length) {
214
217
  throw invalidV2RequestError(
215
218
  'NativeEditorBridge: duplicate collaboration WebSocket subprotocol'
216
219
  );
217
220
  }
221
+
218
222
  const timeoutMillis = value.timeoutMillis;
223
+
219
224
  if (
220
225
  timeoutMillis !== undefined &&
221
226
  (!Number.isSafeInteger(timeoutMillis) ||
@@ -226,20 +231,24 @@ export function collaborationProtocolAdapterDescriptor(
226
231
  'NativeEditorBridge: invalid collaboration protocol adapter timeout'
227
232
  );
228
233
  }
234
+
229
235
  const rawTerminalCloseCodes = value.terminalCloseCodes;
236
+
230
237
  if (
231
238
  rawTerminalCloseCodes !== undefined &&
232
239
  (!Array.isArray(rawTerminalCloseCodes) ||
233
240
  rawTerminalCloseCodes.some(
234
- (code) => !Number.isSafeInteger(code) || code < 1_000 || code > 4_999
241
+ code => !Number.isSafeInteger(code) || code < 1_000 || code > 4_999
235
242
  ))
236
243
  ) {
237
244
  throw invalidV2RequestError(
238
245
  'NativeEditorBridge: invalid collaboration terminal close code'
239
246
  );
240
247
  }
248
+
241
249
  const terminalCloseCodes =
242
- rawTerminalCloseCodes === undefined ? undefined : [...rawTerminalCloseCodes];
250
+ rawTerminalCloseCodes === undefined ? undefined : [ ...rawTerminalCloseCodes ];
251
+
243
252
  if (
244
253
  terminalCloseCodes !== undefined &&
245
254
  new Set(terminalCloseCodes).size !== terminalCloseCodes.length
@@ -248,6 +257,7 @@ export function collaborationProtocolAdapterDescriptor(
248
257
  'NativeEditorBridge: duplicate collaboration terminal close code'
249
258
  );
250
259
  }
260
+
251
261
  return {
252
262
  protocols,
253
263
  ...(timeoutMillis === undefined ? {} : { timeoutMillis }),
@@ -268,14 +278,15 @@ export function collaborationTransportWireConfig(
268
278
  'NativeEditorBridge: invalid collaboration transport configuration'
269
279
  );
270
280
  }
281
+
271
282
  return {
272
283
  url: config.url,
273
284
  connect: config.connect,
274
285
  ...(config.protocolAdapter === undefined
275
286
  ? {}
276
287
  : {
277
- protocolAdapter: collaborationProtocolAdapterDescriptor(config.protocolAdapter),
278
- }),
288
+ protocolAdapter: collaborationProtocolAdapterDescriptor(config.protocolAdapter),
289
+ }),
279
290
  };
280
291
  }
281
292
 
@@ -294,20 +305,24 @@ export function serializeCollaborationProtocolAdapterResult(
294
305
  'NativeEditorBridge: invalid collaboration protocol adapter result'
295
306
  );
296
307
  }
297
- const frames = (value.frames ?? []).map((frame) => {
308
+
309
+ const frames = (value.frames ?? []).map((frame: NativeCollaborationProtocolFrame) => {
298
310
  if (frame === null || typeof frame !== 'object') {
299
311
  throw invalidV2RequestError(
300
312
  'NativeEditorBridge: invalid collaboration protocol adapter frame'
301
313
  );
302
314
  }
315
+
303
316
  if (frame.type === 'text' && typeof frame.data === 'string') {
304
317
  if (utf8V2JsonByteLength(frame.data) > MAX_COLLABORATION_ADAPTER_FRAME_BYTES) {
305
318
  throw invalidV2RequestError(
306
319
  'NativeEditorBridge: collaboration protocol adapter frame is too large'
307
320
  );
308
321
  }
322
+
309
323
  return { type: 'text' as const, data: frame.data };
310
324
  }
325
+
311
326
  if (
312
327
  frame.type === 'binary' &&
313
328
  frame.data instanceof Uint8Array &&
@@ -318,10 +333,12 @@ export function serializeCollaborationProtocolAdapterResult(
318
333
  data: encodeNativeCollaborationProtocolBytes(frame.data),
319
334
  };
320
335
  }
336
+
321
337
  throw invalidV2RequestError(
322
338
  'NativeEditorBridge: invalid collaboration protocol adapter frame'
323
339
  );
324
340
  });
341
+
325
342
  return JSON.stringify({
326
343
  action: value.action,
327
344
  ...(frames.length === 0 ? {} : { frames }),
@@ -331,16 +348,22 @@ export function serializeCollaborationProtocolAdapterResult(
331
348
  export function normalizeNativeCollaborationTransportDiagnostics(
332
349
  value: unknown
333
350
  ): NativeCollaborationTransportDiagnostics | null {
334
- if (!isPlainRecord(value)) return null;
351
+ if (!isPlainRecord(value)) {
352
+ return null;
353
+ }
354
+
335
355
  const transportState = whitelisted(value.transportState, V2_TRANSPORT_STATES);
356
+
336
357
  const nextDeadlineMillis =
337
358
  value.nextDeadlineMillis === null
338
359
  ? null
339
360
  : normalizeNativeEditorV2DecimalId(value.nextDeadlineMillis);
361
+
340
362
  const remoteCommitApplied = optionalBoolean(value.remoteCommitApplied);
341
363
  const peersChanged = optionalBoolean(value.peersChanged);
342
364
  const renewedLocal = optionalBoolean(value.renewedLocal);
343
365
  const expiredPeerCount = nativeEditorV2U32(value.expiredPeerCount);
366
+
344
367
  if (
345
368
  typeof value.wakeReason !== 'string' ||
346
369
  transportState == null ||
@@ -352,6 +375,7 @@ export function normalizeNativeCollaborationTransportDiagnostics(
352
375
  ) {
353
376
  return null;
354
377
  }
378
+
355
379
  return {
356
380
  wakeReason: value.wakeReason,
357
381
  transportState,
@@ -367,6 +391,7 @@ export const BASE64_ALPHABET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuv
367
391
 
368
392
  export function encodeNativeCollaborationProtocolBytes(bytes: Uint8Array): string {
369
393
  let encoded = '';
394
+
370
395
  for (let index = 0; index < bytes.length; index += 3) {
371
396
  const first = bytes[index];
372
397
  const second = index + 1 < bytes.length ? bytes[index + 1] : 0;
@@ -377,39 +402,68 @@ export function encodeNativeCollaborationProtocolBytes(bytes: Uint8Array): strin
377
402
  encoded += index + 1 < bytes.length ? BASE64_ALPHABET[(value >>> 6) & 63] : '=';
378
403
  encoded += index + 2 < bytes.length ? BASE64_ALPHABET[value & 63] : '=';
379
404
  }
405
+
380
406
  return encoded;
381
407
  }
382
408
 
383
409
  export function decodeNativeCollaborationProtocolBytes(value: string): Uint8Array | null {
384
- if (value.length % 4 !== 0 || !/^[A-Za-z0-9+/]*={0,2}$/.test(value)) return null;
410
+ if (value.length % 4 !== 0 || !/^[A-Za-z0-9+/]*={0,2}$/.test(value)) {
411
+ return null;
412
+ }
413
+
385
414
  const firstPadding = value.indexOf('=');
386
- if (firstPadding >= 0 && firstPadding < value.length - 2) return null;
415
+
416
+ if (firstPadding >= 0 && firstPadding < value.length - 2) {
417
+ return null;
418
+ }
419
+
387
420
  const outputLength =
388
421
  (value.length / 4) * 3 - (value.endsWith('==') ? 2 : value.endsWith('=') ? 1 : 0);
422
+
389
423
  const bytes = new Uint8Array(outputLength);
390
424
  let outputIndex = 0;
425
+
391
426
  for (let index = 0; index < value.length; index += 4) {
392
427
  const first = BASE64_ALPHABET.indexOf(value[index]);
393
428
  const second = BASE64_ALPHABET.indexOf(value[index + 1]);
394
429
  const third = value[index + 2] === '=' ? 0 : BASE64_ALPHABET.indexOf(value[index + 2]);
395
430
  const fourth = value[index + 3] === '=' ? 0 : BASE64_ALPHABET.indexOf(value[index + 3]);
396
- if (first < 0 || second < 0 || third < 0 || fourth < 0) return null;
431
+
432
+ if (first < 0 || second < 0 || third < 0 || fourth < 0) {
433
+ return null;
434
+ }
435
+
397
436
  const decoded = (first << 18) | (second << 12) | (third << 6) | fourth;
398
- if (outputIndex < outputLength) bytes[outputIndex++] = (decoded >>> 16) & 0xff;
399
- if (outputIndex < outputLength) bytes[outputIndex++] = (decoded >>> 8) & 0xff;
400
- if (outputIndex < outputLength) bytes[outputIndex++] = decoded & 0xff;
437
+
438
+ if (outputIndex < outputLength) {
439
+ bytes[outputIndex++] = (decoded >>> 16) & 0xff;
440
+ }
441
+
442
+ if (outputIndex < outputLength) {
443
+ bytes[outputIndex++] = (decoded >>> 8) & 0xff;
444
+ }
445
+
446
+ if (outputIndex < outputLength) {
447
+ bytes[outputIndex++] = decoded & 0xff;
448
+ }
401
449
  }
450
+
402
451
  return bytes;
403
452
  }
404
453
 
405
454
  export function normalizeNativeCollaborationTransportEvent(
406
455
  value: unknown
407
456
  ): NativeCollaborationTransportEvent | null {
408
- if (!isPlainRecord(value)) return null;
457
+ if (!isPlainRecord(value)) {
458
+ return null;
459
+ }
460
+
409
461
  const editorId = normalizeNativeEditorV2DecimalId(value.editorId);
410
462
  const eventSequence = normalizeNativeEditorV2DecimalId(value.eventSequence);
463
+
411
464
  const generation =
412
465
  value.generation === null ? null : normalizeNativeEditorV2DecimalId(value.generation);
466
+
413
467
  if (
414
468
  editorId == null ||
415
469
  editorId === '0' ||
@@ -419,11 +473,16 @@ export function normalizeNativeCollaborationTransportEvent(
419
473
  ) {
420
474
  return null;
421
475
  }
476
+
422
477
  if (value.kind === 'state') {
423
478
  const state = normalizeNativeEditorV2StateValue(value.state);
424
479
  const peers = normalizeNativeEditorV2PeersValue({ peers: value.peers });
425
480
  const diagnostics = normalizeNativeCollaborationTransportDiagnostics(value.diagnostics);
426
- if (state == null || peers == null || diagnostics == null) return null;
481
+
482
+ if (state == null || peers == null || diagnostics == null) {
483
+ return null;
484
+ }
485
+
427
486
  return {
428
487
  editorId,
429
488
  eventSequence,
@@ -434,9 +493,14 @@ export function normalizeNativeCollaborationTransportEvent(
434
493
  diagnostics,
435
494
  };
436
495
  }
496
+
437
497
  if (value.kind === 'error') {
438
498
  const error = normalizeNativeEditorV2Error({ error: value.error });
439
- if (error == null) return null;
499
+
500
+ if (error == null) {
501
+ return null;
502
+ }
503
+
440
504
  return {
441
505
  editorId,
442
506
  eventSequence,
@@ -445,8 +509,10 @@ export function normalizeNativeCollaborationTransportEvent(
445
509
  error: nativeEditorV2ErrorToException(error),
446
510
  };
447
511
  }
512
+
448
513
  if (value.kind === 'protocolAdapter') {
449
514
  const eventId = normalizeNativeEditorV2DecimalId(value.eventId);
515
+
450
516
  if (
451
517
  generation == null ||
452
518
  typeof value.attemptId !== 'string' ||
@@ -458,6 +524,7 @@ export function normalizeNativeCollaborationTransportEvent(
458
524
  ) {
459
525
  return null;
460
526
  }
527
+
461
528
  const base = {
462
529
  editorId,
463
530
  eventSequence,
@@ -465,13 +532,21 @@ export function normalizeNativeCollaborationTransportEvent(
465
532
  kind: 'protocolAdapter' as const,
466
533
  attemptId: value.attemptId,
467
534
  eventId,
468
- negotiatedProtocol: value.negotiatedProtocol as string | null,
535
+ negotiatedProtocol: value.negotiatedProtocol,
469
536
  };
537
+
470
538
  if (value.phase === 'open') {
471
- if (value.frame !== undefined) return null;
539
+ if (value.frame !== undefined) {
540
+ return null;
541
+ }
542
+
472
543
  return { ...base, phase: 'open' };
473
544
  }
474
- if (!isPlainRecord(value.frame) || typeof value.frame.data !== 'string') return null;
545
+
546
+ if (!isPlainRecord(value.frame) || typeof value.frame.data !== 'string') {
547
+ return null;
548
+ }
549
+
475
550
  if (value.frame.type === 'text') {
476
551
  return {
477
552
  ...base,
@@ -479,9 +554,14 @@ export function normalizeNativeCollaborationTransportEvent(
479
554
  frame: { type: 'text', data: value.frame.data },
480
555
  };
481
556
  }
557
+
482
558
  if (value.frame.type === 'binary') {
483
559
  const data = decodeNativeCollaborationProtocolBytes(value.frame.data);
484
- if (data == null) return null;
560
+
561
+ if (data == null) {
562
+ return null;
563
+ }
564
+
485
565
  return {
486
566
  ...base,
487
567
  phase: 'message',
@@ -489,5 +569,6 @@ export function normalizeNativeCollaborationTransportEvent(
489
569
  };
490
570
  }
491
571
  }
572
+
492
573
  return null;
493
574
  }