@tanstack/electron-db-sqlite-persistence 0.1.2
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 +71 -0
- package/dist/cjs/electron-coordinator.cjs +541 -0
- package/dist/cjs/electron-coordinator.cjs.map +1 -0
- package/dist/cjs/electron-coordinator.d.cts +67 -0
- package/dist/cjs/errors.d.cts +33 -0
- package/dist/cjs/index.cjs +14 -0
- package/dist/cjs/index.cjs.map +1 -0
- package/dist/cjs/index.d.cts +8 -0
- package/dist/cjs/main.cjs +213 -0
- package/dist/cjs/main.cjs.map +1 -0
- package/dist/cjs/main.d.cts +12 -0
- package/dist/cjs/protocol.cjs +7 -0
- package/dist/cjs/protocol.cjs.map +1 -0
- package/dist/cjs/protocol.d.cts +104 -0
- package/dist/cjs/renderer.cjs +221 -0
- package/dist/cjs/renderer.cjs.map +1 -0
- package/dist/cjs/renderer.d.cts +13 -0
- package/dist/esm/electron-coordinator.d.ts +67 -0
- package/dist/esm/electron-coordinator.js +541 -0
- package/dist/esm/electron-coordinator.js.map +1 -0
- package/dist/esm/errors.d.ts +33 -0
- package/dist/esm/index.d.ts +8 -0
- package/dist/esm/index.js +11 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/main.d.ts +12 -0
- package/dist/esm/main.js +213 -0
- package/dist/esm/main.js.map +1 -0
- package/dist/esm/protocol.d.ts +104 -0
- package/dist/esm/protocol.js +7 -0
- package/dist/esm/protocol.js.map +1 -0
- package/dist/esm/renderer.d.ts +13 -0
- package/dist/esm/renderer.js +221 -0
- package/dist/esm/renderer.js.map +1 -0
- package/package.json +80 -0
- package/src/electron-coordinator.ts +842 -0
- package/src/errors.ts +110 -0
- package/src/index.ts +17 -0
- package/src/main.ts +315 -0
- package/src/protocol.ts +137 -0
- package/src/renderer.ts +391 -0
package/src/errors.ts
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
ElectronPersistenceMethod,
|
|
3
|
+
ElectronSerializedError,
|
|
4
|
+
} from './protocol'
|
|
5
|
+
|
|
6
|
+
type ElectronPersistenceErrorOptions = {
|
|
7
|
+
code?: string
|
|
8
|
+
cause?: unknown
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export class ElectronPersistenceError extends Error {
|
|
12
|
+
readonly code: string | undefined
|
|
13
|
+
|
|
14
|
+
constructor(message: string, options?: ElectronPersistenceErrorOptions) {
|
|
15
|
+
super(message, { cause: options?.cause })
|
|
16
|
+
this.name = `ElectronPersistenceError`
|
|
17
|
+
this.code = options?.code
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export class UnknownElectronPersistenceCollectionError extends ElectronPersistenceError {
|
|
22
|
+
readonly collectionId: string
|
|
23
|
+
|
|
24
|
+
constructor(collectionId: string) {
|
|
25
|
+
super(
|
|
26
|
+
`Unknown electron persistence collection "${collectionId}". Register the collection adapter in the main process host.`,
|
|
27
|
+
{
|
|
28
|
+
code: `UNKNOWN_COLLECTION`,
|
|
29
|
+
},
|
|
30
|
+
)
|
|
31
|
+
this.name = `UnknownElectronPersistenceCollectionError`
|
|
32
|
+
this.collectionId = collectionId
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export class UnsupportedElectronPersistenceMethodError extends ElectronPersistenceError {
|
|
37
|
+
readonly method: ElectronPersistenceMethod
|
|
38
|
+
readonly collectionId: string
|
|
39
|
+
|
|
40
|
+
constructor(method: ElectronPersistenceMethod, collectionId: string) {
|
|
41
|
+
super(
|
|
42
|
+
`Method "${method}" is not supported by the electron persistence adapter for collection "${collectionId}".`,
|
|
43
|
+
{
|
|
44
|
+
code: `UNSUPPORTED_METHOD`,
|
|
45
|
+
},
|
|
46
|
+
)
|
|
47
|
+
this.name = `UnsupportedElectronPersistenceMethodError`
|
|
48
|
+
this.method = method
|
|
49
|
+
this.collectionId = collectionId
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export class ElectronPersistenceProtocolError extends ElectronPersistenceError {
|
|
54
|
+
constructor(message: string, options?: ElectronPersistenceErrorOptions) {
|
|
55
|
+
super(message, {
|
|
56
|
+
code: options?.code ?? `INVALID_PROTOCOL`,
|
|
57
|
+
cause: options?.cause,
|
|
58
|
+
})
|
|
59
|
+
this.name = `ElectronPersistenceProtocolError`
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export class ElectronPersistenceTimeoutError extends ElectronPersistenceError {
|
|
64
|
+
constructor(message: string) {
|
|
65
|
+
super(message, {
|
|
66
|
+
code: `TIMEOUT`,
|
|
67
|
+
})
|
|
68
|
+
this.name = `ElectronPersistenceTimeoutError`
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export class ElectronPersistenceRpcError extends ElectronPersistenceError {
|
|
73
|
+
readonly method: ElectronPersistenceMethod
|
|
74
|
+
readonly collectionId: string
|
|
75
|
+
readonly requestId: string
|
|
76
|
+
readonly remoteName: string
|
|
77
|
+
|
|
78
|
+
constructor(
|
|
79
|
+
method: ElectronPersistenceMethod,
|
|
80
|
+
collectionId: string,
|
|
81
|
+
requestId: string,
|
|
82
|
+
serializedError: ElectronSerializedError,
|
|
83
|
+
) {
|
|
84
|
+
super(
|
|
85
|
+
`${serializedError.name}: ${serializedError.message} (method=${method}, collection=${collectionId}, request=${requestId})`,
|
|
86
|
+
{
|
|
87
|
+
code: serializedError.code ?? `REMOTE_ERROR`,
|
|
88
|
+
},
|
|
89
|
+
)
|
|
90
|
+
this.name = `ElectronPersistenceRpcError`
|
|
91
|
+
this.method = method
|
|
92
|
+
this.collectionId = collectionId
|
|
93
|
+
this.requestId = requestId
|
|
94
|
+
this.remoteName = serializedError.name
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
static fromSerialized(
|
|
98
|
+
method: ElectronPersistenceMethod,
|
|
99
|
+
collectionId: string,
|
|
100
|
+
requestId: string,
|
|
101
|
+
serializedError: ElectronSerializedError,
|
|
102
|
+
): ElectronPersistenceRpcError {
|
|
103
|
+
return new ElectronPersistenceRpcError(
|
|
104
|
+
method,
|
|
105
|
+
collectionId,
|
|
106
|
+
requestId,
|
|
107
|
+
serializedError,
|
|
108
|
+
)
|
|
109
|
+
}
|
|
110
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export { exposeElectronSQLitePersistence } from './main'
|
|
2
|
+
export type {
|
|
3
|
+
ElectronIpcMainLike,
|
|
4
|
+
ElectronSQLiteMainProcessOptions,
|
|
5
|
+
} from './main'
|
|
6
|
+
export { createElectronSQLitePersistence } from './renderer'
|
|
7
|
+
export type {
|
|
8
|
+
ElectronIpcRendererLike,
|
|
9
|
+
ElectronSQLitePersistenceOptions,
|
|
10
|
+
} from './renderer'
|
|
11
|
+
export { ElectronCollectionCoordinator } from './electron-coordinator'
|
|
12
|
+
export type { ElectronCollectionCoordinatorOptions } from './electron-coordinator'
|
|
13
|
+
export { persistedCollectionOptions } from '@tanstack/db-sqlite-persistence-core'
|
|
14
|
+
export type {
|
|
15
|
+
PersistedCollectionCoordinator,
|
|
16
|
+
PersistedCollectionPersistence,
|
|
17
|
+
} from '@tanstack/db-sqlite-persistence-core'
|
package/src/main.ts
ADDED
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
import { InvalidPersistedCollectionConfigError } from '@tanstack/db-sqlite-persistence-core'
|
|
2
|
+
import {
|
|
3
|
+
DEFAULT_ELECTRON_PERSISTENCE_CHANNEL,
|
|
4
|
+
ELECTRON_PERSISTENCE_PROTOCOL_VERSION,
|
|
5
|
+
} from './protocol'
|
|
6
|
+
import type {
|
|
7
|
+
PersistedCollectionPersistence,
|
|
8
|
+
PersistenceAdapter,
|
|
9
|
+
SQLitePullSinceResult,
|
|
10
|
+
} from '@tanstack/db-sqlite-persistence-core'
|
|
11
|
+
import type {
|
|
12
|
+
ElectronPersistedKey,
|
|
13
|
+
ElectronPersistedRow,
|
|
14
|
+
ElectronPersistenceRequestEnvelope,
|
|
15
|
+
ElectronPersistenceResponseEnvelope,
|
|
16
|
+
ElectronSerializedError,
|
|
17
|
+
} from './protocol'
|
|
18
|
+
|
|
19
|
+
type ElectronMainPersistenceAdapter = PersistenceAdapter<
|
|
20
|
+
ElectronPersistedRow,
|
|
21
|
+
ElectronPersistedKey
|
|
22
|
+
> & {
|
|
23
|
+
loadCollectionMetadata?: (
|
|
24
|
+
collectionId: string,
|
|
25
|
+
) => Promise<Array<{ key: string; value: unknown }>>
|
|
26
|
+
scanRows?: (
|
|
27
|
+
collectionId: string,
|
|
28
|
+
options?: { metadataOnly?: boolean },
|
|
29
|
+
) => Promise<
|
|
30
|
+
Array<{
|
|
31
|
+
key: ElectronPersistedKey
|
|
32
|
+
value: ElectronPersistedRow
|
|
33
|
+
metadata?: unknown
|
|
34
|
+
}>
|
|
35
|
+
>
|
|
36
|
+
pullSince?: (
|
|
37
|
+
collectionId: string,
|
|
38
|
+
fromRowVersion: number,
|
|
39
|
+
) => Promise<SQLitePullSinceResult<ElectronPersistedKey>>
|
|
40
|
+
getStreamPosition?: (collectionId: string) => Promise<{
|
|
41
|
+
latestTerm: number
|
|
42
|
+
latestSeq: number
|
|
43
|
+
latestRowVersion: number
|
|
44
|
+
}>
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function serializeError(error: unknown): ElectronSerializedError {
|
|
48
|
+
const fallbackMessage = `Unknown electron persistence error`
|
|
49
|
+
|
|
50
|
+
if (!(error instanceof Error)) {
|
|
51
|
+
return {
|
|
52
|
+
name: `Error`,
|
|
53
|
+
message: fallbackMessage,
|
|
54
|
+
code: undefined,
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const codedError = error as Error & { code?: unknown }
|
|
59
|
+
return {
|
|
60
|
+
name: error.name || `Error`,
|
|
61
|
+
message: error.message || fallbackMessage,
|
|
62
|
+
stack: error.stack,
|
|
63
|
+
code: typeof codedError.code === `string` ? codedError.code : undefined,
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function createErrorResponse(
|
|
68
|
+
request: ElectronPersistenceRequestEnvelope,
|
|
69
|
+
error: unknown,
|
|
70
|
+
): ElectronPersistenceResponseEnvelope {
|
|
71
|
+
return {
|
|
72
|
+
v: ELECTRON_PERSISTENCE_PROTOCOL_VERSION,
|
|
73
|
+
requestId: request.requestId,
|
|
74
|
+
method: request.method,
|
|
75
|
+
ok: false,
|
|
76
|
+
error: serializeError(error),
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function assertValidRequest(request: ElectronPersistenceRequestEnvelope): void {
|
|
81
|
+
if (request.v !== ELECTRON_PERSISTENCE_PROTOCOL_VERSION) {
|
|
82
|
+
throw new InvalidPersistedCollectionConfigError(
|
|
83
|
+
`Unsupported electron persistence protocol version "${request.v}"`,
|
|
84
|
+
)
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if (
|
|
88
|
+
typeof request.requestId !== `string` ||
|
|
89
|
+
request.requestId.trim().length === 0
|
|
90
|
+
) {
|
|
91
|
+
throw new InvalidPersistedCollectionConfigError(
|
|
92
|
+
`Electron persistence requestId cannot be empty`,
|
|
93
|
+
)
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if (
|
|
97
|
+
typeof request.collectionId !== `string` ||
|
|
98
|
+
request.collectionId.trim().length === 0
|
|
99
|
+
) {
|
|
100
|
+
throw new InvalidPersistedCollectionConfigError(
|
|
101
|
+
`Electron persistence collectionId cannot be empty`,
|
|
102
|
+
)
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
async function executeRequestAgainstAdapter(
|
|
107
|
+
request: ElectronPersistenceRequestEnvelope,
|
|
108
|
+
adapter: ElectronMainPersistenceAdapter,
|
|
109
|
+
): Promise<ElectronPersistenceResponseEnvelope> {
|
|
110
|
+
switch (request.method) {
|
|
111
|
+
case `loadSubset`: {
|
|
112
|
+
const result = await adapter.loadSubset(
|
|
113
|
+
request.collectionId,
|
|
114
|
+
request.payload.options,
|
|
115
|
+
request.payload.ctx,
|
|
116
|
+
)
|
|
117
|
+
return {
|
|
118
|
+
v: ELECTRON_PERSISTENCE_PROTOCOL_VERSION,
|
|
119
|
+
requestId: request.requestId,
|
|
120
|
+
method: request.method,
|
|
121
|
+
ok: true,
|
|
122
|
+
result,
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
case `loadCollectionMetadata`: {
|
|
127
|
+
if (!adapter.loadCollectionMetadata) {
|
|
128
|
+
throw new InvalidPersistedCollectionConfigError(
|
|
129
|
+
`loadCollectionMetadata is not supported by the configured electron persistence adapter`,
|
|
130
|
+
)
|
|
131
|
+
}
|
|
132
|
+
const result = await adapter.loadCollectionMetadata(request.collectionId)
|
|
133
|
+
return {
|
|
134
|
+
v: ELECTRON_PERSISTENCE_PROTOCOL_VERSION,
|
|
135
|
+
requestId: request.requestId,
|
|
136
|
+
method: request.method,
|
|
137
|
+
ok: true,
|
|
138
|
+
result,
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
case `scanRows`: {
|
|
143
|
+
if (!adapter.scanRows) {
|
|
144
|
+
throw new InvalidPersistedCollectionConfigError(
|
|
145
|
+
`scanRows is not supported by the configured electron persistence adapter`,
|
|
146
|
+
)
|
|
147
|
+
}
|
|
148
|
+
const result = await adapter.scanRows(
|
|
149
|
+
request.collectionId,
|
|
150
|
+
request.payload.options,
|
|
151
|
+
)
|
|
152
|
+
return {
|
|
153
|
+
v: ELECTRON_PERSISTENCE_PROTOCOL_VERSION,
|
|
154
|
+
requestId: request.requestId,
|
|
155
|
+
method: request.method,
|
|
156
|
+
ok: true,
|
|
157
|
+
result,
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
case `applyCommittedTx`: {
|
|
162
|
+
await adapter.applyCommittedTx(request.collectionId, request.payload.tx)
|
|
163
|
+
return {
|
|
164
|
+
v: ELECTRON_PERSISTENCE_PROTOCOL_VERSION,
|
|
165
|
+
requestId: request.requestId,
|
|
166
|
+
method: request.method,
|
|
167
|
+
ok: true,
|
|
168
|
+
result: null,
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
case `ensureIndex`: {
|
|
173
|
+
await adapter.ensureIndex(
|
|
174
|
+
request.collectionId,
|
|
175
|
+
request.payload.signature,
|
|
176
|
+
request.payload.spec,
|
|
177
|
+
)
|
|
178
|
+
return {
|
|
179
|
+
v: ELECTRON_PERSISTENCE_PROTOCOL_VERSION,
|
|
180
|
+
requestId: request.requestId,
|
|
181
|
+
method: request.method,
|
|
182
|
+
ok: true,
|
|
183
|
+
result: null,
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
case `markIndexRemoved`: {
|
|
188
|
+
if (!adapter.markIndexRemoved) {
|
|
189
|
+
throw new InvalidPersistedCollectionConfigError(
|
|
190
|
+
`markIndexRemoved is not supported by the configured electron persistence adapter`,
|
|
191
|
+
)
|
|
192
|
+
}
|
|
193
|
+
await adapter.markIndexRemoved(
|
|
194
|
+
request.collectionId,
|
|
195
|
+
request.payload.signature,
|
|
196
|
+
)
|
|
197
|
+
return {
|
|
198
|
+
v: ELECTRON_PERSISTENCE_PROTOCOL_VERSION,
|
|
199
|
+
requestId: request.requestId,
|
|
200
|
+
method: request.method,
|
|
201
|
+
ok: true,
|
|
202
|
+
result: null,
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
case `pullSince`: {
|
|
207
|
+
if (!adapter.pullSince) {
|
|
208
|
+
throw new InvalidPersistedCollectionConfigError(
|
|
209
|
+
`pullSince is not supported by the configured electron persistence adapter`,
|
|
210
|
+
)
|
|
211
|
+
}
|
|
212
|
+
const result = await adapter.pullSince(
|
|
213
|
+
request.collectionId,
|
|
214
|
+
request.payload.fromRowVersion,
|
|
215
|
+
)
|
|
216
|
+
return {
|
|
217
|
+
v: ELECTRON_PERSISTENCE_PROTOCOL_VERSION,
|
|
218
|
+
requestId: request.requestId,
|
|
219
|
+
method: request.method,
|
|
220
|
+
ok: true,
|
|
221
|
+
result,
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
case `getStreamPosition`: {
|
|
226
|
+
if (!adapter.getStreamPosition) {
|
|
227
|
+
throw new InvalidPersistedCollectionConfigError(
|
|
228
|
+
`getStreamPosition is not supported by the configured electron persistence adapter`,
|
|
229
|
+
)
|
|
230
|
+
}
|
|
231
|
+
const position = await adapter.getStreamPosition(request.collectionId)
|
|
232
|
+
return {
|
|
233
|
+
v: ELECTRON_PERSISTENCE_PROTOCOL_VERSION,
|
|
234
|
+
requestId: request.requestId,
|
|
235
|
+
method: request.method,
|
|
236
|
+
ok: true,
|
|
237
|
+
result: position,
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
function resolveModeAwarePersistence(
|
|
244
|
+
persistence: PersistedCollectionPersistence<
|
|
245
|
+
ElectronPersistedRow,
|
|
246
|
+
ElectronPersistedKey
|
|
247
|
+
>,
|
|
248
|
+
request: ElectronPersistenceRequestEnvelope,
|
|
249
|
+
): PersistedCollectionPersistence<ElectronPersistedRow, ElectronPersistedKey> {
|
|
250
|
+
const mode = request.resolution?.mode ?? `sync-absent`
|
|
251
|
+
const schemaVersion = request.resolution?.schemaVersion
|
|
252
|
+
const collectionAwarePersistence =
|
|
253
|
+
persistence.resolvePersistenceForCollection?.({
|
|
254
|
+
collectionId: request.collectionId,
|
|
255
|
+
mode,
|
|
256
|
+
schemaVersion,
|
|
257
|
+
})
|
|
258
|
+
if (collectionAwarePersistence) {
|
|
259
|
+
return collectionAwarePersistence
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
const modeAwarePersistence = persistence.resolvePersistenceForMode?.(mode)
|
|
263
|
+
return modeAwarePersistence ?? persistence
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
export type ElectronIpcMainLike = {
|
|
267
|
+
handle: (
|
|
268
|
+
channel: string,
|
|
269
|
+
listener: (
|
|
270
|
+
event: unknown,
|
|
271
|
+
request: ElectronPersistenceRequestEnvelope,
|
|
272
|
+
) => Promise<ElectronPersistenceResponseEnvelope>,
|
|
273
|
+
) => void
|
|
274
|
+
removeHandler?: (channel: string) => void
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
export type ElectronSQLiteMainProcessOptions = {
|
|
278
|
+
persistence: PersistedCollectionPersistence<
|
|
279
|
+
ElectronPersistedRow,
|
|
280
|
+
ElectronPersistedKey
|
|
281
|
+
>
|
|
282
|
+
ipcMain: ElectronIpcMainLike
|
|
283
|
+
channel?: string
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
export function exposeElectronSQLitePersistence(
|
|
287
|
+
options: ElectronSQLiteMainProcessOptions,
|
|
288
|
+
): () => void {
|
|
289
|
+
const channel = options.channel ?? DEFAULT_ELECTRON_PERSISTENCE_CHANNEL
|
|
290
|
+
options.ipcMain.handle(
|
|
291
|
+
channel,
|
|
292
|
+
async (
|
|
293
|
+
_event,
|
|
294
|
+
request: ElectronPersistenceRequestEnvelope,
|
|
295
|
+
): Promise<ElectronPersistenceResponseEnvelope> => {
|
|
296
|
+
try {
|
|
297
|
+
assertValidRequest(request)
|
|
298
|
+
const modeAwarePersistence = resolveModeAwarePersistence(
|
|
299
|
+
options.persistence,
|
|
300
|
+
request,
|
|
301
|
+
)
|
|
302
|
+
return await executeRequestAgainstAdapter(
|
|
303
|
+
request,
|
|
304
|
+
modeAwarePersistence.adapter,
|
|
305
|
+
)
|
|
306
|
+
} catch (error) {
|
|
307
|
+
return createErrorResponse(request, error)
|
|
308
|
+
}
|
|
309
|
+
},
|
|
310
|
+
)
|
|
311
|
+
|
|
312
|
+
return () => {
|
|
313
|
+
options.ipcMain.removeHandler?.(channel)
|
|
314
|
+
}
|
|
315
|
+
}
|
package/src/protocol.ts
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import type { LoadSubsetOptions } from '@tanstack/db'
|
|
2
|
+
import type {
|
|
3
|
+
PersistedCollectionMode,
|
|
4
|
+
PersistedIndexSpec,
|
|
5
|
+
PersistedTx,
|
|
6
|
+
SQLitePullSinceResult,
|
|
7
|
+
} from '@tanstack/db-sqlite-persistence-core'
|
|
8
|
+
|
|
9
|
+
export const ELECTRON_PERSISTENCE_PROTOCOL_VERSION = 1 as const
|
|
10
|
+
export const DEFAULT_ELECTRON_PERSISTENCE_CHANNEL = `tanstack-db:sqlite-persistence`
|
|
11
|
+
|
|
12
|
+
export type ElectronPersistedRow = Record<string, unknown>
|
|
13
|
+
export type ElectronPersistedKey = string | number
|
|
14
|
+
|
|
15
|
+
export type ElectronPersistenceResolution = {
|
|
16
|
+
mode: PersistedCollectionMode
|
|
17
|
+
schemaVersion?: number
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export type ElectronPersistenceMethod =
|
|
21
|
+
| `loadSubset`
|
|
22
|
+
| `loadCollectionMetadata`
|
|
23
|
+
| `scanRows`
|
|
24
|
+
| `applyCommittedTx`
|
|
25
|
+
| `ensureIndex`
|
|
26
|
+
| `markIndexRemoved`
|
|
27
|
+
| `pullSince`
|
|
28
|
+
| `getStreamPosition`
|
|
29
|
+
|
|
30
|
+
export type ElectronPersistencePayloadMap = {
|
|
31
|
+
loadSubset: {
|
|
32
|
+
options: LoadSubsetOptions
|
|
33
|
+
ctx?: { requiredIndexSignatures?: ReadonlyArray<string> }
|
|
34
|
+
}
|
|
35
|
+
loadCollectionMetadata: {}
|
|
36
|
+
scanRows: {
|
|
37
|
+
options?: {
|
|
38
|
+
metadataOnly?: boolean
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
applyCommittedTx: {
|
|
42
|
+
tx: PersistedTx<ElectronPersistedRow, ElectronPersistedKey>
|
|
43
|
+
}
|
|
44
|
+
ensureIndex: {
|
|
45
|
+
signature: string
|
|
46
|
+
spec: PersistedIndexSpec
|
|
47
|
+
}
|
|
48
|
+
markIndexRemoved: {
|
|
49
|
+
signature: string
|
|
50
|
+
}
|
|
51
|
+
pullSince: {
|
|
52
|
+
fromRowVersion: number
|
|
53
|
+
}
|
|
54
|
+
getStreamPosition: {}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export type ElectronPersistenceResultMap = {
|
|
58
|
+
loadSubset: Array<{ key: ElectronPersistedKey; value: ElectronPersistedRow }>
|
|
59
|
+
loadCollectionMetadata: Array<{ key: string; value: unknown }>
|
|
60
|
+
scanRows: Array<{
|
|
61
|
+
key: ElectronPersistedKey
|
|
62
|
+
value: ElectronPersistedRow
|
|
63
|
+
metadata?: unknown
|
|
64
|
+
}>
|
|
65
|
+
applyCommittedTx: null
|
|
66
|
+
ensureIndex: null
|
|
67
|
+
markIndexRemoved: null
|
|
68
|
+
pullSince: SQLitePullSinceResult<ElectronPersistedKey>
|
|
69
|
+
getStreamPosition: {
|
|
70
|
+
latestTerm: number
|
|
71
|
+
latestSeq: number
|
|
72
|
+
latestRowVersion: number
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export type ElectronSerializedError = {
|
|
77
|
+
name: string
|
|
78
|
+
message: string
|
|
79
|
+
stack?: string
|
|
80
|
+
code?: string
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export type ElectronPersistenceRequestByMethod = {
|
|
84
|
+
[Method in ElectronPersistenceMethod]: {
|
|
85
|
+
v: number
|
|
86
|
+
requestId: string
|
|
87
|
+
collectionId: string
|
|
88
|
+
resolution?: ElectronPersistenceResolution
|
|
89
|
+
method: Method
|
|
90
|
+
payload: ElectronPersistencePayloadMap[Method]
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export type ElectronPersistenceRequest<
|
|
95
|
+
TMethod extends ElectronPersistenceMethod = ElectronPersistenceMethod,
|
|
96
|
+
> = ElectronPersistenceRequestByMethod[TMethod]
|
|
97
|
+
|
|
98
|
+
export type ElectronPersistenceRequestEnvelope =
|
|
99
|
+
ElectronPersistenceRequestByMethod[ElectronPersistenceMethod]
|
|
100
|
+
|
|
101
|
+
type ElectronPersistenceSuccessResponseByMethod = {
|
|
102
|
+
[Method in ElectronPersistenceMethod]: {
|
|
103
|
+
v: number
|
|
104
|
+
requestId: string
|
|
105
|
+
method: Method
|
|
106
|
+
ok: true
|
|
107
|
+
result: ElectronPersistenceResultMap[Method]
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
type ElectronPersistenceErrorResponseByMethod = {
|
|
112
|
+
[Method in ElectronPersistenceMethod]: {
|
|
113
|
+
v: number
|
|
114
|
+
requestId: string
|
|
115
|
+
method: Method
|
|
116
|
+
ok: false
|
|
117
|
+
error: ElectronSerializedError
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
export type ElectronPersistenceResponse<
|
|
122
|
+
TMethod extends ElectronPersistenceMethod = ElectronPersistenceMethod,
|
|
123
|
+
> =
|
|
124
|
+
| ElectronPersistenceSuccessResponseByMethod[TMethod]
|
|
125
|
+
| ElectronPersistenceErrorResponseByMethod[TMethod]
|
|
126
|
+
|
|
127
|
+
export type ElectronPersistenceResponseEnvelope =
|
|
128
|
+
ElectronPersistenceResponse<ElectronPersistenceMethod>
|
|
129
|
+
|
|
130
|
+
export type ElectronPersistenceRequestHandler = (
|
|
131
|
+
request: ElectronPersistenceRequestEnvelope,
|
|
132
|
+
) => Promise<ElectronPersistenceResponseEnvelope>
|
|
133
|
+
|
|
134
|
+
export type ElectronPersistenceInvoke = (
|
|
135
|
+
channel: string,
|
|
136
|
+
request: ElectronPersistenceRequestEnvelope,
|
|
137
|
+
) => Promise<ElectronPersistenceResponseEnvelope>
|