@open-probe/shared 0.1.1

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 open-probe contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,26 @@
1
+ # @open-probe/shared
2
+
3
+ Shared TypeScript types and the **AFS v1** (Annotation Format Schema)
4
+ protocol definitions used across all open-probe packages.
5
+
6
+ This package has no runtime code worth importing on its own; it exists to
7
+ keep `@open-probe/core`, `@open-probe/mcp-server`, `@open-probe/proxy`,
8
+ and any future transports speaking the same wire format.
9
+
10
+ ```ts
11
+ import type {
12
+ Annotation,
13
+ AnnotationIntent,
14
+ ElementInfo,
15
+ Framework,
16
+ ProbeConfig,
17
+ SourceLocation,
18
+ } from '@open-probe/shared';
19
+ ```
20
+
21
+ See the project [README](https://github.com/wzc520pyfm/open-probe#readme)
22
+ for the full architecture.
23
+
24
+ ## License
25
+
26
+ MIT
@@ -0,0 +1,198 @@
1
+ type Framework = 'react' | 'vue3' | 'vue2' | 'svelte' | 'solid' | 'preact' | 'unknown';
2
+ interface SourceLocation {
3
+ filePath: string;
4
+ lineNumber: number;
5
+ columnNumber: number;
6
+ componentName: string;
7
+ }
8
+ interface BoundingBox {
9
+ x: number;
10
+ y: number;
11
+ width: number;
12
+ height: number;
13
+ }
14
+ interface SelectorResult {
15
+ primary: string;
16
+ alternatives: string[];
17
+ specificity: number;
18
+ grepHints: string[];
19
+ }
20
+ interface ElementInfo {
21
+ tagName: string;
22
+ componentName: string | null;
23
+ source: SourceLocation | null;
24
+ stack: SourceLocation[];
25
+ framework: Framework;
26
+ }
27
+
28
+ type AnnotationIntent = 'fix' | 'change' | 'question' | 'approve';
29
+ type AnnotationSeverity = 'blocking' | 'important' | 'suggestion';
30
+ type AnnotationStatus = 'pending' | 'acknowledged' | 'resolved' | 'dismissed';
31
+ type AnnotationKind = 'feedback' | 'placement' | 'rearrange';
32
+ interface ThreadMessage {
33
+ id: string;
34
+ role: 'human' | 'agent';
35
+ content: string;
36
+ timestamp: number;
37
+ }
38
+ interface PlacementData {
39
+ componentType: string;
40
+ width: number;
41
+ height: number;
42
+ scrollY: number;
43
+ text?: string;
44
+ }
45
+ interface RearrangeData {
46
+ selector: string;
47
+ label: string;
48
+ tagName: string;
49
+ originalRect: BoundingBox;
50
+ currentRect: BoundingBox;
51
+ }
52
+ interface Annotation {
53
+ id: string;
54
+ sessionId: string;
55
+ createdAt: string;
56
+ updatedAt?: string;
57
+ url: string;
58
+ status: AnnotationStatus;
59
+ resolvedAt?: string;
60
+ resolvedBy?: 'human' | 'agent';
61
+ comment: string;
62
+ intent: AnnotationIntent;
63
+ severity?: AnnotationSeverity;
64
+ thread?: ThreadMessage[];
65
+ element: string;
66
+ elementPath: string;
67
+ fullPath?: string;
68
+ cssClasses?: string;
69
+ computedStyles?: string;
70
+ accessibility?: string;
71
+ nearbyText?: string;
72
+ selectedText?: string;
73
+ boundingBox?: BoundingBox;
74
+ isFixed?: boolean;
75
+ isMultiSelect?: boolean;
76
+ kind?: AnnotationKind;
77
+ placement?: PlacementData;
78
+ rearrange?: RearrangeData;
79
+ framework: Framework;
80
+ source?: SourceLocation;
81
+ componentStack?: SourceLocation[];
82
+ selector?: SelectorResult;
83
+ outerHtml?: string;
84
+ screenshot?: string;
85
+ }
86
+ interface Session {
87
+ id: string;
88
+ url: string;
89
+ status: 'active' | 'approved' | 'closed';
90
+ createdAt: string;
91
+ updatedAt?: string;
92
+ projectId?: string;
93
+ metadata?: Record<string, unknown>;
94
+ }
95
+ interface SessionWithAnnotations extends Session {
96
+ annotations: Annotation[];
97
+ }
98
+ type AFSEventType = 'session.created' | 'session.updated' | 'session.closed' | 'annotation.created' | 'annotation.updated' | 'annotation.deleted' | 'thread.message' | 'action.requested';
99
+ interface AFSEvent<T = unknown> {
100
+ type: AFSEventType;
101
+ timestamp: string;
102
+ sessionId: string;
103
+ sequence: number;
104
+ payload: T;
105
+ }
106
+ interface PendingResponse {
107
+ count: number;
108
+ annotations: Annotation[];
109
+ }
110
+ type WsMessage = {
111
+ type: 'probe:hello';
112
+ refId: string;
113
+ clientId: string;
114
+ url: string;
115
+ } | {
116
+ type: 'probe:annotation';
117
+ refId: string;
118
+ data: Annotation;
119
+ } | {
120
+ type: 'probe:status';
121
+ refId: string;
122
+ annotationId: string;
123
+ status: AnnotationStatus;
124
+ } | {
125
+ type: 'probe:console';
126
+ refId: string;
127
+ level: 'log' | 'warn' | 'error';
128
+ message: string;
129
+ stack?: string;
130
+ } | {
131
+ type: 'probe:ack';
132
+ refId: string;
133
+ ok: boolean;
134
+ error?: string;
135
+ };
136
+
137
+ type OutputLevel = 'compact' | 'standard' | 'detailed' | 'forensic';
138
+ type ToolbarPosition = 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';
139
+ type Theme = 'auto' | 'light' | 'dark';
140
+ type TransportName = 'clipboard' | 'mcp' | 'server';
141
+ interface SourceMapConfig {
142
+ enabled: boolean;
143
+ timeoutMs: number;
144
+ cacheSize: number;
145
+ allowOrigins: string[];
146
+ }
147
+ interface ResolverConfig {
148
+ enabled: Framework[] | 'auto';
149
+ sourceMap: SourceMapConfig;
150
+ truncateHtml: number;
151
+ }
152
+ interface ToolbarConfig {
153
+ position: ToolbarPosition;
154
+ activationKey: string;
155
+ theme: Theme;
156
+ enabled: boolean;
157
+ hideInProduction: boolean;
158
+ }
159
+ interface SelectorConfig {
160
+ strategies: string[];
161
+ blocklistClassPatterns: string[];
162
+ requireUniqueness: boolean;
163
+ }
164
+ interface McpConfig {
165
+ endpoint: string;
166
+ sessionId?: string;
167
+ apiKey?: string;
168
+ }
169
+ interface ServerTransportConfig {
170
+ endpoint: string;
171
+ protocol: 'http' | 'ws';
172
+ csrfToken?: string;
173
+ headers?: Record<string, string>;
174
+ }
175
+ interface PrivacyConfig {
176
+ redactInputs: boolean;
177
+ redactSelectors: string[];
178
+ captureScreenshot: boolean;
179
+ }
180
+ interface ProbeConfig {
181
+ transport: TransportName | TransportName[];
182
+ outputLevel: OutputLevel;
183
+ toolbar: ToolbarConfig;
184
+ resolver: ResolverConfig;
185
+ selector: SelectorConfig;
186
+ mcp: McpConfig;
187
+ server: ServerTransportConfig;
188
+ privacy: PrivacyConfig;
189
+ debug: boolean;
190
+ }
191
+ declare const DEFAULT_CONFIG: ProbeConfig;
192
+ type DeepPartial<T> = {
193
+ [K in keyof T]?: T[K] extends object ? DeepPartial<T[K]> : T[K];
194
+ };
195
+ declare function defineConfig(config: DeepPartial<ProbeConfig>): DeepPartial<ProbeConfig>;
196
+ declare function mergeConfig(base: ProbeConfig, override: DeepPartial<ProbeConfig> | undefined): ProbeConfig;
197
+
198
+ export { type AFSEvent, type AFSEventType, type Annotation, type AnnotationIntent, type AnnotationKind, type AnnotationSeverity, type AnnotationStatus, type BoundingBox, DEFAULT_CONFIG, type DeepPartial, type ElementInfo, type Framework, type McpConfig, type OutputLevel, type PendingResponse, type PlacementData, type PrivacyConfig, type ProbeConfig, type RearrangeData, type ResolverConfig, type SelectorConfig, type SelectorResult, type ServerTransportConfig, type Session, type SessionWithAnnotations, type SourceLocation, type SourceMapConfig, type Theme, type ThreadMessage, type ToolbarConfig, type ToolbarPosition, type TransportName, type WsMessage, defineConfig, mergeConfig };
package/dist/index.js ADDED
@@ -0,0 +1,90 @@
1
+ // src/config.ts
2
+ var DEFAULT_CONFIG = {
3
+ transport: "clipboard",
4
+ outputLevel: "standard",
5
+ toolbar: {
6
+ position: "bottom-right",
7
+ activationKey: "Mod+Shift+E",
8
+ theme: "auto",
9
+ enabled: true,
10
+ hideInProduction: true
11
+ },
12
+ resolver: {
13
+ enabled: "auto",
14
+ sourceMap: {
15
+ enabled: true,
16
+ timeoutMs: 3e3,
17
+ cacheSize: 64,
18
+ allowOrigins: []
19
+ },
20
+ truncateHtml: 1024
21
+ },
22
+ selector: {
23
+ strategies: [
24
+ "data-testid",
25
+ "aria-label",
26
+ "unique-id",
27
+ "stable-classes",
28
+ "role-and-text",
29
+ "structural"
30
+ ],
31
+ blocklistClassPatterns: [],
32
+ requireUniqueness: false
33
+ },
34
+ mcp: {
35
+ endpoint: "http://127.0.0.1:3100"
36
+ },
37
+ server: {
38
+ endpoint: "",
39
+ protocol: "http"
40
+ },
41
+ privacy: {
42
+ redactInputs: true,
43
+ redactSelectors: ['input[type="password"]', "[data-sensitive]"],
44
+ captureScreenshot: false
45
+ },
46
+ debug: false
47
+ };
48
+ function defineConfig(config) {
49
+ return config;
50
+ }
51
+ function mergeConfig(base, override) {
52
+ if (!override) return base;
53
+ const baseRec = base;
54
+ const overrideRec = override;
55
+ const merged = { ...baseRec };
56
+ for (const key of Object.keys(overrideRec)) {
57
+ const baseVal = baseRec[key];
58
+ const overrideVal = overrideRec[key];
59
+ if (overrideVal === void 0) continue;
60
+ if (baseVal !== null && typeof baseVal === "object" && !Array.isArray(baseVal) && typeof overrideVal === "object" && !Array.isArray(overrideVal)) {
61
+ merged[key] = mergeDeep(
62
+ baseVal,
63
+ overrideVal
64
+ );
65
+ } else {
66
+ merged[key] = overrideVal;
67
+ }
68
+ }
69
+ return merged;
70
+ }
71
+ function mergeDeep(a, b) {
72
+ const out = { ...a };
73
+ for (const key in b) {
74
+ const av = a[key];
75
+ const bv = b[key];
76
+ if (bv === void 0) continue;
77
+ if (av !== null && typeof av === "object" && !Array.isArray(av) && typeof bv === "object" && !Array.isArray(bv)) {
78
+ out[key] = mergeDeep(av, bv);
79
+ } else {
80
+ out[key] = bv;
81
+ }
82
+ }
83
+ return out;
84
+ }
85
+ export {
86
+ DEFAULT_CONFIG,
87
+ defineConfig,
88
+ mergeConfig
89
+ };
90
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/config.ts"],"sourcesContent":["import type { Framework } from './types.js';\n\nexport type OutputLevel = 'compact' | 'standard' | 'detailed' | 'forensic';\nexport type ToolbarPosition = 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';\nexport type Theme = 'auto' | 'light' | 'dark';\nexport type TransportName = 'clipboard' | 'mcp' | 'server';\n\nexport interface SourceMapConfig {\n enabled: boolean;\n timeoutMs: number;\n cacheSize: number;\n allowOrigins: string[];\n}\n\nexport interface ResolverConfig {\n enabled: Framework[] | 'auto';\n sourceMap: SourceMapConfig;\n truncateHtml: number;\n}\n\nexport interface ToolbarConfig {\n position: ToolbarPosition;\n activationKey: string;\n theme: Theme;\n enabled: boolean;\n hideInProduction: boolean;\n}\n\nexport interface SelectorConfig {\n strategies: string[];\n blocklistClassPatterns: string[];\n requireUniqueness: boolean;\n}\n\nexport interface McpConfig {\n endpoint: string;\n sessionId?: string;\n apiKey?: string;\n}\n\nexport interface ServerTransportConfig {\n endpoint: string;\n protocol: 'http' | 'ws';\n csrfToken?: string;\n headers?: Record<string, string>;\n}\n\nexport interface PrivacyConfig {\n redactInputs: boolean;\n redactSelectors: string[];\n captureScreenshot: boolean;\n}\n\nexport interface ProbeConfig {\n transport: TransportName | TransportName[];\n outputLevel: OutputLevel;\n toolbar: ToolbarConfig;\n resolver: ResolverConfig;\n selector: SelectorConfig;\n mcp: McpConfig;\n server: ServerTransportConfig;\n privacy: PrivacyConfig;\n debug: boolean;\n}\n\nexport const DEFAULT_CONFIG: ProbeConfig = {\n transport: 'clipboard',\n outputLevel: 'standard',\n toolbar: {\n position: 'bottom-right',\n activationKey: 'Mod+Shift+E',\n theme: 'auto',\n enabled: true,\n hideInProduction: true,\n },\n resolver: {\n enabled: 'auto',\n sourceMap: {\n enabled: true,\n timeoutMs: 3000,\n cacheSize: 64,\n allowOrigins: [],\n },\n truncateHtml: 1024,\n },\n selector: {\n strategies: [\n 'data-testid',\n 'aria-label',\n 'unique-id',\n 'stable-classes',\n 'role-and-text',\n 'structural',\n ],\n blocklistClassPatterns: [],\n requireUniqueness: false,\n },\n mcp: {\n endpoint: 'http://127.0.0.1:3100',\n },\n server: {\n endpoint: '',\n protocol: 'http',\n },\n privacy: {\n redactInputs: true,\n redactSelectors: ['input[type=\"password\"]', '[data-sensitive]'],\n captureScreenshot: false,\n },\n debug: false,\n};\n\nexport type DeepPartial<T> = {\n [K in keyof T]?: T[K] extends object ? DeepPartial<T[K]> : T[K];\n};\n\nexport function defineConfig(config: DeepPartial<ProbeConfig>): DeepPartial<ProbeConfig> {\n return config;\n}\n\nexport function mergeConfig(\n base: ProbeConfig,\n override: DeepPartial<ProbeConfig> | undefined\n): ProbeConfig {\n if (!override) return base;\n const baseRec = base as unknown as Record<string, unknown>;\n const overrideRec = override as unknown as Record<string, unknown>;\n const merged: Record<string, unknown> = { ...baseRec };\n for (const key of Object.keys(overrideRec)) {\n const baseVal = baseRec[key];\n const overrideVal = overrideRec[key];\n if (overrideVal === undefined) continue;\n if (\n baseVal !== null &&\n typeof baseVal === 'object' &&\n !Array.isArray(baseVal) &&\n typeof overrideVal === 'object' &&\n !Array.isArray(overrideVal)\n ) {\n merged[key] = mergeDeep(\n baseVal as Record<string, unknown>,\n overrideVal as Record<string, unknown>\n );\n } else {\n merged[key] = overrideVal;\n }\n }\n return merged as unknown as ProbeConfig;\n}\n\nfunction mergeDeep(\n a: Record<string, unknown>,\n b: Record<string, unknown>\n): Record<string, unknown> {\n const out: Record<string, unknown> = { ...a };\n for (const key in b) {\n const av = a[key];\n const bv = b[key];\n if (bv === undefined) continue;\n if (\n av !== null &&\n typeof av === 'object' &&\n !Array.isArray(av) &&\n typeof bv === 'object' &&\n !Array.isArray(bv)\n ) {\n out[key] = mergeDeep(av as Record<string, unknown>, bv as Record<string, unknown>);\n } else {\n out[key] = bv;\n }\n }\n return out;\n}\n"],"mappings":";AAiEO,IAAM,iBAA8B;AAAA,EACzC,WAAW;AAAA,EACX,aAAa;AAAA,EACb,SAAS;AAAA,IACP,UAAU;AAAA,IACV,eAAe;AAAA,IACf,OAAO;AAAA,IACP,SAAS;AAAA,IACT,kBAAkB;AAAA,EACpB;AAAA,EACA,UAAU;AAAA,IACR,SAAS;AAAA,IACT,WAAW;AAAA,MACT,SAAS;AAAA,MACT,WAAW;AAAA,MACX,WAAW;AAAA,MACX,cAAc,CAAC;AAAA,IACjB;AAAA,IACA,cAAc;AAAA,EAChB;AAAA,EACA,UAAU;AAAA,IACR,YAAY;AAAA,MACV;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,IACA,wBAAwB,CAAC;AAAA,IACzB,mBAAmB;AAAA,EACrB;AAAA,EACA,KAAK;AAAA,IACH,UAAU;AAAA,EACZ;AAAA,EACA,QAAQ;AAAA,IACN,UAAU;AAAA,IACV,UAAU;AAAA,EACZ;AAAA,EACA,SAAS;AAAA,IACP,cAAc;AAAA,IACd,iBAAiB,CAAC,0BAA0B,kBAAkB;AAAA,IAC9D,mBAAmB;AAAA,EACrB;AAAA,EACA,OAAO;AACT;AAMO,SAAS,aAAa,QAA4D;AACvF,SAAO;AACT;AAEO,SAAS,YACd,MACA,UACa;AACb,MAAI,CAAC,SAAU,QAAO;AACtB,QAAM,UAAU;AAChB,QAAM,cAAc;AACpB,QAAM,SAAkC,EAAE,GAAG,QAAQ;AACrD,aAAW,OAAO,OAAO,KAAK,WAAW,GAAG;AAC1C,UAAM,UAAU,QAAQ,GAAG;AAC3B,UAAM,cAAc,YAAY,GAAG;AACnC,QAAI,gBAAgB,OAAW;AAC/B,QACE,YAAY,QACZ,OAAO,YAAY,YACnB,CAAC,MAAM,QAAQ,OAAO,KACtB,OAAO,gBAAgB,YACvB,CAAC,MAAM,QAAQ,WAAW,GAC1B;AACA,aAAO,GAAG,IAAI;AAAA,QACZ;AAAA,QACA;AAAA,MACF;AAAA,IACF,OAAO;AACL,aAAO,GAAG,IAAI;AAAA,IAChB;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,UACP,GACA,GACyB;AACzB,QAAM,MAA+B,EAAE,GAAG,EAAE;AAC5C,aAAW,OAAO,GAAG;AACnB,UAAM,KAAK,EAAE,GAAG;AAChB,UAAM,KAAK,EAAE,GAAG;AAChB,QAAI,OAAO,OAAW;AACtB,QACE,OAAO,QACP,OAAO,OAAO,YACd,CAAC,MAAM,QAAQ,EAAE,KACjB,OAAO,OAAO,YACd,CAAC,MAAM,QAAQ,EAAE,GACjB;AACA,UAAI,GAAG,IAAI,UAAU,IAA+B,EAA6B;AAAA,IACnF,OAAO;AACL,UAAI,GAAG,IAAI;AAAA,IACb;AAAA,EACF;AACA,SAAO;AACT;","names":[]}
package/package.json ADDED
@@ -0,0 +1,56 @@
1
+ {
2
+ "name": "@open-probe/shared",
3
+ "version": "0.1.1",
4
+ "description": "Shared types and AFS v1 protocol definitions for open-probe.",
5
+ "license": "MIT",
6
+ "author": "open-probe contributors",
7
+ "homepage": "https://github.com/wzc520pyfm/open-probe/tree/main/packages/shared#readme",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/wzc520pyfm/open-probe.git",
11
+ "directory": "packages/shared"
12
+ },
13
+ "bugs": {
14
+ "url": "https://github.com/wzc520pyfm/open-probe/issues"
15
+ },
16
+ "keywords": [
17
+ "open-probe",
18
+ "afs",
19
+ "annotation-format-schema",
20
+ "types"
21
+ ],
22
+ "type": "module",
23
+ "main": "./dist/index.js",
24
+ "module": "./dist/index.js",
25
+ "types": "./dist/index.d.ts",
26
+ "exports": {
27
+ ".": {
28
+ "types": "./dist/index.d.ts",
29
+ "import": "./dist/index.js"
30
+ }
31
+ },
32
+ "files": [
33
+ "dist",
34
+ "README.md",
35
+ "LICENSE"
36
+ ],
37
+ "sideEffects": false,
38
+ "publishConfig": {
39
+ "access": "public"
40
+ },
41
+ "engines": {
42
+ "node": ">=18.18"
43
+ },
44
+ "devDependencies": {
45
+ "tsup": "^8.3.5",
46
+ "typescript": "^5.7.3",
47
+ "vitest": "^2.1.8"
48
+ },
49
+ "scripts": {
50
+ "build": "tsup",
51
+ "dev": "tsup --watch",
52
+ "typecheck": "tsc --noEmit",
53
+ "test": "vitest run --passWithNoTests",
54
+ "clean": "rm -rf dist"
55
+ }
56
+ }