@framers/sql-storage-adapter 0.7.2 → 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 +20 -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/package.json +139 -24
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
|
+
var __export = (target, all) => {
|
|
6
|
+
for (var name in all)
|
|
7
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
8
|
+
};
|
|
9
|
+
var __copyProps = (to, from, except, desc) => {
|
|
10
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
11
|
+
for (let key of __getOwnPropNames(from))
|
|
12
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
13
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
14
|
+
}
|
|
15
|
+
return to;
|
|
16
|
+
};
|
|
17
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
18
|
+
var transport_exports = {};
|
|
19
|
+
__export(transport_exports, {
|
|
20
|
+
BaseTransport: () => BaseTransport,
|
|
21
|
+
TransportError: () => TransportError,
|
|
22
|
+
TransportErrorCodes: () => TransportErrorCodes
|
|
23
|
+
});
|
|
24
|
+
module.exports = __toCommonJS(transport_exports);
|
|
25
|
+
class TransportError extends Error {
|
|
26
|
+
constructor(message, code, options) {
|
|
27
|
+
super(message);
|
|
28
|
+
this.name = "TransportError";
|
|
29
|
+
this.code = code;
|
|
30
|
+
this.recoverable = options?.recoverable ?? false;
|
|
31
|
+
this.cause = options?.cause;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
const TransportErrorCodes = {
|
|
35
|
+
/** Connection failed */
|
|
36
|
+
CONNECTION_FAILED: "CONNECTION_FAILED",
|
|
37
|
+
/** Connection timeout */
|
|
38
|
+
CONNECTION_TIMEOUT: "CONNECTION_TIMEOUT",
|
|
39
|
+
/** Authentication failed */
|
|
40
|
+
AUTH_FAILED: "AUTH_FAILED",
|
|
41
|
+
/** Request timeout */
|
|
42
|
+
REQUEST_TIMEOUT: "REQUEST_TIMEOUT",
|
|
43
|
+
/** Send failed */
|
|
44
|
+
SEND_FAILED: "SEND_FAILED",
|
|
45
|
+
/** Server error */
|
|
46
|
+
SERVER_ERROR: "SERVER_ERROR",
|
|
47
|
+
/** Network error */
|
|
48
|
+
NETWORK_ERROR: "NETWORK_ERROR",
|
|
49
|
+
/** Protocol error */
|
|
50
|
+
PROTOCOL_ERROR: "PROTOCOL_ERROR",
|
|
51
|
+
/** Transport disposed */
|
|
52
|
+
DISPOSED: "DISPOSED"
|
|
53
|
+
};
|
|
54
|
+
class BaseTransport {
|
|
55
|
+
constructor(options) {
|
|
56
|
+
this._state = "disconnected";
|
|
57
|
+
this._disposed = false;
|
|
58
|
+
this._listeners = /* @__PURE__ */ new Map();
|
|
59
|
+
this._options = {
|
|
60
|
+
endpoint: options.endpoint,
|
|
61
|
+
authToken: options.authToken ?? "",
|
|
62
|
+
headers: options.headers ?? {},
|
|
63
|
+
connectionTimeout: options.connectionTimeout ?? 1e4,
|
|
64
|
+
requestTimeout: options.requestTimeout ?? 3e4,
|
|
65
|
+
autoReconnect: options.autoReconnect ?? true,
|
|
66
|
+
reconnectDelay: options.reconnectDelay ?? 1e3,
|
|
67
|
+
maxReconnectDelay: options.maxReconnectDelay ?? 3e4,
|
|
68
|
+
maxReconnectAttempts: options.maxReconnectAttempts ?? 0,
|
|
69
|
+
heartbeatInterval: options.heartbeatInterval ?? 3e4,
|
|
70
|
+
compression: options.compression ?? true
|
|
71
|
+
};
|
|
72
|
+
this._stats = {
|
|
73
|
+
state: "disconnected",
|
|
74
|
+
messagesSent: 0,
|
|
75
|
+
messagesReceived: 0,
|
|
76
|
+
bytesSent: 0,
|
|
77
|
+
bytesReceived: 0,
|
|
78
|
+
reconnectAttempts: 0
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
get state() {
|
|
82
|
+
return this._state;
|
|
83
|
+
}
|
|
84
|
+
get isConnected() {
|
|
85
|
+
return this._state === "connected";
|
|
86
|
+
}
|
|
87
|
+
on(event, listener) {
|
|
88
|
+
if (!this._listeners.has(event)) {
|
|
89
|
+
this._listeners.set(event, /* @__PURE__ */ new Set());
|
|
90
|
+
}
|
|
91
|
+
const listeners = this._listeners.get(event);
|
|
92
|
+
listeners.add(listener);
|
|
93
|
+
return () => {
|
|
94
|
+
listeners.delete(listener);
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
once(event, listener) {
|
|
98
|
+
const wrapper = (eventData) => {
|
|
99
|
+
unsubscribe();
|
|
100
|
+
listener(eventData);
|
|
101
|
+
};
|
|
102
|
+
const unsubscribe = this.on(event, wrapper);
|
|
103
|
+
return unsubscribe;
|
|
104
|
+
}
|
|
105
|
+
getStats() {
|
|
106
|
+
return { ...this._stats, state: this._state };
|
|
107
|
+
}
|
|
108
|
+
async dispose() {
|
|
109
|
+
if (this._disposed)
|
|
110
|
+
return;
|
|
111
|
+
this._disposed = true;
|
|
112
|
+
await this.disconnect("disposed");
|
|
113
|
+
this._listeners.clear();
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Emit an event to all registered listeners.
|
|
117
|
+
*/
|
|
118
|
+
emit(event, data) {
|
|
119
|
+
const listeners = this._listeners.get(event);
|
|
120
|
+
if (!listeners)
|
|
121
|
+
return;
|
|
122
|
+
for (const listener of listeners) {
|
|
123
|
+
try {
|
|
124
|
+
listener(data);
|
|
125
|
+
} catch (error) {
|
|
126
|
+
console.error(`[Transport] Error in ${event} listener:`, error);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Update transport state and emit event.
|
|
132
|
+
*/
|
|
133
|
+
setState(newState) {
|
|
134
|
+
if (this._state === newState)
|
|
135
|
+
return;
|
|
136
|
+
const previousState = this._state;
|
|
137
|
+
this._state = newState;
|
|
138
|
+
this._stats.state = newState;
|
|
139
|
+
this.emit("stateChange", { previousState, currentState: newState });
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Check if transport is disposed and throw if so.
|
|
143
|
+
*/
|
|
144
|
+
checkDisposed() {
|
|
145
|
+
if (this._disposed) {
|
|
146
|
+
throw new TransportError("Transport has been disposed", TransportErrorCodes.DISPOSED, { recoverable: false });
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Calculate next reconnection delay with exponential backoff.
|
|
151
|
+
*/
|
|
152
|
+
calculateReconnectDelay(attempt) {
|
|
153
|
+
const delay = Math.min(this._options.reconnectDelay * Math.pow(2, attempt - 1), this._options.maxReconnectDelay);
|
|
154
|
+
const jitter = delay * 0.2 * (Math.random() * 2 - 1);
|
|
155
|
+
return Math.floor(delay + jitter);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
159
|
+
0 && (module.exports = {
|
|
160
|
+
BaseTransport,
|
|
161
|
+
TransportError,
|
|
162
|
+
TransportErrorCodes
|
|
163
|
+
});
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WebSocket Transport Implementation.
|
|
3
|
+
*
|
|
4
|
+
* Real-time bidirectional sync transport using WebSockets.
|
|
5
|
+
* Supports automatic reconnection, heartbeats, and message compression.
|
|
6
|
+
*
|
|
7
|
+
* @packageDocumentation
|
|
8
|
+
*/
|
|
9
|
+
import { BaseTransport, type TransportOptions } from './transport.js';
|
|
10
|
+
import type { SyncMessage } from '../protocol/messages.js';
|
|
11
|
+
/**
|
|
12
|
+
* WebSocket-specific transport options.
|
|
13
|
+
*/
|
|
14
|
+
export interface WebSocketTransportOptions extends TransportOptions {
|
|
15
|
+
/** WebSocket protocols to use */
|
|
16
|
+
protocols?: string[];
|
|
17
|
+
/** Binary message format */
|
|
18
|
+
binaryType?: 'arraybuffer' | 'blob';
|
|
19
|
+
/** Enable ping/pong heartbeats */
|
|
20
|
+
pingPong?: boolean;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* WebSocket transport for real-time sync.
|
|
24
|
+
*
|
|
25
|
+
* Provides low-latency bidirectional communication with:
|
|
26
|
+
* - Automatic reconnection with exponential backoff
|
|
27
|
+
* - Request/response correlation
|
|
28
|
+
* - Heartbeat keep-alive
|
|
29
|
+
* - Message compression (gzip)
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* ```typescript
|
|
33
|
+
* const transport = new WebSocketTransport({
|
|
34
|
+
* endpoint: 'wss://sync.example.com/v1/sync',
|
|
35
|
+
* authToken: 'bearer-token',
|
|
36
|
+
* autoReconnect: true,
|
|
37
|
+
* heartbeatInterval: 30000,
|
|
38
|
+
* });
|
|
39
|
+
*
|
|
40
|
+
* transport.on('message', ({ message }) => {
|
|
41
|
+
* handleSyncMessage(message);
|
|
42
|
+
* });
|
|
43
|
+
*
|
|
44
|
+
* await transport.connect();
|
|
45
|
+
* ```
|
|
46
|
+
*/
|
|
47
|
+
export declare class WebSocketTransport extends BaseTransport {
|
|
48
|
+
readonly type: "websocket";
|
|
49
|
+
private _ws;
|
|
50
|
+
private _heartbeatTimer;
|
|
51
|
+
private _reconnectTimer;
|
|
52
|
+
private _pendingRequests;
|
|
53
|
+
private _wsOptions;
|
|
54
|
+
private _lastPongAt;
|
|
55
|
+
private _shouldReconnect;
|
|
56
|
+
constructor(options: WebSocketTransportOptions);
|
|
57
|
+
/**
|
|
58
|
+
* Connect to the WebSocket server.
|
|
59
|
+
*/
|
|
60
|
+
connect(): Promise<void>;
|
|
61
|
+
/**
|
|
62
|
+
* Disconnect from the WebSocket server.
|
|
63
|
+
*/
|
|
64
|
+
disconnect(reason?: string): Promise<void>;
|
|
65
|
+
/**
|
|
66
|
+
* Send a sync message.
|
|
67
|
+
*/
|
|
68
|
+
send(message: SyncMessage): Promise<void>;
|
|
69
|
+
/**
|
|
70
|
+
* Send a message and wait for a response.
|
|
71
|
+
*/
|
|
72
|
+
request(message: SyncMessage, timeout?: number): Promise<SyncMessage>;
|
|
73
|
+
/**
|
|
74
|
+
* Create WebSocket connection.
|
|
75
|
+
*/
|
|
76
|
+
private _createConnection;
|
|
77
|
+
/**
|
|
78
|
+
* Build WebSocket URL with auth token.
|
|
79
|
+
*/
|
|
80
|
+
private _buildUrl;
|
|
81
|
+
/**
|
|
82
|
+
* Handle incoming WebSocket message.
|
|
83
|
+
*/
|
|
84
|
+
private _handleMessage;
|
|
85
|
+
/**
|
|
86
|
+
* Handle WebSocket close event.
|
|
87
|
+
*/
|
|
88
|
+
private _handleClose;
|
|
89
|
+
/**
|
|
90
|
+
* Schedule reconnection attempt.
|
|
91
|
+
*/
|
|
92
|
+
private _scheduleReconnect;
|
|
93
|
+
/**
|
|
94
|
+
* Start heartbeat timer.
|
|
95
|
+
*/
|
|
96
|
+
private _startHeartbeat;
|
|
97
|
+
/**
|
|
98
|
+
* Stop heartbeat timer.
|
|
99
|
+
*/
|
|
100
|
+
private _stopHeartbeat;
|
|
101
|
+
/**
|
|
102
|
+
* Clear all timers.
|
|
103
|
+
*/
|
|
104
|
+
private _clearTimers;
|
|
105
|
+
/**
|
|
106
|
+
* Reject all pending requests.
|
|
107
|
+
*/
|
|
108
|
+
private _rejectAllPending;
|
|
109
|
+
/**
|
|
110
|
+
* Serialize message for transmission.
|
|
111
|
+
*/
|
|
112
|
+
private _serialize;
|
|
113
|
+
/**
|
|
114
|
+
* Deserialize received message.
|
|
115
|
+
*/
|
|
116
|
+
private _deserialize;
|
|
117
|
+
/**
|
|
118
|
+
* Dispose of the transport.
|
|
119
|
+
*/
|
|
120
|
+
dispose(): Promise<void>;
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Create a WebSocket transport instance.
|
|
124
|
+
*/
|
|
125
|
+
export declare const createWebSocketTransport: (options: WebSocketTransportOptions) => WebSocketTransport;
|
|
126
|
+
//# sourceMappingURL=websocketTransport.d.ts.map
|
|
@@ -0,0 +1,342 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
|
+
var __export = (target, all) => {
|
|
6
|
+
for (var name in all)
|
|
7
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
8
|
+
};
|
|
9
|
+
var __copyProps = (to, from, except, desc) => {
|
|
10
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
11
|
+
for (let key of __getOwnPropNames(from))
|
|
12
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
13
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
14
|
+
}
|
|
15
|
+
return to;
|
|
16
|
+
};
|
|
17
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
18
|
+
var websocketTransport_exports = {};
|
|
19
|
+
__export(websocketTransport_exports, {
|
|
20
|
+
WebSocketTransport: () => WebSocketTransport,
|
|
21
|
+
createWebSocketTransport: () => createWebSocketTransport
|
|
22
|
+
});
|
|
23
|
+
module.exports = __toCommonJS(websocketTransport_exports);
|
|
24
|
+
var import_transport = require("./transport.js");
|
|
25
|
+
var import_messages = require("../protocol/messages.js");
|
|
26
|
+
class WebSocketTransport extends import_transport.BaseTransport {
|
|
27
|
+
constructor(options) {
|
|
28
|
+
super(options);
|
|
29
|
+
this.type = "websocket";
|
|
30
|
+
this._ws = null;
|
|
31
|
+
this._heartbeatTimer = null;
|
|
32
|
+
this._reconnectTimer = null;
|
|
33
|
+
this._pendingRequests = /* @__PURE__ */ new Map();
|
|
34
|
+
this._lastPongAt = 0;
|
|
35
|
+
this._shouldReconnect = false;
|
|
36
|
+
this._wsOptions = {
|
|
37
|
+
...this._options,
|
|
38
|
+
protocols: options.protocols ?? ["sync-v1"],
|
|
39
|
+
binaryType: options.binaryType ?? "arraybuffer",
|
|
40
|
+
pingPong: options.pingPong ?? true
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Connect to the WebSocket server.
|
|
45
|
+
*/
|
|
46
|
+
async connect() {
|
|
47
|
+
this.checkDisposed();
|
|
48
|
+
if (this._state === "connected" || this._state === "connecting") {
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
this.setState("connecting");
|
|
52
|
+
this._shouldReconnect = this._options.autoReconnect;
|
|
53
|
+
try {
|
|
54
|
+
await this._createConnection();
|
|
55
|
+
} catch (error) {
|
|
56
|
+
this.setState("error");
|
|
57
|
+
throw error;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Disconnect from the WebSocket server.
|
|
62
|
+
*/
|
|
63
|
+
async disconnect(reason = "client disconnect") {
|
|
64
|
+
this._shouldReconnect = false;
|
|
65
|
+
this._clearTimers();
|
|
66
|
+
this._rejectAllPending(new import_transport.TransportError("Disconnected", import_transport.TransportErrorCodes.DISPOSED, { recoverable: false }));
|
|
67
|
+
if (this._ws) {
|
|
68
|
+
try {
|
|
69
|
+
this._ws.close(1e3, reason);
|
|
70
|
+
} catch {
|
|
71
|
+
}
|
|
72
|
+
this._ws = null;
|
|
73
|
+
}
|
|
74
|
+
this.setState("disconnected");
|
|
75
|
+
this.emit("disconnected", { reason, wasClean: true });
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Send a sync message.
|
|
79
|
+
*/
|
|
80
|
+
async send(message) {
|
|
81
|
+
this.checkDisposed();
|
|
82
|
+
if (!this._ws || this._state !== "connected") {
|
|
83
|
+
throw new import_transport.TransportError("Not connected", import_transport.TransportErrorCodes.SEND_FAILED, { recoverable: true });
|
|
84
|
+
}
|
|
85
|
+
const data = this._serialize(message);
|
|
86
|
+
try {
|
|
87
|
+
this._ws.send(data);
|
|
88
|
+
this._stats.messagesSent++;
|
|
89
|
+
this._stats.bytesSent += data.length;
|
|
90
|
+
} catch (error) {
|
|
91
|
+
throw new import_transport.TransportError("Failed to send message", import_transport.TransportErrorCodes.SEND_FAILED, { recoverable: true, cause: error });
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Send a message and wait for a response.
|
|
96
|
+
*/
|
|
97
|
+
async request(message, timeout) {
|
|
98
|
+
this.checkDisposed();
|
|
99
|
+
const requestId = message.messageId;
|
|
100
|
+
const timeoutMs = timeout ?? this._options.requestTimeout;
|
|
101
|
+
return new Promise((resolve, reject) => {
|
|
102
|
+
const timer = setTimeout(() => {
|
|
103
|
+
this._pendingRequests.delete(requestId);
|
|
104
|
+
reject(new import_transport.TransportError("Request timed out", import_transport.TransportErrorCodes.REQUEST_TIMEOUT, { recoverable: true }));
|
|
105
|
+
}, timeoutMs);
|
|
106
|
+
this._pendingRequests.set(requestId, { resolve, reject, timer });
|
|
107
|
+
this.send(message).catch((error) => {
|
|
108
|
+
clearTimeout(timer);
|
|
109
|
+
this._pendingRequests.delete(requestId);
|
|
110
|
+
reject(error);
|
|
111
|
+
});
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Create WebSocket connection.
|
|
116
|
+
*/
|
|
117
|
+
_createConnection() {
|
|
118
|
+
return new Promise((resolve, reject) => {
|
|
119
|
+
const url = this._buildUrl();
|
|
120
|
+
const timeout = setTimeout(() => {
|
|
121
|
+
reject(new import_transport.TransportError("Connection timed out", import_transport.TransportErrorCodes.CONNECTION_TIMEOUT, { recoverable: true }));
|
|
122
|
+
}, this._options.connectionTimeout);
|
|
123
|
+
try {
|
|
124
|
+
this._ws = new WebSocket(url, this._wsOptions.protocols);
|
|
125
|
+
this._ws.binaryType = this._wsOptions.binaryType;
|
|
126
|
+
} catch (error) {
|
|
127
|
+
clearTimeout(timeout);
|
|
128
|
+
reject(new import_transport.TransportError("Failed to create WebSocket", import_transport.TransportErrorCodes.CONNECTION_FAILED, { recoverable: true, cause: error }));
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
this._ws.onopen = () => {
|
|
132
|
+
clearTimeout(timeout);
|
|
133
|
+
this.setState("connected");
|
|
134
|
+
this._stats.connectedAt = Date.now();
|
|
135
|
+
this._stats.reconnectAttempts = 0;
|
|
136
|
+
this._startHeartbeat();
|
|
137
|
+
this.emit("connected", { timestamp: Date.now() });
|
|
138
|
+
resolve();
|
|
139
|
+
};
|
|
140
|
+
this._ws.onclose = (event) => {
|
|
141
|
+
clearTimeout(timeout);
|
|
142
|
+
this._handleClose(event);
|
|
143
|
+
if (this._state === "connecting") {
|
|
144
|
+
reject(new import_transport.TransportError(`Connection closed: ${event.reason || "unknown"}`, import_transport.TransportErrorCodes.CONNECTION_FAILED, { recoverable: true }));
|
|
145
|
+
}
|
|
146
|
+
};
|
|
147
|
+
this._ws.onerror = (event) => {
|
|
148
|
+
const error = new import_transport.TransportError("WebSocket error", import_transport.TransportErrorCodes.NETWORK_ERROR, { recoverable: true });
|
|
149
|
+
this.emit("error", { error, recoverable: true });
|
|
150
|
+
console.error("[WebSocketTransport] Connection error:", event);
|
|
151
|
+
};
|
|
152
|
+
this._ws.onmessage = (event) => {
|
|
153
|
+
this._handleMessage(event);
|
|
154
|
+
};
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Build WebSocket URL with auth token.
|
|
159
|
+
*/
|
|
160
|
+
_buildUrl() {
|
|
161
|
+
const url = new URL(this._options.endpoint);
|
|
162
|
+
if (this._options.authToken) {
|
|
163
|
+
url.searchParams.set("token", this._options.authToken);
|
|
164
|
+
}
|
|
165
|
+
return url.toString();
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Handle incoming WebSocket message.
|
|
169
|
+
*/
|
|
170
|
+
_handleMessage(event) {
|
|
171
|
+
try {
|
|
172
|
+
const message = this._deserialize(event.data);
|
|
173
|
+
if (!(0, import_messages.isSyncMessage)(message)) {
|
|
174
|
+
console.warn("[WebSocketTransport] Received invalid message:", message);
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
this._stats.messagesReceived++;
|
|
178
|
+
this._stats.bytesReceived += typeof event.data === "string" ? event.data.length : event.data.byteLength;
|
|
179
|
+
if (message.type === "heartbeat") {
|
|
180
|
+
this._lastPongAt = Date.now();
|
|
181
|
+
this.send((0, import_messages.createAckMessage)(message.messageId, this._options.authToken || "device")).catch(() => {
|
|
182
|
+
});
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
if (message.type === "ack") {
|
|
186
|
+
const pending = this._pendingRequests.get(message.ackMessageId);
|
|
187
|
+
if (pending) {
|
|
188
|
+
clearTimeout(pending.timer);
|
|
189
|
+
this._pendingRequests.delete(message.ackMessageId);
|
|
190
|
+
pending.resolve(message);
|
|
191
|
+
}
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
if ("inResponseTo" in message && message.inResponseTo) {
|
|
195
|
+
const pending = this._pendingRequests.get(message.inResponseTo);
|
|
196
|
+
if (pending) {
|
|
197
|
+
clearTimeout(pending.timer);
|
|
198
|
+
this._pendingRequests.delete(message.inResponseTo);
|
|
199
|
+
pending.resolve(message);
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
this.emit("message", { message, receivedAt: Date.now() });
|
|
204
|
+
} catch (error) {
|
|
205
|
+
console.error("[WebSocketTransport] Failed to process message:", error);
|
|
206
|
+
this.emit("error", {
|
|
207
|
+
error: new import_transport.TransportError("Failed to process message", import_transport.TransportErrorCodes.PROTOCOL_ERROR, { recoverable: true, cause: error }),
|
|
208
|
+
recoverable: true
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Handle WebSocket close event.
|
|
214
|
+
*/
|
|
215
|
+
_handleClose(event) {
|
|
216
|
+
this._stopHeartbeat();
|
|
217
|
+
const wasConnected = this._state === "connected";
|
|
218
|
+
const wasClean = event.wasClean;
|
|
219
|
+
const reason = event.reason || `Code: ${event.code}`;
|
|
220
|
+
this.emit("disconnected", { reason, wasClean });
|
|
221
|
+
this._rejectAllPending(new import_transport.TransportError("Connection closed", import_transport.TransportErrorCodes.NETWORK_ERROR, { recoverable: this._shouldReconnect }));
|
|
222
|
+
if (this._shouldReconnect && wasConnected) {
|
|
223
|
+
this._scheduleReconnect();
|
|
224
|
+
} else {
|
|
225
|
+
this.setState("disconnected");
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Schedule reconnection attempt.
|
|
230
|
+
*/
|
|
231
|
+
_scheduleReconnect() {
|
|
232
|
+
if (!this._shouldReconnect || this._disposed)
|
|
233
|
+
return;
|
|
234
|
+
const maxAttempts = this._options.maxReconnectAttempts;
|
|
235
|
+
if (maxAttempts > 0 && this._stats.reconnectAttempts >= maxAttempts) {
|
|
236
|
+
console.warn("[WebSocketTransport] Max reconnection attempts reached");
|
|
237
|
+
this.setState("error");
|
|
238
|
+
return;
|
|
239
|
+
}
|
|
240
|
+
this._stats.reconnectAttempts++;
|
|
241
|
+
const delay = this.calculateReconnectDelay(this._stats.reconnectAttempts);
|
|
242
|
+
this.setState("reconnecting");
|
|
243
|
+
this.emit("reconnecting", {
|
|
244
|
+
attempt: this._stats.reconnectAttempts,
|
|
245
|
+
delay
|
|
246
|
+
});
|
|
247
|
+
this._reconnectTimer = setTimeout(async () => {
|
|
248
|
+
if (!this._shouldReconnect || this._disposed)
|
|
249
|
+
return;
|
|
250
|
+
try {
|
|
251
|
+
await this._createConnection();
|
|
252
|
+
} catch (error) {
|
|
253
|
+
console.warn("[WebSocketTransport] Reconnection failed:", error);
|
|
254
|
+
this._scheduleReconnect();
|
|
255
|
+
}
|
|
256
|
+
}, delay);
|
|
257
|
+
}
|
|
258
|
+
/**
|
|
259
|
+
* Start heartbeat timer.
|
|
260
|
+
*/
|
|
261
|
+
_startHeartbeat() {
|
|
262
|
+
if (!this._wsOptions.pingPong || this._options.heartbeatInterval <= 0) {
|
|
263
|
+
return;
|
|
264
|
+
}
|
|
265
|
+
this._lastPongAt = Date.now();
|
|
266
|
+
this._heartbeatTimer = setInterval(() => {
|
|
267
|
+
if (!this._ws || this._state !== "connected")
|
|
268
|
+
return;
|
|
269
|
+
const missedTime = Date.now() - this._lastPongAt;
|
|
270
|
+
if (missedTime > this._options.heartbeatInterval * 3) {
|
|
271
|
+
console.warn("[WebSocketTransport] Heartbeat timeout, reconnecting...");
|
|
272
|
+
this._ws.close(4e3, "Heartbeat timeout");
|
|
273
|
+
return;
|
|
274
|
+
}
|
|
275
|
+
const heartbeat = (0, import_messages.createHeartbeatMessage)(this._options.authToken || "device");
|
|
276
|
+
this.send(heartbeat).catch((error) => {
|
|
277
|
+
console.warn("[WebSocketTransport] Failed to send heartbeat:", error);
|
|
278
|
+
});
|
|
279
|
+
}, this._options.heartbeatInterval);
|
|
280
|
+
}
|
|
281
|
+
/**
|
|
282
|
+
* Stop heartbeat timer.
|
|
283
|
+
*/
|
|
284
|
+
_stopHeartbeat() {
|
|
285
|
+
if (this._heartbeatTimer) {
|
|
286
|
+
clearInterval(this._heartbeatTimer);
|
|
287
|
+
this._heartbeatTimer = null;
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
/**
|
|
291
|
+
* Clear all timers.
|
|
292
|
+
*/
|
|
293
|
+
_clearTimers() {
|
|
294
|
+
this._stopHeartbeat();
|
|
295
|
+
if (this._reconnectTimer) {
|
|
296
|
+
clearTimeout(this._reconnectTimer);
|
|
297
|
+
this._reconnectTimer = null;
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
/**
|
|
301
|
+
* Reject all pending requests.
|
|
302
|
+
*/
|
|
303
|
+
_rejectAllPending(error) {
|
|
304
|
+
for (const [id, pending] of this._pendingRequests) {
|
|
305
|
+
clearTimeout(pending.timer);
|
|
306
|
+
pending.reject(error);
|
|
307
|
+
}
|
|
308
|
+
this._pendingRequests.clear();
|
|
309
|
+
}
|
|
310
|
+
/**
|
|
311
|
+
* Serialize message for transmission.
|
|
312
|
+
*/
|
|
313
|
+
_serialize(message) {
|
|
314
|
+
return JSON.stringify(message);
|
|
315
|
+
}
|
|
316
|
+
/**
|
|
317
|
+
* Deserialize received message.
|
|
318
|
+
*/
|
|
319
|
+
_deserialize(data) {
|
|
320
|
+
if (typeof data === "string") {
|
|
321
|
+
return JSON.parse(data);
|
|
322
|
+
}
|
|
323
|
+
const decoder = new TextDecoder();
|
|
324
|
+
const text = decoder.decode(data);
|
|
325
|
+
return JSON.parse(text);
|
|
326
|
+
}
|
|
327
|
+
/**
|
|
328
|
+
* Dispose of the transport.
|
|
329
|
+
*/
|
|
330
|
+
async dispose() {
|
|
331
|
+
this._shouldReconnect = false;
|
|
332
|
+
await super.dispose();
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
const createWebSocketTransport = (options) => {
|
|
336
|
+
return new WebSocketTransport(options);
|
|
337
|
+
};
|
|
338
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
339
|
+
0 && (module.exports = {
|
|
340
|
+
WebSocketTransport,
|
|
341
|
+
createWebSocketTransport
|
|
342
|
+
});
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { IFullTextSearch } from '../core/contracts/fts.js';
|
|
2
|
+
/**
|
|
3
|
+
* Postgres full-text search using tsvector columns and GIN indexes.
|
|
4
|
+
*
|
|
5
|
+
* Unlike FTS5 (separate virtual table), Postgres stores the tsvector
|
|
6
|
+
* as a column `_tsv` on the content table itself. The `createIndex()`
|
|
7
|
+
* call adds the column, creates the GIN index, and backfills existing rows.
|
|
8
|
+
*/
|
|
9
|
+
export declare class PostgresFts implements IFullTextSearch {
|
|
10
|
+
/** The content table is stored during createIndex for use by other methods. */
|
|
11
|
+
private _contentTable;
|
|
12
|
+
private _columns;
|
|
13
|
+
private _lang;
|
|
14
|
+
createIndex(config: {
|
|
15
|
+
table: string;
|
|
16
|
+
columns: string[];
|
|
17
|
+
contentTable?: string;
|
|
18
|
+
tokenizer?: string;
|
|
19
|
+
}): string;
|
|
20
|
+
matchClause(_indexName: string, queryPlaceholder: string): string;
|
|
21
|
+
rankExpression(_indexName: string, queryPlaceholder?: string): string;
|
|
22
|
+
rebuildCommand(_indexName: string): string;
|
|
23
|
+
syncInsert(_indexName: string, _rowIdExpr: string, columns: string[]): string;
|
|
24
|
+
sanitizeQuery(input: string): string;
|
|
25
|
+
joinClause(contentTable: string, contentAlias: string, _ftsAlias: string, _indexName: string): string;
|
|
26
|
+
/** Map FTS5-style tokenizer strings to Postgres text search configurations. */
|
|
27
|
+
private _tokenizerToLang;
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=PostgresFts.d.ts.map
|