@comergehq/studio 0.1.21 → 0.1.23

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/dist/index.js CHANGED
@@ -567,6 +567,95 @@ var BaseRepository = class {
567
567
  }
568
568
  };
569
569
 
570
+ // src/core/services/supabase/realtimeManager.ts
571
+ var INITIAL_BACKOFF_MS = 1e3;
572
+ var MAX_BACKOFF_MS = 3e4;
573
+ var realtimeLog = log.extend("realtime");
574
+ var entries = /* @__PURE__ */ new Map();
575
+ var subscriberIdCounter = 0;
576
+ function clearTimer(entry) {
577
+ if (!entry.timer) return;
578
+ clearTimeout(entry.timer);
579
+ entry.timer = null;
580
+ }
581
+ function buildChannel(entry) {
582
+ const supabase = getSupabaseClient();
583
+ const channel = supabase.channel(entry.key);
584
+ entry.subscribers.forEach((configure) => {
585
+ configure(channel);
586
+ });
587
+ return channel;
588
+ }
589
+ function scheduleResubscribe(entry, reason) {
590
+ if (entry.timer) return;
591
+ const delay = entry.backoffMs;
592
+ entry.backoffMs = Math.min(entry.backoffMs * 2, MAX_BACKOFF_MS);
593
+ realtimeLog.warn(`[realtime] channel ${entry.key} ${reason}; resubscribe in ${delay}ms`);
594
+ entry.timer = setTimeout(() => {
595
+ entry.timer = null;
596
+ if (!entries.has(entry.key)) return;
597
+ if (entry.subscribers.size === 0) return;
598
+ subscribeChannel(entry);
599
+ }, delay);
600
+ }
601
+ function handleStatus(entry, status) {
602
+ if (status === "SUBSCRIBED") {
603
+ entry.backoffMs = INITIAL_BACKOFF_MS;
604
+ clearTimer(entry);
605
+ return;
606
+ }
607
+ if (status === "CLOSED" || status === "TIMED_OUT" || status === "CHANNEL_ERROR") {
608
+ scheduleResubscribe(entry, status);
609
+ }
610
+ }
611
+ function subscribeChannel(entry) {
612
+ try {
613
+ const supabase = getSupabaseClient();
614
+ if (entry.channel) supabase.removeChannel(entry.channel);
615
+ const channel = buildChannel(entry);
616
+ entry.channel = channel;
617
+ channel.subscribe((status) => handleStatus(entry, status));
618
+ } catch (error) {
619
+ realtimeLog.warn("[realtime] subscribe failed", error);
620
+ scheduleResubscribe(entry, "SUBSCRIBE_FAILED");
621
+ }
622
+ }
623
+ function subscribeManagedChannel(key, configure) {
624
+ let entry = entries.get(key);
625
+ if (!entry) {
626
+ entry = {
627
+ key,
628
+ channel: null,
629
+ subscribers: /* @__PURE__ */ new Map(),
630
+ backoffMs: INITIAL_BACKOFF_MS,
631
+ timer: null
632
+ };
633
+ entries.set(key, entry);
634
+ }
635
+ const subscriberId = ++subscriberIdCounter;
636
+ entry.subscribers.set(subscriberId, configure);
637
+ if (!entry.channel) {
638
+ subscribeChannel(entry);
639
+ } else {
640
+ configure(entry.channel);
641
+ }
642
+ return () => {
643
+ const current = entries.get(key);
644
+ if (!current) return;
645
+ current.subscribers.delete(subscriberId);
646
+ if (current.subscribers.size === 0) {
647
+ clearTimer(current);
648
+ try {
649
+ if (current.channel) getSupabaseClient().removeChannel(current.channel);
650
+ } finally {
651
+ entries.delete(key);
652
+ }
653
+ return;
654
+ }
655
+ subscribeChannel(current);
656
+ };
657
+ }
658
+
570
659
  // src/data/apps/repository.ts
