Skip to content

Commit e1e2103

Browse files
committed
feat: enhance state management by introducing a helper function for persisting and updating local state
1 parent 0605c70 commit e1e2103

7 files changed

Lines changed: 46 additions & 43 deletions

File tree

src/plugin/background-sync.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,15 @@ import { getPluginState } from './state-manager.js';
1212
import { isContinuousSyncReady } from './validation.js';
1313
import { getErrorMessage, writePulledData, persistLocalState } from '../shared/index.js';
1414

15+
/** Helper to persist state and update in-memory state */
16+
async function persistAndUpdateState(pathConfig: PathConfig): Promise<void> {
17+
const state = getPluginState();
18+
const newState = await persistLocalState(pathConfig, state.engine);
19+
if (newState) {
20+
state.localState = newState;
21+
}
22+
}
23+
1524
/** Active file watcher instance */
1625
let activeWatcher: FileWatcher | null = null;
1726

@@ -46,7 +55,7 @@ export function startFileWatcher(pathConfig: PathConfig): void {
4655
const { categories } = await loadLocalData(pathConfig, config.sync);
4756
const result = await engine.sync(categories);
4857
if (result.success) {
49-
await persistLocalState(pathConfig);
58+
await persistAndUpdateState(pathConfig);
5059
}
5160
} catch (error) {
5261
log(`WARNING: File watcher sync failed: ${getErrorMessage(error)}`);
@@ -79,7 +88,7 @@ export function startIntervalSync(pathConfig: PathConfig): void {
7988
const result = await engine.sync(categories);
8089
if (result.success) {
8190
await writePulledData(pathConfig, result);
82-
await persistLocalState(pathConfig);
91+
await persistAndUpdateState(pathConfig);
8392
}
8493
logIntervalResult(result);
8594
} catch (error) {

src/plugin/plugin.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,10 @@ function performInitialSync(pathConfig: PathConfig): void {
139139

140140
if (result.success && result.action !== 'error') {
141141
await writePulledData(pathConfig, result);
142-
await persistLocalState(pathConfig);
142+
const newState = await persistLocalState(pathConfig, engine);
143+
if (newState) {
144+
getPluginState().localState = newState;
145+
}
143146
log(`Initial sync complete in ${String(dur)}ms: ${result.message}`);
144147
} else {
145148
log(`Sync completed in ${String(dur)}ms: ${result.message}`);

src/plugin/sync-handler.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,9 +53,14 @@ async function handleSyncSuccess(
5353
client: LogClient,
5454
result: SyncResult
5555
): Promise<void> {
56+
const state = getPluginState();
57+
5658
// Write pulled data and persist state using shared utilities
5759
await writePulledData(pathConfig, result);
58-
await persistLocalState(pathConfig);
60+
const newState = await persistLocalState(pathConfig, state.engine);
61+
if (newState) {
62+
state.localState = newState;
63+
}
5964

6065
await client.app.log({
6166
body: {

src/shared/index.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,12 @@ export { calculateChecksum, uint8ArrayToBase64, base64ToUint8Array } from './enc
88

99
export { getErrorMessage, getErrorStack, toError, isError } from './error-utils.js';
1010

11-
export { writePulledData, persistLocalState, processSyncResult } from './sync-result-handler.js';
11+
export {
12+
writePulledData,
13+
persistLocalState,
14+
processSyncResult,
15+
type StateProvider,
16+
} from './sync-result-handler.js';
1217

1318
export {
1419
AppError,

src/shared/sync-result-handler.ts

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,15 @@
66
*/
77

88
import type { PathConfig } from '../types/paths.js';
9-
import type { SyncResult } from '../types/sync.js';
9+
import type { SyncResult, LocalSyncState } from '../types/sync.js';
1010
import type { CategoryData } from '../sync/operations/types.js';
1111
import { writeLocalData, deleteTombstonedItems, saveLocalState } from '../data/index.js';
1212
import { syncLog } from '../logging/index.js';
13-
import { getPluginState } from '../plugin/state-manager.js';
13+
14+
/** Interface for engine that can provide local state */
15+
export interface StateProvider {
16+
getLocalState(): LocalSyncState | null;
17+
}
1418

1519
/** Actions that should trigger writing pulled data to disk */
1620
const WRITE_ACTIONS = new Set(['pulled', 'merged', 'pushed']);
@@ -43,22 +47,28 @@ export async function writePulledData(pathConfig: PathConfig, result: SyncResult
4347

4448
/**
4549
* Persist engine's local state to disk after successful sync.
46-
* Updates both the state file and the in-memory plugin state.
50+
* Returns the new state for the caller to update their in-memory state.
4751
*/
48-
export async function persistLocalState(pathConfig: PathConfig): Promise<void> {
49-
const state = getPluginState();
50-
const newState = state.engine?.getLocalState();
52+
export async function persistLocalState(
53+
pathConfig: PathConfig,
54+
engine: StateProvider | null | undefined
55+
): Promise<LocalSyncState | null> {
56+
const newState = engine?.getLocalState() ?? null;
5157
if (newState) {
5258
await saveLocalState(pathConfig, newState);
53-
state.localState = newState;
5459
}
60+
return newState;
5561
}
5662

5763
/**
5864
* Process a successful sync result - write data and persist state.
5965
* Combines writePulledData and persistLocalState into a single call.
6066
*/
61-
export async function processSyncResult(pathConfig: PathConfig, result: SyncResult): Promise<void> {
67+
export async function processSyncResult(
68+
pathConfig: PathConfig,
69+
result: SyncResult,
70+
engine: StateProvider | null | undefined
71+
): Promise<LocalSyncState | null> {
6272
await writePulledData(pathConfig, result);
63-
await persistLocalState(pathConfig);
73+
return persistLocalState(pathConfig, engine);
6474
}

src/sync/engine/types.ts

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66

77
import type { SyncConfig, LocalSyncState } from '../../types/index.js';
88
import type { StorageBackend } from '../../storage/index.js';
9-
import type { CryptoOptions } from '../operations/types.js';
109

1110
export interface SyncEngineOptions {
1211
config: SyncConfig;
@@ -19,15 +18,4 @@ export interface SyncEngineOptions {
1918
lockPath?: string;
2019
}
2120

22-
/** Get crypto options from engine options */
23-
export function getCryptoOptions(options: {
24-
passphrase?: string;
25-
oldPassphrase?: string;
26-
}): CryptoOptions {
27-
const result: CryptoOptions = {};
28-
if (options.passphrase) result.passphrase = options.passphrase;
29-
if (options.oldPassphrase) result.oldPassphrase = options.oldPassphrase;
30-
return result;
31-
}
32-
3321
export const MANIFEST_FILENAME = 'manifest.json';

src/sync/tombstone.ts

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -126,23 +126,6 @@ export function detectLocalDeletions(
126126
return deletions;
127127
}
128128

129-
/**
130-
* Remove items from category info that have tombstones.
131-
* This ensures tombstoned items aren't included in the live items.
132-
*/
133-
export function removeItemsWithTombstones(
134-
items: Record<string, unknown>,
135-
tombstones: Record<string, Tombstone>
136-
): Record<string, unknown> {
137-
const result: Record<string, unknown> = {};
138-
for (const [itemId, item] of Object.entries(items)) {
139-
if (!(itemId in tombstones)) {
140-
result[itemId] = item;
141-
}
142-
}
143-
return result;
144-
}
145-
146129
// Re-export TombstonesFile functions for backward compatibility
147130
export {
148131
parseTombstonesFile,

0 commit comments

Comments
 (0)