@datakable/core 1.0.0 → 1.1.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 (290) hide show
  1. package/README.md +4 -2
  2. package/dist/catalog/codes.cjs +12 -8
  3. package/dist/catalog/codes.cjs.map +1 -1
  4. package/dist/catalog/codes.js +12 -8
  5. package/dist/catalog/codes.js.map +1 -1
  6. package/dist/catalog/slots.cjs +10 -6
  7. package/dist/catalog/slots.cjs.map +1 -1
  8. package/dist/catalog/slots.js +10 -6
  9. package/dist/catalog/slots.js.map +1 -1
  10. package/dist/{codes-BKdS9EiO.d.cts → codes-B9bCK73-.d.cts} +46 -8
  11. package/dist/{codes-BKdS9EiO.d.ts → codes-B9bCK73-.d.ts} +46 -8
  12. package/dist/column/column-def.cjs.map +1 -1
  13. package/dist/column/get-value.cjs +6 -1
  14. package/dist/column/get-value.cjs.map +1 -1
  15. package/dist/column/get-value.js +6 -1
  16. package/dist/column/get-value.js.map +1 -1
  17. package/dist/column-filters.d.cts +2 -2
  18. package/dist/column-filters.d.ts +2 -2
  19. package/dist/diagnostics/build.cjs +10 -4
  20. package/dist/diagnostics/build.cjs.map +1 -1
  21. package/dist/diagnostics/build.js +8 -3
  22. package/dist/diagnostics/build.js.map +1 -1
  23. package/dist/diagnostics/catalog.cjs +11 -5
  24. package/dist/diagnostics/catalog.cjs.map +1 -1
  25. package/dist/diagnostics/catalog.js +10 -5
  26. package/dist/diagnostics/catalog.js.map +1 -1
  27. package/dist/diagnostics/codes.cjs +12 -8
  28. package/dist/diagnostics/codes.cjs.map +1 -1
  29. package/dist/diagnostics/codes.js +12 -8
  30. package/dist/diagnostics/codes.js.map +1 -1
  31. package/dist/diagnostics/console.cjs +13 -6
  32. package/dist/diagnostics/console.cjs.map +1 -1
  33. package/dist/diagnostics/console.js +13 -6
  34. package/dist/diagnostics/console.js.map +1 -1
  35. package/dist/diagnostics/env.cjs +1 -0
  36. package/dist/diagnostics/env.cjs.map +1 -1
  37. package/dist/diagnostics/env.js +1 -0
  38. package/dist/diagnostics/env.js.map +1 -1
  39. package/dist/diagnostics/explain-text.cjs +2 -1
  40. package/dist/diagnostics/explain-text.cjs.map +1 -1
  41. package/dist/diagnostics/explain-text.js +2 -1
  42. package/dist/diagnostics/explain-text.js.map +1 -1
  43. package/dist/diagnostics/explain.cjs +3 -2
  44. package/dist/diagnostics/explain.cjs.map +1 -1
  45. package/dist/diagnostics/explain.js +3 -2
  46. package/dist/diagnostics/explain.js.map +1 -1
  47. package/dist/diagnostics/hub.cjs +6 -5
  48. package/dist/diagnostics/hub.cjs.map +1 -1
  49. package/dist/diagnostics/hub.js +7 -6
  50. package/dist/diagnostics/hub.js.map +1 -1
  51. package/dist/diagnostics/process-guard.cjs +26 -0
  52. package/dist/diagnostics/process-guard.cjs.map +1 -0
  53. package/dist/diagnostics/process-guard.js +9 -0
  54. package/dist/diagnostics/process-guard.js.map +1 -0
  55. package/dist/diagnostics/prose.cjs +120 -0
  56. package/dist/diagnostics/prose.cjs.map +1 -0
  57. package/dist/diagnostics/prose.js +93 -0
  58. package/dist/diagnostics/prose.js.map +1 -0
  59. package/dist/diagnostics/redact.cjs +7 -4
  60. package/dist/diagnostics/redact.cjs.map +1 -1
  61. package/dist/diagnostics/redact.js +6 -4
  62. package/dist/diagnostics/redact.js.map +1 -1
  63. package/dist/diagnostics/trace-store.cjs +6 -0
  64. package/dist/diagnostics/trace-store.cjs.map +1 -1
  65. package/dist/diagnostics/trace-store.js +4 -0
  66. package/dist/diagnostics/trace-store.js.map +1 -1
  67. package/dist/diagnostics/tracer.cjs +74 -13
  68. package/dist/diagnostics/tracer.cjs.map +1 -1
  69. package/dist/diagnostics/tracer.js +75 -14
  70. package/dist/diagnostics/tracer.js.map +1 -1
  71. package/dist/diagnostics/types.cjs.map +1 -1
  72. package/dist/{explain-aagaYHcy.d.cts → explain-Q8Cg0cZy.d.cts} +13 -4
  73. package/dist/{explain-DcUZfFh5.d.ts → explain-i0OATi_W.d.ts} +13 -4
  74. package/dist/feature/codes.cjs +1 -0
  75. package/dist/feature/codes.cjs.map +1 -1
  76. package/dist/feature/codes.js +1 -0
  77. package/dist/feature/codes.js.map +1 -1
  78. package/dist/feature/define.cjs +3 -1
  79. package/dist/feature/define.cjs.map +1 -1
  80. package/dist/feature/define.js +3 -1
  81. package/dist/feature/define.js.map +1 -1
  82. package/dist/feature/install.cjs +4 -3
  83. package/dist/feature/install.cjs.map +1 -1
  84. package/dist/feature/install.js +4 -3
  85. package/dist/feature/install.js.map +1 -1
  86. package/dist/feature/runtime.cjs.map +1 -1
  87. package/dist/feature/runtime.js.map +1 -1
  88. package/dist/features/column-filters/codes.cjs +1 -0
  89. package/dist/features/column-filters/codes.cjs.map +1 -1
  90. package/dist/features/column-filters/codes.js +1 -0
  91. package/dist/features/column-filters/codes.js.map +1 -1
  92. package/dist/features/column-filters/column-filters.cjs +4 -2
  93. package/dist/features/column-filters/column-filters.cjs.map +1 -1
  94. package/dist/features/column-filters/column-filters.js +4 -2
  95. package/dist/features/column-filters/column-filters.js.map +1 -1
  96. package/dist/features/column-filters/match.cjs +5 -5
  97. package/dist/features/column-filters/match.cjs.map +1 -1
  98. package/dist/features/column-filters/match.js +5 -5
  99. package/dist/features/column-filters/match.js.map +1 -1
  100. package/dist/features/pagination/codes.cjs +6 -3
  101. package/dist/features/pagination/codes.cjs.map +1 -1
  102. package/dist/features/pagination/codes.js +6 -3
  103. package/dist/features/pagination/codes.js.map +1 -1
  104. package/dist/features/pagination/pagination.cjs +19 -14
  105. package/dist/features/pagination/pagination.cjs.map +1 -1
  106. package/dist/features/pagination/pagination.js +19 -14
  107. package/dist/features/pagination/pagination.js.map +1 -1
  108. package/dist/features/search/codes.cjs +1 -0
  109. package/dist/features/search/codes.cjs.map +1 -1
  110. package/dist/features/search/codes.js +1 -0
  111. package/dist/features/search/codes.js.map +1 -1
  112. package/dist/features/search/search-index.cjs +105 -48
  113. package/dist/features/search/search-index.cjs.map +1 -1
  114. package/dist/features/search/search-index.js +106 -49
  115. package/dist/features/search/search-index.js.map +1 -1
  116. package/dist/features/search/search.cjs +82 -24
  117. package/dist/features/search/search.cjs.map +1 -1
  118. package/dist/features/search/search.js +82 -24
  119. package/dist/features/search/search.js.map +1 -1
  120. package/dist/features/search/skipped-codes.cjs +45 -0
  121. package/dist/features/search/skipped-codes.cjs.map +1 -0
  122. package/dist/features/search/skipped-codes.js +20 -0
  123. package/dist/features/search/skipped-codes.js.map +1 -0
  124. package/dist/features/sorting/codes.cjs +1 -0
  125. package/dist/features/sorting/codes.cjs.map +1 -1
  126. package/dist/features/sorting/codes.js +1 -0
  127. package/dist/features/sorting/codes.js.map +1 -1
  128. package/dist/features/sorting/sorting.cjs +19 -23
  129. package/dist/features/sorting/sorting.cjs.map +1 -1
  130. package/dist/features/sorting/sorting.js +19 -23
  131. package/dist/features/sorting/sorting.js.map +1 -1
  132. package/dist/features/sorting/strategy.cjs +4 -4
  133. package/dist/features/sorting/strategy.cjs.map +1 -1
  134. package/dist/features/sorting/strategy.js +4 -4
  135. package/dist/features/sorting/strategy.js.map +1 -1
  136. package/dist/features/validity/codes.cjs +1 -0
  137. package/dist/features/validity/codes.cjs.map +1 -1
  138. package/dist/features/validity/codes.js +1 -0
  139. package/dist/features/validity/codes.js.map +1 -1
  140. package/dist/features/validity/validity.cjs +3 -3
  141. package/dist/features/validity/validity.cjs.map +1 -1
  142. package/dist/features/validity/validity.js +3 -3
  143. package/dist/features/validity/validity.js.map +1 -1
  144. package/dist/index.d.cts +16 -11
  145. package/dist/index.d.ts +16 -11
  146. package/dist/ingest/data-check-codes.cjs +4 -2
  147. package/dist/ingest/data-check-codes.cjs.map +1 -1
  148. package/dist/ingest/data-check-codes.js +4 -2
  149. package/dist/ingest/data-check-codes.js.map +1 -1
  150. package/dist/ingest/data-checks.cjs +1 -1
  151. package/dist/ingest/data-checks.cjs.map +1 -1
  152. package/dist/ingest/data-checks.js +1 -1
  153. package/dist/ingest/data-checks.js.map +1 -1
  154. package/dist/ingest/row-key-codes.cjs +1 -0
  155. package/dist/ingest/row-key-codes.cjs.map +1 -1
  156. package/dist/ingest/row-key-codes.js +1 -0
  157. package/dist/ingest/row-key-codes.js.map +1 -1
  158. package/dist/ingest/row-key.cjs +23 -20
  159. package/dist/ingest/row-key.cjs.map +1 -1
  160. package/dist/ingest/row-key.js +23 -20
  161. package/dist/ingest/row-key.js.map +1 -1
  162. package/dist/ingest/schema-codes.cjs +1 -0
  163. package/dist/ingest/schema-codes.cjs.map +1 -1
  164. package/dist/ingest/schema-codes.js +1 -0
  165. package/dist/ingest/schema-codes.js.map +1 -1
  166. package/dist/ingest/unique-fields.cjs +2 -2
  167. package/dist/ingest/unique-fields.cjs.map +1 -1
  168. package/dist/ingest/unique-fields.js +2 -2
  169. package/dist/ingest/unique-fields.js.map +1 -1
  170. package/dist/intercept/boundary.cjs +4 -2
  171. package/dist/intercept/boundary.cjs.map +1 -1
  172. package/dist/intercept/boundary.js +4 -2
  173. package/dist/intercept/boundary.js.map +1 -1
  174. package/dist/intercept/cell-batch.cjs +7 -4
  175. package/dist/intercept/cell-batch.cjs.map +1 -1
  176. package/dist/intercept/cell-batch.js +7 -4
  177. package/dist/intercept/cell-batch.js.map +1 -1
  178. package/dist/intercept/codes.cjs +1 -0
  179. package/dist/intercept/codes.cjs.map +1 -1
  180. package/dist/intercept/codes.js +1 -0
  181. package/dist/intercept/codes.js.map +1 -1
  182. package/dist/intercept/fallbacks.cjs +12 -20
  183. package/dist/intercept/fallbacks.cjs.map +1 -1
  184. package/dist/intercept/fallbacks.js +12 -20
  185. package/dist/intercept/fallbacks.js.map +1 -1
  186. package/dist/intercept/runtime.cjs +7 -9
  187. package/dist/intercept/runtime.cjs.map +1 -1
  188. package/dist/intercept/runtime.js +7 -9
  189. package/dist/intercept/runtime.js.map +1 -1
  190. package/dist/messages/index.cjs +4 -1
  191. package/dist/messages/index.cjs.map +1 -1
  192. package/dist/messages/index.js +4 -1
  193. package/dist/messages/index.js.map +1 -1
  194. package/dist/pagination.d.cts +2 -2
  195. package/dist/pagination.d.ts +2 -2
  196. package/dist/pipeline/codes.cjs +1 -0
  197. package/dist/pipeline/codes.cjs.map +1 -1
  198. package/dist/pipeline/codes.js +1 -0
  199. package/dist/pipeline/codes.js.map +1 -1
  200. package/dist/pipeline/column-cache.cjs +94 -76
  201. package/dist/pipeline/column-cache.cjs.map +1 -1
  202. package/dist/pipeline/column-cache.js +92 -75
  203. package/dist/pipeline/column-cache.js.map +1 -1
  204. package/dist/pipeline/dev-checks.cjs +1 -0
  205. package/dist/pipeline/dev-checks.cjs.map +1 -1
  206. package/dist/pipeline/dev-checks.js +1 -0
  207. package/dist/pipeline/dev-checks.js.map +1 -1
  208. package/dist/pipeline/env-codes.cjs +3 -2
  209. package/dist/pipeline/env-codes.cjs.map +1 -1
  210. package/dist/pipeline/env-codes.js +3 -2
  211. package/dist/pipeline/env-codes.js.map +1 -1
  212. package/dist/pipeline/perf-codes.cjs +1 -0
  213. package/dist/pipeline/perf-codes.cjs.map +1 -1
  214. package/dist/pipeline/perf-codes.js +1 -0
  215. package/dist/pipeline/perf-codes.js.map +1 -1
  216. package/dist/pipeline/row.cjs +8 -7
  217. package/dist/pipeline/row.cjs.map +1 -1
  218. package/dist/pipeline/row.js +8 -7
  219. package/dist/pipeline/row.js.map +1 -1
  220. package/dist/pipeline/runner.cjs +17 -9
  221. package/dist/pipeline/runner.cjs.map +1 -1
  222. package/dist/pipeline/runner.js +17 -9
  223. package/dist/pipeline/runner.js.map +1 -1
  224. package/dist/pipeline/slice.cjs +3 -1
  225. package/dist/pipeline/slice.cjs.map +1 -1
  226. package/dist/pipeline/slice.js +3 -1
  227. package/dist/pipeline/slice.js.map +1 -1
  228. package/dist/schema.d.cts +2 -2
  229. package/dist/schema.d.ts +2 -2
  230. package/dist/{search-async-entry-C3mXxLP8.d.cts → search-async-entry-CuLYPfY_.d.cts} +2 -2
  231. package/dist/{search-async-entry-BmQYT120.d.ts → search-async-entry-Cx7xpuVZ.d.ts} +2 -2
  232. package/dist/search-async.d.cts +3 -3
  233. package/dist/search-async.d.ts +3 -3
  234. package/dist/search.d.cts +8 -6
  235. package/dist/search.d.ts +8 -6
  236. package/dist/server.d.cts +3 -3
  237. package/dist/server.d.ts +3 -3
  238. package/dist/sorting.d.cts +6 -3
  239. package/dist/sorting.d.ts +6 -3
  240. package/dist/source/codes.cjs +1 -0
  241. package/dist/source/codes.cjs.map +1 -1
  242. package/dist/source/codes.js +1 -0
  243. package/dist/source/codes.js.map +1 -1
  244. package/dist/source/fetch-codes.cjs +1 -0
  245. package/dist/source/fetch-codes.cjs.map +1 -1
  246. package/dist/source/fetch-codes.js +1 -0
  247. package/dist/source/fetch-codes.js.map +1 -1
  248. package/dist/table/codes.cjs +1 -0
  249. package/dist/table/codes.cjs.map +1 -1
  250. package/dist/table/codes.js +1 -0
  251. package/dist/table/codes.js.map +1 -1
  252. package/dist/table/create-table.cjs +39 -9
  253. package/dist/table/create-table.cjs.map +1 -1
  254. package/dist/table/create-table.js +39 -9
  255. package/dist/table/create-table.js.map +1 -1
  256. package/dist/table/data-mutation.cjs +1 -0
  257. package/dist/table/data-mutation.cjs.map +1 -1
  258. package/dist/table/data-mutation.js +1 -0
  259. package/dist/table/data-mutation.js.map +1 -1
  260. package/dist/table/internals.cjs.map +1 -1
  261. package/dist/table/internals.js.map +1 -1
  262. package/dist/table/ssr-codes.cjs +1 -0
  263. package/dist/table/ssr-codes.cjs.map +1 -1
  264. package/dist/table/ssr-codes.js +1 -0
  265. package/dist/table/ssr-codes.js.map +1 -1
  266. package/dist/table/ssr.cjs +4 -1
  267. package/dist/table/ssr.cjs.map +1 -1
  268. package/dist/table/ssr.js +4 -1
  269. package/dist/table/ssr.js.map +1 -1
  270. package/dist/table/state-feedback.cjs +19 -0
  271. package/dist/table/state-feedback.cjs.map +1 -1
  272. package/dist/table/state-feedback.js +19 -0
  273. package/dist/table/state-feedback.js.map +1 -1
  274. package/dist/table/types.cjs.map +1 -1
  275. package/dist/table/types.js.map +1 -1
  276. package/dist/validity.d.cts +2 -2
  277. package/dist/validity.d.ts +2 -2
  278. package/dist/version.cjs +1 -1
  279. package/dist/version.cjs.map +1 -1
  280. package/dist/version.js +1 -1
  281. package/dist/version.js.map +1 -1
  282. package/dist/versioning/codes.cjs +18 -0
  283. package/dist/versioning/codes.cjs.map +1 -1
  284. package/dist/versioning/codes.js +18 -0
  285. package/dist/versioning/codes.js.map +1 -1
  286. package/dist/versioning/registry.cjs +4 -2
  287. package/dist/versioning/registry.cjs.map +1 -1
  288. package/dist/versioning/registry.js +4 -2
  289. package/dist/versioning/registry.js.map +1 -1
  290. package/package.json +39 -3
