@datakable/core 1.0.1 → 2.0.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 (280) hide show
  1. package/README.md +5 -3
  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-OsjAR3Wz.d.cts → codes-B9bCK73-.d.cts} +30 -4
  11. package/dist/{codes-OsjAR3Wz.d.ts → codes-B9bCK73-.d.ts} +30 -4
  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 +4 -1
  20. package/dist/diagnostics/build.cjs.map +1 -1
  21. package/dist/diagnostics/build.js +4 -1
  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 +5 -4
  48. package/dist/diagnostics/hub.cjs.map +1 -1
  49. package/dist/diagnostics/hub.js +5 -4
  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-vkD2cewE.d.cts → explain-Q8Cg0cZy.d.cts} +13 -4
  73. package/dist/{explain-Dn99IQt0.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/install.cjs +4 -3
  79. package/dist/feature/install.cjs.map +1 -1
  80. package/dist/feature/install.js +4 -3
  81. package/dist/feature/install.js.map +1 -1
  82. package/dist/features/column-filters/codes.cjs +1 -0
  83. package/dist/features/column-filters/codes.cjs.map +1 -1
  84. package/dist/features/column-filters/codes.js +1 -0
  85. package/dist/features/column-filters/codes.js.map +1 -1
  86. package/dist/features/column-filters/column-filters.cjs +4 -2
  87. package/dist/features/column-filters/column-filters.cjs.map +1 -1
  88. package/dist/features/column-filters/column-filters.js +4 -2
  89. package/dist/features/column-filters/column-filters.js.map +1 -1
  90. package/dist/features/column-filters/match.cjs +5 -5
  91. package/dist/features/column-filters/match.cjs.map +1 -1
  92. package/dist/features/column-filters/match.js +5 -5
  93. package/dist/features/column-filters/match.js.map +1 -1
  94. package/dist/features/pagination/codes.cjs +1 -0
  95. package/dist/features/pagination/codes.cjs.map +1 -1
  96. package/dist/features/pagination/codes.js +1 -0
  97. package/dist/features/pagination/codes.js.map +1 -1
  98. package/dist/features/pagination/pagination.cjs +16 -13
  99. package/dist/features/pagination/pagination.cjs.map +1 -1
  100. package/dist/features/pagination/pagination.js +16 -13
  101. package/dist/features/pagination/pagination.js.map +1 -1
  102. package/dist/features/search/codes.cjs +1 -0
  103. package/dist/features/search/codes.cjs.map +1 -1
  104. package/dist/features/search/codes.js +1 -0
  105. package/dist/features/search/codes.js.map +1 -1
  106. package/dist/features/search/search-index.cjs +68 -15
  107. package/dist/features/search/search-index.cjs.map +1 -1
  108. package/dist/features/search/search-index.js +68 -15
  109. package/dist/features/search/search-index.js.map +1 -1
  110. package/dist/features/search/search.cjs +41 -9
  111. package/dist/features/search/search.cjs.map +1 -1
  112. package/dist/features/search/search.js +41 -9
  113. package/dist/features/search/search.js.map +1 -1
  114. package/dist/features/search/skipped-codes.cjs +45 -0
  115. package/dist/features/search/skipped-codes.cjs.map +1 -0
  116. package/dist/features/search/skipped-codes.js +20 -0
  117. package/dist/features/search/skipped-codes.js.map +1 -0
  118. package/dist/features/sorting/codes.cjs +1 -0
  119. package/dist/features/sorting/codes.cjs.map +1 -1
  120. package/dist/features/sorting/codes.js +1 -0
  121. package/dist/features/sorting/codes.js.map +1 -1
  122. package/dist/features/sorting/sorting.cjs +16 -20
  123. package/dist/features/sorting/sorting.cjs.map +1 -1
  124. package/dist/features/sorting/sorting.js +16 -20
  125. package/dist/features/sorting/sorting.js.map +1 -1
  126. package/dist/features/sorting/strategy.cjs +4 -4
  127. package/dist/features/sorting/strategy.cjs.map +1 -1
  128. package/dist/features/sorting/strategy.js +4 -4
  129. package/dist/features/sorting/strategy.js.map +1 -1
  130. package/dist/features/validity/codes.cjs +1 -0
  131. package/dist/features/validity/codes.cjs.map +1 -1
  132. package/dist/features/validity/codes.js +1 -0
  133. package/dist/features/validity/codes.js.map +1 -1
  134. package/dist/features/validity/validity.cjs +3 -3
  135. package/dist/features/validity/validity.cjs.map +1 -1
  136. package/dist/features/validity/validity.js +3 -3
  137. package/dist/features/validity/validity.js.map +1 -1
  138. package/dist/index.d.cts +13 -10
  139. package/dist/index.d.ts +13 -10
  140. package/dist/ingest/data-check-codes.cjs +4 -2
  141. package/dist/ingest/data-check-codes.cjs.map +1 -1
  142. package/dist/ingest/data-check-codes.js +4 -2
  143. package/dist/ingest/data-check-codes.js.map +1 -1
  144. package/dist/ingest/data-checks.cjs +1 -1
  145. package/dist/ingest/data-checks.cjs.map +1 -1
  146. package/dist/ingest/data-checks.js +1 -1
  147. package/dist/ingest/data-checks.js.map +1 -1
  148. package/dist/ingest/row-key-codes.cjs +1 -0
  149. package/dist/ingest/row-key-codes.cjs.map +1 -1
  150. package/dist/ingest/row-key-codes.js +1 -0
  151. package/dist/ingest/row-key-codes.js.map +1 -1
  152. package/dist/ingest/row-key.cjs +23 -20
  153. package/dist/ingest/row-key.cjs.map +1 -1
  154. package/dist/ingest/row-key.js +23 -20
  155. package/dist/ingest/row-key.js.map +1 -1
  156. package/dist/ingest/schema-codes.cjs +1 -0
  157. package/dist/ingest/schema-codes.cjs.map +1 -1
  158. package/dist/ingest/schema-codes.js +1 -0
  159. package/dist/ingest/schema-codes.js.map +1 -1
  160. package/dist/ingest/unique-fields.cjs +2 -2
  161. package/dist/ingest/unique-fields.cjs.map +1 -1
  162. package/dist/ingest/unique-fields.js +2 -2
  163. package/dist/ingest/unique-fields.js.map +1 -1
  164. package/dist/intercept/boundary.cjs +4 -2
  165. package/dist/intercept/boundary.cjs.map +1 -1
  166. package/dist/intercept/boundary.js +4 -2
  167. package/dist/intercept/boundary.js.map +1 -1
  168. package/dist/intercept/cell-batch.cjs +4 -4
  169. package/dist/intercept/cell-batch.cjs.map +1 -1
  170. package/dist/intercept/cell-batch.js +4 -4
  171. package/dist/intercept/cell-batch.js.map +1 -1
  172. package/dist/intercept/codes.cjs +1 -0
  173. package/dist/intercept/codes.cjs.map +1 -1
  174. package/dist/intercept/codes.js +1 -0
  175. package/dist/intercept/codes.js.map +1 -1
  176. package/dist/intercept/fallbacks.cjs +12 -20
  177. package/dist/intercept/fallbacks.cjs.map +1 -1
  178. package/dist/intercept/fallbacks.js +12 -20
  179. package/dist/intercept/fallbacks.js.map +1 -1
  180. package/dist/intercept/runtime.cjs +7 -9
  181. package/dist/intercept/runtime.cjs.map +1 -1
  182. package/dist/intercept/runtime.js +7 -9
  183. package/dist/intercept/runtime.js.map +1 -1
  184. package/dist/messages/index.cjs +4 -1
  185. package/dist/messages/index.cjs.map +1 -1
  186. package/dist/messages/index.js +4 -1
  187. package/dist/messages/index.js.map +1 -1
  188. package/dist/pagination.d.cts +2 -2
  189. package/dist/pagination.d.ts +2 -2
  190. package/dist/pipeline/codes.cjs +1 -0
  191. package/dist/pipeline/codes.cjs.map +1 -1
  192. package/dist/pipeline/codes.js +1 -0
  193. package/dist/pipeline/codes.js.map +1 -1
  194. package/dist/pipeline/column-cache.cjs +94 -76
  195. package/dist/pipeline/column-cache.cjs.map +1 -1
  196. package/dist/pipeline/column-cache.js +92 -75
  197. package/dist/pipeline/column-cache.js.map +1 -1
  198. package/dist/pipeline/dev-checks.cjs +1 -0
  199. package/dist/pipeline/dev-checks.cjs.map +1 -1
  200. package/dist/pipeline/dev-checks.js +1 -0
  201. package/dist/pipeline/dev-checks.js.map +1 -1
  202. package/dist/pipeline/env-codes.cjs +3 -2
  203. package/dist/pipeline/env-codes.cjs.map +1 -1
  204. package/dist/pipeline/env-codes.js +3 -2
  205. package/dist/pipeline/env-codes.js.map +1 -1
  206. package/dist/pipeline/perf-codes.cjs +1 -0
  207. package/dist/pipeline/perf-codes.cjs.map +1 -1
  208. package/dist/pipeline/perf-codes.js +1 -0
  209. package/dist/pipeline/perf-codes.js.map +1 -1
  210. package/dist/pipeline/runner.cjs +17 -9
  211. package/dist/pipeline/runner.cjs.map +1 -1
  212. package/dist/pipeline/runner.js +17 -9
  213. package/dist/pipeline/runner.js.map +1 -1
  214. package/dist/pipeline/slice.cjs +3 -1
  215. package/dist/pipeline/slice.cjs.map +1 -1
  216. package/dist/pipeline/slice.js +3 -1
  217. package/dist/pipeline/slice.js.map +1 -1
  218. package/dist/schema.d.cts +2 -2
  219. package/dist/schema.d.ts +2 -2
  220. package/dist/{search-async-entry-v5JdEk5Y.d.cts → search-async-entry-CuLYPfY_.d.cts} +2 -2
  221. package/dist/{search-async-entry-DGSw2pDL.d.ts → search-async-entry-Cx7xpuVZ.d.ts} +2 -2
  222. package/dist/search-async.d.cts +3 -3
  223. package/dist/search-async.d.ts +3 -3
  224. package/dist/search.d.cts +8 -6
  225. package/dist/search.d.ts +8 -6
  226. package/dist/server.d.cts +3 -3
  227. package/dist/server.d.ts +3 -3
  228. package/dist/sorting.d.cts +2 -2
  229. package/dist/sorting.d.ts +2 -2
  230. package/dist/source/codes.cjs +1 -0
  231. package/dist/source/codes.cjs.map +1 -1
  232. package/dist/source/codes.js +1 -0
  233. package/dist/source/codes.js.map +1 -1
  234. package/dist/source/fetch-codes.cjs +1 -0
  235. package/dist/source/fetch-codes.cjs.map +1 -1
  236. package/dist/source/fetch-codes.js +1 -0
  237. package/dist/source/fetch-codes.js.map +1 -1
  238. package/dist/table/codes.cjs +1 -0
  239. package/dist/table/codes.cjs.map +1 -1
  240. package/dist/table/codes.js +1 -0
  241. package/dist/table/codes.js.map +1 -1
  242. package/dist/table/create-table.cjs +39 -9
  243. package/dist/table/create-table.cjs.map +1 -1
  244. package/dist/table/create-table.js +39 -9
  245. package/dist/table/create-table.js.map +1 -1
  246. package/dist/table/data-mutation.cjs +1 -0
  247. package/dist/table/data-mutation.cjs.map +1 -1
  248. package/dist/table/data-mutation.js +1 -0
  249. package/dist/table/data-mutation.js.map +1 -1
  250. package/dist/table/internals.cjs.map +1 -1
  251. package/dist/table/internals.js.map +1 -1
  252. package/dist/table/ssr-codes.cjs +1 -0
  253. package/dist/table/ssr-codes.cjs.map +1 -1
  254. package/dist/table/ssr-codes.js +1 -0
  255. package/dist/table/ssr-codes.js.map +1 -1
  256. package/dist/table/ssr.cjs +4 -1
  257. package/dist/table/ssr.cjs.map +1 -1
  258. package/dist/table/ssr.js +4 -1
  259. package/dist/table/ssr.js.map +1 -1
  260. package/dist/table/state-feedback.cjs +19 -0
  261. package/dist/table/state-feedback.cjs.map +1 -1
  262. package/dist/table/state-feedback.js +19 -0
  263. package/dist/table/state-feedback.js.map +1 -1
  264. package/dist/table/types.cjs.map +1 -1
  265. package/dist/table/types.js.map +1 -1
  266. package/dist/validity.d.cts +2 -2
  267. package/dist/validity.d.ts +2 -2
  268. package/dist/version.cjs +1 -1
  269. package/dist/version.cjs.map +1 -1
  270. package/dist/version.js +1 -1
  271. package/dist/version.js.map +1 -1
  272. package/dist/versioning/codes.cjs +18 -0
  273. package/dist/versioning/codes.cjs.map +1 -1
  274. package/dist/versioning/codes.js +18 -0
  275. package/dist/versioning/codes.js.map +1 -1
  276. package/dist/versioning/registry.cjs +4 -2
  277. package/dist/versioning/registry.cjs.map +1 -1
  278. package/dist/versioning/registry.js +4 -2
  279. package/dist/versioning/registry.js.map +1 -1
  280. package/package.json +39 -3
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __copyProps = (to, from, except, desc) => {
7
+ if (from && typeof from === "object" || typeof from === "function") {
8
+ for (let key of __getOwnPropNames(from))
9
+ if (!__hasOwnProp.call(to, key) && key !== except)
10
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
11
+ }
12
+ return to;
13
+ };
14
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
15
+
16
+ // src/diagnostics/process-guard.ts
17
+ var process_guard_exports = {};
18
+ module.exports = __toCommonJS(process_guard_exports);
19
+ try {
20
+ process.env.NODE_ENV;
21
+ } catch {
22
+ throw new ReferenceError(
23
+ `[DataKable] process is not defined: replace process.env.NODE_ENV at build time (e.g. esbuild --define:process.env.NODE_ENV='"production"'), or set globalThis.process = { env: { NODE_ENV: 'production' } } before DataKable loads. See https://github.com/Ink01101011/datakable/blob/main/docs/how-to-fix/process-is-not-defined.md`
24
+ );
25
+ }
26
+ //# sourceMappingURL=process-guard.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/diagnostics/process-guard.ts"],"sourcesContent":["// No @types/node in core: declare just what is read.\ndeclare const process: { env: { NODE_ENV?: string } }\n\n/*\n * Code run without a bundler (CDN, import map) has no `process`: say so and name the fix, instead\n * of the engine's bare \"process is not defined\" (#36).\n *\n * Every module that reads `DEV` imports this module first (the build rewrites `import { DEV } from\n * './env'` to `import './process-guard'`, see scripts/preserve-modules.mjs), so it is evaluated\n * before any `process.env.NODE_ENV` read. It is listed in `sideEffects`, so a bundler run without\n * the replacement (esbuild without --define) keeps it too. Once `process.env.NODE_ENV` is replaced\n * with a literal the `try` body is empty and a minifier removes the statement: production bundles\n * pay nothing (`pnpm check:size`).\n */\ntry {\n process.env.NODE_ENV\n} catch {\n throw new ReferenceError(\n '[DataKable] process is not defined: replace process.env.NODE_ENV at build time (e.g. ' +\n `esbuild --define:process.env.NODE_ENV='\"production\"'), or set globalThis.process = ` +\n \"{ env: { NODE_ENV: 'production' } } before DataKable loads. See \" +\n 'https://github.com/Ink01101011/datakable/blob/main/docs/how-to-fix/process-is-not-defined.md',\n )\n}\n\n// A module, not a script: keeps the `process` declaration above local to this file.\nexport {}\n"],"mappings":";;;;;;;;;;;;;;;;AAAA;AAAA;AAcA,IAAI;AACF,UAAQ,IAAI;AACd,QAAQ;AACN,QAAM,IAAI;AAAA,IACR;AAAA,EAIF;AACF;","names":[]}
@@ -0,0 +1,9 @@
1
+ // src/diagnostics/process-guard.ts
2
+ try {
3
+ process.env.NODE_ENV;
4
+ } catch {
5
+ throw new ReferenceError(
6
+ `[DataKable] process is not defined: replace process.env.NODE_ENV at build time (e.g. esbuild --define:process.env.NODE_ENV='"production"'), or set globalThis.process = { env: { NODE_ENV: 'production' } } before DataKable loads. See https://github.com/Ink01101011/datakable/blob/main/docs/how-to-fix/process-is-not-defined.md`
7
+ );
8
+ }
9
+ //# sourceMappingURL=process-guard.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/diagnostics/process-guard.ts"],"sourcesContent":["// No @types/node in core: declare just what is read.\ndeclare const process: { env: { NODE_ENV?: string } }\n\n/*\n * Code run without a bundler (CDN, import map) has no `process`: say so and name the fix, instead\n * of the engine's bare \"process is not defined\" (#36).\n *\n * Every module that reads `DEV` imports this module first (the build rewrites `import { DEV } from\n * './env'` to `import './process-guard'`, see scripts/preserve-modules.mjs), so it is evaluated\n * before any `process.env.NODE_ENV` read. It is listed in `sideEffects`, so a bundler run without\n * the replacement (esbuild without --define) keeps it too. Once `process.env.NODE_ENV` is replaced\n * with a literal the `try` body is empty and a minifier removes the statement: production bundles\n * pay nothing (`pnpm check:size`).\n */\ntry {\n process.env.NODE_ENV\n} catch {\n throw new ReferenceError(\n '[DataKable] process is not defined: replace process.env.NODE_ENV at build time (e.g. ' +\n `esbuild --define:process.env.NODE_ENV='\"production\"'), or set globalThis.process = ` +\n \"{ env: { NODE_ENV: 'production' } } before DataKable loads. See \" +\n 'https://github.com/Ink01101011/datakable/blob/main/docs/how-to-fix/process-is-not-defined.md',\n )\n}\n\n// A module, not a script: keeps the `process` declaration above local to this file.\nexport {}\n"],"mappings":";AAcA,IAAI;AACF,UAAQ,IAAI;AACd,QAAQ;AACN,QAAM,IAAI;AAAA,IACR;AAAA,EAIF;AACF;","names":[]}
@@ -0,0 +1,120 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/diagnostics/prose.ts
21
+ var prose_exports = {};
22
+ __export(prose_exports, {
23
+ expandDetails: () => expandDetails,
24
+ expandProse: () => expandProse,
25
+ proseMessages: () => proseMessages
26
+ });
27
+ module.exports = __toCommonJS(prose_exports);
28
+ var import_catalog = require("./catalog.cjs");
29
+ var import_process_guard = require("./process-guard.cjs");
30
+ var proseMessages = {
31
+ // Cell slots (`DK_CALLBACK_FAILED` / `DK_CALLBACK_BAD_RETURN` fallback).
32
+ "cells-coerced": "those cells were coerced with the default formatter",
33
+ "cells-warn": "those cells rendered \u26A0",
34
+ // `<DataTable />` (@datakable/react)
35
+ "cells-undefined": "the failed cells read as undefined",
36
+ "cells-empty": "the failed cells render ''",
37
+ "rows-unmatched": "the failed rows are treated as non-matching",
38
+ "rows-last": "the failed rows sort as missing values (last)",
39
+ "cell-undefined": "the cell reads as undefined",
40
+ "row-key-index": "those rows use the fallback key '#<index>'",
41
+ "sorted-native": "the rows were sorted with the native algorithm",
42
+ "sorted-default": "the column was sorted with the default comparator",
43
+ // Operation fallbacks (`intercept/fallbacks.ts`, the boundary's reports).
44
+ "init-continued": "table creation continued without the failed step",
45
+ "options-kept": "the previous options were kept",
46
+ "destroy-continued": "teardown continued; the table is destroyed",
47
+ "update-dropped": "the update was dropped (state unchanged)",
48
+ "data-kept": "the previous data was kept",
49
+ "row-model-kept": "the last good row model was kept",
50
+ "step-passthrough": "the step passed its input through",
51
+ "batch-fallback": "the column's cells use the slot fallback ('' for format, undefined for accessor, non-matching for filterFn, missing (sorted last) for sortBy)",
52
+ "results-kept": "the previous results were kept (status: 'error')",
53
+ "diagnostic-dropped": "the diagnostic was dropped (the logger never kills the table)",
54
+ "returned-undefined": "the operation returned undefined",
55
+ // Features.
56
+ "slice-undefined": "the slice starts as undefined",
57
+ "api-not-installed": "its API was not installed",
58
+ "call-ignored": "the call was ignored",
59
+ "api-missing": "table.{0}() did nothing (the API of that feature was not installed)",
60
+ "apis-missing": "table.{0}() did nothing (the API of those features was not installed)",
61
+ "page-reset": "the pagination state was reset to its initial value",
62
+ "page-index-0": "pageIndex was replaced by 0",
63
+ "page-size": "pageSize was replaced by {0}",
64
+ "validity-ignored": "the call was ignored; the validity filter is unchanged",
65
+ "validity-all": "the table shows every row, as with 'all'",
66
+ "validity-needs-flag": "validity filters rows flagged by schema validation, which needs `schema` and `invalidRows: 'flag'` (without a schema no row is invalid; with 'drop' invalid rows are removed, with 'throw' they throw)",
67
+ "not-searchable": "no column is searchable: give the columns to search a `search` weight",
68
+ collation: `the runtime's collation for "{0}"`,
69
+ "not-algorithm": "{0} is not a sort algorithm (accepted: auto, tim, radix, counting, native, or a function); auto was used",
70
+ "exsorted-failed": "exsorted {0}Sort could not sort these keys; auto was used",
71
+ "exsorted-range": "exsorted {0}Sort could not sort these keys (key range above 1,000,000); auto was used",
72
+ "needs-int-keys": "{0} sorts a single column of safe integer keys (numbers or Dates, no sortFn); auto was used",
73
+ // Sorting reasons (DK_SORT_STRATEGY, `debug: true`).
74
+ "custom-threw": "the custom algorithm threw",
75
+ "custom-bad": "the custom algorithm returned a bad value",
76
+ "not-safe-int": "keys are not all safe integers",
77
+ ranks: "{0}, strings as collation ranks",
78
+ "int-keys": "{0}, safe-integer keys",
79
+ "auto-nearly": "auto: safe integers, nearly sorted ({0} descents)",
80
+ "auto-range": "auto: safe integers, key range {0} \u2264 4n",
81
+ "auto-wide": "auto: safe integers, wide range, n \u2265 10k",
82
+ "auto-wide-small": "auto: safe integers, wide range, n < 10k",
83
+ "auto-ranked-nearly": "auto: collation ranks of a string column, safe integers, nearly sorted ({0} descents)",
84
+ "auto-ranked-range": "auto: collation ranks of a string column, safe integers, key range {0} \u2264 4n",
85
+ "auto-ranked-wide": "auto: collation ranks of a string column, safe integers, wide range, n \u2265 10k",
86
+ "auto-ranked-wide-small": "auto: collation ranks of a string column, safe integers, wide range, n < 10k",
87
+ // Filter values (`DK_FILTER_TYPE_MISMATCH` expected).
88
+ "prims-or-dates": "an array of primitives or Dates",
89
+ "prim-or-date": "a primitive or a Date",
90
+ "range-bound": "number | bigint or a valid Date bound",
91
+ "same-type": "min and max of the same type ({0})",
92
+ // An option given without its wrapper (`DK_INVALID_OPTION` expected).
93
+ wrapped: "{0}({1}) from '@datakable/core/{2}'",
94
+ // DK_INTERNAL problems.
95
+ escaped: "an exception escaped DataKable code",
96
+ "unknown-code": 'unknown diagnostic code "{0}": define it with defineDiagnostic() first',
97
+ "unknown-op": 'Unknown operation "{0}": register it with registerOperation()',
98
+ "boundary-twice": 'A boundary interceptor is already installed ("{0}"); "{1}" was rejected'
99
+ };
100
+ function expandProse(v, dev) {
101
+ const [key, ...args] = v.split("|");
102
+ const text = (process.env.NODE_ENV !== "production" && dev ? proseMessages[key] : void 0) ?? (0, import_catalog.installedText)(key);
103
+ return typeof text === "string" ? text.replace(/\{(\d)\}/g, (_, n) => expandProse(args[n] ?? "", dev)) : v;
104
+ }
105
+ var FIELDS = ["fallback", "reason", "problem", "expected"];
106
+ function expandDetails(details, dev) {
107
+ const out = { ...details };
108
+ for (const f of FIELDS) {
109
+ const v = details[f];
110
+ if (typeof v === "string") out[f] = expandProse(v, dev);
111
+ }
112
+ return out;
113
+ }
114
+ // Annotate the CommonJS export names for ESM import in node:
115
+ 0 && (module.exports = {
116
+ expandDetails,
117
+ expandProse,
118
+ proseMessages
119
+ });
120
+ //# sourceMappingURL=prose.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/diagnostics/prose.ts"],"sourcesContent":["import { installedText } from './catalog'\nimport './process-guard'\n\n/**\n * Production detail prose (§8.2, §9.3): the sentences some details carry (`fallback`, `reason`,\n * `problem`) are written as short keys at the emit site, e.g. `fallback: 'cells-undefined'`, or\n * `'page-size|10'` with arguments. A diagnostic built in development, or in production with\n * `@datakable/core/messages` installed, reads the full sentence (the key is expanded when it is\n * built); production without the messages keeps the key, so the bundle carries no prose. A value\n * that is not a known key (a plugin's own `registerFallback` text) is kept as written.\n *\n * `{0}`, `{1}` are the arguments after the key, separated by `|`.\n */\nexport const proseMessages: Readonly<Record<string, string>> = {\n // Cell slots (`DK_CALLBACK_FAILED` / `DK_CALLBACK_BAD_RETURN` fallback).\n 'cells-coerced': 'those cells were coerced with the default formatter',\n 'cells-warn': 'those cells rendered ⚠', // `<DataTable />` (@datakable/react)\n 'cells-undefined': 'the failed cells read as undefined',\n 'cells-empty': \"the failed cells render ''\",\n 'rows-unmatched': 'the failed rows are treated as non-matching',\n 'rows-last': 'the failed rows sort as missing values (last)',\n 'cell-undefined': 'the cell reads as undefined',\n 'row-key-index': \"those rows use the fallback key '#<index>'\",\n 'sorted-native': 'the rows were sorted with the native algorithm',\n 'sorted-default': 'the column was sorted with the default comparator',\n // Operation fallbacks (`intercept/fallbacks.ts`, the boundary's reports).\n 'init-continued': 'table creation continued without the failed step',\n 'options-kept': 'the previous options were kept',\n 'destroy-continued': 'teardown continued; the table is destroyed',\n 'update-dropped': 'the update was dropped (state unchanged)',\n 'data-kept': 'the previous data was kept',\n 'row-model-kept': 'the last good row model was kept',\n 'step-passthrough': 'the step passed its input through',\n 'batch-fallback':\n \"the column's cells use the slot fallback ('' for format, undefined for accessor, \" +\n 'non-matching for filterFn, missing (sorted last) for sortBy)',\n 'results-kept': \"the previous results were kept (status: 'error')\",\n 'diagnostic-dropped': 'the diagnostic was dropped (the logger never kills the table)',\n 'returned-undefined': 'the operation returned undefined',\n // Features.\n 'slice-undefined': 'the slice starts as undefined',\n 'api-not-installed': 'its API was not installed',\n 'call-ignored': 'the call was ignored',\n 'api-missing': 'table.{0}() did nothing (the API of that feature was not installed)',\n 'apis-missing': 'table.{0}() did nothing (the API of those features was not installed)',\n 'page-reset': 'the pagination state was reset to its initial value',\n 'page-index-0': 'pageIndex was replaced by 0',\n 'page-size': 'pageSize was replaced by {0}',\n 'validity-ignored': 'the call was ignored; the validity filter is unchanged',\n 'validity-all': \"the table shows every row, as with 'all'\",\n 'validity-needs-flag':\n 'validity filters rows flagged by schema validation, which needs `schema` and ' +\n \"`invalidRows: 'flag'` (without a schema no row is invalid; with 'drop' invalid rows \" +\n \"are removed, with 'throw' they throw)\",\n 'not-searchable': 'no column is searchable: give the columns to search a `search` weight',\n collation: 'the runtime\\'s collation for \"{0}\"',\n 'not-algorithm':\n '{0} is not a sort algorithm (accepted: auto, tim, radix, counting, native, or a function); ' +\n 'auto was used',\n 'exsorted-failed': 'exsorted {0}Sort could not sort these keys; auto was used',\n 'exsorted-range':\n 'exsorted {0}Sort could not sort these keys (key range above 1,000,000); auto was used',\n 'needs-int-keys':\n '{0} sorts a single column of safe integer keys (numbers or Dates, no sortFn); auto was used',\n // Sorting reasons (DK_SORT_STRATEGY, `debug: true`).\n 'custom-threw': 'the custom algorithm threw',\n 'custom-bad': 'the custom algorithm returned a bad value',\n 'not-safe-int': 'keys are not all safe integers',\n ranks: '{0}, strings as collation ranks',\n 'int-keys': '{0}, safe-integer keys',\n 'auto-nearly': 'auto: safe integers, nearly sorted ({0} descents)',\n 'auto-range': 'auto: safe integers, key range {0} ≤ 4n',\n 'auto-wide': 'auto: safe integers, wide range, n ≥ 10k',\n 'auto-wide-small': 'auto: safe integers, wide range, n < 10k',\n 'auto-ranked-nearly':\n 'auto: collation ranks of a string column, safe integers, nearly sorted ({0} descents)',\n 'auto-ranked-range':\n 'auto: collation ranks of a string column, safe integers, key range {0} ≤ 4n',\n 'auto-ranked-wide':\n 'auto: collation ranks of a string column, safe integers, wide range, n ≥ 10k',\n 'auto-ranked-wide-small':\n 'auto: collation ranks of a string column, safe integers, wide range, n < 10k',\n // Filter values (`DK_FILTER_TYPE_MISMATCH` expected).\n 'prims-or-dates': 'an array of primitives or Dates',\n 'prim-or-date': 'a primitive or a Date',\n 'range-bound': 'number | bigint or a valid Date bound',\n 'same-type': 'min and max of the same type ({0})',\n // An option given without its wrapper (`DK_INVALID_OPTION` expected).\n wrapped: \"{0}({1}) from '@datakable/core/{2}'\",\n // DK_INTERNAL problems.\n escaped: 'an exception escaped DataKable code',\n 'unknown-code': 'unknown diagnostic code \"{0}\": define it with defineDiagnostic() first',\n 'unknown-op': 'Unknown operation \"{0}\": register it with registerOperation()',\n 'boundary-twice': 'A boundary interceptor is already installed (\"{0}\"); \"{1}\" was rejected',\n}\n\n/**\n * The sentence of a prose key (`'page-size|10'` → `'pageSize was replaced by 10'`): from\n * {@link proseMessages} in development (`dev`), else from the installed messages; `v` itself when\n * neither has the key.\n */\nexport function expandProse(v: string, dev: boolean): string {\n const [key, ...args] = v.split('|') as [string, ...string[]]\n const text = ((process.env.NODE_ENV !== \"production\") && dev ? proseMessages[key] : undefined) ?? installedText(key)\n // An argument may be a key itself (`'ranks|custom-threw'`); a missing one reads as ''. (`n` is\n // the digit string: `args['0']` indexes like `args[0]`.)\n return typeof text === 'string'\n ? text.replace(/\\{(\\d)\\}/g, (_, n: number) => expandProse(args[n] ?? '', dev))\n : v\n}\n\n/** The detail fields that may hold a prose key. */\nconst FIELDS = ['fallback', 'reason', 'problem', 'expected'] as const\n\n/** A copy of `details` with its prose keys expanded. */\nexport function expandDetails(\n details: Record<string, unknown>,\n dev: boolean,\n): Record<string, unknown> {\n const out = { ...details }\n for (const f of FIELDS) {\n const v = details[f]\n if (typeof v === 'string') out[f] = expandProse(v, dev)\n }\n return out\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,qBAA8B;AAC9B,2BAAO;AAYA,IAAM,gBAAkD;AAAA;AAAA,EAE7D,iBAAiB;AAAA,EACjB,cAAc;AAAA;AAAA,EACd,mBAAmB;AAAA,EACnB,eAAe;AAAA,EACf,kBAAkB;AAAA,EAClB,aAAa;AAAA,EACb,kBAAkB;AAAA,EAClB,iBAAiB;AAAA,EACjB,iBAAiB;AAAA,EACjB,kBAAkB;AAAA;AAAA,EAElB,kBAAkB;AAAA,EAClB,gBAAgB;AAAA,EAChB,qBAAqB;AAAA,EACrB,kBAAkB;AAAA,EAClB,aAAa;AAAA,EACb,kBAAkB;AAAA,EAClB,oBAAoB;AAAA,EACpB,kBACE;AAAA,EAEF,gBAAgB;AAAA,EAChB,sBAAsB;AAAA,EACtB,sBAAsB;AAAA;AAAA,EAEtB,mBAAmB;AAAA,EACnB,qBAAqB;AAAA,EACrB,gBAAgB;AAAA,EAChB,eAAe;AAAA,EACf,gBAAgB;AAAA,EAChB,cAAc;AAAA,EACd,gBAAgB;AAAA,EAChB,aAAa;AAAA,EACb,oBAAoB;AAAA,EACpB,gBAAgB;AAAA,EAChB,uBACE;AAAA,EAGF,kBAAkB;AAAA,EAClB,WAAW;AAAA,EACX,iBACE;AAAA,EAEF,mBAAmB;AAAA,EACnB,kBACE;AAAA,EACF,kBACE;AAAA;AAAA,EAEF,gBAAgB;AAAA,EAChB,cAAc;AAAA,EACd,gBAAgB;AAAA,EAChB,OAAO;AAAA,EACP,YAAY;AAAA,EACZ,eAAe;AAAA,EACf,cAAc;AAAA,EACd,aAAa;AAAA,EACb,mBAAmB;AAAA,EACnB,sBACE;AAAA,EACF,qBACE;AAAA,EACF,oBACE;AAAA,EACF,0BACE;AAAA;AAAA,EAEF,kBAAkB;AAAA,EAClB,gBAAgB;AAAA,EAChB,eAAe;AAAA,EACf,aAAa;AAAA;AAAA,EAEb,SAAS;AAAA;AAAA,EAET,SAAS;AAAA,EACT,gBAAgB;AAAA,EAChB,cAAc;AAAA,EACd,kBAAkB;AACpB;AAOO,SAAS,YAAY,GAAW,KAAsB;AAC3D,QAAM,CAAC,KAAK,GAAG,IAAI,IAAI,EAAE,MAAM,GAAG;AAClC,QAAM,QAAS,QAAQ,IAAI,aAAa,gBAAiB,MAAM,cAAc,GAAG,IAAI,eAAc,8BAAc,GAAG;AAGnH,SAAO,OAAO,SAAS,WACnB,KAAK,QAAQ,aAAa,CAAC,GAAG,MAAc,YAAY,KAAK,CAAC,KAAK,IAAI,GAAG,CAAC,IAC3E;AACN;AAGA,IAAM,SAAS,CAAC,YAAY,UAAU,WAAW,UAAU;AAGpD,SAAS,cACd,SACA,KACyB;AACzB,QAAM,MAAM,EAAE,GAAG,QAAQ;AACzB,aAAW,KAAK,QAAQ;AACtB,UAAM,IAAI,QAAQ,CAAC;AACnB,QAAI,OAAO,MAAM,SAAU,KAAI,CAAC,IAAI,YAAY,GAAG,GAAG;AAAA,EACxD;AACA,SAAO;AACT;","names":[]}
@@ -0,0 +1,93 @@
1
+ // src/diagnostics/prose.ts
2
+ import { installedText } from "./catalog.js";
3
+ import "./process-guard.js";
4
+ var proseMessages = {
5
+ // Cell slots (`DK_CALLBACK_FAILED` / `DK_CALLBACK_BAD_RETURN` fallback).
6
+ "cells-coerced": "those cells were coerced with the default formatter",
7
+ "cells-warn": "those cells rendered \u26A0",
8
+ // `<DataTable />` (@datakable/react)
9
+ "cells-undefined": "the failed cells read as undefined",
10
+ "cells-empty": "the failed cells render ''",
11
+ "rows-unmatched": "the failed rows are treated as non-matching",
12
+ "rows-last": "the failed rows sort as missing values (last)",
13
+ "cell-undefined": "the cell reads as undefined",
14
+ "row-key-index": "those rows use the fallback key '#<index>'",
15
+ "sorted-native": "the rows were sorted with the native algorithm",
16
+ "sorted-default": "the column was sorted with the default comparator",
17
+ // Operation fallbacks (`intercept/fallbacks.ts`, the boundary's reports).
18
+ "init-continued": "table creation continued without the failed step",
19
+ "options-kept": "the previous options were kept",
20
+ "destroy-continued": "teardown continued; the table is destroyed",
21
+ "update-dropped": "the update was dropped (state unchanged)",
22
+ "data-kept": "the previous data was kept",
23
+ "row-model-kept": "the last good row model was kept",
24
+ "step-passthrough": "the step passed its input through",
25
+ "batch-fallback": "the column's cells use the slot fallback ('' for format, undefined for accessor, non-matching for filterFn, missing (sorted last) for sortBy)",
26
+ "results-kept": "the previous results were kept (status: 'error')",
27
+ "diagnostic-dropped": "the diagnostic was dropped (the logger never kills the table)",
28
+ "returned-undefined": "the operation returned undefined",
29
+ // Features.
30
+ "slice-undefined": "the slice starts as undefined",
31
+ "api-not-installed": "its API was not installed",
32
+ "call-ignored": "the call was ignored",
33
+ "api-missing": "table.{0}() did nothing (the API of that feature was not installed)",
34
+ "apis-missing": "table.{0}() did nothing (the API of those features was not installed)",
35
+ "page-reset": "the pagination state was reset to its initial value",
36
+ "page-index-0": "pageIndex was replaced by 0",
37
+ "page-size": "pageSize was replaced by {0}",
38
+ "validity-ignored": "the call was ignored; the validity filter is unchanged",
39
+ "validity-all": "the table shows every row, as with 'all'",
40
+ "validity-needs-flag": "validity filters rows flagged by schema validation, which needs `schema` and `invalidRows: 'flag'` (without a schema no row is invalid; with 'drop' invalid rows are removed, with 'throw' they throw)",
41
+ "not-searchable": "no column is searchable: give the columns to search a `search` weight",
42
+ collation: `the runtime's collation for "{0}"`,
43
+ "not-algorithm": "{0} is not a sort algorithm (accepted: auto, tim, radix, counting, native, or a function); auto was used",
44
+ "exsorted-failed": "exsorted {0}Sort could not sort these keys; auto was used",
45
+ "exsorted-range": "exsorted {0}Sort could not sort these keys (key range above 1,000,000); auto was used",
46
+ "needs-int-keys": "{0} sorts a single column of safe integer keys (numbers or Dates, no sortFn); auto was used",
47
+ // Sorting reasons (DK_SORT_STRATEGY, `debug: true`).
48
+ "custom-threw": "the custom algorithm threw",
49
+ "custom-bad": "the custom algorithm returned a bad value",
50
+ "not-safe-int": "keys are not all safe integers",
51
+ ranks: "{0}, strings as collation ranks",
52
+ "int-keys": "{0}, safe-integer keys",
53
+ "auto-nearly": "auto: safe integers, nearly sorted ({0} descents)",
54
+ "auto-range": "auto: safe integers, key range {0} \u2264 4n",
55
+ "auto-wide": "auto: safe integers, wide range, n \u2265 10k",
56
+ "auto-wide-small": "auto: safe integers, wide range, n < 10k",
57
+ "auto-ranked-nearly": "auto: collation ranks of a string column, safe integers, nearly sorted ({0} descents)",
58
+ "auto-ranked-range": "auto: collation ranks of a string column, safe integers, key range {0} \u2264 4n",
59
+ "auto-ranked-wide": "auto: collation ranks of a string column, safe integers, wide range, n \u2265 10k",
60
+ "auto-ranked-wide-small": "auto: collation ranks of a string column, safe integers, wide range, n < 10k",
61
+ // Filter values (`DK_FILTER_TYPE_MISMATCH` expected).
62
+ "prims-or-dates": "an array of primitives or Dates",
63
+ "prim-or-date": "a primitive or a Date",
64
+ "range-bound": "number | bigint or a valid Date bound",
65
+ "same-type": "min and max of the same type ({0})",
66
+ // An option given without its wrapper (`DK_INVALID_OPTION` expected).
67
+ wrapped: "{0}({1}) from '@datakable/core/{2}'",
68
+ // DK_INTERNAL problems.
69
+ escaped: "an exception escaped DataKable code",
70
+ "unknown-code": 'unknown diagnostic code "{0}": define it with defineDiagnostic() first',
71
+ "unknown-op": 'Unknown operation "{0}": register it with registerOperation()',
72
+ "boundary-twice": 'A boundary interceptor is already installed ("{0}"); "{1}" was rejected'
73
+ };
74
+ function expandProse(v, dev) {
75
+ const [key, ...args] = v.split("|");
76
+ const text = (process.env.NODE_ENV !== "production" && dev ? proseMessages[key] : void 0) ?? installedText(key);
77
+ return typeof text === "string" ? text.replace(/\{(\d)\}/g, (_, n) => expandProse(args[n] ?? "", dev)) : v;
78
+ }
79
+ var FIELDS = ["fallback", "reason", "problem", "expected"];
80
+ function expandDetails(details, dev) {
81
+ const out = { ...details };
82
+ for (const f of FIELDS) {
83
+ const v = details[f];
84
+ if (typeof v === "string") out[f] = expandProse(v, dev);
85
+ }
86
+ return out;
87
+ }
88
+ export {
89
+ expandDetails,
90
+ expandProse,
91
+ proseMessages
92
+ };
93
+ //# sourceMappingURL=prose.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/diagnostics/prose.ts"],"sourcesContent":["import { installedText } from './catalog'\nimport './process-guard'\n\n/**\n * Production detail prose (§8.2, §9.3): the sentences some details carry (`fallback`, `reason`,\n * `problem`) are written as short keys at the emit site, e.g. `fallback: 'cells-undefined'`, or\n * `'page-size|10'` with arguments. A diagnostic built in development, or in production with\n * `@datakable/core/messages` installed, reads the full sentence (the key is expanded when it is\n * built); production without the messages keeps the key, so the bundle carries no prose. A value\n * that is not a known key (a plugin's own `registerFallback` text) is kept as written.\n *\n * `{0}`, `{1}` are the arguments after the key, separated by `|`.\n */\nexport const proseMessages: Readonly<Record<string, string>> = {\n // Cell slots (`DK_CALLBACK_FAILED` / `DK_CALLBACK_BAD_RETURN` fallback).\n 'cells-coerced': 'those cells were coerced with the default formatter',\n 'cells-warn': 'those cells rendered ⚠', // `<DataTable />` (@datakable/react)\n 'cells-undefined': 'the failed cells read as undefined',\n 'cells-empty': \"the failed cells render ''\",\n 'rows-unmatched': 'the failed rows are treated as non-matching',\n 'rows-last': 'the failed rows sort as missing values (last)',\n 'cell-undefined': 'the cell reads as undefined',\n 'row-key-index': \"those rows use the fallback key '#<index>'\",\n 'sorted-native': 'the rows were sorted with the native algorithm',\n 'sorted-default': 'the column was sorted with the default comparator',\n // Operation fallbacks (`intercept/fallbacks.ts`, the boundary's reports).\n 'init-continued': 'table creation continued without the failed step',\n 'options-kept': 'the previous options were kept',\n 'destroy-continued': 'teardown continued; the table is destroyed',\n 'update-dropped': 'the update was dropped (state unchanged)',\n 'data-kept': 'the previous data was kept',\n 'row-model-kept': 'the last good row model was kept',\n 'step-passthrough': 'the step passed its input through',\n 'batch-fallback':\n \"the column's cells use the slot fallback ('' for format, undefined for accessor, \" +\n 'non-matching for filterFn, missing (sorted last) for sortBy)',\n 'results-kept': \"the previous results were kept (status: 'error')\",\n 'diagnostic-dropped': 'the diagnostic was dropped (the logger never kills the table)',\n 'returned-undefined': 'the operation returned undefined',\n // Features.\n 'slice-undefined': 'the slice starts as undefined',\n 'api-not-installed': 'its API was not installed',\n 'call-ignored': 'the call was ignored',\n 'api-missing': 'table.{0}() did nothing (the API of that feature was not installed)',\n 'apis-missing': 'table.{0}() did nothing (the API of those features was not installed)',\n 'page-reset': 'the pagination state was reset to its initial value',\n 'page-index-0': 'pageIndex was replaced by 0',\n 'page-size': 'pageSize was replaced by {0}',\n 'validity-ignored': 'the call was ignored; the validity filter is unchanged',\n 'validity-all': \"the table shows every row, as with 'all'\",\n 'validity-needs-flag':\n 'validity filters rows flagged by schema validation, which needs `schema` and ' +\n \"`invalidRows: 'flag'` (without a schema no row is invalid; with 'drop' invalid rows \" +\n \"are removed, with 'throw' they throw)\",\n 'not-searchable': 'no column is searchable: give the columns to search a `search` weight',\n collation: 'the runtime\\'s collation for \"{0}\"',\n 'not-algorithm':\n '{0} is not a sort algorithm (accepted: auto, tim, radix, counting, native, or a function); ' +\n 'auto was used',\n 'exsorted-failed': 'exsorted {0}Sort could not sort these keys; auto was used',\n 'exsorted-range':\n 'exsorted {0}Sort could not sort these keys (key range above 1,000,000); auto was used',\n 'needs-int-keys':\n '{0} sorts a single column of safe integer keys (numbers or Dates, no sortFn); auto was used',\n // Sorting reasons (DK_SORT_STRATEGY, `debug: true`).\n 'custom-threw': 'the custom algorithm threw',\n 'custom-bad': 'the custom algorithm returned a bad value',\n 'not-safe-int': 'keys are not all safe integers',\n ranks: '{0}, strings as collation ranks',\n 'int-keys': '{0}, safe-integer keys',\n 'auto-nearly': 'auto: safe integers, nearly sorted ({0} descents)',\n 'auto-range': 'auto: safe integers, key range {0} ≤ 4n',\n 'auto-wide': 'auto: safe integers, wide range, n ≥ 10k',\n 'auto-wide-small': 'auto: safe integers, wide range, n < 10k',\n 'auto-ranked-nearly':\n 'auto: collation ranks of a string column, safe integers, nearly sorted ({0} descents)',\n 'auto-ranked-range':\n 'auto: collation ranks of a string column, safe integers, key range {0} ≤ 4n',\n 'auto-ranked-wide':\n 'auto: collation ranks of a string column, safe integers, wide range, n ≥ 10k',\n 'auto-ranked-wide-small':\n 'auto: collation ranks of a string column, safe integers, wide range, n < 10k',\n // Filter values (`DK_FILTER_TYPE_MISMATCH` expected).\n 'prims-or-dates': 'an array of primitives or Dates',\n 'prim-or-date': 'a primitive or a Date',\n 'range-bound': 'number | bigint or a valid Date bound',\n 'same-type': 'min and max of the same type ({0})',\n // An option given without its wrapper (`DK_INVALID_OPTION` expected).\n wrapped: \"{0}({1}) from '@datakable/core/{2}'\",\n // DK_INTERNAL problems.\n escaped: 'an exception escaped DataKable code',\n 'unknown-code': 'unknown diagnostic code \"{0}\": define it with defineDiagnostic() first',\n 'unknown-op': 'Unknown operation \"{0}\": register it with registerOperation()',\n 'boundary-twice': 'A boundary interceptor is already installed (\"{0}\"); \"{1}\" was rejected',\n}\n\n/**\n * The sentence of a prose key (`'page-size|10'` → `'pageSize was replaced by 10'`): from\n * {@link proseMessages} in development (`dev`), else from the installed messages; `v` itself when\n * neither has the key.\n */\nexport function expandProse(v: string, dev: boolean): string {\n const [key, ...args] = v.split('|') as [string, ...string[]]\n const text = ((process.env.NODE_ENV !== \"production\") && dev ? proseMessages[key] : undefined) ?? installedText(key)\n // An argument may be a key itself (`'ranks|custom-threw'`); a missing one reads as ''. (`n` is\n // the digit string: `args['0']` indexes like `args[0]`.)\n return typeof text === 'string'\n ? text.replace(/\\{(\\d)\\}/g, (_, n: number) => expandProse(args[n] ?? '', dev))\n : v\n}\n\n/** The detail fields that may hold a prose key. */\nconst FIELDS = ['fallback', 'reason', 'problem', 'expected'] as const\n\n/** A copy of `details` with its prose keys expanded. */\nexport function expandDetails(\n details: Record<string, unknown>,\n dev: boolean,\n): Record<string, unknown> {\n const out = { ...details }\n for (const f of FIELDS) {\n const v = details[f]\n if (typeof v === 'string') out[f] = expandProse(v, dev)\n }\n return out\n}\n"],"mappings":";AAAA,SAAS,qBAAqB;AAC9B,OAAO;AAYA,IAAM,gBAAkD;AAAA;AAAA,EAE7D,iBAAiB;AAAA,EACjB,cAAc;AAAA;AAAA,EACd,mBAAmB;AAAA,EACnB,eAAe;AAAA,EACf,kBAAkB;AAAA,EAClB,aAAa;AAAA,EACb,kBAAkB;AAAA,EAClB,iBAAiB;AAAA,EACjB,iBAAiB;AAAA,EACjB,kBAAkB;AAAA;AAAA,EAElB,kBAAkB;AAAA,EAClB,gBAAgB;AAAA,EAChB,qBAAqB;AAAA,EACrB,kBAAkB;AAAA,EAClB,aAAa;AAAA,EACb,kBAAkB;AAAA,EAClB,oBAAoB;AAAA,EACpB,kBACE;AAAA,EAEF,gBAAgB;AAAA,EAChB,sBAAsB;AAAA,EACtB,sBAAsB;AAAA;AAAA,EAEtB,mBAAmB;AAAA,EACnB,qBAAqB;AAAA,EACrB,gBAAgB;AAAA,EAChB,eAAe;AAAA,EACf,gBAAgB;AAAA,EAChB,cAAc;AAAA,EACd,gBAAgB;AAAA,EAChB,aAAa;AAAA,EACb,oBAAoB;AAAA,EACpB,gBAAgB;AAAA,EAChB,uBACE;AAAA,EAGF,kBAAkB;AAAA,EAClB,WAAW;AAAA,EACX,iBACE;AAAA,EAEF,mBAAmB;AAAA,EACnB,kBACE;AAAA,EACF,kBACE;AAAA;AAAA,EAEF,gBAAgB;AAAA,EAChB,cAAc;AAAA,EACd,gBAAgB;AAAA,EAChB,OAAO;AAAA,EACP,YAAY;AAAA,EACZ,eAAe;AAAA,EACf,cAAc;AAAA,EACd,aAAa;AAAA,EACb,mBAAmB;AAAA,EACnB,sBACE;AAAA,EACF,qBACE;AAAA,EACF,oBACE;AAAA,EACF,0BACE;AAAA;AAAA,EAEF,kBAAkB;AAAA,EAClB,gBAAgB;AAAA,EAChB,eAAe;AAAA,EACf,aAAa;AAAA;AAAA,EAEb,SAAS;AAAA;AAAA,EAET,SAAS;AAAA,EACT,gBAAgB;AAAA,EAChB,cAAc;AAAA,EACd,kBAAkB;AACpB;AAOO,SAAS,YAAY,GAAW,KAAsB;AAC3D,QAAM,CAAC,KAAK,GAAG,IAAI,IAAI,EAAE,MAAM,GAAG;AAClC,QAAM,QAAS,QAAQ,IAAI,aAAa,gBAAiB,MAAM,cAAc,GAAG,IAAI,WAAc,cAAc,GAAG;AAGnH,SAAO,OAAO,SAAS,WACnB,KAAK,QAAQ,aAAa,CAAC,GAAG,MAAc,YAAY,KAAK,CAAC,KAAK,IAAI,GAAG,CAAC,IAC3E;AACN;AAGA,IAAM,SAAS,CAAC,YAAY,UAAU,WAAW,UAAU;AAGpD,SAAS,cACd,SACA,KACyB;AACzB,QAAM,MAAM,EAAE,GAAG,QAAQ;AACzB,aAAW,KAAK,QAAQ;AACtB,UAAM,IAAI,QAAQ,CAAC;AACnB,QAAI,OAAO,MAAM,SAAU,KAAI,CAAC,IAAI,YAAY,GAAG,GAAG;AAAA,EACxD;AACA,SAAO;AACT;","names":[]}
@@ -25,6 +25,7 @@ __export(redact_exports, {
25
25
  SENSITIVE: () => SENSITIVE,
26
26
  describeValue: () => describeValue,
27
27
  hashRowKey: () => hashRowKey,
28
+ pathsOverlap: () => pathsOverlap,
28
29
  redactDetails: () => redactDetails,
29
30
  redactLocation: () => redactLocation,
30
31
  redactionMessages: () => redactionMessages,
@@ -34,6 +35,7 @@ __export(redact_exports, {
34
35
  });
35
36
  module.exports = __toCommonJS(redact_exports);
36
37
  var import_catalog = require("./catalog.cjs");
38
+ var import_process_guard = require("./process-guard.cjs");
37
39
  var SENSITIVE = "[sensitive]";
38
40
  var REDACTED = "[redacted]";
39
41
  var LEVELS = ["safe", "keys", "full"];
@@ -83,7 +85,7 @@ function redactKey(r, path, key) {
83
85
  return r.level === "safe" ? hashRowKey(key) : key;
84
86
  }
85
87
  function redactValue(r, path, value, column) {
86
- if (column !== void 0 && r.sensitive.has(column)) return SENSITIVE;
88
+ if (column !== void 0 && underSensitive(r, column)) return SENSITIVE;
87
89
  const c = custom(r, path, value);
88
90
  if (c !== void 0) return c;
89
91
  return r.level === "full" ? value : describeValue(value);
@@ -92,9 +94,9 @@ function issuePath(path) {
92
94
  if (!path) return "";
93
95
  return path.map((s) => String(typeof s === "object" && s !== null ? s.key : s)).join(".");
94
96
  }
97
+ var pathsOverlap = (a, b) => a === b || a.startsWith(`${b}.`) || b.startsWith(`${a}.`);
95
98
  function underSensitive(r, path) {
96
- if (r.sensitive.size === 0) return false;
97
- for (const col of r.sensitive) if (path === col || path.startsWith(`${col}.`)) return true;
99
+ for (const col of r.sensitive) if (pathsOverlap(path, col)) return true;
98
100
  return false;
99
101
  }
100
102
  function scrubSchemaIssue(issue, r, fieldPath = "issue") {
@@ -106,7 +108,7 @@ function scrubSchemaIssue(issue, r, fieldPath = "issue") {
106
108
  path = "";
107
109
  }
108
110
  const own = `invalid value at ${path || "(root)"}`;
109
- if (underSensitive(r, path)) return { path, message: own };
111
+ if (r.sensitive.size > 0) return { path, message: own };
110
112
  const c = custom(r, fieldPath, i.message);
111
113
  if (c !== void 0) return { path, message: c };
112
114
  return { path, message: r.level === "full" && typeof i.message === "string" ? i.message : own };
@@ -185,6 +187,7 @@ var DK_UNSAFE_REDACTION = (0, import_catalog.defineDiagnostic)(
185
187
  SENSITIVE,
186
188
  describeValue,
187
189
  hashRowKey,
190
+ pathsOverlap,
188
191
  redactDetails,
189
192
  redactLocation,
190
193
  redactionMessages,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/diagnostics/redact.ts"],"sourcesContent":["import { type DiagnosticMessages, defineDiagnostic } from './catalog'\nimport type { Location } from './types'\n\ndeclare module './catalog' {\n interface DiagnosticCatalog {\n DK_UNSAFE_REDACTION: { level: 'full' }\n }\n}\n\n/**\n * Redaction levels (§8.2). `'safe'`: paths, indices, counts, value types, hashed row keys\n * (production default). `'keys'`: + raw row keys (development default). `'full'`: + row values.\n */\nexport type RedactLevel = 'safe' | 'keys' | 'full'\n\n/**\n * Custom rule: return a string to log instead of `value`, or `undefined` for the built-in policy.\n * `path` names the field, e.g. `where.key`, `details.value`, `details.keys.2`, `details.issues.0`.\n * Sensitive columns never reach it.\n */\nexport type RedactFn = (path: string, value: unknown) => string | undefined\n\nexport interface RedactionOptions {\n /** Default `'keys'` in development, `'safe'` in production. */\n level?: RedactLevel\n redact?: RedactFn\n /** Ids / keys of `sensitive: true` columns: never logged at any level. */\n sensitiveColumns?: () => Iterable<string>\n /** The `rowKey` column is sensitive: row keys are hashed at every level. */\n rowKeySensitive?: () => boolean\n}\n\n/**\n * Which detail fields of a diagnostic carry user data, declared on its `defineDiagnostic` entry.\n * Undeclared fields are logged as-is, so they must hold only DataKable-safe data (paths, ids,\n * indices, counts). Text builders receive the redacted values: treat these fields as opaque and\n * only interpolate them.\n *\n * - `rowKey` / `rowKeys`: a row key / an array of them (hashed under `'safe'`).\n * - `value` / `values`: a cell value / an array of them (type summary unless `'full'`). The column\n * is `details.column` when it is a string, else the `where` column id.\n * - `schemaIssues`: one Standard Schema issue or an array of them (`scrubSchemaIssue`).\n * - `error`: a thrown value, e.g. a fetcher error (`scrubError`).\n */\nexport type RedactField = 'rowKey' | 'rowKeys' | 'value' | 'values' | 'schemaIssues' | 'error'\n\n/** A resolved policy, built once per emit. */\nexport interface Redactor {\n level: RedactLevel\n custom: RedactFn | undefined\n sensitive: ReadonlySet<string>\n rowKeySensitive: boolean\n /** Called when the custom rule throws; the value is logged as `[redacted]`. */\n onError?: (error: unknown) => void\n}\n\nexport const SENSITIVE = '[sensitive]'\nexport const REDACTED = '[redacted]'\n\nconst LEVELS: readonly string[] = ['safe', 'keys', 'full']\nconst EMPTY: ReadonlySet<string> = new Set()\n\nexport function resolveRedaction(\n option: RedactLevel | RedactionOptions | undefined,\n dev: boolean,\n): Redactor {\n const o: RedactionOptions = typeof option === 'string' ? { level: option } : (option ?? {})\n const level = o.level ?? (dev ? 'keys' : 'safe')\n const cols = o.sensitiveColumns?.()\n return {\n // An unknown level gets the strictest policy; validating the option is optionValidator's job.\n level: LEVELS.includes(level) ? level : 'safe',\n custom: o.redact,\n sensitive: cols ? new Set(cols) : EMPTY,\n rowKeySensitive: o.rowKeySensitive?.() ?? false,\n }\n}\n\n/** Short 32-bit FNV-1a hash of `String(key)` (UTF-16 code units), as `h:xxxxxxxx`. */\nexport function hashRowKey(key: unknown): string {\n const s = String(key)\n let h = 0x811c9dc5\n for (let i = 0; i < s.length; i++) {\n h ^= s.charCodeAt(i)\n h = Math.imul(h, 0x01000193)\n }\n return `h:${(h >>> 0).toString(16).padStart(8, '0')}`\n}\n\n/** The value's type, never its contents: `string(12)`, `number`, `array(3)`, `date`, … */\nexport function describeValue(v: unknown): string {\n if (v === null) return 'null'\n if (typeof v === 'string') return `string(${v.length})`\n if (typeof v === 'number') return Number.isNaN(v) ? 'number(NaN)' : 'number'\n if (Array.isArray(v)) return `array(${v.length})`\n if (v instanceof Date) return 'date'\n return typeof v\n}\n\nfunction custom(r: Redactor, path: string, value: unknown): string | undefined {\n if (!r.custom) return undefined\n try {\n return r.custom(path, value)\n } catch (e) {\n r.onError?.(e)\n return REDACTED\n }\n}\n\nfunction redactKey(r: Redactor, path: string, key: unknown): unknown {\n // A sensitive rowKey column wins over the custom rule and the level.\n if (r.rowKeySensitive) return hashRowKey(key)\n const c = custom(r, path, key)\n if (c !== undefined) return c\n return r.level === 'safe' ? hashRowKey(key) : key\n}\n\nfunction redactValue(r: Redactor, path: string, value: unknown, column?: string): unknown {\n if (column !== undefined && r.sensitive.has(column)) return SENSITIVE\n const c = custom(r, path, value)\n if (c !== undefined) return c\n return r.level === 'full' ? value : describeValue(value)\n}\n\ntype IssuePath = ReadonlyArray<PropertyKey | { key: PropertyKey }>\n\n/** Joins a Standard Schema issue path: `['user', 0, { key: 'email' }]` → `user.0.email`. */\nfunction issuePath(path: IssuePath | undefined): string {\n if (!path) return ''\n return path.map((s) => String(typeof s === 'object' && s !== null ? s.key : s)).join('.')\n}\n\nfunction underSensitive(r: Redactor, path: string): boolean {\n if (r.sensitive.size === 0) return false\n for (const col of r.sensitive) if (path === col || path.startsWith(`${col}.`)) return true\n return false\n}\n\n/**\n * A schema issue as `{ path, message }`. Validators embed received values in their messages, so\n * under `'safe'` / `'keys'` (and for sensitive columns) the message is DataKable's own text.\n */\nexport function scrubSchemaIssue(\n issue: unknown,\n r: Redactor,\n fieldPath = 'issue',\n): { path: string; message: string } {\n const i = (typeof issue === 'object' && issue !== null ? issue : {}) as {\n message?: unknown\n path?: IssuePath\n }\n let path: string\n try {\n path = issuePath(i.path)\n } catch {\n path = ''\n }\n const own = `invalid value at ${path || '(root)'}`\n if (underSensitive(r, path)) return { path, message: own }\n const c = custom(r, fieldPath, i.message)\n if (c !== undefined) return { path, message: c }\n return { path, message: r.level === 'full' && typeof i.message === 'string' ? i.message : own }\n}\n\n/**\n * A thrown value as `error.name` + `code` only (fetcher errors embed URLs, tokens, payloads). The\n * full error belongs in `context.cause`, which reaches `onDiagnostic` only.\n */\nexport function scrubError(e: unknown): string {\n if (typeof e !== 'object' || e === null) return typeof e\n try {\n const { name, code } = e as { name?: unknown; code?: unknown }\n const n = typeof name === 'string' && name ? name : 'object'\n return typeof code === 'string' || typeof code === 'number' ? `${n} (${code})` : n\n } catch {\n return 'object'\n }\n}\n\n/** Hashes / passes through `where.key` per the policy; other locations hold no user data. */\nexport function redactLocation(where: Location, r: Redactor): Location {\n if (where.kind !== 'row' || where.key === undefined) return where\n const key = redactKey(r, 'where.key', where.key)\n return { kind: 'row', index: where.index, key: typeof key === 'string' ? key : String(key) }\n}\n\n/** A shallow copy of `details` with the declared fields redacted; the input is never mutated. */\nexport function redactDetails(\n details: Record<string, unknown>,\n fields: Readonly<Record<string, RedactField | undefined>> | undefined,\n where: Location,\n r: Redactor,\n): Record<string, unknown> {\n if (!fields) return details\n const out: Record<string, unknown> = { ...details }\n const column =\n typeof details.column === 'string'\n ? details.column\n : where.kind === 'column'\n ? where.id\n : undefined\n for (const name of Object.keys(fields)) {\n const kind = fields[name]\n if (kind === undefined || !(name in details)) continue\n const v = details[name]\n const p = `details.${name}`\n const each = (f: (x: unknown, path: string) => unknown) =>\n Array.isArray(v) ? v.map((x, i) => f(x, `${p}.${i}`)) : f(v, p)\n switch (kind) {\n case 'rowKey':\n out[name] = redactKey(r, p, v)\n break\n case 'rowKeys':\n out[name] = each((x, path) => redactKey(r, path, x))\n break\n case 'value':\n out[name] = redactValue(r, p, v, column)\n break\n case 'values':\n out[name] = each((x, path) => redactValue(r, path, x, column))\n break\n case 'schemaIssues':\n out[name] = each((x, path) => scrubSchemaIssue(x, r, path))\n break\n case 'error':\n out[name] = custom(r, p, v) ?? scrubError(v)\n break\n }\n }\n return out\n}\n\n/** Message text (§8.2): development builds, or production via `@datakable/core/messages`. */\nexport const redactionMessages: DiagnosticMessages<'DK_UNSAFE_REDACTION'> = {\n DK_UNSAFE_REDACTION: {\n problem: (d) => `diagnostics.redact is '${d.level}' in a production build`,\n impact: () =>\n 'raw row keys and cell values (except sensitive columns) reach onDiagnostic, ' +\n 'getDiagnostics() and the console',\n fix: () => [\n \"remove diagnostics.redact in production (the default is 'safe')\",\n \"or use 'keys' to log raw row keys without cell values\",\n 'mark personal-data columns with sensitive: true so they are never logged',\n ],\n },\n}\n\n/** `'full'` in a production build (§8.2: \"warns if enabled in production\"). Emitted by the hub. */\nexport const DK_UNSAFE_REDACTION = defineDiagnostic(\n {\n code: 'DK_UNSAFE_REDACTION',\n level: 'warn',\n where: () => ({ kind: 'option', path: 'diagnostics.redact' }),\n },\n (process.env.NODE_ENV !== \"production\") && redactionMessages.DK_UNSAFE_REDACTION,\n)\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/diagnostics/redact.ts"],"sourcesContent":["import { type DiagnosticMessages, defineDiagnostic } from './catalog'\nimport './process-guard'\nimport type { Location } from './types'\n\ndeclare module './catalog' {\n interface DiagnosticCatalog {\n DK_UNSAFE_REDACTION: { level: 'full' }\n }\n}\n\n/**\n * Redaction levels (§8.2). `'safe'`: paths, indices, counts, value types, hashed row keys\n * (production default). `'keys'`: + raw row keys (development default). `'full'`: + row values.\n */\nexport type RedactLevel = 'safe' | 'keys' | 'full'\n\n/**\n * Custom rule: return a string to log instead of `value`, or `undefined` for the built-in policy.\n * `path` names the field, e.g. `where.key`, `details.value`, `details.keys.2`, `details.issues.0`.\n * Sensitive columns never reach it.\n */\nexport type RedactFn = (path: string, value: unknown) => string | undefined\n\nexport interface RedactionOptions {\n /** Default `'keys'` in development, `'safe'` in production. */\n level?: RedactLevel\n redact?: RedactFn\n /** Ids / keys of `sensitive: true` columns: never logged at any level. */\n sensitiveColumns?: () => Iterable<string>\n /** The `rowKey` path is, is inside or contains a sensitive column: keys hashed at every level. */\n rowKeySensitive?: () => boolean\n}\n\n/**\n * Which detail fields of a diagnostic carry user data, declared on its `defineDiagnostic` entry.\n * Undeclared fields are logged as-is, so they must hold only DataKable-safe data (paths, ids,\n * indices, counts). Text builders receive the redacted values: treat these fields as opaque and\n * only interpolate them.\n *\n * - `rowKey` / `rowKeys`: a row key / an array of them (hashed under `'safe'`).\n * - `value` / `values`: a cell value / an array of them (type summary unless `'full'`). The column\n * is `details.column` when it is a string, else the `where` column id.\n * - `schemaIssues`: one Standard Schema issue or an array of them (`scrubSchemaIssue`).\n * - `error`: a thrown value, e.g. a fetcher error (`scrubError`).\n */\nexport type RedactField = 'rowKey' | 'rowKeys' | 'value' | 'values' | 'schemaIssues' | 'error'\n\n/** A resolved policy, built once per emit. */\nexport interface Redactor {\n level: RedactLevel\n custom: RedactFn | undefined\n sensitive: ReadonlySet<string>\n rowKeySensitive: boolean\n /** Called when the custom rule throws; the value is logged as `[redacted]`. */\n onError?: (error: unknown) => void\n}\n\nexport const SENSITIVE = '[sensitive]'\nexport const REDACTED = '[redacted]'\n\nconst LEVELS: readonly string[] = ['safe', 'keys', 'full']\nconst EMPTY: ReadonlySet<string> = new Set()\n\nexport function resolveRedaction(\n option: RedactLevel | RedactionOptions | undefined,\n dev: boolean,\n): Redactor {\n const o: RedactionOptions = typeof option === 'string' ? { level: option } : (option ?? {})\n const level = o.level ?? (dev ? 'keys' : 'safe')\n const cols = o.sensitiveColumns?.()\n return {\n // An unknown level gets the strictest policy; validating the option is optionValidator's job.\n level: LEVELS.includes(level) ? level : 'safe',\n custom: o.redact,\n sensitive: cols ? new Set(cols) : EMPTY,\n rowKeySensitive: o.rowKeySensitive?.() ?? false,\n }\n}\n\n/** Short 32-bit FNV-1a hash of `String(key)` (UTF-16 code units), as `h:xxxxxxxx`. */\nexport function hashRowKey(key: unknown): string {\n const s = String(key)\n let h = 0x811c9dc5\n for (let i = 0; i < s.length; i++) {\n h ^= s.charCodeAt(i)\n h = Math.imul(h, 0x01000193)\n }\n return `h:${(h >>> 0).toString(16).padStart(8, '0')}`\n}\n\n/** The value's type, never its contents: `string(12)`, `number`, `array(3)`, `date`, … */\nexport function describeValue(v: unknown): string {\n if (v === null) return 'null'\n if (typeof v === 'string') return `string(${v.length})`\n if (typeof v === 'number') return Number.isNaN(v) ? 'number(NaN)' : 'number'\n if (Array.isArray(v)) return `array(${v.length})`\n if (v instanceof Date) return 'date'\n return typeof v\n}\n\nfunction custom(r: Redactor, path: string, value: unknown): string | undefined {\n if (!r.custom) return undefined\n try {\n return r.custom(path, value)\n } catch (e) {\n r.onError?.(e)\n return REDACTED\n }\n}\n\nfunction redactKey(r: Redactor, path: string, key: unknown): unknown {\n // A sensitive rowKey column wins over the custom rule and the level.\n if (r.rowKeySensitive) return hashRowKey(key)\n const c = custom(r, path, key)\n if (c !== undefined) return c\n return r.level === 'safe' ? hashRowKey(key) : key\n}\n\nfunction redactValue(r: Redactor, path: string, value: unknown, column?: string): unknown {\n if (column !== undefined && underSensitive(r, column)) return SENSITIVE\n const c = custom(r, path, value)\n if (c !== undefined) return c\n return r.level === 'full' ? value : describeValue(value)\n}\n\ntype IssuePath = ReadonlyArray<PropertyKey | { key: PropertyKey }>\n\n/** Joins a Standard Schema issue path: `['user', 0, { key: 'email' }]` → `user.0.email`. */\nfunction issuePath(path: IssuePath | undefined): string {\n if (!path) return ''\n return path.map((s) => String(typeof s === 'object' && s !== null ? s.key : s)).join('.')\n}\n\n/** `a` and `b` are the same path or one is inside the other (`contact` ↔ `contact.email`). */\nexport const pathsOverlap = (a: string, b: string): boolean =>\n a === b || a.startsWith(`${b}.`) || b.startsWith(`${a}.`)\n\n/** `path` is, is inside or contains a sensitive column (#45). */\nfunction underSensitive(r: Redactor, path: string): boolean {\n for (const col of r.sensitive) if (pathsOverlap(path, col)) return true\n return false\n}\n\n/**\n * A schema issue as `{ path, message }`. Validators embed received values in their messages, so\n * under `'safe'` / `'keys'` the message is DataKable's own text. So it is at every level when the\n * table has a sensitive column: any message (a root-level refinement, another field's) may embed\n * its value (#46).\n */\nexport function scrubSchemaIssue(\n issue: unknown,\n r: Redactor,\n fieldPath = 'issue',\n): { path: string; message: string } {\n const i = (typeof issue === 'object' && issue !== null ? issue : {}) as {\n message?: unknown\n path?: IssuePath\n }\n let path: string\n try {\n path = issuePath(i.path)\n } catch {\n path = ''\n }\n const own = `invalid value at ${path || '(root)'}`\n if (r.sensitive.size > 0) return { path, message: own }\n const c = custom(r, fieldPath, i.message)\n if (c !== undefined) return { path, message: c }\n return { path, message: r.level === 'full' && typeof i.message === 'string' ? i.message : own }\n}\n\n/**\n * A thrown value as `error.name` + `code` only (fetcher errors embed URLs, tokens, payloads). The\n * full error belongs in `context.cause`, which reaches `onDiagnostic` only.\n */\nexport function scrubError(e: unknown): string {\n if (typeof e !== 'object' || e === null) return typeof e\n try {\n const { name, code } = e as { name?: unknown; code?: unknown }\n const n = typeof name === 'string' && name ? name : 'object'\n return typeof code === 'string' || typeof code === 'number' ? `${n} (${code})` : n\n } catch {\n return 'object'\n }\n}\n\n/** Hashes / passes through `where.key` per the policy; other locations hold no user data. */\nexport function redactLocation(where: Location, r: Redactor): Location {\n if (where.kind !== 'row' || where.key === undefined) return where\n const key = redactKey(r, 'where.key', where.key)\n return { kind: 'row', index: where.index, key: typeof key === 'string' ? key : String(key) }\n}\n\n/** A shallow copy of `details` with the declared fields redacted; the input is never mutated. */\nexport function redactDetails(\n details: Record<string, unknown>,\n fields: Readonly<Record<string, RedactField | undefined>> | undefined,\n where: Location,\n r: Redactor,\n): Record<string, unknown> {\n if (!fields) return details\n const out: Record<string, unknown> = { ...details }\n const column =\n typeof details.column === 'string'\n ? details.column\n : where.kind === 'column'\n ? where.id\n : undefined\n for (const name of Object.keys(fields)) {\n const kind = fields[name]\n if (kind === undefined || !(name in details)) continue\n const v = details[name]\n const p = `details.${name}`\n const each = (f: (x: unknown, path: string) => unknown) =>\n Array.isArray(v) ? v.map((x, i) => f(x, `${p}.${i}`)) : f(v, p)\n switch (kind) {\n case 'rowKey':\n out[name] = redactKey(r, p, v)\n break\n case 'rowKeys':\n out[name] = each((x, path) => redactKey(r, path, x))\n break\n case 'value':\n out[name] = redactValue(r, p, v, column)\n break\n case 'values':\n out[name] = each((x, path) => redactValue(r, path, x, column))\n break\n case 'schemaIssues':\n out[name] = each((x, path) => scrubSchemaIssue(x, r, path))\n break\n case 'error':\n out[name] = custom(r, p, v) ?? scrubError(v)\n break\n }\n }\n return out\n}\n\n/** Message text (§8.2): development builds, or production via `@datakable/core/messages`. */\nexport const redactionMessages: DiagnosticMessages<'DK_UNSAFE_REDACTION'> = {\n DK_UNSAFE_REDACTION: {\n problem: (d) => `diagnostics.redact is '${d.level}' in a production build`,\n impact: () =>\n 'raw row keys and cell values (except sensitive columns) reach onDiagnostic, ' +\n 'getDiagnostics() and the console',\n fix: () => [\n \"remove diagnostics.redact in production (the default is 'safe')\",\n \"or use 'keys' to log raw row keys without cell values\",\n 'mark personal-data columns with sensitive: true so they are never logged',\n ],\n },\n}\n\n/** `'full'` in a production build (§8.2: \"warns if enabled in production\"). Emitted by the hub. */\nexport const DK_UNSAFE_REDACTION = defineDiagnostic(\n {\n code: 'DK_UNSAFE_REDACTION',\n level: 'warn',\n where: () => ({ kind: 'option', path: 'diagnostics.redact' }),\n },\n (process.env.NODE_ENV !== \"production\") && redactionMessages.DK_UNSAFE_REDACTION,\n)\n"],"mappings":"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","names":[]}
@@ -1,5 +1,6 @@
1
1
  // src/diagnostics/redact.ts
2
2
  import { defineDiagnostic } from "./catalog.js";
3
+ import "./process-guard.js";
3
4
  var SENSITIVE = "[sensitive]";
4
5
  var REDACTED = "[redacted]";
5
6
  var LEVELS = ["safe", "keys", "full"];
@@ -49,7 +50,7 @@ function redactKey(r, path, key) {
49
50
  return r.level === "safe" ? hashRowKey(key) : key;
50
51
  }
51
52
  function redactValue(r, path, value, column) {
52
- if (column !== void 0 && r.sensitive.has(column)) return SENSITIVE;
53
+ if (column !== void 0 && underSensitive(r, column)) return SENSITIVE;
53
54
  const c = custom(r, path, value);
54
55
  if (c !== void 0) return c;
55
56
  return r.level === "full" ? value : describeValue(value);
@@ -58,9 +59,9 @@ function issuePath(path) {
58
59
  if (!path) return "";
59
60
  return path.map((s) => String(typeof s === "object" && s !== null ? s.key : s)).join(".");
60
61
  }
62
+ var pathsOverlap = (a, b) => a === b || a.startsWith(`${b}.`) || b.startsWith(`${a}.`);
61
63
  function underSensitive(r, path) {
62
- if (r.sensitive.size === 0) return false;
63
- for (const col of r.sensitive) if (path === col || path.startsWith(`${col}.`)) return true;
64
+ for (const col of r.sensitive) if (pathsOverlap(path, col)) return true;
64
65
  return false;
65
66
  }
66
67
  function scrubSchemaIssue(issue, r, fieldPath = "issue") {
@@ -72,7 +73,7 @@ function scrubSchemaIssue(issue, r, fieldPath = "issue") {
72
73
  path = "";
73
74
  }
74
75
  const own = `invalid value at ${path || "(root)"}`;
75
- if (underSensitive(r, path)) return { path, message: own };
76
+ if (r.sensitive.size > 0) return { path, message: own };
76
77
  const c = custom(r, fieldPath, i.message);
77
78
  if (c !== void 0) return { path, message: c };
78
79
  return { path, message: r.level === "full" && typeof i.message === "string" ? i.message : own };
@@ -150,6 +151,7 @@ export {
150
151
  SENSITIVE,
151
152
  describeValue,
152
153
  hashRowKey,
154
+ pathsOverlap,
153
155
  redactDetails,
154
156
  redactLocation,
155
157
  redactionMessages,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/diagnostics/redact.ts"],"sourcesContent":["import { type DiagnosticMessages, defineDiagnostic } from './catalog'\nimport type { Location } from './types'\n\ndeclare module './catalog' {\n interface DiagnosticCatalog {\n DK_UNSAFE_REDACTION: { level: 'full' }\n }\n}\n\n/**\n * Redaction levels (§8.2). `'safe'`: paths, indices, counts, value types, hashed row keys\n * (production default). `'keys'`: + raw row keys (development default). `'full'`: + row values.\n */\nexport type RedactLevel = 'safe' | 'keys' | 'full'\n\n/**\n * Custom rule: return a string to log instead of `value`, or `undefined` for the built-in policy.\n * `path` names the field, e.g. `where.key`, `details.value`, `details.keys.2`, `details.issues.0`.\n * Sensitive columns never reach it.\n */\nexport type RedactFn = (path: string, value: unknown) => string | undefined\n\nexport interface RedactionOptions {\n /** Default `'keys'` in development, `'safe'` in production. */\n level?: RedactLevel\n redact?: RedactFn\n /** Ids / keys of `sensitive: true` columns: never logged at any level. */\n sensitiveColumns?: () => Iterable<string>\n /** The `rowKey` column is sensitive: row keys are hashed at every level. */\n rowKeySensitive?: () => boolean\n}\n\n/**\n * Which detail fields of a diagnostic carry user data, declared on its `defineDiagnostic` entry.\n * Undeclared fields are logged as-is, so they must hold only DataKable-safe data (paths, ids,\n * indices, counts). Text builders receive the redacted values: treat these fields as opaque and\n * only interpolate them.\n *\n * - `rowKey` / `rowKeys`: a row key / an array of them (hashed under `'safe'`).\n * - `value` / `values`: a cell value / an array of them (type summary unless `'full'`). The column\n * is `details.column` when it is a string, else the `where` column id.\n * - `schemaIssues`: one Standard Schema issue or an array of them (`scrubSchemaIssue`).\n * - `error`: a thrown value, e.g. a fetcher error (`scrubError`).\n */\nexport type RedactField = 'rowKey' | 'rowKeys' | 'value' | 'values' | 'schemaIssues' | 'error'\n\n/** A resolved policy, built once per emit. */\nexport interface Redactor {\n level: RedactLevel\n custom: RedactFn | undefined\n sensitive: ReadonlySet<string>\n rowKeySensitive: boolean\n /** Called when the custom rule throws; the value is logged as `[redacted]`. */\n onError?: (error: unknown) => void\n}\n\nexport const SENSITIVE = '[sensitive]'\nexport const REDACTED = '[redacted]'\n\nconst LEVELS: readonly string[] = ['safe', 'keys', 'full']\nconst EMPTY: ReadonlySet<string> = new Set()\n\nexport function resolveRedaction(\n option: RedactLevel | RedactionOptions | undefined,\n dev: boolean,\n): Redactor {\n const o: RedactionOptions = typeof option === 'string' ? { level: option } : (option ?? {})\n const level = o.level ?? (dev ? 'keys' : 'safe')\n const cols = o.sensitiveColumns?.()\n return {\n // An unknown level gets the strictest policy; validating the option is optionValidator's job.\n level: LEVELS.includes(level) ? level : 'safe',\n custom: o.redact,\n sensitive: cols ? new Set(cols) : EMPTY,\n rowKeySensitive: o.rowKeySensitive?.() ?? false,\n }\n}\n\n/** Short 32-bit FNV-1a hash of `String(key)` (UTF-16 code units), as `h:xxxxxxxx`. */\nexport function hashRowKey(key: unknown): string {\n const s = String(key)\n let h = 0x811c9dc5\n for (let i = 0; i < s.length; i++) {\n h ^= s.charCodeAt(i)\n h = Math.imul(h, 0x01000193)\n }\n return `h:${(h >>> 0).toString(16).padStart(8, '0')}`\n}\n\n/** The value's type, never its contents: `string(12)`, `number`, `array(3)`, `date`, … */\nexport function describeValue(v: unknown): string {\n if (v === null) return 'null'\n if (typeof v === 'string') return `string(${v.length})`\n if (typeof v === 'number') return Number.isNaN(v) ? 'number(NaN)' : 'number'\n if (Array.isArray(v)) return `array(${v.length})`\n if (v instanceof Date) return 'date'\n return typeof v\n}\n\nfunction custom(r: Redactor, path: string, value: unknown): string | undefined {\n if (!r.custom) return undefined\n try {\n return r.custom(path, value)\n } catch (e) {\n r.onError?.(e)\n return REDACTED\n }\n}\n\nfunction redactKey(r: Redactor, path: string, key: unknown): unknown {\n // A sensitive rowKey column wins over the custom rule and the level.\n if (r.rowKeySensitive) return hashRowKey(key)\n const c = custom(r, path, key)\n if (c !== undefined) return c\n return r.level === 'safe' ? hashRowKey(key) : key\n}\n\nfunction redactValue(r: Redactor, path: string, value: unknown, column?: string): unknown {\n if (column !== undefined && r.sensitive.has(column)) return SENSITIVE\n const c = custom(r, path, value)\n if (c !== undefined) return c\n return r.level === 'full' ? value : describeValue(value)\n}\n\ntype IssuePath = ReadonlyArray<PropertyKey | { key: PropertyKey }>\n\n/** Joins a Standard Schema issue path: `['user', 0, { key: 'email' }]` → `user.0.email`. */\nfunction issuePath(path: IssuePath | undefined): string {\n if (!path) return ''\n return path.map((s) => String(typeof s === 'object' && s !== null ? s.key : s)).join('.')\n}\n\nfunction underSensitive(r: Redactor, path: string): boolean {\n if (r.sensitive.size === 0) return false\n for (const col of r.sensitive) if (path === col || path.startsWith(`${col}.`)) return true\n return false\n}\n\n/**\n * A schema issue as `{ path, message }`. Validators embed received values in their messages, so\n * under `'safe'` / `'keys'` (and for sensitive columns) the message is DataKable's own text.\n */\nexport function scrubSchemaIssue(\n issue: unknown,\n r: Redactor,\n fieldPath = 'issue',\n): { path: string; message: string } {\n const i = (typeof issue === 'object' && issue !== null ? issue : {}) as {\n message?: unknown\n path?: IssuePath\n }\n let path: string\n try {\n path = issuePath(i.path)\n } catch {\n path = ''\n }\n const own = `invalid value at ${path || '(root)'}`\n if (underSensitive(r, path)) return { path, message: own }\n const c = custom(r, fieldPath, i.message)\n if (c !== undefined) return { path, message: c }\n return { path, message: r.level === 'full' && typeof i.message === 'string' ? i.message : own }\n}\n\n/**\n * A thrown value as `error.name` + `code` only (fetcher errors embed URLs, tokens, payloads). The\n * full error belongs in `context.cause`, which reaches `onDiagnostic` only.\n */\nexport function scrubError(e: unknown): string {\n if (typeof e !== 'object' || e === null) return typeof e\n try {\n const { name, code } = e as { name?: unknown; code?: unknown }\n const n = typeof name === 'string' && name ? name : 'object'\n return typeof code === 'string' || typeof code === 'number' ? `${n} (${code})` : n\n } catch {\n return 'object'\n }\n}\n\n/** Hashes / passes through `where.key` per the policy; other locations hold no user data. */\nexport function redactLocation(where: Location, r: Redactor): Location {\n if (where.kind !== 'row' || where.key === undefined) return where\n const key = redactKey(r, 'where.key', where.key)\n return { kind: 'row', index: where.index, key: typeof key === 'string' ? key : String(key) }\n}\n\n/** A shallow copy of `details` with the declared fields redacted; the input is never mutated. */\nexport function redactDetails(\n details: Record<string, unknown>,\n fields: Readonly<Record<string, RedactField | undefined>> | undefined,\n where: Location,\n r: Redactor,\n): Record<string, unknown> {\n if (!fields) return details\n const out: Record<string, unknown> = { ...details }\n const column =\n typeof details.column === 'string'\n ? details.column\n : where.kind === 'column'\n ? where.id\n : undefined\n for (const name of Object.keys(fields)) {\n const kind = fields[name]\n if (kind === undefined || !(name in details)) continue\n const v = details[name]\n const p = `details.${name}`\n const each = (f: (x: unknown, path: string) => unknown) =>\n Array.isArray(v) ? v.map((x, i) => f(x, `${p}.${i}`)) : f(v, p)\n switch (kind) {\n case 'rowKey':\n out[name] = redactKey(r, p, v)\n break\n case 'rowKeys':\n out[name] = each((x, path) => redactKey(r, path, x))\n break\n case 'value':\n out[name] = redactValue(r, p, v, column)\n break\n case 'values':\n out[name] = each((x, path) => redactValue(r, path, x, column))\n break\n case 'schemaIssues':\n out[name] = each((x, path) => scrubSchemaIssue(x, r, path))\n break\n case 'error':\n out[name] = custom(r, p, v) ?? scrubError(v)\n break\n }\n }\n return out\n}\n\n/** Message text (§8.2): development builds, or production via `@datakable/core/messages`. */\nexport const redactionMessages: DiagnosticMessages<'DK_UNSAFE_REDACTION'> = {\n DK_UNSAFE_REDACTION: {\n problem: (d) => `diagnostics.redact is '${d.level}' in a production build`,\n impact: () =>\n 'raw row keys and cell values (except sensitive columns) reach onDiagnostic, ' +\n 'getDiagnostics() and the console',\n fix: () => [\n \"remove diagnostics.redact in production (the default is 'safe')\",\n \"or use 'keys' to log raw row keys without cell values\",\n 'mark personal-data columns with sensitive: true so they are never logged',\n ],\n },\n}\n\n/** `'full'` in a production build (§8.2: \"warns if enabled in production\"). Emitted by the hub. */\nexport const DK_UNSAFE_REDACTION = defineDiagnostic(\n {\n code: 'DK_UNSAFE_REDACTION',\n level: 'warn',\n where: () => ({ kind: 'option', path: 'diagnostics.redact' }),\n },\n (process.env.NODE_ENV !== \"production\") && redactionMessages.DK_UNSAFE_REDACTION,\n)\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/diagnostics/redact.ts"],"sourcesContent":["import { type DiagnosticMessages, defineDiagnostic } from './catalog'\nimport './process-guard'\nimport type { Location } from './types'\n\ndeclare module './catalog' {\n interface DiagnosticCatalog {\n DK_UNSAFE_REDACTION: { level: 'full' }\n }\n}\n\n/**\n * Redaction levels (§8.2). `'safe'`: paths, indices, counts, value types, hashed row keys\n * (production default). `'keys'`: + raw row keys (development default). `'full'`: + row values.\n */\nexport type RedactLevel = 'safe' | 'keys' | 'full'\n\n/**\n * Custom rule: return a string to log instead of `value`, or `undefined` for the built-in policy.\n * `path` names the field, e.g. `where.key`, `details.value`, `details.keys.2`, `details.issues.0`.\n * Sensitive columns never reach it.\n */\nexport type RedactFn = (path: string, value: unknown) => string | undefined\n\nexport interface RedactionOptions {\n /** Default `'keys'` in development, `'safe'` in production. */\n level?: RedactLevel\n redact?: RedactFn\n /** Ids / keys of `sensitive: true` columns: never logged at any level. */\n sensitiveColumns?: () => Iterable<string>\n /** The `rowKey` path is, is inside or contains a sensitive column: keys hashed at every level. */\n rowKeySensitive?: () => boolean\n}\n\n/**\n * Which detail fields of a diagnostic carry user data, declared on its `defineDiagnostic` entry.\n * Undeclared fields are logged as-is, so they must hold only DataKable-safe data (paths, ids,\n * indices, counts). Text builders receive the redacted values: treat these fields as opaque and\n * only interpolate them.\n *\n * - `rowKey` / `rowKeys`: a row key / an array of them (hashed under `'safe'`).\n * - `value` / `values`: a cell value / an array of them (type summary unless `'full'`). The column\n * is `details.column` when it is a string, else the `where` column id.\n * - `schemaIssues`: one Standard Schema issue or an array of them (`scrubSchemaIssue`).\n * - `error`: a thrown value, e.g. a fetcher error (`scrubError`).\n */\nexport type RedactField = 'rowKey' | 'rowKeys' | 'value' | 'values' | 'schemaIssues' | 'error'\n\n/** A resolved policy, built once per emit. */\nexport interface Redactor {\n level: RedactLevel\n custom: RedactFn | undefined\n sensitive: ReadonlySet<string>\n rowKeySensitive: boolean\n /** Called when the custom rule throws; the value is logged as `[redacted]`. */\n onError?: (error: unknown) => void\n}\n\nexport const SENSITIVE = '[sensitive]'\nexport const REDACTED = '[redacted]'\n\nconst LEVELS: readonly string[] = ['safe', 'keys', 'full']\nconst EMPTY: ReadonlySet<string> = new Set()\n\nexport function resolveRedaction(\n option: RedactLevel | RedactionOptions | undefined,\n dev: boolean,\n): Redactor {\n const o: RedactionOptions = typeof option === 'string' ? { level: option } : (option ?? {})\n const level = o.level ?? (dev ? 'keys' : 'safe')\n const cols = o.sensitiveColumns?.()\n return {\n // An unknown level gets the strictest policy; validating the option is optionValidator's job.\n level: LEVELS.includes(level) ? level : 'safe',\n custom: o.redact,\n sensitive: cols ? new Set(cols) : EMPTY,\n rowKeySensitive: o.rowKeySensitive?.() ?? false,\n }\n}\n\n/** Short 32-bit FNV-1a hash of `String(key)` (UTF-16 code units), as `h:xxxxxxxx`. */\nexport function hashRowKey(key: unknown): string {\n const s = String(key)\n let h = 0x811c9dc5\n for (let i = 0; i < s.length; i++) {\n h ^= s.charCodeAt(i)\n h = Math.imul(h, 0x01000193)\n }\n return `h:${(h >>> 0).toString(16).padStart(8, '0')}`\n}\n\n/** The value's type, never its contents: `string(12)`, `number`, `array(3)`, `date`, … */\nexport function describeValue(v: unknown): string {\n if (v === null) return 'null'\n if (typeof v === 'string') return `string(${v.length})`\n if (typeof v === 'number') return Number.isNaN(v) ? 'number(NaN)' : 'number'\n if (Array.isArray(v)) return `array(${v.length})`\n if (v instanceof Date) return 'date'\n return typeof v\n}\n\nfunction custom(r: Redactor, path: string, value: unknown): string | undefined {\n if (!r.custom) return undefined\n try {\n return r.custom(path, value)\n } catch (e) {\n r.onError?.(e)\n return REDACTED\n }\n}\n\nfunction redactKey(r: Redactor, path: string, key: unknown): unknown {\n // A sensitive rowKey column wins over the custom rule and the level.\n if (r.rowKeySensitive) return hashRowKey(key)\n const c = custom(r, path, key)\n if (c !== undefined) return c\n return r.level === 'safe' ? hashRowKey(key) : key\n}\n\nfunction redactValue(r: Redactor, path: string, value: unknown, column?: string): unknown {\n if (column !== undefined && underSensitive(r, column)) return SENSITIVE\n const c = custom(r, path, value)\n if (c !== undefined) return c\n return r.level === 'full' ? value : describeValue(value)\n}\n\ntype IssuePath = ReadonlyArray<PropertyKey | { key: PropertyKey }>\n\n/** Joins a Standard Schema issue path: `['user', 0, { key: 'email' }]` → `user.0.email`. */\nfunction issuePath(path: IssuePath | undefined): string {\n if (!path) return ''\n return path.map((s) => String(typeof s === 'object' && s !== null ? s.key : s)).join('.')\n}\n\n/** `a` and `b` are the same path or one is inside the other (`contact` ↔ `contact.email`). */\nexport const pathsOverlap = (a: string, b: string): boolean =>\n a === b || a.startsWith(`${b}.`) || b.startsWith(`${a}.`)\n\n/** `path` is, is inside or contains a sensitive column (#45). */\nfunction underSensitive(r: Redactor, path: string): boolean {\n for (const col of r.sensitive) if (pathsOverlap(path, col)) return true\n return false\n}\n\n/**\n * A schema issue as `{ path, message }`. Validators embed received values in their messages, so\n * under `'safe'` / `'keys'` the message is DataKable's own text. So it is at every level when the\n * table has a sensitive column: any message (a root-level refinement, another field's) may embed\n * its value (#46).\n */\nexport function scrubSchemaIssue(\n issue: unknown,\n r: Redactor,\n fieldPath = 'issue',\n): { path: string; message: string } {\n const i = (typeof issue === 'object' && issue !== null ? issue : {}) as {\n message?: unknown\n path?: IssuePath\n }\n let path: string\n try {\n path = issuePath(i.path)\n } catch {\n path = ''\n }\n const own = `invalid value at ${path || '(root)'}`\n if (r.sensitive.size > 0) return { path, message: own }\n const c = custom(r, fieldPath, i.message)\n if (c !== undefined) return { path, message: c }\n return { path, message: r.level === 'full' && typeof i.message === 'string' ? i.message : own }\n}\n\n/**\n * A thrown value as `error.name` + `code` only (fetcher errors embed URLs, tokens, payloads). The\n * full error belongs in `context.cause`, which reaches `onDiagnostic` only.\n */\nexport function scrubError(e: unknown): string {\n if (typeof e !== 'object' || e === null) return typeof e\n try {\n const { name, code } = e as { name?: unknown; code?: unknown }\n const n = typeof name === 'string' && name ? name : 'object'\n return typeof code === 'string' || typeof code === 'number' ? `${n} (${code})` : n\n } catch {\n return 'object'\n }\n}\n\n/** Hashes / passes through `where.key` per the policy; other locations hold no user data. */\nexport function redactLocation(where: Location, r: Redactor): Location {\n if (where.kind !== 'row' || where.key === undefined) return where\n const key = redactKey(r, 'where.key', where.key)\n return { kind: 'row', index: where.index, key: typeof key === 'string' ? key : String(key) }\n}\n\n/** A shallow copy of `details` with the declared fields redacted; the input is never mutated. */\nexport function redactDetails(\n details: Record<string, unknown>,\n fields: Readonly<Record<string, RedactField | undefined>> | undefined,\n where: Location,\n r: Redactor,\n): Record<string, unknown> {\n if (!fields) return details\n const out: Record<string, unknown> = { ...details }\n const column =\n typeof details.column === 'string'\n ? details.column\n : where.kind === 'column'\n ? where.id\n : undefined\n for (const name of Object.keys(fields)) {\n const kind = fields[name]\n if (kind === undefined || !(name in details)) continue\n const v = details[name]\n const p = `details.${name}`\n const each = (f: (x: unknown, path: string) => unknown) =>\n Array.isArray(v) ? v.map((x, i) => f(x, `${p}.${i}`)) : f(v, p)\n switch (kind) {\n case 'rowKey':\n out[name] = redactKey(r, p, v)\n break\n case 'rowKeys':\n out[name] = each((x, path) => redactKey(r, path, x))\n break\n case 'value':\n out[name] = redactValue(r, p, v, column)\n break\n case 'values':\n out[name] = each((x, path) => redactValue(r, path, x, column))\n break\n case 'schemaIssues':\n out[name] = each((x, path) => scrubSchemaIssue(x, r, path))\n break\n case 'error':\n out[name] = custom(r, p, v) ?? scrubError(v)\n break\n }\n }\n return out\n}\n\n/** Message text (§8.2): development builds, or production via `@datakable/core/messages`. */\nexport const redactionMessages: DiagnosticMessages<'DK_UNSAFE_REDACTION'> = {\n DK_UNSAFE_REDACTION: {\n problem: (d) => `diagnostics.redact is '${d.level}' in a production build`,\n impact: () =>\n 'raw row keys and cell values (except sensitive columns) reach onDiagnostic, ' +\n 'getDiagnostics() and the console',\n fix: () => [\n \"remove diagnostics.redact in production (the default is 'safe')\",\n \"or use 'keys' to log raw row keys without cell values\",\n 'mark personal-data columns with sensitive: true so they are never logged',\n ],\n },\n}\n\n/** `'full'` in a production build (§8.2: \"warns if enabled in production\"). Emitted by the hub. */\nexport const DK_UNSAFE_REDACTION = defineDiagnostic(\n {\n code: 'DK_UNSAFE_REDACTION',\n level: 'warn',\n where: () => ({ kind: 'option', path: 'diagnostics.redact' }),\n },\n (process.env.NODE_ENV !== \"production\") && redactionMessages.DK_UNSAFE_REDACTION,\n)\n"],"mappings":"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","names":[]}
@@ -20,10 +20,14 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/diagnostics/trace-store.ts
21
21
  var trace_store_exports = {};
22
22
  __export(trace_store_exports, {
23
+ SLICED: () => SLICED,
23
24
  readTrace: () => readTrace,
25
+ sliceTimer: () => sliceTimer,
24
26
  writeTrace: () => writeTrace
25
27
  });
26
28
  module.exports = __toCommonJS(trace_store_exports);
29
+ var SLICED = "sliced";
30
+ var sliceTimer = {};
27
31
  var traces = /* @__PURE__ */ new WeakMap();
28
32
  var readTrace = (table) => traces.get(table);
29
33
  var writeTrace = (table, trace) => {
@@ -31,7 +35,9 @@ var writeTrace = (table, trace) => {
31
35
  };
32
36
  // Annotate the CommonJS export names for ESM import in node:
33
37
  0 && (module.exports = {
38
+ SLICED,
34
39
  readTrace,
40
+ sliceTimer,
35
41
  writeTrace
36
42
  });
37
43
  //# sourceMappingURL=trace-store.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/diagnostics/trace-store.ts"],"sourcesContent":["import type { Trigger } from './types'\n\n/** One step of the traced run: counts (never rows) and its duration (§9.1: bounded). */\nexport interface TraceStep {\n readonly input: number\n readonly output: number\n readonly ms: number\n}\n\n/** What the tracer kept of the last `pipeline:run` of a table (the last run only). */\nexport interface Trace {\n readonly run: number\n readonly trigger: Trigger\n /** Duration of the whole run; `undefined` while it is in progress. */\n ms: number | undefined\n /** Steps that ran (a step served from its memo is absent), by feature name. */\n readonly steps: Map<string, TraceStep>\n /** The last `state:dispatch` (its `where`: a method / feature name) and its duration. */\n dispatch: { where: string; ms: number } | undefined\n}\n\n/** Kept apart from the tracer so `explain()` reads traces without bundling the tracer itself. */\nconst traces = new WeakMap<object, Trace>()\n\n/** The last traced run of `table`, if a tracer is installed. */\nexport const readTrace = (table: object): Trace | undefined => traces.get(table)\n\nexport const writeTrace = (table: object, trace: Trace): void => {\n traces.set(table, trace)\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAsBA,IAAM,SAAS,oBAAI,QAAuB;AAGnC,IAAM,YAAY,CAAC,UAAqC,OAAO,IAAI,KAAK;AAExE,IAAM,aAAa,CAAC,OAAe,UAAuB;AAC/D,SAAO,IAAI,OAAO,KAAK;AACzB;","names":[]}
1
+ {"version":3,"sources":["../../src/diagnostics/trace-store.ts"],"sourcesContent":["import type { ContextBase } from '../intercept/context'\nimport type { Trigger } from './types'\n\n/** One step of the traced run: counts (never rows) and its duration (§9.1: bounded). */\nexport interface TraceStep {\n readonly input: number\n readonly output: number\n /** With time-sliced work (#61): the runs that waited on it, this one, and the slices between. */\n readonly ms: number\n /** Time-sliced work (#61): the runs {@link ms} spans (absent when the step ran in one). */\n readonly runs?: number\n}\n\n/** What the tracer kept of the last `pipeline:run` of a table (the last run only). */\nexport interface Trace {\n readonly run: number\n readonly trigger: Trigger\n /** Duration of the whole run; `undefined` while it is in progress. */\n ms: number | undefined\n /** Steps that ran (a step served from its memo is absent), by feature name. */\n readonly steps: Map<string, TraceStep>\n /** The last `state:dispatch` (its `where`: a method / feature name) and its duration. */\n dispatch: { where: string; ms: number } | undefined\n}\n\n/**\n * Set on the `pipeline:step` ctx's `meta` by the runner when the step waits on time-sliced work\n * (its result comes in a later run).\n */\nexport const SLICED = 'sliced'\n\n/**\n * The tracer's (#61): the runner reports each slice of time-sliced work run between pipeline runs\n * (no step is timing it). Unset until a tracer is created.\n */\nexport const sliceTimer: {\n current?: ((base: ContextBase, feature: string, ms: number) => void) | undefined\n} = {}\n\n/** Kept apart from the tracer so `explain()` reads traces without bundling the tracer itself. */\nconst traces = new WeakMap<object, Trace>()\n\n/** The last traced run of `table`, if a tracer is installed. */\nexport const readTrace = (table: object): Trace | undefined => traces.get(table)\n\nexport const writeTrace = (table: object, trace: Trace): void => {\n traces.set(table, trace)\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA6BO,IAAM,SAAS;AAMf,IAAM,aAET,CAAC;AAGL,IAAM,SAAS,oBAAI,QAAuB;AAGnC,IAAM,YAAY,CAAC,UAAqC,OAAO,IAAI,KAAK;AAExE,IAAM,aAAa,CAAC,OAAe,UAAuB;AAC/D,SAAO,IAAI,OAAO,KAAK;AACzB;","names":[]}
@@ -1,11 +1,15 @@
1
1
  // src/diagnostics/trace-store.ts
2
+ var SLICED = "sliced";
3
+ var sliceTimer = {};
2
4
  var traces = /* @__PURE__ */ new WeakMap();
3
5
  var readTrace = (table) => traces.get(table);
4
6
  var writeTrace = (table, trace) => {
5
7
  traces.set(table, trace);
6
8
  };
7
9
  export {
10
+ SLICED,
8
11
  readTrace,
12
+ sliceTimer,
9
13
  writeTrace
10
14
  };
11
15
  //# sourceMappingURL=trace-store.js.map