571
660
  function mapDbAppRow(row) {
572
661
  return {
@@ -648,35 +737,33 @@ var AppsRepositoryImpl = class extends BaseRepository {
648
737
  return this.subscribeToAppChannel(`apps:id:${appId}`, `id=eq.${appId}`, handlers);
649
738
  }
650
739
  subscribeToAppChannel(channelKey, filter, handlers) {
651
- const supabase = getSupabaseClient();
652
- const channel = supabase.channel(channelKey).on(
653
- "postgres_changes",
654
- { event: "INSERT", schema: "public", table: "app", filter },
655
- (payload) => {
656
- var _a;
657
- console.log("[subscribeToAppChannel] onInsert", payload);
658
- (_a = handlers.onInsert) == null ? void 0 : _a.call(handlers, mapDbAppRow(payload.new));
659
- }
660
- ).on(
661
- "postgres_changes",
662
- { event: "UPDATE", schema: "public", table: "app", filter },
663
- (payload) => {
664
- var _a;
665
- console.log("[subscribeToAppChannel] onUpdate", payload);
666
- (_a = handlers.onUpdate) == null ? void 0 : _a.call(handlers, mapDbAppRow(payload.new));
667
- }
668
- ).on(
669
- "postgres_changes",
670
- { event: "DELETE", schema: "public", table: "app", filter },
671
- (payload) => {
672
- var _a;
673
- console.log("[subscribeToAppChannel] onDelete", payload);
674
- (_a = handlers.onDelete) == null ? void 0 : _a.call(handlers, mapDbAppRow(payload.old));
675
- }
676
- ).subscribe();
677
- return () => {
678
- supabase.removeChannel(channel);
679
- };
740
+ return subscribeManagedChannel(channelKey, (channel) => {
741
+ channel.on(
742
+ "postgres_changes",
743
+ { event: "INSERT", schema: "public", table: "app", filter },
744
+ (payload) => {
745
+ var _a;
746
+ console.log("[subscribeToAppChannel] onInsert", payload);
747
+ (_a = handlers.onInsert) == null ? void 0 : _a.call(handlers, mapDbAppRow(payload.new));
748
+ }
749
+ ).on(
750
+ "postgres_changes",
751
+ { event: "UPDATE", schema: "public", table: "app", filter },
752
+ (payload) => {
753
+ var _a;
754
+ console.log("[subscribeToAppChannel] onUpdate", payload);
755
+ (_a = handlers.onUpdate) == null ? void 0 : _a.call(handlers, mapDbAppRow(payload.new));
756
+ }
757
+ ).on(
758
+ "postgres_changes",
759
+ { event: "DELETE", schema: "public", table: "app", filter },
760
+ (payload) => {
761
+ var _a;
762
+ console.log("[subscribeToAppChannel] onDelete", payload);
763
+ (_a = handlers.onDelete) == null ? void 0 : _a.call(handlers, mapDbAppRow(payload.old));
764
+ }
765
+ );
766
+ });
680
767
  }
681
768
  };
682
769
  var appsRepository = new AppsRepositoryImpl(appsRemoteDataSource);
@@ -807,35 +894,33 @@ var MessagesRepositoryImpl = class extends BaseRepository {
807
894
  return this.unwrapOrThrow(res);
808
895
  }
809
896
  subscribeThread(threadId, handlers) {
810
- const supabase = getSupabaseClient();
811
- const channel = supabase.channel(`messages:thread:${threadId}`).on(
812
- "postgres_changes",
813
- { event: "INSERT", schema: "public", table: "message", filter: `thread_id=eq.${threadId}` },
814
- (payload) => {
815
- var _a;
816
- const row = payload.new;
817
- (_a = handlers.onInsert) == null ? void 0 : _a.call(handlers, mapDbRowToMessage(row));
818
- }
819
- ).on(
820
- "postgres_changes",
821
- { event: "UPDATE", schema: "public", table: "message", filter: `thread_id=eq.${threadId}` },
822
- (payload) => {
823
- var _a;
824
- const row = payload.new;
825
- (_a = handlers.onUpdate) == null ? void 0 : _a.call(handlers, mapDbRowToMessage(row));
826
- }
827
- ).on(
828
- "postgres_changes",
829
- { event: "DELETE", schema: "public", table: "message", filter: `thread_id=eq.${threadId}` },
830
- (payload) => {
831
- var _a;
832
- const row = payload.old;
833
- (_a = handlers.onDelete) == null ? void 0 : _a.call(handlers, mapDbRowToMessage(row));
834
- }
835
- ).subscribe();
836
- return () => {
837
- supabase.removeChannel(channel);
838
- };
897
+ return subscribeManagedChannel(`messages:thread:${threadId}`, (channel) => {
898
+ channel.on(
899
+ "postgres_changes",
900
+ { event: "INSERT", schema: "public", table: "message", filter: `thread_id=eq.${threadId}` },
901
+ (payload) => {
902
+ var _a;
903
+ const row = payload.new;
904
+ (_a = handlers.onInsert) == null ? void 0 : _a.call(handlers, mapDbRowToMessage(row));
905
+ }
906
+ ).on(
907
+ "postgres_changes",
908
+ { event: "UPDATE", schema: "public", table: "message", filter: `thread_id=eq.${threadId}` },
909
+ (payload) => {
910
+ var _a;
911
+ const row = payload.new;
912
+ (_a = handlers.onUpdate) == null ? void 0 : _a.call(handlers, mapDbRowToMessage(row));
913
+ }
914
+ ).on(
915
+ "postgres_changes",
916
+ { event: "DELETE", schema: "public", table: "message", filter: `thread_id=eq.${threadId}` },
917
+ (payload) => {
918
+ var _a;
919
+ const row = payload.old;
920
+ (_a = handlers.onDelete) == null ? void 0 : _a.call(handlers, mapDbRowToMessage(row));
921
+ }
922
+ );
923
+ });
839
924
  }
840
925
  };
841
926
  var messagesRepository = new MessagesRepositoryImpl(messagesRemoteDataSource);
