hyperinstant 1.0.1 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,42 +1,23 @@
1
- # HyperInstant v1.0.1
1
+ # HyperInstant v1.1.0 (Legacy-fast)
2
2
 
3
- **HyperInstant** accelerates navigation across any website by intelligently prefetching (and when safe, prerendering) the *right* pages at the *right* time.
4
-
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)
3
+ This package is intentionally a **legacy-fast** build: behavior matches the original **0.1.0** approach
4
+ (simple, ultra-light, perceived-speed first).
14
5
 
6
+ ## CDN
15
7
  ```html
16
8
  <script>
17
9
  window.HyperInstant = {
18
- mode: "balanced", // safe | balanced | aggressive
19
- adapter: "auto", // auto | shopify | woocommerce | nopcommerce | generic
20
- observe: "intent", // intent | intent+viewport
10
+ strategy: "auto",
21
11
  hoverDelay: 65,
12
+ maxPrefetch: 6,
13
+ maxPrerender: 2,
14
+ deny: ["/cart", "/checkout", "/my-account", "/logout", "add-to-cart"],
22
15
  debug: false
23
16
  };
24
17
  </script>
25
- <script src="https://unpkg.com/hyperinstant@1.0.1/dist/hyperinstant.min.js" defer></script>
26
- ```
27
-
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"]
18
+ <script src="https://unpkg.com/hyperinstant@1.1.0/dist/hyperinstant.min.js" defer></script>
33
19
  ```
34
20
 
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.
21
+ ## Notes
22
+ - Uses `<link rel="prefetch|prerender">` for documents
23
+ - No adapters / no auto-tuning / no overlays (by design)
@@ -1,300 +1,124 @@
1
- /*! HyperInstant v1.0.1 | MIT | Putia Web */
2
- (function(){
1
+ /*! HyperInstant v1.1.0 (legacy-fast, 0.1.0 behavior) | MIT | Putia Web */
2
+ (function () {
3
3
  if (window.__HYPERINSTANT_LOADED__) return;
4
4
  window.__HYPERINSTANT_LOADED__ = true;
5
5
 
6
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;
7
+ var strategy = (cfg.strategy || "auto").toLowerCase();
8
+ var hoverDelay = (typeof cfg.hoverDelay === "number") ? cfg.hoverDelay : 65;
9
+ var maxPrefetch = (typeof cfg.maxPrefetch === "number") ? cfg.maxPrefetch : 6;
10
+ var maxPrerender = (typeof cfg.maxPrerender === "number") ? cfg.maxPrerender : 2;
11
+ var deny = Array.isArray(cfg.deny) ? cfg.deny : [];
12
+ var debug = !!cfg.debug;
13
+
14
+ var prefetched = new Set();
15
+ var prerendered = new Set();
16
+ var inflight = new Set();
17
+ var usedPrefetch = 0;
18
+ var usedPrerender = 0;
19
+
20
+ function supportsPrerender() {
21
+ try {
22
+ return "relList" in HTMLLinkElement.prototype &&
23
+ HTMLLinkElement.prototype.relList &&
24
+ HTMLLinkElement.prototype.relList.supports &&
25
+ HTMLLinkElement.prototype.relList.supports("prerender");
26
+ } catch (e) { return false; }
28
27
  }
29
28
 
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)});
29
+ function normalizeUrl(url) {
30
+ try { var u = new URL(url, location.href); u.hash = ""; return u.toString(); }
31
+ catch (e) { return ""; }
40
32
  }
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
33
 
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; };
34
+ function isSameOrigin(url) {
35
+ try { return new URL(url, location.href).origin === location.origin; }
36
+ catch (e) { return false; }
57
37
  }
58
38
 
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){
39
+ function isDenied(url) {
64
40
  if (!url) return true;
65
41
  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
42
 
43
+ var u = String(url);
44
+ for (var i = 0; i < deny.length; i++) {
45
+ var d = deny[i];
46
+ if (d && u.indexOf(String(d)) !== -1) return true;
47
+ }
87
48
  return false;
88
49
  }
89
50
 
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
- };
51
+ function enqueue(url) {
52
+ url = normalizeUrl(url);
53
+ if (!url) return;
54
+ if (isDenied(url)) return;
55
+ if (prefetched.has(url) || prerendered.has(url) || inflight.has(url)) return;
109
56
 
110
- function createScheduler(c, stats){
111
- var queue=[];
112
- var inFlight=new Set();
113
- var loaded=new Set();
114
- var usedPrefetch=0, usedPrerender=0;
57
+ var canPrerender = supportsPrerender() && (usedPrerender < maxPrerender);
58
+ var canPrefetch = (usedPrefetch < maxPrefetch);
115
59
 
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
- }
60
+ var rel = "prefetch";
61
+ if (strategy === "prefetch") rel = "prefetch";
62
+ else if (strategy === "prerender") rel = canPrerender ? "prerender" : "prefetch";
63
+ else rel = canPrerender ? "prerender" : "prefetch";
131
64
 
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
- }
65
+ if (rel === "prefetch" && !canPrefetch) return;
66
+ if (rel === "prerender" && !canPrerender) rel = canPrefetch ? "prefetch" : "";
67
+ if (!rel) return;
140
68
 
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;
69
+ inflight.add(url);
148
70
 
149
- var wantPrerender = b.maxPrerender>usedPrerender && score>=90;
150
- var wantPrefetch = b.maxPrefetch>usedPrefetch;
71
+ var link = document.createElement("link");
72
+ link.rel = rel;
73
+ link.href = url;
74
+ link.as = "document";
151
75
 
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
- }
76
+ if (rel === "prerender") usedPrerender++;
77
+ else usedPrefetch++;
173
78
 
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(){}
79
+ link.onload = function () {
80
+ inflight.delete(url);
81
+ if (rel === "prerender") prerendered.add(url);
82
+ else prefetched.add(url);
83
+ if (debug) console.log("[HyperInstant]", rel, url);
191
84
  };
192
- }
85
+ link.onerror = function () { inflight.delete(url); };
193
86
 
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);
87
+ document.head.appendChild(link);
209
88
  }
210
89
 
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
- }
90
+ var t = null;
91
+ function onHover(e) {
92
+ var a = e.target && e.target.closest ? e.target.closest("a[href]") : null;
93
+ if (!a || !a.href) return;
94
+ if (a.target && a.target !== "_self") return;
95
+ if (a.getAttribute("data-no-instant") !== null) return;
221
96
 
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);
97
+ clearTimeout(t);
98
+ t = setTimeout(function () { enqueue(a.href); }, hoverDelay);
232
99
  }
233
100
 
234
- function startObservers(c, scheduler, stats, tuner){
235
- var hoverTimer=null;
101
+ function onImmediate(e) {
102
+ var a = e.target && e.target.closest ? e.target.closest("a[href]") : null;
103
+ if (!a || !a.href) return;
104
+ if (a.target && a.target !== "_self") return;
105
+ if (a.getAttribute("data-no-instant") !== null) return;
106
+ enqueue(a.href);
107
+ }
236
108
 
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; }
109
+ document.addEventListener("mouseover", onHover, { passive: true });
110
+ document.addEventListener("touchstart", onImmediate, { passive: true });
111
+ document.addEventListener("mousedown", onImmediate, { passive: true });
112
+ document.addEventListener("focusin", onImmediate, { passive: true });
243
113
 
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
- }
114
+ window.addEventListener("pageshow", function () {
115
+ usedPrefetch = 0;
116
+ usedPrerender = 0;
117
+ });
253
118
 
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});
119
+ if (debug) {
120
+ console.log("[HyperInstant] v1.1.0 legacy-fast loaded", {
121
+ strategy: strategy, hoverDelay: hoverDelay, maxPrefetch: maxPrefetch, maxPrerender: maxPrerender
263
122
  });
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
123
  }
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
124
  })();
@@ -1 +1 @@
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);})();
1
+ /*! HyperInstant v1.1.0 (legacy-fast, 0.1.0 behavior) | MIT | Putia Web */ (function (){if (window.__HYPERINSTANT_LOADED__) return; window.__HYPERINSTANT_LOADED__ = true; var cfg = window.HyperInstant ||{}; var strategy = (cfg.strategy || "auto").toLowerCase(); var hoverDelay = (typeof cfg.hoverDelay === "number") ? cfg.hoverDelay : 65; var maxPrefetch = (typeof cfg.maxPrefetch === "number") ? cfg.maxPrefetch : 6; var maxPrerender = (typeof cfg.maxPrerender === "number") ? cfg.maxPrerender : 2; var deny = Array.isArray(cfg.deny) ? cfg.deny : []; var debug = !!cfg.debug; var prefetched = new Set(); var prerendered = new Set(); var inflight = new Set(); var usedPrefetch = 0; var usedPrerender = 0; function supportsPrerender(){try{return "relList" in HTMLLinkElement.prototype && HTMLLinkElement.prototype.relList && HTMLLinkElement.prototype.relList.supports && HTMLLinkElement.prototype.relList.supports("prerender");} catch (e){return false;}} function normalizeUrl(url){try{var u = new URL(url, location.href); u.hash = ""; return u.toString();} catch (e){return "";}} function isSameOrigin(url){try{return new URL(url, location.href).origin === location.origin;} catch (e){return false;}} function isDenied(url){if (!url) return true; if (!isSameOrigin(url)) return true; var u = String(url); for (var i = 0; i < deny.length; i++){var d = deny[i]; if (d && u.indexOf(String(d)) !== -1) return true;} return false;} function enqueue(url){url = normalizeUrl(url); if (!url) return; if (isDenied(url)) return; if (prefetched.has(url) || prerendered.has(url) || inflight.has(url)) return; var canPrerender = supportsPrerender() && (usedPrerender < maxPrerender); var canPrefetch = (usedPrefetch < maxPrefetch); var rel = "prefetch"; if (strategy === "prefetch") rel = "prefetch"; else if (strategy === "prerender") rel = canPrerender ? "prerender" : "prefetch"; else rel = canPrerender ? "prerender" : "prefetch"; if (rel === "prefetch" && !canPrefetch) return; if (rel === "prerender" && !canPrerender) rel = canPrefetch ? "prefetch" : ""; if (!rel) return; inflight.add(url); var link = document.createElement("link"); link.rel = rel; link.href = url; link.as = "document"; if (rel === "prerender") usedPrerender++; else usedPrefetch++; link.onload = function (){inflight.delete(url); if (rel === "prerender") prerendered.add(url); else prefetched.add(url); if (debug) console.log("[HyperInstant]", rel, url);}; link.onerror = function (){inflight.delete(url);}; document.head.appendChild(link);} var t = null; function onHover(e){var a = e.target && e.target.closest ? e.target.closest("a[href]") : null; if (!a || !a.href) return; if (a.target && a.target !== "_self") return; if (a.getAttribute("data-no-instant") !== null) return; clearTimeout(t); t = setTimeout(function (){enqueue(a.href);}, hoverDelay);} function onImmediate(e){var a = e.target && e.target.closest ? e.target.closest("a[href]") : null; if (!a || !a.href) return; if (a.target && a.target !== "_self") return; if (a.getAttribute("data-no-instant") !== null) return; enqueue(a.href);} document.addEventListener("mouseover", onHover,{passive: true}); document.addEventListener("touchstart", onImmediate,{passive: true}); document.addEventListener("mousedown", onImmediate,{passive: true}); document.addEventListener("focusin", onImmediate,{passive: true}); window.addEventListener("pageshow", function (){usedPrefetch = 0; usedPrerender = 0;}); if (debug){console.log("[HyperInstant] v1.1.0 legacy-fast loaded",{strategy: strategy, hoverDelay: hoverDelay, maxPrefetch: maxPrefetch, maxPrerender: maxPrerender});}})();
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "hyperinstant",
3
- "version": "1.0.1",
4
- "description": "Adaptive, safe and intelligent instant navigation engine for any website.",
3
+ "version": "1.1.0",
4
+ "description": "HyperInstant legacy-fast build (same behavior as 0.1.0), packaged as 1.1.0.",
5
5
  "main": "dist/hyperinstant.min.js",
6
6
  "module": "dist/hyperinstant.js",
7
7
  "files": [
@@ -12,20 +12,8 @@
12
12
  "prefetch",
13
13
  "prerender",
14
14
  "instant-page",
15
- "web-performance",
16
- "shopify",
17
- "woocommerce",
18
- "nopcommerce",
19
- "adaptive",
20
- "navigation"
15
+ "web-performance"
21
16
  ],
22
17
  "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"
30
- }
18
+ "license": "MIT"
31
19
  }