vastgrid 0.1.1 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (312) hide show
  1. package/README.md +175 -13
  2. package/dist/canvas/geometry.d.ts +92 -0
  3. package/dist/canvas/geometry.d.ts.map +1 -0
  4. package/dist/canvas/geometry.js +197 -0
  5. package/dist/canvas/geometry.js.map +1 -0
  6. package/dist/canvas/grid-canvas.d.ts +161 -0
  7. package/dist/canvas/grid-canvas.d.ts.map +1 -0
  8. package/dist/canvas/grid-canvas.js +1146 -0
  9. package/dist/canvas/grid-canvas.js.map +1 -0
  10. package/dist/canvas/hooks.d.ts +61 -0
  11. package/dist/canvas/hooks.d.ts.map +1 -0
  12. package/dist/canvas/hooks.js +2 -0
  13. package/dist/canvas/hooks.js.map +1 -0
  14. package/dist/canvas/keys.d.ts +26 -0
  15. package/dist/canvas/keys.d.ts.map +1 -0
  16. package/dist/canvas/keys.js +133 -0
  17. package/dist/canvas/keys.js.map +1 -0
  18. package/dist/canvas/layout.d.ts +26 -0
  19. package/dist/canvas/layout.d.ts.map +1 -0
  20. package/dist/canvas/layout.js +73 -0
  21. package/dist/canvas/layout.js.map +1 -0
  22. package/dist/canvas/scroll.d.ts +31 -0
  23. package/dist/canvas/scroll.d.ts.map +1 -0
  24. package/dist/canvas/scroll.js +111 -0
  25. package/dist/canvas/scroll.js.map +1 -0
  26. package/dist/canvas/text.d.ts +23 -0
  27. package/dist/canvas/text.d.ts.map +1 -0
  28. package/dist/canvas/text.js +142 -0
  29. package/dist/canvas/text.js.map +1 -0
  30. package/dist/{theme.d.ts → canvas/theme.d.ts} +8 -0
  31. package/dist/canvas/theme.d.ts.map +1 -0
  32. package/dist/canvas/theme.js +62 -0
  33. package/dist/canvas/theme.js.map +1 -0
  34. package/dist/core/cache.d.ts +48 -0
  35. package/dist/core/cache.d.ts.map +1 -0
  36. package/dist/core/cache.js +222 -0
  37. package/dist/core/cache.js.map +1 -0
  38. package/dist/core/checked.d.ts +20 -0
  39. package/dist/core/checked.d.ts.map +1 -0
  40. package/dist/core/checked.js +61 -0
  41. package/dist/core/checked.js.map +1 -0
  42. package/dist/core/client.d.ts +33 -0
  43. package/dist/core/client.d.ts.map +1 -0
  44. package/dist/core/client.js +103 -0
  45. package/dist/core/client.js.map +1 -0
  46. package/dist/core/conditions.d.ts +48 -0
  47. package/dist/core/conditions.d.ts.map +1 -0
  48. package/dist/core/conditions.js +105 -0
  49. package/dist/core/conditions.js.map +1 -0
  50. package/dist/core/evaluate.d.ts +20 -0
  51. package/dist/core/evaluate.d.ts.map +1 -0
  52. package/dist/core/evaluate.js +210 -0
  53. package/dist/core/evaluate.js.map +1 -0
  54. package/dist/core/filters.d.ts +51 -0
  55. package/dist/core/filters.d.ts.map +1 -0
  56. package/dist/core/filters.js +303 -0
  57. package/dist/core/filters.js.map +1 -0
  58. package/dist/core/format.d.ts +14 -0
  59. package/dist/core/format.d.ts.map +1 -0
  60. package/dist/core/format.js +303 -0
  61. package/dist/core/format.js.map +1 -0
  62. package/dist/core/measures.d.ts +26 -0
  63. package/dist/core/measures.d.ts.map +1 -0
  64. package/dist/core/measures.js +105 -0
  65. package/dist/core/measures.js.map +1 -0
  66. package/dist/core/request-ids.d.ts +20 -0
  67. package/dist/core/request-ids.d.ts.map +1 -0
  68. package/dist/core/request-ids.js +55 -0
  69. package/dist/core/request-ids.js.map +1 -0
  70. package/dist/core/rows.d.ts +79 -0
  71. package/dist/core/rows.d.ts.map +1 -0
  72. package/dist/core/rows.js +173 -0
  73. package/dist/core/rows.js.map +1 -0
  74. package/dist/core/store.d.ts +233 -0
  75. package/dist/core/store.d.ts.map +1 -0
  76. package/dist/core/store.js +1162 -0
  77. package/dist/core/store.js.map +1 -0
  78. package/dist/core/totals.d.ts +24 -0
  79. package/dist/core/totals.d.ts.map +1 -0
  80. package/dist/core/totals.js +49 -0
  81. package/dist/core/totals.js.map +1 -0
  82. package/dist/core/trace.d.ts +7 -0
  83. package/dist/core/trace.d.ts.map +1 -0
  84. package/dist/core/trace.js +26 -0
  85. package/dist/core/trace.js.map +1 -0
  86. package/dist/core/transports.d.ts +50 -0
  87. package/dist/core/transports.d.ts.map +1 -0
  88. package/dist/core/transports.js +160 -0
  89. package/dist/core/transports.js.map +1 -0
  90. package/dist/core/types.d.ts +150 -0
  91. package/dist/core/types.d.ts.map +1 -0
  92. package/dist/core/types.js +45 -0
  93. package/dist/core/types.js.map +1 -0
  94. package/dist/core.d.ts +12 -0
  95. package/dist/core.d.ts.map +1 -0
  96. package/dist/core.js +11 -0
  97. package/dist/core.js.map +1 -0
  98. package/dist/index.d.ts +15 -6
  99. package/dist/index.d.ts.map +1 -1
  100. package/dist/index.js +13 -7
  101. package/dist/index.js.map +1 -1
  102. package/dist/react/accessible-rows.d.ts +13 -0
  103. package/dist/react/accessible-rows.d.ts.map +1 -0
  104. package/dist/react/accessible-rows.js +320 -0
  105. package/dist/react/accessible-rows.js.map +1 -0
  106. package/dist/react/cell-editor.d.ts +22 -0
  107. package/dist/react/cell-editor.d.ts.map +1 -0
  108. package/dist/react/cell-editor.js +431 -0
  109. package/dist/react/cell-editor.js.map +1 -0
  110. package/dist/react/cell-menu.d.ts +18 -0
  111. package/dist/react/cell-menu.d.ts.map +1 -0
  112. package/dist/react/cell-menu.js +299 -0
  113. package/dist/react/cell-menu.js.map +1 -0
  114. package/dist/react/column-menu.d.ts +16 -0
  115. package/dist/react/column-menu.d.ts.map +1 -0
  116. package/dist/react/column-menu.js +1311 -0
  117. package/dist/react/column-menu.js.map +1 -0
  118. package/dist/react/columns-menu.d.ts +7 -0
  119. package/dist/react/columns-menu.d.ts.map +1 -0
  120. package/dist/react/columns-menu.js +249 -0
  121. package/dist/react/columns-menu.js.map +1 -0
  122. package/dist/react/conditions-menu.d.ts +10 -0
  123. package/dist/react/conditions-menu.d.ts.map +1 -0
  124. package/dist/react/conditions-menu.js +795 -0
  125. package/dist/react/conditions-menu.js.map +1 -0
  126. package/dist/react/context.d.ts +29 -0
  127. package/dist/react/context.d.ts.map +1 -0
  128. package/dist/react/context.js +18 -0
  129. package/dist/react/context.js.map +1 -0
  130. package/dist/react/data-grid.d.ts +79 -0
  131. package/dist/react/data-grid.d.ts.map +1 -0
  132. package/dist/react/data-grid.js +653 -0
  133. package/dist/react/data-grid.js.map +1 -0
  134. package/dist/react/detail-panel.d.ts +22 -0
  135. package/dist/react/detail-panel.d.ts.map +1 -0
  136. package/dist/react/detail-panel.js +242 -0
  137. package/dist/react/detail-panel.js.map +1 -0
  138. package/dist/react/export-menu.d.ts +11 -0
  139. package/dist/react/export-menu.d.ts.map +1 -0
  140. package/dist/react/export-menu.js +304 -0
  141. package/dist/react/export-menu.js.map +1 -0
  142. package/dist/react/find-bar.d.ts +11 -0
  143. package/dist/react/find-bar.d.ts.map +1 -0
  144. package/dist/react/find-bar.js +303 -0
  145. package/dist/react/find-bar.js.map +1 -0
  146. package/dist/react/format-form.d.ts +12 -0
  147. package/dist/react/format-form.d.ts.map +1 -0
  148. package/dist/react/format-form.js +863 -0
  149. package/dist/react/format-form.js.map +1 -0
  150. package/dist/react/formula-menu.d.ts +6 -0
  151. package/dist/react/formula-menu.d.ts.map +1 -0
  152. package/dist/react/formula-menu.js +343 -0
  153. package/dist/react/formula-menu.js.map +1 -0
  154. package/dist/react/grid-body.d.ts +33 -0
  155. package/dist/react/grid-body.d.ts.map +1 -0
  156. package/dist/react/grid-body.js +1389 -0
  157. package/dist/react/grid-body.js.map +1 -0
  158. package/dist/react/group-menu.d.ts +7 -0
  159. package/dist/react/group-menu.d.ts.map +1 -0
  160. package/dist/react/group-menu.js +508 -0
  161. package/dist/react/group-menu.js.map +1 -0
  162. package/dist/react/hooks.d.ts +33 -0
  163. package/dist/react/hooks.d.ts.map +1 -0
  164. package/dist/react/hooks.js +161 -0
  165. package/dist/react/hooks.js.map +1 -0
  166. package/dist/react/messages.d.ts +180 -0
  167. package/dist/react/messages.d.ts.map +1 -0
  168. package/dist/react/messages.js +414 -0
  169. package/dist/react/messages.js.map +1 -0
  170. package/dist/react/save.d.ts +9 -0
  171. package/dist/react/save.d.ts.map +1 -0
  172. package/dist/react/save.js +102 -0
  173. package/dist/react/save.js.map +1 -0
  174. package/dist/react/static-rows.d.ts +9 -0
  175. package/dist/react/static-rows.d.ts.map +1 -0
  176. package/dist/react/static-rows.js +176 -0
  177. package/dist/react/static-rows.js.map +1 -0
  178. package/dist/react/status-bar.d.ts +12 -0
  179. package/dist/react/status-bar.d.ts.map +1 -0
  180. package/dist/react/status-bar.js +413 -0
  181. package/dist/react/status-bar.js.map +1 -0
  182. package/dist/react/toolbar-popover.d.ts +14 -0
  183. package/dist/react/toolbar-popover.d.ts.map +1 -0
  184. package/dist/react/toolbar-popover.js +143 -0
  185. package/dist/react/toolbar-popover.js.map +1 -0
  186. package/dist/react/toolbar.d.ts +13 -0
  187. package/dist/react/toolbar.d.ts.map +1 -0
  188. package/dist/react/toolbar.js +344 -0
  189. package/dist/react/toolbar.js.map +1 -0
  190. package/dist/server.d.ts +22 -0
  191. package/dist/server.d.ts.map +1 -0
  192. package/dist/server.js +45 -0
  193. package/dist/server.js.map +1 -0
  194. package/dist/styles.css +496 -316
  195. package/package.json +42 -17
  196. package/src/canvas/geometry.ts +197 -0
  197. package/src/canvas/grid-canvas.ts +1222 -0
  198. package/src/canvas/hooks.ts +61 -0
  199. package/src/canvas/keys.ts +96 -0
  200. package/src/canvas/layout.ts +77 -0
  201. package/src/canvas/scroll.ts +120 -0
  202. package/src/canvas/text.ts +155 -0
  203. package/src/{theme.ts → canvas/theme.ts} +14 -1
  204. package/src/core/cache.ts +247 -0
  205. package/src/core/checked.ts +64 -0
  206. package/src/core/client.ts +103 -0
  207. package/src/core/conditions.ts +89 -0
  208. package/src/core/evaluate.ts +221 -0
  209. package/src/core/filters.ts +268 -0
  210. package/src/core/format.ts +309 -0
  211. package/src/core/measures.ts +99 -0
  212. package/src/core/request-ids.ts +54 -0
  213. package/src/core/rows.ts +213 -0
  214. package/src/core/store.ts +1122 -0
  215. package/src/core/totals.ts +59 -0
  216. package/src/core/trace.ts +44 -0
  217. package/src/core/transports.ts +177 -0
  218. package/src/core/types.ts +168 -0
  219. package/src/core.ts +39 -0
  220. package/src/index.ts +24 -12
  221. package/src/react/accessible-rows.tsx +242 -0
  222. package/src/react/cell-editor.tsx +216 -0
  223. package/src/react/cell-menu.tsx +166 -0
  224. package/src/react/column-menu.tsx +619 -0
  225. package/src/react/columns-menu.tsx +116 -0
  226. package/src/react/conditions-menu.tsx +289 -0
  227. package/src/react/context.ts +33 -0
  228. package/src/react/data-grid.tsx +286 -0
  229. package/src/react/detail-panel.tsx +92 -0
  230. package/src/react/export-menu.tsx +112 -0
  231. package/src/react/find-bar.tsx +112 -0
  232. package/src/react/format-form.tsx +421 -0
  233. package/src/react/formula-menu.tsx +163 -0
  234. package/src/react/grid-body.tsx +744 -0
  235. package/src/react/group-menu.tsx +214 -0
  236. package/src/react/hooks.ts +104 -0
  237. package/src/react/messages.ts +556 -0
  238. package/src/react/save.ts +42 -0
  239. package/src/react/static-rows.tsx +59 -0
  240. package/src/react/status-bar.tsx +175 -0
  241. package/src/react/toolbar-popover.tsx +69 -0
  242. package/src/react/toolbar.tsx +152 -0
  243. package/src/server.ts +58 -0
  244. package/src/styles.css +496 -316
  245. package/dist/components/bars.d.ts +0 -14
  246. package/dist/components/bars.d.ts.map +0 -1
  247. package/dist/components/bars.js +0 -68
  248. package/dist/components/bars.js.map +0 -1
  249. package/dist/components/cell-inspector.d.ts +0 -11
  250. package/dist/components/cell-inspector.d.ts.map +0 -1
  251. package/dist/components/cell-inspector.js +0 -37
  252. package/dist/components/cell-inspector.js.map +0 -1
  253. package/dist/components/columns-panel.d.ts +0 -12
  254. package/dist/components/columns-panel.d.ts.map +0 -1
  255. package/dist/components/columns-panel.js +0 -11
  256. package/dist/components/columns-panel.js.map +0 -1
  257. package/dist/components/filter-panel.d.ts +0 -22
  258. package/dist/components/filter-panel.d.ts.map +0 -1
  259. package/dist/components/filter-panel.js +0 -169
  260. package/dist/components/filter-panel.js.map +0 -1
  261. package/dist/components/find-bar.d.ts +0 -9
  262. package/dist/components/find-bar.d.ts.map +0 -1
  263. package/dist/components/find-bar.js +0 -46
  264. package/dist/components/find-bar.js.map +0 -1
  265. package/dist/components/popover.d.ts +0 -38
  266. package/dist/components/popover.d.ts.map +0 -1
  267. package/dist/components/popover.js +0 -104
  268. package/dist/components/popover.js.map +0 -1
  269. package/dist/components/stats-panel.d.ts +0 -12
  270. package/dist/components/stats-panel.d.ts.map +0 -1
  271. package/dist/components/stats-panel.js +0 -40
  272. package/dist/components/stats-panel.js.map +0 -1
  273. package/dist/controller.d.ts +0 -227
  274. package/dist/controller.d.ts.map +0 -1
  275. package/dist/controller.js +0 -845
  276. package/dist/controller.js.map +0 -1
  277. package/dist/data-grid.d.ts +0 -51
  278. package/dist/data-grid.d.ts.map +0 -1
  279. package/dist/data-grid.js +0 -704
  280. package/dist/data-grid.js.map +0 -1
  281. package/dist/labels.d.ts +0 -9
  282. package/dist/labels.d.ts.map +0 -1
  283. package/dist/labels.js +0 -38
  284. package/dist/labels.js.map +0 -1
  285. package/dist/messages.d.ts +0 -99
  286. package/dist/messages.d.ts.map +0 -1
  287. package/dist/messages.js +0 -276
  288. package/dist/messages.js.map +0 -1
  289. package/dist/renderer.d.ts +0 -52
  290. package/dist/renderer.d.ts.map +0 -1
  291. package/dist/renderer.js +0 -522
  292. package/dist/renderer.js.map +0 -1
  293. package/dist/text.d.ts +0 -14
  294. package/dist/text.d.ts.map +0 -1
  295. package/dist/text.js +0 -63
  296. package/dist/text.js.map +0 -1
  297. package/dist/theme.d.ts.map +0 -1
  298. package/dist/theme.js +0 -54
  299. package/dist/theme.js.map +0 -1
  300. package/src/components/bars.tsx +0 -180
  301. package/src/components/cell-inspector.tsx +0 -70
  302. package/src/components/columns-panel.tsx +0 -59
  303. package/src/components/filter-panel.tsx +0 -293
  304. package/src/components/find-bar.tsx +0 -104
  305. package/src/components/popover.tsx +0 -194
  306. package/src/components/stats-panel.tsx +0 -153
  307. package/src/controller.ts +0 -945
  308. package/src/data-grid.tsx +0 -1035
  309. package/src/labels.ts +0 -46
  310. package/src/messages.ts +0 -390
  311. package/src/renderer.ts +0 -535
  312. package/src/text.ts +0 -55
