@gscdump/sdk 0.17.1 → 0.17.3

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/dist/index.mjs +125 -85
  2. package/package.json +3 -3
package/dist/index.mjs CHANGED
@@ -166,6 +166,89 @@ function createAnalyticsClient(options = {}) {
166
166
  }
167
167
  };
168
168
  }
169
+ function normalizeLifecycleUrl(url) {
170
+ return (url || "").replace(/^sc-domain:/, "").replace(/^https?:\/\//, "").replace(/^www\./, "").replace(/\/$/, "").toLowerCase();
171
+ }
172
+ function normalizeGscPropertyKey(url) {
173
+ const value = url || "";
174
+ if (!value) return "";
175
+ if (value.startsWith("sc-domain:")) return `domain:${normalizeLifecycleUrl(value)}`;
176
+ if (!/^https?:\/\//.test(value)) return "";
177
+ return `url:${normalizeLifecycleUrl(value)}`;
178
+ }
179
+ function analyticsStatusToSyncStatus(status) {
180
+ switch (status) {
181
+ case "ready":
182
+ case "queryable_live":
183
+ case "queryable_partial": return "synced";
184
+ case "syncing":
185
+ case "preparing": return "syncing";
186
+ case "failed": return "error";
187
+ default: return "pending";
188
+ }
189
+ }
190
+ function lifecycleSiteToUserSite(site) {
191
+ const syncStatus = analyticsStatusToSyncStatus(site.analytics.status);
192
+ return {
193
+ siteId: site.siteId,
194
+ siteUrl: site.gscPropertyUrl || site.requestedUrl,
195
+ analyticsSyncStatus: syncStatus,
196
+ analyticsSyncProgress: site.analytics.progress,
197
+ syncStatus,
198
+ syncProgress: site.analytics.progress,
199
+ indexingEligible: site.indexing.eligible,
200
+ indexingIneligibleReason: site.indexing.reason,
201
+ indexingPermissionLevel: site.permissionLevel,
202
+ indexingStatus: site.indexing.status === "ready" ? "complete" : site.indexing.status === "not_requested" ? "not_started" : "indexing",
203
+ indexingProgress: site.indexing.progress,
204
+ lastSyncAt: site.updatedAt ? Date.parse(site.updatedAt) : null,
205
+ newestDateSynced: site.analytics.syncedRange.newest,
206
+ oldestDateSynced: site.analytics.syncedRange.oldest
207
+ };
208
+ }
209
+ function lifecycleSiteToSyncStatus(site) {
210
+ const syncStatus = analyticsStatusToSyncStatus(site.analytics.status);
211
+ const completed = site.analytics.progress.completed;
212
+ const failed = site.analytics.progress.failed;
213
+ const total = site.analytics.progress.total;
214
+ const queued = Math.max(total - completed - failed, 0);
215
+ return {
216
+ siteUrl: site.gscPropertyUrl || site.requestedUrl,
217
+ syncStatus,
218
+ oldestDateAvailable: site.analytics.syncedRange.oldest,
219
+ oldestDateSynced: site.analytics.syncedRange.oldest,
220
+ newestDateSynced: site.analytics.syncedRange.newest,
221
+ lastSyncAt: site.updatedAt ? Date.parse(site.updatedAt) : null,
222
+ lastError: site.latestError?.message ?? null,
223
+ jobs: {
224
+ queued,
225
+ processing: [
226
+ "queued",
227
+ "preparing",
228
+ "syncing"
229
+ ].includes(site.analytics.status) ? 1 : 0,
230
+ completed,
231
+ failed
232
+ },
233
+ progress: site.analytics.progress.percent,
234
+ jobProgress: site.analytics.progress.percent,
235
+ daysSynced: completed,
236
+ daysAvailable: total,
237
+ isSyncing: [
238
+ "queued",
239
+ "preparing",
240
+ "syncing"
241
+ ].includes(site.analytics.status),
242
+ hasData: site.analytics.queryable,
243
+ isComplete: site.analytics.queryable && site.analytics.status === "ready",
244
+ tables: {}
245
+ };
246
+ }
247
+ function findLifecycleSite(lifecycle, siteIdOrPropertyUrl) {
248
+ const normalized = normalizeLifecycleUrl(siteIdOrPropertyUrl);
249
+ const propertyKey = normalizeGscPropertyKey(siteIdOrPropertyUrl);
250
+ return lifecycle.sites.find((site) => site.siteId === siteIdOrPropertyUrl || site.externalSiteId === siteIdOrPropertyUrl || !!propertyKey && normalizeGscPropertyKey(site.gscPropertyUrl) === propertyKey || !site.gscPropertyUrl && normalizeLifecycleUrl(site.requestedUrl) === normalized || !propertyKey && normalizeLifecycleUrl(site.requestedUrl) === normalized) ?? null;
251
+ }
169
252
  const TRAILING_SLASH_RE$1 = /\/+$/;
170
253
  const LEADING_SLASH_RE = /^\/+/;
171
254
  function trimApiBase(apiBase) {
@@ -303,6 +386,35 @@ function createPartnerClient(options = {}) {
303
386
  err.data = latest;
304
387
  throw err;
305
388
  },
389
+ async waitForUserLifecycleReady(userId, waitOptions = {}) {
390
+ const attempts = waitOptions.attempts ?? 12;
391
+ const intervalMs = waitOptions.intervalMs ?? 1e3;
392
+ let latest = null;
393
+ for (let attempt = 0; attempt < attempts; attempt++) {
394
+ latest = await request(partnerRoutes.users.lifecycle(userId));
395
+ const status = latest.account.status;
396
+ if (status === "ready") return latest;
397
+ if (status === "refresh_missing" || status === "scope_missing" || status === "reauth_required") throw new PartnerApiError({
398
+ kind: "auth",
399
+ statusCode: 401,
400
+ message: "Google Search Console authorization must be refreshed",
401
+ data: latest.account
402
+ });
403
+ if (status === "disconnected" || status === "oauth_received") throw new PartnerApiError({
404
+ kind: "provisioning",
405
+ statusCode: 409,
406
+ message: "gscdump user is not fully connected",
407
+ data: latest.account
408
+ });
409
+ if (attempt < attempts - 1) await sleep(intervalMs);
410
+ }
411
+ throw new PartnerApiError({
412
+ kind: "provisioning",
413
+ statusCode: 409,
414
+ message: "gscdump user database is still provisioning",
415
+ data: latest
416
+ });
417
+ },
306
418
  getUserSites(userId) {
307
419
  return request(partnerRoutes.users.sites(userId), {}, partnerEndpointSchemas.getUserSites.response);
308
420
  },
@@ -332,8 +444,19 @@ function createPartnerClient(options = {}) {
332
444
  getAnalysisSources(siteId, tables) {
333
445
  return request(partnerRoutes.sites.analysisSources(siteId), { query: tablesQuery(tables) }, partnerEndpointSchemas.getAnalysisSources.response);
334
446
  },
335
- getSiteSyncStatus(siteId) {
336
- return request(partnerRoutes.sites.syncStatus(siteId));
447
+ async getSiteSyncStatus(siteId, userId) {
448
+ if (!userId) return request(partnerRoutes.sites.syncStatus(siteId));
449
+ const site = findLifecycleSite(await request(partnerRoutes.users.lifecycle(userId)), siteId);
450
+ if (!site) throw new PartnerApiError({
451
+ kind: "not-found",
452
+ statusCode: 404,
453
+ message: "gscdump lifecycle site not found",
454
+ data: {
455
+ siteId,
456
+ userId
457
+ }
458
+ });
459
+ return lifecycleSiteToSyncStatus(site);
337
460
  },
338
461
  getData(siteId, state, queryOptions) {
339
462
  if (shouldValidate(options, "request")) {
@@ -495,89 +618,6 @@ function createPartnerClient(options = {}) {
495
618
  };
496
619
  }
497
620
  const createGscdumpClient = createPartnerClient;
498
- function normalizeLifecycleUrl(url) {
499
- return (url || "").replace(/^sc-domain:/, "").replace(/^https?:\/\//, "").replace(/^www\./, "").replace(/\/$/, "").toLowerCase();
500
- }
501
- function normalizeGscPropertyKey(url) {
502
- const value = url || "";
503
- if (!value) return "";
504
- if (value.startsWith("sc-domain:")) return `domain:${normalizeLifecycleUrl(value)}`;
505
- if (!/^https?:\/\//.test(value)) return "";
506
- return `url:${normalizeLifecycleUrl(value)}`;
507
- }
508
- function analyticsStatusToSyncStatus(status) {
509
- switch (status) {
510
- case "ready":
511
- case "queryable_live":
512
- case "queryable_partial": return "synced";
513
- case "syncing":
514
- case "preparing": return "syncing";
515
- case "failed": return "error";
516
- default: return "pending";
517
- }
518
- }
519
- function lifecycleSiteToUserSite(site) {
520
- const syncStatus = analyticsStatusToSyncStatus(site.analytics.status);
521
- return {
522
- siteId: site.siteId,
523
- siteUrl: site.gscPropertyUrl || site.requestedUrl,
524
- analyticsSyncStatus: syncStatus,
525
- analyticsSyncProgress: site.analytics.progress,
526
- syncStatus,
527
- syncProgress: site.analytics.progress,
528
- indexingEligible: site.indexing.eligible,
529
- indexingIneligibleReason: site.indexing.reason,
530
- indexingPermissionLevel: site.permissionLevel,
531
- indexingStatus: site.indexing.status === "ready" ? "complete" : site.indexing.status === "not_requested" ? "not_started" : "indexing",
532
- indexingProgress: site.indexing.progress,
533
- lastSyncAt: site.updatedAt ? Date.parse(site.updatedAt) : null,
534
- newestDateSynced: site.analytics.syncedRange.newest,
535
- oldestDateSynced: site.analytics.syncedRange.oldest
536
- };
537
- }
538
- function lifecycleSiteToSyncStatus(site) {
539
- const syncStatus = analyticsStatusToSyncStatus(site.analytics.status);
540
- const completed = site.analytics.progress.completed;
541
- const failed = site.analytics.progress.failed;
542
- const total = site.analytics.progress.total;
543
- const queued = Math.max(total - completed - failed, 0);
544
- return {
545
- siteUrl: site.gscPropertyUrl || site.requestedUrl,
546
- syncStatus,
547
- oldestDateAvailable: site.analytics.syncedRange.oldest,
548
- oldestDateSynced: site.analytics.syncedRange.oldest,
549
- newestDateSynced: site.analytics.syncedRange.newest,
550
- lastSyncAt: site.updatedAt ? Date.parse(site.updatedAt) : null,
551
- lastError: site.latestError?.message ?? null,
552
- jobs: {
553
- queued,
554
- processing: [
555
- "queued",
556
- "preparing",
557
- "syncing"
558
- ].includes(site.analytics.status) ? 1 : 0,
559
- completed,
560
- failed
561
- },
562
- progress: site.analytics.progress.percent,
563
- jobProgress: site.analytics.progress.percent,
564
- daysSynced: completed,
565
- daysAvailable: total,
566
- isSyncing: [
567
- "queued",
568
- "preparing",
569
- "syncing"
570
- ].includes(site.analytics.status),
571
- hasData: site.analytics.queryable,
572
- isComplete: site.analytics.queryable && site.analytics.status === "ready",
573
- tables: {}
574
- };
575
- }
576
- function findLifecycleSite(lifecycle, siteIdOrPropertyUrl) {
577
- const normalized = normalizeLifecycleUrl(siteIdOrPropertyUrl);
578
- const propertyKey = normalizeGscPropertyKey(siteIdOrPropertyUrl);
579
- return lifecycle.sites.find((site) => site.siteId === siteIdOrPropertyUrl || site.externalSiteId === siteIdOrPropertyUrl || !!propertyKey && normalizeGscPropertyKey(site.gscPropertyUrl) === propertyKey || !site.gscPropertyUrl && normalizeLifecycleUrl(site.requestedUrl) === normalized || !propertyKey && normalizeLifecycleUrl(site.requestedUrl) === normalized) ?? null;
580
- }
581
621
  const HTTP_PROTOCOL_RE = /^http/i;
582
622
  const API_SUFFIX_RE = /\/api\/?$/;
583
623
  const TRAILING_SLASH_RE = /\/+$/;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@gscdump/sdk",
3
3
  "type": "module",
4
- "version": "0.17.1",
4
+ "version": "0.17.3",
5
5
  "description": "Consumer SDK for hosted gscdump.com integrations.",
6
6
  "author": {
7
7
  "name": "Harlan Wilton",
@@ -41,7 +41,7 @@
41
41
  "node": ">=18"
42
42
  },
43
43
  "peerDependencies": {
44
- "gscdump": "0.17.1"
44
+ "gscdump": "0.17.3"
45
45
  },
46
46
  "peerDependenciesMeta": {
47
47
  "gscdump": {
@@ -51,7 +51,7 @@
51
51
  "dependencies": {
52
52
  "ofetch": "^1.5.1",
53
53
  "zod": "^4.4.3",
54
- "@gscdump/contracts": "0.17.1"
54
+ "@gscdump/contracts": "0.17.3"
55
55
  },
56
56
  "devDependencies": {
57
57
  "typescript": "^6.0.3",