qapture2 0.8.0 → 0.8.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.
- package/README.md +6 -0
- package/dist/bin/init.cjs +1 -1
- package/dist/{chunk-RJV6FTIB.js → chunk-32LKZ2PG.js} +291 -30
- package/dist/{chunk-E7OFH6EM.cjs → chunk-OSYYMS6R.cjs} +291 -30
- package/dist/index.cjs +5 -5
- package/dist/index.js +1 -1
- package/dist/next.cjs +4 -4
- package/dist/next.js +1 -1
- package/dist/standalone.cjs +2 -2
- package/dist/standalone.js +1 -1
- package/package.json +1 -1
|
@@ -1732,11 +1732,15 @@ var STR = {
|
|
|
1732
1732
|
sel_region: "Region selected",
|
|
1733
1733
|
sel_element: "Element selected",
|
|
1734
1734
|
capturing: "capturing screenshot\u2026",
|
|
1735
|
+
too_heavy: "This page is too big to redraw \u2014 the tab would freeze. Photograph it instead: one frame, and maps and charts come out right.",
|
|
1735
1736
|
no_shot: "no screenshot (location saved)",
|
|
1736
1737
|
annotate_placeholder: "What do you want to do here? (add / remove / change\u2026)",
|
|
1737
1738
|
save_point: "Save point",
|
|
1739
|
+
save_next: "Save + next",
|
|
1740
|
+
save_next_hint: "Save this one and mark up another part of the same screenshot \u2014 no second permission prompt.",
|
|
1741
|
+
shot_reused: "{n} saved from this screenshot",
|
|
1738
1742
|
reselect: "Reselect",
|
|
1739
|
-
save_hint: "\u2318/Ctrl + Enter to save",
|
|
1743
|
+
save_hint: "\u2318/Ctrl + Enter to save \xB7 add Shift to keep the same screenshot",
|
|
1740
1744
|
login_with: "Log in with {field} + password.",
|
|
1741
1745
|
used_count: "{n}/{m} used",
|
|
1742
1746
|
used: "used",
|
|
@@ -1772,6 +1776,9 @@ var STR = {
|
|
|
1772
1776
|
sev_design: "Design",
|
|
1773
1777
|
sev_enhance: "Enhance",
|
|
1774
1778
|
status_open: "Open",
|
|
1779
|
+
status_sent: "Sent",
|
|
1780
|
+
check_fixes: "Check the {n} fixes",
|
|
1781
|
+
check_fixes_hint: "Walk back through everything the last export sent, one spot at a time, and say whether each is now what you asked for.",
|
|
1775
1782
|
status_verified: "Verified",
|
|
1776
1783
|
context_attached: "{n} runtime events attached",
|
|
1777
1784
|
start_walkthrough: "Start walkthrough",
|
|
@@ -1940,11 +1947,15 @@ var STR = {
|
|
|
1940
1947
|
sel_region: "\u062A\u0645 \u062A\u062D\u062F\u064A\u062F \u0645\u0646\u0637\u0642\u0629",
|
|
1941
1948
|
sel_element: "\u062A\u0645 \u062A\u062D\u062F\u064A\u062F \u0639\u0646\u0635\u0631",
|
|
1942
1949
|
capturing: "\u064A\u062A\u0645 \u0627\u0644\u062A\u0642\u0627\u0637 \u0627\u0644\u0635\u0648\u0631\u0629\u2026",
|
|
1950
|
+
too_heavy: "\u0647\u0630\u0647 \u0627\u0644\u0635\u0641\u062D\u0629 \u0623\u0643\u0628\u0631 \u0645\u0646 \u0623\u0646 \u064A\u064F\u0639\u0627\u062F \u0631\u0633\u0645\u0647\u0627 \u2014 \u0633\u064A\u062A\u062C\u0645\u0651\u062F \u0627\u0644\u062A\u0628\u0648\u064A\u0628. \u0635\u0648\u0651\u0631\u0647\u0627 \u0628\u062F\u0644 \u0630\u0644\u0643: \u0625\u0637\u0627\u0631 \u0648\u0627\u062D\u062F\u060C \u0648\u062A\u0638\u0647\u0631 \u0627\u0644\u062E\u0631\u0627\u0626\u0637 \u0648\u0627\u0644\u0631\u0633\u0648\u0645 \u0643\u0645\u0627 \u0647\u064A.",
|
|
1943
1951
|
no_shot: "\u0628\u062F\u0648\u0646 \u0635\u0648\u0631\u0629 (\u062A\u0645 \u062D\u0641\u0638 \u0627\u0644\u0645\u0648\u0642\u0639)",
|
|
1944
1952
|
annotate_placeholder: "\u0645\u0627\u0630\u0627 \u062A\u0631\u064A\u062F \u0623\u0646 \u062A\u0641\u0639\u0644 \u0647\u0646\u0627\u061F (\u0625\u0636\u0627\u0641\u0629 / \u062D\u0630\u0641 / \u062A\u063A\u064A\u064A\u0631\u2026)",
|
|
1945
1953
|
save_point: "\u062D\u0641\u0638 \u0627\u0644\u0646\u0642\u0637\u0629",
|
|
1954
|
+
save_next: "\u062D\u0641\u0638 + \u0627\u0644\u062A\u0627\u0644\u064A",
|
|
1955
|
+
save_next_hint: "\u0627\u062D\u0641\u0638 \u0647\u0630\u0647 \u0648\u062D\u062F\u0651\u062F \u062C\u0632\u0621\u064B\u0627 \u0622\u062E\u0631 \u0645\u0646 \u0646\u0641\u0633 \u0627\u0644\u0644\u0642\u0637\u0629 \u2014 \u0628\u062F\u0648\u0646 \u0637\u0644\u0628 \u0625\u0630\u0646 \u062C\u062F\u064A\u062F.",
|
|
1956
|
+
shot_reused: "\u062D\u064F\u0641\u0638\u062A {n} \u0645\u0646 \u0647\u0630\u0647 \u0627\u0644\u0644\u0642\u0637\u0629",
|
|
1946
1957
|
reselect: "\u0625\u0639\u0627\u062F\u0629 \u0627\u0644\u062A\u062D\u062F\u064A\u062F",
|
|
1947
|
-
save_hint: "\u2318/Ctrl + Enter \u0644\u0644\u062D\u0641\u0638",
|
|
1958
|
+
save_hint: "\u2318/Ctrl + Enter \u0644\u0644\u062D\u0641\u0638 \xB7 \u0623\u0636\u0641 Shift \u0644\u0644\u0628\u0642\u0627\u0621 \u0639\u0644\u0649 \u0646\u0641\u0633 \u0627\u0644\u0644\u0642\u0637\u0629",
|
|
1948
1959
|
login_with: "\u0633\u062C\u0651\u0644 \u0627\u0644\u062F\u062E\u0648\u0644 \u0628\u0640 {field} + \u0643\u0644\u0645\u0629 \u0627\u0644\u0645\u0631\u0648\u0631.",
|
|
1949
1960
|
used_count: "{n}/{m} \u0645\u064F\u0633\u062A\u062E\u062F\u064E\u0645",
|
|
1950
1961
|
used: "\u0645\u064F\u0633\u062A\u062E\u062F\u064E\u0645",
|
|
@@ -1980,6 +1991,9 @@ var STR = {
|
|
|
1980
1991
|
sev_design: "Design",
|
|
1981
1992
|
sev_enhance: "Enhance",
|
|
1982
1993
|
status_open: "\u0645\u0641\u062A\u0648\u062D",
|
|
1994
|
+
status_sent: "\u0645\u064F\u0631\u0633\u064E\u0644",
|
|
1995
|
+
check_fixes: "\u062A\u062D\u0642\u0651\u0642 \u0645\u0646 {n} \u062A\u0639\u062F\u064A\u0644\u0627\u062A",
|
|
1996
|
+
check_fixes_hint: "\u0645\u0631\u0651 \u0639\u0644\u0649 \u0643\u0644 \u0645\u0627 \u0623\u0631\u0633\u0644\u0647 \u0627\u0644\u062A\u0635\u062F\u064A\u0631 \u0627\u0644\u0623\u062E\u064A\u0631\u060C \u0646\u0642\u0637\u0629 \u0646\u0642\u0637\u0629\u060C \u0648\u0642\u0644 \u0647\u0644 \u0635\u0627\u0631 \u0643\u0645\u0627 \u0637\u0644\u0628\u062A \u0623\u0645 \u0644\u0627.",
|
|
1983
1997
|
status_verified: "\u062A\u0645 \u0627\u0644\u062A\u062D\u0642\u0642",
|
|
1984
1998
|
context_attached: "{n} \u0645\u0646 \u0623\u062D\u062F\u0627\u062B \u0627\u0644\u062A\u0634\u063A\u064A\u0644 \u0645\u0631\u0641\u0642\u0629",
|
|
1985
1999
|
start_walkthrough: "\u0627\u0628\u062F\u0623 \u0627\u0644\u062C\u0648\u0644\u0629",
|
|
@@ -2376,6 +2390,25 @@ function getExactCaptureStatus() {
|
|
|
2376
2390
|
function getFrozenFrame() {
|
|
2377
2391
|
return frozen;
|
|
2378
2392
|
}
|
|
2393
|
+
var STILL_REUSE_MS = 9e4;
|
|
2394
|
+
var frozenAtScrollX = 0;
|
|
2395
|
+
var frozenAtScrollY = 0;
|
|
2396
|
+
var frozenAtPath = "";
|
|
2397
|
+
function stillIsCurrent() {
|
|
2398
|
+
if (!frozen) return false;
|
|
2399
|
+
if (typeof window === "undefined") return false;
|
|
2400
|
+
if (Date.now() - frozen.takenAt > STILL_REUSE_MS) return false;
|
|
2401
|
+
if (window.scrollX !== frozenAtScrollX || window.scrollY !== frozenAtScrollY) return false;
|
|
2402
|
+
if (window.location.pathname + window.location.search !== frozenAtPath) return false;
|
|
2403
|
+
const vw = document.documentElement.clientWidth || window.innerWidth;
|
|
2404
|
+
const vh = document.documentElement.clientHeight || window.innerHeight;
|
|
2405
|
+
if (vw !== frozen.viewportWidth || vh !== frozen.viewportHeight) return false;
|
|
2406
|
+
return true;
|
|
2407
|
+
}
|
|
2408
|
+
async function freezeOrReuse() {
|
|
2409
|
+
if (stillIsCurrent()) return frozen;
|
|
2410
|
+
return freezeViewport();
|
|
2411
|
+
}
|
|
2379
2412
|
function releaseFrozenFrame() {
|
|
2380
2413
|
if (frozen) {
|
|
2381
2414
|
frozen.canvas.width = 0;
|
|
@@ -2620,6 +2653,9 @@ async function freezeViewport() {
|
|
|
2620
2653
|
viewportHeight: vh,
|
|
2621
2654
|
takenAt: Date.now()
|
|
2622
2655
|
};
|
|
2656
|
+
frozenAtScrollX = window.scrollX;
|
|
2657
|
+
frozenAtScrollY = window.scrollY;
|
|
2658
|
+
frozenAtPath = window.location.pathname + window.location.search;
|
|
2623
2659
|
lastMode = mode;
|
|
2624
2660
|
return frozen;
|
|
2625
2661
|
} catch {
|
|
@@ -2793,12 +2829,21 @@ function neutralizeDocumentColors(doc, aggressive = false) {
|
|
|
2793
2829
|
|
|
2794
2830
|
// src/lib/capture.ts
|
|
2795
2831
|
var HTML2CANVAS_TIMEOUT_MS = 1e4;
|
|
2832
|
+
var CHUNK_TIMEOUT_MS = 8e3;
|
|
2796
2833
|
var FALLBACK_PAGE_BACKGROUND = "#ffffff";
|
|
2797
2834
|
var MAX_SHOT_EDGE = 1800;
|
|
2798
2835
|
var WEBP_QUALITY = 0.92;
|
|
2799
2836
|
var STUCK_ATTR = "data-qa-stuck";
|
|
2800
2837
|
var MAX_CAPTURE_EDGE = 4e3;
|
|
2801
2838
|
var MAX_RENDER_DEVICE_PIXELS = 16e6;
|
|
2839
|
+
var TOO_HEAVY_NODES = 6e3;
|
|
2840
|
+
function documentWeight() {
|
|
2841
|
+
try {
|
|
2842
|
+
return document.getElementsByTagName("*").length;
|
|
2843
|
+
} catch {
|
|
2844
|
+
return 0;
|
|
2845
|
+
}
|
|
2846
|
+
}
|
|
2802
2847
|
function withTimeout(promise, ms) {
|
|
2803
2848
|
let timer;
|
|
2804
2849
|
return Promise.race([
|
|
@@ -2860,8 +2905,13 @@ function fitToBudget(canvas) {
|
|
|
2860
2905
|
function canvasToBlob(canvas, type, quality) {
|
|
2861
2906
|
return new Promise((resolve) => {
|
|
2862
2907
|
if (canvas.toBlob) {
|
|
2863
|
-
|
|
2864
|
-
|
|
2908
|
+
try {
|
|
2909
|
+
canvas.toBlob((b) => resolve(b), type, quality);
|
|
2910
|
+
return;
|
|
2911
|
+
} catch {
|
|
2912
|
+
resolve(null);
|
|
2913
|
+
return;
|
|
2914
|
+
}
|
|
2865
2915
|
}
|
|
2866
2916
|
try {
|
|
2867
2917
|
const dataUrl = canvas.toDataURL(type, quality);
|
|
@@ -3048,7 +3098,9 @@ function planRender(rect, sx, sy, vw, vh) {
|
|
|
3048
3098
|
};
|
|
3049
3099
|
}
|
|
3050
3100
|
async function captureViaDom(rect, sx, sy, aggressiveColors = false) {
|
|
3051
|
-
const
|
|
3101
|
+
const mod = await withTimeout(import('html2canvas'), CHUNK_TIMEOUT_MS);
|
|
3102
|
+
if (!mod) return null;
|
|
3103
|
+
const { default: html2canvas } = mod;
|
|
3052
3104
|
const { vw, vh } = viewportSize();
|
|
3053
3105
|
const plan = planRender(rect, sx, sy, vw, vh);
|
|
3054
3106
|
let scale = Math.min(window.devicePixelRatio || 1, 2);
|
|
@@ -3067,7 +3119,22 @@ async function captureViaDom(rect, sx, sy, aggressiveColors = false) {
|
|
|
3067
3119
|
height: plan.render.height,
|
|
3068
3120
|
scale,
|
|
3069
3121
|
useCORS: true,
|
|
3070
|
-
allowTaint: true
|
|
3122
|
+
// MUST stay false. `allowTaint: true` tells html2canvas to draw
|
|
3123
|
+
// cross-origin images it could not fetch with CORS -- which succeeds,
|
|
3124
|
+
// and TAINTS the canvas. A tainted canvas throws SecurityError from
|
|
3125
|
+
// toBlob/toDataURL, so the render finishes and then the encode dies,
|
|
3126
|
+
// and the tester gets "couldn't capture" with nothing to look at.
|
|
3127
|
+
//
|
|
3128
|
+
// That is one image away on any real page: a map tile, a news
|
|
3129
|
+
// thumbnail, an avatar, an ad, a CDN logo. It made image-heavy pages
|
|
3130
|
+
// fail 100% of the time while a plain page worked, which is exactly
|
|
3131
|
+
// the "it works for you and not for me" this kept producing.
|
|
3132
|
+
//
|
|
3133
|
+
// False is strictly better: html2canvas SKIPS the images it cannot
|
|
3134
|
+
// read, so those come out blank and everything else comes out right.
|
|
3135
|
+
// A screenshot with two grey rectangles in it is worth having. A
|
|
3136
|
+
// SecurityError is not.
|
|
3137
|
+
allowTaint: false,
|
|
3071
3138
|
// The page's own background, never null — see resolvePageBackground().
|
|
3072
3139
|
// Passed straight to html2canvas's parser, so it gets the same
|
|
3073
3140
|
// CSS Color 4 treatment the document walk applies.
|
|
@@ -3116,6 +3183,10 @@ async function captureRegion(rect, scroll, prefer = "auto") {
|
|
|
3116
3183
|
}
|
|
3117
3184
|
if (prefer === "exact") return { status: "failed" };
|
|
3118
3185
|
}
|
|
3186
|
+
const weight = documentWeight();
|
|
3187
|
+
if (weight > TOO_HEAVY_NODES) {
|
|
3188
|
+
return { status: "too-heavy", nodes: weight };
|
|
3189
|
+
}
|
|
3119
3190
|
try {
|
|
3120
3191
|
const canvas = await captureViaDom(rect, sx, sy);
|
|
3121
3192
|
if (!canvas) return { status: "failed" };
|
|
@@ -3173,6 +3244,12 @@ function formatEvent(ev, t0) {
|
|
|
3173
3244
|
}
|
|
3174
3245
|
return `[${rel}] uncaught: ${oneLine(ev.message)}`;
|
|
3175
3246
|
}
|
|
3247
|
+
function noteCheckLine(note, index) {
|
|
3248
|
+
const where = oneLine(note.route) || "/";
|
|
3249
|
+
const what = oneLine(note.description) || "(no description)";
|
|
3250
|
+
const trimmed = what.length > 160 ? `${what.slice(0, 157)}...` : what;
|
|
3251
|
+
return `- [ ] **check-${index}** (\`${where}\`) \u2014 ${trimmed}`;
|
|
3252
|
+
}
|
|
3176
3253
|
function noteToMarkdown(note, opts) {
|
|
3177
3254
|
const brand = opts?.brand ?? "Qapture";
|
|
3178
3255
|
const idx = opts?.index;
|
|
@@ -3230,6 +3307,14 @@ function noteToMarkdown(note, opts) {
|
|
|
3230
3307
|
lines.push(`${i + 1}. ${formatStep(step, t0)}`);
|
|
3231
3308
|
});
|
|
3232
3309
|
}
|
|
3310
|
+
if (idx != null) {
|
|
3311
|
+
lines.push("");
|
|
3312
|
+
lines.push(`**Check ${idx} \u2014 how this will be graded**`);
|
|
3313
|
+
lines.push("");
|
|
3314
|
+
lines.push(`The tester will be taken back to \`${oneLine(note.route) || "/"}\`` + (target?.selector ? `, shown \`${oneLine(target.selector)}\`` : ", shown this region") + ", and asked: *is this now what I asked for?*");
|
|
3315
|
+
lines.push("");
|
|
3316
|
+
lines.push(`Treat it as done only when the paragraph above is true on that page, on a fresh load, without the tester doing anything extra. Record the outcome against \`check-${idx}\` in \`verify.md\`.`);
|
|
3317
|
+
}
|
|
3233
3318
|
const ctx = note.context;
|
|
3234
3319
|
if (ctx) {
|
|
3235
3320
|
const env = ctx.env;
|
|
@@ -3402,6 +3487,17 @@ Second, **the previous attempt is evidence.** Something about the first reading
|
|
|
3402
3487
|
The tag sets your starting posture; **the words win.** A point tagged Design that says "this crashes" is a bug \u2014 treat it as one, and mention that you changed lane. People pick the wrong chip all the time; that is not a reason to do the wrong work.
|
|
3403
3488
|
|
|
3404
3489
|
And if a point is phrased as a question rather than a report, **answer it \u2014 do not change code on a maybe.**`
|
|
3490
|
+
);
|
|
3491
|
+
sections.push(
|
|
3492
|
+
`## You Are Being Graded On This
|
|
3493
|
+
|
|
3494
|
+
This archive is not a list of suggestions. Every point in \`notes.md\` is an acceptance test, and \`verify.md\` is the checklist those tests live in \u2014 one unticked box per point.
|
|
3495
|
+
|
|
3496
|
+
**What happens next.** The tester will be walked back through these same checks on the real page, in this order, one stop at a time, and asked about each: *is this now what I asked for?* Anything they say is still wrong comes back to you as round two with their new words attached, so nothing quietly disappears.
|
|
3497
|
+
|
|
3498
|
+
**What to do.** Do the work, then fill in \`verify.md\`: tick a box only when the check is true on a fresh load of the page named beside it, with the tester doing nothing extra. Where you could not do something, or you think it is the wrong thing to do, leave the box unticked and write one line saying why. An unticked box with a reason is a good answer. A ticked box that does not hold up is the only bad one \u2014 it costs the tester the trip to find out.
|
|
3499
|
+
|
|
3500
|
+
Hand \`verify.md\` back with the work.`
|
|
3405
3501
|
);
|
|
3406
3502
|
const stack = typeof p.stack === "string" && p.stack.trim() ? p.stack.trim() : "(not provided)";
|
|
3407
3503
|
const runArr = toStrings(p.runCommands);
|
|
@@ -3549,6 +3645,39 @@ async function buildZipBlob(notes, stamp, config, guideChecked, guideSkipped) {
|
|
|
3549
3645
|
` : "";
|
|
3550
3646
|
const notesMd = preambleMd + "\n\n---NOTES---\n\n" + notesHeader + notesBody;
|
|
3551
3647
|
zip.file("notes.md", notesMd);
|
|
3648
|
+
zip.file("verify.md", [
|
|
3649
|
+
`# ${brandLabel} \u2014 checks to satisfy`,
|
|
3650
|
+
"",
|
|
3651
|
+
`Exported: ${stamp}`,
|
|
3652
|
+
`Checks: ${notes.length}`,
|
|
3653
|
+
"",
|
|
3654
|
+
"Each line below is one thing the tester asked for. The full ask, the",
|
|
3655
|
+
"screenshot, the page and the element are in `notes.md` under the matching",
|
|
3656
|
+
'"Point" heading.',
|
|
3657
|
+
"",
|
|
3658
|
+
"**What is expected of you**",
|
|
3659
|
+
"",
|
|
3660
|
+
"1. Do the work in `notes.md`.",
|
|
3661
|
+
"2. Tick a box here only when the check is true on a fresh load of the page",
|
|
3662
|
+
" named beside it, with the tester doing nothing extra.",
|
|
3663
|
+
"3. Leave a box unticked and write one line under it saying why, if you",
|
|
3664
|
+
" could not do it or disagree with it. An unticked box with a reason is a",
|
|
3665
|
+
" good answer; a ticked box that is not true is the only bad one.",
|
|
3666
|
+
"4. Hand this file back with the work.",
|
|
3667
|
+
"",
|
|
3668
|
+
"The tester will then be walked back through these same checks on the real",
|
|
3669
|
+
"page, in this order, and asked about each one. Anything they say is still",
|
|
3670
|
+
"wrong comes back to you as round two, with their new words attached.",
|
|
3671
|
+
"",
|
|
3672
|
+
"---",
|
|
3673
|
+
"",
|
|
3674
|
+
...notes.map((n, i) => noteCheckLine(n, i + 1)),
|
|
3675
|
+
"",
|
|
3676
|
+
"---",
|
|
3677
|
+
"",
|
|
3678
|
+
"Re-open the walkthrough on the tester's machine with `?qa=walk:verify`.",
|
|
3679
|
+
""
|
|
3680
|
+
].join("\n"));
|
|
3552
3681
|
notes.forEach((n, i) => {
|
|
3553
3682
|
if (n.screenshot && shots) {
|
|
3554
3683
|
shots.file(`point-${i + 1}.${shotExtension(n.screenshot)}`, n.screenshot);
|
|
@@ -4188,6 +4317,9 @@ var GUIDE_FAILED_KEY = "guideFailed";
|
|
|
4188
4317
|
var LOGIN_KEY = "logins";
|
|
4189
4318
|
var PENDING_DELETE_KEY = "pendingDeleteIds";
|
|
4190
4319
|
var EXACT_SHOTS_KEY = "exactShots";
|
|
4320
|
+
function exactShotsWanted(store) {
|
|
4321
|
+
return store.getItem(EXACT_SHOTS_KEY) !== "0";
|
|
4322
|
+
}
|
|
4191
4323
|
var SIMPLE_MODE_KEY = "simpleMode";
|
|
4192
4324
|
var COMPACT_KEY = "compactCapture";
|
|
4193
4325
|
var LAST_CAMPAIGN_KEY = "lastCampaign";
|
|
@@ -4228,6 +4360,7 @@ function QaProvider({
|
|
|
4228
4360
|
React.useEffect(() => {
|
|
4229
4361
|
notesRef.current = notes;
|
|
4230
4362
|
}, [notes]);
|
|
4363
|
+
const staleStillTimer = React.useRef(null);
|
|
4231
4364
|
const applyNotes = React.useCallback((updater) => {
|
|
4232
4365
|
const next = updater(notesRef.current);
|
|
4233
4366
|
notesRef.current = next;
|
|
@@ -4266,7 +4399,7 @@ function QaProvider({
|
|
|
4266
4399
|
() => new Set(storage.getJSON(LOGIN_KEY, []))
|
|
4267
4400
|
);
|
|
4268
4401
|
const [exactStatus, setExactStatus] = React.useState(() => {
|
|
4269
|
-
if (storage
|
|
4402
|
+
if (exactShotsWanted(storage)) armExactCapture();
|
|
4270
4403
|
return getExactCaptureStatus();
|
|
4271
4404
|
});
|
|
4272
4405
|
const exactSupported = isExactCaptureSupported();
|
|
@@ -4771,17 +4904,22 @@ function QaProvider({
|
|
|
4771
4904
|
flushPendingDeletes();
|
|
4772
4905
|
for (const timer of noticeTimers.current.values()) clearTimeout(timer);
|
|
4773
4906
|
noticeTimers.current.clear();
|
|
4907
|
+
if (staleStillTimer.current) {
|
|
4908
|
+
clearTimeout(staleStillTimer.current);
|
|
4909
|
+
staleStillTimer.current = null;
|
|
4910
|
+
}
|
|
4774
4911
|
releaseFrozenFrame();
|
|
4775
4912
|
};
|
|
4776
4913
|
}, [flushPendingDeletes]);
|
|
4914
|
+
const STILL_HOLD_MS = 1e5;
|
|
4777
4915
|
const startCapture = React.useCallback((prefill) => {
|
|
4778
4916
|
setIsOpen(false);
|
|
4779
4917
|
setCapturePrefill(prefill ?? "");
|
|
4780
4918
|
setCaptureActive(true);
|
|
4781
|
-
setFrozenAt(null);
|
|
4782
|
-
if (storage
|
|
4919
|
+
if (!stillIsCurrent()) setFrozenAt(null);
|
|
4920
|
+
if (exactShotsWanted(storage) && isExactCaptureSupported()) {
|
|
4783
4921
|
resetExactCaptureDecline();
|
|
4784
|
-
void
|
|
4922
|
+
void freezeOrReuse().then((frame) => {
|
|
4785
4923
|
setFrozenAt(frame?.takenAt ?? null);
|
|
4786
4924
|
setExactStatus(getExactCaptureStatus());
|
|
4787
4925
|
});
|
|
@@ -4789,8 +4927,11 @@ function QaProvider({
|
|
|
4789
4927
|
}, [storage]);
|
|
4790
4928
|
const endCapture = React.useCallback((reopen = true) => {
|
|
4791
4929
|
setCaptureActive(false);
|
|
4792
|
-
|
|
4793
|
-
|
|
4930
|
+
if (staleStillTimer.current) clearTimeout(staleStillTimer.current);
|
|
4931
|
+
staleStillTimer.current = setTimeout(() => {
|
|
4932
|
+
releaseFrozenFrame();
|
|
4933
|
+
staleStillTimer.current = null;
|
|
4934
|
+
}, STILL_HOLD_MS);
|
|
4794
4935
|
if (reopen) setIsOpen(true);
|
|
4795
4936
|
}, []);
|
|
4796
4937
|
const toggleGuide = React.useCallback((key) => {
|
|
@@ -4811,19 +4952,36 @@ function QaProvider({
|
|
|
4811
4952
|
return next;
|
|
4812
4953
|
});
|
|
4813
4954
|
}, [storage]);
|
|
4955
|
+
const stampHandedOff = React.useCallback(async (ids, at) => {
|
|
4956
|
+
if (!ids.length) return;
|
|
4957
|
+
const idSet = new Set(ids);
|
|
4958
|
+
const touched = [];
|
|
4959
|
+
applyNotes(
|
|
4960
|
+
(prev) => prev.map((n) => {
|
|
4961
|
+
if (!idSet.has(n.id)) return n;
|
|
4962
|
+
if ((n.status ?? "open") === "verified") return n;
|
|
4963
|
+
const next = { ...n, handedOffAt: at };
|
|
4964
|
+
touched.push(next);
|
|
4965
|
+
return next;
|
|
4966
|
+
})
|
|
4967
|
+
);
|
|
4968
|
+
for (const note of touched) await idb.put(note);
|
|
4969
|
+
}, [applyNotes, idb]);
|
|
4814
4970
|
const exportZipFn = React.useCallback(
|
|
4815
4971
|
async (filename) => {
|
|
4816
4972
|
if (!notes.length || isExporting) return;
|
|
4817
4973
|
setIsExporting(true);
|
|
4818
4974
|
try {
|
|
4819
|
-
|
|
4975
|
+
const stamp = nowIso();
|
|
4976
|
+
await buildAndDownloadZip(notes, stamp, filename, config, guideChecked, guideSkipped);
|
|
4977
|
+
await stampHandedOff(notes.map((n) => n.id), stamp);
|
|
4820
4978
|
} catch (err) {
|
|
4821
4979
|
console.error("[QA] export failed", err);
|
|
4822
4980
|
} finally {
|
|
4823
4981
|
setIsExporting(false);
|
|
4824
4982
|
}
|
|
4825
4983
|
},
|
|
4826
|
-
[notes, isExporting, config, guideChecked, guideSkipped]
|
|
4984
|
+
[notes, isExporting, config, guideChecked, guideSkipped, stampHandedOff]
|
|
4827
4985
|
);
|
|
4828
4986
|
const exportZipRef = React.useRef(async () => {
|
|
4829
4987
|
});
|
|
@@ -5009,6 +5167,7 @@ function QaProvider({
|
|
|
5009
5167
|
design: 0,
|
|
5010
5168
|
enhance: 0,
|
|
5011
5169
|
open: 0,
|
|
5170
|
+
sent: 0,
|
|
5012
5171
|
fixed: 0,
|
|
5013
5172
|
verified: 0,
|
|
5014
5173
|
thisPage: 0
|
|
@@ -5022,6 +5181,7 @@ function QaProvider({
|
|
|
5022
5181
|
if (status === "verified") counts.verified++;
|
|
5023
5182
|
else if (status === "fixed") counts.fixed++;
|
|
5024
5183
|
else counts.open++;
|
|
5184
|
+
if (n.handedOffAt && status !== "verified") counts.sent++;
|
|
5025
5185
|
if (n.route.split("?")[0] === currentRoute) counts.thisPage++;
|
|
5026
5186
|
}
|
|
5027
5187
|
return counts;
|
|
@@ -5030,7 +5190,9 @@ function QaProvider({
|
|
|
5030
5190
|
const q = filter.query.trim().toLowerCase();
|
|
5031
5191
|
return notes.filter((n) => {
|
|
5032
5192
|
if (filter.severity !== "all" && (n.severity ?? "bug") !== filter.severity) return false;
|
|
5033
|
-
if (filter.status
|
|
5193
|
+
if (filter.status === "sent") {
|
|
5194
|
+
if (!n.handedOffAt || (n.status ?? "open") === "verified") return false;
|
|
5195
|
+
} else if (filter.status !== "all" && (n.status ?? "open") !== filter.status) return false;
|
|
5034
5196
|
if (filter.thisPageOnly && n.route.split("?")[0] !== currentRoute) return false;
|
|
5035
5197
|
if (!q) return true;
|
|
5036
5198
|
const haystack = `${n.description} ${n.route} ${n.target?.selector ?? ""} ${n.target?.text ?? ""}`;
|
|
@@ -5075,6 +5237,7 @@ function QaProvider({
|
|
|
5075
5237
|
const blob = await buildZipBlob(notes, stamp, config, guideChecked, guideSkipped);
|
|
5076
5238
|
if (!blob) return { status: "unsupported" };
|
|
5077
5239
|
const outcome = await shareZipFile(blob, name, config.brand.label);
|
|
5240
|
+
await stampHandedOff(notes.map((n) => n.id), stamp);
|
|
5078
5241
|
if (outcome.status === "needs-gesture") {
|
|
5079
5242
|
setPendingShare({ blob, filename: name });
|
|
5080
5243
|
} else if (outcome.status === "unsupported") {
|
|
@@ -5086,7 +5249,7 @@ function QaProvider({
|
|
|
5086
5249
|
} finally {
|
|
5087
5250
|
setIsExporting(false);
|
|
5088
5251
|
}
|
|
5089
|
-
}, [notes, config, guideChecked, guideSkipped]);
|
|
5252
|
+
}, [notes, config, guideChecked, guideSkipped, stampHandedOff]);
|
|
5090
5253
|
const sharePending = React.useCallback(async () => {
|
|
5091
5254
|
const pending = pendingShare;
|
|
5092
5255
|
if (!pending) return { status: "unsupported" };
|
|
@@ -5302,7 +5465,10 @@ function QaProvider({
|
|
|
5302
5465
|
window.history.replaceState({}, "", window.location.pathname + (qs ? `?${qs}` : ""));
|
|
5303
5466
|
} catch {
|
|
5304
5467
|
}
|
|
5305
|
-
if (which === "
|
|
5468
|
+
if (which === "verify") {
|
|
5469
|
+
setFilterState((prev) => ({ ...prev, status: "sent", severity: "all", thisPageOnly: false }));
|
|
5470
|
+
startWalk("notes", 0);
|
|
5471
|
+
} else if (which === "retest") {
|
|
5306
5472
|
setFilterState((prev) => ({ ...prev, status: "fixed", severity: "all", thisPageOnly: false }));
|
|
5307
5473
|
startWalk("notes", 0);
|
|
5308
5474
|
} else if (which === "notes") {
|
|
@@ -7360,7 +7526,7 @@ function FilterChip({ chip }) {
|
|
|
7360
7526
|
);
|
|
7361
7527
|
}
|
|
7362
7528
|
function NoteFilterBar() {
|
|
7363
|
-
const { filter, setFilter, noteCounts, notes, deleteNotes, t } = useQa();
|
|
7529
|
+
const { filter, setFilter, noteCounts, notes, deleteNotes, startWalk, t } = useQa();
|
|
7364
7530
|
const [confirmPrune, setConfirmPrune] = React.useState(false);
|
|
7365
7531
|
if (notes.length < 3) return null;
|
|
7366
7532
|
const others = notes.filter((n) => (n.status ?? "open") !== "fixed");
|
|
@@ -7402,6 +7568,18 @@ function NoteFilterBar() {
|
|
|
7402
7568
|
tone: "accent",
|
|
7403
7569
|
onClick: sev("design")
|
|
7404
7570
|
},
|
|
7571
|
+
// Only ever shown once something has actually been sent. A chip reading
|
|
7572
|
+
// "Sent 0" on a first run is noise; the same chip reading "Sent 6" the
|
|
7573
|
+
// morning after an export is the one thing the tester came back for.
|
|
7574
|
+
...noteCounts.sent > 0 ? [{
|
|
7575
|
+
key: "sent",
|
|
7576
|
+
label: t("status_sent"),
|
|
7577
|
+
count: noteCounts.sent,
|
|
7578
|
+
active: filter.status === "sent",
|
|
7579
|
+
icon: "Camera",
|
|
7580
|
+
tone: "accent",
|
|
7581
|
+
onClick: () => setFilter({ status: "sent", severity: "all", thisPageOnly: false })
|
|
7582
|
+
}] : [],
|
|
7405
7583
|
{
|
|
7406
7584
|
key: "open",
|
|
7407
7585
|
label: t("status_open"),
|
|
@@ -7470,6 +7648,24 @@ function NoteFilterBar() {
|
|
|
7470
7648
|
}
|
|
7471
7649
|
),
|
|
7472
7650
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "qa-flex qa-flex-wrap qa-gap-1", children: chips.map((chip) => /* @__PURE__ */ jsxRuntime.jsx(FilterChip, { chip }, chip.key)) }),
|
|
7651
|
+
noteCounts.sent > 0 && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
7652
|
+
"button",
|
|
7653
|
+
{
|
|
7654
|
+
type: "button",
|
|
7655
|
+
"data-qa-verify-walk": "true",
|
|
7656
|
+
onClick: () => {
|
|
7657
|
+
setFilter({ status: "sent", severity: "all", thisPageOnly: false });
|
|
7658
|
+
startWalk("notes", 0);
|
|
7659
|
+
},
|
|
7660
|
+
title: t("check_fixes_hint"),
|
|
7661
|
+
className: "qa-tap qa-inline-flex qa-items-center qa-justify-center qa-gap-1.5 qa-rounded-md qa-border qa-border-subtle qa-px-2 qa-py-1.5 qa-text-xs qa-text-hi qa-focus-ring",
|
|
7662
|
+
style: { background: "transparent", cursor: "pointer" },
|
|
7663
|
+
children: [
|
|
7664
|
+
/* @__PURE__ */ jsxRuntime.jsx(Icon, { name: "Check", size: 13 }),
|
|
7665
|
+
t("check_fixes", { n: noteCounts.sent })
|
|
7666
|
+
]
|
|
7667
|
+
}
|
|
7668
|
+
),
|
|
7473
7669
|
showPrune && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "qa-text-11", "data-qa-prune": "true", children: confirmPrune ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "qa-text-mid", children: [
|
|
7474
7670
|
t("keep_only_retest_q", { n: others.length }),
|
|
7475
7671
|
" ",
|
|
@@ -9225,10 +9421,12 @@ function CaptureMode() {
|
|
|
9225
9421
|
const [regionMode, setRegionMode] = React.useState(false);
|
|
9226
9422
|
const [shot, setShot] = React.useState(null);
|
|
9227
9423
|
const stillRef = React.useRef(null);
|
|
9424
|
+
const [notesFromThisShot, setNotesFromThisShot] = React.useState(0);
|
|
9228
9425
|
const [shotEngine, setShotEngine] = React.useState(null);
|
|
9229
9426
|
const [shotUrl, setShotUrl] = React.useState(null);
|
|
9230
9427
|
const [capturing, setCapturing] = React.useState(false);
|
|
9231
9428
|
const [captureError, setCaptureError] = React.useState(false);
|
|
9429
|
+
const [tooHeavy, setTooHeavy] = React.useState(false);
|
|
9232
9430
|
const [description, setDescription] = React.useState(capturePrefill);
|
|
9233
9431
|
const [severity, setSeverity] = React.useState("bug");
|
|
9234
9432
|
const [targetForensics, setTargetForensics] = React.useState(void 0);
|
|
@@ -9258,6 +9456,7 @@ function CaptureMode() {
|
|
|
9258
9456
|
const runCapture = React.useCallback(async (rect) => {
|
|
9259
9457
|
setCapturing(true);
|
|
9260
9458
|
setCaptureError(false);
|
|
9459
|
+
setTooHeavy(false);
|
|
9261
9460
|
lockPageScroll();
|
|
9262
9461
|
try {
|
|
9263
9462
|
const outcome = await captureRegion(rect, scrollSnap.current);
|
|
@@ -9268,6 +9467,7 @@ function CaptureMode() {
|
|
|
9268
9467
|
return;
|
|
9269
9468
|
}
|
|
9270
9469
|
setCaptureError(outcome.status === "failed");
|
|
9470
|
+
setTooHeavy(outcome.status === "too-heavy");
|
|
9271
9471
|
setShotEngine(outcome.status === "ok" ? outcome.engine : null);
|
|
9272
9472
|
setShot(blob);
|
|
9273
9473
|
setShotUrl((old) => {
|
|
@@ -9529,7 +9729,17 @@ function CaptureMode() {
|
|
|
9529
9729
|
canvas.removeAttribute("style");
|
|
9530
9730
|
};
|
|
9531
9731
|
}, [exactShots.frozenAt]);
|
|
9532
|
-
const
|
|
9732
|
+
const resetForNextNote = React.useCallback(() => {
|
|
9733
|
+
setPhase("selecting");
|
|
9734
|
+
setSelection(null);
|
|
9735
|
+
setShot(null);
|
|
9736
|
+
setShotEngine(null);
|
|
9737
|
+
setDescription("");
|
|
9738
|
+
setSeverity("bug");
|
|
9739
|
+
setTargetForensics(void 0);
|
|
9740
|
+
setCaptureError(false);
|
|
9741
|
+
}, []);
|
|
9742
|
+
const save = async (keepGoing = false) => {
|
|
9533
9743
|
if (!selection || !description.trim()) return;
|
|
9534
9744
|
const target = {
|
|
9535
9745
|
kind: selection.kind,
|
|
@@ -9551,6 +9761,11 @@ function CaptureMode() {
|
|
|
9551
9761
|
severity,
|
|
9552
9762
|
forensics: selection.kind === "element" ? targetForensics : void 0
|
|
9553
9763
|
});
|
|
9764
|
+
if (keepGoing) {
|
|
9765
|
+
setNotesFromThisShot((n) => n + 1);
|
|
9766
|
+
resetForNextNote();
|
|
9767
|
+
return;
|
|
9768
|
+
}
|
|
9554
9769
|
endCapture();
|
|
9555
9770
|
};
|
|
9556
9771
|
const popStyleFor = React.useCallback((r, cardWidth = 340) => {
|
|
@@ -9618,6 +9833,21 @@ function CaptureMode() {
|
|
|
9618
9833
|
{
|
|
9619
9834
|
className: "qa-fixed qa-left-half qa-top-4 qa-z-10095 qa-translate-x-neg-half qa-flex qa-items-center qa-gap-3 qa-rounded-full qa-border qa-border-subtle qa-bg-2 qa-px-4 qa-py-2 qa-text-sm qa-text-hi qa-elev-2",
|
|
9620
9835
|
children: [
|
|
9836
|
+
notesFromThisShot > 0 && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
9837
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
9838
|
+
"span",
|
|
9839
|
+
{
|
|
9840
|
+
"data-qa-shot-reused": "true",
|
|
9841
|
+
className: "qa-flex qa-items-center qa-gap-1.5",
|
|
9842
|
+
style: { color: "var(--qa-success)" },
|
|
9843
|
+
children: [
|
|
9844
|
+
/* @__PURE__ */ jsxRuntime.jsx(Icon, { name: "Camera", size: 16 }),
|
|
9845
|
+
t("shot_reused", { n: String(notesFromThisShot) })
|
|
9846
|
+
]
|
|
9847
|
+
}
|
|
9848
|
+
),
|
|
9849
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "qa-opacity-50", children: "\xB7" })
|
|
9850
|
+
] }),
|
|
9621
9851
|
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "qa-flex qa-items-center qa-gap-1.5", children: [
|
|
9622
9852
|
/* @__PURE__ */ jsxRuntime.jsx(Icon, { name: "MousePointerClick", size: 16 }),
|
|
9623
9853
|
t("cap_click")
|
|
@@ -10067,6 +10297,29 @@ function CaptureMode() {
|
|
|
10067
10297
|
)
|
|
10068
10298
|
]
|
|
10069
10299
|
}
|
|
10300
|
+
) : tooHeavy ? (
|
|
10301
|
+
// Not a failure to report — a refusal to explain, with the one
|
|
10302
|
+
// control that actually solves it.
|
|
10303
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "qa-flex qa-flex-col qa-items-center qa-gap-2 qa-py-3 qa-px-3 qa-text-center", children: [
|
|
10304
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "qa-text-xs qa-text-mid", children: t("too_heavy") }),
|
|
10305
|
+
exactShots.supported ? /* @__PURE__ */ jsxRuntime.jsxs(
|
|
10306
|
+
"button",
|
|
10307
|
+
{
|
|
10308
|
+
type: "button",
|
|
10309
|
+
onClick: () => void (async () => {
|
|
10310
|
+
const shot2 = await photographNow();
|
|
10311
|
+
if (shot2 && selection) void runCapture(selection.rect);
|
|
10312
|
+
})(),
|
|
10313
|
+
title: t("exact_hint"),
|
|
10314
|
+
className: "qa-tap qa-inline-flex qa-items-center qa-gap-1.5 qa-rounded-md qa-border qa-border-subtle qa-px-2 qa-py-1 qa-text-xs qa-text-hi qa-focus-ring",
|
|
10315
|
+
style: { background: "transparent", cursor: "pointer" },
|
|
10316
|
+
children: [
|
|
10317
|
+
/* @__PURE__ */ jsxRuntime.jsx(Icon, { name: "Camera", size: 13 }),
|
|
10318
|
+
t("redraw_action")
|
|
10319
|
+
]
|
|
10320
|
+
}
|
|
10321
|
+
) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "qa-text-10 qa-text-mid", children: t("redraw_no_engine") })
|
|
10322
|
+
] })
|
|
10070
10323
|
) : captureError ? (
|
|
10071
10324
|
// The render broke rather than being skipped — offer a retry
|
|
10072
10325
|
// against the same selection instead of a dead-end message.
|
|
@@ -10173,7 +10426,7 @@ function CaptureMode() {
|
|
|
10173
10426
|
value: description,
|
|
10174
10427
|
onChange: (e) => setDescription(e.target.value),
|
|
10175
10428
|
onKeyDown: (e) => {
|
|
10176
|
-
if (e.key === "Enter" && (e.metaKey || e.ctrlKey)) void save();
|
|
10429
|
+
if (e.key === "Enter" && (e.metaKey || e.ctrlKey)) void save(e.shiftKey);
|
|
10177
10430
|
if ((e.altKey || e.metaKey || e.ctrlKey) && SEVERITIES2[Number(e.key) - 1]) {
|
|
10178
10431
|
e.preventDefault();
|
|
10179
10432
|
setSeverity(SEVERITIES2[Number(e.key) - 1]);
|
|
@@ -10198,17 +10451,25 @@ function CaptureMode() {
|
|
|
10198
10451
|
]
|
|
10199
10452
|
}
|
|
10200
10453
|
),
|
|
10454
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
10455
|
+
"button",
|
|
10456
|
+
{
|
|
10457
|
+
"data-qa-save-next": "true",
|
|
10458
|
+
onClick: () => void save(true),
|
|
10459
|
+
disabled: !description.trim(),
|
|
10460
|
+
title: t("save_next_hint"),
|
|
10461
|
+
className: "qa-tap qa-flex qa-items-center qa-justify-center qa-gap-1.5 qa-rounded-lg qa-border qa-border-subtle qa-px-3 qa-py-2 qa-text-sm qa-text-hi",
|
|
10462
|
+
style: { background: "transparent", cursor: "pointer" },
|
|
10463
|
+
children: [
|
|
10464
|
+
/* @__PURE__ */ jsxRuntime.jsx(Icon, { name: "Plus", size: 16 }),
|
|
10465
|
+
t("save_next")
|
|
10466
|
+
]
|
|
10467
|
+
}
|
|
10468
|
+
),
|
|
10201
10469
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
10202
10470
|
"button",
|
|
10203
10471
|
{
|
|
10204
|
-
onClick:
|
|
10205
|
-
setPhase("selecting");
|
|
10206
|
-
setSelection(null);
|
|
10207
|
-
setShot(null);
|
|
10208
|
-
setDescription("");
|
|
10209
|
-
setSeverity("bug");
|
|
10210
|
-
setTargetForensics(void 0);
|
|
10211
|
-
},
|
|
10472
|
+
onClick: resetForNextNote,
|
|
10212
10473
|
className: "qa-tap qa-rounded-lg qa-border qa-border-subtle qa-px-3 qa-py-2 qa-text-sm qa-text-mid",
|
|
10213
10474
|
style: { background: "transparent", cursor: "pointer" },
|
|
10214
10475
|
children: t("reselect")
|
|
@@ -10426,5 +10687,5 @@ function Qapture({ config }) {
|
|
|
10426
10687
|
exports.Qapture = Qapture;
|
|
10427
10688
|
exports.deleteQaDatabase = deleteQaDatabase;
|
|
10428
10689
|
exports.initQaStudio = initQaStudio;
|
|
10429
|
-
//# sourceMappingURL=chunk-
|
|
10430
|
-
//# sourceMappingURL=chunk-
|
|
10690
|
+
//# sourceMappingURL=chunk-OSYYMS6R.cjs.map
|
|
10691
|
+
//# sourceMappingURL=chunk-OSYYMS6R.cjs.map
|
package/dist/index.cjs
CHANGED
|
@@ -1,24 +1,24 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var chunkOSYYMS6R_cjs = require('./chunk-OSYYMS6R.cjs');
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
|
|
7
7
|
Object.defineProperty(exports, "QaStudio", {
|
|
8
8
|
enumerable: true,
|
|
9
|
-
get: function () { return
|
|
9
|
+
get: function () { return chunkOSYYMS6R_cjs.Qapture; }
|
|
10
10
|
});
|
|
11
11
|
Object.defineProperty(exports, "Qapture", {
|
|
12
12
|
enumerable: true,
|
|
13
|
-
get: function () { return
|
|
13
|
+
get: function () { return chunkOSYYMS6R_cjs.Qapture; }
|
|
14
14
|
});
|
|
15
15
|
Object.defineProperty(exports, "deleteQaDatabase", {
|
|
16
16
|
enumerable: true,
|
|
17
|
-
get: function () { return
|
|
17
|
+
get: function () { return chunkOSYYMS6R_cjs.deleteQaDatabase; }
|
|
18
18
|
});
|
|
19
19
|
Object.defineProperty(exports, "initQaStudio", {
|
|
20
20
|
enumerable: true,
|
|
21
|
-
get: function () { return
|
|
21
|
+
get: function () { return chunkOSYYMS6R_cjs.initQaStudio; }
|
|
22
22
|
});
|
|
23
23
|
//# sourceMappingURL=index.cjs.map
|
|
24
24
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.js
CHANGED