@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 +1 @@
1
- {"version":3,"sources":["../../src/intercept/codes.ts"],"sourcesContent":["import { type DiagnosticMessages, defineDiagnostic } from '../diagnostics/catalog'\n\ndeclare module '../diagnostics/catalog' {\n interface DiagnosticCatalog {\n DK_CALLBACK_FAILED: {\n /** The callback's option path, e.g. `columns[2].format`, `fetcher`, `searchFn`. */\n slot: string\n /**\n * A callback passed to a method rather than set as an option: the method (`table.setState`);\n * `slot` is then the argument (`updater`).\n */\n op?: string\n /** Column id, for cell slots. */\n column?: string\n /** A sample of the failing row indices (first few, in order). */\n rows?: readonly number[]\n /** How many calls failed (cells in a column batch; 1 for a single call). */\n count: number\n /** The slot fallback that was applied. */\n fallback: string\n /** `error.name` only; the full error is `context.cause`. */\n errorName?: string\n }\n DK_UNKNOWN: {\n op: string\n slot?: string\n errorName?: string\n fallback: string\n }\n }\n}\n\nconst rowList = (rows: readonly number[] | undefined, count: number) => {\n if (!rows || rows.length === 0) return ''\n const list = rows.map((r) => `#${r}`).join(', ')\n return ` (${count > rows.length ? `first: ${list}, …` : `rows ${list}`})`\n}\n\n/** Message text (§8.2): development builds, or production via `@datakable/core/messages`. */\nexport const boundaryMessages: DiagnosticMessages<'DK_CALLBACK_FAILED' | 'DK_UNKNOWN'> = {\n DK_CALLBACK_FAILED: {\n problem: (d) =>\n `${d.op === undefined ? '' : `${d.op}() `}${d.slot}${d.column === undefined ? '' : ` (column \"${d.column}\")`} threw` +\n `${d.errorName ? ` ${d.errorName}` : ''} for ` +\n `${d.count === 1 ? '1 row' : `${d.count} rows`}${rowList(d.rows, d.count)}`,\n impact: (d) => `${d.fallback}; the rest of the table is unaffected`,\n fix: (d) => [\n `make ${d.op === undefined ? d.slot : `the ${d.slot} passed to ${d.op}()`} total: guard null / undefined / unexpected types and return a fallback ` +\n 'instead of throwing',\n d.rows && d.rows.length > 0\n ? `reproduce with table.explainRow() on row #${d.rows[0]}; the original error is context.cause`\n : 'the original error is context.cause (passed to onDiagnostic)',\n ],\n },\n DK_UNKNOWN: {\n problem: (d) =>\n `${d.errorName ?? 'a non-Error value'} was thrown during ${d.op}` +\n `${d.slot ? ` at ${d.slot}` : ''} from code DataKable could not classify`,\n impact: (d) => `${d.fallback}; the table keeps working`,\n fix: (d) => [\n 'inspect context.cause (passed to onDiagnostic) for the original error and its stack',\n `if your code runs inside ${d.op} (a callback, interceptor or plugin), catch errors there ` +\n 'and return a fallback',\n 'if the stack points into DataKable, report it as a bug',\n ],\n },\n}\n\n/** Codes owned by the errorBoundary (spec §3.4, §8.3, §8.6). `DK_INTERNAL` lives in diagnostics/codes.ts. */\nexport const boundaryDiagnostics = [\n defineDiagnostic(\n {\n code: 'DK_CALLBACK_FAILED',\n level: 'error',\n where: (d) =>\n d.op === undefined\n ? { kind: 'option', path: d.slot }\n : { kind: 'operation', op: d.op, slot: d.slot },\n },\n (process.env.NODE_ENV !== \"production\") && boundaryMessages.DK_CALLBACK_FAILED,\n ),\n defineDiagnostic(\n {\n code: 'DK_UNKNOWN',\n level: 'error',\n where: (d) =>\n d.slot ? { kind: 'operation', op: d.op, slot: d.slot } : { kind: 'operation', op: d.op },\n },\n (process.env.NODE_ENV !== \"production\") && boundaryMessages.DK_UNKNOWN,\n ),\n]\n"],"mappings":";AAAA,SAAkC,wBAAwB;AAgC1D,IAAM,UAAU,CAAC,MAAqC,UAAkB;AACtE,MAAI,CAAC,QAAQ,KAAK,WAAW,EAAG,QAAO;AACvC,QAAM,OAAO,KAAK,IAAI,CAAC,MAAM,IAAI,CAAC,EAAE,EAAE,KAAK,IAAI;AAC/C,SAAO,KAAK,QAAQ,KAAK,SAAS,UAAU,IAAI,aAAQ,QAAQ,IAAI,EAAE;AACxE;AAGO,IAAM,mBAA4E;AAAA,EACvF,oBAAoB;AAAA,IAClB,SAAS,CAAC,MACR,GAAG,EAAE,OAAO,SAAY,KAAK,GAAG,EAAE,EAAE,KAAK,GAAG,EAAE,IAAI,GAAG,EAAE,WAAW,SAAY,KAAK,aAAa,EAAE,MAAM,IAAI,SACzG,EAAE,YAAY,IAAI,EAAE,SAAS,KAAK,EAAE,QACpC,EAAE,UAAU,IAAI,UAAU,GAAG,EAAE,KAAK,OAAO,GAAG,QAAQ,EAAE,MAAM,EAAE,KAAK,CAAC;AAAA,IAC3E,QAAQ,CAAC,MAAM,GAAG,EAAE,QAAQ;AAAA,IAC5B,KAAK,CAAC,MAAM;AAAA,MACV,QAAQ,EAAE,OAAO,SAAY,EAAE,OAAO,OAAO,EAAE,IAAI,cAAc,EAAE,EAAE,IAAI;AAAA,MAEzE,EAAE,QAAQ,EAAE,KAAK,SAAS,IACtB,6CAA6C,EAAE,KAAK,CAAC,CAAC,0CACtD;AAAA,IACN;AAAA,EACF;AAAA,EACA,YAAY;AAAA,IACV,SAAS,CAAC,MACR,GAAG,EAAE,aAAa,mBAAmB,sBAAsB,EAAE,EAAE,GAC5D,EAAE,OAAO,OAAO,EAAE,IAAI,KAAK,EAAE;AAAA,IAClC,QAAQ,CAAC,MAAM,GAAG,EAAE,QAAQ;AAAA,IAC5B,KAAK,CAAC,MAAM;AAAA,MACV;AAAA,MACA,4BAA4B,EAAE,EAAE;AAAA,MAEhC;AAAA,IACF;AAAA,EACF;AACF;AAGO,IAAM,sBAAsB;AAAA,EACjC;AAAA,IACE;AAAA,MACE,MAAM;AAAA,MACN,OAAO;AAAA,MACP,OAAO,CAAC,MACN,EAAE,OAAO,SACL,EAAE,MAAM,UAAU,MAAM,EAAE,KAAK,IAC/B,EAAE,MAAM,aAAa,IAAI,EAAE,IAAI,MAAM,EAAE,KAAK;AAAA,IACpD;AAAA,IACC,QAAQ,IAAI,aAAa,gBAAiB,iBAAiB;AAAA,EAC9D;AAAA,EACA;AAAA,IACE;AAAA,MACE,MAAM;AAAA,MACN,OAAO;AAAA,MACP,OAAO,CAAC,MACN,EAAE,OAAO,EAAE,MAAM,aAAa,IAAI,EAAE,IAAI,MAAM,EAAE,KAAK,IAAI,EAAE,MAAM,aAAa,IAAI,EAAE,GAAG;AAAA,IAC3F;AAAA,IACC,QAAQ,IAAI,aAAa,gBAAiB,iBAAiB;AAAA,EAC9D;AACF;","names":[]}
1
+ {"version":3,"sources":["../../src/intercept/codes.ts"],"sourcesContent":["import { type DiagnosticMessages, defineDiagnostic } from '../diagnostics/catalog'\nimport '../diagnostics/process-guard'\n\ndeclare module '../diagnostics/catalog' {\n interface DiagnosticCatalog {\n DK_CALLBACK_FAILED: {\n /** The callback's option path, e.g. `columns[2].format`, `fetcher`, `searchFn`. */\n slot: string\n /**\n * A callback passed to a method rather than set as an option: the method (`table.setState`);\n * `slot` is then the argument (`updater`).\n */\n op?: string\n /** Column id, for cell slots. */\n column?: string\n /** A sample of the failing row indices (first few, in order). */\n rows?: readonly number[]\n /** How many calls failed (cells in a column batch; 1 for a single call). */\n count: number\n /** The slot fallback that was applied. */\n fallback: string\n /** `error.name` only; the full error is `context.cause`. */\n errorName?: string\n }\n DK_UNKNOWN: {\n op: string\n slot?: string\n errorName?: string\n fallback: string\n }\n }\n}\n\nconst rowList = (rows: readonly number[] | undefined, count: number) => {\n if (!rows || rows.length === 0) return ''\n const list = rows.map((r) => `#${r}`).join(', ')\n return ` (${count > rows.length ? `first: ${list}, …` : `rows ${list}`})`\n}\n\n/** Message text (§8.2): development builds, or production via `@datakable/core/messages`. */\nexport const boundaryMessages: DiagnosticMessages<'DK_CALLBACK_FAILED' | 'DK_UNKNOWN'> = {\n DK_CALLBACK_FAILED: {\n problem: (d) =>\n `${d.op === undefined ? '' : `${d.op}() `}${d.slot}${d.column === undefined ? '' : ` (column \"${d.column}\")`} threw` +\n `${d.errorName ? ` ${d.errorName}` : ''} for ` +\n `${d.count === 1 ? '1 row' : `${d.count} rows`}${rowList(d.rows, d.count)}`,\n impact: (d) => `${d.fallback}; the rest of the table is unaffected`,\n fix: (d) => [\n `make ${d.op === undefined ? d.slot : `the ${d.slot} passed to ${d.op}()`} total: guard null / undefined / unexpected types and return a fallback ` +\n 'instead of throwing',\n d.rows && d.rows.length > 0\n ? `reproduce with table.explainRow() on row #${d.rows[0]}; the original error is context.cause`\n : 'the original error is context.cause (passed to onDiagnostic)',\n ],\n },\n DK_UNKNOWN: {\n problem: (d) =>\n `${d.errorName ?? 'a non-Error value'} was thrown during ${d.op}` +\n `${d.slot ? ` at ${d.slot}` : ''} from code DataKable could not classify`,\n impact: (d) => `${d.fallback}; the table keeps working`,\n fix: (d) => [\n 'inspect context.cause (passed to onDiagnostic) for the original error and its stack',\n `if your code runs inside ${d.op} (a callback, interceptor or plugin), catch errors there ` +\n 'and return a fallback',\n 'if the stack points into DataKable, report it as a bug',\n ],\n },\n}\n\n/** Codes owned by the errorBoundary (spec §3.4, §8.3, §8.6). `DK_INTERNAL` lives in diagnostics/codes.ts. */\nexport const boundaryDiagnostics = [\n defineDiagnostic(\n {\n code: 'DK_CALLBACK_FAILED',\n level: 'error',\n where: (d) =>\n d.op === undefined\n ? { kind: 'option', path: d.slot }\n : { kind: 'operation', op: d.op, slot: d.slot },\n },\n (process.env.NODE_ENV !== \"production\") && boundaryMessages.DK_CALLBACK_FAILED,\n ),\n defineDiagnostic(\n {\n code: 'DK_UNKNOWN',\n level: 'error',\n where: (d) =>\n d.slot ? { kind: 'operation', op: d.op, slot: d.slot } : { kind: 'operation', op: d.op },\n },\n (process.env.NODE_ENV !== \"production\") && boundaryMessages.DK_UNKNOWN,\n ),\n]\n"],"mappings":";AAAA,SAAkC,wBAAwB;AAC1D,OAAO;AAgCP,IAAM,UAAU,CAAC,MAAqC,UAAkB;AACtE,MAAI,CAAC,QAAQ,KAAK,WAAW,EAAG,QAAO;AACvC,QAAM,OAAO,KAAK,IAAI,CAAC,MAAM,IAAI,CAAC,EAAE,EAAE,KAAK,IAAI;AAC/C,SAAO,KAAK,QAAQ,KAAK,SAAS,UAAU,IAAI,aAAQ,QAAQ,IAAI,EAAE;AACxE;AAGO,IAAM,mBAA4E;AAAA,EACvF,oBAAoB;AAAA,IAClB,SAAS,CAAC,MACR,GAAG,EAAE,OAAO,SAAY,KAAK,GAAG,EAAE,EAAE,KAAK,GAAG,EAAE,IAAI,GAAG,EAAE,WAAW,SAAY,KAAK,aAAa,EAAE,MAAM,IAAI,SACzG,EAAE,YAAY,IAAI,EAAE,SAAS,KAAK,EAAE,QACpC,EAAE,UAAU,IAAI,UAAU,GAAG,EAAE,KAAK,OAAO,GAAG,QAAQ,EAAE,MAAM,EAAE,KAAK,CAAC;AAAA,IAC3E,QAAQ,CAAC,MAAM,GAAG,EAAE,QAAQ;AAAA,IAC5B,KAAK,CAAC,MAAM;AAAA,MACV,QAAQ,EAAE,OAAO,SAAY,EAAE,OAAO,OAAO,EAAE,IAAI,cAAc,EAAE,EAAE,IAAI;AAAA,MAEzE,EAAE,QAAQ,EAAE,KAAK,SAAS,IACtB,6CAA6C,EAAE,KAAK,CAAC,CAAC,0CACtD;AAAA,IACN;AAAA,EACF;AAAA,EACA,YAAY;AAAA,IACV,SAAS,CAAC,MACR,GAAG,EAAE,aAAa,mBAAmB,sBAAsB,EAAE,EAAE,GAC5D,EAAE,OAAO,OAAO,EAAE,IAAI,KAAK,EAAE;AAAA,IAClC,QAAQ,CAAC,MAAM,GAAG,EAAE,QAAQ;AAAA,IAC5B,KAAK,CAAC,MAAM;AAAA,MACV;AAAA,MACA,4BAA4B,EAAE,EAAE;AAAA,MAEhC;AAAA,IACF;AAAA,EACF;AACF;AAGO,IAAM,sBAAsB;AAAA,EACjC;AAAA,IACE;AAAA,MACE,MAAM;AAAA,MACN,OAAO;AAAA,MACP,OAAO,CAAC,MACN,EAAE,OAAO,SACL,EAAE,MAAM,UAAU,MAAM,EAAE,KAAK,IAC/B,EAAE,MAAM,aAAa,IAAI,EAAE,IAAI,MAAM,EAAE,KAAK;AAAA,IACpD;AAAA,IACC,QAAQ,IAAI,aAAa,gBAAiB,iBAAiB;AAAA,EAC9D;AAAA,EACA;AAAA,IACE;AAAA,MACE,MAAM;AAAA,MACN,OAAO;AAAA,MACP,OAAO,CAAC,MACN,EAAE,OAAO,EAAE,MAAM,aAAa,IAAI,EAAE,IAAI,MAAM,EAAE,KAAK,IAAI,EAAE,MAAM,aAAa,IAAI,EAAE,GAAG;AAAA,IAC3F;AAAA,IACC,QAAQ,IAAI,aAAa,gBAAiB,iBAAiB;AAAA,EAC9D;AACF;","names":[]}
@@ -34,46 +34,38 @@ function allRows(n) {
34
34
  return out;
35
35
  }
