@smart-data-engines/sde 0.1.0-dev.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 (131) hide show
  1. package/LICENSE +201 -0
  2. package/NOTICE +13 -0
  3. package/README.md +153 -0
  4. package/bin/weather.mjs +32 -0
  5. package/dist/_usage.d.ts +30 -0
  6. package/dist/_usage.js +194 -0
  7. package/dist/_usage.js.map +1 -0
  8. package/dist/bulk.d.ts +9 -0
  9. package/dist/bulk.js +83 -0
  10. package/dist/bulk.js.map +1 -0
  11. package/dist/canonical.d.ts +46 -0
  12. package/dist/canonical.js +150 -0
  13. package/dist/canonical.js.map +1 -0
  14. package/dist/capabilities.d.ts +48 -0
  15. package/dist/capabilities.js +62 -0
  16. package/dist/capabilities.js.map +1 -0
  17. package/dist/cutover.d.ts +36 -0
  18. package/dist/cutover.js +219 -0
  19. package/dist/cutover.js.map +1 -0
  20. package/dist/demo/model.d.ts +28 -0
  21. package/dist/demo/model.js +40 -0
  22. package/dist/demo/model.js.map +1 -0
  23. package/dist/demo/project.d.ts +19 -0
  24. package/dist/demo/project.js +128 -0
  25. package/dist/demo/project.js.map +1 -0
  26. package/dist/demo/weather.d.ts +73 -0
  27. package/dist/demo/weather.js +334 -0
  28. package/dist/demo/weather.js.map +1 -0
  29. package/dist/engines/_clickhouse-connection.d.ts +17 -0
  30. package/dist/engines/_clickhouse-connection.js +182 -0
  31. package/dist/engines/_clickhouse-connection.js.map +1 -0
  32. package/dist/engines/_tls-peer-identity.d.ts +2 -0
  33. package/dist/engines/_tls-peer-identity.js +23 -0
  34. package/dist/engines/_tls-peer-identity.js.map +1 -0
  35. package/dist/engines/_write-fences.d.ts +51 -0
  36. package/dist/engines/_write-fences.js +189 -0
  37. package/dist/engines/_write-fences.js.map +1 -0
  38. package/dist/engines/clickhouse.d.ts +193 -0
  39. package/dist/engines/clickhouse.js +899 -0
  40. package/dist/engines/clickhouse.js.map +1 -0
  41. package/dist/engines/postgres.d.ts +293 -0
  42. package/dist/engines/postgres.js +981 -0
  43. package/dist/engines/postgres.js.map +1 -0
  44. package/dist/errors.d.ts +89 -0
  45. package/dist/errors.js +90 -0
  46. package/dist/errors.js.map +1 -0
  47. package/dist/frozen-verification.d.ts +26 -0
  48. package/dist/frozen-verification.js +67 -0
  49. package/dist/frozen-verification.js.map +1 -0
  50. package/dist/generation.d.ts +34 -0
  51. package/dist/generation.js +81 -0
  52. package/dist/generation.js.map +1 -0
  53. package/dist/groups.d.ts +17 -0
  54. package/dist/groups.js +66 -0
  55. package/dist/groups.js.map +1 -0
  56. package/dist/hashing.d.ts +68 -0
  57. package/dist/hashing.js +146 -0
  58. package/dist/hashing.js.map +1 -0
  59. package/dist/in-place-index.d.ts +43 -0
  60. package/dist/in-place-index.js +272 -0
  61. package/dist/in-place-index.js.map +1 -0
  62. package/dist/index.d.ts +79 -0
  63. package/dist/index.js +64 -0
  64. package/dist/index.js.map +1 -0
  65. package/dist/inspection.d.ts +19 -0
  66. package/dist/inspection.js +31 -0
  67. package/dist/inspection.js.map +1 -0
  68. package/dist/internal.d.ts +42 -0
  69. package/dist/internal.js +56 -0
  70. package/dist/internal.js.map +1 -0
  71. package/dist/layout.d.ts +36 -0
  72. package/dist/layout.js +62 -0
  73. package/dist/layout.js.map +1 -0
  74. package/dist/migration.d.ts +197 -0
  75. package/dist/migration.js +592 -0
  76. package/dist/migration.js.map +1 -0
  77. package/dist/model.d.ts +93 -0
  78. package/dist/model.js +313 -0
  79. package/dist/model.js.map +1 -0
  80. package/dist/physical.d.ts +128 -0
  81. package/dist/physical.js +421 -0
  82. package/dist/physical.js.map +1 -0
  83. package/dist/placement.d.ts +157 -0
  84. package/dist/placement.js +651 -0
  85. package/dist/placement.js.map +1 -0
  86. package/dist/provisioning.d.ts +6 -0
  87. package/dist/provisioning.js +45 -0
  88. package/dist/provisioning.js.map +1 -0
  89. package/dist/query.d.ts +68 -0
  90. package/dist/query.js +340 -0
  91. package/dist/query.js.map +1 -0
  92. package/dist/routing.d.ts +25 -0
  93. package/dist/routing.js +35 -0
  94. package/dist/routing.js.map +1 -0
  95. package/dist/schema.d.ts +110 -0
  96. package/dist/schema.js +337 -0
  97. package/dist/schema.js.map +1 -0
  98. package/dist/session.d.ts +195 -0
  99. package/dist/session.js +870 -0
  100. package/dist/session.js.map +1 -0
  101. package/dist/shapes.d.ts +30 -0
  102. package/dist/shapes.js +112 -0
  103. package/dist/shapes.js.map +1 -0
  104. package/dist/staging.d.ts +29 -0
  105. package/dist/staging.js +214 -0
  106. package/dist/staging.js.map +1 -0
  107. package/dist/telemetry.d.ts +468 -0
  108. package/dist/telemetry.js +872 -0
  109. package/dist/telemetry.js.map +1 -0
  110. package/dist/testing/loader.d.ts +38 -0
  111. package/dist/testing/loader.js +86 -0
  112. package/dist/testing/loader.js.map +1 -0
  113. package/dist/testing/memory.d.ts +131 -0
  114. package/dist/testing/memory.js +311 -0
  115. package/dist/testing/memory.js.map +1 -0
  116. package/dist/timestamp.d.ts +20 -0
  117. package/dist/timestamp.js +89 -0
  118. package/dist/timestamp.js.map +1 -0
  119. package/dist/types.d.ts +79 -0
  120. package/dist/types.js +100 -0
  121. package/dist/types.js.map +1 -0
  122. package/dist/verification.d.ts +41 -0
  123. package/dist/verification.js +169 -0
  124. package/dist/verification.js.map +1 -0
  125. package/dist/watermark.d.ts +103 -0
  126. package/dist/watermark.js +170 -0
  127. package/dist/watermark.js.map +1 -0
  128. package/dist/write-fence.d.ts +58 -0
  129. package/dist/write-fence.js +225 -0
  130. package/dist/write-fence.js.map +1 -0
  131. package/package.json +86 -0
