@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,219 @@
1
+ /** Validate a signed local cutover authorization without adopting a map or touching an engine. */
2
+ import { createHash } from 'node:crypto';
3
+ import { CanonicalError, canonicalBytes, compareCodePoints } from './canonical.js';
4
+ import { MapError, MigrationRefused } from './errors.js';
5
+ import { checkMapProject, GENERATIONS_SINCE, MAX_EPOCH } from './generation.js';
6
+ import { fingerprintOf, loadMap, verifyMapSignature } from './placement.js';
7
+ import { enumerateShapes, shapeId } from './shapes.js';
8
+ import { VerificationRequest } from './verification.js';
9
+ /** A move: the maintained copy that takes over is in another engine binding than the source. */
10
+ export const CUTOVER_PROTOCOL = 1;
11
+ /** A relayout: the copy that takes over is in the source's own engine binding, under fresh names. */
12
+ export const CUTOVER_RELAYOUT_PROTOCOL = 2;
13
+ const FIELDS = ['kind', 'protocol', 'plan_id', 'project_id', 'group', 'pause_budget_ms',
14
+ 'query_impact_digest', 'verification', 'before', 'success', 'abort', 'signature'].sort(compareCodePoints);
15
+ const provenance = new WeakMap();
16
+ function record(value, name) {
17
+ if (typeof value !== 'object' || value === null || Array.isArray(value)) {
18
+ throw new MigrationRefused(`cutover ${name} must be an object`);
19
+ }
20
+ return value;
21
+ }
22
+ function hex(value, width, name) {
23
+ if (typeof value !== 'string' || !new RegExp(`^[0-9a-f]{${width}}$`).test(value)) {
24
+ throw new MigrationRefused(`cutover ${name} must be ${width} lowercase hexadecimal digits`);
25
+ }
26
+ return value;
27
+ }
28
+ function positive(value, name) {
29
+ if (typeof value !== 'number' || !Number.isSafeInteger(value) || value < 1 || value > MAX_EPOCH) {
30
+ throw new MigrationRefused(`cutover ${name} must be a positive safe integer`);
31
+ }
32
+ return value;
33
+ }
34
+ function equal(left, right) {
35
+ return canonicalBytes(left).equals(canonicalBytes(right));
36
+ }
37
+ function signature(document) {
38
+ const value = record(document['signature'], 'signature');
39
+ const names = Object.keys(value).sort(compareCodePoints);
40
+ if (!equal(names, ['alg', 'value']) && !equal(names, ['alg', 'key_id', 'value'])) {
41
+ throw new MigrationRefused('cutover signatures have missing or unknown fields');
42
+ }
43
+ if (value['alg'] !== 'ed25519' || typeof value['value'] !== 'string') {
44
+ throw new MigrationRefused('cutover signatures must use ed25519 and canonical base64');
45
+ }
46
+ const decoded = Buffer.from(value['value'], 'base64');
47
+ if (decoded.length !== 64 || decoded.toString('base64') !== value['value']) {
48
+ throw new MigrationRefused('cutover signatures must use ed25519 and canonical base64');
49
+ }
50
+ if ('key_id' in value && typeof value['key_id'] !== 'string') {
51
+ throw new MigrationRefused('cutover signature key_id must be a string');
52
+ }
53
+ }
54
+ function except(value, keys) {
55
+ return Object.fromEntries(Object.entries(value).filter(([name]) => !keys.includes(name)));
56
+ }
57
+ export class CutoverPlan {
58
+ planId;
59
+ projectId;
60
+ group;
61
+ before;
62
+ success;
63
+ abort;
64
+ verification;
65
+ pauseBudgetMs;
66
+ queryImpactDigest;
67
+ verifiedWith;
68
+ constructor(planId, projectId, group, before, success, abort, verification, pauseBudgetMs, queryImpactDigest, verifiedWith) {
69
+ this.planId = planId;
70
+ this.projectId = projectId;
71
+ this.group = group;
72
+ this.before = before;
73
+ this.success = success;
74
+ this.abort = abort;
75
+ this.verification = verification;
76
+ this.pauseBudgetMs = pauseBudgetMs;
77
+ this.queryImpactDigest = queryImpactDigest;
78
+ this.verifiedWith = verifiedWith;
79
+ Object.freeze(this);
80
+ }
81
+ loaded() {
82
+ const saved = provenance.get(this);
83
+ if (saved === undefined)
84
+ throw new MigrationRefused('cutover execution requires an immutable loaded plan');
85
+ return saved;
86
+ }
87
+ get fingerprint() { return provenance.get(this)?.fingerprint; }
88
+ get sourceEpoch() { this.loaded(); return this.before.groups[this.group].writeEpoch; }
89
+ get maintenanceEpoch() { return this.sourceEpoch + 1; }
90
+ get activationEpoch() { return this.sourceEpoch + 2; }
91
+ asRecord() { return JSON.parse(this.loaded().document); }
92
+ candidatePayload(outcome) {
93
+ if (outcome !== 'success' && outcome !== 'abort')
94
+ throw new MigrationRefused('cutover outcome must be success or abort');
95
+ return canonicalBytes(this.asRecord()[outcome]);
96
+ }
97
+ checkCurrent(current) {
98
+ this.loaded();
99
+ checkMapProject(current, this.projectId);
100
+ if (!current.signed || fingerprintOf(current) !== fingerprintOf(this.before)) {
101
+ throw new MigrationRefused('cutover plan does not name the current placement map');
102
+ }
103
+ }
104
+ }
105
+ function load(raw, model, projectId, publicKey) {
106
+ const body = record(structuredClone(raw), 'plan');
107
+ if (!equal(Object.keys(body).sort(compareCodePoints), FIELDS)) {
108
+ throw new MigrationRefused('cutover plan has missing or unknown fields');
109
+ }
110
+ if (typeof body['protocol'] !== 'number' || ![CUTOVER_PROTOCOL, CUTOVER_RELAYOUT_PROTOCOL].includes(body['protocol'])) {
111
+ throw new MigrationRefused('unsupported cutover plan protocol');
112
+ }
113
+ const protocol = body['protocol'];
114
+ if (body['kind'] !== 'sde-cutover')
115
+ throw new MigrationRefused('unsupported cutover document kind');
116
+ const identity = hex(body['plan_id'], 32, 'plan_id'), local = hex(body['project_id'], 32, 'project_id');
117
+ if (local !== projectId)
118
+ throw new MigrationRefused('cutover plan belongs to another locally configured project');
119
+ const budget = positive(body['pause_budget_ms'], 'pause_budget_ms');
120
+ const approval = hex(body['query_impact_digest'], 64, 'query_impact_digest'), group = body['group'];
121
+ if (typeof group !== 'string' || group.length === 0)
122
+ throw new MigrationRefused('cutover group must be a nonempty string');
123
+ signature(body);
124
+ const verifiedWith = verifyMapSignature(body, publicKey);
125
+ const documents = Object.fromEntries(['before', 'success', 'abort'].map(name => [name, record(body[name], name)]));
126
+ const maps = {};
127
+ for (const name of ['before', 'success', 'abort']) {
128
+ const document = documents[name];
129
+ signature(document);
130
+ for (const value of Object.values(record(document['groups'], 'groups'))) {
131
+ const spot = record(value, 'group'), derived = spot['derived'] === undefined ? [] : spot['derived'];
132
+ if (!Array.isArray(derived))
133
+ throw new MigrationRefused('cutover derived copies must be an array');
134
+ for (const value of [spot['source'], ...derived]) {
135
+ const material = record(value, 'materialization'), layout = record(material['layout'], 'layout');
136
+ if (layout['auto'])
137
+ throw new MigrationRefused('cutover maps require explicit physical layouts');
138
+ }
139
+ }
140
+ const parsed = loadMap(document, { model, publicKey, requireSignature: true });
141
+ // Generations arrived in contract 4 and contract 5 keeps them. The three candidates share every
142
+ // top-level attribute, contract included, which the comparison below enforces.
143
+ if (parsed.contract < GENERATIONS_SINCE) {
144
+ throw new MigrationRefused(`cutover protocol ${protocol} requires placement map contract ${GENERATIONS_SINCE} or later`);
145
+ }
146
+ checkMapProject(parsed, projectId);
147
+ positive(parsed.mapVersion, 'map_version');
148
+ maps[name] = parsed;
149
+ }
150
+ const before = maps['before'], success = maps['success'], abort = maps['abort'];
151
+ if (!(before.mapVersion < success.mapVersion && success.mapVersion < abort.mapVersion)) {
152
+ throw new MigrationRefused('cutover versions must increase from before to success to abort');
153
+ }
154
+ const request = VerificationRequest.fromRecord(body['verification']);
155
+ if (!request.requiresSignature)
156
+ throw new MigrationRefused('cutover verification must require the signed before map');
157
+ request.checkSession(before, projectId, group);
158
+ const spot = before.groups[group];
159
+ if (spot.derived.length !== 1 || spot.alsoWrite.length !== 1 || spot.alsoWrite[0].id !== spot.derived[0].id) {
160
+ throw new MigrationRefused('cutover requires exactly one derived copy maintained by fan-out');
161
+ }
162
+ const source = spot.source, target = spot.derived[0], epoch = spot.writeEpoch;
163
+ const same = source.engine === target.engine;
164
+ if (protocol === CUTOVER_PROTOCOL && same)
165
+ throw new MigrationRefused('cutover source and target must use different engine bindings');
166
+ if (protocol === CUTOVER_RELAYOUT_PROTOCOL && !same) {
167
+ throw new MigrationRefused("a relayout (cutover protocol 2) activates a copy in the source's own engine binding");
168
+ }
169
+ if (epoch > MAX_EPOCH - 2)
170
+ throw new MigrationRefused('cutover needs two available write generations');
171
+ const affected = new Set(enumerateShapes(model).filter(shape => shape.group === group).map(shapeId));
172
+ if ([...affected].some(shape => (before.routing[shape] ?? source.id) !== source.id)) {
173
+ throw new MigrationRefused('cutover before-map reads must still use the source');
174
+ }
175
+ const beforeRaw = documents['before'], beforeGroups = record(beforeRaw['groups'], 'groups');
176
+ const routes = Object.fromEntries(Object.entries(before.routing).filter(([shape]) => !affected.has(shape)));
177
+ const stableKeys = ['signature', 'map_version', 'groups', 'routing'];
178
+ const stable = except(beforeRaw, stableKeys);
179
+ for (const [name, material, terminalEpoch] of [['success', target, epoch + 2], ['abort', source, epoch + 1]]) {
180
+ const document = documents[name], parsed = maps[name], groups = record(document['groups'], 'groups');
181
+ if (!equal(except(document, stableKeys), stable) || !equal(Object.keys(parsed.groups).sort(compareCodePoints), Object.keys(before.groups).sort(compareCodePoints))) {
182
+ throw new MigrationRefused('cutover cannot change other map attributes or groups');
183
+ }
184
+ if (!equal(parsed.routing, routes))
185
+ throw new MigrationRefused('cutover terminal routing must preserve the unaffected groups');
186
+ for (const other of Object.keys(before.groups)) {
187
+ if (other !== group && !equal(groups[other], beforeGroups[other]))
188
+ throw new MigrationRefused('cutover cannot change an unaffected group');
189
+ }
190
+ const terminal = record(groups[group], 'terminal group');
191
+ if (!equal(Object.keys(terminal).sort(compareCodePoints), ['source', 'write_epoch']) || terminal['write_epoch'] !== terminalEpoch) {
192
+ throw new MigrationRefused('cutover terminal group must contain only its source and decision generation');
193
+ }
194
+ const candidate = record(terminal['source'], 'terminal source');
195
+ if (typeof candidate['id'] !== 'string' || candidate['id'].length === 0) {
196
+ throw new MigrationRefused('cutover terminal source must have a nonempty string id');
197
+ }
198
+ const originalGroup = record(beforeGroups[group], 'group');
199
+ const original = record(name === 'abort' ? originalGroup['source'] : originalGroup['derived'][0], 'materialization');
200
+ if (!equal(except(candidate, ['id']), except(original, ['id', 'lag_budget_ms'])) || parsed.groups[group].source.engine !== material.engine) {
201
+ throw new MigrationRefused('cutover terminal map changed the authorized physical materialization');
202
+ }
203
+ }
204
+ const plan = new CutoverPlan(identity, local, group, before, success, abort, request, budget, approval, verifiedWith);
205
+ provenance.set(plan, { document: canonicalBytes(body).toString('utf8'),
206
+ fingerprint: createHash('sha256').update(canonicalBytes(except(body, ['signature']))).digest('hex') });
207
+ return plan;
208
+ }
209
+ export function loadCutoverPlan(raw, options) {
210
+ try {
211
+ return load(raw, options.model, options.projectId, options.publicKey);
212
+ }
213
+ catch (error) {
214
+ if (error instanceof MapError || error instanceof CanonicalError)
215
+ throw new MigrationRefused(`cutover document refused: ${error.message}`);
216
+ throw error;
217
+ }
218
+ }
219
+ //# sourceMappingURL=cutover.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cutover.js","sourceRoot":"","sources":["../src/cutover.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ import { Timestamp } from '../timestamp.js';
2
+ export declare function weatherModel(): import("../model.js").LogicalModel;
3
+ export declare const baseTime: Timestamp;
4
+ export declare const celsiusBaseCents = 1525, celsiusModulus = 1000;
5
+ export declare const humidityBase = 30, humidityModulus = 70;
6
+ export declare const generatorSpec: Readonly<{
7
+ kind: "sde-weather-generator";
8
+ version: 1;
9
+ worker: 0;
10
+ station_template: "weather-{run_id}-{worker}";
11
+ seed_template: "sde-weather-v1:{run_id}:{worker}:{sequence}";
12
+ base_time: string;
13
+ timestamp_step_microseconds: 1;
14
+ celsius_base_cents: 1525;
15
+ celsius_modulus: 1000;
16
+ humidity_base: 30;
17
+ humidity_modulus: 70;
18
+ id: "first 16 bytes of SHA256(UTF8(seed)), RFC4122 UUID version bits";
19
+ uuid_version: 4;
20
+ }>;
21
+ export declare const generatorId: string;
22
+ export declare function reading(runId: string, worker: number, sequence: number): {
23
+ station: string;
24
+ at: Timestamp;
25
+ celsius: string;
26
+ humidity: bigint;
27
+ id: string;
28
+ };
@@ -0,0 +1,40 @@
1
+ /** The same fixed logical Weather model used by the Python customer starter. */
2
+ import { createHash } from 'node:crypto';
3
+ import { canonicalBytes } from '../canonical.js';
4
+ import { assemble } from '../model.js';
5
+ import { Timestamp } from '../timestamp.js';
6
+ export function weatherModel() {
7
+ return assemble([{ name: 'WeatherReading', fields: [
8
+ { name: 'at', type: 'timestamptz', nullable: false },
9
+ { name: 'celsius', type: 'decimal(8,2)', nullable: false },
10
+ { name: 'humidity', type: 'int64', nullable: false },
11
+ { name: 'id', type: 'uuid', nullable: false },
12
+ { name: 'station', type: 'string', nullable: false },
13
+ ], key: ['station', 'at'], pii: [], residency: 'EU' }], [], [], { amount: '500.00', currency: 'EUR' });
14
+ }
15
+ export const baseTime = Timestamp.from('2026-01-01T00:00:00.000000Z');
16
+ const stationTemplate = 'weather-{run_id}-{worker}', seedTemplate = 'sde-weather-v1:{run_id}:{worker}:{sequence}';
17
+ export const celsiusBaseCents = 1525, celsiusModulus = 1000;
18
+ export const humidityBase = 30, humidityModulus = 70;
19
+ const uuidVersion = 4;
20
+ export const generatorSpec = Object.freeze({
21
+ kind: 'sde-weather-generator', version: 1, worker: 0,
22
+ station_template: stationTemplate, seed_template: seedTemplate,
23
+ base_time: baseTime.toISOString(), timestamp_step_microseconds: 1,
24
+ celsius_base_cents: celsiusBaseCents, celsius_modulus: celsiusModulus,
25
+ humidity_base: humidityBase, humidity_modulus: humidityModulus,
26
+ id: 'first 16 bytes of SHA256(UTF8(seed)), RFC4122 UUID version bits', uuid_version: uuidVersion,
27
+ });
28
+ export const generatorId = 'weather-v1:' + createHash('sha256').update(canonicalBytes(generatorSpec)).digest('hex');
29
+ export function reading(runId, worker, sequence) {
30
+ const bytes = createHash('sha256').update(seedTemplate.replace('{run_id}', runId).replace('{worker}', String(worker)).replace('{sequence}', String(sequence))).digest().subarray(0, 16);
31
+ bytes[6] = (bytes[6] & 0x0f) | (uuidVersion << 4);
32
+ bytes[8] = (bytes[8] & 0x3f) | 0x80;
33
+ const hex = bytes.toString('hex'), cents = celsiusBaseCents + sequence % celsiusModulus;
34
+ return { station: stationTemplate.replace('{run_id}', runId).replace('{worker}', String(worker)),
35
+ at: Timestamp.fromEpochMicroseconds(baseTime.epochMicroseconds + BigInt(sequence)),
36
+ celsius: `${Math.floor(cents / 100)}.${String(cents % 100).padStart(2, '0')}`,
37
+ humidity: BigInt(humidityBase + sequence % humidityModulus),
38
+ id: `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}` };
39
+ }
40
+ //# sourceMappingURL=model.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"model.js","sourceRoot":"","sources":["../../src/demo/model.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ export declare class DemoRefused extends Error {
2
+ constructor(message: string);
3
+ }
4
+ export declare function object(value: unknown): Record<string, unknown>;
5
+ export declare function read(path: string, privateFile?: boolean): {
6
+ value: Record<string, unknown>;
7
+ payload: NonSharedBuffer;
8
+ };
9
+ export declare function write(path: string, value: unknown): void;
10
+ export interface Binding {
11
+ dialect: 'postgres' | 'clickhouse';
12
+ dsn: string;
13
+ }
14
+ export declare function project(root: string): {
15
+ model: import("../model.js").LogicalModel;
16
+ bindings: Record<string, Binding>;
17
+ projectId: string;
18
+ activeMap: () => import("../placement.js").PlacementMap;
19
+ };
@@ -0,0 +1,128 @@
1
+ /** Runtime-only local configuration. This module never reads operator credentials. */
2
+ import { createHash, randomUUID } from 'node:crypto';
3
+ import { closeSync, existsSync, fsyncSync, lstatSync, mkdirSync, openSync, readFileSync, renameSync, unlinkSync, writeFileSync } from 'node:fs';
4
+ import { dirname, join } from 'node:path';
5
+ import { canonicalBytes, digest16 } from '../canonical.js';
6
+ import { checkMapProject } from '../generation.js';
7
+ import { loadMap } from '../placement.js';
8
+ import { neutralDeclaration } from '../model.js';
9
+ import { weatherModel } from './model.js';
10
+ export class DemoRefused extends Error {
11
+ constructor(message) { super(message); this.name = 'DemoRefused'; }
12
+ }
13
+ export function object(value) {
14
+ if (!value || typeof value !== 'object' || Array.isArray(value))
15
+ throw new DemoRefused('Expected a local JSON object.');
16
+ return value;
17
+ }
18
+ export function read(path, privateFile = false) {
19
+ const stat = lstatSync(path);
20
+ if (!stat.isFile() || stat.size > 2 * 1024 * 1024 || (privateFile && (stat.mode & 0o777) !== 0o600)) {
21
+ throw new DemoRefused('A required local file is invalid; credential files need mode 0600.');
22
+ }
23
+ const payload = readFileSync(path);
24
+ if (payload.length > 2 * 1024 * 1024)
25
+ throw new DemoRefused('The local input exceeds 2 MiB.');
26
+ return { value: object(JSON.parse(payload.toString('utf8'))), payload };
27
+ }
28
+ function ensureDirectory(path) {
29
+ if (existsSync(path))
30
+ return;
31
+ const parent = dirname(path);
32
+ ensureDirectory(parent);
33
+ try {
34
+ mkdirSync(path, { mode: 0o700 });
35
+ }
36
+ catch (error) {
37
+ if (error.code !== 'EEXIST')
38
+ throw error;
39
+ }
40
+ const fd = openSync(parent, 'r');
41
+ try {
42
+ fsyncSync(fd);
43
+ }
44
+ finally {
45
+ closeSync(fd);
46
+ }
47
+ }
48
+ export function write(path, value) {
49
+ const directory = dirname(path);
50
+ ensureDirectory(directory);
51
+ const temporary = join(directory, `.weather-${randomUUID()}.tmp`);
52
+ const fd = openSync(temporary, 'wx', 0o600);
53
+ try {
54
+ writeFileSync(fd, JSON.stringify(value) + '\n');
55
+ fsyncSync(fd);
56
+ }
57
+ finally {
58
+ closeSync(fd);
59
+ }
60
+ try {
61
+ renameSync(temporary, path);
62
+ const parent = openSync(directory, 'r');
63
+ try {
64
+ fsyncSync(parent);
65
+ }
66
+ finally {
67
+ closeSync(parent);
68
+ }
69
+ }
70
+ finally {
71
+ if (existsSync(temporary))
72
+ unlinkSync(temporary);
73
+ }
74
+ }
75
+ export function project(root) {
76
+ if (existsSync(join(root, 'reset-request.json')))
77
+ throw new DemoRefused('Reset was requested; set up a fresh directory.');
78
+ const config = read(join(root, 'config.json')).value;
79
+ const marker = read(join(root, 'setup-complete.json')).value;
80
+ if (Object.keys(config).sort().join(',') !== 'engines,model,project_id,protocol,public_keys' || config.protocol !== 1 ||
81
+ marker.protocol !== 1 || marker.config_digest !== digest16(config)) {
82
+ throw new DemoRefused('Setup is incomplete or config changed; restore the enrolled configuration.');
83
+ }
84
+ const model = weatherModel();
85
+ if (!canonicalBytes(object(config.model)).equals(canonicalBytes(neutralDeclaration(model)))) {
86
+ throw new DemoRefused('The starter requires the Weather model.');
87
+ }
88
+ const publicKey = Object.create(null);
89
+ for (const [name, value] of Object.entries(object(config.public_keys))) {
90
+ if (typeof value !== 'string' || !name)
91
+ throw new DemoRefused('Invalid trusted public key.');
92
+ const decoded = Buffer.from(value, 'base64');
93
+ if (decoded.length !== 32 || decoded.toString('base64') !== value)
94
+ throw new DemoRefused('Invalid Ed25519 key encoding.');
95
+ publicKey[name] = decoded;
96
+ }
97
+ if (!Object.keys(publicKey).length || typeof config.project_id !== 'string')
98
+ throw new DemoRefused('Missing project or trusted keys.');
99
+ const metadata = read(join(root, 'resources.json')).value;
100
+ const credentials = read(join(root, 'runtime-credentials.json'), true);
101
+ if (metadata.status !== 'ready' || object(metadata.credential_hashes).runtime !==
102
+ createHash('sha256').update(credentials.payload).digest('hex')) {
103
+ throw new DemoRefused('Runtime credentials differ from the ready resource allocation.');
104
+ }
105
+ const bindings = {};
106
+ const engines = object(config.engines);
107
+ if (Object.keys(engines).sort().join(',') !== Object.keys(credentials.value).sort().join(',')) {
108
+ throw new DemoRefused('Runtime credential bindings are incomplete.');
109
+ }
110
+ for (const [name, value] of Object.entries(engines)) {
111
+ const entry = object(value), dsn = credentials.value[name];
112
+ if (!/^[a-z][a-z0-9_-]{0,47}$/.test(name) || !['postgres', 'clickhouse'].includes(String(entry.dialect)) ||
113
+ typeof dsn !== 'string' || !dsn)
114
+ throw new DemoRefused('Invalid runtime engine binding.');
115
+ bindings[name] = { dialect: entry.dialect, dsn };
116
+ }
117
+ const projectId = config.project_id;
118
+ function activeMap() {
119
+ if (existsSync(join(root, 'reset-request.json')))
120
+ throw new DemoRefused('Reset was requested; the workload has stopped.');
121
+ const placement = loadMap(read(join(root, 'state', 'active-map.json')).value, { model, publicKey, requireSignature: true });
122
+ checkMapProject(placement, projectId);
123
+ return placement;
124
+ }
125
+ activeMap();
126
+ return { model, bindings, projectId, activeMap };
127
+ }
128
+ //# sourceMappingURL=project.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"project.js","sourceRoot":"","sources":["../../src/demo/project.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,73 @@
1
+ import type { Row } from '../session.js';
2
+ /** What a run can drive. The CLI offers and the runtime accepts this one list. */
3
+ export declare const workloads: readonly ["mixed", "point", "analytics", "fleet", "alerts"];
4
+ export type Workload = typeof workloads[number];
5
+ /**
6
+ * The alert threshold. Humidity is 30 + sequence % 70, so a reading alerts when sequence % 70 is 65
7
+ * or more - five readings in seventy, known exactly from the sequence number.
8
+ */
9
+ export declare const alertHumidity = 95;
10
+ export declare const alertPage = 100;
11
+ export interface RunOptions {
12
+ iterations?: number;
13
+ batchSize?: number;
14
+ intervalMs?: number;
15
+ recoveryMs?: number;
16
+ workload?: Workload;
17
+ }
18
+ export interface RunReport {
19
+ protocol: 2;
20
+ generator_id: string;
21
+ run_id: string;
22
+ language: 'typescript';
23
+ status: 'running' | 'complete' | 'incomplete';
24
+ workload: string;
25
+ sdk_version: string;
26
+ sdk_module: string;
27
+ project_id: string;
28
+ model_version: string;
29
+ acknowledged_rows: number;
30
+ verified_after_uncertain_rows: number;
31
+ verified_rows: number;
32
+ pending: {
33
+ first: number;
34
+ count: number;
35
+ } | null;
36
+ map_versions: number[];
37
+ read_retries: number;
38
+ elapsed_ns?: string;
39
+ failure?: string;
40
+ cleanup_failed?: boolean;
41
+ }
42
+ /**
43
+ * Every earlier run of this project, by run ID, with the rows it verified.
44
+ *
45
+ * Fleet analytics reads every station's rows in one time window, and every run in a directory writes
46
+ * the same timeline, so the exact answer is a sum over the runs - known exactly, because generated
47
+ * values depend only on the sequence number and each run's local report says how many rows it
48
+ * verified. A run that did not complete makes that sum unknowable, so the workload refuses instead
49
+ * of comparing a read with a guess - except a run that failed before its first write, which wrote no
50
+ * row (failedBeforeWriting). The same rules as the Python starter's fleet_runs.
51
+ */
52
+ export declare function fleetRuns(root: string, projectId: string): Map<string, number>;
53
+ /**
54
+ * The first page, row count and celsius total of the window holding sequences 1..through. A page is
55
+ * in key order, station then time; a station is its run's namespace and is ASCII, so the default
56
+ * string order is the engines' byte order.
57
+ */
58
+ export declare function fleetExpected(runs: Map<string, number>, through: number, limit: number): [Row[], number, string];
59
+ /**
60
+ * The first page, count and celsius total of this run's alerts among sequences 1..through. One
61
+ * station, so key order - station, then time - is sequence order. With no alert yet the total is
62
+ * null, as the library reports a summary of no values on every engine. The same rules as the Python
63
+ * starter's alert_expected.
64
+ */
65
+ export declare function alertExpected(runId: string, through: number, limit: number): [Row[], number, string | null];
66
+ /**
67
+ * Refuse before a run's report exists when a binding's driver cannot be imported. Without this the
68
+ * first session open failed inside the run's retry loop: ten seconds of retries, a message that could
69
+ * only say the operation did not complete, and a report left `incomplete`. ClickHouse is spoken over
70
+ * fetch and needs no package. The import is the adapter's own, resolved from this package.
71
+ */
72
+ export declare function requireDrivers(dialects: Iterable<string>, load?: (name: string) => Promise<unknown>): Promise<void>;
73
+ export declare function runWeather(root: string, options?: RunOptions): Promise<RunReport>;