@datakable/core 2.0.1 → 2.0.3

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 (125) hide show
  1. package/README.md +3 -2
  2. package/dist/{codes-B9bCK73-.d.cts → codes-4sYQv_7J.d.cts} +42 -12
  3. package/dist/{codes-B9bCK73-.d.ts → codes-4sYQv_7J.d.ts} +42 -12
  4. package/dist/column-filters.d.cts +2 -2
  5. package/dist/column-filters.d.ts +2 -2
  6. package/dist/diagnostics/build.cjs +1 -1
  7. package/dist/diagnostics/build.cjs.map +1 -1
  8. package/dist/diagnostics/build.js +2 -2
  9. package/dist/diagnostics/build.js.map +1 -1
  10. package/dist/diagnostics/console.cjs +15 -4
  11. package/dist/diagnostics/console.cjs.map +1 -1
  12. package/dist/diagnostics/console.js +15 -4
  13. package/dist/diagnostics/console.js.map +1 -1
  14. package/dist/diagnostics/explain.cjs.map +1 -1
  15. package/dist/diagnostics/explain.js.map +1 -1
  16. package/dist/diagnostics/hub.cjs +7 -1
  17. package/dist/diagnostics/hub.cjs.map +1 -1
  18. package/dist/diagnostics/hub.js +7 -1
  19. package/dist/diagnostics/hub.js.map +1 -1
  20. package/dist/diagnostics/prose.cjs +10 -1
  21. package/dist/diagnostics/prose.cjs.map +1 -1
  22. package/dist/diagnostics/prose.js +9 -1
  23. package/dist/diagnostics/prose.js.map +1 -1
  24. package/dist/diagnostics/redact.cjs +1 -1
  25. package/dist/diagnostics/redact.cjs.map +1 -1
  26. package/dist/diagnostics/redact.js +1 -1
  27. package/dist/diagnostics/redact.js.map +1 -1
  28. package/dist/diagnostics/types.cjs.map +1 -1
  29. package/dist/{explain-i0OATi_W.d.ts → explain-DmwN_RG9.d.cts} +13 -6
  30. package/dist/{explain-Q8Cg0cZy.d.cts → explain-Dr3SmMNY.d.ts} +13 -6
  31. package/dist/feature/install.cjs +2 -1
  32. package/dist/feature/install.cjs.map +1 -1
  33. package/dist/feature/install.js +2 -1
  34. package/dist/feature/install.js.map +1 -1
  35. package/dist/feature/slice-guard.cjs +76 -0
  36. package/dist/feature/slice-guard.cjs.map +1 -0
  37. package/dist/feature/slice-guard.js +50 -0
  38. package/dist/feature/slice-guard.js.map +1 -0
  39. package/dist/features/column-filters/codes.cjs +2 -19
  40. package/dist/features/column-filters/codes.cjs.map +1 -1
  41. package/dist/features/column-filters/codes.js +2 -19
  42. package/dist/features/column-filters/codes.js.map +1 -1
  43. package/dist/features/column-filters/column-filters.cjs +37 -22
  44. package/dist/features/column-filters/column-filters.cjs.map +1 -1
  45. package/dist/features/column-filters/column-filters.js +37 -22
  46. package/dist/features/column-filters/column-filters.js.map +1 -1
  47. package/dist/features/column-filters/match.cjs +6 -2
  48. package/dist/features/column-filters/match.cjs.map +1 -1
  49. package/dist/features/column-filters/match.js +6 -2
  50. package/dist/features/column-filters/match.js.map +1 -1
  51. package/dist/features/pagination/pagination.cjs +2 -2
  52. package/dist/features/pagination/pagination.cjs.map +1 -1
  53. package/dist/features/pagination/pagination.js +2 -2
  54. package/dist/features/pagination/pagination.js.map +1 -1
  55. package/dist/features/search/codes.cjs +18 -2
  56. package/dist/features/search/codes.cjs.map +1 -1
  57. package/dist/features/search/codes.js +16 -1
  58. package/dist/features/search/codes.js.map +1 -1
  59. package/dist/features/search/search-engine.cjs +24 -5
  60. package/dist/features/search/search-engine.cjs.map +1 -1
  61. package/dist/features/search/search-engine.js +25 -6
  62. package/dist/features/search/search-engine.js.map +1 -1
  63. package/dist/features/sorting/sorting.cjs +55 -24
  64. package/dist/features/sorting/sorting.cjs.map +1 -1
  65. package/dist/features/sorting/sorting.js +55 -24
  66. package/dist/features/sorting/sorting.js.map +1 -1
  67. package/dist/index.d.cts +26 -17
  68. package/dist/index.d.ts +26 -17
  69. package/dist/intercept/runtime.cjs +3 -2
  70. package/dist/intercept/runtime.cjs.map +1 -1
  71. package/dist/intercept/runtime.js +3 -2
  72. package/dist/intercept/runtime.js.map +1 -1
  73. package/dist/messages/index.cjs +2 -0
  74. package/dist/messages/index.cjs.map +1 -1
  75. package/dist/messages/index.js +2 -0
  76. package/dist/messages/index.js.map +1 -1
  77. package/dist/pagination.d.cts +2 -2
  78. package/dist/pagination.d.ts +2 -2
  79. package/dist/schema.d.cts +2 -2
  80. package/dist/schema.d.ts +2 -2
  81. package/dist/{search-async-entry-CuLYPfY_.d.cts → search-async-entry-BiemO3JT.d.cts} +2 -2
  82. package/dist/{search-async-entry-Cx7xpuVZ.d.ts → search-async-entry-GRj0E06n.d.ts} +2 -2
  83. package/dist/search-async.d.cts +3 -3
  84. package/dist/search-async.d.ts +3 -3
  85. package/dist/search.d.cts +4 -4
  86. package/dist/search.d.ts +4 -4
  87. package/dist/server.d.cts +3 -3
  88. package/dist/server.d.ts +3 -3
  89. package/dist/sorting.d.cts +2 -2
  90. package/dist/sorting.d.ts +2 -2
  91. package/dist/source/async-control.cjs +2 -1
  92. package/dist/source/async-control.cjs.map +1 -1
  93. package/dist/source/async-control.js +2 -1
  94. package/dist/source/async-control.js.map +1 -1
  95. package/dist/source/fetcher.cjs.map +1 -1
  96. package/dist/source/fetcher.js.map +1 -1
  97. package/dist/source/server.cjs +58 -5
  98. package/dist/source/server.cjs.map +1 -1
  99. package/dist/source/server.js +58 -5
  100. package/dist/source/server.js.map +1 -1
  101. package/dist/table/create-table.cjs +30 -20
  102. package/dist/table/create-table.cjs.map +1 -1
  103. package/dist/table/create-table.js +30 -20
  104. package/dist/table/create-table.js.map +1 -1
  105. package/dist/table/index.cjs +3 -0
  106. package/dist/table/index.cjs.map +1 -1
  107. package/dist/table/index.js +5 -1
  108. package/dist/table/index.js.map +1 -1
  109. package/dist/table/state-codes.cjs +72 -0
  110. package/dist/table/state-codes.cjs.map +1 -0
  111. package/dist/table/state-codes.js +45 -0
  112. package/dist/table/state-codes.js.map +1 -0
  113. package/dist/table/types.cjs.map +1 -1
  114. package/dist/table/types.js.map +1 -1
  115. package/dist/validity.d.cts +2 -2
  116. package/dist/validity.d.ts +2 -2
  117. package/dist/version.cjs +1 -1
  118. package/dist/version.cjs.map +1 -1
  119. package/dist/version.js +1 -1
  120. package/dist/version.js.map +1 -1
  121. package/package.json +1 -1
  122. package/dist/ingest/test-schemas.cjs +0 -73
  123. package/dist/ingest/test-schemas.cjs.map +0 -1
  124. package/dist/ingest/test-schemas.js +0 -46
  125. package/dist/ingest/test-schemas.js.map +0 -1
package/README.md CHANGED
@@ -404,8 +404,9 @@ for (const d of table.getDiagnostics()) console.log(d.code, d.where, d.fix)
404
404
  - **Redaction** (`diagnostics.redact`): `'safe'` logs paths, indices, counts, value types and
405
405
  hashed row keys (production default); `'keys'` adds raw row keys (development default); `'full'`
406
406
  adds row values. A custom `redact(path, value)` can rewrite any field. Columns with
407
- `sensitive: true` are never logged at any level, and fetcher errors are logged by name only (the
408
- original goes to `onDiagnostic` as `context.cause`).
407
+ `sensitive: true` are never logged at any level (a sensitive `rowKey` is logged as
408
+ `[sensitive]`, not hashed), and fetcher errors are logged by name only (the original goes to
409
+ `onDiagnostic` as `context.cause`; `getDiagnostics()` leaves it out).
409
410
  - **Production text:** production builds keep `code`, `where`, `context` and a docs URL and drop
410
411
  the `problem` / `impact` / `fix` text. To keep it:
411
412
 
@@ -55,7 +55,11 @@ interface DiagnosticContext {
55
55
  };
56
56
  /** e.g. `DK_SCHEMA_INVALID_ROW#run57` */
57
57
  causedBy?: string;
58
- /** Original error (ES2022 cause). Reaches `onDiagnostic` only; `toJSON` and the console leave it out. */
58
+ /**
59
+ * Original error (ES2022 cause). Reaches code you install (`onDiagnostic`, `diagnostic:emit`
60
+ * interceptors, the `redact` seam) and, under `strict`, the thrown `DatakableError`'s `cause`;
61
+ * `getDiagnostics()`, `toJSON` and the console leave it out.
62
+ */
59
63
  cause?: unknown;
60
64
  }
61
65
  interface Diagnostic {
@@ -119,7 +123,7 @@ interface RedactionOptions {
119
123
  redact?: RedactFn;
120
124
  /** Ids / keys of `sensitive: true` columns: never logged at any level. */
121
125
  sensitiveColumns?: () => Iterable<string>;
122
- /** The `rowKey` path is, is inside or contains a sensitive column: keys hashed at every level. */
126
+ /** The `rowKey` path is, is inside or contains a sensitive column: keys logged as `[sensitive]` at every level. */
123
127
  rowKeySensitive?: () => boolean;
124
128
  }
125
129
  /**
@@ -728,6 +732,14 @@ declare module '@datakable/core' {
728
732
  /** Whether a previous `searchFn` result is shown (`false`: none applied yet). */
729
733
  hadResults: boolean;
730
734
  };
