@platformatic/sqlite-js-stream 0.0.0-stage → 0.1.1

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 (162) hide show
  1. package/CHANGELOG.md +40 -0
  2. package/LICENSE +202 -0
  3. package/NOTICE +22 -0
  4. package/README.md +482 -2
  5. package/dist/backends/file/index.d.ts +4 -0
  6. package/dist/backends/file/index.d.ts.map +1 -0
  7. package/dist/backends/file/index.js +3 -0
  8. package/dist/backends/file/leaser.d.ts +20 -0
  9. package/dist/backends/file/leaser.d.ts.map +1 -0
  10. package/dist/backends/file/leaser.js +123 -0
  11. package/dist/backends/file/replica-client.d.ts +38 -0
  12. package/dist/backends/file/replica-client.d.ts.map +1 -0
  13. package/dist/backends/file/replica-client.js +209 -0
  14. package/dist/db.d.ts +80 -0
  15. package/dist/db.d.ts.map +1 -0
  16. package/dist/db.js +484 -0
  17. package/dist/errors.d.ts +42 -0
  18. package/dist/errors.d.ts.map +1 -0
  19. package/dist/errors.js +66 -0
  20. package/dist/index.d.ts +19 -0
  21. package/dist/index.d.ts.map +1 -0
  22. package/dist/index.js +22 -0
  23. package/dist/leaser.d.ts +55 -0
  24. package/dist/leaser.d.ts.map +1 -0
  25. package/dist/leaser.js +60 -0
  26. package/dist/ltx/byte-reader.d.ts +18 -0
  27. package/dist/ltx/byte-reader.d.ts.map +1 -0
  28. package/dist/ltx/byte-reader.js +38 -0
  29. package/dist/ltx/bytes.d.ts +20 -0
  30. package/dist/ltx/bytes.d.ts.map +1 -0
  31. package/dist/ltx/bytes.js +69 -0
  32. package/dist/ltx/checksum.d.ts +20 -0
  33. package/dist/ltx/checksum.d.ts.map +1 -0
  34. package/dist/ltx/checksum.js +42 -0
  35. package/dist/ltx/compaction-level.d.ts +58 -0
  36. package/dist/ltx/compaction-level.d.ts.map +1 -0
  37. package/dist/ltx/compaction-level.js +115 -0
  38. package/dist/ltx/compactor.d.ts +33 -0
  39. package/dist/ltx/compactor.d.ts.map +1 -0
  40. package/dist/ltx/compactor.js +137 -0
  41. package/dist/ltx/constants.d.ts +49 -0
  42. package/dist/ltx/constants.d.ts.map +1 -0
  43. package/dist/ltx/constants.js +58 -0
  44. package/dist/ltx/crc64.d.ts +29 -0
  45. package/dist/ltx/crc64.d.ts.map +1 -0
  46. package/dist/ltx/crc64.js +57 -0
  47. package/dist/ltx/decoder.d.ts +55 -0
  48. package/dist/ltx/decoder.d.ts.map +1 -0
  49. package/dist/ltx/decoder.js +236 -0
  50. package/dist/ltx/encoder.d.ts +49 -0
  51. package/dist/ltx/encoder.d.ts.map +1 -0
  52. package/dist/ltx/encoder.js +159 -0
  53. package/dist/ltx/file-info.d.ts +24 -0
  54. package/dist/ltx/file-info.d.ts.map +1 -0
  55. package/dist/ltx/file-info.js +74 -0
  56. package/dist/ltx/filename.d.ts +13 -0
  57. package/dist/ltx/filename.d.ts.map +1 -0
  58. package/dist/ltx/filename.js +23 -0
  59. package/dist/ltx/header.d.ts +17 -0
  60. package/dist/ltx/header.d.ts.map +1 -0
  61. package/dist/ltx/header.js +115 -0
  62. package/dist/ltx/index.d.ts +24 -0
  63. package/dist/ltx/index.d.ts.map +1 -0
  64. package/dist/ltx/index.js +25 -0
  65. package/dist/ltx/lz4.d.ts +41 -0
  66. package/dist/ltx/lz4.d.ts.map +1 -0
  67. package/dist/ltx/lz4.js +264 -0
  68. package/dist/ltx/page-index.d.ts +26 -0
  69. package/dist/ltx/page-index.d.ts.map +1 -0
  70. package/dist/ltx/page-index.js +118 -0
  71. package/dist/ltx/page.d.ts +27 -0
  72. package/dist/ltx/page.d.ts.map +1 -0
  73. package/dist/ltx/page.js +66 -0
  74. package/dist/ltx/sink.d.ts +17 -0
  75. package/dist/ltx/sink.d.ts.map +1 -0
  76. package/dist/ltx/sink.js +21 -0
  77. package/dist/ltx/stream.d.ts +64 -0
  78. package/dist/ltx/stream.d.ts.map +1 -0
  79. package/dist/ltx/stream.js +248 -0
  80. package/dist/ltx/streaming-compactor.d.ts +34 -0
  81. package/dist/ltx/streaming-compactor.d.ts.map +1 -0
  82. package/dist/ltx/streaming-compactor.js +140 -0
  83. package/dist/ltx/trailer.d.ts +12 -0
  84. package/dist/ltx/trailer.d.ts.map +1 -0
  85. package/dist/ltx/trailer.js +47 -0
  86. package/dist/ltx/types.d.ts +79 -0
  87. package/dist/ltx/types.d.ts.map +1 -0
  88. package/dist/ltx/types.js +70 -0
  89. package/dist/replica-client.d.ts +92 -0
  90. package/dist/replica-client.d.ts.map +1 -0
  91. package/dist/replica-client.js +122 -0
  92. package/dist/replica-url.d.ts +20 -0
  93. package/dist/replica-url.d.ts.map +1 -0
  94. package/dist/replica-url.js +49 -0
  95. package/dist/replica.d.ts +379 -0
  96. package/dist/replica.d.ts.map +1 -0
  97. package/dist/replica.js +1253 -0
  98. package/dist/store.d.ts +34 -0
  99. package/dist/store.d.ts.map +1 -0
  100. package/dist/store.js +60 -0
  101. package/dist/util/fs.d.ts +28 -0
  102. package/dist/util/fs.d.ts.map +1 -0
  103. package/dist/util/fs.js +73 -0
  104. package/dist/util/logger.d.ts +10 -0
  105. package/dist/util/logger.d.ts.map +1 -0
  106. package/dist/util/logger.js +7 -0
  107. package/dist/util/stream.d.ts +11 -0
  108. package/dist/util/stream.d.ts.map +1 -0
  109. package/dist/util/stream.js +25 -0
  110. package/dist/wal/checksum.d.ts +17 -0
  111. package/dist/wal/checksum.d.ts.map +1 -0
  112. package/dist/wal/checksum.js +30 -0
  113. package/dist/wal/constants.d.ts +8 -0
  114. package/dist/wal/constants.d.ts.map +1 -0
  115. package/dist/wal/constants.js +7 -0
  116. package/dist/wal/index.d.ts +5 -0
  117. package/dist/wal/index.d.ts.map +1 -0
  118. package/dist/wal/index.js +4 -0
  119. package/dist/wal/reader.d.ts +61 -0
  120. package/dist/wal/reader.d.ts.map +1 -0
  121. package/dist/wal/reader.js +207 -0
  122. package/package.json +68 -3
  123. package/src/backends/file/index.ts +3 -0
  124. package/src/backends/file/leaser.ts +145 -0
  125. package/src/backends/file/replica-client.ts +246 -0
  126. package/src/db.ts +553 -0
  127. package/src/errors.ts +74 -0
  128. package/src/index.ts +26 -0
  129. package/src/leaser.ts +86 -0
  130. package/src/ltx/byte-reader.ts +46 -0
  131. package/src/ltx/bytes.ts +87 -0
  132. package/src/ltx/checksum.ts +46 -0
  133. package/src/ltx/compaction-level.ts +135 -0
  134. package/src/ltx/compactor.ts +167 -0
  135. package/src/ltx/constants.ts +71 -0
  136. package/src/ltx/crc64.ts +65 -0
  137. package/src/ltx/decoder.ts +282 -0
  138. package/src/ltx/encoder.ts +200 -0
  139. package/src/ltx/file-info.ts +81 -0
  140. package/src/ltx/filename.ts +27 -0
  141. package/src/ltx/header.ts +126 -0
  142. package/src/ltx/index.ts +27 -0
  143. package/src/ltx/lz4.ts +279 -0
  144. package/src/ltx/page-index.ts +140 -0
  145. package/src/ltx/page.ts +80 -0
  146. package/src/ltx/sink.ts +33 -0
  147. package/src/ltx/stream.ts +286 -0
  148. package/src/ltx/streaming-compactor.ts +169 -0
  149. package/src/ltx/trailer.ts +58 -0
  150. package/src/ltx/types.ts +152 -0
  151. package/src/lz4js.d.ts +27 -0
  152. package/src/replica-client.ts +222 -0
  153. package/src/replica-url.ts +72 -0
  154. package/src/replica.ts +1480 -0
  155. package/src/store.ts +71 -0
  156. package/src/util/fs.ts +82 -0
  157. package/src/util/logger.ts +15 -0
  158. package/src/util/stream.ts +28 -0
  159. package/src/wal/checksum.ts +39 -0
  160. package/src/wal/constants.ts +10 -0
  161. package/src/wal/index.ts +5 -0
  162. package/src/wal/reader.ts +264 -0