@@ -0,0 +1,421 @@
1
+ /**
2
+ * The physical design vocabulary a placement map can carry, and the rules each element obeys.
3
+ *
4
+ * Placement map contract 5 lets a layout say three things about storage beyond tables and column
5
+ * types: the physical order of an entity's key, a time partition, and indexes of a named method.
6
+ * They are chosen by the control plane and a library only renders them. Every element is a closed
7
+ * vocabulary rendered by this library; nothing in a map is pasted into DDL.
8
+ *
9
+ * This is the port of the reference's `sde/physical.py`, and it is one module for the reason that
10
+ * one is: the map parser, the DDL renderer and the adapters' verification all read it, because a
11
+ * second copy of "which index methods ClickHouse has" is how a map gets signed that no library can
12
+ * apply. The two data rules - a partition follows the key, and `key_order` only reorders the key -
13
+ * were measured on PostgreSQL 15.19 and ClickHouse 24.8.14.39 before they were written; the
14
+ * reference module carries the measurements.
15
+ */
16
+ import { MapError } from './errors.js';
17
+ import { compareCodePoints } from './canonical.js';
18
+ export const PHYSICAL_DESIGN_SINCE = 5;
19
+ /** The placement map contract that introduced `key_order`, `partition_by` and index methods. */
20
+ export const GRANULARITIES = ['day', 'month', 'year'];
21
+ /**
22
+ * Time partition sizes. No week: ClickHouse's `toStartOfWeek` depends on a mode, and a closed
23
+ * vocabulary has no modes.
24
+ */
25
+ export const TEMPORAL_TYPES = ['date', 'timestamptz'];
26
+ /**
27
+ * Neutral types a partition may be derived from. `timestamp` is absent on purpose: its ClickHouse
28
+ * column carries no zone, so the partition a value falls into follows the server's configured
29
+ * timezone, and a reconfigured server would put one key into two partitions for ever.
30
+ */
31
+ export const POSTGRES_METHODS = ['brin', 'btree'];
32
+ export const CLICKHOUSE_METHODS = ['bloom_filter', 'minmax', 'set'];
33
+ /** ClickHouse data-skipping index types. It has no B-tree; its primary index is `ORDER BY`. */
34
+ export const INDEX_METHODS = [...POSTGRES_METHODS, ...CLICKHOUSE_METHODS].sort(compareCodePoints);
35
+ export const GRANULARITY_RANGE = [1, 1024];
36
+ export const SET_ROWS_RANGE = [1, 65536];
37
+ /** `set(0)` means unlimited in ClickHouse, an unbounded memory commitment, so zero is outside. */
38
+ const LEGACY_INDEX_KEYS = new Set(['columns', 'entity', 'name']);
39
+ const LATER_INDEX_KEYS = new Set(['granularity', 'max_rows', 'method']);
40
+ const INDEX_KEYS = new Set([...LEGACY_INDEX_KEYS, ...LATER_INDEX_KEYS]);
41
+ export const PARTITION_FUNCTIONS = Object.freeze({
42
+ day: 'toDate',
43
+ month: 'toYYYYMM',
44
+ year: 'toYear',
45
+ });
46
+ /** ClickHouse partition expressions, as its catalogue reports them back. */
47
+ export const PARTITIONING_DIALECTS = new Set(['clickhouse']);
48
+ /**
49
+ * Dialects that render `partition_by`. PostgreSQL is absent on purpose: declarative partitioning
50
+ * there needs every partition created before a row can arrive, a lifecycle this product does not
51
+ * manage, and an unpartitioned table under a map that says otherwise would be a silent drop.
52
+ */
53
+ export const METHODS_BY_DIALECT = Object.freeze({
54
+ clickhouse: CLICKHOUSE_METHODS,
55
+ postgres: POSTGRES_METHODS,
56
+ });
57
+ function isRecord(value) {
58
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
59
+ }
60
+ function isInteger(value) {
61
+ return typeof value === 'number' && Number.isInteger(value);
62
+ }
63
+ function show(value) {
64
+ return value === undefined ? 'undefined' : JSON.stringify(value);
65
+ }
66
+ function sortedKeys(value) {
67
+ return Object.keys(value).sort(compareCodePoints);
68
+ }
69
+ /** An index's method. Absent means `btree`, what every map before contract 5 meant. */
70
+ export function indexMethod(index) {
71
+ return index['method'] === undefined ? 'btree' : String(index['method']);
72
+ }
73
+ function nonEmptyNames(value) {
74
+ return (Array.isArray(value) &&
75
+ value.length > 0 &&
76
+ value.every((column) => typeof column === 'string' && column.length > 0));
77
+ }
78
+ /** `key_order`: entity -> the physical order of that entity's key columns. */
79
+ export function parseKeyOrder(raw, where, tables) {
80
+ if (!isRecord(raw))
81
+ throw new MapError(`${where}: key_order maps an entity to a list of its key columns`);
82
+ const out = Object.create(null);
83
+ for (const entity of sortedKeys(raw)) {
84
+ const columns = raw[entity];
85
+ if (!Object.hasOwn(tables, entity)) {
86
+ throw new MapError(`${where}: key_order names '${entity}', which has no table in this layout. It has ` +
87
+ `${JSON.stringify(sortedKeys(tables))}.`);
88
+ }
89
+ if (!nonEmptyNames(columns)) {
90
+ throw new MapError(`${where}: key_order['${entity}'] must be a non-empty list of column names`);
91
+ }
92
+ if (new Set(columns).size !== columns.length) {
93
+ throw new MapError(`${where}: key_order['${entity}'] names a column twice: ${JSON.stringify(columns)}. A key ` +
94
+ 'order is a permutation of the key, so each key column appears exactly once.');
95
+ }
96
+ out[entity] = [...columns];
97
+ }
98
+ return out;
99
+ }
100
+ /** `partition_by`: entity -> `{"field": ..., "granularity": ...}`, and nothing else. */
101
+ export function parsePartitionBy(raw, where, tables) {
102
+ if (!isRecord(raw)) {
103
+ throw new MapError(`${where}: partition_by maps an entity to a {field, granularity} object`);
104
+ }
105
+ const out = Object.create(null);
106
+ for (const entity of sortedKeys(raw)) {
107
+ const spec = raw[entity];
108
+ if (!Object.hasOwn(tables, entity)) {
109
+ throw new MapError(`${where}: partition_by names '${entity}', which has no table in this layout. It has ` +
110
+ `${JSON.stringify(sortedKeys(tables))}.`);
111
+ }
112
+ const keys = isRecord(spec) ? sortedKeys(spec) : null;
113
+ if (keys === null || keys.length !== 2 || keys[0] !== 'field' || keys[1] !== 'granularity') {
114
+ throw new MapError(`${where}: partition_by['${entity}'] must be exactly {"field": ..., "granularity": ...}; ` +
115
+ `found keys ${keys === null ? (Array.isArray(spec) ? 'list' : typeof spec) : JSON.stringify(keys)}. ` +
116
+ 'The vocabulary is closed so that nothing in a map is pasted into DDL.');
117
+ }
118
+ const record = spec;
119
+ const field = record['field'];
120
+ const granularity = record['granularity'];
121
+ if (typeof field !== 'string' || field.length === 0) {
122
+ throw new MapError(`${where}: partition_by['${entity}'].field must name a column`);
123
+ }
124
+ if (typeof granularity !== 'string' || !GRANULARITIES.includes(granularity)) {
125
+ throw new MapError(`${where}: partition_by['${entity}'].granularity is ${show(granularity)}; it is one of ` +
126
+ `${JSON.stringify(GRANULARITIES)}.`);
127
+ }
128
+ out[entity] = Object.freeze({ field, granularity });
129
+ }
130
+ return out;
131
+ }
132
+ /**
133
+ * Index definitions, validated where the map arrives rather than when DDL is rendered.
134
+ *
135
+ * The structural half applies to every contract and is a tightening; the method, granularity and
136
+ * `max_rows` keys are contract 5, because an earlier library ignores them and would build a B-tree
137
+ * where a later one builds BRIN from the same document.
138
+ */
139
+ export function parseIndexes(raw, where, tables, columns, contract) {
140
+ if (raw === undefined || raw === null)
141
+ return [];
142
+ if (!Array.isArray(raw))
143
+ throw new MapError(`${where}: indexes is a list of index definitions`);
144
+ const allowed = contract >= PHYSICAL_DESIGN_SINCE ? INDEX_KEYS : LEGACY_INDEX_KEYS;
145
+ const out = [];
146
+ const names = new Set();
147
+ raw.forEach((index, position) => {
148
+ const at = `${where}: indexes[${position}]`;
149
+ if (!isRecord(index))
150
+ throw new MapError(`${at} must be an object`);
151
+ const unknown = sortedKeys(index).filter((key) => !allowed.has(key));
152
+ if (unknown.length > 0) {
153
+ const later = unknown.filter((key) => LATER_INDEX_KEYS.has(key));
154
+ if (later.length > 0) {
155
+ throw new MapError(`${at} uses ${JSON.stringify(later)}, which placement map contract ${PHYSICAL_DESIGN_SINCE} ` +
156
+ `introduced, in a document declaring contract ${contract}. A library of that contract ` +
157
+ 'would ignore the key and create a different index from the same document, which is ' +
158
+ 'the difference the version exists to prevent.');
159
+ }
160
+ throw new MapError(`${at} has keys this format does not define: ${JSON.stringify(unknown)}`);
161
+ }
162
+ const entity = index['entity'];
163
+ const name = index['name'];
164
+ const cols = index['columns'];
165
+ if (typeof entity !== 'string' || !Object.hasOwn(tables, entity)) {
166
+ throw new MapError(`${at} names entity ${show(entity)}, which has no table in this layout. It has ` +
167
+ `${JSON.stringify(sortedKeys(tables))}.`);
168
+ }
169
+ if (typeof name !== 'string' || name.length === 0)
170
+ throw new MapError(`${at} needs a non-empty name`);
171
+ if (names.has(name))
172
+ throw new MapError(`${at} reuses the index name '${name}'`);
173
+ names.add(name);
174
+ if (!nonEmptyNames(cols) || new Set(cols).size !== cols.length) {
175
+ throw new MapError(`${at} needs a non-empty list of distinct column names`);
176
+ }
177
+ const declared = Object.hasOwn(columns, entity) ? columns[entity] : undefined;
178
+ if (declared !== undefined && Object.keys(declared).length > 0) {
179
+ const missing = cols.filter((column) => !Object.hasOwn(declared, column));
180
+ if (missing.length > 0) {
181
+ throw new MapError(`${at} indexes ${JSON.stringify(missing)}, which '${entity}' does not have in this ` +
182
+ 'layout. An index on a missing column is refused by the engine at CREATE INDEX, in ' +
183
+ "the client's process, rather than here.");
184
+ }
185
+ }
186
+ const method = index['method'] === undefined ? 'btree' : index['method'];
187
+ if (typeof method !== 'string' || !INDEX_METHODS.includes(method)) {
188
+ throw new MapError(`${at} has method ${show(method)}; the methods are ${JSON.stringify(INDEX_METHODS)}`);
189
+ }
190
+ const granularity = index['granularity'];
191
+ const maxRows = index['max_rows'];
192
+ if (CLICKHOUSE_METHODS.includes(method)) {
193
+ const [low, high] = GRANULARITY_RANGE;
194
+ if (!isInteger(granularity) || granularity < low || granularity > high) {
195
+ throw new MapError(`${at}: a ${method} index needs an integer granularity from ${low} to ${high}; found ` +
196
+ show(granularity));
197
+ }
198
+ if (cols.length !== 1) {
199
+ throw new MapError(`${at}: a ${method} index summarises exactly one column, found ${JSON.stringify(cols)}`);
200
+ }
201
+ }
202
+ else if (granularity !== undefined) {
203
+ throw new MapError(`${at}: granularity belongs to data-skipping indexes, not ${method}`);
204
+ }
205
+ if (method === 'set') {
206
+ const [low, high] = SET_ROWS_RANGE;
207
+ if (!isInteger(maxRows) || maxRows < low || maxRows > high) {
208
+ throw new MapError(`${at}: a set index needs an integer max_rows from ${low} to ${high}; found ` +
209
+ `${show(maxRows)}. Zero means unlimited in ClickHouse, which is not a choice this ` +
210
+ 'format offers.');
211
+ }
212
+ }
213
+ else if (maxRows !== undefined) {
214
+ throw new MapError(`${at}: max_rows belongs to set indexes, not ${method}`);
215
+ }
216
+ out.push({ ...index });
217
+ });
218
+ return out;
219
+ }
220
+ /**
221
+ * The two rules that need the model: a permutation of the key, and a partition on a key column.
222
+ *
223
+ * A renderer without the model repeats the key half against the keys it is given (`effectiveKey`,
224
+ * `partitionExpression`), which keeps the data rule true for a caller that skipped the model.
225
+ */
226
+ export function checkAgainstModel(where, entity, key, fieldTypes, keyOrder, partition) {
227
+ if (keyOrder !== undefined && !samePermutation(keyOrder, key)) {
228
+ throw new MapError(`${where}: key_order['${entity}'] is ${JSON.stringify(keyOrder)} and the declared key is ` +
229
+ `${JSON.stringify(key)}. A key order reorders the key; it cannot add, drop or replace a ` +
230
+ 'column, because the key is what makes a row the same row in every engine.');
231
+ }
232
+ if (partition !== undefined) {
233
+ const field = partition.field;
234
+ if (!key.includes(field)) {
235
+ throw new MapError(`${where}: partition_by['${entity}'] partitions on '${field}', which is not in the key ` +
236
+ `${JSON.stringify(key)}. ClickHouse collapses rows of one key only inside one ` +
237
+ 'partition, so two writes of one key could land in two partitions and stay two rows ' +
238
+ 'physically for ever - measured: after OPTIMIZE FINAL both remained.');
239
+ }
240
+ const kind = Object.hasOwn(fieldTypes, field) ? fieldTypes[field] : undefined;
241
+ if (kind === undefined || !TEMPORAL_TYPES.includes(kind)) {
242
+ throw new MapError(`${where}: partition_by['${entity}'] partitions on '${field}', which is ${show(kind)}; a ` +
243
+ `time partition needs one of ${JSON.stringify(TEMPORAL_TYPES)}.`);
244
+ }
245
+ }
246
+ }
247
+ function samePermutation(left, right) {
248
+ if (left.length !== right.length)
249
+ return false;
250
+ const a = [...left].sort(compareCodePoints);
251
+ const b = [...right].sort(compareCodePoints);
252
+ return a.every((value, position) => value === b[position]);
253
+ }
254
+ /** The key in physical order: `key_order` when present, the declared order otherwise. */
255
+ export function effectiveKey(where, entity, key, keyOrder, error = MapError) {
256
+ const ordered = Object.hasOwn(keyOrder, entity) ? keyOrder[entity] : undefined;
257
+ if (ordered === undefined)
258
+ return [...key];
259
+ if (!samePermutation(ordered, key)) {
260
+ throw new error(`${where}: key_order['${entity}'] is ${JSON.stringify(ordered)} and the key is ` +
261
+ `${JSON.stringify(key)}. A key order must be a permutation of the key.`);
262
+ }
263
+ return [...ordered];
264
+ }
265
+ /** `[function, field]` for a ClickHouse partition, after the key rule is checked again. */
266
+ export function partitionExpression(where, entity, key, partition, error = MapError) {
267
+ if (partition === undefined)
268
+ return null;
269
+ if (!key.includes(partition.field)) {
270
+ throw new error(`${where}: partition_by['${entity}'] partitions on '${partition.field}', outside the key ` +
271
+ `${JSON.stringify(key)}; duplicates of one key would survive merges in two partitions.`);
272
+ }
273
+ const fn = PARTITION_FUNCTIONS[partition.granularity];
274
+ if (fn === undefined)
275
+ throw new error(`${where}: unknown partition granularity ${partition.granularity}`);
276
+ return [fn, partition.field];
277
+ }
278
+ /**
279
+ * What a dialect renders, for whoever has to propose a physical design for it.
280
+ *
281
+ * The control plane hands the reference's version of this to a model; this port exists so that a
282
+ * TypeScript caller asking the same question gets the same answer, key for key.
283
+ */
284
+ export function capabilities(dialect) {
285
+ const methodsOf = Object.hasOwn(METHODS_BY_DIALECT, dialect) ? METHODS_BY_DIALECT[dialect] : undefined;
286
+ if (methodsOf === undefined)
287
+ return { physical_design: false };
288
+ const methods = {};
289
+ for (const method of methodsOf) {
290
+ const entry = {};
291
+ if (CLICKHOUSE_METHODS.includes(method)) {
292
+ entry['granularity'] = [...GRANULARITY_RANGE];
293
+ entry['columns'] = 1;
294
+ }
295
+ if (method === 'set')
296
+ entry['max_rows'] = [...SET_ROWS_RANGE];
297
+ methods[method] = entry;
298
+ }
299
+ return {
300
+ physical_design: true,
301
+ key_order: true,
302
+ partition_granularities: PARTITIONING_DIALECTS.has(dialect) ? [...GRANULARITIES] : [],
303
+ partition_on: 'a key column of type date or timestamptz',
304
+ index_methods: methods,
305
+ };
306
+ }
307
+ export function describeFinding(finding) {
308
+ return `${finding.table}: ${finding.aspect} is ${finding.found} and the map declares ${finding.declared}`;
309
+ }
310
+ /** The physical expectations of every table a layout names, in table order. */
311
+ export function declaredTables(layout, keys) {
312
+ const out = [];
313
+ const entries = Object.entries(layout.tables).sort(([, a], [, b]) => compareCodePoints(a, b));
314
+ const indexes = [...layout.indexes].sort((a, b) => compareCodePoints(String(a['name']), String(b['name'])));
315
+ for (const [entity, table] of entries) {
316
+ const key = Object.hasOwn(keys, entity) ? [...(keys[entity] ?? [])] : [];
317
+ const where = `table '${table}'`;
318
+ const ordered = effectiveKey(where, entity, key, layout.keyOrder ?? {});
319
+ const spec = Object.hasOwn(layout.partitionBy, entity) ? layout.partitionBy[entity] : undefined;
320
+ const partition = partitionExpression(where, entity, key, spec);
321
+ const declared = [];
322
+ for (const index of indexes) {
323
+ if (String(index['entity']) !== entity)
324
+ continue;
325
+ const method = indexMethod(index);
326
+ const granularity = index['granularity'];
327
+ declared.push({
328
+ name: String(index['name']),
329
+ method,
330
+ columns: index['columns'].map(String),
331
+ granularity: typeof granularity === 'number' ? granularity : null,
332
+ typeFull: method === 'set' ? `set(${String(index['max_rows'])})` : method,
333
+ });
334
+ }
335
+ out.push({ table, key: ordered, partition, indexes: declared });
336
+ }
337
+ return out;
338
+ }
339
+ const BARE = /[A-Za-z_][A-Za-z0-9_]*/y;
340
+ /**
341
+ * ``a, `b c`, d`` -> `["a", "b c", "d"]`: names as ClickHouse's catalogue writes them.
342
+ *
343
+ * A name is bare or backtick-quoted with a backslash escaping the next character - the rule this
344
+ * library writes. Anything else throws: an expression the parser does not understand is not
345
+ * evidence that the table matches.
346
+ */
347
+ export function parseIdentifierList(text) {
348
+ const names = [];
349
+ let position = 0;
350
+ const length = text.length;
351
+ while (position < length) {
352
+ if (text[position] === '`') {
353
+ position += 1;
354
+ let name = '';
355
+ for (;;) {
356
+ if (position >= length)
357
+ throw new Error(`unterminated quoted name in ${JSON.stringify(text)}`);
358
+ const char = text[position];
359
+ if (char === '\\') {
360
+ if (position + 1 >= length)
361
+ throw new Error(`dangling escape in ${JSON.stringify(text)}`);
362
+ name += text[position + 1];
363
+ position += 2;
364
+ continue;
365
+ }
366
+ if (char === '`') {
367
+ position += 1;
368
+ break;
369
+ }
370
+ name += char;
371
+ position += 1;
372
+ }
373
+ names.push(name);
374
+ }
375
+ else {
376
+ BARE.lastIndex = position;
377
+ const match = BARE.exec(text);
378
+ if (match === null)
379
+ throw new Error(`not a list of column names: ${JSON.stringify(text)}`);
380
+ names.push(match[0]);
381
+ position = BARE.lastIndex;
382
+ }
383
+ if (position < length) {
384
+ // A separator is only ever between two names: ", " at the end is not a list.
385
+ if (!text.startsWith(', ', position) || position + 2 >= length) {
386
+ throw new Error(`not a list of column names: ${JSON.stringify(text)}`);
387
+ }
388
+ position += 2;
389
+ }
390
+ }
391
+ return names;
392
+ }
393
+ /** ``toYYYYMM(`at`)`` -> `["toYYYYMM", "at"]`; an empty key -> `null`. */
394
+ export function parsePartitionKey(text) {
395
+ if (text === '')
396
+ return null;
397
+ const match = /^([A-Za-z][A-Za-z0-9]*)\((.*)\)$/s.exec(text);
398
+ if (match === null)
399
+ throw new Error(`not a single-function partition key: ${JSON.stringify(text)}`);
400
+ const names = parseIdentifierList(match[2]);
401
+ if (names.length !== 1)
402
+ throw new Error(`not a single-function partition key: ${JSON.stringify(text)}`);
403
+ return [match[1], names[0]];
404
+ }
405
+ /**
406
+ * Throw when a table differs physically. Provisioning calls this; sessions do not.
407
+ *
408
+ * A session only reports (`session.physical`): the difference is performance, and turning it into
409
+ * the application's outage is what requirement 3.6 forbids. Provisioning is where a person applying
410
+ * a map can act on it.
411
+ */
412
+ export function refuseFindings(findings, error) {
413
+ if (findings.length === 0)
414
+ return;
415
+ const details = findings.map(describeFinding).join('; ');
416
+ throw new error(`existing tables differ from the physical design this map declares: ${details}. ` +
417
+ '`CREATE ... IF NOT EXISTS` keeps whatever table or index already has the name, so this ' +
418
+ 'came from an earlier map or from outside SDE. A new layout needs fresh tables (staging), ' +
419
+ 'not the old ones under the new declaration.');
420
+ }
421
+ //# sourceMappingURL=physical.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"physical.js","sourceRoot":"","sources":["../src/physical.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AACtC,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAA;AAElD,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,CAAA;AACtC,gGAAgG;AAEhG,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,CAAU,CAAA;AAC9D;;;GAGG;AAEH,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,MAAM,EAAE,aAAa,CAAU,CAAA;AAC9D;;;;GAIG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,MAAM,EAAE,OAAO,CAAU,CAAA;AAC1D,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,cAAc,EAAE,QAAQ,EAAE,KAAK,CAAU,CAAA;AAC5E,+FAA+F;AAE/F,MAAM,CAAC,MAAM,aAAa,GAAsB,CAAC,GAAG,gBAAgB,EAAE,GAAG,kBAAkB,CAAC,CAAC,IAAI,CAC/F,iBAAiB,CAClB,CAAA;AAED,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,CAAC,EAAE,IAAI,CAAU,CAAA;AACnD,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,CAAC,EAAE,KAAK,CAAU,CAAA;AACjD,kGAAkG;AAElG,MAAM,iBAAiB,GAAwB,IAAI,GAAG,CAAC,CAAC,SAAS,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAA;AACrF,MAAM,gBAAgB,GAAwB,IAAI,GAAG,CAAC,CAAC,aAAa,EAAE,UAAU,EAAE,QAAQ,CAAC,CAAC,CAAA;AAC5F,MAAM,UAAU,GAAwB,IAAI,GAAG,CAAC,CAAC,GAAG,iBAAiB,EAAE,GAAG,gBAAgB,CAAC,CAAC,CAAA;AAE5F,MAAM,CAAC,MAAM,mBAAmB,GAAqC,MAAM,CAAC,MAAM,CAAC;IACjF,GAAG,EAAE,QAAQ;IACb,KAAK,EAAE,UAAU;IACjB,IAAI,EAAE,QAAQ;CACf,CAAC,CAAA;AACF,4EAA4E;AAE5E,MAAM,CAAC,MAAM,qBAAqB,GAAwB,IAAI,GAAG,CAAC,CAAC,YAAY,CAAC,CAAC,CAAA;AACjF;;;;GAIG;AAEH,MAAM,CAAC,MAAM,kBAAkB,GAAgD,MAAM,CAAC,MAAM,CAAC;IAC3F,UAAU,EAAE,kBAAkB;IAC9B,QAAQ,EAAE,gBAAgB;CAC3B,CAAC,CAAA;AAMF,SAAS,QAAQ,CAAC,KAAc;IAC9B,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAA;AAC7E,CAAC;AAED,SAAS,SAAS,CAAC,KAAc;IAC/B,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,CAAA;AAC7D,CAAC;AAED,SAAS,IAAI,CAAC,KAAc;IAC1B,OAAO,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAA;AAClE,CAAC;AAED,SAAS,UAAU,CAAC,KAA8B;IAChD,OAAO,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAA;AACnD,CAAC;AAED,uFAAuF;AACvF,MAAM,UAAU,WAAW,CAAC,KAAwC;IAClE,OAAO,KAAK,CAAC,QAAQ,CAAC,KAAK,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAA;AAC1E,CAAC;AAED,SAAS,aAAa,CAAC,KAAc;IACnC,OAAO,CACL,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QACpB,KAAK,CAAC,MAAM,GAAG,CAAC;QAChB,KAAK,CAAC,KAAK,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CACzE,CAAA;AACH,CAAC;AAED,8EAA8E;AAC9E,MAAM,UAAU,aAAa,CAC3B,GAAY,EACZ,KAAa,EACb,MAAwC;IAExC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC;QAAE,MAAM,IAAI,QAAQ,CAAC,GAAG,KAAK,yDAAyD,CAAC,CAAA;IACzG,MAAM,GAAG,GAAsC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;IAClE,KAAK,MAAM,MAAM,IAAI,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QACrC,MAAM,OAAO,GAAG,GAAG,CAAC,MAAM,CAAC,CAAA;QAC3B,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC;YACnC,MAAM,IAAI,QAAQ,CAChB,GAAG,KAAK,sBAAsB,MAAM,+CAA+C;gBACjF,GAAG,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,GAAG,CAC3C,CAAA;QACH,CAAC;QACD,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,EAAE,CAAC;YAC5B,MAAM,IAAI,QAAQ,CAAC,GAAG,KAAK,gBAAgB,MAAM,6CAA6C,CAAC,CAAA;QACjG,CAAC;QACD,IAAI,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC,IAAI,KAAK,OAAO,CAAC,MAAM,EAAE,CAAC;YAC7C,MAAM,IAAI,QAAQ,CAChB,GAAG,KAAK,gBAAgB,MAAM,4BAA4B,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,UAAU;gBACzF,6EAA6E,CAChF,CAAA;QACH,CAAC;QACD,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,OAAO,CAAC,CAAA;IAC5B,CAAC;IACD,OAAO,GAAG,CAAA;AACZ,CAAC;AAED,wFAAwF;AACxF,MAAM,UAAU,gBAAgB,CAC9B,GAAY,EACZ,KAAa,EACb,MAAwC;IAExC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QACnB,MAAM,IAAI,QAAQ,CAAC,GAAG,KAAK,gEAAgE,CAAC,CAAA;IAC9F,CAAC;IACD,MAAM,GAAG,GAAkC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;IAC9D,KAAK,MAAM,MAAM,IAAI,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QACrC,MAAM,IAAI,GAAG,GAAG,CAAC,MAAM,CAAC,CAAA;QACxB,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC;YACnC,MAAM,IAAI,QAAQ,CAChB,GAAG,KAAK,yBAAyB,MAAM,+CAA+C;gBACpF,GAAG,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,GAAG,CAC3C,CAAA;QACH,CAAC;QACD,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;QACrD,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,OAAO,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,aAAa,EAAE,CAAC;YAC3F,MAAM,IAAI,QAAQ,CAChB,GAAG,KAAK,mBAAmB,MAAM,yDAAyD;gBACxF,cAAc,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI;gBACrG,uEAAuE,CAC1E,CAAA;QACH,CAAC;QACD,MAAM,MAAM,GAAG,IAA+B,CAAA;QAC9C,MAAM,KAAK,GAAG,MAAM,CAAC,OAAO,CAAC,CAAA;QAC7B,MAAM,WAAW,GAAG,MAAM,CAAC,aAAa,CAAC,CAAA;QACzC,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACpD,MAAM,IAAI,QAAQ,CAAC,GAAG,KAAK,mBAAmB,MAAM,6BAA6B,CAAC,CAAA;QACpF,CAAC;QACD,IAAI,OAAO,WAAW,KAAK,QAAQ,IAAI,CAAE,aAAmC,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC;YACnG,MAAM,IAAI,QAAQ,CAChB,GAAG,KAAK,mBAAmB,MAAM,qBAAqB,IAAI,CAAC,WAAW,CAAC,iBAAiB;gBACtF,GAAG,IAAI,CAAC,SAAS,CAAC,aAAa,CAAC,GAAG,CACtC,CAAA;QACH,CAAC;QACD,GAAG,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC,CAAA;IACrD,CAAC;IACD,OAAO,GAAG,CAAA;AACZ,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,YAAY,CAC1B,GAAY,EACZ,KAAa,EACb,MAAwC,EACxC,OAAmE,EACnE,QAAgB;IAEhB,IAAI,GAAG,KAAK,SAAS,IAAI,GAAG,KAAK,IAAI;QAAE,OAAO,EAAE,CAAA;IAChD,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC;QAAE,MAAM,IAAI,QAAQ,CAAC,GAAG,KAAK,0CAA0C,CAAC,CAAA;IAC/F,MAAM,OAAO,GAAG,QAAQ,IAAI,qBAAqB,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,iBAAiB,CAAA;IAClF,MAAM,GAAG,GAAwC,EAAE,CAAA;IACnD,MAAM,KAAK,GAAG,IAAI,GAAG,EAAU,CAAA;IAC/B,GAAG,CAAC,OAAO,CAAC,CAAC,KAAc,EAAE,QAAgB,EAAE,EAAE;QAC/C,MAAM,EAAE,GAAG,GAAG,KAAK,aAAa,QAAQ,GAAG,CAAA;QAC3C,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC;YAAE,MAAM,IAAI,QAAQ,CAAC,GAAG,EAAE,oBAAoB,CAAC,CAAA;QACnE,MAAM,OAAO,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAA;QACpE,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACvB,MAAM,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,gBAAgB,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAA;YAChE,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACrB,MAAM,IAAI,QAAQ,CAChB,GAAG,EAAE,SAAS,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,kCAAkC,qBAAqB,GAAG;oBAC3F,gDAAgD,QAAQ,+BAA+B;oBACvF,qFAAqF;oBACrF,+CAA+C,CAClD,CAAA;YACH,CAAC;YACD,MAAM,IAAI,QAAQ,CAAC,GAAG,EAAE,0CAA0C,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE,CAAC,CAAA;QAC9F,CAAC;QACD,MAAM,MAAM,GAAG,KAAK,CAAC,QAAQ,CAAC,CAAA;QAC9B,MAAM,IAAI,GAAG,KAAK,CAAC,MAAM,CAAC,CAAA;QAC1B,MAAM,IAAI,GAAG,KAAK,CAAC,SAAS,CAAC,CAAA;QAC7B,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC;YACjE,MAAM,IAAI,QAAQ,CAChB,GAAG,EAAE,iBAAiB,IAAI,CAAC,MAAM,CAAC,8CAA8C;gBAC9E,GAAG,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,GAAG,CAC3C,CAAA;QACH,CAAC;QACD,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;YAAE,MAAM,IAAI,QAAQ,CAAC,GAAG,EAAE,yBAAyB,CAAC,CAAA;QACrG,IAAI,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC;YAAE,MAAM,IAAI,QAAQ,CAAC,GAAG,EAAE,2BAA2B,IAAI,GAAG,CAAC,CAAA;QAChF,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;QACf,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,IAAI,GAAG,CAAC,IAAI,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,MAAM,EAAE,CAAC;YAC/D,MAAM,IAAI,QAAQ,CAAC,GAAG,EAAE,kDAAkD,CAAC,CAAA;QAC7E,CAAC;QACD,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;QAC7E,IAAI,QAAQ,KAAK,SAAS,IAAI,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC/D,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAA;YACzE,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACvB,MAAM,IAAI,QAAQ,CAChB,GAAG,EAAE,YAAY,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,YAAY,MAAM,0BAA0B;oBAClF,oFAAoF;oBACpF,yCAAyC,CAC5C,CAAA;YACH,CAAC;QACH,CAAC;QACD,MAAM,MAAM,GAAG,KAAK,CAAC,QAAQ,CAAC,KAAK,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAA;QACxE,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;YAClE,MAAM,IAAI,QAAQ,CAAC,GAAG,EAAE,eAAe,IAAI,CAAC,MAAM,CAAC,qBAAqB,IAAI,CAAC,SAAS,CAAC,aAAa,CAAC,EAAE,CAAC,CAAA;QAC1G,CAAC;QACD,MAAM,WAAW,GAAG,KAAK,CAAC,aAAa,CAAC,CAAA;QACxC,MAAM,OAAO,GAAG,KAAK,CAAC,UAAU,CAAC,CAAA;QACjC,IAAK,kBAAwC,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;YAC/D,MAAM,CAAC,GAAG,EAAE,IAAI,CAAC,GAAG,iBAAiB,CAAA;YACrC,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,IAAI,WAAW,GAAG,GAAG,IAAI,WAAW,GAAG,IAAI,EAAE,CAAC;gBACvE,MAAM,IAAI,QAAQ,CAChB,GAAG,EAAE,OAAO,MAAM,4CAA4C,GAAG,OAAO,IAAI,UAAU;oBACpF,IAAI,CAAC,WAAW,CAAC,CACpB,CAAA;YACH,CAAC;YACD,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACtB,MAAM,IAAI,QAAQ,CAAC,GAAG,EAAE,OAAO,MAAM,+CAA+C,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;YAC7G,CAAC;QACH,CAAC;aAAM,IAAI,WAAW,KAAK,SAAS,EAAE,CAAC;YACrC,MAAM,IAAI,QAAQ,CAAC,GAAG,EAAE,uDAAuD,MAAM,EAAE,CAAC,CAAA;QAC1F,CAAC;QACD,IAAI,MAAM,KAAK,KAAK,EAAE,CAAC;YACrB,MAAM,CAAC,GAAG,EAAE,IAAI,CAAC,GAAG,cAAc,CAAA;YAClC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,OAAO,GAAG,GAAG,IAAI,OAAO,GAAG,IAAI,EAAE,CAAC;gBAC3D,MAAM,IAAI,QAAQ,CAChB,GAAG,EAAE,gDAAgD,GAAG,OAAO,IAAI,UAAU;oBAC3E,GAAG,IAAI,CAAC,OAAO,CAAC,mEAAmE;oBACnF,gBAAgB,CACnB,CAAA;YACH,CAAC;QACH,CAAC;aAAM,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;YACjC,MAAM,IAAI,QAAQ,CAAC,GAAG,EAAE,0CAA0C,MAAM,EAAE,CAAC,CAAA;QAC7E,CAAC;QACD,GAAG,CAAC,IAAI,CAAC,EAAE,GAAG,KAAK,EAAE,CAAC,CAAA;IACxB,CAAC,CAAC,CAAA;IACF,OAAO,GAAG,CAAA;AACZ,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,iBAAiB,CAC/B,KAAa,EACb,MAAc,EACd,GAAsB,EACtB,UAA4C,EAC5C,QAAuC,EACvC,SAAoC;IAEpC,IAAI,QAAQ,KAAK,SAAS,IAAI,CAAC,eAAe,CAAC,QAAQ,EAAE,GAAG,CAAC,EAAE,CAAC;QAC9D,MAAM,IAAI,QAAQ,CAChB,GAAG,KAAK,gBAAgB,MAAM,SAAS,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,2BAA2B;YACxF,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,mEAAmE;YACzF,2EAA2E,CAC9E,CAAA;IACH,CAAC;IACD,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;QAC5B,MAAM,KAAK,GAAG,SAAS,CAAC,KAAK,CAAA;QAC7B,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;YACzB,MAAM,IAAI,QAAQ,CAChB,GAAG,KAAK,mBAAmB,MAAM,qBAAqB,KAAK,6BAA6B;gBACtF,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,yDAAyD;gBAC/E,qFAAqF;gBACrF,qEAAqE,CACxE,CAAA;QACH,CAAC;QACD,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;QAC7E,IAAI,IAAI,KAAK,SAAS,IAAI,CAAE,cAAoC,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;YAChF,MAAM,IAAI,QAAQ,CAChB,GAAG,KAAK,mBAAmB,MAAM,qBAAqB,KAAK,eAAe,IAAI,CAAC,IAAI,CAAC,MAAM;gBACxF,+BAA+B,IAAI,CAAC,SAAS,CAAC,cAAc,CAAC,GAAG,CACnE,CAAA;QACH,CAAC;IACH,CAAC;AACH,CAAC;AAED,SAAS,eAAe,CAAC,IAAuB,EAAE,KAAwB;IACxE,IAAI,IAAI,CAAC,MAAM,KAAK,KAAK,CAAC,MAAM;QAAE,OAAO,KAAK,CAAA;IAC9C,MAAM,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAA;IAC3C,MAAM,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAA;IAC5C,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,QAAQ,EAAE,EAAE,CAAC,KAAK,KAAK,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAA;AAC5D,CAAC;AAED,yFAAyF;AACzF,MAAM,UAAU,YAAY,CAC1B,KAAa,EACb,MAAc,EACd,GAAsB,EACtB,QAAqD,EACrD,QAAoB,QAAQ;IAE5B,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;IAC9E,IAAI,OAAO,KAAK,SAAS;QAAE,OAAO,CAAC,GAAG,GAAG,CAAC,CAAA;IAC1C,IAAI,CAAC,eAAe,CAAC,OAAO,EAAE,GAAG,CAAC,EAAE,CAAC;QACnC,MAAM,IAAI,KAAK,CACb,GAAG,KAAK,gBAAgB,MAAM,SAAS,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,kBAAkB;YAC9E,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,iDAAiD,CAC1E,CAAA;IACH,CAAC;IACD,OAAO,CAAC,GAAG,OAAO,CAAC,CAAA;AACrB,CAAC;AAED,2FAA2F;AAC3F,MAAM,UAAU,mBAAmB,CACjC,KAAa,EACb,MAAc,EACd,GAAsB,EACtB,SAAoC,EACpC,QAAoB,QAAQ;IAE5B,IAAI,SAAS,KAAK,SAAS;QAAE,OAAO,IAAI,CAAA;IACxC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC;QACnC,MAAM,IAAI,KAAK,CACb,GAAG,KAAK,mBAAmB,MAAM,qBAAqB,SAAS,CAAC,KAAK,qBAAqB;YACxF,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,iEAAiE,CAC1F,CAAA;IACH,CAAC;IACD,MAAM,EAAE,GAAG,mBAAmB,CAAC,SAAS,CAAC,WAAW,CAAC,CAAA;IACrD,IAAI,EAAE,KAAK,SAAS;QAAE,MAAM,IAAI,KAAK,CAAC,GAAG,KAAK,mCAAmC,SAAS,CAAC,WAAW,EAAE,CAAC,CAAA;IACzG,OAAO,CAAC,EAAE,EAAE,SAAS,CAAC,KAAK,CAAC,CAAA;AAC9B,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,YAAY,CAAC,OAAe;IAC1C,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,CAAC,kBAAkB,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,kBAAkB,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;IACtG,IAAI,SAAS,KAAK,SAAS;QAAE,OAAO,EAAE,eAAe,EAAE,KAAK,EAAE,CAAA;IAC9D,MAAM,OAAO,GAA4B,EAAE,CAAA;IAC3C,KAAK,MAAM,MAAM,IAAI,SAAS,EAAE,CAAC;QAC/B,MAAM,KAAK,GAA4B,EAAE,CAAA;QACzC,IAAK,kBAAwC,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;YAC/D,KAAK,CAAC,aAAa,CAAC,GAAG,CAAC,GAAG,iBAAiB,CAAC,CAAA;YAC7C,KAAK,CAAC,SAAS,CAAC,GAAG,CAAC,CAAA;QACtB,CAAC;QACD,IAAI,MAAM,KAAK,KAAK;YAAE,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,cAAc,CAAC,CAAA;QAC7D,OAAO,CAAC,MAAM,CAAC,GAAG,KAAK,CAAA;IACzB,CAAC;IACD,OAAO;QACL,eAAe,EAAE,IAAI;QACrB,SAAS,EAAE,IAAI;QACf,uBAAuB,EAAE,qBAAqB,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,aAAa,CAAC,CAAC,CAAC,CAAC,EAAE;QACrF,YAAY,EAAE,0CAA0C;QACxD,aAAa,EAAE,OAAO;KACvB,CAAA;AACH,CAAC;AAkBD,MAAM,UAAU,eAAe,CAAC,OAAwB;IACtD,OAAO,GAAG,OAAO,CAAC,KAAK,KAAK,OAAO,CAAC,MAAM,OAAO,OAAO,CAAC,KAAK,yBAAyB,OAAO,CAAC,QAAQ,EAAE,CAAA;AAC3G,CAAC;AAwBD,+EAA+E;AAC/E,MAAM,UAAU,cAAc,CAC5B,MAAsB,EACtB,IAAiD;IAEjD,MAAM,GAAG,GAAoB,EAAE,CAAA;IAC/B,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAA;IAC7F,MAAM,OAAO,GAAG,CAAC,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAA;IAC3G,KAAK,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,IAAI,OAAO,EAAE,CAAC;QACtC,MAAM,GAAG,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAA;QACxE,MAAM,KAAK,GAAG,UAAU,KAAK,GAAG,CAAA;QAChC,MAAM,OAAO,GAAG,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAA;QACvE,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;QAC/F,MAAM,SAAS,GAAG,mBAAmB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,CAAC,CAAA;QAC/D,MAAM,QAAQ,GAAoB,EAAE,CAAA;QACpC,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;YAC5B,IAAI,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,KAAK,MAAM;gBAAE,SAAQ;YAChD,MAAM,MAAM,GAAG,WAAW,CAAC,KAAK,CAAC,CAAA;YACjC,MAAM,WAAW,GAAG,KAAK,CAAC,aAAa,CAAC,CAAA;YACxC,QAAQ,CAAC,IAAI,CAAC;gBACZ,IAAI,EAAE,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;gBAC3B,MAAM;gBACN,OAAO,EAAG,KAAK,CAAC,SAAS,CAAe,CAAC,GAAG,CAAC,MAAM,CAAC;gBACpD,WAAW,EAAE,OAAO,WAAW,KAAK,QAAQ,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI;gBACjE,QAAQ,EAAE,MAAM,KAAK,KAAK,CAAC,CAAC,CAAC,OAAO,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM;aAC1E,CAAC,CAAA;QACJ,CAAC;QACD,GAAG,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,CAAA;IACjE,CAAC;IACD,OAAO,GAAG,CAAA;AACZ,CAAC;AAED,MAAM,IAAI,GAAG,yBAAyB,CAAA;AAEtC;;;;;;GAMG;AACH,MAAM,UAAU,mBAAmB,CAAC,IAAY;IAC9C,MAAM,KAAK,GAAa,EAAE,CAAA;IAC1B,IAAI,QAAQ,GAAG,CAAC,CAAA;IAChB,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAA;IAC1B,OAAO,QAAQ,GAAG,MAAM,EAAE,CAAC;QACzB,IAAI,IAAI,CAAC,QAAQ,CAAC,KAAK,GAAG,EAAE,CAAC;YAC3B,QAAQ,IAAI,CAAC,CAAA;YACb,IAAI,IAAI,GAAG,EAAE,CAAA;YACb,SAAS,CAAC;gBACR,IAAI,QAAQ,IAAI,MAAM;oBAAE,MAAM,IAAI,KAAK,CAAC,+BAA+B,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;gBAC9F,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,CAAE,CAAA;gBAC5B,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;oBAClB,IAAI,QAAQ,GAAG,CAAC,IAAI,MAAM;wBAAE,MAAM,IAAI,KAAK,CAAC,sBAAsB,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;oBACzF,IAAI,IAAI,IAAI,CAAC,QAAQ,GAAG,CAAC,CAAE,CAAA;oBAC3B,QAAQ,IAAI,CAAC,CAAA;oBACb,SAAQ;gBACV,CAAC;gBACD,IAAI,IAAI,KAAK,GAAG,EAAE,CAAC;oBACjB,QAAQ,IAAI,CAAC,CAAA;oBACb,MAAK;gBACP,CAAC;gBACD,IAAI,IAAI,IAAI,CAAA;gBACZ,QAAQ,IAAI,CAAC,CAAA;YACf,CAAC;YACD,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QAClB,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,SAAS,GAAG,QAAQ,CAAA;YACzB,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;YAC7B,IAAI,KAAK,KAAK,IAAI;gBAAE,MAAM,IAAI,KAAK,CAAC,+BAA+B,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;YAC1F,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAA;YACpB,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAA;QAC3B,CAAC;QACD,IAAI,QAAQ,GAAG,MAAM,EAAE,CAAC;YACtB,6EAA6E;YAC7E,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,EAAE,QAAQ,CAAC,IAAI,QAAQ,GAAG,CAAC,IAAI,MAAM,EAAE,CAAC;gBAC/D,MAAM,IAAI,KAAK,CAAC,+BAA+B,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;YACxE,CAAC;YACD,QAAQ,IAAI,CAAC,CAAA;QACf,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAA;AACd,CAAC;AAED,0EAA0E;AAC1E,MAAM,UAAU,iBAAiB,CAAC,IAAY;IAC5C,IAAI,IAAI,KAAK,EAAE;QAAE,OAAO,IAAI,CAAA;IAC5B,MAAM,KAAK,GAAG,mCAAmC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IAC5D,IAAI,KAAK,KAAK,IAAI;QAAE,MAAM,IAAI,KAAK,CAAC,wCAAwC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;IACnG,MAAM,KAAK,GAAG,mBAAmB,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC,CAAA;IAC5C,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,wCAAwC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;IACvG,OAAO,CAAC,KAAK,CAAC,CAAC,CAAE,EAAE,KAAK,CAAC,CAAC,CAAE,CAAC,CAAA;AAC/B,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,cAAc,CAAC,QAAoC,EAAE,KAAiB;IACpF,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;QAAE,OAAM;IACjC,MAAM,OAAO,GAAG,QAAQ,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IACxD,MAAM,IAAI,KAAK,CACb,sEAAsE,OAAO,IAAI;QAC/E,yFAAyF;QACzF,2FAA2F;QAC3F,6CAA6C,CAChD,CAAA;AACH,CAAC"}
@@ -0,0 +1,157 @@
1
+ /**
2
+ * The placement map: where every group lives, and where every operation goes.
3
+ *
4
+ * The only instruction this library takes from outside, and therefore the one input that refuses
5
+ * rather than degrades. A bad signature, a mismatched model version, an unknown contract version:
6
+ * all of them stop the library from starting, because the map decides where data is written.
7
+ *
8
+ * An unsigned map is valid - that is the no-account mode, and it is a supported way to use this
9
+ * library rather than a gap. What is refused is a map carrying a signature, and therefore claiming to
10
+ * come from us, when there is no key to check the claim against.
11
+ */
12
+ import type { LogicalModel } from './model.js';
13
+ import type { PartitionSpec } from './physical.js';
14
+ export interface PhysicalLayout {
15
+ readonly tables: Readonly<Record<string, string>>;
16
+ readonly columns: Readonly<Record<string, Readonly<Record<string, string>>>>;
17
+ readonly indexes: readonly Readonly<Record<string, unknown>>[];
18
+ /** Entity -> `{field, granularity}`, contract 5. See `physical.ts`. */
19
+ readonly partitionBy: Readonly<Record<string, PartitionSpec>>;
20
+ /**
21
+ * Entity -> its key columns in physical order, contract 5. Absent: the declared order.
22
+ *
23
+ * Optional in the type because a layout written by hand before contract 5 has no reason to carry
24
+ * it, and absent means exactly what every earlier map meant.
25
+ */
26
+ readonly keyOrder?: Readonly<Record<string, readonly string[]>>;
27
+ }
28
+ export interface Materialization {
29
+ readonly id: string;
30
+ readonly engine: string;
31
+ readonly layout: PhysicalLayout;
32
+ readonly lagBudgetMs: number | null;
33
+ }
34
+ export interface GroupPlacement {
35
+ readonly group: string;
36
+ readonly source: Materialization;
37
+ readonly derived: readonly Materialization[];
38
+ /**
39
+ * Derived copies that writes are **also** sent to, additionally and never authoritatively.
40
+ *
41
+ * This is how a migration reaches a library, and the reason no phase name appears anywhere in a
42
+ * map. A library does not need to know what `DUAL_WRITE` means; it needs to know where writes go
43
+ * and where reads go, and both were already things a map says. The phase in the document as well
44
+ * would be a second representation of a fact the fan-out and the routing table already carry.
45
+ *
46
+ * This runtime has no engine adapters, so it never performs the fan-out - and it parses and
47
+ * refuses exactly as the reference implementation does, because a fan-out target read differently
48
+ * in two languages is a row written to one copy and not the other.
49
+ */
50
+ readonly alsoWrite: readonly Materialization[];
51
+ readonly writeEpoch?: number | undefined;
52
+ }
53
+ export interface PlacementMap {
54
+ readonly contract: number;
55
+ readonly modelVersion: string;
56
+ readonly mapVersion: number;
57
+ readonly groups: Readonly<Record<string, GroupPlacement>>;
58
+ readonly routing: Readonly<Record<string, string>>;
59
+ readonly signed: boolean;
60
+ /**
61
+ * Which of the caller's public keys verified this map, by the caller's own name for it.
62
+ *
63
+ * `null` for an unsigned map and also for one verified against a bare key, where there was no
64
+ * name to report; `signed` tells those apart.
65
+ *
66
+ * Public because a rotation needs it. Adding a key is safe and reversible; **removing** one is
67
+ * the irreversible half, and a client cannot know when the old key is safe to drop without
68
+ * seeing which key the maps they are actually receiving were signed with.
69
+ */
70
+ readonly projectId?: string | undefined;
71
+ readonly fingerprint?: string | undefined;
72
+ readonly verifiedWith: string | null;
73
+ }
74
+ export interface LoadOptions {
75
+ readonly model?: LogicalModel;
76
+ /**
77
+ * Raw 32-byte Ed25519 public key, or several of them under the caller's own names.
78
+ *
79
+ * The mapping form is what makes a rotation possible without breaking the client: while both
80
+ * keys are configured, maps signed with either are accepted. What a runbook needs is not a key
81
+ * but something to *remove*, and "remove k1" is only an instruction if k1 is what the client
82
+ * wrote in their configuration.
83
+ */
84
+ readonly publicKey?: Uint8Array | Readonly<Record<string, Uint8Array>>;
85
+ readonly requireSignature?: boolean;
86
+ }
87
+ export declare const MAP_CONTRACT = 5;
88
+ /**
89
+ * The placement map's format version, which is not the IR's - see `CONTRACT`.
90
+ *
91
+ * Five since 23 September 2026, for the physical design vocabulary (`physical.ts`): the order of a
92
+ * key, a time partition, and index methods. An earlier library would ignore `"method": "brin"` and
93
+ * build a B-tree from the same document, which is a loosening and therefore a bump. A contract-5
94
+ * library reads contracts 1 to 4 with their meaning unchanged, and refuses the new keys in them.
95
+ *
96
+ * Two because the map gained `also_write`, which a contract-1 library would ignore while a
97
+ * contract-2 one honours it: the same document, two different sets of engines written to, and the
98
+ * difference decided by which version happens to be installed. A loosening bumps the number.
99
+ */
100
+ export declare const ALSO_WRITE_SINCE = 2;
101
+ /**
102
+ * The contract that introduced `also_write`.
103
+ *
104
+ * A document declaring an earlier contract and carrying the key is refused. That is a *tightening*
105
+ * - no bump - and it exists because of who makes the mistake: a producer that grew the key and
106
+ * forgot to raise the number, which is what happened on the control-plane side of the very change
107
+ * that added it.
108
+ */
109
+ export declare const MAP_CONTRACT_FLOOR = 1;
110
+ /**
111
+ * The oldest map format this library still reads.
112
+ *
113
+ * Backwards compatible, forwards strict, and the asymmetry is knowledge rather than kindness: every
114
+ * contract-1 document is a valid contract-2 one with a key absent, which reads as "no dual write"
115
+ * and is a complete meaning. What came after this library cannot be known, so a higher number is
116
+ * refused rather than interpreted.
117
+ */
118
+ export declare const WATERMARK_TABLE = "sde_map_state";
119
+ /**
120
+ * The table the Python library keeps its map bookkeeping in: the highest map version applied
121
+ * against an engine, which is what stops an older signed map being loaded over a newer one.
122
+ *
123
+ * This runtime has no engine adapters, so it never writes that table - and it refuses a layout
124
+ * naming it anyway. The rule is a *parsing* rule, and a parsing rule that holds in one language
125
+ * and not the other is exactly the divergence the conformance suite exists to catch: one map, two
126
+ * libraries, accepted here and refused there. Nothing in this file could have discovered that on
127
+ * its own.
128
+ */
129
+ export declare const BACKFILL_TABLE = "sde_backfill_state";
130
+ /**
131
+ * The table the Python library keeps its backfill progress in: how many rows of each entity a
132
+ * migration has copied into an engine, which is what lets an interrupted backfill resume.
133
+ *
134
+ * The second reserved name, and the reason the refusal below is written over a table of them
135
+ * rather than over one string.
136
+ */
137
+ export declare const RESERVED_TABLES: ReadonlyArray<readonly [string, string]>;
138
+ /**
139
+ * Verify, and report **which** of the caller's keys did it.
140
+ *
141
+ * **Every key is tried, and `key_id` only decides the order.** The signature block is excluded
142
+ * from the signed payload in its entirety, so `key_id` is not covered by the signature and anybody
143
+ * can edit it. Treating it as authoritative would be trusting an attacker's annotation; making it
144
+ * authenticated would change what the payload is, which recomputes every signature ever issued and
145
+ * is a contract bump in every language at once. As an ordering it costs nothing to be wrong about.
146
+ *
147
+ * The cost of accepting a set is real: **an old key verifies for as long as the client keeps it.**
148
+ * This library has no clock, so it cannot expire one - and that same absence is what makes "you
149
+ * stop paying and nothing breaks" true. Revocation is the client removing a key from their own
150
+ * configuration, which is why the id that verified is reported.
151
+ */
152
+ /** Internal shared verifier for signed instruction envelopes; not a package entry point. */
153
+ export declare function verifyMapSignature(raw: Record<string, unknown>, publicKey: Uint8Array | Readonly<Record<string, Uint8Array>>): string | null;
154
+ export declare function loadMap(raw: unknown, options?: LoadOptions): PlacementMap;
155
+ export declare function fingerprintOf(map: PlacementMap): string | undefined;
156
+ export declare function placementOf(map: PlacementMap, group: string): GroupPlacement;
157
+ export declare function materializationById(placement: GroupPlacement, id: string): Materialization;