@mrbelloc/encrypted-store 0.2.3 → 0.3.0

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.
Files changed (2) hide show
  1. package/README.md +81 -1
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -41,6 +41,12 @@ const store = new EncryptedStore(db, "my-password", {
41
41
  console.log(`Deleted ${table}:`, docs);
42
42
  });
43
43
  },
44
+ decryptionError: (events) => {
45
+ events.forEach(({ docId, error, doc }) => {
46
+ console.error(`Failed to decrypt ${docId}:`, error.message);
47
+ console.log("Raw encrypted document:", doc);
48
+ });
49
+ },
44
50
  });
45
51
 
46
52
  // Load existing data
@@ -64,16 +70,23 @@ Creates an encrypted store.
64
70
 
65
71
  - `db`: Fireproof database instance
66
72
  - `password`: Encryption password (string)
67
- - `listener`: Object with three callbacks:
73
+ - `listener`: Object with callbacks:
68
74
  - `docsAdded(events: TableEvent[])`: Fired when new documents are added
69
75
  - `docsChanged(events: TableEvent[])`: Fired when documents are updated
70
76
  - `docsDeleted(events: TableEvent[])`: Fired when documents are deleted
77
+ - `decryptionError?(events: DecryptionErrorEvent[])`: Optional. Fired when documents fail to decrypt
71
78
 
72
79
  Each `TableEvent` has:
73
80
 
74
81
  - `table`: Document type (e.g., "users", "transactions")
75
82
  - `docs`: Array of documents with that type
76
83
 
84
+ Each `DecryptionErrorEvent` has:
85
+
86
+ - `docId`: Full document ID that failed to decrypt (e.g., "users_alice")
87
+ - `error`: Error object with details about why decryption failed
88
+ - `doc`: The raw encrypted document from Fireproof (includes `_id` and `d` fields)
89
+
77
90
  ### `await store.loadAll()`
78
91
 
79
92
  Loads all existing documents and sets up change detection. Call this once after creating the store.
@@ -123,6 +136,58 @@ store.disconnectRemote();
123
136
 
124
137
  **Note:** Remote servers only see encrypted blobs - they cannot read your data.
125
138
 
139
+ ### Testing Remote Sync
140
+
141
+ To test that remote sync is working:
142
+
143
+ 1. **Connect to a remote server** using one of the Fireproof connectors (PartyKit, Netlify, etc.)
144
+ 2. **Monitor decryption errors** - If data arrives from another client encrypted with a different password or corrupted, you'll receive `decryptionError` events
145
+ 3. **Use the decryptionError callback** to verify connectivity and detect synchronization issues
146
+
147
+ ```typescript
148
+ const store = new EncryptedStore(db, "my-password", {
149
+ docsAdded: (events) => {
150
+ console.log("✓ Received new documents from remote");
151
+ },
152
+ docsChanged: (events) => {
153
+ console.log("✓ Received document updates from remote");
154
+ },
155
+ docsDeleted: (events) => {
156
+ console.log("✓ Received document deletions from remote");
157
+ },
158
+ decryptionError: (events) => {
159
+ // This fires when remote data can't be decrypted
160
+ // Useful for detecting sync issues or password mismatches
161
+ events.forEach(({ docId, error, doc }) => {
162
+ console.warn(`⚠ Failed to decrypt ${docId}:`, error.message);
163
+ console.log("Raw encrypted document available for debugging:", doc);
164
+ });
165
+ },
166
+ });
167
+
168
+ await store.connectRemote(connect, {
169
+ namespace: "my-app",
170
+ host: "http://localhost:1999",
171
+ });
172
+ ```
173
+
174
+ **Important:** Unlike traditional databases like CouchDB/PouchDB, Fireproof connectors don't provide connection status events. The subscription mechanism handles both local and remote changes automatically. Monitor the event callbacks to verify sync is working.
175
+
176
+ ## Decryption Error Handling
177
+
178
+ The store automatically handles documents that fail to decrypt:
179
+
180
+ - **Wrong password**: Documents encrypted with a different password will trigger `decryptionError` events
181
+ - **Corrupted data**: Malformed or corrupted encrypted data is caught and reported
182
+ - **Graceful degradation**: Successfully decrypted documents are still processed; failures don't stop the store
183
+ - **Remote sync issues**: Detect when remote clients are using different passwords or sending corrupted data
184
+
185
+ This is especially useful when:
186
+ - Testing remote sync connectivity
187
+ - Debugging encryption/decryption issues
188
+ - Detecting data corruption
189
+ - Monitoring multi-client scenarios with different encryption keys
190
+
126
191
  ## How It Works
127
192
 
128
193
  1. **Encryption**: Documents are encrypted with AES-256-GCM before storage
@@ -130,6 +195,7 @@ store.disconnectRemote();
130
195
  3. **Change Detection**: Fireproof's subscribe notifies us of changes
131
196
  4. **Diff Computation**: We track IDs and decrypt only changed documents
132
197
  5. **Events**: Your app gets organized events by table (added/changed/deleted)
198
+ 6. **Error Handling**: Failed decryptions are reported via optional callback
133
199
 
134
200
  ## Example: React Integration
135
201
 
@@ -177,6 +243,13 @@ function useEncryptedStore(dbName: string, password: string) {
177
243
  }
178
244
  });
179
245
  },
246
+ decryptionError: (events) => {
247
+ // Handle decryption errors (optional)
248
+ events.forEach(({ docId, error, doc }) => {
249
+ console.error(`Failed to decrypt ${docId}:`, error.message);
250
+ // Raw encrypted document is available in doc.d if needed
251
+ });
252
+ },
180
253
  });
181
254
 
182
255
  encryptedStore.loadAll();
@@ -195,10 +268,17 @@ interface TableEvent {
195
268
  docs: Doc[];
196
269
  }
197
270
 
271
+ interface DecryptionErrorEvent {
272
+ docId: string;
273
+ error: Error;
274
+ doc: any; // The raw encrypted document from Fireproof
275
+ }
276
+
198
277
  interface StoreListener {
199
278
  docsAdded: (events: TableEvent[]) => void;
200
279
  docsChanged: (events: TableEvent[]) => void;
201
280
  docsDeleted: (events: TableEvent[]) => void;
281
+ decryptionError?: (events: DecryptionErrorEvent[]) => void;
202
282
  }
203
283
 
204
284
  interface Doc {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mrbelloc/encrypted-store",
3
- "version": "0.2.3",
3
+ "version": "0.3.0",
4
4
  "description": "Client-side encrypted storage with change detection for small datasets in PWAs",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",