@onekeyfe/react-native-native-list 3.0.105

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 (181) hide show
  1. package/README.md +342 -0
  2. package/android/CMakeLists.txt +20 -0
  3. package/android/build.gradle +105 -0
  4. package/android/gradle.properties +4 -0
  5. package/android/src/main/AndroidManifest.xml +1 -0
  6. package/android/src/main/cpp/cpp-adapter.cpp +6 -0
  7. package/android/src/main/java/com/onekey/nativelist/HybridNativeList.kt +125 -0
  8. package/android/src/main/java/com/onekey/nativelist/NativeListAdapter.kt +165 -0
  9. package/android/src/main/java/com/onekey/nativelist/NativeListModels.kt +147 -0
  10. package/android/src/main/java/com/onekey/nativelist/NativeListPackage.kt +25 -0
  11. package/android/src/main/java/com/onekey/nativelist/NativeListRowView.kt +2939 -0
  12. package/android/src/main/java/com/onekey/nativelist/NativeListView.kt +1794 -0
  13. package/common/fonts/Roobert-Bold.ttf +0 -0
  14. package/common/fonts/Roobert-Medium.ttf +0 -0
  15. package/common/fonts/Roobert-Regular.ttf +0 -0
  16. package/common/fonts/Roobert-SemiBold.ttf +0 -0
  17. package/docs/DESIGN.md +129 -0
  18. package/ios/HybridNativeList.swift +131 -0
  19. package/ios/NativeListCell.swift +2858 -0
  20. package/ios/NativeListDesignAssets.swift +110 -0
  21. package/ios/NativeListModels.swift +215 -0
  22. package/ios/RNCNativeListView.swift +1737 -0
  23. package/ios/Resources/NativeListIcons.xcassets/Contents.json +1 -0
  24. package/ios/Resources/NativeListIcons.xcassets/onekey_arrow_bottom.imageset/Contents.json +1 -0
  25. package/ios/Resources/NativeListIcons.xcassets/onekey_arrow_bottom.imageset/icon.svg +1 -0
  26. package/ios/Resources/NativeListIcons.xcassets/onekey_arrow_top.imageset/Contents.json +1 -0
  27. package/ios/Resources/NativeListIcons.xcassets/onekey_arrow_top.imageset/icon.svg +1 -0
  28. package/ios/Resources/NativeListIcons.xcassets/onekey_chart_trending_up.imageset/Contents.json +1 -0
  29. package/ios/Resources/NativeListIcons.xcassets/onekey_chart_trending_up.imageset/icon.svg +1 -0
  30. package/ios/Resources/NativeListIcons.xcassets/onekey_checkbox_checked.imageset/Contents.json +1 -0
  31. package/ios/Resources/NativeListIcons.xcassets/onekey_checkbox_checked.imageset/icon.svg +1 -0
  32. package/ios/Resources/NativeListIcons.xcassets/onekey_checkbox_indeterminate.imageset/Contents.json +1 -0
  33. package/ios/Resources/NativeListIcons.xcassets/onekey_checkbox_indeterminate.imageset/icon.svg +1 -0
  34. package/ios/Resources/NativeListIcons.xcassets/onekey_chevron_bottom.imageset/Contents.json +1 -0
  35. package/ios/Resources/NativeListIcons.xcassets/onekey_chevron_bottom.imageset/icon.svg +1 -0
  36. package/ios/Resources/NativeListIcons.xcassets/onekey_chevron_grabber_ver.imageset/Contents.json +1 -0
  37. package/ios/Resources/NativeListIcons.xcassets/onekey_chevron_grabber_ver.imageset/icon.svg +1 -0
  38. package/ios/Resources/NativeListIcons.xcassets/onekey_chevron_right_small.imageset/Contents.json +1 -0
  39. package/ios/Resources/NativeListIcons.xcassets/onekey_chevron_right_small.imageset/icon.svg +1 -0
  40. package/ios/Resources/NativeListIcons.xcassets/onekey_chevron_top.imageset/Contents.json +1 -0
  41. package/ios/Resources/NativeListIcons.xcassets/onekey_chevron_top.imageset/icon.svg +1 -0
  42. package/ios/Resources/NativeListIcons.xcassets/onekey_dot_hor.imageset/Contents.json +1 -0
  43. package/ios/Resources/NativeListIcons.xcassets/onekey_dot_hor.imageset/icon.svg +1 -0
  44. package/ios/Resources/NativeListIcons.xcassets/onekey_drag.imageset/Contents.json +1 -0
  45. package/ios/Resources/NativeListIcons.xcassets/onekey_drag.imageset/icon.svg +1 -0
  46. package/ios/Resources/NativeListIcons.xcassets/onekey_error_solid.imageset/Contents.json +1 -0
  47. package/ios/Resources/NativeListIcons.xcassets/onekey_error_solid.imageset/icon.svg +1 -0
  48. package/ios/Resources/NativeListIcons.xcassets/onekey_image_square_waves.imageset/Contents.json +1 -0
  49. package/ios/Resources/NativeListIcons.xcassets/onekey_image_square_waves.imageset/icon.svg +1 -0
  50. package/ios/Resources/NativeListIcons.xcassets/onekey_info_circle.imageset/Contents.json +1 -0
  51. package/ios/Resources/NativeListIcons.xcassets/onekey_info_circle.imageset/icon.svg +1 -0
  52. package/ios/Resources/NativeListIcons.xcassets/onekey_minus_circle.imageset/Contents.json +1 -0
  53. package/ios/Resources/NativeListIcons.xcassets/onekey_minus_circle.imageset/icon.svg +1 -0
  54. package/ios/Resources/NativeListIcons.xcassets/onekey_minus_circle_solid.imageset/Contents.json +1 -0
  55. package/ios/Resources/NativeListIcons.xcassets/onekey_minus_circle_solid.imageset/icon.svg +1 -0
  56. package/ios/Resources/NativeListIcons.xcassets/onekey_pencil.imageset/Contents.json +1 -0
  57. package/ios/Resources/NativeListIcons.xcassets/onekey_pencil.imageset/icon.svg +1 -0
  58. package/ios/Resources/NativeListIcons.xcassets/onekey_plus_circle.imageset/Contents.json +1 -0
  59. package/ios/Resources/NativeListIcons.xcassets/onekey_plus_circle.imageset/icon.svg +1 -0
  60. package/ios/Resources/NativeListIcons.xcassets/onekey_plus_small.imageset/Contents.json +1 -0
  61. package/ios/Resources/NativeListIcons.xcassets/onekey_plus_small.imageset/icon.svg +1 -0
  62. package/ios/Resources/NativeListIcons.xcassets/onekey_questionmark_solid.imageset/Contents.json +1 -0
  63. package/ios/Resources/NativeListIcons.xcassets/onekey_questionmark_solid.imageset/icon.svg +1 -0
  64. package/ios/Resources/NativeListIcons.xcassets/onekey_shield_exclamation.imageset/Contents.json +1 -0
  65. package/ios/Resources/NativeListIcons.xcassets/onekey_shield_exclamation.imageset/icon.svg +1 -0
  66. package/ios/Resources/NativeListIcons.xcassets/onekey_speaker_promote.imageset/Contents.json +1 -0
  67. package/ios/Resources/NativeListIcons.xcassets/onekey_speaker_promote.imageset/icon.svg +1 -0
  68. package/ios/Resources/NativeListIcons.xcassets/onekey_star.imageset/Contents.json +1 -0
  69. package/ios/Resources/NativeListIcons.xcassets/onekey_star.imageset/icon.svg +1 -0
  70. package/ios/Resources/NativeListIcons.xcassets/onekey_star_solid.imageset/Contents.json +1 -0
  71. package/ios/Resources/NativeListIcons.xcassets/onekey_star_solid.imageset/icon.svg +1 -0
  72. package/ios/Resources/NativeListIcons.xcassets/onekey_swap_hor.imageset/Contents.json +1 -0
  73. package/ios/Resources/NativeListIcons.xcassets/onekey_swap_hor.imageset/icon.svg +1 -0
  74. package/lib/module/NativeList.js +183 -0
  75. package/lib/module/NativeList.nitro.js +4 -0
  76. package/lib/module/NativeList.types.js +4 -0
  77. package/lib/module/NativeList.web.js +167 -0
  78. package/lib/module/index.js +6 -0
  79. package/lib/module/models.js +2 -0
  80. package/lib/module/package.json +1 -0
  81. package/lib/module/scrolling.js +121 -0
  82. package/lib/module/selection.js +85 -0
  83. package/lib/module/validation.js +562 -0
  84. package/lib/module/web/NativeListWebEngine.js +2238 -0
  85. package/lib/nitrogen/generated/.gitattributes +1 -0
  86. package/lib/nitrogen/generated/android/c++/JFunc_void_std__string.hpp +76 -0
  87. package/lib/nitrogen/generated/android/c++/JHybridNativeListSpec.cpp +201 -0
  88. package/lib/nitrogen/generated/android/c++/JHybridNativeListSpec.hpp +84 -0
  89. package/lib/nitrogen/generated/android/c++/JNativeListScrollAlignment.hpp +64 -0
  90. package/lib/nitrogen/generated/android/c++/views/JHybridNativeListStateUpdater.cpp +104 -0
  91. package/lib/nitrogen/generated/android/c++/views/JHybridNativeListStateUpdater.hpp +54 -0
  92. package/lib/nitrogen/generated/android/kotlin/com/margelo/nitro/nativelist/Func_void_std__string.kt +78 -0
  93. package/lib/nitrogen/generated/android/kotlin/com/margelo/nitro/nativelist/HybridNativeListSpec.kt +177 -0
  94. package/lib/nitrogen/generated/android/kotlin/com/margelo/nitro/nativelist/NativeListScrollAlignment.kt +25 -0
  95. package/lib/nitrogen/generated/android/kotlin/com/margelo/nitro/nativelist/nativelistOnLoad.kt +35 -0
  96. package/lib/nitrogen/generated/android/kotlin/com/margelo/nitro/nativelist/views/HybridNativeListManager.kt +96 -0
  97. package/lib/nitrogen/generated/android/kotlin/com/margelo/nitro/nativelist/views/HybridNativeListStateUpdater.kt +23 -0
  98. package/lib/nitrogen/generated/android/nativelist+autolinking.cmake +83 -0
  99. package/lib/nitrogen/generated/android/nativelist+autolinking.gradle +27 -0
  100. package/lib/nitrogen/generated/android/nativelistOnLoad.cpp +58 -0
  101. package/lib/nitrogen/generated/android/nativelistOnLoad.hpp +34 -0
  102. package/lib/nitrogen/generated/ios/NativeListModule+autolinking.rb +62 -0
  103. package/lib/nitrogen/generated/ios/NativeListModule-Swift-Cxx-Bridge.cpp +41 -0
  104. package/lib/nitrogen/generated/ios/NativeListModule-Swift-Cxx-Bridge.hpp +91 -0
  105. package/lib/nitrogen/generated/ios/NativeListModule-Swift-Cxx-Umbrella.hpp +49 -0
  106. package/lib/nitrogen/generated/ios/NativeListModuleAutolinking.mm +33 -0
  107. package/lib/nitrogen/generated/ios/NativeListModuleAutolinking.swift +26 -0
  108. package/lib/nitrogen/generated/ios/c++/HybridNativeListSpecSwift.cpp +11 -0
  109. package/lib/nitrogen/generated/ios/c++/HybridNativeListSpecSwift.hpp +180 -0
  110. package/lib/nitrogen/generated/ios/c++/views/HybridNativeListComponent.mm +180 -0
  111. package/lib/nitrogen/generated/ios/swift/Func_void_std__string.swift +46 -0
  112. package/lib/nitrogen/generated/ios/swift/HybridNativeListSpec.swift +69 -0
  113. package/lib/nitrogen/generated/ios/swift/HybridNativeListSpec_cxx.swift +447 -0
  114. package/lib/nitrogen/generated/ios/swift/NativeListScrollAlignment.swift +48 -0
  115. package/lib/nitrogen/generated/shared/c++/HybridNativeListSpec.cpp +43 -0
  116. package/lib/nitrogen/generated/shared/c++/HybridNativeListSpec.hpp +87 -0
  117. package/lib/nitrogen/generated/shared/c++/NativeListScrollAlignment.hpp +84 -0
  118. package/lib/nitrogen/generated/shared/c++/views/HybridNativeListComponent.cpp +46 -0
  119. package/lib/nitrogen/generated/shared/c++/views/HybridNativeListComponent.hpp +103 -0
  120. package/lib/nitrogen/generated/shared/json/NativeListConfig.json +16 -0
  121. package/lib/typescript/package.json +1 -0
  122. package/lib/typescript/src/NativeList.d.ts +18 -0
  123. package/lib/typescript/src/NativeList.nitro.d.ts +29 -0
  124. package/lib/typescript/src/NativeList.types.d.ts +87 -0
  125. package/lib/typescript/src/NativeList.web.d.ts +19 -0
  126. package/lib/typescript/src/index.d.ts +7 -0
  127. package/lib/typescript/src/models.d.ts +456 -0
  128. package/lib/typescript/src/scrolling.d.ts +32 -0
  129. package/lib/typescript/src/selection.d.ts +27 -0
  130. package/lib/typescript/src/validation.d.ts +7 -0
  131. package/lib/typescript/src/web/NativeListWebEngine.d.ts +203 -0
  132. package/nitro.json +23 -0
  133. package/nitrogen/generated/.gitattributes +1 -0
  134. package/nitrogen/generated/android/c++/JFunc_void_std__string.hpp +76 -0
  135. package/nitrogen/generated/android/c++/JHybridNativeListSpec.cpp +201 -0
  136. package/nitrogen/generated/android/c++/JHybridNativeListSpec.hpp +84 -0
  137. package/nitrogen/generated/android/c++/JNativeListScrollAlignment.hpp +64 -0
  138. package/nitrogen/generated/android/c++/views/JHybridNativeListStateUpdater.cpp +104 -0
  139. package/nitrogen/generated/android/c++/views/JHybridNativeListStateUpdater.hpp +54 -0
  140. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nativelist/Func_void_std__string.kt +78 -0
  141. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nativelist/HybridNativeListSpec.kt +177 -0
  142. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nativelist/NativeListScrollAlignment.kt +25 -0
  143. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nativelist/nativelistOnLoad.kt +35 -0
  144. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nativelist/views/HybridNativeListManager.kt +96 -0
  145. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nativelist/views/HybridNativeListStateUpdater.kt +23 -0
  146. package/nitrogen/generated/android/nativelist+autolinking.cmake +83 -0
  147. package/nitrogen/generated/android/nativelist+autolinking.gradle +27 -0
  148. package/nitrogen/generated/android/nativelistOnLoad.cpp +58 -0
  149. package/nitrogen/generated/android/nativelistOnLoad.hpp +34 -0
  150. package/nitrogen/generated/ios/NativeListModule+autolinking.rb +62 -0
  151. package/nitrogen/generated/ios/NativeListModule-Swift-Cxx-Bridge.cpp +41 -0
  152. package/nitrogen/generated/ios/NativeListModule-Swift-Cxx-Bridge.hpp +91 -0
  153. package/nitrogen/generated/ios/NativeListModule-Swift-Cxx-Umbrella.hpp +49 -0
  154. package/nitrogen/generated/ios/NativeListModuleAutolinking.mm +33 -0
  155. package/nitrogen/generated/ios/NativeListModuleAutolinking.swift +26 -0
  156. package/nitrogen/generated/ios/c++/HybridNativeListSpecSwift.cpp +11 -0
  157. package/nitrogen/generated/ios/c++/HybridNativeListSpecSwift.hpp +180 -0
  158. package/nitrogen/generated/ios/c++/views/HybridNativeListComponent.mm +180 -0
  159. package/nitrogen/generated/ios/swift/Func_void_std__string.swift +46 -0
  160. package/nitrogen/generated/ios/swift/HybridNativeListSpec.swift +69 -0
  161. package/nitrogen/generated/ios/swift/HybridNativeListSpec_cxx.swift +447 -0
  162. package/nitrogen/generated/ios/swift/NativeListScrollAlignment.swift +48 -0
  163. package/nitrogen/generated/shared/c++/HybridNativeListSpec.cpp +43 -0
  164. package/nitrogen/generated/shared/c++/HybridNativeListSpec.hpp +87 -0
  165. package/nitrogen/generated/shared/c++/NativeListScrollAlignment.hpp +84 -0
  166. package/nitrogen/generated/shared/c++/views/HybridNativeListComponent.cpp +46 -0
  167. package/nitrogen/generated/shared/c++/views/HybridNativeListComponent.hpp +103 -0
  168. package/nitrogen/generated/shared/json/NativeListConfig.json +16 -0
  169. package/package.json +126 -0
  170. package/react-native-native-list.podspec +38 -0
  171. package/react-native.config.js +19 -0
  172. package/src/NativeList.nitro.ts +48 -0
  173. package/src/NativeList.tsx +298 -0
  174. package/src/NativeList.types.ts +125 -0
  175. package/src/NativeList.web.tsx +258 -0
  176. package/src/index.ts +35 -0
  177. package/src/models.ts +604 -0
  178. package/src/scrolling.ts +189 -0
  179. package/src/selection.ts +159 -0
  180. package/src/validation.ts +877 -0
  181. package/src/web/NativeListWebEngine.ts +3767 -0
