@delali/sirannon-db 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.
@@ -0,0 +1,295 @@
1
+ import Database from 'better-sqlite3';
2
+ import { B as BackupScheduleOptions, D as DatabaseOptions, L as LifecycleConfig, P as Params, E as ExecuteResult } from '../types-DArCObcu.js';
3
+ export { A as AfterQueryHook, a as BeforeConnectHook, b as BeforeQueryHook, c as BeforeSubscribeHook, C as CDCMetrics, d as ChangeEvent, e as ChangeOperation, f as ClientOptions, g as ConnectionHookContext, h as ConnectionMetrics, i as CorsOptions, j as DatabaseCloseHook, k as DatabaseOpenHook, H as HookConfig, M as MetricsConfig, O as OnRequestHook, Q as QueryHookContext, l as QueryMetrics, R as RequestContext, m as RequestDenial, S as ServerOptions, n as SirannonOptions, o as Subscription, p as SubscriptionBuilder, W as WSHandlerOptions } from '../types-DArCObcu.js';
4
+ import { D as Database$1, M as Migration, a as MigrationResult, R as RollbackResult } from '../sirannon-BJ8Yd1Uf.js';
5
+ export { A as AppliedMigration, b as AppliedMigrationEntry, H as HookDispose, c as HookEvent, d as HookEventContextMap, e as HookHandler, f as HookRegistry, g as MetricsCollector, S as Sirannon, h as SubscribeHookContext, T as Transaction } from '../sirannon-BJ8Yd1Uf.js';
6
+
7
+ type SqliteDb$4 = InstanceType<typeof Database>;
8
+ declare class BackupManager {
9
+ /**
10
+ * Creates a one-shot backup of the database using VACUUM INTO.
11
+ * Produces a fresh, defragmented copy at the specified destination path.
12
+ *
13
+ * The destination file must not already exist. Parent directories are
14
+ * created automatically when missing.
15
+ *
16
+ * Note: there is a narrow TOCTOU window between the existence check and
17
+ * the VACUUM INTO statement. In the unlikely event that another process
18
+ * creates a file at the same path during that window, VACUUM INTO may
19
+ * silently overwrite it depending on the SQLite version.
20
+ */
21
+ backup(db: SqliteDb$4, destPath: string): void;
22
+ /**
23
+ * Generates a timestamped backup filename.
24
+ *
25
+ * Format: `backup-YYYY-MM-DDTHH-MM-SS-mmmZ.db`
26
+ *
27
+ * Colons and dots in the ISO timestamp are replaced with hyphens so the
28
+ * filename is safe on every major filesystem.
29
+ */
30
+ generateFilename(): string;
31
+ /**
32
+ * Removes old backup files in {@link dir}, keeping the {@link maxFiles}
33
+ * most recent entries. Only files matching the `backup-*.db` naming
34
+ * convention are considered; other files in the directory are left alone.
35
+ *
36
+ * When {@link maxFiles} is zero or negative the method is a no-op.
37
+ * A non-existent directory is silently ignored.
38
+ */
39
+ rotate(dir: string, maxFiles: number): void;
40
+ }
41
+
42
+ type SqliteDb$3 = InstanceType<typeof Database>;
43
+ declare class BackupScheduler {
44
+ private readonly manager;
45
+ constructor(manager?: BackupManager);
46
+ /**
47
+ * Schedules periodic backups on a cron expression.
48
+ *
49
+ * Each tick creates a timestamped backup file inside {@link options.destDir}
50
+ * and rotates old files so no more than {@link options.maxFiles} (default 5)
51
+ * are retained.
52
+ *
53
+ * Provide {@link options.onError} to receive notification when a scheduled
54
+ * backup fails. Without it, errors are silently discarded to prevent
55
+ * unhandled exceptions from crashing the process.
56
+ *
57
+ * The underlying timer is unreferenced so it won't keep the Node.js
58
+ * process alive on its own (consistent with the CDC polling timer).
59
+ *
60
+ * Returns a cancel function that stops the scheduled job immediately.
61
+ */
62
+ schedule(db: SqliteDb$3, options: BackupScheduleOptions): () => void;
63
+ }
64
+
65
+ interface ConnectionPoolOptions {
66
+ path: string;
67
+ readOnly?: boolean;
68
+ readPoolSize?: number;
69
+ walMode?: boolean;
70
+ }
71
+ type SqliteDb$2 = InstanceType<typeof Database>;
72
+ declare class ConnectionPool {
73
+ private readonly writer;
74
+ private readonly readers;
75
+ private readerIndex;
76
+ private closed;
77
+ constructor(options: ConnectionPoolOptions);
78
+ acquireReader(): SqliteDb$2;
79
+ acquireWriter(): SqliteDb$2;
80
+ get readerCount(): number;
81
+ get isReadOnly(): boolean;
82
+ loadExtension(extensionPath: string): void;
83
+ close(): void;
84
+ }
85
+
86
+ /**
87
+ * Base class for all sirannon-db errors. Extend this class to create
88
+ * domain-specific errors that carry a machine-readable {@link code}.
89
+ */
90
+ declare class SirannonError extends Error {
91
+ readonly code: string;
92
+ constructor(message: string, code: string);
93
+ }
94
+ /**
95
+ * Thrown when a database ID cannot be resolved in the registry.
96
+ * This typically means the database was never opened or has already been closed.
97
+ */
98
+ declare class DatabaseNotFoundError extends SirannonError {
99
+ constructor(id: string);
100
+ }
101
+ /**
102
+ * Thrown when attempting to register a database with an ID that is already
103
+ * in use. Each database ID must be unique within the registry.
104
+ */
105
+ declare class DatabaseAlreadyExistsError extends SirannonError {
106
+ constructor(id: string);
107
+ }
108
+ /**
109
+ * Thrown when a write operation is attempted on a database that was opened
110
+ * in read-only mode.
111
+ */
112
+ declare class ReadOnlyError extends SirannonError {
113
+ constructor(id: string);
114
+ }
115
+ /**
116
+ * Thrown when SQLite fails to execute a statement. The {@link sql} property
117
+ * holds the original SQL string that caused the failure, which is useful for
118
+ * debugging and logging.
119
+ */
120
+ declare class QueryError extends SirannonError {
121
+ readonly sql: string;
122
+ constructor(message: string, sql: string);
123
+ }
124
+ /**
125
+ * Thrown when a transaction cannot be committed or is forcibly rolled back.
126
+ * Check the message for the underlying cause.
127
+ */
128
+ declare class TransactionError extends SirannonError {
129
+ constructor(message: string);
130
+ }
131
+ /**
132
+ * Thrown when a migration step fails. The {@link version} property identifies
133
+ * which schema version triggered the error so the failure can be pinpointed
134
+ * in the migration history.
135
+ */
136
+ declare class MigrationError extends SirannonError {
137
+ readonly version: number;
138
+ constructor(message: string, version: number, code?: string);
139
+ }
140
+ /**
141
+ * Thrown when a before-hook explicitly rejects an operation. The optional
142
+ * `reason` string is surfaced in the message so callers can distinguish
143
+ * between different hook policies.
144
+ */
145
+ declare class HookDeniedError extends SirannonError {
146
+ constructor(hookName: string, reason?: string);
147
+ }
148
+ /**
149
+ * Thrown when the change-data-capture pipeline encounters an unrecoverable
150
+ * error, such as a failed event dispatch or a corrupt change record.
151
+ */
152
+ declare class CDCError extends SirannonError {
153
+ constructor(message: string);
154
+ }
155
+ /**
156
+ * Thrown when a backup operation fails, whether that is an online backup via
157
+ * the SQLite backup API or a file-level copy.
158
+ */
159
+ declare class BackupError extends SirannonError {
160
+ constructor(message: string);
161
+ }
162
+ /**
163
+ * Thrown when the connection pool reaches its limit or is configured with
164
+ * invalid parameters such as a minimum size greater than the maximum.
165
+ */
166
+ declare class ConnectionPoolError extends SirannonError {
167
+ constructor(message: string);
168
+ }
169
+ /**
170
+ * Thrown when opening a new database would exceed the configured cap on
171
+ * concurrently open databases. Close an existing database before opening
172
+ * another one.
173
+ */
174
+ declare class MaxDatabasesError extends SirannonError {
175
+ constructor(max: number);
176
+ }
177
+ /**
178
+ * Thrown when a native SQLite extension cannot be loaded. The `path` argument
179
+ * is the filesystem path passed to `load_extension`, and the optional `cause`
180
+ * string carries the error detail reported by SQLite.
181
+ */
182
+ declare class ExtensionError extends SirannonError {
183
+ constructor(path: string, cause?: string);
184
+ }
185
+
186
+ /**
187
+ * Callbacks the LifecycleManager uses to interact with the database registry
188
+ * (Sirannon). Injected at construction to avoid circular dependencies.
189
+ */
190
+ interface LifecycleCallbacks {
191
+ open: (id: string, path: string, options?: DatabaseOptions) => Database$1;
192
+ close: (id: string) => void;
193
+ count: () => number;
194
+ has: (id: string) => boolean;
195
+ }
196
+ /**
197
+ * Manages automatic database lifecycle: on-demand opening via a resolver,
198
+ * idle-timeout based closing, and LRU eviction when the maximum number of
199
+ * open databases is reached.
200
+ */
201
+ declare class LifecycleManager {
202
+ private readonly config;
203
+ private readonly callbacks;
204
+ private readonly lastAccess;
205
+ private idleTimer;
206
+ private _disposed;
207
+ constructor(config: LifecycleConfig, callbacks: LifecycleCallbacks);
208
+ /**
209
+ * Attempt to auto-open a database by ID using the configured resolver.
210
+ * Returns the opened Database, or `undefined` when no resolver is
211
+ * configured or the resolver does not recognise the ID.
212
+ *
213
+ * Throws {@link MaxDatabasesError} when the registry is at capacity and
214
+ * eviction cannot free a slot.
215
+ */
216
+ resolve(id: string): Database$1 | undefined;
217
+ /** Record an access for the given database ID. */
218
+ markActive(id: string): void;
219
+ /**
220
+ * Close every database whose last access was longer ago than the
221
+ * configured idle timeout. Also cleans up tracking entries for
222
+ * databases that were closed externally.
223
+ */
224
+ checkIdle(): void;
225
+ /**
226
+ * Close the least-recently-used tracked database. Called internally
227
+ * by {@link resolve} when `maxOpen` capacity is reached.
228
+ */
229
+ evict(): void;
230
+ /** Remove a database from idle tracking (e.g. after an explicit close). */
231
+ untrack(id: string): void;
232
+ /** Whether this manager has been disposed. */
233
+ get disposed(): boolean;
234
+ /** The number of databases currently tracked for idle management. */
235
+ get trackedCount(): number;
236
+ /** Shut down the manager: stop the idle timer and clear all state. */
237
+ dispose(): void;
238
+ private ensureNotDisposed;
239
+ }
240
+
241
+ /**
242
+ * Options for {@link createTenantResolver}.
243
+ */
244
+ interface TenantResolverOptions {
245
+ /** Base directory where tenant database files are stored. */
246
+ basePath: string;
247
+ /** File extension for database files. Default: `'.db'`. */
248
+ extension?: string;
249
+ /** Default options applied to every auto-opened tenant database. */
250
+ defaultOptions?: DatabaseOptions;
251
+ }
252
+ /**
253
+ * Validate and sanitize a tenant ID. Returns the ID unchanged when
254
+ * it passes validation, or `undefined` when it is invalid.
255
+ *
256
+ * Rules:
257
+ * - Must be 1–255 characters long
258
+ * - Must start with a letter or digit
259
+ * - May contain letters, digits, hyphens, and underscores
260
+ * - Must not contain `..` (redundant given the regex, but explicit)
261
+ */
262
+ declare function sanitizeTenantId(id: string): string | undefined;
263
+ /**
264
+ * Build a filesystem path for a tenant database.
265
+ *
266
+ * @throws {Error} when the tenant ID fails validation.
267
+ */
268
+ declare function tenantPath(basePath: string, tenantId: string, extension?: string): string;
269
+ /**
270
+ * Create a resolver function suitable for {@link LifecycleConfig.autoOpen}.
271
+ * Maps tenant IDs to database file paths under a common base directory.
272
+ *
273
+ * Invalid tenant IDs (path traversal, special characters) cause the
274
+ * resolver to return `undefined`, preventing the database from opening.
275
+ */
276
+ declare function createTenantResolver(options: TenantResolverOptions): (id: string) => {
277
+ path: string;
278
+ options?: DatabaseOptions;
279
+ } | undefined;
280
+
281
+ type SqliteDb$1 = InstanceType<typeof Database>;
282
+ declare class MigrationRunner {
283
+ static run(db: SqliteDb$1, input: string | Migration[]): MigrationResult;
284
+ static rollback(db: SqliteDb$1, input: string | Migration[], version?: number): RollbackResult;
285
+ private static validateMigrations;
286
+ private static getAppliedVersions;
287
+ }
288
+
289
+ type SqliteDb = InstanceType<typeof Database>;
290
+ declare function query<T = Record<string, unknown>>(db: SqliteDb, sql: string, params?: Params): T[];
291
+ declare function queryOne<T = Record<string, unknown>>(db: SqliteDb, sql: string, params?: Params): T | undefined;
292
+ declare function execute(db: SqliteDb, sql: string, params?: Params): ExecuteResult;
293
+ declare function executeBatch(db: SqliteDb, sql: string, paramsBatch: Params[]): ExecuteResult[];
294
+
295
+ export { BackupError, BackupManager, BackupScheduleOptions, BackupScheduler, CDCError, ConnectionPool, ConnectionPoolError, type ConnectionPoolOptions, Database$1 as Database, DatabaseAlreadyExistsError, DatabaseNotFoundError, DatabaseOptions, ExecuteResult, ExtensionError, HookDeniedError, type LifecycleCallbacks, LifecycleConfig, LifecycleManager, MaxDatabasesError, Migration, MigrationError, MigrationResult, MigrationRunner, Params, QueryError, ReadOnlyError, RollbackResult, SirannonError, type TenantResolverOptions, TransactionError, createTenantResolver, execute, executeBatch, query, queryOne, sanitizeTenantId, tenantPath };