web-remarq 0.5.0 → 0.7.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/README.md +62 -3
- package/dist/core/index.cjs +193 -41
- package/dist/core/index.cjs.map +1 -1
- package/dist/core/index.d.cts +76 -14
- package/dist/core/index.d.ts +76 -14
- package/dist/core/index.js +187 -40
- package/dist/core/index.js.map +1 -1
- package/dist/index.cjs +557 -119
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +60 -3
- package/dist/index.d.ts +60 -3
- package/dist/index.js +556 -119
- package/dist/index.js.map +1 -1
- package/dist/web-remarq.global.global.js +556 -119
- package/dist/web-remarq.global.global.js.map +1 -1
- package/package.json +1 -1
package/dist/core/index.d.cts
CHANGED
|
@@ -26,6 +26,16 @@ interface ElementFingerprint {
|
|
|
26
26
|
detectedSource: string | null;
|
|
27
27
|
detectedComponent: string | null;
|
|
28
28
|
}
|
|
29
|
+
type AnnotationStatus = 'pending' | 'in_progress' | 'fixed_unverified' | 'verified' | 'dismissed';
|
|
30
|
+
type Actor = 'designer' | 'agent' | 'developer';
|
|
31
|
+
type AnnotationEventType = 'created' | 'acknowledged' | 'fix_claimed' | 'verified' | 'rejected' | 'dismissed' | 'reopened' | 'migrated';
|
|
32
|
+
interface AnnotationEvent {
|
|
33
|
+
type: AnnotationEventType;
|
|
34
|
+
actor: Actor | null;
|
|
35
|
+
actorName?: string;
|
|
36
|
+
timestamp: number;
|
|
37
|
+
reason?: string;
|
|
38
|
+
}
|
|
29
39
|
interface Annotation {
|
|
30
40
|
id: string;
|
|
31
41
|
comment: string;
|
|
@@ -34,7 +44,8 @@ interface Annotation {
|
|
|
34
44
|
viewport: string;
|
|
35
45
|
viewportBucket: number;
|
|
36
46
|
timestamp: number;
|
|
37
|
-
status:
|
|
47
|
+
status: AnnotationStatus;
|
|
48
|
+
lifecycle: AnnotationEvent[];
|
|
38
49
|
}
|
|
39
50
|
interface AnnotationStore {
|
|
40
51
|
version: 1;
|
|
@@ -47,6 +58,7 @@ interface WebRemarqOptions {
|
|
|
47
58
|
dataAttribute?: string;
|
|
48
59
|
position?: ToolbarPosition;
|
|
49
60
|
shortcuts?: boolean;
|
|
61
|
+
storage?: StorageAdapter;
|
|
50
62
|
}
|
|
51
63
|
type SearchConfidence = 'high' | 'medium' | 'low';
|
|
52
64
|
interface GrepQuery {
|
|
@@ -66,14 +78,21 @@ interface AgentAnnotationSource {
|
|
|
66
78
|
column: number;
|
|
67
79
|
component: string | null;
|
|
68
80
|
}
|
|
81
|
+
interface AgentLifecycleEvent {
|
|
82
|
+
type: AnnotationEventType;
|
|
83
|
+
actor: Actor | null;
|
|
84
|
+
timestamp: number;
|
|
85
|
+
reason?: string;
|
|
86
|
+
}
|
|
69
87
|
interface AgentAnnotation {
|
|
70
88
|
id: string;
|
|
71
89
|
route: string;
|
|
72
90
|
comment: string;
|
|
73
|
-
status:
|
|
91
|
+
status: AnnotationStatus;
|
|
74
92
|
timestamp: number;
|
|
75
93
|
source: AgentAnnotationSource | null;
|
|
76
94
|
searchHints: AgentSearchHints;
|
|
95
|
+
lifecycle: AgentLifecycleEvent[];
|
|
77
96
|
}
|
|
78
97
|
interface AgentExport {
|
|
79
98
|
version: 1;
|
|
@@ -81,27 +100,54 @@ interface AgentExport {
|
|
|
81
100
|
viewportBucket: number;
|
|
82
101
|
annotations: AgentAnnotation[];
|
|
83
102
|
}
|
|
103
|
+
interface StorageChangeEvent {
|
|
104
|
+
type: 'add' | 'update' | 'remove' | 'clear';
|
|
105
|
+
annotation?: Annotation;
|
|
106
|
+
id?: string;
|
|
107
|
+
}
|
|
108
|
+
interface StorageAdapter {
|
|
109
|
+
load(): Promise<AnnotationStore | null>;
|
|
110
|
+
save(annotation: Annotation): Promise<void>;
|
|
111
|
+
remove(id: string): Promise<void>;
|
|
112
|
+
clear(): Promise<void>;
|
|
113
|
+
subscribe?(callback: (event: StorageChangeEvent) => void): () => void;
|
|
114
|
+
readonly isMemoryOnly?: boolean;
|
|
115
|
+
}
|
|
84
116
|
|
|
85
117
|
declare function createFingerprint(el: HTMLElement, options?: Pick<WebRemarqOptions, 'classFilter' | 'dataAttribute'>): ElementFingerprint;
|
|
86
118
|
|
|
87
119
|
declare function matchElement(fp: ElementFingerprint, options?: Pick<WebRemarqOptions, 'dataAttribute'>): HTMLElement | null;
|
|
88
120
|
|
|
121
|
+
declare function migrateAnnotation(legacy: any): Annotation;
|
|
89
122
|
declare class AnnotationStorage {
|
|
90
|
-
private
|
|
91
|
-
private
|
|
92
|
-
|
|
93
|
-
constructor();
|
|
123
|
+
private adapter;
|
|
124
|
+
private cache;
|
|
125
|
+
readonly ready: Promise<void>;
|
|
126
|
+
constructor(adapter: StorageAdapter);
|
|
127
|
+
get isMemoryOnly(): boolean;
|
|
94
128
|
getAll(): Annotation[];
|
|
95
129
|
getByRoute(route: string): Annotation[];
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
130
|
+
getById(id: string): Annotation | undefined;
|
|
131
|
+
add(annotation: Annotation): Promise<void>;
|
|
132
|
+
remove(id: string): Promise<void>;
|
|
133
|
+
update(id: string, changes: Partial<Annotation>): Promise<void>;
|
|
134
|
+
clearAll(): Promise<void>;
|
|
100
135
|
exportJSON(): AnnotationStore;
|
|
101
|
-
importJSON(data: AnnotationStore): void
|
|
136
|
+
importJSON(data: AnnotationStore): Promise<void>;
|
|
137
|
+
private init;
|
|
102
138
|
private migrateViewportBuckets;
|
|
103
|
-
|
|
104
|
-
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
declare class LocalStorageAdapter implements StorageAdapter {
|
|
142
|
+
isMemoryOnly: boolean;
|
|
143
|
+
private extraFields;
|
|
144
|
+
private memoryStore;
|
|
145
|
+
load(): Promise<AnnotationStore | null>;
|
|
146
|
+
save(annotation: Annotation): Promise<void>;
|
|
147
|
+
remove(id: string): Promise<void>;
|
|
148
|
+
clear(): Promise<void>;
|
|
149
|
+
private ensureStore;
|
|
150
|
+
private persist;
|
|
105
151
|
}
|
|
106
152
|
|
|
107
153
|
/**
|
|
@@ -116,4 +162,20 @@ declare function detectSource(el: HTMLElement): SourceDetectionResult;
|
|
|
116
162
|
|
|
117
163
|
declare function generateAgentExport(annotations: Annotation[], viewportBucket: number): AgentExport;
|
|
118
164
|
|
|
119
|
-
|
|
165
|
+
type LifecycleAction = 'acknowledge' | 'claimFix' | 'verify' | 'reject' | 'dismiss' | 'reopen';
|
|
166
|
+
declare class InvalidTransitionError extends Error {
|
|
167
|
+
constructor(from: AnnotationStatus, action: LifecycleAction);
|
|
168
|
+
}
|
|
169
|
+
interface EventOpts {
|
|
170
|
+
actor?: Actor;
|
|
171
|
+
actorName?: string;
|
|
172
|
+
reason?: string;
|
|
173
|
+
timestamp?: number;
|
|
174
|
+
}
|
|
175
|
+
declare function createEvent(type: AnnotationEventType, opts?: EventOpts): AnnotationEvent;
|
|
176
|
+
declare function transition(annotation: Annotation, action: LifecycleAction, opts?: EventOpts): {
|
|
177
|
+
status: AnnotationStatus;
|
|
178
|
+
event: AnnotationEvent;
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
export { type Actor, type AgentAnnotation, type AgentAnnotationSource, type AgentExport, type AgentLifecycleEvent, type AgentSearchHints, type Annotation, type AnnotationEvent, type AnnotationEventType, type AnnotationStatus, AnnotationStorage, type AnnotationStore, type CSSModuleClass, type ElementFingerprint, type EventOpts, type GrepQuery, InvalidTransitionError, type LifecycleAction, LocalStorageAdapter, type SearchConfidence, type SourceDetectionResult, type StorageAdapter, type StorageChangeEvent, type ToolbarPosition, createEvent, createFingerprint, detectRemarqPlugin, detectSource, generateAgentExport, matchElement, migrateAnnotation, transition };
|
package/dist/core/index.d.ts
CHANGED
|
@@ -26,6 +26,16 @@ interface ElementFingerprint {
|
|
|
26
26
|
detectedSource: string | null;
|
|
27
27
|
detectedComponent: string | null;
|
|
28
28
|
}
|
|
29
|
+
type AnnotationStatus = 'pending' | 'in_progress' | 'fixed_unverified' | 'verified' | 'dismissed';
|
|
30
|
+
type Actor = 'designer' | 'agent' | 'developer';
|
|
31
|
+
type AnnotationEventType = 'created' | 'acknowledged' | 'fix_claimed' | 'verified' | 'rejected' | 'dismissed' | 'reopened' | 'migrated';
|
|
32
|
+
interface AnnotationEvent {
|
|
33
|
+
type: AnnotationEventType;
|
|
34
|
+
actor: Actor | null;
|
|
35
|
+
actorName?: string;
|
|
36
|
+
timestamp: number;
|
|
37
|
+
reason?: string;
|
|
38
|
+
}
|
|
29
39
|
interface Annotation {
|
|
30
40
|
id: string;
|
|
31
41
|
comment: string;
|
|
@@ -34,7 +44,8 @@ interface Annotation {
|
|
|
34
44
|
viewport: string;
|
|
35
45
|
viewportBucket: number;
|
|
36
46
|
timestamp: number;
|
|
37
|
-
status:
|
|
47
|
+
status: AnnotationStatus;
|
|
48
|
+
lifecycle: AnnotationEvent[];
|
|
38
49
|
}
|
|
39
50
|
interface AnnotationStore {
|
|
40
51
|
version: 1;
|
|
@@ -47,6 +58,7 @@ interface WebRemarqOptions {
|
|
|
47
58
|
dataAttribute?: string;
|
|
48
59
|
position?: ToolbarPosition;
|
|
49
60
|
shortcuts?: boolean;
|
|
61
|
+
storage?: StorageAdapter;
|
|
50
62
|
}
|
|
51
63
|
type SearchConfidence = 'high' | 'medium' | 'low';
|
|
52
64
|
interface GrepQuery {
|
|
@@ -66,14 +78,21 @@ interface AgentAnnotationSource {
|
|
|
66
78
|
column: number;
|
|
67
79
|
component: string | null;
|
|
68
80
|
}
|
|
81
|
+
interface AgentLifecycleEvent {
|
|
82
|
+
type: AnnotationEventType;
|
|
83
|
+
actor: Actor | null;
|
|
84
|
+
timestamp: number;
|
|
85
|
+
reason?: string;
|
|
86
|
+
}
|
|
69
87
|
interface AgentAnnotation {
|
|
70
88
|
id: string;
|
|
71
89
|
route: string;
|
|
72
90
|
comment: string;
|
|
73
|
-
status:
|
|
91
|
+
status: AnnotationStatus;
|
|
74
92
|
timestamp: number;
|
|
75
93
|
source: AgentAnnotationSource | null;
|
|
76
94
|
searchHints: AgentSearchHints;
|
|
95
|
+
lifecycle: AgentLifecycleEvent[];
|
|
77
96
|
}
|
|
78
97
|
interface AgentExport {
|
|
79
98
|
version: 1;
|
|
@@ -81,27 +100,54 @@ interface AgentExport {
|
|
|
81
100
|
viewportBucket: number;
|
|
82
101
|
annotations: AgentAnnotation[];
|
|
83
102
|
}
|
|
103
|
+
interface StorageChangeEvent {
|
|
104
|
+
type: 'add' | 'update' | 'remove' | 'clear';
|
|
105
|
+
annotation?: Annotation;
|
|
106
|
+
id?: string;
|
|
107
|
+
}
|
|
108
|
+
interface StorageAdapter {
|
|
109
|
+
load(): Promise<AnnotationStore | null>;
|
|
110
|
+
save(annotation: Annotation): Promise<void>;
|
|
111
|
+
remove(id: string): Promise<void>;
|
|
112
|
+
clear(): Promise<void>;
|
|
113
|
+
subscribe?(callback: (event: StorageChangeEvent) => void): () => void;
|
|
114
|
+
readonly isMemoryOnly?: boolean;
|
|
115
|
+
}
|
|
84
116
|
|
|
85
117
|
declare function createFingerprint(el: HTMLElement, options?: Pick<WebRemarqOptions, 'classFilter' | 'dataAttribute'>): ElementFingerprint;
|
|
86
118
|
|
|
87
119
|
declare function matchElement(fp: ElementFingerprint, options?: Pick<WebRemarqOptions, 'dataAttribute'>): HTMLElement | null;
|
|
88
120
|
|
|
121
|
+
declare function migrateAnnotation(legacy: any): Annotation;
|
|
89
122
|
declare class AnnotationStorage {
|
|
90
|
-
private
|
|
91
|
-
private
|
|
92
|
-
|
|
93
|
-
constructor();
|
|
123
|
+
private adapter;
|
|
124
|
+
private cache;
|
|
125
|
+
readonly ready: Promise<void>;
|
|
126
|
+
constructor(adapter: StorageAdapter);
|
|
127
|
+
get isMemoryOnly(): boolean;
|
|
94
128
|
getAll(): Annotation[];
|
|
95
129
|
getByRoute(route: string): Annotation[];
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
130
|
+
getById(id: string): Annotation | undefined;
|
|
131
|
+
add(annotation: Annotation): Promise<void>;
|
|
132
|
+
remove(id: string): Promise<void>;
|
|
133
|
+
update(id: string, changes: Partial<Annotation>): Promise<void>;
|
|
134
|
+
clearAll(): Promise<void>;
|
|
100
135
|
exportJSON(): AnnotationStore;
|
|
101
|
-
importJSON(data: AnnotationStore): void
|
|
136
|
+
importJSON(data: AnnotationStore): Promise<void>;
|
|
137
|
+
private init;
|
|
102
138
|
private migrateViewportBuckets;
|
|
103
|
-
|
|
104
|
-
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
declare class LocalStorageAdapter implements StorageAdapter {
|
|
142
|
+
isMemoryOnly: boolean;
|
|
143
|
+
private extraFields;
|
|
144
|
+
private memoryStore;
|
|
145
|
+
load(): Promise<AnnotationStore | null>;
|
|
146
|
+
save(annotation: Annotation): Promise<void>;
|
|
147
|
+
remove(id: string): Promise<void>;
|
|
148
|
+
clear(): Promise<void>;
|
|
149
|
+
private ensureStore;
|
|
150
|
+
private persist;
|
|
105
151
|
}
|
|
106
152
|
|
|
107
153
|
/**
|
|
@@ -116,4 +162,20 @@ declare function detectSource(el: HTMLElement): SourceDetectionResult;
|
|
|
116
162
|
|
|
117
163
|
declare function generateAgentExport(annotations: Annotation[], viewportBucket: number): AgentExport;
|
|
118
164
|
|
|
119
|
-
|
|
165
|
+
type LifecycleAction = 'acknowledge' | 'claimFix' | 'verify' | 'reject' | 'dismiss' | 'reopen';
|
|
166
|
+
declare class InvalidTransitionError extends Error {
|
|
167
|
+
constructor(from: AnnotationStatus, action: LifecycleAction);
|
|
168
|
+
}
|
|
169
|
+
interface EventOpts {
|
|
170
|
+
actor?: Actor;
|
|
171
|
+
actorName?: string;
|
|
172
|
+
reason?: string;
|
|
173
|
+
timestamp?: number;
|
|
174
|
+
}
|
|
175
|
+
declare function createEvent(type: AnnotationEventType, opts?: EventOpts): AnnotationEvent;
|
|
176
|
+
declare function transition(annotation: Annotation, action: LifecycleAction, opts?: EventOpts): {
|
|
177
|
+
status: AnnotationStatus;
|
|
178
|
+
event: AnnotationEvent;
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
export { type Actor, type AgentAnnotation, type AgentAnnotationSource, type AgentExport, type AgentLifecycleEvent, type AgentSearchHints, type Annotation, type AnnotationEvent, type AnnotationEventType, type AnnotationStatus, AnnotationStorage, type AnnotationStore, type CSSModuleClass, type ElementFingerprint, type EventOpts, type GrepQuery, InvalidTransitionError, type LifecycleAction, LocalStorageAdapter, type SearchConfidence, type SourceDetectionResult, type StorageAdapter, type StorageChangeEvent, type ToolbarPosition, createEvent, createFingerprint, detectRemarqPlugin, detectSource, generateAgentExport, matchElement, migrateAnnotation, transition };
|
package/dist/core/index.js
CHANGED
|
@@ -351,79 +351,151 @@ function toBucket(width) {
|
|
|
351
351
|
}
|
|
352
352
|
|
|
353
353
|
// src/core/storage.ts
|
|
354
|
-
|
|
354
|
+
function migrateAnnotation(legacy) {
|
|
355
|
+
const rawStatus = legacy.status;
|
|
356
|
+
const status = rawStatus === "resolved" ? "verified" : rawStatus;
|
|
357
|
+
if (Array.isArray(legacy.lifecycle) && legacy.lifecycle.length > 0) {
|
|
358
|
+
return __spreadProps(__spreadValues({}, legacy), { status, lifecycle: legacy.lifecycle });
|
|
359
|
+
}
|
|
360
|
+
const createdTs = typeof legacy.timestamp === "number" ? legacy.timestamp : Date.now();
|
|
361
|
+
const lifecycle = [
|
|
362
|
+
{ type: "created", actor: "designer", timestamp: createdTs }
|
|
363
|
+
];
|
|
364
|
+
if (rawStatus === "resolved") {
|
|
365
|
+
lifecycle.push({ type: "migrated", actor: null, timestamp: Date.now() });
|
|
366
|
+
}
|
|
367
|
+
return __spreadProps(__spreadValues({}, legacy), { status, lifecycle });
|
|
368
|
+
}
|
|
355
369
|
var AnnotationStorage = class {
|
|
356
|
-
constructor() {
|
|
357
|
-
this.
|
|
358
|
-
this.
|
|
359
|
-
this.
|
|
360
|
-
|
|
370
|
+
constructor(adapter) {
|
|
371
|
+
this.adapter = adapter;
|
|
372
|
+
this.cache = [];
|
|
373
|
+
this.ready = this.init();
|
|
374
|
+
}
|
|
375
|
+
get isMemoryOnly() {
|
|
376
|
+
var _a;
|
|
377
|
+
return (_a = this.adapter.isMemoryOnly) != null ? _a : false;
|
|
361
378
|
}
|
|
362
379
|
getAll() {
|
|
363
|
-
return [...this.
|
|
380
|
+
return [...this.cache];
|
|
364
381
|
}
|
|
365
382
|
getByRoute(route) {
|
|
366
|
-
return this.
|
|
383
|
+
return this.cache.filter((a) => a.route === route);
|
|
367
384
|
}
|
|
368
|
-
|
|
369
|
-
this.
|
|
370
|
-
this.save();
|
|
385
|
+
getById(id) {
|
|
386
|
+
return this.cache.find((a) => a.id === id);
|
|
371
387
|
}
|
|
372
|
-
|
|
373
|
-
this.
|
|
374
|
-
this.save();
|
|
388
|
+
async add(annotation) {
|
|
389
|
+
this.cache.push(annotation);
|
|
390
|
+
await this.adapter.save(annotation);
|
|
375
391
|
}
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
392
|
+
async remove(id) {
|
|
393
|
+
this.cache = this.cache.filter((a) => a.id !== id);
|
|
394
|
+
await this.adapter.remove(id);
|
|
395
|
+
}
|
|
396
|
+
async update(id, changes) {
|
|
397
|
+
const idx = this.cache.findIndex((a) => a.id === id);
|
|
398
|
+
if (idx === -1) return;
|
|
399
|
+
const updated = __spreadValues(__spreadValues({}, this.cache[idx]), changes);
|
|
400
|
+
this.cache[idx] = updated;
|
|
401
|
+
await this.adapter.save(updated);
|
|
382
402
|
}
|
|
383
|
-
clearAll() {
|
|
384
|
-
this.
|
|
385
|
-
this.
|
|
403
|
+
async clearAll() {
|
|
404
|
+
this.cache = [];
|
|
405
|
+
await this.adapter.clear();
|
|
386
406
|
}
|
|
387
407
|
exportJSON() {
|
|
388
408
|
return {
|
|
389
409
|
version: 1,
|
|
390
|
-
annotations: [...this.
|
|
410
|
+
annotations: [...this.cache]
|
|
391
411
|
};
|
|
392
412
|
}
|
|
393
|
-
importJSON(data) {
|
|
394
|
-
this.
|
|
413
|
+
async importJSON(data) {
|
|
414
|
+
this.cache = data.annotations.map(migrateAnnotation);
|
|
395
415
|
this.migrateViewportBuckets();
|
|
396
|
-
this.
|
|
416
|
+
await this.adapter.clear();
|
|
417
|
+
for (const ann of this.cache) {
|
|
418
|
+
await this.adapter.save(ann);
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
async init() {
|
|
422
|
+
const data = await this.adapter.load();
|
|
423
|
+
if (data) {
|
|
424
|
+
this.cache = data.annotations.map(migrateAnnotation);
|
|
425
|
+
this.migrateViewportBuckets();
|
|
426
|
+
}
|
|
397
427
|
}
|
|
398
428
|
migrateViewportBuckets() {
|
|
399
|
-
for (const ann of this.
|
|
429
|
+
for (const ann of this.cache) {
|
|
400
430
|
if (ann.viewportBucket == null && ann.viewport) {
|
|
401
431
|
const width = parseInt(ann.viewport.split("x")[0], 10);
|
|
402
432
|
ann.viewportBucket = toBucket(width);
|
|
403
433
|
}
|
|
404
434
|
}
|
|
405
435
|
}
|
|
406
|
-
|
|
436
|
+
};
|
|
437
|
+
|
|
438
|
+
// src/core/local-storage-adapter.ts
|
|
439
|
+
var STORAGE_KEY = "remarq:annotations";
|
|
440
|
+
var LocalStorageAdapter = class {
|
|
441
|
+
constructor() {
|
|
442
|
+
this.isMemoryOnly = false;
|
|
443
|
+
this.extraFields = {};
|
|
444
|
+
this.memoryStore = null;
|
|
445
|
+
}
|
|
446
|
+
async load() {
|
|
447
|
+
if (this.isMemoryOnly) return this.memoryStore;
|
|
407
448
|
try {
|
|
408
449
|
const raw = localStorage.getItem(STORAGE_KEY);
|
|
409
|
-
if (raw)
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
450
|
+
if (!raw) return null;
|
|
451
|
+
const parsed = JSON.parse(raw);
|
|
452
|
+
const _a = parsed, { version, annotations } = _a, rest = __objRest(_a, ["version", "annotations"]);
|
|
453
|
+
this.extraFields = rest;
|
|
454
|
+
const store = {
|
|
455
|
+
version: 1,
|
|
456
|
+
annotations: Array.isArray(annotations) ? annotations : []
|
|
457
|
+
};
|
|
458
|
+
this.memoryStore = store;
|
|
459
|
+
return store;
|
|
416
460
|
} catch (e) {
|
|
417
461
|
this.isMemoryOnly = true;
|
|
462
|
+
return this.memoryStore;
|
|
418
463
|
}
|
|
419
464
|
}
|
|
420
|
-
save() {
|
|
465
|
+
async save(annotation) {
|
|
466
|
+
const store = await this.ensureStore();
|
|
467
|
+
const idx = store.annotations.findIndex((a) => a.id === annotation.id);
|
|
468
|
+
if (idx === -1) {
|
|
469
|
+
store.annotations.push(annotation);
|
|
470
|
+
} else {
|
|
471
|
+
store.annotations[idx] = annotation;
|
|
472
|
+
}
|
|
473
|
+
this.persist(store);
|
|
474
|
+
}
|
|
475
|
+
async remove(id) {
|
|
476
|
+
const store = await this.ensureStore();
|
|
477
|
+
store.annotations = store.annotations.filter((a) => a.id !== id);
|
|
478
|
+
this.persist(store);
|
|
479
|
+
}
|
|
480
|
+
async clear() {
|
|
481
|
+
const store = await this.ensureStore();
|
|
482
|
+
store.annotations = [];
|
|
483
|
+
this.persist(store);
|
|
484
|
+
}
|
|
485
|
+
async ensureStore() {
|
|
486
|
+
if (this.memoryStore) return this.memoryStore;
|
|
487
|
+
const loaded = await this.load();
|
|
488
|
+
if (loaded) return loaded;
|
|
489
|
+
this.memoryStore = { version: 1, annotations: [] };
|
|
490
|
+
return this.memoryStore;
|
|
491
|
+
}
|
|
492
|
+
persist(store) {
|
|
421
493
|
if (this.isMemoryOnly) return;
|
|
422
494
|
try {
|
|
423
495
|
const data = __spreadProps(__spreadValues({
|
|
424
496
|
version: 1
|
|
425
497
|
}, this.extraFields), {
|
|
426
|
-
annotations:
|
|
498
|
+
annotations: store.annotations
|
|
427
499
|
});
|
|
428
500
|
localStorage.setItem(STORAGE_KEY, JSON.stringify(data));
|
|
429
501
|
} catch (e) {
|
|
@@ -504,7 +576,16 @@ function generateAgentExport(annotations, viewportBucket) {
|
|
|
504
576
|
status: ann.status,
|
|
505
577
|
timestamp: ann.timestamp,
|
|
506
578
|
source: resolveSource(ann.fingerprint),
|
|
507
|
-
searchHints: buildSearchHints(ann.fingerprint)
|
|
579
|
+
searchHints: buildSearchHints(ann.fingerprint),
|
|
580
|
+
lifecycle: ann.lifecycle.map((ev) => {
|
|
581
|
+
const out = {
|
|
582
|
+
type: ev.type,
|
|
583
|
+
actor: ev.actor,
|
|
584
|
+
timestamp: ev.timestamp
|
|
585
|
+
};
|
|
586
|
+
if (ev.reason !== void 0) out.reason = ev.reason;
|
|
587
|
+
return out;
|
|
588
|
+
})
|
|
508
589
|
}));
|
|
509
590
|
return {
|
|
510
591
|
version: 1,
|
|
@@ -513,12 +594,78 @@ function generateAgentExport(annotations, viewportBucket) {
|
|
|
513
594
|
annotations: agentAnnotations
|
|
514
595
|
};
|
|
515
596
|
}
|
|
597
|
+
|
|
598
|
+
// src/core/lifecycle.ts
|
|
599
|
+
var InvalidTransitionError = class extends Error {
|
|
600
|
+
constructor(from, action) {
|
|
601
|
+
super(`Cannot ${action} from status "${from}"`);
|
|
602
|
+
this.name = "InvalidTransitionError";
|
|
603
|
+
}
|
|
604
|
+
};
|
|
605
|
+
var ACTION_TO_EVENT = {
|
|
606
|
+
acknowledge: "acknowledged",
|
|
607
|
+
claimFix: "fix_claimed",
|
|
608
|
+
verify: "verified",
|
|
609
|
+
reject: "rejected",
|
|
610
|
+
dismiss: "dismissed",
|
|
611
|
+
reopen: "reopened"
|
|
612
|
+
};
|
|
613
|
+
var DEFAULT_ACTOR_BY_EVENT = {
|
|
614
|
+
created: "designer",
|
|
615
|
+
acknowledged: "developer",
|
|
616
|
+
fix_claimed: "agent",
|
|
617
|
+
verified: "developer",
|
|
618
|
+
rejected: "developer",
|
|
619
|
+
dismissed: "developer",
|
|
620
|
+
reopened: "developer",
|
|
621
|
+
migrated: null
|
|
622
|
+
};
|
|
623
|
+
function createEvent(type, opts = {}) {
|
|
624
|
+
var _a, _b;
|
|
625
|
+
const event = {
|
|
626
|
+
type,
|
|
627
|
+
actor: (_a = opts.actor) != null ? _a : DEFAULT_ACTOR_BY_EVENT[type],
|
|
628
|
+
timestamp: (_b = opts.timestamp) != null ? _b : Date.now()
|
|
629
|
+
};
|
|
630
|
+
if (opts.actorName !== void 0) event.actorName = opts.actorName;
|
|
631
|
+
if (opts.reason !== void 0) event.reason = opts.reason;
|
|
632
|
+
return event;
|
|
633
|
+
}
|
|
634
|
+
function nextStatus(from, action) {
|
|
635
|
+
switch (action) {
|
|
636
|
+
case "acknowledge":
|
|
637
|
+
return from === "pending" ? "in_progress" : null;
|
|
638
|
+
case "claimFix":
|
|
639
|
+
return from === "pending" || from === "in_progress" ? "fixed_unverified" : null;
|
|
640
|
+
case "verify":
|
|
641
|
+
return from === "fixed_unverified" || from === "in_progress" ? "verified" : null;
|
|
642
|
+
case "reject":
|
|
643
|
+
return from === "fixed_unverified" ? "pending" : null;
|
|
644
|
+
case "dismiss":
|
|
645
|
+
return from === "pending" || from === "in_progress" || from === "fixed_unverified" ? "dismissed" : null;
|
|
646
|
+
case "reopen":
|
|
647
|
+
return from === "dismissed" || from === "verified" ? "pending" : null;
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
function transition(annotation, action, opts = {}) {
|
|
651
|
+
const next = nextStatus(annotation.status, action);
|
|
652
|
+
if (next === null) {
|
|
653
|
+
throw new InvalidTransitionError(annotation.status, action);
|
|
654
|
+
}
|
|
655
|
+
const event = createEvent(ACTION_TO_EVENT[action], opts);
|
|
656
|
+
return { status: next, event };
|
|
657
|
+
}
|
|
516
658
|
export {
|
|
517
659
|
AnnotationStorage,
|
|
660
|
+
InvalidTransitionError,
|
|
661
|
+
LocalStorageAdapter,
|
|
662
|
+
createEvent,
|
|
518
663
|
createFingerprint,
|
|
519
664
|
detectRemarqPlugin,
|
|
520
665
|
detectSource,
|
|
521
666
|
generateAgentExport,
|
|
522
|
-
matchElement
|
|
667
|
+
matchElement,
|
|
668
|
+
migrateAnnotation,
|
|
669
|
+
transition
|
|
523
670
|
};
|
|
524
671
|
//# sourceMappingURL=index.js.map
|