checkpoint-cli 1.0.1 → 1.0.3
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.js +32 -6
- package/dist/tracking-script-minimal.js +53 -10
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -12,6 +12,8 @@ const chalk_1 = __importDefault(require("chalk"));
|
|
|
12
12
|
const supabase_js_1 = require("@supabase/supabase-js");
|
|
13
13
|
const config_js_1 = require("./config.js");
|
|
14
14
|
const tracking_script_minimal_js_1 = require("./tracking-script-minimal.js");
|
|
15
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
16
|
+
const { version: cliVersion } = require('../package.json');
|
|
15
17
|
/* ── Authenticated Supabase Client ── */
|
|
16
18
|
function getSupabase() {
|
|
17
19
|
const config = (0, config_js_1.loadConfig)();
|
|
@@ -104,10 +106,33 @@ async function getAuthenticatedClient() {
|
|
|
104
106
|
}
|
|
105
107
|
/* ── Injection Proxy ── */
|
|
106
108
|
function startInjectionProxy(targetPort) {
|
|
107
|
-
const
|
|
108
|
-
const
|
|
109
|
+
const AGENT_PATH = '/__checkpoint/agent.min.js';
|
|
110
|
+
const agentScript = (0, tracking_script_minimal_js_1.buildMinimalTrackingScript)();
|
|
111
|
+
const extractNonce = (html) => {
|
|
112
|
+
const nonceMatch = html.match(/<script\b[^>]*\bnonce=(?:"([^"]+)"|'([^']+)'|([^\s>]+))/i);
|
|
113
|
+
return nonceMatch?.[1] ?? nonceMatch?.[2] ?? nonceMatch?.[3] ?? null;
|
|
114
|
+
};
|
|
115
|
+
const buildInjectionTag = (html) => {
|
|
116
|
+
const nonce = extractNonce(html);
|
|
117
|
+
const nonceAttr = nonce ? ` nonce="${nonce.replace(/"/g, '"')}"` : '';
|
|
118
|
+
return `<script data-checkpoint-script="minimal-v1" src="${AGENT_PATH}"${nonceAttr} defer></script>`;
|
|
119
|
+
};
|
|
109
120
|
return new Promise((resolve, reject) => {
|
|
110
121
|
const server = http_1.default.createServer((req, res) => {
|
|
122
|
+
const pathname = new URL(req.url || '/', 'http://checkpoint.local').pathname;
|
|
123
|
+
if (pathname === AGENT_PATH) {
|
|
124
|
+
res.writeHead(200, {
|
|
125
|
+
'content-type': 'application/javascript; charset=utf-8',
|
|
126
|
+
'cache-control': 'no-store, max-age=0',
|
|
127
|
+
'x-content-type-options': 'nosniff',
|
|
128
|
+
});
|
|
129
|
+
if (req.method === 'HEAD') {
|
|
130
|
+
res.end();
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
res.end(agentScript);
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
111
136
|
const fwdHeaders = { ...req.headers, host: `localhost:${targetPort}` };
|
|
112
137
|
delete fwdHeaders['accept-encoding'];
|
|
113
138
|
const proxyReq = http_1.default.request({
|
|
@@ -128,15 +153,16 @@ function startInjectionProxy(targetPort) {
|
|
|
128
153
|
proxyRes.on('data', (chunk) => chunks.push(chunk));
|
|
129
154
|
proxyRes.on('end', () => {
|
|
130
155
|
let body = Buffer.concat(chunks).toString('utf-8');
|
|
156
|
+
const scriptTag = buildInjectionTag(body);
|
|
131
157
|
if (!body.includes('data-checkpoint-script="minimal-v1"')) {
|
|
132
158
|
if (body.includes('</head>')) {
|
|
133
|
-
body = body.replace('</head>', () =>
|
|
159
|
+
body = body.replace('</head>', () => scriptTag + '\n</head>');
|
|
134
160
|
}
|
|
135
161
|
else if (body.includes('</body>')) {
|
|
136
|
-
body = body.replace('</body>', () =>
|
|
162
|
+
body = body.replace('</body>', () => scriptTag + '\n</body>');
|
|
137
163
|
}
|
|
138
164
|
else {
|
|
139
|
-
body +=
|
|
165
|
+
body += scriptTag;
|
|
140
166
|
}
|
|
141
167
|
}
|
|
142
168
|
const headers = { ...proxyRes.headers };
|
|
@@ -555,7 +581,7 @@ const program = new commander_1.Command();
|
|
|
555
581
|
program
|
|
556
582
|
.name('checkpoint')
|
|
557
583
|
.description('Share your localhost with reviewers — get visual feedback directly on the page.\n\nQuick start:\n 1. checkpoint login Sign in to your Checkpoint account\n 2. checkpoint start -p 3000 Start tunneling and get a share link\n\nReuse a tunnel name to keep the same share URL and preserve all comments.')
|
|
558
|
-
.version(
|
|
584
|
+
.version(cliVersion);
|
|
559
585
|
// ── checkpoint login ──
|
|
560
586
|
program
|
|
561
587
|
.command('login')
|
|
@@ -18,6 +18,23 @@ function buildMinimalTrackingScript() {
|
|
|
18
18
|
var lastPath='';
|
|
19
19
|
var mutationTick=false;
|
|
20
20
|
var pendingPickCommit=false;
|
|
21
|
+
var parentTargetOrigin='*';
|
|
22
|
+
|
|
23
|
+
function initParentOrigin(){
|
|
24
|
+
try{
|
|
25
|
+
if(!document.referrer) return;
|
|
26
|
+
var parsed=new URL(document.referrer);
|
|
27
|
+
if(parsed.protocol==='http:'||parsed.protocol==='https:') parentTargetOrigin=parsed.origin;
|
|
28
|
+
}catch(e){}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function postToParent(payload){
|
|
32
|
+
try{
|
|
33
|
+
window.parent.postMessage(payload,parentTargetOrigin);
|
|
34
|
+
return;
|
|
35
|
+
}catch(e){}
|
|
36
|
+
try{ window.parent.postMessage(payload,'*'); }catch(e){}
|
|
37
|
+
}
|
|
21
38
|
|
|
22
39
|
function getMetrics(){
|
|
23
40
|
var de=document.documentElement;
|
|
@@ -31,6 +48,27 @@ function buildMinimalTrackingScript() {
|
|
|
31
48
|
};
|
|
32
49
|
}
|
|
33
50
|
|
|
51
|
+
function reportReady(){
|
|
52
|
+
try{
|
|
53
|
+
postToParent({
|
|
54
|
+
type:'checkpoint:ready',
|
|
55
|
+
path:location.pathname+location.search+location.hash,
|
|
56
|
+
version:'minimal-v1',
|
|
57
|
+
capabilities:{ pickMode:true, resolveAnchors:true, sourceAnchors:true }
|
|
58
|
+
});
|
|
59
|
+
}catch(e){}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function reportDiagnostic(code,detail){
|
|
63
|
+
try{
|
|
64
|
+
postToParent({
|
|
65
|
+
type:'checkpoint:diagnostic',
|
|
66
|
+
code:code||'unknown',
|
|
67
|
+
detail:detail||''
|
|
68
|
+
});
|
|
69
|
+
}catch(e){}
|
|
70
|
+
}
|
|
71
|
+
|
|
34
72
|
function clampPercent(v){
|
|
35
73
|
if(v<0) return 0;
|
|
36
74
|
if(v>100) return 100;
|
|
@@ -732,7 +770,7 @@ inspectBox.style.border='2px solid #F26522';
|
|
|
732
770
|
|
|
733
771
|
function postPickResult(target,clientX,clientY){
|
|
734
772
|
var payload=buildAnchorPayload(target,clientX,clientY);
|
|
735
|
-
|
|
773
|
+
postToParent({
|
|
736
774
|
type:'checkpoint:pickResult',
|
|
737
775
|
path:location.pathname+location.search+location.hash,
|
|
738
776
|
anchorPayload:payload,
|
|
@@ -742,7 +780,7 @@ inspectBox.style.border='2px solid #F26522';
|
|
|
742
780
|
scrollY:payload.coord_fallback&&typeof payload.coord_fallback.scroll_y==='number'?payload.coord_fallback.scroll_y:0,
|
|
743
781
|
viewHeight:payload.coord_fallback&&typeof payload.coord_fallback.viewport_height==='number'?payload.coord_fallback.viewport_height:0
|
|
744
782
|
}
|
|
745
|
-
}
|
|
783
|
+
});
|
|
746
784
|
}
|
|
747
785
|
|
|
748
786
|
function setPickMode(enabled){
|
|
@@ -854,7 +892,7 @@ inspectBox.style.border='2px solid #F26522';
|
|
|
854
892
|
function reportScroll(){
|
|
855
893
|
try{
|
|
856
894
|
var m=getMetrics();
|
|
857
|
-
|
|
895
|
+
postToParent({
|
|
858
896
|
type:'checkpoint:scroll',
|
|
859
897
|
scrollX:m.scrollX,
|
|
860
898
|
scrollY:m.scrollY,
|
|
@@ -862,7 +900,7 @@ inspectBox.style.border='2px solid #F26522';
|
|
|
862
900
|
docHeight:m.docHeight,
|
|
863
901
|
viewWidth:m.viewWidth,
|
|
864
902
|
viewHeight:m.viewHeight
|
|
865
|
-
}
|
|
903
|
+
});
|
|
866
904
|
}catch(e){}
|
|
867
905
|
}
|
|
868
906
|
|
|
@@ -871,7 +909,7 @@ inspectBox.style.border='2px solid #F26522';
|
|
|
871
909
|
var p=location.pathname+location.search+location.hash;
|
|
872
910
|
if(p===lastPath) return;
|
|
873
911
|
lastPath=p;
|
|
874
|
-
|
|
912
|
+
postToParent({ type:'checkpoint:navigate', path:p });
|
|
875
913
|
reportScroll();
|
|
876
914
|
}catch(e){}
|
|
877
915
|
}
|
|
@@ -881,11 +919,11 @@ inspectBox.style.border='2px solid #F26522';
|
|
|
881
919
|
mutationTick=true;
|
|
882
920
|
requestAnimationFrame(function(){
|
|
883
921
|
mutationTick=false;
|
|
884
|
-
|
|
922
|
+
postToParent({
|
|
885
923
|
type:'checkpoint:domMutation',
|
|
886
924
|
reason:'mutation',
|
|
887
925
|
path:location.pathname+location.search+location.hash
|
|
888
|
-
}
|
|
926
|
+
});
|
|
889
927
|
});
|
|
890
928
|
}
|
|
891
929
|
|
|
@@ -895,9 +933,13 @@ inspectBox.style.border='2px solid #F26522';
|
|
|
895
933
|
var observer=new MutationObserver(function(){ reportDomMutation(); });
|
|
896
934
|
observer.observe(document.documentElement,{ childList:true, subtree:true, attributes:true });
|
|
897
935
|
window.addEventListener('beforeunload',function(){ try{observer.disconnect();}catch(e){}; });
|
|
898
|
-
}catch(e){
|
|
936
|
+
}catch(e){
|
|
937
|
+
reportDiagnostic('mutation_observer_failed',String(e&&e.message?e.message:e));
|
|
938
|
+
}
|
|
899
939
|
}
|
|
900
940
|
|
|
941
|
+
initParentOrigin();
|
|
942
|
+
reportReady();
|
|
901
943
|
reportNav();
|
|
902
944
|
reportScroll();
|
|
903
945
|
setupMutationObserver();
|
|
@@ -912,6 +954,7 @@ inspectBox.style.border='2px solid #F26522';
|
|
|
912
954
|
|
|
913
955
|
window.addEventListener('message',function(e){
|
|
914
956
|
try{
|
|
957
|
+
if(e.source!==window.parent) return;
|
|
915
958
|
var d=e.data;
|
|
916
959
|
if(!d||typeof d!=='object') return;
|
|
917
960
|
if(d.type==='checkpoint:scrollTo'&&typeof d.y==='number'){
|
|
@@ -937,11 +980,11 @@ inspectBox.style.border='2px solid #F26522';
|
|
|
937
980
|
coordFallback:result.coordFallback||null
|
|
938
981
|
});
|
|
939
982
|
}
|
|
940
|
-
|
|
983
|
+
postToParent({
|
|
941
984
|
type:'checkpoint:anchorsResolved',
|
|
942
985
|
path:location.pathname+location.search+location.hash,
|
|
943
986
|
positions:positions
|
|
944
|
-
}
|
|
987
|
+
});
|
|
945
988
|
}
|
|
946
989
|
}catch(ex){}
|
|
947
990
|
});
|