@bobfrankston/gcards 0.1.32 → 0.1.34
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/gcards.ts +23 -5
- package/glib/gutils.ts +11 -1
- package/package.json +1 -1
package/gcards.ts
CHANGED
|
@@ -179,7 +179,16 @@ interface DeletedIndex {
|
|
|
179
179
|
function loadDeleted(paths: UserPaths): DeletedIndex {
|
|
180
180
|
if (fs.existsSync(paths.deletedFile)) {
|
|
181
181
|
try {
|
|
182
|
-
|
|
182
|
+
const parsed = parseJsonc(fs.readFileSync(paths.deletedFile, 'utf-8'));
|
|
183
|
+
if (!parsed || typeof parsed !== 'object') {
|
|
184
|
+
console.warn(`Warning: ${paths.deletedFile} is not a valid object, returning empty deleted index`);
|
|
185
|
+
return { deleted: {} };
|
|
186
|
+
}
|
|
187
|
+
if (!parsed.deleted || typeof parsed.deleted !== 'object') {
|
|
188
|
+
console.warn(`Warning: ${paths.deletedFile} missing or invalid deleted field, initializing empty`);
|
|
189
|
+
parsed.deleted = {};
|
|
190
|
+
}
|
|
191
|
+
return parsed as DeletedIndex;
|
|
183
192
|
} catch (e: any) {
|
|
184
193
|
throw new Error(`Failed to parse ${paths.deletedFile}: ${e.message}`);
|
|
185
194
|
}
|
|
@@ -228,7 +237,16 @@ interface PhotosIndex {
|
|
|
228
237
|
function loadPhotos(paths: UserPaths): PhotosIndex {
|
|
229
238
|
if (fs.existsSync(paths.photosFile)) {
|
|
230
239
|
try {
|
|
231
|
-
|
|
240
|
+
const parsed = parseJsonc(fs.readFileSync(paths.photosFile, 'utf-8'));
|
|
241
|
+
if (!parsed || typeof parsed !== 'object') {
|
|
242
|
+
console.warn(`Warning: ${paths.photosFile} is not a valid object, returning empty photos index`);
|
|
243
|
+
return { photos: {} };
|
|
244
|
+
}
|
|
245
|
+
if (!parsed.photos || typeof parsed.photos !== 'object') {
|
|
246
|
+
console.warn(`Warning: ${paths.photosFile} missing or invalid photos field, initializing empty`);
|
|
247
|
+
parsed.photos = {};
|
|
248
|
+
}
|
|
249
|
+
return parsed as PhotosIndex;
|
|
232
250
|
} catch (e: any) {
|
|
233
251
|
throw new Error(`Failed to parse ${paths.photosFile}: ${e.message}`);
|
|
234
252
|
}
|
|
@@ -1262,20 +1280,20 @@ async function pushContacts(user: string, options: { yes: boolean; verbose: bool
|
|
|
1262
1280
|
await sleep(1500); // Google tightened limits - need ~1.5s between ops
|
|
1263
1281
|
} catch (error: any) {
|
|
1264
1282
|
const fileName = path.basename(change.filePath);
|
|
1265
|
-
const errorMsg = `${fileName}: ${error.message}`;
|
|
1283
|
+
const errorMsg = `${change.displayName} (${fileName}): ${error.message}`;
|
|
1266
1284
|
console.log(` ERROR: ${error.message}`);
|
|
1267
1285
|
problems.push(errorMsg);
|
|
1268
1286
|
errorCount++;
|
|
1269
1287
|
|
|
1270
1288
|
// Check for etag mismatch - needs resync
|
|
1271
1289
|
if (error.message?.includes('FAILED_PRECONDITION') || error.message?.includes('etag')) {
|
|
1272
|
-
console.log(` →
|
|
1290
|
+
console.log(` → ${change.displayName} changed on Google. Run 'gcards sync' then retry.`);
|
|
1273
1291
|
continue;
|
|
1274
1292
|
}
|
|
1275
1293
|
|
|
1276
1294
|
// Check for 404 - contact deleted on server, remove locally
|
|
1277
1295
|
if (error.message?.includes('404') || error.message?.includes('NOT_FOUND')) {
|
|
1278
|
-
console.log(` →
|
|
1296
|
+
console.log(` → ${change.displayName} deleted on Google. Removing local copy.`);
|
|
1279
1297
|
// Move to deleted folder
|
|
1280
1298
|
if (fs.existsSync(change.filePath)) {
|
|
1281
1299
|
const id = path.basename(change.filePath, '.json');
|
package/glib/gutils.ts
CHANGED
|
@@ -84,7 +84,17 @@ export function ensureUserDir(user: string): void {
|
|
|
84
84
|
export function loadIndex(paths: UserPaths): ContactIndex {
|
|
85
85
|
if (fs.existsSync(paths.indexFile)) {
|
|
86
86
|
try {
|
|
87
|
-
|
|
87
|
+
const parsed = parseJsonc(fs.readFileSync(paths.indexFile, 'utf-8'));
|
|
88
|
+
// Ensure contacts field exists
|
|
89
|
+
if (!parsed || typeof parsed !== 'object') {
|
|
90
|
+
console.warn(`Warning: ${paths.indexFile} is not a valid object, returning empty index`);
|
|
91
|
+
return { contacts: {}, lastSync: '' };
|
|
92
|
+
}
|
|
93
|
+
if (!parsed.contacts || typeof parsed.contacts !== 'object') {
|
|
94
|
+
console.warn(`Warning: ${paths.indexFile} missing or invalid contacts field, initializing empty`);
|
|
95
|
+
parsed.contacts = {};
|
|
96
|
+
}
|
|
97
|
+
return parsed as ContactIndex;
|
|
88
98
|
} catch (e: any) {
|
|
89
99
|
throw new Error(`Failed to parse ${paths.indexFile}: ${e.message}`);
|
|
90
100
|
}
|