@sentinel-js/react 0.1.4 → 0.1.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -9,7 +9,7 @@ export interface SentinelConfig {
9
9
  silent?: boolean;
10
10
  /** Callback fired when an update is detected (useful for custom UIs) */
11
11
  onUpdateAvailable?: (version: string) => void;
12
- /** Automatically check for updates on window focus */
12
+ /** Automatically check for updates on window focus / visibility change */
13
13
  checkOnFocus?: boolean;
14
14
  }
15
15
  export interface SentinelState {
@@ -17,8 +17,8 @@ export interface SentinelState {
17
17
  currentVersion: string;
18
18
  remoteVersion: string | null;
19
19
  }
20
- export declare const useSentinel: ({ pollingInterval, versionFileUrl, silent, onUpdateAvailable, checkOnFocus }?: SentinelConfig) => {
21
- reload: () => void;
20
+ export declare const useSentinel: ({ pollingInterval, versionFileUrl, silent, onUpdateAvailable, checkOnFocus, }?: SentinelConfig) => {
21
+ reload: () => Promise<void>;
22
22
  checkNow: () => Promise<void>;
23
23
  hasUpdate: boolean;
24
24
  currentVersion: string;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAmD,MAAM,OAAO,CAAC;AAIxE,MAAM,WAAW,cAAc;IAC7B,mEAAmE;IACnE,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,yDAAyD;IACzD,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,iEAAiE;IACjE,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,wEAAwE;IACxE,iBAAiB,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IAC9C,sDAAsD;IACtD,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,OAAO,CAAC;IACnB,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B;AAkCD,eAAO,MAAM,WAAW,GAAI,+EAMzB,cAAmB;;;eA3CT,OAAO;oBACF,MAAM;mBACP,MAAM,GAAG,IAAI;CAqI7B,CAAC;AAIF,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EAAE,CAAC,cAAc,GAAG;IAAE,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAA;CAAE,CAcxG,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAmD,MAAM,OAAO,CAAC;AAIxE,MAAM,WAAW,cAAc;IAC7B,mEAAmE;IACnE,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,yDAAyD;IACzD,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,iEAAiE;IACjE,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,wEAAwE;IACxE,iBAAiB,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IAC9C,0EAA0E;IAC1E,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,OAAO,CAAC;IACnB,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B;AAgFD,eAAO,MAAM,WAAW,GAAI,gFAMzB,cAAmB;;;eAzFT,OAAO;oBACF,MAAM;mBACP,MAAM,GAAG,IAAI;CA+M7B,CAAC;AAIF,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EAAE,CAClC,cAAc,GAAG;IAAE,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAA;CAAE,CAkBrE,CAAC"}
package/dist/index.es.js CHANGED
@@ -1,64 +1,103 @@
1
- import { jsxs as g, jsx as h } from "react/jsx-runtime";
2
- import { useState as m, useRef as S, useEffect as d, useCallback as v } from "react";
3
- const b = (e) => {
4
- const o = history.pushState, r = history.replaceState;
5
- return history.pushState = function(...t) {
6
- o.apply(history, t), e();
7
- }, history.replaceState = function(...t) {
8
- r.apply(history, t), e();
9
- }, window.addEventListener("popstate", e), () => {
10
- window.removeEventListener("popstate", e);
11
- };
12
- }, E = ({
13
- pollingInterval: e = 6e4,
14
- versionFileUrl: o = "/version.json",
15
- silent: r = !1,
16
- onUpdateAvailable: t,
17
- checkOnFocus: p = !0
1
+ import { jsxs as x, jsx as y } from "react/jsx-runtime";
2
+ import { useState as b, useRef as p, useEffect as h, useCallback as R } from "react";
3
+ const S = async () => {
4
+ if (typeof navigator < "u" && !navigator.onLine) {
5
+ console.warn("[Sentinel] Cannot update: User is offline. Aborting reload to preserve PWA.");
6
+ return;
7
+ }
8
+ if ("serviceWorker" in navigator)
9
+ try {
10
+ const e = await navigator.serviceWorker.getRegistrations();
11
+ await Promise.all(e.map((n) => n.unregister()));
12
+ } catch (e) {
13
+ console.warn("[Sentinel] Failed to unregister service workers:", e);
14
+ }
15
+ if (typeof caches < "u")
16
+ try {
17
+ const e = await caches.keys();
18
+ await Promise.all(e.map((n) => caches.delete(n)));
19
+ } catch (e) {
20
+ console.warn("[Sentinel] Failed to clear CacheStorage:", e);
21
+ }
22
+ const t = new URL(window.location.href);
23
+ t.searchParams.set("sentinel_refresh", Date.now().toString()), window.location.href = t.toString();
24
+ }, a = "sentinel:routechange", _ = () => {
25
+ if (typeof history > "u" || history.__sentinelPatched) return;
26
+ const t = history.pushState, e = history.replaceState;
27
+ history.pushState = function(...n) {
28
+ t.apply(history, n), window.dispatchEvent(new Event(a));
29
+ }, history.replaceState = function(...n) {
30
+ e.apply(history, n), window.dispatchEvent(new Event(a));
31
+ }, history.__sentinelPatched = !0;
32
+ }, L = ({
33
+ pollingInterval: t = 6e4,
34
+ versionFileUrl: e = "/version.json",
35
+ silent: n = !1,
36
+ onUpdateAvailable: c,
37
+ checkOnFocus: l = !0
18
38
  } = {}) => {
19
- const w = typeof __SENTINEL_VERSION__ < "u" ? __SENTINEL_VERSION__ : "unknown", [s, x] = m({
39
+ const v = typeof __SENTINEL_VERSION__ < "u" ? __SENTINEL_VERSION__ : "unknown", [m, E] = b({
20
40
  hasUpdate: !1,
21
- currentVersion: w,
41
+ currentVersion: v,
22
42
  remoteVersion: null
23
- }), u = S(!1), l = S(t);
24
- d(() => {
25
- l.current = t;
26
- }, [t]);
27
- const i = v(async () => {
28
- try {
29
- const n = await fetch(`${o}?t=${Date.now()}`);
30
- if (!n.ok) return;
31
- const c = (await n.json()).version;
32
- if (c && c !== s.currentVersion) {
33
- if (u.current) return;
34
- u.current = !0, x((y) => ({ ...y, hasUpdate: !0, remoteVersion: c })), l.current && l.current(c);
43
+ }), d = p(!1), u = p(c), g = p(v);
44
+ h(() => {
45
+ u.current = c;
46
+ }, [c]);
47
+ const r = R(async () => {
48
+ if (!(typeof navigator < "u" && !navigator.onLine))
49
+ try {
50
+ const o = await fetch(`${e}?t=${Date.now()}`);
51
+ if (!o.ok) return;
52
+ const i = (await o.json()).version;
53
+ if (i && i !== g.current) {
54
+ if (d.current) return;
55
+ d.current = !0, E((s) => ({ ...s, hasUpdate: !0, remoteVersion: i })), u.current && u.current(i);
56
+ }
57
+ } catch (o) {
58
+ console.error("[Sentinel] Failed to check version:", o);
35
59
  }
36
- } catch (n) {
37
- console.error("[Sentinel] Failed to check version:", n);
38
- }
39
- }, [o, s.currentVersion]);
40
- return d(() => {
41
- s.currentVersion === "unknown" && console.warn("[Sentinel] Current version is unknown. Ensure @sentinel/vite-plugin is installed."), i();
42
- const n = setInterval(i, e), a = () => {
43
- p && i();
60
+ }, [e]);
61
+ return h(() => {
62
+ g.current === "unknown" && console.warn(
63
+ "[Sentinel] Current version is unknown. Ensure @sentinel/vite-plugin is installed."
64
+ ), r();
65
+ const o = setInterval(r, t), f = () => {
66
+ l && r();
67
+ }, i = () => {
68
+ l && document.visibilityState === "visible" && r();
69
+ }, s = () => r();
70
+ return window.addEventListener("focus", f), document.addEventListener("visibilitychange", i), window.addEventListener("online", s), () => {
71
+ clearInterval(o), window.removeEventListener("focus", f), document.removeEventListener("visibilitychange", i), window.removeEventListener("online", s);
44
72
  };
45
- return window.addEventListener("focus", a), () => {
46
- clearInterval(n), window.removeEventListener("focus", a);
73
+ }, [r, t, l]), h(() => {
74
+ if (!n) return;
75
+ _();
76
+ const o = () => {
77
+ d.current && (console.log("[Sentinel] Silent update: Route changed, reloading app..."), S());
47
78
  };
48
- }, [i, e, p, s.currentVersion]), d(() => r ? b(() => {
49
- u.current && (console.log("[Sentinel] Silent update: Route changed, reloading app..."), window.location.reload());
50
- }) : void 0, [r]), {
51
- ...s,
52
- reload: () => window.location.reload(),
53
- checkNow: i
79
+ return window.addEventListener(a, o), window.addEventListener("popstate", o), () => {
80
+ window.removeEventListener(a, o), window.removeEventListener("popstate", o);
81
+ };
82
+ }, [n]), {
83
+ ...m,
84
+ reload: S,
85
+ checkNow: r
54
86
  };
55
- }, _ = (e) => {
56
- const { hasUpdate: o, reload: r } = E(e);
57
- return !o || e.silent ? null : /* @__PURE__ */ g("div", { style: { ...f.toast, ...e.style }, className: e.className, children: [
58
- /* @__PURE__ */ h("span", { style: f.text, children: "New version available" }),
59
- /* @__PURE__ */ h("button", { style: f.button, onClick: r, children: "Refresh" })
60
- ] });
61
- }, f = {
87
+ }, C = (t) => {
88
+ const { hasUpdate: e, reload: n } = L(t);
89
+ return !e || t.silent ? null : /* @__PURE__ */ x(
90
+ "div",
91
+ {
92
+ style: { ...w.toast, ...t.style },
93
+ className: t.className,
94
+ children: [
95
+ /* @__PURE__ */ y("span", { style: w.text, children: "New version available" }),
96
+ /* @__PURE__ */ y("button", { style: w.button, onClick: n, children: "Refresh" })
97
+ ]
98
+ }
99
+ );
100
+ }, w = {
62
101
  toast: {
63
102
  position: "fixed",
64
103
  bottom: "24px",
@@ -92,6 +131,6 @@ const b = (e) => {
92
131
  }
93
132
  };
94
133
  export {
95
- _ as SentinelToast,
96
- E as useSentinel
134
+ C as SentinelToast,
135
+ L as useSentinel
97
136
  };
package/dist/index.umd.js CHANGED
@@ -1 +1 @@
1
- (function(t,n){typeof exports=="object"&&typeof module<"u"?n(exports,require("react/jsx-runtime"),require("react")):typeof define=="function"&&define.amd?define(["exports","react/jsx-runtime","react"],n):(t=typeof globalThis<"u"?globalThis:t||self,n(t.SentinelReact={},t.jsxRuntime,t.React))})(this,function(t,n,o){"use strict";const y=e=>{const i=history.pushState,a=history.replaceState;return history.pushState=function(...r){i.apply(history,r),e()},history.replaceState=function(...r){a.apply(history,r),e()},window.addEventListener("popstate",e),()=>{window.removeEventListener("popstate",e)}},S=({pollingInterval:e=6e4,versionFileUrl:i="/version.json",silent:a=!1,onUpdateAvailable:r,checkOnFocus:x=!0}={})=>{const g=typeof __SENTINEL_VERSION__<"u"?__SENTINEL_VERSION__:"unknown",[u,m]=o.useState({hasUpdate:!1,currentVersion:g,remoteVersion:null}),p=o.useRef(!1),h=o.useRef(r);o.useEffect(()=>{h.current=r},[r]);const c=o.useCallback(async()=>{try{const s=await fetch(`${i}?t=${Date.now()}`);if(!s.ok)return;const l=(await s.json()).version;if(l&&l!==u.currentVersion){if(p.current)return;p.current=!0,m(v=>({...v,hasUpdate:!0,remoteVersion:l})),h.current&&h.current(l)}}catch(s){console.error("[Sentinel] Failed to check version:",s)}},[i,u.currentVersion]);return o.useEffect(()=>{u.currentVersion==="unknown"&&console.warn("[Sentinel] Current version is unknown. Ensure @sentinel/vite-plugin is installed."),c();const s=setInterval(c,e),d=()=>{x&&c()};return window.addEventListener("focus",d),()=>{clearInterval(s),window.removeEventListener("focus",d)}},[c,e,x,u.currentVersion]),o.useEffect(()=>a?y(()=>{p.current&&(console.log("[Sentinel] Silent update: Route changed, reloading app..."),window.location.reload())}):void 0,[a]),{...u,reload:()=>window.location.reload(),checkNow:c}},w=e=>{const{hasUpdate:i,reload:a}=S(e);return!i||e.silent?null:n.jsxs("div",{style:{...f.toast,...e.style},className:e.className,children:[n.jsx("span",{style:f.text,children:"New version available"}),n.jsx("button",{style:f.button,onClick:a,children:"Refresh"})]})},f={toast:{position:"fixed",bottom:"24px",right:"24px",backgroundColor:"#1f1f1f",color:"#ffffff",padding:"12px 20px",borderRadius:"8px",boxShadow:"0 4px 12px rgba(0,0,0,0.15)",display:"flex",alignItems:"center",gap:"16px",zIndex:9999,fontFamily:'-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',border:"1px solid #333"},text:{fontSize:"14px",fontWeight:500},button:{backgroundColor:"#3b82f6",border:"none",color:"white",padding:"8px 16px",borderRadius:"6px",cursor:"pointer",fontWeight:600,fontSize:"13px",transition:"background-color 0.2s"}};t.SentinelToast=w,t.useSentinel=S,Object.defineProperty(t,Symbol.toStringTag,{value:"Module"})});
1
+ (function(i,s){typeof exports=="object"&&typeof module<"u"?s(exports,require("react/jsx-runtime"),require("react")):typeof define=="function"&&define.amd?define(["exports","react/jsx-runtime","react"],s):(i=typeof globalThis<"u"?globalThis:i||self,s(i.SentinelReact={},i.jsxRuntime,i.React))})(this,function(i,s,r){"use strict";const y=async()=>{if(typeof navigator<"u"&&!navigator.onLine){console.warn("[Sentinel] Cannot update: User is offline. Aborting reload to preserve PWA.");return}if("serviceWorker"in navigator)try{const e=await navigator.serviceWorker.getRegistrations();await Promise.all(e.map(n=>n.unregister()))}catch(e){console.warn("[Sentinel] Failed to unregister service workers:",e)}if(typeof caches<"u")try{const e=await caches.keys();await Promise.all(e.map(n=>caches.delete(n)))}catch(e){console.warn("[Sentinel] Failed to clear CacheStorage:",e)}const t=new URL(window.location.href);t.searchParams.set("sentinel_refresh",Date.now().toString()),window.location.href=t.toString()},l="sentinel:routechange",m=()=>{if(typeof history>"u"||history.__sentinelPatched)return;const t=history.pushState,e=history.replaceState;history.pushState=function(...n){t.apply(history,n),window.dispatchEvent(new Event(l))},history.replaceState=function(...n){e.apply(history,n),window.dispatchEvent(new Event(l))},history.__sentinelPatched=!0},g=({pollingInterval:t=6e4,versionFileUrl:e="/version.json",silent:n=!1,onUpdateAvailable:f,checkOnFocus:p=!0}={})=>{const S=typeof __SENTINEL_VERSION__<"u"?__SENTINEL_VERSION__:"unknown",[b,R]=r.useState({hasUpdate:!1,currentVersion:S,remoteVersion:null}),h=r.useRef(!1),w=r.useRef(f),E=r.useRef(S);r.useEffect(()=>{w.current=f},[f]);const a=r.useCallback(async()=>{if(!(typeof navigator<"u"&&!navigator.onLine))try{const o=await fetch(`${e}?t=${Date.now()}`);if(!o.ok)return;const c=(await o.json()).version;if(c&&c!==E.current){if(h.current)return;h.current=!0,R(d=>({...d,hasUpdate:!0,remoteVersion:c})),w.current&&w.current(c)}}catch(o){console.error("[Sentinel] Failed to check version:",o)}},[e]);return r.useEffect(()=>{E.current==="unknown"&&console.warn("[Sentinel] Current version is unknown. Ensure @sentinel/vite-plugin is installed."),a();const o=setInterval(a,t),v=()=>{p&&a()},c=()=>{p&&document.visibilityState==="visible"&&a()},d=()=>a();return window.addEventListener("focus",v),document.addEventListener("visibilitychange",c),window.addEventListener("online",d),()=>{clearInterval(o),window.removeEventListener("focus",v),document.removeEventListener("visibilitychange",c),window.removeEventListener("online",d)}},[a,t,p]),r.useEffect(()=>{if(!n)return;m();const o=()=>{h.current&&(console.log("[Sentinel] Silent update: Route changed, reloading app..."),y())};return window.addEventListener(l,o),window.addEventListener("popstate",o),()=>{window.removeEventListener(l,o),window.removeEventListener("popstate",o)}},[n]),{...b,reload:y,checkNow:a}},x=t=>{const{hasUpdate:e,reload:n}=g(t);return!e||t.silent?null:s.jsxs("div",{style:{...u.toast,...t.style},className:t.className,children:[s.jsx("span",{style:u.text,children:"New version available"}),s.jsx("button",{style:u.button,onClick:n,children:"Refresh"})]})},u={toast:{position:"fixed",bottom:"24px",right:"24px",backgroundColor:"#1f1f1f",color:"#ffffff",padding:"12px 20px",borderRadius:"8px",boxShadow:"0 4px 12px rgba(0,0,0,0.15)",display:"flex",alignItems:"center",gap:"16px",zIndex:9999,fontFamily:'-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',border:"1px solid #333"},text:{fontSize:"14px",fontWeight:500},button:{backgroundColor:"#3b82f6",border:"none",color:"white",padding:"8px 16px",borderRadius:"6px",cursor:"pointer",fontWeight:600,fontSize:"13px",transition:"background-color 0.2s"}};i.SentinelToast=x,i.useSentinel=g,Object.defineProperty(i,Symbol.toStringTag,{value:"Module"})});
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sentinel-js/react",
3
- "version": "0.1.4",
3
+ "version": "0.1.6",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "main": "./dist/index.umd.js",
@@ -37,6 +37,11 @@
37
37
  },
38
38
  "repository": {
39
39
  "type": "git",
40
- "url": "git+https://github.com/TheJavaScriptDojoOfficial/sentinel-monorepo/blob/main/packages/react/README.md"
40
+ "url": "git+https://github.com/TheJavaScriptDojoOfficial/sentinel-monorepo.git",
41
+ "directory": "packages/react"
42
+ },
43
+ "homepage": "https://github.com/TheJavaScriptDojoOfficial/sentinel-monorepo#readme",
44
+ "bugs": {
45
+ "url": "https://github.com/TheJavaScriptDojoOfficial/sentinel-monorepo/issues"
41
46
  }
42
47
  }