@@ -0,0 +1,92 @@
1
+ /**
2
+ * ReplicaClient interface and shared helpers for interacting with a replica
3
+ * (an LTX destination). Mirrors litestream's `replica_client.go`.
4
+ *
5
+ * The interface is async/iterable oriented rather than Go's iterator/readcloser
6
+ * model, but the semantics match:
7
+ * - ltxFiles returns LTX file metadata for a level, optionally seeking by TXID.
8
+ * - openLtxFile returns a byte stream for a range of an LTX file.
9
+ * - writeLtxFile writes an LTX file, preserving its creation timestamp.
10
+ */
11
+ import type { Readable } from 'node:stream';
12
+ import type { FileInfo, Header, PageIndex, TXID } from './ltx/index.js';
13
+ import { formatFilename, parseFilename, type DecodedPage } from './ltx/index.js';
14
+ import { SqliteJsStreamError } from './errors.js';
15
+ import type { Logger } from './util/logger.js';
16
+ /** Sentinel error to stop early iteration in FindLTXFiles. */
17
+ export declare const ErrStopIter: unique symbol;
18
+ import { SnapshotLevel } from './ltx/constants.js';
19
+ /** SnapshotLevel is the LTX level reserved for full snapshots. */
20
+ export { SnapshotLevel };
21
+ export interface ReplicaClient {
22
+ /** Type returns the type of client (e.g. "file"). */
23
+ type(): string;
24
+ /** Init initializes the replica client connection (idempotent). */
25
+ init(): Promise<void>;
26
+ /**
27
+ * ltxFiles returns all LTX files for a level. If seek is non-zero, only files
28
+ * with MinTXID >= seek are returned. useMetadata controls timestamp accuracy.
29
+ */
30
+ ltxFiles(opts: LTXFilesOptions): AsyncIterable<FileInfo>;
31
+ /**
32
+ * openLtxFile returns a reader over an LTX file range. If size is 0 the range
33
+ * extends to the end of the file. Throws if the file does not exist.
34
+ */
35
+ openLtxFile(opts: OpenLTXFileOptions): Promise<Readable>;
36
+ /** writeLtxFile writes an LTX file to the replica and returns its metadata. */
37
+ writeLtxFile(opts: WriteLTXFileOptions, body: AsyncIterable<Uint8Array | string>): Promise<FileInfo>;
38
+ /** deleteLtxFiles deletes one or more LTX files. */
39
+ deleteLtxFiles(infos: FileInfo[]): Promise<void>;
40
+ /** deleteAll deletes all files on the replica. */
41
+ deleteAll(): Promise<void>;
42
+ /** setLogger sets the logger for the client. */
43
+ setLogger(logger: Logger): void;
44
+ }
45
+ export interface LTXFilesOptions {
46
+ level: number;
47
+ seek: TXID;
48
+ useMetadata: boolean;
49
+ }
50
+ export interface OpenLTXFileOptions {
51
+ level: number;
52
+ minTXID: TXID;
53
+ maxTXID: TXID;
54
+ offset: number;
55
+ size: number;
56
+ }
57
+ export interface WriteLTXFileOptions {
58
+ level: number;
59
+ minTXID: TXID;
60
+ maxTXID: TXID;
61
+ }
62
+ /** LTXDir returns the path to an LTX directory (root/ltx). */
63
+ export declare function ltxDir(root: string): string;
64
+ /** LTXLevelDir returns the path to an LTX level directory. */
65
+ export declare function ltxLevelDir(root: string, level: number): string;
66
+ /** LTXFilePath returns the path to a single LTX file. */
67
+ export declare function ltxFilePath(root: string, level: number, minTXID: TXID, maxTXID: TXID): string;
68
+ /** LTXError wraps errors reading/writing a specific LTX file. */
69
+ export declare class LTXError extends SqliteJsStreamError {
70
+ readonly op: string;
71
+ readonly path: string;
72
+ readonly level: number;
73
+ readonly minTXID: TXID;
74
+ readonly maxTXID: TXID;
75
+ readonly cause: unknown;
76
+ constructor(op: string, path: string, level: number, minTXID: TXID, maxTXID: TXID, err: unknown);
77
+ }
78
+ /**
79
+ * FindLTXFiles returns a list of LTX files on a level matching `filter`.
80
+ * The filter may throw ErrStopIter to end iteration early.
81
+ */
82
+ export declare function findLtxFiles(_ctx: unknown, client: ReplicaClient, level: number, useMetadata: boolean, filter: (info: FileInfo) => boolean | Promise<boolean>): Promise<FileInfo[]>;
83
+ /** FetchLTXHeader reads & returns the LTX header for the given file info. */
84
+ export declare function fetchLtxHeader(client: ReplicaClient, info: FileInfo): Promise<Header>;
85
+ /** FetchPageIndex decodes the page index from the tail of an LTX file. */
86
+ export declare function fetchPageIndex(client: ReplicaClient, info: FileInfo): Promise<PageIndex>;
87
+ /** Streaming fetchTail for the page index; sizes and reopens as needed. */
88
+ export declare function fetchPageIndexData(client: ReplicaClient, info: FileInfo): Promise<Uint8Array>;
89
+ /** FetchPage fetches and decodes a single page frame from an LTX file. */
90
+ export declare function fetchPage(client: ReplicaClient, level: number, minTXID: TXID, maxTXID: TXID, offset: number, size: number): Promise<DecodedPage>;
91
+ export { formatFilename, parseFilename };
92
+ //# sourceMappingURL=replica-client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"replica-client.d.ts","sourceRoot":"","sources":["../src/replica-client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,122 @@
1
+ /**
2
+ * ReplicaClient interface and shared helpers for interacting with a replica
3
+ * (an LTX destination). Mirrors litestream's `replica_client.go`.
4
+ *
5
+ * The interface is async/iterable oriented rather than Go's iterator/readcloser
6
+ * model, but the semantics match:
7
+ * - ltxFiles returns LTX file metadata for a level, optionally seeking by TXID.
8
+ * - openLtxFile returns a byte stream for a range of an LTX file.
9
+ * - writeLtxFile writes an LTX file, preserving its creation timestamp.
10
+ */
11
+ import nodePath from 'node:path';
12
+ import { decodePageData, decodePageIndex, formatFilename, HeaderSize, parseFilename, TrailerSize, unmarshalHeader, } from "./ltx/index.js";
13
+ import { ByteReader } from "./ltx/index.js";
14
+ import { LTXFormatError, SqliteJsStreamError } from "./errors.js";
15
+ import { readU64BE } from "./ltx/index.js";
16
+ import { readAll } from "./util/stream.js";
17
+ /** Sentinel error to stop early iteration in FindLTXFiles. */
18
+ export const ErrStopIter = Symbol('stop iterator');
19
+ import { SnapshotLevel } from "./ltx/constants.js";
20
+ /** SnapshotLevel is the LTX level reserved for full snapshots. */
21
+ export { SnapshotLevel };
22
+ /** LTXDir returns the path to an LTX directory (root/ltx). */
23
+ export function ltxDir(root) {
24
+ return nodePath.join(root, 'ltx');
25
+ }
26
+ /** LTXLevelDir returns the path to an LTX level directory. */
27
+ export function ltxLevelDir(root, level) {
28
+ return nodePath.join(ltxDir(root), String(level));
29
+ }
30
+ /** LTXFilePath returns the path to a single LTX file. */
31
+ export function ltxFilePath(root, level, minTXID, maxTXID) {
32
+ return nodePath.join(ltxLevelDir(root, level), formatFilename(minTXID, maxTXID));
33
+ }
34
+ /** LTXError wraps errors reading/writing a specific LTX file. */
35
+ export class LTXError extends SqliteJsStreamError {
36
+ op;
37
+ path;
38
+ level;
39
+ minTXID;
40
+ maxTXID;
41
+ cause;
42
+ constructor(op, path, level, minTXID, maxTXID, err) {
43
+ super('ERR_LTX', `${op} ltx file: ${err instanceof Error ? err.message : String(err)}`);
44
+ this.name = 'LTXError';
45
+ this.op = op;
46
+ this.path = path;
47
+ this.level = level;
48
+ this.minTXID = minTXID;
49
+ this.maxTXID = maxTXID;
50
+ this.cause = err;
51
+ }
52
+ }
53
+ const DEFAULT_ESTIMATED_PAGE_INDEX_SIZE = 32 * 1024;
54
+ /**
55
+ * FindLTXFiles returns a list of LTX files on a level matching `filter`.
56
+ * The filter may throw ErrStopIter to end iteration early.
57
+ */
58
+ export async function findLtxFiles(_ctx, client, level, useMetadata, filter) {
59
+ const out = [];
60
+ for await (const info of client.ltxFiles({ level, seek: 0n, useMetadata })) {
61
+ const match = await filter(info);
62
+ if (match)
63
+ out.push(info);
64
+ }
65
+ return out;
66
+ }
67
+ /** FetchLTXHeader reads & returns the LTX header for the given file info. */
68
+ export async function fetchLtxHeader(client, info) {
69
+ const rc = await client.openLtxFile({
70
+ level: info.level,
71
+ minTXID: info.minTXID,
72
+ maxTXID: info.maxTXID,
73
+ offset: 0,
74
+ size: HeaderSize,
75
+ });
76
+ const b = await readAll(rc);
77
+ return unmarshalHeader(b);
78
+ }
79
+ /** FetchPageIndex decodes the page index from the tail of an LTX file. */
80
+ export async function fetchPageIndex(client, info) {
81
+ const b = await fetchPageIndexData(client, info);
82
+ const r = new ByteReader(b, 0);
83
+ return decodePageIndex(r, info.level, info.minTXID, info.maxTXID);
84
+ }
85
+ /** Streaming fetchTail for the page index; sizes and reopens as needed. */
86
+ export async function fetchPageIndexData(client, info) {
87
+ let offset = info.size - DEFAULT_ESTIMATED_PAGE_INDEX_SIZE;
88
+ if (offset < 0)
89
+ offset = 0;
90
+ const f = await client.openLtxFile({
91
+ level: info.level,
92
+ minTXID: info.minTXID,
93
+ maxTXID: info.maxTXID,
94
+ offset,
95
+ size: 0,
96
+ });
97
+ const b = await readAll(f);
98
+ if (b.length < TrailerSize + 8) {
99
+ throw new LTXFormatError(`ltx file too short to contain a page index: ${b.length} bytes`);
100
+ }
101
+ const size = readU64BE(b, b.length - TrailerSize - 8);
102
+ const relativeStart = b.length - Number(size) - TrailerSize - 8;
103
+ if (relativeStart > 0) {
104
+ return b.subarray(relativeStart);
105
+ }
106
+ const f2 = await client.openLtxFile({
107
+ level: info.level,
108
+ minTXID: info.minTXID,
109
+ maxTXID: info.maxTXID,
110
+ offset: info.size - TrailerSize - 8 - Number(size),
111
+ size: 0,
112
+ });
113
+ return readAll(f2);
114
+ }
115
+ /** FetchPage fetches and decodes a single page frame from an LTX file. */
116
+ export async function fetchPage(client, level, minTXID, maxTXID, offset, size) {
117
+ const f = await client.openLtxFile({ level, minTXID, maxTXID, offset, size });
118
+ const b = await readAll(f);
119
+ return decodePageData(b);
120
+ }
121
+ // Re-exported for convenience in the file backend.
122
+ export { formatFilename, parseFilename };
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Replica URL parsing and replica-client factory registration.
3
+ * Mirrors litestream's `replica_url.go` (simplified: file scheme only for now).
4
+ */
5
+ import type { ReplicaClient } from './replica-client.js';
6
+ export type ReplicaClientFactory = (scheme: string, host: string, urlPath: string, query: URLSearchParams | null, userinfo: string | null) => ReplicaClient;
7
+ export interface ParsedReplicaURL {
8
+ scheme: string;
9
+ host: string;
10
+ urlPath: string;
11
+ query: URLSearchParams | null;
12
+ userinfo: string | null;
13
+ }
14
+ /** RegisterReplicaClientFactory registers a factory for a URL scheme. */
15
+ export declare function registerReplicaClientFactory(scheme: string, factory: ReplicaClientFactory): void;
16
+ /** NewReplicaClientFromURL creates a ReplicaClient from a URL string. */
17
+ export declare function newReplicaClientFromURL(rawURL: string): ReplicaClient;
18
+ /** ParseReplicaURLWithQuery parses a replica URL into components. */
19
+ export declare function parseReplicaURLWithQuery(s: string): ParsedReplicaURL;
20
+ //# sourceMappingURL=replica-url.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"replica-url.d.ts","sourceRoot":"","sources":["../src/replica-url.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAGzD,MAAM,MAAM,oBAAoB,GAAG,CACjC,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,eAAe,GAAG,IAAI,EAC7B,QAAQ,EAAE,MAAM,GAAG,IAAI,KACpB,aAAa,CAAC;AAEnB,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,eAAe,GAAG,IAAI,CAAC;IAC9B,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB;AAID,yEAAyE;AACzE,wBAAgB,4BAA4B,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,oBAAoB,GAAG,IAAI,CAEhG;AAED,yEAAyE;AACzE,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,MAAM,GAAG,aAAa,CAOrE;AAED,qEAAqE;AACrE,wBAAgB,wBAAwB,CAAC,CAAC,EAAE,MAAM,GAAG,gBAAgB,CA6BpE"}
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Replica URL parsing and replica-client factory registration.
3
+ * Mirrors litestream's `replica_url.go` (simplified: file scheme only for now).
4
+ */
5
+ import { ReplicaURLError } from "./errors.js";
6
+ const factories = new Map();
7
+ /** RegisterReplicaClientFactory registers a factory for a URL scheme. */
8
+ export function registerReplicaClientFactory(scheme, factory) {
9
+ factories.set(scheme, factory);
10
+ }
11
+ /** NewReplicaClientFromURL creates a ReplicaClient from a URL string. */
12
+ export function newReplicaClientFromURL(rawURL) {
13
+ const parsed = parseReplicaURLWithQuery(rawURL);
14
+ const factory = factories.get(parsed.scheme);
15
+ if (!factory) {
16
+ throw new ReplicaURLError(`unsupported replica URL scheme: ${parsed.scheme}`);
17
+ }
18
+ return factory(parsed.scheme, parsed.host, parsed.urlPath, parsed.query, parsed.userinfo);
19
+ }
20
+ /** ParseReplicaURLWithQuery parses a replica URL into components. */
21
+ export function parseReplicaURLWithQuery(s) {
22
+ let u;
23
+ try {
24
+ u = new URL(s);
25
+ }
26
+ catch (err) {
27
+ throw new ReplicaURLError(`parse replica url ${JSON.stringify(s)}: ${err instanceof Error ? err.message : String(err)}`);
28
+ }
29
+ const scheme = u.protocol.replace(/:$/, '');
30
+ if (scheme === 'file') {
31
+ return {
32
+ scheme: 'file',
33
+ host: '',
34
+ urlPath: u.pathname,
35
+ query: null,
36
+ userinfo: null,
37
+ };
38
+ }
39
+ if (scheme === '') {
40
+ throw new ReplicaURLError(`replica url scheme required: ${s}`);
41
+ }
42
+ return {
43
+ scheme,
44
+ host: u.host,
45
+ urlPath: decodeURIComponent(u.pathname),
46
+ query: u.searchParams,
47
+ userinfo: u.username ? `${u.username}:${u.password}` : null,
48
+ };
49
+ }
@@ -0,0 +1,379 @@
1
+ /**
2
+ * Replica manages replication of a single SQLite database (identified by its
3
+ * `path`) to a ReplicaClient.
4
+ *
5
+ * It reads the database + WAL directly from disk, writes level-0/level-9 LTX
6
+ * files into a local cache, uploads them to the client, tracks the replicated
7
+ * position, and can restore a database by merging LTX files. Mirrors
8
+ * litestream's `replica.go`, but is agnostic to the SQLite driver the
9
+ * application uses.
10
+ *
11
+ * For snapshot consistency it opens its own **independent read-only** SQLite
12
+ * connection (never the application's writable one) to pin the WAL while it
13
+ * reads. A single SQLite connection holds one transaction at a time, so
14
+ * reusing an application `DatabaseSync` handle would merge the read snapshot
15
+ * with the app's writes (and could read uncommitted rows). Keep the app's
16
+ * writer and the library's reader on separate connections to the same file.
17
+ */
18
+ import { CompactionLevels, type FileInfo } from './ltx/index.js';
19
+ import type { ReplicaClient } from './replica-client.js';
20
+ import { type Leaser } from './leaser.js';
21
+ import type { Logger } from './util/logger.js';
22
+ import { SqliteJsStreamError } from './errors.js';
23
+ export interface RestoreOptions {
24
+ outputPath: string;
25
+ txID?: bigint;
26
+ timestamp?: Date;
27
+ }
28
+ /** Options for {@link Replica.follow}, litestream's `restore -f` continuous mode. */
29
+ export interface FollowOptions {
30
+ /** Output database path to continuously restore into. */
31
+ outputPath: string;
32
+ /** Milliseconds between polls for new LTX files. Defaults to 1000. */
33
+ intervalMs?: number;
34
+ /** Abort to stop the follow loop. */
35
+ signal?: AbortSignal;
36
+ /**
37
+ * Sidecar file recording the last applied TXID, so a later `follow()` can
38
+ * resume instead of re-restoring. Defaults to `${outputPath}-txid`. Written
39
+ * atomically (temp + rename) after each applied batch. `follow()` refuses to
40
+ * resume when the DB exists but this file is missing (it cannot prove the DB
41
+ * matches the replica and would otherwise corrupt it).
42
+ */
43
+ txidFile?: string;
44
+ }
45
+ /**
46
+ * Base class for errors thrown by {@link Replica.follow}. Carries a stable,
47
+ * Node-style `code` so callers can branch on the failure without matching
48
+ * message text, and can be caught via `instanceof`.
49
+ */
50
+ export declare class FollowError extends SqliteJsStreamError {
51
+ constructor(code: string, message: string);
52
+ }
53
+ /** The database exists but its `-txid` sidecar is missing, so we can't resume. */
54
+ export declare class FollowMissingTxidError extends FollowError {
55
+ constructor(message: string);
56
+ }
57
+ /** The `-txid` sidecar is present but does not parse as a TXID. */
58
+ export declare class FollowInvalidTxidError extends FollowError {
59
+ constructor(message: string);
60
+ }
61
+ /** The saved TXID is ahead of anything the replica holds; re-restore. */
62
+ export declare class FollowAheadOfLatestError extends FollowError {
63
+ constructor(message: string);
64
+ }
65
+ /** The saved TXID is below the retained window; retention pruned the next file. */
66
+ export declare class FollowDataGapError extends FollowError {
67
+ constructor(message: string);
68
+ }
69
+ /** Follow was aborted before the initial restore could complete. */
70
+ export declare class FollowAbortedError extends FollowError {
71
+ constructor(message: string);
72
+ }
73
+ export interface SyncStatus {
74
+ localTXID: bigint;
75
+ remoteTXID: bigint;
76
+ inSync: boolean;
77
+ }
78
+ /**
79
+ * Default highest LTX compaction level (L0 -> L1 -> ... -> L{max}) for the
80
+ * legacy {@link CompactOptions.maxLevel} path. Prefer {@link CompactionLevels}.
81
+ */
82
+ export declare const DefaultMaxCompactionLevel = 3;
83
+ export interface CompactOptions {
84
+ /**
85
+ * Destination level to compact into (1..maxLevel). When omitted, the first
86
+ * level (1..maxLevel) that has pending source files is compacted.
87
+ */
88
+ dstLevel?: number;
89
+ }
90
+ /** Retention/GC policy for pruning old snapshots and compacted files. */
91
+ export interface RetentionOptions {
92
+ /**
93
+ * Delete level-9 snapshots older than this many milliseconds. The newest
94
+ * snapshot is always kept. Defaults to 0 (keep all snapshots).
95
+ */
96
+ snapshotRetentionMs?: number;
97
+ /**
98
+ * Keep at least this many newest level-9 snapshots even if they are older
99
+ * than {@link snapshotRetentionMs}. Defaults to 1 (always keep the newest).
100
+ */
101
+ snapshotRetain?: number;
102
+ /**
103
+ * Minimum age (ms) before a level-0 file that has been compacted into level-1
104
+ * is deleted. Defaults to 0 (no L0 time-based GC).
105
+ */
106
+ l0RetentionMs?: number;
107
+ }
108
+ export interface RetentionResult {
109
+ snapshotsDeleted: number;
110
+ filesDeleted: number;
111
+ /** MaxTXID of the last snapshot that was deleted; files below it are removed. */
112
+ boundary: bigint;
113
+ }
114
+ /** Returned by compaction scheduling when there is nothing to compact. */
115
+ export declare class ErrNoCompactionError extends SqliteJsStreamError {
116
+ constructor();
117
+ }
118
+ export declare const ErrNoCompaction: ErrNoCompactionError;
119
+ /** Returned when a level was already compacted within its current time bucket. */
120
+ export declare class ErrCompactionTooEarlyError extends SqliteJsStreamError {
121
+ constructor();
122
+ }
123
+ export declare const ErrCompactionTooEarly: ErrCompactionTooEarlyError;
124
+ /** Raised when a restore/plan cannot find LTX files at or below the target. */
125
+ export declare class NoMatchingBackupError extends SqliteJsStreamError {
126
+ constructor(message?: string);
127
+ }
128
+ export interface ReplicaRunOptions {
129
+ /** Milliseconds between syncs. Defaults to 1000. */
130
+ intervalMs?: number;
131
+ /** Abort to stop continuous syncing. */
132
+ signal?: AbortSignal;
133
+ /**
134
+ * Per-level compaction schedule. Defaults to {@link defaultCompactionLevels}.
135
+ * Levels are compacted at most once per wall-clock bucket.
136
+ */
137
+ compactionLevels?: CompactionLevels;
138
+ /**
139
+ * Legacy: max compaction level when {@link compactionLevels} is not given.
140
+ * Defaults to {@link DefaultMaxCompactionLevel}.
141
+ */
142
+ maxLevel?: number;
143
+ /**
144
+ * Legacy: cascade-compact all levels every N ms (disables per-level buckets
145
+ * when set). Defaults to 0 (disabled).
146
+ */
147
+ compactionIntervalMs?: number;
148
+ /** Legacy: run {@link Replica.enforceRetention} every N ms. Defaults to 0. */
149
+ retentionIntervalMs?: number;
150
+ /** Retention policy used by the legacy retention loop. */
151
+ retention?: RetentionOptions;
152
+ /**
153
+ * Milliseconds between level-9 snapshots while running (0 disables).
154
+ * Defaults to 0.
155
+ */
156
+ snapshotIntervalMs?: number;
157
+ /** Time-based snapshot retention (ms) applied after each snapshot. */
158
+ snapshotRetentionMs?: number;
159
+ /** Keep at least this many newest snapshots (default 1). */
160
+ snapshotRetain?: number;
161
+ /**
162
+ * Min age (ms) before a compacted level-0 file is deleted. When > 0 an L0
163
+ * retention pass runs on {@link l0RetentionCheckIntervalMs}. Defaults to 0.
164
+ */
165
+ l0RetentionMs?: number;
166
+ /** How often (ms) to run the L0 time-retention pass. Defaults to 15s. */
167
+ l0RetentionCheckIntervalMs?: number;
168
+ }
169
+ /** Replica replicates a single database (by path) to a ReplicaClient. */
170
+ export declare class Replica {
171
+ readonly path: string;
172
+ readonly client: ReplicaClient;
173
+ private logger;
174
+ private posValue;
175
+ private db;
176
+ private compactionLevelsValue;
177
+ private leaserValue;
178
+ private leasePrimary;
179
+ private leaseCurrent;
180
+ private leaseTimer;
181
+ private runActive;
182
+ constructor(path: string, client: ReplicaClient, logger?: Logger, options?: {
183
+ maxLevel?: number;
184
+ compactionLevels?: CompactionLevels;
185
+ leaser?: Leaser;
186
+ });
187
+ /** Leaser optionally bounds this replica to a single primary across hosts. */
188
+ get leaser(): Leaser | null;
189
+ set leaser(leaser: Leaser | null);
190
+ /**
191
+ * IsPrimary reports whether this replica may currently write. Always true
192
+ * when no {@link Leaser} is configured; false while another host holds the
193
+ * lease. Updated by {@link run}.
194
+ */
195
+ isPrimary(): boolean;
196
+ /** @internal Throws if a leaser is set but this replica does not hold it. */
197
+ private assertCanWrite;
198
+ /** Per-level compaction schedule. Defaults to {@link defaultCompactionLevels}. */
199
+ get compactionLevels(): CompactionLevels;
200
+ set compactionLevels(levels: CompactionLevels);
201
+ /** Highest non-snapshot compaction level this replica will produce. */
202
+ get maxCompactionLevel(): number;
203
+ set maxCompactionLevel(level: number);
204
+ /** Lazily opens the local database reader (cached). */
205
+ private localDb;
206
+ /** Pos returns the current replicated position (max level-0 maxTXID). */
207
+ pos(): Promise<bigint>;
208
+ /**
209
+ * CalcPos finds the maximum TXID on the replica across all levels. Since
210
+ * compaction moves the newest data to higher levels and prunes level-0, the
211
+ * position must be derived from every level (and any snapshot).
212
+ */
213
+ calcPos(): Promise<bigint>;
214
+ /** LocalPos returns the local cached position (max local level-0 maxTXID). */
215
+ localPos(): Promise<bigint>;
216
+ /**
217
+ * Sync builds a level-0 LTX file locally (if there are new WAL changes) and
218
+ * uploads any pending local files to the client. Returns the file that was
219
+ * written locally, or null if there was nothing new to do.
220
+ */
221
+ sync(): Promise<FileInfo | null>;
222
+ /** SyncAndWait uploads all pending LTX files; harmless if already synced. */
223
+ syncAndWait(): Promise<void>;
224
+ /**
225
+ * Run continuously drives the replica until `signal` is aborted. It syncs on
226
+ * `intervalMs`, compacts per level on each level's wall-clock bucket, takes
227
+ * snapshots on `snapshotIntervalMs`, and enforces retention. Errors are logged
228
+ * and the loop keeps going, so a transient failure does not stop replication.
229
+ *
230
+ * Compaction mirrors litestream: each level is compacted at most once per
231
+ * bucket (see {@link CompactionLevels}); the legacy `compactionIntervalMs`
232
+ * cascades all levels on a fixed interval instead.
233
+ */
234
+ run(opt?: ReplicaRunOptions): Promise<void>;
235
+ /**
236
+ * Schedules the next lease renewal to fire just before expiry, independent of
237
+ * the run-loop cadence. Reschedules after every successful renewal.
238
+ */
239
+ private scheduleLeaseRenewal;
240
+ /** Renews the lease and reschedules; reverts to follower if we lost it. */
241
+ private renewLeaseLoop;
242
+ /** Cancels any pending lease renewal. */
243
+ private stopLeaseRenewal;
244
+ /** Snapshot writes and uploads a level-9 full-database LTX file. */
245
+ snapshot(): Promise<FileInfo | null>;
246
+ /** SyncStatus reports the local and remote positions. */
247
+ syncStatus(): Promise<SyncStatus>;
248
+ /** Uploads a single local LTX file to the client. */
249
+ private uploadLtxFile;
250
+ /** EnsureExists restores the local database if it is missing. */
251
+ ensureExists(): Promise<void>;
252
+ /** Restore reconstructs a SQLite database at `outputPath` from LTX files. */
253
+ restore(opt: RestoreOptions): Promise<void>;
254
+ /**
255
+ * Follow continuously restores new LTX files into {@link FollowOptions.outputPath},
256
+ * keeping a read-only replica of the database up to date with the primary.
257
+ *
258
+ * On the first call (no output DB yet, or the replica is empty) it restores the
259
+ * latest backup as the base, then polls (every {@link FollowOptions.intervalMs})
260
+ * and applies any newly replicated LTX files as they appear. It records the
261
+ * applied TXID in a `-txid` sidecar after each batch so a later `follow()` can
262
+ * resume, and the loop runs until {@link FollowOptions.signal} is aborted.
263
+ *
264
+ * The restored database must only be opened **read-only**; writing to it while
265
+ * follow runs will conflict with the pages we overlay.
266
+ */
267
+ follow(opt: FollowOptions): Promise<void>;
268
+ /**
269
+ * Guards a follow() resume against an inconsistent state: if the saved TXID is
270
+ * ahead of every TXID the replica holds, the DB/sidecar cannot be trusted and
271
+ * must be re-restored. (A saved TXID below the retained window is caught later
272
+ * as a data gap in {@link collectFollowBatch}.)
273
+ */
274
+ private validateResumePoint;
275
+ /**
276
+ * Waits for the first backup to appear on an empty replica, then restores it
277
+ * as the follow base. Returns the plan that was applied.
278
+ */
279
+ private waitForInitialRestore;
280
+ /**
281
+ * Returns the contiguous run of LTX files (across all compaction levels) that
282
+ * extend the applied position `currentMax`, in application order. Prefers the
283
+ * highest (most compacted) level for a range and stops at the first gap. Throws
284
+ * if the very next file (currentMax + 1) is missing, e.g. retention pruned it.
285
+ */
286
+ private collectFollowBatch;
287
+ /**
288
+ * Applies a contiguous batch of LTX files to the existing `outputPath` DB by
289
+ * overlaying each file's pages (a later page wins) and truncating to the final
290
+ * commit size. Returns the TXID now applied.
291
+ */
292
+ private applyFollowBatch;
293
+ /** Opens a streaming LTX reader over a plan file from the client. */
294
+ private openStreamReader;
295
+ /** Close releases any internal database connection. */
296
+ close(): void;
297
+ /**
298
+ * Compact merges source LTX files into the next level. If `dstLevel` is
299
+ * given, compacts that level; otherwise compacts the first level (1..max)
300
+ * that has pending source files. Returns the written file, or null if there
301
+ * was nothing to compact.
302
+ */
303
+ compact(options?: CompactOptions): Promise<FileInfo | null>;
304
+ /**
305
+ * CompactLevel compacts pending files at `dstLevel - 1` into a single file at
306
+ * `dstLevel`. It streams readers (local cache preferred, client fallback),
307
+ * writes the result locally via a file-backed sink, uploads it to the client,
308
+ * and returns the new file's metadata. Source files are left in place; GC is
309
+ * performed by {@link enforceRetention}.
310
+ */
311
+ compactLevel(dstLevel: number): Promise<FileInfo | null>;
312
+ /**
313
+ * CompactDB compacts `dstLevel` if it is time to do so and there is pending
314
+ * source data. Mirrors litestream's `Store.CompactDB`: it refuses to re-compact
315
+ * within the level's current time bucket (throws {@link ErrCompactionTooEarly})
316
+ * and skips when there is nothing to do (throws {@link ErrNoCompaction}).
317
+ */
318
+ compactDB(dstLevel: number, now: number): Promise<FileInfo | null>;
319
+ /**
320
+ * CompactSnapshot takes a level-9 snapshot if it is time to do so and the
321
+ * database has advanced past the current snapshot. Mirrors `Store.CompactDB`
322
+ * for the snapshot level.
323
+ */
324
+ compactSnapshot(now: number, intervalMs: number): Promise<FileInfo | null>;
325
+ /** MaxLTXFileInfo returns the highest-TXID file at a level, or null. */
326
+ maxLTXFileInfo(level: number): Promise<FileInfo | null>;
327
+ /**
328
+ * EnforceRetention prunes old snapshots and superseded files.
329
+ *
330
+ * 1. Snapshots older than `snapshotRetentionMs` are deleted (the newest is
331
+ * always kept; `snapshotRetain` may cap how many newest are kept).
332
+ * 2. The resulting snapshot boundary is cascaded down through levels 0..max:
333
+ * any file whose maxTXID is below the oldest retained snapshot's maxTXID
334
+ * is deleted (it is superseded by that snapshot).
335
+ * 3. Level-0 files that have been compacted into a higher level and are older
336
+ * than `l0RetentionMs` are deleted (except the newest, the live head).
337
+ */
338
+ enforceRetention(options?: RetentionOptions): Promise<RetentionResult>;
339
+ /**
340
+ * EnforceSnapshotRetention deletes snapshots older than `retentionMs` and
341
+ * returns the boundary (max maxTXID of the deleted snapshots). The newest
342
+ * snapshot is always kept; `retain` may keep additional newest snapshots.
343
+ */
344
+ enforceSnapshotRetention(now: number, retentionMs: number, retain?: number): Promise<{
345
+ deleted: number;
346
+ boundary: bigint;
347
+ }>;
348
+ /**
349
+ * EnforceRetentionByTXID deletes files at `level` with maxTXID below `txID`,
350
+ * always keeping at least one file. Returns the number deleted.
351
+ */
352
+ enforceRetentionByTXID(level: number, txID: bigint): Promise<number>;
353
+ /**
354
+ * EnforceL0RetentionByTime deletes level-0 files that have been compacted into
355
+ * a higher level and are older than `l0RetentionMs`. It never deletes the
356
+ * newest level-0 file (the live head) and preserves contiguous L0 coverage by
357
+ * stopping at the first file that is not old enough.
358
+ */
359
+ enforceL0RetentionByTime(now: number, l0RetentionMs: number): Promise<number>;
360
+ /** Returns true if `info` is fully contained in a file at a higher level. */
361
+ private isCoveredByHigherLevel;
362
+ /** Lists LTX files at a remote level. */
363
+ private listRemoteLevel;
364
+ /** Deletes files from the client and the local cache. */
365
+ private deleteFiles;
366
+ /**
367
+ * Opens a streaming LTX reader for a source file, preferring the local cache
368
+ * and falling back to the client. Collects cleanup callbacks for the streams.
369
+ */
370
+ private openSourceReader;
371
+ }
372
+ /**
373
+ * CalcRestorePlan returns LTX files to apply, in order, to reconstruct a
374
+ * database up to `txID` (0 = latest). It prefers the latest level-9 snapshot
375
+ * before the target as the base, then appends contiguous files across all
376
+ * compaction levels (0..maxLevel) that extend the range.
377
+ */
378
+ export declare function calcRestorePlan(client: ReplicaClient, txID: bigint): Promise<FileInfo[]>;
379
+ //# sourceMappingURL=replica.d.ts.map