@bbearai/core 0.5.0 → 0.5.2
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 +10 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +62 -16
- package/dist/index.mjs +62 -16
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -252,6 +252,8 @@ interface TestAssignment {
|
|
|
252
252
|
group?: TestGroup;
|
|
253
253
|
/** Required app role for testing (e.g., Owner, Manager) */
|
|
254
254
|
role?: ProjectRole;
|
|
255
|
+
/** Platforms this test applies to (e.g., ['ios', 'web']) */
|
|
256
|
+
platforms?: string[];
|
|
255
257
|
};
|
|
256
258
|
status: 'pending' | 'in_progress' | 'passed' | 'failed' | 'blocked' | 'skipped';
|
|
257
259
|
/** Reason for skipping (when status is 'skipped') */
|
|
@@ -881,6 +883,14 @@ declare class BugBearClient {
|
|
|
881
883
|
error?: string;
|
|
882
884
|
durationSeconds?: number;
|
|
883
885
|
}>;
|
|
886
|
+
/**
|
|
887
|
+
* Reopen a completed assignment — sets it back to in_progress with a fresh timer.
|
|
888
|
+
* Clears completed_at and duration_seconds so it can be re-evaluated.
|
|
889
|
+
*/
|
|
890
|
+
reopenAssignment(assignmentId: string): Promise<{
|
|
891
|
+
success: boolean;
|
|
892
|
+
error?: string;
|
|
893
|
+
}>;
|
|
884
894
|
/**
|
|
885
895
|
* Skip a test assignment with a required reason
|
|
886
896
|
* Marks the assignment as 'skipped' and records why it was skipped
|
package/dist/index.d.ts
CHANGED
|
@@ -252,6 +252,8 @@ interface TestAssignment {
|
|
|
252
252
|
group?: TestGroup;
|
|
253
253
|
/** Required app role for testing (e.g., Owner, Manager) */
|
|
254
254
|
role?: ProjectRole;
|
|
255
|
+
/** Platforms this test applies to (e.g., ['ios', 'web']) */
|
|
256
|
+
platforms?: string[];
|
|
255
257
|
};
|
|
256
258
|
status: 'pending' | 'in_progress' | 'passed' | 'failed' | 'blocked' | 'skipped';
|
|
257
259
|
/** Reason for skipping (when status is 'skipped') */
|
|
@@ -881,6 +883,14 @@ declare class BugBearClient {
|
|
|
881
883
|
error?: string;
|
|
882
884
|
durationSeconds?: number;
|
|
883
885
|
}>;
|
|
886
|
+
/**
|
|
887
|
+
* Reopen a completed assignment — sets it back to in_progress with a fresh timer.
|
|
888
|
+
* Clears completed_at and duration_seconds so it can be re-evaluated.
|
|
889
|
+
*/
|
|
890
|
+
reopenAssignment(assignmentId: string): Promise<{
|
|
891
|
+
success: boolean;
|
|
892
|
+
error?: string;
|
|
893
|
+
}>;
|
|
884
894
|
/**
|
|
885
895
|
* Skip a test assignment with a required reason
|
|
886
896
|
* Marks the assignment as 'skipped' and records why it was skipped
|
package/dist/index.js
CHANGED
|
@@ -661,8 +661,8 @@ var BugBearClient = class {
|
|
|
661
661
|
return { success: false, error: rateLimit.error };
|
|
662
662
|
}
|
|
663
663
|
if (!userInfo) {
|
|
664
|
-
console.error("BugBear: No user info available, cannot submit report");
|
|
665
|
-
return { success: false, error: "
|
|
664
|
+
console.error("BugBear: No user info available, cannot submit report. Ensure your BugBear config provides a getCurrentUser() callback that returns { id, email }.");
|
|
665
|
+
return { success: false, error: "Unable to identify user. Check that your app passes a getCurrentUser callback to BugBear config." };
|
|
666
666
|
}
|
|
667
667
|
const testerInfo = await this.getTesterInfo();
|
|
668
668
|
fullReport = {
|
|
@@ -725,10 +725,11 @@ var BugBearClient = class {
|
|
|
725
725
|
const pageSize = Math.min(options?.pageSize ?? 100, 100);
|
|
726
726
|
const from = (options?.page ?? 0) * pageSize;
|
|
727
727
|
const to = from + pageSize - 1;
|
|
728
|
-
const
|
|
728
|
+
const selectFields = `
|
|
729
729
|
id,
|
|
730
730
|
status,
|
|
731
731
|
started_at,
|
|
732
|
+
completed_at,
|
|
732
733
|
skip_reason,
|
|
733
734
|
is_verification,
|
|
734
735
|
original_report_id,
|
|
@@ -763,20 +764,23 @@ var BugBearClient = class {
|
|
|
763
764
|
color,
|
|
764
765
|
description,
|
|
765
766
|
login_hint
|
|
766
|
-
)
|
|
767
|
+
),
|
|
768
|
+
platforms
|
|
767
769
|
)
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
770
|
+
`;
|
|
771
|
+
const [pendingResult, completedResult] = await Promise.all([
|
|
772
|
+
this.supabase.from("test_assignments").select(selectFields).eq("project_id", this.config.projectId).eq("tester_id", testerInfo.id).in("status", ["pending", "in_progress"]).order("created_at", { ascending: true }).range(from, to),
|
|
773
|
+
this.supabase.from("test_assignments").select(selectFields).eq("project_id", this.config.projectId).eq("tester_id", testerInfo.id).in("status", ["passed", "failed", "skipped", "blocked"]).order("completed_at", { ascending: false }).limit(100)
|
|
774
|
+
]);
|
|
775
|
+
if (pendingResult.error) {
|
|
776
|
+
console.error("BugBear: Failed to fetch assignments", formatPgError(pendingResult.error));
|
|
771
777
|
return [];
|
|
772
778
|
}
|
|
773
|
-
const
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
return true;
|
|
779
|
-
}).map((item) => ({
|
|
779
|
+
const allData = [
|
|
780
|
+
...pendingResult.data || [],
|
|
781
|
+
...completedResult.data || []
|
|
782
|
+
];
|
|
783
|
+
const mapItem = (item) => ({
|
|
780
784
|
id: item.id,
|
|
781
785
|
status: item.status,
|
|
782
786
|
startedAt: item.started_at,
|
|
@@ -814,12 +818,24 @@ var BugBearClient = class {
|
|
|
814
818
|
color: item.test_case.role.color,
|
|
815
819
|
description: item.test_case.role.description,
|
|
816
820
|
loginHint: item.test_case.role.login_hint
|
|
817
|
-
} : void 0
|
|
821
|
+
} : void 0,
|
|
822
|
+
platforms: item.test_case.platforms || void 0
|
|
818
823
|
}
|
|
819
|
-
})
|
|
824
|
+
});
|
|
825
|
+
const mapped = allData.filter((item) => {
|
|
826
|
+
if (!item.test_case) {
|
|
827
|
+
console.warn("BugBear: Assignment returned without test_case", { id: item.id });
|
|
828
|
+
return false;
|
|
829
|
+
}
|
|
830
|
+
return true;
|
|
831
|
+
}).map(mapItem);
|
|
820
832
|
mapped.sort((a, b) => {
|
|
821
833
|
if (a.isVerification && !b.isVerification) return -1;
|
|
822
834
|
if (!a.isVerification && b.isVerification) return 1;
|
|
835
|
+
const aActive = a.status === "pending" || a.status === "in_progress";
|
|
836
|
+
const bActive = b.status === "pending" || b.status === "in_progress";
|
|
837
|
+
if (aActive && !bActive) return -1;
|
|
838
|
+
if (!aActive && bActive) return 1;
|
|
823
839
|
return 0;
|
|
824
840
|
});
|
|
825
841
|
return mapped;
|
|
@@ -984,6 +1000,36 @@ var BugBearClient = class {
|
|
|
984
1000
|
async failAssignment(assignmentId) {
|
|
985
1001
|
return this.updateAssignmentStatus(assignmentId, "failed");
|
|
986
1002
|
}
|
|
1003
|
+
/**
|
|
1004
|
+
* Reopen a completed assignment — sets it back to in_progress with a fresh timer.
|
|
1005
|
+
* Clears completed_at and duration_seconds so it can be re-evaluated.
|
|
1006
|
+
*/
|
|
1007
|
+
async reopenAssignment(assignmentId) {
|
|
1008
|
+
try {
|
|
1009
|
+
const { data: current, error: fetchError } = await this.supabase.from("test_assignments").select("status").eq("id", assignmentId).single();
|
|
1010
|
+
if (fetchError || !current) {
|
|
1011
|
+
return { success: false, error: "Assignment not found" };
|
|
1012
|
+
}
|
|
1013
|
+
if (current.status === "pending" || current.status === "in_progress") {
|
|
1014
|
+
return { success: true };
|
|
1015
|
+
}
|
|
1016
|
+
const { error } = await this.supabase.from("test_assignments").update({
|
|
1017
|
+
status: "in_progress",
|
|
1018
|
+
started_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1019
|
+
completed_at: null,
|
|
1020
|
+
duration_seconds: null,
|
|
1021
|
+
skip_reason: null
|
|
1022
|
+
}).eq("id", assignmentId).eq("status", current.status);
|
|
1023
|
+
if (error) {
|
|
1024
|
+
console.error("BugBear: Failed to reopen assignment", error);
|
|
1025
|
+
return { success: false, error: error.message };
|
|
1026
|
+
}
|
|
1027
|
+
return { success: true };
|
|
1028
|
+
} catch (err) {
|
|
1029
|
+
const message = err instanceof Error ? err.message : "Unknown error";
|
|
1030
|
+
return { success: false, error: message };
|
|
1031
|
+
}
|
|
1032
|
+
}
|
|
987
1033
|
/**
|
|
988
1034
|
* Skip a test assignment with a required reason
|
|
989
1035
|
* Marks the assignment as 'skipped' and records why it was skipped
|
package/dist/index.mjs
CHANGED
|
@@ -627,8 +627,8 @@ var BugBearClient = class {
|
|
|
627
627
|
return { success: false, error: rateLimit.error };
|
|
628
628
|
}
|
|
629
629
|
if (!userInfo) {
|
|
630
|
-
console.error("BugBear: No user info available, cannot submit report");
|
|
631
|
-
return { success: false, error: "
|
|
630
|
+
console.error("BugBear: No user info available, cannot submit report. Ensure your BugBear config provides a getCurrentUser() callback that returns { id, email }.");
|
|
631
|
+
return { success: false, error: "Unable to identify user. Check that your app passes a getCurrentUser callback to BugBear config." };
|
|
632
632
|
}
|
|
633
633
|
const testerInfo = await this.getTesterInfo();
|
|
634
634
|
fullReport = {
|
|
@@ -691,10 +691,11 @@ var BugBearClient = class {
|
|
|
691
691
|
const pageSize = Math.min(options?.pageSize ?? 100, 100);
|
|
692
692
|
const from = (options?.page ?? 0) * pageSize;
|
|
693
693
|
const to = from + pageSize - 1;
|
|
694
|
-
const
|
|
694
|
+
const selectFields = `
|
|
695
695
|
id,
|
|
696
696
|
status,
|
|
697
697
|
started_at,
|
|
698
|
+
completed_at,
|
|
698
699
|
skip_reason,
|
|
699
700
|
is_verification,
|
|
700
701
|
original_report_id,
|
|
@@ -729,20 +730,23 @@ var BugBearClient = class {
|
|
|
729
730
|
color,
|
|
730
731
|
description,
|
|
731
732
|
login_hint
|
|
732
|
-
)
|
|
733
|
+
),
|
|
734
|
+
platforms
|
|
733
735
|
)
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
736
|
+
`;
|
|
737
|
+
const [pendingResult, completedResult] = await Promise.all([
|
|
738
|
+
this.supabase.from("test_assignments").select(selectFields).eq("project_id", this.config.projectId).eq("tester_id", testerInfo.id).in("status", ["pending", "in_progress"]).order("created_at", { ascending: true }).range(from, to),
|
|
739
|
+
this.supabase.from("test_assignments").select(selectFields).eq("project_id", this.config.projectId).eq("tester_id", testerInfo.id).in("status", ["passed", "failed", "skipped", "blocked"]).order("completed_at", { ascending: false }).limit(100)
|
|
740
|
+
]);
|
|
741
|
+
if (pendingResult.error) {
|
|
742
|
+
console.error("BugBear: Failed to fetch assignments", formatPgError(pendingResult.error));
|
|
737
743
|
return [];
|
|
738
744
|
}
|
|
739
|
-
const
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
return true;
|
|
745
|
-
}).map((item) => ({
|
|
745
|
+
const allData = [
|
|
746
|
+
...pendingResult.data || [],
|
|
747
|
+
...completedResult.data || []
|
|
748
|
+
];
|
|
749
|
+
const mapItem = (item) => ({
|
|
746
750
|
id: item.id,
|
|
747
751
|
status: item.status,
|
|
748
752
|
startedAt: item.started_at,
|
|
@@ -780,12 +784,24 @@ var BugBearClient = class {
|
|
|
780
784
|
color: item.test_case.role.color,
|
|
781
785
|
description: item.test_case.role.description,
|
|
782
786
|
loginHint: item.test_case.role.login_hint
|
|
783
|
-
} : void 0
|
|
787
|
+
} : void 0,
|
|
788
|
+
platforms: item.test_case.platforms || void 0
|
|
784
789
|
}
|
|
785
|
-
})
|
|
790
|
+
});
|
|
791
|
+
const mapped = allData.filter((item) => {
|
|
792
|
+
if (!item.test_case) {
|
|
793
|
+
console.warn("BugBear: Assignment returned without test_case", { id: item.id });
|
|
794
|
+
return false;
|
|
795
|
+
}
|
|
796
|
+
return true;
|
|
797
|
+
}).map(mapItem);
|
|
786
798
|
mapped.sort((a, b) => {
|
|
787
799
|
if (a.isVerification && !b.isVerification) return -1;
|
|
788
800
|
if (!a.isVerification && b.isVerification) return 1;
|
|
801
|
+
const aActive = a.status === "pending" || a.status === "in_progress";
|
|
802
|
+
const bActive = b.status === "pending" || b.status === "in_progress";
|
|
803
|
+
if (aActive && !bActive) return -1;
|
|
804
|
+
if (!aActive && bActive) return 1;
|
|
789
805
|
return 0;
|
|
790
806
|
});
|
|
791
807
|
return mapped;
|
|
@@ -950,6 +966,36 @@ var BugBearClient = class {
|
|
|
950
966
|
async failAssignment(assignmentId) {
|
|
951
967
|
return this.updateAssignmentStatus(assignmentId, "failed");
|
|
952
968
|
}
|
|
969
|
+
/**
|
|
970
|
+
* Reopen a completed assignment — sets it back to in_progress with a fresh timer.
|
|
971
|
+
* Clears completed_at and duration_seconds so it can be re-evaluated.
|
|
972
|
+
*/
|
|
973
|
+
async reopenAssignment(assignmentId) {
|
|
974
|
+
try {
|
|
975
|
+
const { data: current, error: fetchError } = await this.supabase.from("test_assignments").select("status").eq("id", assignmentId).single();
|
|
976
|
+
if (fetchError || !current) {
|
|
977
|
+
return { success: false, error: "Assignment not found" };
|
|
978
|
+
}
|
|
979
|
+
if (current.status === "pending" || current.status === "in_progress") {
|
|
980
|
+
return { success: true };
|
|
981
|
+
}
|
|
982
|
+
const { error } = await this.supabase.from("test_assignments").update({
|
|
983
|
+
status: "in_progress",
|
|
984
|
+
started_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
985
|
+
completed_at: null,
|
|
986
|
+
duration_seconds: null,
|
|
987
|
+
skip_reason: null
|
|
988
|
+
}).eq("id", assignmentId).eq("status", current.status);
|
|
989
|
+
if (error) {
|
|
990
|
+
console.error("BugBear: Failed to reopen assignment", error);
|
|
991
|
+
return { success: false, error: error.message };
|
|
992
|
+
}
|
|
993
|
+
return { success: true };
|
|
994
|
+
} catch (err) {
|
|
995
|
+
const message = err instanceof Error ? err.message : "Unknown error";
|
|
996
|
+
return { success: false, error: message };
|
|
997
|
+
}
|
|
998
|
+
}
|
|
953
999
|
/**
|
|
954
1000
|
* Skip a test assignment with a required reason
|
|
955
1001
|
* Marks the assignment as 'skipped' and records why it was skipped
|