@@ -1,6 +1,8 @@
1
1
  // src/pipeline/runner.ts
2
2
  import { getValue } from "../column/get-value.js";
3
3
  import { keepDiagnostics } from "../diagnostics/catalog.js";
4
+ import "../diagnostics/process-guard.js";
5
+ import { SLICED, sliceTimer } from "../diagnostics/trace-store.js";
4
6
  import { featureDiagnostics } from "../feature/codes.js";
5
7
  import { matchCellIssues } from "../ingest/cell-issues.js";
6
8
  import { resolveRowKeys } from "../ingest/row-key.js";
@@ -52,7 +54,8 @@ function createPipeline(host) {
52
54
  // Not during SSR, and not for the first row model (the hydrated client matches the server).
53
55
  enabled: () => refresh !== void 0 && last !== void 0 && host.base().phase === "client",
54
56
  trigger: () => host.base().trigger,
55
- done: (trigger) => refresh?.(trigger)
57
+ done: (trigger) => refresh?.(trigger),
58
+ timed: (feature, ms) => sliceTimer.current?.(host.base(), feature, ms)
56
59
  });
57
60
  function reportCell(col, index, e, field) {
58
61
  const name = errorName(e);
@@ -63,7 +66,7 @@ function createPipeline(host) {
63
66
  column: col.id,
64
67
  rows: [index],
65
68
  count: 1,
66
- fallback: "the cell reads as undefined",
69
+ fallback: "cell-undefined",
67
70
  ...name === void 0 ? {} : { errorName: name }
68
71
  },
69
72
  { cause: e }
@@ -118,7 +121,7 @@ function createPipeline(host) {
118
121
  slot: "rowKey",
119
122
  rows: Array.from(keyFailures.sample()),
120
123
  count: keyFailures.count,
121
- fallback: "those rows use the fallback key '#<index>'",
124
+ fallback: "row-key-index",
122
125
  ...name === void 0 ? {} : { errorName: name }
123
126
  },
124
127
  { cause: keyError }
@@ -178,6 +181,10 @@ function createPipeline(host) {
178
181
  const col = cols.byId.get(id);
179
182
  return col ? cache.formatted(data, col) : void 0;
180
183
  },
184
+ *formattedSliced(id) {
185
+ const col = cols.byId.get(id);
186
+ return col ? yield* cache.formattedSliced(data, col) : void 0;
187
+ },
181
188
  batch: (id, slot, rows, body) => {
182
189
  const col = cols.byId.get(id);
183
190
  if (col) cache.batch(col, slot, slot, rows, body);
@@ -221,13 +228,14 @@ function createPipeline(host) {
221
228
  {
222
229
  feature: f.name,
223
230
  hook: "rowModel",
224
- fallback: "the step passed its input through",
231
+ fallback: "step-passthrough",
225
232
  ...name === void 0 ? {} : { errorName: name }
226
233
  },
227
234
  { cause: e }
228
235
  );
229
236
  return input;
230
237
  }
238
+ if (waiting > waited) ctx2.meta.set(SLICED, true);
231
239
  if (process.env.NODE_ENV !== "production" && !checkStep(stepEmit, f.name, input, before, out, data.length)) return input;
232
240
  ok = true;
233
241
  return out instanceof Uint32Array ? out : input;
@@ -262,11 +270,11 @@ function createPipeline(host) {
262
270
  });
263
271
  } finally {
264
272
  slicer?.end();
265
- }
266
- if (result) model = result;
267
- else {
268
- const isInitialLoad = host.isInitialLoad();
269
- model = last ? { ...last.model, status: "error", isInitialLoad } : { rows: EMPTY, filteredCount: 0, totalCount: 0, status: "error", isInitialLoad };
273
+ if (result) model = result;
274
+ else {
275
+ const isInitialLoad = host.isInitialLoad();
276
+ model = last ? { ...last.model, status: "error", isInitialLoad } : { rows: EMPTY, filteredCount: 0, totalCount: 0, status: "error", isInitialLoad };
277
+ }
270
278
  }
271
279
  return model;
