checkpoint-cli 0.2.0 → 0.2.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.
Files changed (2) hide show
  1. package/dist/index.js +213 -71
  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,133 @@ 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
+
123
253
  function elementSelector(el){
124
254
  if(!el||!el.tagName) return '';
125
255
  var tag=el.tagName.toLowerCase();
@@ -372,6 +502,9 @@ function trackingScript() {
372
502
  }
373
503
 
374
504
  function buildAnchorPayload(el,clientX,clientY){
505
+ var sourceTarget=findBestSourceAnchorTarget(el);
506
+ var anchorEl=sourceTarget.element||el;
507
+ var sourceAnchor=sourceTarget.sourceAnchor||getSourceAnchor(anchorEl)||null;
375
508
  var metrics=getMetrics();
376
509
  var textSelf='';
377
510
  var textParent='';
@@ -381,7 +514,7 @@ function trackingScript() {
381
514
  }catch(e){}
382
515
  var fallback=buildCoordFallback(clientX,clientY,metrics);
383
516
  try{
384
- var rect=el&&el.getBoundingClientRect?el.getBoundingClientRect():null;
517
+ var rect=anchorEl&&anchorEl.getBoundingClientRect?anchorEl.getBoundingClientRect():null;
385
518
  if(rect){
386
519
  var safeW=Math.max(1,rect.width||1);
387
520
  var safeH=Math.max(1,rect.height||1);
@@ -390,15 +523,15 @@ function trackingScript() {
390
523
  }
391
524
  }catch(e){}
392
525
  return {
393
- selector_chain:getSelectorChain(el),
394
- dom_fingerprint:getDomFingerprint(el),
526
+ selector_chain:[],
527
+ dom_fingerprint:null,
395
528
  text_context:{
396
529
  self:textSelf,
397
530
  parent:textParent
398
531
  },
399
- container_hint:getContainerHint(el),
532
+ container_hint:null,
400
533
  transient_context:getTransientContext(el),
401
- source_anchor:getSourceAnchor(el),
534
+ source_anchor:sourceAnchor,
402
535
  coord_fallback:fallback
403
536
  };
404
537
  }
@@ -548,6 +681,44 @@ function trackingScript() {
548
681
  };
549
682
  }
550
683
 
684
+ function getSourceAnchorStrength(anchor){
685
+ if(!anchor||typeof anchor!=='object') return 0;
686
+ var score=0;
687
+ if(anchor.explicit_id) score+=2000;
688
+ if(anchor.react_key) score+=400;
689
+ if(anchor.source_file) score+=420;
690
+ if(typeof anchor.source_line==='number') score+=260;
691
+ if(anchor.component_name) score+=160;
692
+ if(Array.isArray(anchor.owner_path)&&anchor.owner_path.length>0){
693
+ score+=Math.min(220,anchor.owner_path.length*28);
694
+ }
695
+ return score;
696
+ }
697
+
698
+ function findBestSourceAnchorTarget(el){
699
+ if(!el||el.nodeType!==1) return { element:el, sourceAnchor:null };
700
+ var current=el;
701
+ var bestEl=el;
702
+ var bestAnchor=null;
703
+ var bestScore=0;
704
+ var depth=0;
705
+ while(current&&current.nodeType===1&&depth<12){
706
+ var anchor=getSourceAnchor(current);
707
+ var score=getSourceAnchorStrength(anchor);
708
+ if(score>bestScore){
709
+ bestScore=score;
710
+ bestAnchor=anchor;
711
+ bestEl=current;
712
+ }
713
+ if(anchor&&anchor.explicit_id){
714
+ return { element:current, sourceAnchor:anchor };
715
+ }
716
+ current=current.parentElement;
717
+ depth++;
718
+ }
719
+ return { element:bestEl, sourceAnchor:bestAnchor };
720
+ }
721
+
551
722
  function ownerPathSuffixMatches(current,expected){
552
723
  if(!Array.isArray(current)||!Array.isArray(expected)||current.length===0||expected.length===0) return 0;
553
724
  var i=current.length-1;
@@ -734,7 +905,10 @@ function trackingScript() {
734
905
  }
735
906
  consider(docNodes);
736
907
  }
737
- if(bestScore<220){
908
+ var minScore=160;
909
+ if(sourceAnchor.explicit_id) minScore=900;
910
+ else if(sourceAnchor.source_file) minScore=260;
911
+ if(bestScore<minScore){
738
912
  return { element:null, score:bestScore };
739
913
  }
740
914
  return { element:best, score:bestScore };
@@ -771,9 +945,6 @@ function trackingScript() {
771
945
 
772
946
  function resolveAnchor(payload){
773
947
  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
948
  var metrics=getMetrics();
778
949
  var transientRoot=null;
779
950
  var hasTransientContext=!!(payload.transient_context&&typeof payload.transient_context==='object');
@@ -784,72 +955,32 @@ function trackingScript() {
784
955
  }
785
956
  }
786
957
 
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
- }
800
- }
801
- return false;
802
- }
803
-
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';
958
+ if(!payload.source_anchor){
959
+ if(payload.coord_fallback){
960
+ return {
961
+ coordFallback:payload.coord_fallback,
962
+ strategy:'fallback',
963
+ matchedSelector:'legacy_coord_fallback',
964
+ status:'fallback_only'
965
+ };
814
966
  }
815
- }
816
- if(!element){
817
- trySelectorChain(document,'document');
967
+ return {coordFallback:null,strategy:'none',matchedSelector:null,status:'none'};
818
968
  }
