@m2farhood-2/qapture 0.2.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.cjs ADDED
@@ -0,0 +1,20 @@
1
+ 'use strict';
2
+
3
+ var chunkCJQHPDT7_cjs = require('./chunk-CJQHPDT7.cjs');
4
+
5
+
6
+
7
+ Object.defineProperty(exports, "QaStudio", {
8
+ enumerable: true,
9
+ get: function () { return chunkCJQHPDT7_cjs.Qapture; }
10
+ });
11
+ Object.defineProperty(exports, "Qapture", {
12
+ enumerable: true,
13
+ get: function () { return chunkCJQHPDT7_cjs.Qapture; }
14
+ });
15
+ Object.defineProperty(exports, "initQaStudio", {
16
+ enumerable: true,
17
+ get: function () { return chunkCJQHPDT7_cjs.initQaStudio; }
18
+ });
19
+ //# sourceMappingURL=index.cjs.map
20
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1,179 @@
1
+ /**
2
+ * schema.ts — all public config types + a runtime validator for qapture.
3
+ *
4
+ * validateConfig() deep-merges user input over the built-in defaults, coerces
5
+ * or skips invalid entries, and NEVER throws. Returns a fully-resolved config
6
+ * plus human-readable warnings.
7
+ *
8
+ * Also exports DEFAULT_THEME so that defaults.ts can import it without
9
+ * creating a circular dependency (defaults.ts → schema.ts, not the reverse).
10
+ */
11
+ /** A bilingual string: either a plain string (language-neutral) or { en, ar? }. */
12
+ type QaBilingual = string | {
13
+ en: string;
14
+ ar?: string;
15
+ };
16
+ /** Brand colour palette for the QA panel. All fields optional on input. */
17
+ type QaTheme = {
18
+ primary: string;
19
+ primaryDark: string;
20
+ accent: string;
21
+ accentDark: string;
22
+ sage: string;
23
+ cream: string;
24
+ mauve: string;
25
+ surface: string;
26
+ ink: string;
27
+ };
28
+ /** A single test credential row. */
29
+ type QaCredential = {
30
+ role: string;
31
+ roleAr?: string;
32
+ login: string;
33
+ password: string;
34
+ seeded?: boolean;
35
+ hint?: {
36
+ en: string;
37
+ ar?: string;
38
+ };
39
+ };
40
+ /** Risk level for a journey step. */
41
+ type QaRisk = 'red' | 'amber' | 'green';
42
+ /** One step inside a journey lane. */
43
+ type QaJourneyStep = {
44
+ path: string;
45
+ what: QaBilingual;
46
+ risk?: QaRisk;
47
+ riskWhy?: string;
48
+ };
49
+ /** A role-grouped journey lane. */
50
+ type QaJourneyLane = {
51
+ id: string;
52
+ color?: string;
53
+ role: QaBilingual;
54
+ steps: QaJourneyStep[];
55
+ };
56
+ /**
57
+ * Freeform preamble block consumed by AI agents in Phase 2.
58
+ * All fields optional; additional keys allowed via index signature.
59
+ *
60
+ * conventions, invariants, verifySteps, and runCommands all accept either a
61
+ * single string (plain text / newline-separated) or an explicit string[].
62
+ * The export layer normalises both forms before rendering.
63
+ */
64
+ type QaPreamble = {
65
+ projectName?: string;
66
+ oneLiner?: string;
67
+ stack?: string;
68
+ runCommands?: string | string[];
69
+ /** Numbered conventions list — plain string or explicit array. */
70
+ conventions?: string | string[];
71
+ /** Do-not-break invariants — plain string or explicit array. */
72
+ invariants?: string | string[];
73
+ /** Steps to verify a fix — plain string or explicit array. */
74
+ verifySteps?: string | string[];
75
+ additionalContext?: string;
76
+ [key: string]: unknown;
77
+ };
78
+ type QaConfig = {
79
+ /** Storage + DB namespace. Defaults to 'qapture'. */
80
+ namespace?: string;
81
+ /** Override any subset of the colour palette. */
82
+ theme?: Partial<QaTheme>;
83
+ /** Panel brand label. */
84
+ brand?: {
85
+ label?: string;
86
+ };
87
+ /** Display label for the login/username field. */
88
+ loginField?: {
89
+ en: string;
90
+ ar?: string;
91
+ };
92
+ /** Test credentials list. */
93
+ credentials?: QaCredential[];
94
+ /** Role-grouped testing journey. */
95
+ journey?: QaJourneyLane[];
96
+ /** AI agent preamble block. */
97
+ preamble?: QaPreamble;
98
+ /** If true, default language initializes to 'ar' (RTL). */
99
+ rtl?: boolean;
100
+ /**
101
+ * Whether the panel is visible.
102
+ * - true / false: always show / always hide
103
+ * - undefined (default): ShadowMount treats as "dev-only" (show only when
104
+ * process.env.NODE_ENV !== 'production' or equivalent)
105
+ */
106
+ visible?: boolean;
107
+ /** Always visible, even in production. Overrides `visible`. */
108
+ alwaysVisible?: boolean;
109
+ /** Keyboard shortcut to toggle the panel. Default: 'shift+alt+q'. */
110
+ hotkey?: string;
111
+ };
112
+ type ResolvedConfig = {
113
+ namespace: string;
114
+ theme: QaTheme;
115
+ brand: {
116
+ label: string;
117
+ };
118
+ loginField: {
119
+ en: string;
120
+ ar?: string;
121
+ };
122
+ credentials: QaCredential[];
123
+ journey: QaJourneyLane[];
124
+ preamble: QaPreamble | null;
125
+ rtl: boolean;
126
+ /**
127
+ * Visibility sentinel.
128
+ * - true: always show
129
+ * - false: always hide
130
+ * - undefined: dev-only (ShadowMount interprets at mount time)
131
+ *
132
+ * The key is always present in ResolvedConfig; only the value may be undefined.
133
+ */
134
+ visible: boolean | undefined;
135
+ alwaysVisible: boolean;
136
+ hotkey: string;
137
+ };
138
+
139
+ /**
140
+ * qapture — public API.
141
+ *
142
+ * Ships ZERO AI: this is a keyless, secretless, 100% client-side capture
143
+ * widget. The <Qapture/> component and initQaStudio() imperative function
144
+ * both mount an isolated Shadow-DOM host on the client and render nothing on
145
+ * the server (SSR-safe).
146
+ */
147
+
148
+ /**
149
+ * Mount qapture imperatively.
150
+ *
151
+ * Validates and resolves the supplied config, then mounts the widget into an
152
+ * isolated Shadow-DOM host attached to document.body. Returns a handle with a
153
+ * destroy() method that unmounts and cleans up.
154
+ *
155
+ * SSR-safe: returns a no-op destroy() when called outside a browser.
156
+ */
157
+ declare function initQaStudio(config?: QaConfig): {
158
+ destroy(): void;
159
+ };
160
+ /**
161
+ * Drop-in React component that mounts qapture on the client.
162
+ *
163
+ * Renders `null` (SSR-safe). On mount it calls initQaStudio() and returns its
164
+ * destroy() for useEffect cleanup. Config changes after mount are ignored
165
+ * (destroy + remount if needed).
166
+ *
167
+ * Usage (Next.js App Router):
168
+ * import { Qapture } from 'qapture/next'; // adds 'use client' banner
169
+ * <Qapture config={qaConfig} />
170
+ *
171
+ * Usage (any React app):
172
+ * import { Qapture } from 'qapture';
173
+ * <Qapture config={qaConfig} />
174
+ */
175
+ declare function Qapture({ config }: {
176
+ config?: QaConfig;
177
+ }): null;
178
+
179
+ export { type QaBilingual, type QaConfig, type QaCredential, type QaJourneyLane, type QaJourneyStep, type QaPreamble, type QaRisk, Qapture as QaStudio, type QaTheme, Qapture, type ResolvedConfig, initQaStudio };
@@ -0,0 +1,179 @@
1
+ /**
2
+ * schema.ts — all public config types + a runtime validator for qapture.
3
+ *
4
+ * validateConfig() deep-merges user input over the built-in defaults, coerces
5
+ * or skips invalid entries, and NEVER throws. Returns a fully-resolved config
6
+ * plus human-readable warnings.
7
+ *
8
+ * Also exports DEFAULT_THEME so that defaults.ts can import it without
9
+ * creating a circular dependency (defaults.ts → schema.ts, not the reverse).
10
+ */
11
+ /** A bilingual string: either a plain string (language-neutral) or { en, ar? }. */
12
+ type QaBilingual = string | {
13
+ en: string;
14
+ ar?: string;
15
+ };
16
+ /** Brand colour palette for the QA panel. All fields optional on input. */
17
+ type QaTheme = {
18
+ primary: string;
19
+ primaryDark: string;
20
+ accent: string;
21
+ accentDark: string;
22
+ sage: string;
23
+ cream: string;
24
+ mauve: string;
25
+ surface: string;
26
+ ink: string;
27
+ };
28
+ /** A single test credential row. */
29
+ type QaCredential = {
30
+ role: string;
31
+ roleAr?: string;
32
+ login: string;
33
+ password: string;
34
+ seeded?: boolean;
35
+ hint?: {
36
+ en: string;
37
+ ar?: string;
38
+ };
39
+ };
40
+ /** Risk level for a journey step. */
41
+ type QaRisk = 'red' | 'amber' | 'green';
42
+ /** One step inside a journey lane. */
43
+ type QaJourneyStep = {
44
+ path: string;
45
+ what: QaBilingual;
46
+ risk?: QaRisk;
47
+ riskWhy?: string;
48
+ };
49
+ /** A role-grouped journey lane. */
50
+ type QaJourneyLane = {
51
+ id: string;
52
+ color?: string;
53
+ role: QaBilingual;
54
+ steps: QaJourneyStep[];
55
+ };
56
+ /**
57
+ * Freeform preamble block consumed by AI agents in Phase 2.
58
+ * All fields optional; additional keys allowed via index signature.
59
+ *
60
+ * conventions, invariants, verifySteps, and runCommands all accept either a
61
+ * single string (plain text / newline-separated) or an explicit string[].
62
+ * The export layer normalises both forms before rendering.
63
+ */
64
+ type QaPreamble = {
65
+ projectName?: string;
66
+ oneLiner?: string;
67
+ stack?: string;
68
+ runCommands?: string | string[];
69
+ /** Numbered conventions list — plain string or explicit array. */
70
+ conventions?: string | string[];
71
+ /** Do-not-break invariants — plain string or explicit array. */
72
+ invariants?: string | string[];
73
+ /** Steps to verify a fix — plain string or explicit array. */
74
+ verifySteps?: string | string[];
75
+ additionalContext?: string;
76
+ [key: string]: unknown;
77
+ };
78
+ type QaConfig = {
79
+ /** Storage + DB namespace. Defaults to 'qapture'. */
80
+ namespace?: string;
81
+ /** Override any subset of the colour palette. */
82
+ theme?: Partial<QaTheme>;
83
+ /** Panel brand label. */
84
+ brand?: {
85
+ label?: string;
86
+ };
87
+ /** Display label for the login/username field. */
88
+ loginField?: {
89
+ en: string;
90
+ ar?: string;
91
+ };
92
+ /** Test credentials list. */
93
+ credentials?: QaCredential[];
94
+ /** Role-grouped testing journey. */
95
+ journey?: QaJourneyLane[];
96
+ /** AI agent preamble block. */
97
+ preamble?: QaPreamble;
98
+ /** If true, default language initializes to 'ar' (RTL). */
99
+ rtl?: boolean;
100
+ /**
101
+ * Whether the panel is visible.
102
+ * - true / false: always show / always hide
103
+ * - undefined (default): ShadowMount treats as "dev-only" (show only when
104
+ * process.env.NODE_ENV !== 'production' or equivalent)
105
+ */
106
+ visible?: boolean;
107
+ /** Always visible, even in production. Overrides `visible`. */
108
+ alwaysVisible?: boolean;
109
+ /** Keyboard shortcut to toggle the panel. Default: 'shift+alt+q'. */
110
+ hotkey?: string;
111
+ };
112
+ type ResolvedConfig = {
113
+ namespace: string;
114
+ theme: QaTheme;
115
+ brand: {
116
+ label: string;
117
+ };
118
+ loginField: {
119
+ en: string;
120
+ ar?: string;
121
+ };
122
+ credentials: QaCredential[];
123
+ journey: QaJourneyLane[];
124
+ preamble: QaPreamble | null;
125
+ rtl: boolean;
126
+ /**
127
+ * Visibility sentinel.
128
+ * - true: always show
129
+ * - false: always hide
130
+ * - undefined: dev-only (ShadowMount interprets at mount time)
131
+ *
132
+ * The key is always present in ResolvedConfig; only the value may be undefined.
133
+ */
134
+ visible: boolean | undefined;
135
+ alwaysVisible: boolean;
136
+ hotkey: string;
137
+ };
138
+
139
+ /**
140
+ * qapture — public API.
141
+ *
142
+ * Ships ZERO AI: this is a keyless, secretless, 100% client-side capture
143
+ * widget. The <Qapture/> component and initQaStudio() imperative function
144
+ * both mount an isolated Shadow-DOM host on the client and render nothing on
145
+ * the server (SSR-safe).
146
+ */
147
+
148
+ /**
149
+ * Mount qapture imperatively.
150
+ *
151
+ * Validates and resolves the supplied config, then mounts the widget into an
152
+ * isolated Shadow-DOM host attached to document.body. Returns a handle with a
153
+ * destroy() method that unmounts and cleans up.
154
+ *
155
+ * SSR-safe: returns a no-op destroy() when called outside a browser.
156
+ */
157
+ declare function initQaStudio(config?: QaConfig): {
158
+ destroy(): void;
159
+ };
160
+ /**
161
+ * Drop-in React component that mounts qapture on the client.
162
+ *
163
+ * Renders `null` (SSR-safe). On mount it calls initQaStudio() and returns its
164
+ * destroy() for useEffect cleanup. Config changes after mount are ignored
165
+ * (destroy + remount if needed).
166
+ *
167
+ * Usage (Next.js App Router):
168
+ * import { Qapture } from 'qapture/next'; // adds 'use client' banner
169
+ * <Qapture config={qaConfig} />
170
+ *
171
+ * Usage (any React app):
172
+ * import { Qapture } from 'qapture';
173
+ * <Qapture config={qaConfig} />
174
+ */
175
+ declare function Qapture({ config }: {
176
+ config?: QaConfig;
177
+ }): null;
178
+
179
+ export { type QaBilingual, type QaConfig, type QaCredential, type QaJourneyLane, type QaJourneyStep, type QaPreamble, type QaRisk, Qapture as QaStudio, type QaTheme, Qapture, type ResolvedConfig, initQaStudio };
package/dist/index.js ADDED
@@ -0,0 +1,3 @@
1
+ export { Qapture as QaStudio, Qapture, initQaStudio } from './chunk-OPZF4IVW.js';
2
+ //# sourceMappingURL=index.js.map
3
+ //# sourceMappingURL=index.js.map
package/dist/next.cjs ADDED
@@ -0,0 +1,21 @@
1
+ "use client";
2
+ 'use strict';
3
+
4
+ var chunkCJQHPDT7_cjs = require('./chunk-CJQHPDT7.cjs');
5
+
6
+
7
+
8
+ Object.defineProperty(exports, "QaStudio", {
9
+ enumerable: true,
10
+ get: function () { return chunkCJQHPDT7_cjs.Qapture; }
11
+ });
12
+ Object.defineProperty(exports, "Qapture", {
13
+ enumerable: true,
14
+ get: function () { return chunkCJQHPDT7_cjs.Qapture; }
15
+ });
16
+ Object.defineProperty(exports, "initQaStudio", {
17
+ enumerable: true,
18
+ get: function () { return chunkCJQHPDT7_cjs.initQaStudio; }
19
+ });
20
+ //# sourceMappingURL=next.cjs.map
21
+ //# sourceMappingURL=next.cjs.map
@@ -0,0 +1 @@
1
+ export { QaConfig, QaStudio, QaStudio as Qapture, initQaStudio } from './index.cjs';
package/dist/next.d.ts ADDED
@@ -0,0 +1 @@
1
+ export { QaConfig, QaStudio, QaStudio as Qapture, initQaStudio } from './index.js';
package/dist/next.js ADDED
@@ -0,0 +1,4 @@
1
+ "use client";
2
+ export { Qapture as QaStudio, Qapture, initQaStudio } from './chunk-OPZF4IVW.js';
3
+ //# sourceMappingURL=next.js.map
4
+ //# sourceMappingURL=next.js.map
@@ -0,0 +1,39 @@
1
+ 'use strict';
2
+
3
+ var chunkCJQHPDT7_cjs = require('./chunk-CJQHPDT7.cjs');
4
+
5
+ // src/standalone.ts
6
+ if (typeof window !== "undefined" && typeof customElements !== "undefined" && !customElements.get("qapture-widget")) {
7
+ import('./index.cjs').then(({ initQaStudio: init }) => {
8
+ customElements.define(
9
+ "qapture-widget",
10
+ class QaStudioWidget extends HTMLElement {
11
+ connectedCallback() {
12
+ let cfg = {};
13
+ try {
14
+ const attr = this.getAttribute("config");
15
+ if (attr) cfg = JSON.parse(attr);
16
+ } catch {
17
+ }
18
+ const propCfg = this["config"];
19
+ if (propCfg && typeof propCfg === "object" && !Array.isArray(propCfg)) {
20
+ cfg = propCfg;
21
+ }
22
+ const instance = init(cfg);
23
+ this._destroy = instance.destroy;
24
+ }
25
+ disconnectedCallback() {
26
+ this._destroy?.();
27
+ }
28
+ }
29
+ );
30
+ }).catch(() => {
31
+ });
32
+ }
33
+
34
+ Object.defineProperty(exports, "initQaStudio", {
35
+ enumerable: true,
36
+ get: function () { return chunkCJQHPDT7_cjs.initQaStudio; }
37
+ });
38
+ //# sourceMappingURL=standalone.cjs.map
39
+ //# sourceMappingURL=standalone.cjs.map
@@ -0,0 +1 @@
1
+ export { QaConfig, initQaStudio } from './index.cjs';
@@ -0,0 +1 @@
1
+ export { QaConfig, initQaStudio } from './index.js';
@@ -0,0 +1,32 @@
1
+ export { initQaStudio } from './chunk-OPZF4IVW.js';
2
+
3
+ // src/standalone.ts
4
+ if (typeof window !== "undefined" && typeof customElements !== "undefined" && !customElements.get("qapture-widget")) {
5
+ import('./index.js').then(({ initQaStudio: init }) => {
6
+ customElements.define(
7
+ "qapture-widget",
8
+ class QaStudioWidget extends HTMLElement {
9
+ connectedCallback() {
10
+ let cfg = {};
11
+ try {
12
+ const attr = this.getAttribute("config");
13
+ if (attr) cfg = JSON.parse(attr);
14
+ } catch {
15
+ }
16
+ const propCfg = this["config"];
17
+ if (propCfg && typeof propCfg === "object" && !Array.isArray(propCfg)) {
18
+ cfg = propCfg;
19
+ }
20
+ const instance = init(cfg);
21
+ this._destroy = instance.destroy;
22
+ }
23
+ disconnectedCallback() {
24
+ this._destroy?.();
25
+ }
26
+ }
27
+ );
28
+ }).catch(() => {
29
+ });
30
+ }
31
+ //# sourceMappingURL=standalone.js.map
32
+ //# sourceMappingURL=standalone.js.map
package/package.json ADDED
@@ -0,0 +1,116 @@
1
+ {
2
+ "name": "@m2farhood-2/qapture",
3
+ "version": "0.2.0",
4
+ "description": "Drop-in, AI-aware in-browser QA capture widget. A tester annotates the live app (element/region + auto-screenshot + note), tracks a graded testing journey, and exports a ZIP your own coding agent reads. Ships zero AI.",
5
+ "type": "module",
6
+ "license": "MIT",
7
+ "publishConfig": {
8
+ "access": "public"
9
+ },
10
+ "keywords": [
11
+ "qa",
12
+ "testing",
13
+ "annotation",
14
+ "screenshot",
15
+ "ai",
16
+ "agents",
17
+ "claude-code",
18
+ "widget",
19
+ "shadow-dom"
20
+ ],
21
+ "main": "./dist/index.cjs",
22
+ "module": "./dist/index.js",
23
+ "types": "./dist/index.d.ts",
24
+ "exports": {
25
+ ".": {
26
+ "import": {
27
+ "types": "./dist/index.d.ts",
28
+ "default": "./dist/index.js"
29
+ },
30
+ "require": {
31
+ "types": "./dist/index.d.cts",
32
+ "default": "./dist/index.cjs"
33
+ }
34
+ },
35
+ "./next": {
36
+ "import": {
37
+ "types": "./dist/next.d.ts",
38
+ "default": "./dist/next.js"
39
+ },
40
+ "require": {
41
+ "types": "./dist/next.d.cts",
42
+ "default": "./dist/next.cjs"
43
+ }
44
+ },
45
+ "./standalone": {
46
+ "import": {
47
+ "types": "./dist/standalone.d.ts",
48
+ "default": "./dist/standalone.js"
49
+ },
50
+ "require": {
51
+ "types": "./dist/standalone.d.cts",
52
+ "default": "./dist/standalone.cjs"
53
+ }
54
+ },
55
+ "./package.json": "./package.json"
56
+ },
57
+ "bin": {
58
+ "qapture": "./dist/bin/init.cjs"
59
+ },
60
+ "repository": {
61
+ "type": "git",
62
+ "url": "git+https://github.com/mohammed-farhood/qapture.git"
63
+ },
64
+ "homepage": "https://github.com/mohammed-farhood/qapture#readme",
65
+ "bugs": {
66
+ "url": "https://github.com/mohammed-farhood/qapture/issues"
67
+ },
68
+ "files": [
69
+ "dist",
70
+ "!dist/**/*.map",
71
+ "!dist/_export-test.mjs",
72
+ "README.md",
73
+ "LICENSE"
74
+ ],
75
+ "sideEffects": false,
76
+ "scripts": {
77
+ "build": "tsup && node scripts/postbuild.mjs",
78
+ "prepublishOnly": "npm run build",
79
+ "dev": "tsup --watch",
80
+ "typecheck": "tsc --noEmit",
81
+ "smoke": "node scripts/smoke.mjs",
82
+ "export-smoke": "esbuild src/lib/exportZip.ts --bundle --format=esm --platform=node --outfile=dist/_export-test.mjs --log-level=error && node scripts/export-smoke.mjs dist/_export-test.mjs",
83
+ "browser-test": "node scripts/browser-test.mjs",
84
+ "verify": "npm run typecheck && npm run build && npm run smoke && npm run export-smoke",
85
+ "play": "npm --prefix playground run dev"
86
+ },
87
+ "engines": {
88
+ "node": ">=18"
89
+ },
90
+ "peerDependencies": {
91
+ "react": ">=18.0.0",
92
+ "react-dom": ">=18.0.0"
93
+ },
94
+ "peerDependenciesMeta": {
95
+ "react": {
96
+ "optional": false
97
+ },
98
+ "react-dom": {
99
+ "optional": false
100
+ }
101
+ },
102
+ "dependencies": {
103
+ "html2canvas": "^1.4.1",
104
+ "jszip": "^3.10.1"
105
+ },
106
+ "devDependencies": {
107
+ "@types/react": "^18.3.12",
108
+ "@types/react-dom": "^18.3.1",
109
+ "jsdom": "^29.1.1",
110
+ "puppeteer-core": "^25.2.1",
111
+ "react": "^18.3.1",
112
+ "react-dom": "^18.3.1",
113
+ "tsup": "^8.3.5",
114
+ "typescript": "^5.6.3"
115
+ }
116
+ }