@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,7 @@
1
1
  // src/diagnostics/codes.ts
2
2
  import { VERSION } from "../version.js";
3
3
  import { defineDiagnostic } from "./catalog.js";
4
+ import "./process-guard.js";
4
5
  var ISSUES = "https://github.com/Ink01101011/datakable/issues/new";
5
6
  function issueLink(d) {
6
7
  const title = `DK_INTERNAL in ${d.op}${d.errorName ? ` (${d.errorName})` : ""}`;
@@ -64,14 +65,17 @@ var coreDiagnostics = [
64
65
  },
65
66
  process.env.NODE_ENV !== "production" && coreMessages.DK_INTERCEPTOR_FAILED
66
67
  ),
67
- defineDiagnostic(
68
- {
69
- code: "DK_HOT_INTERCEPTOR",
70
- level: "warn",
71
- where: (d) => ({ kind: "interceptor", name: d.interceptor, op: d.op })
72
- },
73
- process.env.NODE_ENV !== "production" && coreMessages.DK_HOT_INTERCEPTOR
74
- ),
68
+ // Dev-only warning (never emitted in production): no definition there either.
69
+ ...process.env.NODE_ENV !== "production" ? [
70
+ defineDiagnostic(
71
+ {
72
+ code: "DK_HOT_INTERCEPTOR",
73
+ level: "warn",
74
+ where: (d) => ({ kind: "interceptor", name: d.interceptor, op: d.op })
75
+ },
76
+ process.env.NODE_ENV !== "production" && coreMessages.DK_HOT_INTERCEPTOR
77
+ )
78
+ ] : [],
75
79
  defineDiagnostic(
76
80
  {
77
81
  code: "DK_OPERATION_CONFLICT",
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/diagnostics/codes.ts"],"sourcesContent":["import { VERSION } from '../version'\nimport { type DiagnosticMessages, defineDiagnostic } from './catalog'\n\ndeclare module './catalog' {\n interface DiagnosticCatalog {\n DK_INTERCEPTOR_FAILED: { interceptor: string; op: string; slot: string }\n DK_HOT_INTERCEPTOR: { interceptor: string; op: string }\n DK_OPERATION_CONFLICT: {\n op: string\n kind: string\n hot: boolean\n previousKind: string\n previousHot: boolean\n }\n DK_INTERNAL: {\n op: string\n problem: string\n /** The ctx `where` of the failed call (errorBoundary). */\n slot?: string\n /** `error.name` of the classified throw (errorBoundary). */\n errorName?: string\n /** The registry fallback applied (errorBoundary); invariant callers abort instead. */\n fallback?: string\n /**\n * `error.message` of the classified throw (errorBoundary). Engine messages embed row values\n * (`Cannot create property 'x' on string '<value>'`), so it is redacted as a cell value.\n */\n message?: unknown\n }\n }\n}\n\nconst ISSUES = 'https://github.com/Ink01101011/datakable/issues/new'\n\n/** Prefilled GitHub issue (§8.3): version, op, slot and error name — never values. */\nfunction issueLink(d: { op: string; slot?: string; errorName?: string }): string {\n const title = `DK_INTERNAL in ${d.op}${d.errorName ? ` (${d.errorName})` : ''}`\n const body = [\n `package: @datakable/core@${VERSION}`,\n `operation: ${d.op}`,\n `slot: ${d.slot ?? '-'}`,\n `error: ${d.errorName ?? '-'}`,\n '',\n 'diagnostic.toJSON():',\n '',\n 'table.explain():',\n '',\n ].join('\\n')\n return `${ISSUES}?title=${encodeURIComponent(title)}&body=${encodeURIComponent(body)}`\n}\n\n/** Message text (§8.2): development builds, or production via `@datakable/core/messages`. */\nexport const coreMessages: DiagnosticMessages<\n 'DK_INTERCEPTOR_FAILED' | 'DK_HOT_INTERCEPTOR' | 'DK_OPERATION_CONFLICT' | 'DK_INTERNAL'\n> = {\n DK_INTERCEPTOR_FAILED: {\n problem: (d) => `interceptor \"${d.interceptor}\" threw on ${d.op} (at ${d.slot})`,\n impact: () => 'the interceptor was skipped for this call; the operation ran without it',\n fix: (d) => [\n `catch errors inside \"${d.interceptor}\" and always return next() (or a valid result)`,\n `see context.cause for the original error`,\n ],\n },\n DK_HOT_INTERCEPTOR: {\n problem: (d) =>\n `interceptor \"${d.interceptor}\" is attached to hot op \"${d.op}\" without hot: true`,\n // Measured by intercept/chain.bench.ts (Apple M4 Pro, Node 25.2.1): one pass-through\n // interceptor adds ~10 ns per call; spec §9.2 measured +15% when wrapping per cell. Kept inside\n // the builder (no module constant), so production bundles carry none of it.\n impact: () =>\n 'it runs once per column per pipeline run; measured cost: ~10 ns per call per ' +\n 'interceptor (+15% on a per-cell format call, spec §9.2) on top of the interceptor body, ' +\n 'which runs columns × pipeline runs times. It still runs (dev-only warning).',\n fix: (d) => [\n `set hot: true on \"${d.interceptor}\" to accept the cost, and never loop per cell inside it`,\n `attach \"${d.interceptor}\" to cold ops only (list them in \\`on\\` instead of '*' / '${d.op}')`,\n ],\n },\n DK_OPERATION_CONFLICT: {\n problem: (d) =>\n `operation \"${d.op}\" is already registered as ${d.previousKind}` +\n `${d.previousHot ? ' (hot)' : ''}; got ${d.kind}${d.hot ? ' (hot)' : ''}`,\n impact: () => 'the registration was rejected; the first one stays in effect',\n fix: (d) => [\n `register \"${d.op}\" with the same kind and hot flag (${d.previousKind}, hot: ${d.previousHot})`,\n `or give the new operation its own name, e.g. \"myplugin:${d.op.split(':').pop()}\"`,\n ],\n },\n DK_INTERNAL: {\n problem: (d) =>\n d.errorName\n ? `${d.errorName} thrown inside DataKable code during ${d.op}` +\n `${d.message === undefined ? '' : ` (message: ${String(d.message)})`} — likely a DataKable bug`\n : d.problem,\n impact: (d) => (d.fallback ? `${d.fallback}; the table keeps working` : 'the call was aborted'),\n fix: (d) => [\n `this is likely a DataKable bug or a plugin wiring error — report it: ${issueLink(d)}`,\n 'attach diagnostic.toJSON() and table.explain() (both redacted) to the issue',\n 'meanwhile, check plugins / interceptors registered on this operation',\n ],\n },\n}\n\n/** Codes owned by core plumbing (interceptor runtime, op registry). Features define their own. */\nexport const coreDiagnostics = [\n defineDiagnostic(\n {\n code: 'DK_INTERCEPTOR_FAILED',\n level: 'error',\n where: (d) => ({ kind: 'interceptor', name: d.interceptor, op: d.op }),\n },\n (process.env.NODE_ENV !== \"production\") && coreMessages.DK_INTERCEPTOR_FAILED,\n ),\n defineDiagnostic(\n {\n code: 'DK_HOT_INTERCEPTOR',\n level: 'warn',\n where: (d) => ({ kind: 'interceptor', name: d.interceptor, op: d.op }),\n },\n (process.env.NODE_ENV !== \"production\") && coreMessages.DK_HOT_INTERCEPTOR,\n ),\n defineDiagnostic(\n {\n code: 'DK_OPERATION_CONFLICT',\n level: 'error',\n config: true,\n where: (d) => ({ kind: 'operation', op: d.op }),\n },\n (process.env.NODE_ENV !== \"production\") && coreMessages.DK_OPERATION_CONFLICT,\n ),\n // Core invariants (unknown op, boundary installed twice) and throws that errorBoundary traced to\n // DataKable's own code (top stack frame in a datakable path).\n defineDiagnostic(\n {\n code: 'DK_INTERNAL',\n level: 'error',\n where: (d) =>\n d.slot ? { kind: 'operation', op: d.op, slot: d.slot } : { kind: 'operation', op: d.op },\n redact: { message: 'value' },\n },\n (process.env.NODE_ENV !== \"production\") && coreMessages.DK_INTERNAL,\n ),\n]\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/diagnostics/codes.ts"],"sourcesContent":["import { VERSION } from '../version'\nimport { type DiagnosticMessages, defineDiagnostic } from './catalog'\nimport './process-guard'\n\ndeclare module './catalog' {\n interface DiagnosticCatalog {\n DK_INTERCEPTOR_FAILED: { interceptor: string; op: string; slot: string }\n DK_HOT_INTERCEPTOR: { interceptor: string; op: string }\n DK_OPERATION_CONFLICT: {\n op: string\n kind: string\n hot: boolean\n previousKind: string\n previousHot: boolean\n }\n DK_INTERNAL: {\n op: string\n problem: string\n /** The ctx `where` of the failed call (errorBoundary). */\n slot?: string\n /** `error.name` of the classified throw (errorBoundary). */\n errorName?: string\n /** The registry fallback applied (errorBoundary); invariant callers abort instead. */\n fallback?: string\n /**\n * `error.message` of the classified throw (errorBoundary). Engine messages embed row values\n * (`Cannot create property 'x' on string '<value>'`), so it is redacted as a cell value.\n */\n message?: unknown\n }\n }\n}\n\nconst ISSUES = 'https://github.com/Ink01101011/datakable/issues/new'\n\n/** Prefilled GitHub issue (§8.3): version, op, slot and error name — never values. */\nfunction issueLink(d: { op: string; slot?: string; errorName?: string }): string {\n const title = `DK_INTERNAL in ${d.op}${d.errorName ? ` (${d.errorName})` : ''}`\n const body = [\n `package: @datakable/core@${VERSION}`,\n `operation: ${d.op}`,\n `slot: ${d.slot ?? '-'}`,\n `error: ${d.errorName ?? '-'}`,\n '',\n 'diagnostic.toJSON():',\n '',\n 'table.explain():',\n '',\n ].join('\\n')\n return `${ISSUES}?title=${encodeURIComponent(title)}&body=${encodeURIComponent(body)}`\n}\n\n/** Message text (§8.2): development builds, or production via `@datakable/core/messages`. */\nexport const coreMessages: DiagnosticMessages<\n 'DK_INTERCEPTOR_FAILED' | 'DK_HOT_INTERCEPTOR' | 'DK_OPERATION_CONFLICT' | 'DK_INTERNAL'\n> = {\n DK_INTERCEPTOR_FAILED: {\n problem: (d) => `interceptor \"${d.interceptor}\" threw on ${d.op} (at ${d.slot})`,\n impact: () => 'the interceptor was skipped for this call; the operation ran without it',\n fix: (d) => [\n `catch errors inside \"${d.interceptor}\" and always return next() (or a valid result)`,\n `see context.cause for the original error`,\n ],\n },\n DK_HOT_INTERCEPTOR: {\n problem: (d) =>\n `interceptor \"${d.interceptor}\" is attached to hot op \"${d.op}\" without hot: true`,\n // Measured by intercept/chain.bench.ts (Apple M4 Pro, Node 25.2.1): one pass-through\n // interceptor adds ~10 ns per call; spec §9.2 measured +15% when wrapping per cell. Kept inside\n // the builder (no module constant), so production bundles carry none of it.\n impact: () =>\n 'it runs once per column per pipeline run; measured cost: ~10 ns per call per ' +\n 'interceptor (+15% on a per-cell format call, spec §9.2) on top of the interceptor body, ' +\n 'which runs columns × pipeline runs times. It still runs (dev-only warning).',\n fix: (d) => [\n `set hot: true on \"${d.interceptor}\" to accept the cost, and never loop per cell inside it`,\n `attach \"${d.interceptor}\" to cold ops only (list them in \\`on\\` instead of '*' / '${d.op}')`,\n ],\n },\n DK_OPERATION_CONFLICT: {\n problem: (d) =>\n `operation \"${d.op}\" is already registered as ${d.previousKind}` +\n `${d.previousHot ? ' (hot)' : ''}; got ${d.kind}${d.hot ? ' (hot)' : ''}`,\n impact: () => 'the registration was rejected; the first one stays in effect',\n fix: (d) => [\n `register \"${d.op}\" with the same kind and hot flag (${d.previousKind}, hot: ${d.previousHot})`,\n `or give the new operation its own name, e.g. \"myplugin:${d.op.split(':').pop()}\"`,\n ],\n },\n DK_INTERNAL: {\n problem: (d) =>\n d.errorName\n ? `${d.errorName} thrown inside DataKable code during ${d.op}` +\n `${d.message === undefined ? '' : ` (message: ${String(d.message)})`} — likely a DataKable bug`\n : d.problem,\n impact: (d) => (d.fallback ? `${d.fallback}; the table keeps working` : 'the call was aborted'),\n fix: (d) => [\n `this is likely a DataKable bug or a plugin wiring error — report it: ${issueLink(d)}`,\n 'attach diagnostic.toJSON() and table.explain() (both redacted) to the issue',\n 'meanwhile, check plugins / interceptors registered on this operation',\n ],\n },\n}\n\n/** Codes owned by core plumbing (interceptor runtime, op registry). Features define their own. */\nexport const coreDiagnostics = [\n defineDiagnostic(\n {\n code: 'DK_INTERCEPTOR_FAILED',\n level: 'error',\n where: (d) => ({ kind: 'interceptor', name: d.interceptor, op: d.op }),\n },\n (process.env.NODE_ENV !== \"production\") && coreMessages.DK_INTERCEPTOR_FAILED,\n ),\n // Dev-only warning (never emitted in production): no definition there either.\n ...((process.env.NODE_ENV !== \"production\")\n ? [\n defineDiagnostic(\n {\n code: 'DK_HOT_INTERCEPTOR',\n level: 'warn',\n where: (d) => ({ kind: 'interceptor', name: d.interceptor, op: d.op }),\n },\n (process.env.NODE_ENV !== \"production\") && coreMessages.DK_HOT_INTERCEPTOR,\n ),\n ]\n : []),\n defineDiagnostic(\n {\n code: 'DK_OPERATION_CONFLICT',\n level: 'error',\n config: true,\n where: (d) => ({ kind: 'operation', op: d.op }),\n },\n (process.env.NODE_ENV !== \"production\") && coreMessages.DK_OPERATION_CONFLICT,\n ),\n // Core invariants (unknown op, boundary installed twice) and throws that errorBoundary traced to\n // DataKable's own code (top stack frame in a datakable path).\n defineDiagnostic(\n {\n code: 'DK_INTERNAL',\n level: 'error',\n where: (d) =>\n d.slot ? { kind: 'operation', op: d.op, slot: d.slot } : { kind: 'operation', op: d.op },\n redact: { message: 'value' },\n },\n (process.env.NODE_ENV !== \"production\") && coreMessages.DK_INTERNAL,\n ),\n]\n"],"mappings":"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","names":[]}
@@ -25,6 +25,7 @@ __export(console_exports, {
25
25
  });
26
26
  module.exports = __toCommonJS(console_exports);
27
27
  var import_build = require("./build.cjs");
28
+ var import_process_guard = require("./process-guard.cjs");
28
29
  var ICON = { error: "\u2716", warn: "\u26A0", info: "\u2139" };
29
30
  function formatDiagnostic(d) {
30
31
  const header = `${ICON[d.level]} [DataKable ${d.context.table}] ${d.code}: ${d.problem}`;
@@ -60,14 +61,20 @@ function createConsoleSink(o) {
60
61
  return;
61
62
  }
62
63
  printed++;
63
- if (!(process.env.NODE_ENV !== "production") || !o.dev) {
64
- console.error(`[DataKable ${o.table}] ${d.code} at ${(0, import_build.formatWhere)(d.where)} \u2014 ${d.docs}`);
64
+ if (process.env.NODE_ENV !== "production" && o.dev) {
65
+ const { header, body } = formatDiagnostic(d);
66
+ const log = d.level === "error" ? "error" : d.level === "warn" ? "warn" : "info";
67
+ if (typeof console.groupCollapsed !== "function" || typeof console.groupEnd !== "function") {
68
+ console[log](`${header}
69
+ ${body}`);
70
+ return;
71
+ }
72
+ console.groupCollapsed(header);
73
+ console[log](body);
74
+ console.groupEnd();
65
75
  return;
66
76
  }
67
- const { header, body } = formatDiagnostic(d);
68
- console.groupCollapsed(header);
69
- (d.level === "error" ? console.error : d.level === "warn" ? console.warn : console.info)(body);
70
- console.groupEnd();
77
+ console.error(`[DataKable ${o.table}] ${d.code} at ${(0, import_build.formatWhere)(d.where)} \u2014 ${d.docs}`);
71
78
  };
72
79
  }
73
80
  // Annotate the CommonJS export names for ESM import in node:
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/diagnostics/console.ts"],"sourcesContent":["import { formatWhere } from './build'\nimport type { Diagnostic } from './types'\n\nconst ICON = { error: '✖', warn: '⚠', info: 'ℹ' } as const\n\n/** The §8.1 console text: header + aligned body. Also usable by explain() and tests. */\nexport function formatDiagnostic(d: Diagnostic): { header: string; body: string } {\n const header = `${ICON[d.level]} [DataKable ${d.context.table}] ${d.code}: ${d.problem}`\n const lines = [` where ${formatWhere(d.where)}`]\n if (d.impact) lines.push(` impact ${d.impact}`)\n d.fix.forEach((f, i) => {\n lines.push(`${i === 0 ? ' fix ' : ' '}${i + 1}. ${f}`)\n })\n lines.push(` docs ${d.docs}`)\n const c = d.context\n lines.push(` context trigger=${c.trigger} run=${c.run} phase=${c.phase}`)\n return { header, body: lines.join('\\n') }\n}\n\nexport interface ConsoleSinkOptions {\n table: string\n dev: boolean\n rateLimit: { max: number; windowMs: number }\n now: () => number\n}\n\n/**\n * Default console sink (§8.2): dev prints one collapsed group per diagnostic; prod prints\n * error level only, on one line. A fixed-window rate limit protects the console; what it holds back\n * is still in getDiagnostics() and onDiagnostic.\n */\nexport function createConsoleSink(o: ConsoleSinkOptions): (d: Diagnostic) => void {\n let windowStart = Number.NEGATIVE_INFINITY\n let printed = 0\n let suppressed = 0\n // The grouped format is development-only: a production build prints one line (§8.2). `(process.env.NODE_ENV !== \"production\")` is\n // read inline so the bundler drops the grouped branch.\n return (d) => {\n if ((!(process.env.NODE_ENV !== \"production\") || !o.dev) && d.level !== 'error') return\n const t = o.now()\n if (t - windowStart >= o.rateLimit.windowMs) {\n if (suppressed > 0) {\n console.warn(\n `[DataKable ${o.table}] ${suppressed} diagnostics were not printed (rate limit); ` +\n 'read them with getDiagnostics() or onDiagnostic',\n )\n }\n windowStart = t\n printed = 0\n suppressed = 0\n }\n if (printed >= o.rateLimit.max) {\n suppressed++\n return\n }\n printed++\n if (!(process.env.NODE_ENV !== \"production\") || !o.dev) {\n console.error(`[DataKable ${o.table}] ${d.code} at ${formatWhere(d.where)} — ${d.docs}`)\n return\n }\n const { header, body } = formatDiagnostic(d)\n console.groupCollapsed(header)\n ;(d.level === 'error' ? console.error : d.level === 'warn' ? console.warn : console.info)(body)\n console.groupEnd()\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAA4B;AAG5B,IAAM,OAAO,EAAE,OAAO,UAAK,MAAM,UAAK,MAAM,SAAI;AAGzC,SAAS,iBAAiB,GAAiD;AAChF,QAAM,SAAS,GAAG,KAAK,EAAE,KAAK,CAAC,eAAe,EAAE,QAAQ,KAAK,KAAK,EAAE,IAAI,KAAK,EAAE,OAAO;AACtF,QAAM,QAAQ,CAAC,iBAAa,0BAAY,EAAE,KAAK,CAAC,EAAE;AAClD,MAAI,EAAE,OAAQ,OAAM,KAAK,aAAa,EAAE,MAAM,EAAE;AAChD,IAAE,IAAI,QAAQ,CAAC,GAAG,MAAM;AACtB,UAAM,KAAK,GAAG,MAAM,IAAI,eAAe,YAAY,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE;AAAA,EACrE,CAAC;AACD,QAAM,KAAK,aAAa,EAAE,IAAI,EAAE;AAChC,QAAM,IAAI,EAAE;AACZ,QAAM,KAAK,qBAAqB,EAAE,OAAO,QAAQ,EAAE,GAAG,UAAU,EAAE,KAAK,EAAE;AACzE,SAAO,EAAE,QAAQ,MAAM,MAAM,KAAK,IAAI,EAAE;AAC1C;AAcO,SAAS,kBAAkB,GAAgD;AAChF,MAAI,cAAc,OAAO;AACzB,MAAI,UAAU;AACd,MAAI,aAAa;AAGjB,SAAO,CAAC,MAAM;AACZ,SAAK,EAAE,QAAQ,IAAI,aAAa,iBAAiB,CAAC,EAAE,QAAQ,EAAE,UAAU,QAAS;AACjF,UAAM,IAAI,EAAE,IAAI;AAChB,QAAI,IAAI,eAAe,EAAE,UAAU,UAAU;AAC3C,UAAI,aAAa,GAAG;AAClB,gBAAQ;AAAA,UACN,cAAc,EAAE,KAAK,KAAK,UAAU;AAAA,QAEtC;AAAA,MACF;AACA,oBAAc;AACd,gBAAU;AACV,mBAAa;AAAA,IACf;AACA,QAAI,WAAW,EAAE,UAAU,KAAK;AAC9B;AACA;AAAA,IACF;AACA;AACA,QAAI,EAAE,QAAQ,IAAI,aAAa,iBAAiB,CAAC,EAAE,KAAK;AACtD,cAAQ,MAAM,cAAc,EAAE,KAAK,KAAK,EAAE,IAAI,WAAO,0BAAY,EAAE,KAAK,CAAC,WAAM,EAAE,IAAI,EAAE;AACvF;AAAA,IACF;AACA,UAAM,EAAE,QAAQ,KAAK,IAAI,iBAAiB,CAAC;AAC3C,YAAQ,eAAe,MAAM;AAC5B,KAAC,EAAE,UAAU,UAAU,QAAQ,QAAQ,EAAE,UAAU,SAAS,QAAQ,OAAO,QAAQ,MAAM,IAAI;AAC9F,YAAQ,SAAS;AAAA,EACnB;AACF;","names":[]}
1
+ {"version":3,"sources":["../../src/diagnostics/console.ts"],"sourcesContent":["import { formatWhere } from './build'\nimport './process-guard'\nimport type { Diagnostic } from './types'\n\nconst ICON = { error: '✖', warn: '⚠', info: 'ℹ' } as const\n\n/** The §8.1 console text: header + aligned body. Also usable by explain() and tests. */\nexport function formatDiagnostic(d: Diagnostic): { header: string; body: string } {\n const header = `${ICON[d.level]} [DataKable ${d.context.table}] ${d.code}: ${d.problem}`\n const lines = [` where ${formatWhere(d.where)}`]\n if (d.impact) lines.push(` impact ${d.impact}`)\n d.fix.forEach((f, i) => {\n lines.push(`${i === 0 ? ' fix ' : ' '}${i + 1}. ${f}`)\n })\n lines.push(` docs ${d.docs}`)\n const c = d.context\n lines.push(` context trigger=${c.trigger} run=${c.run} phase=${c.phase}`)\n return { header, body: lines.join('\\n') }\n}\n\nexport interface ConsoleSinkOptions {\n table: string\n dev: boolean\n rateLimit: { max: number; windowMs: number }\n now: () => number\n}\n\n/**\n * Default console sink (§8.2): dev prints one collapsed group per diagnostic; prod prints\n * error level only, on one line. A fixed-window rate limit protects the console; what it holds back\n * is still in getDiagnostics() and onDiagnostic.\n */\nexport function createConsoleSink(o: ConsoleSinkOptions): (d: Diagnostic) => void {\n let windowStart = Number.NEGATIVE_INFINITY\n let printed = 0\n let suppressed = 0\n // The grouped format is development-only: a production build prints one line (§8.2). `(process.env.NODE_ENV !== \"production\")` is\n // read inline so the bundler drops the grouped branch.\n return (d) => {\n if ((!(process.env.NODE_ENV !== \"production\") || !o.dev) && d.level !== 'error') return\n const t = o.now()\n if (t - windowStart >= o.rateLimit.windowMs) {\n if (suppressed > 0) {\n console.warn(\n `[DataKable ${o.table}] ${suppressed} diagnostics were not printed (rate limit); ` +\n 'read them with getDiagnostics() or onDiagnostic',\n )\n }\n windowStart = t\n printed = 0\n suppressed = 0\n }\n if (printed >= o.rateLimit.max) {\n suppressed++\n return\n }\n printed++\n // `(process.env.NODE_ENV !== \"production\") &&` first, not an early `if (!(process.env.NODE_ENV !== \"production\")) return`: a branch that folds to `false` is removed\n // while parsing, so a production bundle keeps no `formatDiagnostic` (code after a folded early\n // return is dropped only when printing, after tree shaking kept what it calls).\n if ((process.env.NODE_ENV !== \"production\") && o.dev) {\n const { header, body } = formatDiagnostic(d)\n const log = d.level === 'error' ? 'error' : d.level === 'warn' ? 'warn' : 'info'\n // Runtimes without console groups (the Edge Runtime: log/info/warn/error/debug only) get the\n // same text as one call.\n if (typeof console.groupCollapsed !== 'function' || typeof console.groupEnd !== 'function') {\n console[log](`${header}\\n${body}`)\n return\n }\n console.groupCollapsed(header)\n console[log](body)\n console.groupEnd()\n return\n }\n console.error(`[DataKable ${o.table}] ${d.code} at ${formatWhere(d.where)} — ${d.docs}`)\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAA4B;AAC5B,2BAAO;AAGP,IAAM,OAAO,EAAE,OAAO,UAAK,MAAM,UAAK,MAAM,SAAI;AAGzC,SAAS,iBAAiB,GAAiD;AAChF,QAAM,SAAS,GAAG,KAAK,EAAE,KAAK,CAAC,eAAe,EAAE,QAAQ,KAAK,KAAK,EAAE,IAAI,KAAK,EAAE,OAAO;AACtF,QAAM,QAAQ,CAAC,iBAAa,0BAAY,EAAE,KAAK,CAAC,EAAE;AAClD,MAAI,EAAE,OAAQ,OAAM,KAAK,aAAa,EAAE,MAAM,EAAE;AAChD,IAAE,IAAI,QAAQ,CAAC,GAAG,MAAM;AACtB,UAAM,KAAK,GAAG,MAAM,IAAI,eAAe,YAAY,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE;AAAA,EACrE,CAAC;AACD,QAAM,KAAK,aAAa,EAAE,IAAI,EAAE;AAChC,QAAM,IAAI,EAAE;AACZ,QAAM,KAAK,qBAAqB,EAAE,OAAO,QAAQ,EAAE,GAAG,UAAU,EAAE,KAAK,EAAE;AACzE,SAAO,EAAE,QAAQ,MAAM,MAAM,KAAK,IAAI,EAAE;AAC1C;AAcO,SAAS,kBAAkB,GAAgD;AAChF,MAAI,cAAc,OAAO;AACzB,MAAI,UAAU;AACd,MAAI,aAAa;AAGjB,SAAO,CAAC,MAAM;AACZ,SAAK,EAAE,QAAQ,IAAI,aAAa,iBAAiB,CAAC,EAAE,QAAQ,EAAE,UAAU,QAAS;AACjF,UAAM,IAAI,EAAE,IAAI;AAChB,QAAI,IAAI,eAAe,EAAE,UAAU,UAAU;AAC3C,UAAI,aAAa,GAAG;AAClB,gBAAQ;AAAA,UACN,cAAc,EAAE,KAAK,KAAK,UAAU;AAAA,QAEtC;AAAA,MACF;AACA,oBAAc;AACd,gBAAU;AACV,mBAAa;AAAA,IACf;AACA,QAAI,WAAW,EAAE,UAAU,KAAK;AAC9B;AACA;AAAA,IACF;AACA;AAIA,QAAK,QAAQ,IAAI,aAAa,gBAAiB,EAAE,KAAK;AACpD,YAAM,EAAE,QAAQ,KAAK,IAAI,iBAAiB,CAAC;AAC3C,YAAM,MAAM,EAAE,UAAU,UAAU,UAAU,EAAE,UAAU,SAAS,SAAS;AAG1E,UAAI,OAAO,QAAQ,mBAAmB,cAAc,OAAO,QAAQ,aAAa,YAAY;AAC1F,gBAAQ,GAAG,EAAE,GAAG,MAAM;AAAA,EAAK,IAAI,EAAE;AACjC;AAAA,MACF;AACA,cAAQ,eAAe,MAAM;AAC7B,cAAQ,GAAG,EAAE,IAAI;AACjB,cAAQ,SAAS;AACjB;AAAA,IACF;AACA,YAAQ,MAAM,cAAc,EAAE,KAAK,KAAK,EAAE,IAAI,WAAO,0BAAY,EAAE,KAAK,CAAC,WAAM,EAAE,IAAI,EAAE;AAAA,EACzF;AACF;","names":[]}
@@ -1,5 +1,6 @@
1
1
  // src/diagnostics/console.ts
2
2
  import { formatWhere } from "./build.js";
3
+ import "./process-guard.js";
3
4
  var ICON = { error: "\u2716", warn: "\u26A0", info: "\u2139" };
4
5
  function formatDiagnostic(d) {
5
6
  const header = `${ICON[d.level]} [DataKable ${d.context.table}] ${d.code}: ${d.problem}`;
@@ -35,14 +36,20 @@ function createConsoleSink(o) {
35
36
  return;
36
37
  }
37
38
  printed++;
38
- if (!(process.env.NODE_ENV !== "production") || !o.dev) {
39
- console.error(`[DataKable ${o.table}] ${d.code} at ${formatWhere(d.where)} \u2014 ${d.docs}`);
39
+ if (process.env.NODE_ENV !== "production" && o.dev) {
40
+ const { header, body } = formatDiagnostic(d);
41
+ const log = d.level === "error" ? "error" : d.level === "warn" ? "warn" : "info";
42
+ if (typeof console.groupCollapsed !== "function" || typeof console.groupEnd !== "function") {
43
+ console[log](`${header}
44
+ ${body}`);
45
+ return;
46
+ }
47
+ console.groupCollapsed(header);
48
+ console[log](body);
49
+ console.groupEnd();
40
50
  return;
41
51
  }
42
- const { header, body } = formatDiagnostic(d);
43
- console.groupCollapsed(header);
44
- (d.level === "error" ? console.error : d.level === "warn" ? console.warn : console.info)(body);
45
- console.groupEnd();
52
+ console.error(`[DataKable ${o.table}] ${d.code} at ${formatWhere(d.where)} \u2014 ${d.docs}`);
46
53
  };
47
54
  }
48
55
  export {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/diagnostics/console.ts"],"sourcesContent":["import { formatWhere } from './build'\nimport type { Diagnostic } from './types'\n\nconst ICON = { error: '✖', warn: '⚠', info: 'ℹ' } as const\n\n/** The §8.1 console text: header + aligned body. Also usable by explain() and tests. */\nexport function formatDiagnostic(d: Diagnostic): { header: string; body: string } {\n const header = `${ICON[d.level]} [DataKable ${d.context.table}] ${d.code}: ${d.problem}`\n const lines = [` where ${formatWhere(d.where)}`]\n if (d.impact) lines.push(` impact ${d.impact}`)\n d.fix.forEach((f, i) => {\n lines.push(`${i === 0 ? ' fix ' : ' '}${i + 1}. ${f}`)\n })\n lines.push(` docs ${d.docs}`)\n const c = d.context\n lines.push(` context trigger=${c.trigger} run=${c.run} phase=${c.phase}`)\n return { header, body: lines.join('\\n') }\n}\n\nexport interface ConsoleSinkOptions {\n table: string\n dev: boolean\n rateLimit: { max: number; windowMs: number }\n now: () => number\n}\n\n/**\n * Default console sink (§8.2): dev prints one collapsed group per diagnostic; prod prints\n * error level only, on one line. A fixed-window rate limit protects the console; what it holds back\n * is still in getDiagnostics() and onDiagnostic.\n */\nexport function createConsoleSink(o: ConsoleSinkOptions): (d: Diagnostic) => void {\n let windowStart = Number.NEGATIVE_INFINITY\n let printed = 0\n let suppressed = 0\n // The grouped format is development-only: a production build prints one line (§8.2). `(process.env.NODE_ENV !== \"production\")` is\n // read inline so the bundler drops the grouped branch.\n return (d) => {\n if ((!(process.env.NODE_ENV !== \"production\") || !o.dev) && d.level !== 'error') return\n const t = o.now()\n if (t - windowStart >= o.rateLimit.windowMs) {\n if (suppressed > 0) {\n console.warn(\n `[DataKable ${o.table}] ${suppressed} diagnostics were not printed (rate limit); ` +\n 'read them with getDiagnostics() or onDiagnostic',\n )\n }\n windowStart = t\n printed = 0\n suppressed = 0\n }\n if (printed >= o.rateLimit.max) {\n suppressed++\n return\n }\n printed++\n if (!(process.env.NODE_ENV !== \"production\") || !o.dev) {\n console.error(`[DataKable ${o.table}] ${d.code} at ${formatWhere(d.where)} — ${d.docs}`)\n return\n }\n const { header, body } = formatDiagnostic(d)\n console.groupCollapsed(header)\n ;(d.level === 'error' ? console.error : d.level === 'warn' ? console.warn : console.info)(body)\n console.groupEnd()\n }\n}\n"],"mappings":";AAAA,SAAS,mBAAmB;AAG5B,IAAM,OAAO,EAAE,OAAO,UAAK,MAAM,UAAK,MAAM,SAAI;AAGzC,SAAS,iBAAiB,GAAiD;AAChF,QAAM,SAAS,GAAG,KAAK,EAAE,KAAK,CAAC,eAAe,EAAE,QAAQ,KAAK,KAAK,EAAE,IAAI,KAAK,EAAE,OAAO;AACtF,QAAM,QAAQ,CAAC,aAAa,YAAY,EAAE,KAAK,CAAC,EAAE;AAClD,MAAI,EAAE,OAAQ,OAAM,KAAK,aAAa,EAAE,MAAM,EAAE;AAChD,IAAE,IAAI,QAAQ,CAAC,GAAG,MAAM;AACtB,UAAM,KAAK,GAAG,MAAM,IAAI,eAAe,YAAY,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE;AAAA,EACrE,CAAC;AACD,QAAM,KAAK,aAAa,EAAE,IAAI,EAAE;AAChC,QAAM,IAAI,EAAE;AACZ,QAAM,KAAK,qBAAqB,EAAE,OAAO,QAAQ,EAAE,GAAG,UAAU,EAAE,KAAK,EAAE;AACzE,SAAO,EAAE,QAAQ,MAAM,MAAM,KAAK,IAAI,EAAE;AAC1C;AAcO,SAAS,kBAAkB,GAAgD;AAChF,MAAI,cAAc,OAAO;AACzB,MAAI,UAAU;AACd,MAAI,aAAa;AAGjB,SAAO,CAAC,MAAM;AACZ,SAAK,EAAE,QAAQ,IAAI,aAAa,iBAAiB,CAAC,EAAE,QAAQ,EAAE,UAAU,QAAS;AACjF,UAAM,IAAI,EAAE,IAAI;AAChB,QAAI,IAAI,eAAe,EAAE,UAAU,UAAU;AAC3C,UAAI,aAAa,GAAG;AAClB,gBAAQ;AAAA,UACN,cAAc,EAAE,KAAK,KAAK,UAAU;AAAA,QAEtC;AAAA,MACF;AACA,oBAAc;AACd,gBAAU;AACV,mBAAa;AAAA,IACf;AACA,QAAI,WAAW,EAAE,UAAU,KAAK;AAC9B;AACA;AAAA,IACF;AACA;AACA,QAAI,EAAE,QAAQ,IAAI,aAAa,iBAAiB,CAAC,EAAE,KAAK;AACtD,cAAQ,MAAM,cAAc,EAAE,KAAK,KAAK,EAAE,IAAI,OAAO,YAAY,EAAE,KAAK,CAAC,WAAM,EAAE,IAAI,EAAE;AACvF;AAAA,IACF;AACA,UAAM,EAAE,QAAQ,KAAK,IAAI,iBAAiB,CAAC;AAC3C,YAAQ,eAAe,MAAM;AAC5B,KAAC,EAAE,UAAU,UAAU,QAAQ,QAAQ,EAAE,UAAU,SAAS,QAAQ,OAAO,QAAQ,MAAM,IAAI;AAC9F,YAAQ,SAAS;AAAA,EACnB;AACF;","names":[]}
1
+ {"version":3,"sources":["../../src/diagnostics/console.ts"],"sourcesContent":["import { formatWhere } from './build'\nimport './process-guard'\nimport type { Diagnostic } from './types'\n\nconst ICON = { error: '✖', warn: '⚠', info: 'ℹ' } as const\n\n/** The §8.1 console text: header + aligned body. Also usable by explain() and tests. */\nexport function formatDiagnostic(d: Diagnostic): { header: string; body: string } {\n const header = `${ICON[d.level]} [DataKable ${d.context.table}] ${d.code}: ${d.problem}`\n const lines = [` where ${formatWhere(d.where)}`]\n if (d.impact) lines.push(` impact ${d.impact}`)\n d.fix.forEach((f, i) => {\n lines.push(`${i === 0 ? ' fix ' : ' '}${i + 1}. ${f}`)\n })\n lines.push(` docs ${d.docs}`)\n const c = d.context\n lines.push(` context trigger=${c.trigger} run=${c.run} phase=${c.phase}`)\n return { header, body: lines.join('\\n') }\n}\n\nexport interface ConsoleSinkOptions {\n table: string\n dev: boolean\n rateLimit: { max: number; windowMs: number }\n now: () => number\n}\n\n/**\n * Default console sink (§8.2): dev prints one collapsed group per diagnostic; prod prints\n * error level only, on one line. A fixed-window rate limit protects the console; what it holds back\n * is still in getDiagnostics() and onDiagnostic.\n */\nexport function createConsoleSink(o: ConsoleSinkOptions): (d: Diagnostic) => void {\n let windowStart = Number.NEGATIVE_INFINITY\n let printed = 0\n let suppressed = 0\n // The grouped format is development-only: a production build prints one line (§8.2). `(process.env.NODE_ENV !== \"production\")` is\n // read inline so the bundler drops the grouped branch.\n return (d) => {\n if ((!(process.env.NODE_ENV !== \"production\") || !o.dev) && d.level !== 'error') return\n const t = o.now()\n if (t - windowStart >= o.rateLimit.windowMs) {\n if (suppressed > 0) {\n console.warn(\n `[DataKable ${o.table}] ${suppressed} diagnostics were not printed (rate limit); ` +\n 'read them with getDiagnostics() or onDiagnostic',\n )\n }\n windowStart = t\n printed = 0\n suppressed = 0\n }\n if (printed >= o.rateLimit.max) {\n suppressed++\n return\n }\n printed++\n // `(process.env.NODE_ENV !== \"production\") &&` first, not an early `if (!(process.env.NODE_ENV !== \"production\")) return`: a branch that folds to `false` is removed\n // while parsing, so a production bundle keeps no `formatDiagnostic` (code after a folded early\n // return is dropped only when printing, after tree shaking kept what it calls).\n if ((process.env.NODE_ENV !== \"production\") && o.dev) {\n const { header, body } = formatDiagnostic(d)\n const log = d.level === 'error' ? 'error' : d.level === 'warn' ? 'warn' : 'info'\n // Runtimes without console groups (the Edge Runtime: log/info/warn/error/debug only) get the\n // same text as one call.\n if (typeof console.groupCollapsed !== 'function' || typeof console.groupEnd !== 'function') {\n console[log](`${header}\\n${body}`)\n return\n }\n console.groupCollapsed(header)\n console[log](body)\n console.groupEnd()\n return\n }\n console.error(`[DataKable ${o.table}] ${d.code} at ${formatWhere(d.where)} — ${d.docs}`)\n }\n}\n"],"mappings":";AAAA,SAAS,mBAAmB;AAC5B,OAAO;AAGP,IAAM,OAAO,EAAE,OAAO,UAAK,MAAM,UAAK,MAAM,SAAI;AAGzC,SAAS,iBAAiB,GAAiD;AAChF,QAAM,SAAS,GAAG,KAAK,EAAE,KAAK,CAAC,eAAe,EAAE,QAAQ,KAAK,KAAK,EAAE,IAAI,KAAK,EAAE,OAAO;AACtF,QAAM,QAAQ,CAAC,aAAa,YAAY,EAAE,KAAK,CAAC,EAAE;AAClD,MAAI,EAAE,OAAQ,OAAM,KAAK,aAAa,EAAE,MAAM,EAAE;AAChD,IAAE,IAAI,QAAQ,CAAC,GAAG,MAAM;AACtB,UAAM,KAAK,GAAG,MAAM,IAAI,eAAe,YAAY,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE;AAAA,EACrE,CAAC;AACD,QAAM,KAAK,aAAa,EAAE,IAAI,EAAE;AAChC,QAAM,IAAI,EAAE;AACZ,QAAM,KAAK,qBAAqB,EAAE,OAAO,QAAQ,EAAE,GAAG,UAAU,EAAE,KAAK,EAAE;AACzE,SAAO,EAAE,QAAQ,MAAM,MAAM,KAAK,IAAI,EAAE;AAC1C;AAcO,SAAS,kBAAkB,GAAgD;AAChF,MAAI,cAAc,OAAO;AACzB,MAAI,UAAU;AACd,MAAI,aAAa;AAGjB,SAAO,CAAC,MAAM;AACZ,SAAK,EAAE,QAAQ,IAAI,aAAa,iBAAiB,CAAC,EAAE,QAAQ,EAAE,UAAU,QAAS;AACjF,UAAM,IAAI,EAAE,IAAI;AAChB,QAAI,IAAI,eAAe,EAAE,UAAU,UAAU;AAC3C,UAAI,aAAa,GAAG;AAClB,gBAAQ;AAAA,UACN,cAAc,EAAE,KAAK,KAAK,UAAU;AAAA,QAEtC;AAAA,MACF;AACA,oBAAc;AACd,gBAAU;AACV,mBAAa;AAAA,IACf;AACA,QAAI,WAAW,EAAE,UAAU,KAAK;AAC9B;AACA;AAAA,IACF;AACA;AAIA,QAAK,QAAQ,IAAI,aAAa,gBAAiB,EAAE,KAAK;AACpD,YAAM,EAAE,QAAQ,KAAK,IAAI,iBAAiB,CAAC;AAC3C,YAAM,MAAM,EAAE,UAAU,UAAU,UAAU,EAAE,UAAU,SAAS,SAAS;AAG1E,UAAI,OAAO,QAAQ,mBAAmB,cAAc,OAAO,QAAQ,aAAa,YAAY;AAC1F,gBAAQ,GAAG,EAAE,GAAG,MAAM;AAAA,EAAK,IAAI,EAAE;AACjC;AAAA,MACF;AACA,cAAQ,eAAe,MAAM;AAC7B,cAAQ,GAAG,EAAE,IAAI;AACjB,cAAQ,SAAS;AACjB;AAAA,IACF;AACA,YAAQ,MAAM,cAAc,EAAE,KAAK,KAAK,EAAE,IAAI,OAAO,YAAY,EAAE,KAAK,CAAC,WAAM,EAAE,IAAI,EAAE;AAAA,EACzF;AACF;","names":[]}
@@ -23,6 +23,7 @@ __export(env_exports, {
23
23
  DEV: () => DEV
24
24
  });
25
25
  module.exports = __toCommonJS(env_exports);
26
+ var import_process_guard = require("./process-guard.cjs");
26
27
  var DEV = process.env.NODE_ENV !== "production";
27
28
  // Annotate the CommonJS export names for ESM import in node:
28
29
  0 && (module.exports = {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/diagnostics/env.ts"],"sourcesContent":["// No @types/node in core: declare just what is read.\ndeclare const process: { env: { NODE_ENV?: string } }\n\n/**\n * Development build: text builders, dev checks and dev-only warnings are on (§8.2).\n *\n * Written as the bare `process.env.NODE_ENV` read on purpose: bundlers replace it with a string\n * literal, so `DEV` folds to a constant and every `if (DEV)` branch is removed from a production\n * bundle. A `typeof process` guard would keep it a runtime value (and `true` in browsers).\n */\nexport const DEV: boolean = process.env.NODE_ENV !== 'production'\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAUO,IAAM,MAAe,QAAQ,IAAI,aAAa;","names":[]}
1
+ {"version":3,"sources":["../../src/diagnostics/env.ts"],"sourcesContent":["// The helpful error when `process` is missing (#36); evaluated before the read below.\nimport './process-guard'\n\n// No @types/node in core: declare just what is read.\ndeclare const process: { env: { NODE_ENV?: string } }\n\n/**\n * Development build: text builders, dev checks and dev-only warnings are on (§8.2).\n *\n * Written as the bare `process.env.NODE_ENV` read on purpose: bundlers replace it with a string\n * literal, so `DEV` folds to a constant and every `if (DEV)` branch is removed from a production\n * bundle. A `typeof process` guard would keep it a runtime value (and `true` in browsers).\n */\nexport const DEV: boolean = process.env.NODE_ENV !== 'production'\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AACA,2BAAO;AAYA,IAAM,MAAe,QAAQ,IAAI,aAAa;","names":[]}
@@ -1,4 +1,5 @@
1
1
  // src/diagnostics/env.ts
2
+ import "./process-guard.js";
2
3
  var DEV = process.env.NODE_ENV !== "production";
3
4
  export {
4
5
  DEV
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/diagnostics/env.ts"],"sourcesContent":["// No @types/node in core: declare just what is read.\ndeclare const process: { env: { NODE_ENV?: string } }\n\n/**\n * Development build: text builders, dev checks and dev-only warnings are on (§8.2).\n *\n * Written as the bare `process.env.NODE_ENV` read on purpose: bundlers replace it with a string\n * literal, so `DEV` folds to a constant and every `if (DEV)` branch is removed from a production\n * bundle. A `typeof process` guard would keep it a runtime value (and `true` in browsers).\n */\nexport const DEV: boolean = process.env.NODE_ENV !== 'production'\n"],"mappings":";AAUO,IAAM,MAAe,QAAQ,IAAI,aAAa;","names":[]}
1
+ {"version":3,"sources":["../../src/diagnostics/env.ts"],"sourcesContent":["// The helpful error when `process` is missing (#36); evaluated before the read below.\nimport './process-guard'\n\n// No @types/node in core: declare just what is read.\ndeclare const process: { env: { NODE_ENV?: string } }\n\n/**\n * Development build: text builders, dev checks and dev-only warnings are on (§8.2).\n *\n * Written as the bare `process.env.NODE_ENV` read on purpose: bundlers replace it with a string\n * literal, so `DEV` folds to a constant and every `if (DEV)` branch is removed from a production\n * bundle. A `typeof process` guard would keep it a runtime value (and `true` in browsers).\n */\nexport const DEV: boolean = process.env.NODE_ENV !== 'production'\n"],"mappings":";AACA,OAAO;AAYA,IAAM,MAAe,QAAQ,IAAI,aAAa;","names":[]}
@@ -40,7 +40,8 @@ function formatTableExplanation(e) {
40
40
  continue;
41
41
  }
42
42
  const flag = s.failed ? " failed" : s.cached ? " cached" : "";
43
- parts.push(`${s.feature} ${s.output}${flag}${ms(s.ms)}`);
43
+ const sliced = s.runs ? ` (sliced, ${s.runs} runs)` : "";
44
+ parts.push(`${s.feature} ${s.output}${flag}${ms(s.ms)}${sliced}`);
44
45
  }
45
46
  if (e.page) parts.push(`page ${e.page.index + 1}/${e.page.count} (${e.visible})`);
46
47
  const open = e.diagnostics === 1 ? "1 open diagnostic" : `${e.diagnostics} open diagnostics`;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/diagnostics/explain-text.ts"],"sourcesContent":["import type { RowExplanation, RowStep, TableExplanation } from './explain'\n\n// Console text of explain() / explainRow() (§8.4). Development only: production `toString()` is the\n// JSON of the structured result, so bundlers drop this module (§8.2 prod stripping).\n\nconst ms = (v: number | undefined) => (v === undefined ? '' : ` ${v.toFixed(1)} ms`)\n\n/** `run 57 · trigger api:setSearch · 1203 rows → schema 1198 (5 dropped) → … → page 1/2 (10)` */\nexport function formatTableExplanation(e: TableExplanation): string {\n const parts: string[] = []\n if (e.schema) {\n const { mode, invalid } = e.schema\n const before = mode === 'flag' ? e.rows : e.rows + invalid\n parts.push(`${before} rows`)\n parts.push(`schema ${e.rows} (${invalid} ${mode === 'flag' ? 'flagged' : 'dropped'})`)\n } else parts.push(`${e.rows} rows`)\n for (const s of e.steps) {\n if (s.stage === 'paginate' && e.page) continue\n if (s.mode === 'server') {\n parts.push(`${s.feature} (server)`)\n continue\n }\n const flag = s.failed ? ' failed' : s.cached ? ' cached' : ''\n parts.push(`${s.feature} ${s.output}${flag}${ms(s.ms)}`)\n }\n if (e.page) parts.push(`page ${e.page.index + 1}/${e.page.count} (${e.visible})`)\n const open = e.diagnostics === 1 ? '1 open diagnostic' : `${e.diagnostics} open diagnostics`\n return (\n `run ${e.run}${ms(e.ms)} · trigger ${e.trigger} · ${parts.join(' → ')} · status ${e.status}` +\n ` · ${open}`\n )\n}\n\nconst fmt = (v: unknown) => (typeof v === 'string' ? v : JSON.stringify(v))\n\n/** What a removing step did, in words. */\nfunction reason(s: RowStep): string {\n const d = s.detail ?? {}\n if (s.stage === 'paginate' && typeof d.page === 'number') {\n return `on page ${d.page} of ${d.pageCount}, page ${d.currentPage} is shown`\n }\n if (s.stage === 'search') {\n const q = `query (${d.queryLength} chars)`\n return d.searchFn\n ? `${q}: not in the searchFn result`\n : `${q} did not match (threshold ${d.threshold})`\n }\n if (Array.isArray(d.filters)) {\n return (d.filters as Record<string, unknown>[])\n .map((f) => `${f.column} ${f.type} ${fmt(f.value)} → ${fmt(f.cell)} fails`)\n .join('; ')\n }\n if (d.validity !== undefined) {\n return `validity '${String(d.validity)}' hides ${d.flagged ? 'flagged' : 'valid'} rows`\n }\n return 'its rowModel did not return the row'\n}\n\n/** The fix for the removing step, best first. */\nfunction fix(e: RowExplanation, s: RowStep | undefined): string {\n if (e.removedBy === 'schema') {\n return \"correct the data at the issue paths, or invalidRows: 'flag' to keep invalid rows\"\n }\n if (!s) return ''\n const d = s.detail ?? {}\n if (s.stage === 'paginate' && typeof d.page === 'number') return `setPageIndex(${d.page - 1})`\n if (s.stage === 'search') {\n if (d.searchFn) return 'check what searchFn returns for this query'\n const lower = Math.max(0, Math.round(((d.threshold as number) - 0.1) * 10) / 10)\n return `search({ threshold: ${lower} }) or check the query spelling`\n }\n if (Array.isArray(d.filters)) {\n const cols = (d.filters as { column: string }[]).map((f) => `'${f.column}'`)\n return `setColumnFilter(${cols[0]}, undefined) or resetColumnFilters()`\n }\n if (d.validity !== undefined) return \"setValidity('all')\"\n return `check table.getState().${s.feature}`\n}\n\nconst pad = (name: string, width: number) => name.padEnd(width)\n\n/** `✓ schema valid` / `✗ search query (8 chars) … ← removed here` / `fix …` */\nexport function formatRowExplanation(e: RowExplanation): string {\n const key = fmt(e.key)\n if (!e.found) {\n return (\n `row ${key}: not found in the data (${e.rows} rows, run ${e.run})\\n` +\n ' fix check the key against rowKey (without rowKey the key is the row index)'\n )\n }\n const width = Math.max(8, ...e.steps.map((s) => s.feature.length)) + 1\n const where = e.index === undefined ? `options.data[${e.rawIndex}]` : `data index ${e.index}`\n const lines = [`row ${key} · ${where} · run ${e.run}${e.visible ? ' · visible' : ''}`]\n const issues = e.issues?.map((i) => `${i.path || '(root)'}: ${i.message}`).join('; ')\n if (e.schema === 'none') lines.push(` – ${pad('schema', width)}no schema`)\n else if (e.schema === 'valid') lines.push(` ✓ ${pad('schema', width)}valid`)\n else if (e.schema === 'flagged')\n lines.push(` ✓ ${pad('schema', width)}flagged (kept): ${issues}`)\n else lines.push(` ✗ ${pad('schema', width)}invalid: ${issues} ← removed here`)\n let removing: RowStep | undefined\n for (const s of e.steps) {\n const name = pad(s.feature, width)\n if (s.outcome === 'removed') {\n removing = s\n lines.push(` ✗ ${name}${reason(s)} ← removed here`)\n } else if (s.outcome === 'kept' || s.outcome === 'failed') {\n const at = `position ${(s.position ?? 0) + 1} of ${s.of}`\n lines.push(\n s.outcome === 'kept'\n ? ` ✓ ${name}${at}`\n : ` ! ${name}failed in this run (input passed through); ${at}`,\n )\n } else if (s.outcome === 'skipped') lines.push(` – ${name}skipped (server mode)`)\n else lines.push(` · ${name}not reached`)\n }\n const f = fix(e, removing)\n if (f) lines.push(` ${pad('fix', width + 2)}${f}`)\n return lines.join('\\n')\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/diagnostics/explain-text.ts"],"sourcesContent":["import type { RowExplanation, RowStep, TableExplanation } from './explain'\n\n// Console text of explain() / explainRow() (§8.4). Development only: production `toString()` is the\n// JSON of the structured result, so bundlers drop this module (§8.2 prod stripping).\n\nconst ms = (v: number | undefined) => (v === undefined ? '' : ` ${v.toFixed(1)} ms`)\n\n/** `run 57 · trigger api:setSearch · 1203 rows → schema 1198 (5 dropped) → … → page 1/2 (10)` */\nexport function formatTableExplanation(e: TableExplanation): string {\n const parts: string[] = []\n if (e.schema) {\n const { mode, invalid } = e.schema\n const before = mode === 'flag' ? e.rows : e.rows + invalid\n parts.push(`${before} rows`)\n parts.push(`schema ${e.rows} (${invalid} ${mode === 'flag' ? 'flagged' : 'dropped'})`)\n } else parts.push(`${e.rows} rows`)\n for (const s of e.steps) {\n if (s.stage === 'paginate' && e.page) continue\n if (s.mode === 'server') {\n parts.push(`${s.feature} (server)`)\n continue\n }\n const flag = s.failed ? ' failed' : s.cached ? ' cached' : ''\n const sliced = s.runs ? ` (sliced, ${s.runs} runs)` : ''\n parts.push(`${s.feature} ${s.output}${flag}${ms(s.ms)}${sliced}`)\n }\n if (e.page) parts.push(`page ${e.page.index + 1}/${e.page.count} (${e.visible})`)\n const open = e.diagnostics === 1 ? '1 open diagnostic' : `${e.diagnostics} open diagnostics`\n return (\n `run ${e.run}${ms(e.ms)} · trigger ${e.trigger} · ${parts.join(' → ')} · status ${e.status}` +\n ` · ${open}`\n )\n}\n\nconst fmt = (v: unknown) => (typeof v === 'string' ? v : JSON.stringify(v))\n\n/** What a removing step did, in words. */\nfunction reason(s: RowStep): string {\n const d = s.detail ?? {}\n if (s.stage === 'paginate' && typeof d.page === 'number') {\n return `on page ${d.page} of ${d.pageCount}, page ${d.currentPage} is shown`\n }\n if (s.stage === 'search') {\n const q = `query (${d.queryLength} chars)`\n return d.searchFn\n ? `${q}: not in the searchFn result`\n : `${q} did not match (threshold ${d.threshold})`\n }\n if (Array.isArray(d.filters)) {\n return (d.filters as Record<string, unknown>[])\n .map((f) => `${f.column} ${f.type} ${fmt(f.value)} → ${fmt(f.cell)} fails`)\n .join('; ')\n }\n if (d.validity !== undefined) {\n return `validity '${String(d.validity)}' hides ${d.flagged ? 'flagged' : 'valid'} rows`\n }\n return 'its rowModel did not return the row'\n}\n\n/** The fix for the removing step, best first. */\nfunction fix(e: RowExplanation, s: RowStep | undefined): string {\n if (e.removedBy === 'schema') {\n return \"correct the data at the issue paths, or invalidRows: 'flag' to keep invalid rows\"\n }\n if (!s) return ''\n const d = s.detail ?? {}\n if (s.stage === 'paginate' && typeof d.page === 'number') return `setPageIndex(${d.page - 1})`\n if (s.stage === 'search') {\n if (d.searchFn) return 'check what searchFn returns for this query'\n const lower = Math.max(0, Math.round(((d.threshold as number) - 0.1) * 10) / 10)\n return `search({ threshold: ${lower} }) or check the query spelling`\n }\n if (Array.isArray(d.filters)) {\n const cols = (d.filters as { column: string }[]).map((f) => `'${f.column}'`)\n return `setColumnFilter(${cols[0]}, undefined) or resetColumnFilters()`\n }\n if (d.validity !== undefined) return \"setValidity('all')\"\n return `check table.getState().${s.feature}`\n}\n\nconst pad = (name: string, width: number) => name.padEnd(width)\n\n/** `✓ schema valid` / `✗ search query (8 chars) … ← removed here` / `fix …` */\nexport function formatRowExplanation(e: RowExplanation): string {\n const key = fmt(e.key)\n if (!e.found) {\n return (\n `row ${key}: not found in the data (${e.rows} rows, run ${e.run})\\n` +\n ' fix check the key against rowKey (without rowKey the key is the row index)'\n )\n }\n const width = Math.max(8, ...e.steps.map((s) => s.feature.length)) + 1\n const where = e.index === undefined ? `options.data[${e.rawIndex}]` : `data index ${e.index}`\n const lines = [`row ${key} · ${where} · run ${e.run}${e.visible ? ' · visible' : ''}`]\n const issues = e.issues?.map((i) => `${i.path || '(root)'}: ${i.message}`).join('; ')\n if (e.schema === 'none') lines.push(` – ${pad('schema', width)}no schema`)\n else if (e.schema === 'valid') lines.push(` ✓ ${pad('schema', width)}valid`)\n else if (e.schema === 'flagged')\n lines.push(` ✓ ${pad('schema', width)}flagged (kept): ${issues}`)\n else lines.push(` ✗ ${pad('schema', width)}invalid: ${issues} ← removed here`)\n let removing: RowStep | undefined\n for (const s of e.steps) {\n const name = pad(s.feature, width)\n if (s.outcome === 'removed') {\n removing = s\n lines.push(` ✗ ${name}${reason(s)} ← removed here`)\n } else if (s.outcome === 'kept' || s.outcome === 'failed') {\n const at = `position ${(s.position ?? 0) + 1} of ${s.of}`\n lines.push(\n s.outcome === 'kept'\n ? ` ✓ ${name}${at}`\n : ` ! ${name}failed in this run (input passed through); ${at}`,\n )\n } else if (s.outcome === 'skipped') lines.push(` – ${name}skipped (server mode)`)\n else lines.push(` · ${name}not reached`)\n }\n const f = fix(e, removing)\n if (f) lines.push(` ${pad('fix', width + 2)}${f}`)\n return lines.join('\\n')\n}\n"],"mappings":"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","names":[]}
@@ -15,7 +15,8 @@ function formatTableExplanation(e) {
15
15
  continue;
16
16
  }
17
17
  const flag = s.failed ? " failed" : s.cached ? " cached" : "";
18
- parts.push(`${s.feature} ${s.output}${flag}${ms(s.ms)}`);
18
+ const sliced = s.runs ? ` (sliced, ${s.runs} runs)` : "";
19
+ parts.push(`${s.feature} ${s.output}${flag}${ms(s.ms)}${sliced}`);
19
20
  }
20
21
  if (e.page) parts.push(`page ${e.page.index + 1}/${e.page.count} (${e.visible})`);
21
22
  const open = e.diagnostics === 1 ? "1 open diagnostic" : `${e.diagnostics} open diagnostics`;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/diagnostics/explain-text.ts"],"sourcesContent":["import type { RowExplanation, RowStep, TableExplanation } from './explain'\n\n// Console text of explain() / explainRow() (§8.4). Development only: production `toString()` is the\n// JSON of the structured result, so bundlers drop this module (§8.2 prod stripping).\n\nconst ms = (v: number | undefined) => (v === undefined ? '' : ` ${v.toFixed(1)} ms`)\n\n/** `run 57 · trigger api:setSearch · 1203 rows → schema 1198 (5 dropped) → … → page 1/2 (10)` */\nexport function formatTableExplanation(e: TableExplanation): string {\n const parts: string[] = []\n if (e.schema) {\n const { mode, invalid } = e.schema\n const before = mode === 'flag' ? e.rows : e.rows + invalid\n parts.push(`${before} rows`)\n parts.push(`schema ${e.rows} (${invalid} ${mode === 'flag' ? 'flagged' : 'dropped'})`)\n } else parts.push(`${e.rows} rows`)\n for (const s of e.steps) {\n if (s.stage === 'paginate' && e.page) continue\n if (s.mode === 'server') {\n parts.push(`${s.feature} (server)`)\n continue\n }\n const flag = s.failed ? ' failed' : s.cached ? ' cached' : ''\n parts.push(`${s.feature} ${s.output}${flag}${ms(s.ms)}`)\n }\n if (e.page) parts.push(`page ${e.page.index + 1}/${e.page.count} (${e.visible})`)\n const open = e.diagnostics === 1 ? '1 open diagnostic' : `${e.diagnostics} open diagnostics`\n return (\n `run ${e.run}${ms(e.ms)} · trigger ${e.trigger} · ${parts.join(' → ')} · status ${e.status}` +\n ` · ${open}`\n )\n}\n\nconst fmt = (v: unknown) => (typeof v === 'string' ? v : JSON.stringify(v))\n\n/** What a removing step did, in words. */\nfunction reason(s: RowStep): string {\n const d = s.detail ?? {}\n if (s.stage === 'paginate' && typeof d.page === 'number') {\n return `on page ${d.page} of ${d.pageCount}, page ${d.currentPage} is shown`\n }\n if (s.stage === 'search') {\n const q = `query (${d.queryLength} chars)`\n return d.searchFn\n ? `${q}: not in the searchFn result`\n : `${q} did not match (threshold ${d.threshold})`\n }\n if (Array.isArray(d.filters)) {\n return (d.filters as Record<string, unknown>[])\n .map((f) => `${f.column} ${f.type} ${fmt(f.value)} → ${fmt(f.cell)} fails`)\n .join('; ')\n }\n if (d.validity !== undefined) {\n return `validity '${String(d.validity)}' hides ${d.flagged ? 'flagged' : 'valid'} rows`\n }\n return 'its rowModel did not return the row'\n}\n\n/** The fix for the removing step, best first. */\nfunction fix(e: RowExplanation, s: RowStep | undefined): string {\n if (e.removedBy === 'schema') {\n return \"correct the data at the issue paths, or invalidRows: 'flag' to keep invalid rows\"\n }\n if (!s) return ''\n const d = s.detail ?? {}\n if (s.stage === 'paginate' && typeof d.page === 'number') return `setPageIndex(${d.page - 1})`\n if (s.stage === 'search') {\n if (d.searchFn) return 'check what searchFn returns for this query'\n const lower = Math.max(0, Math.round(((d.threshold as number) - 0.1) * 10) / 10)\n return `search({ threshold: ${lower} }) or check the query spelling`\n }\n if (Array.isArray(d.filters)) {\n const cols = (d.filters as { column: string }[]).map((f) => `'${f.column}'`)\n return `setColumnFilter(${cols[0]}, undefined) or resetColumnFilters()`\n }\n if (d.validity !== undefined) return \"setValidity('all')\"\n return `check table.getState().${s.feature}`\n}\n\nconst pad = (name: string, width: number) => name.padEnd(width)\n\n/** `✓ schema valid` / `✗ search query (8 chars) … ← removed here` / `fix …` */\nexport function formatRowExplanation(e: RowExplanation): string {\n const key = fmt(e.key)\n if (!e.found) {\n return (\n `row ${key}: not found in the data (${e.rows} rows, run ${e.run})\\n` +\n ' fix check the key against rowKey (without rowKey the key is the row index)'\n )\n }\n const width = Math.max(8, ...e.steps.map((s) => s.feature.length)) + 1\n const where = e.index === undefined ? `options.data[${e.rawIndex}]` : `data index ${e.index}`\n const lines = [`row ${key} · ${where} · run ${e.run}${e.visible ? ' · visible' : ''}`]\n const issues = e.issues?.map((i) => `${i.path || '(root)'}: ${i.message}`).join('; ')\n if (e.schema === 'none') lines.push(` – ${pad('schema', width)}no schema`)\n else if (e.schema === 'valid') lines.push(` ✓ ${pad('schema', width)}valid`)\n else if (e.schema === 'flagged')\n lines.push(` ✓ ${pad('schema', width)}flagged (kept): ${issues}`)\n else lines.push(` ✗ ${pad('schema', width)}invalid: ${issues} ← removed here`)\n let removing: RowStep | undefined\n for (const s of e.steps) {\n const name = pad(s.feature, width)\n if (s.outcome === 'removed') {\n removing = s\n lines.push(` ✗ ${name}${reason(s)} ← removed here`)\n } else if (s.outcome === 'kept' || s.outcome === 'failed') {\n const at = `position ${(s.position ?? 0) + 1} of ${s.of}`\n lines.push(\n s.outcome === 'kept'\n ? ` ✓ ${name}${at}`\n : ` ! ${name}failed in this run (input passed through); ${at}`,\n )\n } else if (s.outcome === 'skipped') lines.push(` – ${name}skipped (server mode)`)\n else lines.push(` · ${name}not reached`)\n }\n const f = fix(e, removing)\n if (f) lines.push(` ${pad('fix', width + 2)}${f}`)\n return lines.join('\\n')\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/diagnostics/explain-text.ts"],"sourcesContent":["import type { RowExplanation, RowStep, TableExplanation } from './explain'\n\n// Console text of explain() / explainRow() (§8.4). Development only: production `toString()` is the\n// JSON of the structured result, so bundlers drop this module (§8.2 prod stripping).\n\nconst ms = (v: number | undefined) => (v === undefined ? '' : ` ${v.toFixed(1)} ms`)\n\n/** `run 57 · trigger api:setSearch · 1203 rows → schema 1198 (5 dropped) → … → page 1/2 (10)` */\nexport function formatTableExplanation(e: TableExplanation): string {\n const parts: string[] = []\n if (e.schema) {\n const { mode, invalid } = e.schema\n const before = mode === 'flag' ? e.rows : e.rows + invalid\n parts.push(`${before} rows`)\n parts.push(`schema ${e.rows} (${invalid} ${mode === 'flag' ? 'flagged' : 'dropped'})`)\n } else parts.push(`${e.rows} rows`)\n for (const s of e.steps) {\n if (s.stage === 'paginate' && e.page) continue\n if (s.mode === 'server') {\n parts.push(`${s.feature} (server)`)\n continue\n }\n const flag = s.failed ? ' failed' : s.cached ? ' cached' : ''\n const sliced = s.runs ? ` (sliced, ${s.runs} runs)` : ''\n parts.push(`${s.feature} ${s.output}${flag}${ms(s.ms)}${sliced}`)\n }\n if (e.page) parts.push(`page ${e.page.index + 1}/${e.page.count} (${e.visible})`)\n const open = e.diagnostics === 1 ? '1 open diagnostic' : `${e.diagnostics} open diagnostics`\n return (\n `run ${e.run}${ms(e.ms)} · trigger ${e.trigger} · ${parts.join(' → ')} · status ${e.status}` +\n ` · ${open}`\n )\n}\n\nconst fmt = (v: unknown) => (typeof v === 'string' ? v : JSON.stringify(v))\n\n/** What a removing step did, in words. */\nfunction reason(s: RowStep): string {\n const d = s.detail ?? {}\n if (s.stage === 'paginate' && typeof d.page === 'number') {\n return `on page ${d.page} of ${d.pageCount}, page ${d.currentPage} is shown`\n }\n if (s.stage === 'search') {\n const q = `query (${d.queryLength} chars)`\n return d.searchFn\n ? `${q}: not in the searchFn result`\n : `${q} did not match (threshold ${d.threshold})`\n }\n if (Array.isArray(d.filters)) {\n return (d.filters as Record<string, unknown>[])\n .map((f) => `${f.column} ${f.type} ${fmt(f.value)} → ${fmt(f.cell)} fails`)\n .join('; ')\n }\n if (d.validity !== undefined) {\n return `validity '${String(d.validity)}' hides ${d.flagged ? 'flagged' : 'valid'} rows`\n }\n return 'its rowModel did not return the row'\n}\n\n/** The fix for the removing step, best first. */\nfunction fix(e: RowExplanation, s: RowStep | undefined): string {\n if (e.removedBy === 'schema') {\n return \"correct the data at the issue paths, or invalidRows: 'flag' to keep invalid rows\"\n }\n if (!s) return ''\n const d = s.detail ?? {}\n if (s.stage === 'paginate' && typeof d.page === 'number') return `setPageIndex(${d.page - 1})`\n if (s.stage === 'search') {\n if (d.searchFn) return 'check what searchFn returns for this query'\n const lower = Math.max(0, Math.round(((d.threshold as number) - 0.1) * 10) / 10)\n return `search({ threshold: ${lower} }) or check the query spelling`\n }\n if (Array.isArray(d.filters)) {\n const cols = (d.filters as { column: string }[]).map((f) => `'${f.column}'`)\n return `setColumnFilter(${cols[0]}, undefined) or resetColumnFilters()`\n }\n if (d.validity !== undefined) return \"setValidity('all')\"\n return `check table.getState().${s.feature}`\n}\n\nconst pad = (name: string, width: number) => name.padEnd(width)\n\n/** `✓ schema valid` / `✗ search query (8 chars) … ← removed here` / `fix …` */\nexport function formatRowExplanation(e: RowExplanation): string {\n const key = fmt(e.key)\n if (!e.found) {\n return (\n `row ${key}: not found in the data (${e.rows} rows, run ${e.run})\\n` +\n ' fix check the key against rowKey (without rowKey the key is the row index)'\n )\n }\n const width = Math.max(8, ...e.steps.map((s) => s.feature.length)) + 1\n const where = e.index === undefined ? `options.data[${e.rawIndex}]` : `data index ${e.index}`\n const lines = [`row ${key} · ${where} · run ${e.run}${e.visible ? ' · visible' : ''}`]\n const issues = e.issues?.map((i) => `${i.path || '(root)'}: ${i.message}`).join('; ')\n if (e.schema === 'none') lines.push(` – ${pad('schema', width)}no schema`)\n else if (e.schema === 'valid') lines.push(` ✓ ${pad('schema', width)}valid`)\n else if (e.schema === 'flagged')\n lines.push(` ✓ ${pad('schema', width)}flagged (kept): ${issues}`)\n else lines.push(` ✗ ${pad('schema', width)}invalid: ${issues} ← removed here`)\n let removing: RowStep | undefined\n for (const s of e.steps) {\n const name = pad(s.feature, width)\n if (s.outcome === 'removed') {\n removing = s\n lines.push(` ✗ ${name}${reason(s)} ← removed here`)\n } else if (s.outcome === 'kept' || s.outcome === 'failed') {\n const at = `position ${(s.position ?? 0) + 1} of ${s.of}`\n lines.push(\n s.outcome === 'kept'\n ? ` ✓ ${name}${at}`\n : ` ! ${name}failed in this run (input passed through); ${at}`,\n )\n } else if (s.outcome === 'skipped') lines.push(` – ${name}skipped (server mode)`)\n else lines.push(` · ${name}not reached`)\n }\n const f = fix(e, removing)\n if (f) lines.push(` ${pad('fix', width + 2)}${f}`)\n return lines.join('\\n')\n}\n"],"mappings":"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","names":[]}
@@ -28,6 +28,7 @@ __export(explain_exports, {
28
28
  });
29
29
  module.exports = __toCommonJS(explain_exports);
30
30
  var import_row_key = require("../ingest/row-key.cjs");
31
+ var import_process_guard = require("./process-guard.cjs");
31
32
  var import_explain_text = require("./explain-text.cjs");
32
33
  var import_redact = require("./redact.cjs");
33
34
  var import_trace_store = require("./trace-store.cjs");
@@ -62,10 +63,10 @@ function explainTable(host) {
62
63
  const rec = last?.steps.find((s) => s.feature === f);
63
64
  if (!rec) continue;
64
65
  flowing = rec.output.length;
65
- const ms = traced ? trace.steps.get(f.name)?.ms : void 0;
66
+ const t = traced ? trace.steps.get(f.name) : void 0;
66
67
  steps.push({
67
68
  ...step(f, "client", rec.input.length, rec.output.length, rec.cached, rec.failed),
68
- ...ms === void 0 ? {} : { ms }
69
+ ...t ? { ms: t.ms, ...t.runs ? { runs: t.runs } : {} } : {}
69
70
  });
70
71
  }
71
72
  const mode = host.schemaMode();
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/diagnostics/explain.ts"],"sourcesContent":["import type { AnyFeature, RowModelContext, Stage } from '../feature/types'\nimport { resolveRowKeys } from '../ingest/row-key'\nimport type { SchemaOutcome } from '../ingest/schema'\nimport type { InvalidRowsMode } from '../ingest/schema-codes'\nimport type { RowKey } from '../pipeline/row'\nimport type { RunRecord } from '../pipeline/runner'\nimport type { RowModel, RowModelStatus } from '../pipeline/types'\nimport type { explainDetail } from './explain-detail'\nimport { formatRowExplanation, formatTableExplanation } from './explain-text'\nimport { type RedactionOptions, redactDetails, resolveRedaction, scrubSchemaIssue } from './redact'\nimport { readTrace } from './trace-store'\nimport type { Diagnostic, Location, Trigger } from './types'\n\n/** What `createTable` gives `explain()` / `explainRow()`: read-only views of the table. */\nexport interface ExplainHost {\n readonly table: object\n /** Installed features in pipeline (stage) order. */\n readonly features: readonly AnyFeature[]\n /** The current row model (computed if data, state or columns changed, like `getRowModel()`). */\n rowModel(): RowModel<unknown>\n lastRun(): RunRecord | undefined\n /** A step context for replaying a `rowModel` on chosen rows (no diagnostics, no interceptors). */\n replay(name: string): RowModelContext\n data(): readonly unknown[]\n state(): Readonly<Record<string, unknown>>\n rowKey(): unknown\n /** `options.invalidRows` when a schema is set; `undefined` without one. */\n schemaMode(): InvalidRowsMode | undefined\n schema(): SchemaOutcome | undefined\n diagnostics(): readonly Diagnostic[]\n readonly redaction: RedactionOptions\n /** Why a step removed a row (`explainDetail`): it comes with the features (their runtime). */\n readonly detail?: typeof explainDetail\n}\n\n/** One step of {@link TableExplanation}: counts only. */\nexport interface ExplainStep {\n readonly feature: string\n readonly stage: Stage\n /** `'server'`: the server ran the step; its counts are the rows it was given. */\n readonly mode: 'client' | 'server'\n readonly input: number\n readonly output: number\n /** Served from the step memo in this run (nothing changed for it). */\n readonly cached: boolean\n /** The step threw or returned a bad output and passed its input through. */\n readonly failed: boolean\n /** Duration (tracer only, development or `interceptors: [tracer()]`). */\n readonly ms?: number\n}\n\n/** What `table.explain()` returns (§8.4); `String(e)` is the console summary. */\nexport interface TableExplanation {\n readonly run: number\n readonly trigger: Trigger\n readonly status: RowModelStatus\n /** Rows after ingest (after the schema dropped invalid rows). */\n readonly rows: number\n /** With a schema: its `invalidRows` mode and how many rows failed it. */\n readonly schema?: { readonly mode: InvalidRowsMode; readonly invalid: number }\n readonly steps: readonly ExplainStep[]\n /** Rows after filter and search (`getRowModel().filteredCount`). */\n readonly filteredCount: number\n /** With a pagination slice: the page shown (0-based), the page count and the page size. */\n readonly page?: { readonly index: number; readonly count: number; readonly size: number }\n /** Rows in `getRowModel().rows`. */\n readonly visible: number\n /** Error and warning diagnostics in `getDiagnostics()`. */\n readonly diagnostics: number\n /** Timings come from the tracer (it saw this run). */\n readonly traced: boolean\n /** Duration of the run (tracer only). */\n readonly ms?: number\n toString(): string\n}\n\n/**\n * `kept` / `removed` by the step, `skipped` (server mode), `failed` (passed its input through),\n * `not-reached` (an earlier step or the schema removed the row).\n */\nexport type RowStepOutcome = 'kept' | 'removed' | 'skipped' | 'failed' | 'not-reached'\n\nexport interface RowStep {\n readonly feature: string\n readonly stage: Stage\n readonly outcome: RowStepOutcome\n /** Kept: the row's position in the step output (0-based) and the output size. */\n readonly position?: number\n readonly of?: number\n /** Why the step removed the row (redacted). */\n readonly detail?: Readonly<Record<string, unknown>>\n}\n\n/** What `table.explainRow(key)` returns (§8.4); `String(e)` is the console report. */\nexport interface RowExplanation {\n /** The key asked for, redacted (a hash under `'safe'`). */\n readonly key: unknown\n readonly found: boolean\n /** Position in `getData()`; absent when not found or dropped by the schema. */\n readonly index?: number\n /** Position in `options.data` of a row the schema dropped. */\n readonly rawIndex?: number\n readonly schema: 'none' | 'valid' | 'flagged' | 'dropped'\n /** Schema issues of a flagged / dropped row (paths + DataKable's own text unless `'full'`). */\n readonly issues?: readonly { path: string; message: string }[]\n readonly steps: readonly RowStep[]\n /** The step that removed the row: a feature name, or `'schema'`. */\n readonly removedBy?: string\n /** The row is in `getRowModel().rows`. */\n readonly visible: boolean\n readonly run: number\n /** Rows after ingest (for \"not found\"). */\n readonly rows: number\n toString(): string\n}\n\nconst NOOP = () => {}\n\n/** Steps that take part in the row model: a stage and a `rowModel` (server mode included). */\nconst pipelineSteps = (features: readonly AnyFeature[]) =>\n features.filter((f) => f.stage !== 'none' && typeof f.rowModel === 'function')\n\nconst isServer = (f: AnyFeature) => f.mode === 'server'\n\n/** `{ pageIndex, pageSize }` of the first paginate-stage slice that has them. */\nexport function pageOf(host: ExplainHost): { index: number; size: number } | undefined {\n for (const f of host.features) {\n if (f.stage !== 'paginate') continue\n const s = host.state()[f.name] as { pageIndex?: unknown; pageSize?: unknown } | undefined\n if (typeof s?.pageIndex === 'number' && typeof s.pageSize === 'number' && s.pageSize > 0) {\n return { index: s.pageIndex, size: s.pageSize }\n }\n }\n return undefined\n}\n\nexport const pageCount = (rows: number, size: number) => Math.ceil(rows / size)\n\n/** Clamped like pagination does (the page actually shown). */\nexport const shownPage = (index: number, count: number) => Math.max(0, Math.min(index, count - 1))\n\n/** `table.explain()` (§8.4): the last run's counts, with tracer timings when it was traced. */\nexport function explainTable(host: ExplainHost): TableExplanation {\n const model = host.rowModel()\n const last = host.lastRun()\n const trace = readTrace(host.table)\n const traced = trace !== undefined && last !== undefined && trace.run === last.run\n const steps: ExplainStep[] = []\n let flowing = model.totalCount\n for (const f of pipelineSteps(host.features)) {\n if (isServer(f)) {\n steps.push(step(f, 'server', flowing, flowing, false, false))\n continue\n }\n const rec = last?.steps.find((s) => s.feature === f)\n if (!rec) continue\n flowing = rec.output.length\n const ms = traced ? trace.steps.get(f.name)?.ms : undefined\n steps.push({\n ...step(f, 'client', rec.input.length, rec.output.length, rec.cached, rec.failed),\n ...(ms === undefined ? {} : { ms }),\n })\n }\n const mode = host.schemaMode()\n const schema = host.schema()\n const p = pageOf(host)\n const count = p ? pageCount(model.filteredCount, p.size) : 0\n let diagnostics = 0\n for (const d of host.diagnostics()) if (d.level !== 'info') diagnostics++\n const e: TableExplanation = {\n run: last?.run ?? 0,\n trigger: last?.trigger ?? 'init',\n status: model.status,\n rows: model.totalCount,\n ...(mode === undefined ? {} : { schema: { mode, invalid: schema?.invalid.length ?? 0 } }),\n steps,\n filteredCount: model.filteredCount,\n ...(p ? { page: { index: shownPage(p.index, count), count, size: p.size } } : {}),\n visible: model.rows.length,\n diagnostics,\n traced,\n ...(traced && trace.ms !== undefined ? { ms: trace.ms } : {}),\n toString: () => ((process.env.NODE_ENV !== \"production\") ? formatTableExplanation(e) : JSON.stringify(e)),\n }\n return e\n}\n\nfunction step(\n f: AnyFeature,\n mode: 'client' | 'server',\n input: number,\n output: number,\n cached: boolean,\n failed: boolean,\n): ExplainStep {\n return { feature: f.name, stage: f.stage, mode, input, output, cached, failed }\n}\n\n/** Index of the row whose key equals `key` (`42` matches `'42'`), or -1. */\nfunction findKey(rows: readonly unknown[], rowKey: unknown, key: unknown): number {\n const keyOf = resolveRowKeys(rows, rowKey, NOOP, NOOP)\n const s = String(key)\n for (let i = 0; i < rows.length; i++) {\n const k = keyOf(rows[i], i)\n if (k === key || String(k) === s) return i\n }\n return -1\n}\n\n/**\n * `table.explainRow(key)` (§8.4): replays the row through every stage of the last run — schema,\n * then each step in pipeline order — and names the step that removed it. Survival is read from the\n * recorded step input / output (no per-row bookkeeping during normal runs); a removal by a filter\n * replays its filters on the single row to name the ones that reject it. Read-only: no state\n * change, no notification, no diagnostic. Every value it shows is redacted (§8.2).\n */\nexport function explainRow(host: ExplainHost, key: RowKey): RowExplanation {\n const model = host.rowModel()\n const last = host.lastRun()\n const data = host.data()\n const r = resolveRedaction(host.redaction, (process.env.NODE_ENV !== \"production\"))\n const where: Location = { kind: 'feature', name: 'explainRow' }\n const shownKey = redactDetails({ key }, { key: 'rowKey' }, where, r).key\n const mode = host.schemaMode()\n const outcome = host.schema()\n const rowKey = host.rowKey()\n\n const index = findKey(data, rowKey, key)\n let schema: RowExplanation['schema'] = mode === undefined ? 'none' : 'valid'\n let rawIndex: number | undefined\n let issues: readonly unknown[] | undefined\n if (index >= 0) {\n issues = outcome?.flagged?.get(index)\n if (issues) schema = 'flagged'\n } else if (outcome && outcome.invalid.length > 0 && rowKey !== undefined && mode !== 'flag') {\n // Dropped by the schema: looked up among the invalid raw rows by the same key.\n const i = findKey(\n outcome.invalid.map((x) => x.raw),\n rowKey,\n key,\n )\n const inv = outcome.invalid[i]\n if (inv) {\n schema = 'dropped'\n rawIndex = inv.index\n issues = inv.issues\n }\n }\n const found = index >= 0 || rawIndex !== undefined\n let removedBy: string | undefined = schema === 'dropped' ? 'schema' : undefined\n const steps: RowStep[] = []\n for (const f of pipelineSteps(host.features)) {\n const base = { feature: f.name, stage: f.stage }\n if (!found || removedBy !== undefined) {\n steps.push({ ...base, outcome: 'not-reached' })\n continue\n }\n if (isServer(f)) {\n steps.push({ ...base, outcome: 'skipped' })\n continue\n }\n const rec = last?.steps.find((s) => s.feature === f)\n if (!rec) {\n steps.push({ ...base, outcome: 'not-reached' })\n continue\n }\n const position = rec.output.indexOf(index)\n if (position >= 0) {\n const of = rec.output.length\n steps.push({ ...base, outcome: rec.failed ? 'failed' : 'kept', position, of })\n continue\n }\n removedBy = f.name\n const detail = host.detail?.(host, f, rec.input, index, r, where)\n steps.push({ ...base, outcome: 'removed', ...(detail ? { detail } : {}) })\n }\n const e: RowExplanation = {\n key: shownKey,\n found,\n ...(index >= 0 ? { index } : {}),\n ...(rawIndex === undefined ? {} : { rawIndex }),\n schema,\n ...(issues ? { issues: issues.map((x, i) => scrubSchemaIssue(x, r, `issues.${i}`)) } : {}),\n steps,\n ...(removedBy === undefined ? {} : { removedBy }),\n visible: index >= 0 && model.rows.some((row) => (row as { index?: unknown }).index === index),\n run: last?.run ?? 0,\n rows: data.length,\n toString: () => ((process.env.NODE_ENV !== \"production\") ? formatRowExplanation(e) : JSON.stringify(e)),\n }\n return e\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/diagnostics/explain.ts"],"sourcesContent":["import type { AnyFeature, RowModelContext, Stage } from '../feature/types'\nimport { resolveRowKeys } from '../ingest/row-key'\nimport type { SchemaOutcome } from '../ingest/schema'\nimport type { InvalidRowsMode } from '../ingest/schema-codes'\nimport type { RowKey } from '../pipeline/row'\nimport type { RunRecord } from '../pipeline/runner'\nimport type { RowModel, RowModelStatus } from '../pipeline/types'\nimport './process-guard'\nimport type { explainDetail } from './explain-detail'\nimport { formatRowExplanation, formatTableExplanation } from './explain-text'\nimport { type RedactionOptions, redactDetails, resolveRedaction, scrubSchemaIssue } from './redact'\nimport { readTrace } from './trace-store'\nimport type { Diagnostic, Location, Trigger } from './types'\n\n/** What `createTable` gives `explain()` / `explainRow()`: read-only views of the table. */\nexport interface ExplainHost {\n readonly table: object\n /** Installed features in pipeline (stage) order. */\n readonly features: readonly AnyFeature[]\n /** The current row model (computed if data, state or columns changed, like `getRowModel()`). */\n rowModel(): RowModel<unknown>\n lastRun(): RunRecord | undefined\n /** A step context for replaying a `rowModel` on chosen rows (no diagnostics, no interceptors). */\n replay(name: string): RowModelContext\n data(): readonly unknown[]\n state(): Readonly<Record<string, unknown>>\n rowKey(): unknown\n /** `options.invalidRows` when a schema is set; `undefined` without one. */\n schemaMode(): InvalidRowsMode | undefined\n schema(): SchemaOutcome | undefined\n diagnostics(): readonly Diagnostic[]\n readonly redaction: RedactionOptions\n /** Why a step removed a row (`explainDetail`): it comes with the features (their runtime). */\n readonly detail?: typeof explainDetail\n}\n\n/** One step of {@link TableExplanation}: counts only. */\nexport interface ExplainStep {\n readonly feature: string\n readonly stage: Stage\n /** `'server'`: the server ran the step; its counts are the rows it was given. */\n readonly mode: 'client' | 'server'\n readonly input: number\n readonly output: number\n /** Served from the step memo in this run (nothing changed for it). */\n readonly cached: boolean\n /** The step threw or returned a bad output and passed its input through. */\n readonly failed: boolean\n /**\n * Duration (tracer only, development or `interceptors: [tracer()]`). A step that waited on\n * time-sliced work: the total of its runs and of the slices between them (#61).\n */\n readonly ms?: number\n /** Time-sliced work (#61): the runs {@link ms} spans; absent when the step ran in one. */\n readonly runs?: number\n}\n\n/** What `table.explain()` returns (§8.4); `String(e)` is the console summary. */\nexport interface TableExplanation {\n readonly run: number\n readonly trigger: Trigger\n readonly status: RowModelStatus\n /** Rows after ingest (after the schema dropped invalid rows). */\n readonly rows: number\n /** With a schema: its `invalidRows` mode and how many rows failed it. */\n readonly schema?: { readonly mode: InvalidRowsMode; readonly invalid: number }\n readonly steps: readonly ExplainStep[]\n /** Rows after filter and search (`getRowModel().filteredCount`). */\n readonly filteredCount: number\n /** With a pagination slice: the page shown (0-based), the page count and the page size. */\n readonly page?: { readonly index: number; readonly count: number; readonly size: number }\n /** Rows in `getRowModel().rows`. */\n readonly visible: number\n /** Error and warning diagnostics in `getDiagnostics()`. */\n readonly diagnostics: number\n /** Timings come from the tracer (it saw this run). */\n readonly traced: boolean\n /** Duration of the run (tracer only). */\n readonly ms?: number\n toString(): string\n}\n\n/**\n * `kept` / `removed` by the step, `skipped` (server mode), `failed` (passed its input through),\n * `not-reached` (an earlier step or the schema removed the row).\n */\nexport type RowStepOutcome = 'kept' | 'removed' | 'skipped' | 'failed' | 'not-reached'\n\nexport interface RowStep {\n readonly feature: string\n readonly stage: Stage\n readonly outcome: RowStepOutcome\n /** Kept: the row's position in the step output (0-based) and the output size. */\n readonly position?: number\n readonly of?: number\n /** Why the step removed the row (redacted). */\n readonly detail?: Readonly<Record<string, unknown>>\n}\n\n/** What `table.explainRow(key)` returns (§8.4); `String(e)` is the console report. */\nexport interface RowExplanation {\n /** The key asked for, redacted (a hash under `'safe'`). */\n readonly key: unknown\n readonly found: boolean\n /** Position in `getData()`; absent when not found or dropped by the schema. */\n readonly index?: number\n /** Position in `options.data` of a row the schema dropped. */\n readonly rawIndex?: number\n readonly schema: 'none' | 'valid' | 'flagged' | 'dropped'\n /** Schema issues of a flagged / dropped row (paths + DataKable's own text unless `'full'`). */\n readonly issues?: readonly { path: string; message: string }[]\n readonly steps: readonly RowStep[]\n /** The step that removed the row: a feature name, or `'schema'`. */\n readonly removedBy?: string\n /** The row is in `getRowModel().rows`. */\n readonly visible: boolean\n readonly run: number\n /** Rows after ingest (for \"not found\"). */\n readonly rows: number\n toString(): string\n}\n\nconst NOOP = () => {}\n\n/** Steps that take part in the row model: a stage and a `rowModel` (server mode included). */\nconst pipelineSteps = (features: readonly AnyFeature[]) =>\n features.filter((f) => f.stage !== 'none' && typeof f.rowModel === 'function')\n\nconst isServer = (f: AnyFeature) => f.mode === 'server'\n\n/** `{ pageIndex, pageSize }` of the first paginate-stage slice that has them. */\nexport function pageOf(host: ExplainHost): { index: number; size: number } | undefined {\n for (const f of host.features) {\n if (f.stage !== 'paginate') continue\n const s = host.state()[f.name] as { pageIndex?: unknown; pageSize?: unknown } | undefined\n if (typeof s?.pageIndex === 'number' && typeof s.pageSize === 'number' && s.pageSize > 0) {\n return { index: s.pageIndex, size: s.pageSize }\n }\n }\n return undefined\n}\n\nexport const pageCount = (rows: number, size: number) => Math.ceil(rows / size)\n\n/** Clamped like pagination does (the page actually shown). */\nexport const shownPage = (index: number, count: number) => Math.max(0, Math.min(index, count - 1))\n\n/** `table.explain()` (§8.4): the last run's counts, with tracer timings when it was traced. */\nexport function explainTable(host: ExplainHost): TableExplanation {\n const model = host.rowModel()\n const last = host.lastRun()\n const trace = readTrace(host.table)\n const traced = trace !== undefined && last !== undefined && trace.run === last.run\n const steps: ExplainStep[] = []\n let flowing = model.totalCount\n for (const f of pipelineSteps(host.features)) {\n if (isServer(f)) {\n steps.push(step(f, 'server', flowing, flowing, false, false))\n continue\n }\n const rec = last?.steps.find((s) => s.feature === f)\n if (!rec) continue\n flowing = rec.output.length\n const t = traced ? trace.steps.get(f.name) : undefined\n steps.push({\n ...step(f, 'client', rec.input.length, rec.output.length, rec.cached, rec.failed),\n ...(t ? { ms: t.ms, ...(t.runs ? { runs: t.runs } : {}) } : {}),\n })\n }\n const mode = host.schemaMode()\n const schema = host.schema()\n const p = pageOf(host)\n const count = p ? pageCount(model.filteredCount, p.size) : 0\n let diagnostics = 0\n for (const d of host.diagnostics()) if (d.level !== 'info') diagnostics++\n const e: TableExplanation = {\n run: last?.run ?? 0,\n trigger: last?.trigger ?? 'init',\n status: model.status,\n rows: model.totalCount,\n ...(mode === undefined ? {} : { schema: { mode, invalid: schema?.invalid.length ?? 0 } }),\n steps,\n filteredCount: model.filteredCount,\n ...(p ? { page: { index: shownPage(p.index, count), count, size: p.size } } : {}),\n visible: model.rows.length,\n diagnostics,\n traced,\n ...(traced && trace.ms !== undefined ? { ms: trace.ms } : {}),\n toString: () => ((process.env.NODE_ENV !== \"production\") ? formatTableExplanation(e) : JSON.stringify(e)),\n }\n return e\n}\n\nfunction step(\n f: AnyFeature,\n mode: 'client' | 'server',\n input: number,\n output: number,\n cached: boolean,\n failed: boolean,\n): ExplainStep {\n return { feature: f.name, stage: f.stage, mode, input, output, cached, failed }\n}\n\n/** Index of the row whose key equals `key` (`42` matches `'42'`), or -1. */\nfunction findKey(rows: readonly unknown[], rowKey: unknown, key: unknown): number {\n const keyOf = resolveRowKeys(rows, rowKey, NOOP, NOOP)\n const s = String(key)\n for (let i = 0; i < rows.length; i++) {\n const k = keyOf(rows[i], i)\n if (k === key || String(k) === s) return i\n }\n return -1\n}\n\n/**\n * `table.explainRow(key)` (§8.4): replays the row through every stage of the last run — schema,\n * then each step in pipeline order — and names the step that removed it. Survival is read from the\n * recorded step input / output (no per-row bookkeeping during normal runs); a removal by a filter\n * replays its filters on the single row to name the ones that reject it. Read-only: no state\n * change, no notification, no diagnostic. Every value it shows is redacted (§8.2).\n */\nexport function explainRow(host: ExplainHost, key: RowKey): RowExplanation {\n const model = host.rowModel()\n const last = host.lastRun()\n const data = host.data()\n const r = resolveRedaction(host.redaction, (process.env.NODE_ENV !== \"production\"))\n const where: Location = { kind: 'feature', name: 'explainRow' }\n const shownKey = redactDetails({ key }, { key: 'rowKey' }, where, r).key\n const mode = host.schemaMode()\n const outcome = host.schema()\n const rowKey = host.rowKey()\n\n const index = findKey(data, rowKey, key)\n let schema: RowExplanation['schema'] = mode === undefined ? 'none' : 'valid'\n let rawIndex: number | undefined\n let issues: readonly unknown[] | undefined\n if (index >= 0) {\n issues = outcome?.flagged?.get(index)\n if (issues) schema = 'flagged'\n } else if (outcome && outcome.invalid.length > 0 && rowKey !== undefined && mode !== 'flag') {\n // Dropped by the schema: looked up among the invalid raw rows by the same key.\n const i = findKey(\n outcome.invalid.map((x) => x.raw),\n rowKey,\n key,\n )\n const inv = outcome.invalid[i]\n if (inv) {\n schema = 'dropped'\n rawIndex = inv.index\n issues = inv.issues\n }\n }\n const found = index >= 0 || rawIndex !== undefined\n let removedBy: string | undefined = schema === 'dropped' ? 'schema' : undefined\n const steps: RowStep[] = []\n for (const f of pipelineSteps(host.features)) {\n const base = { feature: f.name, stage: f.stage }\n if (!found || removedBy !== undefined) {\n steps.push({ ...base, outcome: 'not-reached' })\n continue\n }\n if (isServer(f)) {\n steps.push({ ...base, outcome: 'skipped' })\n continue\n }\n const rec = last?.steps.find((s) => s.feature === f)\n if (!rec) {\n steps.push({ ...base, outcome: 'not-reached' })\n continue\n }\n const position = rec.output.indexOf(index)\n if (position >= 0) {\n const of = rec.output.length\n steps.push({ ...base, outcome: rec.failed ? 'failed' : 'kept', position, of })\n continue\n }\n removedBy = f.name\n const detail = host.detail?.(host, f, rec.input, index, r, where)\n steps.push({ ...base, outcome: 'removed', ...(detail ? { detail } : {}) })\n }\n const e: RowExplanation = {\n key: shownKey,\n found,\n ...(index >= 0 ? { index } : {}),\n ...(rawIndex === undefined ? {} : { rawIndex }),\n schema,\n ...(issues ? { issues: issues.map((x, i) => scrubSchemaIssue(x, r, `issues.${i}`)) } : {}),\n steps,\n ...(removedBy === undefined ? {} : { removedBy }),\n visible: index >= 0 && model.rows.some((row) => (row as { index?: unknown }).index === index),\n run: last?.run ?? 0,\n rows: data.length,\n toString: () => ((process.env.NODE_ENV !== \"production\") ? formatRowExplanation(e) : JSON.stringify(e)),\n }\n return e\n}\n"],"mappings":"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","names":[]}
@@ -1,5 +1,6 @@
1
1
  // src/diagnostics/explain.ts
2
2
  import { resolveRowKeys } from "../ingest/row-key.js";
3
+ import "./process-guard.js";
3
4
  import { formatRowExplanation, formatTableExplanation } from "./explain-text.js";
4
5
  import { redactDetails, resolveRedaction, scrubSchemaIssue } from "./redact.js";
5
6
  import { readTrace } from "./trace-store.js";
@@ -34,10 +35,10 @@ function explainTable(host) {
34
35
  const rec = last?.steps.find((s) => s.feature === f);
35
36
  if (!rec) continue;
36
37
  flowing = rec.output.length;
37
- const ms = traced ? trace.steps.get(f.name)?.ms : void 0;
38
+ const t = traced ? trace.steps.get(f.name) : void 0;
38
39
  steps.push({
39
40
  ...step(f, "client", rec.input.length, rec.output.length, rec.cached, rec.failed),
40
- ...ms === void 0 ? {} : { ms }
41
+ ...t ? { ms: t.ms, ...t.runs ? { runs: t.runs } : {} } : {}
41
42
  });
42
43
  }
43
44
  const mode = host.schemaMode();
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/diagnostics/explain.ts"],"sourcesContent":["import type { AnyFeature, RowModelContext, Stage } from '../feature/types'\nimport { resolveRowKeys } from '../ingest/row-key'\nimport type { SchemaOutcome } from '../ingest/schema'\nimport type { InvalidRowsMode } from '../ingest/schema-codes'\nimport type { RowKey } from '../pipeline/row'\nimport type { RunRecord } from '../pipeline/runner'\nimport type { RowModel, RowModelStatus } from '../pipeline/types'\nimport type { explainDetail } from './explain-detail'\nimport { formatRowExplanation, formatTableExplanation } from './explain-text'\nimport { type RedactionOptions, redactDetails, resolveRedaction, scrubSchemaIssue } from './redact'\nimport { readTrace } from './trace-store'\nimport type { Diagnostic, Location, Trigger } from './types'\n\n/** What `createTable` gives `explain()` / `explainRow()`: read-only views of the table. */\nexport interface ExplainHost {\n readonly table: object\n /** Installed features in pipeline (stage) order. */\n readonly features: readonly AnyFeature[]\n /** The current row model (computed if data, state or columns changed, like `getRowModel()`). */\n rowModel(): RowModel<unknown>\n lastRun(): RunRecord | undefined\n /** A step context for replaying a `rowModel` on chosen rows (no diagnostics, no interceptors). */\n replay(name: string): RowModelContext\n data(): readonly unknown[]\n state(): Readonly<Record<string, unknown>>\n rowKey(): unknown\n /** `options.invalidRows` when a schema is set; `undefined` without one. */\n schemaMode(): InvalidRowsMode | undefined\n schema(): SchemaOutcome | undefined\n diagnostics(): readonly Diagnostic[]\n readonly redaction: RedactionOptions\n /** Why a step removed a row (`explainDetail`): it comes with the features (their runtime). */\n readonly detail?: typeof explainDetail\n}\n\n/** One step of {@link TableExplanation}: counts only. */\nexport interface ExplainStep {\n readonly feature: string\n readonly stage: Stage\n /** `'server'`: the server ran the step; its counts are the rows it was given. */\n readonly mode: 'client' | 'server'\n readonly input: number\n readonly output: number\n /** Served from the step memo in this run (nothing changed for it). */\n readonly cached: boolean\n /** The step threw or returned a bad output and passed its input through. */\n readonly failed: boolean\n /** Duration (tracer only, development or `interceptors: [tracer()]`). */\n readonly ms?: number\n}\n\n/** What `table.explain()` returns (§8.4); `String(e)` is the console summary. */\nexport interface TableExplanation {\n readonly run: number\n readonly trigger: Trigger\n readonly status: RowModelStatus\n /** Rows after ingest (after the schema dropped invalid rows). */\n readonly rows: number\n /** With a schema: its `invalidRows` mode and how many rows failed it. */\n readonly schema?: { readonly mode: InvalidRowsMode; readonly invalid: number }\n readonly steps: readonly ExplainStep[]\n /** Rows after filter and search (`getRowModel().filteredCount`). */\n readonly filteredCount: number\n /** With a pagination slice: the page shown (0-based), the page count and the page size. */\n readonly page?: { readonly index: number; readonly count: number; readonly size: number }\n /** Rows in `getRowModel().rows`. */\n readonly visible: number\n /** Error and warning diagnostics in `getDiagnostics()`. */\n readonly diagnostics: number\n /** Timings come from the tracer (it saw this run). */\n readonly traced: boolean\n /** Duration of the run (tracer only). */\n readonly ms?: number\n toString(): string\n}\n\n/**\n * `kept` / `removed` by the step, `skipped` (server mode), `failed` (passed its input through),\n * `not-reached` (an earlier step or the schema removed the row).\n */\nexport type RowStepOutcome = 'kept' | 'removed' | 'skipped' | 'failed' | 'not-reached'\n\nexport interface RowStep {\n readonly feature: string\n readonly stage: Stage\n readonly outcome: RowStepOutcome\n /** Kept: the row's position in the step output (0-based) and the output size. */\n readonly position?: number\n readonly of?: number\n /** Why the step removed the row (redacted). */\n readonly detail?: Readonly<Record<string, unknown>>\n}\n\n/** What `table.explainRow(key)` returns (§8.4); `String(e)` is the console report. */\nexport interface RowExplanation {\n /** The key asked for, redacted (a hash under `'safe'`). */\n readonly key: unknown\n readonly found: boolean\n /** Position in `getData()`; absent when not found or dropped by the schema. */\n readonly index?: number\n /** Position in `options.data` of a row the schema dropped. */\n readonly rawIndex?: number\n readonly schema: 'none' | 'valid' | 'flagged' | 'dropped'\n /** Schema issues of a flagged / dropped row (paths + DataKable's own text unless `'full'`). */\n readonly issues?: readonly { path: string; message: string }[]\n readonly steps: readonly RowStep[]\n /** The step that removed the row: a feature name, or `'schema'`. */\n readonly removedBy?: string\n /** The row is in `getRowModel().rows`. */\n readonly visible: boolean\n readonly run: number\n /** Rows after ingest (for \"not found\"). */\n readonly rows: number\n toString(): string\n}\n\nconst NOOP = () => {}\n\n/** Steps that take part in the row model: a stage and a `rowModel` (server mode included). */\nconst pipelineSteps = (features: readonly AnyFeature[]) =>\n features.filter((f) => f.stage !== 'none' && typeof f.rowModel === 'function')\n\nconst isServer = (f: AnyFeature) => f.mode === 'server'\n\n/** `{ pageIndex, pageSize }` of the first paginate-stage slice that has them. */\nexport function pageOf(host: ExplainHost): { index: number; size: number } | undefined {\n for (const f of host.features) {\n if (f.stage !== 'paginate') continue\n const s = host.state()[f.name] as { pageIndex?: unknown; pageSize?: unknown } | undefined\n if (typeof s?.pageIndex === 'number' && typeof s.pageSize === 'number' && s.pageSize > 0) {\n return { index: s.pageIndex, size: s.pageSize }\n }\n }\n return undefined\n}\n\nexport const pageCount = (rows: number, size: number) => Math.ceil(rows / size)\n\n/** Clamped like pagination does (the page actually shown). */\nexport const shownPage = (index: number, count: number) => Math.max(0, Math.min(index, count - 1))\n\n/** `table.explain()` (§8.4): the last run's counts, with tracer timings when it was traced. */\nexport function explainTable(host: ExplainHost): TableExplanation {\n const model = host.rowModel()\n const last = host.lastRun()\n const trace = readTrace(host.table)\n const traced = trace !== undefined && last !== undefined && trace.run === last.run\n const steps: ExplainStep[] = []\n let flowing = model.totalCount\n for (const f of pipelineSteps(host.features)) {\n if (isServer(f)) {\n steps.push(step(f, 'server', flowing, flowing, false, false))\n continue\n }\n const rec = last?.steps.find((s) => s.feature === f)\n if (!rec) continue\n flowing = rec.output.length\n const ms = traced ? trace.steps.get(f.name)?.ms : undefined\n steps.push({\n ...step(f, 'client', rec.input.length, rec.output.length, rec.cached, rec.failed),\n ...(ms === undefined ? {} : { ms }),\n })\n }\n const mode = host.schemaMode()\n const schema = host.schema()\n const p = pageOf(host)\n const count = p ? pageCount(model.filteredCount, p.size) : 0\n let diagnostics = 0\n for (const d of host.diagnostics()) if (d.level !== 'info') diagnostics++\n const e: TableExplanation = {\n run: last?.run ?? 0,\n trigger: last?.trigger ?? 'init',\n status: model.status,\n rows: model.totalCount,\n ...(mode === undefined ? {} : { schema: { mode, invalid: schema?.invalid.length ?? 0 } }),\n steps,\n filteredCount: model.filteredCount,\n ...(p ? { page: { index: shownPage(p.index, count), count, size: p.size } } : {}),\n visible: model.rows.length,\n diagnostics,\n traced,\n ...(traced && trace.ms !== undefined ? { ms: trace.ms } : {}),\n toString: () => ((process.env.NODE_ENV !== \"production\") ? formatTableExplanation(e) : JSON.stringify(e)),\n }\n return e\n}\n\nfunction step(\n f: AnyFeature,\n mode: 'client' | 'server',\n input: number,\n output: number,\n cached: boolean,\n failed: boolean,\n): ExplainStep {\n return { feature: f.name, stage: f.stage, mode, input, output, cached, failed }\n}\n\n/** Index of the row whose key equals `key` (`42` matches `'42'`), or -1. */\nfunction findKey(rows: readonly unknown[], rowKey: unknown, key: unknown): number {\n const keyOf = resolveRowKeys(rows, rowKey, NOOP, NOOP)\n const s = String(key)\n for (let i = 0; i < rows.length; i++) {\n const k = keyOf(rows[i], i)\n if (k === key || String(k) === s) return i\n }\n return -1\n}\n\n/**\n * `table.explainRow(key)` (§8.4): replays the row through every stage of the last run — schema,\n * then each step in pipeline order — and names the step that removed it. Survival is read from the\n * recorded step input / output (no per-row bookkeeping during normal runs); a removal by a filter\n * replays its filters on the single row to name the ones that reject it. Read-only: no state\n * change, no notification, no diagnostic. Every value it shows is redacted (§8.2).\n */\nexport function explainRow(host: ExplainHost, key: RowKey): RowExplanation {\n const model = host.rowModel()\n const last = host.lastRun()\n const data = host.data()\n const r = resolveRedaction(host.redaction, (process.env.NODE_ENV !== \"production\"))\n const where: Location = { kind: 'feature', name: 'explainRow' }\n const shownKey = redactDetails({ key }, { key: 'rowKey' }, where, r).key\n const mode = host.schemaMode()\n const outcome = host.schema()\n const rowKey = host.rowKey()\n\n const index = findKey(data, rowKey, key)\n let schema: RowExplanation['schema'] = mode === undefined ? 'none' : 'valid'\n let rawIndex: number | undefined\n let issues: readonly unknown[] | undefined\n if (index >= 0) {\n issues = outcome?.flagged?.get(index)\n if (issues) schema = 'flagged'\n } else if (outcome && outcome.invalid.length > 0 && rowKey !== undefined && mode !== 'flag') {\n // Dropped by the schema: looked up among the invalid raw rows by the same key.\n const i = findKey(\n outcome.invalid.map((x) => x.raw),\n rowKey,\n key,\n )\n const inv = outcome.invalid[i]\n if (inv) {\n schema = 'dropped'\n rawIndex = inv.index\n issues = inv.issues\n }\n }\n const found = index >= 0 || rawIndex !== undefined\n let removedBy: string | undefined = schema === 'dropped' ? 'schema' : undefined\n const steps: RowStep[] = []\n for (const f of pipelineSteps(host.features)) {\n const base = { feature: f.name, stage: f.stage }\n if (!found || removedBy !== undefined) {\n steps.push({ ...base, outcome: 'not-reached' })\n continue\n }\n if (isServer(f)) {\n steps.push({ ...base, outcome: 'skipped' })\n continue\n }\n const rec = last?.steps.find((s) => s.feature === f)\n if (!rec) {\n steps.push({ ...base, outcome: 'not-reached' })\n continue\n }\n const position = rec.output.indexOf(index)\n if (position >= 0) {\n const of = rec.output.length\n steps.push({ ...base, outcome: rec.failed ? 'failed' : 'kept', position, of })\n continue\n }\n removedBy = f.name\n const detail = host.detail?.(host, f, rec.input, index, r, where)\n steps.push({ ...base, outcome: 'removed', ...(detail ? { detail } : {}) })\n }\n const e: RowExplanation = {\n key: shownKey,\n found,\n ...(index >= 0 ? { index } : {}),\n ...(rawIndex === undefined ? {} : { rawIndex }),\n schema,\n ...(issues ? { issues: issues.map((x, i) => scrubSchemaIssue(x, r, `issues.${i}`)) } : {}),\n steps,\n ...(removedBy === undefined ? {} : { removedBy }),\n visible: index >= 0 && model.rows.some((row) => (row as { index?: unknown }).index === index),\n run: last?.run ?? 0,\n rows: data.length,\n toString: () => ((process.env.NODE_ENV !== \"production\") ? formatRowExplanation(e) : JSON.stringify(e)),\n }\n return e\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/diagnostics/explain.ts"],"sourcesContent":["import type { AnyFeature, RowModelContext, Stage } from '../feature/types'\nimport { resolveRowKeys } from '../ingest/row-key'\nimport type { SchemaOutcome } from '../ingest/schema'\nimport type { InvalidRowsMode } from '../ingest/schema-codes'\nimport type { RowKey } from '../pipeline/row'\nimport type { RunRecord } from '../pipeline/runner'\nimport type { RowModel, RowModelStatus } from '../pipeline/types'\nimport './process-guard'\nimport type { explainDetail } from './explain-detail'\nimport { formatRowExplanation, formatTableExplanation } from './explain-text'\nimport { type RedactionOptions, redactDetails, resolveRedaction, scrubSchemaIssue } from './redact'\nimport { readTrace } from './trace-store'\nimport type { Diagnostic, Location, Trigger } from './types'\n\n/** What `createTable` gives `explain()` / `explainRow()`: read-only views of the table. */\nexport interface ExplainHost {\n readonly table: object\n /** Installed features in pipeline (stage) order. */\n readonly features: readonly AnyFeature[]\n /** The current row model (computed if data, state or columns changed, like `getRowModel()`). */\n rowModel(): RowModel<unknown>\n lastRun(): RunRecord | undefined\n /** A step context for replaying a `rowModel` on chosen rows (no diagnostics, no interceptors). */\n replay(name: string): RowModelContext\n data(): readonly unknown[]\n state(): Readonly<Record<string, unknown>>\n rowKey(): unknown\n /** `options.invalidRows` when a schema is set; `undefined` without one. */\n schemaMode(): InvalidRowsMode | undefined\n schema(): SchemaOutcome | undefined\n diagnostics(): readonly Diagnostic[]\n readonly redaction: RedactionOptions\n /** Why a step removed a row (`explainDetail`): it comes with the features (their runtime). */\n readonly detail?: typeof explainDetail\n}\n\n/** One step of {@link TableExplanation}: counts only. */\nexport interface ExplainStep {\n readonly feature: string\n readonly stage: Stage\n /** `'server'`: the server ran the step; its counts are the rows it was given. */\n readonly mode: 'client' | 'server'\n readonly input: number\n readonly output: number\n /** Served from the step memo in this run (nothing changed for it). */\n readonly cached: boolean\n /** The step threw or returned a bad output and passed its input through. */\n readonly failed: boolean\n /**\n * Duration (tracer only, development or `interceptors: [tracer()]`). A step that waited on\n * time-sliced work: the total of its runs and of the slices between them (#61).\n */\n readonly ms?: number\n /** Time-sliced work (#61): the runs {@link ms} spans; absent when the step ran in one. */\n readonly runs?: number\n}\n\n/** What `table.explain()` returns (§8.4); `String(e)` is the console summary. */\nexport interface TableExplanation {\n readonly run: number\n readonly trigger: Trigger\n readonly status: RowModelStatus\n /** Rows after ingest (after the schema dropped invalid rows). */\n readonly rows: number\n /** With a schema: its `invalidRows` mode and how many rows failed it. */\n readonly schema?: { readonly mode: InvalidRowsMode; readonly invalid: number }\n readonly steps: readonly ExplainStep[]\n /** Rows after filter and search (`getRowModel().filteredCount`). */\n readonly filteredCount: number\n /** With a pagination slice: the page shown (0-based), the page count and the page size. */\n readonly page?: { readonly index: number; readonly count: number; readonly size: number }\n /** Rows in `getRowModel().rows`. */\n readonly visible: number\n /** Error and warning diagnostics in `getDiagnostics()`. */\n readonly diagnostics: number\n /** Timings come from the tracer (it saw this run). */\n readonly traced: boolean\n /** Duration of the run (tracer only). */\n readonly ms?: number\n toString(): string\n}\n\n/**\n * `kept` / `removed` by the step, `skipped` (server mode), `failed` (passed its input through),\n * `not-reached` (an earlier step or the schema removed the row).\n */\nexport type RowStepOutcome = 'kept' | 'removed' | 'skipped' | 'failed' | 'not-reached'\n\nexport interface RowStep {\n readonly feature: string\n readonly stage: Stage\n readonly outcome: RowStepOutcome\n /** Kept: the row's position in the step output (0-based) and the output size. */\n readonly position?: number\n readonly of?: number\n /** Why the step removed the row (redacted). */\n readonly detail?: Readonly<Record<string, unknown>>\n}\n\n/** What `table.explainRow(key)` returns (§8.4); `String(e)` is the console report. */\nexport interface RowExplanation {\n /** The key asked for, redacted (a hash under `'safe'`). */\n readonly key: unknown\n readonly found: boolean\n /** Position in `getData()`; absent when not found or dropped by the schema. */\n readonly index?: number\n /** Position in `options.data` of a row the schema dropped. */\n readonly rawIndex?: number\n readonly schema: 'none' | 'valid' | 'flagged' | 'dropped'\n /** Schema issues of a flagged / dropped row (paths + DataKable's own text unless `'full'`). */\n readonly issues?: readonly { path: string; message: string }[]\n readonly steps: readonly RowStep[]\n /** The step that removed the row: a feature name, or `'schema'`. */\n readonly removedBy?: string\n /** The row is in `getRowModel().rows`. */\n readonly visible: boolean\n readonly run: number\n /** Rows after ingest (for \"not found\"). */\n readonly rows: number\n toString(): string\n}\n\nconst NOOP = () => {}\n\n/** Steps that take part in the row model: a stage and a `rowModel` (server mode included). */\nconst pipelineSteps = (features: readonly AnyFeature[]) =>\n features.filter((f) => f.stage !== 'none' && typeof f.rowModel === 'function')\n\nconst isServer = (f: AnyFeature) => f.mode === 'server'\n\n/** `{ pageIndex, pageSize }` of the first paginate-stage slice that has them. */\nexport function pageOf(host: ExplainHost): { index: number; size: number } | undefined {\n for (const f of host.features) {\n if (f.stage !== 'paginate') continue\n const s = host.state()[f.name] as { pageIndex?: unknown; pageSize?: unknown } | undefined\n if (typeof s?.pageIndex === 'number' && typeof s.pageSize === 'number' && s.pageSize > 0) {\n return { index: s.pageIndex, size: s.pageSize }\n }\n }\n return undefined\n}\n\nexport const pageCount = (rows: number, size: number) => Math.ceil(rows / size)\n\n/** Clamped like pagination does (the page actually shown). */\nexport const shownPage = (index: number, count: number) => Math.max(0, Math.min(index, count - 1))\n\n/** `table.explain()` (§8.4): the last run's counts, with tracer timings when it was traced. */\nexport function explainTable(host: ExplainHost): TableExplanation {\n const model = host.rowModel()\n const last = host.lastRun()\n const trace = readTrace(host.table)\n const traced = trace !== undefined && last !== undefined && trace.run === last.run\n const steps: ExplainStep[] = []\n let flowing = model.totalCount\n for (const f of pipelineSteps(host.features)) {\n if (isServer(f)) {\n steps.push(step(f, 'server', flowing, flowing, false, false))\n continue\n }\n const rec = last?.steps.find((s) => s.feature === f)\n if (!rec) continue\n flowing = rec.output.length\n const t = traced ? trace.steps.get(f.name) : undefined\n steps.push({\n ...step(f, 'client', rec.input.length, rec.output.length, rec.cached, rec.failed),\n ...(t ? { ms: t.ms, ...(t.runs ? { runs: t.runs } : {}) } : {}),\n })\n }\n const mode = host.schemaMode()\n const schema = host.schema()\n const p = pageOf(host)\n const count = p ? pageCount(model.filteredCount, p.size) : 0\n let diagnostics = 0\n for (const d of host.diagnostics()) if (d.level !== 'info') diagnostics++\n const e: TableExplanation = {\n run: last?.run ?? 0,\n trigger: last?.trigger ?? 'init',\n status: model.status,\n rows: model.totalCount,\n ...(mode === undefined ? {} : { schema: { mode, invalid: schema?.invalid.length ?? 0 } }),\n steps,\n filteredCount: model.filteredCount,\n ...(p ? { page: { index: shownPage(p.index, count), count, size: p.size } } : {}),\n visible: model.rows.length,\n diagnostics,\n traced,\n ...(traced && trace.ms !== undefined ? { ms: trace.ms } : {}),\n toString: () => ((process.env.NODE_ENV !== \"production\") ? formatTableExplanation(e) : JSON.stringify(e)),\n }\n return e\n}\n\nfunction step(\n f: AnyFeature,\n mode: 'client' | 'server',\n input: number,\n output: number,\n cached: boolean,\n failed: boolean,\n): ExplainStep {\n return { feature: f.name, stage: f.stage, mode, input, output, cached, failed }\n}\n\n/** Index of the row whose key equals `key` (`42` matches `'42'`), or -1. */\nfunction findKey(rows: readonly unknown[], rowKey: unknown, key: unknown): number {\n const keyOf = resolveRowKeys(rows, rowKey, NOOP, NOOP)\n const s = String(key)\n for (let i = 0; i < rows.length; i++) {\n const k = keyOf(rows[i], i)\n if (k === key || String(k) === s) return i\n }\n return -1\n}\n\n/**\n * `table.explainRow(key)` (§8.4): replays the row through every stage of the last run — schema,\n * then each step in pipeline order — and names the step that removed it. Survival is read from the\n * recorded step input / output (no per-row bookkeeping during normal runs); a removal by a filter\n * replays its filters on the single row to name the ones that reject it. Read-only: no state\n * change, no notification, no diagnostic. Every value it shows is redacted (§8.2).\n */\nexport function explainRow(host: ExplainHost, key: RowKey): RowExplanation {\n const model = host.rowModel()\n const last = host.lastRun()\n const data = host.data()\n const r = resolveRedaction(host.redaction, (process.env.NODE_ENV !== \"production\"))\n const where: Location = { kind: 'feature', name: 'explainRow' }\n const shownKey = redactDetails({ key }, { key: 'rowKey' }, where, r).key\n const mode = host.schemaMode()\n const outcome = host.schema()\n const rowKey = host.rowKey()\n\n const index = findKey(data, rowKey, key)\n let schema: RowExplanation['schema'] = mode === undefined ? 'none' : 'valid'\n let rawIndex: number | undefined\n let issues: readonly unknown[] | undefined\n if (index >= 0) {\n issues = outcome?.flagged?.get(index)\n if (issues) schema = 'flagged'\n } else if (outcome && outcome.invalid.length > 0 && rowKey !== undefined && mode !== 'flag') {\n // Dropped by the schema: looked up among the invalid raw rows by the same key.\n const i = findKey(\n outcome.invalid.map((x) => x.raw),\n rowKey,\n key,\n )\n const inv = outcome.invalid[i]\n if (inv) {\n schema = 'dropped'\n rawIndex = inv.index\n issues = inv.issues\n }\n }\n const found = index >= 0 || rawIndex !== undefined\n let removedBy: string | undefined = schema === 'dropped' ? 'schema' : undefined\n const steps: RowStep[] = []\n for (const f of pipelineSteps(host.features)) {\n const base = { feature: f.name, stage: f.stage }\n if (!found || removedBy !== undefined) {\n steps.push({ ...base, outcome: 'not-reached' })\n continue\n }\n if (isServer(f)) {\n steps.push({ ...base, outcome: 'skipped' })\n continue\n }\n const rec = last?.steps.find((s) => s.feature === f)\n if (!rec) {\n steps.push({ ...base, outcome: 'not-reached' })\n continue\n }\n const position = rec.output.indexOf(index)\n if (position >= 0) {\n const of = rec.output.length\n steps.push({ ...base, outcome: rec.failed ? 'failed' : 'kept', position, of })\n continue\n }\n removedBy = f.name\n const detail = host.detail?.(host, f, rec.input, index, r, where)\n steps.push({ ...base, outcome: 'removed', ...(detail ? { detail } : {}) })\n }\n const e: RowExplanation = {\n key: shownKey,\n found,\n ...(index >= 0 ? { index } : {}),\n ...(rawIndex === undefined ? {} : { rawIndex }),\n schema,\n ...(issues ? { issues: issues.map((x, i) => scrubSchemaIssue(x, r, `issues.${i}`)) } : {}),\n steps,\n ...(removedBy === undefined ? {} : { removedBy }),\n visible: index >= 0 && model.rows.some((row) => (row as { index?: unknown }).index === index),\n run: last?.run ?? 0,\n rows: data.length,\n toString: () => ((process.env.NODE_ENV !== \"production\") ? formatRowExplanation(e) : JSON.stringify(e)),\n }\n return e\n}\n"],"mappings":"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","names":[]}