819
969
 
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
- }
970
+ var sourceScope=transientRoot||document;
971
+ var sourceMatch=resolveFromSourceAnchor(payload.source_anchor,payload,metrics,sourceScope);
972
+ if(!sourceMatch||!sourceMatch.element){
973
+ return {coordFallback:null,strategy:'fallback',matchedSelector:'source_anchor_miss',status:'fallback_only'};
837
974
  }
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);
975
+ var point=getAnchorClientPoint(sourceMatch.element,payload);
850
976
  var clientX=point.clientX;
851
977
  var clientY=point.clientY;
852
- return {coordFallback:buildCoordFallback(clientX,clientY,metrics),strategy:strategy,matchedSelector:matchedSelector,status:'resolved'};
978
+ return {
979
+ coordFallback:buildCoordFallback(clientX,clientY,metrics),
980
+ strategy:'source',
981
+ matchedSelector:'source_anchor',
982
+ status:'resolved'
983
+ };
853
984
  }
854
985
 
855
986
  function setPickMode(enabled){
@@ -865,12 +996,22 @@ function trackingScript() {
865
996
  window.removeEventListener('click',pickClickHandler,true);
866
997
  pickClickHandler=null;
867
998
  }
999
+ if(pickMoveHandler){
1000
+ window.removeEventListener('mousemove',pickMoveHandler,true);
1001
+ pickMoveHandler=null;
1002
+ }
868
1003
  if(pickEscHandler){
869
1004
  window.removeEventListener('keydown',pickEscHandler,true);
870
1005
  pickEscHandler=null;
871
1006
  }
1007
+ hidePickInspectUi();
872
1008
  return;
873
1009
  }
1010
+ pickMoveHandler=function(ev){
1011
+ if(!pickMode) return;
1012
+ var target=ev.target&&ev.target.nodeType===1?ev.target:null;
1013
+ renderPickInspect(target,ev.clientX,ev.clientY);
1014
+ };
874
1015
  pickClickHandler=function(ev){
875
1016
  try{
876
1017
  if(!pickMode) return;
@@ -901,6 +1042,7 @@ function trackingScript() {
901
1042
  setPickMode(false);
902
1043
  }
903
1044
  };
1045
+ window.addEventListener('mousemove',pickMoveHandler,true);
904
1046
  window.addEventListener('click',pickClickHandler,true);
905
1047
  window.addEventListener('keydown',pickEscHandler,true);
906
1048
  }
@@ -1063,7 +1205,7 @@ function startInjectionProxy(targetPort) {
1063
1205
  proxyRes.on('data', (chunk) => chunks.push(chunk));
1064
1206
  proxyRes.on('end', () => {
1065
1207
  let body = Buffer.concat(chunks).toString('utf-8');
1066
- if (!body.includes('data-checkpoint')) {
1208
+ if (!body.includes('data-checkpoint-script="1"')) {
1067
1209
  if (body.includes('</head>')) {
1068
1210
  body = body.replace('</head>', SCRIPT + '\n</head>');
1069
1211
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "checkpoint-cli",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "description": "Share your localhost with reviewers — get visual feedback directly on the page",
5
5
  "keywords": [
6
6
  "checkpoint",