checkpoint-cli 0.2.0 → 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +234 -72
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -81,12 +81,15 @@ function requireAuth() {
81
81
  /* ── Checkpoint Tracking Script (injected into HTML responses) ── */
82
82
  function trackingScript() {
83
83
  return `
84
- <script data-checkpoint>
84
+ <script data-checkpoint-script="1">
85
85
  (function(){
86
86
  var lastPath='';
87
87
  var pickMode=false;
88
88
  var pickClickHandler=null;
89
89
  var pickEscHandler=null;
90
+ var pickMoveHandler=null;
91
+ var pickInspectBox=null;
92
+ var pickInspectLabel=null;
90
93
 
91
94
  function getMetrics(){
92
95
  var de=document.documentElement;
@@ -120,6 +123,153 @@ function trackingScript() {
120
123
  return String(value).replace(/\\s+/g,' ').trim().slice(0,120);
121
124
  }
122
125
 
126
+ function getFileLeaf(path){
127
+ if(!path) return '';
128
+ try{
129
+ var raw=String(path);
130
+ var parts=raw.split(/[\\\\/]/);
131
+ return parts[parts.length-1]||raw;
132
+ }catch(e){}
133
+ return '';
134
+ }
135
+
136
+ function getInspectElementLabel(el){
137
+ if(!el||!el.tagName) return '(unknown)';
138
+ var tag=String(el.tagName).toLowerCase();
139
+ var id=el.id?('#'+el.id):'';
140
+ var classes='';
141
+ try{
142
+ var cls=(el.className&&typeof el.className==='string')
143
+ ? el.className.trim().split(/\\s+/).filter(Boolean).slice(0,3)
144
+ : [];
145
+ if(cls.length>0){
146
+ classes='.'+cls.join('.');
147
+ }
148
+ }catch(e){}
149
+ return shortText(tag+id+classes);
150
+ }
151
+
152
+ function ensurePickInspectUi(){
153
+ if(!document.body) return;
154
+ if(!pickInspectBox){
155
+ pickInspectBox=document.createElement('div');
156
+ pickInspectBox.setAttribute('data-checkpoint-inspect','box');
157
+ pickInspectBox.style.position='fixed';
158
+ pickInspectBox.style.left='0';
159
+ pickInspectBox.style.top='0';
160
+ pickInspectBox.style.width='0';
161
+ pickInspectBox.style.height='0';
162
+ pickInspectBox.style.border='2px solid #6366f1';
163
+ pickInspectBox.style.background='rgba(99,102,241,0.12)';
164
+ pickInspectBox.style.boxSizing='border-box';
165
+ pickInspectBox.style.borderRadius='4px';
166
+ pickInspectBox.style.pointerEvents='none';
167
+ pickInspectBox.style.zIndex='2147483646';
168
+ pickInspectBox.style.display='none';
169
+ document.body.appendChild(pickInspectBox);
170
+ }
171
+ if(!pickInspectLabel){
172
+ pickInspectLabel=document.createElement('div');
173
+ pickInspectLabel.setAttribute('data-checkpoint-inspect','label');
174
+ pickInspectLabel.style.position='fixed';
175
+ pickInspectLabel.style.left='0';
176
+ pickInspectLabel.style.top='0';
177
+ pickInspectLabel.style.maxWidth='380px';
178
+ pickInspectLabel.style.padding='6px 8px';
179
+ pickInspectLabel.style.borderRadius='8px';
180
+ pickInspectLabel.style.border='1px solid rgba(148,163,184,0.45)';
181
+ pickInspectLabel.style.background='rgba(15,23,42,0.96)';
182
+ pickInspectLabel.style.color='#e2e8f0';
183
+ pickInspectLabel.style.font='12px/1.35 ui-monospace, SFMono-Regular, Menlo, monospace';
184
+ pickInspectLabel.style.whiteSpace='pre-line';
185
+ pickInspectLabel.style.wordBreak='break-word';
186
+ pickInspectLabel.style.pointerEvents='none';
187
+ pickInspectLabel.style.zIndex='2147483647';
188
+ pickInspectLabel.style.display='none';
189
+ pickInspectLabel.style.boxShadow='0 6px 20px rgba(0,0,0,0.35)';
190
+ document.body.appendChild(pickInspectLabel);
191
+ }
192
+ }
193
+
194
+ function hidePickInspectUi(){
195
+ if(pickInspectBox) pickInspectBox.style.display='none';
196
+ if(pickInspectLabel) pickInspectLabel.style.display='none';
197
+ }
198
+
199
+ function renderPickInspect(target,mouseX,mouseY){
200
+ ensurePickInspectUi();
201
+ if(!pickInspectBox||!pickInspectLabel||!target||target.nodeType!==1){
202
+ hidePickInspectUi();
203
+ return;
204
+ }
205
+ var sourceTarget=findBestSourceAnchorTarget(target);
206
+ var anchorEl=sourceTarget.element||target;
207
+ var sourceAnchor=sourceTarget.sourceAnchor||getSourceAnchor(anchorEl);
208
+ var rect=anchorEl.getBoundingClientRect?anchorEl.getBoundingClientRect():null;
209
+ if(!rect||rect.width<1||rect.height<1){
210
+ hidePickInspectUi();
211
+ return;
212
+ }
213
+
214
+ pickInspectBox.style.display='block';
215
+ pickInspectBox.style.left=Math.max(0,rect.left)+'px';
216
+ pickInspectBox.style.top=Math.max(0,rect.top)+'px';
217
+ pickInspectBox.style.width=Math.max(1,rect.width)+'px';
218
+ pickInspectBox.style.height=Math.max(1,rect.height)+'px';
219
+
220
+ var primary=getInspectElementLabel(anchorEl);
221
+ var sourceLabel='(no source metadata)';
222
+ if(sourceAnchor){
223
+ var leaf=getFileLeaf(sourceAnchor.source_file);
224
+ if(leaf&&typeof sourceAnchor.source_line==='number'){
225
+ sourceLabel=leaf+':'+sourceAnchor.source_line;
226
+ }else if(leaf){
227
+ sourceLabel=leaf;
228
+ }else if(sourceAnchor.component_name){
229
+ sourceLabel=sourceAnchor.component_name;
230
+ }
231
+ if(sourceAnchor.explicit_id){
232
+ sourceLabel=sourceLabel+' · #'+sourceAnchor.explicit_id;
233
+ }
234
+ }
235
+ pickInspectLabel.textContent=primary+'\\n'+sourceLabel;
236
+ pickInspectLabel.style.display='block';
237
+
238
+ var viewW=window.innerWidth||document.documentElement.clientWidth||0;
239
+ var viewH=window.innerHeight||document.documentElement.clientHeight||0;
240
+ var labelRect=pickInspectLabel.getBoundingClientRect();
241
+ var left=mouseX+14;
242
+ var top=mouseY+14;
243
+ if(left+labelRect.width>viewW-8){
244
+ left=Math.max(8,mouseX-labelRect.width-14);
245
+ }
246
+ if(top+labelRect.height>viewH-8){
247
+ top=Math.max(8,mouseY-labelRect.height-14);
248
+ }
249
+ pickInspectLabel.style.left=left+'px';
250
+ pickInspectLabel.style.top=top+'px';
251
+ }
252
+
253
+ function getEventElement(ev){
254
+ if(!ev) return null;
255
+ var target=ev.target||null;
256
+ if(target&&target.nodeType===1){
257
+ return target;
258
+ }
259
+ if(target&&target.nodeType===3&&target.parentElement){
260
+ return target.parentElement;
261
+ }
262
+ try{
263
+ if(typeof ev.clientX==='number'&&typeof ev.clientY==='number'&&document.elementFromPoint){
264
+ var node=document.elementFromPoint(ev.clientX,ev.clientY);
265
+ if(node&&node.nodeType===1){
266
+ return node;
267
+ }
268
+ }
269
+ }catch(e){}
270
+ return null;
271
+ }
272
+
123
273
  function elementSelector(el){
124
274
  if(!el||!el.tagName) return '';
125
275
  var tag=el.tagName.toLowerCase();
@@ -372,6 +522,9 @@ function trackingScript() {
372
522
  }
373
523
 
374
524
  function buildAnchorPayload(el,clientX,clientY){
525
+ var sourceTarget=findBestSourceAnchorTarget(el);
526
+ var anchorEl=sourceTarget.element||el;
527
+ var sourceAnchor=sourceTarget.sourceAnchor||getSourceAnchor(anchorEl)||null;
375
528
  var metrics=getMetrics();
376
529
  var textSelf='';
377
530
  var textParent='';
@@ -381,7 +534,7 @@ function trackingScript() {
381
534
  }catch(e){}
382
535
  var fallback=buildCoordFallback(clientX,clientY,metrics);
383
536
  try{
384
- var rect=el&&el.getBoundingClientRect?el.getBoundingClientRect():null;
537
+ var rect=anchorEl&&anchorEl.getBoundingClientRect?anchorEl.getBoundingClientRect():null;
385
538
  if(rect){
386
539
  var safeW=Math.max(1,rect.width||1);
387
540
  var safeH=Math.max(1,rect.height||1);
@@ -390,15 +543,15 @@ function trackingScript() {
390
543
  }
391
544
  }catch(e){}
392
545
  return {
393
- selector_chain:getSelectorChain(el),
394
- dom_fingerprint:getDomFingerprint(el),
546
+ selector_chain:[],
547
+ dom_fingerprint:null,
395
548
  text_context:{
396
549
  self:textSelf,
397
550
  parent:textParent
398
551
  },
399
- container_hint:getContainerHint(el),
552
+ container_hint:null,
400
553
  transient_context:getTransientContext(el),
401
- source_anchor:getSourceAnchor(el),
554
+ source_anchor:sourceAnchor,
402
555
  coord_fallback:fallback
403
556
  };
404
557
  }
@@ -548,6 +701,44 @@ function trackingScript() {
548
701
  };
549
702
  }
550
703
 
704
+ function getSourceAnchorStrength(anchor){
705
+ if(!anchor||typeof anchor!=='object') return 0;
706
+ var score=0;
707
+ if(anchor.explicit_id) score+=2000;
708
+ if(anchor.react_key) score+=400;
709
+ if(anchor.source_file) score+=420;
710
+ if(typeof anchor.source_line==='number') score+=260;
711
+ if(anchor.component_name) score+=160;
712
+ if(Array.isArray(anchor.owner_path)&&anchor.owner_path.length>0){
713
+ score+=Math.min(220,anchor.owner_path.length*28);
714
+ }
715
+ return score;
716
+ }
717
+
718
+ function findBestSourceAnchorTarget(el){
719
+ if(!el||el.nodeType!==1) return { element:el, sourceAnchor:null };
720
+ var current=el;
721
+ var bestEl=el;
722
+ var bestAnchor=null;
723
+ var bestScore=0;
724
+ var depth=0;
725
+ while(current&&current.nodeType===1&&depth<12){
726
+ var anchor=getSourceAnchor(current);
727
+ var score=getSourceAnchorStrength(anchor);
728
+ if(score>bestScore){
729
+ bestScore=score;
730
+ bestAnchor=anchor;
731
+ bestEl=current;
732
+ }
733
+ if(anchor&&anchor.explicit_id){
734
+ return { element:current, sourceAnchor:anchor };
735
+ }
736
+ current=current.parentElement;
737
+ depth++;
738
+ }
739
+ return { element:bestEl, sourceAnchor:bestAnchor };
740
+ }
741
+
551
742
  function ownerPathSuffixMatches(current,expected){
552
743
  if(!Array.isArray(current)||!Array.isArray(expected)||current.length===0||expected.length===0) return 0;
553
744
  var i=current.length-1;
@@ -734,7 +925,10 @@ function trackingScript() {
734
925
  }
735
926
  consider(docNodes);
736
927
  }
737
- if(bestScore<220){
928
+ var minScore=160;
929
+ if(sourceAnchor.explicit_id) minScore=900;
930
+ else if(sourceAnchor.source_file) minScore=260;
931
+ if(bestScore<minScore){
738
932
  return { element:null, score:bestScore };
739
933
  }
740
934
  return { element:best, score:bestScore };
@@ -771,9 +965,6 @@ function trackingScript() {
771
965
 
772
966
  function resolveAnchor(payload){
773
967
  if(!payload||typeof payload!=='object') return {coordFallback:null,strategy:'none',matchedSelector:null,status:'none'};
774
- var element=null;
775
- var strategy='none';
776
- var matchedSelector=null;
777
968
  var metrics=getMetrics();
778
969
  var transientRoot=null;
779
970
  var hasTransientContext=!!(payload.transient_context&&typeof payload.transient_context==='object');
@@ -784,72 +975,32 @@ function trackingScript() {
784
975
  }
785
976
  }
786
977
 
787
- function trySelectorChain(scope,scopeTag){
788
- if(!Array.isArray(payload.selector_chain)) return false;
789
- for(var i=0;i<payload.selector_chain.length;i++){
790
- var candidate=payload.selector_chain[i];
791
- if(!candidate||typeof candidate.selector!=='string') continue;
792
- var nodes=querySelectorAllSafe(scope,candidate.selector);
793
- var found=pickBestElement(nodes,payload,metrics,null);
794
- if(found&&found.element){
795
- element=found.element;
796
- strategy='selector';
797
- matchedSelector=(scopeTag?scopeTag+': ':'')+candidate.selector;
798
- return true;
799
- }
978
+ if(!payload.source_anchor){
979
+ if(payload.coord_fallback){
980
+ return {
981
+ coordFallback:payload.coord_fallback,
982
+ strategy:'fallback',
983
+ matchedSelector:'legacy_coord_fallback',
984
+ status:'fallback_only'
985
+ };
800
986
  }
801
- return false;
987
+ return {coordFallback:null,strategy:'none',matchedSelector:null,status:'none'};
802
988
  }
803
989
 
804
- if(transientRoot){
805
- trySelectorChain(transientRoot,'transient_root');
806
- }
807
- if(!element&&payload.source_anchor){
808
- var sourceScope=transientRoot||document;
809
- var sourceMatch=resolveFromSourceAnchor(payload.source_anchor,payload,metrics,sourceScope);
810
- if(sourceMatch&&sourceMatch.element){
811
- element=sourceMatch.element;
812
- strategy='source';
813
- matchedSelector='source_anchor';
814
- }
990
+ var sourceScope=transientRoot||document;
991
+ var sourceMatch=resolveFromSourceAnchor(payload.source_anchor,payload,metrics,sourceScope);
992
+ if(!sourceMatch||!sourceMatch.element){
993
+ return {coordFallback:null,strategy:'fallback',matchedSelector:'source_anchor_miss',status:'fallback_only'};
815
994
  }
816
- if(!element){
817
- trySelectorChain(document,'document');
818
- }
819
-
820
- if(
821
- !element&&
822
- payload.container_hint&&
823
- typeof payload.container_hint.selector==='string'&&
824
- isStrongContainerHint(payload.container_hint)
825
- ){
826
- var containerNodesInRoot=transientRoot?querySelectorAllSafe(transientRoot,payload.container_hint.selector):[];
827
- var containerMatch=pickBestElement(containerNodesInRoot,payload,metrics,null);
828
- if(!containerMatch.element){
829
- var containerNodes=querySelectorAllSafe(document,payload.container_hint.selector);
830
- containerMatch=pickBestElement(containerNodes,payload,metrics,null);
831
- }
832
- if(containerMatch.element){
833
- element=containerMatch.element;
834
- strategy='container';
835
- matchedSelector=payload.container_hint.selector;
836
- }
837
- }
838
- if(!element){
839
- var fpMatch=resolveFromFingerprint(payload.dom_fingerprint,payload,metrics,transientRoot||undefined);
840
- if(!fpMatch.element){
841
- fpMatch=resolveFromFingerprint(payload.dom_fingerprint,payload,metrics,document);
842
- }
843
- if(fpMatch.element){
844
- element=fpMatch.element;
845
- strategy='fingerprint';
846
- }
847
- }
848
- if(!element) return {coordFallback:null,strategy:'fallback',matchedSelector:null,status:'fallback_only'};
849
- var point=getAnchorClientPoint(element,payload);
995
+ var point=getAnchorClientPoint(sourceMatch.element,payload);
850
996
  var clientX=point.clientX;
851
997
  var clientY=point.clientY;
852
- return {coordFallback:buildCoordFallback(clientX,clientY,metrics),strategy:strategy,matchedSelector:matchedSelector,status:'resolved'};
998
+ return {
999
+ coordFallback:buildCoordFallback(clientX,clientY,metrics),
1000
+ strategy:'source',
1001
+ matchedSelector:'source_anchor',
1002
+ status:'resolved'
1003
+ };
853
1004
  }
854
1005
 
855
1006
  function setPickMode(enabled){
@@ -865,12 +1016,22 @@ function trackingScript() {
865
1016
  window.removeEventListener('click',pickClickHandler,true);
866
1017
  pickClickHandler=null;
867
1018
  }
1019
+ if(pickMoveHandler){
1020
+ window.removeEventListener('mousemove',pickMoveHandler,true);
1021
+ pickMoveHandler=null;
1022
+ }
868
1023
  if(pickEscHandler){
869
1024
  window.removeEventListener('keydown',pickEscHandler,true);
870
1025
  pickEscHandler=null;
871
1026
  }
1027
+ hidePickInspectUi();
872
1028
  return;
873
1029
  }
1030
+ pickMoveHandler=function(ev){
1031
+ if(!pickMode) return;
1032
+ var target=getEventElement(ev);
1033
+ renderPickInspect(target,ev.clientX,ev.clientY);
1034
+ };
874
1035
  pickClickHandler=function(ev){
875
1036
  try{
876
1037
  if(!pickMode) return;
@@ -879,7 +1040,7 @@ function trackingScript() {
879
1040
  if(typeof ev.stopImmediatePropagation==='function'){
880
1041
  ev.stopImmediatePropagation();
881
1042
  }
882
- var target=ev.target&&ev.target.nodeType===1?ev.target:null;
1043
+ var target=getEventElement(ev);
883
1044
  if(!target) return;
884
1045
  var payload=buildAnchorPayload(target,ev.clientX,ev.clientY);
885
1046
  window.parent.postMessage({
@@ -901,6 +1062,7 @@ function trackingScript() {
901
1062
  setPickMode(false);
902
1063
  }
903
1064
  };
1065
+ window.addEventListener('mousemove',pickMoveHandler,true);
904
1066
  window.addEventListener('click',pickClickHandler,true);
905
1067
  window.addEventListener('keydown',pickEscHandler,true);
906
1068
  }
@@ -1063,7 +1225,7 @@ function startInjectionProxy(targetPort) {
1063
1225
  proxyRes.on('data', (chunk) => chunks.push(chunk));
1064
1226
  proxyRes.on('end', () => {
1065
1227
  let body = Buffer.concat(chunks).toString('utf-8');
1066
- if (!body.includes('data-checkpoint')) {
1228
+ if (!body.includes('data-checkpoint-script="1"')) {
1067
1229
  if (body.includes('</head>')) {
1068
1230
  body = body.replace('</head>', SCRIPT + '\n</head>');
1069
1231
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "checkpoint-cli",
3
- "version": "0.2.0",
3
+ "version": "0.2.2",
4
4
  "description": "Share your localhost with reviewers — get visual feedback directly on the page",
5
5
  "keywords": [
6
6
  "checkpoint",