@delali/sirannon-db 0.1.4 → 0.1.5
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/README.md +415 -39
- package/dist/backup-scheduler/index.d.ts +2 -2
- package/dist/change-tracker-CFTQ9TSn.d.ts +89 -0
- package/dist/chunk-3MCMONVP.mjs +115 -0
- package/dist/chunk-ER7ODTDA.mjs +23 -0
- package/dist/chunk-GS7T5YMI.mjs +51 -0
- package/dist/{chunk-AX66KWBR.mjs → chunk-UTO3ZAFS.mjs} +226 -64
- package/dist/chunk-UVMVN3OT.mjs +111 -0
- package/dist/client/index.d.ts +99 -42
- package/dist/client/index.mjs +726 -26
- package/dist/core/index.d.ts +11 -108
- package/dist/core/index.mjs +134 -168
- package/dist/{sirannon-B1oTfebD.d.ts → database-BVY1GqE7.d.ts} +8 -33
- package/dist/errors-C00ed08Q.d.ts +101 -0
- package/dist/file-migrations/index.d.ts +2 -2
- package/dist/{index-hXiis3N-.d.ts → index-CLdNrcPz.d.ts} +1 -1
- package/dist/replication/coordinator/etcd.d.ts +44 -0
- package/dist/replication/coordinator/etcd.mjs +650 -0
- package/dist/replication/index.d.ts +491 -0
- package/dist/replication/index.mjs +3784 -0
- package/dist/server/index.d.ts +14 -3
- package/dist/server/index.mjs +262 -44
- package/dist/sirannon-Cd-lK6T0.d.ts +31 -0
- package/dist/transport/grpc.d.ts +316 -0
- package/dist/transport/grpc.mjs +3341 -0
- package/dist/transport/memory.d.ts +221 -0
- package/dist/transport/memory.mjs +337 -0
- package/dist/types-B2byqt0B.d.ts +273 -0
- package/dist/types-BEu1I_9_.d.ts +139 -0
- package/dist/types-BeozgNPr.d.ts +26 -0
- package/dist/{types-DtDutWRU.d.ts → types-D-74JiXb.d.ts} +78 -2
- package/package.json +54 -10
- package/dist/types-DRkJlqex.d.ts +0 -38
package/dist/core/index.d.ts
CHANGED
|
@@ -1,12 +1,15 @@
|
|
|
1
|
-
export { B as BackupManager, a as BackupScheduler } from '../index-
|
|
1
|
+
export { B as BackupManager, a as BackupScheduler } from '../index-CLdNrcPz.js';
|
|
2
|
+
export { C as ChangeTracker, a as ChangeTrackerOptions } from '../change-tracker-CFTQ9TSn.js';
|
|
2
3
|
import { S as SQLiteDriver, a as SQLiteConnection } from '../types-BFSsG77t.js';
|
|
3
4
|
export { D as DriverCapabilities, O as OpenOptions, R as RunResult, b as SQLiteStatement } from '../types-BFSsG77t.js';
|
|
4
|
-
import { D as Database } from '../
|
|
5
|
-
export { H as HookDispose, a as HookEvent, b as HookEventContextMap, c as HookHandler, d as HookRegistry, M as MetricsCollector, S as
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
5
|
+
import { D as Database } from '../database-BVY1GqE7.js';
|
|
6
|
+
export { H as HookDispose, a as HookEvent, b as HookEventContextMap, c as HookHandler, d as HookRegistry, M as MetricsCollector, S as SubscribeHookContext } from '../database-BVY1GqE7.js';
|
|
7
|
+
export { B as BackupError, C as CDCError, a as ConnectionPoolError, D as DatabaseAlreadyExistsError, b as DatabaseNotFoundError, E as ExtensionError, H as HookDeniedError, M as MaxDatabasesError, c as MigrationError, Q as QueryError, R as ReadOnlyError, S as SirannonError, T as TransactionError } from '../errors-C00ed08Q.js';
|
|
8
|
+
import { D as DatabaseOptions, L as LifecycleConfig, P as Params, E as ExecuteResult } from '../types-D-74JiXb.js';
|
|
9
|
+
export { A as AfterQueryHook, m as BackupScheduleOptions, a as BeforeConnectHook, B as BeforeQueryHook, g as BeforeSubscribeHook, j as CDCMetrics, C as ChangeEvent, n as ChangeOperation, o as ClientOptions, p as ClusterReadEndpointInfo, q as ClusterStatusInfo, f as ConnectionHookContext, i as ConnectionMetrics, r as CorsOptions, c as DatabaseCloseHook, b as DatabaseOpenHook, H as HookConfig, M as MetricsConfig, O as OnRequestHook, Q as QueryHookContext, h as QueryMetrics, k as QueryOptions, R as ReadConcern, s as ReadConcernLevel, t as ReplicationStatusInfo, u as RequestContext, v as RequestDenial, w as ServerExecutionTarget, x as ServerExecutionTargetResolver, d as ServerOptions, S as SirannonOptions, y as Subscription, l as SubscriptionBuilder, T as Transaction, e as WSHandlerOptions, W as WriteConcern, z as WriteConcernLevel } from '../types-D-74JiXb.js';
|
|
10
|
+
import { M as Migration, a as MigrationResult, R as RollbackResult } from '../types-BeozgNPr.js';
|
|
11
|
+
export { A as AppliedMigration, b as AppliedMigrationEntry } from '../types-BeozgNPr.js';
|
|
12
|
+
export { S as Sirannon } from '../sirannon-Cd-lK6T0.js';
|
|
10
13
|
|
|
11
14
|
interface ConnectionPoolOptions {
|
|
12
15
|
driver: SQLiteDriver;
|
|
@@ -31,106 +34,6 @@ declare class ConnectionPool {
|
|
|
31
34
|
|
|
32
35
|
declare function defineDriver(config: SQLiteDriver): SQLiteDriver;
|
|
33
36
|
|
|
34
|
-
/**
|
|
35
|
-
* Base class for all sirannon-db errors. Extend this class to create
|
|
36
|
-
* domain-specific errors that carry a machine-readable {@link code}.
|
|
37
|
-
*/
|
|
38
|
-
declare class SirannonError extends Error {
|
|
39
|
-
readonly code: string;
|
|
40
|
-
constructor(message: string, code: string);
|
|
41
|
-
}
|
|
42
|
-
/**
|
|
43
|
-
* Thrown when a database ID cannot be resolved in the registry.
|
|
44
|
-
* This typically means the database was never opened or has already been closed.
|
|
45
|
-
*/
|
|
46
|
-
declare class DatabaseNotFoundError extends SirannonError {
|
|
47
|
-
constructor(id: string);
|
|
48
|
-
}
|
|
49
|
-
/**
|
|
50
|
-
* Thrown when attempting to register a database with an ID that is already
|
|
51
|
-
* in use. Each database ID must be unique within the registry.
|
|
52
|
-
*/
|
|
53
|
-
declare class DatabaseAlreadyExistsError extends SirannonError {
|
|
54
|
-
constructor(id: string);
|
|
55
|
-
}
|
|
56
|
-
/**
|
|
57
|
-
* Thrown when a write operation is attempted on a database that was opened
|
|
58
|
-
* in read-only mode.
|
|
59
|
-
*/
|
|
60
|
-
declare class ReadOnlyError extends SirannonError {
|
|
61
|
-
constructor(id: string);
|
|
62
|
-
}
|
|
63
|
-
/**
|
|
64
|
-
* Thrown when SQLite fails to execute a statement. The {@link sql} property
|
|
65
|
-
* holds the original SQL string that caused the failure, which is useful for
|
|
66
|
-
* debugging and logging.
|
|
67
|
-
*/
|
|
68
|
-
declare class QueryError extends SirannonError {
|
|
69
|
-
readonly sql: string;
|
|
70
|
-
constructor(message: string, sql: string);
|
|
71
|
-
}
|
|
72
|
-
/**
|
|
73
|
-
* Thrown when a transaction cannot be committed or is forcibly rolled back.
|
|
74
|
-
* Check the message for the underlying cause.
|
|
75
|
-
*/
|
|
76
|
-
declare class TransactionError extends SirannonError {
|
|
77
|
-
constructor(message: string);
|
|
78
|
-
}
|
|
79
|
-
/**
|
|
80
|
-
* Thrown when a migration step fails. The {@link version} property identifies
|
|
81
|
-
* which schema version triggered the error so the failure can be pinpointed
|
|
82
|
-
* in the migration history.
|
|
83
|
-
*/
|
|
84
|
-
declare class MigrationError extends SirannonError {
|
|
85
|
-
readonly version: number;
|
|
86
|
-
constructor(message: string, version: number, code?: string);
|
|
87
|
-
}
|
|
88
|
-
/**
|
|
89
|
-
* Thrown when a before-hook explicitly rejects an operation. The optional
|
|
90
|
-
* `reason` string is surfaced in the message so callers can distinguish
|
|
91
|
-
* between different hook policies.
|
|
92
|
-
*/
|
|
93
|
-
declare class HookDeniedError extends SirannonError {
|
|
94
|
-
constructor(hookName: string, reason?: string);
|
|
95
|
-
}
|
|
96
|
-
/**
|
|
97
|
-
* Thrown when the change-data-capture pipeline encounters an unrecoverable
|
|
98
|
-
* error, such as a failed event dispatch or a corrupt change record.
|
|
99
|
-
*/
|
|
100
|
-
declare class CDCError extends SirannonError {
|
|
101
|
-
constructor(message: string);
|
|
102
|
-
}
|
|
103
|
-
/**
|
|
104
|
-
* Thrown when a backup operation fails, whether that is an online backup via
|
|
105
|
-
* the SQLite backup API or a file-level copy.
|
|
106
|
-
*/
|
|
107
|
-
declare class BackupError extends SirannonError {
|
|
108
|
-
constructor(message: string);
|
|
109
|
-
}
|
|
110
|
-
/**
|
|
111
|
-
* Thrown when the connection pool reaches its limit or is configured with
|
|
112
|
-
* invalid parameters such as a minimum size greater than the maximum.
|
|
113
|
-
*/
|
|
114
|
-
declare class ConnectionPoolError extends SirannonError {
|
|
115
|
-
constructor(message: string);
|
|
116
|
-
}
|
|
117
|
-
/**
|
|
118
|
-
* Thrown when opening a new database would exceed the configured cap on
|
|
119
|
-
* concurrently open databases. Close an existing database before opening
|
|
120
|
-
* another one.
|
|
121
|
-
*/
|
|
122
|
-
declare class MaxDatabasesError extends SirannonError {
|
|
123
|
-
constructor(max: number);
|
|
124
|
-
}
|
|
125
|
-
/**
|
|
126
|
-
* Thrown when a native SQLite extension cannot be loaded. The `path` argument
|
|
127
|
-
* is the filesystem path passed to `load_extension`, and the optional `cause`
|
|
128
|
-
* string carries the error detail reported by SQLite.
|
|
129
|
-
*/
|
|
130
|
-
declare class ExtensionError extends SirannonError {
|
|
131
|
-
constructor(path: string, cause?: string);
|
|
132
|
-
}
|
|
133
|
-
|
|
134
37
|
interface LifecycleCallbacks {
|
|
135
38
|
open: (id: string, path: string, options?: DatabaseOptions) => Promise<Database>;
|
|
136
39
|
close: (id: string) => Promise<void>;
|
|
@@ -180,4 +83,4 @@ declare function queryOne<T = Record<string, unknown>>(conn: SQLiteConnection, s
|
|
|
180
83
|
declare function execute(conn: SQLiteConnection, sql: string, params?: Params): Promise<ExecuteResult>;
|
|
181
84
|
declare function executeBatch(conn: SQLiteConnection, sql: string, paramsBatch: Params[]): Promise<ExecuteResult[]>;
|
|
182
85
|
|
|
183
|
-
export {
|
|
86
|
+
export { ConnectionPool, type ConnectionPoolOptions, Database, DatabaseOptions, ExecuteResult, type LifecycleCallbacks, LifecycleConfig, LifecycleManager, Migration, MigrationResult, MigrationRunner, Params, RollbackResult, SQLiteConnection, SQLiteDriver, type TenantResolverOptions, createTenantResolver, defineDriver, execute, executeBatch, query, queryOne, sanitizeTenantId, tenantPath };
|
package/dist/core/index.mjs
CHANGED
|
@@ -1,8 +1,12 @@
|
|
|
1
|
-
import { SubscriptionBuilderImpl, ChangeTracker, SubscriptionManager, startPolling } from '../chunk-
|
|
1
|
+
import { SubscriptionBuilderImpl, ChangeTracker, SubscriptionManager, startPolling } from '../chunk-UTO3ZAFS.mjs';
|
|
2
|
+
export { ChangeTracker } from '../chunk-UTO3ZAFS.mjs';
|
|
2
3
|
export { defineDriver } from '../chunk-74UN4DIE.mjs';
|
|
3
4
|
import { BackupManager, BackupScheduler } from '../chunk-PXKAKK2V.mjs';
|
|
4
5
|
export { BackupManager, BackupScheduler } from '../chunk-PXKAKK2V.mjs';
|
|
5
|
-
import {
|
|
6
|
+
import { Transaction, query, queryOne, execute, executeBatch } from '../chunk-3MCMONVP.mjs';
|
|
7
|
+
export { Transaction, execute, executeBatch, query, queryOne } from '../chunk-3MCMONVP.mjs';
|
|
8
|
+
import '../chunk-GS7T5YMI.mjs';
|
|
9
|
+
import { ConnectionPoolError, MigrationError, ReadOnlyError, SirannonError, MaxDatabasesError, DatabaseAlreadyExistsError, DatabaseNotFoundError, ExtensionError } from '../chunk-O7BHI3CF.mjs';
|
|
6
10
|
export { BackupError, CDCError, ConnectionPoolError, DatabaseAlreadyExistsError, DatabaseNotFoundError, ExtensionError, HookDeniedError, MaxDatabasesError, MigrationError, QueryError, ReadOnlyError, SirannonError, TransactionError } from '../chunk-O7BHI3CF.mjs';
|
|
7
11
|
|
|
8
12
|
// src/core/connection-pool.ts
|
|
@@ -96,6 +100,81 @@ var ConnectionPool = class _ConnectionPool {
|
|
|
96
100
|
}
|
|
97
101
|
};
|
|
98
102
|
|
|
103
|
+
// src/core/cdc/ddl-handler.ts
|
|
104
|
+
var DDL_PREFIX_RE = /^\s*(CREATE\s+TABLE|ALTER\s+TABLE\s+\S+\s+ADD\s+COLUMN|DROP\s+TABLE|CREATE\s+INDEX|DROP\s+INDEX)\b/i;
|
|
105
|
+
var DROP_TABLE_RE = /^\s*DROP\s+TABLE\s+(?:IF\s+EXISTS\s+)?"?([A-Za-z_][A-Za-z0-9_]*)"?\s*;?\s*$/i;
|
|
106
|
+
function isCdcRelevantDdl(sql) {
|
|
107
|
+
return DDL_PREFIX_RE.test(sql);
|
|
108
|
+
}
|
|
109
|
+
function extractDroppedTable(sql) {
|
|
110
|
+
const m = DROP_TABLE_RE.exec(sql);
|
|
111
|
+
return m?.[1] ?? null;
|
|
112
|
+
}
|
|
113
|
+
async function applyDdlSideEffects(tracker, writerConn, sql) {
|
|
114
|
+
if (tracker.watchedTables.size === 0) {
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
await tracker.refreshAllTriggersUsingConnection(writerConn);
|
|
118
|
+
const dropped = extractDroppedTable(sql);
|
|
119
|
+
if (dropped !== null) {
|
|
120
|
+
await tracker.pruneDroppedTables(writerConn, [dropped]);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// src/core/cdc/cdc-aware-transaction.ts
|
|
125
|
+
var CdcAwareTransaction = class extends Transaction {
|
|
126
|
+
constructor(txConn, tracker, state) {
|
|
127
|
+
super(txConn);
|
|
128
|
+
this.tracker = tracker;
|
|
129
|
+
this.state = state;
|
|
130
|
+
this.txConn = txConn;
|
|
131
|
+
}
|
|
132
|
+
txConn;
|
|
133
|
+
async execute(sql, params) {
|
|
134
|
+
const isDdl = isCdcRelevantDdl(sql);
|
|
135
|
+
const result = await super.execute(sql, params);
|
|
136
|
+
if (!isDdl) {
|
|
137
|
+
return result;
|
|
138
|
+
}
|
|
139
|
+
this.state.sawDdl = true;
|
|
140
|
+
const dropped = extractDroppedTable(sql);
|
|
141
|
+
if (dropped !== null) {
|
|
142
|
+
this.state.droppedTables.push(dropped);
|
|
143
|
+
}
|
|
144
|
+
if (this.tracker.watchedTables.size > 0) {
|
|
145
|
+
await this.tracker.refreshAllTriggersUsingConnection(this.txConn);
|
|
146
|
+
}
|
|
147
|
+
return result;
|
|
148
|
+
}
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
// src/core/extension-loader.ts
|
|
152
|
+
async function loadExtension(driver, writer, extensionPath) {
|
|
153
|
+
if (!driver.capabilities.extensions) {
|
|
154
|
+
throw new ExtensionError(extensionPath, "Extensions are not supported by the current driver");
|
|
155
|
+
}
|
|
156
|
+
if (!extensionPath || extensionPath.includes("\0")) {
|
|
157
|
+
throw new ExtensionError(extensionPath || "", "Extension path is empty or contains null bytes");
|
|
158
|
+
}
|
|
159
|
+
for (let i = 0; i < extensionPath.length; i++) {
|
|
160
|
+
if (extensionPath.charCodeAt(i) <= 31) {
|
|
161
|
+
throw new ExtensionError(extensionPath, "Extension path contains control characters");
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
const segments = extensionPath.split(/[/\\]/);
|
|
165
|
+
if (segments.includes("..")) {
|
|
166
|
+
throw new ExtensionError(extensionPath, "Extension path must not contain directory traversal segments");
|
|
167
|
+
}
|
|
168
|
+
const { resolve } = await import('path');
|
|
169
|
+
const resolved = resolve(extensionPath);
|
|
170
|
+
try {
|
|
171
|
+
const escaped = resolved.replace(/'/g, "''");
|
|
172
|
+
await writer.exec(`SELECT load_extension('${escaped}')`);
|
|
173
|
+
} catch (err) {
|
|
174
|
+
throw new ExtensionError(extensionPath, err instanceof Error ? err.message : String(err));
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
99
178
|
// src/core/hooks/registry.ts
|
|
100
179
|
var HOOK_CONFIG_MAP = {
|
|
101
180
|
onBeforeQuery: "beforeQuery",
|
|
@@ -178,118 +257,6 @@ var HookRegistry = class {
|
|
|
178
257
|
}
|
|
179
258
|
};
|
|
180
259
|
|
|
181
|
-
// src/core/query-executor.ts
|
|
182
|
-
var STATEMENT_CACHE_CAPACITY = 128;
|
|
183
|
-
var statementCaches = /* @__PURE__ */ new WeakMap();
|
|
184
|
-
async function getStatement(conn, sql) {
|
|
185
|
-
let cache = statementCaches.get(conn);
|
|
186
|
-
if (!cache) {
|
|
187
|
-
cache = /* @__PURE__ */ new Map();
|
|
188
|
-
statementCaches.set(conn, cache);
|
|
189
|
-
}
|
|
190
|
-
const cached = cache.get(sql);
|
|
191
|
-
if (cached) {
|
|
192
|
-
cache.delete(sql);
|
|
193
|
-
cache.set(sql, cached);
|
|
194
|
-
return cached;
|
|
195
|
-
}
|
|
196
|
-
const pending = conn.prepare(sql);
|
|
197
|
-
cache.set(sql, pending);
|
|
198
|
-
if (cache.size > STATEMENT_CACHE_CAPACITY) {
|
|
199
|
-
const oldest = cache.keys().next().value;
|
|
200
|
-
if (oldest !== void 0) {
|
|
201
|
-
cache.delete(oldest);
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
try {
|
|
205
|
-
return await pending;
|
|
206
|
-
} catch (err) {
|
|
207
|
-
cache.delete(sql);
|
|
208
|
-
throw err;
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
function bindParams(params) {
|
|
212
|
-
if (params === void 0) return [];
|
|
213
|
-
if (Array.isArray(params)) return params;
|
|
214
|
-
return [params];
|
|
215
|
-
}
|
|
216
|
-
async function query(conn, sql, params) {
|
|
217
|
-
try {
|
|
218
|
-
const stmt = await getStatement(conn, sql);
|
|
219
|
-
return await stmt.all(...bindParams(params));
|
|
220
|
-
} catch (err) {
|
|
221
|
-
throw new QueryError(err instanceof Error ? err.message : String(err), sql);
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
async function queryOne(conn, sql, params) {
|
|
225
|
-
try {
|
|
226
|
-
const stmt = await getStatement(conn, sql);
|
|
227
|
-
return await stmt.get(...bindParams(params));
|
|
228
|
-
} catch (err) {
|
|
229
|
-
throw new QueryError(err instanceof Error ? err.message : String(err), sql);
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
async function execute(conn, sql, params) {
|
|
233
|
-
try {
|
|
234
|
-
const stmt = await getStatement(conn, sql);
|
|
235
|
-
const result = await stmt.run(...bindParams(params));
|
|
236
|
-
return {
|
|
237
|
-
changes: result.changes,
|
|
238
|
-
lastInsertRowId: result.lastInsertRowId
|
|
239
|
-
};
|
|
240
|
-
} catch (err) {
|
|
241
|
-
throw new QueryError(err instanceof Error ? err.message : String(err), sql);
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
async function executeBatch(conn, sql, paramsBatch) {
|
|
245
|
-
try {
|
|
246
|
-
const stmt = await getStatement(conn, sql);
|
|
247
|
-
const results = [];
|
|
248
|
-
for (const params of paramsBatch) {
|
|
249
|
-
const result = await stmt.run(...bindParams(params));
|
|
250
|
-
results.push({
|
|
251
|
-
changes: result.changes,
|
|
252
|
-
lastInsertRowId: result.lastInsertRowId
|
|
253
|
-
});
|
|
254
|
-
}
|
|
255
|
-
return results;
|
|
256
|
-
} catch (err) {
|
|
257
|
-
throw new QueryError(err instanceof Error ? err.message : String(err), sql);
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
// src/core/transaction.ts
|
|
262
|
-
var Transaction = class _Transaction {
|
|
263
|
-
constructor(conn) {
|
|
264
|
-
this.conn = conn;
|
|
265
|
-
}
|
|
266
|
-
_lastInsertRowId = 0;
|
|
267
|
-
async query(sql, params) {
|
|
268
|
-
return query(this.conn, sql, params);
|
|
269
|
-
}
|
|
270
|
-
async execute(sql, params) {
|
|
271
|
-
const result = await execute(this.conn, sql, params);
|
|
272
|
-
this._lastInsertRowId = result.lastInsertRowId;
|
|
273
|
-
return result;
|
|
274
|
-
}
|
|
275
|
-
async executeBatch(sql, paramsBatch) {
|
|
276
|
-
const results = await executeBatch(this.conn, sql, paramsBatch);
|
|
277
|
-
if (results.length > 0) {
|
|
278
|
-
this._lastInsertRowId = results[results.length - 1].lastInsertRowId;
|
|
279
|
-
}
|
|
280
|
-
return results;
|
|
281
|
-
}
|
|
282
|
-
get lastInsertRowId() {
|
|
283
|
-
return this._lastInsertRowId;
|
|
284
|
-
}
|
|
285
|
-
static async run(conn, fn) {
|
|
286
|
-
return conn.transaction(async (txConn) => {
|
|
287
|
-
const tx = new _Transaction(txConn);
|
|
288
|
-
return fn(tx);
|
|
289
|
-
});
|
|
290
|
-
}
|
|
291
|
-
};
|
|
292
|
-
|
|
293
260
|
// src/core/migrations/runner.ts
|
|
294
261
|
var CREATE_TRACKING_TABLE = `
|
|
295
262
|
CREATE TABLE IF NOT EXISTS _sirannon_migrations (
|
|
@@ -488,9 +455,9 @@ var Database = class _Database {
|
|
|
488
455
|
});
|
|
489
456
|
return new _Database(id, path, pool, driver, options, internals);
|
|
490
457
|
}
|
|
491
|
-
async query(sql, params) {
|
|
458
|
+
async query(sql, params, options) {
|
|
492
459
|
this.ensureOpen();
|
|
493
|
-
this.fireBeforeQueryHooks(sql, params);
|
|
460
|
+
this.fireBeforeQueryHooks(sql, params, options);
|
|
494
461
|
const start = performance.now();
|
|
495
462
|
try {
|
|
496
463
|
const reader = this.pool.acquireReader();
|
|
@@ -505,9 +472,9 @@ var Database = class _Database {
|
|
|
505
472
|
this.fireAfterQueryHooks(sql, params, performance.now() - start);
|
|
506
473
|
}
|
|
507
474
|
}
|
|
508
|
-
async queryOne(sql, params) {
|
|
475
|
+
async queryOne(sql, params, options) {
|
|
509
476
|
this.ensureOpen();
|
|
510
|
-
this.fireBeforeQueryHooks(sql, params);
|
|
477
|
+
this.fireBeforeQueryHooks(sql, params, options);
|
|
511
478
|
const start = performance.now();
|
|
512
479
|
try {
|
|
513
480
|
const reader = this.pool.acquireReader();
|
|
@@ -522,39 +489,37 @@ var Database = class _Database {
|
|
|
522
489
|
this.fireAfterQueryHooks(sql, params, performance.now() - start);
|
|
523
490
|
}
|
|
524
491
|
}
|
|
525
|
-
async execute(sql, params) {
|
|
492
|
+
async execute(sql, params, options) {
|
|
526
493
|
this.ensureOpen();
|
|
527
494
|
if (this.readOnly) throw new ReadOnlyError(this.id);
|
|
528
|
-
this.fireBeforeQueryHooks(sql, params);
|
|
495
|
+
this.fireBeforeQueryHooks(sql, params, options);
|
|
529
496
|
const start = performance.now();
|
|
530
497
|
try {
|
|
531
498
|
const writer = this.pool.acquireWriter();
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
return await execute(writer, sql, params);
|
|
499
|
+
const result = this.metricsCollector ? await this.metricsCollector.trackQuery(() => execute(writer, sql, params), {
|
|
500
|
+
databaseId: this.id,
|
|
501
|
+
sql
|
|
502
|
+
}) : await execute(writer, sql, params);
|
|
503
|
+
await this.maybeApplyDdlSideEffects(writer, sql);
|
|
504
|
+
return result;
|
|
539
505
|
} finally {
|
|
540
506
|
this.fireAfterQueryHooks(sql, params, performance.now() - start);
|
|
541
507
|
}
|
|
542
508
|
}
|
|
543
|
-
async executeBatch(sql, paramsBatch) {
|
|
509
|
+
async executeBatch(sql, paramsBatch, options) {
|
|
544
510
|
this.ensureOpen();
|
|
545
511
|
if (this.readOnly) throw new ReadOnlyError(this.id);
|
|
546
|
-
this.fireBeforeQueryHooks(sql);
|
|
512
|
+
this.fireBeforeQueryHooks(sql, void 0, options);
|
|
547
513
|
const start = performance.now();
|
|
548
514
|
try {
|
|
549
515
|
const writer = this.pool.acquireWriter();
|
|
550
516
|
const batchFn = () => writer.transaction(async (txConn) => executeBatch(txConn, sql, paramsBatch));
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
return await batchFn();
|
|
517
|
+
const results = this.metricsCollector ? await this.metricsCollector.trackQuery(batchFn, {
|
|
518
|
+
databaseId: this.id,
|
|
519
|
+
sql
|
|
520
|
+
}) : await batchFn();
|
|
521
|
+
await this.maybeApplyDdlSideEffects(writer, sql);
|
|
522
|
+
return results;
|
|
558
523
|
} finally {
|
|
559
524
|
this.fireAfterQueryHooks(sql, void 0, performance.now() - start);
|
|
560
525
|
}
|
|
@@ -563,7 +528,25 @@ var Database = class _Database {
|
|
|
563
528
|
this.ensureOpen();
|
|
564
529
|
if (this.readOnly) throw new ReadOnlyError(this.id);
|
|
565
530
|
const writer = this.pool.acquireWriter();
|
|
566
|
-
|
|
531
|
+
const tracker = this.changeTracker;
|
|
532
|
+
if (!tracker) {
|
|
533
|
+
return Transaction.run(writer, fn);
|
|
534
|
+
}
|
|
535
|
+
const state = { sawDdl: false, droppedTables: [] };
|
|
536
|
+
const result = await writer.transaction(async (txConn) => {
|
|
537
|
+
const tx = new CdcAwareTransaction(txConn, tracker, state);
|
|
538
|
+
return fn(tx);
|
|
539
|
+
});
|
|
540
|
+
if (state.sawDdl && state.droppedTables.length > 0) {
|
|
541
|
+
await tracker.pruneDroppedTables(writer, state.droppedTables);
|
|
542
|
+
}
|
|
543
|
+
return result;
|
|
544
|
+
}
|
|
545
|
+
async maybeApplyDdlSideEffects(writer, sql) {
|
|
546
|
+
const tracker = this.changeTracker;
|
|
547
|
+
if (!tracker) return;
|
|
548
|
+
if (!isCdcRelevantDdl(sql)) return;
|
|
549
|
+
await applyDdlSideEffects(tracker, writer, sql);
|
|
567
550
|
}
|
|
568
551
|
async watch(table) {
|
|
569
552
|
this.ensureOpen();
|
|
@@ -614,30 +597,8 @@ var Database = class _Database {
|
|
|
614
597
|
}
|
|
615
598
|
async loadExtension(extensionPath) {
|
|
616
599
|
this.ensureOpen();
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
}
|
|
620
|
-
if (!extensionPath || extensionPath.includes("\0")) {
|
|
621
|
-
throw new ExtensionError(extensionPath || "", "Extension path is empty or contains null bytes");
|
|
622
|
-
}
|
|
623
|
-
for (let i = 0; i < extensionPath.length; i++) {
|
|
624
|
-
if (extensionPath.charCodeAt(i) <= 31) {
|
|
625
|
-
throw new ExtensionError(extensionPath, "Extension path contains control characters");
|
|
626
|
-
}
|
|
627
|
-
}
|
|
628
|
-
const segments = extensionPath.split(/[/\\]/);
|
|
629
|
-
if (segments.includes("..")) {
|
|
630
|
-
throw new ExtensionError(extensionPath, "Extension path must not contain directory traversal segments");
|
|
631
|
-
}
|
|
632
|
-
const { resolve } = await import('path');
|
|
633
|
-
const resolved = resolve(extensionPath);
|
|
634
|
-
try {
|
|
635
|
-
const writer = this.pool.acquireWriter();
|
|
636
|
-
const escaped = resolved.replace(/'/g, "''");
|
|
637
|
-
await writer.exec(`SELECT load_extension('${escaped}')`);
|
|
638
|
-
} catch (err) {
|
|
639
|
-
throw new ExtensionError(extensionPath, err instanceof Error ? err.message : String(err));
|
|
640
|
-
}
|
|
600
|
+
const writer = this.pool.acquireWriter();
|
|
601
|
+
await loadExtension(this.driver, writer, extensionPath);
|
|
641
602
|
}
|
|
642
603
|
onBeforeQuery(hook) {
|
|
643
604
|
this.hookRegistry.register("beforeQuery", hook);
|
|
@@ -707,11 +668,17 @@ var Database = class _Database {
|
|
|
707
668
|
this.stopCdcPolling = null;
|
|
708
669
|
}
|
|
709
670
|
}
|
|
710
|
-
fireBeforeQueryHooks(sql, params) {
|
|
671
|
+
fireBeforeQueryHooks(sql, params, options) {
|
|
711
672
|
const hasParent = this.parentHooks?.has("beforeQuery");
|
|
712
673
|
const hasLocal = this.hookRegistry.has("beforeQuery");
|
|
713
674
|
if (!hasParent && !hasLocal) return;
|
|
714
|
-
const ctx = {
|
|
675
|
+
const ctx = {
|
|
676
|
+
databaseId: this.id,
|
|
677
|
+
sql,
|
|
678
|
+
params,
|
|
679
|
+
writeConcern: options?.writeConcern,
|
|
680
|
+
readConcern: options?.readConcern
|
|
681
|
+
};
|
|
715
682
|
this.parentHooks?.invokeSync("beforeQuery", ctx);
|
|
716
683
|
this.hookRegistry.invokeSync("beforeQuery", ctx);
|
|
717
684
|
}
|
|
@@ -745,12 +712,11 @@ var LifecycleManager = class {
|
|
|
745
712
|
const timeout = config.idleTimeout;
|
|
746
713
|
if (timeout && timeout > 0) {
|
|
747
714
|
const interval = Math.min(Math.max(Math.floor(timeout / 2), 100), 6e4);
|
|
748
|
-
|
|
715
|
+
const timer = setInterval(async () => {
|
|
749
716
|
await this.#runIdleCheck();
|
|
750
717
|
}, interval);
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
}
|
|
718
|
+
timer.unref?.();
|
|
719
|
+
this.idleTimer = timer;
|
|
754
720
|
}
|
|
755
721
|
}
|
|
756
722
|
async resolve(id) {
|
|
@@ -1103,4 +1069,4 @@ var Sirannon = class {
|
|
|
1103
1069
|
}
|
|
1104
1070
|
};
|
|
1105
1071
|
|
|
1106
|
-
export { ConnectionPool, Database, HookRegistry, LifecycleManager, MetricsCollector, MigrationRunner, Sirannon,
|
|
1072
|
+
export { ConnectionPool, Database, HookRegistry, LifecycleManager, MetricsCollector, MigrationRunner, Sirannon, createTenantResolver, sanitizeTenantId, tenantPath };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { S as SQLiteDriver } from './types-BFSsG77t.js';
|
|
2
|
-
import { Q as QueryHookContext,
|
|
3
|
-
import {
|
|
2
|
+
import { Q as QueryHookContext, f as ConnectionHookContext, g as BeforeSubscribeHook, H as HookConfig, M as MetricsConfig, h as QueryMetrics, i as ConnectionMetrics, j as CDCMetrics, D as DatabaseOptions, P as Params, k as QueryOptions, E as ExecuteResult, T as Transaction, l as SubscriptionBuilder, m as BackupScheduleOptions, B as BeforeQueryHook, A as AfterQueryHook } from './types-D-74JiXb.js';
|
|
3
|
+
import { M as Migration, a as MigrationResult, R as RollbackResult } from './types-BeozgNPr.js';
|
|
4
4
|
|
|
5
5
|
type HookEvent = 'beforeQuery' | 'afterQuery' | 'beforeConnect' | 'databaseOpen' | 'databaseClose' | 'beforeSubscribe';
|
|
6
6
|
type SubscribeHookContext = Parameters<BeforeSubscribeHook>[0];
|
|
@@ -64,11 +64,12 @@ declare class Database {
|
|
|
64
64
|
private readonly scheduledBackupCancellers;
|
|
65
65
|
private constructor();
|
|
66
66
|
static create(id: string, path: string, driver: SQLiteDriver, options?: DatabaseOptions, internals?: DatabaseInternals): Promise<Database>;
|
|
67
|
-
query<T = Record<string, unknown>>(sql: string, params?: Params): Promise<T[]>;
|
|
68
|
-
queryOne<T = Record<string, unknown>>(sql: string, params?: Params): Promise<T | undefined>;
|
|
69
|
-
execute(sql: string, params?: Params): Promise<ExecuteResult>;
|
|
70
|
-
executeBatch(sql: string, paramsBatch: Params[]): Promise<ExecuteResult[]>;
|
|
67
|
+
query<T = Record<string, unknown>>(sql: string, params?: Params, options?: QueryOptions): Promise<T[]>;
|
|
68
|
+
queryOne<T = Record<string, unknown>>(sql: string, params?: Params, options?: QueryOptions): Promise<T | undefined>;
|
|
69
|
+
execute(sql: string, params?: Params, options?: QueryOptions): Promise<ExecuteResult>;
|
|
70
|
+
executeBatch(sql: string, paramsBatch: Params[], options?: QueryOptions): Promise<ExecuteResult[]>;
|
|
71
71
|
transaction<T>(fn: (tx: Transaction) => Promise<T>): Promise<T>;
|
|
72
|
+
private maybeApplyDdlSideEffects;
|
|
72
73
|
watch(table: string): Promise<void>;
|
|
73
74
|
unwatch(table: string): Promise<void>;
|
|
74
75
|
on(table: string): SubscriptionBuilder;
|
|
@@ -91,30 +92,4 @@ declare class Database {
|
|
|
91
92
|
private fireAfterQueryHooks;
|
|
92
93
|
}
|
|
93
94
|
|
|
94
|
-
|
|
95
|
-
readonly options: SirannonOptions;
|
|
96
|
-
private readonly dbs;
|
|
97
|
-
private readonly opening;
|
|
98
|
-
private _shutdown;
|
|
99
|
-
private readonly _driver;
|
|
100
|
-
private readonly hookRegistry;
|
|
101
|
-
private readonly metricsCollector;
|
|
102
|
-
private readonly lifecycleManager;
|
|
103
|
-
constructor(options: SirannonOptions);
|
|
104
|
-
get driver(): SQLiteDriver;
|
|
105
|
-
open(id: string, path: string, options?: DatabaseOptions): Promise<Database>;
|
|
106
|
-
close(id: string): Promise<void>;
|
|
107
|
-
get(id: string): Database | undefined;
|
|
108
|
-
resolve(id: string): Promise<Database | undefined>;
|
|
109
|
-
has(id: string): boolean;
|
|
110
|
-
databases(): Map<string, Database>;
|
|
111
|
-
shutdown(): Promise<void>;
|
|
112
|
-
onBeforeQuery(hook: BeforeQueryHook): void;
|
|
113
|
-
onAfterQuery(hook: AfterQueryHook): void;
|
|
114
|
-
onBeforeConnect(hook: BeforeConnectHook): void;
|
|
115
|
-
onDatabaseOpen(hook: DatabaseOpenHook): void;
|
|
116
|
-
onDatabaseClose(hook: DatabaseCloseHook): void;
|
|
117
|
-
private ensureRunning;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
export { Database as D, type HookDispose as H, MetricsCollector as M, Sirannon as S, type HookEvent as a, type HookEventContextMap as b, type HookHandler as c, HookRegistry as d, type SubscribeHookContext as e };
|
|
95
|
+
export { Database as D, type HookDispose as H, MetricsCollector as M, type SubscribeHookContext as S, type HookEvent as a, type HookEventContextMap as b, type HookHandler as c, HookRegistry as d };
|