@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/column/column-def.ts"],"sourcesContent":["import type { RowIssue } from '../pipeline/row'\nimport type { IsAny, Path, PathValue, Primitive } from './path'\n\n/** Whole-row `any` is treated as `Record<string, unknown>` (spec §4.2); other rows pass through. */\nexport type LooseRow<T> = IsAny<T> extends true ? Record<string, unknown> : T\n\n/** `true` for `any` and `unknown`: values whose shape is not known at compile time. */\ntype IsLoose<V> = IsAny<V> extends true ? true : unknown extends V ? true : false\n\n/** Type-agnostic filter kinds, the only ones allowed for `any` / `unknown` values. */\ntype LooseFilter = { type: 'equals' } | { type: 'contains' }\n\n// The filter sets are named so a wrong kind reads \"not assignable to type 'StringFilter'\" instead\n// of an inlined union (docs/how-to-fix/reading-type-errors.md, E3).\n/** Filter kinds for number, bigint and `Date` values. */\ntype NumberFilter = { type: 'range' } | { type: 'equals' } | { type: 'in' }\n/** Filter kinds for string values. `range` is not one of them. */\ntype StringFilter = { type: 'equals' } | { type: 'in' } | { type: 'contains' }\n/** Filter kinds for boolean values. */\ntype BooleanFilter = { type: 'equals' }\n\n/**\n * Filter kinds allowed for a column whose value type is `V` (spec §4.1, §6.1). Arrays of\n * primitives take their element's kinds (an array cell matches if any element matches).\n */\nexport type FilterFor<V> =\n IsLoose<V> extends true\n ? LooseFilter\n : NonNullable<V> extends number | bigint | Date\n ? NumberFilter\n : NonNullable<V> extends string\n ? StringFilter\n : NonNullable<V> extends boolean\n ? BooleanFilter\n : NonNullable<V> extends readonly (infer E)[]\n ? FilterFor<E>\n : never\n\n/** Values the default formatter can render: primitives, `Date`, arrays of those. */\ntype Displayable = Primitive | readonly Primitive[]\n\n/** Argument of a column's `cell` renderer. */\nexport type CellContext<T, V> = { row: T; value: V }\n\n/** Argument of a column's `invalidCell` renderer (a flagged row, `invalidRows: 'flag'`, §5.1). */\nexport type InvalidCellContext = {\n /** The raw, unvalidated row. */\n original: unknown\n /** The cell's raw value (the column's key path or accessor over `original`). */\n value: unknown\n /** The row's schema issues that touch this cell: `row.getCellIssues(column)`. */\n issues: readonly RowIssue[]\n}\n\n/** Built-in sort algorithms, or a custom one over row indices (spec §6.4). */\nexport type SortAlgorithm =\n | 'auto'\n | 'tim'\n | 'radix'\n | 'counting'\n | 'native'\n | ((indices: Uint32Array, compare: (a: number, b: number) => number) => Uint32Array)\n\n/** Fields shared by every column whose value type is `V`. */\ntype BaseColumn<T, V, R> = {\n header?: string\n /** Search weight; omit to exclude the column from search. */\n search?: number\n sortable?: boolean\n sortFn?: (a: V, b: V) => number\n sortBy?: (row: T) => Primitive\n sortAlgorithm?: SortAlgorithm\n filter?: FilterFor<V>\n /** Never logged by diagnostics at any level. */\n sensitive?: boolean\n invalidCell?: (ctx: InvalidCellContext) => R\n /**\n * Renders the cell. Required (or `format`) when the value is an object, a function or an\n * array of objects — the default formatter cannot display those. Primitives, `Date`, arrays of\n * primitives, `unknown` and `any` need neither. Returns `R` (`ReactNode` in\n * `@datakable/react`).\n */\n cell?: (ctx: CellContext<T, V>) => R\n /**\n * Formats the value to a string. Required (or `cell`) when the value is an object, a function\n * or an array of objects — the default formatter cannot display those. Primitives, `Date`,\n * arrays of primitives, `unknown` and `any` need neither.\n */\n format?: (value: V) => string\n}\n\n/**\n * Rendering requirement for value `V`: objects, functions and arrays of objects MUST give `cell`\n * or `format`. Primitives, `Date`, arrays of primitives, `unknown` and `any` need neither.\n */\nexport type RenderReq<T, V, R> =\n IsLoose<V> extends true\n ? BaseColumn<T, V, R>\n : [NonNullable<V>] extends [Displayable]\n ? BaseColumn<T, V, R>\n : BaseColumn<T, V, R> & (NeedsCell<T, V, R> | NeedsFormat<V>)\n\n// The two ways to satisfy the rendering requirement are named so that a column missing both reads\n// \"Property 'format' is missing ... required in type 'NeedsFormat<V>'\", with `NeedsCell<T, V, R>`\n// listed as the alternative (docs/how-to-fix/reading-type-errors.md, E4 / E5). The JSDoc repeats BaseColumn's\n// word for word: autocomplete on a required `cell` / `format` shows it once only while the copies\n// are identical (pinned in type-errors.test.ts).\n\n/** Value `V` cannot be shown by the default formatter: the column needs `cell` (or `format`). */\ntype NeedsCell<T, V, R> = {\n /**\n * Renders the cell. Required (or `format`) when the value is an object, a function or an\n * array of objects — the default formatter cannot display those. Primitives, `Date`, arrays of\n * primitives, `unknown` and `any` need neither. Returns `R` (`ReactNode` in\n * `@datakable/react`).\n */\n cell: (ctx: CellContext<T, V>) => R\n}\n\n/** Value `V` cannot be shown by the default formatter: the column needs `format` (or `cell`). */\ntype NeedsFormat<V> = {\n /**\n * Formats the value to a string. Required (or `cell`) when the value is an object, a function\n * or an array of objects — the default formatter cannot display those. Primitives, `Date`,\n * arrays of primitives, `unknown` and `any` need neither.\n */\n format: (value: V) => string\n}\n\n/**\n * Sort requirement for value `V` (spec §6.4): an object, function or array-of-objects column has\n * no default order, so `sortable: true` needs `sortFn` or `sortBy`. Primitives, `Date`, arrays of\n * primitives, `unknown` and `any` need neither.\n */\nexport type SortReq<T, V> =\n IsLoose<V> extends true\n ? unknown\n : [NonNullable<V>] extends [Displayable]\n ? unknown\n : { sortable?: false } | NeedsSortFn<V> | NeedsSortBy<T>\n\n/** `sortable: true` on a column without a default order: compare the values with `sortFn`. */\ntype NeedsSortFn<V> = { sortable: true; sortFn: (a: V, b: V) => number }\n/** `sortable: true` on a column without a default order: sort by a primitive key. */\ntype NeedsSortBy<T> = { sortable: true; sortBy: (row: T) => Primitive }\n\n/** A column bound to a dot-path of `T`; a distributive union over every path. */\nexport type KeyColumn<T, R> = {\n [P in Path<T>]: { key: P } & RenderReq<T, PathValue<T, P>, R> & SortReq<T, PathValue<T, P>>\n}[Path<T>]\n\n/** A derived column: `accessor` computes the value from the (contextually typed) row. */\nexport type AccessorColumn<T, R> = {\n id: string\n accessor: (row: T) => unknown\n key?: never\n} & BaseColumn<T, unknown, R>\n\n/**\n * One column of a table over rows `T`. `R` is the `cell` render result (`unknown` in core,\n * `ReactNode` in `@datakable/react`). Whole-row `any` is treated as `Record<string, unknown>`.\n */\nexport type ColumnDef<T, R = unknown> = KeyColumn<LooseRow<T>, R> | AccessorColumn<LooseRow<T>, R>\n"],"mappings":";;;;;;;;;;;;;;;;AAAA;AAAA;","names":[]}
1
+ {"version":3,"sources":["../../src/column/column-def.ts"],"sourcesContent":["import type { RowIssue } from '../pipeline/row'\nimport type { IsAny, Path, PathValue, Primitive } from './path'\n\n/** Whole-row `any` is treated as `Record<string, unknown>` (spec §4.2); other rows pass through. */\nexport type LooseRow<T> = IsAny<T> extends true ? Record<string, unknown> : T\n\n/** `true` for `any` and `unknown`: values whose shape is not known at compile time. */\ntype IsLoose<V> = IsAny<V> extends true ? true : unknown extends V ? true : false\n\n/** Type-agnostic filter kinds, the only ones allowed for `any` / `unknown` values. */\ntype LooseFilter = { type: 'equals' } | { type: 'contains' }\n\n// The filter sets are named so a wrong kind reads \"not assignable to type 'StringFilter'\" instead\n// of an inlined union (docs/how-to-fix/reading-type-errors.md, E3).\n/** Filter kinds for number, bigint and `Date` values. */\ntype NumberFilter = { type: 'range' } | { type: 'equals' } | { type: 'in' }\n/** Filter kinds for string values. `range` is not one of them. */\ntype StringFilter = { type: 'equals' } | { type: 'in' } | { type: 'contains' }\n/** Filter kinds for boolean values. */\ntype BooleanFilter = { type: 'equals' }\n\n/**\n * Filter kinds allowed for a column whose value type is `V` (spec §4.1, §6.1). Arrays of\n * primitives take their element's kinds (an array cell matches if any element matches).\n */\nexport type FilterFor<V> =\n IsLoose<V> extends true\n ? LooseFilter\n : NonNullable<V> extends number | bigint | Date\n ? NumberFilter\n : NonNullable<V> extends string\n ? StringFilter\n : NonNullable<V> extends boolean\n ? BooleanFilter\n : NonNullable<V> extends readonly (infer E)[]\n ? FilterFor<E>\n : never\n\n/** Values the default formatter can render: primitives, `Date`, arrays of those. */\ntype Displayable = Primitive | readonly Primitive[]\n\n/** Argument of a column's `cell` renderer. */\nexport type CellContext<T, V> = { row: T; value: V }\n\n/** Argument of a column's `invalidCell` renderer (a flagged row, `invalidRows: 'flag'`, §5.1). */\nexport type InvalidCellContext = {\n /** The raw, unvalidated row. */\n original: unknown\n /** The cell's raw value (the column's key path or accessor over `original`). */\n value: unknown\n /** The row's schema issues that touch this cell: `row.getCellIssues(column)`. */\n issues: readonly RowIssue[]\n}\n\n/** Built-in sort algorithms, or a custom one over row indices (spec §6.4). */\nexport type SortAlgorithm =\n | 'auto'\n | 'tim'\n | 'radix'\n | 'counting'\n | 'native'\n | ((indices: Uint32Array, compare: (a: number, b: number) => number) => Uint32Array)\n\n/** Fields shared by every column whose value type is `V`. */\ntype BaseColumn<T, V, R> = {\n header?: string\n /**\n * Search weight. Once any column declares one, only weighted columns are searched; when none\n * does, the columns of strings, numbers and booleans are (a date, array or object column needs a\n * weight to be searched).\n */\n search?: number\n sortable?: boolean\n sortFn?: (a: V, b: V) => number\n sortBy?: (row: T) => Primitive\n sortAlgorithm?: SortAlgorithm\n filter?: FilterFor<V>\n /** Never logged by diagnostics at any level. */\n sensitive?: boolean\n invalidCell?: (ctx: InvalidCellContext) => R\n /**\n * Renders the cell. Required (or `format`) when the value is an object, a function or an\n * array of objects — the default formatter cannot display those. Primitives, `Date`, arrays of\n * primitives, `unknown` and `any` need neither. Returns `R` (`ReactNode` in\n * `@datakable/react`).\n */\n cell?: (ctx: CellContext<T, V>) => R\n /**\n * Formats the value to a string. Required (or `cell`) when the value is an object, a function\n * or an array of objects — the default formatter cannot display those. Primitives, `Date`,\n * arrays of primitives, `unknown` and `any` need neither.\n */\n format?: (value: V) => string\n}\n\n/**\n * Rendering requirement for value `V`: objects, functions and arrays of objects MUST give `cell`\n * or `format`. Primitives, `Date`, arrays of primitives, `unknown` and `any` need neither.\n */\nexport type RenderReq<T, V, R> =\n IsLoose<V> extends true\n ? BaseColumn<T, V, R>\n : [NonNullable<V>] extends [Displayable]\n ? BaseColumn<T, V, R>\n : BaseColumn<T, V, R> & (NeedsCell<T, V, R> | NeedsFormat<V>)\n\n// The two ways to satisfy the rendering requirement are named so that a column missing both reads\n// \"Property 'format' is missing ... required in type 'NeedsFormat<V>'\", with `NeedsCell<T, V, R>`\n// listed as the alternative (docs/how-to-fix/reading-type-errors.md, E4 / E5). The JSDoc repeats BaseColumn's\n// word for word: autocomplete on a required `cell` / `format` shows it once only while the copies\n// are identical (pinned in type-errors.test.ts).\n\n/** Value `V` cannot be shown by the default formatter: the column needs `cell` (or `format`). */\ntype NeedsCell<T, V, R> = {\n /**\n * Renders the cell. Required (or `format`) when the value is an object, a function or an\n * array of objects — the default formatter cannot display those. Primitives, `Date`, arrays of\n * primitives, `unknown` and `any` need neither. Returns `R` (`ReactNode` in\n * `@datakable/react`).\n */\n cell: (ctx: CellContext<T, V>) => R\n}\n\n/** Value `V` cannot be shown by the default formatter: the column needs `format` (or `cell`). */\ntype NeedsFormat<V> = {\n /**\n * Formats the value to a string. Required (or `cell`) when the value is an object, a function\n * or an array of objects — the default formatter cannot display those. Primitives, `Date`,\n * arrays of primitives, `unknown` and `any` need neither.\n */\n format: (value: V) => string\n}\n\n/**\n * Sort requirement for value `V` (spec §6.4): an object, function or array-of-objects column has\n * no default order, so `sortable: true` needs `sortFn` or `sortBy`. Primitives, `Date`, arrays of\n * primitives, `unknown` and `any` need neither.\n */\nexport type SortReq<T, V> =\n IsLoose<V> extends true\n ? unknown\n : [NonNullable<V>] extends [Displayable]\n ? unknown\n : { sortable?: false } | NeedsSortFn<V> | NeedsSortBy<T>\n\n/** `sortable: true` on a column without a default order: compare the values with `sortFn`. */\ntype NeedsSortFn<V> = { sortable: true; sortFn: (a: V, b: V) => number }\n/** `sortable: true` on a column without a default order: sort by a primitive key. */\ntype NeedsSortBy<T> = { sortable: true; sortBy: (row: T) => Primitive }\n\n/** A column bound to a dot-path of `T`; a distributive union over every path. */\nexport type KeyColumn<T, R> = {\n [P in Path<T>]: { key: P } & RenderReq<T, PathValue<T, P>, R> & SortReq<T, PathValue<T, P>>\n}[Path<T>]\n\n/** A derived column: `accessor` computes the value from the (contextually typed) row. */\nexport type AccessorColumn<T, R> = {\n id: string\n accessor: (row: T) => unknown\n key?: never\n} & BaseColumn<T, unknown, R>\n\n/**\n * One column of a table over rows `T`. `R` is the `cell` render result (`unknown` in core,\n * `ReactNode` in `@datakable/react`). Whole-row `any` is treated as `Record<string, unknown>`.\n */\nexport type ColumnDef<T, R = unknown> = KeyColumn<LooseRow<T>, R> | AccessorColumn<LooseRow<T>, R>\n"],"mappings":";;;;;;;;;;;;;;;;AAAA;AAAA;","names":[]}
@@ -33,7 +33,12 @@ function getValue(row, path, onError) {
33
33
  try {
34
34
  for (let i = 0; i < segs.length; i++) {
35
35
  if (cur === null || typeof cur !== "object") return void 0;
36
- cur = cur[segs[i]];
36
+ const seg = segs[i];
37
+ const next = cur[seg];
38
+ if ((typeof next === "function" || seg === "__proto__") && !Object.hasOwn(cur, seg)) {
39
+ return void 0;
40
+ }
41
+ cur = next;
37
42
  }
38
43
  } catch (error) {
39
44
  onError?.(error);
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/column/get-value.ts"],"sourcesContent":["/** A dot-path split into its segments once, for repeated per-cell walks. */\nexport type CompiledPath = readonly string[]\n\n/** Splits a dot-path (`'address.geo.lat'`) into segments. Call once per column, not per cell. */\nexport function compilePath(path: string): CompiledPath {\n return path.split('.')\n}\n\n/**\n * Reads the value at `path` of `row`, defensively (§4.3): a `null`, `undefined` or non-object\n * (primitive, function) part-way through yields `undefined`. Arrays are walked by index. Never\n * throws: a throwing getter or Proxy trap yields `undefined` and is passed to `onError`.\n *\n * Hot paths should pass a {@link compilePath} result so the walk allocates nothing per cell.\n */\nexport function getValue(\n row: unknown,\n path: string | CompiledPath,\n onError?: (error: unknown) => void,\n): unknown {\n const segs = typeof path === 'string' ? compilePath(path) : path\n let cur: unknown = row\n try {\n for (let i = 0; i < segs.length; i++) {\n if (cur === null || typeof cur !== 'object') return undefined\n cur = (cur as Record<string, unknown>)[segs[i] as string]\n }\n } catch (error) {\n // The column cache (pipeline/column-cache.ts) passes onError and reports DK_CALLBACK_FAILED\n // once per column batch with the failing row indices (no per-cell emit).\n onError?.(error)\n return undefined\n }\n return cur\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAIO,SAAS,YAAY,MAA4B;AACtD,SAAO,KAAK,MAAM,GAAG;AACvB;AASO,SAAS,SACd,KACA,MACA,SACS;AACT,QAAM,OAAO,OAAO,SAAS,WAAW,YAAY,IAAI,IAAI;AAC5D,MAAI,MAAe;AACnB,MAAI;AACF,aAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;AACpC,UAAI,QAAQ,QAAQ,OAAO,QAAQ,SAAU,QAAO;AACpD,YAAO,IAAgC,KAAK,CAAC,CAAW;AAAA,IAC1D;AAAA,EACF,SAAS,OAAO;AAGd,cAAU,KAAK;AACf,WAAO;AAAA,EACT;AACA,SAAO;AACT;","names":[]}
1
+ {"version":3,"sources":["../../src/column/get-value.ts"],"sourcesContent":["/** A dot-path split into its segments once, for repeated per-cell walks. */\nexport type CompiledPath = readonly string[]\n\n/** Splits a dot-path (`'address.geo.lat'`) into segments. Call once per column, not per cell. */\nexport function compilePath(path: string): CompiledPath {\n return path.split('.')\n}\n\n/**\n * Reads the value at `path` of `row`, defensively (§4.3): a `null`, `undefined` or non-object\n * (primitive, function) part-way through yields `undefined`. Arrays are walked by index. An\n * inherited method or `__proto__` (`constructor`, `toString`, `map`) yields `undefined`. Never\n * throws: a throwing getter or Proxy trap yields `undefined` and is passed to `onError`.\n *\n * Hot paths should pass a {@link compilePath} result so the walk allocates nothing per cell.\n */\nexport function getValue(\n row: unknown,\n path: string | CompiledPath,\n onError?: (error: unknown) => void,\n): unknown {\n const segs = typeof path === 'string' ? compilePath(path) : path\n let cur: unknown = row\n try {\n for (let i = 0; i < segs.length; i++) {\n if (cur === null || typeof cur !== 'object') return undefined\n const seg = segs[i] as string\n const next = (cur as Record<string, unknown>)[seg]\n // Inherited methods and `__proto__` (`constructor`, `toString`) are not row data (#42);\n // checked only for function values, so plain data and class getters cost nothing more.\n if ((typeof next === 'function' || seg === '__proto__') && !Object.hasOwn(cur, seg)) {\n return undefined\n }\n cur = next\n }\n } catch (error) {\n // The column cache (pipeline/column-cache.ts) passes onError and reports DK_CALLBACK_FAILED\n // once per column batch with the failing row indices (no per-cell emit).\n onError?.(error)\n return undefined\n }\n return cur\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAIO,SAAS,YAAY,MAA4B;AACtD,SAAO,KAAK,MAAM,GAAG;AACvB;AAUO,SAAS,SACd,KACA,MACA,SACS;AACT,QAAM,OAAO,OAAO,SAAS,WAAW,YAAY,IAAI,IAAI;AAC5D,MAAI,MAAe;AACnB,MAAI;AACF,aAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;AACpC,UAAI,QAAQ,QAAQ,OAAO,QAAQ,SAAU,QAAO;AACpD,YAAM,MAAM,KAAK,CAAC;AAClB,YAAM,OAAQ,IAAgC,GAAG;AAGjD,WAAK,OAAO,SAAS,cAAc,QAAQ,gBAAgB,CAAC,OAAO,OAAO,KAAK,GAAG,GAAG;AACnF,eAAO;AAAA,MACT;AACA,YAAM;AAAA,IACR;AAAA,EACF,SAAS,OAAO;AAGd,cAAU,KAAK;AACf,WAAO;AAAA,EACT;AACA,SAAO;AACT;","names":[]}
@@ -8,7 +8,12 @@ function getValue(row, path, onError) {
8
8
  try {
9
9
  for (let i = 0; i < segs.length; i++) {
10
10
  if (cur === null || typeof cur !== "object") return void 0;
11
- cur = cur[segs[i]];
11
+ const seg = segs[i];
12
+ const next = cur[seg];
13
+ if ((typeof next === "function" || seg === "__proto__") && !Object.hasOwn(cur, seg)) {
14
+ return void 0;
15
+ }
16
+ cur = next;
12
17
  }
13
18
  } catch (error) {
14
19
  onError?.(error);
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/column/get-value.ts"],"sourcesContent":["/** A dot-path split into its segments once, for repeated per-cell walks. */\nexport type CompiledPath = readonly string[]\n\n/** Splits a dot-path (`'address.geo.lat'`) into segments. Call once per column, not per cell. */\nexport function compilePath(path: string): CompiledPath {\n return path.split('.')\n}\n\n/**\n * Reads the value at `path` of `row`, defensively (§4.3): a `null`, `undefined` or non-object\n * (primitive, function) part-way through yields `undefined`. Arrays are walked by index. Never\n * throws: a throwing getter or Proxy trap yields `undefined` and is passed to `onError`.\n *\n * Hot paths should pass a {@link compilePath} result so the walk allocates nothing per cell.\n */\nexport function getValue(\n row: unknown,\n path: string | CompiledPath,\n onError?: (error: unknown) => void,\n): unknown {\n const segs = typeof path === 'string' ? compilePath(path) : path\n let cur: unknown = row\n try {\n for (let i = 0; i < segs.length; i++) {\n if (cur === null || typeof cur !== 'object') return undefined\n cur = (cur as Record<string, unknown>)[segs[i] as string]\n }\n } catch (error) {\n // The column cache (pipeline/column-cache.ts) passes onError and reports DK_CALLBACK_FAILED\n // once per column batch with the failing row indices (no per-cell emit).\n onError?.(error)\n return undefined\n }\n return cur\n}\n"],"mappings":";AAIO,SAAS,YAAY,MAA4B;AACtD,SAAO,KAAK,MAAM,GAAG;AACvB;AASO,SAAS,SACd,KACA,MACA,SACS;AACT,QAAM,OAAO,OAAO,SAAS,WAAW,YAAY,IAAI,IAAI;AAC5D,MAAI,MAAe;AACnB,MAAI;AACF,aAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;AACpC,UAAI,QAAQ,QAAQ,OAAO,QAAQ,SAAU,QAAO;AACpD,YAAO,IAAgC,KAAK,CAAC,CAAW;AAAA,IAC1D;AAAA,EACF,SAAS,OAAO;AAGd,cAAU,KAAK;AACf,WAAO;AAAA,EACT;AACA,SAAO;AACT;","names":[]}
1
+ {"version":3,"sources":["../../src/column/get-value.ts"],"sourcesContent":["/** A dot-path split into its segments once, for repeated per-cell walks. */\nexport type CompiledPath = readonly string[]\n\n/** Splits a dot-path (`'address.geo.lat'`) into segments. Call once per column, not per cell. */\nexport function compilePath(path: string): CompiledPath {\n return path.split('.')\n}\n\n/**\n * Reads the value at `path` of `row`, defensively (§4.3): a `null`, `undefined` or non-object\n * (primitive, function) part-way through yields `undefined`. Arrays are walked by index. An\n * inherited method or `__proto__` (`constructor`, `toString`, `map`) yields `undefined`. Never\n * throws: a throwing getter or Proxy trap yields `undefined` and is passed to `onError`.\n *\n * Hot paths should pass a {@link compilePath} result so the walk allocates nothing per cell.\n */\nexport function getValue(\n row: unknown,\n path: string | CompiledPath,\n onError?: (error: unknown) => void,\n): unknown {\n const segs = typeof path === 'string' ? compilePath(path) : path\n let cur: unknown = row\n try {\n for (let i = 0; i < segs.length; i++) {\n if (cur === null || typeof cur !== 'object') return undefined\n const seg = segs[i] as string\n const next = (cur as Record<string, unknown>)[seg]\n // Inherited methods and `__proto__` (`constructor`, `toString`) are not row data (#42);\n // checked only for function values, so plain data and class getters cost nothing more.\n if ((typeof next === 'function' || seg === '__proto__') && !Object.hasOwn(cur, seg)) {\n return undefined\n }\n cur = next\n }\n } catch (error) {\n // The column cache (pipeline/column-cache.ts) passes onError and reports DK_CALLBACK_FAILED\n // once per column batch with the failing row indices (no per-cell emit).\n onError?.(error)\n return undefined\n }\n return cur\n}\n"],"mappings":";AAIO,SAAS,YAAY,MAA4B;AACtD,SAAO,KAAK,MAAM,GAAG;AACvB;AAUO,SAAS,SACd,KACA,MACA,SACS;AACT,QAAM,OAAO,OAAO,SAAS,WAAW,YAAY,IAAI,IAAI;AAC5D,MAAI,MAAe;AACnB,MAAI;AACF,aAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;AACpC,UAAI,QAAQ,QAAQ,OAAO,QAAQ,SAAU,QAAO;AACpD,YAAM,MAAM,KAAK,CAAC;AAClB,YAAM,OAAQ,IAAgC,GAAG;AAGjD,WAAK,OAAO,SAAS,cAAc,QAAQ,gBAAgB,CAAC,OAAO,OAAO,KAAK,GAAG,GAAG;AACnF,eAAO;AAAA,MACT;AACA,YAAM;AAAA,IACR;AAAA,EACF,SAAS,OAAO;AAGd,cAAU,KAAK;AACf,WAAO;AAAA,EACT;AACA,SAAO;AACT;","names":[]}
@@ -1,5 +1,5 @@
1
- export { U as columnFiltersDiagnostics } from './codes-BKdS9EiO.cjs';
2
- import { G as FilterFor, a1 as Path, P as LooseRow, a2 as PathValue, e as FeatureTypes, F as Feature } from './explain-aagaYHcy.cjs';
1
+ export { U as columnFiltersDiagnostics } from './codes-B9bCK73-.cjs';
2
+ import { G as FilterFor, a1 as Path, P as LooseRow, a2 as PathValue, e as FeatureTypes, F as Feature } from './explain-Q8Cg0cZy.cjs';
3
3
  import { a as DataMode } from './mode-DFV8ryXo.cjs';
4
4
 
5
5
  /** The value a filter compares against: the element type for array-valued cells (§6.1). */
@@ -1,5 +1,5 @@
1
- export { U as columnFiltersDiagnostics } from './codes-BKdS9EiO.js';
2
- import { G as FilterFor, a1 as Path, P as LooseRow, a2 as PathValue, e as FeatureTypes, F as Feature } from './explain-DcUZfFh5.js';
1
+ export { U as columnFiltersDiagnostics } from './codes-B9bCK73-.js';
2
+ import { G as FilterFor, a1 as Path, P as LooseRow, a2 as PathValue, e as FeatureTypes, F as Feature } from './explain-i0OATi_W.js';
3
3
  import { a as DataMode } from './mode-DFV8ryXo.js';
4
4
 
5
5
  /** The value a filter compares against: the element type for array-valued cells (§6.1). */
@@ -27,17 +27,21 @@ __export(build_exports, {
27
27
  defaultPhase: () => defaultPhase,
28
28
  formatWhere: () => formatWhere,
29
29
  internalError: () => internalError,
30
- throwConfigError: () => throwConfigError
30
+ throwConfigError: () => throwConfigError,
31
+ wallClock: () => wallClock
31
32
  });
32
33
  module.exports = __toCommonJS(build_exports);
33
34
  var import_version = require("../version.cjs");
34
35
  var import_catalog = require("./catalog.cjs");
35
36
  var import_codes = require("./codes.cjs");
37
+ var import_process_guard = require("./process-guard.cjs");
38
+ var import_prose = require("./prose.cjs");
36
39
  var import_redact = require("./redact.cjs");
37
40
  var import_safe_json = require("./safe-json.cjs");
38
41
  var PACKAGE = `@datakable/core@${import_version.VERSION}`;
39
42
  var DOCS = "https://github.com/Ink01101011/datakable/blob/main/docs/errors.md";
40
43
  var INTERNAL = import_codes.coreDiagnostics.find((d) => d.code === "DK_INTERNAL");
44
+ var wallClock = () => typeof performance === "object" && performance?.timeOrigin ? Math.floor(performance.timeOrigin + performance.now()) : Date.now();
41
45
  var defaultPhase = () => typeof document === "undefined" ? "ssr" : "client";
42
46
  function formatWhere(where) {
43
47
  switch (where.kind) {
@@ -91,11 +95,12 @@ function buildDiagnostic(code, details, input = {}) {
91
95
  def = INTERNAL;
92
96
  d = {
93
97
  op: "diagnostic:emit",
94
- problem: `unknown diagnostic code "${code}": define it with defineDiagnostic() first`
98
+ problem: `unknown-code|${code}`
95
99
  };
96
100
  }
97
101
  const b = def;
98
102
  const dev = input.dev ?? process.env.NODE_ENV !== "production";
103
+ if (dev || (0, import_catalog.hasMessages)()) d = (0, import_prose.expandDetails)(d, dev);
99
104
  const r = input.redaction ?? (0, import_redact.resolveRedaction)(void 0, dev);
100
105
  const where = (0, import_redact.redactLocation)(b.where(d), r);
101
106
  d = (0, import_redact.redactDetails)(
@@ -107,7 +112,7 @@ function buildDiagnostic(code, details, input = {}) {
107
112
  const dd = d;
108
113
  const t = dev || (0, import_catalog.hasMessages)() ? (0, import_catalog.getDiagnosticText)(def.code) : void 0;
109
114
  const whereText = formatWhere(where);
110
- const now = input.now ?? Date.now();
115
+ const now = input.now ?? wallClock();
111
116
  const context = {
112
117
  table: input.table ?? "(global)",
113
118
  package: PACKAGE,
@@ -180,6 +185,7 @@ function internalError(op, problem) {
180
185
  defaultPhase,
181
186
  formatWhere,
182
187
  internalError,
183
- throwConfigError
188
+ throwConfigError,
189
+ wallClock
184
190
  });
185
191
  //# sourceMappingURL=build.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/diagnostics/build.ts"],"sourcesContent":["import { VERSION } from '../version'\nimport {\n type DiagnosticCode,\n type DiagnosticDefinition,\n type DiagnosticDetails,\n type DiagnosticText,\n getDiagnosticDefinition,\n getDiagnosticText,\n hasMessages,\n} from './catalog'\nimport { coreDiagnostics } from './codes'\nimport {\n type RedactField,\n type Redactor,\n redactDetails,\n redactLocation,\n resolveRedaction,\n} from './redact'\nimport { toSafeJson } from './safe-json'\nimport type {\n Diagnostic,\n DiagnosticContext,\n DiagnosticLevel,\n DiagnosticStateSummary,\n Location,\n Phase,\n Trigger,\n} from './types'\n\nexport const PACKAGE = `@datakable/core@${VERSION}`\nconst DOCS = 'https://github.com/Ink01101011/datakable/blob/main/docs/errors.md'\n\n// Referencing the core entries keeps them in the bundle (`sideEffects: false`).\nconst INTERNAL = coreDiagnostics.find((d) => d.code === 'DK_INTERNAL') as DiagnosticDefinition\n\n/** Everything the enrich step adds; all optional so a diagnostic can be built outside a table. */\nexport interface BuildInput {\n table?: string\n createdAt?: string\n trigger?: Trigger\n run?: number\n phase?: Phase\n mode?: Record<string, 'client' | 'server'>\n state?: DiagnosticStateSummary\n /** Timestamp for `occurrences`. Default `Date.now()`. */\n now?: number\n cause?: unknown\n causedBy?: string\n /** Build the problem / impact / fix text. Default: development builds only (§8.2); production\n * builds also build it once `@datakable/core/messages` is installed. */\n dev?: boolean\n /** Redaction policy (§8.2). Default: `'keys'` when `dev`, else `'safe'`. */\n redaction?: Redactor\n}\n\nexport const defaultPhase = (): Phase => (typeof document === 'undefined' ? 'ssr' : 'client')\n\nexport function formatWhere(where: Location): string {\n switch (where.kind) {\n case 'column':\n return `columns[${where.index}] (id \"${where.id}\")`\n case 'feature':\n return `feature \"${where.name}\"`\n case 'option':\n return `options.${where.path}`\n case 'row':\n return where.key === undefined\n ? `row #${where.index}`\n : `row #${where.index} (key ${where.key})`\n case 'interceptor':\n return `interceptor \"${where.name}\" on ${where.op}`\n case 'operation':\n return where.slot ? `operation ${where.op} at ${where.slot}` : `operation ${where.op}`\n }\n}\n\nclass DiagnosticRecord implements Diagnostic {\n constructor(\n public code: DiagnosticCode,\n public level: DiagnosticLevel,\n public problem: string,\n public where: Location,\n public impact: string,\n public fix: string[],\n public docs: string,\n public details: Record<string, unknown>,\n public context: DiagnosticContext,\n public fingerprint: string,\n ) {}\n\n toJSON(): object {\n const { cause: _cause, ...context } = this.context\n return {\n code: this.code,\n level: this.level,\n problem: this.problem,\n where: toSafeJson(this.where),\n impact: this.impact,\n fix: this.fix,\n docs: this.docs,\n details: toSafeJson(this.details),\n context: toSafeJson(context),\n fingerprint: this.fingerprint,\n }\n }\n}\n\n/**\n * Builds a diagnostic from a catalog code + details (the `enrich` step). Never throws for an unknown\n * code: that becomes `DK_INTERNAL`, so a typo in a plugin cannot take the logger down.\n */\nexport function buildDiagnostic<C extends DiagnosticCode>(\n code: C,\n details: DiagnosticDetails<C>,\n input: BuildInput = {},\n): Diagnostic {\n let def = getDiagnosticDefinition(code)\n let d = details as Record<string, unknown>\n if (!def) {\n def = INTERNAL\n d = {\n op: 'diagnostic:emit',\n problem: `unknown diagnostic code \"${code}\": define it with defineDiagnostic() first`,\n }\n }\n const b = def as unknown as DiagnosticDefinition<'DK_INTERNAL'>\n const dev = input.dev ?? (process.env.NODE_ENV !== \"production\")\n // Redact first: `where`, the text builders, the fingerprint and the docs URL only ever see\n // redacted data, so no consumer downstream (interceptors, sinks, strict errors) can leak it.\n const r = input.redaction ?? resolveRedaction(undefined, dev)\n const where = redactLocation(b.where(d as DiagnosticDetails<'DK_INTERNAL'>), r)\n d = redactDetails(\n d,\n def.redact as Readonly<Record<string, RedactField | undefined>> | undefined,\n where,\n r,\n )\n const dd = d as DiagnosticDetails<'DK_INTERNAL'>\n // Text: development builds, or production with `@datakable/core/messages` installed (§8.2).\n const t =\n dev || hasMessages()\n ? (getDiagnosticText(def.code) as DiagnosticText<'DK_INTERNAL'> | undefined)\n : undefined\n const whereText = formatWhere(where)\n const now = input.now ?? Date.now()\n const context: DiagnosticContext = {\n table: input.table ?? '(global)',\n package: PACKAGE,\n trigger: input.trigger ?? 'init',\n run: input.run ?? 0,\n phase: input.phase ?? defaultPhase(),\n mode: input.mode ?? {},\n state: input.state ?? { searchLength: 0, activeFilters: [], sort: [], page: 0 },\n occurrences: { count: 1, first: now, last: now },\n }\n if (input.createdAt !== undefined) context.createdAt = input.createdAt\n if (input.causedBy !== undefined) context.causedBy = input.causedBy\n if (input.cause !== undefined) context.cause = input.cause\n let docs = def.docs ?? `${DOCS}#${def.code.toLowerCase()}`\n if (!dev) {\n const hash = docs.indexOf('#')\n const params = `?v=${VERSION}&where=${encodeURIComponent(whereText)}`\n docs = hash < 0 ? docs + params : docs.slice(0, hash) + params + docs.slice(hash)\n }\n return new DiagnosticRecord(\n def.code,\n def.level,\n t ? t.problem(dd) : '',\n where,\n t ? t.impact(dd) : '',\n t ? t.fix(dd) : [],\n docs,\n d,\n context,\n `${def.code}@${whereText}`,\n )\n}\n\n/** Thrown under `strict: true` for error-level diagnostics, and for core invariants (§8.2). */\nexport class DatakableError extends Error {\n override name = 'DatakableError'\n readonly code: DiagnosticCode\n readonly level: DiagnosticLevel\n readonly problem: string\n readonly where: Location\n readonly impact: string\n readonly fix: string[]\n readonly docs: string\n readonly diagnostic: Diagnostic\n\n constructor(d: Diagnostic) {\n const lines = [`${d.code}: ${d.problem || '(see docs)'}`, ` where ${formatWhere(d.where)}`]\n d.fix.forEach((f, i) => {\n lines.push(`${i === 0 ? ' fix ' : ' '}${i + 1}. ${f}`)\n })\n lines.push(` docs ${d.docs}`)\n super(lines.join('\\n'), d.context.cause === undefined ? undefined : { cause: d.context.cause })\n this.code = d.code\n this.level = d.level\n this.problem = d.problem\n this.where = d.where\n this.impact = d.impact\n this.fix = d.fix\n this.docs = d.docs\n this.diagnostic = d\n }\n}\n\n/** Deterministic programmer errors thrown at creation (`error (config)` codes, §8.6). */\nexport class DatakableConfigError extends DatakableError {\n override name = 'DatakableConfigError'\n}\n\nexport function throwConfigError<C extends DiagnosticCode>(\n code: C,\n details: DiagnosticDetails<C>,\n input?: BuildInput,\n): never {\n throw new DatakableConfigError(buildDiagnostic(code, details, input))\n}\n\n/** A core invariant broke (unregistered op, boundary installed twice): `DK_INTERNAL`. */\nexport function internalError(op: string, problem: string): DatakableError {\n return new DatakableError(buildDiagnostic('DK_INTERNAL', { op, problem }))\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/diagnostics/build.ts"],"sourcesContent":["import { VERSION } from '../version'\nimport {\n type DiagnosticCode,\n type DiagnosticDefinition,\n type DiagnosticDetails,\n type DiagnosticText,\n getDiagnosticDefinition,\n getDiagnosticText,\n hasMessages,\n} from './catalog'\nimport { coreDiagnostics } from './codes'\nimport './process-guard'\nimport { expandDetails } from './prose'\nimport {\n type RedactField,\n type Redactor,\n redactDetails,\n redactLocation,\n resolveRedaction,\n} from './redact'\nimport { toSafeJson } from './safe-json'\nimport type {\n Diagnostic,\n DiagnosticContext,\n DiagnosticLevel,\n DiagnosticStateSummary,\n Location,\n Phase,\n Trigger,\n} from './types'\n\nexport const PACKAGE = `@datakable/core@${VERSION}`\nconst DOCS = 'https://github.com/Ink01101011/datakable/blob/main/docs/errors.md'\n\n// Referencing the core entries keeps them in the bundle (`sideEffects: false`).\nconst INTERNAL = coreDiagnostics.find((d) => d.code === 'DK_INTERNAL') as DiagnosticDefinition\n\n/** Everything the enrich step adds; all optional so a diagnostic can be built outside a table. */\nexport interface BuildInput {\n table?: string\n createdAt?: string\n trigger?: Trigger\n run?: number\n phase?: Phase\n mode?: Record<string, 'client' | 'server'>\n state?: DiagnosticStateSummary\n /** Timestamp for `occurrences` (epoch ms). Default `wallClock()`. */\n now?: number\n cause?: unknown\n causedBy?: string\n /** Build the problem / impact / fix text. Default: development builds only (§8.2); production\n * builds also build it once `@datakable/core/messages` is installed. */\n dev?: boolean\n /** Redaction policy (§8.2). Default: `'keys'` when `dev`, else `'safe'`. */\n redaction?: Redactor\n}\n\n/**\n * Epoch ms read through `performance`, never `Date` (#7): Next 16 `cacheComponents` aborts a\n * prerender that reads `Date.now()` and reserves `performance` for introspection like this.\n */\nexport const wallClock = (): number =>\n typeof performance === 'object' && performance?.timeOrigin\n ? Math.floor(performance.timeOrigin + performance.now())\n : Date.now()\n\nexport const defaultPhase = (): Phase => (typeof document === 'undefined' ? 'ssr' : 'client')\n\nexport function formatWhere(where: Location): string {\n switch (where.kind) {\n case 'column':\n return `columns[${where.index}] (id \"${where.id}\")`\n case 'feature':\n return `feature \"${where.name}\"`\n case 'option':\n return `options.${where.path}`\n case 'row':\n return where.key === undefined\n ? `row #${where.index}`\n : `row #${where.index} (key ${where.key})`\n case 'interceptor':\n return `interceptor \"${where.name}\" on ${where.op}`\n case 'operation':\n return where.slot ? `operation ${where.op} at ${where.slot}` : `operation ${where.op}`\n }\n}\n\nclass DiagnosticRecord implements Diagnostic {\n constructor(\n public code: DiagnosticCode,\n public level: DiagnosticLevel,\n public problem: string,\n public where: Location,\n public impact: string,\n public fix: string[],\n public docs: string,\n public details: Record<string, unknown>,\n public context: DiagnosticContext,\n public fingerprint: string,\n ) {}\n\n toJSON(): object {\n const { cause: _cause, ...context } = this.context\n return {\n code: this.code,\n level: this.level,\n problem: this.problem,\n where: toSafeJson(this.where),\n impact: this.impact,\n fix: this.fix,\n docs: this.docs,\n details: toSafeJson(this.details),\n context: toSafeJson(context),\n fingerprint: this.fingerprint,\n }\n }\n}\n\n/**\n * Builds a diagnostic from a catalog code + details (the `enrich` step). Never throws for an unknown\n * code: that becomes `DK_INTERNAL`, so a typo in a plugin cannot take the logger down.\n */\nexport function buildDiagnostic<C extends DiagnosticCode>(\n code: C,\n details: DiagnosticDetails<C>,\n input: BuildInput = {},\n): Diagnostic {\n let def = getDiagnosticDefinition(code)\n let d = details as Record<string, unknown>\n if (!def) {\n def = INTERNAL\n d = {\n op: 'diagnostic:emit',\n problem: `unknown-code|${code}`,\n }\n }\n const b = def as unknown as DiagnosticDefinition<'DK_INTERNAL'>\n const dev = input.dev ?? (process.env.NODE_ENV !== \"production\")\n // Detail prose keys (`fallback: 'cells-undefined'`) read as sentences wherever text is built.\n if (dev || hasMessages()) d = expandDetails(d, dev)\n // Redact first: `where`, the text builders, the fingerprint and the docs URL only ever see\n // redacted data, so no consumer downstream (interceptors, sinks, strict errors) can leak it.\n const r = input.redaction ?? resolveRedaction(undefined, dev)\n const where = redactLocation(b.where(d as DiagnosticDetails<'DK_INTERNAL'>), r)\n d = redactDetails(\n d,\n def.redact as Readonly<Record<string, RedactField | undefined>> | undefined,\n where,\n r,\n )\n const dd = d as DiagnosticDetails<'DK_INTERNAL'>\n // Text: development builds, or production with `@datakable/core/messages` installed (§8.2).\n const t =\n dev || hasMessages()\n ? (getDiagnosticText(def.code) as DiagnosticText<'DK_INTERNAL'> | undefined)\n : undefined\n const whereText = formatWhere(where)\n const now = input.now ?? wallClock()\n const context: DiagnosticContext = {\n table: input.table ?? '(global)',\n package: PACKAGE,\n trigger: input.trigger ?? 'init',\n run: input.run ?? 0,\n phase: input.phase ?? defaultPhase(),\n mode: input.mode ?? {},\n state: input.state ?? { searchLength: 0, activeFilters: [], sort: [], page: 0 },\n occurrences: { count: 1, first: now, last: now },\n }\n if (input.createdAt !== undefined) context.createdAt = input.createdAt\n if (input.causedBy !== undefined) context.causedBy = input.causedBy\n if (input.cause !== undefined) context.cause = input.cause\n let docs = def.docs ?? `${DOCS}#${def.code.toLowerCase()}`\n if (!dev) {\n const hash = docs.indexOf('#')\n const params = `?v=${VERSION}&where=${encodeURIComponent(whereText)}`\n docs = hash < 0 ? docs + params : docs.slice(0, hash) + params + docs.slice(hash)\n }\n return new DiagnosticRecord(\n def.code,\n def.level,\n t ? t.problem(dd) : '',\n where,\n t ? t.impact(dd) : '',\n t ? t.fix(dd) : [],\n docs,\n d,\n context,\n `${def.code}@${whereText}`,\n )\n}\n\n/** Thrown under `strict: true` for error-level diagnostics, and for core invariants (§8.2). */\nexport class DatakableError extends Error {\n override name = 'DatakableError'\n readonly code: DiagnosticCode\n readonly level: DiagnosticLevel\n readonly problem: string\n readonly where: Location\n readonly impact: string\n readonly fix: string[]\n readonly docs: string\n readonly diagnostic: Diagnostic\n\n constructor(d: Diagnostic) {\n const lines = [`${d.code}: ${d.problem || '(see docs)'}`, ` where ${formatWhere(d.where)}`]\n d.fix.forEach((f, i) => {\n lines.push(`${i === 0 ? ' fix ' : ' '}${i + 1}. ${f}`)\n })\n lines.push(` docs ${d.docs}`)\n super(lines.join('\\n'), d.context.cause === undefined ? undefined : { cause: d.context.cause })\n this.code = d.code\n this.level = d.level\n this.problem = d.problem\n this.where = d.where\n this.impact = d.impact\n this.fix = d.fix\n this.docs = d.docs\n this.diagnostic = d\n }\n}\n\n/** Deterministic programmer errors thrown at creation (`error (config)` codes, §8.6). */\nexport class DatakableConfigError extends DatakableError {\n override name = 'DatakableConfigError'\n}\n\nexport function throwConfigError<C extends DiagnosticCode>(\n code: C,\n details: DiagnosticDetails<C>,\n input?: BuildInput,\n): never {\n throw new DatakableConfigError(buildDiagnostic(code, details, input))\n}\n\n/** A core invariant broke (unregistered op, boundary installed twice): `DK_INTERNAL`. */\nexport function internalError(op: string, problem: string): DatakableError {\n return new DatakableError(buildDiagnostic('DK_INTERNAL', { op, problem }))\n}\n"],"mappings":"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","names":[]}
@@ -6,6 +6,8 @@ import {
6
6
  hasMessages
7
7
  } from "./catalog.js";
8
8
  import { coreDiagnostics } from "./codes.js";
9
+ import "./process-guard.js";
10
+ import { expandDetails } from "./prose.js";
9
11
  import {
10
12
  redactDetails,
11
13
  redactLocation,
@@ -15,6 +17,7 @@ import { toSafeJson } from "./safe-json.js";
15
17
  var PACKAGE = `@datakable/core@${VERSION}`;
16
18
  var DOCS = "https://github.com/Ink01101011/datakable/blob/main/docs/errors.md";
17
19
  var INTERNAL = coreDiagnostics.find((d) => d.code === "DK_INTERNAL");
20
+ var wallClock = () => typeof performance === "object" && performance?.timeOrigin ? Math.floor(performance.timeOrigin + performance.now()) : Date.now();
18
21
  var defaultPhase = () => typeof document === "undefined" ? "ssr" : "client";
19
22
  function formatWhere(where) {
20
23
  switch (where.kind) {
@@ -68,11 +71,12 @@ function buildDiagnostic(code, details, input = {}) {
68
71
  def = INTERNAL;
69
72
  d = {
70
73
  op: "diagnostic:emit",
71
- problem: `unknown diagnostic code "${code}": define it with defineDiagnostic() first`
74
+ problem: `unknown-code|${code}`
72
75
  };
73
76
  }
74
77
  const b = def;
75
78
  const dev = input.dev ?? process.env.NODE_ENV !== "production";
79
+ if (dev || hasMessages()) d = expandDetails(d, dev);
76
80
  const r = input.redaction ?? resolveRedaction(void 0, dev);
77
81
  const where = redactLocation(b.where(d), r);
78
82
  d = redactDetails(
@@ -84,7 +88,7 @@ function buildDiagnostic(code, details, input = {}) {
84
88
  const dd = d;
85
89
  const t = dev || hasMessages() ? getDiagnosticText(def.code) : void 0;
86
90
  const whereText = formatWhere(where);
87
- const now = input.now ?? Date.now();
91
+ const now = input.now ?? wallClock();
88
92
  const context = {
89
93
  table: input.table ?? "(global)",
90
94
  package: PACKAGE,
@@ -156,6 +160,7 @@ export {
156
160
  defaultPhase,
157
161
  formatWhere,
158
162
  internalError,
159
- throwConfigError
163
+ throwConfigError,
164
+ wallClock
160
165
  };
161
166
  //# sourceMappingURL=build.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/diagnostics/build.ts"],"sourcesContent":["import { VERSION } from '../version'\nimport {\n type DiagnosticCode,\n type DiagnosticDefinition,\n type DiagnosticDetails,\n type DiagnosticText,\n getDiagnosticDefinition,\n getDiagnosticText,\n hasMessages,\n} from './catalog'\nimport { coreDiagnostics } from './codes'\nimport {\n type RedactField,\n type Redactor,\n redactDetails,\n redactLocation,\n resolveRedaction,\n} from './redact'\nimport { toSafeJson } from './safe-json'\nimport type {\n Diagnostic,\n DiagnosticContext,\n DiagnosticLevel,\n DiagnosticStateSummary,\n Location,\n Phase,\n Trigger,\n} from './types'\n\nexport const PACKAGE = `@datakable/core@${VERSION}`\nconst DOCS = 'https://github.com/Ink01101011/datakable/blob/main/docs/errors.md'\n\n// Referencing the core entries keeps them in the bundle (`sideEffects: false`).\nconst INTERNAL = coreDiagnostics.find((d) => d.code === 'DK_INTERNAL') as DiagnosticDefinition\n\n/** Everything the enrich step adds; all optional so a diagnostic can be built outside a table. */\nexport interface BuildInput {\n table?: string\n createdAt?: string\n trigger?: Trigger\n run?: number\n phase?: Phase\n mode?: Record<string, 'client' | 'server'>\n state?: DiagnosticStateSummary\n /** Timestamp for `occurrences`. Default `Date.now()`. */\n now?: number\n cause?: unknown\n causedBy?: string\n /** Build the problem / impact / fix text. Default: development builds only (§8.2); production\n * builds also build it once `@datakable/core/messages` is installed. */\n dev?: boolean\n /** Redaction policy (§8.2). Default: `'keys'` when `dev`, else `'safe'`. */\n redaction?: Redactor\n}\n\nexport const defaultPhase = (): Phase => (typeof document === 'undefined' ? 'ssr' : 'client')\n\nexport function formatWhere(where: Location): string {\n switch (where.kind) {\n case 'column':\n return `columns[${where.index}] (id \"${where.id}\")`\n case 'feature':\n return `feature \"${where.name}\"`\n case 'option':\n return `options.${where.path}`\n case 'row':\n return where.key === undefined\n ? `row #${where.index}`\n : `row #${where.index} (key ${where.key})`\n case 'interceptor':\n return `interceptor \"${where.name}\" on ${where.op}`\n case 'operation':\n return where.slot ? `operation ${where.op} at ${where.slot}` : `operation ${where.op}`\n }\n}\n\nclass DiagnosticRecord implements Diagnostic {\n constructor(\n public code: DiagnosticCode,\n public level: DiagnosticLevel,\n public problem: string,\n public where: Location,\n public impact: string,\n public fix: string[],\n public docs: string,\n public details: Record<string, unknown>,\n public context: DiagnosticContext,\n public fingerprint: string,\n ) {}\n\n toJSON(): object {\n const { cause: _cause, ...context } = this.context\n return {\n code: this.code,\n level: this.level,\n problem: this.problem,\n where: toSafeJson(this.where),\n impact: this.impact,\n fix: this.fix,\n docs: this.docs,\n details: toSafeJson(this.details),\n context: toSafeJson(context),\n fingerprint: this.fingerprint,\n }\n }\n}\n\n/**\n * Builds a diagnostic from a catalog code + details (the `enrich` step). Never throws for an unknown\n * code: that becomes `DK_INTERNAL`, so a typo in a plugin cannot take the logger down.\n */\nexport function buildDiagnostic<C extends DiagnosticCode>(\n code: C,\n details: DiagnosticDetails<C>,\n input: BuildInput = {},\n): Diagnostic {\n let def = getDiagnosticDefinition(code)\n let d = details as Record<string, unknown>\n if (!def) {\n def = INTERNAL\n d = {\n op: 'diagnostic:emit',\n problem: `unknown diagnostic code \"${code}\": define it with defineDiagnostic() first`,\n }\n }\n const b = def as unknown as DiagnosticDefinition<'DK_INTERNAL'>\n const dev = input.dev ?? (process.env.NODE_ENV !== \"production\")\n // Redact first: `where`, the text builders, the fingerprint and the docs URL only ever see\n // redacted data, so no consumer downstream (interceptors, sinks, strict errors) can leak it.\n const r = input.redaction ?? resolveRedaction(undefined, dev)\n const where = redactLocation(b.where(d as DiagnosticDetails<'DK_INTERNAL'>), r)\n d = redactDetails(\n d,\n def.redact as Readonly<Record<string, RedactField | undefined>> | undefined,\n where,\n r,\n )\n const dd = d as DiagnosticDetails<'DK_INTERNAL'>\n // Text: development builds, or production with `@datakable/core/messages` installed (§8.2).\n const t =\n dev || hasMessages()\n ? (getDiagnosticText(def.code) as DiagnosticText<'DK_INTERNAL'> | undefined)\n : undefined\n const whereText = formatWhere(where)\n const now = input.now ?? Date.now()\n const context: DiagnosticContext = {\n table: input.table ?? '(global)',\n package: PACKAGE,\n trigger: input.trigger ?? 'init',\n run: input.run ?? 0,\n phase: input.phase ?? defaultPhase(),\n mode: input.mode ?? {},\n state: input.state ?? { searchLength: 0, activeFilters: [], sort: [], page: 0 },\n occurrences: { count: 1, first: now, last: now },\n }\n if (input.createdAt !== undefined) context.createdAt = input.createdAt\n if (input.causedBy !== undefined) context.causedBy = input.causedBy\n if (input.cause !== undefined) context.cause = input.cause\n let docs = def.docs ?? `${DOCS}#${def.code.toLowerCase()}`\n if (!dev) {\n const hash = docs.indexOf('#')\n const params = `?v=${VERSION}&where=${encodeURIComponent(whereText)}`\n docs = hash < 0 ? docs + params : docs.slice(0, hash) + params + docs.slice(hash)\n }\n return new DiagnosticRecord(\n def.code,\n def.level,\n t ? t.problem(dd) : '',\n where,\n t ? t.impact(dd) : '',\n t ? t.fix(dd) : [],\n docs,\n d,\n context,\n `${def.code}@${whereText}`,\n )\n}\n\n/** Thrown under `strict: true` for error-level diagnostics, and for core invariants (§8.2). */\nexport class DatakableError extends Error {\n override name = 'DatakableError'\n readonly code: DiagnosticCode\n readonly level: DiagnosticLevel\n readonly problem: string\n readonly where: Location\n readonly impact: string\n readonly fix: string[]\n readonly docs: string\n readonly diagnostic: Diagnostic\n\n constructor(d: Diagnostic) {\n const lines = [`${d.code}: ${d.problem || '(see docs)'}`, ` where ${formatWhere(d.where)}`]\n d.fix.forEach((f, i) => {\n lines.push(`${i === 0 ? ' fix ' : ' '}${i + 1}. ${f}`)\n })\n lines.push(` docs ${d.docs}`)\n super(lines.join('\\n'), d.context.cause === undefined ? undefined : { cause: d.context.cause })\n this.code = d.code\n this.level = d.level\n this.problem = d.problem\n this.where = d.where\n this.impact = d.impact\n this.fix = d.fix\n this.docs = d.docs\n this.diagnostic = d\n }\n}\n\n/** Deterministic programmer errors thrown at creation (`error (config)` codes, §8.6). */\nexport class DatakableConfigError extends DatakableError {\n override name = 'DatakableConfigError'\n}\n\nexport function throwConfigError<C extends DiagnosticCode>(\n code: C,\n details: DiagnosticDetails<C>,\n input?: BuildInput,\n): never {\n throw new DatakableConfigError(buildDiagnostic(code, details, input))\n}\n\n/** A core invariant broke (unregistered op, boundary installed twice): `DK_INTERNAL`. */\nexport function internalError(op: string, problem: string): DatakableError {\n return new DatakableError(buildDiagnostic('DK_INTERNAL', { op, problem }))\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/diagnostics/build.ts"],"sourcesContent":["import { VERSION } from '../version'\nimport {\n type DiagnosticCode,\n type DiagnosticDefinition,\n type DiagnosticDetails,\n type DiagnosticText,\n getDiagnosticDefinition,\n getDiagnosticText,\n hasMessages,\n} from './catalog'\nimport { coreDiagnostics } from './codes'\nimport './process-guard'\nimport { expandDetails } from './prose'\nimport {\n type RedactField,\n type Redactor,\n redactDetails,\n redactLocation,\n resolveRedaction,\n} from './redact'\nimport { toSafeJson } from './safe-json'\nimport type {\n Diagnostic,\n DiagnosticContext,\n DiagnosticLevel,\n DiagnosticStateSummary,\n Location,\n Phase,\n Trigger,\n} from './types'\n\nexport const PACKAGE = `@datakable/core@${VERSION}`\nconst DOCS = 'https://github.com/Ink01101011/datakable/blob/main/docs/errors.md'\n\n// Referencing the core entries keeps them in the bundle (`sideEffects: false`).\nconst INTERNAL = coreDiagnostics.find((d) => d.code === 'DK_INTERNAL') as DiagnosticDefinition\n\n/** Everything the enrich step adds; all optional so a diagnostic can be built outside a table. */\nexport interface BuildInput {\n table?: string\n createdAt?: string\n trigger?: Trigger\n run?: number\n phase?: Phase\n mode?: Record<string, 'client' | 'server'>\n state?: DiagnosticStateSummary\n /** Timestamp for `occurrences` (epoch ms). Default `wallClock()`. */\n now?: number\n cause?: unknown\n causedBy?: string\n /** Build the problem / impact / fix text. Default: development builds only (§8.2); production\n * builds also build it once `@datakable/core/messages` is installed. */\n dev?: boolean\n /** Redaction policy (§8.2). Default: `'keys'` when `dev`, else `'safe'`. */\n redaction?: Redactor\n}\n\n/**\n * Epoch ms read through `performance`, never `Date` (#7): Next 16 `cacheComponents` aborts a\n * prerender that reads `Date.now()` and reserves `performance` for introspection like this.\n */\nexport const wallClock = (): number =>\n typeof performance === 'object' && performance?.timeOrigin\n ? Math.floor(performance.timeOrigin + performance.now())\n : Date.now()\n\nexport const defaultPhase = (): Phase => (typeof document === 'undefined' ? 'ssr' : 'client')\n\nexport function formatWhere(where: Location): string {\n switch (where.kind) {\n case 'column':\n return `columns[${where.index}] (id \"${where.id}\")`\n case 'feature':\n return `feature \"${where.name}\"`\n case 'option':\n return `options.${where.path}`\n case 'row':\n return where.key === undefined\n ? `row #${where.index}`\n : `row #${where.index} (key ${where.key})`\n case 'interceptor':\n return `interceptor \"${where.name}\" on ${where.op}`\n case 'operation':\n return where.slot ? `operation ${where.op} at ${where.slot}` : `operation ${where.op}`\n }\n}\n\nclass DiagnosticRecord implements Diagnostic {\n constructor(\n public code: DiagnosticCode,\n public level: DiagnosticLevel,\n public problem: string,\n public where: Location,\n public impact: string,\n public fix: string[],\n public docs: string,\n public details: Record<string, unknown>,\n public context: DiagnosticContext,\n public fingerprint: string,\n ) {}\n\n toJSON(): object {\n const { cause: _cause, ...context } = this.context\n return {\n code: this.code,\n level: this.level,\n problem: this.problem,\n where: toSafeJson(this.where),\n impact: this.impact,\n fix: this.fix,\n docs: this.docs,\n details: toSafeJson(this.details),\n context: toSafeJson(context),\n fingerprint: this.fingerprint,\n }\n }\n}\n\n/**\n * Builds a diagnostic from a catalog code + details (the `enrich` step). Never throws for an unknown\n * code: that becomes `DK_INTERNAL`, so a typo in a plugin cannot take the logger down.\n */\nexport function buildDiagnostic<C extends DiagnosticCode>(\n code: C,\n details: DiagnosticDetails<C>,\n input: BuildInput = {},\n): Diagnostic {\n let def = getDiagnosticDefinition(code)\n let d = details as Record<string, unknown>\n if (!def) {\n def = INTERNAL\n d = {\n op: 'diagnostic:emit',\n problem: `unknown-code|${code}`,\n }\n }\n const b = def as unknown as DiagnosticDefinition<'DK_INTERNAL'>\n const dev = input.dev ?? (process.env.NODE_ENV !== \"production\")\n // Detail prose keys (`fallback: 'cells-undefined'`) read as sentences wherever text is built.\n if (dev || hasMessages()) d = expandDetails(d, dev)\n // Redact first: `where`, the text builders, the fingerprint and the docs URL only ever see\n // redacted data, so no consumer downstream (interceptors, sinks, strict errors) can leak it.\n const r = input.redaction ?? resolveRedaction(undefined, dev)\n const where = redactLocation(b.where(d as DiagnosticDetails<'DK_INTERNAL'>), r)\n d = redactDetails(\n d,\n def.redact as Readonly<Record<string, RedactField | undefined>> | undefined,\n where,\n r,\n )\n const dd = d as DiagnosticDetails<'DK_INTERNAL'>\n // Text: development builds, or production with `@datakable/core/messages` installed (§8.2).\n const t =\n dev || hasMessages()\n ? (getDiagnosticText(def.code) as DiagnosticText<'DK_INTERNAL'> | undefined)\n : undefined\n const whereText = formatWhere(where)\n const now = input.now ?? wallClock()\n const context: DiagnosticContext = {\n table: input.table ?? '(global)',\n package: PACKAGE,\n trigger: input.trigger ?? 'init',\n run: input.run ?? 0,\n phase: input.phase ?? defaultPhase(),\n mode: input.mode ?? {},\n state: input.state ?? { searchLength: 0, activeFilters: [], sort: [], page: 0 },\n occurrences: { count: 1, first: now, last: now },\n }\n if (input.createdAt !== undefined) context.createdAt = input.createdAt\n if (input.causedBy !== undefined) context.causedBy = input.causedBy\n if (input.cause !== undefined) context.cause = input.cause\n let docs = def.docs ?? `${DOCS}#${def.code.toLowerCase()}`\n if (!dev) {\n const hash = docs.indexOf('#')\n const params = `?v=${VERSION}&where=${encodeURIComponent(whereText)}`\n docs = hash < 0 ? docs + params : docs.slice(0, hash) + params + docs.slice(hash)\n }\n return new DiagnosticRecord(\n def.code,\n def.level,\n t ? t.problem(dd) : '',\n where,\n t ? t.impact(dd) : '',\n t ? t.fix(dd) : [],\n docs,\n d,\n context,\n `${def.code}@${whereText}`,\n )\n}\n\n/** Thrown under `strict: true` for error-level diagnostics, and for core invariants (§8.2). */\nexport class DatakableError extends Error {\n override name = 'DatakableError'\n readonly code: DiagnosticCode\n readonly level: DiagnosticLevel\n readonly problem: string\n readonly where: Location\n readonly impact: string\n readonly fix: string[]\n readonly docs: string\n readonly diagnostic: Diagnostic\n\n constructor(d: Diagnostic) {\n const lines = [`${d.code}: ${d.problem || '(see docs)'}`, ` where ${formatWhere(d.where)}`]\n d.fix.forEach((f, i) => {\n lines.push(`${i === 0 ? ' fix ' : ' '}${i + 1}. ${f}`)\n })\n lines.push(` docs ${d.docs}`)\n super(lines.join('\\n'), d.context.cause === undefined ? undefined : { cause: d.context.cause })\n this.code = d.code\n this.level = d.level\n this.problem = d.problem\n this.where = d.where\n this.impact = d.impact\n this.fix = d.fix\n this.docs = d.docs\n this.diagnostic = d\n }\n}\n\n/** Deterministic programmer errors thrown at creation (`error (config)` codes, §8.6). */\nexport class DatakableConfigError extends DatakableError {\n override name = 'DatakableConfigError'\n}\n\nexport function throwConfigError<C extends DiagnosticCode>(\n code: C,\n details: DiagnosticDetails<C>,\n input?: BuildInput,\n): never {\n throw new DatakableConfigError(buildDiagnostic(code, details, input))\n}\n\n/** A core invariant broke (unregistered op, boundary installed twice): `DK_INTERNAL`. */\nexport function internalError(op: string, problem: string): DatakableError {\n return new DatakableError(buildDiagnostic('DK_INTERNAL', { op, problem }))\n}\n"],"mappings":"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","names":[]}
@@ -25,18 +25,22 @@ __export(catalog_exports, {
25
25
  getDiagnosticText: () => getDiagnosticText,
26
26
  hasMessages: () => hasMessages,
27
27
  installMessages: () => installMessages,
28
+ installedText: () => installedText,
28
29
  keepDiagnostics: () => keepDiagnostics,
29
30
  listDiagnosticCodes: () => listDiagnosticCodes
30
31
  });
31
32
  module.exports = __toCommonJS(catalog_exports);
33
+ var import_process_guard = require("./process-guard.cjs");
32
34
  var registry = /* @__PURE__ */ new Map();
33
35
  function defineDiagnostic(meta, text) {
34
36
  const definition = text ? { ...meta, ...text } : meta;
35
- const prev = registry.get(definition.code);
36
- if (process.env.NODE_ENV !== "production" && prev && prev.level !== definition.level) {
37
- throw new Error(
38
- `[DataKable] diagnostic code ${definition.code} is already defined as level "${prev.level}"; codes are never redefined \u2014 pick a new code`
39
- );
37
+ if (process.env.NODE_ENV !== "production") {
38
+ const prev = registry.get(definition.code);
39
+ if (prev && prev.level !== definition.level) {
40
+ throw new Error(
41
+ `[DataKable] diagnostic code ${definition.code} is already defined as level "${prev.level}"; codes are never redefined \u2014 pick a new code`
42
+ );
43
+ }
40
44
  }
41
45
  registry.set(definition.code, definition);
42
46
  return definition;
@@ -47,6 +51,7 @@ function installMessages(...all) {
47
51
  for (const code of Object.keys(m)) messages.set(code, m[code]);
48
52
  }
49
53
  }
54
+ var installedText = (key) => messages.get(key);
50
55
  var hasMessages = () => messages.size > 0;
51
56
  function getDiagnosticText(code) {
52
57
  const def = registry.get(code);
@@ -70,6 +75,7 @@ function listDiagnosticCodes() {
70
75
  getDiagnosticText,
71
76
  hasMessages,
72
77
  installMessages,
78
+ installedText,
73
79
  keepDiagnostics,
74
80
  listDiagnosticCodes
75
81
  });
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/diagnostics/catalog.ts"],"sourcesContent":["import type { RedactField } from './redact'\nimport type { DiagnosticLevel, Location } from './types'\n\n/**\n * Code → details type, one entry per diagnostic code. Open for declaration merging, like\n * `Operations`: the module that owns a code declares its details next to its `defineDiagnostic`\n * (`declare module '@datakable/core' { interface DiagnosticCatalog { DK_X: {...} } }`).\n */\n// biome-ignore lint/suspicious/noEmptyInterface: filled by declaration merging\nexport interface DiagnosticCatalog {}\n\nexport type DiagnosticCode = keyof DiagnosticCatalog & string\nexport type DiagnosticDetails<C extends DiagnosticCode> = DiagnosticCatalog[C]\n\n/**\n * The human-readable half of a catalog entry (§8.2). The builders get the emitted details and must\n * compute their text from that real data. They run only in development, or in production after\n * `import '@datakable/core/messages'` (`datakable/messages`), so keep them pure and cheap.\n */\nexport interface DiagnosticText<C extends DiagnosticCode = DiagnosticCode> {\n problem(details: DiagnosticDetails<C>): string\n /** Consequence + the fallback applied. */\n impact(details: DiagnosticDetails<C>): string\n /** Concrete fixes, best first; never empty. */\n fix(details: DiagnosticDetails<C>): string[]\n}\n\n/** Text for several codes, keyed by code (one object per owning module). */\nexport type DiagnosticMessages<C extends DiagnosticCode> = { readonly [K in C]: DiagnosticText<K> }\n\n/**\n * One catalog entry (§3.5, §8.3). `where` runs always; the text builders (`DiagnosticText`) only in\n * development or with messages opted in.\n */\nexport interface DiagnosticDefinition<C extends DiagnosticCode = DiagnosticCode>\n extends DiagnosticText<C> {\n readonly code: C\n readonly level: DiagnosticLevel\n /** `error (config)` codes: thrown as `DatakableConfigError` at creation (§8.6). */\n readonly config?: boolean\n where(details: DiagnosticDetails<C>): Location\n /** Overrides the default `docs/errors.md#<code>` URL. */\n readonly docs?: string\n /**\n * Detail fields that carry user data (row keys, cell values, schema issues, thrown errors), so\n * redaction (§8.2) rewrites them before `where`, the text builders or any sink see them. See\n * `RedactField`. Fields not listed are logged as-is.\n */\n readonly redact?: { readonly [K in keyof DiagnosticDetails<C>]?: RedactField }\n}\n\n/** A definition without its text: the part a production bundle keeps. */\nexport type DiagnosticMeta<C extends DiagnosticCode = DiagnosticCode> = Omit<\n DiagnosticDefinition<C>,\n keyof DiagnosticText\n>\n\nconst registry = new Map<string, DiagnosticDefinition>()\n\n/**\n * Adds a code to the catalog and returns the definition. A code may be defined again only with the\n * same level (module re-evaluation); a code is never redefined with another meaning (§8.5).\n *\n * Core passes the text separately as `(process.env.NODE_ENV !== \"production\") && messages.DK_X` (§8.2): a production bundle folds that\n * to `false`, drops the module's message object, and keeps only `code`, `level`, `where` and\n * `redact`. The same message object is what `@datakable/core/messages` installs.\n */\nexport function defineDiagnostic<const C extends DiagnosticCode>(\n definition: DiagnosticDefinition<C>,\n): DiagnosticDefinition<C>\nexport function defineDiagnostic<const C extends DiagnosticCode>(\n meta: DiagnosticMeta<C>,\n text: DiagnosticText<C> | false,\n): DiagnosticDefinition<C>\nexport function defineDiagnostic<const C extends DiagnosticCode>(\n meta: DiagnosticMeta<C> & Partial<DiagnosticText<C>>,\n text?: DiagnosticText<C> | false,\n): DiagnosticDefinition<C> {\n const definition = (text ? { ...meta, ...text } : meta) as DiagnosticDefinition<C>\n const prev = registry.get(definition.code)\n // Development check: codes are fixed at build time, a production bundle skips it.\n if ((process.env.NODE_ENV !== \"production\") && prev && prev.level !== definition.level) {\n throw new Error(\n `[DataKable] diagnostic code ${definition.code} is already defined as level ` +\n `\"${prev.level}\"; codes are never redefined — pick a new code`,\n )\n }\n registry.set(definition.code, definition as unknown as DiagnosticDefinition)\n return definition\n}\n\nconst messages = new Map<string, DiagnosticText>()\n\n/**\n * Installs full message text for production builds (§8.2); called by `@datakable/core/messages`.\n * Development builds already carry the text on each definition.\n */\nexport function installMessages(...all: ReadonlyArray<Readonly<Record<string, unknown>>>): void {\n for (const m of all) {\n for (const code of Object.keys(m)) messages.set(code, m[code] as DiagnosticText)\n }\n}\n\n/** `true` once `installMessages` ran: production diagnostics then build their text too. */\nexport const hasMessages = (): boolean => messages.size > 0\n\n/** The text builders for a code: from its definition (development) or installed messages. */\nexport function getDiagnosticText(code: string): DiagnosticText | undefined {\n const def = registry.get(code)\n return def && typeof def.problem === 'function' ? def : messages.get(code)\n}\n\n/**\n * Uses the definitions of the codes a module emits, so a bundler keeps them. `@datakable/core` is\n * built one file per module with `sideEffects: false`: a codes module that is only referenced\n * (`void defs`) is dropped from a consumer's bundle together with its `defineDiagnostic` calls, and\n * the codes would then emit as unknown. Call this at the top level of the emitting module. It\n * (re-)registers the definitions, which is idempotent. `pnpm check:catalog` verifies it per bundle.\n */\nexport function keepDiagnostics(\n ...lists: ReadonlyArray<readonly { readonly code: string }[]>\n): void {\n for (const list of lists) {\n for (const def of list) registry.set(def.code, def as unknown as DiagnosticDefinition)\n }\n}\n\nexport function getDiagnosticDefinition(code: string): DiagnosticDefinition | undefined {\n return registry.get(code)\n}\n\nexport function listDiagnosticCodes(): string[] {\n return [...registry.keys()]\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAyDA,IAAM,WAAW,oBAAI,IAAkC;AAiBhD,SAAS,iBACd,MACA,MACyB;AACzB,QAAM,aAAc,OAAO,EAAE,GAAG,MAAM,GAAG,KAAK,IAAI;AAClD,QAAM,OAAO,SAAS,IAAI,WAAW,IAAI;AAEzC,MAAK,QAAQ,IAAI,aAAa,gBAAiB,QAAQ,KAAK,UAAU,WAAW,OAAO;AACtF,UAAM,IAAI;AAAA,MACR,+BAA+B,WAAW,IAAI,iCACxC,KAAK,KAAK;AAAA,IAClB;AAAA,EACF;AACA,WAAS,IAAI,WAAW,MAAM,UAA6C;AAC3E,SAAO;AACT;AAEA,IAAM,WAAW,oBAAI,IAA4B;AAM1C,SAAS,mBAAmB,KAA6D;AAC9F,aAAW,KAAK,KAAK;AACnB,eAAW,QAAQ,OAAO,KAAK,CAAC,EAAG,UAAS,IAAI,MAAM,EAAE,IAAI,CAAmB;AAAA,EACjF;AACF;AAGO,IAAM,cAAc,MAAe,SAAS,OAAO;AAGnD,SAAS,kBAAkB,MAA0C;AAC1E,QAAM,MAAM,SAAS,IAAI,IAAI;AAC7B,SAAO,OAAO,OAAO,IAAI,YAAY,aAAa,MAAM,SAAS,IAAI,IAAI;AAC3E;AASO,SAAS,mBACX,OACG;AACN,aAAW,QAAQ,OAAO;AACxB,eAAW,OAAO,KAAM,UAAS,IAAI,IAAI,MAAM,GAAsC;AAAA,EACvF;AACF;AAEO,SAAS,wBAAwB,MAAgD;AACtF,SAAO,SAAS,IAAI,IAAI;AAC1B;AAEO,SAAS,sBAAgC;AAC9C,SAAO,CAAC,GAAG,SAAS,KAAK,CAAC;AAC5B;","names":[]}
1
+ {"version":3,"sources":["../../src/diagnostics/catalog.ts"],"sourcesContent":["import './process-guard'\nimport type { RedactField } from './redact'\nimport type { DiagnosticLevel, Location } from './types'\n\n/**\n * Code → details type, one entry per diagnostic code. Open for declaration merging, like\n * `Operations`: the module that owns a code declares its details next to its `defineDiagnostic`\n * (`declare module '@datakable/core' { interface DiagnosticCatalog { DK_X: {...} } }`).\n */\n// biome-ignore lint/suspicious/noEmptyInterface: filled by declaration merging\nexport interface DiagnosticCatalog {}\n\nexport type DiagnosticCode = keyof DiagnosticCatalog & string\nexport type DiagnosticDetails<C extends DiagnosticCode> = DiagnosticCatalog[C]\n\n/**\n * The human-readable half of a catalog entry (§8.2). The builders get the emitted details and must\n * compute their text from that real data. They run only in development, or in production after\n * `import '@datakable/core/messages'` (`datakable/messages`), so keep them pure and cheap.\n */\nexport interface DiagnosticText<C extends DiagnosticCode = DiagnosticCode> {\n problem(details: DiagnosticDetails<C>): string\n /** Consequence + the fallback applied. */\n impact(details: DiagnosticDetails<C>): string\n /** Concrete fixes, best first; never empty. */\n fix(details: DiagnosticDetails<C>): string[]\n}\n\n/** Text for several codes, keyed by code (one object per owning module). */\nexport type DiagnosticMessages<C extends DiagnosticCode> = { readonly [K in C]: DiagnosticText<K> }\n\n/**\n * One catalog entry (§3.5, §8.3). `where` runs always; the text builders (`DiagnosticText`) only in\n * development or with messages opted in.\n */\nexport interface DiagnosticDefinition<C extends DiagnosticCode = DiagnosticCode>\n extends DiagnosticText<C> {\n readonly code: C\n readonly level: DiagnosticLevel\n /** `error (config)` codes: thrown as `DatakableConfigError` at creation (§8.6). */\n readonly config?: boolean\n where(details: DiagnosticDetails<C>): Location\n /** Overrides the default `docs/errors.md#<code>` URL. */\n readonly docs?: string\n /**\n * Detail fields that carry user data (row keys, cell values, schema issues, thrown errors), so\n * redaction (§8.2) rewrites them before `where`, the text builders or any sink see them. See\n * `RedactField`. Fields not listed are logged as-is.\n */\n readonly redact?: { readonly [K in keyof DiagnosticDetails<C>]?: RedactField }\n}\n\n/** A definition without its text: the part a production bundle keeps. */\nexport type DiagnosticMeta<C extends DiagnosticCode = DiagnosticCode> = Omit<\n DiagnosticDefinition<C>,\n keyof DiagnosticText\n>\n\nconst registry = new Map<string, DiagnosticDefinition>()\n\n/**\n * Adds a code to the catalog and returns the definition. A code may be defined again only with the\n * same level (module re-evaluation); a code is never redefined with another meaning (§8.5).\n *\n * Core passes the text separately as `(process.env.NODE_ENV !== \"production\") && messages.DK_X` (§8.2): a production bundle folds that\n * to `false`, drops the module's message object, and keeps only `code`, `level`, `where` and\n * `redact`. The same message object is what `@datakable/core/messages` installs.\n */\nexport function defineDiagnostic<const C extends DiagnosticCode>(\n definition: DiagnosticDefinition<C>,\n): DiagnosticDefinition<C>\nexport function defineDiagnostic<const C extends DiagnosticCode>(\n meta: DiagnosticMeta<C>,\n text: DiagnosticText<C> | false,\n): DiagnosticDefinition<C>\nexport function defineDiagnostic<const C extends DiagnosticCode>(\n meta: DiagnosticMeta<C> & Partial<DiagnosticText<C>>,\n text?: DiagnosticText<C> | false,\n): DiagnosticDefinition<C> {\n const definition = (text ? { ...meta, ...text } : meta) as DiagnosticDefinition<C>\n // Development check: codes are fixed at build time, a production bundle skips it.\n if ((process.env.NODE_ENV !== \"production\")) {\n const prev = registry.get(definition.code)\n if (prev && prev.level !== definition.level) {\n throw new Error(\n `[DataKable] diagnostic code ${definition.code} is already defined as level ` +\n `\"${prev.level}\"; codes are never redefined — pick a new code`,\n )\n }\n }\n registry.set(definition.code, definition as unknown as DiagnosticDefinition)\n return definition\n}\n\nconst messages = new Map<string, DiagnosticText>()\n\n/**\n * Installs full message text for production builds (§8.2); called by `@datakable/core/messages`.\n * Development builds already carry the text on each definition.\n */\nexport function installMessages(...all: ReadonlyArray<Readonly<Record<string, unknown>>>): void {\n for (const m of all) {\n for (const code of Object.keys(m)) messages.set(code, m[code] as DiagnosticText)\n }\n}\n\n/** An installed message by key: a code's text builders, or a detail prose sentence (`prose.ts`). */\nexport const installedText = (key: string): unknown => messages.get(key)\n\n/** `true` once `installMessages` ran: production diagnostics then build their text too. */\nexport const hasMessages = (): boolean => messages.size > 0\n\n/** The text builders for a code: from its definition (development) or installed messages. */\nexport function getDiagnosticText(code: string): DiagnosticText | undefined {\n const def = registry.get(code)\n return def && typeof def.problem === 'function' ? def : messages.get(code)\n}\n\n/**\n * Uses the definitions of the codes a module emits, so a bundler keeps them. `@datakable/core` is\n * built one file per module with `sideEffects: false`: a codes module that is only referenced\n * (`void defs`) is dropped from a consumer's bundle together with its `defineDiagnostic` calls, and\n * the codes would then emit as unknown. Call this at the top level of the emitting module. It\n * (re-)registers the definitions, which is idempotent. `pnpm check:catalog` verifies it per bundle.\n */\nexport function keepDiagnostics(\n ...lists: ReadonlyArray<readonly { readonly code: string }[]>\n): void {\n for (const list of lists) {\n for (const def of list) registry.set(def.code, def as unknown as DiagnosticDefinition)\n }\n}\n\nexport function getDiagnosticDefinition(code: string): DiagnosticDefinition | undefined {\n return registry.get(code)\n}\n\nexport function listDiagnosticCodes(): string[] {\n return [...registry.keys()]\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,2BAAO;AA0DP,IAAM,WAAW,oBAAI,IAAkC;AAiBhD,SAAS,iBACd,MACA,MACyB;AACzB,QAAM,aAAc,OAAO,EAAE,GAAG,MAAM,GAAG,KAAK,IAAI;AAElD,MAAK,QAAQ,IAAI,aAAa,cAAe;AAC3C,UAAM,OAAO,SAAS,IAAI,WAAW,IAAI;AACzC,QAAI,QAAQ,KAAK,UAAU,WAAW,OAAO;AAC3C,YAAM,IAAI;AAAA,QACR,+BAA+B,WAAW,IAAI,iCACxC,KAAK,KAAK;AAAA,MAClB;AAAA,IACF;AAAA,EACF;AACA,WAAS,IAAI,WAAW,MAAM,UAA6C;AAC3E,SAAO;AACT;AAEA,IAAM,WAAW,oBAAI,IAA4B;AAM1C,SAAS,mBAAmB,KAA6D;AAC9F,aAAW,KAAK,KAAK;AACnB,eAAW,QAAQ,OAAO,KAAK,CAAC,EAAG,UAAS,IAAI,MAAM,EAAE,IAAI,CAAmB;AAAA,EACjF;AACF;AAGO,IAAM,gBAAgB,CAAC,QAAyB,SAAS,IAAI,GAAG;AAGhE,IAAM,cAAc,MAAe,SAAS,OAAO;AAGnD,SAAS,kBAAkB,MAA0C;AAC1E,QAAM,MAAM,SAAS,IAAI,IAAI;AAC7B,SAAO,OAAO,OAAO,IAAI,YAAY,aAAa,MAAM,SAAS,IAAI,IAAI;AAC3E;AASO,SAAS,mBACX,OACG;AACN,aAAW,QAAQ,OAAO;AACxB,eAAW,OAAO,KAAM,UAAS,IAAI,IAAI,MAAM,GAAsC;AAAA,EACvF;AACF;AAEO,SAAS,wBAAwB,MAAgD;AACtF,SAAO,SAAS,IAAI,IAAI;AAC1B;AAEO,SAAS,sBAAgC;AAC9C,SAAO,CAAC,GAAG,SAAS,KAAK,CAAC;AAC5B;","names":[]}
@@ -1,12 +1,15 @@
1
1
  // src/diagnostics/catalog.ts
2
+ import "./process-guard.js";
2
3
  var registry = /* @__PURE__ */ new Map();
3
4
  function defineDiagnostic(meta, text) {
4
5
  const definition = text ? { ...meta, ...text } : meta;
5
- const prev = registry.get(definition.code);
6
- if (process.env.NODE_ENV !== "production" && prev && prev.level !== definition.level) {
7
- throw new Error(
8
- `[DataKable] diagnostic code ${definition.code} is already defined as level "${prev.level}"; codes are never redefined \u2014 pick a new code`
9
- );
6
+ if (process.env.NODE_ENV !== "production") {
7
+ const prev = registry.get(definition.code);
8
+ if (prev && prev.level !== definition.level) {
9
+ throw new Error(
10
+ `[DataKable] diagnostic code ${definition.code} is already defined as level "${prev.level}"; codes are never redefined \u2014 pick a new code`
11
+ );
12
+ }
10
13
  }
11
14
  registry.set(definition.code, definition);
12
15
  return definition;
@@ -17,6 +20,7 @@ function installMessages(...all) {
17
20
  for (const code of Object.keys(m)) messages.set(code, m[code]);
18
21
  }
19
22
  }
23
+ var installedText = (key) => messages.get(key);
20
24
  var hasMessages = () => messages.size > 0;
21
25
  function getDiagnosticText(code) {
22
26
  const def = registry.get(code);
@@ -39,6 +43,7 @@ export {
39
43
  getDiagnosticText,
40
44
  hasMessages,
41
45
  installMessages,
46
+ installedText,
42
47
  keepDiagnostics,
43
48
  listDiagnosticCodes
44
49
  };
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/diagnostics/catalog.ts"],"sourcesContent":["import type { RedactField } from './redact'\nimport type { DiagnosticLevel, Location } from './types'\n\n/**\n * Code → details type, one entry per diagnostic code. Open for declaration merging, like\n * `Operations`: the module that owns a code declares its details next to its `defineDiagnostic`\n * (`declare module '@datakable/core' { interface DiagnosticCatalog { DK_X: {...} } }`).\n */\n// biome-ignore lint/suspicious/noEmptyInterface: filled by declaration merging\nexport interface DiagnosticCatalog {}\n\nexport type DiagnosticCode = keyof DiagnosticCatalog & string\nexport type DiagnosticDetails<C extends DiagnosticCode> = DiagnosticCatalog[C]\n\n/**\n * The human-readable half of a catalog entry (§8.2). The builders get the emitted details and must\n * compute their text from that real data. They run only in development, or in production after\n * `import '@datakable/core/messages'` (`datakable/messages`), so keep them pure and cheap.\n */\nexport interface DiagnosticText<C extends DiagnosticCode = DiagnosticCode> {\n problem(details: DiagnosticDetails<C>): string\n /** Consequence + the fallback applied. */\n impact(details: DiagnosticDetails<C>): string\n /** Concrete fixes, best first; never empty. */\n fix(details: DiagnosticDetails<C>): string[]\n}\n\n/** Text for several codes, keyed by code (one object per owning module). */\nexport type DiagnosticMessages<C extends DiagnosticCode> = { readonly [K in C]: DiagnosticText<K> }\n\n/**\n * One catalog entry (§3.5, §8.3). `where` runs always; the text builders (`DiagnosticText`) only in\n * development or with messages opted in.\n */\nexport interface DiagnosticDefinition<C extends DiagnosticCode = DiagnosticCode>\n extends DiagnosticText<C> {\n readonly code: C\n readonly level: DiagnosticLevel\n /** `error (config)` codes: thrown as `DatakableConfigError` at creation (§8.6). */\n readonly config?: boolean\n where(details: DiagnosticDetails<C>): Location\n /** Overrides the default `docs/errors.md#<code>` URL. */\n readonly docs?: string\n /**\n * Detail fields that carry user data (row keys, cell values, schema issues, thrown errors), so\n * redaction (§8.2) rewrites them before `where`, the text builders or any sink see them. See\n * `RedactField`. Fields not listed are logged as-is.\n */\n readonly redact?: { readonly [K in keyof DiagnosticDetails<C>]?: RedactField }\n}\n\n/** A definition without its text: the part a production bundle keeps. */\nexport type DiagnosticMeta<C extends DiagnosticCode = DiagnosticCode> = Omit<\n DiagnosticDefinition<C>,\n keyof DiagnosticText\n>\n\nconst registry = new Map<string, DiagnosticDefinition>()\n\n/**\n * Adds a code to the catalog and returns the definition. A code may be defined again only with the\n * same level (module re-evaluation); a code is never redefined with another meaning (§8.5).\n *\n * Core passes the text separately as `(process.env.NODE_ENV !== \"production\") && messages.DK_X` (§8.2): a production bundle folds that\n * to `false`, drops the module's message object, and keeps only `code`, `level`, `where` and\n * `redact`. The same message object is what `@datakable/core/messages` installs.\n */\nexport function defineDiagnostic<const C extends DiagnosticCode>(\n definition: DiagnosticDefinition<C>,\n): DiagnosticDefinition<C>\nexport function defineDiagnostic<const C extends DiagnosticCode>(\n meta: DiagnosticMeta<C>,\n text: DiagnosticText<C> | false,\n): DiagnosticDefinition<C>\nexport function defineDiagnostic<const C extends DiagnosticCode>(\n meta: DiagnosticMeta<C> & Partial<DiagnosticText<C>>,\n text?: DiagnosticText<C> | false,\n): DiagnosticDefinition<C> {\n const definition = (text ? { ...meta, ...text } : meta) as DiagnosticDefinition<C>\n const prev = registry.get(definition.code)\n // Development check: codes are fixed at build time, a production bundle skips it.\n if ((process.env.NODE_ENV !== \"production\") && prev && prev.level !== definition.level) {\n throw new Error(\n `[DataKable] diagnostic code ${definition.code} is already defined as level ` +\n `\"${prev.level}\"; codes are never redefined — pick a new code`,\n )\n }\n registry.set(definition.code, definition as unknown as DiagnosticDefinition)\n return definition\n}\n\nconst messages = new Map<string, DiagnosticText>()\n\n/**\n * Installs full message text for production builds (§8.2); called by `@datakable/core/messages`.\n * Development builds already carry the text on each definition.\n */\nexport function installMessages(...all: ReadonlyArray<Readonly<Record<string, unknown>>>): void {\n for (const m of all) {\n for (const code of Object.keys(m)) messages.set(code, m[code] as DiagnosticText)\n }\n}\n\n/** `true` once `installMessages` ran: production diagnostics then build their text too. */\nexport const hasMessages = (): boolean => messages.size > 0\n\n/** The text builders for a code: from its definition (development) or installed messages. */\nexport function getDiagnosticText(code: string): DiagnosticText | undefined {\n const def = registry.get(code)\n return def && typeof def.problem === 'function' ? def : messages.get(code)\n}\n\n/**\n * Uses the definitions of the codes a module emits, so a bundler keeps them. `@datakable/core` is\n * built one file per module with `sideEffects: false`: a codes module that is only referenced\n * (`void defs`) is dropped from a consumer's bundle together with its `defineDiagnostic` calls, and\n * the codes would then emit as unknown. Call this at the top level of the emitting module. It\n * (re-)registers the definitions, which is idempotent. `pnpm check:catalog` verifies it per bundle.\n */\nexport function keepDiagnostics(\n ...lists: ReadonlyArray<readonly { readonly code: string }[]>\n): void {\n for (const list of lists) {\n for (const def of list) registry.set(def.code, def as unknown as DiagnosticDefinition)\n }\n}\n\nexport function getDiagnosticDefinition(code: string): DiagnosticDefinition | undefined {\n return registry.get(code)\n}\n\nexport function listDiagnosticCodes(): string[] {\n return [...registry.keys()]\n}\n"],"mappings":";AAyDA,IAAM,WAAW,oBAAI,IAAkC;AAiBhD,SAAS,iBACd,MACA,MACyB;AACzB,QAAM,aAAc,OAAO,EAAE,GAAG,MAAM,GAAG,KAAK,IAAI;AAClD,QAAM,OAAO,SAAS,IAAI,WAAW,IAAI;AAEzC,MAAK,QAAQ,IAAI,aAAa,gBAAiB,QAAQ,KAAK,UAAU,WAAW,OAAO;AACtF,UAAM,IAAI;AAAA,MACR,+BAA+B,WAAW,IAAI,iCACxC,KAAK,KAAK;AAAA,IAClB;AAAA,EACF;AACA,WAAS,IAAI,WAAW,MAAM,UAA6C;AAC3E,SAAO;AACT;AAEA,IAAM,WAAW,oBAAI,IAA4B;AAM1C,SAAS,mBAAmB,KAA6D;AAC9F,aAAW,KAAK,KAAK;AACnB,eAAW,QAAQ,OAAO,KAAK,CAAC,EAAG,UAAS,IAAI,MAAM,EAAE,IAAI,CAAmB;AAAA,EACjF;AACF;AAGO,IAAM,cAAc,MAAe,SAAS,OAAO;AAGnD,SAAS,kBAAkB,MAA0C;AAC1E,QAAM,MAAM,SAAS,IAAI,IAAI;AAC7B,SAAO,OAAO,OAAO,IAAI,YAAY,aAAa,MAAM,SAAS,IAAI,IAAI;AAC3E;AASO,SAAS,mBACX,OACG;AACN,aAAW,QAAQ,OAAO;AACxB,eAAW,OAAO,KAAM,UAAS,IAAI,IAAI,MAAM,GAAsC;AAAA,EACvF;AACF;AAEO,SAAS,wBAAwB,MAAgD;AACtF,SAAO,SAAS,IAAI,IAAI;AAC1B;AAEO,SAAS,sBAAgC;AAC9C,SAAO,CAAC,GAAG,SAAS,KAAK,CAAC;AAC5B;","names":[]}
1
+ {"version":3,"sources":["../../src/diagnostics/catalog.ts"],"sourcesContent":["import './process-guard'\nimport type { RedactField } from './redact'\nimport type { DiagnosticLevel, Location } from './types'\n\n/**\n * Code → details type, one entry per diagnostic code. Open for declaration merging, like\n * `Operations`: the module that owns a code declares its details next to its `defineDiagnostic`\n * (`declare module '@datakable/core' { interface DiagnosticCatalog { DK_X: {...} } }`).\n */\n// biome-ignore lint/suspicious/noEmptyInterface: filled by declaration merging\nexport interface DiagnosticCatalog {}\n\nexport type DiagnosticCode = keyof DiagnosticCatalog & string\nexport type DiagnosticDetails<C extends DiagnosticCode> = DiagnosticCatalog[C]\n\n/**\n * The human-readable half of a catalog entry (§8.2). The builders get the emitted details and must\n * compute their text from that real data. They run only in development, or in production after\n * `import '@datakable/core/messages'` (`datakable/messages`), so keep them pure and cheap.\n */\nexport interface DiagnosticText<C extends DiagnosticCode = DiagnosticCode> {\n problem(details: DiagnosticDetails<C>): string\n /** Consequence + the fallback applied. */\n impact(details: DiagnosticDetails<C>): string\n /** Concrete fixes, best first; never empty. */\n fix(details: DiagnosticDetails<C>): string[]\n}\n\n/** Text for several codes, keyed by code (one object per owning module). */\nexport type DiagnosticMessages<C extends DiagnosticCode> = { readonly [K in C]: DiagnosticText<K> }\n\n/**\n * One catalog entry (§3.5, §8.3). `where` runs always; the text builders (`DiagnosticText`) only in\n * development or with messages opted in.\n */\nexport interface DiagnosticDefinition<C extends DiagnosticCode = DiagnosticCode>\n extends DiagnosticText<C> {\n readonly code: C\n readonly level: DiagnosticLevel\n /** `error (config)` codes: thrown as `DatakableConfigError` at creation (§8.6). */\n readonly config?: boolean\n where(details: DiagnosticDetails<C>): Location\n /** Overrides the default `docs/errors.md#<code>` URL. */\n readonly docs?: string\n /**\n * Detail fields that carry user data (row keys, cell values, schema issues, thrown errors), so\n * redaction (§8.2) rewrites them before `where`, the text builders or any sink see them. See\n * `RedactField`. Fields not listed are logged as-is.\n */\n readonly redact?: { readonly [K in keyof DiagnosticDetails<C>]?: RedactField }\n}\n\n/** A definition without its text: the part a production bundle keeps. */\nexport type DiagnosticMeta<C extends DiagnosticCode = DiagnosticCode> = Omit<\n DiagnosticDefinition<C>,\n keyof DiagnosticText\n>\n\nconst registry = new Map<string, DiagnosticDefinition>()\n\n/**\n * Adds a code to the catalog and returns the definition. A code may be defined again only with the\n * same level (module re-evaluation); a code is never redefined with another meaning (§8.5).\n *\n * Core passes the text separately as `(process.env.NODE_ENV !== \"production\") && messages.DK_X` (§8.2): a production bundle folds that\n * to `false`, drops the module's message object, and keeps only `code`, `level`, `where` and\n * `redact`. The same message object is what `@datakable/core/messages` installs.\n */\nexport function defineDiagnostic<const C extends DiagnosticCode>(\n definition: DiagnosticDefinition<C>,\n): DiagnosticDefinition<C>\nexport function defineDiagnostic<const C extends DiagnosticCode>(\n meta: DiagnosticMeta<C>,\n text: DiagnosticText<C> | false,\n): DiagnosticDefinition<C>\nexport function defineDiagnostic<const C extends DiagnosticCode>(\n meta: DiagnosticMeta<C> & Partial<DiagnosticText<C>>,\n text?: DiagnosticText<C> | false,\n): DiagnosticDefinition<C> {\n const definition = (text ? { ...meta, ...text } : meta) as DiagnosticDefinition<C>\n // Development check: codes are fixed at build time, a production bundle skips it.\n if ((process.env.NODE_ENV !== \"production\")) {\n const prev = registry.get(definition.code)\n if (prev && prev.level !== definition.level) {\n throw new Error(\n `[DataKable] diagnostic code ${definition.code} is already defined as level ` +\n `\"${prev.level}\"; codes are never redefined — pick a new code`,\n )\n }\n }\n registry.set(definition.code, definition as unknown as DiagnosticDefinition)\n return definition\n}\n\nconst messages = new Map<string, DiagnosticText>()\n\n/**\n * Installs full message text for production builds (§8.2); called by `@datakable/core/messages`.\n * Development builds already carry the text on each definition.\n */\nexport function installMessages(...all: ReadonlyArray<Readonly<Record<string, unknown>>>): void {\n for (const m of all) {\n for (const code of Object.keys(m)) messages.set(code, m[code] as DiagnosticText)\n }\n}\n\n/** An installed message by key: a code's text builders, or a detail prose sentence (`prose.ts`). */\nexport const installedText = (key: string): unknown => messages.get(key)\n\n/** `true` once `installMessages` ran: production diagnostics then build their text too. */\nexport const hasMessages = (): boolean => messages.size > 0\n\n/** The text builders for a code: from its definition (development) or installed messages. */\nexport function getDiagnosticText(code: string): DiagnosticText | undefined {\n const def = registry.get(code)\n return def && typeof def.problem === 'function' ? def : messages.get(code)\n}\n\n/**\n * Uses the definitions of the codes a module emits, so a bundler keeps them. `@datakable/core` is\n * built one file per module with `sideEffects: false`: a codes module that is only referenced\n * (`void defs`) is dropped from a consumer's bundle together with its `defineDiagnostic` calls, and\n * the codes would then emit as unknown. Call this at the top level of the emitting module. It\n * (re-)registers the definitions, which is idempotent. `pnpm check:catalog` verifies it per bundle.\n */\nexport function keepDiagnostics(\n ...lists: ReadonlyArray<readonly { readonly code: string }[]>\n): void {\n for (const list of lists) {\n for (const def of list) registry.set(def.code, def as unknown as DiagnosticDefinition)\n }\n}\n\nexport function getDiagnosticDefinition(code: string): DiagnosticDefinition | undefined {\n return registry.get(code)\n}\n\nexport function listDiagnosticCodes(): string[] {\n return [...registry.keys()]\n}\n"],"mappings":";AAAA,OAAO;AA0DP,IAAM,WAAW,oBAAI,IAAkC;AAiBhD,SAAS,iBACd,MACA,MACyB;AACzB,QAAM,aAAc,OAAO,EAAE,GAAG,MAAM,GAAG,KAAK,IAAI;AAElD,MAAK,QAAQ,IAAI,aAAa,cAAe;AAC3C,UAAM,OAAO,SAAS,IAAI,WAAW,IAAI;AACzC,QAAI,QAAQ,KAAK,UAAU,WAAW,OAAO;AAC3C,YAAM,IAAI;AAAA,QACR,+BAA+B,WAAW,IAAI,iCACxC,KAAK,KAAK;AAAA,MAClB;AAAA,IACF;AAAA,EACF;AACA,WAAS,IAAI,WAAW,MAAM,UAA6C;AAC3E,SAAO;AACT;AAEA,IAAM,WAAW,oBAAI,IAA4B;AAM1C,SAAS,mBAAmB,KAA6D;AAC9F,aAAW,KAAK,KAAK;AACnB,eAAW,QAAQ,OAAO,KAAK,CAAC,EAAG,UAAS,IAAI,MAAM,EAAE,IAAI,CAAmB;AAAA,EACjF;AACF;AAGO,IAAM,gBAAgB,CAAC,QAAyB,SAAS,IAAI,GAAG;AAGhE,IAAM,cAAc,MAAe,SAAS,OAAO;AAGnD,SAAS,kBAAkB,MAA0C;AAC1E,QAAM,MAAM,SAAS,IAAI,IAAI;AAC7B,SAAO,OAAO,OAAO,IAAI,YAAY,aAAa,MAAM,SAAS,IAAI,IAAI;AAC3E;AASO,SAAS,mBACX,OACG;AACN,aAAW,QAAQ,OAAO;AACxB,eAAW,OAAO,KAAM,UAAS,IAAI,IAAI,MAAM,GAAsC;AAAA,EACvF;AACF;AAEO,SAAS,wBAAwB,MAAgD;AACtF,SAAO,SAAS,IAAI,IAAI;AAC1B;AAEO,SAAS,sBAAgC;AAC9C,SAAO,CAAC,GAAG,SAAS,KAAK,CAAC;AAC5B;","names":[]}
@@ -26,6 +26,7 @@ __export(codes_exports, {
26
26
  module.exports = __toCommonJS(codes_exports);
27
27
  var import_version = require("../version.cjs");
28
28
  var import_catalog = require("./catalog.cjs");
29
+ var import_process_guard = require("./process-guard.cjs");
29
30
  var ISSUES = "https://github.com/Ink01101011/datakable/issues/new";
30
31
  function issueLink(d) {
31
32
  const title = `DK_INTERNAL in ${d.op}${d.errorName ? ` (${d.errorName})` : ""}`;
@@ -89,14 +90,17 @@ var coreDiagnostics = [
89
90
  },
90
91
  process.env.NODE_ENV !== "production" && coreMessages.DK_INTERCEPTOR_FAILED
91
92
  ),
92
- (0, import_catalog.defineDiagnostic)(
93
- {
94
- code: "DK_HOT_INTERCEPTOR",
95
- level: "warn",
96
- where: (d) => ({ kind: "interceptor", name: d.interceptor, op: d.op })
97
- },
98
- process.env.NODE_ENV !== "production" && coreMessages.DK_HOT_INTERCEPTOR
99
- ),
93
+ // Dev-only warning (never emitted in production): no definition there either.
94
+ ...process.env.NODE_ENV !== "production" ? [
95
+ (0, import_catalog.defineDiagnostic)(
96
+ {
97
+ code: "DK_HOT_INTERCEPTOR",
98
+ level: "warn",
99
+ where: (d) => ({ kind: "interceptor", name: d.interceptor, op: d.op })
100
+ },
101
+ process.env.NODE_ENV !== "production" && coreMessages.DK_HOT_INTERCEPTOR
102
+ )
103
+ ] : [],
100
104
  (0, import_catalog.defineDiagnostic)(
101
105
  {
102
106
  code: "DK_OPERATION_CONFLICT",
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/diagnostics/codes.ts"],"sourcesContent":["import { VERSION } from '../version'\nimport { type DiagnosticMessages, defineDiagnostic } from './catalog'\n\ndeclare module './catalog' {\n interface DiagnosticCatalog {\n DK_INTERCEPTOR_FAILED: { interceptor: string; op: string; slot: string }\n DK_HOT_INTERCEPTOR: { interceptor: string; op: string }\n DK_OPERATION_CONFLICT: {\n op: string\n kind: string\n hot: boolean\n previousKind: string\n previousHot: boolean\n }\n DK_INTERNAL: {\n op: string\n problem: string\n /** The ctx `where` of the failed call (errorBoundary). */\n slot?: string\n /** `error.name` of the classified throw (errorBoundary). */\n errorName?: string\n /** The registry fallback applied (errorBoundary); invariant callers abort instead. */\n fallback?: string\n /**\n * `error.message` of the classified throw (errorBoundary). Engine messages embed row values\n * (`Cannot create property 'x' on string '<value>'`), so it is redacted as a cell value.\n */\n message?: unknown\n }\n }\n}\n\nconst ISSUES = 'https://github.com/Ink01101011/datakable/issues/new'\n\n/** Prefilled GitHub issue (§8.3): version, op, slot and error name — never values. */\nfunction issueLink(d: { op: string; slot?: string; errorName?: string }): string {\n const title = `DK_INTERNAL in ${d.op}${d.errorName ? ` (${d.errorName})` : ''}`\n const body = [\n `package: @datakable/core@${VERSION}`,\n `operation: ${d.op}`,\n `slot: ${d.slot ?? '-'}`,\n `error: ${d.errorName ?? '-'}`,\n '',\n 'diagnostic.toJSON():',\n '',\n 'table.explain():',\n '',\n ].join('\\n')\n return `${ISSUES}?title=${encodeURIComponent(title)}&body=${encodeURIComponent(body)}`\n}\n\n/** Message text (§8.2): development builds, or production via `@datakable/core/messages`. */\nexport const coreMessages: DiagnosticMessages<\n 'DK_INTERCEPTOR_FAILED' | 'DK_HOT_INTERCEPTOR' | 'DK_OPERATION_CONFLICT' | 'DK_INTERNAL'\n> = {\n DK_INTERCEPTOR_FAILED: {\n problem: (d) => `interceptor \"${d.interceptor}\" threw on ${d.op} (at ${d.slot})`,\n impact: () => 'the interceptor was skipped for this call; the operation ran without it',\n fix: (d) => [\n `catch errors inside \"${d.interceptor}\" and always return next() (or a valid result)`,\n `see context.cause for the original error`,\n ],\n },\n DK_HOT_INTERCEPTOR: {\n problem: (d) =>\n `interceptor \"${d.interceptor}\" is attached to hot op \"${d.op}\" without hot: true`,\n // Measured by intercept/chain.bench.ts (Apple M4 Pro, Node 25.2.1): one pass-through\n // interceptor adds ~10 ns per call; spec §9.2 measured +15% when wrapping per cell. Kept inside\n // the builder (no module constant), so production bundles carry none of it.\n impact: () =>\n 'it runs once per column per pipeline run; measured cost: ~10 ns per call per ' +\n 'interceptor (+15% on a per-cell format call, spec §9.2) on top of the interceptor body, ' +\n 'which runs columns × pipeline runs times. It still runs (dev-only warning).',\n fix: (d) => [\n `set hot: true on \"${d.interceptor}\" to accept the cost, and never loop per cell inside it`,\n `attach \"${d.interceptor}\" to cold ops only (list them in \\`on\\` instead of '*' / '${d.op}')`,\n ],\n },\n DK_OPERATION_CONFLICT: {\n problem: (d) =>\n `operation \"${d.op}\" is already registered as ${d.previousKind}` +\n `${d.previousHot ? ' (hot)' : ''}; got ${d.kind}${d.hot ? ' (hot)' : ''}`,\n impact: () => 'the registration was rejected; the first one stays in effect',\n fix: (d) => [\n `register \"${d.op}\" with the same kind and hot flag (${d.previousKind}, hot: ${d.previousHot})`,\n `or give the new operation its own name, e.g. \"myplugin:${d.op.split(':').pop()}\"`,\n ],\n },\n DK_INTERNAL: {\n problem: (d) =>\n d.errorName\n ? `${d.errorName} thrown inside DataKable code during ${d.op}` +\n `${d.message === undefined ? '' : ` (message: ${String(d.message)})`} — likely a DataKable bug`\n : d.problem,\n impact: (d) => (d.fallback ? `${d.fallback}; the table keeps working` : 'the call was aborted'),\n fix: (d) => [\n `this is likely a DataKable bug or a plugin wiring error — report it: ${issueLink(d)}`,\n 'attach diagnostic.toJSON() and table.explain() (both redacted) to the issue',\n 'meanwhile, check plugins / interceptors registered on this operation',\n ],\n },\n}\n\n/** Codes owned by core plumbing (interceptor runtime, op registry). Features define their own. */\nexport const coreDiagnostics = [\n defineDiagnostic(\n {\n code: 'DK_INTERCEPTOR_FAILED',\n level: 'error',\n where: (d) => ({ kind: 'interceptor', name: d.interceptor, op: d.op }),\n },\n (process.env.NODE_ENV !== \"production\") && coreMessages.DK_INTERCEPTOR_FAILED,\n ),\n defineDiagnostic(\n {\n code: 'DK_HOT_INTERCEPTOR',\n level: 'warn',\n where: (d) => ({ kind: 'interceptor', name: d.interceptor, op: d.op }),\n },\n (process.env.NODE_ENV !== \"production\") && coreMessages.DK_HOT_INTERCEPTOR,\n ),\n defineDiagnostic(\n {\n code: 'DK_OPERATION_CONFLICT',\n level: 'error',\n config: true,\n where: (d) => ({ kind: 'operation', op: d.op }),\n },\n (process.env.NODE_ENV !== \"production\") && coreMessages.DK_OPERATION_CONFLICT,\n ),\n // Core invariants (unknown op, boundary installed twice) and throws that errorBoundary traced to\n // DataKable's own code (top stack frame in a datakable path).\n defineDiagnostic(\n {\n code: 'DK_INTERNAL',\n level: 'error',\n where: (d) =>\n d.slot ? { kind: 'operation', op: d.op, slot: d.slot } : { kind: 'operation', op: d.op },\n redact: { message: 'value' },\n },\n (process.env.NODE_ENV !== \"production\") && coreMessages.DK_INTERNAL,\n ),\n]\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/diagnostics/codes.ts"],"sourcesContent":["import { VERSION } from '../version'\nimport { type DiagnosticMessages, defineDiagnostic } from './catalog'\nimport './process-guard'\n\ndeclare module './catalog' {\n interface DiagnosticCatalog {\n DK_INTERCEPTOR_FAILED: { interceptor: string; op: string; slot: string }\n DK_HOT_INTERCEPTOR: { interceptor: string; op: string }\n DK_OPERATION_CONFLICT: {\n op: string\n kind: string\n hot: boolean\n previousKind: string\n previousHot: boolean\n }\n DK_INTERNAL: {\n op: string\n problem: string\n /** The ctx `where` of the failed call (errorBoundary). */\n slot?: string\n /** `error.name` of the classified throw (errorBoundary). */\n errorName?: string\n /** The registry fallback applied (errorBoundary); invariant callers abort instead. */\n fallback?: string\n /**\n * `error.message` of the classified throw (errorBoundary). Engine messages embed row values\n * (`Cannot create property 'x' on string '<value>'`), so it is redacted as a cell value.\n */\n message?: unknown\n }\n }\n}\n\nconst ISSUES = 'https://github.com/Ink01101011/datakable/issues/new'\n\n/** Prefilled GitHub issue (§8.3): version, op, slot and error name — never values. */\nfunction issueLink(d: { op: string; slot?: string; errorName?: string }): string {\n const title = `DK_INTERNAL in ${d.op}${d.errorName ? ` (${d.errorName})` : ''}`\n const body = [\n `package: @datakable/core@${VERSION}`,\n `operation: ${d.op}`,\n `slot: ${d.slot ?? '-'}`,\n `error: ${d.errorName ?? '-'}`,\n '',\n 'diagnostic.toJSON():',\n '',\n 'table.explain():',\n '',\n ].join('\\n')\n return `${ISSUES}?title=${encodeURIComponent(title)}&body=${encodeURIComponent(body)}`\n}\n\n/** Message text (§8.2): development builds, or production via `@datakable/core/messages`. */\nexport const coreMessages: DiagnosticMessages<\n 'DK_INTERCEPTOR_FAILED' | 'DK_HOT_INTERCEPTOR' | 'DK_OPERATION_CONFLICT' | 'DK_INTERNAL'\n> = {\n DK_INTERCEPTOR_FAILED: {\n problem: (d) => `interceptor \"${d.interceptor}\" threw on ${d.op} (at ${d.slot})`,\n impact: () => 'the interceptor was skipped for this call; the operation ran without it',\n fix: (d) => [\n `catch errors inside \"${d.interceptor}\" and always return next() (or a valid result)`,\n `see context.cause for the original error`,\n ],\n },\n DK_HOT_INTERCEPTOR: {\n problem: (d) =>\n `interceptor \"${d.interceptor}\" is attached to hot op \"${d.op}\" without hot: true`,\n // Measured by intercept/chain.bench.ts (Apple M4 Pro, Node 25.2.1): one pass-through\n // interceptor adds ~10 ns per call; spec §9.2 measured +15% when wrapping per cell. Kept inside\n // the builder (no module constant), so production bundles carry none of it.\n impact: () =>\n 'it runs once per column per pipeline run; measured cost: ~10 ns per call per ' +\n 'interceptor (+15% on a per-cell format call, spec §9.2) on top of the interceptor body, ' +\n 'which runs columns × pipeline runs times. It still runs (dev-only warning).',\n fix: (d) => [\n `set hot: true on \"${d.interceptor}\" to accept the cost, and never loop per cell inside it`,\n `attach \"${d.interceptor}\" to cold ops only (list them in \\`on\\` instead of '*' / '${d.op}')`,\n ],\n },\n DK_OPERATION_CONFLICT: {\n problem: (d) =>\n `operation \"${d.op}\" is already registered as ${d.previousKind}` +\n `${d.previousHot ? ' (hot)' : ''}; got ${d.kind}${d.hot ? ' (hot)' : ''}`,\n impact: () => 'the registration was rejected; the first one stays in effect',\n fix: (d) => [\n `register \"${d.op}\" with the same kind and hot flag (${d.previousKind}, hot: ${d.previousHot})`,\n `or give the new operation its own name, e.g. \"myplugin:${d.op.split(':').pop()}\"`,\n ],\n },\n DK_INTERNAL: {\n problem: (d) =>\n d.errorName\n ? `${d.errorName} thrown inside DataKable code during ${d.op}` +\n `${d.message === undefined ? '' : ` (message: ${String(d.message)})`} — likely a DataKable bug`\n : d.problem,\n impact: (d) => (d.fallback ? `${d.fallback}; the table keeps working` : 'the call was aborted'),\n fix: (d) => [\n `this is likely a DataKable bug or a plugin wiring error — report it: ${issueLink(d)}`,\n 'attach diagnostic.toJSON() and table.explain() (both redacted) to the issue',\n 'meanwhile, check plugins / interceptors registered on this operation',\n ],\n },\n}\n\n/** Codes owned by core plumbing (interceptor runtime, op registry). Features define their own. */\nexport const coreDiagnostics = [\n defineDiagnostic(\n {\n code: 'DK_INTERCEPTOR_FAILED',\n level: 'error',\n where: (d) => ({ kind: 'interceptor', name: d.interceptor, op: d.op }),\n },\n (process.env.NODE_ENV !== \"production\") && coreMessages.DK_INTERCEPTOR_FAILED,\n ),\n // Dev-only warning (never emitted in production): no definition there either.\n ...((process.env.NODE_ENV !== \"production\")\n ? [\n defineDiagnostic(\n {\n code: 'DK_HOT_INTERCEPTOR',\n level: 'warn',\n where: (d) => ({ kind: 'interceptor', name: d.interceptor, op: d.op }),\n },\n (process.env.NODE_ENV !== \"production\") && coreMessages.DK_HOT_INTERCEPTOR,\n ),\n ]\n : []),\n defineDiagnostic(\n {\n code: 'DK_OPERATION_CONFLICT',\n level: 'error',\n config: true,\n where: (d) => ({ kind: 'operation', op: d.op }),\n },\n (process.env.NODE_ENV !== \"production\") && coreMessages.DK_OPERATION_CONFLICT,\n ),\n // Core invariants (unknown op, boundary installed twice) and throws that errorBoundary traced to\n // DataKable's own code (top stack frame in a datakable path).\n defineDiagnostic(\n {\n code: 'DK_INTERNAL',\n level: 'error',\n where: (d) =>\n d.slot ? { kind: 'operation', op: d.op, slot: d.slot } : { kind: 'operation', op: d.op },\n redact: { message: 'value' },\n },\n (process.env.NODE_ENV !== \"production\") && coreMessages.DK_INTERNAL,\n ),\n]\n"],"mappings":"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","names":[]}