hyperinstant 0.1.0 → 1.0.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 +2 -18
- package/README.md +30 -13
- package/dist/hyperinstant.js +300 -0
- package/dist/hyperinstant.min.js +1 -2
- package/package.json +19 -18
- package/dist/hyperinstant.esm.js +0 -2
- package/dist/hyperinstant.esm.js.map +0 -7
- package/dist/hyperinstant.min.js.map +0 -7
package/LICENSE
CHANGED
|
@@ -1,21 +1,5 @@
|
|
|
1
1
|
MIT License
|
|
2
2
|
|
|
3
|
-
Copyright (c) 2026
|
|
3
|
+
Copyright (c) 2026 Putia Web
|
|
4
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 all
|
|
13
|
-
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 THE
|
|
21
|
-
SOFTWARE.
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy...
|
package/README.md
CHANGED
|
@@ -1,25 +1,42 @@
|
|
|
1
|
-
#
|
|
1
|
+
# HyperInstant v1.0.1
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
**HyperInstant** accelerates navigation across any website by intelligently prefetching (and when safe, prerendering) the *right* pages at the *right* time.
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
5
|
+
### ✅ Key features
|
|
6
|
+
- **Adaptive engine** (network-aware budgets + intent scoring)
|
|
7
|
+
- **Safe by default** (auto-deny rules for cart/checkout/account/actions)
|
|
8
|
+
- **Platform adapters** (auto: Shopify / WooCommerce / nopCommerce)
|
|
9
|
+
- **Local stats** (hit-rate) + optional debug overlay
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## Quick install (CDN)
|
|
10
14
|
|
|
11
|
-
## CDN usage (unpkg)
|
|
12
15
|
```html
|
|
13
16
|
<script>
|
|
14
17
|
window.HyperInstant = {
|
|
15
|
-
|
|
18
|
+
mode: "balanced", // safe | balanced | aggressive
|
|
19
|
+
adapter: "auto", // auto | shopify | woocommerce | nopcommerce | generic
|
|
20
|
+
observe: "intent", // intent | intent+viewport
|
|
16
21
|
hoverDelay: 65,
|
|
17
|
-
maxPrefetch: 6,
|
|
18
|
-
maxPrerender: 2,
|
|
19
|
-
deny: ["/cart", "/checkout", "/my-account", "/logout", "add-to-cart"],
|
|
20
22
|
debug: false
|
|
21
23
|
};
|
|
22
24
|
</script>
|
|
25
|
+
<script src="https://unpkg.com/hyperinstant@1.0.1/dist/hyperinstant.min.js" defer></script>
|
|
26
|
+
```
|
|
23
27
|
|
|
24
|
-
|
|
28
|
+
## Recommended deny additions for eCommerce (optional)
|
|
29
|
+
You can add project-specific entries (strings are matched by `.includes()`):
|
|
30
|
+
|
|
31
|
+
```js
|
|
32
|
+
deny: ["/cart", "/checkout", "/account", "add-to-cart"]
|
|
25
33
|
```
|
|
34
|
+
|
|
35
|
+
## Debug
|
|
36
|
+
Set `debug: true` to enable:
|
|
37
|
+
- `window.HyperInstantStats` (stats API)
|
|
38
|
+
- optional mini overlay (`debugOverlay: true`)
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
MIT License.
|
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
/*! HyperInstant v1.0.1 | MIT | Putia Web */
|
|
2
|
+
(function(){
|
|
3
|
+
if (window.__HYPERINSTANT_LOADED__) return;
|
|
4
|
+
window.__HYPERINSTANT_LOADED__ = true;
|
|
5
|
+
|
|
6
|
+
var cfg = window.HyperInstant || {};
|
|
7
|
+
|
|
8
|
+
function clamp(n,a,b){ return Math.max(a, Math.min(b,n)); }
|
|
9
|
+
function isSameOrigin(url){ try{ return new URL(url, location.href).origin === location.origin; }catch(e){ return false; } }
|
|
10
|
+
function normalizeUrl(url){ try{ var u=new URL(url, location.href); u.hash=""; return u.toString(); }catch(e){ return ""; } }
|
|
11
|
+
function getConn(){ var c=navigator.connection||navigator.mozConnection||navigator.webkitConnection; return { saveData:!!(c&&c.saveData), effectiveType:(c&&c.effectiveType)?String(c.effectiveType):"unknown", downlink:(c&&typeof c.downlink==="number")?c.downlink:null, rtt:(c&&typeof c.rtt==="number")?c.rtt:null }; }
|
|
12
|
+
function supportsPrerender(){ try{ return "relList" in HTMLLinkElement.prototype && HTMLLinkElement.prototype.relList.supports && HTMLLinkElement.prototype.relList.supports("prerender"); }catch(e){ return false; } }
|
|
13
|
+
function inNav(a){ try{ return !!a.closest("nav, header, [role='navigation'], .header, .site-header"); }catch(e){ return false; } }
|
|
14
|
+
|
|
15
|
+
function applyModeDefaults(c){
|
|
16
|
+
var mode = String(c.mode||"safe").toLowerCase();
|
|
17
|
+
var out = Object.assign({}, c);
|
|
18
|
+
if (mode==="aggressive"){ out.maxPrefetch = out.maxPrefetch ?? 10; out.maxPrerender = out.maxPrerender ?? 2; out.observe = out.observe ?? "intent+viewport"; }
|
|
19
|
+
else if (mode==="balanced"){ out.maxPrefetch = out.maxPrefetch ?? 6; out.maxPrerender = out.maxPrerender ?? 1; out.observe = out.observe ?? "intent"; }
|
|
20
|
+
else { out.maxPrefetch = out.maxPrefetch ?? 4; out.maxPrerender = out.maxPrerender ?? 0; out.observe = out.observe ?? "intent"; }
|
|
21
|
+
out.hoverDelay = out.hoverDelay ?? 65;
|
|
22
|
+
out.debug = !!out.debug;
|
|
23
|
+
out.debugOverlay = !!out.debugOverlay;
|
|
24
|
+
out.budget = out.budget ?? "auto";
|
|
25
|
+
out.events = out.events ?? ["mouseover","touchstart","mousedown","focusin"];
|
|
26
|
+
out.deny = out.deny ?? [];
|
|
27
|
+
return out;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function hasMeta(name){ return !!document.querySelector('meta[name="'+name+'"]'); }
|
|
31
|
+
function shopifyAdapter(c){
|
|
32
|
+
var deny=new Set([].concat(c.deny||[]));
|
|
33
|
+
["/cart","/checkout","/account","/account/login","/account/register","/account/logout","/search","cart/add","cart/change","cart/update","?variant=","variant=","sections="].forEach(function(x){ deny.add(x); });
|
|
34
|
+
return Object.assign({}, c, {deny:Array.from(deny)});
|
|
35
|
+
}
|
|
36
|
+
function wooAdapter(c){
|
|
37
|
+
var deny=new Set([].concat(c.deny||[]));
|
|
38
|
+
["/cart","/checkout","/my-account","add-to-cart","wc-ajax","remove_item","update_cart","apply_coupon"].forEach(function(x){ deny.add(x); });
|
|
39
|
+
return Object.assign({}, c, {deny:Array.from(deny)});
|
|
40
|
+
}
|
|
41
|
+
function nopAdapter(c){
|
|
42
|
+
var deny=new Set([].concat(c.deny||[]));
|
|
43
|
+
["/shoppingcart","/checkout","/login","/register","/logout","/customer","addproducttocart","updateshoppingcart","updatecart","deleteitem","/wishlist","/compareproducts","/search","?q="].forEach(function(x){ deny.add(x); });
|
|
44
|
+
return Object.assign({}, c, {deny:Array.from(deny)});
|
|
45
|
+
}
|
|
46
|
+
function detectAdapter(name){
|
|
47
|
+
name = String(name||"auto").toLowerCase();
|
|
48
|
+
if (name==="shopify") return shopifyAdapter;
|
|
49
|
+
if (name==="woocommerce") return wooAdapter;
|
|
50
|
+
if (name==="nopcommerce") return nopAdapter;
|
|
51
|
+
if (name==="generic") return function(x){ return x; };
|
|
52
|
+
|
|
53
|
+
try{ if (window.Shopify || hasMeta("shopify-digital-wallet") || hasMeta("shopify-checkout-api-token")) return shopifyAdapter; }catch(e){}
|
|
54
|
+
try{ if (window.wc_add_to_cart_params || window.wc_cart_fragments_params || (document.body&&String(document.body.className||"").includes("woocommerce"))) return wooAdapter; }catch(e){}
|
|
55
|
+
try{ if (window.nopCommerce || document.querySelector("a[href*='shoppingcart']") || document.querySelector("form[action*='addproducttocart']")) return nopAdapter; }catch(e){}
|
|
56
|
+
return function(x){ return x; };
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
var AUTO_KEYWORDS=["logout","logoff","signin","sign-in","login","register","account","checkout","cart","basket","order","orders","pay","payment","add-to-cart","addtocart","addproducttocart","remove","update","change","delete","wc-ajax","admin-ajax","ajax","sections=","variant=","token","returnurl","redirect"];
|
|
60
|
+
var AUTO_PATHS=["/checkout","/cart","/shoppingcart","/account","/my-account","/logout","/login","/register"];
|
|
61
|
+
var AUTO_PARAMS=["add","remove","update","change","delete","token","variant","sections","returnurl","redirect"];
|
|
62
|
+
|
|
63
|
+
function shouldDeny(url, c){
|
|
64
|
+
if (!url) return true;
|
|
65
|
+
if (!isSameOrigin(url)) return true;
|
|
66
|
+
var u = String(url).toLowerCase();
|
|
67
|
+
|
|
68
|
+
var denyList = c.deny || [];
|
|
69
|
+
for (var i=0;i<denyList.length;i++){ var r=denyList[i]; if (r && u.includes(String(r).toLowerCase())) return true; }
|
|
70
|
+
|
|
71
|
+
try{
|
|
72
|
+
var p = new URL(url, location.href).pathname.toLowerCase();
|
|
73
|
+
for (var j=0;j<AUTO_PATHS.length;j++){
|
|
74
|
+
var ap=AUTO_PATHS[j];
|
|
75
|
+
if (p===ap || p.startsWith(ap+"/")) return true;
|
|
76
|
+
}
|
|
77
|
+
}catch(e){}
|
|
78
|
+
|
|
79
|
+
for (var k=0;k<AUTO_KEYWORDS.length;k++){ if (u.includes(AUTO_KEYWORDS[k])) return true; }
|
|
80
|
+
|
|
81
|
+
try{
|
|
82
|
+
var uu = new URL(url, location.href);
|
|
83
|
+
var sp = uu.searchParams;
|
|
84
|
+
for (var q=0;q<AUTO_PARAMS.length;q++){ if (sp.has(AUTO_PARAMS[q])) return true; }
|
|
85
|
+
}catch(e){}
|
|
86
|
+
|
|
87
|
+
return false;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function Stats(){
|
|
91
|
+
this.startedAt=Date.now();
|
|
92
|
+
this.seen=0; this.denied=0; this.enqueued=0;
|
|
93
|
+
this.prefetched=0; this.prerendered=0;
|
|
94
|
+
this.clicked=0; this.hit=0;
|
|
95
|
+
this._loaded=new Map();
|
|
96
|
+
}
|
|
97
|
+
Stats.prototype.markLoaded=function(url,type){
|
|
98
|
+
if(!this._loaded.has(url)){
|
|
99
|
+
this._loaded.set(url,{type:type,t:Date.now()});
|
|
100
|
+
if(type==="prerender") this.prerendered++; else this.prefetched++;
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
Stats.prototype.isLoaded=function(url){ return this._loaded.has(url); };
|
|
104
|
+
Stats.prototype.markClick=function(url){ this.clicked++; if(this._loaded.has(url)) this.hit++; };
|
|
105
|
+
Object.defineProperty(Stats.prototype,"hitRate",{ get:function(){ var d=this.prefetched+this.prerendered; return d? (this.hit/d):0; } });
|
|
106
|
+
Stats.prototype.snapshot=function(){
|
|
107
|
+
return { version:"1.0.1", uptimeSec:Math.round((Date.now()-this.startedAt)/1000), seen:this.seen, denied:this.denied, enqueued:this.enqueued, prefetched:this.prefetched, prerendered:this.prerendered, clicked:this.clicked, hit:this.hit, hitRate:Number(this.hitRate.toFixed(3)) };
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
function createScheduler(c, stats){
|
|
111
|
+
var queue=[];
|
|
112
|
+
var inFlight=new Set();
|
|
113
|
+
var loaded=new Set();
|
|
114
|
+
var usedPrefetch=0, usedPrerender=0;
|
|
115
|
+
|
|
116
|
+
function computeBudgets(){
|
|
117
|
+
if (c.budget && typeof c.budget==="object"){
|
|
118
|
+
return { maxPrefetch: c.budget.maxPrefetch ?? c.maxPrefetch, maxPrerender: c.budget.maxPrerender ?? c.maxPrerender };
|
|
119
|
+
}
|
|
120
|
+
var ci=getConn();
|
|
121
|
+
var mp=c.maxPrefetch, mr=c.maxPrerender;
|
|
122
|
+
if (ci.saveData){ mr=0; mp=Math.min(mp,2); }
|
|
123
|
+
if (String(ci.effectiveType).includes("2g")){ mr=0; mp=Math.min(mp,2); }
|
|
124
|
+
if (String(ci.effectiveType).includes("3g")){ mr=Math.min(mr,0); mp=Math.min(mp,4); }
|
|
125
|
+
if (typeof ci.rtt==="number" && ci.rtt>300){ mr=0; mp=Math.min(mp,3); }
|
|
126
|
+
if (typeof ci.downlink==="number" && ci.downlink<1.2){ mr=0; mp=Math.min(mp,3); }
|
|
127
|
+
mp=clamp(mp,0,12); mr=clamp(mr,0,3);
|
|
128
|
+
if (!supportsPrerender()) mr=0;
|
|
129
|
+
return { maxPrefetch: mp, maxPrerender: mr };
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function enqueue(rawUrl, score){
|
|
133
|
+
var url=normalizeUrl(rawUrl);
|
|
134
|
+
if(!url) return;
|
|
135
|
+
stats.enqueued++;
|
|
136
|
+
queue.push({url:url,score:score,t:Date.now()});
|
|
137
|
+
queue.sort(function(a,b){ return b.score-a.score; });
|
|
138
|
+
pump();
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function pump(){
|
|
142
|
+
var b=computeBudgets();
|
|
143
|
+
while(queue.length){
|
|
144
|
+
var n=queue.shift();
|
|
145
|
+
var url=n.url, score=n.score;
|
|
146
|
+
if(loaded.has(url) || stats.isLoaded(url)) continue;
|
|
147
|
+
if(inFlight.has(url)) continue;
|
|
148
|
+
|
|
149
|
+
var wantPrerender = b.maxPrerender>usedPrerender && score>=90;
|
|
150
|
+
var wantPrefetch = b.maxPrefetch>usedPrefetch;
|
|
151
|
+
|
|
152
|
+
if(!wantPrerender && !wantPrefetch) break;
|
|
153
|
+
|
|
154
|
+
var type = wantPrerender ? "prerender" : "prefetch";
|
|
155
|
+
if(type==="prerender") usedPrerender++; else usedPrefetch++;
|
|
156
|
+
|
|
157
|
+
inFlight.add(url);
|
|
158
|
+
var link=document.createElement("link");
|
|
159
|
+
link.rel=type;
|
|
160
|
+
link.href=url;
|
|
161
|
+
link.as="document";
|
|
162
|
+
link.fetchPriority = (score>=90) ? "high" : (score>=70 ? "auto" : "low");
|
|
163
|
+
|
|
164
|
+
link.onload=function(){
|
|
165
|
+
loaded.add(url);
|
|
166
|
+
inFlight.delete(url);
|
|
167
|
+
stats.markLoaded(url,type);
|
|
168
|
+
};
|
|
169
|
+
link.onerror=function(){ inFlight.delete(url); };
|
|
170
|
+
document.head.appendChild(link);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
window.addEventListener("pageshow", function(){ usedPrefetch=0; usedPrerender=0; });
|
|
175
|
+
|
|
176
|
+
return { enqueue: enqueue };
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
function createTuner(c, stats){
|
|
180
|
+
var intentCount=0;
|
|
181
|
+
function maybeTune(){
|
|
182
|
+
var total = stats.prefetched + stats.prerendered;
|
|
183
|
+
if(total<12) return;
|
|
184
|
+
var hr = stats.hitRate;
|
|
185
|
+
if (hr>=0.35) c.hoverDelay = clamp((c.hoverDelay||65)-10, 25, 140);
|
|
186
|
+
else if (hr<=0.15) c.hoverDelay = clamp((c.hoverDelay||65)+15, 25, 180);
|
|
187
|
+
}
|
|
188
|
+
return {
|
|
189
|
+
onEnqueue:function(){ intentCount++; if(intentCount%20===0) maybeTune(); },
|
|
190
|
+
onClick:function(){}
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
function maybeOverlay(c, stats){
|
|
195
|
+
if(!c.debug || !c.debugOverlay) return;
|
|
196
|
+
var el=document.createElement("div");
|
|
197
|
+
el.style.cssText="position:fixed;bottom:12px;right:12px;z-index:2147483647;background:rgba(0,0,0,.75);color:#fff;padding:10px 12px;border-radius:10px;font:12px/1.35 system-ui,-apple-system,Segoe UI,Roboto,Arial;box-shadow:0 10px 30px rgba(0,0,0,.35);max-width:280px";
|
|
198
|
+
function render(){
|
|
199
|
+
var s=stats.snapshot();
|
|
200
|
+
el.innerHTML="<div style='font-weight:700;margin-bottom:6px'>HyperInstant "+s.version+"</div>"+
|
|
201
|
+
"<div>Loaded: <b>"+(s.prefetched+s.prerendered)+"</b> (P:"+s.prefetched+" R:"+s.prerendered+")</div>"+
|
|
202
|
+
"<div>Hit-rate: <b>"+Math.round(s.hitRate*100)+"%</b></div>"+
|
|
203
|
+
"<div>HoverDelay: <b>"+c.hoverDelay+"ms</b></div>"+
|
|
204
|
+
"<div style='opacity:.8;margin-top:6px'>Clicks: "+s.clicked+" • Seen: "+s.seen+"</div>";
|
|
205
|
+
}
|
|
206
|
+
render();
|
|
207
|
+
document.addEventListener("DOMContentLoaded", function(){ document.body.appendChild(el); });
|
|
208
|
+
setInterval(render, 1200);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
function eligibleLink(target){
|
|
212
|
+
var a = target && target.closest ? target.closest("a[href]") : null;
|
|
213
|
+
if(!a || !a.href) return null;
|
|
214
|
+
var rel = String(a.getAttribute("rel")||"").toLowerCase();
|
|
215
|
+
if(rel.includes("nofollow")) return null;
|
|
216
|
+
if(a.getAttribute("data-no-instant")!==null) return null;
|
|
217
|
+
if(a.getAttribute("data-hyperinstant")==="off") return null;
|
|
218
|
+
if(a.target && a.target!=="_self") return null;
|
|
219
|
+
return a;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
function score(signal, a){
|
|
223
|
+
var s=60;
|
|
224
|
+
if(signal==="mousedown") s=100;
|
|
225
|
+
else if(signal==="touchstart") s=96;
|
|
226
|
+
else if(signal==="focusin") s=86;
|
|
227
|
+
else if(signal==="mouseover") s=72;
|
|
228
|
+
else if(signal==="viewport") s=40;
|
|
229
|
+
if(inNav(a)) s+=8;
|
|
230
|
+
if(String(a.getAttribute("data-hyperinstant-priority")||"").toLowerCase()==="high") s+=12;
|
|
231
|
+
return Math.min(110,s);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
function startObservers(c, scheduler, stats, tuner){
|
|
235
|
+
var hoverTimer=null;
|
|
236
|
+
|
|
237
|
+
function onIntent(e){
|
|
238
|
+
var a=eligibleLink(e.target);
|
|
239
|
+
if(!a) return;
|
|
240
|
+
var url=a.href;
|
|
241
|
+
stats.seen++;
|
|
242
|
+
if(shouldDeny(url,c)){ stats.denied++; return; }
|
|
243
|
+
|
|
244
|
+
var sig=e.type;
|
|
245
|
+
var sc=score(sig,a);
|
|
246
|
+
clearTimeout(hoverTimer);
|
|
247
|
+
var delay = (sig==="mouseover") ? c.hoverDelay : 0;
|
|
248
|
+
hoverTimer=setTimeout(function(){
|
|
249
|
+
scheduler.enqueue(url, sc);
|
|
250
|
+
tuner.onEnqueue();
|
|
251
|
+
}, delay);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
function onClick(e){
|
|
255
|
+
var a=eligibleLink(e.target);
|
|
256
|
+
if(!a) return;
|
|
257
|
+
stats.markClick(a.href);
|
|
258
|
+
tuner.onClick();
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
(c.events||["mouseover","touchstart","mousedown","focusin"]).forEach(function(evt){
|
|
262
|
+
document.addEventListener(evt, onIntent, {passive:true, capture:true});
|
|
263
|
+
});
|
|
264
|
+
document.addEventListener("click", onClick, {passive:true, capture:true});
|
|
265
|
+
|
|
266
|
+
if (String(c.observe||"intent").toLowerCase().includes("viewport") && "IntersectionObserver" in window) {
|
|
267
|
+
var io=new IntersectionObserver(function(entries){
|
|
268
|
+
entries.forEach(function(ent){
|
|
269
|
+
if(!ent.isIntersecting) return;
|
|
270
|
+
var a=eligibleLink(ent.target);
|
|
271
|
+
if(!a) return;
|
|
272
|
+
var url=a.href;
|
|
273
|
+
if(shouldDeny(url,c)) return;
|
|
274
|
+
scheduler.enqueue(url, score("viewport", a));
|
|
275
|
+
io.unobserve(ent.target);
|
|
276
|
+
});
|
|
277
|
+
}, {root:null, rootMargin:"200px 0px", threshold:0.01});
|
|
278
|
+
|
|
279
|
+
function scan(){
|
|
280
|
+
document.querySelectorAll("a[data-hyperinstant-viewport='on'][href]").forEach(function(a){ io.observe(a); });
|
|
281
|
+
}
|
|
282
|
+
scan();
|
|
283
|
+
var mo=new MutationObserver(function(){ scan(); });
|
|
284
|
+
mo.observe(document.documentElement, {childList:true, subtree:true});
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
// init
|
|
289
|
+
var c = applyModeDefaults(cfg);
|
|
290
|
+
var adapter = detectAdapter(c.adapter);
|
|
291
|
+
c = adapter(c);
|
|
292
|
+
|
|
293
|
+
var stats = new Stats();
|
|
294
|
+
var tuner = createTuner(c, stats);
|
|
295
|
+
var scheduler = createScheduler(c, stats);
|
|
296
|
+
|
|
297
|
+
if (c.debug) { window.HyperInstantStats = stats; console.log("[HyperInstant] v1.0.1 loaded", c); }
|
|
298
|
+
startObservers(c, scheduler, stats, tuner);
|
|
299
|
+
maybeOverlay(c, stats);
|
|
300
|
+
})();
|
package/dist/hyperinstant.min.js
CHANGED
|
@@ -1,2 +1 @@
|
|
|
1
|
-
"use strict";var HyperInstantLib=(()=>{var w=Object.defineProperty;var A=Object.getOwnPropertyDescriptor;var I=Object.getOwnPropertyNames;var O=Object.prototype.hasOwnProperty;var k=(t,e)=>{for(var n in e)w(t,n,{get:e[n],enumerable:!0})},L=(t,e,n,s)=>{if(e&&typeof e=="object"||typeof e=="function")for(let i of I(e))!O.call(t,i)&&i!==n&&w(t,i,{get:()=>e[i],enumerable:!(s=A(e,i))||s.enumerable});return t};var P=t=>L(w({},"__esModule",{value:!0}),t);var R={};k(R,{start:()=>y});function v(t,e){let n=new URL(t.toString());return n.hash="",e&&(n.search=""),n.toString()}function h(t,e){return typeof e=="string"?t.includes(e):e.test(t)}function x(t){let e=(t.getAttribute("href")||"").trim();return!(!e||e.startsWith("#")||e.startsWith("mailto:")||e.startsWith("tel:")||e.startsWith("javascript:")||t.hasAttribute("download")||(t.getAttribute("target")||"").toLowerCase()==="_blank")}function E(t){let{url:e,origin:n,allowSameOriginOnly:s,allow:i,deny:c}=t;if(s&&e.origin!==n)return!1;let l=e.toString(),u=e.pathname+e.search;for(let f of c)if(h(l,f)||h(u,f))return!1;if(i.length>0){for(let f of i)if(h(l,f)||h(u,f))return!0;return!1}return!0}function H(t,e,n=!1){try{let s=document.createElement("script");s.type="speculationrules";let i={};return i[t]=[{source:"list",urls:e}],s.textContent=JSON.stringify(i),document.head.appendChild(s),n&&console.log("[HyperInstant] speculationrules injected:",t,e),!0}catch{return!1}}function S(t,e=!1){try{let n=document.createElement("link");return n.rel="prefetch",n.href=t,n.as="document",document.head.appendChild(n),e&&console.log("[HyperInstant] link prefetch:",t),!0}catch{return!1}}function C(t){var n,s,i,c,l,u,f,m,p,o,r,a;let e=t||{};return{strategy:(n=e.strategy)!=null?n:"auto",hoverDelay:(s=e.hoverDelay)!=null?s:65,touchEnabled:(i=e.touchEnabled)!=null?i:!0,allowSameOriginOnly:(c=e.allowSameOriginOnly)!=null?c:!0,deny:(l=e.deny)!=null?l:["/cart","/checkout","/my-account","/account","/logout","add-to-cart"],allow:(u=e.allow)!=null?u:[],ignoreQueryParams:(f=e.ignoreQueryParams)!=null?f:!0,maxPrefetch:(m=e.maxPrefetch)!=null?m:6,maxPrerender:(p=e.maxPrerender)!=null?p:2,respectSaveData:(o=e.respectSaveData)!=null?o:!0,minEffectiveType:(r=e.minEffectiveType)!=null?r:"4g",debug:(a=e.debug)!=null?a:!1}}function T(t){let e=navigator,n=e.connection||e.mozConnection||e.webkitConnection;if(t.respectSaveData&&(n==null?void 0:n.saveData)===!0)return!1;let s=n==null?void 0:n.effectiveType;if(!s)return!0;let i=["2g","3g","4g"],c=i.indexOf(t.minEffectiveType),l=i.indexOf(s);return c===-1||l===-1?!0:l>=c}function y(t){let e=C(t!=null?t:window.HyperInstant),n=location.origin;if(!T(e)){e.debug&&console.log("[HyperInstant] disabled by network/save-data");return}let s=new Set,i=0,c=0,l=new WeakMap;function u(o){return o==="prefetch-only"?"prefetch":o==="prerender-first"||c<e.maxPrerender?"prerender":"prefetch"}function f(o){return o==="prefetch"?i<e.maxPrefetch:c<e.maxPrerender}function m(o){if(s.has(o))return;s.add(o);let r=u(e.strategy);if(!f(r))return;!H(r,[o],e.debug)&&r==="prefetch"&&S(o,e.debug),r==="prefetch"?i++:c++}function p(o){if(!x(o))return;let r;try{r=new URL(o.href,location.href)}catch{return}if(!E({url:r,origin:n,allowSameOriginOnly:e.allowSameOriginOnly,allow:e.allow,deny:e.deny}))return;let a=v(r,e.ignoreQueryParams);m(a)}document.addEventListener("mouseover",o=>{var b;let r=o.target;if(!r)return;let a=(b=r.closest)==null?void 0:b.call(r,"a");if(!a||l.get(a))return;let g=window.setTimeout(()=>{l.delete(a),p(a)},e.hoverDelay);l.set(a,g)},{passive:!0}),document.addEventListener("mouseout",o=>{var g;let r=o.target;if(!r)return;let a=(g=r.closest)==null?void 0:g.call(r,"a");if(!a)return;let d=l.get(a);d&&(window.clearTimeout(d),l.delete(a))},{passive:!0}),e.touchEnabled&&document.addEventListener("touchstart",o=>{var d;let r=o.target;if(!r)return;let a=(d=r.closest)==null?void 0:d.call(r,"a");a&&p(a)},{passive:!0}),e.debug&&console.log("[HyperInstant] started",e)}typeof window!="undefined"&&(window.HyperInstantStart=()=>y(window.HyperInstant),y(window.HyperInstant));return P(R);})();
|
|
2
|
-
//# sourceMappingURL=hyperinstant.min.js.map
|
|
1
|
+
/*! HyperInstant v1.0.1 | MIT | Putia Web */ (function(){if (window.__HYPERINSTANT_LOADED__) return; window.__HYPERINSTANT_LOADED__ = true; var cfg = window.HyperInstant ||{}; function clamp(n,a,b){return Math.max(a, Math.min(b,n));} function isSameOrigin(url){try{return new URL(url, location.href).origin === location.origin;}catch(e){return false;}} function normalizeUrl(url){try{var u=new URL(url, location.href); u.hash=""; return u.toString();}catch(e){return "";}} function getConn(){var c=navigator.connection||navigator.mozConnection||navigator.webkitConnection; return{saveData:!!(c&&c.saveData), effectiveType:(c&&c.effectiveType)?String(c.effectiveType):"unknown", downlink:(c&&typeof c.downlink==="number")?c.downlink:null, rtt:(c&&typeof c.rtt==="number")?c.rtt:null};} function supportsPrerender(){try{return "relList" in HTMLLinkElement.prototype && HTMLLinkElement.prototype.relList.supports && HTMLLinkElement.prototype.relList.supports("prerender");}catch(e){return false;}} function inNav(a){try{return !!a.closest("nav, header, [role='navigation'], .header, .site-header");}catch(e){return false;}} function applyModeDefaults(c){var mode = String(c.mode||"safe").toLowerCase(); var out = Object.assign({}, c); if (mode==="aggressive"){out.maxPrefetch = out.maxPrefetch ?? 10; out.maxPrerender = out.maxPrerender ?? 2; out.observe = out.observe ?? "intent+viewport";} else if (mode==="balanced"){out.maxPrefetch = out.maxPrefetch ?? 6; out.maxPrerender = out.maxPrerender ?? 1; out.observe = out.observe ?? "intent";} else{out.maxPrefetch = out.maxPrefetch ?? 4; out.maxPrerender = out.maxPrerender ?? 0; out.observe = out.observe ?? "intent";} out.hoverDelay = out.hoverDelay ?? 65; out.debug = !!out.debug; out.debugOverlay = !!out.debugOverlay; out.budget = out.budget ?? "auto"; out.events = out.events ?? ["mouseover","touchstart","mousedown","focusin"]; out.deny = out.deny ?? []; return out;} function hasMeta(name){return !!document.querySelector('meta[name="'+name+'"]');} function shopifyAdapter(c){var deny=new Set([].concat(c.deny||[])); ["/cart","/checkout","/account","/account/login","/account/register","/account/logout","/search","cart/add","cart/change","cart/update","?variant=","variant=","sections="].forEach(function(x){deny.add(x);}); return Object.assign({}, c,{deny:Array.from(deny)});} function wooAdapter(c){var deny=new Set([].concat(c.deny||[])); ["/cart","/checkout","/my-account","add-to-cart","wc-ajax","remove_item","update_cart","apply_coupon"].forEach(function(x){deny.add(x);}); return Object.assign({}, c,{deny:Array.from(deny)});} function nopAdapter(c){var deny=new Set([].concat(c.deny||[])); ["/shoppingcart","/checkout","/login","/register","/logout","/customer","addproducttocart","updateshoppingcart","updatecart","deleteitem","/wishlist","/compareproducts","/search","?q="].forEach(function(x){deny.add(x);}); return Object.assign({}, c,{deny:Array.from(deny)});} function detectAdapter(name){name = String(name||"auto").toLowerCase(); if (name==="shopify") return shopifyAdapter; if (name==="woocommerce") return wooAdapter; if (name==="nopcommerce") return nopAdapter; if (name==="generic") return function(x){return x;}; try{if (window.Shopify || hasMeta("shopify-digital-wallet") || hasMeta("shopify-checkout-api-token")) return shopifyAdapter;}catch(e){} try{if (window.wc_add_to_cart_params || window.wc_cart_fragments_params || (document.body&&String(document.body.className||"").includes("woocommerce"))) return wooAdapter;}catch(e){} try{if (window.nopCommerce || document.querySelector("a[href*='shoppingcart']") || document.querySelector("form[action*='addproducttocart']")) return nopAdapter;}catch(e){} return function(x){return x;};} var AUTO_KEYWORDS=["logout","logoff","signin","sign-in","login","register","account","checkout","cart","basket","order","orders","pay","payment","add-to-cart","addtocart","addproducttocart","remove","update","change","delete","wc-ajax","admin-ajax","ajax","sections=","variant=","token","returnurl","redirect"]; var AUTO_PATHS=["/checkout","/cart","/shoppingcart","/account","/my-account","/logout","/login","/register"]; var AUTO_PARAMS=["add","remove","update","change","delete","token","variant","sections","returnurl","redirect"]; function shouldDeny(url, c){if (!url) return true; if (!isSameOrigin(url)) return true; var u = String(url).toLowerCase(); var denyList = c.deny || []; for (var i=0;i<denyList.length;i++){var r=denyList[i]; if (r && u.includes(String(r).toLowerCase())) return true;} try{var p = new URL(url, location.href).pathname.toLowerCase(); for (var j=0;j<AUTO_PATHS.length;j++){var ap=AUTO_PATHS[j]; if (p===ap || p.startsWith(ap+"/")) return true;}}catch(e){} for (var k=0;k<AUTO_KEYWORDS.length;k++){if (u.includes(AUTO_KEYWORDS[k])) return true;} try{var uu = new URL(url, location.href); var sp = uu.searchParams; for (var q=0;q<AUTO_PARAMS.length;q++){if (sp.has(AUTO_PARAMS[q])) return true;}}catch(e){} return false;} function Stats(){this.startedAt=Date.now(); this.seen=0; this.denied=0; this.enqueued=0; this.prefetched=0; this.prerendered=0; this.clicked=0; this.hit=0; this._loaded=new Map();} Stats.prototype.markLoaded=function(url,type){if(!this._loaded.has(url)){this._loaded.set(url,{type:type,t:Date.now()}); if(type==="prerender") this.prerendered++; else this.prefetched++;}}; Stats.prototype.isLoaded=function(url){return this._loaded.has(url);}; Stats.prototype.markClick=function(url){this.clicked++; if(this._loaded.has(url)) this.hit++;}; Object.defineProperty(Stats.prototype,"hitRate",{get:function(){var d=this.prefetched+this.prerendered; return d? (this.hit/d):0;}}); Stats.prototype.snapshot=function(){return{version:"1.0.1", uptimeSec:Math.round((Date.now()-this.startedAt)/1000), seen:this.seen, denied:this.denied, enqueued:this.enqueued, prefetched:this.prefetched, prerendered:this.prerendered, clicked:this.clicked, hit:this.hit, hitRate:Number(this.hitRate.toFixed(3))};}; function createScheduler(c, stats){var queue=[]; var inFlight=new Set(); var loaded=new Set(); var usedPrefetch=0, usedPrerender=0; function computeBudgets(){if (c.budget && typeof c.budget==="object"){return{maxPrefetch: c.budget.maxPrefetch ?? c.maxPrefetch, maxPrerender: c.budget.maxPrerender ?? c.maxPrerender};} var ci=getConn(); var mp=c.maxPrefetch, mr=c.maxPrerender; if (ci.saveData){mr=0; mp=Math.min(mp,2);} if (String(ci.effectiveType).includes("2g")){mr=0; mp=Math.min(mp,2);} if (String(ci.effectiveType).includes("3g")){mr=Math.min(mr,0); mp=Math.min(mp,4);} if (typeof ci.rtt==="number" && ci.rtt>300){mr=0; mp=Math.min(mp,3);} if (typeof ci.downlink==="number" && ci.downlink<1.2){mr=0; mp=Math.min(mp,3);} mp=clamp(mp,0,12); mr=clamp(mr,0,3); if (!supportsPrerender()) mr=0; return{maxPrefetch: mp, maxPrerender: mr};} function enqueue(rawUrl, score){var url=normalizeUrl(rawUrl); if(!url) return; stats.enqueued++; queue.push({url:url,score:score,t:Date.now()}); queue.sort(function(a,b){return b.score-a.score;}); pump();} function pump(){var b=computeBudgets(); while(queue.length){var n=queue.shift(); var url=n.url, score=n.score; if(loaded.has(url) || stats.isLoaded(url)) continue; if(inFlight.has(url)) continue; var wantPrerender = b.maxPrerender>usedPrerender && score>=90; var wantPrefetch = b.maxPrefetch>usedPrefetch; if(!wantPrerender && !wantPrefetch) break; var type = wantPrerender ? "prerender" : "prefetch"; if(type==="prerender") usedPrerender++; else usedPrefetch++; inFlight.add(url); var link=document.createElement("link"); link.rel=type; link.href=url; link.as="document"; link.fetchPriority = (score>=90) ? "high" : (score>=70 ? "auto" : "low"); link.onload=function(){loaded.add(url); inFlight.delete(url); stats.markLoaded(url,type);}; link.onerror=function(){inFlight.delete(url);}; document.head.appendChild(link);}} window.addEventListener("pageshow", function(){usedPrefetch=0; usedPrerender=0;}); return{enqueue: enqueue};} function createTuner(c, stats){var intentCount=0; function maybeTune(){var total = stats.prefetched + stats.prerendered; if(total<12) return; var hr = stats.hitRate; if (hr>=0.35) c.hoverDelay = clamp((c.hoverDelay||65)-10, 25, 140); else if (hr<=0.15) c.hoverDelay = clamp((c.hoverDelay||65)+15, 25, 180);} return{onEnqueue:function(){intentCount++; if(intentCount%20===0) maybeTune();}, onClick:function(){}};} function maybeOverlay(c, stats){if(!c.debug || !c.debugOverlay) return; var el=document.createElement("div"); el.style.cssText="position:fixed;bottom:12px;right:12px;z-index:2147483647;background:rgba(0,0,0,.75);color:#fff;padding:10px 12px;border-radius:10px;font:12px/1.35 system-ui,-apple-system,Segoe UI,Roboto,Arial;box-shadow:0 10px 30px rgba(0,0,0,.35);max-width:280px"; function render(){var s=stats.snapshot(); el.innerHTML="<div style='font-weight:700;margin-bottom:6px'>HyperInstant "+s.version+"</div>"+ "<div>Loaded: <b>"+(s.prefetched+s.prerendered)+"</b> (P:"+s.prefetched+" R:"+s.prerendered+")</div>"+ "<div>Hit-rate: <b>"+Math.round(s.hitRate*100)+"%</b></div>"+ "<div>HoverDelay: <b>"+c.hoverDelay+"ms</b></div>"+ "<div style='opacity:.8;margin-top:6px'>Clicks: "+s.clicked+" • Seen: "+s.seen+"</div>";} render(); document.addEventListener("DOMContentLoaded", function(){document.body.appendChild(el);}); setInterval(render, 1200);} function eligibleLink(target){var a = target && target.closest ? target.closest("a[href]") : null; if(!a || !a.href) return null; var rel = String(a.getAttribute("rel")||"").toLowerCase(); if(rel.includes("nofollow")) return null; if(a.getAttribute("data-no-instant")!==null) return null; if(a.getAttribute("data-hyperinstant")==="off") return null; if(a.target && a.target!=="_self") return null; return a;} function score(signal, a){var s=60; if(signal==="mousedown") s=100; else if(signal==="touchstart") s=96; else if(signal==="focusin") s=86; else if(signal==="mouseover") s=72; else if(signal==="viewport") s=40; if(inNav(a)) s+=8; if(String(a.getAttribute("data-hyperinstant-priority")||"").toLowerCase()==="high") s+=12; return Math.min(110,s);} function startObservers(c, scheduler, stats, tuner){var hoverTimer=null; function onIntent(e){var a=eligibleLink(e.target); if(!a) return; var url=a.href; stats.seen++; if(shouldDeny(url,c)){stats.denied++; return;} var sig=e.type; var sc=score(sig,a); clearTimeout(hoverTimer); var delay = (sig==="mouseover") ? c.hoverDelay : 0; hoverTimer=setTimeout(function(){scheduler.enqueue(url, sc); tuner.onEnqueue();}, delay);} function onClick(e){var a=eligibleLink(e.target); if(!a) return; stats.markClick(a.href); tuner.onClick();} (c.events||["mouseover","touchstart","mousedown","focusin"]).forEach(function(evt){document.addEventListener(evt, onIntent,{passive:true, capture:true});}); document.addEventListener("click", onClick,{passive:true, capture:true}); if (String(c.observe||"intent").toLowerCase().includes("viewport") && "IntersectionObserver" in window){var io=new IntersectionObserver(function(entries){entries.forEach(function(ent){if(!ent.isIntersecting) return; var a=eligibleLink(ent.target); if(!a) return; var url=a.href; if(shouldDeny(url,c)) return; scheduler.enqueue(url, score("viewport", a)); io.unobserve(ent.target);});},{root:null, rootMargin:"200px 0px", threshold:0.01}); function scan(){document.querySelectorAll("a[data-hyperinstant-viewport='on'][href]").forEach(function(a){io.observe(a);});} scan(); var mo=new MutationObserver(function(){scan();}); mo.observe(document.documentElement,{childList:true, subtree:true});}} // init var c = applyModeDefaults(cfg); var adapter = detectAdapter(c.adapter); c = adapter(c); var stats = new Stats(); var tuner = createTuner(c, stats); var scheduler = createScheduler(c, stats); if (c.debug){window.HyperInstantStats = stats; console.log("[HyperInstant] v1.0.1 loaded", c);} startObservers(c, scheduler, stats, tuner); maybeOverlay(c, stats);})();
|
package/package.json
CHANGED
|
@@ -1,30 +1,31 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hyperinstant",
|
|
3
|
-
"version": "0.1
|
|
4
|
-
"description": "
|
|
5
|
-
"
|
|
6
|
-
"
|
|
7
|
-
"main": "./dist/hyperinstant.min.js",
|
|
8
|
-
"module": "./dist/hyperinstant.esm.js",
|
|
3
|
+
"version": "1.0.1",
|
|
4
|
+
"description": "Adaptive, safe and intelligent instant navigation engine for any website.",
|
|
5
|
+
"main": "dist/hyperinstant.min.js",
|
|
6
|
+
"module": "dist/hyperinstant.js",
|
|
9
7
|
"files": [
|
|
10
|
-
"dist"
|
|
11
|
-
"README.md",
|
|
12
|
-
"LICENSE"
|
|
8
|
+
"dist"
|
|
13
9
|
],
|
|
14
|
-
"scripts": {
|
|
15
|
-
"build": "node build.mjs",
|
|
16
|
-
"dev": "node build.mjs --watch"
|
|
17
|
-
},
|
|
18
10
|
"keywords": [
|
|
11
|
+
"performance",
|
|
19
12
|
"prefetch",
|
|
20
13
|
"prerender",
|
|
21
|
-
"performance",
|
|
22
|
-
"speculationrules",
|
|
23
14
|
"instant-page",
|
|
15
|
+
"web-performance",
|
|
16
|
+
"shopify",
|
|
17
|
+
"woocommerce",
|
|
18
|
+
"nopcommerce",
|
|
19
|
+
"adaptive",
|
|
24
20
|
"navigation"
|
|
25
21
|
],
|
|
26
|
-
"
|
|
27
|
-
|
|
28
|
-
|
|
22
|
+
"author": "Putia Web",
|
|
23
|
+
"license": "MIT",
|
|
24
|
+
"repository": {
|
|
25
|
+
"type": "git",
|
|
26
|
+
"url": "https://example.com/putiaweb/hyperinstant"
|
|
27
|
+
},
|
|
28
|
+
"bugs": {
|
|
29
|
+
"url": "https://example.com/putiaweb/hyperinstant/issues"
|
|
29
30
|
}
|
|
30
31
|
}
|
package/dist/hyperinstant.esm.js
DELETED
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
function b(n,e){let r=new URL(n.toString());return r.hash="",e&&(r.search=""),r.toString()}function h(n,e){return typeof e=="string"?n.includes(e):e.test(n)}function v(n){let e=(n.getAttribute("href")||"").trim();return!(!e||e.startsWith("#")||e.startsWith("mailto:")||e.startsWith("tel:")||e.startsWith("javascript:")||n.hasAttribute("download")||(n.getAttribute("target")||"").toLowerCase()==="_blank")}function x(n){let{url:e,origin:r,allowSameOriginOnly:a,allow:s,deny:c}=n;if(a&&e.origin!==r)return!1;let l=e.toString(),u=e.pathname+e.search;for(let f of c)if(h(l,f)||h(u,f))return!1;if(s.length>0){for(let f of s)if(h(l,f)||h(u,f))return!0;return!1}return!0}function E(n,e,r=!1){try{let a=document.createElement("script");a.type="speculationrules";let s={};return s[n]=[{source:"list",urls:e}],a.textContent=JSON.stringify(s),document.head.appendChild(a),r&&console.log("[HyperInstant] speculationrules injected:",n,e),!0}catch{return!1}}function H(n,e=!1){try{let r=document.createElement("link");return r.rel="prefetch",r.href=n,r.as="document",document.head.appendChild(r),e&&console.log("[HyperInstant] link prefetch:",n),!0}catch{return!1}}function S(n){var r,a,s,c,l,u,f,m,p,o,t,i;let e=n||{};return{strategy:(r=e.strategy)!=null?r:"auto",hoverDelay:(a=e.hoverDelay)!=null?a:65,touchEnabled:(s=e.touchEnabled)!=null?s:!0,allowSameOriginOnly:(c=e.allowSameOriginOnly)!=null?c:!0,deny:(l=e.deny)!=null?l:["/cart","/checkout","/my-account","/account","/logout","add-to-cart"],allow:(u=e.allow)!=null?u:[],ignoreQueryParams:(f=e.ignoreQueryParams)!=null?f:!0,maxPrefetch:(m=e.maxPrefetch)!=null?m:6,maxPrerender:(p=e.maxPrerender)!=null?p:2,respectSaveData:(o=e.respectSaveData)!=null?o:!0,minEffectiveType:(t=e.minEffectiveType)!=null?t:"4g",debug:(i=e.debug)!=null?i:!1}}function A(n){let e=navigator,r=e.connection||e.mozConnection||e.webkitConnection;if(n.respectSaveData&&(r==null?void 0:r.saveData)===!0)return!1;let a=r==null?void 0:r.effectiveType;if(!a)return!0;let s=["2g","3g","4g"],c=s.indexOf(n.minEffectiveType),l=s.indexOf(a);return c===-1||l===-1?!0:l>=c}function y(n){let e=S(n!=null?n:window.HyperInstant),r=location.origin;if(!A(e)){e.debug&&console.log("[HyperInstant] disabled by network/save-data");return}let a=new Set,s=0,c=0,l=new WeakMap;function u(o){return o==="prefetch-only"?"prefetch":o==="prerender-first"||c<e.maxPrerender?"prerender":"prefetch"}function f(o){return o==="prefetch"?s<e.maxPrefetch:c<e.maxPrerender}function m(o){if(a.has(o))return;a.add(o);let t=u(e.strategy);if(!f(t))return;!E(t,[o],e.debug)&&t==="prefetch"&&H(o,e.debug),t==="prefetch"?s++:c++}function p(o){if(!v(o))return;let t;try{t=new URL(o.href,location.href)}catch{return}if(!x({url:t,origin:r,allowSameOriginOnly:e.allowSameOriginOnly,allow:e.allow,deny:e.deny}))return;let i=b(t,e.ignoreQueryParams);m(i)}document.addEventListener("mouseover",o=>{var w;let t=o.target;if(!t)return;let i=(w=t.closest)==null?void 0:w.call(t,"a");if(!i||l.get(i))return;let g=window.setTimeout(()=>{l.delete(i),p(i)},e.hoverDelay);l.set(i,g)},{passive:!0}),document.addEventListener("mouseout",o=>{var g;let t=o.target;if(!t)return;let i=(g=t.closest)==null?void 0:g.call(t,"a");if(!i)return;let d=l.get(i);d&&(window.clearTimeout(d),l.delete(i))},{passive:!0}),e.touchEnabled&&document.addEventListener("touchstart",o=>{var d;let t=o.target;if(!t)return;let i=(d=t.closest)==null?void 0:d.call(t,"a");i&&p(i)},{passive:!0}),e.debug&&console.log("[HyperInstant] started",e)}typeof window!="undefined"&&(window.HyperInstantStart=()=>y(window.HyperInstant),y(window.HyperInstant));export{y as start};
|
|
2
|
-
//# sourceMappingURL=hyperinstant.esm.js.map
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../src/url.ts", "../src/filters.ts", "../src/speculation.ts", "../src/prefetch.ts", "../src/core.ts", "../src/index.ts"],
|
|
4
|
-
"sourcesContent": ["export function normalizeUrl(url: URL, ignoreQueryParams: boolean): string {\n const u = new URL(url.toString());\n u.hash = \"\";\n if (ignoreQueryParams) u.search = \"\";\n return u.toString();\n}\n", "export function matchesRule(value: string, rule: string | RegExp): boolean {\n if (typeof rule === \"string\") return value.includes(rule);\n return rule.test(value);\n}\n\nexport function shouldHandleAnchor(a: HTMLAnchorElement): boolean {\n const href = (a.getAttribute(\"href\") || \"\").trim();\n if (!href) return false;\n if (href.startsWith(\"#\")) return false;\n if (href.startsWith(\"mailto:\") || href.startsWith(\"tel:\")) return false;\n if (href.startsWith(\"javascript:\")) return false;\n if (a.hasAttribute(\"download\")) return false;\n\n const target = (a.getAttribute(\"target\") || \"\").toLowerCase();\n if (target === \"_blank\") return false;\n\n return true;\n}\n\nexport function shouldAllowUrl(opts: {\n url: URL;\n origin: string;\n allowSameOriginOnly: boolean;\n allow: Array<string | RegExp>;\n deny: Array<string | RegExp>;\n}): boolean {\n const { url, origin, allowSameOriginOnly, allow, deny } = opts;\n\n if (allowSameOriginOnly && url.origin !== origin) return false;\n\n const full = url.toString();\n const path = url.pathname + url.search;\n\n for (const r of deny) {\n if (matchesRule(full, r) || matchesRule(path, r)) return false;\n }\n\n if (allow.length > 0) {\n for (const r of allow) {\n if (matchesRule(full, r) || matchesRule(path, r)) return true;\n }\n return false;\n }\n\n return true;\n}\n", "export type SpecAction = \"prefetch\" | \"prerender\";\n\nexport function injectSpeculationRules(action: SpecAction, urls: string[], debug = false): boolean {\n try {\n const script = document.createElement(\"script\");\n script.type = \"speculationrules\";\n\n const payload: any = {};\n payload[action] = [{ source: \"list\", urls }];\n\n script.textContent = JSON.stringify(payload);\n document.head.appendChild(script);\n\n if (debug) console.log(\"[HyperInstant] speculationrules injected:\", action, urls);\n return true;\n } catch {\n return false;\n }\n}\n", "export function linkPrefetch(url: string, debug = false): boolean {\n try {\n const l = document.createElement(\"link\");\n l.rel = \"prefetch\";\n l.href = url;\n l.as = \"document\";\n document.head.appendChild(l);\n if (debug) console.log(\"[HyperInstant] link prefetch:\", url);\n return true;\n } catch {\n return false;\n }\n}\n", "import { HyperInstantConfig, NormalizedConfig, Strategy } from \"./types.js\";\nimport { normalizeUrl } from \"./url.js\";\nimport { shouldHandleAnchor, shouldAllowUrl } from \"./filters.js\";\nimport { injectSpeculationRules } from \"./speculation.js\";\nimport { linkPrefetch } from \"./prefetch.js\";\n\ndeclare global {\n interface Window {\n HyperInstant?: HyperInstantConfig;\n HyperInstantStart?: () => void;\n }\n}\n\nfunction normalizeConfig(input?: HyperInstantConfig): NormalizedConfig {\n const cfg = input || {};\n return {\n strategy: cfg.strategy ?? \"auto\",\n hoverDelay: cfg.hoverDelay ?? 65,\n touchEnabled: cfg.touchEnabled ?? true,\n\n allowSameOriginOnly: cfg.allowSameOriginOnly ?? true,\n deny: cfg.deny ?? [\"/cart\", \"/checkout\", \"/my-account\", \"/account\", \"/logout\", \"add-to-cart\"],\n allow: cfg.allow ?? [],\n ignoreQueryParams: cfg.ignoreQueryParams ?? true,\n\n maxPrefetch: cfg.maxPrefetch ?? 6,\n maxPrerender: cfg.maxPrerender ?? 2,\n\n respectSaveData: cfg.respectSaveData ?? true,\n minEffectiveType: cfg.minEffectiveType ?? \"4g\",\n\n debug: cfg.debug ?? false\n };\n}\n\nfunction networkOk(cfg: NormalizedConfig): boolean {\n const nav: any = navigator as any;\n const conn = nav.connection || nav.mozConnection || nav.webkitConnection;\n\n if (cfg.respectSaveData && (conn?.saveData === true)) return false;\n\n const eff = conn?.effectiveType as string | undefined;\n if (!eff) return true;\n\n const order = [\"2g\", \"3g\", \"4g\"];\n const minIdx = order.indexOf(cfg.minEffectiveType);\n const effIdx = order.indexOf(eff);\n if (minIdx === -1 || effIdx === -1) return true;\n return effIdx >= minIdx;\n}\n\nexport function start(userCfg?: HyperInstantConfig): void {\n const cfg = normalizeConfig(userCfg ?? window.HyperInstant);\n const origin = location.origin;\n\n if (!networkOk(cfg)) {\n if (cfg.debug) console.log(\"[HyperInstant] disabled by network/save-data\");\n return;\n }\n\n const seen = new Set<string>();\n let prefetchCount = 0;\n let prerenderCount = 0;\n\n const hoverTimers = new WeakMap<Element, number>();\n\n function pickAction(strategy: Strategy): \"prefetch\" | \"prerender\" {\n if (strategy === \"prefetch-only\") return \"prefetch\";\n if (strategy === \"prerender-first\") return \"prerender\";\n if (prerenderCount < cfg.maxPrerender) return \"prerender\";\n return \"prefetch\";\n }\n\n function canProceed(action: \"prefetch\" | \"prerender\"): boolean {\n if (action === \"prefetch\") return prefetchCount < cfg.maxPrefetch;\n return prerenderCount < cfg.maxPrerender;\n }\n\n function doWarm(urlString: string): void {\n if (seen.has(urlString)) return;\n seen.add(urlString);\n\n const action = pickAction(cfg.strategy);\n if (!canProceed(action)) return;\n\n const okSpec = injectSpeculationRules(action, [urlString], cfg.debug);\n if (!okSpec && action === \"prefetch\") linkPrefetch(urlString, cfg.debug);\n\n if (action === \"prefetch\") prefetchCount++;\n else prerenderCount++;\n }\n\n function handlePotentialLink(a: HTMLAnchorElement): void {\n if (!shouldHandleAnchor(a)) return;\n\n let url: URL;\n try { url = new URL(a.href, location.href); }\n catch { return; }\n\n if (!shouldAllowUrl({ url, origin, allowSameOriginOnly: cfg.allowSameOriginOnly, allow: cfg.allow, deny: cfg.deny })) return;\n\n const norm = normalizeUrl(url, cfg.ignoreQueryParams);\n doWarm(norm);\n }\n\n document.addEventListener(\"mouseover\", (e) => {\n const t = e.target as Element | null;\n if (!t) return;\n const a = (t.closest?.(\"a\") as HTMLAnchorElement | null);\n if (!a) return;\n\n const existing = hoverTimers.get(a);\n if (existing) return;\n\n const id = window.setTimeout(() => {\n hoverTimers.delete(a);\n handlePotentialLink(a);\n }, cfg.hoverDelay);\n\n hoverTimers.set(a, id);\n }, { passive: true });\n\n document.addEventListener(\"mouseout\", (e) => {\n const t = e.target as Element | null;\n if (!t) return;\n const a = (t.closest?.(\"a\") as HTMLAnchorElement | null);\n if (!a) return;\n\n const id = hoverTimers.get(a);\n if (id) {\n window.clearTimeout(id);\n hoverTimers.delete(a);\n }\n }, { passive: true });\n\n if (cfg.touchEnabled) {\n document.addEventListener(\"touchstart\", (e) => {\n const t = e.target as Element | null;\n if (!t) return;\n const a = (t.closest?.(\"a\") as HTMLAnchorElement | null);\n if (!a) return;\n handlePotentialLink(a);\n }, { passive: true });\n }\n\n if (cfg.debug) console.log(\"[HyperInstant] started\", cfg);\n}\n", "import { start } from \"./core.js\";\nexport { start };\n\nif (typeof window !== \"undefined\") {\n window.HyperInstantStart = () => start(window.HyperInstant);\n start(window.HyperInstant);\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": ["normalizeUrl", "url", "ignoreQueryParams", "u", "matchesRule", "value", "rule", "shouldHandleAnchor", "a", "href", "shouldAllowUrl", "opts", "url", "origin", "allowSameOriginOnly", "allow", "deny", "full", "path", "r", "injectSpeculationRules", "action", "urls", "debug", "script", "payload", "linkPrefetch", "url", "debug", "l", "normalizeConfig", "input", "_a", "_b", "_c", "_d", "_e", "_f", "_g", "_h", "_i", "_j", "_k", "_l", "cfg", "networkOk", "nav", "conn", "eff", "order", "minIdx", "effIdx", "start", "userCfg", "origin", "seen", "prefetchCount", "prerenderCount", "hoverTimers", "pickAction", "strategy", "canProceed", "action", "doWarm", "urlString", "injectSpeculationRules", "linkPrefetch", "handlePotentialLink", "a", "shouldHandleAnchor", "url", "shouldAllowUrl", "norm", "normalizeUrl", "e", "id", "start"]
|
|
7
|
-
}
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../src/index.ts", "../src/url.ts", "../src/filters.ts", "../src/speculation.ts", "../src/prefetch.ts", "../src/core.ts"],
|
|
4
|
-
"sourcesContent": ["import { start } from \"./core.js\";\nexport { start };\n\nif (typeof window !== \"undefined\") {\n window.HyperInstantStart = () => start(window.HyperInstant);\n start(window.HyperInstant);\n}\n", "export function normalizeUrl(url: URL, ignoreQueryParams: boolean): string {\n const u = new URL(url.toString());\n u.hash = \"\";\n if (ignoreQueryParams) u.search = \"\";\n return u.toString();\n}\n", "export function matchesRule(value: string, rule: string | RegExp): boolean {\n if (typeof rule === \"string\") return value.includes(rule);\n return rule.test(value);\n}\n\nexport function shouldHandleAnchor(a: HTMLAnchorElement): boolean {\n const href = (a.getAttribute(\"href\") || \"\").trim();\n if (!href) return false;\n if (href.startsWith(\"#\")) return false;\n if (href.startsWith(\"mailto:\") || href.startsWith(\"tel:\")) return false;\n if (href.startsWith(\"javascript:\")) return false;\n if (a.hasAttribute(\"download\")) return false;\n\n const target = (a.getAttribute(\"target\") || \"\").toLowerCase();\n if (target === \"_blank\") return false;\n\n return true;\n}\n\nexport function shouldAllowUrl(opts: {\n url: URL;\n origin: string;\n allowSameOriginOnly: boolean;\n allow: Array<string | RegExp>;\n deny: Array<string | RegExp>;\n}): boolean {\n const { url, origin, allowSameOriginOnly, allow, deny } = opts;\n\n if (allowSameOriginOnly && url.origin !== origin) return false;\n\n const full = url.toString();\n const path = url.pathname + url.search;\n\n for (const r of deny) {\n if (matchesRule(full, r) || matchesRule(path, r)) return false;\n }\n\n if (allow.length > 0) {\n for (const r of allow) {\n if (matchesRule(full, r) || matchesRule(path, r)) return true;\n }\n return false;\n }\n\n return true;\n}\n", "export type SpecAction = \"prefetch\" | \"prerender\";\n\nexport function injectSpeculationRules(action: SpecAction, urls: string[], debug = false): boolean {\n try {\n const script = document.createElement(\"script\");\n script.type = \"speculationrules\";\n\n const payload: any = {};\n payload[action] = [{ source: \"list\", urls }];\n\n script.textContent = JSON.stringify(payload);\n document.head.appendChild(script);\n\n if (debug) console.log(\"[HyperInstant] speculationrules injected:\", action, urls);\n return true;\n } catch {\n return false;\n }\n}\n", "export function linkPrefetch(url: string, debug = false): boolean {\n try {\n const l = document.createElement(\"link\");\n l.rel = \"prefetch\";\n l.href = url;\n l.as = \"document\";\n document.head.appendChild(l);\n if (debug) console.log(\"[HyperInstant] link prefetch:\", url);\n return true;\n } catch {\n return false;\n }\n}\n", "import { HyperInstantConfig, NormalizedConfig, Strategy } from \"./types.js\";\nimport { normalizeUrl } from \"./url.js\";\nimport { shouldHandleAnchor, shouldAllowUrl } from \"./filters.js\";\nimport { injectSpeculationRules } from \"./speculation.js\";\nimport { linkPrefetch } from \"./prefetch.js\";\n\ndeclare global {\n interface Window {\n HyperInstant?: HyperInstantConfig;\n HyperInstantStart?: () => void;\n }\n}\n\nfunction normalizeConfig(input?: HyperInstantConfig): NormalizedConfig {\n const cfg = input || {};\n return {\n strategy: cfg.strategy ?? \"auto\",\n hoverDelay: cfg.hoverDelay ?? 65,\n touchEnabled: cfg.touchEnabled ?? true,\n\n allowSameOriginOnly: cfg.allowSameOriginOnly ?? true,\n deny: cfg.deny ?? [\"/cart\", \"/checkout\", \"/my-account\", \"/account\", \"/logout\", \"add-to-cart\"],\n allow: cfg.allow ?? [],\n ignoreQueryParams: cfg.ignoreQueryParams ?? true,\n\n maxPrefetch: cfg.maxPrefetch ?? 6,\n maxPrerender: cfg.maxPrerender ?? 2,\n\n respectSaveData: cfg.respectSaveData ?? true,\n minEffectiveType: cfg.minEffectiveType ?? \"4g\",\n\n debug: cfg.debug ?? false\n };\n}\n\nfunction networkOk(cfg: NormalizedConfig): boolean {\n const nav: any = navigator as any;\n const conn = nav.connection || nav.mozConnection || nav.webkitConnection;\n\n if (cfg.respectSaveData && (conn?.saveData === true)) return false;\n\n const eff = conn?.effectiveType as string | undefined;\n if (!eff) return true;\n\n const order = [\"2g\", \"3g\", \"4g\"];\n const minIdx = order.indexOf(cfg.minEffectiveType);\n const effIdx = order.indexOf(eff);\n if (minIdx === -1 || effIdx === -1) return true;\n return effIdx >= minIdx;\n}\n\nexport function start(userCfg?: HyperInstantConfig): void {\n const cfg = normalizeConfig(userCfg ?? window.HyperInstant);\n const origin = location.origin;\n\n if (!networkOk(cfg)) {\n if (cfg.debug) console.log(\"[HyperInstant] disabled by network/save-data\");\n return;\n }\n\n const seen = new Set<string>();\n let prefetchCount = 0;\n let prerenderCount = 0;\n\n const hoverTimers = new WeakMap<Element, number>();\n\n function pickAction(strategy: Strategy): \"prefetch\" | \"prerender\" {\n if (strategy === \"prefetch-only\") return \"prefetch\";\n if (strategy === \"prerender-first\") return \"prerender\";\n if (prerenderCount < cfg.maxPrerender) return \"prerender\";\n return \"prefetch\";\n }\n\n function canProceed(action: \"prefetch\" | \"prerender\"): boolean {\n if (action === \"prefetch\") return prefetchCount < cfg.maxPrefetch;\n return prerenderCount < cfg.maxPrerender;\n }\n\n function doWarm(urlString: string): void {\n if (seen.has(urlString)) return;\n seen.add(urlString);\n\n const action = pickAction(cfg.strategy);\n if (!canProceed(action)) return;\n\n const okSpec = injectSpeculationRules(action, [urlString], cfg.debug);\n if (!okSpec && action === \"prefetch\") linkPrefetch(urlString, cfg.debug);\n\n if (action === \"prefetch\") prefetchCount++;\n else prerenderCount++;\n }\n\n function handlePotentialLink(a: HTMLAnchorElement): void {\n if (!shouldHandleAnchor(a)) return;\n\n let url: URL;\n try { url = new URL(a.href, location.href); }\n catch { return; }\n\n if (!shouldAllowUrl({ url, origin, allowSameOriginOnly: cfg.allowSameOriginOnly, allow: cfg.allow, deny: cfg.deny })) return;\n\n const norm = normalizeUrl(url, cfg.ignoreQueryParams);\n doWarm(norm);\n }\n\n document.addEventListener(\"mouseover\", (e) => {\n const t = e.target as Element | null;\n if (!t) return;\n const a = (t.closest?.(\"a\") as HTMLAnchorElement | null);\n if (!a) return;\n\n const existing = hoverTimers.get(a);\n if (existing) return;\n\n const id = window.setTimeout(() => {\n hoverTimers.delete(a);\n handlePotentialLink(a);\n }, cfg.hoverDelay);\n\n hoverTimers.set(a, id);\n }, { passive: true });\n\n document.addEventListener(\"mouseout\", (e) => {\n const t = e.target as Element | null;\n if (!t) return;\n const a = (t.closest?.(\"a\") as HTMLAnchorElement | null);\n if (!a) return;\n\n const id = hoverTimers.get(a);\n if (id) {\n window.clearTimeout(id);\n hoverTimers.delete(a);\n }\n }, { passive: true });\n\n if (cfg.touchEnabled) {\n document.addEventListener(\"touchstart\", (e) => {\n const t = e.target as Element | null;\n if (!t) return;\n const a = (t.closest?.(\"a\") as HTMLAnchorElement | null);\n if (!a) return;\n handlePotentialLink(a);\n }, { passive: true });\n }\n\n if (cfg.debug) console.log(\"[HyperInstant] started\", cfg);\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": ["index_exports", "__export", "start", "normalizeUrl", "url", "ignoreQueryParams", "u", "matchesRule", "value", "rule", "shouldHandleAnchor", "a", "href", "shouldAllowUrl", "opts", "url", "origin", "allowSameOriginOnly", "allow", "deny", "full", "path", "r", "injectSpeculationRules", "action", "urls", "debug", "script", "payload", "linkPrefetch", "url", "debug", "l", "normalizeConfig", "input", "_a", "_b", "_c", "_d", "_e", "_f", "_g", "_h", "_i", "_j", "_k", "_l", "cfg", "networkOk", "nav", "conn", "eff", "order", "minIdx", "effIdx", "start", "userCfg", "origin", "seen", "prefetchCount", "prerenderCount", "hoverTimers", "pickAction", "strategy", "canProceed", "action", "doWarm", "urlString", "injectSpeculationRules", "linkPrefetch", "handlePotentialLink", "a", "shouldHandleAnchor", "url", "shouldAllowUrl", "norm", "normalizeUrl", "e", "t", "id", "start"]
|
|
7
|
-
}
|