@@ -0,0 +1,562 @@
1
+ "use strict";
2
+
3
+ const MAX_KEY_LENGTH = 256;
4
+ const MAX_TEXT_LENGTH = 4096;
5
+ const MAX_BADGES = 2;
6
+ const MAX_TRAILING_ACCESSORIES = 2;
7
+ const MAX_FOOTER_ACTIONS = 3;
8
+ const MAX_IMAGE_EDGE = 4096;
9
+ const MAX_IMAGE_HEADERS = 32;
10
+ const MAX_HEADER_LENGTH = 4096;
11
+ const MAX_SPACER_HEIGHT = 512;
12
+ const MAX_SECTION_INDEX_TITLE_LENGTH = 8;
13
+ function fail(path, message) {
14
+ throw new Error(`NativeList ${path}: ${message}`);
15
+ }
16
+ function assertPlainSerializable(value, path, seen) {
17
+ if (value === null || value === undefined) return;
18
+ const valueType = typeof value;
19
+ if (valueType === 'string' || valueType === 'boolean') return;
20
+ if (valueType === 'number') {
21
+ if (!Number.isFinite(value)) fail(path, 'numbers must be finite');
22
+ return;
23
+ }
24
+ if (valueType !== 'object') fail(path, 'must contain only plain serializable data');
25
+ const objectValue = value;
26
+ if (seen.has(objectValue)) fail(path, 'must not contain circular references');
27
+ seen.add(objectValue);
28
+ if (Array.isArray(value)) {
29
+ value.forEach((item, index) => assertPlainSerializable(item, `${path}[${index}]`, seen));
30
+ } else {
31
+ const prototype = Object.getPrototypeOf(value);
32
+ if (prototype !== Object.prototype && prototype !== null) {
33
+ fail(path, 'must contain plain objects only');
34
+ }
35
+ Object.entries(value).forEach(([key, item]) => assertPlainSerializable(item, `${path}.${key}`, seen));
36
+ }
37
+ seen.delete(objectValue);
38
+ }
39
+ function assertKey(key, path) {
40
+ if (typeof key !== 'string' || key.length === 0 || key.length > MAX_KEY_LENGTH) {
41
+ fail(path, `must be a non-empty string no longer than ${MAX_KEY_LENGTH} characters`);
42
+ }
43
+ if (key.trim() !== key) fail(path, 'must not have leading or trailing whitespace');
44
+ }
45
+ function assertText(text, path) {
46
+ if (text === undefined) return;
47
+ if (typeof text !== 'string' || text.length > MAX_TEXT_LENGTH) {
48
+ fail(path, `must be a string no longer than ${MAX_TEXT_LENGTH} characters`);
49
+ }
50
+ }
51
+ function assertSectionIndexTitle(title, path) {
52
+ if (title === undefined) return;
53
+ if (typeof title !== 'string' || title.length === 0 || Array.from(title).length > MAX_SECTION_INDEX_TITLE_LENGTH) {
54
+ fail(path, `must be a non-empty string no longer than ${MAX_SECTION_INDEX_TITLE_LENGTH} Unicode code points`);
55
+ }
56
+ if (title.trim() !== title) {
57
+ fail(path, 'must not have leading or trailing whitespace');
58
+ }
59
+ }
60
+ function assertTextTone(tone, path) {
61
+ if (tone !== undefined && !['primary', 'secondary', 'positive', 'negative'].includes(tone)) {
62
+ fail(path, 'must be primary, secondary, positive, or negative');
63
+ }
64
+ }
65
+ function assertSectionHeaderVariant(variant, path) {
66
+ if (variant !== undefined && !['summary', 'gallery', 'history'].includes(variant)) {
67
+ fail(path, 'must be summary, gallery, or history when provided');
68
+ }
69
+ }
70
+ function assertNonNegativeNumber(value, path) {
71
+ if (value !== undefined && value < 0) {
72
+ fail(path, 'must be non-negative');
73
+ }
74
+ }
75
+ function assertVisualShape(shape, path) {
76
+ if (shape !== undefined && !['circle', 'rounded', 'square'].includes(shape)) {
77
+ fail(path, 'must be circle, rounded, or square');
78
+ }
79
+ }
80
+ function assertTrailingAccessories(accessories, path) {
81
+ accessories?.forEach((accessory, index) => {
82
+ const accessoryPath = `${path}[${index}]`;
83
+ if (accessory.kind === 'progress' && (accessory.value < 0 || accessory.value > 1)) {
84
+ fail(`${accessoryPath}.value`, 'must be within 0...1');
85
+ }
86
+ if (accessory.kind === 'valuePair') {
87
+ assertTextTone(accessory.primaryTone, `${accessoryPath}.primaryTone`);
88
+ assertTextTone(accessory.secondaryTone, `${accessoryPath}.secondaryTone`);
89
+ }
90
+ });
91
+ }
92
+ function assertImage(image, path) {
93
+ if (!image) return;
94
+ if (!image.uri.trim()) fail(`${path}.uri`, 'must not be empty');
95
+ if (!Number.isFinite(image.width) || !Number.isFinite(image.height) || image.width <= 0 || image.height <= 0 || image.width > MAX_IMAGE_EDGE || image.height > MAX_IMAGE_EDGE) {
96
+ fail(path, `width and height must be within 1...${MAX_IMAGE_EDGE}`);
97
+ }
98
+ if (image.overscan !== undefined && (image.overscan < 1 || image.overscan > 4)) {
99
+ fail(`${path}.overscan`, 'must be within 1...4');
100
+ }
101
+ if (image.headers) {
102
+ const entries = Object.entries(image.headers);
103
+ if (entries.length > MAX_IMAGE_HEADERS) {
104
+ fail(`${path}.headers`, `supports at most ${MAX_IMAGE_HEADERS} headers`);
105
+ }
106
+ entries.forEach(([key, value]) => {
107
+ if (!key.trim() || key.length > MAX_HEADER_LENGTH || typeof value !== 'string' || value.length > MAX_HEADER_LENGTH) {
108
+ fail(`${path}.headers`, `keys and values must be within 1...${MAX_HEADER_LENGTH} characters`);
109
+ }
110
+ });
111
+ }
112
+ }
113
+ function assertLeadingVisual(visual, path) {
114
+ if (!visual) return;
115
+ if (visual.kind === 'stackedImages') {
116
+ if (visual.images.length < 2 || visual.images.length > 3) {
117
+ fail(`${path}.images`, 'must contain 2 or 3 images');
118
+ }
119
+ visual.images.forEach((image, index) => assertImage(image, `${path}.images[${index}]`));
120
+ } else if (visual.kind === 'image') {
121
+ assertImage(visual.image, `${path}.image`);
122
+ assertVisualShape(visual.shape, `${path}.shape`);
123
+ } else if (visual.kind !== 'icon') {
124
+ assertImage(visual.image, `${path}.image`);
125
+ assertVisualShape(visual.shape, `${path}.shape`);
126
+ assertText(visual.cornerIcon?.name, `${path}.cornerIcon.name`);
127
+ if (visual.kind === 'token') {
128
+ assertImage(visual.networkImage, `${path}.networkImage`);
129
+ }
130
+ }
131
+ }
132
+ function assertVisual(row, path) {
133
+ const visuals = row.type === 'identity' ? [row.leading] : row.type === 'rail' ? [row.visual] : row.type === 'activity' ? [row.leading, row.secondaryLeading] : row.type === 'message' ? [row.leading] : row.type === 'dataRow' ? [row.leading] : row.type === 'metricCard' ? [row.visual] : [];
134
+ visuals.forEach((visual, index) => {
135
+ assertLeadingVisual(visual, `${path}.visual[${index}]`);
136
+ });
137
+ }
138
+ function assertActivity(row, path) {
139
+ if ((row.footerActions?.length ?? 0) > MAX_FOOTER_ACTIONS) {
140
+ fail(`${path}.footerActions`, `supports at most ${MAX_FOOTER_ACTIONS} actions`);
141
+ }
142
+ const keys = new Set();
143
+ row.footerActions?.forEach((action, index) => {
144
+ assertKey(action.key, `${path}.footerActions[${index}].key`);
145
+ if (keys.has(action.key)) fail(`${path}.footerActions`, `duplicate action key "${action.key}"`);
146
+ keys.add(action.key);
147
+ });
148
+ }
149
+ function assertWalletGroup(row, path) {
150
+ if (row.parent.key !== row.key) {
151
+ fail(`${path}.parent.key`, 'must match the wallet group key');
152
+ }
153
+ if (row.children.length === 0) {
154
+ fail(`${path}.children`, 'must contain at least one child wallet');
155
+ }
156
+ const members = [row.parent, ...row.children];
157
+ const keys = new Set();
158
+ members.forEach((member, memberIndex) => {
159
+ const memberPath = memberIndex === 0 ? `${path}.parent` : `${path}.children[${memberIndex - 1}]`;
160
+ if (member.type !== 'identity' || member.presentation !== 'walletSidebar') {
161
+ fail(memberPath, 'must be a walletSidebar identity row');
162
+ }
163
+ assertRow(member, memberIndex, memberPath);
164
+ if (keys.has(member.key)) {
165
+ fail(memberPath, `duplicate wallet member key "${member.key}"`);
166
+ }
167
+ keys.add(member.key);
168
+ });
169
+ }
170
+ function assertRow(row, index, path = `rows[${index}]`) {
171
+ assertKey(row.key, `${path}.key`);
172
+ if (row.groupId && !row.groupPosition) {
173
+ fail(`${path}.groupPosition`, 'is required when groupId is present');
174
+ }
175
+ if (!row.groupId && row.groupPosition) {
176
+ fail(`${path}.groupId`, 'is required when groupPosition is present');
177
+ }
178
+ assertVisual(row, path);
179
+ switch (row.type) {
180
+ case 'walletGroup':
181
+ assertWalletGroup(row, path);
182
+ break;
183
+ case 'identity':
184
+ if (row.presentation !== undefined && row.presentation !== 'walletSidebar' && row.presentation !== 'accountSelector' && row.presentation !== 'networkSelector') {
185
+ fail(`${path}.presentation`, 'must be walletSidebar, accountSelector, or networkSelector when provided');
186
+ }
187
+ assertText(row.title, `${path}.title`);
188
+ assertText(row.subtitle, `${path}.subtitle`);
189
+ assertText(row.tertiary, `${path}.tertiary`);
190
+ if (row.tertiaryTone !== undefined && !['secondary', 'info'].includes(row.tertiaryTone)) {
191
+ fail(`${path}.tertiaryTone`, 'must be secondary or info');
192
+ }
193
+ if ((row.badges?.length ?? 0) > MAX_BADGES) {
194
+ fail(`${path}.badges`, `supports at most ${MAX_BADGES} badges`);
195
+ }
196
+ if ((row.trailing?.length ?? 0) > MAX_TRAILING_ACCESSORIES) {
197
+ fail(`${path}.trailing`, `supports at most ${MAX_TRAILING_ACCESSORIES} accessories`);
198
+ }
199
+ assertTrailingAccessories(row.trailing, `${path}.trailing`);
200
+ assertTrailingAccessories(row.leadingAction ? [row.leadingAction] : undefined, `${path}.leadingAction`);
201
+ break;
202
+ case 'rail':
203
+ assertText(row.title, `${path}.title`);
204
+ break;
205
+ case 'activity':
206
+ assertActivity(row, path);
207
+ break;
208
+ case 'message':
209
+ assertText(row.title, `${path}.title`);
210
+ assertText(row.body, `${path}.body`);
211
+ if ((row.bodyLines ?? 3) < 1 || (row.bodyLines ?? 3) > 3) {
212
+ fail(`${path}.bodyLines`, 'must be within 1...3');
213
+ }
214
+ assertImage(row.thumbnail, `${path}.thumbnail`);
215
+ break;
216
+ case 'dataRow':
217
+ if (row.columns.length < 2 || row.columns.length > 4) {
218
+ fail(`${path}.columns`, 'must contain 2...4 columns');
219
+ }
220
+ row.columns.forEach((column, columnIndex) => {
221
+ assertKey(column.key, `${path}.columns[${columnIndex}].key`);
222
+ assertText(column.text, `${path}.columns[${columnIndex}].text`);
223
+ assertText(column.secondaryLeadingText, `${path}.columns[${columnIndex}].secondaryLeadingText`);
224
+ assertText(column.secondaryText, `${path}.columns[${columnIndex}].secondaryText`);
225
+ assertTextTone(column.secondaryTone, `${path}.columns[${columnIndex}].secondaryTone`);
226
+ });
227
+ if ((row.badges?.length ?? 0) > MAX_BADGES) {
228
+ fail(`${path}.badges`, `supports at most ${MAX_BADGES} badges`);
229
+ }
230
+ break;
231
+ case 'mediaTile':
232
+ assertImage(row.image, `${path}.image`);
233
+ if (row.imageState !== undefined && !['empty', 'error'].includes(row.imageState)) {
234
+ fail(`${path}.imageState`, 'must be empty or error when provided');
235
+ }
236
+ if (row.imageState === undefined && row.image === undefined) {
237
+ fail(`${path}.image`, 'is required unless imageState is empty or error');
238
+ }
239
+ assertImage(row.networkImage, `${path}.networkImage`);
240
+ assertText(row.title, `${path}.title`);
241
+ assertText(row.subtitle, `${path}.subtitle`);
242
+ break;
243
+ case 'metricCard':
244
+ assertText(row.title, `${path}.title`);
245
+ assertText(row.value, `${path}.value`);
246
+ assertText(row.subtitle, `${path}.subtitle`);
247
+ assertText(row.trend, `${path}.trend`);
248
+ if (row.variant !== undefined && !['standard', 'activity', 'performance'].includes(row.variant)) {
249
+ fail(`${path}.variant`, 'must be standard, activity, or performance');
250
+ }
251
+ if (row.metrics && (row.metrics.length < 2 || row.metrics.length > 5)) {
252
+ fail(`${path}.metrics`, 'must contain 2...5 metrics');
253
+ }
254
+ row.metrics?.forEach((metric, metricIndex) => {
255
+ assertKey(metric.key, `${path}.metrics[${metricIndex}].key`);
256
+ assertText(metric.label, `${path}.metrics[${metricIndex}].label`);
257
+ assertText(metric.value, `${path}.metrics[${metricIndex}].value`);
258
+ assertTextTone(metric.tone, `${path}.metrics[${metricIndex}].tone`);
259
+ assertLeadingVisual(metric.visual, `${path}.metrics[${metricIndex}].visual`);
260
+ });
261
+ if (row.progress !== undefined && (row.progress < 0 || row.progress > 1)) {
262
+ fail(`${path}.progress`, 'must be within 0...1');
263
+ }
264
+ break;
265
+ case 'sectionHeader':
266
+ assertKey(row.sectionKey, `${path}.sectionKey`);
267
+ if (row.presentation !== undefined && row.presentation !== 'networkSelector') {
268
+ fail(`${path}.presentation`, 'must be networkSelector when provided');
269
+ }
270
+ assertSectionIndexTitle(row.indexTitle, `${path}.indexTitle`);
271
+ assertSectionHeaderVariant(row.variant, `${path}.variant`);
272
+ assertText(row.title, `${path}.title`);
273
+ assertText(row.subtitle, `${path}.subtitle`);
274
+ assertText(row.value, `${path}.value`);
275
+ if (row.valueActionKey !== undefined) {
276
+ assertKey(row.valueActionKey, `${path}.valueActionKey`);
277
+ }
278
+ assertTrailingAccessories(row.titleIcon ? [row.titleIcon] : undefined, `${path}.titleIcon`);
279
+ assertTrailingAccessories(row.valueIcon ? [row.valueIcon] : undefined, `${path}.valueIcon`);
280
+ if (row.variant === 'summary' && row.checkbox !== undefined) {
281
+ fail(`${path}.checkbox`, 'is not supported by summary headers');
282
+ }
283
+ break;
284
+ case 'action':
285
+ if (row.presentation !== undefined && row.presentation !== 'accountSelector') {
286
+ fail(`${path}.presentation`, 'must be accountSelector when provided');
287
+ }
288
+ assertKey(row.actionKey, `${path}.actionKey`);
289
+ assertText(row.title, `${path}.title`);
290
+ if ((row.trailing?.length ?? 0) > MAX_TRAILING_ACCESSORIES) {
291
+ fail(`${path}.trailing`, `supports at most ${MAX_TRAILING_ACCESSORIES} accessories`);
292
+ }
293
+ assertTrailingAccessories(row.trailing, `${path}.trailing`);
294
+ break;
295
+ case 'system':
296
+ if (!['loading', 'retry', 'noMatch', 'end', 'spacer'].includes(row.variant)) {
297
+ fail(`${path}.variant`, 'must be loading, retry, noMatch, end, or spacer');
298
+ }
299
+ if (row.variant !== 'spacer') {
300
+ assertText(row.message, `${path}.message`);
301
+ }
302
+ if (row.variant === 'spacer' && (row.height < 0 || row.height > MAX_SPACER_HEIGHT)) {
303
+ fail(`${path}.height`, `must be within 0...${MAX_SPACER_HEIGHT}`);
304
+ }
305
+ if (row.variant === 'retry') {
306
+ assertKey(row.actionKey, `${path}.actionKey`);
307
+ }
308
+ break;
309
+ }
310
+ }
311
+ function assertGroups(rows) {
312
+ let index = 0;
313
+ while (index < rows.length) {
314
+ const groupId = rows[index]?.groupId;
315
+ if (!groupId) {
316
+ index += 1;
317
+ continue;
318
+ }
319
+ const start = index;
320
+ while (index < rows.length && rows[index]?.groupId === groupId) index += 1;
321
+ const group = rows.slice(start, index);
322
+ const expected = group.length === 1 ? ['single'] : group.map((_, groupIndex) => groupIndex === 0 ? 'first' : groupIndex === group.length - 1 ? 'last' : 'middle');
323
+ group.forEach((row, groupIndex) => {
324
+ if (row.groupPosition !== expected[groupIndex]) {
325
+ fail(`rows[${start + groupIndex}].groupPosition`, `must be "${expected[groupIndex]}"`);
326
+ }
327
+ });
328
+ if (rows.slice(index).some(row => row.groupId === groupId)) {
329
+ fail(`rows[${start}].groupId`, `group "${groupId}" must be contiguous`);
330
+ }
331
+ }
332
+ }
333
+ export function validateSnapshot(snapshot) {
334
+ assertPlainSerializable(snapshot, 'snapshot', new Set());
335
+ if (snapshot.schemaVersion !== 1) fail('snapshot.schemaVersion', 'must be 1');
336
+ if (!Number.isSafeInteger(snapshot.generation) || snapshot.generation < 0) {
337
+ fail('snapshot.generation', 'must be a non-negative safe integer');
338
+ }
339
+ if (snapshot.layout.kind === 'grid' && !snapshot.layout.gridColumns) {
340
+ fail('snapshot.layout.gridColumns', 'is required for grid layout');
341
+ }
342
+ assertNonNegativeNumber(snapshot.layout.contentPadding, 'snapshot.layout.contentPadding');
343
+ assertNonNegativeNumber(snapshot.layout.contentPaddingHorizontal, 'snapshot.layout.contentPaddingHorizontal');
344
+ assertNonNegativeNumber(snapshot.layout.contentPaddingTop, 'snapshot.layout.contentPaddingTop');
345
+ assertNonNegativeNumber(snapshot.layout.contentPaddingBottom, 'snapshot.layout.contentPaddingBottom');
346
+ assertNonNegativeNumber(snapshot.layout.itemSpacing, 'snapshot.layout.itemSpacing');
347
+ if (snapshot.capabilities?.endReachedThreshold !== undefined && (snapshot.capabilities.endReachedThreshold < 0 || snapshot.capabilities.endReachedThreshold > 1)) {
348
+ fail('snapshot.capabilities.endReachedThreshold', 'must be within 0...1');
349
+ }
350
+ const sectionIndex = snapshot.capabilities?.sectionIndex;
351
+ if (sectionIndex !== undefined) {
352
+ if (typeof sectionIndex.enabled !== 'boolean') {
353
+ fail('snapshot.capabilities.sectionIndex.enabled', 'must be a boolean');
354
+ }
355
+ if (sectionIndex.hapticsEnabled !== undefined && typeof sectionIndex.hapticsEnabled !== 'boolean') {
356
+ fail('snapshot.capabilities.sectionIndex.hapticsEnabled', 'must be a boolean');
357
+ }
358
+ if (sectionIndex.enabled && (snapshot.layout.kind !== 'sectioned' || snapshot.layout.orientation === 'horizontal')) {
359
+ fail('snapshot.capabilities.sectionIndex', 'requires a vertical sectioned layout');
360
+ }
361
+ }
362
+ const rowKeys = new Set();
363
+ const sectionIndexTitles = new Set();
364
+ snapshot.rows.forEach((row, index) => {
365
+ assertRow(row, index);
366
+ if (rowKeys.has(row.key)) fail(`rows[${index}].key`, `duplicate key "${row.key}"`);
367
+ rowKeys.add(row.key);
368
+ if (row.type === 'sectionHeader' && row.indexTitle !== undefined) {
369
+ const normalizedTitle = row.indexTitle.normalize('NFC');
370
+ if (sectionIndexTitles.has(normalizedTitle)) {
371
+ fail(`rows[${index}].indexTitle`, `duplicate index title "${row.indexTitle}"`);
372
+ }
373
+ sectionIndexTitles.add(normalizedTitle);
374
+ }
375
+ });
376
+ if (snapshot.emptyState) assertRow(snapshot.emptyState, 0, 'emptyState');
377
+ if (snapshot.fixedFooter) assertRow(snapshot.fixedFooter, 0, 'fixedFooter');
378
+ assertGroups(snapshot.rows);
379
+ const selectedKeys = new Set();
380
+ snapshot.selection?.selectedKeys.forEach((key, index) => {
381
+ assertKey(key, `snapshot.selection.selectedKeys[${index}]`);
382
+ if (!rowKeys.has(key)) fail('snapshot.selection.selectedKeys', `unknown row key "${key}"`);
383
+ const selectedRow = snapshot.rows.find(row => row.key === key);
384
+ if (selectedRow?.disabled || selectedRow?.type === 'sectionHeader' || selectedRow?.type === 'action' || selectedRow?.type === 'system') {
385
+ fail('snapshot.selection.selectedKeys', `row "${key}" is not selectable`);
386
+ }
387
+ if (selectedKeys.has(key)) fail('snapshot.selection.selectedKeys', `duplicate key "${key}"`);
388
+ selectedKeys.add(key);
389
+ });
390
+ if (snapshot.selection?.mode === 'none' && selectedKeys.size > 0) {
391
+ fail('snapshot.selection.selectedKeys', 'must be empty when selection mode is none');
392
+ }
393
+ if (snapshot.selection?.mode === 'single' && selectedKeys.size > 1) {
394
+ fail('snapshot.selection.selectedKeys', 'supports at most one key in single mode');
395
+ }
396
+ return snapshot;
397
+ }
398
+ function assertPatchChanges(patch, index) {
399
+ const path = `patches[${index}].changes`;
400
+ if (patch.changes.revision !== undefined && (!Number.isSafeInteger(patch.changes.revision) || patch.changes.revision < 0)) {
401
+ fail(`${path}.revision`, 'must be a non-negative safe integer');
402
+ }
403
+ switch (patch.type) {
404
+ case 'identity':
405
+ assertText(patch.changes.title, `${path}.title`);
406
+ assertText(patch.changes.subtitle, `${path}.subtitle`);
407
+ assertText(patch.changes.tertiary, `${path}.tertiary`);
408
+ if (patch.changes.tertiaryTone !== undefined && !['secondary', 'info'].includes(patch.changes.tertiaryTone)) {
409
+ fail(`${path}.tertiaryTone`, 'must be secondary or info');
410
+ }
411
+ assertLeadingVisual(patch.changes.leading, `${path}.leading`);
412
+ assertTrailingAccessories(patch.changes.leadingAction ? [patch.changes.leadingAction] : undefined, `${path}.leadingAction`);
413
+ if ((patch.changes.badges?.length ?? 0) > MAX_BADGES) {
414
+ fail(`${path}.badges`, `supports at most ${MAX_BADGES} badges`);
415
+ }
416
+ if ((patch.changes.trailing?.length ?? 0) > MAX_TRAILING_ACCESSORIES) {
417
+ fail(`${path}.trailing`, `supports at most ${MAX_TRAILING_ACCESSORIES} accessories`);
418
+ }
419
+ assertTrailingAccessories(patch.changes.trailing, `${path}.trailing`);
420
+ break;
421
+ case 'rail':
422
+ assertText(patch.changes.title, `${path}.title`);
423
+ assertLeadingVisual(patch.changes.visual, `${path}.visual`);
424
+ break;
425
+ case 'activity':
426
+ assertText(patch.changes.title, `${path}.title`);
427
+ assertText(patch.changes.description, `${path}.description`);
428
+ assertText(patch.changes.status, `${path}.status`);
429
+ assertText(patch.changes.primaryAmount, `${path}.primaryAmount`);
430
+ assertText(patch.changes.secondaryAmount, `${path}.secondaryAmount`);
431
+ assertLeadingVisual(patch.changes.leading, `${path}.leading`);
432
+ assertLeadingVisual(patch.changes.secondaryLeading, `${path}.secondaryLeading`);
433
+ if ((patch.changes.footerActions?.length ?? 0) > MAX_FOOTER_ACTIONS) {
434
+ fail(`${path}.footerActions`, `supports at most ${MAX_FOOTER_ACTIONS} actions`);
435
+ }
436
+ break;
437
+ case 'message':
438
+ assertText(patch.changes.title, `${path}.title`);
439
+ assertText(patch.changes.body, `${path}.body`);
440
+ assertText(patch.changes.time, `${path}.time`);
441
+ if (patch.changes.bodyLines !== undefined && (patch.changes.bodyLines < 1 || patch.changes.bodyLines > 3)) {
442
+ fail(`${path}.bodyLines`, 'must be within 1...3');
443
+ }
444
+ assertImage(patch.changes.thumbnail, `${path}.thumbnail`);
445
+ break;
446
+ case 'dataRow':
447
+ if (patch.changes.columns && (patch.changes.columns.length < 2 || patch.changes.columns.length > 4)) {
448
+ fail(`${path}.columns`, 'must contain 2...4 columns');
449
+ }
450
+ patch.changes.columns?.forEach((column, columnIndex) => {
451
+ assertKey(column.key, `${path}.columns[${columnIndex}].key`);
452
+ assertText(column.text, `${path}.columns[${columnIndex}].text`);
453
+ assertText(column.secondaryText, `${path}.columns[${columnIndex}].secondaryText`);
454
+ assertTextTone(column.secondaryTone, `${path}.columns[${columnIndex}].secondaryTone`);
455
+ });
456
+ if ((patch.changes.badges?.length ?? 0) > MAX_BADGES) {
457
+ fail(`${path}.badges`, `supports at most ${MAX_BADGES} badges`);
458
+ }
459
+ break;
460
+ case 'mediaTile':
461
+ assertImage(patch.changes.image, `${path}.image`);
462
+ if (patch.changes.imageState !== undefined && !['empty', 'error'].includes(patch.changes.imageState)) {
463
+ fail(`${path}.imageState`, 'must be empty or error when provided');
464
+ }
465
+ assertImage(patch.changes.networkImage, `${path}.networkImage`);
466
+ assertText(patch.changes.title, `${path}.title`);
467
+ assertText(patch.changes.subtitle, `${path}.subtitle`);
468
+ break;
469
+ case 'metricCard':
470
+ assertText(patch.changes.title, `${path}.title`);
471
+ assertText(patch.changes.value, `${path}.value`);
472
+ assertText(patch.changes.subtitle, `${path}.subtitle`);
473
+ assertText(patch.changes.trend, `${path}.trend`);
474
+ assertLeadingVisual(patch.changes.visual, `${path}.visual`);
475
+ if (patch.changes.variant !== undefined && !['standard', 'activity', 'performance'].includes(patch.changes.variant)) {
476
+ fail(`${path}.variant`, 'must be standard, activity, or performance');
477
+ }
478
+ if (patch.changes.metrics && (patch.changes.metrics.length < 2 || patch.changes.metrics.length > 5)) {
479
+ fail(`${path}.metrics`, 'must contain 2...5 metrics');
480
+ }
481
+ patch.changes.metrics?.forEach((metric, metricIndex) => {
482
+ assertKey(metric.key, `${path}.metrics[${metricIndex}].key`);
483
+ assertText(metric.label, `${path}.metrics[${metricIndex}].label`);
484
+ assertText(metric.value, `${path}.metrics[${metricIndex}].value`);
485
+ assertTextTone(metric.tone, `${path}.metrics[${metricIndex}].tone`);
486
+ assertLeadingVisual(metric.visual, `${path}.metrics[${metricIndex}].visual`);
487
+ });
488
+ if (patch.changes.progress !== undefined && (patch.changes.progress < 0 || patch.changes.progress > 1)) {
489
+ fail(`${path}.progress`, 'must be within 0...1');
490
+ }
491
+ break;
492
+ case 'sectionHeader':
493
+ assertSectionHeaderVariant(patch.changes.variant, `${path}.variant`);
494
+ assertText(patch.changes.title, `${path}.title`);
495
+ assertText(patch.changes.subtitle, `${path}.subtitle`);
496
+ assertText(patch.changes.value, `${path}.value`);
497
+ if (patch.changes.valueActionKey !== undefined) {
498
+ assertKey(patch.changes.valueActionKey, `${path}.valueActionKey`);
499
+ }
500
+ assertTrailingAccessories(patch.changes.titleIcon ? [patch.changes.titleIcon] : undefined, `${path}.titleIcon`);
501
+ assertTrailingAccessories(patch.changes.valueIcon ? [patch.changes.valueIcon] : undefined, `${path}.valueIcon`);
502
+ break;
503
+ case 'action':
504
+ assertText(patch.changes.title, `${path}.title`);
505
+ if ((patch.changes.trailing?.length ?? 0) > MAX_TRAILING_ACCESSORIES) {
506
+ fail(`${path}.trailing`, `supports at most ${MAX_TRAILING_ACCESSORIES} accessories`);
507
+ }
508
+ assertTrailingAccessories(patch.changes.trailing, `${path}.trailing`);
509
+ break;
510
+ case 'system':
511
+ assertText(patch.changes.message, `${path}.message`);
512
+ break;
513
+ default:
514
+ fail(`patches[${index}].type`, 'is not supported');
515
+ }
516
+ }
517
+ export function validatePatches(patches) {
518
+ assertPlainSerializable(patches, 'patches', new Set());
519
+ const keys = new Set();
520
+ patches.forEach((patch, index) => {
521
+ assertKey(patch.key, `patches[${index}].key`);
522
+ if (keys.has(patch.key)) fail(`patches[${index}].key`, `duplicate key "${patch.key}"`);
523
+ keys.add(patch.key);
524
+ if (Object.keys(patch.changes).length === 0) {
525
+ fail(`patches[${index}].changes`, 'must contain at least one field');
526
+ }
527
+ assertPatchChanges(patch, index);
528
+ });
529
+ return patches;
530
+ }
531
+ export function applyRowPatches(snapshot, patches) {
532
+ validatePatches(patches);
533
+ const patchByKey = new Map(patches.map(patch => [patch.key, patch]));
534
+ const knownKeys = new Set(snapshot.rows.map(row => row.key));
535
+ patches.forEach(patch => {
536
+ if (!knownKeys.has(patch.key)) fail('patches', `unknown row key "${patch.key}"`);
537
+ });
538
+ const rows = snapshot.rows.map(row => {
539
+ const patch = patchByKey.get(row.key);
540
+ if (!patch) return row;
541
+ if (patch.type !== row.type) {
542
+ fail('patches', `row "${row.key}" is ${row.type}, not ${patch.type}`);
543
+ }
544
+ return {
545
+ ...row,
546
+ ...patch.changes,
547
+ key: row.key,
548
+ type: row.type
549
+ };
550
+ });
551
+ return validateSnapshot({
552
+ ...snapshot,
553
+ rows
554
+ });
555
+ }
556
+ export function serializeSnapshot(snapshot) {
557
+ return JSON.stringify(validateSnapshot(snapshot));
558
+ }
559
+ export function serializePatches(patches) {
560
+ return JSON.stringify(validatePatches(patches));
561
+ }
562
+ //# sourceMappingURL=validation.js.map