735
+ DK_SEARCH_UNKNOWN_KEYS: {
736
+ /** Returned `{ keys }` that match no row's key (compared as strings). */
737
+ count: number;
738
+ /** How many keys `searchFn` returned. */
739
+ returned: number;
740
+ /** A sample of the unmatched keys (first few; redacted as row keys). */
741
+ keys: readonly unknown[];
742
+ };
731
743
  DK_SEARCH_COLUMN_SKIPPED: {
732
744
  /** Column id (`key` or `id`). */
733
745
  column: string;
@@ -1062,6 +1074,32 @@ declare module '@datakable/core' {
1062
1074
  /** SSR codes (§7.2, §8.3): kept by `createDeferred` (ssr.ts) and `@datakable/react`. */
1063
1075
  declare const ssrDiagnostics: (DiagnosticDefinition<"DK_SSR_ASYNC_DEFERRED"> | DiagnosticDefinition<"DK_HYDRATION_MISMATCH">)[];
1064
1076
 
1077
+ declare module '@datakable/core' {
1078
+ interface DiagnosticCatalog {
1079
+ DK_STATE_UNKNOWN_KEY: {
1080
+ /** The state slice holding the key, e.g. `columnFilters`; `''` for a top-level state key. */
1081
+ slice: string;
1082
+ /** The key that names no column (or `__proto__`, which is never applied, #102). */
1083
+ key: string;
1084
+ /** The table's column ids (did-you-mean); empty for `__proto__`. */
1085
+ known: readonly string[];
1086
+ };
1087
+ DK_INVALID_STATE: {
1088
+ /** The feature slice, e.g. `sorting`. */
1089
+ slice: string;
1090
+ /** What the slice was (`describeValue`), or what was wrong with it, e.g. `by[1] null`. */
1091
+ received: string;
1092
+ /** What was stored instead. */
1093
+ fallback: string;
1094
+ };
1095
+ }
1096
+ }
1097
+ /**
1098
+ * Codes about the state itself, shared by core and features (§7.2, §8.3). `DK_INVALID_STATE` is
1099
+ * reported by the development-only slice guard (`feature/slice-guard.ts`), which defines it.
1100
+ */
1101
+ declare const stateDiagnostics: DiagnosticDefinition<"DK_STATE_UNKNOWN_KEY">[];
1102
+
1065
1103
  declare module '@datakable/core' {
1066
1104
  interface DiagnosticCatalog {
1067
1105
  DK_DEPRECATED: {
@@ -1131,17 +1169,9 @@ declare module '@datakable/core' {
1131
1169
  /** A sample of their row indices (first few, in order). */
1132
1170
  rows: readonly number[];
1133
1171
  };
1134
- DK_STATE_UNKNOWN_KEY: {
1135
- /** The state slice holding the key, e.g. `columnFilters`. */
1136
- slice: string;
1137
- /** The key that names no column. */
1138
- key: string;
1139
- /** The table's column ids (did-you-mean). */
1140
- known: readonly string[];
1141
- };
1142
1172
  }
1143
1173
  }
1144
1174
  /** Codes owned by the `columnFilters` feature (§6.1, §8.3). */
1145
- declare const columnFiltersDiagnostics: (DiagnosticDefinition<"DK_FILTER_TYPE_MISMATCH"> | DiagnosticDefinition<"DK_STATE_UNKNOWN_KEY">)[];
1175
+ declare const columnFiltersDiagnostics: (DiagnosticDefinition<"DK_STATE_UNKNOWN_KEY"> | DiagnosticDefinition<"DK_FILTER_TYPE_MISMATCH">)[];
1146
1176
 
1147
- export { defineSlot as $, type Redactor as A, type BadResponse as B, SCHEMA_INGEST as C, type Diagnostic as D, type Emit as E, type FlaggedRow as F, SENSITIVE as G, type SchemaIssueColumn as H, type InvalidRowsMode as I, type SchemaOutcome as J, type SlotDefinition as K, type Location as L, type SlotReturns as M, asyncDiagnostics as N, boundaryDiagnostics as O, type Phase as P, buildDiagnostic as Q, type RowIssue as R, StandardSchemaV1 as S, type Trigger as T, columnFiltersDiagnostics as U, type ValidRow as V, comparatorDiagnostics as W, coreDiagnostics as X, dataCheckDiagnostics as Y, dataMutationDiagnostics as Z, defineDiagnostic as _, type EmitOptions as a, describeReturn as a0, describeValue as a1, envDiagnostics as a2, featureDiagnostics as a3, fetchDiagnostics as a4, formatSlot as a5, formatWhere as a6, getDiagnosticDefinition as a7, getDiagnosticText as a8, getSlot as a9, hasMessages as aa, hashRowKey as ab, installMessages as ac, isStandardSchema as ad, keepDiagnostics as ae, listDiagnosticCodes as af, matchesSlot as ag, optionDiagnostics as ah, paginationDiagnostics as ai, pipelineDiagnostics as aj, resolveRedaction as ak, rowKeyDiagnostics as al, schemaDiagnostics as am, scrubError as an, scrubSchemaIssue as ao, searchDiagnostics as ap, slotDiagnostics as aq, sortingDiagnostics as ar, ssrDiagnostics as as, stepDiagnostics as at, tableDiagnostics as au, throwConfigError as av, validityDiagnostics as aw, versioningDiagnostics as ax, Row as b, type DiagnosticCode as c, type DiagnosticDetails as d, type TableSchema as e, type RedactLevel as f, type RedactFn as g, type InvalidRow as h, type RowKey as i, type DiagnosticStateSummary as j, type RedactionOptions as k, type DiagnosticDefinition as l, type BuildInput as m, DK_UNSAFE_REDACTION as n, DatakableConfigError as o, DatakableError as p, DatakableSchemaError as q, type DiagnosticCatalog as r, type DiagnosticContext as s, type DiagnosticLevel as t, type DiagnosticMessages as u, type DiagnosticMeta as v, type DiagnosticText as w, type FlaggedInvalidRow as x, REDACTED as y, type RedactField as z };
1177
+ export { defineSlot as $, type Redactor as A, type BadResponse as B, SCHEMA_INGEST as C, type Diagnostic as D, type Emit as E, type FlaggedRow as F, SENSITIVE as G, type SchemaIssueColumn as H, type InvalidRowsMode as I, type SchemaOutcome as J, type SlotDefinition as K, type Location as L, type SlotReturns as M, asyncDiagnostics as N, boundaryDiagnostics as O, type Phase as P, buildDiagnostic as Q, type RowIssue as R, StandardSchemaV1 as S, type Trigger as T, columnFiltersDiagnostics as U, type ValidRow as V, comparatorDiagnostics as W, coreDiagnostics as X, dataCheckDiagnostics as Y, dataMutationDiagnostics as Z, defineDiagnostic as _, type EmitOptions as a, describeReturn as a0, describeValue as a1, envDiagnostics as a2, featureDiagnostics as a3, fetchDiagnostics as a4, formatSlot as a5, formatWhere as a6, getDiagnosticDefinition as a7, getDiagnosticText as a8, getSlot as a9, hasMessages as aa, hashRowKey as ab, installMessages as ac, isStandardSchema as ad, keepDiagnostics as ae, listDiagnosticCodes as af, matchesSlot as ag, optionDiagnostics as ah, paginationDiagnostics as ai, pipelineDiagnostics as aj, resolveRedaction as ak, rowKeyDiagnostics as al, schemaDiagnostics as am, scrubError as an, scrubSchemaIssue as ao, searchDiagnostics as ap, slotDiagnostics as aq, sortingDiagnostics as ar, ssrDiagnostics as as, stateDiagnostics as at, stepDiagnostics as au, tableDiagnostics as av, throwConfigError as aw, validityDiagnostics as ax, versioningDiagnostics as ay, Row as b, type DiagnosticCode as c, type DiagnosticDetails as d, type TableSchema as e, type RedactLevel as f, type RedactFn as g, type InvalidRow as h, type RowKey as i, type DiagnosticStateSummary as j, type RedactionOptions as k, type DiagnosticDefinition as l, type BuildInput as m, DK_UNSAFE_REDACTION as n, DatakableConfigError as o, DatakableError as p, DatakableSchemaError as q, type DiagnosticCatalog as r, type DiagnosticContext as s, type DiagnosticLevel as t, type DiagnosticMessages as u, type DiagnosticMeta as v, type DiagnosticText as w, type FlaggedInvalidRow as x, REDACTED as y, type RedactField as z };
@@ -55,7 +55,11 @@ interface DiagnosticContext {
55
55
  };
56
56
  /** e.g. `DK_SCHEMA_INVALID_ROW#run57` */
57
57
  causedBy?: string;
58
- /** Original error (ES2022 cause). Reaches `onDiagnostic` only; `toJSON` and the console leave it out. */
58
+ /**
59
+ * Original error (ES2022 cause). Reaches code you install (`onDiagnostic`, `diagnostic:emit`
60
+ * interceptors, the `redact` seam) and, under `strict`, the thrown `DatakableError`'s `cause`;
61
+ * `getDiagnostics()`, `toJSON` and the console leave it out.
62
+ */
59
63
  cause?: unknown;
60
64
  }
61
65
  interface Diagnostic {
@@ -119,7 +123,7 @@ interface RedactionOptions {
119
123
  redact?: RedactFn;
120
124
  /** Ids / keys of `sensitive: true` columns: never logged at any level. */
121
125
  sensitiveColumns?: () => Iterable<string>;
122
- /** The `rowKey` path is, is inside or contains a sensitive column: keys hashed at every level. */
126
+ /** The `rowKey` path is, is inside or contains a sensitive column: keys logged as `[sensitive]` at every level. */
123
127
  rowKeySensitive?: () => boolean;
124
128
  }
125
129
  /**
@@ -728,6 +732,14 @@ declare module '@datakable/core' {
728
732
  /** Whether a previous `searchFn` result is shown (`false`: none applied yet). */
729
733
  hadResults: boolean;
730
734
  };
735
+ DK_SEARCH_UNKNOWN_KEYS: {
736
+ /** Returned `{ keys }` that match no row's key (compared as strings). */
737
+ count: number;
738
+ /** How many keys `searchFn` returned. */
739
+ returned: number;
740
+ /** A sample of the unmatched keys (first few; redacted as row keys). */
741
+ keys: readonly unknown[];
742
+ };
731
743
  DK_SEARCH_COLUMN_SKIPPED: {
732
744
  /** Column id (`key` or `id`). */
733
745
  column: string;
@@ -1062,6 +1074,32 @@ declare module '@datakable/core' {
1062
1074
  /** SSR codes (§7.2, §8.3): kept by `createDeferred` (ssr.ts) and `@datakable/react`. */
1063
1075
  declare const ssrDiagnostics: (DiagnosticDefinition<"DK_SSR_ASYNC_DEFERRED"> | DiagnosticDefinition<"DK_HYDRATION_MISMATCH">)[];
1064
1076
 
1077
+ declare module '@datakable/core' {
1078
+ interface DiagnosticCatalog {
1079
+ DK_STATE_UNKNOWN_KEY: {
1080
+ /** The state slice holding the key, e.g. `columnFilters`; `''` for a top-level state key. */
1081
+ slice: string;
1082
+ /** The key that names no column (or `__proto__`, which is never applied, #102). */
1083
+ key: string;
1084
+ /** The table's column ids (did-you-mean); empty for `__proto__`. */
1085
+ known: readonly string[];
1086
+ };
1087
+ DK_INVALID_STATE: {
1088
+ /** The feature slice, e.g. `sorting`. */
1089
+ slice: string;
1090
+ /** What the slice was (`describeValue`), or what was wrong with it, e.g. `by[1] null`. */
1091
+ received: string;
1092
+ /** What was stored instead. */
1093
+ fallback: string;
1094
+ };
1095
+ }
1096
+ }
1097
+ /**
1098
+ * Codes about the state itself, shared by core and features (§7.2, §8.3). `DK_INVALID_STATE` is
1099
+ * reported by the development-only slice guard (`feature/slice-guard.ts`), which defines it.
1100
+ */
1101
+ declare const stateDiagnostics: DiagnosticDefinition<"DK_STATE_UNKNOWN_KEY">[];
1102
+
1065
1103
  declare module '@datakable/core' {
1066
1104
  interface DiagnosticCatalog {
1067
1105
  DK_DEPRECATED: {
@@ -1131,17 +1169,9 @@ declare module '@datakable/core' {
1131
1169
  /** A sample of their row indices (first few, in order). */
1132
1170
  rows: readonly number[];
1133
1171
  };
1134
- DK_STATE_UNKNOWN_KEY: {
1135
- /** The state slice holding the key, e.g. `columnFilters`. */
1136
- slice: string;
1137
- /** The key that names no column. */
1138
- key: string;
1139
- /** The table's column ids (did-you-mean). */
1140
- known: readonly string[];
1141
- };
1142
1172
  }
1143
1173
  }
1144
1174
  /** Codes owned by the `columnFilters` feature (§6.1, §8.3). */
1145
- declare const columnFiltersDiagnostics: (DiagnosticDefinition<"DK_FILTER_TYPE_MISMATCH"> | DiagnosticDefinition<"DK_STATE_UNKNOWN_KEY">)[];
1175
+ declare const columnFiltersDiagnostics: (DiagnosticDefinition<"DK_STATE_UNKNOWN_KEY"> | DiagnosticDefinition<"DK_FILTER_TYPE_MISMATCH">)[];
1146
1176
 
1147
- export { defineSlot as $, type Redactor as A, type BadResponse as B, SCHEMA_INGEST as C, type Diagnostic as D, type Emit as E, type FlaggedRow as F, SENSITIVE as G, type SchemaIssueColumn as H, type InvalidRowsMode as I, type SchemaOutcome as J, type SlotDefinition as K, type Location as L, type SlotReturns as M, asyncDiagnostics as N, boundaryDiagnostics as O, type Phase as P, buildDiagnostic as Q, type RowIssue as R, StandardSchemaV1 as S, type Trigger as T, columnFiltersDiagnostics as U, type ValidRow as V, comparatorDiagnostics as W, coreDiagnostics as X, dataCheckDiagnostics as Y, dataMutationDiagnostics as Z, defineDiagnostic as _, type EmitOptions as a, describeReturn as a0, describeValue as a1, envDiagnostics as a2, featureDiagnostics as a3, fetchDiagnostics as a4, formatSlot as a5, formatWhere as a6, getDiagnosticDefinition as a7, getDiagnosticText as a8, getSlot as a9, hasMessages as aa, hashRowKey as ab, installMessages as ac, isStandardSchema as ad, keepDiagnostics as ae, listDiagnosticCodes as af, matchesSlot as ag, optionDiagnostics as ah, paginationDiagnostics as ai, pipelineDiagnostics as aj, resolveRedaction as ak, rowKeyDiagnostics as al, schemaDiagnostics as am, scrubError as an, scrubSchemaIssue as ao, searchDiagnostics as ap, slotDiagnostics as aq, sortingDiagnostics as ar, ssrDiagnostics as as, stepDiagnostics as at, tableDiagnostics as au, throwConfigError as av, validityDiagnostics as aw, versioningDiagnostics as ax, Row as b, type DiagnosticCode as c, type DiagnosticDetails as d, type TableSchema as e, type RedactLevel as f, type RedactFn as g, type InvalidRow as h, type RowKey as i, type DiagnosticStateSummary as j, type RedactionOptions as k, type DiagnosticDefinition as l, type BuildInput as m, DK_UNSAFE_REDACTION as n, DatakableConfigError as o, DatakableError as p, DatakableSchemaError as q, type DiagnosticCatalog as r, type DiagnosticContext as s, type DiagnosticLevel as t, type DiagnosticMessages as u, type DiagnosticMeta as v, type DiagnosticText as w, type FlaggedInvalidRow as x, REDACTED as y, type RedactField as z };
1177
+ export { defineSlot as $, type Redactor as A, type BadResponse as B, SCHEMA_INGEST as C, type Diagnostic as D, type Emit as E, type FlaggedRow as F, SENSITIVE as G, type SchemaIssueColumn as H, type InvalidRowsMode as I, type SchemaOutcome as J, type SlotDefinition as K, type Location as L, type SlotReturns as M, asyncDiagnostics as N, boundaryDiagnostics as O, type Phase as P, buildDiagnostic as Q, type RowIssue as R, StandardSchemaV1 as S, type Trigger as T, columnFiltersDiagnostics as U, type ValidRow as V, comparatorDiagnostics as W, coreDiagnostics as X, dataCheckDiagnostics as Y, dataMutationDiagnostics as Z, defineDiagnostic as _, type EmitOptions as a, describeReturn as a0, describeValue as a1, envDiagnostics as a2, featureDiagnostics as a3, fetchDiagnostics as a4, formatSlot as a5, formatWhere as a6, getDiagnosticDefinition as a7, getDiagnosticText as a8, getSlot as a9, hasMessages as aa, hashRowKey as ab, installMessages as ac, isStandardSchema as ad, keepDiagnostics as ae, listDiagnosticCodes as af, matchesSlot as ag, optionDiagnostics as ah, paginationDiagnostics as ai, pipelineDiagnostics as aj, resolveRedaction as ak, rowKeyDiagnostics as al, schemaDiagnostics as am, scrubError as an, scrubSchemaIssue as ao, searchDiagnostics as ap, slotDiagnostics as aq, sortingDiagnostics as ar, ssrDiagnostics as as, stateDiagnostics as at, stepDiagnostics as au, tableDiagnostics as av, throwConfigError as aw, validityDiagnostics as ax, versioningDiagnostics as ay, Row as b, type DiagnosticCode as c, type DiagnosticDetails as d, type TableSchema as e, type RedactLevel as f, type RedactFn as g, type InvalidRow as h, type RowKey as i, type DiagnosticStateSummary as j, type RedactionOptions as k, type DiagnosticDefinition as l, type BuildInput as m, DK_UNSAFE_REDACTION as n, DatakableConfigError as o, DatakableError as p, DatakableSchemaError as q, type DiagnosticCatalog as r, type DiagnosticContext as s, type DiagnosticLevel as t, type DiagnosticMessages as u, type DiagnosticMeta as v, type DiagnosticText as w, type FlaggedInvalidRow as x, REDACTED as y, type RedactField as z };
@@ -1,5 +1,5 @@
1
- export { U as columnFiltersDiagnostics } from './codes-B9bCK73-.cjs';
2
- import { G as FilterFor, a1 as Path, P as LooseRow, a2 as PathValue, e as FeatureTypes, F as Feature } from './explain-Q8Cg0cZy.cjs';
1
+ export { U as columnFiltersDiagnostics } from './codes-4sYQv_7J.cjs';
2
+ import { G as FilterFor, a1 as Path, P as LooseRow, a2 as PathValue, e as FeatureTypes, F as Feature } from './explain-DmwN_RG9.cjs';
3
3
  import { a as DataMode } from './mode-DFV8ryXo.cjs';
4
4
 
5
5
  /** The value a filter compares against: the element type for array-valued cells (§6.1). */
@@ -1,5 +1,5 @@
1
- export { U as columnFiltersDiagnostics } from './codes-B9bCK73-.js';
2
- import { G as FilterFor, a1 as Path, P as LooseRow, a2 as PathValue, e as FeatureTypes, F as Feature } from './explain-i0OATi_W.js';
1
+ export { U as columnFiltersDiagnostics } from './codes-4sYQv_7J.js';
2
+ import { G as FilterFor, a1 as Path, P as LooseRow, a2 as PathValue, e as FeatureTypes, F as Feature } from './explain-Dr3SmMNY.js';
3
3
  import { a as DataMode } from './mode-DFV8ryXo.js';
4
4
 
5
5
  /** The value a filter compares against: the element type for array-valued cells (§6.1). */
@@ -95,7 +95,7 @@ function buildDiagnostic(code, details, input = {}) {
95
95
  def = INTERNAL;
96
96
  d = {
97
97
  op: "diagnostic:emit",
98
- problem: `unknown-code|${code}`
98
+ problem: `unknown-code|${(0, import_prose.proseArg)(code)}`
99
99
  };
100
100
  }
101
101
  const b = def;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/diagnostics/build.ts"],"sourcesContent":["import { VERSION } from '../version'\nimport {\n type DiagnosticCode,\n type DiagnosticDefinition,\n type DiagnosticDetails,\n type DiagnosticText,\n getDiagnosticDefinition,\n getDiagnosticText,\n hasMessages,\n} from './catalog'\nimport { coreDiagnostics } from './codes'\nimport './process-guard'\nimport { expandDetails } from './prose'\nimport {\n type RedactField,\n type Redactor,\n redactDetails,\n redactLocation,\n resolveRedaction,\n} from './redact'\nimport { toSafeJson } from './safe-json'\nimport type {\n Diagnostic,\n DiagnosticContext,\n DiagnosticLevel,\n DiagnosticStateSummary,\n Location,\n Phase,\n Trigger,\n} from './types'\n\nexport const PACKAGE = `@datakable/core@${VERSION}`\nconst DOCS = 'https://github.com/Ink01101011/datakable/blob/main/docs/errors.md'\n\n// Referencing the core entries keeps them in the bundle (`sideEffects: false`).\nconst INTERNAL = coreDiagnostics.find((d) => d.code === 'DK_INTERNAL') as DiagnosticDefinition\n\n/** Everything the enrich step adds; all optional so a diagnostic can be built outside a table. */\nexport interface BuildInput {\n table?: string\n createdAt?: string\n trigger?: Trigger\n run?: number\n phase?: Phase\n mode?: Record<string, 'client' | 'server'>\n state?: DiagnosticStateSummary\n /** Timestamp for `occurrences` (epoch ms). Default `wallClock()`. */\n now?: number\n cause?: unknown\n causedBy?: string\n /** Build the problem / impact / fix text. Default: development builds only (§8.2); production\n * builds also build it once `@datakable/core/messages` is installed. */\n dev?: boolean\n /** Redaction policy (§8.2). Default: `'keys'` when `dev`, else `'safe'`. */\n redaction?: Redactor\n}\n\n/**\n * Epoch ms read through `performance`, never `Date` (#7): Next 16 `cacheComponents` aborts a\n * prerender that reads `Date.now()` and reserves `performance` for introspection like this.\n */\nexport const wallClock = (): number =>\n typeof performance === 'object' && performance?.timeOrigin\n ? Math.floor(performance.timeOrigin + performance.now())\n : Date.now()\n\nexport const defaultPhase = (): Phase => (typeof document === 'undefined' ? 'ssr' : 'client')\n\nexport function formatWhere(where: Location): string {\n switch (where.kind) {\n case 'column':\n return `columns[${where.index}] (id \"${where.id}\")`\n case 'feature':\n return `feature \"${where.name}\"`\n case 'option':\n return `options.${where.path}`\n case 'row':\n return where.key === undefined\n ? `row #${where.index}`\n : `row #${where.index} (key ${where.key})`\n case 'interceptor':\n return `interceptor \"${where.name}\" on ${where.op}`\n case 'operation':\n return where.slot ? `operation ${where.op} at ${where.slot}` : `operation ${where.op}`\n }\n}\n\nclass DiagnosticRecord implements Diagnostic {\n constructor(\n public code: DiagnosticCode,\n public level: DiagnosticLevel,\n public problem: string,\n public where: Location,\n public impact: string,\n public fix: string[],\n public docs: string,\n public details: Record<string, unknown>,\n public context: DiagnosticContext,\n public fingerprint: string,\n ) {}\n\n toJSON(): object {\n const { cause: _cause, ...context } = this.context\n return {\n code: this.code,\n level: this.level,\n problem: this.problem,\n where: toSafeJson(this.where),\n impact: this.impact,\n fix: this.fix,\n docs: this.docs,\n details: toSafeJson(this.details),\n context: toSafeJson(context),\n fingerprint: this.fingerprint,\n }\n }\n}\n\n/**\n * Builds a diagnostic from a catalog code + details (the `enrich` step). Never throws for an unknown\n * code: that becomes `DK_INTERNAL`, so a typo in a plugin cannot take the logger down.\n */\nexport function buildDiagnostic<C extends DiagnosticCode>(\n code: C,\n details: DiagnosticDetails<C>,\n input: BuildInput = {},\n): Diagnostic {\n let def = getDiagnosticDefinition(code)\n let d = details as Record<string, unknown>\n if (!def) {\n def = INTERNAL\n d = {\n op: 'diagnostic:emit',\n problem: `unknown-code|${code}`,\n }\n }\n const b = def as unknown as DiagnosticDefinition<'DK_INTERNAL'>\n const dev = input.dev ?? (process.env.NODE_ENV !== \"production\")\n // Detail prose keys (`fallback: 'cells-undefined'`) read as sentences wherever text is built.\n if (dev || hasMessages()) d = expandDetails(d, dev)\n // Redact first: `where`, the text builders, the fingerprint and the docs URL only ever see\n // redacted data, so no consumer downstream (interceptors, sinks, strict errors) can leak it.\n const r = input.redaction ?? resolveRedaction(undefined, dev)\n const where = redactLocation(b.where(d as DiagnosticDetails<'DK_INTERNAL'>), r)\n d = redactDetails(\n d,\n def.redact as Readonly<Record<string, RedactField | undefined>> | undefined,\n where,\n r,\n )\n const dd = d as DiagnosticDetails<'DK_INTERNAL'>\n // Text: development builds, or production with `@datakable/core/messages` installed (§8.2).\n const t =\n dev || hasMessages()\n ? (getDiagnosticText(def.code) as DiagnosticText<'DK_INTERNAL'> | undefined)\n : undefined\n const whereText = formatWhere(where)\n const now = input.now ?? wallClock()\n const context: DiagnosticContext = {\n table: input.table ?? '(global)',\n package: PACKAGE,\n trigger: input.trigger ?? 'init',\n run: input.run ?? 0,\n phase: input.phase ?? defaultPhase(),\n mode: input.mode ?? {},\n state: input.state ?? { searchLength: 0, activeFilters: [], sort: [], page: 0 },\n occurrences: { count: 1, first: now, last: now },\n }\n if (input.createdAt !== undefined) context.createdAt = input.createdAt\n if (input.causedBy !== undefined) context.causedBy = input.causedBy\n if (input.cause !== undefined) context.cause = input.cause\n let docs = def.docs ?? `${DOCS}#${def.code.toLowerCase()}`\n if (!dev) {\n const hash = docs.indexOf('#')\n const params = `?v=${VERSION}&where=${encodeURIComponent(whereText)}`\n docs = hash < 0 ? docs + params : docs.slice(0, hash) + params + docs.slice(hash)\n }\n return new DiagnosticRecord(\n def.code,\n def.level,\n t ? t.problem(dd) : '',\n where,\n t ? t.impact(dd) : '',\n t ? t.fix(dd) : [],\n docs,\n d,\n context,\n `${def.code}@${whereText}`,\n )\n}\n\n/** Thrown under `strict: true` for error-level diagnostics, and for core invariants (§8.2). */\nexport class DatakableError extends Error {\n override name = 'DatakableError'\n readonly code: DiagnosticCode\n readonly level: DiagnosticLevel\n readonly problem: string\n readonly where: Location\n readonly impact: string\n readonly fix: string[]\n readonly docs: string\n readonly diagnostic: Diagnostic\n\n constructor(d: Diagnostic) {\n const lines = [`${d.code}: ${d.problem || '(see docs)'}`, ` where ${formatWhere(d.where)}`]\n d.fix.forEach((f, i) => {\n lines.push(`${i === 0 ? ' fix ' : ' '}${i + 1}. ${f}`)\n })\n lines.push(` docs ${d.docs}`)\n super(lines.join('\\n'), d.context.cause === undefined ? undefined : { cause: d.context.cause })\n this.code = d.code\n this.level = d.level\n this.problem = d.problem\n this.where = d.where\n this.impact = d.impact\n this.fix = d.fix\n this.docs = d.docs\n this.diagnostic = d\n }\n}\n\n/** Deterministic programmer errors thrown at creation (`error (config)` codes, §8.6). */\nexport class DatakableConfigError extends DatakableError {\n override name = 'DatakableConfigError'\n}\n\nexport function throwConfigError<C extends DiagnosticCode>(\n code: C,\n details: DiagnosticDetails<C>,\n input?: BuildInput,\n): never {\n throw new DatakableConfigError(buildDiagnostic(code, details, input))\n}\n\n/** A core invariant broke (unregistered op, boundary installed twice): `DK_INTERNAL`. */\nexport function internalError(op: string, problem: string): DatakableError {\n return new DatakableError(buildDiagnostic('DK_INTERNAL', { op, problem }))\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/diagnostics/build.ts"],"sourcesContent":["import { VERSION } from '../version'\nimport {\n type DiagnosticCode,\n type DiagnosticDefinition,\n type DiagnosticDetails,\n type DiagnosticText,\n getDiagnosticDefinition,\n getDiagnosticText,\n hasMessages,\n} from './catalog'\nimport { coreDiagnostics } from './codes'\nimport './process-guard'\nimport { expandDetails, proseArg } from './prose'\nimport {\n type RedactField,\n type Redactor,\n redactDetails,\n redactLocation,\n resolveRedaction,\n} from './redact'\nimport { toSafeJson } from './safe-json'\nimport type {\n Diagnostic,\n DiagnosticContext,\n DiagnosticLevel,\n DiagnosticStateSummary,\n Location,\n Phase,\n Trigger,\n} from './types'\n\nexport const PACKAGE = `@datakable/core@${VERSION}`\nconst DOCS = 'https://github.com/Ink01101011/datakable/blob/main/docs/errors.md'\n\n// Referencing the core entries keeps them in the bundle (`sideEffects: false`).\nconst INTERNAL = coreDiagnostics.find((d) => d.code === 'DK_INTERNAL') as DiagnosticDefinition\n\n/** Everything the enrich step adds; all optional so a diagnostic can be built outside a table. */\nexport interface BuildInput {\n table?: string\n createdAt?: string\n trigger?: Trigger\n run?: number\n phase?: Phase\n mode?: Record<string, 'client' | 'server'>\n state?: DiagnosticStateSummary\n /** Timestamp for `occurrences` (epoch ms). Default `wallClock()`. */\n now?: number\n cause?: unknown\n causedBy?: string\n /** Build the problem / impact / fix text. Default: development builds only (§8.2); production\n * builds also build it once `@datakable/core/messages` is installed. */\n dev?: boolean\n /** Redaction policy (§8.2). Default: `'keys'` when `dev`, else `'safe'`. */\n redaction?: Redactor\n}\n\n/**\n * Epoch ms read through `performance`, never `Date` (#7): Next 16 `cacheComponents` aborts a\n * prerender that reads `Date.now()` and reserves `performance` for introspection like this.\n */\nexport const wallClock = (): number =>\n typeof performance === 'object' && performance?.timeOrigin\n ? Math.floor(performance.timeOrigin + performance.now())\n : Date.now()\n\nexport const defaultPhase = (): Phase => (typeof document === 'undefined' ? 'ssr' : 'client')\n\nexport function formatWhere(where: Location): string {\n switch (where.kind) {\n case 'column':\n return `columns[${where.index}] (id \"${where.id}\")`\n case 'feature':\n return `feature \"${where.name}\"`\n case 'option':\n return `options.${where.path}`\n case 'row':\n return where.key === undefined\n ? `row #${where.index}`\n : `row #${where.index} (key ${where.key})`\n case 'interceptor':\n return `interceptor \"${where.name}\" on ${where.op}`\n case 'operation':\n return where.slot ? `operation ${where.op} at ${where.slot}` : `operation ${where.op}`\n }\n}\n\nclass DiagnosticRecord implements Diagnostic {\n constructor(\n public code: DiagnosticCode,\n public level: DiagnosticLevel,\n public problem: string,\n public where: Location,\n public impact: string,\n public fix: string[],\n public docs: string,\n public details: Record<string, unknown>,\n public context: DiagnosticContext,\n public fingerprint: string,\n ) {}\n\n toJSON(): object {\n const { cause: _cause, ...context } = this.context\n return {\n code: this.code,\n level: this.level,\n problem: this.problem,\n where: toSafeJson(this.where),\n impact: this.impact,\n fix: this.fix,\n docs: this.docs,\n details: toSafeJson(this.details),\n context: toSafeJson(context),\n fingerprint: this.fingerprint,\n }\n }\n}\n\n/**\n * Builds a diagnostic from a catalog code + details (the `enrich` step). Never throws for an unknown\n * code: that becomes `DK_INTERNAL`, so a typo in a plugin cannot take the logger down.\n */\nexport function buildDiagnostic<C extends DiagnosticCode>(\n code: C,\n details: DiagnosticDetails<C>,\n input: BuildInput = {},\n): Diagnostic {\n let def = getDiagnosticDefinition(code)\n let d = details as Record<string, unknown>\n if (!def) {\n def = INTERNAL\n d = {\n op: 'diagnostic:emit',\n problem: `unknown-code|${proseArg(code)}`,\n }\n }\n const b = def as unknown as DiagnosticDefinition<'DK_INTERNAL'>\n const dev = input.dev ?? (process.env.NODE_ENV !== \"production\")\n // Detail prose keys (`fallback: 'cells-undefined'`) read as sentences wherever text is built.\n if (dev || hasMessages()) d = expandDetails(d, dev)\n // Redact first: `where`, the text builders, the fingerprint and the docs URL only ever see\n // redacted data, so no consumer downstream (interceptors, sinks, strict errors) can leak it.\n const r = input.redaction ?? resolveRedaction(undefined, dev)\n const where = redactLocation(b.where(d as DiagnosticDetails<'DK_INTERNAL'>), r)\n d = redactDetails(\n d,\n def.redact as Readonly<Record<string, RedactField | undefined>> | undefined,\n where,\n r,\n )\n const dd = d as DiagnosticDetails<'DK_INTERNAL'>\n // Text: development builds, or production with `@datakable/core/messages` installed (§8.2).\n const t =\n dev || hasMessages()\n ? (getDiagnosticText(def.code) as DiagnosticText<'DK_INTERNAL'> | undefined)\n : undefined\n const whereText = formatWhere(where)\n const now = input.now ?? wallClock()\n const context: DiagnosticContext = {\n table: input.table ?? '(global)',\n package: PACKAGE,\n trigger: input.trigger ?? 'init',\n run: input.run ?? 0,\n phase: input.phase ?? defaultPhase(),\n mode: input.mode ?? {},\n state: input.state ?? { searchLength: 0, activeFilters: [], sort: [], page: 0 },\n occurrences: { count: 1, first: now, last: now },\n }\n if (input.createdAt !== undefined) context.createdAt = input.createdAt\n if (input.causedBy !== undefined) context.causedBy = input.causedBy\n if (input.cause !== undefined) context.cause = input.cause\n let docs = def.docs ?? `${DOCS}#${def.code.toLowerCase()}`\n if (!dev) {\n const hash = docs.indexOf('#')\n const params = `?v=${VERSION}&where=${encodeURIComponent(whereText)}`\n docs = hash < 0 ? docs + params : docs.slice(0, hash) + params + docs.slice(hash)\n }\n return new DiagnosticRecord(\n def.code,\n def.level,\n t ? t.problem(dd) : '',\n where,\n t ? t.impact(dd) : '',\n t ? t.fix(dd) : [],\n docs,\n d,\n context,\n `${def.code}@${whereText}`,\n )\n}\n\n/** Thrown under `strict: true` for error-level diagnostics, and for core invariants (§8.2). */\nexport class DatakableError extends Error {\n override name = 'DatakableError'\n readonly code: DiagnosticCode\n readonly level: DiagnosticLevel\n readonly problem: string\n readonly where: Location\n readonly impact: string\n readonly fix: string[]\n readonly docs: string\n readonly diagnostic: Diagnostic\n\n constructor(d: Diagnostic) {\n const lines = [`${d.code}: ${d.problem || '(see docs)'}`, ` where ${formatWhere(d.where)}`]\n d.fix.forEach((f, i) => {\n lines.push(`${i === 0 ? ' fix ' : ' '}${i + 1}. ${f}`)\n })\n lines.push(` docs ${d.docs}`)\n super(lines.join('\\n'), d.context.cause === undefined ? undefined : { cause: d.context.cause })\n this.code = d.code\n this.level = d.level\n this.problem = d.problem\n this.where = d.where\n this.impact = d.impact\n this.fix = d.fix\n this.docs = d.docs\n this.diagnostic = d\n }\n}\n\n/** Deterministic programmer errors thrown at creation (`error (config)` codes, §8.6). */\nexport class DatakableConfigError extends DatakableError {\n override name = 'DatakableConfigError'\n}\n\nexport function throwConfigError<C extends DiagnosticCode>(\n code: C,\n details: DiagnosticDetails<C>,\n input?: BuildInput,\n): never {\n throw new DatakableConfigError(buildDiagnostic(code, details, input))\n}\n\n/** A core invariant broke (unregistered op, boundary installed twice): `DK_INTERNAL`. */\nexport function internalError(op: string, problem: string): DatakableError {\n return new DatakableError(buildDiagnostic('DK_INTERNAL', { op, problem }))\n}\n"],"mappings":"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","names":[]}
@@ -7,7 +7,7 @@ import {
7
7
  } from "./catalog.js";
8
8
  import { coreDiagnostics } from "./codes.js";
9
9
  import "./process-guard.js";
10
- import { expandDetails } from "./prose.js";
10
+ import { expandDetails, proseArg } from "./prose.js";
11
11
  import {
12
12
  redactDetails,
13
13
  redactLocation,
@@ -71,7 +71,7 @@ function buildDiagnostic(code, details, input = {}) {
71
71
  def = INTERNAL;
72
72
  d = {
73
73
  op: "diagnostic:emit",
74
- problem: `unknown-code|${code}`
74
+ problem: `unknown-code|${proseArg(code)}`
75
75
  };
76
76
  }
77
77
  const b = def;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/diagnostics/build.ts"],"sourcesContent":["import { VERSION } from '../version'\nimport {\n type DiagnosticCode,\n type DiagnosticDefinition,\n type DiagnosticDetails,\n type DiagnosticText,\n getDiagnosticDefinition,\n getDiagnosticText,\n hasMessages,\n} from './catalog'\nimport { coreDiagnostics } from './codes'\nimport './process-guard'\nimport { expandDetails } from './prose'\nimport {\n type RedactField,\n type Redactor,\n redactDetails,\n redactLocation,\n resolveRedaction,\n} from './redact'\nimport { toSafeJson } from './safe-json'\nimport type {\n Diagnostic,\n DiagnosticContext,\n DiagnosticLevel,\n DiagnosticStateSummary,\n Location,\n Phase,\n Trigger,\n} from './types'\n\nexport const PACKAGE = `@datakable/core@${VERSION}`\nconst DOCS = 'https://github.com/Ink01101011/datakable/blob/main/docs/errors.md'\n\n// Referencing the core entries keeps them in the bundle (`sideEffects: false`).\nconst INTERNAL = coreDiagnostics.find((d) => d.code === 'DK_INTERNAL') as DiagnosticDefinition\n\n/** Everything the enrich step adds; all optional so a diagnostic can be built outside a table. */\nexport interface BuildInput {\n table?: string\n createdAt?: string\n trigger?: Trigger\n run?: number\n phase?: Phase\n mode?: Record<string, 'client' | 'server'>\n state?: DiagnosticStateSummary\n /** Timestamp for `occurrences` (epoch ms). Default `wallClock()`. */\n now?: number\n cause?: unknown\n causedBy?: string\n /** Build the problem / impact / fix text. Default: development builds only (§8.2); production\n * builds also build it once `@datakable/core/messages` is installed. */\n dev?: boolean\n /** Redaction policy (§8.2). Default: `'keys'` when `dev`, else `'safe'`. */\n redaction?: Redactor\n}\n\n/**\n * Epoch ms read through `performance`, never `Date` (#7): Next 16 `cacheComponents` aborts a\n * prerender that reads `Date.now()` and reserves `performance` for introspection like this.\n */\nexport const wallClock = (): number =>\n typeof performance === 'object' && performance?.timeOrigin\n ? Math.floor(performance.timeOrigin + performance.now())\n : Date.now()\n\nexport const defaultPhase = (): Phase => (typeof document === 'undefined' ? 'ssr' : 'client')\n\nexport function formatWhere(where: Location): string {\n switch (where.kind) {\n case 'column':\n return `columns[${where.index}] (id \"${where.id}\")`\n case 'feature':\n return `feature \"${where.name}\"`\n case 'option':\n return `options.${where.path}`\n case 'row':\n return where.key === undefined\n ? `row #${where.index}`\n : `row #${where.index} (key ${where.key})`\n case 'interceptor':\n return `interceptor \"${where.name}\" on ${where.op}`\n case 'operation':\n return where.slot ? `operation ${where.op} at ${where.slot}` : `operation ${where.op}`\n }\n}\n\nclass DiagnosticRecord implements Diagnostic {\n constructor(\n public code: DiagnosticCode,\n public level: DiagnosticLevel,\n public problem: string,\n public where: Location,\n public impact: string,\n public fix: string[],\n public docs: string,\n public details: Record<string, unknown>,\n public context: DiagnosticContext,\n public fingerprint: string,\n ) {}\n\n toJSON(): object {\n const { cause: _cause, ...context } = this.context\n return {\n code: this.code,\n level: this.level,\n problem: this.problem,\n where: toSafeJson(this.where),\n impact: this.impact,\n fix: this.fix,\n docs: this.docs,\n details: toSafeJson(this.details),\n context: toSafeJson(context),\n fingerprint: this.fingerprint,\n }\n }\n}\n\n/**\n * Builds a diagnostic from a catalog code + details (the `enrich` step). Never throws for an unknown\n * code: that becomes `DK_INTERNAL`, so a typo in a plugin cannot take the logger down.\n */\nexport function buildDiagnostic<C extends DiagnosticCode>(\n code: C,\n details: DiagnosticDetails<C>,\n input: BuildInput = {},\n): Diagnostic {\n let def = getDiagnosticDefinition(code)\n let d = details as Record<string, unknown>\n if (!def) {\n def = INTERNAL\n d = {\n op: 'diagnostic:emit',\n problem: `unknown-code|${code}`,\n }\n }\n const b = def as unknown as DiagnosticDefinition<'DK_INTERNAL'>\n const dev = input.dev ?? (process.env.NODE_ENV !== \"production\")\n // Detail prose keys (`fallback: 'cells-undefined'`) read as sentences wherever text is built.\n if (dev || hasMessages()) d = expandDetails(d, dev)\n // Redact first: `where`, the text builders, the fingerprint and the docs URL only ever see\n // redacted data, so no consumer downstream (interceptors, sinks, strict errors) can leak it.\n const r = input.redaction ?? resolveRedaction(undefined, dev)\n const where = redactLocation(b.where(d as DiagnosticDetails<'DK_INTERNAL'>), r)\n d = redactDetails(\n d,\n def.redact as Readonly<Record<string, RedactField | undefined>> | undefined,\n where,\n r,\n )\n const dd = d as DiagnosticDetails<'DK_INTERNAL'>\n // Text: development builds, or production with `@datakable/core/messages` installed (§8.2).\n const t =\n dev || hasMessages()\n ? (getDiagnosticText(def.code) as DiagnosticText<'DK_INTERNAL'> | undefined)\n : undefined\n const whereText = formatWhere(where)\n const now = input.now ?? wallClock()\n const context: DiagnosticContext = {\n table: input.table ?? '(global)',\n package: PACKAGE,\n trigger: input.trigger ?? 'init',\n run: input.run ?? 0,\n phase: input.phase ?? defaultPhase(),\n mode: input.mode ?? {},\n state: input.state ?? { searchLength: 0, activeFilters: [], sort: [], page: 0 },\n occurrences: { count: 1, first: now, last: now },\n }\n if (input.createdAt !== undefined) context.createdAt = input.createdAt\n if (input.causedBy !== undefined) context.causedBy = input.causedBy\n if (input.cause !== undefined) context.cause = input.cause\n let docs = def.docs ?? `${DOCS}#${def.code.toLowerCase()}`\n if (!dev) {\n const hash = docs.indexOf('#')\n const params = `?v=${VERSION}&where=${encodeURIComponent(whereText)}`\n docs = hash < 0 ? docs + params : docs.slice(0, hash) + params + docs.slice(hash)\n }\n return new DiagnosticRecord(\n def.code,\n def.level,\n t ? t.problem(dd) : '',\n where,\n t ? t.impact(dd) : '',\n t ? t.fix(dd) : [],\n docs,\n d,\n context,\n `${def.code}@${whereText}`,\n )\n}\n\n/** Thrown under `strict: true` for error-level diagnostics, and for core invariants (§8.2). */\nexport class DatakableError extends Error {\n override name = 'DatakableError'\n readonly code: DiagnosticCode\n readonly level: DiagnosticLevel\n readonly problem: string\n readonly where: Location\n readonly impact: string\n readonly fix: string[]\n readonly docs: string\n readonly diagnostic: Diagnostic\n\n constructor(d: Diagnostic) {\n const lines = [`${d.code}: ${d.problem || '(see docs)'}`, ` where ${formatWhere(d.where)}`]\n d.fix.forEach((f, i) => {\n lines.push(`${i === 0 ? ' fix ' : ' '}${i + 1}. ${f}`)\n })\n lines.push(` docs ${d.docs}`)\n super(lines.join('\\n'), d.context.cause === undefined ? undefined : { cause: d.context.cause })\n this.code = d.code\n this.level = d.level\n this.problem = d.problem\n this.where = d.where\n this.impact = d.impact\n this.fix = d.fix\n this.docs = d.docs\n this.diagnostic = d\n }\n}\n\n/** Deterministic programmer errors thrown at creation (`error (config)` codes, §8.6). */\nexport class DatakableConfigError extends DatakableError {\n override name = 'DatakableConfigError'\n}\n\nexport function throwConfigError<C extends DiagnosticCode>(\n code: C,\n details: DiagnosticDetails<C>,\n input?: BuildInput,\n): never {\n throw new DatakableConfigError(buildDiagnostic(code, details, input))\n}\n\n/** A core invariant broke (unregistered op, boundary installed twice): `DK_INTERNAL`. */\nexport function internalError(op: string, problem: string): DatakableError {\n return new DatakableError(buildDiagnostic('DK_INTERNAL', { op, problem }))\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/diagnostics/build.ts"],"sourcesContent":["import { VERSION } from '../version'\nimport {\n type DiagnosticCode,\n type DiagnosticDefinition,\n type DiagnosticDetails,\n type DiagnosticText,\n getDiagnosticDefinition,\n getDiagnosticText,\n hasMessages,\n} from './catalog'\nimport { coreDiagnostics } from './codes'\nimport './process-guard'\nimport { expandDetails, proseArg } from './prose'\nimport {\n type RedactField,\n type Redactor,\n redactDetails,\n redactLocation,\n resolveRedaction,\n} from './redact'\nimport { toSafeJson } from './safe-json'\nimport type {\n Diagnostic,\n DiagnosticContext,\n DiagnosticLevel,\n DiagnosticStateSummary,\n Location,\n Phase,\n Trigger,\n} from './types'\n\nexport const PACKAGE = `@datakable/core@${VERSION}`\nconst DOCS = 'https://github.com/Ink01101011/datakable/blob/main/docs/errors.md'\n\n// Referencing the core entries keeps them in the bundle (`sideEffects: false`).\nconst INTERNAL = coreDiagnostics.find((d) => d.code === 'DK_INTERNAL') as DiagnosticDefinition\n\n/** Everything the enrich step adds; all optional so a diagnostic can be built outside a table. */\nexport interface BuildInput {\n table?: string\n createdAt?: string\n trigger?: Trigger\n run?: number\n phase?: Phase\n mode?: Record<string, 'client' | 'server'>\n state?: DiagnosticStateSummary\n /** Timestamp for `occurrences` (epoch ms). Default `wallClock()`. */\n now?: number\n cause?: unknown\n causedBy?: string\n /** Build the problem / impact / fix text. Default: development builds only (§8.2); production\n * builds also build it once `@datakable/core/messages` is installed. */\n dev?: boolean\n /** Redaction policy (§8.2). Default: `'keys'` when `dev`, else `'safe'`. */\n redaction?: Redactor\n}\n\n/**\n * Epoch ms read through `performance`, never `Date` (#7): Next 16 `cacheComponents` aborts a\n * prerender that reads `Date.now()` and reserves `performance` for introspection like this.\n */\nexport const wallClock = (): number =>\n typeof performance === 'object' && performance?.timeOrigin\n ? Math.floor(performance.timeOrigin + performance.now())\n : Date.now()\n\nexport const defaultPhase = (): Phase => (typeof document === 'undefined' ? 'ssr' : 'client')\n\nexport function formatWhere(where: Location): string {\n switch (where.kind) {\n case 'column':\n return `columns[${where.index}] (id \"${where.id}\")`\n case 'feature':\n return `feature \"${where.name}\"`\n case 'option':\n return `options.${where.path}`\n case 'row':\n return where.key === undefined\n ? `row #${where.index}`\n : `row #${where.index} (key ${where.key})`\n case 'interceptor':\n return `interceptor \"${where.name}\" on ${where.op}`\n case 'operation':\n return where.slot ? `operation ${where.op} at ${where.slot}` : `operation ${where.op}`\n }\n}\n\nclass DiagnosticRecord implements Diagnostic {\n constructor(\n public code: DiagnosticCode,\n public level: DiagnosticLevel,\n public problem: string,\n public where: Location,\n public impact: string,\n public fix: string[],\n public docs: string,\n public details: Record<string, unknown>,\n public context: DiagnosticContext,\n public fingerprint: string,\n ) {}\n\n toJSON(): object {\n const { cause: _cause, ...context } = this.context\n return {\n code: this.code,\n level: this.level,\n problem: this.problem,\n where: toSafeJson(this.where),\n impact: this.impact,\n fix: this.fix,\n docs: this.docs,\n details: toSafeJson(this.details),\n context: toSafeJson(context),\n fingerprint: this.fingerprint,\n }\n }\n}\n\n/**\n * Builds a diagnostic from a catalog code + details (the `enrich` step). Never throws for an unknown\n * code: that becomes `DK_INTERNAL`, so a typo in a plugin cannot take the logger down.\n */\nexport function buildDiagnostic<C extends DiagnosticCode>(\n code: C,\n details: DiagnosticDetails<C>,\n input: BuildInput = {},\n): Diagnostic {\n let def = getDiagnosticDefinition(code)\n let d = details as Record<string, unknown>\n if (!def) {\n def = INTERNAL\n d = {\n op: 'diagnostic:emit',\n problem: `unknown-code|${proseArg(code)}`,\n }\n }\n const b = def as unknown as DiagnosticDefinition<'DK_INTERNAL'>\n const dev = input.dev ?? (process.env.NODE_ENV !== \"production\")\n // Detail prose keys (`fallback: 'cells-undefined'`) read as sentences wherever text is built.\n if (dev || hasMessages()) d = expandDetails(d, dev)\n // Redact first: `where`, the text builders, the fingerprint and the docs URL only ever see\n // redacted data, so no consumer downstream (interceptors, sinks, strict errors) can leak it.\n const r = input.redaction ?? resolveRedaction(undefined, dev)\n const where = redactLocation(b.where(d as DiagnosticDetails<'DK_INTERNAL'>), r)\n d = redactDetails(\n d,\n def.redact as Readonly<Record<string, RedactField | undefined>> | undefined,\n where,\n r,\n )\n const dd = d as DiagnosticDetails<'DK_INTERNAL'>\n // Text: development builds, or production with `@datakable/core/messages` installed (§8.2).\n const t =\n dev || hasMessages()\n ? (getDiagnosticText(def.code) as DiagnosticText<'DK_INTERNAL'> | undefined)\n : undefined\n const whereText = formatWhere(where)\n const now = input.now ?? wallClock()\n const context: DiagnosticContext = {\n table: input.table ?? '(global)',\n package: PACKAGE,\n trigger: input.trigger ?? 'init',\n run: input.run ?? 0,\n phase: input.phase ?? defaultPhase(),\n mode: input.mode ?? {},\n state: input.state ?? { searchLength: 0, activeFilters: [], sort: [], page: 0 },\n occurrences: { count: 1, first: now, last: now },\n }\n if (input.createdAt !== undefined) context.createdAt = input.createdAt\n if (input.causedBy !== undefined) context.causedBy = input.causedBy\n if (input.cause !== undefined) context.cause = input.cause\n let docs = def.docs ?? `${DOCS}#${def.code.toLowerCase()}`\n if (!dev) {\n const hash = docs.indexOf('#')\n const params = `?v=${VERSION}&where=${encodeURIComponent(whereText)}`\n docs = hash < 0 ? docs + params : docs.slice(0, hash) + params + docs.slice(hash)\n }\n return new DiagnosticRecord(\n def.code,\n def.level,\n t ? t.problem(dd) : '',\n where,\n t ? t.impact(dd) : '',\n t ? t.fix(dd) : [],\n docs,\n d,\n context,\n `${def.code}@${whereText}`,\n )\n}\n\n/** Thrown under `strict: true` for error-level diagnostics, and for core invariants (§8.2). */\nexport class DatakableError extends Error {\n override name = 'DatakableError'\n readonly code: DiagnosticCode\n readonly level: DiagnosticLevel\n readonly problem: string\n readonly where: Location\n readonly impact: string\n readonly fix: string[]\n readonly docs: string\n readonly diagnostic: Diagnostic\n\n constructor(d: Diagnostic) {\n const lines = [`${d.code}: ${d.problem || '(see docs)'}`, ` where ${formatWhere(d.where)}`]\n d.fix.forEach((f, i) => {\n lines.push(`${i === 0 ? ' fix ' : ' '}${i + 1}. ${f}`)\n })\n lines.push(` docs ${d.docs}`)\n super(lines.join('\\n'), d.context.cause === undefined ? undefined : { cause: d.context.cause })\n this.code = d.code\n this.level = d.level\n this.problem = d.problem\n this.where = d.where\n this.impact = d.impact\n this.fix = d.fix\n this.docs = d.docs\n this.diagnostic = d\n }\n}\n\n/** Deterministic programmer errors thrown at creation (`error (config)` codes, §8.6). */\nexport class DatakableConfigError extends DatakableError {\n override name = 'DatakableConfigError'\n}\n\nexport function throwConfigError<C extends DiagnosticCode>(\n code: C,\n details: DiagnosticDetails<C>,\n input?: BuildInput,\n): never {\n throw new DatakableConfigError(buildDiagnostic(code, details, input))\n}\n\n/** A core invariant broke (unregistered op, boundary installed twice): `DK_INTERNAL`. */\nexport function internalError(op: string, problem: string): DatakableError {\n return new DatakableError(buildDiagnostic('DK_INTERNAL', { op, problem }))\n}\n"],"mappings":"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","names":[]}
@@ -27,8 +27,17 @@ module.exports = __toCommonJS(console_exports);
27
27
  var import_build = require("./build.cjs");
28
28
  var import_process_guard = require("./process-guard.cjs");
29
29
  var ICON = { error: "\u2716", warn: "\u26A0", info: "\u2139" };
30
+ var printable = (s) => (
31
+ // biome-ignore lint/suspicious/noControlCharactersInRegex: the characters to escape
32
+ s.replace(
33
+ /[\u0000-\u001f\u007f-\u009f\u2028\u2029]/g,
34
+ (c) => c === "\n" ? "\\n" : `\\u${(c.charCodeAt(0) + 65536).toString(16).slice(1)}`
35
+ )
36
+ );
30
37
  function formatDiagnostic(d) {
31
- const header = `${ICON[d.level]} [DataKable ${d.context.table}] ${d.code}: ${d.problem}`;
38
+ const header = printable(
39
+ `${ICON[d.level]} [DataKable ${d.context.table}] ${d.code}: ${d.problem}`
40
+ );
32
41
  const lines = [` where ${(0, import_build.formatWhere)(d.where)}`];
33
42
  if (d.impact) lines.push(` impact ${d.impact}`);
34
43
  d.fix.forEach((f, i) => {
@@ -37,7 +46,7 @@ function formatDiagnostic(d) {
37
46
  lines.push(` docs ${d.docs}`);
38
47
  const c = d.context;
39
48
  lines.push(` context trigger=${c.trigger} run=${c.run} phase=${c.phase}`);
40
- return { header, body: lines.join("\n") };
49
+ return { header, body: lines.map(printable).join("\n") };
41
50
  }
42
51
  function createConsoleSink(o) {
43
52
  let windowStart = Number.NEGATIVE_INFINITY;
@@ -49,7 +58,7 @@ function createConsoleSink(o) {
49
58
  if (t - windowStart >= o.rateLimit.windowMs) {
50
59
  if (suppressed > 0) {
51
60
  console.warn(
52
- `[DataKable ${o.table}] ${suppressed} diagnostics were not printed (rate limit); read them with getDiagnostics() or onDiagnostic`
61
+ `[DataKable ${printable(o.table)}] ${suppressed} diagnostics were not printed (rate limit); read them with getDiagnostics() or onDiagnostic`
53
62
  );
54
63
  }
55
64
  windowStart = t;
@@ -74,7 +83,9 @@ ${body}`);
74
83
  console.groupEnd();
75
84
  return;
76
85
  }
77
- console.error(`[DataKable ${o.table}] ${d.code} at ${(0, import_build.formatWhere)(d.where)} \u2014 ${d.docs}`);
86
+ console.error(
87
+ printable(`[DataKable ${o.table}] ${d.code} at ${(0, import_build.formatWhere)(d.where)} \u2014 ${d.docs}`)
88
+ );
78
89
  };
79
90
  }
80
91
  // Annotate the CommonJS export names for ESM import in node:
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/diagnostics/console.ts"],"sourcesContent":["import { formatWhere } from './build'\nimport './process-guard'\nimport type { Diagnostic } from './types'\n\nconst ICON = { error: '✖', warn: '⚠', info: 'ℹ' } as const\n\n/** The §8.1 console text: header + aligned body. Also usable by explain() and tests. */\nexport function formatDiagnostic(d: Diagnostic): { header: string; body: string } {\n const header = `${ICON[d.level]} [DataKable ${d.context.table}] ${d.code}: ${d.problem}`\n const lines = [` where ${formatWhere(d.where)}`]\n if (d.impact) lines.push(` impact ${d.impact}`)\n d.fix.forEach((f, i) => {\n lines.push(`${i === 0 ? ' fix ' : ' '}${i + 1}. ${f}`)\n })\n lines.push(` docs ${d.docs}`)\n const c = d.context\n lines.push(` context trigger=${c.trigger} run=${c.run} phase=${c.phase}`)\n return { header, body: lines.join('\\n') }\n}\n\nexport interface ConsoleSinkOptions {\n table: string\n dev: boolean\n rateLimit: { max: number; windowMs: number }\n now: () => number\n}\n\n/**\n * Default console sink (§8.2): dev prints one collapsed group per diagnostic; prod prints\n * error level only, on one line. A fixed-window rate limit protects the console; what it holds back\n * is still in getDiagnostics() and onDiagnostic.\n */\nexport function createConsoleSink(o: ConsoleSinkOptions): (d: Diagnostic) => void {\n let windowStart = Number.NEGATIVE_INFINITY\n let printed = 0\n let suppressed = 0\n // The grouped format is development-only: a production build prints one line (§8.2). `(process.env.NODE_ENV !== \"production\")` is\n // read inline so the bundler drops the grouped branch.\n return (d) => {\n if ((!(process.env.NODE_ENV !== \"production\") || !o.dev) && d.level !== 'error') return\n const t = o.now()\n if (t - windowStart >= o.rateLimit.windowMs) {\n if (suppressed > 0) {\n console.warn(\n `[DataKable ${o.table}] ${suppressed} diagnostics were not printed (rate limit); ` +\n 'read them with getDiagnostics() or onDiagnostic',\n )\n }\n windowStart = t\n printed = 0\n suppressed = 0\n }\n if (printed >= o.rateLimit.max) {\n suppressed++\n return\n }\n printed++\n // `(process.env.NODE_ENV !== \"production\") &&` first, not an early `if (!(process.env.NODE_ENV !== \"production\")) return`: a branch that folds to `false` is removed\n // while parsing, so a production bundle keeps no `formatDiagnostic` (code after a folded early\n // return is dropped only when printing, after tree shaking kept what it calls).\n if ((process.env.NODE_ENV !== \"production\") && o.dev) {\n const { header, body } = formatDiagnostic(d)\n const log = d.level === 'error' ? 'error' : d.level === 'warn' ? 'warn' : 'info'\n // Runtimes without console groups (the Edge Runtime: log/info/warn/error/debug only) get the\n // same text as one call.\n if (typeof console.groupCollapsed !== 'function' || typeof console.groupEnd !== 'function') {\n console[log](`${header}\\n${body}`)\n return\n }\n console.groupCollapsed(header)\n console[log](body)\n console.groupEnd()\n return\n }\n console.error(`[DataKable ${o.table}] ${d.code} at ${formatWhere(d.where)} — ${d.docs}`)\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAA4B;AAC5B,2BAAO;AAGP,IAAM,OAAO,EAAE,OAAO,UAAK,MAAM,UAAK,MAAM,SAAI;AAGzC,SAAS,iBAAiB,GAAiD;AAChF,QAAM,SAAS,GAAG,KAAK,EAAE,KAAK,CAAC,eAAe,EAAE,QAAQ,KAAK,KAAK,EAAE,IAAI,KAAK,EAAE,OAAO;AACtF,QAAM,QAAQ,CAAC,iBAAa,0BAAY,EAAE,KAAK,CAAC,EAAE;AAClD,MAAI,EAAE,OAAQ,OAAM,KAAK,aAAa,EAAE,MAAM,EAAE;AAChD,IAAE,IAAI,QAAQ,CAAC,GAAG,MAAM;AACtB,UAAM,KAAK,GAAG,MAAM,IAAI,eAAe,YAAY,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE;AAAA,EACrE,CAAC;AACD,QAAM,KAAK,aAAa,EAAE,IAAI,EAAE;AAChC,QAAM,IAAI,EAAE;AACZ,QAAM,KAAK,qBAAqB,EAAE,OAAO,QAAQ,EAAE,GAAG,UAAU,EAAE,KAAK,EAAE;AACzE,SAAO,EAAE,QAAQ,MAAM,MAAM,KAAK,IAAI,EAAE;AAC1C;AAcO,SAAS,kBAAkB,GAAgD;AAChF,MAAI,cAAc,OAAO;AACzB,MAAI,UAAU;AACd,MAAI,aAAa;AAGjB,SAAO,CAAC,MAAM;AACZ,SAAK,EAAE,QAAQ,IAAI,aAAa,iBAAiB,CAAC,EAAE,QAAQ,EAAE,UAAU,QAAS;AACjF,UAAM,IAAI,EAAE,IAAI;AAChB,QAAI,IAAI,eAAe,EAAE,UAAU,UAAU;AAC3C,UAAI,aAAa,GAAG;AAClB,gBAAQ;AAAA,UACN,cAAc,EAAE,KAAK,KAAK,UAAU;AAAA,QAEtC;AAAA,MACF;AACA,oBAAc;AACd,gBAAU;AACV,mBAAa;AAAA,IACf;AACA,QAAI,WAAW,EAAE,UAAU,KAAK;AAC9B;AACA;AAAA,IACF;AACA;AAIA,QAAK,QAAQ,IAAI,aAAa,gBAAiB,EAAE,KAAK;AACpD,YAAM,EAAE,QAAQ,KAAK,IAAI,iBAAiB,CAAC;AAC3C,YAAM,MAAM,EAAE,UAAU,UAAU,UAAU,EAAE,UAAU,SAAS,SAAS;AAG1E,UAAI,OAAO,QAAQ,mBAAmB,cAAc,OAAO,QAAQ,aAAa,YAAY;AAC1F,gBAAQ,GAAG,EAAE,GAAG,MAAM;AAAA,EAAK,IAAI,EAAE;AACjC;AAAA,MACF;AACA,cAAQ,eAAe,MAAM;AAC7B,cAAQ,GAAG,EAAE,IAAI;AACjB,cAAQ,SAAS;AACjB;AAAA,IACF;AACA,YAAQ,MAAM,cAAc,EAAE,KAAK,KAAK,EAAE,IAAI,WAAO,0BAAY,EAAE,KAAK,CAAC,WAAM,EAAE,IAAI,EAAE;AAAA,EACzF;AACF;","names":[]}
1
+ {"version":3,"sources":["../../src/diagnostics/console.ts"],"sourcesContent":["import { formatWhere } from './build'\nimport './process-guard'\nimport type { Diagnostic } from './types'\n\nconst ICON = { error: '✖', warn: '⚠', info: 'ℹ' } as const\n\n/**\n * Console text is printed with its C0 / C1 control characters, DEL and line breaks escaped\n * (`\\u001b`, `\\n`, ...): ids, keys and table names can come from URLs or data, and must not\n * forge a line or send terminal escapes (#104). The diagnostic object keeps the raw values.\n */\nconst printable = (s: string): string =>\n // biome-ignore lint/suspicious/noControlCharactersInRegex: the characters to escape\n s.replace(/[\\u0000-\\u001f\\u007f-\\u009f\\u2028\\u2029]/g, (c) =>\n c === '\\n' ? '\\\\n' : `\\\\u${(c.charCodeAt(0) + 0x10000).toString(16).slice(1)}`,\n )\n\n/**\n * The §8.1 console text: header + aligned body, each line {@link printable}. Also usable by\n * explain() and tests.\n */\nexport function formatDiagnostic(d: Diagnostic): { header: string; body: string } {\n const header = printable(\n `${ICON[d.level]} [DataKable ${d.context.table}] ${d.code}: ${d.problem}`,\n )\n const lines = [` where ${formatWhere(d.where)}`]\n if (d.impact) lines.push(` impact ${d.impact}`)\n d.fix.forEach((f, i) => {\n lines.push(`${i === 0 ? ' fix ' : ' '}${i + 1}. ${f}`)\n })\n lines.push(` docs ${d.docs}`)\n const c = d.context\n lines.push(` context trigger=${c.trigger} run=${c.run} phase=${c.phase}`)\n return { header, body: lines.map(printable).join('\\n') }\n}\n\nexport interface ConsoleSinkOptions {\n table: string\n dev: boolean\n rateLimit: { max: number; windowMs: number }\n now: () => number\n}\n\n/**\n * Default console sink (§8.2): dev prints one collapsed group per diagnostic; prod prints\n * error level only, on one line. A fixed-window rate limit protects the console; what it holds back\n * is still in getDiagnostics() and onDiagnostic.\n */\nexport function createConsoleSink(o: ConsoleSinkOptions): (d: Diagnostic) => void {\n let windowStart = Number.NEGATIVE_INFINITY\n let printed = 0\n let suppressed = 0\n // The grouped format is development-only: a production build prints one line (§8.2). `(process.env.NODE_ENV !== \"production\")` is\n // read inline so the bundler drops the grouped branch.\n return (d) => {\n if ((!(process.env.NODE_ENV !== \"production\") || !o.dev) && d.level !== 'error') return\n const t = o.now()\n if (t - windowStart >= o.rateLimit.windowMs) {\n if (suppressed > 0) {\n console.warn(\n `[DataKable ${printable(o.table)}] ${suppressed} diagnostics were not printed (rate limit); ` +\n 'read them with getDiagnostics() or onDiagnostic',\n )\n }\n windowStart = t\n printed = 0\n suppressed = 0\n }\n if (printed >= o.rateLimit.max) {\n suppressed++\n return\n }\n printed++\n // `(process.env.NODE_ENV !== \"production\") &&` first, not an early `if (!(process.env.NODE_ENV !== \"production\")) return`: a branch that folds to `false` is removed\n // while parsing, so a production bundle keeps no `formatDiagnostic` (code after a folded early\n // return is dropped only when printing, after tree shaking kept what it calls).\n if ((process.env.NODE_ENV !== \"production\") && o.dev) {\n const { header, body } = formatDiagnostic(d)\n const log = d.level === 'error' ? 'error' : d.level === 'warn' ? 'warn' : 'info'\n // Runtimes without console groups (the Edge Runtime: log/info/warn/error/debug only) get the\n // same text as one call.\n if (typeof console.groupCollapsed !== 'function' || typeof console.groupEnd !== 'function') {\n console[log](`${header}\\n${body}`)\n return\n }\n console.groupCollapsed(header)\n console[log](body)\n console.groupEnd()\n return\n }\n console.error(\n printable(`[DataKable ${o.table}] ${d.code} at ${formatWhere(d.where)} — ${d.docs}`),\n )\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAA4B;AAC5B,2BAAO;AAGP,IAAM,OAAO,EAAE,OAAO,UAAK,MAAM,UAAK,MAAM,SAAI;AAOhD,IAAM,YAAY,CAAC;AAAA;AAAA,EAEjB,EAAE;AAAA,IAAQ;AAAA,IAA6C,CAAC,MACtD,MAAM,OAAO,QAAQ,OAAO,EAAE,WAAW,CAAC,IAAI,OAAS,SAAS,EAAE,EAAE,MAAM,CAAC,CAAC;AAAA,EAC9E;AAAA;AAMK,SAAS,iBAAiB,GAAiD;AAChF,QAAM,SAAS;AAAA,IACb,GAAG,KAAK,EAAE,KAAK,CAAC,eAAe,EAAE,QAAQ,KAAK,KAAK,EAAE,IAAI,KAAK,EAAE,OAAO;AAAA,EACzE;AACA,QAAM,QAAQ,CAAC,iBAAa,0BAAY,EAAE,KAAK,CAAC,EAAE;AAClD,MAAI,EAAE,OAAQ,OAAM,KAAK,aAAa,EAAE,MAAM,EAAE;AAChD,IAAE,IAAI,QAAQ,CAAC,GAAG,MAAM;AACtB,UAAM,KAAK,GAAG,MAAM,IAAI,eAAe,YAAY,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE;AAAA,EACrE,CAAC;AACD,QAAM,KAAK,aAAa,EAAE,IAAI,EAAE;AAChC,QAAM,IAAI,EAAE;AACZ,QAAM,KAAK,qBAAqB,EAAE,OAAO,QAAQ,EAAE,GAAG,UAAU,EAAE,KAAK,EAAE;AACzE,SAAO,EAAE,QAAQ,MAAM,MAAM,IAAI,SAAS,EAAE,KAAK,IAAI,EAAE;AACzD;AAcO,SAAS,kBAAkB,GAAgD;AAChF,MAAI,cAAc,OAAO;AACzB,MAAI,UAAU;AACd,MAAI,aAAa;AAGjB,SAAO,CAAC,MAAM;AACZ,SAAK,EAAE,QAAQ,IAAI,aAAa,iBAAiB,CAAC,EAAE,QAAQ,EAAE,UAAU,QAAS;AACjF,UAAM,IAAI,EAAE,IAAI;AAChB,QAAI,IAAI,eAAe,EAAE,UAAU,UAAU;AAC3C,UAAI,aAAa,GAAG;AAClB,gBAAQ;AAAA,UACN,cAAc,UAAU,EAAE,KAAK,CAAC,KAAK,UAAU;AAAA,QAEjD;AAAA,MACF;AACA,oBAAc;AACd,gBAAU;AACV,mBAAa;AAAA,IACf;AACA,QAAI,WAAW,EAAE,UAAU,KAAK;AAC9B;AACA;AAAA,IACF;AACA;AAIA,QAAK,QAAQ,IAAI,aAAa,gBAAiB,EAAE,KAAK;AACpD,YAAM,EAAE,QAAQ,KAAK,IAAI,iBAAiB,CAAC;AAC3C,YAAM,MAAM,EAAE,UAAU,UAAU,UAAU,EAAE,UAAU,SAAS,SAAS;AAG1E,UAAI,OAAO,QAAQ,mBAAmB,cAAc,OAAO,QAAQ,aAAa,YAAY;AAC1F,gBAAQ,GAAG,EAAE,GAAG,MAAM;AAAA,EAAK,IAAI,EAAE;AACjC;AAAA,MACF;AACA,cAAQ,eAAe,MAAM;AAC7B,cAAQ,GAAG,EAAE,IAAI;AACjB,cAAQ,SAAS;AACjB;AAAA,IACF;AACA,YAAQ;AAAA,MACN,UAAU,cAAc,EAAE,KAAK,KAAK,EAAE,IAAI,WAAO,0BAAY,EAAE,KAAK,CAAC,WAAM,EAAE,IAAI,EAAE;AAAA,IACrF;AAAA,EACF;AACF;","names":[]}
@@ -2,8 +2,17 @@
2
2
  import { formatWhere } from "./build.js";
3
3
  import "./process-guard.js";
4
4
  var ICON = { error: "\u2716", warn: "\u26A0", info: "\u2139" };
5
+ var printable = (s) => (
6
+ // biome-ignore lint/suspicious/noControlCharactersInRegex: the characters to escape
7
+ s.replace(
8
+ /[\u0000-\u001f\u007f-\u009f\u2028\u2029]/g,
9
+ (c) => c === "\n" ? "\\n" : `\\u${(c.charCodeAt(0) + 65536).toString(16).slice(1)}`
10
+ )
11
+ );
5
12
  function formatDiagnostic(d) {
6
- const header = `${ICON[d.level]} [DataKable ${d.context.table}] ${d.code}: ${d.problem}`;
13
+ const header = printable(
14
+ `${ICON[d.level]} [DataKable ${d.context.table}] ${d.code}: ${d.problem}`
15
+ );
7
16
  const lines = [` where ${formatWhere(d.where)}`];
8
17
  if (d.impact) lines.push(` impact ${d.impact}`);
9
18
  d.fix.forEach((f, i) => {
@@ -12,7 +21,7 @@ function formatDiagnostic(d) {
12
21
  lines.push(` docs ${d.docs}`);
13
22
  const c = d.context;
14
23
  lines.push(` context trigger=${c.trigger} run=${c.run} phase=${c.phase}`);
15
- return { header, body: lines.join("\n") };
24
+ return { header, body: lines.map(printable).join("\n") };
16
25
  }
17
26
  function createConsoleSink(o) {
18
27
  let windowStart = Number.NEGATIVE_INFINITY;
@@ -24,7 +33,7 @@ function createConsoleSink(o) {
24
33
  if (t - windowStart >= o.rateLimit.windowMs) {
25
34
  if (suppressed > 0) {
26
35
  console.warn(
27
- `[DataKable ${o.table}] ${suppressed} diagnostics were not printed (rate limit); read them with getDiagnostics() or onDiagnostic`
36
+ `[DataKable ${printable(o.table)}] ${suppressed} diagnostics were not printed (rate limit); read them with getDiagnostics() or onDiagnostic`
28
37
  );
29
38
  }
30
39
  windowStart = t;
@@ -49,7 +58,9 @@ ${body}`);
49
58
  console.groupEnd();
50
59
  return;
51
60
  }
52
- console.error(`[DataKable ${o.table}] ${d.code} at ${formatWhere(d.where)} \u2014 ${d.docs}`);
61
+ console.error(
62
+ printable(`[DataKable ${o.table}] ${d.code} at ${formatWhere(d.where)} \u2014 ${d.docs}`)
63
+ );
53
64
  };
54
65
  }
55
66
  export {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/diagnostics/console.ts"],"sourcesContent":["import { formatWhere } from './build'\nimport './process-guard'\nimport type { Diagnostic } from './types'\n\nconst ICON = { error: '✖', warn: '⚠', info: 'ℹ' } as const\n\n/** The §8.1 console text: header + aligned body. Also usable by explain() and tests. */\nexport function formatDiagnostic(d: Diagnostic): { header: string; body: string } {\n const header = `${ICON[d.level]} [DataKable ${d.context.table}] ${d.code}: ${d.problem}`\n const lines = [` where ${formatWhere(d.where)}`]\n if (d.impact) lines.push(` impact ${d.impact}`)\n d.fix.forEach((f, i) => {\n lines.push(`${i === 0 ? ' fix ' : ' '}${i + 1}. ${f}`)\n })\n lines.push(` docs ${d.docs}`)\n const c = d.context\n lines.push(` context trigger=${c.trigger} run=${c.run} phase=${c.phase}`)\n return { header, body: lines.join('\\n') }\n}\n\nexport interface ConsoleSinkOptions {\n table: string\n dev: boolean\n rateLimit: { max: number; windowMs: number }\n now: () => number\n}\n\n/**\n * Default console sink (§8.2): dev prints one collapsed group per diagnostic; prod prints\n * error level only, on one line. A fixed-window rate limit protects the console; what it holds back\n * is still in getDiagnostics() and onDiagnostic.\n */\nexport function createConsoleSink(o: ConsoleSinkOptions): (d: Diagnostic) => void {\n let windowStart = Number.NEGATIVE_INFINITY\n let printed = 0\n let suppressed = 0\n // The grouped format is development-only: a production build prints one line (§8.2). `(process.env.NODE_ENV !== \"production\")` is\n // read inline so the bundler drops the grouped branch.\n return (d) => {\n if ((!(process.env.NODE_ENV !== \"production\") || !o.dev) && d.level !== 'error') return\n const t = o.now()\n if (t - windowStart >= o.rateLimit.windowMs) {\n if (suppressed > 0) {\n console.warn(\n `[DataKable ${o.table}] ${suppressed} diagnostics were not printed (rate limit); ` +\n 'read them with getDiagnostics() or onDiagnostic',\n )\n }\n windowStart = t\n printed = 0\n suppressed = 0\n }\n if (printed >= o.rateLimit.max) {\n suppressed++\n return\n }\n printed++\n // `(process.env.NODE_ENV !== \"production\") &&` first, not an early `if (!(process.env.NODE_ENV !== \"production\")) return`: a branch that folds to `false` is removed\n // while parsing, so a production bundle keeps no `formatDiagnostic` (code after a folded early\n // return is dropped only when printing, after tree shaking kept what it calls).\n if ((process.env.NODE_ENV !== \"production\") && o.dev) {\n const { header, body } = formatDiagnostic(d)\n const log = d.level === 'error' ? 'error' : d.level === 'warn' ? 'warn' : 'info'\n // Runtimes without console groups (the Edge Runtime: log/info/warn/error/debug only) get the\n // same text as one call.\n if (typeof console.groupCollapsed !== 'function' || typeof console.groupEnd !== 'function') {\n console[log](`${header}\\n${body}`)\n return\n }\n console.groupCollapsed(header)\n console[log](body)\n console.groupEnd()\n return\n }\n console.error(`[DataKable ${o.table}] ${d.code} at ${formatWhere(d.where)} — ${d.docs}`)\n }\n}\n"],"mappings":";AAAA,SAAS,mBAAmB;AAC5B,OAAO;AAGP,IAAM,OAAO,EAAE,OAAO,UAAK,MAAM,UAAK,MAAM,SAAI;AAGzC,SAAS,iBAAiB,GAAiD;AAChF,QAAM,SAAS,GAAG,KAAK,EAAE,KAAK,CAAC,eAAe,EAAE,QAAQ,KAAK,KAAK,EAAE,IAAI,KAAK,EAAE,OAAO;AACtF,QAAM,QAAQ,CAAC,aAAa,YAAY,EAAE,KAAK,CAAC,EAAE;AAClD,MAAI,EAAE,OAAQ,OAAM,KAAK,aAAa,EAAE,MAAM,EAAE;AAChD,IAAE,IAAI,QAAQ,CAAC,GAAG,MAAM;AACtB,UAAM,KAAK,GAAG,MAAM,IAAI,eAAe,YAAY,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE;AAAA,EACrE,CAAC;AACD,QAAM,KAAK,aAAa,EAAE,IAAI,EAAE;AAChC,QAAM,IAAI,EAAE;AACZ,QAAM,KAAK,qBAAqB,EAAE,OAAO,QAAQ,EAAE,GAAG,UAAU,EAAE,KAAK,EAAE;AACzE,SAAO,EAAE,QAAQ,MAAM,MAAM,KAAK,IAAI,EAAE;AAC1C;AAcO,SAAS,kBAAkB,GAAgD;AAChF,MAAI,cAAc,OAAO;AACzB,MAAI,UAAU;AACd,MAAI,aAAa;AAGjB,SAAO,CAAC,MAAM;AACZ,SAAK,EAAE,QAAQ,IAAI,aAAa,iBAAiB,CAAC,EAAE,QAAQ,EAAE,UAAU,QAAS;AACjF,UAAM,IAAI,EAAE,IAAI;AAChB,QAAI,IAAI,eAAe,EAAE,UAAU,UAAU;AAC3C,UAAI,aAAa,GAAG;AAClB,gBAAQ;AAAA,UACN,cAAc,EAAE,KAAK,KAAK,UAAU;AAAA,QAEtC;AAAA,MACF;AACA,oBAAc;AACd,gBAAU;AACV,mBAAa;AAAA,IACf;AACA,QAAI,WAAW,EAAE,UAAU,KAAK;AAC9B;AACA;AAAA,IACF;AACA;AAIA,QAAK,QAAQ,IAAI,aAAa,gBAAiB,EAAE,KAAK;AACpD,YAAM,EAAE,QAAQ,KAAK,IAAI,iBAAiB,CAAC;AAC3C,YAAM,MAAM,EAAE,UAAU,UAAU,UAAU,EAAE,UAAU,SAAS,SAAS;AAG1E,UAAI,OAAO,QAAQ,mBAAmB,cAAc,OAAO,QAAQ,aAAa,YAAY;AAC1F,gBAAQ,GAAG,EAAE,GAAG,MAAM;AAAA,EAAK,IAAI,EAAE;AACjC;AAAA,MACF;AACA,cAAQ,eAAe,MAAM;AAC7B,cAAQ,GAAG,EAAE,IAAI;AACjB,cAAQ,SAAS;AACjB;AAAA,IACF;AACA,YAAQ,MAAM,cAAc,EAAE,KAAK,KAAK,EAAE,IAAI,OAAO,YAAY,EAAE,KAAK,CAAC,WAAM,EAAE,IAAI,EAAE;AAAA,EACzF;AACF;","names":[]}
1
+ {"version":3,"sources":["../../src/diagnostics/console.ts"],"sourcesContent":["import { formatWhere } from './build'\nimport './process-guard'\nimport type { Diagnostic } from './types'\n\nconst ICON = { error: '✖', warn: '⚠', info: 'ℹ' } as const\n\n/**\n * Console text is printed with its C0 / C1 control characters, DEL and line breaks escaped\n * (`\\u001b`, `\\n`, ...): ids, keys and table names can come from URLs or data, and must not\n * forge a line or send terminal escapes (#104). The diagnostic object keeps the raw values.\n */\nconst printable = (s: string): string =>\n // biome-ignore lint/suspicious/noControlCharactersInRegex: the characters to escape\n s.replace(/[\\u0000-\\u001f\\u007f-\\u009f\\u2028\\u2029]/g, (c) =>\n c === '\\n' ? '\\\\n' : `\\\\u${(c.charCodeAt(0) + 0x10000).toString(16).slice(1)}`,\n )\n\n/**\n * The §8.1 console text: header + aligned body, each line {@link printable}. Also usable by\n * explain() and tests.\n */\nexport function formatDiagnostic(d: Diagnostic): { header: string; body: string } {\n const header = printable(\n `${ICON[d.level]} [DataKable ${d.context.table}] ${d.code}: ${d.problem}`,\n )\n const lines = [` where ${formatWhere(d.where)}`]\n if (d.impact) lines.push(` impact ${d.impact}`)\n d.fix.forEach((f, i) => {\n lines.push(`${i === 0 ? ' fix ' : ' '}${i + 1}. ${f}`)\n })\n lines.push(` docs ${d.docs}`)\n const c = d.context\n lines.push(` context trigger=${c.trigger} run=${c.run} phase=${c.phase}`)\n return { header, body: lines.map(printable).join('\\n') }\n}\n\nexport interface ConsoleSinkOptions {\n table: string\n dev: boolean\n rateLimit: { max: number; windowMs: number }\n now: () => number\n}\n\n/**\n * Default console sink (§8.2): dev prints one collapsed group per diagnostic; prod prints\n * error level only, on one line. A fixed-window rate limit protects the console; what it holds back\n * is still in getDiagnostics() and onDiagnostic.\n */\nexport function createConsoleSink(o: ConsoleSinkOptions): (d: Diagnostic) => void {\n let windowStart = Number.NEGATIVE_INFINITY\n let printed = 0\n let suppressed = 0\n // The grouped format is development-only: a production build prints one line (§8.2). `(process.env.NODE_ENV !== \"production\")` is\n // read inline so the bundler drops the grouped branch.\n return (d) => {\n if ((!(process.env.NODE_ENV !== \"production\") || !o.dev) && d.level !== 'error') return\n const t = o.now()\n if (t - windowStart >= o.rateLimit.windowMs) {\n if (suppressed > 0) {\n console.warn(\n `[DataKable ${printable(o.table)}] ${suppressed} diagnostics were not printed (rate limit); ` +\n 'read them with getDiagnostics() or onDiagnostic',\n )\n }\n windowStart = t\n printed = 0\n suppressed = 0\n }\n if (printed >= o.rateLimit.max) {\n suppressed++\n return\n }\n printed++\n // `(process.env.NODE_ENV !== \"production\") &&` first, not an early `if (!(process.env.NODE_ENV !== \"production\")) return`: a branch that folds to `false` is removed\n // while parsing, so a production bundle keeps no `formatDiagnostic` (code after a folded early\n // return is dropped only when printing, after tree shaking kept what it calls).\n if ((process.env.NODE_ENV !== \"production\") && o.dev) {\n const { header, body } = formatDiagnostic(d)\n const log = d.level === 'error' ? 'error' : d.level === 'warn' ? 'warn' : 'info'\n // Runtimes without console groups (the Edge Runtime: log/info/warn/error/debug only) get the\n // same text as one call.\n if (typeof console.groupCollapsed !== 'function' || typeof console.groupEnd !== 'function') {\n console[log](`${header}\\n${body}`)\n return\n }\n console.groupCollapsed(header)\n console[log](body)\n console.groupEnd()\n return\n }\n console.error(\n printable(`[DataKable ${o.table}] ${d.code} at ${formatWhere(d.where)} — ${d.docs}`),\n )\n }\n}\n"],"mappings":";AAAA,SAAS,mBAAmB;AAC5B,OAAO;AAGP,IAAM,OAAO,EAAE,OAAO,UAAK,MAAM,UAAK,MAAM,SAAI;AAOhD,IAAM,YAAY,CAAC;AAAA;AAAA,EAEjB,EAAE;AAAA,IAAQ;AAAA,IAA6C,CAAC,MACtD,MAAM,OAAO,QAAQ,OAAO,EAAE,WAAW,CAAC,IAAI,OAAS,SAAS,EAAE,EAAE,MAAM,CAAC,CAAC;AAAA,EAC9E;AAAA;AAMK,SAAS,iBAAiB,GAAiD;AAChF,QAAM,SAAS;AAAA,IACb,GAAG,KAAK,EAAE,KAAK,CAAC,eAAe,EAAE,QAAQ,KAAK,KAAK,EAAE,IAAI,KAAK,EAAE,OAAO;AAAA,EACzE;AACA,QAAM,QAAQ,CAAC,aAAa,YAAY,EAAE,KAAK,CAAC,EAAE;AAClD,MAAI,EAAE,OAAQ,OAAM,KAAK,aAAa,EAAE,MAAM,EAAE;AAChD,IAAE,IAAI,QAAQ,CAAC,GAAG,MAAM;AACtB,UAAM,KAAK,GAAG,MAAM,IAAI,eAAe,YAAY,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE;AAAA,EACrE,CAAC;AACD,QAAM,KAAK,aAAa,EAAE,IAAI,EAAE;AAChC,QAAM,IAAI,EAAE;AACZ,QAAM,KAAK,qBAAqB,EAAE,OAAO,QAAQ,EAAE,GAAG,UAAU,EAAE,KAAK,EAAE;AACzE,SAAO,EAAE,QAAQ,MAAM,MAAM,IAAI,SAAS,EAAE,KAAK,IAAI,EAAE;AACzD;AAcO,SAAS,kBAAkB,GAAgD;AAChF,MAAI,cAAc,OAAO;AACzB,MAAI,UAAU;AACd,MAAI,aAAa;AAGjB,SAAO,CAAC,MAAM;AACZ,SAAK,EAAE,QAAQ,IAAI,aAAa,iBAAiB,CAAC,EAAE,QAAQ,EAAE,UAAU,QAAS;AACjF,UAAM,IAAI,EAAE,IAAI;AAChB,QAAI,IAAI,eAAe,EAAE,UAAU,UAAU;AAC3C,UAAI,aAAa,GAAG;AAClB,gBAAQ;AAAA,UACN,cAAc,UAAU,EAAE,KAAK,CAAC,KAAK,UAAU;AAAA,QAEjD;AAAA,MACF;AACA,oBAAc;AACd,gBAAU;AACV,mBAAa;AAAA,IACf;AACA,QAAI,WAAW,EAAE,UAAU,KAAK;AAC9B;AACA;AAAA,IACF;AACA;AAIA,QAAK,QAAQ,IAAI,aAAa,gBAAiB,EAAE,KAAK;AACpD,YAAM,EAAE,QAAQ,KAAK,IAAI,iBAAiB,CAAC;AAC3C,YAAM,MAAM,EAAE,UAAU,UAAU,UAAU,EAAE,UAAU,SAAS,SAAS;AAG1E,UAAI,OAAO,QAAQ,mBAAmB,cAAc,OAAO,QAAQ,aAAa,YAAY;AAC1F,gBAAQ,GAAG,EAAE,GAAG,MAAM;AAAA,EAAK,IAAI,EAAE;AACjC;AAAA,MACF;AACA,cAAQ,eAAe,MAAM;AAC7B,cAAQ,GAAG,EAAE,IAAI;AACjB,cAAQ,SAAS;AACjB;AAAA,IACF;AACA,YAAQ;AAAA,MACN,UAAU,cAAc,EAAE,KAAK,KAAK,EAAE,IAAI,OAAO,YAAY,EAAE,KAAK,CAAC,WAAM,EAAE,IAAI,EAAE;AAAA,IACrF;AAAA,EACF;AACF;","names":[]}