stellar-drive 1.2.14 → 1.2.15

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.
@@ -79,7 +79,8 @@ function createSyncStatusStore() {
79
79
  lastSyncTime: null,
80
80
  syncMessage: null,
81
81
  isTabVisible: true,
82
- realtimeState: 'disconnected'
82
+ realtimeState: 'disconnected',
83
+ progress: null
83
84
  });
84
85
  // ---------------------------------------------------------------------------
85
86
  // Anti-Flicker Timing State
@@ -234,6 +235,40 @@ function createSyncStatusStore() {
234
235
  * @see {@link RealtimeState} for possible values
235
236
  */
236
237
  setRealtimeState: (realtimeState) => update((state) => ({ ...state, realtimeState })),
238
+ /**
239
+ * Begin tracking a high-volume batch push. Populates the `progress` field
240
+ * with an initial snapshot so the UI can render a progress bar instead of
241
+ * just an indeterminate spinner.
242
+ *
243
+ * @param total - Queue size at the start of the push (the denominator)
244
+ */
245
+ startProgress: (total) => update((state) => ({
246
+ ...state,
247
+ progress: { total, completed: 0, failed: 0, currentTable: null }
248
+ })),
249
+ /**
250
+ * Advance the batch-push progress counters. Called after each batch or
251
+ * individual item finishes so the UI can reflect real-time throughput.
252
+ *
253
+ * @param delta - How many items finished since the last update
254
+ * @param failed - How many of those items failed (defaults to 0)
255
+ * @param currentTable - Optional table name currently being processed
256
+ */
257
+ advanceProgress: (delta, failed = 0, currentTable) => update((state) => {
258
+ if (!state.progress)
259
+ return state;
260
+ return {
261
+ ...state,
262
+ progress: {
263
+ total: state.progress.total,
264
+ completed: state.progress.completed + delta,
265
+ failed: state.progress.failed + failed,
266
+ currentTable: currentTable !== undefined ? currentTable : state.progress.currentTable
267
+ }
268
+ };
269
+ }),
270
+ /** Clear progress tracking — call when a large push completes (or aborts). */
271
+ clearProgress: () => update((state) => ({ ...state, progress: null })),
237
272
  /**
238
273
  * Reset the entire store to its initial default state.
239
274
  *
@@ -258,7 +293,8 @@ function createSyncStatusStore() {
258
293
  lastSyncTime: null,
259
294
  syncMessage: null,
260
295
  isTabVisible: true,
261
- realtimeState: 'disconnected'
296
+ realtimeState: 'disconnected',
297
+ progress: null
262
298
  });
263
299
  }
264
300
  };
@@ -1 +1 @@
1
- {"version":3,"file":"sync.js","sourceRoot":"","sources":["../../src/stores/sync.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"sync.js","sourceRoot":"","sources":["../../src/stores/sync.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "stellar-drive",
3
- "version": "1.2.14",
3
+ "version": "1.2.15",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -21,7 +21,7 @@
21
21
  */
22
22
 
23
23
  import { syncStatusStore, isOnline } from 'stellar-drive/stores';
24
- import type { SyncError, RealtimeState } from 'stellar-drive/types';
24
+ import type { SyncError, RealtimeState, SyncProgress } from 'stellar-drive/types';
25
25
  import { runFullSync } from 'stellar-drive';
26
26
  import type { SyncStatus } from 'stellar-drive/types';
27
27
 
@@ -49,6 +49,8 @@
49
49
  let syncMessage = $state<string | null>(null);
50
50
  /** Supabase Realtime connection state */
51
51
  let realtimeState = $state<RealtimeState>('disconnected');
52
+ /** Live progress for a high-volume batch push (null outside of one). */
53
+ let progress = $state<SyncProgress | null>(null);
52
54
  /** Whether the tooltip is visible */
53
55
  let showTooltip = $state(false);
54
56
  /** Whether the error-details panel inside the tooltip is expanded */
@@ -89,6 +91,7 @@
89
91
  syncErrors = value.syncErrors;
90
92
  lastSyncTime = value.lastSyncTime;
91
93
  syncMessage = value.syncMessage;
94
+ progress = value.progress;
92
95
 
93
96
  // Track realtime state changes for smooth animation
94
97
  if (value.realtimeState !== prevRealtimeState) {
@@ -125,13 +128,20 @@
125
128
  // =============================================================================
126
129
 
127
130
  /**
128
- * Trigger a full manual sync when the indicator is clicked (only if online
129
- * and not already syncing).
131
+ * Trigger a full manual sync when the indicator is clicked.
132
+ *
133
+ * Clickable whenever online — during `catching-up` the user can still
134
+ * click to queue another sync pass (it will coalesce harmlessly), which
135
+ * gives the user a sense of agency during long batch pushes instead of
136
+ * staring at a disabled button. During `syncing` we still block to avoid
137
+ * stacking concurrent short-cycle syncs.
130
138
  */
131
139
  function handleSyncClick() {
132
- if (online && status !== 'syncing') {
133
- runFullSync(false);
134
- }
140
+ if (!online) return;
141
+ // Allow clicks during catching-up so the user has an escape hatch;
142
+ // runFullSync is idempotent via the internal sync lock.
143
+ if (status === 'syncing' && !progress) return;
144
+ runFullSync(false);
135
145
  }
136
146
 
137
147
  /**
@@ -180,17 +190,30 @@
180
190
  // =============================================================================
181
191
 
182
192
  /**
183
- * Map the raw sync status + online flag into one of five display states:
184
- * `offline` | `syncing` | `error` | `pending` | `synced`.
193
+ * Map the raw sync status + online flag into one of six display states:
194
+ * `offline` | `catching-up` | `syncing` | `error` | `pending` | `synced`.
195
+ *
196
+ * `catching-up` is distinct from `syncing` — it surfaces *during* a
197
+ * high-volume batch push where the progress monitor is populating
198
+ * `progress`. The UI shows a determinate ring (with percentage) instead
199
+ * of an opaque spinner, and the button is clickable so the user knows
200
+ * work is in flight AND can still force-resync if they get impatient.
185
201
  */
186
202
  const displayState = $derived(() => {
187
203
  if (!online) return 'offline';
204
+ if (progress && progress.total > 0) return 'catching-up';
188
205
  if (status === 'syncing') return 'syncing';
189
206
  if (status === 'error') return 'error';
190
207
  if (pendingCount > 0) return 'pending';
191
208
  return 'synced';
192
209
  });
193
210
 
211
+ /** Percentage completed for the catching-up progress ring (0–100). */
212
+ const progressPct = $derived(() => {
213
+ if (!progress || progress.total === 0) return 0;
214
+ return Math.min(100, Math.round((progress.completed / progress.total) * 100));
215
+ });
216
+
194
217
  // =============================================================================
195
218
  // Effect — Transition Animation Trigger
196
219
  // =============================================================================
@@ -243,6 +266,8 @@
243
266
  switch (state) {
244
267
  case 'offline':
245
268
  return 'Offline';
269
+ case 'catching-up':
270
+ return 'Catching Up';
246
271
  case 'syncing':
247
272
  return 'Syncing';
248
273
  case 'error':
@@ -277,6 +302,13 @@
277
302
  switch (state) {
278
303
  case 'offline':
279
304
  return "Changes will sync when you're back online.";
305
+ case 'catching-up': {
306
+ const prog = progress;
307
+ if (!prog) return 'Syncing a large batch…';
308
+ const pct = progressPct();
309
+ const remaining = Math.max(0, prog.total - prog.completed);
310
+ return `${prog.completed.toLocaleString()} of ${prog.total.toLocaleString()} synced · ${remaining.toLocaleString()} to go (${pct}%)`;
311
+ }
280
312
  case 'syncing':
281
313
  return 'Syncing your data...';
282
314
  case 'error':
@@ -384,17 +416,51 @@
384
416
  <button
385
417
  class="sync-indicator"
386
418
  class:offline={displayState() === 'offline'}
419
+ class:catching-up={displayState() === 'catching-up'}
387
420
  class:syncing={displayState() === 'syncing'}
388
421
  class:error={displayState() === 'error'}
389
422
  class:pending={displayState() === 'pending'}
390
423
  class:synced={displayState() === 'synced'}
391
424
  onclick={handleSyncClick}
392
- disabled={!online || status === 'syncing'}
425
+ disabled={!online || (status === 'syncing' && !progress)}
393
426
  aria-label={statusLabel()}
394
427
  >
395
428
  <!-- Animated ring around the button -->
396
429
  <span class="indicator-ring"></span>
397
430
 
431
+ <!-- ═══ Catching-Up Progress Ring (determinate SVG circle) ═══ -->
432
+ {#if displayState() === 'catching-up'}
433
+ <svg
434
+ class="progress-ring"
435
+ width="36"
436
+ height="36"
437
+ viewBox="0 0 36 36"
438
+ aria-hidden="true"
439
+ >
440
+ <!-- Background track -->
441
+ <circle
442
+ class="progress-ring-track"
443
+ cx="18"
444
+ cy="18"
445
+ r="15.5"
446
+ fill="none"
447
+ stroke-width="2.25"
448
+ />
449
+ <!-- Foreground arc — stroke-dasharray driven by progressPct -->
450
+ <circle
451
+ class="progress-ring-arc"
452
+ cx="18"
453
+ cy="18"
454
+ r="15.5"
455
+ fill="none"
456
+ stroke-width="2.25"
457
+ stroke-linecap="round"
458
+ style:stroke-dasharray={`${(progressPct() / 100) * 97.39} 97.39`}
459
+ transform="rotate(-90 18 18)"
460
+ />
461
+ </svg>
462
+ {/if}
463
+
398
464
  <!-- ═══ Morphing Icon Container ═══ -->
399
465
  <span class="indicator-core" class:transitioning={isTransitioning}>
400
466
  <!-- Offline Icon (wifi-off) -->
@@ -487,6 +553,11 @@
487
553
  d="M21.5 2v6h-6M2.5 22v-6h6M2 11.5a10 10 0 0 1 18.8-4.3M22 12.5a10 10 0 0 1-18.8 4.2"
488
554
  />
489
555
  </svg>
556
+
557
+ <!-- Catching-Up Percentage (sits inside the progress ring) -->
558
+ {#if displayState() === 'catching-up'}
559
+ <span class="progress-pct">{progressPct()}</span>
560
+ {/if}
490
561
  </span>
491
562
 
492
563
  <!-- Pending count badge -->
@@ -520,12 +591,18 @@
520
591
  <div
521
592
  class="status-dot"
522
593
  class:offline={displayState() === 'offline'}
594
+ class:catching-up={displayState() === 'catching-up'}
523
595
  class:syncing={displayState() === 'syncing'}
524
596
  class:error={displayState() === 'error'}
525
597
  class:pending={displayState() === 'pending'}
526
598
  class:synced={displayState() === 'synced'}
527
599
  ></div>
528
600
  <span class="status-label">{statusLabel()}</span>
601
+ {#if displayState() === 'catching-up' && progress}
602
+ <span class="progress-count">
603
+ {progress.completed.toLocaleString()} / {progress.total.toLocaleString()}
604
+ </span>
605
+ {/if}
529
606
  {#if realtimeLabel() && displayState() !== 'offline'}
530
607
  <span
531
608
  class="realtime-badge"
@@ -538,9 +615,17 @@
538
615
  {realtimeLabel()}
539
616
  </span>
540
617
  {/if}
541
- {#if formattedLastSync() && displayState() !== 'syncing'}
618
+ {#if formattedLastSync() && displayState() !== 'syncing' && displayState() !== 'catching-up'}
542
619
  <span class="last-sync">{formattedLastSync()}</span>
543
620
  {/if}
621
+
622
+ <!-- ── In-Tooltip Progress Bar (shown while catching up) ── -->
623
+ {#if displayState() === 'catching-up'}
624
+ <div class="catching-up-bar" role="progressbar" aria-valuenow={progressPct()} aria-valuemin="0" aria-valuemax="100">
625
+ <span class="catching-up-bar-fill" style:width={`${progressPct()}%`}></span>
626
+ <span class="catching-up-bar-shimmer"></span>
627
+ </div>
628
+ {/if}
544
629
  </div>
545
630
 
546
631
  <!-- ── Status Description ── -->
@@ -1034,6 +1119,115 @@
1034
1119
  }
1035
1120
  }
1036
1121
 
1122
+ /* ═══ Catching-Up State (high-volume batch push in flight) ═══ */
1123
+
1124
+ .sync-indicator.catching-up {
1125
+ /* Sapphire → primary gradient border communicates "work flowing in" */
1126
+ border-color: rgba(108, 92, 231, 0.5);
1127
+ background: linear-gradient(
1128
+ 135deg,
1129
+ color-mix(in srgb, var(--color-primary) 10%, transparent) 0%,
1130
+ color-mix(in srgb, var(--color-primary) 3%, transparent) 100%
1131
+ );
1132
+ }
1133
+
1134
+ .sync-indicator.catching-up:not(:disabled):hover {
1135
+ box-shadow: 0 0 28px var(--color-primary-glow);
1136
+ }
1137
+
1138
+ /* Determinate progress ring — scaled to sit over the button's border */
1139
+ .progress-ring {
1140
+ position: absolute;
1141
+ inset: -4px;
1142
+ width: calc(100% + 8px);
1143
+ height: calc(100% + 8px);
1144
+ pointer-events: none;
1145
+ }
1146
+
1147
+ .progress-ring-track {
1148
+ stroke: rgba(108, 92, 231, 0.15);
1149
+ }
1150
+
1151
+ .progress-ring-arc {
1152
+ stroke: var(--color-primary-light, #a29bfe);
1153
+ filter: drop-shadow(0 0 3px color-mix(in srgb, var(--color-primary) 55%, transparent));
1154
+ transition: stroke-dasharray 0.35s cubic-bezier(0.22, 1, 0.36, 1);
1155
+ }
1156
+
1157
+ /* Percentage text sitting inside the ring */
1158
+ .progress-pct {
1159
+ position: absolute;
1160
+ inset: 0;
1161
+ display: flex;
1162
+ align-items: center;
1163
+ justify-content: center;
1164
+ font-size: 10px;
1165
+ font-weight: 700;
1166
+ font-variant-numeric: tabular-nums;
1167
+ color: var(--color-primary-light, #a29bfe);
1168
+ letter-spacing: -0.02em;
1169
+ }
1170
+
1171
+ .progress-pct::after {
1172
+ content: '%';
1173
+ font-size: 7px;
1174
+ font-weight: 600;
1175
+ margin-left: 1px;
1176
+ opacity: 0.7;
1177
+ }
1178
+
1179
+ /* Running count chip shown in tooltip header */
1180
+ .progress-count {
1181
+ margin-left: auto;
1182
+ font-size: 11px;
1183
+ font-weight: 600;
1184
+ font-variant-numeric: tabular-nums;
1185
+ color: var(--color-primary-light, #a29bfe);
1186
+ letter-spacing: -0.01em;
1187
+ }
1188
+
1189
+ /* In-tooltip progress bar with shimmer */
1190
+ .catching-up-bar {
1191
+ position: relative;
1192
+ width: 100%;
1193
+ height: 4px;
1194
+ margin-top: 4px;
1195
+ background: rgba(108, 92, 231, 0.12);
1196
+ border-radius: 2px;
1197
+ overflow: hidden;
1198
+ }
1199
+
1200
+ .catching-up-bar-fill {
1201
+ position: absolute;
1202
+ inset: 0 auto 0 0;
1203
+ background: linear-gradient(
1204
+ 90deg,
1205
+ var(--color-primary, #6c5ce7) 0%,
1206
+ var(--color-primary-light, #a29bfe) 100%
1207
+ );
1208
+ border-radius: 2px;
1209
+ transition: width 0.35s cubic-bezier(0.22, 1, 0.36, 1);
1210
+ }
1211
+
1212
+ .catching-up-bar-shimmer {
1213
+ position: absolute;
1214
+ inset: 0;
1215
+ background: linear-gradient(
1216
+ 90deg,
1217
+ transparent 0%,
1218
+ rgba(255, 255, 255, 0.22) 50%,
1219
+ transparent 100%
1220
+ );
1221
+ transform: translateX(-100%);
1222
+ animation: catching-up-shimmer 1.6s ease-in-out infinite;
1223
+ }
1224
+
1225
+ @keyframes catching-up-shimmer {
1226
+ to {
1227
+ transform: translateX(100%);
1228
+ }
1229
+ }
1230
+
1037
1231
  /* ═══ Pending State ═══ */
1038
1232
 
1039
1233
  .sync-indicator.pending {
@@ -1329,6 +1523,12 @@
1329
1523
  animation: dotPulse 1s ease-in-out infinite;
1330
1524
  }
1331
1525
 
1526
+ .status-dot.catching-up {
1527
+ background: var(--color-primary-light, #a29bfe);
1528
+ box-shadow: 0 0 10px var(--color-primary-glow);
1529
+ animation: dotPulse 1.4s ease-in-out infinite;
1530
+ }
1531
+
1332
1532
  @keyframes dotPulse {
1333
1533
  0%,
1334
1534
  100% {