@bbearai/core 0.7.2 → 0.8.0

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.d.mts CHANGED
@@ -479,6 +479,7 @@ interface TesterThread {
479
479
  createdAt: string;
480
480
  unreadCount: number;
481
481
  lastMessage?: TesterMessage;
482
+ reporterName?: string;
482
483
  }
483
484
  interface TesterMessage {
484
485
  id: string;
@@ -1102,6 +1103,12 @@ declare class BugBearClient {
1102
1103
  private initialized;
1103
1104
  /** Initialization error, if any. */
1104
1105
  private initError;
1106
+ /** Active presence session ID (passive time tracking). */
1107
+ private _presenceSessionId;
1108
+ /** Heartbeat interval for presence tracking. */
1109
+ private _presenceInterval;
1110
+ /** Whether presence is paused (tab hidden / app backgrounded). */
1111
+ private _presencePaused;
1105
1112
  constructor(config: BugBearConfig);
1106
1113
  /** Whether the client is ready for requests. */
1107
1114
  get isReady(): boolean;
@@ -1561,6 +1568,22 @@ declare class BugBearClient {
1561
1568
  * Transform database finding to QAFinding type
1562
1569
  */
1563
1570
  private transformFinding;
1571
+ /** Current presence session ID (null if not tracking). */
1572
+ get presenceSessionId(): string | null;
1573
+ /**
1574
+ * Start passive presence tracking for this tester.
1575
+ * Idempotent — reuses an existing active session if one exists.
1576
+ */
1577
+ startPresence(platform: 'web' | 'ios' | 'android'): Promise<string | null>;
1578
+ /** Gracefully end the current presence session. */
1579
+ endPresence(): Promise<void>;
1580
+ /** Pause heartbeat (tab hidden / app backgrounded). Sends one final beat. */
1581
+ pausePresence(): void;
1582
+ /** Resume heartbeat after pause. Restarts if session was cleaned up. */
1583
+ resumePresence(): Promise<void>;
1584
+ private heartbeatPresence;
1585
+ private startPresenceHeartbeat;
1586
+ private stopPresenceHeartbeat;
1564
1587
  }
1565
1588
  /**
1566
1589
  * Create a BugBear client instance
package/dist/index.d.ts CHANGED
@@ -479,6 +479,7 @@ interface TesterThread {
479
479
  createdAt: string;
480
480
  unreadCount: number;
481
481
  lastMessage?: TesterMessage;
482
+ reporterName?: string;
482
483
  }
483
484
  interface TesterMessage {
484
485
  id: string;
@@ -1102,6 +1103,12 @@ declare class BugBearClient {
1102
1103
  private initialized;
1103
1104
  /** Initialization error, if any. */
1104
1105
  private initError;
1106
+ /** Active presence session ID (passive time tracking). */
1107
+ private _presenceSessionId;
1108
+ /** Heartbeat interval for presence tracking. */
1109
+ private _presenceInterval;
1110
+ /** Whether presence is paused (tab hidden / app backgrounded). */
1111
+ private _presencePaused;
1105
1112
  constructor(config: BugBearConfig);
1106
1113
  /** Whether the client is ready for requests. */
1107
1114
  get isReady(): boolean;
@@ -1561,6 +1568,22 @@ declare class BugBearClient {
1561
1568
  * Transform database finding to QAFinding type
1562
1569
  */
1563
1570
  private transformFinding;
1571
+ /** Current presence session ID (null if not tracking). */
1572
+ get presenceSessionId(): string | null;
1573
+ /**
1574
+ * Start passive presence tracking for this tester.
1575
+ * Idempotent — reuses an existing active session if one exists.
1576
+ */
1577
+ startPresence(platform: 'web' | 'ios' | 'android'): Promise<string | null>;
1578
+ /** Gracefully end the current presence session. */
1579
+ endPresence(): Promise<void>;
1580
+ /** Pause heartbeat (tab hidden / app backgrounded). Sends one final beat. */
1581
+ pausePresence(): void;
1582
+ /** Resume heartbeat after pause. Restarts if session was cleaned up. */
1583
+ resumePresence(): Promise<void>;
1584
+ private heartbeatPresence;
1585
+ private startPresenceHeartbeat;
1586
+ private stopPresenceHeartbeat;
1564
1587
  }
1565
1588
  /**
1566
1589
  * Create a BugBear client instance
package/dist/index.js CHANGED
@@ -914,6 +914,12 @@ var BugBearClient = class {
914
914
  this.initialized = false;
915
915
  /** Initialization error, if any. */
916
916
  this.initError = null;
917
+ /** Active presence session ID (passive time tracking). */
918
+ this._presenceSessionId = null;
919
+ /** Heartbeat interval for presence tracking. */
920
+ this._presenceInterval = null;
921
+ /** Whether presence is paused (tab hidden / app backgrounded). */
922
+ this._presencePaused = false;
917
923
  this.config = config;
918
924
  if (config.apiKey) {
919
925
  this.pendingInit = this.resolveFromApiKey(config.apiKey);
@@ -2559,6 +2565,7 @@ var BugBearClient = class {
2559
2565
  lastMessageAt: row.last_message_at,
2560
2566
  createdAt: row.created_at,
2561
2567
  unreadCount: Number(row.unread_count) || 0,
2568
+ reporterName: row.reporter_name || void 0,
2562
2569
  lastMessage: row.last_message_preview ? {
2563
2570
  id: "",
2564
2571
  threadId: row.thread_id,
@@ -2998,6 +3005,93 @@ var BugBearClient = class {
2998
3005
  updatedAt: data.updated_at
2999
3006
  };
3000
3007
  }
3008
+ // ─── Passive Presence Tracking ──────────────────────────────
3009
+ /** Current presence session ID (null if not tracking). */
3010
+ get presenceSessionId() {
3011
+ return this._presenceSessionId;
3012
+ }
3013
+ /**
3014
+ * Start passive presence tracking for this tester.
3015
+ * Idempotent — reuses an existing active session if one exists.
3016
+ */
3017
+ async startPresence(platform) {
3018
+ try {
3019
+ await this.ensureReady();
3020
+ const testerInfo = await this.getTesterInfo();
3021
+ if (!testerInfo) return null;
3022
+ const { data, error } = await this.supabase.rpc("upsert_tester_presence", {
3023
+ p_project_id: this.config.projectId,
3024
+ p_tester_id: testerInfo.id,
3025
+ p_platform: platform
3026
+ });
3027
+ if (error) {
3028
+ console.error("BugBear: Failed to start presence", formatPgError(error));
3029
+ return null;
3030
+ }
3031
+ this._presenceSessionId = data;
3032
+ this._presencePaused = false;
3033
+ this.startPresenceHeartbeat();
3034
+ return data;
3035
+ } catch (err) {
3036
+ console.error("BugBear: Error starting presence", err);
3037
+ return null;
3038
+ }
3039
+ }
3040
+ /** Gracefully end the current presence session. */
3041
+ async endPresence() {
3042
+ this.stopPresenceHeartbeat();
3043
+ if (!this._presenceSessionId) return;
3044
+ try {
3045
+ await this.supabase.rpc("end_tester_presence", {
3046
+ p_session_id: this._presenceSessionId
3047
+ });
3048
+ } catch {
3049
+ }
3050
+ this._presenceSessionId = null;
3051
+ }
3052
+ /** Pause heartbeat (tab hidden / app backgrounded). Sends one final beat. */
3053
+ pausePresence() {
3054
+ this._presencePaused = true;
3055
+ this.heartbeatPresence();
3056
+ }
3057
+ /** Resume heartbeat after pause. Restarts if session was cleaned up. */
3058
+ async resumePresence() {
3059
+ if (!this._presenceSessionId) return;
3060
+ this._presencePaused = false;
3061
+ try {
3062
+ const { data } = await this.supabase.rpc("heartbeat_tester_presence", {
3063
+ p_session_id: this._presenceSessionId
3064
+ });
3065
+ if (!data) {
3066
+ this._presenceSessionId = null;
3067
+ }
3068
+ } catch {
3069
+ this._presenceSessionId = null;
3070
+ }
3071
+ }
3072
+ async heartbeatPresence() {
3073
+ if (!this._presenceSessionId || this._presencePaused) return;
3074
+ try {
3075
+ const { data, error } = await this.supabase.rpc("heartbeat_tester_presence", {
3076
+ p_session_id: this._presenceSessionId
3077
+ });
3078
+ if (error || data === false) {
3079
+ this.stopPresenceHeartbeat();
3080
+ this._presenceSessionId = null;
3081
+ }
3082
+ } catch {
3083
+ }
3084
+ }
3085
+ startPresenceHeartbeat() {
3086
+ this.stopPresenceHeartbeat();
3087
+ this._presenceInterval = setInterval(() => this.heartbeatPresence(), 6e4);
3088
+ }
3089
+ stopPresenceHeartbeat() {
3090
+ if (this._presenceInterval) {
3091
+ clearInterval(this._presenceInterval);
3092
+ this._presenceInterval = null;
3093
+ }
3094
+ }
3001
3095
  };
3002
3096
  function createBugBear(config) {
3003
3097
  return new BugBearClient(config);
package/dist/index.mjs CHANGED
@@ -868,6 +868,12 @@ var BugBearClient = class {
868
868
  this.initialized = false;
869
869
  /** Initialization error, if any. */
870
870
  this.initError = null;
871
+ /** Active presence session ID (passive time tracking). */
872
+ this._presenceSessionId = null;
873
+ /** Heartbeat interval for presence tracking. */
874
+ this._presenceInterval = null;
875
+ /** Whether presence is paused (tab hidden / app backgrounded). */
876
+ this._presencePaused = false;
871
877
  this.config = config;
872
878
  if (config.apiKey) {
873
879
  this.pendingInit = this.resolveFromApiKey(config.apiKey);
@@ -2513,6 +2519,7 @@ var BugBearClient = class {
2513
2519
  lastMessageAt: row.last_message_at,
2514
2520
  createdAt: row.created_at,
2515
2521
  unreadCount: Number(row.unread_count) || 0,
2522
+ reporterName: row.reporter_name || void 0,
2516
2523
  lastMessage: row.last_message_preview ? {
2517
2524
  id: "",
2518
2525
  threadId: row.thread_id,
@@ -2952,6 +2959,93 @@ var BugBearClient = class {
2952
2959
  updatedAt: data.updated_at
2953
2960
  };
2954
2961
  }
2962
+ // ─── Passive Presence Tracking ──────────────────────────────
2963
+ /** Current presence session ID (null if not tracking). */
2964
+ get presenceSessionId() {
2965
+ return this._presenceSessionId;
2966
+ }
2967
+ /**
2968
+ * Start passive presence tracking for this tester.
2969
+ * Idempotent — reuses an existing active session if one exists.
2970
+ */
2971
+ async startPresence(platform) {
2972
+ try {
2973
+ await this.ensureReady();
2974
+ const testerInfo = await this.getTesterInfo();
2975
+ if (!testerInfo) return null;
2976
+ const { data, error } = await this.supabase.rpc("upsert_tester_presence", {
2977
+ p_project_id: this.config.projectId,
2978
+ p_tester_id: testerInfo.id,
2979
+ p_platform: platform
2980
+ });
2981
+ if (error) {
2982
+ console.error("BugBear: Failed to start presence", formatPgError(error));
2983
+ return null;
2984
+ }
2985
+ this._presenceSessionId = data;
2986
+ this._presencePaused = false;
2987
+ this.startPresenceHeartbeat();
2988
+ return data;
2989
+ } catch (err) {
2990
+ console.error("BugBear: Error starting presence", err);
2991
+ return null;
2992
+ }
2993
+ }
2994
+ /** Gracefully end the current presence session. */
2995
+ async endPresence() {
2996
+ this.stopPresenceHeartbeat();
2997
+ if (!this._presenceSessionId) return;
2998
+ try {
2999
+ await this.supabase.rpc("end_tester_presence", {
3000
+ p_session_id: this._presenceSessionId
3001
+ });
3002
+ } catch {
3003
+ }
3004
+ this._presenceSessionId = null;
3005
+ }
3006
+ /** Pause heartbeat (tab hidden / app backgrounded). Sends one final beat. */
3007
+ pausePresence() {
3008
+ this._presencePaused = true;
3009
+ this.heartbeatPresence();
3010
+ }
3011
+ /** Resume heartbeat after pause. Restarts if session was cleaned up. */
3012
+ async resumePresence() {
3013
+ if (!this._presenceSessionId) return;
3014
+ this._presencePaused = false;
3015
+ try {
3016
+ const { data } = await this.supabase.rpc("heartbeat_tester_presence", {
3017
+ p_session_id: this._presenceSessionId
3018
+ });
3019
+ if (!data) {
3020
+ this._presenceSessionId = null;
3021
+ }
3022
+ } catch {
3023
+ this._presenceSessionId = null;
3024
+ }
3025
+ }
3026
+ async heartbeatPresence() {
3027
+ if (!this._presenceSessionId || this._presencePaused) return;
3028
+ try {
3029
+ const { data, error } = await this.supabase.rpc("heartbeat_tester_presence", {
3030
+ p_session_id: this._presenceSessionId
3031
+ });
3032
+ if (error || data === false) {
3033
+ this.stopPresenceHeartbeat();
3034
+ this._presenceSessionId = null;
3035
+ }
3036
+ } catch {
3037
+ }
3038
+ }
3039
+ startPresenceHeartbeat() {
3040
+ this.stopPresenceHeartbeat();
3041
+ this._presenceInterval = setInterval(() => this.heartbeatPresence(), 6e4);
3042
+ }
3043
+ stopPresenceHeartbeat() {
3044
+ if (this._presenceInterval) {
3045
+ clearInterval(this._presenceInterval);
3046
+ this._presenceInterval = null;
3047
+ }
3048
+ }
2955
3049
  };
2956
3050
  function createBugBear(config) {
2957
3051
  return new BugBearClient(config);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bbearai/core",
3
- "version": "0.7.2",
3
+ "version": "0.8.0",
4
4
  "description": "Core utilities and types for BugBear QA platform",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",