@framers/sql-storage-adapter 0.7.1 → 0.7.3
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 +43 -0
- package/dist/adapters/electron/preload.cjs +289 -0
- package/dist/adapters/electron/renderer.d.ts +9 -0
- package/dist/adapters/electron/renderer.d.ts.map +1 -0
- package/dist/adapters/electron/renderer.js +8 -0
- package/dist/adapters/electron/renderer.js.map +1 -0
- package/dist/cjs/adapters/__tests__/indexedDbAdapter.spec.d.ts +2 -0
- package/dist/cjs/adapters/__tests__/indexedDbAdapter.spec.js +133 -0
- package/dist/cjs/adapters/baseStorageAdapter.d.ts +368 -0
- package/dist/cjs/adapters/baseStorageAdapter.js +744 -0
- package/dist/cjs/adapters/betterSqliteAdapter.d.ts +124 -0
- package/dist/cjs/adapters/betterSqliteAdapter.js +334 -0
- package/dist/cjs/adapters/capacitorSqliteAdapter.d.ts +83 -0
- package/dist/cjs/adapters/capacitorSqliteAdapter.js +250 -0
- package/dist/cjs/adapters/electron/electronMainAdapter.d.ts +251 -0
- package/dist/cjs/adapters/electron/electronMainAdapter.js +392 -0
- package/dist/cjs/adapters/electron/electronRendererAdapter.d.ts +177 -0
- package/dist/cjs/adapters/electron/electronRendererAdapter.js +283 -0
- package/dist/cjs/adapters/electron/index.d.ts +74 -0
- package/dist/cjs/adapters/electron/index.js +86 -0
- package/dist/cjs/adapters/electron/ipc/channels.d.ts +196 -0
- package/dist/cjs/adapters/electron/ipc/channels.js +127 -0
- package/dist/cjs/adapters/electron/ipc/index.d.ts +11 -0
- package/dist/cjs/adapters/electron/ipc/index.js +38 -0
- package/dist/cjs/adapters/electron/ipc/protocol.d.ts +78 -0
- package/dist/cjs/adapters/electron/ipc/protocol.js +341 -0
- package/dist/cjs/adapters/electron/ipc/types.d.ts +248 -0
- package/dist/cjs/adapters/electron/ipc/types.js +15 -0
- package/dist/cjs/adapters/electron/migration/autoMigrator.d.ts +184 -0
- package/dist/cjs/adapters/electron/migration/autoMigrator.js +441 -0
- package/dist/cjs/adapters/electron/migration/index.d.ts +9 -0
- package/dist/cjs/adapters/electron/migration/index.js +29 -0
- package/dist/cjs/adapters/electron/preload.d.ts +126 -0
- package/dist/cjs/adapters/electron/preload.js +233 -0
- package/dist/cjs/adapters/electron/recovery/corruptionDetector.d.ts +214 -0
- package/dist/cjs/adapters/electron/recovery/corruptionDetector.js +359 -0
- package/dist/cjs/adapters/electron/recovery/index.d.ts +11 -0
- package/dist/cjs/adapters/electron/recovery/index.js +34 -0
- package/dist/cjs/adapters/electron/recovery/walCheckpoint.d.ts +186 -0
- package/dist/cjs/adapters/electron/recovery/walCheckpoint.js +263 -0
- package/dist/cjs/adapters/electron/renderer.d.ts +9 -0
- package/dist/cjs/adapters/electron/renderer.js +33 -0
- package/dist/cjs/adapters/electron/window/index.d.ts +9 -0
- package/dist/cjs/adapters/electron/window/index.js +29 -0
- package/dist/cjs/adapters/electron/window/windowManager.d.ts +190 -0
- package/dist/cjs/adapters/electron/window/windowManager.js +321 -0
- package/dist/cjs/adapters/indexedDbAdapter.d.ts +490 -0
- package/dist/cjs/adapters/indexedDbAdapter.js +993 -0
- package/dist/cjs/adapters/postgresAdapter.d.ts +424 -0
- package/dist/cjs/adapters/postgresAdapter.js +889 -0
- package/dist/cjs/adapters/sqlJsAdapter.d.ts +64 -0
- package/dist/cjs/adapters/sqlJsAdapter.js +268 -0
- package/dist/cjs/adapters/supabase.d.ts +58 -0
- package/dist/cjs/adapters/supabase.js +401 -0
- package/dist/cjs/codecs/BrowserBlobCodec.d.ts +14 -0
- package/dist/cjs/codecs/BrowserBlobCodec.js +57 -0
- package/dist/cjs/codecs/NodeBlobCodec.d.ts +14 -0
- package/dist/cjs/codecs/NodeBlobCodec.js +59 -0
- package/dist/cjs/core/contracts/blobCodec.d.ts +15 -0
- package/dist/cjs/core/contracts/blobCodec.js +15 -0
- package/dist/cjs/core/contracts/context.d.ts +221 -0
- package/dist/cjs/core/contracts/context.js +15 -0
- package/dist/cjs/core/contracts/dialect.d.ts +154 -0
- package/dist/cjs/core/contracts/dialect.js +15 -0
- package/dist/cjs/core/contracts/events.d.ts +225 -0
- package/dist/cjs/core/contracts/events.js +15 -0
- package/dist/cjs/core/contracts/exporter.d.ts +13 -0
- package/dist/cjs/core/contracts/exporter.js +15 -0
- package/dist/cjs/core/contracts/extensions.d.ts +73 -0
- package/dist/cjs/core/contracts/extensions.js +15 -0
- package/dist/cjs/core/contracts/features.d.ts +25 -0
- package/dist/cjs/core/contracts/features.js +61 -0
- package/dist/cjs/core/contracts/fts.d.ts +66 -0
- package/dist/cjs/core/contracts/fts.js +15 -0
- package/dist/cjs/core/contracts/hooks.d.ts +481 -0
- package/dist/cjs/core/contracts/hooks.js +140 -0
- package/dist/cjs/core/contracts/index.d.ts +260 -0
- package/dist/cjs/core/contracts/index.js +41 -0
- package/dist/cjs/core/contracts/limitations.d.ts +46 -0
- package/dist/cjs/core/contracts/limitations.js +218 -0
- package/dist/cjs/core/contracts/performance.d.ts +308 -0
- package/dist/cjs/core/contracts/performance.js +144 -0
- package/dist/cjs/core/database.d.ts +220 -0
- package/dist/cjs/core/database.js +136 -0
- package/dist/cjs/core/portable.d.ts +23 -0
- package/dist/cjs/core/portable.js +66 -0
- package/dist/cjs/core/resolver.d.ts +77 -0
- package/dist/cjs/core/resolver.js +235 -0
- package/dist/cjs/dialects/PostgresDialect.d.ts +35 -0
- package/dist/cjs/dialects/PostgresDialect.js +143 -0
- package/dist/cjs/dialects/SqliteDialect.d.ts +35 -0
- package/dist/cjs/dialects/SqliteDialect.js +142 -0
- package/dist/cjs/dialects/shared.d.ts +17 -0
- package/dist/cjs/dialects/shared.js +90 -0
- package/dist/cjs/exporters/PostgresExporter.d.ts +14 -0
- package/dist/cjs/exporters/PostgresExporter.js +61 -0
- package/dist/cjs/exporters/SqliteFileExporter.d.ts +16 -0
- package/dist/cjs/exporters/SqliteFileExporter.js +43 -0
- package/dist/cjs/features/backup/cloudBackup.d.ts +219 -0
- package/dist/cjs/features/backup/cloudBackup.js +209 -0
- package/dist/cjs/features/kv/idb.d.ts +79 -0
- package/dist/cjs/features/kv/idb.js +32 -0
- package/dist/cjs/features/kv/index.d.ts +14 -0
- package/dist/cjs/features/kv/index.js +40 -0
- package/dist/cjs/features/kv/indexedDbKeyValueStore.d.ts +77 -0
- package/dist/cjs/features/kv/indexedDbKeyValueStore.js +116 -0
- package/dist/cjs/features/kv/keyValueStore.d.ts +48 -0
- package/dist/cjs/features/kv/keyValueStore.js +67 -0
- package/dist/cjs/features/kv/sqlKeyValueStore.d.ts +34 -0
- package/dist/cjs/features/kv/sqlKeyValueStore.js +81 -0
- package/dist/cjs/features/kv/valueCodec.d.ts +35 -0
- package/dist/cjs/features/kv/valueCodec.js +426 -0
- package/dist/cjs/features/migrations/dataExport.d.ts +77 -0
- package/dist/cjs/features/migrations/dataExport.js +194 -0
- package/dist/cjs/features/migrations/dataImport.d.ts +54 -0
- package/dist/cjs/features/migrations/dataImport.js +300 -0
- package/dist/cjs/features/migrations/migration.d.ts +89 -0
- package/dist/cjs/features/migrations/migration.js +187 -0
- package/dist/cjs/features/migrations/schemaMigrations.d.ts +93 -0
- package/dist/cjs/features/migrations/schemaMigrations.js +220 -0
- package/dist/cjs/features/sync/conflicts/conflictResolver.d.ts +222 -0
- package/dist/cjs/features/sync/conflicts/conflictResolver.js +366 -0
- package/dist/cjs/features/sync/conflicts/index.d.ts +9 -0
- package/dist/cjs/features/sync/conflicts/index.js +21 -0
- package/dist/cjs/features/sync/crossPlatformSync.d.ts +281 -0
- package/dist/cjs/features/sync/crossPlatformSync.js +551 -0
- package/dist/cjs/features/sync/devices/deviceManager.d.ts +243 -0
- package/dist/cjs/features/sync/devices/deviceManager.js +450 -0
- package/dist/cjs/features/sync/devices/index.d.ts +10 -0
- package/dist/cjs/features/sync/devices/index.js +21 -0
- package/dist/cjs/features/sync/index.d.ts +37 -0
- package/dist/cjs/features/sync/index.js +111 -0
- package/dist/cjs/features/sync/protocol/index.d.ts +11 -0
- package/dist/cjs/features/sync/protocol/index.js +23 -0
- package/dist/cjs/features/sync/protocol/messages.d.ts +348 -0
- package/dist/cjs/features/sync/protocol/messages.js +215 -0
- package/dist/cjs/features/sync/protocol/vectorClock.d.ts +164 -0
- package/dist/cjs/features/sync/protocol/vectorClock.js +256 -0
- package/dist/cjs/features/sync/syncManager.d.ts +348 -0
- package/dist/cjs/features/sync/syncManager.js +455 -0
- package/dist/cjs/features/sync/tables/index.d.ts +10 -0
- package/dist/cjs/features/sync/tables/index.js +21 -0
- package/dist/cjs/features/sync/tables/syncLogManager.d.ts +216 -0
- package/dist/cjs/features/sync/tables/syncLogManager.js +423 -0
- package/dist/cjs/features/sync/transport/httpTransport.d.ts +123 -0
- package/dist/cjs/features/sync/transport/httpTransport.js +346 -0
- package/dist/cjs/features/sync/transport/index.d.ts +12 -0
- package/dist/cjs/features/sync/transport/index.js +25 -0
- package/dist/cjs/features/sync/transport/transport.d.ts +259 -0
- package/dist/cjs/features/sync/transport/transport.js +163 -0
- package/dist/cjs/features/sync/transport/websocketTransport.d.ts +126 -0
- package/dist/cjs/features/sync/transport/websocketTransport.js +342 -0
- package/dist/cjs/fts/PostgresFts.d.ts +29 -0
- package/dist/cjs/fts/PostgresFts.js +77 -0
- package/dist/cjs/fts/SqliteFts5.d.ts +22 -0
- package/dist/cjs/fts/SqliteFts5.js +58 -0
- package/dist/cjs/index.d.ts +30 -0
- package/dist/cjs/index.js +101 -0
- package/dist/cjs/package.json +3 -0
- package/dist/cjs/shared/connectionGate.d.ts +94 -0
- package/dist/cjs/shared/connectionGate.js +77 -0
- package/dist/cjs/shared/errors.d.ts +23 -0
- package/dist/cjs/shared/errors.js +45 -0
- package/dist/cjs/shared/logger.d.ts +26 -0
- package/dist/cjs/shared/logger.js +40 -0
- package/dist/cjs/shared/parameterUtils.d.ts +16 -0
- package/dist/cjs/shared/parameterUtils.js +59 -0
- package/dist/cjs/shared/postgresTarget.d.ts +11 -0
- package/dist/cjs/shared/postgresTarget.js +30 -0
- package/dist/cjs/shared/segment.d.ts +43 -0
- package/dist/cjs/shared/segment.js +63 -0
- package/dist/cjs/shared/serializedTransaction.d.ts +14 -0
- package/dist/cjs/shared/serializedTransaction.js +74 -0
- package/dist/cjs/shared/splitSqlStatements.d.ts +27 -0
- package/dist/cjs/shared/splitSqlStatements.js +163 -0
- package/dist/cjs/shared/sqlPlaceholders.d.ts +48 -0
- package/dist/cjs/shared/sqlPlaceholders.js +263 -0
- package/dist/cjs/types/index.d.ts +29 -0
- package/dist/cjs/types/index.js +33 -0
- package/dist/core/portable.d.ts +23 -0
- package/dist/core/portable.d.ts.map +1 -0
- package/dist/core/portable.js +23 -0
- package/dist/core/portable.js.map +1 -0
- package/dist/features/migrations/schemaMigrations.d.ts +93 -0
- package/dist/features/migrations/schemaMigrations.d.ts.map +1 -0
- package/dist/features/migrations/schemaMigrations.js +216 -0
- package/dist/features/migrations/schemaMigrations.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/package.json +139 -24
|
@@ -0,0 +1,392 @@
|
|
|
1
|
+
var __create = Object.create;
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __export = (target, all) => {
|
|
8
|
+
for (var name in all)
|
|
9
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
|
+
};
|
|
11
|
+
var __copyProps = (to, from, except, desc) => {
|
|
12
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
13
|
+
for (let key of __getOwnPropNames(from))
|
|
14
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
15
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
16
|
+
}
|
|
17
|
+
return to;
|
|
18
|
+
};
|
|
19
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
20
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
21
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
22
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
23
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
24
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
25
|
+
mod
|
|
26
|
+
));
|
|
27
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
28
|
+
var electronMainAdapter_exports = {};
|
|
29
|
+
__export(electronMainAdapter_exports, {
|
|
30
|
+
ElectronMainAdapter: () => ElectronMainAdapter,
|
|
31
|
+
createElectronMainAdapter: () => createElectronMainAdapter
|
|
32
|
+
});
|
|
33
|
+
module.exports = __toCommonJS(electronMainAdapter_exports);
|
|
34
|
+
var import_path = __toESM(require("path"));
|
|
35
|
+
var import_electron = require("electron");
|
|
36
|
+
var import_betterSqliteAdapter = require("../betterSqliteAdapter.js");
|
|
37
|
+
var import_protocol = require("./ipc/protocol.js");
|
|
38
|
+
var import_channels = require("./ipc/channels.js");
|
|
39
|
+
var import_segment = require("../../shared/segment.js");
|
|
40
|
+
const DEFAULT_WAL_CONFIG = {
|
|
41
|
+
enabled: true,
|
|
42
|
+
checkpointInterval: 3e5,
|
|
43
|
+
// 5 minutes
|
|
44
|
+
autoCheckpointPages: 1e3,
|
|
45
|
+
synchronous: "NORMAL"
|
|
46
|
+
};
|
|
47
|
+
const DEFAULT_RECOVERY_CONFIG = {
|
|
48
|
+
enabled: true,
|
|
49
|
+
checkOnOpen: true,
|
|
50
|
+
autoRepair: true,
|
|
51
|
+
integrityCheckTimeout: 3e4
|
|
52
|
+
};
|
|
53
|
+
const DEFAULT_MULTI_WINDOW_CONFIG = {
|
|
54
|
+
enabled: true,
|
|
55
|
+
broadcastChanges: true
|
|
56
|
+
};
|
|
57
|
+
class ElectronMainAdapter {
|
|
58
|
+
constructor(options) {
|
|
59
|
+
this.kind = "electron-main";
|
|
60
|
+
this.isInitialized = false;
|
|
61
|
+
this.walCheckpointTimer = null;
|
|
62
|
+
this.backupTimer = null;
|
|
63
|
+
this.options = options;
|
|
64
|
+
this.walConfig = { ...DEFAULT_WAL_CONFIG, ...options.wal };
|
|
65
|
+
this.recoveryConfig = { ...DEFAULT_RECOVERY_CONFIG, ...options.recovery };
|
|
66
|
+
this.multiWindowConfig = { ...DEFAULT_MULTI_WINDOW_CONFIG, ...options.multiWindow };
|
|
67
|
+
this.filePath = (0, import_segment.segmentFilePath)(options.filePath, options.segment);
|
|
68
|
+
this.innerAdapter = (0, import_betterSqliteAdapter.createBetterSqliteAdapter)(options.filePath, { segment: options.segment });
|
|
69
|
+
const baseCapabilities = new Set(this.innerAdapter.capabilities);
|
|
70
|
+
baseCapabilities.add("batch");
|
|
71
|
+
this.capabilities = baseCapabilities;
|
|
72
|
+
}
|
|
73
|
+
// ============================================================================
|
|
74
|
+
// Lifecycle Methods
|
|
75
|
+
// ============================================================================
|
|
76
|
+
/**
|
|
77
|
+
* Open the database and initialize all subsystems.
|
|
78
|
+
*/
|
|
79
|
+
async open(openOptions) {
|
|
80
|
+
if (this.isInitialized) {
|
|
81
|
+
this.log("Already initialized, skipping open()");
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
try {
|
|
85
|
+
await this.innerAdapter.open(openOptions);
|
|
86
|
+
if (this.recoveryConfig.enabled && this.recoveryConfig.checkOnOpen) {
|
|
87
|
+
await this.runIntegrityCheck();
|
|
88
|
+
}
|
|
89
|
+
if (this.walConfig.enabled) {
|
|
90
|
+
await this.configureWalMode();
|
|
91
|
+
this.startWalCheckpointTimer();
|
|
92
|
+
}
|
|
93
|
+
if (this.options.segment === void 0) {
|
|
94
|
+
(0, import_protocol.initializeIpcProtocol)(this);
|
|
95
|
+
}
|
|
96
|
+
if (this.options.backup?.enabled && this.options.backup.provider) {
|
|
97
|
+
this.startBackupScheduler();
|
|
98
|
+
}
|
|
99
|
+
this.isInitialized = true;
|
|
100
|
+
this.log("Electron Main Adapter initialized successfully");
|
|
101
|
+
} catch (error) {
|
|
102
|
+
this.log(`Failed to initialize: ${error}`);
|
|
103
|
+
throw error;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Close the database and cleanup all subsystems.
|
|
108
|
+
*/
|
|
109
|
+
async close() {
|
|
110
|
+
if (!this.isInitialized) {
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
try {
|
|
114
|
+
if (this.walCheckpointTimer) {
|
|
115
|
+
clearInterval(this.walCheckpointTimer);
|
|
116
|
+
this.walCheckpointTimer = null;
|
|
117
|
+
}
|
|
118
|
+
if (this.backupTimer) {
|
|
119
|
+
clearInterval(this.backupTimer);
|
|
120
|
+
this.backupTimer = null;
|
|
121
|
+
}
|
|
122
|
+
if (this.walConfig.enabled) {
|
|
123
|
+
await this.runWalCheckpoint();
|
|
124
|
+
}
|
|
125
|
+
if (this.options.segment === void 0) {
|
|
126
|
+
(0, import_protocol.disposeIpcProtocol)();
|
|
127
|
+
}
|
|
128
|
+
await this.innerAdapter.close();
|
|
129
|
+
this.isInitialized = false;
|
|
130
|
+
this.log("Electron Main Adapter closed");
|
|
131
|
+
} catch (error) {
|
|
132
|
+
this.log(`Error during close: ${error}`);
|
|
133
|
+
throw error;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
// ============================================================================
|
|
137
|
+
// Storage Adapter Interface
|
|
138
|
+
// ============================================================================
|
|
139
|
+
async run(statement, parameters) {
|
|
140
|
+
const result = await this.innerAdapter.run(statement, parameters);
|
|
141
|
+
if (this.multiWindowConfig.enabled && this.multiWindowConfig.broadcastChanges) {
|
|
142
|
+
this.broadcastChange({
|
|
143
|
+
type: this.detectMutationType(statement),
|
|
144
|
+
tables: this.extractTables(statement),
|
|
145
|
+
changes: result.changes,
|
|
146
|
+
timestamp: Date.now()
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
return result;
|
|
150
|
+
}
|
|
151
|
+
async get(statement, parameters) {
|
|
152
|
+
return this.innerAdapter.get(statement, parameters);
|
|
153
|
+
}
|
|
154
|
+
async all(statement, parameters) {
|
|
155
|
+
return this.innerAdapter.all(statement, parameters);
|
|
156
|
+
}
|
|
157
|
+
async exec(script) {
|
|
158
|
+
await this.innerAdapter.exec(script);
|
|
159
|
+
if (this.multiWindowConfig.enabled && this.multiWindowConfig.broadcastChanges) {
|
|
160
|
+
this.broadcastChange({
|
|
161
|
+
type: "transaction",
|
|
162
|
+
tables: [],
|
|
163
|
+
changes: 0,
|
|
164
|
+
timestamp: Date.now()
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
async transaction(fn) {
|
|
169
|
+
const result = await this.innerAdapter.transaction(fn);
|
|
170
|
+
if (this.multiWindowConfig.enabled && this.multiWindowConfig.broadcastChanges) {
|
|
171
|
+
this.broadcastChange({
|
|
172
|
+
type: "transaction",
|
|
173
|
+
tables: [],
|
|
174
|
+
changes: 0,
|
|
175
|
+
timestamp: Date.now()
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
return result;
|
|
179
|
+
}
|
|
180
|
+
async batch(operations) {
|
|
181
|
+
if (!this.innerAdapter.batch) {
|
|
182
|
+
throw new Error("Batch operations not supported");
|
|
183
|
+
}
|
|
184
|
+
const result = await this.innerAdapter.batch(operations);
|
|
185
|
+
if (this.multiWindowConfig.enabled && this.multiWindowConfig.broadcastChanges) {
|
|
186
|
+
this.broadcastChange({
|
|
187
|
+
type: "transaction",
|
|
188
|
+
tables: operations.flatMap((op) => this.extractTables(op.statement)),
|
|
189
|
+
changes: result.successful,
|
|
190
|
+
timestamp: Date.now()
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
return result;
|
|
194
|
+
}
|
|
195
|
+
prepare(statement) {
|
|
196
|
+
if (!this.innerAdapter.prepare) {
|
|
197
|
+
throw new Error("Prepared statements not supported");
|
|
198
|
+
}
|
|
199
|
+
return this.innerAdapter.prepare(statement);
|
|
200
|
+
}
|
|
201
|
+
// ============================================================================
|
|
202
|
+
// WAL Management
|
|
203
|
+
// ============================================================================
|
|
204
|
+
/**
|
|
205
|
+
* Configure WAL mode on the database.
|
|
206
|
+
*/
|
|
207
|
+
async configureWalMode() {
|
|
208
|
+
await this.innerAdapter.exec(`
|
|
209
|
+
PRAGMA journal_mode = WAL;
|
|
210
|
+
PRAGMA synchronous = ${this.walConfig.synchronous};
|
|
211
|
+
PRAGMA wal_autocheckpoint = ${this.walConfig.autoCheckpointPages};
|
|
212
|
+
`);
|
|
213
|
+
this.log("WAL mode configured");
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Start the WAL checkpoint timer.
|
|
217
|
+
*/
|
|
218
|
+
startWalCheckpointTimer() {
|
|
219
|
+
if (this.walCheckpointTimer) {
|
|
220
|
+
clearInterval(this.walCheckpointTimer);
|
|
221
|
+
}
|
|
222
|
+
this.walCheckpointTimer = setInterval(() => this.runWalCheckpoint().catch((err) => this.log(`WAL checkpoint error: ${err}`)), this.walConfig.checkpointInterval);
|
|
223
|
+
}
|
|
224
|
+
/**
|
|
225
|
+
* Run a WAL checkpoint.
|
|
226
|
+
*/
|
|
227
|
+
async runWalCheckpoint() {
|
|
228
|
+
const result = await this.innerAdapter.get("PRAGMA wal_checkpoint(PASSIVE)");
|
|
229
|
+
const checkpointResult = {
|
|
230
|
+
framesCheckpointed: result?.checkpointed ?? 0,
|
|
231
|
+
totalFrames: result?.log ?? 0
|
|
232
|
+
};
|
|
233
|
+
this.log(`WAL checkpoint: ${checkpointResult.framesCheckpointed}/${checkpointResult.totalFrames} frames`);
|
|
234
|
+
return checkpointResult;
|
|
235
|
+
}
|
|
236
|
+
// ============================================================================
|
|
237
|
+
// Integrity Check & Recovery
|
|
238
|
+
// ============================================================================
|
|
239
|
+
/**
|
|
240
|
+
* Run an integrity check on the database.
|
|
241
|
+
*/
|
|
242
|
+
async runIntegrityCheck() {
|
|
243
|
+
const results = await this.innerAdapter.all("PRAGMA integrity_check");
|
|
244
|
+
const issues = results.map((r) => r.integrity_check).filter((msg) => msg !== "ok");
|
|
245
|
+
const ok = issues.length === 0;
|
|
246
|
+
if (!ok) {
|
|
247
|
+
this.log(`Integrity check found ${issues.length} issues`);
|
|
248
|
+
if (this.recoveryConfig.autoRepair) {
|
|
249
|
+
await this.attemptRepair();
|
|
250
|
+
}
|
|
251
|
+
} else {
|
|
252
|
+
this.log("Integrity check passed");
|
|
253
|
+
}
|
|
254
|
+
return { ok, issues };
|
|
255
|
+
}
|
|
256
|
+
/**
|
|
257
|
+
* Attempt to repair the database.
|
|
258
|
+
*/
|
|
259
|
+
async attemptRepair() {
|
|
260
|
+
this.log("Attempting database repair...");
|
|
261
|
+
try {
|
|
262
|
+
await this.innerAdapter.exec("VACUUM");
|
|
263
|
+
this.log("VACUUM completed successfully");
|
|
264
|
+
} catch (error) {
|
|
265
|
+
this.log(`Repair failed: ${error}`);
|
|
266
|
+
throw new Error(`Database repair failed: ${error}`);
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
// ============================================================================
|
|
270
|
+
// Backup Management
|
|
271
|
+
// ============================================================================
|
|
272
|
+
/**
|
|
273
|
+
* Start the backup scheduler.
|
|
274
|
+
*/
|
|
275
|
+
startBackupScheduler() {
|
|
276
|
+
const interval = this.options.backup?.interval ?? 36e5;
|
|
277
|
+
this.backupTimer = setInterval(() => this.runBackup().catch((err) => this.log(`Backup error: ${err}`)), interval);
|
|
278
|
+
}
|
|
279
|
+
/**
|
|
280
|
+
* Run a backup.
|
|
281
|
+
*/
|
|
282
|
+
async runBackup() {
|
|
283
|
+
if (!this.options.backup?.provider) {
|
|
284
|
+
throw new Error("No backup provider configured");
|
|
285
|
+
}
|
|
286
|
+
const backupPath = `${this.filePath}.backup`;
|
|
287
|
+
const remotePath = `backups/${import_path.default.basename(this.filePath)}_${Date.now()}.db`;
|
|
288
|
+
await this.innerAdapter.exec(`VACUUM INTO '${backupPath}'`);
|
|
289
|
+
await this.options.backup.provider.upload(backupPath, remotePath);
|
|
290
|
+
await this.cleanupOldBackups();
|
|
291
|
+
this.log(`Backup completed: ${remotePath}`);
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
294
|
+
* Cleanup old backups beyond the retention limit.
|
|
295
|
+
*/
|
|
296
|
+
async cleanupOldBackups() {
|
|
297
|
+
if (!this.options.backup?.provider)
|
|
298
|
+
return;
|
|
299
|
+
const maxBackups = this.options.backup.maxBackups ?? 7;
|
|
300
|
+
const backups = await this.options.backup.provider.list();
|
|
301
|
+
if (backups.length > maxBackups) {
|
|
302
|
+
backups.sort((a, b) => a.createdAt.getTime() - b.createdAt.getTime());
|
|
303
|
+
const toDelete = backups.slice(0, backups.length - maxBackups);
|
|
304
|
+
for (const backup of toDelete) {
|
|
305
|
+
await this.options.backup.provider.delete(backup.path);
|
|
306
|
+
this.log(`Deleted old backup: ${backup.path}`);
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
// ============================================================================
|
|
311
|
+
// Multi-Window Broadcasting
|
|
312
|
+
// ============================================================================
|
|
313
|
+
/**
|
|
314
|
+
* Broadcast a database change to all windows.
|
|
315
|
+
*/
|
|
316
|
+
broadcastChange(change) {
|
|
317
|
+
const allWindows = import_electron.BrowserWindow.getAllWindows();
|
|
318
|
+
for (const win of allWindows) {
|
|
319
|
+
if (!win.isDestroyed()) {
|
|
320
|
+
win.webContents.send(import_channels.BROADCAST_CHANNELS.DB_CHANGE, change);
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
// ============================================================================
|
|
325
|
+
// Helper Methods
|
|
326
|
+
// ============================================================================
|
|
327
|
+
/**
|
|
328
|
+
* Detect mutation type from SQL statement.
|
|
329
|
+
*/
|
|
330
|
+
detectMutationType(statement) {
|
|
331
|
+
const upper = statement.trim().toUpperCase();
|
|
332
|
+
if (upper.startsWith("INSERT"))
|
|
333
|
+
return "insert";
|
|
334
|
+
if (upper.startsWith("UPDATE"))
|
|
335
|
+
return "update";
|
|
336
|
+
if (upper.startsWith("DELETE"))
|
|
337
|
+
return "delete";
|
|
338
|
+
return "transaction";
|
|
339
|
+
}
|
|
340
|
+
/**
|
|
341
|
+
* Extract table names from SQL statement.
|
|
342
|
+
*/
|
|
343
|
+
extractTables(statement) {
|
|
344
|
+
const tables = [];
|
|
345
|
+
const patterns = [
|
|
346
|
+
/FROM\s+([^\s,;(]+)/gi,
|
|
347
|
+
/INSERT\s+INTO\s+([^\s(]+)/gi,
|
|
348
|
+
/UPDATE\s+([^\s]+)/gi,
|
|
349
|
+
/DELETE\s+FROM\s+([^\s]+)/gi
|
|
350
|
+
];
|
|
351
|
+
for (const pattern of patterns) {
|
|
352
|
+
const matches = statement.matchAll(pattern);
|
|
353
|
+
for (const match of matches) {
|
|
354
|
+
if (match[1]) {
|
|
355
|
+
tables.push(match[1].toLowerCase().replace(/["`[\]]/g, ""));
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
return [...new Set(tables)];
|
|
360
|
+
}
|
|
361
|
+
/**
|
|
362
|
+
* Log a message if verbose mode is enabled.
|
|
363
|
+
*/
|
|
364
|
+
log(message) {
|
|
365
|
+
if (this.options.verbose) {
|
|
366
|
+
console.log(`[ElectronMainAdapter] ${message}`);
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
// ============================================================================
|
|
370
|
+
// Public Utilities
|
|
371
|
+
// ============================================================================
|
|
372
|
+
/**
|
|
373
|
+
* Check if the adapter is initialized.
|
|
374
|
+
*/
|
|
375
|
+
isOpen() {
|
|
376
|
+
return this.isInitialized;
|
|
377
|
+
}
|
|
378
|
+
/**
|
|
379
|
+
* Get the database file path.
|
|
380
|
+
*/
|
|
381
|
+
getFilePath() {
|
|
382
|
+
return this.filePath;
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
function createElectronMainAdapter(options) {
|
|
386
|
+
return new ElectronMainAdapter(options);
|
|
387
|
+
}
|
|
388
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
389
|
+
0 && (module.exports = {
|
|
390
|
+
ElectronMainAdapter,
|
|
391
|
+
createElectronMainAdapter
|
|
392
|
+
});
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Electron Renderer Process Storage Adapter.
|
|
3
|
+
*
|
|
4
|
+
* Provides the same StorageAdapter interface to renderer processes
|
|
5
|
+
* by proxying all operations to the main process via IPC.
|
|
6
|
+
*
|
|
7
|
+
* ## Architecture
|
|
8
|
+
* This adapter runs in renderer processes and communicates with
|
|
9
|
+
* ElectronMainAdapter in the main process via the preload script API.
|
|
10
|
+
*
|
|
11
|
+
* ## Requirements
|
|
12
|
+
* - Preload script must be loaded and expose `window.sqlStorage`
|
|
13
|
+
* - Main process must have ElectronMainAdapter initialized
|
|
14
|
+
*
|
|
15
|
+
* ## Usage
|
|
16
|
+
* ```typescript
|
|
17
|
+
* import { createElectronRendererAdapter } from '@framers/sql-storage-adapter/electron';
|
|
18
|
+
*
|
|
19
|
+
* const db = createElectronRendererAdapter({
|
|
20
|
+
* onDatabaseChange: (change) => {
|
|
21
|
+
* console.log('Database changed:', change);
|
|
22
|
+
* // React to changes from other windows
|
|
23
|
+
* },
|
|
24
|
+
* });
|
|
25
|
+
*
|
|
26
|
+
* await db.open();
|
|
27
|
+
* const users = await db.all('SELECT * FROM users');
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
import type { StorageAdapter, StorageCapability, StorageOpenOptions, StorageParameters, StorageRunResult, BatchOperation, BatchResult, PreparedStatement } from '../../core/contracts/index.js';
|
|
31
|
+
import type { DbChangeEvent, SyncStatus } from './ipc/types.js';
|
|
32
|
+
/**
|
|
33
|
+
* Options for ElectronRendererAdapter.
|
|
34
|
+
*/
|
|
35
|
+
export interface ElectronRendererAdapterOptions {
|
|
36
|
+
/**
|
|
37
|
+
* Callback when database changes from another window.
|
|
38
|
+
* Use this to invalidate caches or refresh UI.
|
|
39
|
+
*/
|
|
40
|
+
onDatabaseChange?: (event: DbChangeEvent) => void;
|
|
41
|
+
/**
|
|
42
|
+
* Callback when sync progress updates.
|
|
43
|
+
*/
|
|
44
|
+
onSyncProgress?: (progress: number) => void;
|
|
45
|
+
/**
|
|
46
|
+
* Callback when sync completes.
|
|
47
|
+
*/
|
|
48
|
+
onSyncComplete?: () => void;
|
|
49
|
+
/**
|
|
50
|
+
* Callback when sync encounters an error.
|
|
51
|
+
*/
|
|
52
|
+
onSyncError?: (error: Error) => void;
|
|
53
|
+
/**
|
|
54
|
+
* Enable verbose logging (default: false).
|
|
55
|
+
*/
|
|
56
|
+
verbose?: boolean;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Storage adapter for Electron renderer processes.
|
|
60
|
+
*
|
|
61
|
+
* Proxies all database operations to the main process via IPC.
|
|
62
|
+
* Implements the same StorageAdapter interface as other adapters.
|
|
63
|
+
*/
|
|
64
|
+
export declare class ElectronRendererAdapter implements StorageAdapter {
|
|
65
|
+
readonly kind = "electron-renderer";
|
|
66
|
+
capabilities: ReadonlySet<StorageCapability>;
|
|
67
|
+
private readonly options;
|
|
68
|
+
private eventUnsubscribers;
|
|
69
|
+
private isInitialized;
|
|
70
|
+
private cachedCapabilities;
|
|
71
|
+
constructor(options?: ElectronRendererAdapterOptions);
|
|
72
|
+
/**
|
|
73
|
+
* Get the preload API, throwing if not available.
|
|
74
|
+
*/
|
|
75
|
+
private getApi;
|
|
76
|
+
/**
|
|
77
|
+
* Log a message if verbose mode is enabled.
|
|
78
|
+
*/
|
|
79
|
+
private log;
|
|
80
|
+
/**
|
|
81
|
+
* Open connection to the database via main process.
|
|
82
|
+
*/
|
|
83
|
+
open(options?: StorageOpenOptions): Promise<void>;
|
|
84
|
+
/**
|
|
85
|
+
* Close connection.
|
|
86
|
+
*/
|
|
87
|
+
close(): Promise<void>;
|
|
88
|
+
/**
|
|
89
|
+
* Subscribe to database events from main process.
|
|
90
|
+
*/
|
|
91
|
+
private subscribeToEvents;
|
|
92
|
+
/**
|
|
93
|
+
* Execute a mutation statement (INSERT, UPDATE, DELETE).
|
|
94
|
+
*/
|
|
95
|
+
run(statement: string, parameters?: StorageParameters): Promise<StorageRunResult>;
|
|
96
|
+
/**
|
|
97
|
+
* Get a single row.
|
|
98
|
+
*/
|
|
99
|
+
get<T = unknown>(statement: string, parameters?: StorageParameters): Promise<T | null>;
|
|
100
|
+
/**
|
|
101
|
+
* Get all matching rows.
|
|
102
|
+
*/
|
|
103
|
+
all<T = unknown>(statement: string, parameters?: StorageParameters): Promise<T[]>;
|
|
104
|
+
/**
|
|
105
|
+
* Execute a SQL script.
|
|
106
|
+
*/
|
|
107
|
+
exec(script: string): Promise<void>;
|
|
108
|
+
/**
|
|
109
|
+
* Execute operations within a transaction.
|
|
110
|
+
*/
|
|
111
|
+
transaction<T>(fn: (trx: StorageAdapter) => Promise<T>): Promise<T>;
|
|
112
|
+
/**
|
|
113
|
+
* Execute batch operations.
|
|
114
|
+
*/
|
|
115
|
+
batch(operations: BatchOperation[]): Promise<BatchResult>;
|
|
116
|
+
/**
|
|
117
|
+
* Prepared statements are not directly supported in renderer.
|
|
118
|
+
* Use the main process adapter for prepared statements.
|
|
119
|
+
*/
|
|
120
|
+
prepare?<T = unknown>(_statement: string): PreparedStatement<T>;
|
|
121
|
+
/**
|
|
122
|
+
* Get current sync status.
|
|
123
|
+
*/
|
|
124
|
+
getSyncStatus(): Promise<SyncStatus>;
|
|
125
|
+
/**
|
|
126
|
+
* Trigger a manual sync.
|
|
127
|
+
*/
|
|
128
|
+
triggerSync(): Promise<void>;
|
|
129
|
+
/**
|
|
130
|
+
* Assert that the adapter is open.
|
|
131
|
+
*/
|
|
132
|
+
private assertOpen;
|
|
133
|
+
/**
|
|
134
|
+
* Check if the adapter is open.
|
|
135
|
+
*/
|
|
136
|
+
isOpen(): boolean;
|
|
137
|
+
/**
|
|
138
|
+
* Check if the main process database is open.
|
|
139
|
+
*/
|
|
140
|
+
isMainProcessOpen(): Promise<boolean>;
|
|
141
|
+
/**
|
|
142
|
+
* Add an event listener for database changes.
|
|
143
|
+
*/
|
|
144
|
+
onDatabaseChange(callback: (event: DbChangeEvent) => void): () => void;
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Create an Electron Renderer Process Storage Adapter.
|
|
148
|
+
*
|
|
149
|
+
* This adapter proxies all database operations to the main process
|
|
150
|
+
* via IPC. Use it in renderer processes to access the shared database.
|
|
151
|
+
*
|
|
152
|
+
* @param options - Adapter configuration
|
|
153
|
+
* @returns ElectronRendererAdapter instance
|
|
154
|
+
*
|
|
155
|
+
* @example
|
|
156
|
+
* ```typescript
|
|
157
|
+
* const db = createElectronRendererAdapter({
|
|
158
|
+
* onDatabaseChange: (change) => {
|
|
159
|
+
* console.log('Database changed:', change);
|
|
160
|
+
* // Refresh data or invalidate caches
|
|
161
|
+
* },
|
|
162
|
+
* });
|
|
163
|
+
*
|
|
164
|
+
* await db.open();
|
|
165
|
+
* const users = await db.all('SELECT * FROM users');
|
|
166
|
+
* ```
|
|
167
|
+
*/
|
|
168
|
+
export declare function createElectronRendererAdapter(options?: ElectronRendererAdapterOptions): ElectronRendererAdapter;
|
|
169
|
+
/**
|
|
170
|
+
* Helper to detect if running in Electron renderer.
|
|
171
|
+
*/
|
|
172
|
+
export declare function isElectronRenderer(): boolean;
|
|
173
|
+
/**
|
|
174
|
+
* Helper to check if preload API is available.
|
|
175
|
+
*/
|
|
176
|
+
export declare function isPreloadApiAvailable(): boolean;
|
|
177
|
+
//# sourceMappingURL=electronRendererAdapter.d.ts.map
|