@@ -2399,18 +2484,15 @@ function Bubble({
2399
2484
  [height, rotation, scale, size, translateX, translateY]
2400
2485
  );
2401
2486
  const animateOut = (0, import_react.useCallback)(() => {
2487
+ var _a;
2402
2488
  if (isAnimatingOut.current) return;
2403
2489
  isAnimatingOut.current = true;
2404
2490
  try {
2405
2491
  void Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Medium);
2406
2492
  } catch {
2407
2493
  }
2408
- animateToHidden({
2409
- onFinish: () => {
2410
- var _a;
2411
- (_a = onPressRef.current) == null ? void 0 : _a.call(onPressRef);
2412
- }
2413
- });
2494
+ (_a = onPressRef.current) == null ? void 0 : _a.call(onPressRef);
2495
+ animateToHidden();
2414
2496
  }, [animateToHidden]);
2415
2497
  (0, import_react.useEffect)(() => {
2416
2498
  if (isLoading) {
@@ -7323,42 +7405,40 @@ var EditQueueRepositoryImpl = class extends BaseRepository {
7323
7405
  return this.unwrapOrThrow(res);
7324
7406
  }
7325
7407
  subscribeEditQueue(appId, handlers) {
7326
- const supabase = getSupabaseClient();
7327
- const channel = supabase.channel(`edit-queue:app:${appId}`).on(
7328
- "postgres_changes",
7329
- { event: "INSERT", schema: "public", table: "app_job_queue", filter: `app_id=eq.${appId}` },
7330
- (payload) => {
7331
- var _a;
7332
- const row = payload.new;
7333
- if (row.kind !== "edit") return;
7334
- const item = mapQueueItem(row);
7335
- if (!ACTIVE_STATUSES.includes(item.status)) return;
7336
- (_a = handlers.onInsert) == null ? void 0 : _a.call(handlers, item);
7337
- }
7338
- ).on(
7339
- "postgres_changes",
7340
- { event: "UPDATE", schema: "public", table: "app_job_queue", filter: `app_id=eq.${appId}` },
7341
- (payload) => {
7342
- var _a, _b;
7343
- const row = payload.new;
7344
- if (row.kind !== "edit") return;
7345
- const item = mapQueueItem(row);
7346
- if (ACTIVE_STATUSES.includes(item.status)) (_a = handlers.onUpdate) == null ? void 0 : _a.call(handlers, item);
7347
- else (_b = handlers.onDelete) == null ? void 0 : _b.call(handlers, item);
7348
- }
7349
- ).on(
7350
- "postgres_changes",
7351
- { event: "DELETE", schema: "public", table: "app_job_queue", filter: `app_id=eq.${appId}` },
7352
- (payload) => {
7353
- var _a;
7354
- const row = payload.old;
7355
- if (row.kind !== "edit") return;
7356
- (_a = handlers.onDelete) == null ? void 0 : _a.call(handlers, mapQueueItem(row));
7357
- }
7358
- ).subscribe();
7359
- return () => {
7360
- supabase.removeChannel(channel);
7361
- };
7408
+ return subscribeManagedChannel(`edit-queue:app:${appId}`, (channel) => {
7409
+ channel.on(
7410
+ "postgres_changes",
7411
+ { event: "INSERT", schema: "public", table: "app_job_queue", filter: `app_id=eq.${appId}` },
7412
+ (payload) => {
7413
+ var _a;
7414
+ const row = payload.new;
7415
+ if (row.kind !== "edit") return;
7416
+ const item = mapQueueItem(row);
7417
+ if (!ACTIVE_STATUSES.includes(item.status)) return;
7418
+ (_a = handlers.onInsert) == null ? void 0 : _a.call(handlers, item);
7419
+ }
7420
+ ).on(
7421
+ "postgres_changes",
7422
+ { event: "UPDATE", schema: "public", table: "app_job_queue", filter: `app_id=eq.${appId}` },
7423
+ (payload) => {
7424
+ var _a, _b;
7425
+ const row = payload.new;
7426
+ if (row.kind !== "edit") return;
7427
+ const item = mapQueueItem(row);
7428
+ if (ACTIVE_STATUSES.includes(item.status)) (_a = handlers.onUpdate) == null ? void 0 : _a.call(handlers, item);
7429
+ else (_b = handlers.onDelete) == null ? void 0 : _b.call(handlers, item);
7430
+ }
7431
+ ).on(
7432
+ "postgres_changes",
7433
+ { event: "DELETE", schema: "public", table: "app_job_queue", filter: `app_id=eq.${appId}` },
7434
+ (payload) => {
7435
+ var _a;
7436
+ const row = payload.old;
7437
+ if (row.kind !== "edit") return;
7438
+ (_a = handlers.onDelete) == null ? void 0 : _a.call(handlers, mapQueueItem(row));
7439
+ }
7440
+ );
7441
+ });
7362
7442
  }
7363
7443
  };
7364
7444
  var editQueueRepository = new EditQueueRepositoryImpl(