36
36
  var builtins = {
37
- "table:init": {
38
- describe: "table creation continued without the failed step",
39
- value: () => void 0
40
- },
41
- "table:setOptions": { describe: "the previous options were kept", value: () => void 0 },
42
- "table:destroy": {
43
- describe: "teardown continued; the table is destroyed",
44
- value: () => void 0
45
- },
46
- "state:dispatch": {
47
- describe: "the update was dropped (state unchanged)",
48
- value: () => void 0
49
- },
37
+ // `describe`: prose keys (diagnostics/prose.ts); a plugin's own fallback may use plain text.
38
+ "table:init": { describe: "init-continued", value: () => void 0 },
39
+ "table:setOptions": { describe: "options-kept", value: () => void 0 },
40
+ "table:destroy": { describe: "destroy-continued", value: () => void 0 },
41
+ "state:dispatch": { describe: "update-dropped", value: () => void 0 },
50
42
  "data:ingest": {
51
- describe: "the previous data was kept",
43
+ describe: "data-kept",
52
44
  value: (ctx) => ctx.meta.get(FALLBACK) ?? []
53
45
  },
54
46
  "pipeline:run": {
55
- describe: "the last good row model was kept",
47
+ describe: "row-model-kept",
56
48
  value: (ctx) => ctx.meta.get(FALLBACK) ?? allRows(ctx.input.rowCount)
57
49
  },
58
50
  "pipeline:step": {
59
- describe: "the step passed its input through",
51
+ describe: "step-passthrough",
60
52
  value: (ctx) => ctx.input.indices
61
53
  },
62
54
  "column:batch": {
63
- describe: "the column's cells use the slot fallback ('' for format, undefined for accessor, non-matching for filterFn, missing (sorted last) for sortBy)",
55
+ describe: "batch-fallback",
64
56
  value: () => void 0
65
57
  },
66
58
  "async:request": {
67
- describe: "the previous results were kept (status: 'error')",
59
+ describe: "results-kept",
68
60
  value: (ctx) => Promise.resolve(ctx.meta.get(FALLBACK))
69
61
  },
70
62
  "diagnostic:emit": {
71
- describe: "the diagnostic was dropped (the logger never kills the table)",
63
+ describe: "diagnostic-dropped",
72
64
  silent: true,
73
65
  value: () => void 0
74
66
  }
75
67
  };
76
- var NONE = { describe: "the operation returned undefined", value: () => void 0 };
68
+ var NONE = { describe: "returned-undefined", value: () => void 0 };
77
69
  var registry = new Map(Object.entries(builtins));
