@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.
- package/README.md +8 -116
- package/THIRD_PARTY_NOTICES.md +1 -1
- package/android/build.gradle +3 -0
- package/android/src/main/java/com/apollohg/editor/EditorEditTextImages.kt +25 -0
- package/android/src/main/java/com/apollohg/editor/EditorV2RenderValidation.kt +1 -0
- package/android/src/main/java/com/apollohg/editor/ImageResizeOverlayView.kt +101 -33
- package/android/src/main/java/com/apollohg/editor/RenderMediaSpans.kt +15 -3
- package/android/src/main/java/com/apollohg/editor/RichTextEditorView.kt +14 -0
- package/android/src/main/java/com/apollohg/editor/viewer/AndroidProseLayoutEngine.kt +1 -1
- package/app.plugin.js +42 -39
- package/dist/AtomHost.js +18 -11
- package/dist/EditorAddon.js +4 -2
- package/dist/EditorAddonNormalization.js +17 -9
- package/dist/EditorMentionThemeNormalization.js +6 -3
- package/dist/EditorMentionThemeValidation.js +28 -11
- package/dist/EditorStyleSheetNormalization.js +85 -38
- package/dist/EditorStyleSheetTypes.d.ts +1 -1
- package/dist/EditorTheme.d.ts +4 -0
- package/dist/EditorTheme.js +5 -3
- package/dist/EditorToolbarComponent.d.ts +1 -1
- package/dist/EditorToolbarComponent.js +1 -1
- package/dist/EditorToolbarRegistry.js +5 -5
- package/dist/EditorToolbarTypes.d.ts +12 -12
- package/dist/EditorToolbarVisuals.js +1 -1
- package/dist/ExternalTextComposition.js +89 -43
- package/dist/ImageLoadingPolicy.d.ts +1 -1
- package/dist/NativeEditorBoundaryError.d.ts +7 -7
- package/dist/NativeEditorBoundaryError.js +9 -5
- package/dist/NativeEditorCollaborationTransport.d.ts +7 -7
- package/dist/NativeEditorCollaborationTransport.js +28 -15
- package/dist/NativeEditorCreateConfig.js +11 -6
- package/dist/NativeEditorCreateJson.js +51 -25
- package/dist/NativeEditorCreateValidation.js +11 -6
- package/dist/NativeEditorDocumentBridge.d.ts +1 -1
- package/dist/NativeEditorDocumentBridge.js +32 -18
- package/dist/NativeEditorDocumentHandle.d.ts +4 -4
- package/dist/NativeEditorDocumentHandle.js +1 -1
- package/dist/NativeEditorLocalAwareness.js +25 -13
- package/dist/NativeEditorNativeModule.d.ts +8 -1
- package/dist/NativeEditorNativeModule.js +7 -5
- package/dist/NativeEditorRenderNormalization.js +66 -25
- package/dist/NativeEditorResultNormalization.js +53 -29
- package/dist/NativeEditorTypes.d.ts +10 -10
- package/dist/NativeEditorV2Decimal.js +6 -3
- package/dist/NativeProseViewer.js +11 -3
- package/dist/ResourceLimits.d.ts +2 -2
- package/dist/ResourceLimits.js +7 -2
- package/dist/RichTextEditor.js +1 -1
- package/dist/RichTextEditorNativeTypes.d.ts +1 -1
- package/dist/RichTextEditorNativeView.d.ts +1 -3
- package/dist/RichTextEditorSerialization.js +24 -14
- package/dist/RichTextEditorTypes.d.ts +1 -1
- package/dist/YjsCollaboration.d.ts +7 -7
- package/dist/YjsCollaboration.js +42 -26
- package/dist/addons.d.ts +4 -4
- package/dist/addons.js +3 -3
- package/dist/atomInstances.js +6 -3
- package/dist/atomUpdates.js +7 -4
- package/dist/atoms.js +20 -12
- package/dist/attributeValidation.js +55 -24
- package/dist/contentExpression.js +80 -42
- package/dist/listMarkers.d.ts +1 -1
- package/dist/listMarkers.js +1 -1
- package/dist/schemaDefinition.d.ts +1 -1
- package/dist/schemaDefinition.js +23 -14
- package/dist/schemaDocument.js +1 -1
- package/dist/schemaDocumentConstruction.js +25 -14
- package/dist/schemaNormalization.js +51 -29
- package/dist/schemaPresets.d.ts +1 -1
- package/dist/schemaPresets.js +9 -4
- package/dist/schemaResolution.js +46 -25
- package/dist/specs/PreparedProseViewerNativeComponent.d.ts +4 -0
- package/dist/useEditorToolbarInteractions.d.ts +2 -2
- package/dist/useEditorToolbarInteractions.js +45 -23
- package/dist/useEditorToolbarItems.d.ts +1 -1
- package/dist/useEditorToolbarItems.js +4 -3
- package/dist/useEditorToolbarPresentation.d.ts +3 -3
- package/dist/useEditorToolbarPresentation.js +4 -4
- package/dist/useEditorToolbarState.d.ts +1 -1
- package/dist/useEditorToolbarState.js +1 -1
- package/dist/useFocusPreservingFrames.js +11 -8
- package/dist/useNativeEditor.d.ts +1 -1
- package/dist/useNativeEditor.js +21 -11
- package/dist/useRichTextEditorCommands.d.ts +2 -2
- package/dist/useRichTextEditorCommands.js +59 -29
- package/dist/useRichTextEditorEvents.d.ts +3 -3
- package/dist/useRichTextEditorEvents.js +75 -32
- package/dist/useRichTextEditorMentions.d.ts +4 -4
- package/dist/useRichTextEditorMentions.js +48 -29
- package/dist/useRichTextEditorPresentation.d.ts +4 -4
- package/dist/useRichTextEditorPresentation.js +25 -23
- package/dist/useRichTextEditorState.d.ts +3 -3
- package/dist/useRichTextEditorState.js +20 -15
- package/dist/useRichTextEditorUpdates.d.ts +1 -1
- package/dist/useRichTextEditorUpdates.js +99 -41
- package/dist/useViewerAtoms.js +63 -36
- package/ios/EditorCore.xcframework/ios-arm64/libeditor_core.a +0 -0
- package/ios/EditorCore.xcframework/ios-arm64_x86_64-simulator/libeditor_core.a +0 -0
- package/ios/EditorInteractionOverlays.swift +114 -122
- package/ios/EditorLayoutManager.swift +13 -3
- package/ios/EditorStyleSheet.swift +12 -1
- package/ios/EditorTextView+Images.swift +32 -10
- package/ios/EditorTextView.swift +1 -1
- package/ios/EditorV2Adapter+RenderValidation.swift +2 -2
- package/ios/NativeToolbar+ButtonStyle.swift +17 -5
- package/ios/NativeToolbar+Diagnostics.swift +15 -0
- package/ios/RenderBridge+Atoms.swift +0 -1
- package/ios/RenderBridge+Attachments.swift +0 -29
- package/ios/RichTextEditorView.swift +4 -12
- package/ios/Viewer/CoreTextProseLayoutEngine+AttributedText.swift +3 -2
- package/package.json +11 -3
- package/react-native.config.js +1 -1
- package/rust/android/arm64-v8a/libeditor_core.so +0 -0
- package/rust/android/armeabi-v7a/libeditor_core.so +0 -0
- package/rust/android/x86/libeditor_core.so +0 -0
- package/rust/android/x86_64/libeditor_core.so +0 -0
- package/src/AtomHost.tsx +58 -28
- package/src/EditorAddon.ts +18 -8
- package/src/EditorAddonNormalization.ts +40 -11
- package/src/EditorMentionThemeNormalization.ts +15 -4
- package/src/EditorMentionThemeValidation.ts +51 -14
- package/src/EditorStyleSheet.ts +1 -0
- package/src/EditorStyleSheetNormalization.ts +195 -64
- package/src/EditorStyleSheetTypes.ts +1 -1
- package/src/EditorTheme.ts +13 -5
- package/src/EditorToolbarComponent.tsx +2 -1
- package/src/EditorToolbarRegistry.tsx +23 -13
- package/src/EditorToolbarTypes.tsx +12 -12
- package/src/EditorToolbarVisuals.tsx +6 -3
- package/src/EditorUpdateRevision.ts +1 -0
- package/src/ExternalTextComposition.ts +259 -49
- package/src/ImageLoadingPolicy.ts +3 -1
- package/src/NativeEditorBoundaryError.ts +38 -11
- package/src/NativeEditorCollaborationTransport.ts +108 -27
- package/src/NativeEditorCreateConfig.ts +92 -19
- package/src/NativeEditorCreateJson.ts +163 -26
- package/src/NativeEditorCreateValidation.ts +33 -12
- package/src/NativeEditorDocumentBridge.ts +111 -19
- package/src/NativeEditorDocumentHandle.ts +9 -4
- package/src/NativeEditorLocalAwareness.ts +70 -15
- package/src/NativeEditorNativeModule.ts +13 -9
- package/src/NativeEditorRenderNormalization.ts +128 -29
- package/src/NativeEditorResultNormalization.ts +143 -32
- package/src/NativeEditorTypes.ts +12 -11
- package/src/NativeEditorV2Decimal.ts +12 -3
- package/src/NativeProseViewer.tsx +46 -16
- package/src/ResourceLimits.ts +15 -8
- package/src/RichTextEditor.tsx +3 -1
- package/src/RichTextEditorNativeTypes.tsx +1 -1
- package/src/RichTextEditorNativeView.tsx +2 -8
- package/src/RichTextEditorSerialization.tsx +70 -24
- package/src/RichTextEditorTypes.tsx +1 -1
- package/src/YjsCollaboration.ts +143 -47
- package/src/addons.ts +12 -8
- package/src/atomInstances.ts +25 -5
- package/src/atomUpdates.ts +23 -6
- package/src/atoms.ts +85 -18
- package/src/attributeValidation.ts +97 -33
- package/src/contentExpression.ts +218 -63
- package/src/listMarkers.ts +1 -1
- package/src/schemaDefinition.ts +82 -20
- package/src/schemaDocument.ts +15 -1
- package/src/schemaDocumentConstruction.ts +80 -16
- package/src/schemaNormalization.ts +155 -41
- package/src/schemaPresets.ts +37 -31
- package/src/schemaResolution.ts +126 -27
- package/src/specs/PreparedProseViewerNativeComponent.ts +4 -2
- package/src/useEditorToolbarInteractions.tsx +85 -36
- package/src/useEditorToolbarItems.tsx +50 -22
- package/src/useEditorToolbarPresentation.tsx +81 -58
- package/src/useEditorToolbarState.tsx +8 -6
- package/src/useFocusPreservingFrames.ts +43 -15
- package/src/useNativeEditor.ts +111 -51
- package/src/useRichTextEditorCommands.tsx +127 -54
- package/src/useRichTextEditorEvents.tsx +144 -42
- package/src/useRichTextEditorMentions.tsx +118 -37
- package/src/useRichTextEditorPresentation.tsx +128 -114
- package/src/useRichTextEditorState.tsx +76 -40
- package/src/useRichTextEditorUpdates.tsx +207 -56
- package/src/useViewerAtoms.tsx +162 -66
|
@@ -95,7 +95,10 @@ export type V2JsonSerializationFrame =
|
|
|
95
95
|
| V2JsonSerializationObjectFrame;
|
|
96
96
|
|
|
97
97
|
export function chargeV2JsonWork(state: V2JsonNormalizationTraversal, label: string): void {
|
|
98
|
-
if (state.work >= V2_CREATE_JSON_MAX_WORK)
|
|
98
|
+
if (state.work >= V2_CREATE_JSON_MAX_WORK) {
|
|
99
|
+
invalidV2JsonValue(label);
|
|
100
|
+
}
|
|
101
|
+
|
|
99
102
|
state.work += 1;
|
|
100
103
|
}
|
|
101
104
|
|
|
@@ -111,6 +114,7 @@ export function chargeV2JsonBytes(
|
|
|
111
114
|
) {
|
|
112
115
|
invalidV2JsonValue(label);
|
|
113
116
|
}
|
|
117
|
+
|
|
114
118
|
budget.bytes += amount;
|
|
115
119
|
}
|
|
116
120
|
|
|
@@ -118,7 +122,10 @@ export function chargeV2JsonSerializationWork(
|
|
|
118
122
|
state: V2JsonSerializationState,
|
|
119
123
|
label: string
|
|
120
124
|
): void {
|
|
121
|
-
if (state.work >= V2_CREATE_WIRE_MAX_BYTES)
|
|
125
|
+
if (state.work >= V2_CREATE_WIRE_MAX_BYTES) {
|
|
126
|
+
invalidV2JsonValue(label);
|
|
127
|
+
}
|
|
128
|
+
|
|
122
129
|
state.work += 1;
|
|
123
130
|
}
|
|
124
131
|
|
|
@@ -134,13 +141,16 @@ export function chargeV2JsonSerializationBytes(
|
|
|
134
141
|
) {
|
|
135
142
|
invalidV2JsonValue(label);
|
|
136
143
|
}
|
|
144
|
+
|
|
137
145
|
state.bytes += amount;
|
|
138
146
|
}
|
|
139
147
|
|
|
140
148
|
export function utf8V2JsonByteLength(value: string): number {
|
|
141
149
|
let bytes = 0;
|
|
150
|
+
|
|
142
151
|
for (let index = 0; index < value.length; index += 1) {
|
|
143
152
|
const code = V2_CREATE_STRING_CHAR_CODE_AT.call(value, index);
|
|
153
|
+
|
|
144
154
|
if (code <= 0x7f) {
|
|
145
155
|
bytes += 1;
|
|
146
156
|
} else if (code <= 0x7ff) {
|
|
@@ -150,6 +160,7 @@ export function utf8V2JsonByteLength(value: string): number {
|
|
|
150
160
|
index + 1 < value.length
|
|
151
161
|
? V2_CREATE_STRING_CHAR_CODE_AT.call(value, index + 1)
|
|
152
162
|
: -1;
|
|
163
|
+
|
|
153
164
|
if (next >= 0xdc00 && next <= 0xdfff) {
|
|
154
165
|
bytes += 4;
|
|
155
166
|
index += 1;
|
|
@@ -160,11 +171,15 @@ export function utf8V2JsonByteLength(value: string): number {
|
|
|
160
171
|
bytes += 3;
|
|
161
172
|
}
|
|
162
173
|
}
|
|
174
|
+
|
|
163
175
|
return bytes;
|
|
164
176
|
}
|
|
165
177
|
|
|
166
178
|
export function serializeV2JsonNumber(value: number, label: string): string {
|
|
167
|
-
if (!Number.isFinite(value))
|
|
179
|
+
if (!Number.isFinite(value)) {
|
|
180
|
+
invalidV2JsonValue(label);
|
|
181
|
+
}
|
|
182
|
+
|
|
168
183
|
return value === 0 ? '0' : V2_CREATE_NUMBER_TO_STRING.call(value);
|
|
169
184
|
}
|
|
170
185
|
|
|
@@ -174,8 +189,10 @@ export function chargeV2JsonStringBytes(
|
|
|
174
189
|
label: string
|
|
175
190
|
): void {
|
|
176
191
|
chargeV2JsonBytes(budget, 2, label);
|
|
192
|
+
|
|
177
193
|
for (let index = 0; index < value.length; index += 1) {
|
|
178
194
|
const code = V2_CREATE_STRING_CHAR_CODE_AT.call(value, index);
|
|
195
|
+
|
|
179
196
|
if (code === 0x22 || code === 0x5c || code === 0x08 || code === 0x09) {
|
|
180
197
|
chargeV2JsonBytes(budget, 2, label);
|
|
181
198
|
} else if (code === 0x0a || code === 0x0c || code === 0x0d) {
|
|
@@ -191,6 +208,7 @@ export function chargeV2JsonStringBytes(
|
|
|
191
208
|
index + 1 < value.length
|
|
192
209
|
? V2_CREATE_STRING_CHAR_CODE_AT.call(value, index + 1)
|
|
193
210
|
: -1;
|
|
211
|
+
|
|
194
212
|
if (next >= 0xdc00 && next <= 0xdfff) {
|
|
195
213
|
chargeV2JsonBytes(budget, 4, label);
|
|
196
214
|
index += 1;
|
|
@@ -212,8 +230,11 @@ export function normalizeV2JsonValue(
|
|
|
212
230
|
budget: V2JsonNormalizationBudget = { bytes: 0 }
|
|
213
231
|
): unknown {
|
|
214
232
|
let normalizedRoot: unknown;
|
|
233
|
+
|
|
215
234
|
const frames: V2JsonNormalizationFrame[] = [
|
|
216
|
-
{
|
|
235
|
+
{
|
|
236
|
+
type: 'value', value, depth: 0, target: null, key: null,
|
|
237
|
+
},
|
|
217
238
|
];
|
|
218
239
|
|
|
219
240
|
const installNormalizedValue = (
|
|
@@ -223,9 +244,14 @@ export function normalizeV2JsonValue(
|
|
|
223
244
|
): void => {
|
|
224
245
|
if (target === null) {
|
|
225
246
|
normalizedRoot = normalized;
|
|
247
|
+
|
|
226
248
|
return;
|
|
227
249
|
}
|
|
228
|
-
|
|
250
|
+
|
|
251
|
+
if (key === null) {
|
|
252
|
+
invalidV2JsonValue(label);
|
|
253
|
+
}
|
|
254
|
+
|
|
229
255
|
Object.defineProperty(target, key, {
|
|
230
256
|
configurable: true,
|
|
231
257
|
enumerable: true,
|
|
@@ -236,23 +262,34 @@ export function normalizeV2JsonValue(
|
|
|
236
262
|
|
|
237
263
|
while (frames.length > 0) {
|
|
238
264
|
const frame = frames.pop();
|
|
239
|
-
|
|
265
|
+
|
|
266
|
+
if (frame === undefined) {
|
|
267
|
+
invalidV2JsonValue(label);
|
|
268
|
+
}
|
|
240
269
|
|
|
241
270
|
if (frame.type === 'array') {
|
|
242
271
|
if (frame.nextKeyIndex === frame.keys.length) {
|
|
243
|
-
if (frame.elementCount !== frame.length)
|
|
272
|
+
if (frame.elementCount !== frame.length) {
|
|
273
|
+
invalidV2JsonValue(label);
|
|
274
|
+
}
|
|
275
|
+
|
|
244
276
|
Object.setPrototypeOf(frame.normalized, null);
|
|
245
277
|
continue;
|
|
246
278
|
}
|
|
279
|
+
|
|
247
280
|
const key = frame.keys[frame.nextKeyIndex];
|
|
281
|
+
|
|
248
282
|
if (key === 'length') {
|
|
249
283
|
frames.push({ ...frame, nextKeyIndex: frame.nextKeyIndex + 1 });
|
|
250
284
|
continue;
|
|
251
285
|
}
|
|
286
|
+
|
|
252
287
|
if (typeof key !== 'string' || !/^(0|[1-9]\d*)$/.test(key)) {
|
|
253
288
|
invalidV2JsonValue(label);
|
|
254
289
|
}
|
|
290
|
+
|
|
255
291
|
const index = Number(key);
|
|
292
|
+
|
|
256
293
|
if (
|
|
257
294
|
!Number.isSafeInteger(index) ||
|
|
258
295
|
index !== frame.elementCount ||
|
|
@@ -261,7 +298,9 @@ export function normalizeV2JsonValue(
|
|
|
261
298
|
) {
|
|
262
299
|
invalidV2JsonValue(label);
|
|
263
300
|
}
|
|
301
|
+
|
|
264
302
|
const descriptor = Object.getOwnPropertyDescriptor(frame.value, key);
|
|
303
|
+
|
|
265
304
|
if (
|
|
266
305
|
descriptor === undefined ||
|
|
267
306
|
!('value' in descriptor) ||
|
|
@@ -269,12 +308,17 @@ export function normalizeV2JsonValue(
|
|
|
269
308
|
) {
|
|
270
309
|
invalidV2JsonValue(label);
|
|
271
310
|
}
|
|
272
|
-
|
|
311
|
+
|
|
312
|
+
if (frame.elementCount > 0) {
|
|
313
|
+
chargeV2JsonBytes(budget, 1, label);
|
|
314
|
+
}
|
|
315
|
+
|
|
273
316
|
frames.push({
|
|
274
317
|
...frame,
|
|
275
318
|
nextKeyIndex: frame.nextKeyIndex + 1,
|
|
276
319
|
elementCount: frame.elementCount + 1,
|
|
277
320
|
});
|
|
321
|
+
|
|
278
322
|
frames.push({
|
|
279
323
|
type: 'value',
|
|
280
324
|
value: descriptor.value,
|
|
@@ -282,14 +326,23 @@ export function normalizeV2JsonValue(
|
|
|
282
326
|
target: frame.normalized,
|
|
283
327
|
key: frame.elementCount,
|
|
284
328
|
});
|
|
329
|
+
|
|
285
330
|
continue;
|
|
286
331
|
}
|
|
287
332
|
|
|
288
333
|
if (frame.type === 'object') {
|
|
289
|
-
if (frame.nextKeyIndex === frame.keys.length)
|
|
334
|
+
if (frame.nextKeyIndex === frame.keys.length) {
|
|
335
|
+
continue;
|
|
336
|
+
}
|
|
337
|
+
|
|
290
338
|
const key = frame.keys[frame.nextKeyIndex];
|
|
291
|
-
|
|
339
|
+
|
|
340
|
+
if (typeof key !== 'string') {
|
|
341
|
+
invalidV2JsonValue(label);
|
|
342
|
+
}
|
|
343
|
+
|
|
292
344
|
const descriptor = Object.getOwnPropertyDescriptor(frame.value, key);
|
|
345
|
+
|
|
293
346
|
if (
|
|
294
347
|
descriptor === undefined ||
|
|
295
348
|
!('value' in descriptor) ||
|
|
@@ -297,21 +350,29 @@ export function normalizeV2JsonValue(
|
|
|
297
350
|
) {
|
|
298
351
|
invalidV2JsonValue(label);
|
|
299
352
|
}
|
|
353
|
+
|
|
300
354
|
if (descriptor.value === undefined) {
|
|
301
355
|
frames.push({
|
|
302
356
|
...frame,
|
|
303
357
|
nextKeyIndex: frame.nextKeyIndex + 1,
|
|
304
358
|
});
|
|
359
|
+
|
|
305
360
|
continue;
|
|
306
361
|
}
|
|
307
|
-
|
|
362
|
+
|
|
363
|
+
if (frame.fieldCount > 0) {
|
|
364
|
+
chargeV2JsonBytes(budget, 1, label);
|
|
365
|
+
}
|
|
366
|
+
|
|
308
367
|
chargeV2JsonStringBytes(key, budget, label);
|
|
309
368
|
chargeV2JsonBytes(budget, 1, label);
|
|
369
|
+
|
|
310
370
|
frames.push({
|
|
311
371
|
...frame,
|
|
312
372
|
nextKeyIndex: frame.nextKeyIndex + 1,
|
|
313
373
|
fieldCount: frame.fieldCount + 1,
|
|
314
374
|
});
|
|
375
|
+
|
|
315
376
|
frames.push({
|
|
316
377
|
type: 'value',
|
|
317
378
|
value: descriptor.value,
|
|
@@ -319,42 +380,62 @@ export function normalizeV2JsonValue(
|
|
|
319
380
|
target: frame.normalized,
|
|
320
381
|
key,
|
|
321
382
|
});
|
|
383
|
+
|
|
322
384
|
continue;
|
|
323
385
|
}
|
|
324
386
|
|
|
325
|
-
if (frame.depth > V2_CREATE_JSON_MAX_DEPTH)
|
|
387
|
+
if (frame.depth > V2_CREATE_JSON_MAX_DEPTH) {
|
|
388
|
+
invalidV2JsonValue(label);
|
|
389
|
+
}
|
|
390
|
+
|
|
326
391
|
chargeV2JsonWork(traversal, label);
|
|
392
|
+
|
|
327
393
|
if (frame.value === null) {
|
|
328
394
|
chargeV2JsonBytes(budget, 4, label);
|
|
329
395
|
installNormalizedValue(frame.target, frame.key, frame.value);
|
|
330
396
|
continue;
|
|
331
397
|
}
|
|
398
|
+
|
|
332
399
|
if (typeof frame.value === 'string') {
|
|
333
400
|
chargeV2JsonStringBytes(frame.value, budget, label);
|
|
334
401
|
installNormalizedValue(frame.target, frame.key, frame.value);
|
|
335
402
|
continue;
|
|
336
403
|
}
|
|
404
|
+
|
|
337
405
|
if (typeof frame.value === 'boolean') {
|
|
338
406
|
chargeV2JsonBytes(budget, frame.value ? 4 : 5, label);
|
|
339
407
|
installNormalizedValue(frame.target, frame.key, frame.value);
|
|
340
408
|
continue;
|
|
341
409
|
}
|
|
410
|
+
|
|
342
411
|
if (typeof frame.value === 'number') {
|
|
343
412
|
const serialized = serializeV2JsonNumber(frame.value, label);
|
|
344
413
|
chargeV2JsonBytes(budget, serialized.length, label);
|
|
345
414
|
installNormalizedValue(frame.target, frame.key, frame.value);
|
|
346
415
|
continue;
|
|
347
416
|
}
|
|
348
|
-
if (typeof frame.value !== 'object') invalidV2JsonValue(label);
|
|
349
417
|
|
|
350
|
-
if (
|
|
418
|
+
if (typeof frame.value !== 'object') {
|
|
419
|
+
invalidV2JsonValue(label);
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
if (traversal.seen.has(frame.value)) {
|
|
423
|
+
invalidV2JsonValue(label);
|
|
424
|
+
}
|
|
425
|
+
|
|
351
426
|
traversal.seen.add(frame.value);
|
|
352
427
|
chargeV2JsonBytes(budget, 2, label);
|
|
353
428
|
const childDepth = frame.depth + 1;
|
|
429
|
+
|
|
354
430
|
if (Array.isArray(frame.value)) {
|
|
355
431
|
const prototype = Object.getPrototypeOf(frame.value);
|
|
356
|
-
|
|
432
|
+
|
|
433
|
+
if (prototype !== Array.prototype && prototype !== null) {
|
|
434
|
+
invalidV2JsonValue(label);
|
|
435
|
+
}
|
|
436
|
+
|
|
357
437
|
const lengthDescriptor = Object.getOwnPropertyDescriptor(frame.value, 'length');
|
|
438
|
+
|
|
358
439
|
if (
|
|
359
440
|
lengthDescriptor === undefined ||
|
|
360
441
|
!('value' in lengthDescriptor) ||
|
|
@@ -362,8 +443,10 @@ export function normalizeV2JsonValue(
|
|
|
362
443
|
) {
|
|
363
444
|
invalidV2JsonValue(label);
|
|
364
445
|
}
|
|
446
|
+
|
|
365
447
|
const normalized: unknown[] = [];
|
|
366
448
|
installNormalizedValue(frame.target, frame.key, normalized);
|
|
449
|
+
|
|
367
450
|
frames.push({
|
|
368
451
|
type: 'array',
|
|
369
452
|
value: frame.value,
|
|
@@ -374,12 +457,17 @@ export function normalizeV2JsonValue(
|
|
|
374
457
|
nextKeyIndex: 0,
|
|
375
458
|
elementCount: 0,
|
|
376
459
|
});
|
|
460
|
+
|
|
377
461
|
continue;
|
|
378
462
|
}
|
|
379
463
|
|
|
380
|
-
if (!isV2CreateRecord(frame.value))
|
|
464
|
+
if (!isV2CreateRecord(frame.value)) {
|
|
465
|
+
invalidV2JsonValue(label);
|
|
466
|
+
}
|
|
467
|
+
|
|
381
468
|
const normalized = emptyV2CreateRecord();
|
|
382
469
|
installNormalizedValue(frame.target, frame.key, normalized);
|
|
470
|
+
|
|
383
471
|
frames.push({
|
|
384
472
|
type: 'object',
|
|
385
473
|
value: frame.value,
|
|
@@ -391,17 +479,22 @@ export function normalizeV2JsonValue(
|
|
|
391
479
|
});
|
|
392
480
|
}
|
|
393
481
|
|
|
394
|
-
if (normalizedRoot === undefined)
|
|
482
|
+
if (normalizedRoot === undefined) {
|
|
483
|
+
invalidV2JsonValue(label);
|
|
484
|
+
}
|
|
485
|
+
|
|
395
486
|
return normalizedRoot;
|
|
396
487
|
}
|
|
397
488
|
|
|
398
489
|
export class V2JsonSerializationWriter {
|
|
399
490
|
private readonly _chunks: string[] = [];
|
|
491
|
+
|
|
400
492
|
private _current = '';
|
|
401
493
|
|
|
402
494
|
append(value: string, state: V2JsonSerializationState, label: string): void {
|
|
403
495
|
chargeV2JsonSerializationBytes(state, utf8V2JsonByteLength(value), label);
|
|
404
496
|
this._current += value;
|
|
497
|
+
|
|
405
498
|
if (this._current.length >= V2_CREATE_JSON_OUTPUT_CHUNK_SIZE) {
|
|
406
499
|
this._chunks.push(this._current);
|
|
407
500
|
this._current = '';
|
|
@@ -409,7 +502,10 @@ export class V2JsonSerializationWriter {
|
|
|
409
502
|
}
|
|
410
503
|
|
|
411
504
|
finish(): string {
|
|
412
|
-
if (this._current.length > 0)
|
|
505
|
+
if (this._current.length > 0) {
|
|
506
|
+
this._chunks.push(this._current);
|
|
507
|
+
}
|
|
508
|
+
|
|
413
509
|
return this._chunks.join('');
|
|
414
510
|
}
|
|
415
511
|
}
|
|
@@ -422,10 +518,12 @@ export function appendV2JsonString(
|
|
|
422
518
|
): void {
|
|
423
519
|
writer.append('"', state, label);
|
|
424
520
|
let segmentStart = 0;
|
|
521
|
+
|
|
425
522
|
for (let index = 0; index < value.length; index += 1) {
|
|
426
523
|
chargeV2JsonSerializationWork(state, label);
|
|
427
524
|
const code = V2_CREATE_STRING_CHAR_CODE_AT.call(value, index);
|
|
428
525
|
let escape: string | undefined;
|
|
526
|
+
|
|
429
527
|
switch (code) {
|
|
430
528
|
case 0x08:
|
|
431
529
|
escape = '\\b';
|
|
@@ -456,6 +554,7 @@ export function appendV2JsonString(
|
|
|
456
554
|
index + 1 < value.length
|
|
457
555
|
? V2_CREATE_STRING_CHAR_CODE_AT.call(value, index + 1)
|
|
458
556
|
: -1;
|
|
557
|
+
|
|
459
558
|
if (next >= 0xdc00 && next <= 0xdfff) {
|
|
460
559
|
chargeV2JsonSerializationWork(state, label);
|
|
461
560
|
index += 1;
|
|
@@ -465,18 +564,26 @@ export function appendV2JsonString(
|
|
|
465
564
|
} else if (code >= 0xdc00 && code <= 0xdfff) {
|
|
466
565
|
escape = `\\u${code.toString(16).padStart(4, '0')}`;
|
|
467
566
|
}
|
|
567
|
+
|
|
468
568
|
break;
|
|
469
569
|
}
|
|
470
|
-
|
|
570
|
+
|
|
571
|
+
if (escape === undefined) {
|
|
572
|
+
continue;
|
|
573
|
+
}
|
|
574
|
+
|
|
471
575
|
if (segmentStart < index) {
|
|
472
576
|
writer.append(V2_CREATE_STRING_SLICE.call(value, segmentStart, index), state, label);
|
|
473
577
|
}
|
|
578
|
+
|
|
474
579
|
writer.append(escape, state, label);
|
|
475
580
|
segmentStart = index + 1;
|
|
476
581
|
}
|
|
582
|
+
|
|
477
583
|
if (segmentStart < value.length) {
|
|
478
584
|
writer.append(V2_CREATE_STRING_SLICE.call(value, segmentStart), state, label);
|
|
479
585
|
}
|
|
586
|
+
|
|
480
587
|
writer.append('"', state, label);
|
|
481
588
|
}
|
|
482
589
|
|
|
@@ -484,19 +591,27 @@ export function serializeV2CreateEnvelope(value: Record<string, unknown>): strin
|
|
|
484
591
|
const label = 'v2 create config';
|
|
485
592
|
const writer = new V2JsonSerializationWriter();
|
|
486
593
|
const state: V2JsonSerializationState = { bytes: 0, work: 0 };
|
|
487
|
-
const frames: V2JsonSerializationFrame[] = [{ type: 'value', value, depth: 0 }];
|
|
594
|
+
const frames: V2JsonSerializationFrame[] = [ { type: 'value', value, depth: 0 } ];
|
|
488
595
|
|
|
489
596
|
while (frames.length > 0) {
|
|
490
597
|
const frame = frames.pop();
|
|
491
|
-
|
|
598
|
+
|
|
599
|
+
if (frame === undefined) {
|
|
600
|
+
invalidV2JsonValue(label);
|
|
601
|
+
}
|
|
492
602
|
|
|
493
603
|
if (frame.type === 'array') {
|
|
494
604
|
if (frame.index === frame.length) {
|
|
495
605
|
writer.append(']', state, label);
|
|
496
606
|
continue;
|
|
497
607
|
}
|
|
498
|
-
|
|
608
|
+
|
|
609
|
+
if (frame.index > 0) {
|
|
610
|
+
writer.append(',', state, label);
|
|
611
|
+
}
|
|
612
|
+
|
|
499
613
|
const descriptor = Object.getOwnPropertyDescriptor(frame.value, String(frame.index));
|
|
614
|
+
|
|
500
615
|
if (
|
|
501
616
|
descriptor === undefined ||
|
|
502
617
|
!('value' in descriptor) ||
|
|
@@ -504,6 +619,7 @@ export function serializeV2CreateEnvelope(value: Record<string, unknown>): strin
|
|
|
504
619
|
) {
|
|
505
620
|
invalidV2JsonValue(label);
|
|
506
621
|
}
|
|
622
|
+
|
|
507
623
|
frames.push({ ...frame, index: frame.index + 1 });
|
|
508
624
|
frames.push({ type: 'value', value: descriptor.value, depth: frame.depth + 1 });
|
|
509
625
|
continue;
|
|
@@ -514,9 +630,14 @@ export function serializeV2CreateEnvelope(value: Record<string, unknown>): strin
|
|
|
514
630
|
writer.append('}', state, label);
|
|
515
631
|
continue;
|
|
516
632
|
}
|
|
517
|
-
|
|
633
|
+
|
|
634
|
+
if (frame.index > 0) {
|
|
635
|
+
writer.append(',', state, label);
|
|
636
|
+
}
|
|
637
|
+
|
|
518
638
|
const key = frame.keys[frame.index];
|
|
519
639
|
const descriptor = Object.getOwnPropertyDescriptor(frame.value, key);
|
|
640
|
+
|
|
520
641
|
if (
|
|
521
642
|
descriptor === undefined ||
|
|
522
643
|
!('value' in descriptor) ||
|
|
@@ -524,6 +645,7 @@ export function serializeV2CreateEnvelope(value: Record<string, unknown>): strin
|
|
|
524
645
|
) {
|
|
525
646
|
invalidV2JsonValue(label);
|
|
526
647
|
}
|
|
648
|
+
|
|
527
649
|
appendV2JsonString(writer, key, state, label);
|
|
528
650
|
writer.append(':', state, label);
|
|
529
651
|
frames.push({ ...frame, index: frame.index + 1 });
|
|
@@ -531,8 +653,12 @@ export function serializeV2CreateEnvelope(value: Record<string, unknown>): strin
|
|
|
531
653
|
continue;
|
|
532
654
|
}
|
|
533
655
|
|
|
534
|
-
if (frame.depth > V2_CREATE_ENVELOPE_JSON_MAX_DEPTH)
|
|
656
|
+
if (frame.depth > V2_CREATE_ENVELOPE_JSON_MAX_DEPTH) {
|
|
657
|
+
invalidV2JsonValue(label);
|
|
658
|
+
}
|
|
659
|
+
|
|
535
660
|
chargeV2JsonSerializationWork(state, label);
|
|
661
|
+
|
|
536
662
|
if (frame.value === null) {
|
|
537
663
|
writer.append('null', state, label);
|
|
538
664
|
} else if (typeof frame.value === 'string') {
|
|
@@ -542,8 +668,12 @@ export function serializeV2CreateEnvelope(value: Record<string, unknown>): strin
|
|
|
542
668
|
} else if (typeof frame.value === 'number') {
|
|
543
669
|
writer.append(serializeV2JsonNumber(frame.value, label), state, label);
|
|
544
670
|
} else if (Array.isArray(frame.value)) {
|
|
545
|
-
if (Object.getPrototypeOf(frame.value) !== null)
|
|
671
|
+
if (Object.getPrototypeOf(frame.value) !== null) {
|
|
672
|
+
invalidV2JsonValue(label);
|
|
673
|
+
}
|
|
674
|
+
|
|
546
675
|
const lengthDescriptor = Object.getOwnPropertyDescriptor(frame.value, 'length');
|
|
676
|
+
|
|
547
677
|
if (
|
|
548
678
|
lengthDescriptor === undefined ||
|
|
549
679
|
!('value' in lengthDescriptor) ||
|
|
@@ -551,7 +681,9 @@ export function serializeV2CreateEnvelope(value: Record<string, unknown>): strin
|
|
|
551
681
|
) {
|
|
552
682
|
invalidV2JsonValue(label);
|
|
553
683
|
}
|
|
684
|
+
|
|
554
685
|
writer.append('[', state, label);
|
|
686
|
+
|
|
555
687
|
frames.push({
|
|
556
688
|
type: 'array',
|
|
557
689
|
value: frame.value,
|
|
@@ -561,8 +693,13 @@ export function serializeV2CreateEnvelope(value: Record<string, unknown>): strin
|
|
|
561
693
|
});
|
|
562
694
|
} else if (isV2CreateRecord(frame.value) && Object.getPrototypeOf(frame.value) === null) {
|
|
563
695
|
const keys = Reflect.ownKeys(frame.value);
|
|
564
|
-
|
|
696
|
+
|
|
697
|
+
if (keys.some(key => typeof key !== 'string')) {
|
|
698
|
+
invalidV2JsonValue(label);
|
|
699
|
+
}
|
|
700
|
+
|
|
565
701
|
writer.append('{', state, label);
|
|
702
|
+
|
|
566
703
|
frames.push({
|
|
567
704
|
type: 'object',
|
|
568
705
|
value: frame.value,
|
|
@@ -20,7 +20,7 @@ export const V2_CREATE_POLICY_KEYS = new Set([
|
|
|
20
20
|
'allowBase64Images',
|
|
21
21
|
]);
|
|
22
22
|
|
|
23
|
-
export const V2_CREATE_LIMIT_KEYS = new Set(['resource', 'editing', 'collaboration']);
|
|
23
|
+
export const V2_CREATE_LIMIT_KEYS = new Set([ 'resource', 'editing', 'collaboration' ]);
|
|
24
24
|
|
|
25
25
|
export const V2_CREATE_RESOURCE_LIMIT_KEYS = new Set([
|
|
26
26
|
'maxInputBytes',
|
|
@@ -53,13 +53,13 @@ export const V2_CREATE_COLLABORATION_LIMIT_KEYS = new Set([
|
|
|
53
53
|
]);
|
|
54
54
|
|
|
55
55
|
export const V2_CREATE_INITIALIZATION_KEYS: Readonly<Record<string, ReadonlySet<string>>> = {
|
|
56
|
-
localEmpty: new Set(['type']),
|
|
57
|
-
localJson: new Set(['type', 'json']),
|
|
58
|
-
localHtml: new Set(['type', 'html']),
|
|
59
|
-
room: new Set(['type', 'documentId', 'lineageId', 'snapshot']),
|
|
56
|
+
localEmpty: new Set([ 'type' ]),
|
|
57
|
+
localJson: new Set([ 'type', 'json' ]),
|
|
58
|
+
localHtml: new Set([ 'type', 'html' ]),
|
|
59
|
+
room: new Set([ 'type', 'documentId', 'lineageId', 'snapshot' ]),
|
|
60
60
|
};
|
|
61
61
|
|
|
62
|
-
export const V2_CREATE_ROOM_SNAPSHOT_KEYS = new Set(['metadata', 'encodedState']);
|
|
62
|
+
export const V2_CREATE_ROOM_SNAPSHOT_KEYS = new Set([ 'metadata', 'encodedState' ]);
|
|
63
63
|
|
|
64
64
|
export const V2_CREATE_SNAPSHOT_METADATA_KEYS = new Set([
|
|
65
65
|
'formatVersion',
|
|
@@ -107,7 +107,10 @@ export function validateV2CreateLimits(limits: NativeEditorCreateConfig['limits'
|
|
|
107
107
|
try {
|
|
108
108
|
validateEditorCreateLimits(limits);
|
|
109
109
|
} catch (error) {
|
|
110
|
-
if (!(error instanceof NativeEditorBoundaryError))
|
|
110
|
+
if (!(error instanceof NativeEditorBoundaryError)) {
|
|
111
|
+
throw error;
|
|
112
|
+
}
|
|
113
|
+
|
|
111
114
|
throw new NativeEditorEngineBoundaryError({
|
|
112
115
|
domain: 'boundary',
|
|
113
116
|
code: error.code,
|
|
@@ -126,8 +129,12 @@ export function emptyV2CreateRecord(): Record<string, unknown> {
|
|
|
126
129
|
}
|
|
127
130
|
|
|
128
131
|
export function isV2CreateRecord(value: unknown): value is Record<string, unknown> {
|
|
129
|
-
if (value == null || typeof value !== 'object' || Array.isArray(value))
|
|
132
|
+
if (value == null || typeof value !== 'object' || Array.isArray(value)) {
|
|
133
|
+
return false;
|
|
134
|
+
}
|
|
135
|
+
|
|
130
136
|
const prototype = Object.getPrototypeOf(value);
|
|
137
|
+
|
|
131
138
|
return prototype === Object.prototype || prototype === null;
|
|
132
139
|
}
|
|
133
140
|
|
|
@@ -137,12 +144,17 @@ export function hasOwnV2CreateKey(value: Record<string, unknown>, key: string):
|
|
|
137
144
|
|
|
138
145
|
export function ownV2CreateValue(value: Record<string, unknown>, key: string): unknown {
|
|
139
146
|
const descriptor = Object.getOwnPropertyDescriptor(value, key);
|
|
140
|
-
|
|
147
|
+
|
|
148
|
+
if (descriptor === undefined) {
|
|
149
|
+
return undefined;
|
|
150
|
+
}
|
|
151
|
+
|
|
141
152
|
if (!('value' in descriptor)) {
|
|
142
153
|
throw invalidV2CreateRequestError(
|
|
143
154
|
`NativeEditorBridge: accessor ${key} is not allowed for v2 create`
|
|
144
155
|
);
|
|
145
156
|
}
|
|
157
|
+
|
|
146
158
|
return descriptor.value;
|
|
147
159
|
}
|
|
148
160
|
|
|
@@ -153,7 +165,7 @@ export function requireKnownV2CreateKeys(
|
|
|
153
165
|
): asserts value is Record<string, unknown> {
|
|
154
166
|
if (
|
|
155
167
|
!isV2CreateRecord(value) ||
|
|
156
|
-
Reflect.ownKeys(value).some(
|
|
168
|
+
Reflect.ownKeys(value).some(key => typeof key !== 'string' || !allowed.has(key))
|
|
157
169
|
) {
|
|
158
170
|
throw invalidV2CreateRequestError(`NativeEditorBridge: invalid ${label} for v2 create`);
|
|
159
171
|
}
|
|
@@ -166,13 +178,22 @@ export function normalizeV2CreateRecord(
|
|
|
166
178
|
): Record<string, unknown> {
|
|
167
179
|
requireKnownV2CreateKeys(value, allowed, label);
|
|
168
180
|
const normalized = emptyV2CreateRecord();
|
|
181
|
+
|
|
169
182
|
for (const key of allowed) {
|
|
170
|
-
if (!hasOwnV2CreateKey(value, key))
|
|
183
|
+
if (!hasOwnV2CreateKey(value, key)) {
|
|
184
|
+
continue;
|
|
185
|
+
}
|
|
186
|
+
|
|
171
187
|
const fieldValue = ownV2CreateValue(value, key);
|
|
188
|
+
|
|
172
189
|
if (fieldValue === null) {
|
|
173
190
|
throw invalidV2CreateRequestError(`NativeEditorBridge: invalid ${label} for v2 create`);
|
|
174
191
|
}
|
|
175
|
-
|
|
192
|
+
|
|
193
|
+
if (fieldValue !== undefined) {
|
|
194
|
+
normalized[key] = fieldValue;
|
|
195
|
+
}
|
|
176
196
|
}
|
|
197
|
+
|
|
177
198
|
return normalized;
|
|
178
199
|
}
|