272
280
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/pipeline/runner.ts"],"sourcesContent":["import { getValue } from '../column/get-value'\nimport { keepDiagnostics } from '../diagnostics/catalog'\nimport type { Emit, Trigger } from '../diagnostics/types'\nimport { featureDiagnostics } from '../feature/codes'\nimport type { FeatureRuntime } from '../feature/runtime'\nimport type { AnyFeature, RowModelContext } from '../feature/types'\nimport { matchCellIssues } from '../ingest/cell-issues'\nimport { type KeyOf, resolveRowKeys } from '../ingest/row-key'\nimport { CellFailures } from '../intercept/cell-batch'\nimport { errorName } from '../intercept/classify'\nimport { type ContextBase, createContext } from '../intercept/context'\nimport { FALLBACK } from '../intercept/fallbacks'\nimport type { InterceptorRuntime } from '../intercept/runtime'\nimport type { TableState } from '../table/types'\nimport type { ColumnCache } from './column-cache'\nimport { type ResolvedColumn, type ResolvedColumns, resolveColumns } from './columns'\nimport { checkStep, indexPrint, stepDiagnostics } from './dev-checks'\nimport { allRows } from './indices'\nimport { lazyRows, Row, type RowIssue, type RowSource } from './row'\nimport type { Slicer } from './slice'\nimport { inStepDiagnosticSetsError } from './status-rule'\nimport type { RowModel, RowModelStatus } from './types'\n\nkeepDiagnostics(featureDiagnostics, stepDiagnostics)\n\nconst EMPTY: readonly never[] = []\nconst NO_EMIT = (() => undefined) as Emit\n\n/** What `createTable` gives the runner. */\nexport interface PipelineHost {\n readonly runtime: InterceptorRuntime\n /**\n * What the features brought (`runtimeFor`): the column cache and time-slicing of their steps.\n * Always set when a feature has a `rowModel`; a table without features runs no step.\n */\n readonly featureRuntime?: FeatureRuntime | undefined\n readonly emit: Emit\n /** Installed features in pipeline (stage) order. */\n readonly features: readonly AnyFeature[]\n /** `options.features` in the listed order: `where` = `features[<listed index>].rowModel`. */\n readonly listed: readonly AnyFeature[]\n base(): ContextBase\n /** Starts a pipeline run: increments and returns the run id. */\n nextRun(): number\n getData(): readonly unknown[]\n getState(): TableState\n getColumns(): readonly unknown[] | undefined\n getRowKey(): unknown\n /** `RowModel.isInitialLoad`: no data applied yet (§6.6). */\n isInitialLoad(): boolean\n /**\n * The table's status outside the pipeline (`'validating'`, `'error'` after a failed ingest, …);\n * a step failing in this run makes the row model `'error'` regardless.\n */\n status(): RowModelStatus\n /** Schema issues of a flagged row by data index (`invalidRows: 'flag'`); else `undefined`. */\n issues(index: number): readonly RowIssue[] | undefined\n /** `schema` + `invalidRows: 'flag'` (read once): steps get `RowModelContext.flagged`. */\n readonly flagMode?: boolean\n /**\n * Time-sliced work (§9.1, `RowModelContext.slice`) ended: recompute the row model and notify,\n * under the trigger of the run that started it. Without it nothing is sliced.\n */\n refresh?(trigger: Trigger): void\n}\n\nexport interface Pipeline<T> {\n /** Runs `pipeline:run` and returns the row model (the previous object when nothing changed). */\n run(): RowModel<T>\n /** The last row model, if the pipeline ran. */\n current(): RowModel<T> | undefined\n /** The last run (`explain`, §8.4); `undefined` before the first. */\n lastRun(): RunRecord | undefined\n /**\n * A `rowModel` context over the current data and columns for replaying a step on chosen rows\n * (`explainRow`, §8.4): diagnostics are dropped and `batch` runs its body directly (no\n * interceptors), so a replay reports nothing and changes nothing.\n */\n replayContext(name: string): RowModelContext\n /** Cancels time-sliced work in progress (`destroy()`). */\n dispose(): void\n}\n\n/**\n * One step of the last run (`explain` / `explainRow`, §8.4): references to the index arrays the\n * step memo holds anyway, never copies. `cached`: served from the memo; `failed`: the step threw or\n * returned a bad output and passed its input through.\n */\nexport interface RunRecord {\n readonly run: number\n readonly trigger: Trigger\n /** The client steps that ran, in order (fewer when `pipeline:run` itself failed). */\n readonly steps: readonly StepRecord[]\n}\n\nexport interface StepRecord {\n readonly feature: AnyFeature\n readonly input: Uint32Array\n readonly output: Uint32Array\n readonly cached: boolean\n readonly failed: boolean\n}\n\ninterface StepMemo {\n input: Uint32Array\n state: unknown\n columns: readonly unknown[]\n output: Uint32Array\n}\n\ninterface Built<T> {\n model: RowModel<T>\n data: readonly unknown[]\n indices: Uint32Array\n columns: readonly unknown[]\n rowKey: unknown\n}\n\n/**\n * The index-based pipeline (§3.3, §9.1): each step consumes and produces a `Uint32Array` of row\n * indices, is memoised on (input reference, own slice, columns), and `Row` objects are created only\n * for the final (visible) indices, each when it is first read.\n */\nexport function createPipeline<T>(host: PipelineHost): Pipeline<T> {\n /**\n * In-step diagnostics the §6.6 status rule counts (`inStepDiagnosticSetsError`), ever reported:\n * a step whose run moved it makes the row model `'error'` and is not memoised.\n */\n const flags = { count: 0 }\n /** `emit` for steps and the column cache: counts through the status rule. */\n const stepEmit = ((code, details, options) => {\n if (inStepDiagnosticSetsError(code)) flags.count++\n host.emit(code, details, options)\n }) as Emit\n const rt = host.featureRuntime\n // Only steps (and explainRow's replay of them) read the cache: they exist only with a runtime.\n const cache = rt?.createColumnCache({\n runtime: host.runtime,\n emit: stepEmit,\n base: () => host.base(),\n flags,\n }) as ColumnCache\n // A server-mode feature (§7.1) only holds state: the server ran its step.\n const steps = host.features.filter(\n (f) => f.stage !== 'none' && f.mode !== 'server' && typeof f.rowModel === 'function',\n )\n const where = new Map(steps.map((f) => [f, `features[${host.listed.indexOf(f)}].rowModel`]))\n const memo = new Map<AnyFeature, StepMemo>()\n const sources = new WeakMap<ResolvedColumns, RowSource>()\n const keyFailures = new CellFailures()\n /** The first `rowKey` error of the current build (its `cause`). */\n let keyError: unknown\n const keyFailed = (index: number, e: unknown) => {\n if (keyFailures.count === 0) keyError = e\n keyFailures.add(index, e)\n }\n let last: Built<T> | undefined\n /** Row keys resolved over all rows (§5.2), per (data, rowKey) reference. */\n let keys: { data: readonly unknown[]; rowKey: unknown; keyOf: KeyOf } | undefined\n let model: RowModel<T> | undefined\n /** The last run (replaced per run; a few references per step). */\n let lastRun: RunRecord | undefined\n /** Steps of the current run waiting on time-sliced work (§9.1): the row model is 'pending'. */\n let waiting = 0\n const refresh = host.refresh\n const slicer: Slicer | undefined = rt?.createSlicer({\n emit: stepEmit,\n // Not during SSR, and not for the first row model (the hydrated client matches the server).\n enabled: () => refresh !== undefined && last !== undefined && host.base().phase === 'client',\n trigger: () => host.base().trigger,\n done: (trigger) => refresh?.(trigger),\n })\n\n /** `Row.getValue` failures: one emit per failing cell, built only when a cell fails. */\n function reportCell(col: ResolvedColumn, index: number, e: unknown, field: string) {\n const name = errorName(e)\n host.emit(\n 'DK_CALLBACK_FAILED',\n {\n slot: `columns[${col.index}].${field}`,\n column: col.id,\n rows: [index],\n count: 1,\n fallback: 'the cell reads as undefined',\n ...(name === undefined ? {} : { errorName: name }),\n },\n { cause: e },\n )\n }\n // A key-path read error, captured by a closure made once (Row.getValue is per cell: no\n // allocation per call).\n let pathFailed = false\n let pathError: unknown\n const onPathError = (e: unknown) => {\n pathFailed = true\n pathError = e\n }\n\n function rowSource(cols: ResolvedColumns): RowSource {\n let s = sources.get(cols)\n if (s) return s\n s = {\n value(index, original, id) {\n const col = cols.byId.get(id)\n if (!col) return undefined\n if (col.path) {\n const v = getValue(original, col.path, onPathError)\n if (pathFailed) {\n const e = pathError\n pathFailed = false\n pathError = undefined\n reportCell(col, index, e, 'key')\n }\n return v\n }\n if (!col.accessor) return undefined\n try {\n return col.accessor(original)\n } catch (e) {\n reportCell(col, index, e, 'accessor')\n return undefined\n }\n },\n issues: (index) => host.issues(index),\n cellIssues(issues, id) {\n const col = cols.byId.get(id)\n return col ? matchCellIssues(issues, col.path) : EMPTY\n },\n }\n sources.set(cols, s)\n return s\n }\n\n function reportKeyFailures() {\n if (keyFailures.count === 0) return\n const name = errorName(keyError)\n host.emit(\n 'DK_CALLBACK_FAILED',\n {\n slot: 'rowKey',\n rows: Array.from(keyFailures.sample()),\n count: keyFailures.count,\n fallback: \"those rows use the fallback key '#<index>'\",\n ...(name === undefined ? {} : { errorName: name }),\n },\n { cause: keyError },\n )\n keyFailures.reset()\n keyError = undefined\n }\n\n function build(\n data: readonly unknown[],\n indices: Uint32Array,\n columns: readonly unknown[],\n filteredCount: number,\n status: RowModelStatus,\n ): RowModel<T> {\n const rowKey = host.getRowKey()\n const isInitialLoad = host.isInitialLoad()\n const prev = last\n if (\n prev &&\n prev.indices === indices &&\n prev.data === data &&\n prev.columns === columns &&\n prev.rowKey === rowKey &&\n prev.model.status === status &&\n prev.model.isInitialLoad === isInitialLoad\n ) {\n return prev.model\n }\n const source = rowSource(resolveColumns(columns))\n keyFailures.reset()\n if (keys?.data !== data || keys.rowKey !== rowKey) {\n keys = { data, rowKey, keyOf: resolveRowKeys(data, rowKey, host.emit, keyFailed) }\n }\n const keyOf = keys.keyOf\n reportKeyFailures()\n // A data array whose rows cannot be read fails this run (the last good row model is kept),\n // not a later read of `rows[i]`.\n for (let i = 0; i < indices.length; i++) void data[indices[i] as number]\n // Rows are built when read (§9.3: no Row per visible row up front). The key scan above read\n // every key; one that throws only now is reported now.\n const rows = lazyRows(indices.length, (i) => {\n const r = indices[i] as number\n const original = data[r] as T\n const row = new Row<T>(source, r, keyOf(original, r), original)\n reportKeyFailures()\n return row\n })\n const m: RowModel<T> = { rows, filteredCount, totalCount: data.length, status, isInitialLoad }\n last = { model: m, data, indices, columns, rowKey }\n return m\n }\n\n function run(): RowModel<T> {\n host.nextRun()\n const data = host.getData()\n const columns = host.getColumns() ?? EMPTY\n const cols = resolveColumns(columns)\n const state = host.getState()\n let failed = false\n let result: RowModel<T> | undefined\n const records: StepRecord[] = []\n const { run: runId, trigger } = host.base()\n lastRun = { run: runId, trigger, steps: records }\n\n const rowModelContext = (name: string): RowModelContext => ({\n name,\n data,\n emit: stepEmit,\n ...(host.flagMode ? { flagged: (i: number) => host.issues(i) } : {}),\n run: host.base().run,\n columns,\n getColumnValues: (id) => {\n const col = cols.byId.get(id)\n return col ? cache.values(data, col) : undefined\n },\n getFormattedValues: (id) => {\n const col = cols.byId.get(id)\n return col ? cache.formatted(data, col) : undefined\n },\n batch: (id, slot, rows, body) => {\n const col = cols.byId.get(id)\n if (col) cache.batch(col, slot, slot, rows, body)\n return col !== undefined\n },\n slice: (key, job) => {\n const r = (slicer as Slicer).run(key, job, name)\n if (r === undefined) waiting++\n return r\n },\n })\n\n function step(f: AnyFeature, input: Uint32Array): Uint32Array {\n const slice = state[f.name]\n const m = memo.get(f)\n if (m && m.input === input && Object.is(m.state, slice) && m.columns === columns) {\n records.push({ feature: f, input, output: m.output, cached: true, failed: false })\n return m.output\n }\n let ok = false\n const flagged = flags.count\n const waited = waiting\n const ctx = createContext(\n 'pipeline:step',\n { stage: f.stage, feature: f.name, indices: input },\n where.get(f) as string,\n host.base(),\n )\n const output = host.runtime.run('pipeline:step', ctx, () => {\n let out: unknown\n // Dev check (§3.4 devChecks): a bounded fingerprint of the input before rowModel runs.\n const before = (process.env.NODE_ENV !== \"production\") ? indexPrint(input) : 0\n try {\n out = (f.rowModel as NonNullable<AnyFeature['rowModel']>)(\n input,\n slice,\n rowModelContext(f.name),\n )\n } catch (e) {\n const name = errorName(e)\n host.emit(\n 'DK_FEATURE_FAILED',\n {\n feature: f.name,\n hook: 'rowModel',\n fallback: 'the step passed its input through',\n ...(name === undefined ? {} : { errorName: name }),\n },\n { cause: e },\n )\n return input\n }\n // Dev: a mutated input warns; a bad output passes the input through, not memoised.\n if ((process.env.NODE_ENV !== \"production\") && !checkStep(stepEmit, f.name, input, before, out, data.length)) return input\n ok = true\n return out instanceof Uint32Array ? out : input\n })\n // A counted in-step diagnostic (status rule): 'error' with the step's output, re-run next time.\n // A step waiting on sliced work returned a stand-in: re-run next time too.\n if (ok && flags.count === flagged) {\n if (waiting === waited) memo.set(f, { input, state: slice, columns, output })\n else memo.delete(f)\n } else {\n failed = true\n memo.delete(f)\n }\n records.push({ feature: f, input, output, cached: false, failed: !ok })\n return output\n }\n\n const ctx = createContext('pipeline:run', { rowCount: data.length }, 'features', host.base())\n // The last good row model (§3.4): its indices; the runner keeps the matching rows below.\n if (last) ctx.meta.set(FALLBACK, last.indices)\n waiting = 0\n slicer?.begin()\n try {\n void host.runtime.run('pipeline:run', ctx, () => {\n let indices = allRows(data)\n let filteredCount = -1\n for (const f of steps) {\n if (f.stage === 'paginate' && filteredCount < 0) filteredCount = indices.length\n indices = step(f, indices)\n }\n if (filteredCount < 0) filteredCount = indices.length\n // Sliced work in progress is 'pending', below every other status (§6.6 precedence).\n const outside = host.status()\n const status = failed ? 'error' : waiting > 0 && outside === 'idle' ? 'pending' : outside\n result = build(data, indices, columns, filteredCount, status)\n return indices\n })\n } finally {\n // Sliced work no step asked for in this run is stale: cancelled.\n slicer?.end()\n }\n if (result) model = result\n else {\n // pipeline:run failed: the boundary reported it; keep the last good rows.\n const isInitialLoad = host.isInitialLoad()\n model = last\n ? { ...last.model, status: 'error', isInitialLoad }\n : { rows: EMPTY, filteredCount: 0, totalCount: 0, status: 'error', isInitialLoad }\n }\n return model\n }\n\n function replayContext(name: string): RowModelContext {\n const data = host.getData()\n const columns = host.getColumns() ?? EMPTY\n const cols = resolveColumns(columns)\n return {\n name,\n data,\n emit: NO_EMIT,\n ...(host.flagMode ? { flagged: (i: number) => host.issues(i) } : {}),\n run: host.base().run,\n columns,\n getColumnValues: (id) => {\n const col = cols.byId.get(id)\n return col ? cache.values(data, col) : undefined\n },\n getFormattedValues: (id) => {\n const col = cols.byId.get(id)\n return col ? cache.formatted(data, col) : undefined\n },\n batch: (id, _slot, _rows, body) => {\n if (!cols.byId.has(id)) return false\n body()\n return true\n },\n }\n }\n\n return {\n run,\n current: () => model,\n lastRun: () => lastRun,\n replayContext,\n dispose: () => slicer?.cancel(),\n }\n}\n"],"mappings":"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","names":["ctx"]}
1
+ {"version":3,"sources":["../../src/pipeline/runner.ts"],"sourcesContent":["import { getValue } from '../column/get-value'\nimport { keepDiagnostics } from '../diagnostics/catalog'\nimport '../diagnostics/process-guard'\nimport { SLICED, sliceTimer } from '../diagnostics/trace-store'\nimport type { Emit, Trigger } from '../diagnostics/types'\nimport { featureDiagnostics } from '../feature/codes'\nimport type { FeatureRuntime } from '../feature/runtime'\nimport type { AnyFeature, RowModelContext } from '../feature/types'\nimport { matchCellIssues } from '../ingest/cell-issues'\nimport { type KeyOf, resolveRowKeys } from '../ingest/row-key'\nimport { CellFailures } from '../intercept/cell-batch'\nimport { errorName } from '../intercept/classify'\nimport { type ContextBase, createContext } from '../intercept/context'\nimport { FALLBACK } from '../intercept/fallbacks'\nimport type { InterceptorRuntime } from '../intercept/runtime'\nimport type { TableState } from '../table/types'\nimport type { ColumnCache, SlicedFormatting } from './column-cache'\nimport { type ResolvedColumn, type ResolvedColumns, resolveColumns } from './columns'\nimport { checkStep, indexPrint, stepDiagnostics } from './dev-checks'\nimport { allRows } from './indices'\nimport { lazyRows, Row, type RowIssue, type RowSource } from './row'\nimport type { Slicer } from './slice'\nimport { inStepDiagnosticSetsError } from './status-rule'\nimport type { RowModel, RowModelStatus } from './types'\n\nkeepDiagnostics(featureDiagnostics, stepDiagnostics)\n\nconst EMPTY: readonly never[] = []\nconst NO_EMIT = (() => undefined) as Emit\n\n/** What `createTable` gives the runner. */\nexport interface PipelineHost {\n readonly runtime: InterceptorRuntime\n /**\n * What the features brought (`runtimeFor`): the column cache and time-slicing of their steps.\n * Always set when a feature has a `rowModel`; a table without features runs no step.\n */\n readonly featureRuntime?: FeatureRuntime | undefined\n readonly emit: Emit\n /** Installed features in pipeline (stage) order. */\n readonly features: readonly AnyFeature[]\n /** `options.features` in the listed order: `where` = `features[<listed index>].rowModel`. */\n readonly listed: readonly AnyFeature[]\n base(): ContextBase\n /** Starts a pipeline run: increments and returns the run id. */\n nextRun(): number\n getData(): readonly unknown[]\n getState(): TableState\n getColumns(): readonly unknown[] | undefined\n getRowKey(): unknown\n /** `RowModel.isInitialLoad`: no data applied yet (§6.6). */\n isInitialLoad(): boolean\n /**\n * The table's status outside the pipeline (`'validating'`, `'error'` after a failed ingest, …);\n * a step failing in this run makes the row model `'error'` regardless.\n */\n status(): RowModelStatus\n /** Schema issues of a flagged row by data index (`invalidRows: 'flag'`); else `undefined`. */\n issues(index: number): readonly RowIssue[] | undefined\n /** `schema` + `invalidRows: 'flag'` (read once): steps get `RowModelContext.flagged`. */\n readonly flagMode?: boolean\n /**\n * Time-sliced work (§9.1, `RowModelContext.slice`) ended: recompute the row model and notify,\n * under the trigger of the run that started it. Without it nothing is sliced.\n */\n refresh?(trigger: Trigger): void\n}\n\nexport interface Pipeline<T> {\n /** Runs `pipeline:run` and returns the row model (the previous object when nothing changed). */\n run(): RowModel<T>\n /** The last row model, if the pipeline ran. */\n current(): RowModel<T> | undefined\n /** The last run (`explain`, §8.4); `undefined` before the first. */\n lastRun(): RunRecord | undefined\n /**\n * A `rowModel` context over the current data and columns for replaying a step on chosen rows\n * (`explainRow`, §8.4): diagnostics are dropped and `batch` runs its body directly (no\n * interceptors), so a replay reports nothing and changes nothing.\n */\n replayContext(name: string): RowModelContext\n /** Cancels time-sliced work in progress (`destroy()`). */\n dispose(): void\n}\n\n/**\n * One step of the last run (`explain` / `explainRow`, §8.4): references to the index arrays the\n * step memo holds anyway, never copies. `cached`: served from the memo; `failed`: the step threw or\n * returned a bad output and passed its input through.\n */\nexport interface RunRecord {\n readonly run: number\n readonly trigger: Trigger\n /** The client steps that ran, in order (fewer when `pipeline:run` itself failed). */\n readonly steps: readonly StepRecord[]\n}\n\nexport interface StepRecord {\n readonly feature: AnyFeature\n readonly input: Uint32Array\n readonly output: Uint32Array\n readonly cached: boolean\n readonly failed: boolean\n}\n\ninterface StepMemo {\n input: Uint32Array\n state: unknown\n columns: readonly unknown[]\n output: Uint32Array\n}\n\ninterface Built<T> {\n model: RowModel<T>\n data: readonly unknown[]\n indices: Uint32Array\n columns: readonly unknown[]\n rowKey: unknown\n}\n\n/**\n * The index-based pipeline (§3.3, §9.1): each step consumes and produces a `Uint32Array` of row\n * indices, is memoised on (input reference, own slice, columns), and `Row` objects are created only\n * for the final (visible) indices, each when it is first read.\n */\nexport function createPipeline<T>(host: PipelineHost): Pipeline<T> {\n /**\n * In-step diagnostics the §6.6 status rule counts (`inStepDiagnosticSetsError`), ever reported:\n * a step whose run moved it makes the row model `'error'` and is not memoised.\n */\n const flags = { count: 0 }\n /** `emit` for steps and the column cache: counts through the status rule. */\n const stepEmit = ((code, details, options) => {\n if (inStepDiagnosticSetsError(code)) flags.count++\n host.emit(code, details, options)\n }) as Emit\n const rt = host.featureRuntime\n // Only steps (and explainRow's replay of them) read the cache: they exist only with a runtime.\n const cache = rt?.createColumnCache({\n runtime: host.runtime,\n emit: stepEmit,\n base: () => host.base(),\n flags,\n }) as ColumnCache\n // A server-mode feature (§7.1) only holds state: the server ran its step.\n const steps = host.features.filter(\n (f) => f.stage !== 'none' && f.mode !== 'server' && typeof f.rowModel === 'function',\n )\n const where = new Map(steps.map((f) => [f, `features[${host.listed.indexOf(f)}].rowModel`]))\n const memo = new Map<AnyFeature, StepMemo>()\n const sources = new WeakMap<ResolvedColumns, RowSource>()\n const keyFailures = new CellFailures()\n /** The first `rowKey` error of the current build (its `cause`). */\n let keyError: unknown\n const keyFailed = (index: number, e: unknown) => {\n if (keyFailures.count === 0) keyError = e\n keyFailures.add(index, e)\n }\n let last: Built<T> | undefined\n /** Row keys resolved over all rows (§5.2), per (data, rowKey) reference. */\n let keys: { data: readonly unknown[]; rowKey: unknown; keyOf: KeyOf } | undefined\n let model: RowModel<T> | undefined\n /** The last run (replaced per run; a few references per step). */\n let lastRun: RunRecord | undefined\n /** Steps of the current run waiting on time-sliced work (§9.1): the row model is 'pending'. */\n let waiting = 0\n const refresh = host.refresh\n const slicer: Slicer | undefined = rt?.createSlicer({\n emit: stepEmit,\n // Not during SSR, and not for the first row model (the hydrated client matches the server).\n enabled: () => refresh !== undefined && last !== undefined && host.base().phase === 'client',\n trigger: () => host.base().trigger,\n done: (trigger) => refresh?.(trigger),\n timed: (feature, ms) => sliceTimer.current?.(host.base(), feature, ms),\n })\n\n /** `Row.getValue` failures: one emit per failing cell, built only when a cell fails. */\n function reportCell(col: ResolvedColumn, index: number, e: unknown, field: string) {\n const name = errorName(e)\n host.emit(\n 'DK_CALLBACK_FAILED',\n {\n slot: `columns[${col.index}].${field}`,\n column: col.id,\n rows: [index],\n count: 1,\n fallback: 'cell-undefined',\n ...(name === undefined ? {} : { errorName: name }),\n },\n { cause: e },\n )\n }\n // A key-path read error, captured by a closure made once (Row.getValue is per cell: no\n // allocation per call).\n let pathFailed = false\n let pathError: unknown\n const onPathError = (e: unknown) => {\n pathFailed = true\n pathError = e\n }\n\n function rowSource(cols: ResolvedColumns): RowSource {\n let s = sources.get(cols)\n if (s) return s\n s = {\n value(index, original, id) {\n const col = cols.byId.get(id)\n if (!col) return undefined\n if (col.path) {\n const v = getValue(original, col.path, onPathError)\n if (pathFailed) {\n const e = pathError\n pathFailed = false\n pathError = undefined\n reportCell(col, index, e, 'key')\n }\n return v\n }\n if (!col.accessor) return undefined\n try {\n return col.accessor(original)\n } catch (e) {\n reportCell(col, index, e, 'accessor')\n return undefined\n }\n },\n issues: (index) => host.issues(index),\n cellIssues(issues, id) {\n const col = cols.byId.get(id)\n return col ? matchCellIssues(issues, col.path) : EMPTY\n },\n }\n sources.set(cols, s)\n return s\n }\n\n function reportKeyFailures() {\n if (keyFailures.count === 0) return\n const name = errorName(keyError)\n host.emit(\n 'DK_CALLBACK_FAILED',\n {\n slot: 'rowKey',\n rows: Array.from(keyFailures.sample()),\n count: keyFailures.count,\n fallback: 'row-key-index',\n ...(name === undefined ? {} : { errorName: name }),\n },\n { cause: keyError },\n )\n keyFailures.reset()\n keyError = undefined\n }\n\n function build(\n data: readonly unknown[],\n indices: Uint32Array,\n columns: readonly unknown[],\n filteredCount: number,\n status: RowModelStatus,\n ): RowModel<T> {\n const rowKey = host.getRowKey()\n const isInitialLoad = host.isInitialLoad()\n const prev = last\n if (\n prev &&\n prev.indices === indices &&\n prev.data === data &&\n prev.columns === columns &&\n prev.rowKey === rowKey &&\n prev.model.status === status &&\n prev.model.isInitialLoad === isInitialLoad\n ) {\n return prev.model\n }\n const source = rowSource(resolveColumns(columns))\n keyFailures.reset()\n if (keys?.data !== data || keys.rowKey !== rowKey) {\n keys = { data, rowKey, keyOf: resolveRowKeys(data, rowKey, host.emit, keyFailed) }\n }\n const keyOf = keys.keyOf\n reportKeyFailures()\n // A data array whose rows cannot be read fails this run (the last good row model is kept),\n // not a later read of `rows[i]`.\n for (let i = 0; i < indices.length; i++) void data[indices[i] as number]\n // Rows are built when read (§9.3: no Row per visible row up front). The key scan above read\n // every key; one that throws only now is reported now.\n const rows = lazyRows(indices.length, (i) => {\n const r = indices[i] as number\n const original = data[r] as T\n const row = new Row<T>(source, r, keyOf(original, r), original)\n reportKeyFailures()\n return row\n })\n const m: RowModel<T> = { rows, filteredCount, totalCount: data.length, status, isInitialLoad }\n last = { model: m, data, indices, columns, rowKey }\n return m\n }\n\n function run(): RowModel<T> {\n host.nextRun()\n const data = host.getData()\n const columns = host.getColumns() ?? EMPTY\n const cols = resolveColumns(columns)\n const state = host.getState()\n let failed = false\n let result: RowModel<T> | undefined\n const records: StepRecord[] = []\n const { run: runId, trigger } = host.base()\n lastRun = { run: runId, trigger, steps: records }\n\n const rowModelContext = (name: string): RowModelContext & SlicedFormatting => ({\n name,\n data,\n emit: stepEmit,\n ...(host.flagMode ? { flagged: (i: number) => host.issues(i) } : {}),\n run: host.base().run,\n columns,\n getColumnValues: (id) => {\n const col = cols.byId.get(id)\n return col ? cache.values(data, col) : undefined\n },\n getFormattedValues: (id) => {\n const col = cols.byId.get(id)\n return col ? cache.formatted(data, col) : undefined\n },\n *formattedSliced(id) {\n const col = cols.byId.get(id)\n return col ? yield* cache.formattedSliced(data, col) : undefined\n },\n batch: (id, slot, rows, body) => {\n const col = cols.byId.get(id)\n if (col) cache.batch(col, slot, slot, rows, body)\n return col !== undefined\n },\n slice: (key, job) => {\n const r = (slicer as Slicer).run(key, job, name)\n if (r === undefined) waiting++\n return r\n },\n })\n\n function step(f: AnyFeature, input: Uint32Array): Uint32Array {\n const slice = state[f.name]\n const m = memo.get(f)\n if (m && m.input === input && Object.is(m.state, slice) && m.columns === columns) {\n records.push({ feature: f, input, output: m.output, cached: true, failed: false })\n return m.output\n }\n let ok = false\n const flagged = flags.count\n const waited = waiting\n const ctx = createContext(\n 'pipeline:step',\n { stage: f.stage, feature: f.name, indices: input },\n where.get(f) as string,\n host.base(),\n )\n const output = host.runtime.run('pipeline:step', ctx, () => {\n let out: unknown\n // Dev check (§3.4 devChecks): a bounded fingerprint of the input before rowModel runs.\n const before = (process.env.NODE_ENV !== \"production\") ? indexPrint(input) : 0\n try {\n out = (f.rowModel as NonNullable<AnyFeature['rowModel']>)(\n input,\n slice,\n rowModelContext(f.name),\n )\n } catch (e) {\n const name = errorName(e)\n host.emit(\n 'DK_FEATURE_FAILED',\n {\n feature: f.name,\n hook: 'rowModel',\n fallback: 'step-passthrough',\n ...(name === undefined ? {} : { errorName: name }),\n },\n { cause: e },\n )\n return input\n }\n // The tracer adds the time of this sliced work to the step (#61).\n if (waiting > waited) ctx.meta.set(SLICED, true)\n // Dev: a mutated input warns; a bad output passes the input through, not memoised.\n if ((process.env.NODE_ENV !== \"production\") && !checkStep(stepEmit, f.name, input, before, out, data.length)) return input\n ok = true\n return out instanceof Uint32Array ? out : input\n })\n // A counted in-step diagnostic (status rule): 'error' with the step's output, re-run next time.\n // A step waiting on sliced work returned a stand-in: re-run next time too.\n if (ok && flags.count === flagged) {\n if (waiting === waited) memo.set(f, { input, state: slice, columns, output })\n else memo.delete(f)\n } else {\n failed = true\n memo.delete(f)\n }\n records.push({ feature: f, input, output, cached: false, failed: !ok })\n return output\n }\n\n const ctx = createContext('pipeline:run', { rowCount: data.length }, 'features', host.base())\n // The last good row model (§3.4): its indices; the runner keeps the matching rows below.\n if (last) ctx.meta.set(FALLBACK, last.indices)\n waiting = 0\n slicer?.begin()\n try {\n void host.runtime.run('pipeline:run', ctx, () => {\n let indices = allRows(data)\n let filteredCount = -1\n for (const f of steps) {\n if (f.stage === 'paginate' && filteredCount < 0) filteredCount = indices.length\n indices = step(f, indices)\n }\n if (filteredCount < 0) filteredCount = indices.length\n // Sliced work in progress is 'pending', below every other status (§6.6 precedence).\n const outside = host.status()\n const status = failed ? 'error' : waiting > 0 && outside === 'idle' ? 'pending' : outside\n result = build(data, indices, columns, filteredCount, status)\n return indices\n })\n } finally {\n // Sliced work no step asked for in this run is stale: cancelled.\n slicer?.end()\n if (result) model = result\n else {\n // pipeline:run failed: the boundary reported it, or a strict throw is leaving the run\n // (#43). Either way the last good rows with status 'error', never an empty 'idle' model.\n const isInitialLoad = host.isInitialLoad()\n model = last\n ? { ...last.model, status: 'error', isInitialLoad }\n : { rows: EMPTY, filteredCount: 0, totalCount: 0, status: 'error', isInitialLoad }\n }\n }\n return model\n }\n\n function replayContext(name: string): RowModelContext {\n const data = host.getData()\n const columns = host.getColumns() ?? EMPTY\n const cols = resolveColumns(columns)\n return {\n name,\n data,\n emit: NO_EMIT,\n ...(host.flagMode ? { flagged: (i: number) => host.issues(i) } : {}),\n run: host.base().run,\n columns,\n getColumnValues: (id) => {\n const col = cols.byId.get(id)\n return col ? cache.values(data, col) : undefined\n },\n getFormattedValues: (id) => {\n const col = cols.byId.get(id)\n return col ? cache.formatted(data, col) : undefined\n },\n batch: (id, _slot, _rows, body) => {\n if (!cols.byId.has(id)) return false\n body()\n return true\n },\n }\n }\n\n return {\n run,\n current: () => model,\n lastRun: () => lastRun,\n replayContext,\n dispose: () => slicer?.cancel(),\n }\n}\n"],"mappings":"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","names":["ctx"]}
@@ -75,7 +75,9 @@ function createSlicer(host) {
75
75
  while (task.state === "running") {
76
76
  await pause(task.feature);
77
77
  if (task.state !== "running") return;
78
- advance(task, now() + SLICE_MS);
78
+ const start = now();
79
+ advance(task, start + SLICE_MS);
80
+ host.timed?.(task.feature, now() - start);
79
81
  }
80
82
  running.delete(task);
81
83
  host.done(task.trigger);
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/pipeline/slice.ts"],"sourcesContent":["import { keepDiagnostics } from '../diagnostics/catalog'\nimport type { Emit, Trigger } from '../diagnostics/types'\nimport { envDiagnostics } from './env-codes'\n\nkeepDiagnostics(envDiagnostics)\n\n/**\n * Time-sliced work (§9.1): a generator that `yield`s between chunks of work (every few thousand\n * rows). Its return value is the result.\n */\nexport type SliceJob<R> = () => Iterator<unknown, R, undefined>\n\n/**\n * One slice of work, in milliseconds. A job that finishes within it never goes async (small\n * tables keep synchronous row models); the slices of a longer one stay well under the 50 ms\n * long-task budget (§9.3) with the rest of the pipeline run around them.\n */\nexport const SLICE_MS = 8\n\nexport interface SlicerHost {\n readonly emit: Emit\n /** Slicing is allowed now: in the browser, after the table's first row model. */\n enabled(): boolean\n /** The trigger of the current run (a finished job recomputes under it). */\n trigger(): Trigger\n /** A job ended (its result or error is ready): recompute the row model and notify. */\n done(trigger: Trigger): void\n}\n\nexport interface Slicer {\n /**\n * The result of the job for `key`: started on the first call (one synchronous slice), then\n * `undefined` until it has finished. A job that threw rethrows here, in the step that asks.\n */\n run<R>(key: object, job: SliceJob<R>, feature: string): R | undefined\n /** Starts a pipeline run: jobs that no step asks for until {@link end} are cancelled. */\n begin(): void\n end(): void\n /** Cancels every job (`destroy()`). */\n cancel(): void\n}\n\n/** Runs `job` to completion (no slicing). */\nexport function runJob<R>(job: SliceJob<R>): R {\n const it = job()\n for (;;) {\n const r = it.next()\n if (r.done) return r.value\n }\n}\n\n/**\n * `ctx.slice(key, job)` where the runner provides it (a table run), else the whole job now. For\n * features: `undefined` means \"still running\" (return a stand-in).\n */\nexport function sliced<R>(\n ctx: { slice?: <X>(key: object, job: SliceJob<X>) => X | undefined },\n key: object,\n job: SliceJob<R>,\n): R | undefined {\n return ctx.slice ? ctx.slice(key, job) : runJob(job)\n}\n\ninterface Task {\n readonly key: object\n readonly it: Iterator<unknown, unknown, undefined>\n readonly trigger: Trigger\n readonly feature: string\n state: 'running' | 'done' | 'failed' | 'cancelled'\n value: unknown\n}\n\nconst now = (): number =>\n typeof performance === 'object' && typeof performance?.now === 'function'\n ? performance.now()\n : Date.now()\n\ntype Scheduler = { yield?: () => Promise<void> }\n\n/** Runs `task` until it ends or `deadline` passes (checked at each `yield`). */\nfunction advance(task: Task, deadline: number) {\n try {\n for (;;) {\n const r = task.it.next()\n if (r.done) {\n task.state = 'done'\n task.value = r.value\n return\n }\n if (now() >= deadline) return\n }\n } catch (e) {\n task.state = 'failed'\n task.value = e\n }\n}\n\n/**\n * The table's slicer (§9.1). Between slices it yields to the main thread with\n * `scheduler.yield()`, or `setTimeout` where that is missing (`DK_ENV_FALLBACK`, once per table).\n * Jobs are keyed by an object of the caller (e.g. the data / columns they read), so a job is\n * started once and its result is shared by later runs.\n */\nexport function createSlicer(host: SlicerHost): Slicer {\n const tasks = new WeakMap<object, Task>()\n const running = new Set<Task>()\n let asked: Set<Task> | undefined\n let reported = false\n\n function pause(feature: string): Promise<void> {\n const s = (globalThis as { scheduler?: Scheduler }).scheduler\n if (typeof s?.yield === 'function') return s.yield()\n if (!reported) {\n reported = true\n host.emit('DK_ENV_FALLBACK', { api: 'scheduler.yield', feature, fallback: 'setTimeout' })\n }\n return new Promise((resolve) => setTimeout(resolve, 0))\n }\n\n async function drive(task: Task) {\n while (task.state === 'running') {\n await pause(task.feature)\n if (task.state !== 'running') return\n advance(task, now() + SLICE_MS)\n }\n running.delete(task)\n host.done(task.trigger)\n }\n\n function result(task: Task): unknown {\n if (task.state === 'failed') throw task.value\n return task.state === 'done' ? task.value : undefined\n }\n\n return {\n run<R>(key: object, job: SliceJob<R>, feature: string): R | undefined {\n const known = tasks.get(key)\n if (known && known.state !== 'cancelled') {\n asked?.add(known)\n return result(known) as R | undefined\n }\n const task: Task = {\n key,\n it: job(),\n trigger: host.trigger(),\n feature,\n state: 'running',\n value: undefined,\n }\n tasks.set(key, task)\n advance(task, host.enabled() ? now() + SLICE_MS : Number.POSITIVE_INFINITY)\n if (task.state === 'running') {\n running.add(task)\n asked?.add(task)\n // `drive` never rejects: `advance` catches the job's errors, `done` is the table's.\n void drive(task).catch(() => {})\n }\n return result(task) as R | undefined\n },\n begin() {\n asked = new Set()\n },\n end() {\n const keep = asked\n asked = undefined\n if (!keep) return\n for (const task of running) {\n if (keep.has(task)) continue\n task.state = 'cancelled'\n running.delete(task)\n tasks.delete(task.key)\n }\n },\n cancel() {\n for (const task of running) {\n task.state = 'cancelled'\n tasks.delete(task.key)\n }\n running.clear()\n },\n }\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/pipeline/slice.ts"],"sourcesContent":["import { keepDiagnostics } from '../diagnostics/catalog'\nimport type { Emit, Trigger } from '../diagnostics/types'\nimport { envDiagnostics } from './env-codes'\n\nkeepDiagnostics(envDiagnostics)\n\n/**\n * Time-sliced work (§9.1): a generator that `yield`s between chunks of work (every few thousand\n * rows). Its return value is the result.\n */\nexport type SliceJob<R> = () => Iterator<unknown, R, undefined>\n\n/**\n * One slice of work, in milliseconds. A job that finishes within it never goes async (small\n * tables keep synchronous row models); the slices of a longer one stay well under the 50 ms\n * long-task budget (§9.3) with the rest of the pipeline run around them.\n */\nexport const SLICE_MS = 8\n\nexport interface SlicerHost {\n readonly emit: Emit\n /** Slicing is allowed now: in the browser, after the table's first row model. */\n enabled(): boolean\n /** The trigger of the current run (a finished job recomputes under it). */\n trigger(): Trigger\n /** A job ended (its result or error is ready): recompute the row model and notify. */\n done(trigger: Trigger): void\n /** A slice run between pipeline runs took `ms` (the tracer's, #61). */\n timed?(feature: string, ms: number): void\n}\n\nexport interface Slicer {\n /**\n * The result of the job for `key`: started on the first call (one synchronous slice), then\n * `undefined` until it has finished. A job that threw rethrows here, in the step that asks.\n */\n run<R>(key: object, job: SliceJob<R>, feature: string): R | undefined\n /** Starts a pipeline run: jobs that no step asks for until {@link end} are cancelled. */\n begin(): void\n end(): void\n /** Cancels every job (`destroy()`). */\n cancel(): void\n}\n\n/** Runs `job` to completion (no slicing). */\nexport function runJob<R>(job: SliceJob<R>): R {\n const it = job()\n for (;;) {\n const r = it.next()\n if (r.done) return r.value\n }\n}\n\n/**\n * `ctx.slice(key, job)` where the runner provides it (a table run), else the whole job now. For\n * features: `undefined` means \"still running\" (return a stand-in).\n */\nexport function sliced<R>(\n ctx: { slice?: <X>(key: object, job: SliceJob<X>) => X | undefined },\n key: object,\n job: SliceJob<R>,\n): R | undefined {\n return ctx.slice ? ctx.slice(key, job) : runJob(job)\n}\n\ninterface Task {\n readonly key: object\n readonly it: Iterator<unknown, unknown, undefined>\n readonly trigger: Trigger\n readonly feature: string\n state: 'running' | 'done' | 'failed' | 'cancelled'\n value: unknown\n}\n\nconst now = (): number =>\n typeof performance === 'object' && typeof performance?.now === 'function'\n ? performance.now()\n : Date.now()\n\ntype Scheduler = { yield?: () => Promise<void> }\n\n/** Runs `task` until it ends or `deadline` passes (checked at each `yield`). */\nfunction advance(task: Task, deadline: number) {\n try {\n for (;;) {\n const r = task.it.next()\n if (r.done) {\n task.state = 'done'\n task.value = r.value\n return\n }\n if (now() >= deadline) return\n }\n } catch (e) {\n task.state = 'failed'\n task.value = e\n }\n}\n\n/**\n * The table's slicer (§9.1). Between slices it yields to the main thread with\n * `scheduler.yield()`, or `setTimeout` where that is missing (`DK_ENV_FALLBACK`, once per table).\n * Jobs are keyed by an object of the caller (e.g. the data / columns they read), so a job is\n * started once and its result is shared by later runs.\n */\nexport function createSlicer(host: SlicerHost): Slicer {\n const tasks = new WeakMap<object, Task>()\n const running = new Set<Task>()\n let asked: Set<Task> | undefined\n let reported = false\n\n function pause(feature: string): Promise<void> {\n const s = (globalThis as { scheduler?: Scheduler }).scheduler\n if (typeof s?.yield === 'function') return s.yield()\n if (!reported) {\n reported = true\n host.emit('DK_ENV_FALLBACK', { api: 'scheduler.yield', feature, fallback: 'setTimeout' })\n }\n return new Promise((resolve) => setTimeout(resolve, 0))\n }\n\n async function drive(task: Task) {\n while (task.state === 'running') {\n await pause(task.feature)\n if (task.state !== 'running') return\n const start = now()\n advance(task, start + SLICE_MS)\n host.timed?.(task.feature, now() - start)\n }\n running.delete(task)\n host.done(task.trigger)\n }\n\n function result(task: Task): unknown {\n if (task.state === 'failed') throw task.value\n return task.state === 'done' ? task.value : undefined\n }\n\n return {\n run<R>(key: object, job: SliceJob<R>, feature: string): R | undefined {\n const known = tasks.get(key)\n if (known && known.state !== 'cancelled') {\n asked?.add(known)\n return result(known) as R | undefined\n }\n const task: Task = {\n key,\n it: job(),\n trigger: host.trigger(),\n feature,\n state: 'running',\n value: undefined,\n }\n tasks.set(key, task)\n advance(task, host.enabled() ? now() + SLICE_MS : Number.POSITIVE_INFINITY)\n if (task.state === 'running') {\n running.add(task)\n asked?.add(task)\n // `drive` never rejects: `advance` catches the job's errors, `done` is the table's.\n void drive(task).catch(() => {})\n }\n return result(task) as R | undefined\n },\n begin() {\n asked = new Set()\n },\n end() {\n const keep = asked\n asked = undefined\n if (!keep) return\n for (const task of running) {\n if (keep.has(task)) continue\n task.state = 'cancelled'\n running.delete(task)\n tasks.delete(task.key)\n }\n },\n cancel() {\n for (const task of running) {\n task.state = 'cancelled'\n tasks.delete(task.key)\n }\n running.clear()\n },\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,qBAAgC;AAEhC,uBAA+B;AAAA,IAE/B,gCAAgB,+BAAc;AAavB,IAAM,WAAW;AA4BjB,SAAS,OAAU,KAAqB;AAC7C,QAAM,KAAK,IAAI;AACf,aAAS;AACP,UAAM,IAAI,GAAG,KAAK;AAClB,QAAI,EAAE,KAAM,QAAO,EAAE;AAAA,EACvB;AACF;AAMO,SAAS,OACd,KACA,KACA,KACe;AACf,SAAO,IAAI,QAAQ,IAAI,MAAM,KAAK,GAAG,IAAI,OAAO,GAAG;AACrD;AAWA,IAAM,MAAM,MACV,OAAO,gBAAgB,YAAY,OAAO,aAAa,QAAQ,aAC3D,YAAY,IAAI,IAChB,KAAK,IAAI;AAKf,SAAS,QAAQ,MAAY,UAAkB;AAC7C,MAAI;AACF,eAAS;AACP,YAAM,IAAI,KAAK,GAAG,KAAK;AACvB,UAAI,EAAE,MAAM;AACV,aAAK,QAAQ;AACb,aAAK,QAAQ,EAAE;AACf;AAAA,MACF;AACA,UAAI,IAAI,KAAK,SAAU;AAAA,IACzB;AAAA,EACF,SAAS,GAAG;AACV,SAAK,QAAQ;AACb,SAAK,QAAQ;AAAA,EACf;AACF;AAQO,SAAS,aAAa,MAA0B;AACrD,QAAM,QAAQ,oBAAI,QAAsB;AACxC,QAAM,UAAU,oBAAI,IAAU;AAC9B,MAAI;AACJ,MAAI,WAAW;AAEf,WAAS,MAAM,SAAgC;AAC7C,UAAM,IAAK,WAAyC;AACpD,QAAI,OAAO,GAAG,UAAU,WAAY,QAAO,EAAE,MAAM;AACnD,QAAI,CAAC,UAAU;AACb,iBAAW;AACX,WAAK,KAAK,mBAAmB,EAAE,KAAK,mBAAmB,SAAS,UAAU,aAAa,CAAC;AAAA,IAC1F;AACA,WAAO,IAAI,QAAQ,CAAC,YAAY,WAAW,SAAS,CAAC,CAAC;AAAA,EACxD;AAEA,iBAAe,MAAM,MAAY;AAC/B,WAAO,KAAK,UAAU,WAAW;AAC/B,YAAM,MAAM,KAAK,OAAO;AACxB,UAAI,KAAK,UAAU,UAAW;AAC9B,YAAM,QAAQ,IAAI;AAClB,cAAQ,MAAM,QAAQ,QAAQ;AAC9B,WAAK,QAAQ,KAAK,SAAS,IAAI,IAAI,KAAK;AAAA,IAC1C;AACA,YAAQ,OAAO,IAAI;AACnB,SAAK,KAAK,KAAK,OAAO;AAAA,EACxB;AAEA,WAAS,OAAO,MAAqB;AACnC,QAAI,KAAK,UAAU,SAAU,OAAM,KAAK;AACxC,WAAO,KAAK,UAAU,SAAS,KAAK,QAAQ;AAAA,EAC9C;AAEA,SAAO;AAAA,IACL,IAAO,KAAa,KAAkB,SAAgC;AACpE,YAAM,QAAQ,MAAM,IAAI,GAAG;AAC3B,UAAI,SAAS,MAAM,UAAU,aAAa;AACxC,eAAO,IAAI,KAAK;AAChB,eAAO,OAAO,KAAK;AAAA,MACrB;AACA,YAAM,OAAa;AAAA,QACjB;AAAA,QACA,IAAI,IAAI;AAAA,QACR,SAAS,KAAK,QAAQ;AAAA,QACtB;AAAA,QACA,OAAO;AAAA,QACP,OAAO;AAAA,MACT;AACA,YAAM,IAAI,KAAK,IAAI;AACnB,cAAQ,MAAM,KAAK,QAAQ,IAAI,IAAI,IAAI,WAAW,OAAO,iBAAiB;AAC1E,UAAI,KAAK,UAAU,WAAW;AAC5B,gBAAQ,IAAI,IAAI;AAChB,eAAO,IAAI,IAAI;AAEf,aAAK,MAAM,IAAI,EAAE,MAAM,MAAM;AAAA,QAAC,CAAC;AAAA,MACjC;AACA,aAAO,OAAO,IAAI;AAAA,IACpB;AAAA,IACA,QAAQ;AACN,cAAQ,oBAAI,IAAI;AAAA,IAClB;AAAA,IACA,MAAM;AACJ,YAAM,OAAO;AACb,cAAQ;AACR,UAAI,CAAC,KAAM;AACX,iBAAW,QAAQ,SAAS;AAC1B,YAAI,KAAK,IAAI,IAAI,EAAG;AACpB,aAAK,QAAQ;AACb,gBAAQ,OAAO,IAAI;AACnB,cAAM,OAAO,KAAK,GAAG;AAAA,MACvB;AAAA,IACF;AAAA,IACA,SAAS;AACP,iBAAW,QAAQ,SAAS;AAC1B,aAAK,QAAQ;AACb,cAAM,OAAO,KAAK,GAAG;AAAA,MACvB;AACA,cAAQ,MAAM;AAAA,IAChB;AAAA,EACF;AACF;","names":[]}
@@ -48,7 +48,9 @@ function createSlicer(host) {
48
48
  while (task.state === "running") {
49
49
  await pause(task.feature);
50
50
  if (task.state !== "running") return;
51
- advance(task, now() + SLICE_MS);
51
+ const start = now();
52
+ advance(task, start + SLICE_MS);
53
+ host.timed?.(task.feature, now() - start);
52
54
  }
53
55
  running.delete(task);
54
56
  host.done(task.trigger);
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/pipeline/slice.ts"],"sourcesContent":["import { keepDiagnostics } from '../diagnostics/catalog'\nimport type { Emit, Trigger } from '../diagnostics/types'\nimport { envDiagnostics } from './env-codes'\n\nkeepDiagnostics(envDiagnostics)\n\n/**\n * Time-sliced work (§9.1): a generator that `yield`s between chunks of work (every few thousand\n * rows). Its return value is the result.\n */\nexport type SliceJob<R> = () => Iterator<unknown, R, undefined>\n\n/**\n * One slice of work, in milliseconds. A job that finishes within it never goes async (small\n * tables keep synchronous row models); the slices of a longer one stay well under the 50 ms\n * long-task budget (§9.3) with the rest of the pipeline run around them.\n */\nexport const SLICE_MS = 8\n\nexport interface SlicerHost {\n readonly emit: Emit\n /** Slicing is allowed now: in the browser, after the table's first row model. */\n enabled(): boolean\n /** The trigger of the current run (a finished job recomputes under it). */\n trigger(): Trigger\n /** A job ended (its result or error is ready): recompute the row model and notify. */\n done(trigger: Trigger): void\n}\n\nexport interface Slicer {\n /**\n * The result of the job for `key`: started on the first call (one synchronous slice), then\n * `undefined` until it has finished. A job that threw rethrows here, in the step that asks.\n */\n run<R>(key: object, job: SliceJob<R>, feature: string): R | undefined\n /** Starts a pipeline run: jobs that no step asks for until {@link end} are cancelled. */\n begin(): void\n end(): void\n /** Cancels every job (`destroy()`). */\n cancel(): void\n}\n\n/** Runs `job` to completion (no slicing). */\nexport function runJob<R>(job: SliceJob<R>): R {\n const it = job()\n for (;;) {\n const r = it.next()\n if (r.done) return r.value\n }\n}\n\n/**\n * `ctx.slice(key, job)` where the runner provides it (a table run), else the whole job now. For\n * features: `undefined` means \"still running\" (return a stand-in).\n */\nexport function sliced<R>(\n ctx: { slice?: <X>(key: object, job: SliceJob<X>) => X | undefined },\n key: object,\n job: SliceJob<R>,\n): R | undefined {\n return ctx.slice ? ctx.slice(key, job) : runJob(job)\n}\n\ninterface Task {\n readonly key: object\n readonly it: Iterator<unknown, unknown, undefined>\n readonly trigger: Trigger\n readonly feature: string\n state: 'running' | 'done' | 'failed' | 'cancelled'\n value: unknown\n}\n\nconst now = (): number =>\n typeof performance === 'object' && typeof performance?.now === 'function'\n ? performance.now()\n : Date.now()\n\ntype Scheduler = { yield?: () => Promise<void> }\n\n/** Runs `task` until it ends or `deadline` passes (checked at each `yield`). */\nfunction advance(task: Task, deadline: number) {\n try {\n for (;;) {\n const r = task.it.next()\n if (r.done) {\n task.state = 'done'\n task.value = r.value\n return\n }\n if (now() >= deadline) return\n }\n } catch (e) {\n task.state = 'failed'\n task.value = e\n }\n}\n\n/**\n * The table's slicer (§9.1). Between slices it yields to the main thread with\n * `scheduler.yield()`, or `setTimeout` where that is missing (`DK_ENV_FALLBACK`, once per table).\n * Jobs are keyed by an object of the caller (e.g. the data / columns they read), so a job is\n * started once and its result is shared by later runs.\n */\nexport function createSlicer(host: SlicerHost): Slicer {\n const tasks = new WeakMap<object, Task>()\n const running = new Set<Task>()\n let asked: Set<Task> | undefined\n let reported = false\n\n function pause(feature: string): Promise<void> {\n const s = (globalThis as { scheduler?: Scheduler }).scheduler\n if (typeof s?.yield === 'function') return s.yield()\n if (!reported) {\n reported = true\n host.emit('DK_ENV_FALLBACK', { api: 'scheduler.yield', feature, fallback: 'setTimeout' })\n }\n return new Promise((resolve) => setTimeout(resolve, 0))\n }\n\n async function drive(task: Task) {\n while (task.state === 'running') {\n await pause(task.feature)\n if (task.state !== 'running') return\n advance(task, now() + SLICE_MS)\n }\n running.delete(task)\n host.done(task.trigger)\n }\n\n function result(task: Task): unknown {\n if (task.state === 'failed') throw task.value\n return task.state === 'done' ? task.value : undefined\n }\n\n return {\n run<R>(key: object, job: SliceJob<R>, feature: string): R | undefined {\n const known = tasks.get(key)\n if (known && known.state !== 'cancelled') {\n asked?.add(known)\n return result(known) as R | undefined\n }\n const task: Task = {\n key,\n it: job(),\n trigger: host.trigger(),\n feature,\n state: 'running',\n value: undefined,\n }\n tasks.set(key, task)\n advance(task, host.enabled() ? now() + SLICE_MS : Number.POSITIVE_INFINITY)\n if (task.state === 'running') {\n running.add(task)\n asked?.add(task)\n // `drive` never rejects: `advance` catches the job's errors, `done` is the table's.\n void drive(task).catch(() => {})\n }\n return result(task) as R | undefined\n },\n begin() {\n asked = new Set()\n },\n end() {\n const keep = asked\n asked = undefined\n if (!keep) return\n for (const task of running) {\n if (keep.has(task)) continue\n task.state = 'cancelled'\n running.delete(task)\n tasks.delete(task.key)\n }\n },\n cancel() {\n for (const task of running) {\n task.state = 'cancelled'\n tasks.delete(task.key)\n }\n running.clear()\n },\n }\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/pipeline/slice.ts"],"sourcesContent":["import { keepDiagnostics } from '../diagnostics/catalog'\nimport type { Emit, Trigger } from '../diagnostics/types'\nimport { envDiagnostics } from './env-codes'\n\nkeepDiagnostics(envDiagnostics)\n\n/**\n * Time-sliced work (§9.1): a generator that `yield`s between chunks of work (every few thousand\n * rows). Its return value is the result.\n */\nexport type SliceJob<R> = () => Iterator<unknown, R, undefined>\n\n/**\n * One slice of work, in milliseconds. A job that finishes within it never goes async (small\n * tables keep synchronous row models); the slices of a longer one stay well under the 50 ms\n * long-task budget (§9.3) with the rest of the pipeline run around them.\n */\nexport const SLICE_MS = 8\n\nexport interface SlicerHost {\n readonly emit: Emit\n /** Slicing is allowed now: in the browser, after the table's first row model. */\n enabled(): boolean\n /** The trigger of the current run (a finished job recomputes under it). */\n trigger(): Trigger\n /** A job ended (its result or error is ready): recompute the row model and notify. */\n done(trigger: Trigger): void\n /** A slice run between pipeline runs took `ms` (the tracer's, #61). */\n timed?(feature: string, ms: number): void\n}\n\nexport interface Slicer {\n /**\n * The result of the job for `key`: started on the first call (one synchronous slice), then\n * `undefined` until it has finished. A job that threw rethrows here, in the step that asks.\n */\n run<R>(key: object, job: SliceJob<R>, feature: string): R | undefined\n /** Starts a pipeline run: jobs that no step asks for until {@link end} are cancelled. */\n begin(): void\n end(): void\n /** Cancels every job (`destroy()`). */\n cancel(): void\n}\n\n/** Runs `job` to completion (no slicing). */\nexport function runJob<R>(job: SliceJob<R>): R {\n const it = job()\n for (;;) {\n const r = it.next()\n if (r.done) return r.value\n }\n}\n\n/**\n * `ctx.slice(key, job)` where the runner provides it (a table run), else the whole job now. For\n * features: `undefined` means \"still running\" (return a stand-in).\n */\nexport function sliced<R>(\n ctx: { slice?: <X>(key: object, job: SliceJob<X>) => X | undefined },\n key: object,\n job: SliceJob<R>,\n): R | undefined {\n return ctx.slice ? ctx.slice(key, job) : runJob(job)\n}\n\ninterface Task {\n readonly key: object\n readonly it: Iterator<unknown, unknown, undefined>\n readonly trigger: Trigger\n readonly feature: string\n state: 'running' | 'done' | 'failed' | 'cancelled'\n value: unknown\n}\n\nconst now = (): number =>\n typeof performance === 'object' && typeof performance?.now === 'function'\n ? performance.now()\n : Date.now()\n\ntype Scheduler = { yield?: () => Promise<void> }\n\n/** Runs `task` until it ends or `deadline` passes (checked at each `yield`). */\nfunction advance(task: Task, deadline: number) {\n try {\n for (;;) {\n const r = task.it.next()\n if (r.done) {\n task.state = 'done'\n task.value = r.value\n return\n }\n if (now() >= deadline) return\n }\n } catch (e) {\n task.state = 'failed'\n task.value = e\n }\n}\n\n/**\n * The table's slicer (§9.1). Between slices it yields to the main thread with\n * `scheduler.yield()`, or `setTimeout` where that is missing (`DK_ENV_FALLBACK`, once per table).\n * Jobs are keyed by an object of the caller (e.g. the data / columns they read), so a job is\n * started once and its result is shared by later runs.\n */\nexport function createSlicer(host: SlicerHost): Slicer {\n const tasks = new WeakMap<object, Task>()\n const running = new Set<Task>()\n let asked: Set<Task> | undefined\n let reported = false\n\n function pause(feature: string): Promise<void> {\n const s = (globalThis as { scheduler?: Scheduler }).scheduler\n if (typeof s?.yield === 'function') return s.yield()\n if (!reported) {\n reported = true\n host.emit('DK_ENV_FALLBACK', { api: 'scheduler.yield', feature, fallback: 'setTimeout' })\n }\n return new Promise((resolve) => setTimeout(resolve, 0))\n }\n\n async function drive(task: Task) {\n while (task.state === 'running') {\n await pause(task.feature)\n if (task.state !== 'running') return\n const start = now()\n advance(task, start + SLICE_MS)\n host.timed?.(task.feature, now() - start)\n }\n running.delete(task)\n host.done(task.trigger)\n }\n\n function result(task: Task): unknown {\n if (task.state === 'failed') throw task.value\n return task.state === 'done' ? task.value : undefined\n }\n\n return {\n run<R>(key: object, job: SliceJob<R>, feature: string): R | undefined {\n const known = tasks.get(key)\n if (known && known.state !== 'cancelled') {\n asked?.add(known)\n return result(known) as R | undefined\n }\n const task: Task = {\n key,\n it: job(),\n trigger: host.trigger(),\n feature,\n state: 'running',\n value: undefined,\n }\n tasks.set(key, task)\n advance(task, host.enabled() ? now() + SLICE_MS : Number.POSITIVE_INFINITY)\n if (task.state === 'running') {\n running.add(task)\n asked?.add(task)\n // `drive` never rejects: `advance` catches the job's errors, `done` is the table's.\n void drive(task).catch(() => {})\n }\n return result(task) as R | undefined\n },\n begin() {\n asked = new Set()\n },\n end() {\n const keep = asked\n asked = undefined\n if (!keep) return\n for (const task of running) {\n if (keep.has(task)) continue\n task.state = 'cancelled'\n running.delete(task)\n tasks.delete(task.key)\n }\n },\n cancel() {\n for (const task of running) {\n task.state = 'cancelled'\n tasks.delete(task.key)\n }\n running.clear()\n },\n }\n}\n"],"mappings":"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","names":[]}
package/dist/schema.d.cts CHANGED
@@ -1,5 +1,5 @@
1
- import { S as StandardSchemaV1, e as TableSchema } from './codes-BKdS9EiO.cjs';
2
- export { q as DatakableSchemaError, h as InvalidRow, I as InvalidRowsMode, C as SCHEMA_INGEST, H as SchemaIssueColumn, J as SchemaOutcome, ad as isStandardSchema, am as schemaDiagnostics } from './codes-BKdS9EiO.cjs';
1
+ import { S as StandardSchemaV1, e as TableSchema } from './codes-B9bCK73-.cjs';
2
+ export { q as DatakableSchemaError, h as InvalidRow, I as InvalidRowsMode, C as SCHEMA_INGEST, H as SchemaIssueColumn, J as SchemaOutcome, ad as isStandardSchema, am as schemaDiagnostics } from './codes-B9bCK73-.cjs';
3
3
 
4
4
  /**
5
5
  * Opts a Standard Schema v1 (zod, valibot, arktype, …) into table validation (§5.1):
package/dist/schema.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { S as StandardSchemaV1, e as TableSchema } from './codes-BKdS9EiO.js';
2
- export { q as DatakableSchemaError, h as InvalidRow, I as InvalidRowsMode, C as SCHEMA_INGEST, H as SchemaIssueColumn, J as SchemaOutcome, ad as isStandardSchema, am as schemaDiagnostics } from './codes-BKdS9EiO.js';
1
+ import { S as StandardSchemaV1, e as TableSchema } from './codes-B9bCK73-.js';
2
+ export { q as DatakableSchemaError, h as InvalidRow, I as InvalidRowsMode, C as SCHEMA_INGEST, H as SchemaIssueColumn, J as SchemaOutcome, ad as isStandardSchema, am as schemaDiagnostics } from './codes-B9bCK73-.js';
3
3
 
4
4
  /**
5
5
  * Opts a Standard Schema v1 (zod, valibot, arktype, …) into table validation (§5.1):
@@ -1,5 +1,5 @@
1
- import { i as RowKey } from './codes-BKdS9EiO.cjs';
2
- import { R as RowModelContext, c as FeatureContext } from './explain-aagaYHcy.cjs';
1
+ import { i as RowKey } from './codes-B9bCK73-.cjs';
2
+ import { R as RowModelContext, c as FeatureContext } from './explain-Q8Cg0cZy.cjs';
3
3
 
4
4
  /** What `setSearch` / `flushSearch` resolve to; they never reject. */
5
5
  interface SearchOutcome {
@@ -1,5 +1,5 @@
1
- import { i as RowKey } from './codes-BKdS9EiO.js';
2
- import { R as RowModelContext, c as FeatureContext } from './explain-DcUZfFh5.js';
1
+ import { i as RowKey } from './codes-B9bCK73-.js';
2
+ import { R as RowModelContext, c as FeatureContext } from './explain-i0OATi_W.js';
3
3
 
4
4
  /** What `setSearch` / `flushSearch` resolve to; they never reject. */
5
5
  interface SearchOutcome {
@@ -1,3 +1,3 @@
1
- export { ap as searchDiagnostics } from './codes-BKdS9EiO.cjs';
2
- export { A as AsyncSearchFn, a as SEARCH_ENGINE, b as SearchFn, c as SearchFnContext, e as SearchResult, w as withSearchFn } from './search-async-entry-C3mXxLP8.cjs';
3
- import './explain-aagaYHcy.cjs';
1
+ export { ap as searchDiagnostics } from './codes-B9bCK73-.cjs';
2
+ export { A as AsyncSearchFn, a as SEARCH_ENGINE, b as SearchFn, c as SearchFnContext, e as SearchResult, w as withSearchFn } from './search-async-entry-CuLYPfY_.cjs';
3
+ import './explain-Q8Cg0cZy.cjs';
@@ -1,3 +1,3 @@
1
- export { ap as searchDiagnostics } from './codes-BKdS9EiO.js';
2
- export { A as AsyncSearchFn, a as SEARCH_ENGINE, b as SearchFn, c as SearchFnContext, e as SearchResult, w as withSearchFn } from './search-async-entry-BmQYT120.js';
3
- import './explain-DcUZfFh5.js';
1
+ export { ap as searchDiagnostics } from './codes-B9bCK73-.js';
2
+ export { A as AsyncSearchFn, a as SEARCH_ENGINE, b as SearchFn, c as SearchFnContext, e as SearchResult, w as withSearchFn } from './search-async-entry-Cx7xpuVZ.js';
3
+ import './explain-i0OATi_W.js';
package/dist/search.d.cts CHANGED
@@ -1,8 +1,8 @@
1
- export { ap as searchDiagnostics } from './codes-BKdS9EiO.cjs';
2
- import { d as AnyRow, F as Feature, b as FixedTypes } from './explain-aagaYHcy.cjs';
1
+ export { ap as searchDiagnostics } from './codes-B9bCK73-.cjs';
2
+ import { d as AnyRow, F as Feature, b as FixedTypes } from './explain-Q8Cg0cZy.cjs';
3
3
  import { a as DataMode } from './mode-DFV8ryXo.cjs';
4
- import { d as SearchOutcome, A as AsyncSearchFn, S as SearchState } from './search-async-entry-C3mXxLP8.cjs';
5
- export { a as SEARCH_ENGINE, b as SearchFn, c as SearchFnContext, e as SearchResult, f as SearchStatus, w as withSearchFn } from './search-async-entry-C3mXxLP8.cjs';
4
+ import { d as SearchOutcome, A as AsyncSearchFn, S as SearchState } from './search-async-entry-CuLYPfY_.cjs';
5
+ export { a as SEARCH_ENGINE, b as SearchFn, c as SearchFnContext, e as SearchResult, f as SearchStatus, w as withSearchFn } from './search-async-entry-CuLYPfY_.cjs';
6
6
 
7
7
  interface SearchApi {
8
8
  /** Sets `input` (and `query`, with the client's immediate typing strategy). */
@@ -33,7 +33,8 @@ interface SearchTyping {
33
33
  wait?: SearchWait;
34
34
  /**
35
35
  * Debounce only. `'trailing'` (default): apply after the burst. `'leading'`: apply the first
36
- * keystroke at once and drop the rest of the burst (`flushSearch()` applies them).
36
+ * keystroke at once and drop the rest of the burst (`flushSearch()` applies them; otherwise
37
+ * their `setSearch()` promises resolve `'superseded'` when the silence window ends).
37
38
  */
38
39
  behavior?: 'trailing' | 'leading';
39
40
  /** A trimmed input shorter than this is applied as an empty query (all rows). Default 0. */
@@ -70,7 +71,8 @@ interface SearchOptions<T = AnyRow> {
70
71
  }
71
72
  /**
72
73
  * Global search (§6.3), client mode: fuzzy matching with `ex-search` on the formatted values of the
73
- * searchable columns (`search: weight`; every column at weight 1 when none declares one).
74
+ * searchable columns (`search: weight`; when none declares one, every column of primitives at
75
+ * weight 1, #27).
74
76
  *
75
77
  * - The matcher is built on the first non-blank query, once per data + columns (not per keystroke),
76
78
  * over the column cache's values; ex-search reads the projection `{ i, c0, c1, … }` one chunk of
package/dist/search.d.ts CHANGED
@@ -1,8 +1,8 @@
1
- export { ap as searchDiagnostics } from './codes-BKdS9EiO.js';
2
- import { d as AnyRow, F as Feature, b as FixedTypes } from './explain-DcUZfFh5.js';
1
+ export { ap as searchDiagnostics } from './codes-B9bCK73-.js';
2
+ import { d as AnyRow, F as Feature, b as FixedTypes } from './explain-i0OATi_W.js';
3
3
  import { a as DataMode } from './mode-DFV8ryXo.js';
4
- import { d as SearchOutcome, A as AsyncSearchFn, S as SearchState } from './search-async-entry-BmQYT120.js';
5
- export { a as SEARCH_ENGINE, b as SearchFn, c as SearchFnContext, e as SearchResult, f as SearchStatus, w as withSearchFn } from './search-async-entry-BmQYT120.js';
4
+ import { d as SearchOutcome, A as AsyncSearchFn, S as SearchState } from './search-async-entry-Cx7xpuVZ.js';
5
+ export { a as SEARCH_ENGINE, b as SearchFn, c as SearchFnContext, e as SearchResult, f as SearchStatus, w as withSearchFn } from './search-async-entry-Cx7xpuVZ.js';
6
6
 
7
7
  interface SearchApi {
8
8
  /** Sets `input` (and `query`, with the client's immediate typing strategy). */
@@ -33,7 +33,8 @@ interface SearchTyping {
33
33
  wait?: SearchWait;
34
34
  /**
35
35
  * Debounce only. `'trailing'` (default): apply after the burst. `'leading'`: apply the first
36
- * keystroke at once and drop the rest of the burst (`flushSearch()` applies them).
36
+ * keystroke at once and drop the rest of the burst (`flushSearch()` applies them; otherwise
37
+ * their `setSearch()` promises resolve `'superseded'` when the silence window ends).
37
38
  */
38
39
  behavior?: 'trailing' | 'leading';
39
40
  /** A trimmed input shorter than this is applied as an empty query (all rows). Default 0. */
@@ -70,7 +71,8 @@ interface SearchOptions<T = AnyRow> {
70
71
  }
71
72
  /**
72
73
  * Global search (§6.3), client mode: fuzzy matching with `ex-search` on the formatted values of the
73
- * searchable columns (`search: weight`; every column at weight 1 when none declares one).
74
+ * searchable columns (`search: weight`; when none declares one, every column of primitives at
75
+ * weight 1, #27).
74
76
  *
75
77
  * - The matcher is built on the first non-blank query, once per data + columns (not per keystroke),
76
78
  * over the column cache's values; ex-search reads the projection `{ i, c0, c1, … }` one chunk of
package/dist/server.d.cts CHANGED
@@ -1,6 +1,6 @@
1
- import { a as Interceptor, D as Fetcher, i as ServerFetcher } from './explain-aagaYHcy.cjs';
2
- export { x as FetchOutcome, y as FetchParams, z as FetchResult, ab as SERVER_SOURCE } from './explain-aagaYHcy.cjs';
3
- export { B as BadResponse, N as asyncDiagnostics, a4 as fetchDiagnostics } from './codes-BKdS9EiO.cjs';
1
+ import { a as Interceptor, D as Fetcher, i as ServerFetcher } from './explain-Q8Cg0cZy.cjs';
2
+ export { x as FetchOutcome, y as FetchParams, z as FetchResult, ab as SERVER_SOURCE } from './explain-Q8Cg0cZy.cjs';
3
+ export { B as BadResponse, N as asyncDiagnostics, a4 as fetchDiagnostics } from './codes-B9bCK73-.cjs';
4
4
 
5
5
  /** Spec §7.1: a request that has not settled after 30 s is aborted (`DK_ASYNC_TIMEOUT`). */
6
6
  declare const DEFAULT_ASYNC_TIMEOUT = 30000;
package/dist/server.d.ts CHANGED
@@ -1,6 +1,6 @@
1
- import { a as Interceptor, D as Fetcher, i as ServerFetcher } from './explain-DcUZfFh5.js';
2
- export { x as FetchOutcome, y as FetchParams, z as FetchResult, ab as SERVER_SOURCE } from './explain-DcUZfFh5.js';
3
- export { B as BadResponse, N as asyncDiagnostics, a4 as fetchDiagnostics } from './codes-BKdS9EiO.js';
1
+ import { a as Interceptor, D as Fetcher, i as ServerFetcher } from './explain-i0OATi_W.js';
2
+ export { x as FetchOutcome, y as FetchParams, z as FetchResult, ab as SERVER_SOURCE } from './explain-i0OATi_W.js';
3
+ export { B as BadResponse, N as asyncDiagnostics, a4 as fetchDiagnostics } from './codes-B9bCK73-.js';
4
4
 
5
5
  /** Spec §7.1: a request that has not settled after 30 s is aborted (`DK_ASYNC_TIMEOUT`). */
6
6
  declare const DEFAULT_ASYNC_TIMEOUT = 30000;
@@ -1,5 +1,5 @@
1
- export { W as comparatorDiagnostics, ar as sortingDiagnostics } from './codes-BKdS9EiO.cjs';
2
- import { ad as SortAlgorithm, a1 as Path, e as FeatureTypes, F as Feature } from './explain-aagaYHcy.cjs';
1
+ export { W as comparatorDiagnostics, ar as sortingDiagnostics } from './codes-B9bCK73-.cjs';
2
+ import { ad as SortAlgorithm, a1 as Path, e as FeatureTypes, F as Feature } from './explain-Q8Cg0cZy.cjs';
3
3
  import { a as DataMode } from './mode-DFV8ryXo.cjs';
4
4
 
5
5
  /** The rank of `v` in {@link RANK}. */
@@ -47,7 +47,10 @@ interface SortingTypes extends FeatureTypes {
47
47
  */
48
48
  type SortAlgorithmOption = SortAlgorithm;
49
49
  interface SortingOptions {
50
- /** Locale(s) of the string collator (`Intl.Collator(locale, { numeric: true })`); default: the runtime's. */
50
+ /**
51
+ * Locale(s) of the string collator (`Intl.Collator(locale, { numeric: true })`). Default `'en'`,
52
+ * not the runtime's: the server and the browser must sort alike (SSR hydration, #12).
53
+ */
51
54
  locale?: string | readonly string[];
52
55
  /** The sort algorithm (default `'auto'`); a column's `sortAlgorithm` takes precedence. */
53
56
  algorithm?: SortAlgorithmOption;
package/dist/sorting.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- export { W as comparatorDiagnostics, ar as sortingDiagnostics } from './codes-BKdS9EiO.js';
2
- import { ad as SortAlgorithm, a1 as Path, e as FeatureTypes, F as Feature } from './explain-DcUZfFh5.js';
1
+ export { W as comparatorDiagnostics, ar as sortingDiagnostics } from './codes-B9bCK73-.js';
2
+ import { ad as SortAlgorithm, a1 as Path, e as FeatureTypes, F as Feature } from './explain-i0OATi_W.js';
3
3
  import { a as DataMode } from './mode-DFV8ryXo.js';
4
4
 
5
5
  /** The rank of `v` in {@link RANK}. */
@@ -47,7 +47,10 @@ interface SortingTypes extends FeatureTypes {
47
47
  */
48
48
  type SortAlgorithmOption = SortAlgorithm;
49
49
  interface SortingOptions {
50
- /** Locale(s) of the string collator (`Intl.Collator(locale, { numeric: true })`); default: the runtime's. */
50
+ /**
51
+ * Locale(s) of the string collator (`Intl.Collator(locale, { numeric: true })`). Default `'en'`,
52
+ * not the runtime's: the server and the browser must sort alike (SSR hydration, #12).
53
+ */
51
54
  locale?: string | readonly string[];
52
55
  /** The sort algorithm (default `'auto'`); a column's `sortAlgorithm` takes precedence. */
53
56
  algorithm?: SortAlgorithmOption;
@@ -25,6 +25,7 @@ __export(codes_exports, {
25
25
  });
26
26
  module.exports = __toCommonJS(codes_exports);
27
27
  var import_catalog = require("../diagnostics/catalog.cjs");
28
+ var import_process_guard = require("../diagnostics/process-guard.cjs");
28
29
  var asyncMessages = {
29
30
  DK_ASYNC_TIMEOUT: {
30
31
  problem: (d) => `${d.source} did not settle within the timeout (${d.timeout} ms)`,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/source/codes.ts"],"sourcesContent":["import { type DiagnosticMessages, defineDiagnostic } from '../diagnostics/catalog'\n\ndeclare module '../diagnostics/catalog' {\n interface DiagnosticCatalog {\n DK_ASYNC_TIMEOUT: {\n /** The option that ran too long (`fetcher`, `searchFn`); a closed set, never row data. */\n source: string\n /** The timeout that was exceeded, in ms. */\n timeout: number\n }\n }\n}\n\n/** Message text (§8.2): development builds, or production via `@datakable/core/messages`. */\nexport const asyncMessages: DiagnosticMessages<'DK_ASYNC_TIMEOUT'> = {\n DK_ASYNC_TIMEOUT: {\n problem: (d) => `${d.source} did not settle within the timeout (${d.timeout} ms)`,\n impact: () =>\n 'the request was aborted and its late result is ignored; the previous results were kept ' +\n \"(status: 'error')\",\n fix: (d) => [\n `make ${d.source} answer faster (smaller pages, a server-side index), or raise \\`timeout\\` ` +\n `(now ${d.timeout} ms)`,\n `pass ctx.signal to fetch() inside ${d.source} so the timed-out request is cancelled on the ` +\n 'network too',\n ],\n },\n}\n\n/** Codes owned by asyncControl (spec §3.4, §7.1, §8.3). */\nexport const asyncDiagnostics = [\n defineDiagnostic(\n {\n code: 'DK_ASYNC_TIMEOUT',\n level: 'error',\n where: (d) => ({ kind: 'option', path: d.source }),\n },\n (process.env.NODE_ENV !== \"production\") && asyncMessages.DK_ASYNC_TIMEOUT,\n ),\n]\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,qBAA0D;AAcnD,IAAM,gBAAwD;AAAA,EACnE,kBAAkB;AAAA,IAChB,SAAS,CAAC,MAAM,GAAG,EAAE,MAAM,uCAAuC,EAAE,OAAO;AAAA,IAC3E,QAAQ,MACN;AAAA,IAEF,KAAK,CAAC,MAAM;AAAA,MACV,QAAQ,EAAE,MAAM,kFACN,EAAE,OAAO;AAAA,MACnB,qCAAqC,EAAE,MAAM;AAAA,IAE/C;AAAA,EACF;AACF;AAGO,IAAM,mBAAmB;AAAA,MAC9B;AAAA,IACE;AAAA,MACE,MAAM;AAAA,MACN,OAAO;AAAA,MACP,OAAO,CAAC,OAAO,EAAE,MAAM,UAAU,MAAM,EAAE,OAAO;AAAA,IAClD;AAAA,IACC,QAAQ,IAAI,aAAa,gBAAiB,cAAc;AAAA,EAC3D;AACF;","names":[]}
1
+ {"version":3,"sources":["../../src/source/codes.ts"],"sourcesContent":["import { type DiagnosticMessages, defineDiagnostic } from '../diagnostics/catalog'\nimport '../diagnostics/process-guard'\n\ndeclare module '../diagnostics/catalog' {\n interface DiagnosticCatalog {\n DK_ASYNC_TIMEOUT: {\n /** The option that ran too long (`fetcher`, `searchFn`); a closed set, never row data. */\n source: string\n /** The timeout that was exceeded, in ms. */\n timeout: number\n }\n }\n}\n\n/** Message text (§8.2): development builds, or production via `@datakable/core/messages`. */\nexport const asyncMessages: DiagnosticMessages<'DK_ASYNC_TIMEOUT'> = {\n DK_ASYNC_TIMEOUT: {\n problem: (d) => `${d.source} did not settle within the timeout (${d.timeout} ms)`,\n impact: () =>\n 'the request was aborted and its late result is ignored; the previous results were kept ' +\n \"(status: 'error')\",\n fix: (d) => [\n `make ${d.source} answer faster (smaller pages, a server-side index), or raise \\`timeout\\` ` +\n `(now ${d.timeout} ms)`,\n `pass ctx.signal to fetch() inside ${d.source} so the timed-out request is cancelled on the ` +\n 'network too',\n ],\n },\n}\n\n/** Codes owned by asyncControl (spec §3.4, §7.1, §8.3). */\nexport const asyncDiagnostics = [\n defineDiagnostic(\n {\n code: 'DK_ASYNC_TIMEOUT',\n level: 'error',\n where: (d) => ({ kind: 'option', path: d.source }),\n },\n (process.env.NODE_ENV !== \"production\") && asyncMessages.DK_ASYNC_TIMEOUT,\n ),\n]\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,qBAA0D;AAC1D,2BAAO;AAcA,IAAM,gBAAwD;AAAA,EACnE,kBAAkB;AAAA,IAChB,SAAS,CAAC,MAAM,GAAG,EAAE,MAAM,uCAAuC,EAAE,OAAO;AAAA,IAC3E,QAAQ,MACN;AAAA,IAEF,KAAK,CAAC,MAAM;AAAA,MACV,QAAQ,EAAE,MAAM,kFACN,EAAE,OAAO;AAAA,MACnB,qCAAqC,EAAE,MAAM;AAAA,IAE/C;AAAA,EACF;AACF;AAGO,IAAM,mBAAmB;AAAA,MAC9B;AAAA,IACE;AAAA,MACE,MAAM;AAAA,MACN,OAAO;AAAA,MACP,OAAO,CAAC,OAAO,EAAE,MAAM,UAAU,MAAM,EAAE,OAAO;AAAA,IAClD;AAAA,IACC,QAAQ,IAAI,aAAa,gBAAiB,cAAc;AAAA,EAC3D;AACF;","names":[]}
@@ -1,5 +1,6 @@
1
1
  // src/source/codes.ts
2
2
  import { defineDiagnostic } from "../diagnostics/catalog.js";
3
+ import "../diagnostics/process-guard.js";
3
4
  var asyncMessages = {
4
5
  DK_ASYNC_TIMEOUT: {
5
6
  problem: (d) => `${d.source} did not settle within the timeout (${d.timeout} ms)`,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/source/codes.ts"],"sourcesContent":["import { type DiagnosticMessages, defineDiagnostic } from '../diagnostics/catalog'\n\ndeclare module '../diagnostics/catalog' {\n interface DiagnosticCatalog {\n DK_ASYNC_TIMEOUT: {\n /** The option that ran too long (`fetcher`, `searchFn`); a closed set, never row data. */\n source: string\n /** The timeout that was exceeded, in ms. */\n timeout: number\n }\n }\n}\n\n/** Message text (§8.2): development builds, or production via `@datakable/core/messages`. */\nexport const asyncMessages: DiagnosticMessages<'DK_ASYNC_TIMEOUT'> = {\n DK_ASYNC_TIMEOUT: {\n problem: (d) => `${d.source} did not settle within the timeout (${d.timeout} ms)`,\n impact: () =>\n 'the request was aborted and its late result is ignored; the previous results were kept ' +\n \"(status: 'error')\",\n fix: (d) => [\n `make ${d.source} answer faster (smaller pages, a server-side index), or raise \\`timeout\\` ` +\n `(now ${d.timeout} ms)`,\n `pass ctx.signal to fetch() inside ${d.source} so the timed-out request is cancelled on the ` +\n 'network too',\n ],\n },\n}\n\n/** Codes owned by asyncControl (spec §3.4, §7.1, §8.3). */\nexport const asyncDiagnostics = [\n defineDiagnostic(\n {\n code: 'DK_ASYNC_TIMEOUT',\n level: 'error',\n where: (d) => ({ kind: 'option', path: d.source }),\n },\n (process.env.NODE_ENV !== \"production\") && asyncMessages.DK_ASYNC_TIMEOUT,\n ),\n]\n"],"mappings":";AAAA,SAAkC,wBAAwB;AAcnD,IAAM,gBAAwD;AAAA,EACnE,kBAAkB;AAAA,IAChB,SAAS,CAAC,MAAM,GAAG,EAAE,MAAM,uCAAuC,EAAE,OAAO;AAAA,IAC3E,QAAQ,MACN;AAAA,IAEF,KAAK,CAAC,MAAM;AAAA,MACV,QAAQ,EAAE,MAAM,kFACN,EAAE,OAAO;AAAA,MACnB,qCAAqC,EAAE,MAAM;AAAA,IAE/C;AAAA,EACF;AACF;AAGO,IAAM,mBAAmB;AAAA,EAC9B;AAAA,IACE;AAAA,MACE,MAAM;AAAA,MACN,OAAO;AAAA,MACP,OAAO,CAAC,OAAO,EAAE,MAAM,UAAU,MAAM,EAAE,OAAO;AAAA,IAClD;AAAA,IACC,QAAQ,IAAI,aAAa,gBAAiB,cAAc;AAAA,EAC3D;AACF;","names":[]}
1
+ {"version":3,"sources":["../../src/source/codes.ts"],"sourcesContent":["import { type DiagnosticMessages, defineDiagnostic } from '../diagnostics/catalog'\nimport '../diagnostics/process-guard'\n\ndeclare module '../diagnostics/catalog' {\n interface DiagnosticCatalog {\n DK_ASYNC_TIMEOUT: {\n /** The option that ran too long (`fetcher`, `searchFn`); a closed set, never row data. */\n source: string\n /** The timeout that was exceeded, in ms. */\n timeout: number\n }\n }\n}\n\n/** Message text (§8.2): development builds, or production via `@datakable/core/messages`. */\nexport const asyncMessages: DiagnosticMessages<'DK_ASYNC_TIMEOUT'> = {\n DK_ASYNC_TIMEOUT: {\n problem: (d) => `${d.source} did not settle within the timeout (${d.timeout} ms)`,\n impact: () =>\n 'the request was aborted and its late result is ignored; the previous results were kept ' +\n \"(status: 'error')\",\n fix: (d) => [\n `make ${d.source} answer faster (smaller pages, a server-side index), or raise \\`timeout\\` ` +\n `(now ${d.timeout} ms)`,\n `pass ctx.signal to fetch() inside ${d.source} so the timed-out request is cancelled on the ` +\n 'network too',\n ],\n },\n}\n\n/** Codes owned by asyncControl (spec §3.4, §7.1, §8.3). */\nexport const asyncDiagnostics = [\n defineDiagnostic(\n {\n code: 'DK_ASYNC_TIMEOUT',\n level: 'error',\n where: (d) => ({ kind: 'option', path: d.source }),\n },\n (process.env.NODE_ENV !== \"production\") && asyncMessages.DK_ASYNC_TIMEOUT,\n ),\n]\n"],"mappings":";AAAA,SAAkC,wBAAwB;AAC1D,OAAO;AAcA,IAAM,gBAAwD;AAAA,EACnE,kBAAkB;AAAA,IAChB,SAAS,CAAC,MAAM,GAAG,EAAE,MAAM,uCAAuC,EAAE,OAAO;AAAA,IAC3E,QAAQ,MACN;AAAA,IAEF,KAAK,CAAC,MAAM;AAAA,MACV,QAAQ,EAAE,MAAM,kFACN,EAAE,OAAO;AAAA,MACnB,qCAAqC,EAAE,MAAM;AAAA,IAE/C;AAAA,EACF;AACF;AAGO,IAAM,mBAAmB;AAAA,EAC9B;AAAA,IACE;AAAA,MACE,MAAM;AAAA,MACN,OAAO;AAAA,MACP,OAAO,CAAC,OAAO,EAAE,MAAM,UAAU,MAAM,EAAE,OAAO;AAAA,IAClD;AAAA,IACC,QAAQ,IAAI,aAAa,gBAAiB,cAAc;AAAA,EAC3D;AACF;","names":[]}
@@ -25,6 +25,7 @@ __export(fetch_codes_exports, {
25
25
  });
26
26
  module.exports = __toCommonJS(fetch_codes_exports);
27
27
  var import_catalog = require("../diagnostics/catalog.cjs");
28
+ var import_process_guard = require("../diagnostics/process-guard.cjs");
28
29
  var BAD = {
29
30
  "not-an-object": (d) => `fetcher resolved with ${d.received}, not { rows, rowCount }`,
30
31
  "rows-not-an-array": (d) => `fetcher result.rows is ${d.received}, not an array`,