@@ -0,0 +1,222 @@
1
+ /** Rows in a block of the cache: reads cover whole blocks. */
2
+ export const BLOCK_ROWS = 256;
3
+
4
+ /** A read of rows `[start, end)` of a view, for some of its columns. */
5
+
6
+ /** Rows of a view that the engine gave, by column. */
7
+
8
+ /** Bytes that a value takes in the cache, roughly. */
9
+ function sizeOf(value) {
10
+ if (typeof value === "string") return 16 + value.length * 2;
11
+ return 8;
12
+ }
13
+
14
+ /**
15
+ * The rows of one view that the store has read, in blocks of `BLOCK_ROWS` rows, with a budget of bytes beyond
16
+ * which the blocks used least recently leave (§4.1 of react.md: rows are not in snapshots).
17
+ */
18
+ export class ViewCache {
19
+ blocks = new Map();
20
+ clock = 0;
21
+ /** Bytes the blocks take, roughly. */
22
+ bytes = 0;
23
+ /** Changes whenever rows arrive or leave. */
24
+ version = 0;
25
+ block(row) {
26
+ return this.blocks.get(Math.floor(row / BLOCK_ROWS));
27
+ }
28
+ ensure(index) {
29
+ let block = this.blocks.get(index);
30
+ if (!block) {
31
+ block = {
32
+ index,
33
+ length: 0,
34
+ rowIds: undefined,
35
+ values: new Map(),
36
+ cut: new Map(),
37
+ reading: new Set(),
38
+ used: 0,
39
+ bytes: 0
40
+ };
41
+ this.blocks.set(index, block);
42
+ }
43
+ return block;
44
+ }
45
+
46
+ /** The value of a cell; undefined while it is not read. */
47
+ value(row, column) {
48
+ const block = this.block(row);
49
+ const offset = row - (block?.index ?? 0) * BLOCK_ROWS;
50
+ if (!block || offset >= block.length) return undefined;
51
+ return block.values.get(column)?.[offset];
52
+ }
53
+
54
+ /** Whether the engine cut the value of a cell to the text limit, so that the grid shows that it goes on. */
55
+ isCut(row, column) {
56
+ const block = this.block(row);
57
+ return block?.cut.get(column)?.has(row - block.index * BLOCK_ROWS) ?? false;
58
+ }
59
+
60
+ /** The row ID of a row; undefined while it is not read or in a view without row IDs. */
61
+ rowId(row) {
62
+ const block = this.block(row);
63
+ if (!block?.rowIds) return undefined;
64
+ return block.rowIds[row - block.index * BLOCK_ROWS];
65
+ }
66
+
67
+ /** A row as commands read it (§6.1): its key and its values, or undefined while it is not read. */
68
+ loaded(row, rowKey) {
69
+ const block = this.block(row);
70
+ const offset = row - (block?.index ?? 0) * BLOCK_ROWS;
71
+ if (!block || block.rowIds === undefined || offset >= block.length) return undefined;
72
+ let key;
73
+ const id = block.rowIds?.[offset];
74
+ if (id !== undefined) {
75
+ if (rowKey === undefined) key = {
76
+ rowId: id
77
+ };else {
78
+ // A row whose key column is null is keyed by its row ID (§5.3).
79
+ const value = block.values.get(rowKey)?.[offset];
80
+ if (value !== undefined) key = value === null ? {
81
+ rowId: id
82
+ } : {
83
+ value
84
+ };
85
+ }
86
+ }
87
+ const values = block.values;
88
+ return {
89
+ ...(key === undefined ? {} : {
90
+ key
91
+ }),
92
+ has: column => values.has(column),
93
+ get: column => values.get(column)?.[offset] ?? null
94
+ };
95
+ }
96
+
97
+ /**
98
+ * What to read so that rows `[start, end)` have `columns`: reads of runs of blocks that lack the same columns,
99
+ * each of at most `maxCells` cells, leaving out what is read or being read.
100
+ */
101
+ reads(start, end, columns, rowCount, maxCells = 262_144) {
102
+ const reads = [];
103
+ if (end <= start || columns.length === 0) return reads;
104
+ const last = Math.floor((Math.min(end, rowCount) - 1) / BLOCK_ROWS);
105
+ let run = null;
106
+ const flush = () => {
107
+ if (!run) return;
108
+ reads.push({
109
+ start: run.first * BLOCK_ROWS,
110
+ end: Math.min((run.last + 1) * BLOCK_ROWS, rowCount),
111
+ columns: run.columns
112
+ });
113
+ run = null;
114
+ };
115
+ for (let index = Math.floor(start / BLOCK_ROWS); index <= last; index++) {
116
+ const block = this.blocks.get(index);
117
+ // A block read while the view was shorter (a table or view still being made, §9) is read again whole.
118
+ const short = block !== undefined && block.rowIds !== undefined && block.length < Math.min(BLOCK_ROWS, rowCount - index * BLOCK_ROWS);
119
+ const missing = block && !short ? columns.filter(column => !block.values.has(column) && !block.reading.has(column)) : columns.filter(column => !block?.reading.has(column));
120
+ if (missing.length === 0) {
121
+ flush();
122
+ continue;
123
+ }
124
+ const key = missing.join("\u0000");
125
+ const blocks = Math.max(1, Math.floor(maxCells / (missing.length * BLOCK_ROWS)));
126
+ if (run && run.key === key && index === run.last + 1 && run.last - run.first + 1 < blocks) {
127
+ run.last = index;
128
+ } else {
129
+ flush();
130
+ run = {
131
+ first: index,
132
+ last: index,
133
+ columns: missing,
134
+ key
135
+ };
136
+ }
137
+ }
138
+ flush();
139
+ return reads;
140
+ }
141
+
142
+ /** Marks the columns of a read as being read, or no longer. */
143
+ reading(read, on) {
144
+ for (let index = Math.floor(read.start / BLOCK_ROWS); index * BLOCK_ROWS < read.end; index++) {
145
+ const block = this.ensure(index);
146
+ for (const column of read.columns) {
147
+ if (on) block.reading.add(column);else block.reading.delete(column);
148
+ }
149
+ }
150
+ }
151
+
152
+ /**
153
+ * Takes the rows of a read, which starts at a block: `rows` holds the values of `columns` for rows `start` to
154
+ * `start + rows.length`.
155
+ */
156
+ receive(start, rowIds, columns, rows, cut) {
157
+ const end = start + rows.length;
158
+ for (let index = Math.floor(start / BLOCK_ROWS); index * BLOCK_ROWS < end; index++) {
159
+ const block = this.ensure(index);
160
+ const before = block.bytes;
161
+ const first = Math.max(start, index * BLOCK_ROWS);
162
+ const stop = Math.min(end, (index + 1) * BLOCK_ROWS);
163
+ block.length = Math.max(block.length, stop - index * BLOCK_ROWS);
164
+ // A view that is still being made may have more rows in its last block at a later read (§9).
165
+ const ids = rowIds === null ? null : rowIds.slice(first - start, stop - start);
166
+ if (block.rowIds === undefined || ids !== null && block.rowIds !== null && ids.length > block.rowIds.length) {
167
+ block.rowIds = ids;
168
+ }
169
+ columns.forEach((column, position) => {
170
+ let values = block.values.get(column);
171
+ if (!values) {
172
+ values = new Array(BLOCK_ROWS);
173
+ block.values.set(column, values);
174
+ }
175
+ for (let row = first; row < stop; row++) {
176
+ const value = rows[row - start][position] ?? null;
177
+ const offset = row - index * BLOCK_ROWS;
178
+ const old = values[offset];
179
+ if (old !== undefined) block.bytes -= sizeOf(old);
180
+ values[offset] = value;
181
+ block.bytes += sizeOf(value);
182
+ }
183
+ block.reading.delete(column);
184
+ const offsets = cut?.[column];
185
+ if (offsets) {
186
+ const set = block.cut.get(column) ?? new Set();
187
+ for (const offset of offsets) {
188
+ const row = start + offset;
189
+ if (row >= first && row < stop) set.add(row - index * BLOCK_ROWS);
190
+ }
191
+ block.cut.set(column, set);
192
+ }
193
+ });
194
+ this.bytes += block.bytes - before;
195
+ }
196
+ this.version++;
197
+ }
198
+
199
+ /** Marks the blocks of rows `[start, end)` as used now, so that they leave last. */
200
+ touch(start, end) {
201
+ const time = ++this.clock;
202
+ for (let index = Math.floor(start / BLOCK_ROWS); index * BLOCK_ROWS < end; index++) {
203
+ const block = this.blocks.get(index);
204
+ if (block) block.used = time;
205
+ }
206
+ }
207
+
208
+ /** Removes the blocks used least recently until the cache fits `budget` bytes, keeping rows `[start, end)`. */
209
+ evict(budget, start, end) {
210
+ if (this.bytes <= budget) return;
211
+ const first = Math.floor(start / BLOCK_ROWS);
212
+ const last = Math.floor(Math.max(start, end - 1) / BLOCK_ROWS);
213
+ const candidates = [...this.blocks.values()].filter(block => (block.index < first || block.index > last) && block.reading.size === 0).sort((a, b) => a.used - b.used);
214
+ for (const block of candidates) {
215
+ if (this.bytes <= budget) break;
216
+ this.blocks.delete(block.index);
217
+ this.bytes -= block.bytes;
218
+ }
219
+ this.version++;
220
+ }
221
+ }
222
+ //# sourceMappingURL=cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["BLOCK_ROWS","sizeOf","value","length","ViewCache","blocks","Map","clock","bytes","version","block","row","get","Math","floor","ensure","index","rowIds","undefined","values","cut","reading","Set","used","set","column","offset","isCut","has","rowId","loaded","rowKey","key","id","reads","start","end","columns","rowCount","maxCells","last","min","run","flush","push","first","short","missing","filter","join","max","read","on","add","delete","receive","rows","before","stop","ids","slice","forEach","position","Array","old","offsets","touch","time","evict","budget","candidates","size","sort","a","b"],"sources":["cache.ts"],"sourcesContent":["import type { JsonValue, LoadedRow, RowKey } from \"vastgrid-spec\";\n\n/** Rows in a block of the cache: reads cover whole blocks. */\nexport const BLOCK_ROWS = 256;\n\n/** A read of rows `[start, end)` of a view, for some of its columns. */\nexport interface Read {\n start: number;\n end: number;\n columns: string[];\n}\n\n/** Rows of a view that the engine gave, by column. */\ninterface Block {\n readonly index: number;\n /** Rows held: `BLOCK_ROWS`, fewer at the end of the view; 0 until a read answers. */\n length: number;\n /** Row IDs of the rows; null for views without them, undefined until a read answers. */\n rowIds: number[] | null | undefined;\n readonly values: Map<string, JsonValue[]>;\n /** Offsets of the values that the engine cut to the text limit (§8.4), by column. */\n readonly cut: Map<string, Set<number>>;\n /** Columns being read. */\n readonly reading: Set<string>;\n used: number;\n bytes: number;\n}\n\n/** Bytes that a value takes in the cache, roughly. */\nfunction sizeOf(value: JsonValue): number {\n if (typeof value === \"string\") return 16 + value.length * 2;\n return 8;\n}\n\n/**\n * The rows of one view that the store has read, in blocks of `BLOCK_ROWS` rows, with a budget of bytes beyond\n * which the blocks used least recently leave (§4.1 of react.md: rows are not in snapshots).\n */\nexport class ViewCache {\n private readonly blocks = new Map<number, Block>();\n private clock = 0;\n /** Bytes the blocks take, roughly. */\n bytes = 0;\n /** Changes whenever rows arrive or leave. */\n version = 0;\n\n private block(row: number): Block | undefined {\n return this.blocks.get(Math.floor(row / BLOCK_ROWS));\n }\n\n private ensure(index: number): Block {\n let block = this.blocks.get(index);\n if (!block) {\n block = {\n index,\n length: 0,\n rowIds: undefined,\n values: new Map(),\n cut: new Map(),\n reading: new Set(),\n used: 0,\n bytes: 0,\n };\n this.blocks.set(index, block);\n }\n return block;\n }\n\n /** The value of a cell; undefined while it is not read. */\n value(row: number, column: string): JsonValue | undefined {\n const block = this.block(row);\n const offset = row - (block?.index ?? 0) * BLOCK_ROWS;\n if (!block || offset >= block.length) return undefined;\n return block.values.get(column)?.[offset];\n }\n\n /** Whether the engine cut the value of a cell to the text limit, so that the grid shows that it goes on. */\n isCut(row: number, column: string): boolean {\n const block = this.block(row);\n return block?.cut.get(column)?.has(row - block.index * BLOCK_ROWS) ?? false;\n }\n\n /** The row ID of a row; undefined while it is not read or in a view without row IDs. */\n rowId(row: number): number | undefined {\n const block = this.block(row);\n if (!block?.rowIds) return undefined;\n return block.rowIds[row - block.index * BLOCK_ROWS];\n }\n\n /** A row as commands read it (§6.1): its key and its values, or undefined while it is not read. */\n loaded(row: number, rowKey: string | undefined): LoadedRow | undefined {\n const block = this.block(row);\n const offset = row - (block?.index ?? 0) * BLOCK_ROWS;\n if (!block || block.rowIds === undefined || offset >= block.length) return undefined;\n let key: RowKey | undefined;\n const id = block.rowIds?.[offset];\n if (id !== undefined) {\n if (rowKey === undefined) key = { rowId: id };\n else {\n // A row whose key column is null is keyed by its row ID (§5.3).\n const value = block.values.get(rowKey)?.[offset];\n if (value !== undefined) key = value === null ? { rowId: id } : { value };\n }\n }\n const values = block.values;\n return {\n ...(key === undefined ? {} : { key }),\n has: (column) => values.has(column),\n get: (column) => values.get(column)?.[offset] ?? null,\n };\n }\n\n /**\n * What to read so that rows `[start, end)` have `columns`: reads of runs of blocks that lack the same columns,\n * each of at most `maxCells` cells, leaving out what is read or being read.\n */\n reads(start: number, end: number, columns: readonly string[], rowCount: number, maxCells = 262_144): Read[] {\n const reads: Read[] = [];\n if (end <= start || columns.length === 0) return reads;\n const last = Math.floor((Math.min(end, rowCount) - 1) / BLOCK_ROWS);\n let run: { first: number; last: number; columns: string[]; key: string } | null = null;\n const flush = () => {\n if (!run) return;\n reads.push({\n start: run.first * BLOCK_ROWS,\n end: Math.min((run.last + 1) * BLOCK_ROWS, rowCount),\n columns: run.columns,\n });\n run = null;\n };\n for (let index = Math.floor(start / BLOCK_ROWS); index <= last; index++) {\n const block = this.blocks.get(index);\n // A block read while the view was shorter (a table or view still being made, §9) is read again whole.\n const short =\n block !== undefined &&\n block.rowIds !== undefined &&\n block.length < Math.min(BLOCK_ROWS, rowCount - index * BLOCK_ROWS);\n const missing =\n block && !short\n ? columns.filter((column) => !block.values.has(column) && !block.reading.has(column))\n : columns.filter((column) => !block?.reading.has(column));\n if (missing.length === 0) {\n flush();\n continue;\n }\n const key = missing.join(\"\\u0000\");\n const blocks = Math.max(1, Math.floor(maxCells / (missing.length * BLOCK_ROWS)));\n if (run && run.key === key && index === run.last + 1 && run.last - run.first + 1 < blocks) {\n run.last = index;\n } else {\n flush();\n run = { first: index, last: index, columns: missing, key };\n }\n }\n flush();\n return reads;\n }\n\n /** Marks the columns of a read as being read, or no longer. */\n reading(read: Read, on: boolean) {\n for (let index = Math.floor(read.start / BLOCK_ROWS); index * BLOCK_ROWS < read.end; index++) {\n const block = this.ensure(index);\n for (const column of read.columns) {\n if (on) block.reading.add(column);\n else block.reading.delete(column);\n }\n }\n }\n\n /**\n * Takes the rows of a read, which starts at a block: `rows` holds the values of `columns` for rows `start` to\n * `start + rows.length`.\n */\n receive(\n start: number,\n rowIds: number[] | null,\n columns: readonly string[],\n rows: readonly (readonly JsonValue[])[],\n cut: Record<string, number[]> | undefined,\n ) {\n const end = start + rows.length;\n for (let index = Math.floor(start / BLOCK_ROWS); index * BLOCK_ROWS < end; index++) {\n const block = this.ensure(index);\n const before = block.bytes;\n const first = Math.max(start, index * BLOCK_ROWS);\n const stop = Math.min(end, (index + 1) * BLOCK_ROWS);\n block.length = Math.max(block.length, stop - index * BLOCK_ROWS);\n // A view that is still being made may have more rows in its last block at a later read (§9).\n const ids = rowIds === null ? null : rowIds.slice(first - start, stop - start);\n if (block.rowIds === undefined || (ids !== null && block.rowIds !== null && ids.length > block.rowIds.length)) {\n block.rowIds = ids;\n }\n columns.forEach((column, position) => {\n let values = block.values.get(column);\n if (!values) {\n values = new Array<JsonValue>(BLOCK_ROWS);\n block.values.set(column, values);\n }\n for (let row = first; row < stop; row++) {\n const value = rows[row - start][position] ?? null;\n const offset = row - index * BLOCK_ROWS;\n const old = values[offset];\n if (old !== undefined) block.bytes -= sizeOf(old);\n values[offset] = value;\n block.bytes += sizeOf(value);\n }\n block.reading.delete(column);\n const offsets = cut?.[column];\n if (offsets) {\n const set = block.cut.get(column) ?? new Set<number>();\n for (const offset of offsets) {\n const row = start + offset;\n if (row >= first && row < stop) set.add(row - index * BLOCK_ROWS);\n }\n block.cut.set(column, set);\n }\n });\n this.bytes += block.bytes - before;\n }\n this.version++;\n }\n\n /** Marks the blocks of rows `[start, end)` as used now, so that they leave last. */\n touch(start: number, end: number) {\n const time = ++this.clock;\n for (let index = Math.floor(start / BLOCK_ROWS); index * BLOCK_ROWS < end; index++) {\n const block = this.blocks.get(index);\n if (block) block.used = time;\n }\n }\n\n /** Removes the blocks used least recently until the cache fits `budget` bytes, keeping rows `[start, end)`. */\n evict(budget: number, start: number, end: number) {\n if (this.bytes <= budget) return;\n const first = Math.floor(start / BLOCK_ROWS);\n const last = Math.floor(Math.max(start, end - 1) / BLOCK_ROWS);\n const candidates = [...this.blocks.values()]\n .filter((block) => (block.index < first || block.index > last) && block.reading.size === 0)\n .sort((a, b) => a.used - b.used);\n for (const block of candidates) {\n if (this.bytes <= budget) break;\n this.blocks.delete(block.index);\n this.bytes -= block.bytes;\n }\n this.version++;\n }\n}\n"],"mappings":"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","ignoreList":[]}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Checked rows (§5.2.1 of the specification) as the grid shows them: whether a row of the view is checked, not
3
+ * checked or unknown, and how many rows of the view are checked.
4
+ */
5
+ import { type Checked, type Plan, type RowKey } from "vastgrid-spec";
6
+ export type CheckState = "checked" | "unchecked" | "unknown";
7
+ /** Whether a row of the view, by its key, is checked. */
8
+ export declare function checkState(checked: Checked | undefined, plan: Plan | undefined, key: RowKey): CheckState;
9
+ /**
10
+ * How many rows of the view are checked, or null when it is not known: rows of `exclude` that the view does not
11
+ * cover, and keys of `include` and `exclude` that are not rows of the view (filtered out) are counted as if they
12
+ * were, so the count is exact when every key is a row of the view.
13
+ */
14
+ export declare function checkedCount(checked: Checked | undefined, plan: Plan | undefined, rowCount: number): number | null;
15
+ /**
16
+ * The state of the header's check box: every row of the view checked (`exclude` without keys, covering the view),
17
+ * none, some, or unknown. Keys of `include` may be rows of other views, so they make "some", never "all".
18
+ */
19
+ export declare function allState(checked: Checked | undefined, plan: Plan | undefined, rowCount: number): "all" | "none" | "some" | "unknown";
20
+ //# sourceMappingURL=checked.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"checked.d.ts","sourceRoot":"","sources":["../../src/core/checked.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,KAAK,OAAO,EAA0B,KAAK,IAAI,EAAW,KAAK,MAAM,EAAE,MAAM,eAAe,CAAC;AAEtG,MAAM,MAAM,UAAU,GAAG,SAAS,GAAG,WAAW,GAAG,SAAS,CAAC;AA2B7D,yDAAyD;AACzD,wBAAgB,UAAU,CAAC,OAAO,EAAE,OAAO,GAAG,SAAS,EAAE,IAAI,EAAE,IAAI,GAAG,SAAS,EAAE,GAAG,EAAE,MAAM,GAAG,UAAU,CAMxG;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,OAAO,GAAG,SAAS,EAAE,IAAI,EAAE,IAAI,GAAG,SAAS,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAKlH;AAED;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,OAAO,EAAE,OAAO,GAAG,SAAS,EAAE,IAAI,EAAE,IAAI,GAAG,SAAS,EAAE,QAAQ,EAAE,MAAM,uCAK9F"}
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Checked rows (§5.2.1 of the specification) as the grid shows them: whether a row of the view is checked, not
3
+ * checked or unknown, and how many rows of the view are checked.
4
+ */
5
+ import { canonicalJson, keyText, partsOf } from "vastgrid-spec";
6
+ /** Whether the view's `where` implies the `where` of checked rows, so that every row of it is known (§5.2.1). */
7
+ function coversView(checked, plan) {
8
+ if (!checked || checked.mode === "include" || checked.where === undefined) return true;
9
+ const view = partsOf(plan?.where).map(part => ({
10
+ part,
11
+ json: canonicalJson(part)
12
+ }));
13
+ return partsOf(checked.where).every(part => {
14
+ const json = canonicalJson(part);
15
+ return view.some(item => item.json === json || "search" in part && "search" in item.part && item.part.search.includes(part.search));
16
+ });
17
+ }
18
+ const keySets = new WeakMap();
19
+
20
+ /** The keys of checked rows by their text (`keyText`, which is the same for the same keys, §5.3), made once. */
21
+ function keysOf(checked) {
22
+ let set = keySets.get(checked);
23
+ if (!set) {
24
+ set = new Set(checked.keys.map(keyText));
25
+ keySets.set(checked, set);
26
+ }
27
+ return set;
28
+ }
29
+
30
+ /** Whether a row of the view, by its key, is checked. */
31
+ export function checkState(checked, plan, key) {
32
+ if (!checked) return "unchecked";
33
+ const listed = keysOf(checked).has(keyText(key));
34
+ if (checked.mode === "include") return listed ? "checked" : "unchecked";
35
+ if (!coversView(checked, plan)) return "unknown";
36
+ return listed ? "unchecked" : "checked";
37
+ }
38
+
39
+ /**
40
+ * How many rows of the view are checked, or null when it is not known: rows of `exclude` that the view does not
41
+ * cover, and keys of `include` and `exclude` that are not rows of the view (filtered out) are counted as if they
42
+ * were, so the count is exact when every key is a row of the view.
43
+ */
44
+ export function checkedCount(checked, plan, rowCount) {
45
+ if (!checked) return 0;
46
+ if (checked.mode === "include") return checked.keys.length;
47
+ if (!coversView(checked, plan)) return null;
48
+ return Math.max(0, rowCount - checked.keys.length);
49
+ }
50
+
51
+ /**
52
+ * The state of the header's check box: every row of the view checked (`exclude` without keys, covering the view),
53
+ * none, some, or unknown. Keys of `include` may be rows of other views, so they make "some", never "all".
54
+ */
55
+ export function allState(checked, plan, rowCount) {
56
+ if (!checked || checked.mode === "include" && checked.keys.length === 0) return "none";
57
+ if (checked.mode === "include") return "some";
58
+ if (!coversView(checked, plan)) return "unknown";
59
+ return checked.keys.length === 0 ? "all" : checked.keys.length >= rowCount ? "none" : "some";
60
+ }
61
+ //# sourceMappingURL=checked.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["canonicalJson","keyText","partsOf","coversView","checked","plan","mode","where","undefined","view","map","part","json","every","some","item","search","includes","keySets","WeakMap","keysOf","set","get","Set","keys","checkState","key","listed","has","checkedCount","rowCount","length","Math","max","allState"],"sources":["checked.ts"],"sourcesContent":["/**\n * Checked rows (§5.2.1 of the specification) as the grid shows them: whether a row of the view is checked, not\n * checked or unknown, and how many rows of the view are checked.\n */\nimport { type Checked, canonicalJson, keyText, type Plan, partsOf, type RowKey } from \"vastgrid-spec\";\n\nexport type CheckState = \"checked\" | \"unchecked\" | \"unknown\";\n\n/** Whether the view's `where` implies the `where` of checked rows, so that every row of it is known (§5.2.1). */\nfunction coversView(checked: Checked | undefined, plan: Plan | undefined): boolean {\n if (!checked || checked.mode === \"include\" || checked.where === undefined) return true;\n const view = partsOf(plan?.where).map((part) => ({ part, json: canonicalJson(part) }));\n return partsOf(checked.where).every((part) => {\n const json = canonicalJson(part);\n return view.some(\n (item) =>\n item.json === json || (\"search\" in part && \"search\" in item.part && item.part.search.includes(part.search)),\n );\n });\n}\n\nconst keySets = new WeakMap<Checked, Set<string>>();\n\n/** The keys of checked rows by their text (`keyText`, which is the same for the same keys, §5.3), made once. */\nfunction keysOf(checked: Checked): Set<string> {\n let set = keySets.get(checked);\n if (!set) {\n set = new Set(checked.keys.map(keyText));\n keySets.set(checked, set);\n }\n return set;\n}\n\n/** Whether a row of the view, by its key, is checked. */\nexport function checkState(checked: Checked | undefined, plan: Plan | undefined, key: RowKey): CheckState {\n if (!checked) return \"unchecked\";\n const listed = keysOf(checked).has(keyText(key));\n if (checked.mode === \"include\") return listed ? \"checked\" : \"unchecked\";\n if (!coversView(checked, plan)) return \"unknown\";\n return listed ? \"unchecked\" : \"checked\";\n}\n\n/**\n * How many rows of the view are checked, or null when it is not known: rows of `exclude` that the view does not\n * cover, and keys of `include` and `exclude` that are not rows of the view (filtered out) are counted as if they\n * were, so the count is exact when every key is a row of the view.\n */\nexport function checkedCount(checked: Checked | undefined, plan: Plan | undefined, rowCount: number): number | null {\n if (!checked) return 0;\n if (checked.mode === \"include\") return checked.keys.length;\n if (!coversView(checked, plan)) return null;\n return Math.max(0, rowCount - checked.keys.length);\n}\n\n/**\n * The state of the header's check box: every row of the view checked (`exclude` without keys, covering the view),\n * none, some, or unknown. Keys of `include` may be rows of other views, so they make \"some\", never \"all\".\n */\nexport function allState(checked: Checked | undefined, plan: Plan | undefined, rowCount: number) {\n if (!checked || (checked.mode === \"include\" && checked.keys.length === 0)) return \"none\";\n if (checked.mode === \"include\") return \"some\";\n if (!coversView(checked, plan)) return \"unknown\";\n return checked.keys.length === 0 ? \"all\" : checked.keys.length >= rowCount ? \"none\" : \"some\";\n}\n"],"mappings":"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","ignoreList":[]}
@@ -0,0 +1,33 @@
1
+ import { type Operation } from "vastgrid-spec";
2
+ import { type RequestMessage } from "./types.js";
3
+ /**
4
+ * Carries messages (§8 of the specification) to an engine and gives back its answers: a function call, a Web
5
+ * Worker, HTTP, a Server Function, an MCP tool call (§4.4 of react.md).
6
+ */
7
+ export interface Transport {
8
+ /** Sends a request and gives its response; `cancel` has none. */
9
+ send(request: RequestMessage, options: {
10
+ signal?: AbortSignal;
11
+ }): Promise<unknown>;
12
+ /** Follows the engine's events (§8.5), when the transport carries them. */
13
+ subscribe?(listener: (event: unknown) => void): () => void;
14
+ /**
15
+ * How a request in flight is cancelled (§8.6): by a `cancel` request (the default), or by the transport itself
16
+ * when the signal given to `send` aborts (an HTTP request is aborted).
17
+ */
18
+ cancels?: "message" | "signal";
19
+ /**
20
+ * Where the file of an `export` without a target can be downloaded, by the `target` of its answer (§8.2): the
21
+ * HTTP transport's `<url>/exports/<target>`. Absent when the transport has no such place.
22
+ */
23
+ exportUrl?(target: string): string;
24
+ }
25
+ /** Sends requests through a transport: gives them ids, checks the answers and cancels what is no longer needed. */
26
+ export declare class GridClient {
27
+ readonly transport: Transport;
28
+ constructor(transport: Transport);
29
+ request<T>(op: Operation, members: Record<string, unknown>, signal?: AbortSignal): Promise<T>;
30
+ /** Follows the engine's events, checked (§8.5); events that do not follow §8 are left out. */
31
+ subscribe(listener: (event: Record<string, unknown>) => void): () => void;
32
+ }
33
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/core/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAA6B,KAAK,SAAS,EAAuC,MAAM,eAAe,CAAC;AAE/G,OAAO,EAAa,KAAK,cAAc,EAAE,MAAM,YAAY,CAAC;AAE5D;;;GAGG;AACH,MAAM,WAAW,SAAS;IACxB,iEAAiE;IACjE,IAAI,CAAC,OAAO,EAAE,cAAc,EAAE,OAAO,EAAE;QAAE,MAAM,CAAC,EAAE,WAAW,CAAA;KAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACnF,2EAA2E;IAC3E,SAAS,CAAC,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,GAAG,MAAM,IAAI,CAAC;IAC3D;;;OAGG;IACH,OAAO,CAAC,EAAE,SAAS,GAAG,QAAQ,CAAC;IAC/B;;;OAGG;IACH,SAAS,CAAC,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC;CACpC;AAwCD,mHAAmH;AACnH,qBAAa,UAAU;IACT,QAAQ,CAAC,SAAS,EAAE,SAAS;IAAzC,YAAqB,SAAS,EAAE,SAAS,EAAI;IAE7C,OAAO,CAAC,CAAC,EAAE,EAAE,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,CAAC,CAAC,CAsB5F;IAED,8FAA8F;IAC9F,SAAS,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,GAAG,MAAM,IAAI,CASxE;CACF"}
@@ -0,0 +1,103 @@
1
+ import { checkEvent, checkResponse, ProtocolError, toStructuredEncoding } from "vastgrid-spec";
2
+ import { now, track } from "./trace.js";
3
+ import { GridError } from "./types.js";
4
+
5
+ /**
6
+ * Carries messages (§8 of the specification) to an engine and gives back its answers: a function call, a Web
7
+ * Worker, HTTP, a Server Function, an MCP tool call (§4.4 of react.md).
8
+ */
9
+
10
+ function cancelled(op) {
11
+ return new GridError("cancelled", "The request was cancelled.", {
12
+ op
13
+ });
14
+ }
15
+
16
+ /** Reads a response: its result, or the error it carries as a `GridError`. */
17
+ function read(message, op) {
18
+ let response;
19
+ try {
20
+ response = checkResponse(message, op);
21
+ } catch (error) {
22
+ // A response that does not follow §8 is an internal error for the client (§8.1).
23
+ if (error instanceof ProtocolError) {
24
+ throw new GridError("internal", `The engine's response does not follow the protocol: ${error.message}`, {
25
+ op,
26
+ reason: error.reason,
27
+ path: error.path
28
+ });
29
+ }
30
+ throw error;
31
+ }
32
+ const error = response.error;
33
+ if (error) {
34
+ throw new GridError(error.code, error.message, {
35
+ op,
36
+ reason: error.reason,
37
+ path: error.path,
38
+ details: error.details
39
+ });
40
+ }
41
+ return toStructuredEncoding(response).result;
42
+ }
43
+
44
+ // Clients can share a transport or reach the same engine through different transports. Their requests and
45
+ // cancellations must use distinct ids, including after a store is disconnected and another is created.
46
+ let nextId = 1;
47
+
48
+ /** Sends requests through a transport: gives them ids, checks the answers and cancels what is no longer needed. */
49
+ export class GridClient {
50
+ constructor(transport) {
51
+ this.transport = transport;
52
+ }
53
+ request(op, members, signal) {
54
+ if (signal?.aborted) return Promise.reject(cancelled(op));
55
+ const id = nextId++;
56
+ const started = now();
57
+ const bySignal = this.transport.cancels === "signal";
58
+ const sent = this.transport.send({
59
+ v: 2,
60
+ id,
61
+ op,
62
+ ...members
63
+ }, bySignal && signal ? {
64
+ signal
65
+ } : {});
66
+ if (!signal) return sent.then(response => read(response, op)).finally(() => track(op, started, "requests"));
67
+ let stop = () => {};
68
+ const aborted = new Promise((_, reject) => {
69
+ const abort = () => {
70
+ if (!bySignal) {
71
+ this.transport.send({
72
+ v: 2,
73
+ id: nextId++,
74
+ op: "cancel",
75
+ request: id
76
+ }, {}).catch(() => {});
77
+ }
78
+ reject(cancelled(op));
79
+ };
80
+ signal.addEventListener("abort", abort, {
81
+ once: true
82
+ });
83
+ stop = () => signal.removeEventListener("abort", abort);
84
+ });
85
+ return Promise.race([sent.then(response => read(response, op)), aborted]).finally(() => {
86
+ stop();
87
+ track(op, started, "requests");
88
+ });
89
+ }
90
+
91
+ /** Follows the engine's events, checked (§8.5); events that do not follow §8 are left out. */
92
+ subscribe(listener) {
93
+ if (!this.transport.subscribe) return () => {};
94
+ return this.transport.subscribe(event => {
95
+ try {
96
+ listener(checkEvent(event));
97
+ } catch (error) {
98
+ if (!(error instanceof ProtocolError)) throw error;
99
+ }
100
+ });
101
+ }
102
+ }
103
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["checkEvent","checkResponse","ProtocolError","toStructuredEncoding","now","track","GridError","cancelled","op","read","message","response","error","reason","path","code","details","result","nextId","GridClient","constructor","transport","request","members","signal","aborted","Promise","reject","id","started","bySignal","cancels","sent","send","v","then","finally","stop","_","abort","catch","addEventListener","once","removeEventListener","race","subscribe","listener","event"],"sources":["client.ts"],"sourcesContent":["import { checkEvent, checkResponse, type Operation, ProtocolError, toStructuredEncoding } from \"vastgrid-spec\";\nimport { now, track } from \"./trace.js\";\nimport { GridError, type RequestMessage } from \"./types.js\";\n\n/**\n * Carries messages (§8 of the specification) to an engine and gives back its answers: a function call, a Web\n * Worker, HTTP, a Server Function, an MCP tool call (§4.4 of react.md).\n */\nexport interface Transport {\n /** Sends a request and gives its response; `cancel` has none. */\n send(request: RequestMessage, options: { signal?: AbortSignal }): Promise<unknown>;\n /** Follows the engine's events (§8.5), when the transport carries them. */\n subscribe?(listener: (event: unknown) => void): () => void;\n /**\n * How a request in flight is cancelled (§8.6): by a `cancel` request (the default), or by the transport itself\n * when the signal given to `send` aborts (an HTTP request is aborted).\n */\n cancels?: \"message\" | \"signal\";\n /**\n * Where the file of an `export` without a target can be downloaded, by the `target` of its answer (§8.2): the\n * HTTP transport's `<url>/exports/<target>`. Absent when the transport has no such place.\n */\n exportUrl?(target: string): string;\n}\n\nfunction cancelled(op: Operation) {\n return new GridError(\"cancelled\", \"The request was cancelled.\", { op });\n}\n\n/** Reads a response: its result, or the error it carries as a `GridError`. */\nfunction read<T>(message: unknown, op: Operation): T {\n let response: Record<string, unknown>;\n try {\n response = checkResponse(message, op);\n } catch (error) {\n // A response that does not follow §8 is an internal error for the client (§8.1).\n if (error instanceof ProtocolError) {\n throw new GridError(\"internal\", `The engine's response does not follow the protocol: ${error.message}`, {\n op,\n reason: error.reason,\n path: error.path,\n });\n }\n throw error;\n }\n const error = response.error as\n | { code: GridError[\"code\"]; message: string; reason?: string; path?: string; details?: Record<string, unknown> }\n | undefined;\n if (error) {\n throw new GridError(error.code, error.message, {\n op,\n reason: error.reason,\n path: error.path,\n details: error.details,\n });\n }\n return toStructuredEncoding(response).result as T;\n}\n\n// Clients can share a transport or reach the same engine through different transports. Their requests and\n// cancellations must use distinct ids, including after a store is disconnected and another is created.\nlet nextId = 1;\n\n/** Sends requests through a transport: gives them ids, checks the answers and cancels what is no longer needed. */\nexport class GridClient {\n constructor(readonly transport: Transport) {}\n\n request<T>(op: Operation, members: Record<string, unknown>, signal?: AbortSignal): Promise<T> {\n if (signal?.aborted) return Promise.reject(cancelled(op));\n const id = nextId++;\n const started = now();\n const bySignal = this.transport.cancels === \"signal\";\n const sent = this.transport.send({ v: 2, id, op, ...members }, bySignal && signal ? { signal } : {});\n if (!signal) return sent.then((response) => read<T>(response, op)).finally(() => track(op, started, \"requests\"));\n let stop = () => {};\n const aborted = new Promise<never>((_, reject) => {\n const abort = () => {\n if (!bySignal) {\n this.transport.send({ v: 2, id: nextId++, op: \"cancel\", request: id }, {}).catch(() => {});\n }\n reject(cancelled(op));\n };\n signal.addEventListener(\"abort\", abort, { once: true });\n stop = () => signal.removeEventListener(\"abort\", abort);\n });\n return Promise.race([sent.then((response) => read<T>(response, op)), aborted]).finally(() => {\n stop();\n track(op, started, \"requests\");\n });\n }\n\n /** Follows the engine's events, checked (§8.5); events that do not follow §8 are left out. */\n subscribe(listener: (event: Record<string, unknown>) => void): () => void {\n if (!this.transport.subscribe) return () => {};\n return this.transport.subscribe((event) => {\n try {\n listener(checkEvent(event));\n } catch (error) {\n if (!(error instanceof ProtocolError)) throw error;\n }\n });\n }\n}\n"],"mappings":"AAAA,SAASA,UAAU,EAAEC,aAAa,EAAkBC,aAAa,EAAEC,oBAAoB,QAAQ,eAAe;AAC9G,SAASC,GAAG,EAAEC,KAAK,QAAQ,YAAY;AACvC,SAASC,SAAS,QAA6B,YAAY;;AAE3D;AACA;AACA;AACA;;AAkBA,SAASC,SAASA,CAACC,EAAa,EAAE;EAChC,OAAO,IAAIF,SAAS,CAAC,WAAW,EAAE,4BAA4B,EAAE;IAAEE;EAAG,CAAC,CAAC;AACzE;;AAEA;AACA,SAASC,IAAIA,CAAIC,OAAgB,EAAEF,EAAa,EAAK;EACnD,IAAIG,QAAiC;EACrC,IAAI;IACFA,QAAQ,GAAGV,aAAa,CAACS,OAAO,EAAEF,EAAE,CAAC;EACvC,CAAC,CAAC,OAAOI,KAAK,EAAE;IACd;IACA,IAAIA,KAAK,YAAYV,aAAa,EAAE;MAClC,MAAM,IAAII,SAAS,CAAC,UAAU,EAAE,uDAAuDM,KAAK,CAACF,OAAO,EAAE,EAAE;QACtGF,EAAE;QACFK,MAAM,EAAED,KAAK,CAACC,MAAM;QACpBC,IAAI,EAAEF,KAAK,CAACE;MACd,CAAC,CAAC;IACJ;IACA,MAAMF,KAAK;EACb;EACA,MAAMA,KAAK,GAAGD,QAAQ,CAACC,KAEV;EACb,IAAIA,KAAK,EAAE;IACT,MAAM,IAAIN,SAAS,CAACM,KAAK,CAACG,IAAI,EAAEH,KAAK,CAACF,OAAO,EAAE;MAC7CF,EAAE;MACFK,MAAM,EAAED,KAAK,CAACC,MAAM;MACpBC,IAAI,EAAEF,KAAK,CAACE,IAAI;MAChBE,OAAO,EAAEJ,KAAK,CAACI;IACjB,CAAC,CAAC;EACJ;EACA,OAAOb,oBAAoB,CAACQ,QAAQ,CAAC,CAACM,MAAM;AAC9C;;AAEA;AACA;AACA,IAAIC,MAAM,GAAG,CAAC;;AAEd;AACA,OAAO,MAAMC,UAAU,CAAC;EACtBC,WAAWA,CAAUC,SAAoB,EAAE;IAAA,KAAtBA,SAAoB,GAApBA,SAAoB;EAAG;EAE5CC,OAAOA,CAAId,EAAa,EAAEe,OAAgC,EAAEC,MAAoB,EAAc;IAC5F,IAAIA,MAAM,EAAEC,OAAO,EAAE,OAAOC,OAAO,CAACC,MAAM,CAACpB,SAAS,CAACC,EAAE,CAAC,CAAC;IACzD,MAAMoB,EAAE,GAAGV,MAAM,EAAE;IACnB,MAAMW,OAAO,GAAGzB,GAAG,CAAC,CAAC;IACrB,MAAM0B,QAAQ,GAAG,IAAI,CAACT,SAAS,CAACU,OAAO,KAAK,QAAQ;IACpD,MAAMC,IAAI,GAAG,IAAI,CAACX,SAAS,CAACY,IAAI,CAAC;MAAEC,CAAC,EAAE,CAAC;MAAEN,EAAE;MAAEpB,EAAE;MAAE,GAAGe;IAAQ,CAAC,EAAEO,QAAQ,IAAIN,MAAM,GAAG;MAAEA;IAAO,CAAC,GAAG,CAAC,CAAC,CAAC;IACpG,IAAI,CAACA,MAAM,EAAE,OAAOQ,IAAI,CAACG,IAAI,CAAExB,QAAQ,IAAKF,IAAI,CAAIE,QAAQ,EAAEH,EAAE,CAAC,CAAC,CAAC4B,OAAO,CAAC,MAAM/B,KAAK,CAACG,EAAE,EAAEqB,OAAO,EAAE,UAAU,CAAC,CAAC;IAChH,IAAIQ,IAAI,GAAGA,CAAA,KAAM,CAAC,CAAC;IACnB,MAAMZ,OAAO,GAAG,IAAIC,OAAO,CAAQ,CAACY,CAAC,EAAEX,MAAM,KAAK;MAChD,MAAMY,KAAK,GAAGA,CAAA,KAAM;QAClB,IAAI,CAACT,QAAQ,EAAE;UACb,IAAI,CAACT,SAAS,CAACY,IAAI,CAAC;YAAEC,CAAC,EAAE,CAAC;YAAEN,EAAE,EAAEV,MAAM,EAAE;YAAEV,EAAE,EAAE,QAAQ;YAAEc,OAAO,EAAEM;UAAG,CAAC,EAAE,CAAC,CAAC,CAAC,CAACY,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC;QAC5F;QACAb,MAAM,CAACpB,SAAS,CAACC,EAAE,CAAC,CAAC;MACvB,CAAC;MACDgB,MAAM,CAACiB,gBAAgB,CAAC,OAAO,EAAEF,KAAK,EAAE;QAAEG,IAAI,EAAE;MAAK,CAAC,CAAC;MACvDL,IAAI,GAAGA,CAAA,KAAMb,MAAM,CAACmB,mBAAmB,CAAC,OAAO,EAAEJ,KAAK,CAAC;IACzD,CAAC,CAAC;IACF,OAAOb,OAAO,CAACkB,IAAI,CAAC,CAACZ,IAAI,CAACG,IAAI,CAAExB,QAAQ,IAAKF,IAAI,CAAIE,QAAQ,EAAEH,EAAE,CAAC,CAAC,EAAEiB,OAAO,CAAC,CAAC,CAACW,OAAO,CAAC,MAAM;MAC3FC,IAAI,CAAC,CAAC;MACNhC,KAAK,CAACG,EAAE,EAAEqB,OAAO,EAAE,UAAU,CAAC;IAChC,CAAC,CAAC;EACJ;;EAEA;EACAgB,SAASA,CAACC,QAAkD,EAAc;IACxE,IAAI,CAAC,IAAI,CAACzB,SAAS,CAACwB,SAAS,EAAE,OAAO,MAAM,CAAC,CAAC;IAC9C,OAAO,IAAI,CAACxB,SAAS,CAACwB,SAAS,CAAEE,KAAK,IAAK;MACzC,IAAI;QACFD,QAAQ,CAAC9C,UAAU,CAAC+C,KAAK,CAAC,CAAC;MAC7B,CAAC,CAAC,OAAOnC,KAAK,EAAE;QACd,IAAI,EAAEA,KAAK,YAAYV,aAAa,CAAC,EAAE,MAAMU,KAAK;MACpD;IACF,CAAC,CAAC;EACJ;AACF","ignoreList":[]}
@@ -0,0 +1,48 @@
1
+ /**
2
+ * The conditions of a plan's `where` (§6.2.1 of the specification) as a tree that the conditions menu edits: groups
3
+ * whose items all hold (`and`) or one of which holds (`or`), conditions on one column in the column menu's terms
4
+ * (`ColumnFilter`), and expressions that it does not take apart, kept as they are.
5
+ */
6
+ import { type Column, type Expr } from "vastgrid-spec";
7
+ import { type ColumnFilter } from "./filters.js";
8
+ export type ConditionNode = {
9
+ kind: "group";
10
+ id: number;
11
+ op: "and" | "or";
12
+ items: ConditionNode[];
13
+ } | {
14
+ kind: "condition";
15
+ id: number;
16
+ column: string;
17
+ filter: ColumnFilter & {
18
+ kind: "condition";
19
+ };
20
+ } | {
21
+ kind: "expression";
22
+ id: number;
23
+ expr: Expr;
24
+ };
25
+ /** A new id for a node, for React's keys. */
26
+ export declare function nodeId(): number;
27
+ /**
28
+ * The conditions of `where` as a group of its parts that are not the search (`and`); a `where` that is one `or`
29
+ * is that group.
30
+ */
31
+ export declare function readConditions(where: Expr | undefined): ConditionNode & {
32
+ kind: "group";
33
+ };
34
+ /** A condition that does not compile: the node, and which of its texts. */
35
+ export declare class ConditionError extends Error {
36
+ readonly node: number;
37
+ readonly side: "first" | "second";
38
+ constructor(node: number, side: "first" | "second");
39
+ }
40
+ /**
41
+ * The `where` of `filter.set` for a tree (the search is kept by the command): an `and` group gives its items as
42
+ * parts; conditions without text keep every row and are left out. Text that is not a value of its column throws a
43
+ * `ConditionError`.
44
+ */
45
+ export declare function writeConditions(group: ConditionNode & {
46
+ kind: "group";
47
+ }, columns: readonly Column[]): Expr | null;
48
+ //# sourceMappingURL=conditions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"conditions.d.ts","sourceRoot":"","sources":["../../src/core/conditions.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,KAAK,MAAM,EAAa,KAAK,IAAI,EAAyC,MAAM,eAAe,CAAC;AACzG,OAAO,EAAE,KAAK,YAAY,EAA4C,MAAM,cAAc,CAAC;AAE3F,MAAM,MAAM,aAAa,GACrB;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,KAAK,GAAG,IAAI,CAAC;IAAC,KAAK,EAAE,aAAa,EAAE,CAAA;CAAE,GACvE;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,YAAY,GAAG;QAAE,IAAI,EAAE,WAAW,CAAA;KAAE,CAAA;CAAE,GAC/F;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,IAAI,CAAA;CAAE,CAAC;AAInD,6CAA6C;AAC7C,wBAAgB,MAAM,WAErB;AAiBD;;;GAGG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,IAAI,GAAG,SAAS,GAAG,aAAa,GAAG;IAAE,IAAI,EAAE,OAAO,CAAA;CAAE,CAOzF;AAED,2EAA2E;AAC3E,qBAAa,cAAe,SAAQ,KAAK;IAErC,QAAQ,CAAC,IAAI,EAAE,MAAM;IACrB,QAAQ,CAAC,IAAI,EAAE,OAAO,GAAG,QAAQ;IAFnC,YACW,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,OAAO,GAAG,QAAQ,EAGlC;CACF;AAwBD;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,aAAa,GAAG;IAAE,IAAI,EAAE,OAAO,CAAA;CAAE,EAAE,OAAO,EAAE,SAAS,MAAM,EAAE,GAAG,IAAI,GAAG,IAAI,CAGjH"}