@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 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
- return parseJsonc(fs.readFileSync(paths.deletedFile, 'utf-8'));
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
- return parseJsonc(fs.readFileSync(paths.photosFile, 'utf-8'));
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(` → Contact changed on Google. Run 'gcards sync' then retry.`);
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(` → Contact deleted on Google. Removing local copy.`);
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
- return parseJsonc(fs.readFileSync(paths.indexFile, 'utf-8'));
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
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bobfrankston/gcards",
3
- "version": "0.1.32",
3
+ "version": "0.1.34",
4
4
  "description": "Google Contacts cleanup and management tool",
5
5
  "type": "module",
6
6
  "main": "gcards.ts",