@syncular/client 0.15.8 → 0.15.10
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/dist/encryption.d.ts +19 -2
- package/dist/encryption.js +34 -2
- package/dist/schema.js +0 -3
- package/dist/worker-entry.js +4 -0
- package/dist/worker-host.d.ts +3 -0
- package/dist/worker-host.js +3 -0
- package/dist/worker-protocol.d.ts +3 -0
- package/package.json +3 -3
- package/src/encryption.ts +74 -4
- package/src/schema.ts +0 -5
- package/src/worker-entry.ts +4 -0
- package/src/worker-host.ts +6 -0
- package/src/worker-protocol.ts +3 -0
package/dist/encryption.d.ts
CHANGED
|
@@ -20,14 +20,31 @@ import type { CompiledClientTable } from './schema.js';
|
|
|
20
20
|
export interface EncryptionConfig {
|
|
21
21
|
/** `keyId → 32-byte key`, or `undefined` if unknown (decrypt fails loud). */
|
|
22
22
|
readonly keyProvider: (keyId: string) => Uint8Array | undefined;
|
|
23
|
-
/**
|
|
24
|
-
|
|
23
|
+
/**
|
|
24
|
+
* Choose the key-id for an encrypt. The plaintext positional row is supplied
|
|
25
|
+
* so direct clients can select a Facility/workspace/key-grant key without
|
|
26
|
+
* deriving privacy-sensitive state from an opaque row id. Default: the
|
|
27
|
+
* configured `keyIdColumns[table]`, then the table name.
|
|
28
|
+
*/
|
|
29
|
+
readonly keyIdFor?: (table: string, rowId: string, values: readonly RowValue[]) => string;
|
|
30
|
+
/**
|
|
31
|
+
* Portable declarative selector used by Worker/Tauri hosts. Each value names
|
|
32
|
+
* a non-encrypted string column whose row value is the active key id.
|
|
33
|
+
*/
|
|
34
|
+
readonly keyIdColumns?: Readonly<Record<string, string>>;
|
|
25
35
|
/**
|
|
26
36
|
* Nonce source (§5.11). Production omits this (secure RNG). ONLY the crypto
|
|
27
37
|
* golden-vector generator injects a fixed nonce — never a production path.
|
|
28
38
|
*/
|
|
29
39
|
readonly nonceSource?: NonceSource;
|
|
30
40
|
}
|
|
41
|
+
/** Structured-clone/JSON-safe keyring accepted by Worker and Tauri hosts. */
|
|
42
|
+
export interface EncryptionKeyringConfig {
|
|
43
|
+
readonly keys: Readonly<Record<string, Uint8Array>>;
|
|
44
|
+
readonly keyIdColumns?: Readonly<Record<string, string>>;
|
|
45
|
+
}
|
|
46
|
+
/** Convert a portable keyring into the direct-client encryption contract. */
|
|
47
|
+
export declare function encryptionConfigFromKeyring(keyring: EncryptionKeyringConfig): EncryptionConfig;
|
|
31
48
|
/**
|
|
32
49
|
* Encrypt the encrypted columns of a positional row value array in place-safe
|
|
33
50
|
* fashion (returns a new array). Called at the outbox encode-at-send seam
|
package/dist/encryption.js
CHANGED
|
@@ -9,6 +9,39 @@
|
|
|
9
9
|
* envelope primitives.
|
|
10
10
|
*/
|
|
11
11
|
import { DecryptError, decryptValue, encryptValue, } from '@syncular/core';
|
|
12
|
+
/** Convert a portable keyring into the direct-client encryption contract. */
|
|
13
|
+
export function encryptionConfigFromKeyring(keyring) {
|
|
14
|
+
return {
|
|
15
|
+
keyProvider: (keyId) => keyring.keys[keyId],
|
|
16
|
+
...(keyring.keyIdColumns !== undefined
|
|
17
|
+
? { keyIdColumns: keyring.keyIdColumns }
|
|
18
|
+
: {}),
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
function encryptionKeyId(config, table, rowId, values) {
|
|
22
|
+
if (config.keyIdFor !== undefined) {
|
|
23
|
+
const selected = config.keyIdFor(table.name, rowId, values);
|
|
24
|
+
if (selected.length === 0) {
|
|
25
|
+
throw new DecryptError(`empty encryption key id selected for table ${JSON.stringify(table.name)}`);
|
|
26
|
+
}
|
|
27
|
+
return selected;
|
|
28
|
+
}
|
|
29
|
+
const selectorColumn = config.keyIdColumns?.[table.name];
|
|
30
|
+
if (selectorColumn === undefined)
|
|
31
|
+
return table.name;
|
|
32
|
+
const index = table.columns.findIndex((column) => column.name === selectorColumn);
|
|
33
|
+
if (index < 0) {
|
|
34
|
+
throw new DecryptError(`encryption key-id column ${JSON.stringify(selectorColumn)} is not present on table ${JSON.stringify(table.name)}`);
|
|
35
|
+
}
|
|
36
|
+
if (table.columns[index]?.encrypted === true) {
|
|
37
|
+
throw new DecryptError(`encryption key-id column ${JSON.stringify(selectorColumn)} on table ${JSON.stringify(table.name)} must not be encrypted`);
|
|
38
|
+
}
|
|
39
|
+
const selected = values[index];
|
|
40
|
+
if (typeof selected !== 'string' || selected.length === 0) {
|
|
41
|
+
throw new DecryptError(`encryption key-id column ${JSON.stringify(selectorColumn)} on table ${JSON.stringify(table.name)} must contain a non-empty string`);
|
|
42
|
+
}
|
|
43
|
+
return selected;
|
|
44
|
+
}
|
|
12
45
|
function declaredTypeOf(column) {
|
|
13
46
|
// An encrypted column always carries declaredType (typegen guarantees it;
|
|
14
47
|
// §5.11). Fall back to the wire type defensively.
|
|
@@ -24,8 +57,8 @@ function declaredTypeOf(column) {
|
|
|
24
57
|
export async function encryptRowValues(config, table, rowId, values) {
|
|
25
58
|
if (!table.hasEncryptedColumns)
|
|
26
59
|
return values.slice();
|
|
27
|
-
const keyIdFor = config.keyIdFor ?? ((t) => t);
|
|
28
60
|
const out = values.slice();
|
|
61
|
+
const keyId = encryptionKeyId(config, table, rowId, values);
|
|
29
62
|
for (let i = 0; i < table.columns.length; i++) {
|
|
30
63
|
const column = table.columns[i];
|
|
31
64
|
if (column === undefined || !column.encrypted)
|
|
@@ -33,7 +66,6 @@ export async function encryptRowValues(config, table, rowId, values) {
|
|
|
33
66
|
const value = out[i];
|
|
34
67
|
if (value === null || value === undefined)
|
|
35
68
|
continue; // NULL stays NULL
|
|
36
|
-
const keyId = keyIdFor(table.name, rowId);
|
|
37
69
|
const key = config.keyProvider(keyId);
|
|
38
70
|
if (key === undefined) {
|
|
39
71
|
throw new DecryptError(`no encryption key for keyId ${JSON.stringify(keyId)} (table ${table.name})`);
|
package/dist/schema.js
CHANGED
|
@@ -104,9 +104,6 @@ export function compileClientSchema(schema) {
|
|
|
104
104
|
if (localColumnType(column) !== 'string') {
|
|
105
105
|
throw new Error(`table ${table.name}: FTS projection ${JSON.stringify(index.name)} column ${JSON.stringify(columnName)} must have string type`);
|
|
106
106
|
}
|
|
107
|
-
if (column.encrypted === true) {
|
|
108
|
-
throw new Error(`table ${table.name}: FTS projection ${JSON.stringify(index.name)} cannot index encrypted column ${JSON.stringify(columnName)}`);
|
|
109
|
-
}
|
|
110
107
|
}
|
|
111
108
|
if (!ALLOWED_FTS_TOKENIZERS.has(index.tokenize)) {
|
|
112
109
|
throw new Error(`table ${table.name}: FTS projection ${JSON.stringify(index.name)} tokenizer ${JSON.stringify(index.tokenize)} is not allowlisted`);
|
package/dist/worker-entry.js
CHANGED
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
* the core owns exactly one loop.
|
|
15
15
|
*/
|
|
16
16
|
import { SyncClient } from './client.js';
|
|
17
|
+
import { encryptionConfigFromKeyring } from './encryption.js';
|
|
17
18
|
import { ClientSyncError } from './errors.js';
|
|
18
19
|
import { httpBlobTransport, httpSegmentDownloader, httpSyncTransport, webSocketRealtimeConnector, } from './http.js';
|
|
19
20
|
import { openPersistentWasmDatabase } from './wasm-database.js';
|
|
@@ -216,6 +217,9 @@ export function startSyncWorker(overrides = {}) {
|
|
|
216
217
|
},
|
|
217
218
|
...(config.clientId !== undefined ? { clientId: config.clientId } : {}),
|
|
218
219
|
...(config.limits !== undefined ? { limits: config.limits } : {}),
|
|
220
|
+
...(config.encryption !== undefined
|
|
221
|
+
? { encryption: encryptionConfigFromKeyring(config.encryption) }
|
|
222
|
+
: {}),
|
|
219
223
|
onSyncNeeded: (reason) => {
|
|
220
224
|
post({ t: 'event', event: { kind: 'sync-needed', reason } });
|
|
221
225
|
consumeSyncIntent({ kind: 'interactive' });
|
package/dist/worker-host.d.ts
CHANGED
|
@@ -25,6 +25,7 @@ import type { WakeReason } from '@syncular/core';
|
|
|
25
25
|
import type { BlobRef, CachedBlob } from './blob.js';
|
|
26
26
|
import type { ConflictRecord, LeaseState, MutationInput, PresencePeer, QueryReadSpec, QuerySnapshot, RejectionRecord, SchemaFloor, SubscribeInput, SyncClientLimits, SyncSummary, WindowState } from './client.js';
|
|
27
27
|
import type { SqlRow, SqlValue } from './database.js';
|
|
28
|
+
import type { EncryptionKeyringConfig } from './encryption.js';
|
|
28
29
|
import { ChangeEmitter, type ClientChangeListener, InvalidationEmitter, type InvalidationListener, type LocalRevision, type SyncStatusSnapshot } from './invalidation.js';
|
|
29
30
|
import { type LeaderLease, type LeaderLock } from './leader-lock.js';
|
|
30
31
|
import { type CrossTabChannel, FollowerLink, LeaderBridge } from './multi-tab.js';
|
|
@@ -46,6 +47,8 @@ export interface SyncClientHandleConfig {
|
|
|
46
47
|
readonly schema: ClientSchema;
|
|
47
48
|
readonly database: WorkerDatabaseInit;
|
|
48
49
|
readonly endpoints: WorkerEndpoints;
|
|
50
|
+
/** Structured-clone-safe E2EE keyring installed only in the leader worker. */
|
|
51
|
+
readonly encryption?: EncryptionKeyringConfig;
|
|
49
52
|
readonly clientId?: string;
|
|
50
53
|
readonly limits?: SyncClientLimits;
|
|
51
54
|
/** Worker-side host loop (§8.4); default true. */
|
package/dist/worker-host.js
CHANGED
|
@@ -367,6 +367,9 @@ function buildInitConfig(config) {
|
|
|
367
367
|
schema: config.schema,
|
|
368
368
|
database: config.database,
|
|
369
369
|
endpoints: config.endpoints,
|
|
370
|
+
...(config.encryption !== undefined
|
|
371
|
+
? { encryption: config.encryption }
|
|
372
|
+
: {}),
|
|
370
373
|
...(config.clientId !== undefined ? { clientId: config.clientId } : {}),
|
|
371
374
|
...(config.limits !== undefined ? { limits: config.limits } : {}),
|
|
372
375
|
...(config.autoSync !== undefined ? { autoSync: config.autoSync } : {}),
|
|
@@ -20,6 +20,7 @@ import type { WakeReason } from '@syncular/core';
|
|
|
20
20
|
import type { BlobRef, CachedBlob } from './blob.js';
|
|
21
21
|
import type { ConflictRecord, LeaseState, MutationInput, PresencePeer, QueryReadSpec, QuerySnapshot, RejectionRecord, SchemaFloor, SubscribeInput, SyncClientLimits, SyncSummary, WindowState } from './client.js';
|
|
22
22
|
import type { SqlRow, SqlValue } from './database.js';
|
|
23
|
+
import type { EncryptionKeyringConfig } from './encryption.js';
|
|
23
24
|
import type { ClientChangeBatch, LocalRevision, SyncStatusSnapshot } from './invalidation.js';
|
|
24
25
|
import type { OutboxCommit } from './outbox.js';
|
|
25
26
|
import type { CommitOutcome, CommitOutcomeQuery, ResolveCommitOutcomeInput } from './outcomes.js';
|
|
@@ -61,6 +62,8 @@ export interface WorkerInitConfig {
|
|
|
61
62
|
readonly schema: ClientSchema;
|
|
62
63
|
readonly database: WorkerDatabaseInit;
|
|
63
64
|
readonly endpoints: WorkerEndpoints;
|
|
65
|
+
/** Portable raw keyring installed inside the worker-owned client core. */
|
|
66
|
+
readonly encryption?: EncryptionKeyringConfig;
|
|
64
67
|
readonly clientId?: string;
|
|
65
68
|
readonly limits?: SyncClientLimits;
|
|
66
69
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@syncular/client",
|
|
3
|
-
"version": "0.15.
|
|
3
|
+
"version": "0.15.10",
|
|
4
4
|
"description": "Syncular TypeScript client core — offline-first sync over SQLite (WASM/OPFS, Bun, Node)",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"author": "Benjamin Kniffler",
|
|
@@ -81,7 +81,7 @@
|
|
|
81
81
|
},
|
|
82
82
|
"dependencies": {
|
|
83
83
|
"@sqlite.org/sqlite-wasm": "^3.53.0-build1",
|
|
84
|
-
"@syncular/core": "0.15.
|
|
84
|
+
"@syncular/core": "0.15.10"
|
|
85
85
|
},
|
|
86
86
|
"peerDependencies": {
|
|
87
87
|
"better-sqlite3": ">=11"
|
|
@@ -92,7 +92,7 @@
|
|
|
92
92
|
}
|
|
93
93
|
},
|
|
94
94
|
"devDependencies": {
|
|
95
|
-
"@syncular/server": "0.15.
|
|
95
|
+
"@syncular/server": "0.15.10",
|
|
96
96
|
"@types/better-sqlite3": "^7.6.13",
|
|
97
97
|
"better-sqlite3": "^12.11.1"
|
|
98
98
|
}
|
package/src/encryption.ts
CHANGED
|
@@ -30,8 +30,22 @@ import type { CompiledClientTable } from './schema';
|
|
|
30
30
|
export interface EncryptionConfig {
|
|
31
31
|
/** `keyId → 32-byte key`, or `undefined` if unknown (decrypt fails loud). */
|
|
32
32
|
readonly keyProvider: (keyId: string) => Uint8Array | undefined;
|
|
33
|
-
/**
|
|
34
|
-
|
|
33
|
+
/**
|
|
34
|
+
* Choose the key-id for an encrypt. The plaintext positional row is supplied
|
|
35
|
+
* so direct clients can select a Facility/workspace/key-grant key without
|
|
36
|
+
* deriving privacy-sensitive state from an opaque row id. Default: the
|
|
37
|
+
* configured `keyIdColumns[table]`, then the table name.
|
|
38
|
+
*/
|
|
39
|
+
readonly keyIdFor?: (
|
|
40
|
+
table: string,
|
|
41
|
+
rowId: string,
|
|
42
|
+
values: readonly RowValue[],
|
|
43
|
+
) => string;
|
|
44
|
+
/**
|
|
45
|
+
* Portable declarative selector used by Worker/Tauri hosts. Each value names
|
|
46
|
+
* a non-encrypted string column whose row value is the active key id.
|
|
47
|
+
*/
|
|
48
|
+
readonly keyIdColumns?: Readonly<Record<string, string>>;
|
|
35
49
|
/**
|
|
36
50
|
* Nonce source (§5.11). Production omits this (secure RNG). ONLY the crypto
|
|
37
51
|
* golden-vector generator injects a fixed nonce — never a production path.
|
|
@@ -39,6 +53,63 @@ export interface EncryptionConfig {
|
|
|
39
53
|
readonly nonceSource?: NonceSource;
|
|
40
54
|
}
|
|
41
55
|
|
|
56
|
+
/** Structured-clone/JSON-safe keyring accepted by Worker and Tauri hosts. */
|
|
57
|
+
export interface EncryptionKeyringConfig {
|
|
58
|
+
readonly keys: Readonly<Record<string, Uint8Array>>;
|
|
59
|
+
readonly keyIdColumns?: Readonly<Record<string, string>>;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/** Convert a portable keyring into the direct-client encryption contract. */
|
|
63
|
+
export function encryptionConfigFromKeyring(
|
|
64
|
+
keyring: EncryptionKeyringConfig,
|
|
65
|
+
): EncryptionConfig {
|
|
66
|
+
return {
|
|
67
|
+
keyProvider: (keyId) => keyring.keys[keyId],
|
|
68
|
+
...(keyring.keyIdColumns !== undefined
|
|
69
|
+
? { keyIdColumns: keyring.keyIdColumns }
|
|
70
|
+
: {}),
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function encryptionKeyId(
|
|
75
|
+
config: EncryptionConfig,
|
|
76
|
+
table: CompiledClientTable,
|
|
77
|
+
rowId: string,
|
|
78
|
+
values: readonly RowValue[],
|
|
79
|
+
): string {
|
|
80
|
+
if (config.keyIdFor !== undefined) {
|
|
81
|
+
const selected = config.keyIdFor(table.name, rowId, values);
|
|
82
|
+
if (selected.length === 0) {
|
|
83
|
+
throw new DecryptError(
|
|
84
|
+
`empty encryption key id selected for table ${JSON.stringify(table.name)}`,
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
return selected;
|
|
88
|
+
}
|
|
89
|
+
const selectorColumn = config.keyIdColumns?.[table.name];
|
|
90
|
+
if (selectorColumn === undefined) return table.name;
|
|
91
|
+
const index = table.columns.findIndex(
|
|
92
|
+
(column) => column.name === selectorColumn,
|
|
93
|
+
);
|
|
94
|
+
if (index < 0) {
|
|
95
|
+
throw new DecryptError(
|
|
96
|
+
`encryption key-id column ${JSON.stringify(selectorColumn)} is not present on table ${JSON.stringify(table.name)}`,
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
if (table.columns[index]?.encrypted === true) {
|
|
100
|
+
throw new DecryptError(
|
|
101
|
+
`encryption key-id column ${JSON.stringify(selectorColumn)} on table ${JSON.stringify(table.name)} must not be encrypted`,
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
const selected = values[index];
|
|
105
|
+
if (typeof selected !== 'string' || selected.length === 0) {
|
|
106
|
+
throw new DecryptError(
|
|
107
|
+
`encryption key-id column ${JSON.stringify(selectorColumn)} on table ${JSON.stringify(table.name)} must contain a non-empty string`,
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
return selected;
|
|
111
|
+
}
|
|
112
|
+
|
|
42
113
|
function declaredTypeOf(column: RowColumn): DeclaredType {
|
|
43
114
|
// An encrypted column always carries declaredType (typegen guarantees it;
|
|
44
115
|
// §5.11). Fall back to the wire type defensively.
|
|
@@ -59,14 +130,13 @@ export async function encryptRowValues(
|
|
|
59
130
|
values: readonly RowValue[],
|
|
60
131
|
): Promise<RowValue[]> {
|
|
61
132
|
if (!table.hasEncryptedColumns) return values.slice();
|
|
62
|
-
const keyIdFor = config.keyIdFor ?? ((t: string) => t);
|
|
63
133
|
const out = values.slice();
|
|
134
|
+
const keyId = encryptionKeyId(config, table, rowId, values);
|
|
64
135
|
for (let i = 0; i < table.columns.length; i++) {
|
|
65
136
|
const column = table.columns[i];
|
|
66
137
|
if (column === undefined || !column.encrypted) continue;
|
|
67
138
|
const value = out[i];
|
|
68
139
|
if (value === null || value === undefined) continue; // NULL stays NULL
|
|
69
|
-
const keyId = keyIdFor(table.name, rowId);
|
|
70
140
|
const key = config.keyProvider(keyId);
|
|
71
141
|
if (key === undefined) {
|
|
72
142
|
throw new DecryptError(
|
package/src/schema.ts
CHANGED
|
@@ -216,11 +216,6 @@ export function compileClientSchema(
|
|
|
216
216
|
`table ${table.name}: FTS projection ${JSON.stringify(index.name)} column ${JSON.stringify(columnName)} must have string type`,
|
|
217
217
|
);
|
|
218
218
|
}
|
|
219
|
-
if (column.encrypted === true) {
|
|
220
|
-
throw new Error(
|
|
221
|
-
`table ${table.name}: FTS projection ${JSON.stringify(index.name)} cannot index encrypted column ${JSON.stringify(columnName)}`,
|
|
222
|
-
);
|
|
223
|
-
}
|
|
224
219
|
}
|
|
225
220
|
if (!ALLOWED_FTS_TOKENIZERS.has(index.tokenize)) {
|
|
226
221
|
throw new Error(
|
package/src/worker-entry.ts
CHANGED
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
*/
|
|
16
16
|
import { SyncClient } from './client';
|
|
17
17
|
import type { ClientDatabase } from './database';
|
|
18
|
+
import { encryptionConfigFromKeyring } from './encryption';
|
|
18
19
|
import { ClientSyncError } from './errors';
|
|
19
20
|
import {
|
|
20
21
|
httpBlobTransport,
|
|
@@ -299,6 +300,9 @@ export function startSyncWorker(overrides: SyncWorkerOverrides = {}): void {
|
|
|
299
300
|
},
|
|
300
301
|
...(config.clientId !== undefined ? { clientId: config.clientId } : {}),
|
|
301
302
|
...(config.limits !== undefined ? { limits: config.limits } : {}),
|
|
303
|
+
...(config.encryption !== undefined
|
|
304
|
+
? { encryption: encryptionConfigFromKeyring(config.encryption) }
|
|
305
|
+
: {}),
|
|
302
306
|
onSyncNeeded: (reason) => {
|
|
303
307
|
post({ t: 'event', event: { kind: 'sync-needed', reason } });
|
|
304
308
|
consumeSyncIntent({ kind: 'interactive' });
|
package/src/worker-host.ts
CHANGED
|
@@ -39,6 +39,7 @@ import type {
|
|
|
39
39
|
} from './client';
|
|
40
40
|
import type { SqlRow, SqlValue } from './database';
|
|
41
41
|
import { registerDevtools } from './devtools';
|
|
42
|
+
import type { EncryptionKeyringConfig } from './encryption';
|
|
42
43
|
import { ClientSyncError } from './errors';
|
|
43
44
|
import {
|
|
44
45
|
ChangeEmitter,
|
|
@@ -100,6 +101,8 @@ export interface SyncClientHandleConfig {
|
|
|
100
101
|
readonly schema: ClientSchema;
|
|
101
102
|
readonly database: WorkerDatabaseInit;
|
|
102
103
|
readonly endpoints: WorkerEndpoints;
|
|
104
|
+
/** Structured-clone-safe E2EE keyring installed only in the leader worker. */
|
|
105
|
+
readonly encryption?: EncryptionKeyringConfig;
|
|
103
106
|
readonly clientId?: string;
|
|
104
107
|
readonly limits?: SyncClientLimits;
|
|
105
108
|
/** Worker-side host loop (§8.4); default true. */
|
|
@@ -624,6 +627,9 @@ function buildInitConfig(config: SyncClientHandleConfig): WorkerInitConfig {
|
|
|
624
627
|
schema: config.schema,
|
|
625
628
|
database: config.database,
|
|
626
629
|
endpoints: config.endpoints,
|
|
630
|
+
...(config.encryption !== undefined
|
|
631
|
+
? { encryption: config.encryption }
|
|
632
|
+
: {}),
|
|
627
633
|
...(config.clientId !== undefined ? { clientId: config.clientId } : {}),
|
|
628
634
|
...(config.limits !== undefined ? { limits: config.limits } : {}),
|
|
629
635
|
...(config.autoSync !== undefined ? { autoSync: config.autoSync } : {}),
|
package/src/worker-protocol.ts
CHANGED
|
@@ -33,6 +33,7 @@ import type {
|
|
|
33
33
|
WindowState,
|
|
34
34
|
} from './client';
|
|
35
35
|
import type { SqlRow, SqlValue } from './database';
|
|
36
|
+
import type { EncryptionKeyringConfig } from './encryption';
|
|
36
37
|
import type {
|
|
37
38
|
ClientChangeBatch,
|
|
38
39
|
LocalRevision,
|
|
@@ -96,6 +97,8 @@ export interface WorkerInitConfig {
|
|
|
96
97
|
readonly schema: ClientSchema;
|
|
97
98
|
readonly database: WorkerDatabaseInit;
|
|
98
99
|
readonly endpoints: WorkerEndpoints;
|
|
100
|
+
/** Portable raw keyring installed inside the worker-owned client core. */
|
|
101
|
+
readonly encryption?: EncryptionKeyringConfig;
|
|
99
102
|
readonly clientId?: string;
|
|
100
103
|
readonly limits?: SyncClientLimits;
|
|
101
104
|
/**
|