78
70
  function registerFallback(op, fallback) {
79
71
  registry.set(op, fallback);
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/intercept/fallbacks.ts"],"sourcesContent":["import type { InterceptorContext } from './context'\nimport type { BuiltinOperations, OpName, OpResult } from './operations'\n\n/**\n * What the errorBoundary returns when an op fails (§3.4 registry table). `describe` becomes the\n * diagnostic's `impact`.\n */\nexport interface Fallback<O extends OpName = OpName> {\n readonly describe: string\n /**\n * Report without the diagnostics pipeline: one `console.error` per table. Used by\n * `diagnostic:emit`, where reporting through the pipeline could recurse.\n */\n readonly silent?: boolean\n value(ctx: InterceptorContext<O>): OpResult<O>\n}\n\n/**\n * `ctx.meta` key for a caller-supplied fallback value: the previous data (`data:ingest`), the last\n * good row model (`pipeline:run`), the previous results (`async:request`). Set it before `run`.\n */\nexport const FALLBACK = 'datakable:fallback'\n\n/**\n * `ctx.meta` key the errorBoundary sets (to the error) when it replaced the op's result with the\n * fallback, so the caller can tell a fallback from a real result (e.g. a failed `data:ingest` sets\n * `status: 'error'`, §6.6).\n */\nexport const FAILED = 'datakable:failed'\n\nfunction allRows(n: number): Uint32Array {\n const out = new Uint32Array(n)\n for (let i = 0; i < n; i++) out[i] = i\n return out\n}\n\nconst builtins: { [K in keyof BuiltinOperations]: Fallback<K> } = {\n 'table:init': {\n describe: 'table creation continued without the failed step',\n value: () => undefined,\n },\n 'table:setOptions': { describe: 'the previous options were kept', value: () => undefined },\n 'table:destroy': {\n describe: 'teardown continued; the table is destroyed',\n value: () => undefined,\n },\n 'state:dispatch': {\n describe: 'the update was dropped (state unchanged)',\n value: () => undefined,\n },\n 'data:ingest': {\n describe: 'the previous data was kept',\n value: (ctx) => (ctx.meta.get(FALLBACK) as readonly unknown[] | undefined) ?? [],\n },\n 'pipeline:run': {\n describe: 'the last good row model was kept',\n value: (ctx) =>\n (ctx.meta.get(FALLBACK) as Uint32Array | undefined) ?? allRows(ctx.input.rowCount),\n },\n 'pipeline:step': {\n describe: 'the step passed its input through',\n value: (ctx) => ctx.input.indices,\n },\n 'column:batch': {\n describe:\n \"the column's cells use the slot fallback ('' for format, undefined for accessor, \" +\n 'non-matching for filterFn, missing (sorted last) for sortBy)',\n value: () => undefined,\n },\n 'async:request': {\n describe: \"the previous results were kept (status: 'error')\",\n value: (ctx) => Promise.resolve(ctx.meta.get(FALLBACK)),\n },\n 'diagnostic:emit': {\n describe: 'the diagnostic was dropped (the logger never kills the table)',\n silent: true,\n value: () => undefined,\n },\n}\n\nconst NONE: Fallback = { describe: 'the operation returned undefined', value: () => undefined }\n\nconst registry = new Map<string, Fallback>(Object.entries(builtins) as [string, Fallback][])\n\n/**\n * Sets the fallback of an op (ops registered by plugins / `@datakable/react`). Process-wide like\n * the op registry; the last registration wins.\n */\nexport function registerFallback<O extends OpName>(op: O, fallback: Fallback<O>): void {\n registry.set(op, fallback as unknown as Fallback)\n}\n\n/** The registered fallback, or one that returns `undefined` for ops without an entry. */\nexport function getFallback(op: string): Fallback {\n return registry.get(op) ?? NONE\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAqBO,IAAM,WAAW;AAOjB,IAAM,SAAS;AAEtB,SAAS,QAAQ,GAAwB;AACvC,QAAM,MAAM,IAAI,YAAY,CAAC;AAC7B,WAAS,IAAI,GAAG,IAAI,GAAG,IAAK,KAAI,CAAC,IAAI;AACrC,SAAO;AACT;AAEA,IAAM,WAA4D;AAAA,EAChE,cAAc;AAAA,IACZ,UAAU;AAAA,IACV,OAAO,MAAM;AAAA,EACf;AAAA,EACA,oBAAoB,EAAE,UAAU,kCAAkC,OAAO,MAAM,OAAU;AAAA,EACzF,iBAAiB;AAAA,IACf,UAAU;AAAA,IACV,OAAO,MAAM;AAAA,EACf;AAAA,EACA,kBAAkB;AAAA,IAChB,UAAU;AAAA,IACV,OAAO,MAAM;AAAA,EACf;AAAA,EACA,eAAe;AAAA,IACb,UAAU;AAAA,IACV,OAAO,CAAC,QAAS,IAAI,KAAK,IAAI,QAAQ,KAAwC,CAAC;AAAA,EACjF;AAAA,EACA,gBAAgB;AAAA,IACd,UAAU;AAAA,IACV,OAAO,CAAC,QACL,IAAI,KAAK,IAAI,QAAQ,KAAiC,QAAQ,IAAI,MAAM,QAAQ;AAAA,EACrF;AAAA,EACA,iBAAiB;AAAA,IACf,UAAU;AAAA,IACV,OAAO,CAAC,QAAQ,IAAI,MAAM;AAAA,EAC5B;AAAA,EACA,gBAAgB;AAAA,IACd,UACE;AAAA,IAEF,OAAO,MAAM;AAAA,EACf;AAAA,EACA,iBAAiB;AAAA,IACf,UAAU;AAAA,IACV,OAAO,CAAC,QAAQ,QAAQ,QAAQ,IAAI,KAAK,IAAI,QAAQ,CAAC;AAAA,EACxD;AAAA,EACA,mBAAmB;AAAA,IACjB,UAAU;AAAA,IACV,QAAQ;AAAA,IACR,OAAO,MAAM;AAAA,EACf;AACF;AAEA,IAAM,OAAiB,EAAE,UAAU,oCAAoC,OAAO,MAAM,OAAU;AAE9F,IAAM,WAAW,IAAI,IAAsB,OAAO,QAAQ,QAAQ,CAAyB;AAMpF,SAAS,iBAAmC,IAAO,UAA6B;AACrF,WAAS,IAAI,IAAI,QAA+B;AAClD;AAGO,SAAS,YAAY,IAAsB;AAChD,SAAO,SAAS,IAAI,EAAE,KAAK;AAC7B;","names":[]}
1
+ {"version":3,"sources":["../../src/intercept/fallbacks.ts"],"sourcesContent":["import type { InterceptorContext } from './context'\nimport type { BuiltinOperations, OpName, OpResult } from './operations'\n\n/**\n * What the errorBoundary returns when an op fails (§3.4 registry table). `describe` becomes the\n * diagnostic's `impact`.\n */\nexport interface Fallback<O extends OpName = OpName> {\n readonly describe: string\n /**\n * Report without the diagnostics pipeline: one `console.error` per table. Used by\n * `diagnostic:emit`, where reporting through the pipeline could recurse.\n */\n readonly silent?: boolean\n value(ctx: InterceptorContext<O>): OpResult<O>\n}\n\n/**\n * `ctx.meta` key for a caller-supplied fallback value: the previous data (`data:ingest`), the last\n * good row model (`pipeline:run`), the previous results (`async:request`). Set it before `run`.\n */\nexport const FALLBACK = 'datakable:fallback'\n\n/**\n * `ctx.meta` key the errorBoundary sets (to the error) when it replaced the op's result with the\n * fallback, so the caller can tell a fallback from a real result (e.g. a failed `data:ingest` sets\n * `status: 'error'`, §6.6).\n */\nexport const FAILED = 'datakable:failed'\n\nfunction allRows(n: number): Uint32Array {\n const out = new Uint32Array(n)\n for (let i = 0; i < n; i++) out[i] = i\n return out\n}\n\nconst builtins: { [K in keyof BuiltinOperations]: Fallback<K> } = {\n // `describe`: prose keys (diagnostics/prose.ts); a plugin's own fallback may use plain text.\n 'table:init': { describe: 'init-continued', value: () => undefined },\n 'table:setOptions': { describe: 'options-kept', value: () => undefined },\n 'table:destroy': { describe: 'destroy-continued', value: () => undefined },\n 'state:dispatch': { describe: 'update-dropped', value: () => undefined },\n 'data:ingest': {\n describe: 'data-kept',\n value: (ctx) => (ctx.meta.get(FALLBACK) as readonly unknown[] | undefined) ?? [],\n },\n 'pipeline:run': {\n describe: 'row-model-kept',\n value: (ctx) =>\n (ctx.meta.get(FALLBACK) as Uint32Array | undefined) ?? allRows(ctx.input.rowCount),\n },\n 'pipeline:step': {\n describe: 'step-passthrough',\n value: (ctx) => ctx.input.indices,\n },\n 'column:batch': {\n describe: 'batch-fallback',\n value: () => undefined,\n },\n 'async:request': {\n describe: 'results-kept',\n value: (ctx) => Promise.resolve(ctx.meta.get(FALLBACK)),\n },\n 'diagnostic:emit': {\n describe: 'diagnostic-dropped',\n silent: true,\n value: () => undefined,\n },\n}\n\nconst NONE: Fallback = { describe: 'returned-undefined', value: () => undefined }\n\nconst registry = new Map<string, Fallback>(Object.entries(builtins) as [string, Fallback][])\n\n/**\n * Sets the fallback of an op (ops registered by plugins / `@datakable/react`). Process-wide like\n * the op registry; the last registration wins.\n */\nexport function registerFallback<O extends OpName>(op: O, fallback: Fallback<O>): void {\n registry.set(op, fallback as unknown as Fallback)\n}\n\n/** The registered fallback, or one that returns `undefined` for ops without an entry. */\nexport function getFallback(op: string): Fallback {\n return registry.get(op) ?? NONE\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAqBO,IAAM,WAAW;AAOjB,IAAM,SAAS;AAEtB,SAAS,QAAQ,GAAwB;AACvC,QAAM,MAAM,IAAI,YAAY,CAAC;AAC7B,WAAS,IAAI,GAAG,IAAI,GAAG,IAAK,KAAI,CAAC,IAAI;AACrC,SAAO;AACT;AAEA,IAAM,WAA4D;AAAA;AAAA,EAEhE,cAAc,EAAE,UAAU,kBAAkB,OAAO,MAAM,OAAU;AAAA,EACnE,oBAAoB,EAAE,UAAU,gBAAgB,OAAO,MAAM,OAAU;AAAA,EACvE,iBAAiB,EAAE,UAAU,qBAAqB,OAAO,MAAM,OAAU;AAAA,EACzE,kBAAkB,EAAE,UAAU,kBAAkB,OAAO,MAAM,OAAU;AAAA,EACvE,eAAe;AAAA,IACb,UAAU;AAAA,IACV,OAAO,CAAC,QAAS,IAAI,KAAK,IAAI,QAAQ,KAAwC,CAAC;AAAA,EACjF;AAAA,EACA,gBAAgB;AAAA,IACd,UAAU;AAAA,IACV,OAAO,CAAC,QACL,IAAI,KAAK,IAAI,QAAQ,KAAiC,QAAQ,IAAI,MAAM,QAAQ;AAAA,EACrF;AAAA,EACA,iBAAiB;AAAA,IACf,UAAU;AAAA,IACV,OAAO,CAAC,QAAQ,IAAI,MAAM;AAAA,EAC5B;AAAA,EACA,gBAAgB;AAAA,IACd,UAAU;AAAA,IACV,OAAO,MAAM;AAAA,EACf;AAAA,EACA,iBAAiB;AAAA,IACf,UAAU;AAAA,IACV,OAAO,CAAC,QAAQ,QAAQ,QAAQ,IAAI,KAAK,IAAI,QAAQ,CAAC;AAAA,EACxD;AAAA,EACA,mBAAmB;AAAA,IACjB,UAAU;AAAA,IACV,QAAQ;AAAA,IACR,OAAO,MAAM;AAAA,EACf;AACF;AAEA,IAAM,OAAiB,EAAE,UAAU,sBAAsB,OAAO,MAAM,OAAU;AAEhF,IAAM,WAAW,IAAI,IAAsB,OAAO,QAAQ,QAAQ,CAAyB;AAMpF,SAAS,iBAAmC,IAAO,UAA6B;AACrF,WAAS,IAAI,IAAI,QAA+B;AAClD;AAGO,SAAS,YAAY,IAAsB;AAChD,SAAO,SAAS,IAAI,EAAE,KAAK;AAC7B;","names":[]}
@@ -7,46 +7,38 @@ function allRows(n) {
7
7
  return out;
8
8
  }
9
9
  var builtins = {
10
- "table:init": {
11
- describe: "table creation continued without the failed step",
12
- value: () => void 0
13
- },
14
- "table:setOptions": { describe: "the previous options were kept", value: () => void 0 },
15
- "table:destroy": {
16
- describe: "teardown continued; the table is destroyed",
17
- value: () => void 0
18
- },
19
- "state:dispatch": {
20
- describe: "the update was dropped (state unchanged)",
21
- value: () => void 0
22
- },
10
+ // `describe`: prose keys (diagnostics/prose.ts); a plugin's own fallback may use plain text.
11
+ "table:init": { describe: "init-continued", value: () => void 0 },
12
+ "table:setOptions": { describe: "options-kept", value: () => void 0 },
13
+ "table:destroy": { describe: "destroy-continued", value: () => void 0 },
14
+ "state:dispatch": { describe: "update-dropped", value: () => void 0 },
23
15
  "data:ingest": {
24
- describe: "the previous data was kept",
16
+ describe: "data-kept",
25
17
  value: (ctx) => ctx.meta.get(FALLBACK) ?? []
26
18
  },
27
19
  "pipeline:run": {
28
- describe: "the last good row model was kept",
20
+ describe: "row-model-kept",
29
21
  value: (ctx) => ctx.meta.get(FALLBACK) ?? allRows(ctx.input.rowCount)
30
22
  },
31
23
  "pipeline:step": {
32
- describe: "the step passed its input through",
24
+ describe: "step-passthrough",
33
25
  value: (ctx) => ctx.input.indices
34
26
  },
35
27
  "column:batch": {
36
- describe: "the column's cells use the slot fallback ('' for format, undefined for accessor, non-matching for filterFn, missing (sorted last) for sortBy)",
28
+ describe: "batch-fallback",
37
29
  value: () => void 0
38
30
  },
39
31
  "async:request": {
40
- describe: "the previous results were kept (status: 'error')",
32
+ describe: "results-kept",
41
33
  value: (ctx) => Promise.resolve(ctx.meta.get(FALLBACK))
42
34
  },
43
35
  "diagnostic:emit": {
44
- describe: "the diagnostic was dropped (the logger never kills the table)",
36
+ describe: "diagnostic-dropped",
45
37
  silent: true,
46
38
  value: () => void 0
47
39
  }
48
40
  };
49
- var NONE = { describe: "the operation returned undefined", value: () => void 0 };
41
+ var NONE = { describe: "returned-undefined", value: () => void 0 };
50
42
  var registry = new Map(Object.entries(builtins));
51
43
  function registerFallback(op, fallback) {
52
44
  registry.set(op, fallback);
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/intercept/fallbacks.ts"],"sourcesContent":["import type { InterceptorContext } from './context'\nimport type { BuiltinOperations, OpName, OpResult } from './operations'\n\n/**\n * What the errorBoundary returns when an op fails (§3.4 registry table). `describe` becomes the\n * diagnostic's `impact`.\n */\nexport interface Fallback<O extends OpName = OpName> {\n readonly describe: string\n /**\n * Report without the diagnostics pipeline: one `console.error` per table. Used by\n * `diagnostic:emit`, where reporting through the pipeline could recurse.\n */\n readonly silent?: boolean\n value(ctx: InterceptorContext<O>): OpResult<O>\n}\n\n/**\n * `ctx.meta` key for a caller-supplied fallback value: the previous data (`data:ingest`), the last\n * good row model (`pipeline:run`), the previous results (`async:request`). Set it before `run`.\n */\nexport const FALLBACK = 'datakable:fallback'\n\n/**\n * `ctx.meta` key the errorBoundary sets (to the error) when it replaced the op's result with the\n * fallback, so the caller can tell a fallback from a real result (e.g. a failed `data:ingest` sets\n * `status: 'error'`, §6.6).\n */\nexport const FAILED = 'datakable:failed'\n\nfunction allRows(n: number): Uint32Array {\n const out = new Uint32Array(n)\n for (let i = 0; i < n; i++) out[i] = i\n return out\n}\n\nconst builtins: { [K in keyof BuiltinOperations]: Fallback<K> } = {\n 'table:init': {\n describe: 'table creation continued without the failed step',\n value: () => undefined,\n },\n 'table:setOptions': { describe: 'the previous options were kept', value: () => undefined },\n 'table:destroy': {\n describe: 'teardown continued; the table is destroyed',\n value: () => undefined,\n },\n 'state:dispatch': {\n describe: 'the update was dropped (state unchanged)',\n value: () => undefined,\n },\n 'data:ingest': {\n describe: 'the previous data was kept',\n value: (ctx) => (ctx.meta.get(FALLBACK) as readonly unknown[] | undefined) ?? [],\n },\n 'pipeline:run': {\n describe: 'the last good row model was kept',\n value: (ctx) =>\n (ctx.meta.get(FALLBACK) as Uint32Array | undefined) ?? allRows(ctx.input.rowCount),\n },\n 'pipeline:step': {\n describe: 'the step passed its input through',\n value: (ctx) => ctx.input.indices,\n },\n 'column:batch': {\n describe:\n \"the column's cells use the slot fallback ('' for format, undefined for accessor, \" +\n 'non-matching for filterFn, missing (sorted last) for sortBy)',\n value: () => undefined,\n },\n 'async:request': {\n describe: \"the previous results were kept (status: 'error')\",\n value: (ctx) => Promise.resolve(ctx.meta.get(FALLBACK)),\n },\n 'diagnostic:emit': {\n describe: 'the diagnostic was dropped (the logger never kills the table)',\n silent: true,\n value: () => undefined,\n },\n}\n\nconst NONE: Fallback = { describe: 'the operation returned undefined', value: () => undefined }\n\nconst registry = new Map<string, Fallback>(Object.entries(builtins) as [string, Fallback][])\n\n/**\n * Sets the fallback of an op (ops registered by plugins / `@datakable/react`). Process-wide like\n * the op registry; the last registration wins.\n */\nexport function registerFallback<O extends OpName>(op: O, fallback: Fallback<O>): void {\n registry.set(op, fallback as unknown as Fallback)\n}\n\n/** The registered fallback, or one that returns `undefined` for ops without an entry. */\nexport function getFallback(op: string): Fallback {\n return registry.get(op) ?? NONE\n}\n"],"mappings":";AAqBO,IAAM,WAAW;AAOjB,IAAM,SAAS;AAEtB,SAAS,QAAQ,GAAwB;AACvC,QAAM,MAAM,IAAI,YAAY,CAAC;AAC7B,WAAS,IAAI,GAAG,IAAI,GAAG,IAAK,KAAI,CAAC,IAAI;AACrC,SAAO;AACT;AAEA,IAAM,WAA4D;AAAA,EAChE,cAAc;AAAA,IACZ,UAAU;AAAA,IACV,OAAO,MAAM;AAAA,EACf;AAAA,EACA,oBAAoB,EAAE,UAAU,kCAAkC,OAAO,MAAM,OAAU;AAAA,EACzF,iBAAiB;AAAA,IACf,UAAU;AAAA,IACV,OAAO,MAAM;AAAA,EACf;AAAA,EACA,kBAAkB;AAAA,IAChB,UAAU;AAAA,IACV,OAAO,MAAM;AAAA,EACf;AAAA,EACA,eAAe;AAAA,IACb,UAAU;AAAA,IACV,OAAO,CAAC,QAAS,IAAI,KAAK,IAAI,QAAQ,KAAwC,CAAC;AAAA,EACjF;AAAA,EACA,gBAAgB;AAAA,IACd,UAAU;AAAA,IACV,OAAO,CAAC,QACL,IAAI,KAAK,IAAI,QAAQ,KAAiC,QAAQ,IAAI,MAAM,QAAQ;AAAA,EACrF;AAAA,EACA,iBAAiB;AAAA,IACf,UAAU;AAAA,IACV,OAAO,CAAC,QAAQ,IAAI,MAAM;AAAA,EAC5B;AAAA,EACA,gBAAgB;AAAA,IACd,UACE;AAAA,IAEF,OAAO,MAAM;AAAA,EACf;AAAA,EACA,iBAAiB;AAAA,IACf,UAAU;AAAA,IACV,OAAO,CAAC,QAAQ,QAAQ,QAAQ,IAAI,KAAK,IAAI,QAAQ,CAAC;AAAA,EACxD;AAAA,EACA,mBAAmB;AAAA,IACjB,UAAU;AAAA,IACV,QAAQ;AAAA,IACR,OAAO,MAAM;AAAA,EACf;AACF;AAEA,IAAM,OAAiB,EAAE,UAAU,oCAAoC,OAAO,MAAM,OAAU;AAE9F,IAAM,WAAW,IAAI,IAAsB,OAAO,QAAQ,QAAQ,CAAyB;AAMpF,SAAS,iBAAmC,IAAO,UAA6B;AACrF,WAAS,IAAI,IAAI,QAA+B;AAClD;AAGO,SAAS,YAAY,IAAsB;AAChD,SAAO,SAAS,IAAI,EAAE,KAAK;AAC7B;","names":[]}
1
+ {"version":3,"sources":["../../src/intercept/fallbacks.ts"],"sourcesContent":["import type { InterceptorContext } from './context'\nimport type { BuiltinOperations, OpName, OpResult } from './operations'\n\n/**\n * What the errorBoundary returns when an op fails (§3.4 registry table). `describe` becomes the\n * diagnostic's `impact`.\n */\nexport interface Fallback<O extends OpName = OpName> {\n readonly describe: string\n /**\n * Report without the diagnostics pipeline: one `console.error` per table. Used by\n * `diagnostic:emit`, where reporting through the pipeline could recurse.\n */\n readonly silent?: boolean\n value(ctx: InterceptorContext<O>): OpResult<O>\n}\n\n/**\n * `ctx.meta` key for a caller-supplied fallback value: the previous data (`data:ingest`), the last\n * good row model (`pipeline:run`), the previous results (`async:request`). Set it before `run`.\n */\nexport const FALLBACK = 'datakable:fallback'\n\n/**\n * `ctx.meta` key the errorBoundary sets (to the error) when it replaced the op's result with the\n * fallback, so the caller can tell a fallback from a real result (e.g. a failed `data:ingest` sets\n * `status: 'error'`, §6.6).\n */\nexport const FAILED = 'datakable:failed'\n\nfunction allRows(n: number): Uint32Array {\n const out = new Uint32Array(n)\n for (let i = 0; i < n; i++) out[i] = i\n return out\n}\n\nconst builtins: { [K in keyof BuiltinOperations]: Fallback<K> } = {\n // `describe`: prose keys (diagnostics/prose.ts); a plugin's own fallback may use plain text.\n 'table:init': { describe: 'init-continued', value: () => undefined },\n 'table:setOptions': { describe: 'options-kept', value: () => undefined },\n 'table:destroy': { describe: 'destroy-continued', value: () => undefined },\n 'state:dispatch': { describe: 'update-dropped', value: () => undefined },\n 'data:ingest': {\n describe: 'data-kept',\n value: (ctx) => (ctx.meta.get(FALLBACK) as readonly unknown[] | undefined) ?? [],\n },\n 'pipeline:run': {\n describe: 'row-model-kept',\n value: (ctx) =>\n (ctx.meta.get(FALLBACK) as Uint32Array | undefined) ?? allRows(ctx.input.rowCount),\n },\n 'pipeline:step': {\n describe: 'step-passthrough',\n value: (ctx) => ctx.input.indices,\n },\n 'column:batch': {\n describe: 'batch-fallback',\n value: () => undefined,\n },\n 'async:request': {\n describe: 'results-kept',\n value: (ctx) => Promise.resolve(ctx.meta.get(FALLBACK)),\n },\n 'diagnostic:emit': {\n describe: 'diagnostic-dropped',\n silent: true,\n value: () => undefined,\n },\n}\n\nconst NONE: Fallback = { describe: 'returned-undefined', value: () => undefined }\n\nconst registry = new Map<string, Fallback>(Object.entries(builtins) as [string, Fallback][])\n\n/**\n * Sets the fallback of an op (ops registered by plugins / `@datakable/react`). Process-wide like\n * the op registry; the last registration wins.\n */\nexport function registerFallback<O extends OpName>(op: O, fallback: Fallback<O>): void {\n registry.set(op, fallback as unknown as Fallback)\n}\n\n/** The registered fallback, or one that returns `undefined` for ops without an entry. */\nexport function getFallback(op: string): Fallback {\n return registry.get(op) ?? NONE\n}\n"],"mappings":";AAqBO,IAAM,WAAW;AAOjB,IAAM,SAAS;AAEtB,SAAS,QAAQ,GAAwB;AACvC,QAAM,MAAM,IAAI,YAAY,CAAC;AAC7B,WAAS,IAAI,GAAG,IAAI,GAAG,IAAK,KAAI,CAAC,IAAI;AACrC,SAAO;AACT;AAEA,IAAM,WAA4D;AAAA;AAAA,EAEhE,cAAc,EAAE,UAAU,kBAAkB,OAAO,MAAM,OAAU;AAAA,EACnE,oBAAoB,EAAE,UAAU,gBAAgB,OAAO,MAAM,OAAU;AAAA,EACvE,iBAAiB,EAAE,UAAU,qBAAqB,OAAO,MAAM,OAAU;AAAA,EACzE,kBAAkB,EAAE,UAAU,kBAAkB,OAAO,MAAM,OAAU;AAAA,EACvE,eAAe;AAAA,IACb,UAAU;AAAA,IACV,OAAO,CAAC,QAAS,IAAI,KAAK,IAAI,QAAQ,KAAwC,CAAC;AAAA,EACjF;AAAA,EACA,gBAAgB;AAAA,IACd,UAAU;AAAA,IACV,OAAO,CAAC,QACL,IAAI,KAAK,IAAI,QAAQ,KAAiC,QAAQ,IAAI,MAAM,QAAQ;AAAA,EACrF;AAAA,EACA,iBAAiB;AAAA,IACf,UAAU;AAAA,IACV,OAAO,CAAC,QAAQ,IAAI,MAAM;AAAA,EAC5B;AAAA,EACA,gBAAgB;AAAA,IACd,UAAU;AAAA,IACV,OAAO,MAAM;AAAA,EACf;AAAA,EACA,iBAAiB;AAAA,IACf,UAAU;AAAA,IACV,OAAO,CAAC,QAAQ,QAAQ,QAAQ,IAAI,KAAK,IAAI,QAAQ,CAAC;AAAA,EACxD;AAAA,EACA,mBAAmB;AAAA,IACjB,UAAU;AAAA,IACV,QAAQ;AAAA,IACR,OAAO,MAAM;AAAA,EACf;AACF;AAEA,IAAM,OAAiB,EAAE,UAAU,sBAAsB,OAAO,MAAM,OAAU;AAEhF,IAAM,WAAW,IAAI,IAAsB,OAAO,QAAQ,QAAQ,CAAyB;AAMpF,SAAS,iBAAmC,IAAO,UAA6B;AACrF,WAAS,IAAI,IAAI,QAA+B;AAClD;AAGO,SAAS,YAAY,IAAsB;AAChD,SAAO,SAAS,IAAI,EAAE,KAAK;AAC7B;","names":[]}
@@ -24,6 +24,7 @@ __export(runtime_exports, {
24
24
  });
25
25
  module.exports = __toCommonJS(runtime_exports);
26
26
  var import_build = require("../diagnostics/build.cjs");
27
+ var import_process_guard = require("../diagnostics/process-guard.cjs");
27
28
  var import_operations = require("./operations.cjs");
28
29
  var NOT_CALLED = 0;
29
30
  var CALLED = 1;
@@ -85,10 +86,10 @@ function createInterceptorRuntime(options = {}) {
85
86
  );
86
87
  }
87
88
  });
88
- const onHotWarning = options.onHotWarning ?? ((w) => {
89
+ const onHotWarning = process.env.NODE_ENV !== "production" ? options.onHotWarning ?? ((w) => {
89
90
  if (emit) emit("DK_HOT_INTERCEPTOR", { interceptor: w.interceptor.name, op: w.op });
90
91
  else console.warn(`[DataKable] ${w.message}`);
91
- });
92
+ }) : void 0;
92
93
  const report = (error, i, ctx) => {
93
94
  try {
94
95
  onError(error, i, ctx);
@@ -99,9 +100,9 @@ function createInterceptorRuntime(options = {}) {
99
100
  let list = [];
100
101
  let boundary;
101
102
  const chains = /* @__PURE__ */ new Map();
102
- const warned = /* @__PURE__ */ new WeakMap();
103
+ const warned = process.env.NODE_ENV !== "production" ? /* @__PURE__ */ new WeakMap() : void 0;
103
104
  function warnHot(i, op) {
104
- if (!(process.env.NODE_ENV !== "production")) return;
105
+ if (!(process.env.NODE_ENV !== "production") || !warned || !onHotWarning) return;
105
106
  let ops = warned.get(i);
106
107
  if (ops?.has(op)) return;
107
108
  if (!ops) {
@@ -121,7 +122,7 @@ function createInterceptorRuntime(options = {}) {
121
122
  function compile(op) {
122
123
  const info = (0, import_operations.getOperation)(op);
123
124
  if (!info) {
124
- throw (0, import_build.internalError)(op, `Unknown operation "${op}": register it with registerOperation()`);
125
+ throw (0, import_build.internalError)(op, `unknown-op|${op}`);
125
126
  }
126
127
  const mine = list.filter((i) => attaches(i, op));
127
128
  if (boundary && attaches(boundary, op)) mine.unshift(boundary);
@@ -151,10 +152,7 @@ function createInterceptorRuntime(options = {}) {
151
152
  setInterceptors,
152
153
  installBoundary(b) {
153
154
  if (boundary) {
154
- throw (0, import_build.internalError)(
155
- "*",
156
- `A boundary interceptor is already installed ("${boundary.name}"); "${b.name}" was rejected`
157
- );
155
+ throw (0, import_build.internalError)("*", `boundary-twice|${boundary.name}|${b.name}`);
158
156
  }
159
157
  boundary = b;
160
158
  compileAll();
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/intercept/runtime.ts"],"sourcesContent":["import { DatakableError, internalError } from '../diagnostics/build'\nimport type { Emit } from '../diagnostics/types'\nimport type { InterceptorContext } from './context'\nimport type { Interceptor } from './define'\nimport { getOperation, listOperations, type OpName, type OpResult } from './operations'\n\nexport type Core<O extends OpName> = (ctx: InterceptorContext<O>) => OpResult<O>\n\nexport interface HotOpWarning {\n interceptor: Interceptor<OpName>\n op: string\n message: string\n}\n\nexport interface InterceptorRuntimeOptions {\n interceptors?: readonly Interceptor<OpName>[]\n /**\n * The table's diagnostic emitter. When given, the default hooks below report through it:\n * `DK_INTERCEPTOR_FAILED` and (dev only) `DK_HOT_INTERCEPTOR`. Without it they use the console.\n */\n emit?: Emit\n /**\n * An interceptor threw (or its promise rejected); it was skipped. Overrides the default report\n * (`DK_INTERCEPTOR_FAILED` via `emit`, else console.error).\n */\n onInterceptorError?: (\n error: unknown,\n interceptor: Interceptor<OpName>,\n ctx: InterceptorContext,\n ) => void\n /**\n * An interceptor is attached to a hot op without `hot: true` (checked when the op's chain is\n * compiled, once per interceptor + op). Overrides the default (`DK_HOT_INTERCEPTOR` via `emit`).\n */\n onHotWarning?: (warning: HotOpWarning) => void\n /** Called each time a chain is compiled (tracing / tests). `length` counts the boundary too. */\n onCompile?: (op: string, length: number) => void\n}\n\nexport interface InterceptorRuntime {\n /** Runs `core` for `op` through the compiled chain. */\n run<O extends OpName>(op: O, ctx: InterceptorContext<O>, core: NoInfer<Core<O>>): OpResult<O>\n /** Replaces the user / feature interceptors and recompiles. The boundary slot is kept. */\n setInterceptors(interceptors: readonly Interceptor<OpName>[]): void\n /** Installs the outermost, non-removable interceptor (errorBoundary, T06). Once only. */\n installBoundary(boundary: Interceptor<OpName>): void\n}\n\ntype AnyCtx = InterceptorContext\ntype AnyCore = (ctx: AnyCtx) => unknown\ntype Chain = (ctx: AnyCtx, core: AnyCore) => unknown\n\nconst NOT_CALLED = 0\nconst CALLED = 1\nconst FAILED_INSIDE = 2\n\nconst direct: Chain = (ctx, core) => core(ctx)\n\nconst isThenable = (v: unknown): v is PromiseLike<unknown> =>\n v != null && typeof (v as { then?: unknown }).then === 'function'\n\nconst attaches = (i: Interceptor<OpName>, op: string) =>\n i.on === '*' || (i.on as readonly string[]).includes(op)\n\n/**\n * Wraps one interceptor around `inner`. Skip semantics (§3.4): if the interceptor throws before\n * calling `next`, `next` runs directly; if it throws after, the result `next` produced is kept so\n * the core never runs twice. An error that came out of `next` belongs to an inner layer and is\n * rethrown untouched. Async results get the same rules on rejection.\n */\nfunction wrap(\n i: Interceptor<OpName>,\n inner: Chain,\n mayBeAsync: boolean,\n report: (error: unknown, i: Interceptor<OpName>, ctx: AnyCtx) => void,\n): Chain {\n const intercept = i.intercept as (ctx: AnyCtx, next: () => unknown) => unknown\n return (ctx, core) => {\n let state = NOT_CALLED\n let out: unknown\n const next = () => {\n state = CALLED\n try {\n out = inner(ctx, core)\n } catch (e) {\n state = FAILED_INSIDE\n throw e\n }\n if (mayBeAsync && isThenable(out)) {\n const p = Promise.resolve(out).then(undefined, (e: unknown) => {\n state = FAILED_INSIDE\n throw e\n })\n // Handled here so an interceptor that drops `next()` never causes an unhandled rejection;\n // whoever awaits `p` still sees the rejection.\n p.catch(() => {})\n out = p\n }\n return out\n }\n const recover = (e: unknown) => {\n if (state === FAILED_INSIDE) throw e\n report(e, i, ctx)\n return state === CALLED ? out : inner(ctx, core)\n }\n let r: unknown\n try {\n r = intercept(ctx, next)\n } catch (e) {\n return recover(e)\n }\n return mayBeAsync && isThenable(r) ? Promise.resolve(r).then(undefined, recover) : r\n }\n}\n\nexport function createInterceptorRuntime(\n options: InterceptorRuntimeOptions = {},\n): InterceptorRuntime {\n const { emit, onCompile } = options\n const onError =\n options.onInterceptorError ??\n ((error: unknown, i: Interceptor<OpName>, ctx: AnyCtx) => {\n if (emit) {\n emit(\n 'DK_INTERCEPTOR_FAILED',\n { interceptor: i.name, op: ctx.op, slot: ctx.where },\n { cause: error, run: ctx.run, trigger: ctx.trigger, phase: ctx.phase },\n )\n } else {\n console.error(\n `[DataKable] interceptor \"${i.name}\" failed on ${ctx.op} and was skipped`,\n error,\n )\n }\n })\n const onHotWarning =\n options.onHotWarning ??\n ((w: HotOpWarning) => {\n if (emit) emit('DK_HOT_INTERCEPTOR', { interceptor: w.interceptor.name, op: w.op })\n else console.warn(`[DataKable] ${w.message}`)\n })\n const report = (error: unknown, i: Interceptor<OpName>, ctx: AnyCtx) => {\n try {\n onError(error, i, ctx)\n } catch (e) {\n // The reporter must never break the operation it reports on — except `strict: true`, whose\n // DatakableError is the requested behaviour.\n if (e instanceof DatakableError) throw e\n }\n }\n\n let list: readonly Interceptor<OpName>[] = []\n let boundary: Interceptor<OpName> | undefined\n const chains = new Map<string, Chain>()\n /** (interceptor, op) pairs already warned about, so recompiles do not repeat the warning. */\n const warned = new WeakMap<Interceptor<OpName>, Set<string>>()\n\n function warnHot(i: Interceptor<OpName>, op: string) {\n if (!(process.env.NODE_ENV !== \"production\")) return // dev-only warning: drops the text below from production bundles\n let ops = warned.get(i)\n if (ops?.has(op)) return\n if (!ops) {\n ops = new Set()\n warned.set(i, ops)\n }\n ops.add(op)\n try {\n onHotWarning({\n interceptor: i,\n op,\n message:\n `Interceptor \"${i.name}\" is attached to hot op \"${op}\" without hot: true. ` +\n // Measured by intercept/chain.bench.ts (Apple M4 Pro, Node 25.2.1). Inline here, inside\n // the (process.env.NODE_ENV !== \"production\")-only function, so production bundles carry none of it.\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 ' +\n 'body, which runs columns × pipeline runs times. ' +\n 'Never loop per cell inside it. Set hot: true to accept the cost, ' +\n 'or attach it to a cold op.',\n })\n } catch {\n // A warning must never break compilation.\n }\n }\n\n function compile(op: string): Chain {\n const info = getOperation(op)\n if (!info) {\n throw internalError(op, `Unknown operation \"${op}\": register it with registerOperation()`)\n }\n const mine = list.filter((i) => attaches(i, op))\n if (boundary && attaches(boundary, op)) mine.unshift(boundary)\n // Checked here, not when the list is set, so ops registered after creation are covered too.\n if ((process.env.NODE_ENV !== \"production\") && info.hot) for (const i of mine) if (!i.hot) warnHot(i, op)\n const mayBeAsync = info.kind !== 'sync'\n const chain = mine.reduceRight<Chain>((inner, i) => wrap(i, inner, mayBeAsync, report), direct)\n chains.set(op, chain)\n onCompile?.(op, mine.length)\n return chain\n }\n\n function compileAll() {\n chains.clear()\n for (const op of listOperations()) compile(op)\n }\n\n function setInterceptors(next: readonly Interceptor<OpName>[]) {\n list = [...next]\n compileAll()\n }\n\n setInterceptors(options.interceptors ?? [])\n\n return {\n run(op, ctx, core) {\n const chain = chains.get(op) ?? compile(op)\n return chain(ctx, core as AnyCore) as OpResult<typeof op>\n },\n setInterceptors,\n installBoundary(b) {\n if (boundary) {\n throw internalError(\n '*',\n `A boundary interceptor is already installed (\"${boundary.name}\"); ` +\n `\"${b.name}\" was rejected`,\n )\n }\n boundary = b\n compileAll()\n },\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAA8C;AAI9C,wBAAyE;AAgDzE,IAAM,aAAa;AACnB,IAAM,SAAS;AACf,IAAM,gBAAgB;AAEtB,IAAM,SAAgB,CAAC,KAAK,SAAS,KAAK,GAAG;AAE7C,IAAM,aAAa,CAAC,MAClB,KAAK,QAAQ,OAAQ,EAAyB,SAAS;AAEzD,IAAM,WAAW,CAAC,GAAwB,OACxC,EAAE,OAAO,OAAQ,EAAE,GAAyB,SAAS,EAAE;AAQzD,SAAS,KACP,GACA,OACA,YACA,QACO;AACP,QAAM,YAAY,EAAE;AACpB,SAAO,CAAC,KAAK,SAAS;AACpB,QAAI,QAAQ;AACZ,QAAI;AACJ,UAAM,OAAO,MAAM;AACjB,cAAQ;AACR,UAAI;AACF,cAAM,MAAM,KAAK,IAAI;AAAA,MACvB,SAAS,GAAG;AACV,gBAAQ;AACR,cAAM;AAAA,MACR;AACA,UAAI,cAAc,WAAW,GAAG,GAAG;AACjC,cAAM,IAAI,QAAQ,QAAQ,GAAG,EAAE,KAAK,QAAW,CAAC,MAAe;AAC7D,kBAAQ;AACR,gBAAM;AAAA,QACR,CAAC;AAGD,UAAE,MAAM,MAAM;AAAA,QAAC,CAAC;AAChB,cAAM;AAAA,MACR;AACA,aAAO;AAAA,IACT;AACA,UAAM,UAAU,CAAC,MAAe;AAC9B,UAAI,UAAU,cAAe,OAAM;AACnC,aAAO,GAAG,GAAG,GAAG;AAChB,aAAO,UAAU,SAAS,MAAM,MAAM,KAAK,IAAI;AAAA,IACjD;AACA,QAAI;AACJ,QAAI;AACF,UAAI,UAAU,KAAK,IAAI;AAAA,IACzB,SAAS,GAAG;AACV,aAAO,QAAQ,CAAC;AAAA,IAClB;AACA,WAAO,cAAc,WAAW,CAAC,IAAI,QAAQ,QAAQ,CAAC,EAAE,KAAK,QAAW,OAAO,IAAI;AAAA,EACrF;AACF;AAEO,SAAS,yBACd,UAAqC,CAAC,GAClB;AACpB,QAAM,EAAE,MAAM,UAAU,IAAI;AAC5B,QAAM,UACJ,QAAQ,uBACP,CAAC,OAAgB,GAAwB,QAAgB;AACxD,QAAI,MAAM;AACR;AAAA,QACE;AAAA,QACA,EAAE,aAAa,EAAE,MAAM,IAAI,IAAI,IAAI,MAAM,IAAI,MAAM;AAAA,QACnD,EAAE,OAAO,OAAO,KAAK,IAAI,KAAK,SAAS,IAAI,SAAS,OAAO,IAAI,MAAM;AAAA,MACvE;AAAA,IACF,OAAO;AACL,cAAQ;AAAA,QACN,4BAA4B,EAAE,IAAI,eAAe,IAAI,EAAE;AAAA,QACvD;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF,QAAM,eACJ,QAAQ,iBACP,CAAC,MAAoB;AACpB,QAAI,KAAM,MAAK,sBAAsB,EAAE,aAAa,EAAE,YAAY,MAAM,IAAI,EAAE,GAAG,CAAC;AAAA,QAC7E,SAAQ,KAAK,eAAe,EAAE,OAAO,EAAE;AAAA,EAC9C;AACF,QAAM,SAAS,CAAC,OAAgB,GAAwB,QAAgB;AACtE,QAAI;AACF,cAAQ,OAAO,GAAG,GAAG;AAAA,IACvB,SAAS,GAAG;AAGV,UAAI,aAAa,4BAAgB,OAAM;AAAA,IACzC;AAAA,EACF;AAEA,MAAI,OAAuC,CAAC;AAC5C,MAAI;AACJ,QAAM,SAAS,oBAAI,IAAmB;AAEtC,QAAM,SAAS,oBAAI,QAA0C;AAE7D,WAAS,QAAQ,GAAwB,IAAY;AACnD,QAAI,EAAE,QAAQ,IAAI,aAAa,cAAe;AAC9C,QAAI,MAAM,OAAO,IAAI,CAAC;AACtB,QAAI,KAAK,IAAI,EAAE,EAAG;AAClB,QAAI,CAAC,KAAK;AACR,YAAM,oBAAI,IAAI;AACd,aAAO,IAAI,GAAG,GAAG;AAAA,IACnB;AACA,QAAI,IAAI,EAAE;AACV,QAAI;AACF,mBAAa;AAAA,QACX,aAAa;AAAA,QACb;AAAA,QACA,SACE,gBAAgB,EAAE,IAAI,4BAA4B,EAAE;AAAA,MAQxD,CAAC;AAAA,IACH,QAAQ;AAAA,IAER;AAAA,EACF;AAEA,WAAS,QAAQ,IAAmB;AAClC,UAAM,WAAO,gCAAa,EAAE;AAC5B,QAAI,CAAC,MAAM;AACT,gBAAM,4BAAc,IAAI,sBAAsB,EAAE,yCAAyC;AAAA,IAC3F;AACA,UAAM,OAAO,KAAK,OAAO,CAAC,MAAM,SAAS,GAAG,EAAE,CAAC;AAC/C,QAAI,YAAY,SAAS,UAAU,EAAE,EAAG,MAAK,QAAQ,QAAQ;AAE7D,QAAK,QAAQ,IAAI,aAAa,gBAAiB,KAAK;AAAK,iBAAW,KAAK,KAAM,KAAI,CAAC,EAAE,IAAK,SAAQ,GAAG,EAAE;AAAA;AACxG,UAAM,aAAa,KAAK,SAAS;AACjC,UAAM,QAAQ,KAAK,YAAmB,CAAC,OAAO,MAAM,KAAK,GAAG,OAAO,YAAY,MAAM,GAAG,MAAM;AAC9F,WAAO,IAAI,IAAI,KAAK;AACpB,gBAAY,IAAI,KAAK,MAAM;AAC3B,WAAO;AAAA,EACT;AAEA,WAAS,aAAa;AACpB,WAAO,MAAM;AACb,eAAW,UAAM,kCAAe,EAAG,SAAQ,EAAE;AAAA,EAC/C;AAEA,WAAS,gBAAgB,MAAsC;AAC7D,WAAO,CAAC,GAAG,IAAI;AACf,eAAW;AAAA,EACb;AAEA,kBAAgB,QAAQ,gBAAgB,CAAC,CAAC;AAE1C,SAAO;AAAA,IACL,IAAI,IAAI,KAAK,MAAM;AACjB,YAAM,QAAQ,OAAO,IAAI,EAAE,KAAK,QAAQ,EAAE;AAC1C,aAAO,MAAM,KAAK,IAAe;AAAA,IACnC;AAAA,IACA;AAAA,IACA,gBAAgB,GAAG;AACjB,UAAI,UAAU;AACZ,kBAAM;AAAA,UACJ;AAAA,UACA,iDAAiD,SAAS,IAAI,QACxD,EAAE,IAAI;AAAA,QACd;AAAA,MACF;AACA,iBAAW;AACX,iBAAW;AAAA,IACb;AAAA,EACF;AACF;","names":[]}
1
+ {"version":3,"sources":["../../src/intercept/runtime.ts"],"sourcesContent":["import { DatakableError, internalError } from '../diagnostics/build'\nimport '../diagnostics/process-guard'\nimport type { Emit } from '../diagnostics/types'\nimport type { InterceptorContext } from './context'\nimport type { Interceptor } from './define'\nimport { getOperation, listOperations, type OpName, type OpResult } from './operations'\n\nexport type Core<O extends OpName> = (ctx: InterceptorContext<O>) => OpResult<O>\n\nexport interface HotOpWarning {\n interceptor: Interceptor<OpName>\n op: string\n message: string\n}\n\nexport interface InterceptorRuntimeOptions {\n interceptors?: readonly Interceptor<OpName>[]\n /**\n * The table's diagnostic emitter. When given, the default hooks below report through it:\n * `DK_INTERCEPTOR_FAILED` and (dev only) `DK_HOT_INTERCEPTOR`. Without it they use the console.\n */\n emit?: Emit\n /**\n * An interceptor threw (or its promise rejected); it was skipped. Overrides the default report\n * (`DK_INTERCEPTOR_FAILED` via `emit`, else console.error).\n */\n onInterceptorError?: (\n error: unknown,\n interceptor: Interceptor<OpName>,\n ctx: InterceptorContext,\n ) => void\n /**\n * An interceptor is attached to a hot op without `hot: true` (checked when the op's chain is\n * compiled, once per interceptor + op). Overrides the default (`DK_HOT_INTERCEPTOR` via `emit`).\n */\n onHotWarning?: (warning: HotOpWarning) => void\n /** Called each time a chain is compiled (tracing / tests). `length` counts the boundary too. */\n onCompile?: (op: string, length: number) => void\n}\n\nexport interface InterceptorRuntime {\n /** Runs `core` for `op` through the compiled chain. */\n run<O extends OpName>(op: O, ctx: InterceptorContext<O>, core: NoInfer<Core<O>>): OpResult<O>\n /** Replaces the user / feature interceptors and recompiles. The boundary slot is kept. */\n setInterceptors(interceptors: readonly Interceptor<OpName>[]): void\n /** Installs the outermost, non-removable interceptor (errorBoundary, T06). Once only. */\n installBoundary(boundary: Interceptor<OpName>): void\n}\n\ntype AnyCtx = InterceptorContext\ntype AnyCore = (ctx: AnyCtx) => unknown\ntype Chain = (ctx: AnyCtx, core: AnyCore) => unknown\n\nconst NOT_CALLED = 0\nconst CALLED = 1\nconst FAILED_INSIDE = 2\n\nconst direct: Chain = (ctx, core) => core(ctx)\n\nconst isThenable = (v: unknown): v is PromiseLike<unknown> =>\n v != null && typeof (v as { then?: unknown }).then === 'function'\n\nconst attaches = (i: Interceptor<OpName>, op: string) =>\n i.on === '*' || (i.on as readonly string[]).includes(op)\n\n/**\n * Wraps one interceptor around `inner`. Skip semantics (§3.4): if the interceptor throws before\n * calling `next`, `next` runs directly; if it throws after, the result `next` produced is kept so\n * the core never runs twice. An error that came out of `next` belongs to an inner layer and is\n * rethrown untouched. Async results get the same rules on rejection.\n */\nfunction wrap(\n i: Interceptor<OpName>,\n inner: Chain,\n mayBeAsync: boolean,\n report: (error: unknown, i: Interceptor<OpName>, ctx: AnyCtx) => void,\n): Chain {\n const intercept = i.intercept as (ctx: AnyCtx, next: () => unknown) => unknown\n return (ctx, core) => {\n let state = NOT_CALLED\n let out: unknown\n const next = () => {\n state = CALLED\n try {\n out = inner(ctx, core)\n } catch (e) {\n state = FAILED_INSIDE\n throw e\n }\n if (mayBeAsync && isThenable(out)) {\n const p = Promise.resolve(out).then(undefined, (e: unknown) => {\n state = FAILED_INSIDE\n throw e\n })\n // Handled here so an interceptor that drops `next()` never causes an unhandled rejection;\n // whoever awaits `p` still sees the rejection.\n p.catch(() => {})\n out = p\n }\n return out\n }\n const recover = (e: unknown) => {\n if (state === FAILED_INSIDE) throw e\n report(e, i, ctx)\n return state === CALLED ? out : inner(ctx, core)\n }\n let r: unknown\n try {\n r = intercept(ctx, next)\n } catch (e) {\n return recover(e)\n }\n return mayBeAsync && isThenable(r) ? Promise.resolve(r).then(undefined, recover) : r\n }\n}\n\nexport function createInterceptorRuntime(\n options: InterceptorRuntimeOptions = {},\n): InterceptorRuntime {\n const { emit, onCompile } = options\n const onError =\n options.onInterceptorError ??\n ((error: unknown, i: Interceptor<OpName>, ctx: AnyCtx) => {\n if (emit) {\n emit(\n 'DK_INTERCEPTOR_FAILED',\n { interceptor: i.name, op: ctx.op, slot: ctx.where },\n { cause: error, run: ctx.run, trigger: ctx.trigger, phase: ctx.phase },\n )\n } else {\n console.error(\n `[DataKable] interceptor \"${i.name}\" failed on ${ctx.op} and was skipped`,\n error,\n )\n }\n })\n // Dev-only (DK_HOT_INTERCEPTOR): `undefined` in production, with the code and its text.\n const onHotWarning = (process.env.NODE_ENV !== \"production\")\n ? (options.onHotWarning ??\n ((w: HotOpWarning) => {\n if (emit) emit('DK_HOT_INTERCEPTOR', { interceptor: w.interceptor.name, op: w.op })\n else console.warn(`[DataKable] ${w.message}`)\n }))\n : undefined\n const report = (error: unknown, i: Interceptor<OpName>, ctx: AnyCtx) => {\n try {\n onError(error, i, ctx)\n } catch (e) {\n // The reporter must never break the operation it reports on — except `strict: true`, whose\n // DatakableError is the requested behaviour.\n if (e instanceof DatakableError) throw e\n }\n }\n\n let list: readonly Interceptor<OpName>[] = []\n let boundary: Interceptor<OpName> | undefined\n const chains = new Map<string, Chain>()\n /** (interceptor, op) pairs already warned about, so recompiles do not repeat the warning. */\n const warned = (process.env.NODE_ENV !== \"production\") ? new WeakMap<Interceptor<OpName>, Set<string>>() : undefined\n\n function warnHot(i: Interceptor<OpName>, op: string) {\n if (!(process.env.NODE_ENV !== \"production\") || !warned || !onHotWarning) return // dev-only: production bundles drop the text below\n let ops = warned.get(i)\n if (ops?.has(op)) return\n if (!ops) {\n ops = new Set()\n warned.set(i, ops)\n }\n ops.add(op)\n try {\n onHotWarning({\n interceptor: i,\n op,\n message:\n `Interceptor \"${i.name}\" is attached to hot op \"${op}\" without hot: true. ` +\n // Measured by intercept/chain.bench.ts (Apple M4 Pro, Node 25.2.1). Inline here, inside\n // the (process.env.NODE_ENV !== \"production\")-only function, so production bundles carry none of it.\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 ' +\n 'body, which runs columns × pipeline runs times. ' +\n 'Never loop per cell inside it. Set hot: true to accept the cost, ' +\n 'or attach it to a cold op.',\n })\n } catch {\n // A warning must never break compilation.\n }\n }\n\n function compile(op: string): Chain {\n const info = getOperation(op)\n if (!info) {\n throw internalError(op, `unknown-op|${op}`)\n }\n const mine = list.filter((i) => attaches(i, op))\n if (boundary && attaches(boundary, op)) mine.unshift(boundary)\n // Checked here, not when the list is set, so ops registered after creation are covered too.\n if ((process.env.NODE_ENV !== \"production\") && info.hot) for (const i of mine) if (!i.hot) warnHot(i, op)\n const mayBeAsync = info.kind !== 'sync'\n const chain = mine.reduceRight<Chain>((inner, i) => wrap(i, inner, mayBeAsync, report), direct)\n chains.set(op, chain)\n onCompile?.(op, mine.length)\n return chain\n }\n\n function compileAll() {\n chains.clear()\n for (const op of listOperations()) compile(op)\n }\n\n function setInterceptors(next: readonly Interceptor<OpName>[]) {\n list = [...next]\n compileAll()\n }\n\n setInterceptors(options.interceptors ?? [])\n\n return {\n run(op, ctx, core) {\n const chain = chains.get(op) ?? compile(op)\n return chain(ctx, core as AnyCore) as OpResult<typeof op>\n },\n setInterceptors,\n installBoundary(b) {\n if (boundary) {\n throw internalError('*', `boundary-twice|${boundary.name}|${b.name}`)\n }\n boundary = b\n compileAll()\n },\n }\n}\n"],"mappings":"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","names":[]}
@@ -1,5 +1,6 @@
1
1
  // src/intercept/runtime.ts
2
2
  import { DatakableError, internalError } from "../diagnostics/build.js";
3
+ import "../diagnostics/process-guard.js";
3
4
  import { getOperation, listOperations } from "./operations.js";
4
5
  var NOT_CALLED = 0;
5
6
  var CALLED = 1;
@@ -61,10 +62,10 @@ function createInterceptorRuntime(options = {}) {
61
62
  );
62
63
  }
63
64
  });
64
- const onHotWarning = options.onHotWarning ?? ((w) => {
65
+ const onHotWarning = process.env.NODE_ENV !== "production" ? options.onHotWarning ?? ((w) => {
65
66
  if (emit) emit("DK_HOT_INTERCEPTOR", { interceptor: w.interceptor.name, op: w.op });
66
67
  else console.warn(`[DataKable] ${w.message}`);
67
- });
68
+ }) : void 0;
68
69
  const report = (error, i, ctx) => {
69
70
  try {
70
71
  onError(error, i, ctx);
@@ -75,9 +76,9 @@ function createInterceptorRuntime(options = {}) {
75
76
  let list = [];
76
77
  let boundary;
77
78
  const chains = /* @__PURE__ */ new Map();
78
- const warned = /* @__PURE__ */ new WeakMap();
79
+ const warned = process.env.NODE_ENV !== "production" ? /* @__PURE__ */ new WeakMap() : void 0;
79
80
  function warnHot(i, op) {
80
- if (!(process.env.NODE_ENV !== "production")) return;
81
+ if (!(process.env.NODE_ENV !== "production") || !warned || !onHotWarning) return;
81
82
  let ops = warned.get(i);
82
83
  if (ops?.has(op)) return;
83
84
  if (!ops) {
@@ -97,7 +98,7 @@ function createInterceptorRuntime(options = {}) {
97
98
  function compile(op) {
98
99
  const info = getOperation(op);
99
100
  if (!info) {
100
- throw internalError(op, `Unknown operation "${op}": register it with registerOperation()`);
101
+ throw internalError(op, `unknown-op|${op}`);
101
102
  }
102
103
  const mine = list.filter((i) => attaches(i, op));
103
104
  if (boundary && attaches(boundary, op)) mine.unshift(boundary);
@@ -127,10 +128,7 @@ function createInterceptorRuntime(options = {}) {
127
128
  setInterceptors,
128
129
  installBoundary(b) {
129
130
  if (boundary) {
130
- throw internalError(
131
- "*",
132
- `A boundary interceptor is already installed ("${boundary.name}"); "${b.name}" was rejected`
133
- );
131
+ throw internalError("*", `boundary-twice|${boundary.name}|${b.name}`);
134
132
  }
135
133
  boundary = b;
136
134
  compileAll();
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/intercept/runtime.ts"],"sourcesContent":["import { DatakableError, internalError } from '../diagnostics/build'\nimport type { Emit } from '../diagnostics/types'\nimport type { InterceptorContext } from './context'\nimport type { Interceptor } from './define'\nimport { getOperation, listOperations, type OpName, type OpResult } from './operations'\n\nexport type Core<O extends OpName> = (ctx: InterceptorContext<O>) => OpResult<O>\n\nexport interface HotOpWarning {\n interceptor: Interceptor<OpName>\n op: string\n message: string\n}\n\nexport interface InterceptorRuntimeOptions {\n interceptors?: readonly Interceptor<OpName>[]\n /**\n * The table's diagnostic emitter. When given, the default hooks below report through it:\n * `DK_INTERCEPTOR_FAILED` and (dev only) `DK_HOT_INTERCEPTOR`. Without it they use the console.\n */\n emit?: Emit\n /**\n * An interceptor threw (or its promise rejected); it was skipped. Overrides the default report\n * (`DK_INTERCEPTOR_FAILED` via `emit`, else console.error).\n */\n onInterceptorError?: (\n error: unknown,\n interceptor: Interceptor<OpName>,\n ctx: InterceptorContext,\n ) => void\n /**\n * An interceptor is attached to a hot op without `hot: true` (checked when the op's chain is\n * compiled, once per interceptor + op). Overrides the default (`DK_HOT_INTERCEPTOR` via `emit`).\n */\n onHotWarning?: (warning: HotOpWarning) => void\n /** Called each time a chain is compiled (tracing / tests). `length` counts the boundary too. */\n onCompile?: (op: string, length: number) => void\n}\n\nexport interface InterceptorRuntime {\n /** Runs `core` for `op` through the compiled chain. */\n run<O extends OpName>(op: O, ctx: InterceptorContext<O>, core: NoInfer<Core<O>>): OpResult<O>\n /** Replaces the user / feature interceptors and recompiles. The boundary slot is kept. */\n setInterceptors(interceptors: readonly Interceptor<OpName>[]): void\n /** Installs the outermost, non-removable interceptor (errorBoundary, T06). Once only. */\n installBoundary(boundary: Interceptor<OpName>): void\n}\n\ntype AnyCtx = InterceptorContext\ntype AnyCore = (ctx: AnyCtx) => unknown\ntype Chain = (ctx: AnyCtx, core: AnyCore) => unknown\n\nconst NOT_CALLED = 0\nconst CALLED = 1\nconst FAILED_INSIDE = 2\n\nconst direct: Chain = (ctx, core) => core(ctx)\n\nconst isThenable = (v: unknown): v is PromiseLike<unknown> =>\n v != null && typeof (v as { then?: unknown }).then === 'function'\n\nconst attaches = (i: Interceptor<OpName>, op: string) =>\n i.on === '*' || (i.on as readonly string[]).includes(op)\n\n/**\n * Wraps one interceptor around `inner`. Skip semantics (§3.4): if the interceptor throws before\n * calling `next`, `next` runs directly; if it throws after, the result `next` produced is kept so\n * the core never runs twice. An error that came out of `next` belongs to an inner layer and is\n * rethrown untouched. Async results get the same rules on rejection.\n */\nfunction wrap(\n i: Interceptor<OpName>,\n inner: Chain,\n mayBeAsync: boolean,\n report: (error: unknown, i: Interceptor<OpName>, ctx: AnyCtx) => void,\n): Chain {\n const intercept = i.intercept as (ctx: AnyCtx, next: () => unknown) => unknown\n return (ctx, core) => {\n let state = NOT_CALLED\n let out: unknown\n const next = () => {\n state = CALLED\n try {\n out = inner(ctx, core)\n } catch (e) {\n state = FAILED_INSIDE\n throw e\n }\n if (mayBeAsync && isThenable(out)) {\n const p = Promise.resolve(out).then(undefined, (e: unknown) => {\n state = FAILED_INSIDE\n throw e\n })\n // Handled here so an interceptor that drops `next()` never causes an unhandled rejection;\n // whoever awaits `p` still sees the rejection.\n p.catch(() => {})\n out = p\n }\n return out\n }\n const recover = (e: unknown) => {\n if (state === FAILED_INSIDE) throw e\n report(e, i, ctx)\n return state === CALLED ? out : inner(ctx, core)\n }\n let r: unknown\n try {\n r = intercept(ctx, next)\n } catch (e) {\n return recover(e)\n }\n return mayBeAsync && isThenable(r) ? Promise.resolve(r).then(undefined, recover) : r\n }\n}\n\nexport function createInterceptorRuntime(\n options: InterceptorRuntimeOptions = {},\n): InterceptorRuntime {\n const { emit, onCompile } = options\n const onError =\n options.onInterceptorError ??\n ((error: unknown, i: Interceptor<OpName>, ctx: AnyCtx) => {\n if (emit) {\n emit(\n 'DK_INTERCEPTOR_FAILED',\n { interceptor: i.name, op: ctx.op, slot: ctx.where },\n { cause: error, run: ctx.run, trigger: ctx.trigger, phase: ctx.phase },\n )\n } else {\n console.error(\n `[DataKable] interceptor \"${i.name}\" failed on ${ctx.op} and was skipped`,\n error,\n )\n }\n })\n const onHotWarning =\n options.onHotWarning ??\n ((w: HotOpWarning) => {\n if (emit) emit('DK_HOT_INTERCEPTOR', { interceptor: w.interceptor.name, op: w.op })\n else console.warn(`[DataKable] ${w.message}`)\n })\n const report = (error: unknown, i: Interceptor<OpName>, ctx: AnyCtx) => {\n try {\n onError(error, i, ctx)\n } catch (e) {\n // The reporter must never break the operation it reports on — except `strict: true`, whose\n // DatakableError is the requested behaviour.\n if (e instanceof DatakableError) throw e\n }\n }\n\n let list: readonly Interceptor<OpName>[] = []\n let boundary: Interceptor<OpName> | undefined\n const chains = new Map<string, Chain>()\n /** (interceptor, op) pairs already warned about, so recompiles do not repeat the warning. */\n const warned = new WeakMap<Interceptor<OpName>, Set<string>>()\n\n function warnHot(i: Interceptor<OpName>, op: string) {\n if (!(process.env.NODE_ENV !== \"production\")) return // dev-only warning: drops the text below from production bundles\n let ops = warned.get(i)\n if (ops?.has(op)) return\n if (!ops) {\n ops = new Set()\n warned.set(i, ops)\n }\n ops.add(op)\n try {\n onHotWarning({\n interceptor: i,\n op,\n message:\n `Interceptor \"${i.name}\" is attached to hot op \"${op}\" without hot: true. ` +\n // Measured by intercept/chain.bench.ts (Apple M4 Pro, Node 25.2.1). Inline here, inside\n // the (process.env.NODE_ENV !== \"production\")-only function, so production bundles carry none of it.\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 ' +\n 'body, which runs columns × pipeline runs times. ' +\n 'Never loop per cell inside it. Set hot: true to accept the cost, ' +\n 'or attach it to a cold op.',\n })\n } catch {\n // A warning must never break compilation.\n }\n }\n\n function compile(op: string): Chain {\n const info = getOperation(op)\n if (!info) {\n throw internalError(op, `Unknown operation \"${op}\": register it with registerOperation()`)\n }\n const mine = list.filter((i) => attaches(i, op))\n if (boundary && attaches(boundary, op)) mine.unshift(boundary)\n // Checked here, not when the list is set, so ops registered after creation are covered too.\n if ((process.env.NODE_ENV !== \"production\") && info.hot) for (const i of mine) if (!i.hot) warnHot(i, op)\n const mayBeAsync = info.kind !== 'sync'\n const chain = mine.reduceRight<Chain>((inner, i) => wrap(i, inner, mayBeAsync, report), direct)\n chains.set(op, chain)\n onCompile?.(op, mine.length)\n return chain\n }\n\n function compileAll() {\n chains.clear()\n for (const op of listOperations()) compile(op)\n }\n\n function setInterceptors(next: readonly Interceptor<OpName>[]) {\n list = [...next]\n compileAll()\n }\n\n setInterceptors(options.interceptors ?? [])\n\n return {\n run(op, ctx, core) {\n const chain = chains.get(op) ?? compile(op)\n return chain(ctx, core as AnyCore) as OpResult<typeof op>\n },\n setInterceptors,\n installBoundary(b) {\n if (boundary) {\n throw internalError(\n '*',\n `A boundary interceptor is already installed (\"${boundary.name}\"); ` +\n `\"${b.name}\" was rejected`,\n )\n }\n boundary = b\n compileAll()\n },\n }\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/intercept/runtime.ts"],"sourcesContent":["import { DatakableError, internalError } from '../diagnostics/build'\nimport '../diagnostics/process-guard'\nimport type { Emit } from '../diagnostics/types'\nimport type { InterceptorContext } from './context'\nimport type { Interceptor } from './define'\nimport { getOperation, listOperations, type OpName, type OpResult } from './operations'\n\nexport type Core<O extends OpName> = (ctx: InterceptorContext<O>) => OpResult<O>\n\nexport interface HotOpWarning {\n interceptor: Interceptor<OpName>\n op: string\n message: string\n}\n\nexport interface InterceptorRuntimeOptions {\n interceptors?: readonly Interceptor<OpName>[]\n /**\n * The table's diagnostic emitter. When given, the default hooks below report through it:\n * `DK_INTERCEPTOR_FAILED` and (dev only) `DK_HOT_INTERCEPTOR`. Without it they use the console.\n */\n emit?: Emit\n /**\n * An interceptor threw (or its promise rejected); it was skipped. Overrides the default report\n * (`DK_INTERCEPTOR_FAILED` via `emit`, else console.error).\n */\n onInterceptorError?: (\n error: unknown,\n interceptor: Interceptor<OpName>,\n ctx: InterceptorContext,\n ) => void\n /**\n * An interceptor is attached to a hot op without `hot: true` (checked when the op's chain is\n * compiled, once per interceptor + op). Overrides the default (`DK_HOT_INTERCEPTOR` via `emit`).\n */\n onHotWarning?: (warning: HotOpWarning) => void\n /** Called each time a chain is compiled (tracing / tests). `length` counts the boundary too. */\n onCompile?: (op: string, length: number) => void\n}\n\nexport interface InterceptorRuntime {\n /** Runs `core` for `op` through the compiled chain. */\n run<O extends OpName>(op: O, ctx: InterceptorContext<O>, core: NoInfer<Core<O>>): OpResult<O>\n /** Replaces the user / feature interceptors and recompiles. The boundary slot is kept. */\n setInterceptors(interceptors: readonly Interceptor<OpName>[]): void\n /** Installs the outermost, non-removable interceptor (errorBoundary, T06). Once only. */\n installBoundary(boundary: Interceptor<OpName>): void\n}\n\ntype AnyCtx = InterceptorContext\ntype AnyCore = (ctx: AnyCtx) => unknown\ntype Chain = (ctx: AnyCtx, core: AnyCore) => unknown\n\nconst NOT_CALLED = 0\nconst CALLED = 1\nconst FAILED_INSIDE = 2\n\nconst direct: Chain = (ctx, core) => core(ctx)\n\nconst isThenable = (v: unknown): v is PromiseLike<unknown> =>\n v != null && typeof (v as { then?: unknown }).then === 'function'\n\nconst attaches = (i: Interceptor<OpName>, op: string) =>\n i.on === '*' || (i.on as readonly string[]).includes(op)\n\n/**\n * Wraps one interceptor around `inner`. Skip semantics (§3.4): if the interceptor throws before\n * calling `next`, `next` runs directly; if it throws after, the result `next` produced is kept so\n * the core never runs twice. An error that came out of `next` belongs to an inner layer and is\n * rethrown untouched. Async results get the same rules on rejection.\n */\nfunction wrap(\n i: Interceptor<OpName>,\n inner: Chain,\n mayBeAsync: boolean,\n report: (error: unknown, i: Interceptor<OpName>, ctx: AnyCtx) => void,\n): Chain {\n const intercept = i.intercept as (ctx: AnyCtx, next: () => unknown) => unknown\n return (ctx, core) => {\n let state = NOT_CALLED\n let out: unknown\n const next = () => {\n state = CALLED\n try {\n out = inner(ctx, core)\n } catch (e) {\n state = FAILED_INSIDE\n throw e\n }\n if (mayBeAsync && isThenable(out)) {\n const p = Promise.resolve(out).then(undefined, (e: unknown) => {\n state = FAILED_INSIDE\n throw e\n })\n // Handled here so an interceptor that drops `next()` never causes an unhandled rejection;\n // whoever awaits `p` still sees the rejection.\n p.catch(() => {})\n out = p\n }\n return out\n }\n const recover = (e: unknown) => {\n if (state === FAILED_INSIDE) throw e\n report(e, i, ctx)\n return state === CALLED ? out : inner(ctx, core)\n }\n let r: unknown\n try {\n r = intercept(ctx, next)\n } catch (e) {\n return recover(e)\n }\n return mayBeAsync && isThenable(r) ? Promise.resolve(r).then(undefined, recover) : r\n }\n}\n\nexport function createInterceptorRuntime(\n options: InterceptorRuntimeOptions = {},\n): InterceptorRuntime {\n const { emit, onCompile } = options\n const onError =\n options.onInterceptorError ??\n ((error: unknown, i: Interceptor<OpName>, ctx: AnyCtx) => {\n if (emit) {\n emit(\n 'DK_INTERCEPTOR_FAILED',\n { interceptor: i.name, op: ctx.op, slot: ctx.where },\n { cause: error, run: ctx.run, trigger: ctx.trigger, phase: ctx.phase },\n )\n } else {\n console.error(\n `[DataKable] interceptor \"${i.name}\" failed on ${ctx.op} and was skipped`,\n error,\n )\n }\n })\n // Dev-only (DK_HOT_INTERCEPTOR): `undefined` in production, with the code and its text.\n const onHotWarning = (process.env.NODE_ENV !== \"production\")\n ? (options.onHotWarning ??\n ((w: HotOpWarning) => {\n if (emit) emit('DK_HOT_INTERCEPTOR', { interceptor: w.interceptor.name, op: w.op })\n else console.warn(`[DataKable] ${w.message}`)\n }))\n : undefined\n const report = (error: unknown, i: Interceptor<OpName>, ctx: AnyCtx) => {\n try {\n onError(error, i, ctx)\n } catch (e) {\n // The reporter must never break the operation it reports on — except `strict: true`, whose\n // DatakableError is the requested behaviour.\n if (e instanceof DatakableError) throw e\n }\n }\n\n let list: readonly Interceptor<OpName>[] = []\n let boundary: Interceptor<OpName> | undefined\n const chains = new Map<string, Chain>()\n /** (interceptor, op) pairs already warned about, so recompiles do not repeat the warning. */\n const warned = (process.env.NODE_ENV !== \"production\") ? new WeakMap<Interceptor<OpName>, Set<string>>() : undefined\n\n function warnHot(i: Interceptor<OpName>, op: string) {\n if (!(process.env.NODE_ENV !== \"production\") || !warned || !onHotWarning) return // dev-only: production bundles drop the text below\n let ops = warned.get(i)\n if (ops?.has(op)) return\n if (!ops) {\n ops = new Set()\n warned.set(i, ops)\n }\n ops.add(op)\n try {\n onHotWarning({\n interceptor: i,\n op,\n message:\n `Interceptor \"${i.name}\" is attached to hot op \"${op}\" without hot: true. ` +\n // Measured by intercept/chain.bench.ts (Apple M4 Pro, Node 25.2.1). Inline here, inside\n // the (process.env.NODE_ENV !== \"production\")-only function, so production bundles carry none of it.\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 ' +\n 'body, which runs columns × pipeline runs times. ' +\n 'Never loop per cell inside it. Set hot: true to accept the cost, ' +\n 'or attach it to a cold op.',\n })\n } catch {\n // A warning must never break compilation.\n }\n }\n\n function compile(op: string): Chain {\n const info = getOperation(op)\n if (!info) {\n throw internalError(op, `unknown-op|${op}`)\n }\n const mine = list.filter((i) => attaches(i, op))\n if (boundary && attaches(boundary, op)) mine.unshift(boundary)\n // Checked here, not when the list is set, so ops registered after creation are covered too.\n if ((process.env.NODE_ENV !== \"production\") && info.hot) for (const i of mine) if (!i.hot) warnHot(i, op)\n const mayBeAsync = info.kind !== 'sync'\n const chain = mine.reduceRight<Chain>((inner, i) => wrap(i, inner, mayBeAsync, report), direct)\n chains.set(op, chain)\n onCompile?.(op, mine.length)\n return chain\n }\n\n function compileAll() {\n chains.clear()\n for (const op of listOperations()) compile(op)\n }\n\n function setInterceptors(next: readonly Interceptor<OpName>[]) {\n list = [...next]\n compileAll()\n }\n\n setInterceptors(options.interceptors ?? [])\n\n return {\n run(op, ctx, core) {\n const chain = chains.get(op) ?? compile(op)\n return chain(ctx, core as AnyCore) as OpResult<typeof op>\n },\n setInterceptors,\n installBoundary(b) {\n if (boundary) {\n throw internalError('*', `boundary-twice|${boundary.name}|${b.name}`)\n }\n boundary = b\n compileAll()\n },\n }\n}\n"],"mappings":"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","names":[]}
@@ -26,6 +26,7 @@ module.exports = __toCommonJS(messages_exports);
26
26
  var import_codes = require("../catalog/codes.cjs");
27
27
  var import_catalog = require("../diagnostics/catalog.cjs");
28
28
  var import_codes2 = require("../diagnostics/codes.cjs");
29
+ var import_prose = require("../diagnostics/prose.cjs");
29
30
  var import_redact = require("../diagnostics/redact.cjs");
30
31
  var import_codes3 = require("../feature/codes.cjs");
31
32
  var import_codes4 = require("../features/column-filters/codes.cjs");
@@ -64,7 +65,9 @@ var allMessages = [
64
65
  import_codes6.searchMessages,
65
66
  import_codes7.sortingMessages,
66
67
  import_codes5.paginationMessages,
67
- import_env_codes.envMessages
68
+ import_env_codes.envMessages,
69
+ // The detail sentences production keeps as keys (`fallback: 'cells-undefined'`).
70
+ import_prose.proseMessages
68
71
  ];
69
72
  (0, import_catalog.installMessages)(...allMessages);
70
73
  // Annotate the CommonJS export names for ESM import in node:
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/messages/index.ts"],"sourcesContent":["/**\n * `@datakable/core/messages` (`datakable/messages`): full diagnostic text in production (§8.2).\n *\n * Production builds strip `problem` / `impact` / `fix` and keep `code`, `where`, `context` and a\n * docs URL. `import '@datakable/core/messages'` once (e.g. in the app entry) installs the text of\n * every code a production build can emit. Development builds already have it. This module is the\n * package's only side effect (`sideEffects` in package.json).\n */\nimport { optionMessages } from '../catalog/codes'\nimport { installMessages } from '../diagnostics/catalog'\nimport { coreMessages } from '../diagnostics/codes'\nimport { redactionMessages } from '../diagnostics/redact'\nimport { featureMessages } from '../feature/codes'\nimport { columnFiltersMessages } from '../features/column-filters/codes'\nimport { paginationMessages } from '../features/pagination/codes'\nimport { searchMessages } from '../features/search/codes'\nimport { sortingMessages } from '../features/sorting/codes'\nimport { validityMessages } from '../features/validity/codes'\nimport { dataCheckMessages } from '../ingest/data-check-codes'\nimport { rowKeyMessages } from '../ingest/row-key-codes'\nimport { schemaMessages } from '../ingest/schema-codes'\nimport { boundaryMessages } from '../intercept/codes'\nimport { pipelineMessages } from '../pipeline/codes'\nimport { envMessages } from '../pipeline/env-codes'\nimport { asyncMessages } from '../source/codes'\nimport { fetchMessages } from '../source/fetch-codes'\nimport { tableMessages } from '../table/codes'\nimport { ssrMessages } from '../table/ssr-codes'\nimport { versioningMessages } from '../versioning/codes'\n\n/** Every message object core ships, one per module that owns codes. */\nexport const allMessages: ReadonlyArray<Readonly<Record<string, unknown>>> = [\n coreMessages,\n redactionMessages,\n optionMessages,\n featureMessages,\n boundaryMessages,\n pipelineMessages,\n tableMessages,\n ssrMessages,\n asyncMessages,\n fetchMessages,\n rowKeyMessages,\n schemaMessages,\n dataCheckMessages,\n versioningMessages,\n columnFiltersMessages,\n validityMessages,\n searchMessages,\n sortingMessages,\n paginationMessages,\n envMessages,\n]\n\ninstallMessages(...allMessages)\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA,mBAA+B;AAC/B,qBAAgC;AAChC,IAAAA,gBAA6B;AAC7B,oBAAkC;AAClC,IAAAA,gBAAgC;AAChC,IAAAA,gBAAsC;AACtC,IAAAA,gBAAmC;AACnC,IAAAA,gBAA+B;AAC/B,IAAAA,gBAAgC;AAChC,IAAAA,gBAAiC;AACjC,8BAAkC;AAClC,2BAA+B;AAC/B,0BAA+B;AAC/B,IAAAA,gBAAiC;AACjC,IAAAA,iBAAiC;AACjC,uBAA4B;AAC5B,IAAAA,iBAA8B;AAC9B,yBAA8B;AAC9B,IAAAA,iBAA8B;AAC9B,uBAA4B;AAC5B,IAAAA,iBAAmC;AAG5B,IAAM,cAAgE;AAAA,EAC3E;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAAA,IAEA,gCAAgB,GAAG,WAAW;","names":["import_codes"]}
1
+ {"version":3,"sources":["../../src/messages/index.ts"],"sourcesContent":["/**\n * `@datakable/core/messages` (`datakable/messages`): full diagnostic text in production (§8.2).\n *\n * Production builds strip `problem` / `impact` / `fix` and keep `code`, `where`, `context` and a\n * docs URL. `import '@datakable/core/messages'` once (e.g. in the app entry) installs the text of\n * every code a production build can emit. Development builds already have it. This module is the\n * package's only side effect (`sideEffects` in package.json).\n */\nimport { optionMessages } from '../catalog/codes'\nimport { installMessages } from '../diagnostics/catalog'\nimport { coreMessages } from '../diagnostics/codes'\nimport { proseMessages } from '../diagnostics/prose'\nimport { redactionMessages } from '../diagnostics/redact'\nimport { featureMessages } from '../feature/codes'\nimport { columnFiltersMessages } from '../features/column-filters/codes'\nimport { paginationMessages } from '../features/pagination/codes'\nimport { searchMessages } from '../features/search/codes'\nimport { sortingMessages } from '../features/sorting/codes'\nimport { validityMessages } from '../features/validity/codes'\nimport { dataCheckMessages } from '../ingest/data-check-codes'\nimport { rowKeyMessages } from '../ingest/row-key-codes'\nimport { schemaMessages } from '../ingest/schema-codes'\nimport { boundaryMessages } from '../intercept/codes'\nimport { pipelineMessages } from '../pipeline/codes'\nimport { envMessages } from '../pipeline/env-codes'\nimport { asyncMessages } from '../source/codes'\nimport { fetchMessages } from '../source/fetch-codes'\nimport { tableMessages } from '../table/codes'\nimport { ssrMessages } from '../table/ssr-codes'\nimport { versioningMessages } from '../versioning/codes'\n\n/** Every message object core ships, one per module that owns codes. */\nexport const allMessages: ReadonlyArray<Readonly<Record<string, unknown>>> = [\n coreMessages,\n redactionMessages,\n optionMessages,\n featureMessages,\n boundaryMessages,\n pipelineMessages,\n tableMessages,\n ssrMessages,\n asyncMessages,\n fetchMessages,\n rowKeyMessages,\n schemaMessages,\n dataCheckMessages,\n versioningMessages,\n columnFiltersMessages,\n validityMessages,\n searchMessages,\n sortingMessages,\n paginationMessages,\n envMessages,\n // The detail sentences production keeps as keys (`fallback: 'cells-undefined'`).\n proseMessages,\n]\n\ninstallMessages(...allMessages)\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA,mBAA+B;AAC/B,qBAAgC;AAChC,IAAAA,gBAA6B;AAC7B,mBAA8B;AAC9B,oBAAkC;AAClC,IAAAA,gBAAgC;AAChC,IAAAA,gBAAsC;AACtC,IAAAA,gBAAmC;AACnC,IAAAA,gBAA+B;AAC/B,IAAAA,gBAAgC;AAChC,IAAAA,gBAAiC;AACjC,8BAAkC;AAClC,2BAA+B;AAC/B,0BAA+B;AAC/B,IAAAA,gBAAiC;AACjC,IAAAA,iBAAiC;AACjC,uBAA4B;AAC5B,IAAAA,iBAA8B;AAC9B,yBAA8B;AAC9B,IAAAA,iBAA8B;AAC9B,uBAA4B;AAC5B,IAAAA,iBAAmC;AAG5B,IAAM,cAAgE;AAAA,EAC3E;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAEA;AACF;AAAA,IAEA,gCAAgB,GAAG,WAAW;","names":["import_codes"]}
@@ -2,6 +2,7 @@
2
2
  import { optionMessages } from "../catalog/codes.js";
3
3
  import { installMessages } from "../diagnostics/catalog.js";
4
4
  import { coreMessages } from "../diagnostics/codes.js";
5
+ import { proseMessages } from "../diagnostics/prose.js";
5
6
  import { redactionMessages } from "../diagnostics/redact.js";
6
7
  import { featureMessages } from "../feature/codes.js";
7
8
  import { columnFiltersMessages } from "../features/column-filters/codes.js";
@@ -40,7 +41,9 @@ var allMessages = [
40
41
  searchMessages,
41
42
  sortingMessages,
42
43
  paginationMessages,
43
- envMessages
44
+ envMessages,
45
+ // The detail sentences production keeps as keys (`fallback: 'cells-undefined'`).
46
+ proseMessages
44
47
  ];
45
48
  installMessages(...allMessages);
46
49
  export {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/messages/index.ts"],"sourcesContent":["/**\n * `@datakable/core/messages` (`datakable/messages`): full diagnostic text in production (§8.2).\n *\n * Production builds strip `problem` / `impact` / `fix` and keep `code`, `where`, `context` and a\n * docs URL. `import '@datakable/core/messages'` once (e.g. in the app entry) installs the text of\n * every code a production build can emit. Development builds already have it. This module is the\n * package's only side effect (`sideEffects` in package.json).\n */\nimport { optionMessages } from '../catalog/codes'\nimport { installMessages } from '../diagnostics/catalog'\nimport { coreMessages } from '../diagnostics/codes'\nimport { redactionMessages } from '../diagnostics/redact'\nimport { featureMessages } from '../feature/codes'\nimport { columnFiltersMessages } from '../features/column-filters/codes'\nimport { paginationMessages } from '../features/pagination/codes'\nimport { searchMessages } from '../features/search/codes'\nimport { sortingMessages } from '../features/sorting/codes'\nimport { validityMessages } from '../features/validity/codes'\nimport { dataCheckMessages } from '../ingest/data-check-codes'\nimport { rowKeyMessages } from '../ingest/row-key-codes'\nimport { schemaMessages } from '../ingest/schema-codes'\nimport { boundaryMessages } from '../intercept/codes'\nimport { pipelineMessages } from '../pipeline/codes'\nimport { envMessages } from '../pipeline/env-codes'\nimport { asyncMessages } from '../source/codes'\nimport { fetchMessages } from '../source/fetch-codes'\nimport { tableMessages } from '../table/codes'\nimport { ssrMessages } from '../table/ssr-codes'\nimport { versioningMessages } from '../versioning/codes'\n\n/** Every message object core ships, one per module that owns codes. */\nexport const allMessages: ReadonlyArray<Readonly<Record<string, unknown>>> = [\n coreMessages,\n redactionMessages,\n optionMessages,\n featureMessages,\n boundaryMessages,\n pipelineMessages,\n tableMessages,\n ssrMessages,\n asyncMessages,\n fetchMessages,\n rowKeyMessages,\n schemaMessages,\n dataCheckMessages,\n versioningMessages,\n columnFiltersMessages,\n validityMessages,\n searchMessages,\n sortingMessages,\n paginationMessages,\n envMessages,\n]\n\ninstallMessages(...allMessages)\n"],"mappings":";AAQA,SAAS,sBAAsB;AAC/B,SAAS,uBAAuB;AAChC,SAAS,oBAAoB;AAC7B,SAAS,yBAAyB;AAClC,SAAS,uBAAuB;AAChC,SAAS,6BAA6B;AACtC,SAAS,0BAA0B;AACnC,SAAS,sBAAsB;AAC/B,SAAS,uBAAuB;AAChC,SAAS,wBAAwB;AACjC,SAAS,yBAAyB;AAClC,SAAS,sBAAsB;AAC/B,SAAS,sBAAsB;AAC/B,SAAS,wBAAwB;AACjC,SAAS,wBAAwB;AACjC,SAAS,mBAAmB;AAC5B,SAAS,qBAAqB;AAC9B,SAAS,qBAAqB;AAC9B,SAAS,qBAAqB;AAC9B,SAAS,mBAAmB;AAC5B,SAAS,0BAA0B;AAG5B,IAAM,cAAgE;AAAA,EAC3E;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAEA,gBAAgB,GAAG,WAAW;","names":[]}
1
+ {"version":3,"sources":["../../src/messages/index.ts"],"sourcesContent":["/**\n * `@datakable/core/messages` (`datakable/messages`): full diagnostic text in production (§8.2).\n *\n * Production builds strip `problem` / `impact` / `fix` and keep `code`, `where`, `context` and a\n * docs URL. `import '@datakable/core/messages'` once (e.g. in the app entry) installs the text of\n * every code a production build can emit. Development builds already have it. This module is the\n * package's only side effect (`sideEffects` in package.json).\n */\nimport { optionMessages } from '../catalog/codes'\nimport { installMessages } from '../diagnostics/catalog'\nimport { coreMessages } from '../diagnostics/codes'\nimport { proseMessages } from '../diagnostics/prose'\nimport { redactionMessages } from '../diagnostics/redact'\nimport { featureMessages } from '../feature/codes'\nimport { columnFiltersMessages } from '../features/column-filters/codes'\nimport { paginationMessages } from '../features/pagination/codes'\nimport { searchMessages } from '../features/search/codes'\nimport { sortingMessages } from '../features/sorting/codes'\nimport { validityMessages } from '../features/validity/codes'\nimport { dataCheckMessages } from '../ingest/data-check-codes'\nimport { rowKeyMessages } from '../ingest/row-key-codes'\nimport { schemaMessages } from '../ingest/schema-codes'\nimport { boundaryMessages } from '../intercept/codes'\nimport { pipelineMessages } from '../pipeline/codes'\nimport { envMessages } from '../pipeline/env-codes'\nimport { asyncMessages } from '../source/codes'\nimport { fetchMessages } from '../source/fetch-codes'\nimport { tableMessages } from '../table/codes'\nimport { ssrMessages } from '../table/ssr-codes'\nimport { versioningMessages } from '../versioning/codes'\n\n/** Every message object core ships, one per module that owns codes. */\nexport const allMessages: ReadonlyArray<Readonly<Record<string, unknown>>> = [\n coreMessages,\n redactionMessages,\n optionMessages,\n featureMessages,\n boundaryMessages,\n pipelineMessages,\n tableMessages,\n ssrMessages,\n asyncMessages,\n fetchMessages,\n rowKeyMessages,\n schemaMessages,\n dataCheckMessages,\n versioningMessages,\n columnFiltersMessages,\n validityMessages,\n searchMessages,\n sortingMessages,\n paginationMessages,\n envMessages,\n // The detail sentences production keeps as keys (`fallback: 'cells-undefined'`).\n proseMessages,\n]\n\ninstallMessages(...allMessages)\n"],"mappings":";AAQA,SAAS,sBAAsB;AAC/B,SAAS,uBAAuB;AAChC,SAAS,oBAAoB;AAC7B,SAAS,qBAAqB;AAC9B,SAAS,yBAAyB;AAClC,SAAS,uBAAuB;AAChC,SAAS,6BAA6B;AACtC,SAAS,0BAA0B;AACnC,SAAS,sBAAsB;AAC/B,SAAS,uBAAuB;AAChC,SAAS,wBAAwB;AACjC,SAAS,yBAAyB;AAClC,SAAS,sBAAsB;AAC/B,SAAS,sBAAsB;AAC/B,SAAS,wBAAwB;AACjC,SAAS,wBAAwB;AACjC,SAAS,mBAAmB;AAC5B,SAAS,qBAAqB;AAC9B,SAAS,qBAAqB;AAC9B,SAAS,qBAAqB;AAC9B,SAAS,mBAAmB;AAC5B,SAAS,0BAA0B;AAG5B,IAAM,cAAgE;AAAA,EAC3E;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAEA;AACF;AAEA,gBAAgB,GAAG,WAAW;","names":[]}
@@ -1,5 +1,5 @@
1
- export { ai as paginationDiagnostics } from './codes-BKdS9EiO.cjs';
2
- import { F as Feature, b as FixedTypes } from './explain-aagaYHcy.cjs';
1
+ export { ai as paginationDiagnostics } from './codes-B9bCK73-.cjs';
2
+ import { F as Feature, b as FixedTypes } from './explain-Q8Cg0cZy.cjs';
3
3
  import { a as DataMode } from './mode-DFV8ryXo.cjs';
4
4
 
5
5
  interface PaginationState {
@@ -1,5 +1,5 @@
1
- export { ai as paginationDiagnostics } from './codes-BKdS9EiO.js';
2
- import { F as Feature, b as FixedTypes } from './explain-DcUZfFh5.js';
1
+ export { ai as paginationDiagnostics } from './codes-B9bCK73-.js';
2
+ import { F as Feature, b as FixedTypes } from './explain-i0OATi_W.js';
3
3
  import { a as DataMode } from './mode-DFV8ryXo.js';
4
4
 
5
5
  interface PaginationState {
@@ -25,6 +25,7 @@ __export(codes_exports, {
25
25
  });
26
26
  module.exports = __toCommonJS(codes_exports);
27
27
  var import_catalog = require("../diagnostics/catalog.cjs");
28
+ var import_process_guard = require("../diagnostics/process-guard.cjs");
28
29
  var rowList = (rows, count) => {
29
30
  const list = rows.map((r) => `#${r}`).join(", ");
30
31
  return count > rows.length ? `first: ${list}, \u2026` : `rows ${list}`;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/pipeline/codes.ts"],"sourcesContent":["import { type DiagnosticMessages, defineDiagnostic } from '../diagnostics/catalog'\n\ndeclare module '../diagnostics/catalog' {\n interface DiagnosticCatalog {\n DK_UNRENDERABLE_VALUE: {\n /** Column id (`key` or `id`). */\n column: string\n /** Position in `options.columns`. */\n index: number\n /** How many cells could not be rendered. */\n count: number\n /** A sample of the row indices (first few, in order). */\n rows: readonly number[]\n /** The type of the first unrenderable value: `object`, `array` or `function`. */\n valueType: string\n }\n }\n}\n\nconst rowList = (rows: readonly number[], count: number) => {\n const list = rows.map((r) => `#${r}`).join(', ')\n return count > rows.length ? `first: ${list}, …` : `rows ${list}`\n}\n\n/** Message text (§8.2): development builds, or production via `@datakable/core/messages`. */\nexport const pipelineMessages: DiagnosticMessages<'DK_UNRENDERABLE_VALUE'> = {\n DK_UNRENDERABLE_VALUE: {\n problem: (d) =>\n `column \"${d.column}\" has ${d.count === 1 ? '1 value' : `${d.count} values`} of type ` +\n `${d.valueType} (${rowList(d.rows, d.count)}) that the default formatter cannot render`,\n impact: () => \"those cells render '' (and match no search)\",\n fix: (d) => [\n `give columns[${d.index}] a format: (value) => string, e.g. format: (v) => v.name`,\n `or render it yourself with cell: ({ value }) => … on columns[${d.index}]`,\n `or point the column at a primitive field: key: '${d.column}.<field>'`,\n ],\n },\n}\n\n/** Codes owned by the pipeline / column cache (§4.3, §8.3). */\nexport const pipelineDiagnostics = [\n defineDiagnostic(\n {\n code: 'DK_UNRENDERABLE_VALUE',\n level: 'warn',\n where: (d) => ({ kind: 'column', index: d.index, id: d.column }),\n },\n (process.env.NODE_ENV !== \"production\") && pipelineMessages.DK_UNRENDERABLE_VALUE,\n ),\n]\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,qBAA0D;AAmB1D,IAAM,UAAU,CAAC,MAAyB,UAAkB;AAC1D,QAAM,OAAO,KAAK,IAAI,CAAC,MAAM,IAAI,CAAC,EAAE,EAAE,KAAK,IAAI;AAC/C,SAAO,QAAQ,KAAK,SAAS,UAAU,IAAI,aAAQ,QAAQ,IAAI;AACjE;AAGO,IAAM,mBAAgE;AAAA,EAC3E,uBAAuB;AAAA,IACrB,SAAS,CAAC,MACR,WAAW,EAAE,MAAM,SAAS,EAAE,UAAU,IAAI,YAAY,GAAG,EAAE,KAAK,SAAS,YACxE,EAAE,SAAS,KAAK,QAAQ,EAAE,MAAM,EAAE,KAAK,CAAC;AAAA,IAC7C,QAAQ,MAAM;AAAA,IACd,KAAK,CAAC,MAAM;AAAA,MACV,gBAAgB,EAAE,KAAK;AAAA,MACvB,qEAAgE,EAAE,KAAK;AAAA,MACvE,mDAAmD,EAAE,MAAM;AAAA,IAC7D;AAAA,EACF;AACF;AAGO,IAAM,sBAAsB;AAAA,MACjC;AAAA,IACE;AAAA,MACE,MAAM;AAAA,MACN,OAAO;AAAA,MACP,OAAO,CAAC,OAAO,EAAE,MAAM,UAAU,OAAO,EAAE,OAAO,IAAI,EAAE,OAAO;AAAA,IAChE;AAAA,IACC,QAAQ,IAAI,aAAa,gBAAiB,iBAAiB;AAAA,EAC9D;AACF;","names":[]}
1
+ {"version":3,"sources":["../../src/pipeline/codes.ts"],"sourcesContent":["import { type DiagnosticMessages, defineDiagnostic } from '../diagnostics/catalog'\nimport '../diagnostics/process-guard'\n\ndeclare module '../diagnostics/catalog' {\n interface DiagnosticCatalog {\n DK_UNRENDERABLE_VALUE: {\n /** Column id (`key` or `id`). */\n column: string\n /** Position in `options.columns`. */\n index: number\n /** How many cells could not be rendered. */\n count: number\n /** A sample of the row indices (first few, in order). */\n rows: readonly number[]\n /** The type of the first unrenderable value: `object`, `array` or `function`. */\n valueType: string\n }\n }\n}\n\nconst rowList = (rows: readonly number[], count: number) => {\n const list = rows.map((r) => `#${r}`).join(', ')\n return count > rows.length ? `first: ${list}, …` : `rows ${list}`\n}\n\n/** Message text (§8.2): development builds, or production via `@datakable/core/messages`. */\nexport const pipelineMessages: DiagnosticMessages<'DK_UNRENDERABLE_VALUE'> = {\n DK_UNRENDERABLE_VALUE: {\n problem: (d) =>\n `column \"${d.column}\" has ${d.count === 1 ? '1 value' : `${d.count} values`} of type ` +\n `${d.valueType} (${rowList(d.rows, d.count)}) that the default formatter cannot render`,\n impact: () => \"those cells render '' (and match no search)\",\n fix: (d) => [\n `give columns[${d.index}] a format: (value) => string, e.g. format: (v) => v.name`,\n `or render it yourself with cell: ({ value }) => … on columns[${d.index}]`,\n `or point the column at a primitive field: key: '${d.column}.<field>'`,\n ],\n },\n}\n\n/** Codes owned by the pipeline / column cache (§4.3, §8.3). */\nexport const pipelineDiagnostics = [\n defineDiagnostic(\n {\n code: 'DK_UNRENDERABLE_VALUE',\n level: 'warn',\n where: (d) => ({ kind: 'column', index: d.index, id: d.column }),\n },\n (process.env.NODE_ENV !== \"production\") && pipelineMessages.DK_UNRENDERABLE_VALUE,\n ),\n]\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,qBAA0D;AAC1D,2BAAO;AAmBP,IAAM,UAAU,CAAC,MAAyB,UAAkB;AAC1D,QAAM,OAAO,KAAK,IAAI,CAAC,MAAM,IAAI,CAAC,EAAE,EAAE,KAAK,IAAI;AAC/C,SAAO,QAAQ,KAAK,SAAS,UAAU,IAAI,aAAQ,QAAQ,IAAI;AACjE;AAGO,IAAM,mBAAgE;AAAA,EAC3E,uBAAuB;AAAA,IACrB,SAAS,CAAC,MACR,WAAW,EAAE,MAAM,SAAS,EAAE,UAAU,IAAI,YAAY,GAAG,EAAE,KAAK,SAAS,YACxE,EAAE,SAAS,KAAK,QAAQ,EAAE,MAAM,EAAE,KAAK,CAAC;AAAA,IAC7C,QAAQ,MAAM;AAAA,IACd,KAAK,CAAC,MAAM;AAAA,MACV,gBAAgB,EAAE,KAAK;AAAA,MACvB,qEAAgE,EAAE,KAAK;AAAA,MACvE,mDAAmD,EAAE,MAAM;AAAA,IAC7D;AAAA,EACF;AACF;AAGO,IAAM,sBAAsB;AAAA,MACjC;AAAA,IACE;AAAA,MACE,MAAM;AAAA,MACN,OAAO;AAAA,MACP,OAAO,CAAC,OAAO,EAAE,MAAM,UAAU,OAAO,EAAE,OAAO,IAAI,EAAE,OAAO;AAAA,IAChE;AAAA,IACC,QAAQ,IAAI,aAAa,gBAAiB,iBAAiB;AAAA,EAC9D;AACF;","names":[]}
@@ -1,5 +1,6 @@
1
1
  // src/pipeline/codes.ts
2
2
  import { defineDiagnostic } from "../diagnostics/catalog.js";
3
+ import "../diagnostics/process-guard.js";
3
4
  var rowList = (rows, count) => {
4
5
  const list = rows.map((r) => `#${r}`).join(", ");
5
6
  return count > rows.length ? `first: ${list}, \u2026` : `rows ${list}`;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/pipeline/codes.ts"],"sourcesContent":["import { type DiagnosticMessages, defineDiagnostic } from '../diagnostics/catalog'\n\ndeclare module '../diagnostics/catalog' {\n interface DiagnosticCatalog {\n DK_UNRENDERABLE_VALUE: {\n /** Column id (`key` or `id`). */\n column: string\n /** Position in `options.columns`. */\n index: number\n /** How many cells could not be rendered. */\n count: number\n /** A sample of the row indices (first few, in order). */\n rows: readonly number[]\n /** The type of the first unrenderable value: `object`, `array` or `function`. */\n valueType: string\n }\n }\n}\n\nconst rowList = (rows: readonly number[], count: number) => {\n const list = rows.map((r) => `#${r}`).join(', ')\n return count > rows.length ? `first: ${list}, …` : `rows ${list}`\n}\n\n/** Message text (§8.2): development builds, or production via `@datakable/core/messages`. */\nexport const pipelineMessages: DiagnosticMessages<'DK_UNRENDERABLE_VALUE'> = {\n DK_UNRENDERABLE_VALUE: {\n problem: (d) =>\n `column \"${d.column}\" has ${d.count === 1 ? '1 value' : `${d.count} values`} of type ` +\n `${d.valueType} (${rowList(d.rows, d.count)}) that the default formatter cannot render`,\n impact: () => \"those cells render '' (and match no search)\",\n fix: (d) => [\n `give columns[${d.index}] a format: (value) => string, e.g. format: (v) => v.name`,\n `or render it yourself with cell: ({ value }) => … on columns[${d.index}]`,\n `or point the column at a primitive field: key: '${d.column}.<field>'`,\n ],\n },\n}\n\n/** Codes owned by the pipeline / column cache (§4.3, §8.3). */\nexport const pipelineDiagnostics = [\n defineDiagnostic(\n {\n code: 'DK_UNRENDERABLE_VALUE',\n level: 'warn',\n where: (d) => ({ kind: 'column', index: d.index, id: d.column }),\n },\n (process.env.NODE_ENV !== \"production\") && pipelineMessages.DK_UNRENDERABLE_VALUE,\n ),\n]\n"],"mappings":";AAAA,SAAkC,wBAAwB;AAmB1D,IAAM,UAAU,CAAC,MAAyB,UAAkB;AAC1D,QAAM,OAAO,KAAK,IAAI,CAAC,MAAM,IAAI,CAAC,EAAE,EAAE,KAAK,IAAI;AAC/C,SAAO,QAAQ,KAAK,SAAS,UAAU,IAAI,aAAQ,QAAQ,IAAI;AACjE;AAGO,IAAM,mBAAgE;AAAA,EAC3E,uBAAuB;AAAA,IACrB,SAAS,CAAC,MACR,WAAW,EAAE,MAAM,SAAS,EAAE,UAAU,IAAI,YAAY,GAAG,EAAE,KAAK,SAAS,YACxE,EAAE,SAAS,KAAK,QAAQ,EAAE,MAAM,EAAE,KAAK,CAAC;AAAA,IAC7C,QAAQ,MAAM;AAAA,IACd,KAAK,CAAC,MAAM;AAAA,MACV,gBAAgB,EAAE,KAAK;AAAA,MACvB,qEAAgE,EAAE,KAAK;AAAA,MACvE,mDAAmD,EAAE,MAAM;AAAA,IAC7D;AAAA,EACF;AACF;AAGO,IAAM,sBAAsB;AAAA,EACjC;AAAA,IACE;AAAA,MACE,MAAM;AAAA,MACN,OAAO;AAAA,MACP,OAAO,CAAC,OAAO,EAAE,MAAM,UAAU,OAAO,EAAE,OAAO,IAAI,EAAE,OAAO;AAAA,IAChE;AAAA,IACC,QAAQ,IAAI,aAAa,gBAAiB,iBAAiB;AAAA,EAC9D;AACF;","names":[]}
1
+ {"version":3,"sources":["../../src/pipeline/codes.ts"],"sourcesContent":["import { type DiagnosticMessages, defineDiagnostic } from '../diagnostics/catalog'\nimport '../diagnostics/process-guard'\n\ndeclare module '../diagnostics/catalog' {\n interface DiagnosticCatalog {\n DK_UNRENDERABLE_VALUE: {\n /** Column id (`key` or `id`). */\n column: string\n /** Position in `options.columns`. */\n index: number\n /** How many cells could not be rendered. */\n count: number\n /** A sample of the row indices (first few, in order). */\n rows: readonly number[]\n /** The type of the first unrenderable value: `object`, `array` or `function`. */\n valueType: string\n }\n }\n}\n\nconst rowList = (rows: readonly number[], count: number) => {\n const list = rows.map((r) => `#${r}`).join(', ')\n return count > rows.length ? `first: ${list}, …` : `rows ${list}`\n}\n\n/** Message text (§8.2): development builds, or production via `@datakable/core/messages`. */\nexport const pipelineMessages: DiagnosticMessages<'DK_UNRENDERABLE_VALUE'> = {\n DK_UNRENDERABLE_VALUE: {\n problem: (d) =>\n `column \"${d.column}\" has ${d.count === 1 ? '1 value' : `${d.count} values`} of type ` +\n `${d.valueType} (${rowList(d.rows, d.count)}) that the default formatter cannot render`,\n impact: () => \"those cells render '' (and match no search)\",\n fix: (d) => [\n `give columns[${d.index}] a format: (value) => string, e.g. format: (v) => v.name`,\n `or render it yourself with cell: ({ value }) => … on columns[${d.index}]`,\n `or point the column at a primitive field: key: '${d.column}.<field>'`,\n ],\n },\n}\n\n/** Codes owned by the pipeline / column cache (§4.3, §8.3). */\nexport const pipelineDiagnostics = [\n defineDiagnostic(\n {\n code: 'DK_UNRENDERABLE_VALUE',\n level: 'warn',\n where: (d) => ({ kind: 'column', index: d.index, id: d.column }),\n },\n (process.env.NODE_ENV !== \"production\") && pipelineMessages.DK_UNRENDERABLE_VALUE,\n ),\n]\n"],"mappings":";AAAA,SAAkC,wBAAwB;AAC1D,OAAO;AAmBP,IAAM,UAAU,CAAC,MAAyB,UAAkB;AAC1D,QAAM,OAAO,KAAK,IAAI,CAAC,MAAM,IAAI,CAAC,EAAE,EAAE,KAAK,IAAI;AAC/C,SAAO,QAAQ,KAAK,SAAS,UAAU,IAAI,aAAQ,QAAQ,IAAI;AACjE;AAGO,IAAM,mBAAgE;AAAA,EAC3E,uBAAuB;AAAA,IACrB,SAAS,CAAC,MACR,WAAW,EAAE,MAAM,SAAS,EAAE,UAAU,IAAI,YAAY,GAAG,EAAE,KAAK,SAAS,YACxE,EAAE,SAAS,KAAK,QAAQ,EAAE,MAAM,EAAE,KAAK,CAAC;AAAA,IAC7C,QAAQ,MAAM;AAAA,IACd,KAAK,CAAC,MAAM;AAAA,MACV,gBAAgB,EAAE,KAAK;AAAA,MACvB,qEAAgE,EAAE,KAAK;AAAA,MACvE,mDAAmD,EAAE,MAAM;AAAA,IAC7D;AAAA,EACF;AACF;AAGO,IAAM,sBAAsB;AAAA,EACjC;AAAA,IACE;AAAA,MACE,MAAM;AAAA,MACN,OAAO;AAAA,MACP,OAAO,CAAC,OAAO,EAAE,MAAM,UAAU,OAAO,EAAE,OAAO,IAAI,EAAE,OAAO;AAAA,IAChE;AAAA,IACC,QAAQ,IAAI,aAAa,gBAAiB,iBAAiB;AAAA,EAC9D;AACF;","names":[]}