@syncular/tauri 0.15.42 → 0.15.43
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/index.d.ts +8 -0
- package/dist/index.js +33 -0
- package/package.json +3 -3
- package/src/index.ts +37 -1
package/dist/index.d.ts
CHANGED
|
@@ -84,8 +84,16 @@ export declare class TauriSyncClient {
|
|
|
84
84
|
__dispatchEvent(event: SyncularEvent): void;
|
|
85
85
|
securityLifecycle(): Promise<SecurityLifecycle>;
|
|
86
86
|
beginSecurityPreflight(): Promise<void>;
|
|
87
|
+
/**
|
|
88
|
+
* Complete the security preflight. `headers` optionally carries a fresh
|
|
89
|
+
* FULL transport header set that the native host applies atomically with
|
|
90
|
+
* the activation, before the startup sync it enqueues — so a preflight
|
|
91
|
+
* that outlives the boot token starts its first round with valid
|
|
92
|
+
* credentials (the direct `setHeaders` path stays refused while gated).
|
|
93
|
+
*/
|
|
87
94
|
activateSecurity(options?: {
|
|
88
95
|
readonly encryption?: EncryptionKeyringConfig;
|
|
96
|
+
readonly headers?: Readonly<Record<string, string>>;
|
|
89
97
|
}): Promise<void>;
|
|
90
98
|
onInvalidate(listener: InvalidationListener): () => void;
|
|
91
99
|
onChange(listener: ClientChangeListener): () => void;
|
package/dist/index.js
CHANGED
|
@@ -158,6 +158,7 @@ export class TauriSyncClient {
|
|
|
158
158
|
#closed = false;
|
|
159
159
|
#securityLifecycle;
|
|
160
160
|
#preflightBarrier;
|
|
161
|
+
#diagnosticsEnabled = false;
|
|
161
162
|
/** @internal — use {@link createTauriSyncClient}. */
|
|
162
163
|
constructor(tauri, unlisten, securityLifecycle = 'active') {
|
|
163
164
|
this.#tauri = tauri;
|
|
@@ -277,6 +278,13 @@ export class TauriSyncClient {
|
|
|
277
278
|
});
|
|
278
279
|
return barrier;
|
|
279
280
|
}
|
|
281
|
+
/**
|
|
282
|
+
* Complete the security preflight. `headers` optionally carries a fresh
|
|
283
|
+
* FULL transport header set that the native host applies atomically with
|
|
284
|
+
* the activation, before the startup sync it enqueues — so a preflight
|
|
285
|
+
* that outlives the boot token starts its first round with valid
|
|
286
|
+
* credentials (the direct `setHeaders` path stays refused while gated).
|
|
287
|
+
*/
|
|
280
288
|
async activateSecurity(options = {}) {
|
|
281
289
|
if (this.#securityLifecycle === 'active') {
|
|
282
290
|
throw new TauriSyncError('sync.invalid_request', 'activateSecurity requires the client to be in security preflight');
|
|
@@ -286,6 +294,7 @@ export class TauriSyncClient {
|
|
|
286
294
|
...(options.encryption !== undefined
|
|
287
295
|
? { encryption: encodeEncryption(options.encryption) }
|
|
288
296
|
: {}),
|
|
297
|
+
...(options.headers !== undefined ? { headers: options.headers } : {}),
|
|
289
298
|
});
|
|
290
299
|
this.#securityLifecycle = 'active';
|
|
291
300
|
}
|
|
@@ -299,8 +308,32 @@ export class TauriSyncClient {
|
|
|
299
308
|
}
|
|
300
309
|
onDiagnostics(listener) {
|
|
301
310
|
this.#diagnosticsListeners.add(listener);
|
|
311
|
+
this.#enableDiagnosticsPush();
|
|
302
312
|
return () => this.#diagnosticsListeners.delete(listener);
|
|
303
313
|
}
|
|
314
|
+
/**
|
|
315
|
+
* Host-local push registration: the native core emits pushed diagnostics
|
|
316
|
+
* snapshots only once a consumer is known (a `diagnosticsSnapshot` pull, or
|
|
317
|
+
* this explicit `enableDiagnostics` signal). Fired once, on the first
|
|
318
|
+
* registered listener, fire-and-forget. The invoke deliberately bypasses
|
|
319
|
+
* the bridge's preflight gate — the command is a pure observability
|
|
320
|
+
* registration handled before dispatch, and the native side stays silent
|
|
321
|
+
* until activation anyway. Errors are tolerated: an older native core
|
|
322
|
+
* rejects the unknown command, and the mount-time snapshot pull path keeps
|
|
323
|
+
* `useDiagnostics` working there.
|
|
324
|
+
*/
|
|
325
|
+
#enableDiagnosticsPush() {
|
|
326
|
+
if (this.#diagnosticsEnabled || this.#closed)
|
|
327
|
+
return;
|
|
328
|
+
this.#diagnosticsEnabled = true;
|
|
329
|
+
void this.#tauri
|
|
330
|
+
.invoke(`${PLUGIN}syncular_command`, {
|
|
331
|
+
command: { method: 'enableDiagnostics', params: {} },
|
|
332
|
+
})
|
|
333
|
+
.catch(() => {
|
|
334
|
+
/* fire-and-forget; an error reply is equally ignored above */
|
|
335
|
+
});
|
|
336
|
+
}
|
|
304
337
|
onPresence(listener) {
|
|
305
338
|
this.#presenceListeners.add(listener);
|
|
306
339
|
return () => this.#presenceListeners.delete(listener);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@syncular/tauri",
|
|
3
|
-
"version": "0.15.
|
|
3
|
+
"version": "0.15.43",
|
|
4
4
|
"description": "Tauri integration for the Syncular client",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"author": "Benjamin Kniffler",
|
|
@@ -48,12 +48,12 @@
|
|
|
48
48
|
"test": "bun test"
|
|
49
49
|
},
|
|
50
50
|
"dependencies": {
|
|
51
|
-
"@syncular/client": "0.15.
|
|
51
|
+
"@syncular/client": "0.15.43"
|
|
52
52
|
},
|
|
53
53
|
"peerDependencies": {
|
|
54
54
|
"@tauri-apps/api": ">=2.0.0"
|
|
55
55
|
},
|
|
56
56
|
"devDependencies": {
|
|
57
|
-
"@syncular/react": "0.15.
|
|
57
|
+
"@syncular/react": "0.15.43"
|
|
58
58
|
}
|
|
59
59
|
}
|
package/src/index.ts
CHANGED
|
@@ -265,6 +265,7 @@ export class TauriSyncClient {
|
|
|
265
265
|
#closed = false;
|
|
266
266
|
#securityLifecycle: SecurityLifecycle;
|
|
267
267
|
#preflightBarrier: Promise<void> | undefined;
|
|
268
|
+
#diagnosticsEnabled = false;
|
|
268
269
|
|
|
269
270
|
/** @internal — use {@link createTauriSyncClient}. */
|
|
270
271
|
constructor(
|
|
@@ -408,8 +409,18 @@ export class TauriSyncClient {
|
|
|
408
409
|
return barrier;
|
|
409
410
|
}
|
|
410
411
|
|
|
412
|
+
/**
|
|
413
|
+
* Complete the security preflight. `headers` optionally carries a fresh
|
|
414
|
+
* FULL transport header set that the native host applies atomically with
|
|
415
|
+
* the activation, before the startup sync it enqueues — so a preflight
|
|
416
|
+
* that outlives the boot token starts its first round with valid
|
|
417
|
+
* credentials (the direct `setHeaders` path stays refused while gated).
|
|
418
|
+
*/
|
|
411
419
|
async activateSecurity(
|
|
412
|
-
options: {
|
|
420
|
+
options: {
|
|
421
|
+
readonly encryption?: EncryptionKeyringConfig;
|
|
422
|
+
readonly headers?: Readonly<Record<string, string>>;
|
|
423
|
+
} = {},
|
|
413
424
|
): Promise<void> {
|
|
414
425
|
if (this.#securityLifecycle === 'active') {
|
|
415
426
|
throw new TauriSyncError(
|
|
@@ -422,6 +433,7 @@ export class TauriSyncClient {
|
|
|
422
433
|
...(options.encryption !== undefined
|
|
423
434
|
? { encryption: encodeEncryption(options.encryption) }
|
|
424
435
|
: {}),
|
|
436
|
+
...(options.headers !== undefined ? { headers: options.headers } : {}),
|
|
425
437
|
});
|
|
426
438
|
this.#securityLifecycle = 'active';
|
|
427
439
|
}
|
|
@@ -438,9 +450,33 @@ export class TauriSyncClient {
|
|
|
438
450
|
|
|
439
451
|
onDiagnostics(listener: ClientDiagnosticsListener): () => void {
|
|
440
452
|
this.#diagnosticsListeners.add(listener);
|
|
453
|
+
this.#enableDiagnosticsPush();
|
|
441
454
|
return () => this.#diagnosticsListeners.delete(listener);
|
|
442
455
|
}
|
|
443
456
|
|
|
457
|
+
/**
|
|
458
|
+
* Host-local push registration: the native core emits pushed diagnostics
|
|
459
|
+
* snapshots only once a consumer is known (a `diagnosticsSnapshot` pull, or
|
|
460
|
+
* this explicit `enableDiagnostics` signal). Fired once, on the first
|
|
461
|
+
* registered listener, fire-and-forget. The invoke deliberately bypasses
|
|
462
|
+
* the bridge's preflight gate — the command is a pure observability
|
|
463
|
+
* registration handled before dispatch, and the native side stays silent
|
|
464
|
+
* until activation anyway. Errors are tolerated: an older native core
|
|
465
|
+
* rejects the unknown command, and the mount-time snapshot pull path keeps
|
|
466
|
+
* `useDiagnostics` working there.
|
|
467
|
+
*/
|
|
468
|
+
#enableDiagnosticsPush(): void {
|
|
469
|
+
if (this.#diagnosticsEnabled || this.#closed) return;
|
|
470
|
+
this.#diagnosticsEnabled = true;
|
|
471
|
+
void this.#tauri
|
|
472
|
+
.invoke<CommandReply>(`${PLUGIN}syncular_command`, {
|
|
473
|
+
command: { method: 'enableDiagnostics', params: {} },
|
|
474
|
+
})
|
|
475
|
+
.catch(() => {
|
|
476
|
+
/* fire-and-forget; an error reply is equally ignored above */
|
|
477
|
+
});
|
|
478
|
+
}
|
|
479
|
+
|
|
444
480
|
onPresence(listener: (scopeKey: string) => void): () => void {
|
|
445
481
|
this.#presenceListeners.add(listener);
|
|
446
482
|
return () => this.#presenceListeners.delete(listener);
|