@bobfrankston/gcards 0.1.18 → 0.1.20

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.
@@ -0,0 +1,33 @@
1
+ {
2
+ "folders": [
3
+ {
4
+ "path": "."
5
+ },
6
+ {
7
+ "path": "../../../projects/OAuth/OauthSupport"
8
+ }
9
+ ],
10
+ "settings": {
11
+ "workbench.colorTheme": "Visual Studio 2019 Dark",
12
+ "workbench.colorCustomizations": {
13
+ "activityBar.activeBackground": "#0ae04a",
14
+ "activityBar.background": "#0ae04a",
15
+ "activityBar.foreground": "#15202b",
16
+ "activityBar.inactiveForeground": "#15202b99",
17
+ "activityBarBadge.background": "#9266f8",
18
+ "activityBarBadge.foreground": "#15202b",
19
+ "commandCenter.border": "#e7e7e799",
20
+ "sash.hoverBorder": "#0ae04a",
21
+ "statusBar.background": "#08af3a",
22
+ "statusBar.foreground": "#e7e7e7",
23
+ "statusBarItem.hoverBackground": "#0ae04a",
24
+ "statusBarItem.remoteBackground": "#08af3a",
25
+ "statusBarItem.remoteForeground": "#e7e7e7",
26
+ "titleBar.activeBackground": "#08af3a",
27
+ "titleBar.activeForeground": "#e7e7e7",
28
+ "titleBar.inactiveBackground": "#08af3a99",
29
+ "titleBar.inactiveForeground": "#e7e7e799"
30
+ },
31
+ "peacock.color": "#08af3a"
32
+ }
33
+ }
package/gcards.ts CHANGED
@@ -79,7 +79,9 @@ function cleanupEscapeHandler(): void {
79
79
  process.stdin.pause();
80
80
  process.stdin.removeAllListeners('data');
81
81
  }
82
- process.stdin.unref(); // Allow Node to exit even if stdin is open
82
+ if (typeof process.stdin.unref === 'function') {
83
+ process.stdin.unref(); // Allow Node to exit even if stdin is open
84
+ }
83
85
  }
84
86
 
85
87
  async function getAccessToken(user: string, writeAccess = false, forceRefresh = false): Promise<string> {
@@ -297,8 +299,15 @@ async function fetchContactsWithRetry(
297
299
  });
298
300
 
299
301
  if (response.status === 410) {
300
- console.log('Sync token expired, performing full sync...');
301
- return fetchContactsWithRetry(accessToken, undefined, pageToken, 0);
302
+ throw new Error('SYNC_TOKEN_EXPIRED');
303
+ }
304
+
305
+ if (response.status === 400) {
306
+ const text = await response.text();
307
+ if (text.includes('EXPIRED_SYNC_TOKEN')) {
308
+ throw new Error('SYNC_TOKEN_EXPIRED');
309
+ }
310
+ throw new Error(`API error: ${response.status} ${text}`);
302
311
  }
303
312
 
304
313
  if (response.status === 429) {
@@ -391,12 +400,30 @@ async function syncContacts(user: string, options: { full: boolean; verbose: boo
391
400
  let deleted = 0;
392
401
  let conflicts = 0;
393
402
  let pageNum = 0;
403
+ let hasMore = true;
394
404
 
395
- do {
405
+ while (hasMore) {
396
406
  pageNum++;
397
407
  process.stdout.write(`\rFetching page ${pageNum}... (${totalProcessed} contacts so far)`);
398
408
 
399
- const response = await fetchContactsWithRetry(accessToken, syncToken || undefined, pageToken);
409
+ let response: GoogleConnectionsResponse;
410
+ try {
411
+ response = await fetchContactsWithRetry(accessToken, syncToken || undefined, pageToken);
412
+ } catch (err) {
413
+ if (err instanceof Error && err.message === 'SYNC_TOKEN_EXPIRED') {
414
+ console.log('\nSync token expired, restarting with full sync...');
415
+ syncToken = null;
416
+ pageToken = undefined;
417
+ pageNum = 0;
418
+ totalProcessed = 0;
419
+ added = 0;
420
+ updated = 0;
421
+ deleted = 0;
422
+ conflicts = 0;
423
+ continue;
424
+ }
425
+ throw err;
426
+ }
400
427
 
401
428
  if (response.connections) {
402
429
  for (const person of response.connections) {
@@ -520,7 +547,9 @@ async function syncContacts(user: string, options: { full: boolean; verbose: boo
520
547
  console.log('\n\nStopped by user. Progress saved.');
521
548
  break;
522
549
  }
523
- } while (pageToken);
550
+
551
+ hasMore = !!pageToken;
552
+ }
524
553
 
525
554
  const activeContacts = Object.keys(index.contacts).length;
526
555
  const tombstones = Object.keys(deletedIndex.deleted).length;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bobfrankston/gcards",
3
- "version": "0.1.18",
3
+ "version": "0.1.20",
4
4
  "description": "Google Contacts cleanup and management tool",
5
5
  "type": "module",
6
6
  "main": "gcards.ts",
@@ -17,7 +17,8 @@
17
17
  "prerelease:local": "git add -A && (git diff-index --quiet HEAD || git commit -m \"Pre-release commit\")",
18
18
  "preversion": "npm run check && git add -A",
19
19
  "postversion": "git push && git push --tags",
20
- "release": "npm whoami && npm run prerelease:local && npm version patch && npm publish --access public"
20
+ "release": "npm whoami && npm run prerelease:local && npm version patch && npm publish --access public",
21
+ "installer": "npm run release && npm install -g @bobfrankston/gcards"
21
22
  },
22
23
  "keywords": [
23
24
  "google",