@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.
- package/README.md +81 -1
- 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
|
|
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 {
|