lakesync 0.1.8 → 0.2.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.
- package/dist/adapter-types-DwsQGQS4.d.ts +94 -0
- package/dist/adapter.d.ts +23 -49
- package/dist/adapter.js +9 -4
- package/dist/analyst.js +1 -1
- package/dist/{base-poller-Bj9kX9dv.d.ts → base-poller-Y7ORYgUv.d.ts} +2 -0
- package/dist/catalogue.js +2 -2
- package/dist/{chunk-LDFFCG2K.js → chunk-4SG66H5K.js} +44 -31
- package/dist/chunk-4SG66H5K.js.map +1 -0
- package/dist/{chunk-LPWXOYNS.js → chunk-C4KD6YKP.js} +59 -43
- package/dist/chunk-C4KD6YKP.js.map +1 -0
- package/dist/{chunk-JI4C4R5H.js → chunk-FIIHPQMQ.js} +196 -118
- package/dist/chunk-FIIHPQMQ.js.map +1 -0
- package/dist/{chunk-TMLG32QV.js → chunk-U2NV4DUX.js} +2 -2
- package/dist/{chunk-QNITY4F6.js → chunk-XVP5DJJ7.js} +16 -13
- package/dist/{chunk-QNITY4F6.js.map → chunk-XVP5DJJ7.js.map} +1 -1
- package/dist/{chunk-KVSWLIJR.js → chunk-YHYBLU6W.js} +2 -2
- package/dist/{chunk-PYRS74YP.js → chunk-ZNY4DSFU.js} +16 -13
- package/dist/{chunk-PYRS74YP.js.map → chunk-ZNY4DSFU.js.map} +1 -1
- package/dist/{chunk-SSICS5KI.js → chunk-ZU7RC7CT.js} +2 -2
- package/dist/client.d.ts +28 -10
- package/dist/client.js +150 -29
- package/dist/client.js.map +1 -1
- package/dist/compactor.d.ts +1 -1
- package/dist/compactor.js +3 -3
- package/dist/connector-jira.d.ts +13 -3
- package/dist/connector-jira.js +6 -2
- package/dist/connector-salesforce.d.ts +13 -3
- package/dist/connector-salesforce.js +6 -2
- package/dist/{coordinator-NXy6tA0h.d.ts → coordinator-eGmZMnJ_.d.ts} +99 -16
- package/dist/create-poller-Cc2MGfhh.d.ts +55 -0
- package/dist/factory-DFfR-030.d.ts +33 -0
- package/dist/gateway-server.d.ts +398 -95
- package/dist/gateway-server.js +743 -56
- package/dist/gateway-server.js.map +1 -1
- package/dist/gateway.d.ts +14 -8
- package/dist/gateway.js +6 -5
- package/dist/index.d.ts +45 -73
- package/dist/index.js +5 -3
- package/dist/parquet.js +2 -2
- package/dist/proto.js +2 -2
- package/dist/react.d.ts +3 -3
- package/dist/{registry-BcspAtZI.d.ts → registry-Dd8JuW8T.d.ts} +1 -1
- package/dist/{request-handler-pUvL7ozF.d.ts → request-handler-B1I5xDOx.d.ts} +71 -27
- package/dist/{src-ROW4XLO7.js → src-WU7IBVC4.js} +6 -4
- package/dist/{types-BrcD1oJg.d.ts → types-D2C9jTbL.d.ts} +33 -23
- package/package.json +1 -1
- package/dist/auth-CAVutXzx.d.ts +0 -30
- package/dist/chunk-JI4C4R5H.js.map +0 -1
- package/dist/chunk-LDFFCG2K.js.map +0 -1
- package/dist/chunk-LPWXOYNS.js.map +0 -1
- package/dist/db-types-CfLMUBfW.d.ts +0 -29
- package/dist/src-B6NLV3FP.js +0 -27
- package/dist/src-ROW4XLO7.js.map +0 -1
- package/dist/src-ZRHKG42A.js +0 -25
- package/dist/src-ZRHKG42A.js.map +0 -1
- package/dist/types-DSC_EiwR.d.ts +0 -45
- /package/dist/{chunk-TMLG32QV.js.map → chunk-U2NV4DUX.js.map} +0 -0
- /package/dist/{chunk-KVSWLIJR.js.map → chunk-YHYBLU6W.js.map} +0 -0
- /package/dist/{chunk-SSICS5KI.js.map → chunk-ZU7RC7CT.js.map} +0 -0
- /package/dist/{src-B6NLV3FP.js.map → src-WU7IBVC4.js.map} +0 -0
|
@@ -1,15 +1,11 @@
|
|
|
1
|
-
import {
|
|
2
|
-
isDatabaseAdapter,
|
|
3
|
-
isMaterialisable
|
|
4
|
-
} from "./chunk-LPWXOYNS.js";
|
|
5
1
|
import {
|
|
6
2
|
buildPartitionSpec,
|
|
7
3
|
lakeSyncTableName,
|
|
8
4
|
tableSchemaToIceberg
|
|
9
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-U2NV4DUX.js";
|
|
10
6
|
import {
|
|
11
7
|
writeDeltasToParquet
|
|
12
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-ZU7RC7CT.js";
|
|
13
9
|
import {
|
|
14
10
|
AdapterNotFoundError,
|
|
15
11
|
BackpressureError,
|
|
@@ -22,6 +18,8 @@ import {
|
|
|
22
18
|
bigintReplacer,
|
|
23
19
|
bigintReviver,
|
|
24
20
|
filterDeltas,
|
|
21
|
+
isDatabaseAdapter,
|
|
22
|
+
isMaterialisable,
|
|
25
23
|
listConnectorDescriptors,
|
|
26
24
|
resolveLWW,
|
|
27
25
|
rowKey,
|
|
@@ -29,25 +27,84 @@ import {
|
|
|
29
27
|
validateAction,
|
|
30
28
|
validateConnectorConfig,
|
|
31
29
|
validateSyncRules
|
|
32
|
-
} from "./chunk-
|
|
30
|
+
} from "./chunk-4SG66H5K.js";
|
|
33
31
|
|
|
34
|
-
// ../gateway/src/
|
|
32
|
+
// ../gateway/src/idempotency-cache.ts
|
|
35
33
|
var DEFAULT_MAX_CACHE_SIZE = 1e4;
|
|
36
34
|
var DEFAULT_CACHE_TTL_MS = 5 * 60 * 1e3;
|
|
35
|
+
var MemoryIdempotencyCache = class {
|
|
36
|
+
entries = /* @__PURE__ */ new Map();
|
|
37
|
+
maxSize;
|
|
38
|
+
ttlMs;
|
|
39
|
+
constructor(config) {
|
|
40
|
+
this.maxSize = config?.maxSize ?? DEFAULT_MAX_CACHE_SIZE;
|
|
41
|
+
this.ttlMs = config?.ttlMs ?? DEFAULT_CACHE_TTL_MS;
|
|
42
|
+
}
|
|
43
|
+
/** {@inheritDoc IdempotencyCache.has} */
|
|
44
|
+
has(actionId) {
|
|
45
|
+
const entry = this.entries.get(actionId);
|
|
46
|
+
if (!entry) return false;
|
|
47
|
+
if (Date.now() - entry.cachedAt > this.ttlMs) {
|
|
48
|
+
this.entries.delete(actionId);
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
return true;
|
|
52
|
+
}
|
|
53
|
+
/** {@inheritDoc IdempotencyCache.get} */
|
|
54
|
+
get(key) {
|
|
55
|
+
const entry = this.entries.get(key);
|
|
56
|
+
if (!entry) return void 0;
|
|
57
|
+
if (Date.now() - entry.cachedAt > this.ttlMs) {
|
|
58
|
+
this.entries.delete(key);
|
|
59
|
+
return void 0;
|
|
60
|
+
}
|
|
61
|
+
return entry.value;
|
|
62
|
+
}
|
|
63
|
+
/** {@inheritDoc IdempotencyCache.set} */
|
|
64
|
+
set(actionId, result, idempotencyKey) {
|
|
65
|
+
this.evictStaleEntries();
|
|
66
|
+
const entry = { value: result, cachedAt: Date.now() };
|
|
67
|
+
this.entries.set(actionId, entry);
|
|
68
|
+
if (idempotencyKey) {
|
|
69
|
+
this.entries.set(`idem:${idempotencyKey}`, entry);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
/** Evict expired entries and trim to max size (counting only non-idem entries). */
|
|
73
|
+
evictStaleEntries() {
|
|
74
|
+
const now = Date.now();
|
|
75
|
+
for (const [key, entry] of this.entries) {
|
|
76
|
+
if (now - entry.cachedAt > this.ttlMs) {
|
|
77
|
+
this.entries.delete(key);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
const actionKeys = [...this.entries.keys()].filter((k) => !k.startsWith("idem:"));
|
|
81
|
+
if (actionKeys.length > this.maxSize) {
|
|
82
|
+
const excess = actionKeys.length - this.maxSize;
|
|
83
|
+
for (let i = 0; i < excess; i++) {
|
|
84
|
+
this.entries.delete(actionKeys[i]);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
// ../gateway/src/action-dispatcher.ts
|
|
37
91
|
var ActionDispatcher = class {
|
|
38
92
|
actionHandlers = /* @__PURE__ */ new Map();
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
93
|
+
cache;
|
|
94
|
+
/**
|
|
95
|
+
* Create an ActionDispatcher.
|
|
96
|
+
*
|
|
97
|
+
* @param handlers - Optional map of connector name to action handler.
|
|
98
|
+
* @param cacheConfig - Optional cache configuration (used when no `cache` is provided).
|
|
99
|
+
* @param cache - Optional pre-built idempotency cache; defaults to a {@link MemoryIdempotencyCache}.
|
|
100
|
+
*/
|
|
101
|
+
constructor(handlers, cacheConfig, cache) {
|
|
44
102
|
if (handlers) {
|
|
45
103
|
for (const [name, handler] of Object.entries(handlers)) {
|
|
46
104
|
this.actionHandlers.set(name, handler);
|
|
47
105
|
}
|
|
48
106
|
}
|
|
49
|
-
this.
|
|
50
|
-
this.cacheTtlMs = cacheConfig?.ttlMs ?? DEFAULT_CACHE_TTL_MS;
|
|
107
|
+
this.cache = cache ?? new MemoryIdempotencyCache(cacheConfig);
|
|
51
108
|
}
|
|
52
109
|
/**
|
|
53
110
|
* Dispatch an action push to registered handlers.
|
|
@@ -62,15 +119,14 @@ var ActionDispatcher = class {
|
|
|
62
119
|
* @returns A `Result` containing results for each action.
|
|
63
120
|
*/
|
|
64
121
|
async dispatch(msg, hlcNow, context) {
|
|
65
|
-
this.evictStaleEntries();
|
|
66
122
|
const results = [];
|
|
67
123
|
for (const action of msg.actions) {
|
|
68
124
|
const validation = validateAction(action);
|
|
69
125
|
if (!validation.ok) {
|
|
70
126
|
return Err(validation.error);
|
|
71
127
|
}
|
|
72
|
-
if (this.
|
|
73
|
-
const cached = this.
|
|
128
|
+
if (this.cache.has(action.actionId)) {
|
|
129
|
+
const cached = this.cache.get(action.actionId);
|
|
74
130
|
if (cached) {
|
|
75
131
|
results.push(cached);
|
|
76
132
|
continue;
|
|
@@ -78,7 +134,7 @@ var ActionDispatcher = class {
|
|
|
78
134
|
continue;
|
|
79
135
|
}
|
|
80
136
|
if (action.idempotencyKey) {
|
|
81
|
-
const cached = this.
|
|
137
|
+
const cached = this.cache.get(`idem:${action.idempotencyKey}`);
|
|
82
138
|
if (cached) {
|
|
83
139
|
results.push(cached);
|
|
84
140
|
continue;
|
|
@@ -93,7 +149,7 @@ var ActionDispatcher = class {
|
|
|
93
149
|
retryable: false
|
|
94
150
|
};
|
|
95
151
|
results.push(errorResult);
|
|
96
|
-
this.
|
|
152
|
+
this.cache.set(action.actionId, errorResult, action.idempotencyKey);
|
|
97
153
|
continue;
|
|
98
154
|
}
|
|
99
155
|
const supported = handler.supportedActions.some((d) => d.actionType === action.actionType);
|
|
@@ -105,13 +161,13 @@ var ActionDispatcher = class {
|
|
|
105
161
|
retryable: false
|
|
106
162
|
};
|
|
107
163
|
results.push(errorResult);
|
|
108
|
-
this.
|
|
164
|
+
this.cache.set(action.actionId, errorResult, action.idempotencyKey);
|
|
109
165
|
continue;
|
|
110
166
|
}
|
|
111
167
|
const execResult = await handler.executeAction(action, context);
|
|
112
168
|
if (execResult.ok) {
|
|
113
169
|
results.push(execResult.value);
|
|
114
|
-
this.
|
|
170
|
+
this.cache.set(action.actionId, execResult.value, action.idempotencyKey);
|
|
115
171
|
} else {
|
|
116
172
|
const err = execResult.error;
|
|
117
173
|
const errorResult = {
|
|
@@ -122,7 +178,7 @@ var ActionDispatcher = class {
|
|
|
122
178
|
};
|
|
123
179
|
results.push(errorResult);
|
|
124
180
|
if (!errorResult.retryable) {
|
|
125
|
-
this.
|
|
181
|
+
this.cache.set(action.actionId, errorResult, action.idempotencyKey);
|
|
126
182
|
}
|
|
127
183
|
}
|
|
128
184
|
}
|
|
@@ -169,47 +225,6 @@ var ActionDispatcher = class {
|
|
|
169
225
|
}
|
|
170
226
|
return { connectors };
|
|
171
227
|
}
|
|
172
|
-
/** Cache an action result for idempotency deduplication. */
|
|
173
|
-
cacheActionResult(action, result) {
|
|
174
|
-
const entry = { value: result, cachedAt: Date.now() };
|
|
175
|
-
this.executedActions.add(action.actionId);
|
|
176
|
-
this.idempotencyMap.set(action.actionId, entry);
|
|
177
|
-
if (action.idempotencyKey) {
|
|
178
|
-
this.idempotencyMap.set(`idem:${action.idempotencyKey}`, entry);
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
/** Get a cached result if it exists and hasn't expired. */
|
|
182
|
-
getCachedResult(key) {
|
|
183
|
-
const entry = this.idempotencyMap.get(key);
|
|
184
|
-
if (!entry) return void 0;
|
|
185
|
-
if (Date.now() - entry.cachedAt > this.cacheTtlMs) {
|
|
186
|
-
this.idempotencyMap.delete(key);
|
|
187
|
-
return void 0;
|
|
188
|
-
}
|
|
189
|
-
return entry.value;
|
|
190
|
-
}
|
|
191
|
-
/** Evict expired entries and trim to max size. */
|
|
192
|
-
evictStaleEntries() {
|
|
193
|
-
const now = Date.now();
|
|
194
|
-
for (const [key, entry] of this.idempotencyMap) {
|
|
195
|
-
if (now - entry.cachedAt > this.cacheTtlMs) {
|
|
196
|
-
this.idempotencyMap.delete(key);
|
|
197
|
-
if (!key.startsWith("idem:")) {
|
|
198
|
-
this.executedActions.delete(key);
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
if (this.executedActions.size > this.maxCacheSize) {
|
|
203
|
-
const excess = this.executedActions.size - this.maxCacheSize;
|
|
204
|
-
let removed = 0;
|
|
205
|
-
for (const actionId of this.executedActions) {
|
|
206
|
-
if (removed >= excess) break;
|
|
207
|
-
this.executedActions.delete(actionId);
|
|
208
|
-
this.idempotencyMap.delete(actionId);
|
|
209
|
-
removed++;
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
228
|
};
|
|
214
229
|
|
|
215
230
|
// ../gateway/src/buffer.ts
|
|
@@ -414,26 +429,39 @@ function hlcRange(entries) {
|
|
|
414
429
|
}
|
|
415
430
|
return { min, max };
|
|
416
431
|
}
|
|
417
|
-
|
|
418
|
-
if (
|
|
432
|
+
function notifyMaterialisationFailure(entries, error, config) {
|
|
433
|
+
if (!config.onMaterialisationFailure) return;
|
|
434
|
+
const tables = new Set(entries.map((e) => e.table));
|
|
435
|
+
for (const table of tables) {
|
|
436
|
+
const count = entries.filter((e) => e.table === table).length;
|
|
437
|
+
config.onMaterialisationFailure(table, count, error);
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
var DatabaseFlushStrategy = class {
|
|
441
|
+
async flush(entries, _byteSize, deps) {
|
|
442
|
+
const adapter = deps.adapter;
|
|
419
443
|
try {
|
|
420
|
-
const result = await
|
|
444
|
+
const result = await adapter.insertDeltas(entries);
|
|
421
445
|
if (!result.ok) {
|
|
422
446
|
deps.restoreEntries(entries);
|
|
423
447
|
return Err(new FlushError(`Database flush failed: ${result.error.message}`));
|
|
424
448
|
}
|
|
425
|
-
if (deps.schemas && deps.schemas.length > 0 && isMaterialisable(
|
|
449
|
+
if (deps.schemas && deps.schemas.length > 0 && isMaterialisable(adapter)) {
|
|
426
450
|
try {
|
|
427
|
-
const matResult = await
|
|
451
|
+
const matResult = await adapter.materialise(entries, deps.schemas);
|
|
428
452
|
if (!matResult.ok) {
|
|
453
|
+
const error = new Error(matResult.error.message);
|
|
429
454
|
console.warn(
|
|
430
455
|
`[lakesync] Materialisation failed (${entries.length} deltas): ${matResult.error.message}`
|
|
431
456
|
);
|
|
457
|
+
notifyMaterialisationFailure(entries, error, deps.config);
|
|
432
458
|
}
|
|
433
459
|
} catch (error) {
|
|
460
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
434
461
|
console.warn(
|
|
435
|
-
`[lakesync] Materialisation error (${entries.length} deltas): ${
|
|
462
|
+
`[lakesync] Materialisation error (${entries.length} deltas): ${err.message}`
|
|
436
463
|
);
|
|
464
|
+
notifyMaterialisationFailure(entries, err, deps.config);
|
|
437
465
|
}
|
|
438
466
|
}
|
|
439
467
|
return Ok(void 0);
|
|
@@ -442,14 +470,14 @@ async function flushEntries(entries, byteSize, deps, keyPrefix) {
|
|
|
442
470
|
return Err(new FlushError(`Unexpected database flush failure: ${toError(error).message}`));
|
|
443
471
|
}
|
|
444
472
|
}
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
const
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
473
|
+
};
|
|
474
|
+
var LakeJsonFlushStrategy = class {
|
|
475
|
+
async flush(entries, byteSize, deps, keyPrefix) {
|
|
476
|
+
const adapter = deps.adapter;
|
|
477
|
+
try {
|
|
478
|
+
const { min, max } = hlcRange(entries);
|
|
479
|
+
const date = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
480
|
+
const prefix = keyPrefix ? `${keyPrefix}-` : "";
|
|
453
481
|
const envelope = {
|
|
454
482
|
version: 1,
|
|
455
483
|
gatewayId: deps.config.gatewayId,
|
|
@@ -459,10 +487,33 @@ async function flushEntries(entries, byteSize, deps, keyPrefix) {
|
|
|
459
487
|
byteSize,
|
|
460
488
|
deltas: entries
|
|
461
489
|
};
|
|
462
|
-
objectKey = `deltas/${date}/${deps.config.gatewayId}/${prefix}${min.toString()}-${max.toString()}.json`;
|
|
463
|
-
data = new TextEncoder().encode(JSON.stringify(envelope, bigintReplacer));
|
|
464
|
-
|
|
465
|
-
|
|
490
|
+
const objectKey = `deltas/${date}/${deps.config.gatewayId}/${prefix}${min.toString()}-${max.toString()}.json`;
|
|
491
|
+
const data = new TextEncoder().encode(JSON.stringify(envelope, bigintReplacer));
|
|
492
|
+
const result = await adapter.putObject(objectKey, data, "application/json");
|
|
493
|
+
if (!result.ok) {
|
|
494
|
+
deps.restoreEntries(entries);
|
|
495
|
+
return Err(new FlushError(`Failed to write flush envelope: ${result.error.message}`));
|
|
496
|
+
}
|
|
497
|
+
if (deps.config.catalogue && deps.config.tableSchema) {
|
|
498
|
+
await commitToCatalogue(
|
|
499
|
+
objectKey,
|
|
500
|
+
data.byteLength,
|
|
501
|
+
entries.length,
|
|
502
|
+
deps.config.catalogue,
|
|
503
|
+
deps.config.tableSchema
|
|
504
|
+
);
|
|
505
|
+
}
|
|
506
|
+
return Ok(void 0);
|
|
507
|
+
} catch (error) {
|
|
508
|
+
deps.restoreEntries(entries);
|
|
509
|
+
return Err(new FlushError(`Unexpected flush failure: ${toError(error).message}`));
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
};
|
|
513
|
+
var LakeParquetFlushStrategy = class {
|
|
514
|
+
async flush(entries, _byteSize, deps, keyPrefix) {
|
|
515
|
+
const adapter = deps.adapter;
|
|
516
|
+
try {
|
|
466
517
|
if (!deps.config.tableSchema) {
|
|
467
518
|
deps.restoreEntries(entries);
|
|
468
519
|
return Err(new FlushError("tableSchema required for Parquet flush"));
|
|
@@ -472,29 +523,43 @@ async function flushEntries(entries, byteSize, deps, keyPrefix) {
|
|
|
472
523
|
deps.restoreEntries(entries);
|
|
473
524
|
return Err(parquetResult.error);
|
|
474
525
|
}
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
526
|
+
const { min, max } = hlcRange(entries);
|
|
527
|
+
const date = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
528
|
+
const prefix = keyPrefix ? `${keyPrefix}-` : "";
|
|
529
|
+
const objectKey = `deltas/${date}/${deps.config.gatewayId}/${prefix}${min.toString()}-${max.toString()}.parquet`;
|
|
530
|
+
const data = parquetResult.value;
|
|
531
|
+
const result = await adapter.putObject(objectKey, data, "application/vnd.apache.parquet");
|
|
532
|
+
if (!result.ok) {
|
|
533
|
+
deps.restoreEntries(entries);
|
|
534
|
+
return Err(new FlushError(`Failed to write flush envelope: ${result.error.message}`));
|
|
535
|
+
}
|
|
536
|
+
if (deps.config.catalogue && deps.config.tableSchema) {
|
|
537
|
+
await commitToCatalogue(
|
|
538
|
+
objectKey,
|
|
539
|
+
data.byteLength,
|
|
540
|
+
entries.length,
|
|
541
|
+
deps.config.catalogue,
|
|
542
|
+
deps.config.tableSchema
|
|
543
|
+
);
|
|
544
|
+
}
|
|
545
|
+
return Ok(void 0);
|
|
546
|
+
} catch (error) {
|
|
481
547
|
deps.restoreEntries(entries);
|
|
482
|
-
return Err(new FlushError(`
|
|
483
|
-
}
|
|
484
|
-
if (deps.config.catalogue && deps.config.tableSchema) {
|
|
485
|
-
await commitToCatalogue(
|
|
486
|
-
objectKey,
|
|
487
|
-
data.byteLength,
|
|
488
|
-
entries.length,
|
|
489
|
-
deps.config.catalogue,
|
|
490
|
-
deps.config.tableSchema
|
|
491
|
-
);
|
|
548
|
+
return Err(new FlushError(`Unexpected flush failure: ${toError(error).message}`));
|
|
492
549
|
}
|
|
493
|
-
return Ok(void 0);
|
|
494
|
-
} catch (error) {
|
|
495
|
-
deps.restoreEntries(entries);
|
|
496
|
-
return Err(new FlushError(`Unexpected flush failure: ${toError(error).message}`));
|
|
497
550
|
}
|
|
551
|
+
};
|
|
552
|
+
var databaseStrategy = new DatabaseFlushStrategy();
|
|
553
|
+
var lakeJsonStrategy = new LakeJsonFlushStrategy();
|
|
554
|
+
var lakeParquetStrategy = new LakeParquetFlushStrategy();
|
|
555
|
+
function selectFlushStrategy(adapter, format) {
|
|
556
|
+
if (isDatabaseAdapter(adapter)) return databaseStrategy;
|
|
557
|
+
if (format === "json") return lakeJsonStrategy;
|
|
558
|
+
return lakeParquetStrategy;
|
|
559
|
+
}
|
|
560
|
+
async function flushEntries(entries, byteSize, deps, keyPrefix) {
|
|
561
|
+
const strategy = selectFlushStrategy(deps.adapter, deps.config.flushFormat);
|
|
562
|
+
return strategy.flush(entries, byteSize, deps, keyPrefix);
|
|
498
563
|
}
|
|
499
564
|
async function commitToCatalogue(objectKey, fileSizeInBytes, recordCount, catalogue, schema) {
|
|
500
565
|
const { namespace, name } = lakeSyncTableName(schema.table);
|
|
@@ -862,6 +927,15 @@ var SyncGateway = class {
|
|
|
862
927
|
return this.sources.list();
|
|
863
928
|
}
|
|
864
929
|
// -----------------------------------------------------------------------
|
|
930
|
+
// Rehydration — restore persisted deltas without push validation
|
|
931
|
+
// -----------------------------------------------------------------------
|
|
932
|
+
/** Rehydrate the buffer with persisted deltas (bypasses push validation). */
|
|
933
|
+
rehydrate(deltas) {
|
|
934
|
+
for (const delta of deltas) {
|
|
935
|
+
this.buffer.append(delta);
|
|
936
|
+
}
|
|
937
|
+
}
|
|
938
|
+
// -----------------------------------------------------------------------
|
|
865
939
|
// Buffer queries
|
|
866
940
|
// -----------------------------------------------------------------------
|
|
867
941
|
/** Get per-table buffer statistics. */
|
|
@@ -1167,17 +1241,17 @@ function handleMetrics(gateway, extra) {
|
|
|
1167
1241
|
|
|
1168
1242
|
// ../gateway/src/schema-manager.ts
|
|
1169
1243
|
var SchemaManager = class {
|
|
1170
|
-
|
|
1171
|
-
version;
|
|
1172
|
-
allowedColumns;
|
|
1244
|
+
state;
|
|
1173
1245
|
constructor(schema, version) {
|
|
1174
|
-
this.
|
|
1175
|
-
|
|
1176
|
-
|
|
1246
|
+
this.state = {
|
|
1247
|
+
schema,
|
|
1248
|
+
version: version ?? 1,
|
|
1249
|
+
allowedColumns: new Set(schema.columns.map((c) => c.name))
|
|
1250
|
+
};
|
|
1177
1251
|
}
|
|
1178
1252
|
/** Get the current schema and version. */
|
|
1179
1253
|
getSchema() {
|
|
1180
|
-
return { schema: this.
|
|
1254
|
+
return { schema: this.state.schema, version: this.state.version };
|
|
1181
1255
|
}
|
|
1182
1256
|
/**
|
|
1183
1257
|
* Validate that a delta's columns are compatible with the current schema.
|
|
@@ -1190,10 +1264,10 @@ var SchemaManager = class {
|
|
|
1190
1264
|
return Ok(void 0);
|
|
1191
1265
|
}
|
|
1192
1266
|
for (const col of delta.columns) {
|
|
1193
|
-
if (!this.allowedColumns.has(col.column)) {
|
|
1267
|
+
if (!this.state.allowedColumns.has(col.column)) {
|
|
1194
1268
|
return Err(
|
|
1195
1269
|
new SchemaError(
|
|
1196
|
-
`Unknown column "${col.column}" in delta for table "${delta.table}". Schema version ${this.version} does not include this column.`
|
|
1270
|
+
`Unknown column "${col.column}" in delta for table "${delta.table}". Schema version ${this.state.version} does not include this column.`
|
|
1197
1271
|
)
|
|
1198
1272
|
);
|
|
1199
1273
|
}
|
|
@@ -1207,10 +1281,10 @@ var SchemaManager = class {
|
|
|
1207
1281
|
* returns a SchemaError.
|
|
1208
1282
|
*/
|
|
1209
1283
|
evolveSchema(newSchema) {
|
|
1210
|
-
if (newSchema.table !== this.
|
|
1284
|
+
if (newSchema.table !== this.state.schema.table) {
|
|
1211
1285
|
return Err(new SchemaError("Cannot evolve schema: table name mismatch"));
|
|
1212
1286
|
}
|
|
1213
|
-
const oldColumnMap = new Map(this.
|
|
1287
|
+
const oldColumnMap = new Map(this.state.schema.columns.map((c) => [c.name, c.type]));
|
|
1214
1288
|
const newColumnMap = new Map(newSchema.columns.map((c) => [c.name, c.type]));
|
|
1215
1289
|
for (const [name] of oldColumnMap) {
|
|
1216
1290
|
if (!newColumnMap.has(name)) {
|
|
@@ -1231,14 +1305,18 @@ var SchemaManager = class {
|
|
|
1231
1305
|
);
|
|
1232
1306
|
}
|
|
1233
1307
|
}
|
|
1234
|
-
this.
|
|
1235
|
-
this.
|
|
1236
|
-
|
|
1237
|
-
|
|
1308
|
+
const newVersion = this.state.version + 1;
|
|
1309
|
+
this.state = {
|
|
1310
|
+
schema: newSchema,
|
|
1311
|
+
version: newVersion,
|
|
1312
|
+
allowedColumns: new Set(newSchema.columns.map((c) => c.name))
|
|
1313
|
+
};
|
|
1314
|
+
return Ok({ version: newVersion });
|
|
1238
1315
|
}
|
|
1239
1316
|
};
|
|
1240
1317
|
|
|
1241
1318
|
export {
|
|
1319
|
+
MemoryIdempotencyCache,
|
|
1242
1320
|
ActionDispatcher,
|
|
1243
1321
|
DeltaBuffer,
|
|
1244
1322
|
MemoryConfigStore,
|
|
@@ -1275,4 +1353,4 @@ export {
|
|
|
1275
1353
|
handleMetrics,
|
|
1276
1354
|
SchemaManager
|
|
1277
1355
|
};
|
|
1278
|
-
//# sourceMappingURL=chunk-
|
|
1356
|
+
//# sourceMappingURL=chunk-FIIHPQMQ.js.map
|