@buoy-gg/clock 7.0.42
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 +58 -0
- package/README.md +29 -0
- package/lib/commonjs/components/ClockBody.js +1 -0
- package/lib/commonjs/components/ClockChip.js +1 -0
- package/lib/commonjs/components/ClockToolView.js +1 -0
- package/lib/commonjs/components/TokenSection.js +1 -0
- package/lib/commonjs/components/format.js +1 -0
- package/lib/commonjs/components/useLiveClock.js +1 -0
- package/lib/commonjs/engine/clockMath.js +1 -0
- package/lib/commonjs/engine/clockStore.js +1 -0
- package/lib/commonjs/engine/patches.js +1 -0
- package/lib/commonjs/engine/persistence.js +1 -0
- package/lib/commonjs/engine/readSavedSync.js +1 -0
- package/lib/commonjs/engine/readSavedSync.web.js +1 -0
- package/lib/commonjs/engine/timers.js +1 -0
- package/lib/commonjs/index.js +1 -0
- package/lib/commonjs/package.json +1 -0
- package/lib/commonjs/preset.js +1 -0
- package/lib/commonjs/sync/clockSyncAdapter.js +1 -0
- package/lib/commonjs/tokens/decode.js +1 -0
- package/lib/commonjs/tokens/extract.js +1 -0
- package/lib/commonjs/tokens/tokenActions.js +1 -0
- package/lib/commonjs/tokens/tokenStore.js +1 -0
- package/lib/module/components/ClockBody.js +1 -0
- package/lib/module/components/ClockChip.js +1 -0
- package/lib/module/components/ClockToolView.js +1 -0
- package/lib/module/components/TokenSection.js +1 -0
- package/lib/module/components/format.js +1 -0
- package/lib/module/components/useLiveClock.js +1 -0
- package/lib/module/engine/clockMath.js +1 -0
- package/lib/module/engine/clockStore.js +1 -0
- package/lib/module/engine/patches.js +1 -0
- package/lib/module/engine/persistence.js +1 -0
- package/lib/module/engine/readSavedSync.js +1 -0
- package/lib/module/engine/readSavedSync.web.js +1 -0
- package/lib/module/engine/timers.js +1 -0
- package/lib/module/index.js +1 -0
- package/lib/module/preset.js +1 -0
- package/lib/module/sync/clockSyncAdapter.js +1 -0
- package/lib/module/tokens/decode.js +1 -0
- package/lib/module/tokens/extract.js +1 -0
- package/lib/module/tokens/tokenActions.js +1 -0
- package/lib/module/tokens/tokenStore.js +1 -0
- package/lib/typescript/components/ClockBody.d.ts +2 -0
- package/lib/typescript/components/ClockChip.d.ts +11 -0
- package/lib/typescript/components/ClockToolView.d.ts +10 -0
- package/lib/typescript/components/TokenSection.d.ts +10 -0
- package/lib/typescript/components/format.d.ts +18 -0
- package/lib/typescript/components/useLiveClock.d.ts +22 -0
- package/lib/typescript/engine/clockMath.d.ts +70 -0
- package/lib/typescript/engine/clockStore.d.ts +94 -0
- package/lib/typescript/engine/patches.d.ts +43 -0
- package/lib/typescript/engine/persistence.d.ts +32 -0
- package/lib/typescript/engine/readSavedSync.d.ts +9 -0
- package/lib/typescript/engine/readSavedSync.web.d.ts +4 -0
- package/lib/typescript/engine/timers.d.ts +44 -0
- package/lib/typescript/index.d.ts +19 -0
- package/lib/typescript/preset.d.ts +45 -0
- package/lib/typescript/sync/clockSyncAdapter.d.ts +30 -0
- package/lib/typescript/tokens/decode.d.ts +67 -0
- package/lib/typescript/tokens/extract.d.ts +75 -0
- package/lib/typescript/tokens/tokenActions.d.ts +28 -0
- package/lib/typescript/tokens/tokenStore.d.ts +116 -0
- package/lib/web/index.mjs +1 -0
- package/package.json +112 -0
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The app's sign-in tokens, as seen in its network traffic.
|
|
3
|
+
*
|
|
4
|
+
* Subscribes to the Network tool's captured requests (when @buoy-gg/network
|
|
5
|
+
* is installed) and keeps one row per place a token is used: the
|
|
6
|
+
* Authorization header to an API, a session cookie, a token header or query
|
|
7
|
+
* parameter. A row follows its token across refreshes, so it can say when
|
|
8
|
+
* the app got a new one, how long that one lasts, whether the app kept
|
|
9
|
+
* sending a token after it expired, and whether it is stuck refreshing.
|
|
10
|
+
*
|
|
11
|
+
* Two clocks matter for a token and this keeps both:
|
|
12
|
+
* - the APP's view (`expiresAt` against the app's clock), which decides
|
|
13
|
+
* whether the app thinks it must refresh, and
|
|
14
|
+
* - the SERVER's view (`serverExpiresAt` against real time), which decides
|
|
15
|
+
* whether the server will accept it. Moving the app's clock splits them.
|
|
16
|
+
*
|
|
17
|
+
* No raw token is kept: rows hold fingerprints and what the token said.
|
|
18
|
+
* This module never imports the clock store (the clock store reads this one).
|
|
19
|
+
*/
|
|
20
|
+
import { appNow } from "../engine/patches";
|
|
21
|
+
import type { TokenClaims, TokenFormat } from "./decode";
|
|
22
|
+
import { type TokenLocation } from "./extract";
|
|
23
|
+
export type TokenCheckKind = "expiry" | "401";
|
|
24
|
+
export interface TokenCheck {
|
|
25
|
+
kind: TokenCheckKind;
|
|
26
|
+
tokenId: string;
|
|
27
|
+
/** Real ms. */
|
|
28
|
+
startedAt: number;
|
|
29
|
+
startFp: string;
|
|
30
|
+
/** The Network override rule that fails the next request (401 checks). */
|
|
31
|
+
ruleId?: string;
|
|
32
|
+
/** Real ms the forced failure reached the app. */
|
|
33
|
+
forcedAt?: number;
|
|
34
|
+
status: "waiting" | "refreshed" | "loop";
|
|
35
|
+
refreshedAt?: number;
|
|
36
|
+
/** How long the new token lasts, from its own expiry. */
|
|
37
|
+
newLifetimeMs?: number;
|
|
38
|
+
newIssuedBy?: string;
|
|
39
|
+
/** New tokens since the check started. */
|
|
40
|
+
newTokens: number;
|
|
41
|
+
/** Requests after the forced 401 that still carried the old token. */
|
|
42
|
+
staleAfterFailure: number;
|
|
43
|
+
/** Token requests that failed while the check ran ("401 POST /oauth/token"). */
|
|
44
|
+
failedRefreshes: number;
|
|
45
|
+
lastRefreshError?: string;
|
|
46
|
+
}
|
|
47
|
+
export interface TokenSummary {
|
|
48
|
+
id: string;
|
|
49
|
+
/** "Access token", "session cookie", "x-api-token header". */
|
|
50
|
+
label: string;
|
|
51
|
+
host: string;
|
|
52
|
+
location: TokenLocation;
|
|
53
|
+
name: string;
|
|
54
|
+
scheme?: string;
|
|
55
|
+
format: TokenFormat;
|
|
56
|
+
formatLabel: string;
|
|
57
|
+
hint?: string;
|
|
58
|
+
claims: TokenClaims;
|
|
59
|
+
/** Short non-secret id of the current token. */
|
|
60
|
+
fingerprint: string;
|
|
61
|
+
issuedAt?: number;
|
|
62
|
+
notBefore?: number;
|
|
63
|
+
/** When the APP's clock reaches this, the token has expired (epoch ms). */
|
|
64
|
+
expiresAt?: number;
|
|
65
|
+
/** When real time reaches this, the server stops accepting it. */
|
|
66
|
+
serverExpiresAt?: number;
|
|
67
|
+
expirySource?: string;
|
|
68
|
+
/** Total lifetime, issued → expires. */
|
|
69
|
+
lifetimeMs?: number;
|
|
70
|
+
neverExpires?: boolean;
|
|
71
|
+
issuedBy?: string;
|
|
72
|
+
refresh?: {
|
|
73
|
+
expiresAt?: number;
|
|
74
|
+
formatLabel: string;
|
|
75
|
+
};
|
|
76
|
+
/** App-clock ms the app first sent this token / last sent it. */
|
|
77
|
+
firstUsed: number;
|
|
78
|
+
lastUsed: number;
|
|
79
|
+
lastUsedReal: number;
|
|
80
|
+
uses: number;
|
|
81
|
+
/** Earlier tokens this row replaced. */
|
|
82
|
+
refreshes: number;
|
|
83
|
+
lastRefreshAt?: number;
|
|
84
|
+
/** New tokens inside the last 20 s; LOOP_COUNT or more is a loop. */
|
|
85
|
+
recentRefreshes: number;
|
|
86
|
+
looping: boolean;
|
|
87
|
+
expiredSends: number;
|
|
88
|
+
rejected: number;
|
|
89
|
+
}
|
|
90
|
+
export interface TokenReport {
|
|
91
|
+
/** @buoy-gg/network is installed, so traffic can be read. */
|
|
92
|
+
available: boolean;
|
|
93
|
+
watching: boolean;
|
|
94
|
+
tokens: TokenSummary[];
|
|
95
|
+
check: TokenCheck | null;
|
|
96
|
+
}
|
|
97
|
+
export declare function subscribeTokens(listener: () => void): () => void;
|
|
98
|
+
/**
|
|
99
|
+
* Start reading the app's traffic. Idempotent. The Network tool replays the
|
|
100
|
+
* requests it still holds, so tokens used before this ran show up too.
|
|
101
|
+
*/
|
|
102
|
+
export declare function startTokenWatch(): boolean;
|
|
103
|
+
export declare function isTokenWatchOn(): boolean;
|
|
104
|
+
export declare function beginTokenCheck(kind: TokenCheckKind, tokenId: string, ruleId?: string): TokenCheck;
|
|
105
|
+
export declare function clearTokenCheck(): void;
|
|
106
|
+
/** Everything the UI, the sync snapshot and the agents read. */
|
|
107
|
+
export declare function getTokenReport(): TokenReport;
|
|
108
|
+
export declare function getTokenRow(id?: string): TokenSummary | null;
|
|
109
|
+
/** The origin a row's token is sent to, for override rules. */
|
|
110
|
+
export declare function getTokenOrigin(id: string): string | null;
|
|
111
|
+
/** What the app's clock reads now (re-exported for token math). */
|
|
112
|
+
export declare const tokenAppNow: typeof appNow;
|
|
113
|
+
/** Test seams. */
|
|
114
|
+
export declare function __ingestForTests(event: unknown): void;
|
|
115
|
+
export declare function __resetTokensForTests(): void;
|
|
116
|
+
//# sourceMappingURL=tokenStore.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use client";var dt=Object.defineProperty;var jr=Object.getOwnPropertyDescriptor;var Lr=Object.getOwnPropertyNames;var Pr=Object.prototype.hasOwnProperty;var Mr=(e,t)=>{for(var r in t)dt(e,r,{get:t[r],enumerable:true})},pt=(e,t,r,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of Lr(t))!Pr.call(e,o)&&o!==r&&dt(e,o,{get:()=>t[o],enumerable:!(n=jr(t,o))||n.enumerable});return e},_r=(e,t,r)=>(pt(e,t,"default"),r&&pt(r,t,"default"));var ht=process.env.NODE_ENV!=="production";typeof window<"u"&&typeof globalThis.global>"u"&&(globalThis.global=globalThis);var mt={};Mr(mt,{AccessibilityInfo:()=>Vr,ActivityIndicator:()=>Pn,Alert:()=>Fn,Animated:()=>yt,AppRegistry:()=>Wr,AppState:()=>Jr,Appearance:()=>Ur,BackHandler:()=>qr,Button:()=>Mn,CheckBox:()=>un,Clipboard:()=>Kr,DeviceEventEmitter:()=>$n,Dimensions:()=>Zr,Easing:()=>Yr,FlatList:()=>fn,I18nManager:()=>Gr,Image:()=>dn,ImageBackground:()=>pn,InteractionManager:()=>Qr,Keyboard:()=>Xr,KeyboardAvoidingView:()=>hn,LayoutAnimation:()=>en,Linking:()=>tn,LogBox:()=>Sn,Modal:()=>jn,NativeEventEmitter:()=>rn,NativeModules:()=>Hr,PanResponder:()=>nn,Picker:()=>mn,PixelRatio:()=>on,Platform:()=>sn,Pressable:()=>Nn,ProgressBar:()=>yn,RefreshControl:()=>gn,SafeAreaView:()=>bn,ScrollView:()=>bt,SectionList:()=>kn,Share:()=>an,StatusBar:()=>xn,StyleSheet:()=>Y,Switch:()=>Ln,Text:()=>g,TextInput:()=>gt,Touchable:()=>vn,TouchableHighlight:()=>En,TouchableNativeFeedback:()=>wn,TouchableOpacity:()=>F,TouchableWithoutFeedback:()=>zn,UIManager:()=>ln,Vibration:()=>cn,View:()=>h,VirtualizedList:()=>An,YellowBox:()=>Tn,findNodeHandle:()=>_n,unstable_createElement:()=>Br,useColorScheme:()=>In,useLocaleContext:()=>Rn,useWindowDimensions:()=>On});_r(mt,Fr);import*as Fr from"react-native-web";import{unstable_createElement as Br,NativeModules as Hr,AccessibilityInfo as Vr,Animated as yt,Appearance as Ur,AppRegistry as Wr,AppState as Jr,BackHandler as qr,Clipboard as Kr,Dimensions as Zr,Easing as Yr,I18nManager as Gr,Keyboard as Xr,InteractionManager as Qr,LayoutAnimation as en,Linking as tn,NativeEventEmitter as rn,PanResponder as nn,PixelRatio as on,Platform as sn,Share as an,StyleSheet as Y,UIManager as ln,Vibration as cn,CheckBox as un,FlatList as fn,Image as dn,ImageBackground as pn,KeyboardAvoidingView as hn,Picker as mn,ProgressBar as yn,RefreshControl as gn,SafeAreaView as bn,SectionList as kn,StatusBar as xn,Touchable as vn,TouchableNativeFeedback as wn,VirtualizedList as An,YellowBox as Tn,LogBox as Sn,DeviceEventEmitter as $n,useColorScheme as In,useLocaleContext as Rn,useWindowDimensions as On}from"react-native-web";import*as O from"react-native-web";import{createElement as Cn,forwardRef as Dn}from"react";function D(e){let t=Dn((n,o)=>{let{accessibilityState:i,accessibilityValue:s,...a}=n;for(let l of["busy","checked","disabled","expanded","selected"])i?.[l]!==void 0&&a[`aria-${l}`]===void 0&&(a[`aria-${l}`]=i[l]);for(let[l,c]of Object.entries({min:"valuemin",max:"valuemax",now:"valuenow",text:"valuetext"}))s?.[l]!==void 0&&a[`aria-${c}`]===void 0&&(a[`aria-${c}`]=s[l]);return Cn(e,{...a,ref:o})}),r=e.State;return r&&Object.assign(t,{State:r}),t.displayName=e.displayName??e.name??"NativeWebView",t}var h=D(O.View),g=D(O.Text),gt=D(O.TextInput),F=D(O.TouchableOpacity),En=D(O.TouchableHighlight),zn=D(O.TouchableWithoutFeedback),Nn=D(O.Pressable),bt=D(O.ScrollView),jn=D(O.Modal),Ln=D(O.Switch),Pn=D(O.ActivityIndicator),Mn=D(O.Button),_n=O.findNodeHandle,Fn={alert(e,t,r,n){if(typeof document>"u")return;let o=document.createElement("dialog");o.dataset.buoyRoot="",o.setAttribute("aria-label",e),o.style.cssText="position:fixed;inset:0;margin:auto;width:min(440px,90vw);padding:24px;border:1px solid #475569;border-radius:14px;background:#17212e;color:#f1f5f9;font:14px system-ui;box-shadow:0 20px 80px #0008;z-index:2147483647";let i=document.createElement("h2");if(i.textContent=e,i.style.cssText="font-size:18px;margin:0 0 12px",o.appendChild(i),t){let c=document.createElement("p");c.textContent=t,c.style.cssText="line-height:1.5;white-space:pre-wrap;margin:0 0 20px",o.appendChild(c)}let s=document.createElement("div");s.style.cssText="display:flex;justify-content:flex-end;flex-wrap:wrap;gap:8px";let a=r?.length?r:[{text:"OK"}],l=()=>{o.close?.(),o.remove()};for(let c of a){let u=document.createElement("button");u.type="button",u.textContent=c.text??"OK",u.style.cssText=`padding:9px 14px;border:1px solid #64748b;border-radius:7px;color:white;background:${c.style==="destructive"?"#a52b38":"#283a4d"};cursor:pointer;font:inherit`,u.onclick=()=>{l(),c.onPress?.()},s.appendChild(u)}o.addEventListener("cancel",c=>{c.preventDefault(),n?.cancelable!==false&&(l(),n?.onDismiss?.())}),o.appendChild(s),document.body.appendChild(o),o.showModal?o.showModal():o.setAttribute("open","")}};var Re=Object.freeze({mode:"real",anchorReal:0,anchorVirtual:0,rate:1}),Oe=.1,Ce=86400,Bn=864e13;function L(e,t){return e.mode==="real"?t:e.mode==="frozen"?e.anchorVirtual:e.anchorVirtual+(t-e.anchorReal)*e.rate}function Hn(e,t){return L(e,t)-t}function G(e){if(!Number.isFinite(e)||Math.abs(e)>Bn)throw new RangeError(`Not a valid time: ${e}`);return Math.round(e)}function De(e,t,r,n=false){return{mode:n?"frozen":"running",anchorReal:t,anchorVirtual:G(r),rate:e.mode==="real"?1:e.rate}}function Vn(e,t,r){if(!Number.isFinite(r))throw new RangeError("Jump must be a number of ms");return De(e,t,L(e,t)+r,e.mode==="frozen")}function Un(e,t,r){return De(e,t,r??L(e,t),true)}function Wn(e,t){return e.mode!=="frozen"?e:{...e,mode:"running",anchorReal:t}}function Jn(e,t,r){if(!Number.isFinite(r)||r<Oe||r>Ce)throw new RangeError(`Speed must be between ${Oe}\xD7 and ${Ce}\xD7`);return e.mode==="real"&&r===1?e:{mode:"running",anchorReal:t,anchorVirtual:G(L(e,t)),rate:r}}function qn(e){let t=e;return!!t&&(t.mode==="real"||t.mode==="running"||t.mode==="frozen")&&Number.isFinite(t.anchorReal)&&Number.isFinite(t.anchorVirtual)&&Number.isFinite(t.rate)&&t.rate>=Oe&&t.rate<=Ce}var Kn={ms:1,millisecond:1,milliseconds:1,s:1e3,sec:1e3,secs:1e3,second:1e3,seconds:1e3,m:6e4,min:6e4,mins:6e4,minute:6e4,minutes:6e4,h:36e5,hr:36e5,hrs:36e5,hour:36e5,hours:36e5,d:864e5,day:864e5,days:864e5,w:6048e5,wk:6048e5,week:6048e5,weeks:6048e5,mo:30*864e5,month:30*864e5,months:30*864e5,y:365*864e5,yr:365*864e5,year:365*864e5,years:365*864e5};function Ee(e){if(typeof e=="number"){if(!Number.isFinite(e))throw new RangeError("Duration must be finite");return Math.round(e)}let t=String(e).trim().toLowerCase();if(!t)throw new RangeError("Duration is empty");let r=1;if((t[0]==="+"||t[0]==="-"||t[0]==="\u2212")&&(r=t[0]==="+"?1:-1,t=t.slice(1).trim()),/^\d+(\.\d+)?$/.test(t))return r*Math.round(Number(t));let n=/(\d+(?:\.\d+)?)\s*([a-z]+)/g,o=0,i="",s;for(;s=n.exec(t);){let a=Kn[s[2]];if(a===void 0)throw new RangeError(`Unknown time unit "${s[2]}" in "${e}"`);o+=Number(s[1])*a,i+=s[0]}if(!i||i.replace(/\s/g,"")!==t.replace(/[\s,]/g,""))throw new RangeError(`Could not read "${e}" as a duration. Try "+1d", "-2h30m" or "90s".`);return r*Math.round(o)}function te(e,{signed:t=true}={}){let r=e<0?"\u2212":"+",n=Math.abs(Math.round(e));if(n<1e3)return t&&n>0?`${r}${n}ms`:"0s";let o=[],i=[["y",365*864e5],["d",864e5],["h",36e5],["m",6e4],["s",1e3]];for(let[s,a]of i)if(n>=a&&(o.push(`${Math.floor(n/a)}${s}`),n%=a),o.length===2)break;return`${t?r:""}${o.join(" ")}`}function kt(e,t,r){if(typeof e=="number")return G(e);let n=String(e).trim();if(!n)throw new RangeError("Time is empty");if(/^now$/i.test(n))return t;if(/^[+\-−]/.test(n))return G(t+Ee(n));if(/^\d{11,}$/.test(n))return G(Number(n));let o=n.replace(/^(\d{4}-\d{2}-\d{2})[ ](\d{2}:\d{2})/,"$1T$2"),i=r(o);if(!Number.isFinite(i))throw new RangeError(`Could not read "${e}" as a time. Use ISO 8601 like 2026-12-31T23:59:50, epoch ms, or "+1d".`);return G(i)}var ze=1e4,xt=[{id:"midnight",label:"Before midnight",hint:"23:59:50 tonight",at(e,t){let r=new t(e);return r.setHours(24,0,0,0),r.getTime()-ze}},{id:"month-end",label:"Month end",hint:"last day, 23:59:50",at(e,t){let r=new t(e);return r.setMonth(r.getMonth()+1,1),r.setHours(0,0,0,0),r.getTime()-ze}},{id:"year-end",label:"New Year's Eve",hint:"Dec 31, 23:59:50",at(e,t){let r=new t(e);return r.setFullYear(r.getFullYear()+1,0,1),r.setHours(0,0,0,0),r.getTime()-ze}},{id:"tomorrow-9",label:"Tomorrow 9 AM",hint:"start of a business day",at(e,t){let r=new t(e);return r.setDate(r.getDate()+1),r.setHours(9,0,0,0),r.getTime()}},{id:"leap-day",label:"Leap day",hint:"next Feb 29, 09:00",at(e,t){let r=new t(e).getFullYear();for(;;){let n=r%4===0&&r%100!==0||r%400===0,o=new t(r,1,29,9,0,0,0).getTime();if(n&&o>e)return o;r+=1}}}],ks=[{label:"1m",ms:6e4},{label:"15m",ms:15*6e4},{label:"1h",ms:36e5},{label:"1d",ms:864e5},{label:"7d",ms:7*864e5},{label:"30d",ms:30*864e5},{label:"1y",ms:365*864e5}];function vt(e){return e===3600?"1h/s":e===600?"10m/s":e===60?"1m/s":`${Number.isInteger(e)?e:e.toFixed(1)}\xD7`}var E=globalThis,pe="__buoyClock",A=E.__buoyRealDate??(Date[pe]?Date.__buoyRealDate:Date);E.__buoyRealDate=A;var wt=A.now.bind(A);function T(){return wt()}E.__buoyRealNow=T;var Ne=null,je=0;function he(){let e=wt();return!Ne||je>0?e:Ne(e)}function At(e){Ne=e}function Le(e){je+=1;try{return e()}finally{je-=1}}E.__buoyWithRealClock=Le;function P(...e){let t=new.target;return t?Reflect.construct(A,e.length===0?[he()]:e,t):new A(he()).toString()}P.prototype=A.prototype;Object.defineProperty(P,"name",{value:"Date"});Object.defineProperty(P,"length",{value:7});Object.defineProperty(P,"now",{value:function(){return he()},writable:true,configurable:true});Object.defineProperty(P,"parse",{value:A.parse,writable:true,configurable:true});Object.defineProperty(P,"UTC",{value:A.UTC,writable:true,configurable:true});Object.defineProperty(P,pe,{value:true});Object.defineProperty(P,"__buoyRealDate",{value:A});var re=P,me=false,ye;function Zn(){return me&&E.Date===re}function Yn(){if(E.Date===re){me=true;return}let e=Object.getOwnPropertyDescriptor(E,"Date");Object.defineProperty(E,"Date",{value:re,writable:e?.writable??true,enumerable:e?.enumerable??false,configurable:true}),ye=Object.getOwnPropertyDescriptor(A.prototype,"constructor");try{Object.defineProperty(A.prototype,"constructor",{value:re,writable:true,enumerable:false,configurable:true})}catch{}me=true}function Gn(){if(E.Date===re){let e=Object.getOwnPropertyDescriptor(E,"Date");Object.defineProperty(E,"Date",{value:A,writable:e?.writable??true,enumerable:e?.enumerable??false,configurable:true})}if(ye){try{Object.defineProperty(A.prototype,"constructor",ye)}catch{}ye=void 0}me=false}var ne=[];function Tt(e){return function(t,...r){return e.call(this,t===void 0?he():t,...r)}}function Xn(){if(ne.length)return;let e=E.Intl?.DateTimeFormat?.prototype;if(e)for(let t of["format","formatToParts"]){let r=Object.getOwnPropertyDescriptor(e,t);if(!(!r||!r.configurable))try{if(typeof r.get=="function"){let n=r.get;Object.defineProperty(e,t,{...r,get(){return Tt(n.call(this))}})}else if(typeof r.value=="function")Object.defineProperty(e,t,{...r,value:Tt(r.value)});else continue;ne.push({proto:e,name:t,original:r})}catch{}}}function Qn(){for(let{proto:e,name:t,original:r}of ne)try{Object.defineProperty(e,t,r)}catch{}ne=[]}function eo(){return ne.length>0}function to(){Yn(),Xn()}function ro(){Gn(),Qn()}var Pe=false;function no(e){let t=Object.getPrototypeOf(e);for(;t&&t!==Object.prototype;){if(!Object.prototype.hasOwnProperty.call(t,pe)){for(let r of["start","onUpdate"]){let n=Object.getOwnPropertyDescriptor(t,r);if(n&&typeof n.value=="function"){let o=n.value;t[r]=function(...i){return Le(()=>o.apply(this,i))}}}try{Object.defineProperty(t,pe,{value:true})}catch{return}}t=Object.getPrototypeOf(t)}}function oo(e){if(Pe)return true;try{let t=e;if(typeof t?.Value!="function")return false;let r=Object.getPrototypeOf(new t.Value(0)),n=r?.animate;return typeof n!="function"?false:(r.animate=function(o,...i){return o&&typeof o=="object"&&no(o),n.call(this,o,...i)},Pe=true,true)}catch{return false}}function io(){return Pe}var oe=globalThis,St="__buoyClockTimer",z=new Map,W=null,$t=0,J=()=>T()+$t;function so(e){(W?.setTimeout??setTimeout)(()=>{throw e},0)}function It(e){let t=Number(e);return Number.isFinite(t)&&t>0?t:0}function ao(){return W!==null}function Rt(){if(W)return true;let{setTimeout:e,clearTimeout:t,setInterval:r,clearInterval:n}=oe;if(typeof e!="function"||typeof t!="function")return false;if(e[St])return true;W={setTimeout:e,clearTimeout:t,setInterval:typeof r=="function"?r:e,clearInterval:typeof n=="function"?n:t};let o=W,i=function(u,x,...w){if(typeof u!="function")return o.setTimeout(u,x,...w);let R=It(x),I,j=function(){return z.delete(I),u.apply(this,w)};return I=o.setTimeout(j,x),z.set(I,{kind:"timeout",callback:u,args:w,delay:R,due:J()+R,realHandle:I,run:j}),I},s=function(u,x,...w){if(typeof u!="function")return o.setInterval(u,x,...w);let R=It(x),I,j=function(){let Z=z.get(I);return Z&&(Z.due=J()+R),u.apply(this,w)};return I=o.setInterval(j,x),z.set(I,{kind:"interval",callback:u,args:w,delay:R,due:J()+R,realHandle:I,run:j}),I},a=(u,x)=>{let w=z.get(u);return w?(z.delete(u),w.kind==="interval"?o.clearInterval(w.realHandle):o.clearTimeout(w.realHandle)):x(u)},l=function(u){return a(u,o.clearTimeout)},c=function(u){return a(u,o.clearInterval)};globalThis.__buoyRealTimers={setTimeout:o.setTimeout,clearTimeout:l,setInterval:o.setInterval,clearInterval:c};for(let u of[i,s,l,c])Object.defineProperty(u,St,{value:true});return oe.setTimeout=i,oe.clearTimeout=l,oe.setInterval=s,oe.clearInterval=c,true}function lo(){let e=J(),t=0,r=0,n=null;for(let o of z.values())if(o.kind==="interval")r+=1;else{t+=1;let i=Math.max(0,o.due-e);(n===null||i<n)&&(n=i)}return{total:t+r,timeouts:t,intervals:r,nextTimeoutInMs:n}}function co(e){let t=J(),r=0;for(let n of z.values())n.due-t<=e&&(r+=1);return r}function uo(e){if(!W||!(e>0))return 0;let t=W;$t+=e;let r=J(),n=[...z.entries()].filter(([,s])=>s.due<=r).sort((s,a)=>s[1].due-a[1].due),o=0;for(let[s,a]of n)if(z.has(s)){a.kind==="timeout"?(z.delete(s),t.clearTimeout(a.realHandle)):a.due=r+a.delay;try{a.callback(...a.args)}catch(l){so(l)}o+=1}let i=J();for(let s of z.values())s.kind==="timeout"&&(t.clearTimeout(s.realHandle),s.realHandle=t.setTimeout(s.run,Math.max(0,s.due-i)));return o}import{devToolsStorageKeys as fo,persistentStorage as Ot}from"@buoy-gg/shared-ui/web";var ie={persist:true,showChip:true,fireTimersOnJump:true},Ct=fo.clock.state();function po(e){if(!e)return null;try{let t=JSON.parse(e);if(!t||t.v!==1)return null;let r=t.settings??{};return{v:1,anchor:qn(t.anchor)?t.anchor:null,settings:{persist:typeof r.persist=="boolean"?r.persist:ie.persist,showChip:typeof r.showChip=="boolean"?r.showChip:ie.showChip,fireTimersOnJump:typeof r.fireTimersOnJump=="boolean"?r.fireTimersOnJump:ie.fireTimersOnJump}}}catch{return null}}async function ho(){try{return po(await Ot.getItem(Ct))}catch{return null}}var Me=Promise.resolve();function mo(e){let t=JSON.stringify(e);return Me=Me.then(()=>Ot.setItem(Ct,t)).catch(()=>{}),Me.then(()=>{})}import{dispatchToolAction as yo}from"@buoy-gg/shared-ui/web";import{loadToolModule as go}from"@buoy-gg/shared-ui/web/utils";var Dt="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",ge={};for(let e=0;e<Dt.length;e++)ge[Dt[e]]=e;ge["-"]=62;ge._=63;function _e(e){let t=e.replace(/=+$/,""),r=[],n=0,o=0;for(let i=0;i<t.length;i++){let s=ge[t[i]];if(s===void 0)return null;n=n<<6|s,o+=6,o>=8&&(o-=8,r.push(n>>o&255))}return r}function bo(e){let t="";for(let r=0;r<e.length;){let n=e[r],o,i;if(n<128)o=n,i=0;else if(n>=192&&n<224)o=n&31,i=1;else if(n>=224&&n<240)o=n&15,i=2;else if(n>=240&&n<248)o=n&7,i=3;else return null;for(let s=1;s<=i;s++){let a=e[r+s];if(a===void 0||(a&192)!==128)return null;o=o<<6|a&63}t+=String.fromCodePoint(o),r+=i+1}return t}function Fe(e){let t=_e(e);return t?Et(t):null}function Et(e){let t=bo(e);if(!t||t[0]!=="{")return null;try{let r=JSON.parse(t);return r&&typeof r=="object"&&!Array.isArray(r)?r:null}catch{return null}}function Be(e){let t=typeof e=="string"&&e.trim()!==""?Number(e):e;return typeof t=="number"&&Number.isFinite(t)&&t>0?t*1e3:void 0}function se(e,t){if(typeof e=="number"&&Number.isFinite(e)&&e>0)return e<1e11?e*1e3:e;if(typeof e=="string"&&e.trim()!==""){let r=e.trim();if(/^\d+(\.\d+)?$/.test(r))return se(Number(r),t);let n=t(r);return Number.isFinite(n)?n:void 0}}function ko(e){let t=typeof e=="string"&&/^\d+(\.\d+)?$/.test(e.trim())?Number(e):e;return typeof t=="number"&&Number.isFinite(t)&&t>0?t:void 0}var xo=/^[A-Za-z0-9_-]{2,}\.[A-Za-z0-9_-]{2,}\.[A-Za-z0-9_-]*$/,vo=/^[A-Za-z0-9_-]{2,}\.[A-Za-z0-9_-]*\.[A-Za-z0-9_-]*\.[A-Za-z0-9_-]{2,}\.[A-Za-z0-9_-]*$/,zt=/^v([1-4])\.(local|public)\.([A-Za-z0-9_-]+)(?:\.([A-Za-z0-9_-]+))?$/,wo={1:256,2:64,3:96,4:64};function B(e){if(typeof e=="string"&&e)return e;if(Array.isArray(e)){let t=e.filter(r=>typeof r=="string");return t.length?t.join(", "):void 0}}function Ao(e,t){let r=e.iss??"",n=e.use;if(r.includes("securetoken.google.com"))return"Firebase ID token";if(r.includes("firebaseappcheck"))return"Firebase App Check token";if(r.includes("cognito-idp"))return n?`Cognito ${n} token`:"Cognito token";if(r.includes("appleid.apple.com"))return"Sign in with Apple token";if(r.includes("accounts.google.com"))return"Google ID token";if(r.includes(".auth0.com")||r.includes("auth0"))return"Auth0 token";if(r.includes("clerk"))return"Clerk session token";if(r.includes("supabase")||r.includes("/auth/v1"))return"Supabase access token";if(r.includes("okta"))return"Okta token";if(r.includes("/realms/"))return"Keycloak token";if(r.includes("login.microsoftonline.com")||r.includes("sts.windows.net"))return"Microsoft Entra token";let o=typeof t?.typ=="string"?t.typ.toLowerCase():"";if(o==="at+jwt"||o==="application/at+jwt")return"OAuth access token"}function To(e,t){let r={iss:B(e.iss),aud:B(e.aud),sub:B(e.sub),scope:B(e.scope??e.scp),use:B(e.token_use)},n=Be(e.exp);return{claims:r,issuedAt:Be(e.iat),notBefore:Be(e.nbf),expiresAt:n,expirySource:n?t:void 0}}function So(e){let[t,r]=e.split("."),n=Fe(t);if(!n||typeof n.alg!="string"&&typeof n.typ!="string")return null;let o=Fe(r);if(!o)return null;let i=typeof n.alg=="string"?n.alg:void 0,s=To(o,"exp claim");return s.claims.alg=i,!s.claims.use&&typeof n.typ=="string"&&n.typ.toUpperCase()!=="JWT"&&(s.claims.use=n.typ),{format:"jwt",formatLabel:i?`JWT \xB7 ${i}`:"JWT",hint:Ao(s.claims,n),...s}}function $o(e){let t=Fe(e.split(".")[0]);return!t||typeof t.enc!="string"?null:{format:"jwe",formatLabel:"Encrypted JWT",claims:{alg:typeof t.alg=="string"?t.alg:void 0}}}function Io(e,t){let r=zt.exec(e);if(!r)return null;let[,n,o,i]=r;if(o==="local")return{format:"paseto-local",formatLabel:`PASETO v${n} (encrypted)`,claims:{}};let s=_e(i),a=wo[n],l=s&&s.length>a?Et(s.slice(0,s.length-a)):null,c={format:"paseto-public",formatLabel:`PASETO v${n}`,claims:{}};return l&&(c.claims={iss:B(l.iss),aud:B(l.aud),sub:B(l.sub)},c.issuedAt=se(l.iat,t),c.notBefore=se(l.nbf,t),c.expiresAt=se(l.exp,t),c.expiresAt&&(c.expirySource="exp claim")),c}function Ro(e){if(!e.startsWith("gAAAAA")||e.length<76)return null;let t=_e(e);if(!t||t[0]!==128||t.length<73||(t.length-57)%16!==0)return null;let r=0;for(let n=1;n<=8;n++)r=r*256+t[n];return r<978307200||r>4102444800?null:{format:"fernet",formatLabel:"Fernet",claims:{},issuedAt:r*1e3}}var Oo=[{test:/^ya29\./,hint:"Google OAuth access token"},{test:/^gh[opsu]_/,hint:"GitHub token"},{test:/^github_pat_/,hint:"GitHub token"},{test:/^xox[abeprs]-/,hint:"Slack token"},{test:/^EAA[A-Za-z0-9]{40,}/,hint:"Facebook access token"},{test:/^shp(at|ca|pa|ss)_/,hint:"Shopify token"},{test:/^(sk|rk|pk)_(live|test)_/,hint:"Stripe API key",neverExpires:true},{test:/^AIza[0-9A-Za-z_-]{35}$/,hint:"Google API key",neverExpires:true}];function be(e,t=Date.parse){let r=e.trim().replace(/^"(.*)"$/,"$1");if(r.length<16||/\s/.test(r))return null;if(xo.test(r)){let i=So(r);if(i)return i}if(vo.test(r)){let i=$o(r);if(i)return i}if(r.startsWith("v")&&zt.test(r)){let i=Io(r,t);if(i)return i}let n=Ro(r);if(n)return n;let o=Oo.find(i=>i.test.test(r));return{format:"opaque",formatLabel:"Opaque",hint:o?.hint,neverExpires:o?.neverExpires,claims:{}}}function Co(e){return!!e&&e.format!=="opaque"}function H(e){let t=2166136261;for(let r=0;r<e.length;r++)t^=e.charCodeAt(r),t=Math.imul(t,16777619)>>>0;return t.toString(16).padStart(8,"0")}function He(e){let t=/^([a-z][a-z0-9+.-]*:\/\/[^/?#]+)/i.exec(e);return t?t[1].toLowerCase():null}function Do(e){let t=He(e);return t?t.replace(/^[a-z][a-z0-9+.-]*:\/\//,""):"unknown"}function Ve(e){return e.replace(/^[a-z][a-z0-9+.-]*:\/\/[^/?#]+/i,"").split(/[?#]/)[0]||"/"}function Eo(e){let t=e.split("#")[0].split("?")[1];if(!t)return[];let r=[];for(let n of t.split("&")){let o=n.indexOf("=");if(!(o<=0))try{r.push([decodeURIComponent(n.slice(0,o)),decodeURIComponent(n.slice(o+1))])}catch{}}return r}var Ue=/(token|jwt|session|auth|appcheck|api[-_]?key|apikey|credential|bearer)/i,zo=new Set(["authorization","cookie","dpop","idempotency-key","x-request-id","x-correlation-id","www-authenticate","proxy-authenticate","x-csrf-token","x-xsrf-token"]),Nt=new Set(["access_token","accesstoken","id_token","token","auth","auth_token","jwt","session","session_token"]),No=new Set(["bearer","token","jwt","dpop","oauth","firebase"]);function jt(e){let t={};if(!e)return t;for(let[r,n]of Object.entries(e))typeof n=="string"?t[r.toLowerCase()]=n:Array.isArray(n)&&(t[r.toLowerCase()]=n.join(", "));return t}function jo(e){let t=[];for(let r of e.split(";")){let n=r.indexOf("=");n<=0||t.push([r.slice(0,n).trim(),r.slice(n+1).trim()])}return t}function ae(e,t,r){let n=be(e,r);return n&&(Co(n)||n.hint||t)?n:null}function Lt(e,t){let r=[],n=jt(e.requestHeaders),o=n.authorization;if(o){let i=/^(\S+)\s+(\S+)$/.exec(o.trim()),s=i?i[1]:void 0,a=i?i[2]:o.trim();if(!s||No.has(s.toLowerCase())){let l=ae(a,true,t);l&&r.push({location:"authorization",name:"Authorization",scheme:s,fp:H(a),info:l})}}for(let[i,s]of Object.entries(n)){if(zo.has(i)||!Ue.test(i))continue;let a=s.replace(/^bearer\s+/i,""),l=ae(a,true,t);l&&r.push({location:"header",name:i,fp:H(a),info:l})}if(n.cookie)for(let[i,s]of jo(n.cookie)){let a=ae(s,Ue.test(i)||/^(sid|sess)/i.test(i),t);a&&r.push({location:"cookie",name:i,fp:H(s),info:a})}for(let[i,s]of Eo(e.url)){let a=ae(s,Nt.has(i.toLowerCase()),t);a&&Nt.has(i.toLowerCase())&&r.push({location:"query",name:i,fp:H(s),info:a})}return r}var Lo=/^(access_?token|accesstoken|token|jwt|auth_?token|session_?token|sessiontoken)$/i,Pt=/^(id_?token|idtoken)$/i,ke=/^(refresh_?token|refreshtoken)$/i,Po=["expires_in","expiresIn","ExpiresIn","expires","ttl"],Mo=["expires_at","expiresAt","ExpiresAt","expiration","Expiration","expiry","expirationTime","expiration_time","access_token_expires_at","accessTokenExpiresAt","accessTokenExpiry"],_o=["refresh_expires_in","refresh_token_expires_in","refreshTokenExpiresIn","refreshExpiresIn"],Fo=["refresh_expires_at","refreshTokenExpiresAt","refresh_token_expires_at"];function Bo(e){if(typeof e!="string")return e;let t=e.trim();if(!(t.startsWith("{")||t.startsWith("[")))return null;try{return JSON.parse(t)}catch{return null}}function We(e,t,r){if(t>4||!e||typeof e!="object")return;if(Array.isArray(e)){for(let o of e.slice(0,5))We(o,t+1,r);return}let n=e;for(let[o,i]of Object.entries(n))typeof i=="string"&&(Lo.test(o)||Pt.test(o)||ke.test(o))?r.push({key:o,value:i,holder:n}):i&&typeof i=="object"&&We(i,t+1,r)}function Ho(e){return ke.test(e)?"refresh":Pt.test(e)?"id":/session/i.test(e)?"session":"access"}function Mt(e,t,r,n,o){for(let i of t){let s=ko(e[i]);if(s!==void 0)return{expiresAt:n+s*1e3,source:i,lifetimeMs:s*1e3}}for(let i of r){let s=se(e[i],o);if(s!==void 0)return{expiresAt:s,source:i}}return{}}function Vo(e){let t=e["set-cookie"];return t?t.split(/,(?=\s*[A-Za-z0-9!#$%&'*+.^_`|~-]+=)/).map(r=>r.trim()):[]}function Uo(e,t){if(e.status===void 0||e.status>=400)return[];let r=`${e.method.toUpperCase()} ${Ve(e.url)}`,n=e.timestamp+(e.duration??0),o=[],i=Bo(e.responseData);if(i){let a=[];We(i,0,a);let l=new Map;for(let c of a.filter(u=>ke.test(u.key))){let u=be(c.value,t);if(!u)continue;let x=Mt(c.holder,_o,Fo,n,t);l.set(c.holder,{fp:H(c.value),expiresAt:u.expiresAt??x.expiresAt,formatLabel:u.formatLabel})}for(let c of a){if(ke.test(c.key))continue;let u=be(c.value,t);if(!u)continue;let x=Mt(c.holder,Po,Mo,n,t);o.push({fp:H(c.value),info:u,role:Ho(c.key),expiresAt:x.expiresAt,expirySource:x.source,lifetimeMs:x.lifetimeMs,issuedBy:r,refresh:l.get(c.holder)})}}let s=jt(e.responseHeaders);for(let a of Vo(s)){let[l,...c]=a.split(";"),u=l.indexOf("=");if(u<=0)continue;let x=l.slice(0,u).trim(),w=l.slice(u+1).trim(),R=ae(w,Ue.test(x)||/^(sid|sess)/i.test(x),t);if(!R||w===""||w.toLowerCase()==="deleted")continue;let I,j,Z;for(let Er of c){let[zr,...Nr]=Er.split("="),ut=zr.trim().toLowerCase(),Ie=Nr.join("=").trim();if(ut==="max-age"&&/^-?\d+$/.test(Ie))Z=Number(Ie)*1e3,I=n+Z,j="Max-Age";else if(ut==="expires"&&j!=="Max-Age"){let ft=t(Ie);Number.isFinite(ft)&&(I=ft,j="Expires")}}o.push({fp:H(w),info:R,role:"cookie",cookie:x,expiresAt:R.expiresAt??I,expirySource:R.expiresAt?R.expirySource:j,lifetimeMs:R.expiresAt?void 0:Z,issuedBy:r})}return o}var Je=e=>A.parse(e),_t=4,Ft=2e4,Wo=8,Jo=8,qo=200,Ko=1e3,C=new Map,X=new Map,Zo=new Set,Yo=new Set,Bt=new Set,Go=/(token|refresh|oauth|session|auth\/)/i,p=null,xe=true,qe=null,Ke=new Set,Ze=false;function le(){Ze||(Ze=true,Promise.resolve().then(()=>{Ze=false,Ke.forEach(e=>e())}))}function Xo(e){return Ke.add(e),()=>{Ke.delete(e)}}function Ht(e,t){if(e.has(t))return false;if(e.size>=Ko){let r=e.values().next().value;r!==void 0&&e.delete(r)}return e.add(t),true}function Ye(e,t){return`${e}|${t.location}:${t.name.toLowerCase()}`}function Vt(e,t){let r=t?.lifetimeMs!==void 0&&t.expiresAt!==void 0,n=r?t.expiresAt:e.expiresAt??t?.expiresAt,o=e.expiresAt??(r?t.observedReal+t.lifetimeMs:t?.expiresAt),i=r?t.expirySource:e.expiresAt?e.expirySource:t?.expirySource,s=r?t.lifetimeMs:e.expiresAt!==void 0&&e.issuedAt!==void 0?e.expiresAt-e.issuedAt:void 0;return{expiresAt:n,serverExpiresAt:o,source:i,lifetimeMs:s}}function Ge(e,t,r,n,o){let i=X.get(t),s=Vt(r,i),a=e.fp!==t;a&&(e.history.unshift({fp:e.fp,firstSeenReal:e.firstSeenReal,expiresAt:e.expiresAt}),e.history.length=Math.min(e.history.length,Jo),e.fp=t,e.firstSeenReal=n,e.firstSeenApp=o,e.uses=0,e.expiredSends=0,e.rejected=0),e.info=r,e.role=i?.role??(a?void 0:e.role),e.issuedBy=i?.issuedBy??(a?void 0:e.issuedBy),e.refresh=i?.refresh??(a?void 0:e.refresh),e.expiresAt=s.expiresAt,e.serverExpiresAt=s.serverExpiresAt,e.expirySource=s.source,e.lifetimeMs=s.lifetimeMs,a&&Qo(e,n)}function Ut(e,t,r,n,o){let i=X.get(r.fp),s=Vt(r.info,i);return{key:e,origin:t,host:Do(t),location:r.location,name:r.name,scheme:r.scheme,fp:r.fp,info:r.info,role:i?.role,issuedBy:i?.issuedBy,refresh:i?.refresh,expiresAt:s.expiresAt,serverExpiresAt:s.serverExpiresAt,expirySource:s.source,lifetimeMs:s.lifetimeMs,firstSeenReal:n,firstSeenApp:o,lastUsedReal:n,lastUsedApp:o,uses:0,expiredSends:0,rejected:0,history:[]}}function Wt(){if(C.size<=Wo)return;let e=null;for(let t of C.values())(!e||t.lastUsedReal<e.lastUsedReal)&&(e=t);e&&e.key!==p?.tokenId&&C.delete(e.key)}function Qo(e,t){!p||p.tokenId!==e.key||(p.newTokens+=1,p.status==="waiting"&&(p.status="refreshed",p.refreshedAt=t,p.ruleId&&p.forcedAt===void 0&&yo("network","deleteOverrideRule",{id:p.ruleId}).catch(()=>{})),p.newTokens>=_t&&t-(p.refreshedAt??t)<=Ft&&(p.status="loop"))}function ei(e){let t=He(e.url);if(!t)return;let r=Lt(e,Je);if(r.length===0)return;let n=T(),o=e.timestamp;for(let i of r){let s=Ye(t,i),a=C.get(s);a?Ge(a,i.fp,i.info,n,o):(a=Ut(s,t,i,n,o),C.set(s,a),Wt()),a.uses+=1,a.lastUsedReal=n,a.lastUsedApp=o,a.expiresAt!==void 0&&o>=a.expiresAt&&(a.expiredSends+=1),p&&p.tokenId===s&&p.forcedAt!==void 0&&i.fp===p.startFp&&(p.staleAfterFailure+=1)}le()}function ti(e){let t=He(e.url);if(!t)return;let r=T(),n=false;if(e.status===401||e.status===403)for(let i of Lt(e,Je)){let s=C.get(Ye(t,i));s&&s.fp===i.fp&&(s.rejected+=1,n=true)}let o=!!p?.ruleId&&e.override?.ruleId===p.ruleId;if(p&&(e.status??0)>=400&&!o){let i=`${e.method.toUpperCase()} ${Ve(e.url)}`;(Bt.has(i)||e.method.toUpperCase()==="POST"&&Go.test(Ve(e.url)))&&(p.failedRefreshes+=1,p.lastRefreshError=`${e.status} ${i}`,n=true)}p?.ruleId&&e.override?.ruleId===p.ruleId&&p.forcedAt===void 0&&(p.forcedAt=r,n=true);for(let i of Uo(e,Je)){if(Bt.add(i.issuedBy),X.set(i.fp,{...i,observedReal:r}),X.size>qo){let s=X.keys().next().value;s!==void 0&&X.delete(s)}if(n=true,i.cookie){let s={location:"cookie",name:i.cookie,fp:i.fp,info:i.info},a=Ye(t,s),l=C.get(a);l?Ge(l,i.fp,i.info,r,e.timestamp):(C.set(a,Ut(a,t,s,r,e.timestamp)),Wt());continue}for(let s of C.values())s.fp===i.fp&&Ge(s,i.fp,s.info,r,s.lastUsedApp)}n&&le()}function ri(e){let t=e;!t||typeof t.id!="string"||typeof t.url!="string"||(Ht(Zo,t.id)&&ei(t),t.status!==void 0&&Ht(Yo,t.id)&&ti(t))}function ve(){if(qe)return true;try{let{networkEventStore:e}=go("@buoy-gg/network");if(!e?.onEvent)throw new Error("no event store");qe=e.onEvent(ri,true),xe=true}catch{xe=false}return le(),xe}function Jt(e,t,r){let n=C.get(t);if(!n)throw new Error(`No token row "${t}".`);return p={kind:e,tokenId:t,startedAt:T(),startFp:n.fp,ruleId:r,status:"waiting",newTokens:0,staleAfterFailure:0,failedRefreshes:0},le(),p}function ni(){p=null,le()}function oi(e){return e.location==="cookie"?`${e.name} cookie`:e.location==="query"?`${e.name} parameter`:e.location==="header"?`${e.name} header`:e.role==="id"||e.info.claims.use==="id"?"ID token":"Access token"}function ii(e,t){let r=[e.firstSeenReal,...e.history.map(o=>o.firstSeenReal)].slice(0,-1).filter(o=>t-o<=Ft).length,n=e.info.issuedAt;return{id:e.key,label:oi(e),host:e.host,location:e.location,name:e.name,scheme:e.scheme,format:e.info.format,formatLabel:e.info.formatLabel,hint:e.info.hint,claims:e.info.claims,fingerprint:e.fp,issuedAt:n,notBefore:e.info.notBefore,expiresAt:e.expiresAt,serverExpiresAt:e.serverExpiresAt,expirySource:e.expirySource,lifetimeMs:e.lifetimeMs,neverExpires:e.info.neverExpires,issuedBy:e.issuedBy,refresh:e.refresh?{expiresAt:e.refresh.expiresAt,formatLabel:e.refresh.formatLabel}:void 0,firstUsed:e.firstSeenApp,lastUsed:e.lastUsedApp,lastUsedReal:e.lastUsedReal,uses:e.uses,refreshes:e.history.length,lastRefreshAt:e.history.length?e.firstSeenReal:void 0,recentRefreshes:r,looping:r>=_t,expiredSends:e.expiredSends,rejected:e.rejected}}function we(){let e=T(),t=[...C.values()].sort((r,n)=>n.lastUsedReal-r.lastUsedReal).map(r=>ii(r,e));if(p?.status==="refreshed"){let r=C.get(p.tokenId);r&&(p.newLifetimeMs=r.lifetimeMs,p.newIssuedBy=r.issuedBy)}return{available:xe,watching:qe!==null,tokens:t,check:p?{...p}:null}}function si(e){let t=we();return e?t.tokens.find(r=>r.id===e)??null:t.tokens.find(r=>r.expiresAt!==void 0)??t.tokens[0]??null}function ai(e){return C.get(e)?.origin??null}var m={anchor:Re,settings:ie,lastJump:null,changedAt:null,hydrated:false},Xe=new Set,Ae=null;function qt(){Ae=null,Xe.forEach(e=>e())}Xo(qt);function ce(e){return Xe.add(e),()=>{Xe.delete(e)}}function li(){return m.settings}function Kt(){return L(m.anchor,T())}function Zt(){return m.anchor.mode!=="real"}function ci(e){if(e.mode==="real"){At(null),ro();return}Rt(),At(t=>L(m.anchor,t)),to()}function ui(){let e={v:1,anchor:m.settings.persist?m.anchor:null,settings:m.settings};mo(e)}function Q(e,{save:t=true}={}){m={...m,...e},e.anchor&&ci(m.anchor),t&&ui(),qt()}function ee(e,t=m.lastJump){Q({anchor:e,lastJump:t,changedAt:T(),hydrated:true})}var Yt=e=>A.parse(e);function Gt(e,t=false){let r=T(),n=L(m.anchor,r),o=kt(e,n,Yt),i=o-n;return ee(De(m.anchor,r,o,t),{byMs:i,firedTimers:0,at:r}),$()}function Qe(e,t){let r=Ee(e),n=T(),o=Vn(m.anchor,n,r),i=(t??m.settings.fireTimersOnJump)&&r>0;if(ee(o,{byMs:r,firedTimers:0,at:n}),i){let s=uo(r);s>0&&Q({lastJump:{byMs:r,firedTimers:s,at:n}},{save:false})}return $()}function et(e){let t=T(),r=L(m.anchor,t),n=e===void 0||e===""?r:kt(e,r,Yt);return ee(Un(m.anchor,t,n)),$()}function tt(){return m.anchor.mode==="frozen"&&ee(Wn(m.anchor,T())),$()}function Xt(e){return ee(Jn(m.anchor,T(),Number(e))),$()}function rt(){return ee(Re,null),$()}function Qt(e){let t={...m.settings};for(let r of Object.keys(ie))typeof e[r]=="boolean"&&(t[r]=e[r]);return Q({settings:t}),$()}function fi(e){return e>0?co(e):0}var er=false;function tr(e){if(!e){Q({hydrated:true},{save:false});return}Q({settings:e.settings,anchor:e.anchor??Re,changedAt:e.anchor?T():null,hydrated:true},{save:false})}function nt(){if(er)return;er=true,Rt();let e=void 0;if(e!==void 0){tr(e);return}ho().then(t=>{m.changedAt===null?tr(t):Q({hydrated:true},{save:false})})}function di(){try{return Intl.DateTimeFormat().resolvedOptions().timeZone??"unknown"}catch{return"unknown"}}function $(){let e=T(),t=L(m.anchor,e);return{mode:m.anchor.mode,active:m.anchor.mode!=="real",rate:m.anchor.rate,virtualNow:t,virtualIso:new A(t).toISOString(),realNow:e,offsetMs:Hn(m.anchor,e),timeZone:di(),timers:lo(),lastJump:m.lastJump,changedAt:m.changedAt,settings:m.settings,hydrated:m.hydrated,tokens:we(),patched:{date:Zn(),intl:eo(),timers:ao(),animatedOnRealClock:io()}}}function rr(){return Ae||(Ae=$()),Ae}import{useSyncExternalStore as pi}from"react";import{ClockToolIcon as nr,FloatingTool as hi,Pause as mi,Play as yi,X as gi,dismissFloatingTool as bi,getFloatingTools as ki,night as ue,openFloatingTool as or}from"@buoy-gg/shared-ui/web";import{useEffect as xi,useState as vi}from"react";function V(e,t=250){let[,r]=vi(0);xi(()=>{let s=setInterval(()=>r(a=>a+1),t);return()=>clearInterval(s)},[t]);let n=T();if(!e)return{virtual:n,real:n};let o=n-e.realNow,i=e.mode==="real"?1:e.rate;return{virtual:e.mode==="frozen"?e.virtualNow:e.virtualNow+o*i,real:n}}var M=e=>String(e).padStart(2,"0");function fe(e){let t=new A(e);return`${M(t.getHours())}:${M(t.getMinutes())}:${M(t.getSeconds())}`}var wi=["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],ir=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];function Ai(e){let t=new A(e);return`${wi[t.getDay()]}, ${ir[t.getMonth()]} ${t.getDate()}, ${t.getFullYear()}`}function Te(e,t=true){let r=new A(e),n=t?fe(e):`${M(r.getHours())}:${M(r.getMinutes())}`;return`${ir[r.getMonth()]} ${r.getDate()} \xB7 ${n}`}function sr(e){let t=new A(e);return`${t.getFullYear()}-${M(t.getMonth()+1)}-${M(t.getDate())} ${M(t.getHours())}:${M(t.getMinutes())}`}function Ti(e){if(Math.abs(e)<1e3)return"matches real time";let t=te(Math.abs(e),{signed:false});return e>0?`${t} ahead of real time`:`${t} behind real time`}function ar(e){return e.mode==="real"?{label:"Real time",tone:"neutral"}:e.mode==="frozen"?{label:"Frozen",tone:"info"}:e.rate!==1?{label:`${vt(e.rate)} speed`,tone:"warning"}:{label:"Overridden",tone:"accent"}}function Si(e){return`clock-jump-${e<0?"minus":"plus"}-${te(Math.abs(e),{signed:false}).replace(/\s/g,"")}`}import{jsx as N,jsxs as ot}from"react/jsx-runtime";var Se="clock-chip",lr={id:Se,render:e=>N(ur,{...e})},$i=()=>ki().some(e=>e.id===Se);function Ii(){or(lr)}var cr=false;function Ri(){if(cr)return;cr=true;let e=false,t=()=>{let r=Zt()&&li().showChip;r&&!e?or(lr):!r&&$i()&&bi(Se),e=r};ce(t),t()}function ur({id:e,revealToken:t}){let r=pi(ce,rr,rr),{virtual:n,real:o}=V(r),i=r.mode==="frozen",s=ar(r),a=n-o,l=`${Math.abs(a)<1e3?"0s":te(a)} \xB7 ${s.label.toLowerCase()}`;return N(hi,{id:e,revealToken:t,variant:"strip",dragFromSurface:true,defaultPlacement:"top",accessibilityLabel:`Move or hide the clock chip. App time ${Te(n)}`,handleAdornment:N(nr,{size:12}),children:ot(h,{style:q.row,children:[N(nr,{size:18}),ot(h,{style:q.text,children:[N(g,{style:q.time,numberOfLines:1,testID:"clock-chip-time",children:Te(n)}),N(g,{style:q.detail,numberOfLines:1,testID:"clock-chip-detail",children:l})]}),ot(F,{testID:i?"clock-chip-resume":"clock-chip-freeze",accessibilityRole:"button",accessibilityLabel:i?"Resume the app clock":"Freeze the app clock",onPress:()=>i?tt():et(),style:q.button,hitSlop:{top:8,bottom:8,left:4,right:4},children:[i?N(yi,{size:16,color:ue.color.accent}):null,i?null:N(mi,{size:16,color:ue.color.text})]}),N(h,{style:q.separator}),N(F,{testID:"clock-chip-reset",accessibilityRole:"button",accessibilityLabel:"Back to real time",onPress:()=>rt(),style:q.button,hitSlop:{top:8,bottom:8,left:4,right:8},children:N(gi,{size:16,color:ue.color.textSecondary})})]})})}var q=Y.create({row:{flexDirection:"row",alignItems:"center",gap:10,paddingLeft:10,paddingRight:4,paddingVertical:6,minWidth:220},text:{flexShrink:1,minWidth:120},time:{color:"#F59E0B",fontSize:14,fontWeight:"600",fontVariant:["tabular-nums"]},detail:{color:ue.color.textSecondary,fontSize:11,fontVariant:["tabular-nums"]},button:{width:32,height:32,alignItems:"center",justifyContent:"center",borderRadius:16},separator:{width:Y.hairlineWidth,height:20,backgroundColor:ue.color.separator}});import{ClockToolIcon as Oi,CLOCK_TOOL_ICON_COLOR as Ci,createToolFactory as Di,defineToolPreset as Ei}from"@buoy-gg/shared-ui/web";import{useEffect as fr,useState as zi}from"react";import{reloadApp as Ni}from"@buoy-gg/shared-ui/web";import{createSyncAdapter as ji}from"@buoy-gg/shared-ui/web";import{dispatchToolAction as dr}from"@buoy-gg/shared-ui/web";var pr="No sign-in token seen yet. Use the app so it sends a signed-in request, then try again. Tokens are read from the Network tool's captured requests.";function hr(e){ve();let t=si(e);if(!t)throw new Error(e?`No token "${e}". Read getState for the current ids.`:pr);return t}function mr(e,t=1e4){let r=hr(e);if(r.expiresAt===void 0)throw new Error(r.neverExpires?`${r.label} for ${r.host} is ${r.hint??"a key"} and never expires.`:`${r.label} for ${r.host} (${r.formatLabel}) has no expiry Buoy can read. Use failNextRequest to test the refresh instead.`);let n=r.expiresAt-Math.max(0,t)-Kt();if(n<=0)throw new Error(`${r.label} for ${r.host} has already expired on the app's clock. Go back to real time, or use failNextRequest.`);return Qe(n),Jt("expiry",r.id),$()}async function yr(e,t=401,r=1){let n=hr(e),o=ai(n.id);if(!o)throw new Error(pr);await gr();let i=t===403?403:401,s=n.location==="authorization"||n.location==="header"?{urlPattern:`${o}/*`,requireHeader:n.name.toLowerCase()}:n.location==="query"?{urlPattern:`${o}/*${n.name}=*`}:{urlPattern:`${o}/*`},a=await dr("network","upsertOverrideRule",{name:"Clock: force a token refresh",...s,kind:"respond",status:i,headers:{"content-type":"application/json","www-authenticate":'Bearer error="invalid_token", error_description="The access token expired"'},body:JSON.stringify({error:"invalid_token",error_description:"The access token expired (forced by Buoy Clock to test token refresh)"}),times:Math.max(1,Math.min(10,Math.round(r)))}).catch(l=>{let c=l instanceof Error?l.message:String(l);throw new Error(c.includes("Unknown tool")?"Failing a request needs the Network tool (@buoy-gg/network).":c)});if(!a?.ok||!a.rule)throw new Error(a?.error??"Network did not add the override.");return Jt("401",n.id,a.rule.id),$()}async function gr(){let e=we().check;e?.ruleId&&e.forcedAt===void 0&&await dr("network","deleteOverrideRule",{id:e.ruleId}).catch(()=>{})}async function br(){return await gr(),ni(),$()}function K(e){return e&&typeof e=="object"?e:{}}function it(e,...t){for(let r of t){let n=e[r];if(typeof n=="string"||typeof n=="number")return n}}function de(e,t){let r=e[t];if(typeof r=="boolean")return r;if(r==="true")return true;if(r==="false")return false}var kr=ji({version:1,getSnapshot(){return $()},subscribe(e){return ce(e)},actions:{getState(){return ve(),$()},setTime(e){let t=K(e),r=it(t,"time","at","date","iso");if(r===void 0)throw new Error('setTime needs `time`: ISO 8601 ("2026-12-31T23:59:50"), epoch ms, or relative ("+1d").');return Gt(r,de(t,"freeze")??false)},shift(e){let t=K(e),r=it(t,"by","ms","duration","delta");if(r===void 0)throw new Error('shift needs `by`: a duration like "+1d", "-2h30m", "90s", or ms.');return Qe(r,de(t,"fireTimers"))},freeze(e){return et(it(K(e),"time","at"))},resume(){return tt()},setRate(e){let t=K(e),r=Number(t.rate??t.speed);if(!Number.isFinite(r))throw new Error("setRate needs a numeric `rate` (1 = normal speed).");return Xt(r)},reset(){return rt()},updateSettings(e){let t=K(e);return Qt({persist:de(t,"persist"),showChip:de(t,"showChip"),fireTimersOnJump:de(t,"fireTimersOnJump")})},jumpToTokenExpiry(e){let t=K(e),r=typeof t.token=="string"?t.token:typeof t.id=="string"?t.id:void 0,n=Number(t.leadMs??t.lead??1e4);return mr(r,Number.isFinite(n)?n:1e4)},failNextRequest(e){let t=K(e),r=typeof t.token=="string"?t.token:typeof t.id=="string"?t.id:void 0,n=Number(t.status??401),o=Number(t.times??1);return yr(r,n,Number.isFinite(o)?o:1)},stopTokenCheck(){return br()}}});import{useState as st}from"react";import{ChevronRight as Li,NightButton as Pi,NightCard as $e,NightChip as Mi,NightFootnote as at,NightRows as lt,NightSectionLabel as xr,NightSegmented as _i,NightSwitch as vr,monoFont as Fi,night as y,useSafeAreaInsets as Bi}from"@buoy-gg/shared-ui/web";import{ChevronRight as Hi,NightButton as wr,NightCard as Vi,NightFootnote as Ui,NightRows as Wi,NightSectionLabel as Ji,night as b}from"@buoy-gg/shared-ui/web";import{jsx as v,jsxs as _}from"react/jsx-runtime";var U=e=>te(Math.abs(e),{signed:false});function qi({snapshot:e,run:t,openId:r,onToggle:n}){let o=e.tokens;return _(h,{children:[v(Ji,{children:o.tokens.length>1?"Sign-in tokens":"Sign-in token"}),v(Vi,{children:_(Wi,{children:[o.tokens.map((i,s)=>_(h,{children:[v(Ki,{token:i,snapshot:e,index:s,open:r===i.id,onPress:()=>n(i.id)}),r===i.id?v(Zi,{token:i,snapshot:e,run:t}):null]},i.id)),o.tokens.length===0?v(h,{style:k.row,testID:"clock-token-empty",children:v(g,{style:k.emptyText,children:o.available?"No token seen yet":"Needs the Network tool"})},"empty"):null]})}),v(Gi,{check:o.check,tokens:o.tokens,snapshot:e,run:t}),o.tokens.length===0?v(Ui,{children:o.available?"Tokens show up here when the app sends a signed-in request.":"Install @buoy-gg/network so the Clock tool can read the app's tokens."}):null]})}function Ki({token:e,snapshot:t,index:r,open:n,onPress:o}){let{virtual:i}=V(t,1e3),s=e.expiresAt!==void 0?e.expiresAt-i:void 0,a=e.neverExpires?"No expiry":s===void 0?"Unknown":s<=0?"Expired":U(s),l=s!==void 0&&s<=0?k.valueDanger:s!==void 0&&s<6e4?k.valueWarning:null;return _(F,{testID:`clock-token-${r}`,accessibilityRole:"button",accessibilityLabel:`${e.label} for ${e.host}: ${s!==void 0&&s>0?`expires in ${a}`:a}`,accessibilityState:{expanded:n},activeOpacity:.6,onPress:o,style:k.row,children:[_(h,{style:k.rowText,children:[v(g,{style:k.rowTitle,numberOfLines:1,children:e.label}),v(g,{style:k.rowSubtitle,numberOfLines:1,children:`${e.host} \xB7 ${e.hint??e.formatLabel}`})]}),_(h,{style:k.rowRight,children:[v(g,{style:[k.value,l],testID:`clock-token-${r}-left`,children:a}),v(h,{style:n?k.chevronOpen:null,children:v(Hi,{size:16,color:b.color.textTertiary})})]})]})}function Zi({token:e,snapshot:t,run:r}){let{virtual:n,real:o}=V(t,1e3),i=Yi(e,n,o),s=e.expiresAt!==void 0&&e.expiresAt-n>1e4;return _(h,{style:k.detail,testID:"clock-token-detail",children:[i.map(a=>v(g,{style:[k.detailLine,a.tone==="warn"?k.warn:null,a.tone==="bad"?k.bad:null],children:a.text},a.text)),_(h,{style:k.buttons,children:[v(h,{style:k.button,children:v(wr,{label:"Jump to Expiry",testID:"clock-token-jump",accessibilityLabel:"Jump the app's clock to ten seconds before this token expires",size:"md",disabled:!s,onPress:()=>r("jumpToTokenExpiry",{token:e.id})})}),v(h,{style:k.button,children:v(wr,{label:"Fail Next Request",testID:"clock-token-fail",accessibilityLabel:"Answer the app's next request to this API with 401",size:"md",onPress:()=>r("failNextRequest",{token:e.id})})})]}),v(g,{style:k.hint,children:s||e.expiresAt===void 0?"Jump tests an app that refreshes before expiry. Fail tests one that refreshes after a 401.":"This token has already expired on the app's clock. Use Real Time to jump to it again."})]})}function Yi(e,t,r){let n=[];if(e.expiresAt!==void 0){if(n.push({text:`Expires ${Te(e.expiresAt)}`}),e.lifetimeMs!==void 0&&e.lifetimeMs>0&&n.push({text:`Lasts ${U(e.lifetimeMs)}${e.expirySource?`, from ${e.expirySource}`:""}`}),e.serverExpiresAt!==void 0){let o=e.expiresAt-t,i=e.serverExpiresAt-r;Math.abs(o-i)>2e3&&n.push({text:i>0?`The server still accepts it for ${U(i)}`:`The server stopped accepting it ${U(i)} ago`})}}else e.neverExpires||n.push({text:"The token doesn't say when it expires, and no login response did either."});if(e.hint&&n.push({text:e.formatLabel}),e.issuedBy&&n.push({text:`Issued by ${e.issuedBy}`}),e.refresh?.expiresAt!==void 0){let o=e.refresh.expiresAt-t;n.push({text:o>0?`Refresh token expires in ${U(o)}`:"Refresh token expired"})}return e.refreshes>0&&e.lastRefreshAt!==void 0&&n.push({text:`Refreshed ${e.refreshes===1?"once":`${e.refreshes} times`}, last at ${fe(e.lastRefreshAt)}`}),n.push({text:`Sent with ${e.uses} request${e.uses===1?"":"s"}`}),e.expiredSends>0&&n.push({text:`Sent ${e.expiredSends} time${e.expiredSends===1?"":"s"} after it expired on the app's clock`,tone:"warn"}),e.rejected>0&&n.push({text:`Rejected by the server ${e.rejected} time${e.rejected===1?"":"s"}`,tone:"warn"}),e.looping&&n.push({text:`Refresh loop: ${e.recentRefreshes} new tokens in 20s`,tone:"bad"}),n}function Gi({check:e,tokens:t,snapshot:r,run:n}){let{virtual:o,real:i}=V(r,1e3);if(!e)return null;let s=t.find(c=>c.id===e.tokenId),{text:a,tone:l}=Xi(e,s,o,i);return _(h,{style:k.check,children:[v(g,{style:[k.checkText,l==="good"?k.good:null,l==="bad"?k.bad:null,l==="warn"?k.warn:null],testID:"clock-token-check",children:a}),v(F,{testID:"clock-token-check-done",accessibilityRole:"button",accessibilityLabel:e.status==="waiting"?"Stop the refresh check":"Dismiss",onPress:()=>n("stopTokenCheck"),hitSlop:{top:8,bottom:8,left:8,right:8},children:v(g,{style:k.checkDone,children:e.status==="waiting"?"Stop":"Done"})})]})}function Xi(e,t,r,n){if(e.status==="loop")return{text:`Refresh loop: ${e.newTokens} new tokens since the check started. The new tokens may already look expired to the app's clock.`,tone:"bad"};if(e.status==="refreshed"){let a=e.newIssuedBy?` by ${e.newIssuedBy}`:"",l=e.newLifetimeMs&&e.newLifetimeMs>0?`. The new token lasts ${U(e.newLifetimeMs)}`:"",c=e.kind==="401"&&e.forcedAt!==void 0?"The app got the 401 and refreshed":"Refreshed",u=e.failedRefreshes>0?` ${e.failedRefreshes===1?"One token request":`${e.failedRefreshes} token requests`} failed first (${e.lastRefreshError}).`:"";return{text:`${c} at ${fe(e.refreshedAt??n)}${a}${l}.${u}`,tone:u?"warn":"good"}}let o=n-e.startedAt,i=(e.staleAfterFailure>0?` It sent the old token again ${e.staleAfterFailure} time${e.staleAfterFailure===1?"":"s"}.`:"")+(e.failedRefreshes>0?` Its token request failed (${e.lastRefreshError}).`:"");if(o>6e4)return{text:`No new token after ${U(o)}. The app may refresh on its next action, or not at all.${i}`,tone:"warn"};if(e.kind==="401")return e.forcedAt===void 0?{text:`The next request to ${t?.host??"the API"} will get a 401. Use the app to send one.`}:{text:`The app got the 401. Waiting for a new token\u2026${i}`,tone:i?"warn":void 0};let s=t?.expiresAt!==void 0?t.expiresAt-r:void 0;return s!==void 0&&s>0?{text:`Expires in ${U(s)} on the app's clock. Waiting for a new token\u2026`}:{text:"Expired on the app's clock. Waiting for the app's next request\u2026"}}var k=Y.create({row:{flexDirection:"row",alignItems:"center",justifyContent:"space-between",gap:12,minHeight:56,paddingHorizontal:b.rowPadH,paddingVertical:10},rowText:{flex:1,minWidth:0},rowTitle:{color:b.color.text,fontSize:b.font.row},rowSubtitle:{color:b.color.textTertiary,fontSize:b.font.caption,marginTop:2},rowRight:{flexDirection:"row",alignItems:"center",gap:6},value:{color:b.color.textSecondary,fontSize:b.font.row,fontVariant:["tabular-nums"]},valueWarning:{color:b.color.warning},valueDanger:{color:b.color.danger},chevronOpen:{transform:[{rotate:"90deg"}]},emptyText:{color:b.color.textSecondary,fontSize:b.font.row},detail:{paddingHorizontal:b.rowPadH,paddingBottom:14,gap:4},detailLine:{color:b.color.textSecondary,fontSize:b.font.caption},buttons:{flexDirection:"row",gap:8,marginTop:8},button:{flex:1},hint:{color:b.color.textTertiary,fontSize:b.font.caption,marginTop:6},check:{flexDirection:"row",alignItems:"flex-start",gap:12,marginTop:8,marginHorizontal:b.labelInset},checkText:{flex:1,color:b.color.textSecondary,fontSize:b.font.caption,lineHeight:18},checkDone:{color:b.color.accent,fontSize:b.font.caption,fontWeight:"600"},good:{color:b.color.accent},warn:{color:b.color.warning},bad:{color:b.color.danger}});import{jsx as f,jsxs as S}from"react/jsx-runtime";var Ar="#F59E0B";function Tr({snapshot:e,onAction:t,onReload:r}){let n=Bi({minBottom:16}),[o,i]=st(null),[s,a]=st(null),l=(u,x)=>{i(null),t(u,x).catch(w=>{i(w instanceof Error?w.message:String(w))})},c=u=>a(x=>x===u?null:u);return e?S(bt,{style:d.fill,contentContainerStyle:[d.content,{paddingBottom:n.bottom}],testID:"clock-scroll",keyboardShouldPersistTaps:"handled",children:[f(Qi,{snapshot:e}),o?f(at,{tone:"danger",centered:true,children:f(g,{testID:"clock-error",children:o})}):null,S(h,{children:[f(xr,{children:"Jump ahead"}),f(ts,{run:l})]}),S(h,{children:[f($e,{children:S(lt,{children:[S(h,{children:[f($r,{title:"Date & Time",testID:"clock-date-row",open:s==="date",onPress:()=>c("date"),value:f(rs,{snapshot:e})}),s==="date"?f(os,{snapshot:e,run:l,onDone:()=>a(null)}):null]},"date"),S(h,{style:d.row,children:[f(g,{style:d.rowTitle,children:"Freeze"}),f(vr,{value:e.mode==="frozen",testID:"clock-freeze",accessibilityLabel:"Freeze the clock",onValueChange:u=>l(u?"freeze":"resume")})]},"freeze"),S(h,{children:[f($r,{title:"Speed",testID:"clock-speed-row",open:s==="speed",onPress:()=>c("speed"),value:f(g,{style:d.rowValue,children:Or(e)})}),s==="speed"?f(is,{snapshot:e,run:l}):null]},"speed")]})}),f(at,{children:"Only this app's clock changes. Screens pick up the new time when they next render, or all at once when you reload."})]}),e.tokens?f(qi,{snapshot:e,run:l,openId:s,onToggle:c}):null,f($e,{children:S(lt,{children:[r?f(Ir,{label:"Reload App",testID:"clock-reload",onPress:r},"reload"):null,f(Ir,{label:"Use Real Time",accessibilityLabel:"Reset to real time",testID:"clock-reset",destructive:true,disabled:e.mode==="real",onPress:()=>l("reset")},"reset")]})}),S(h,{children:[f(xr,{children:"Options"}),f(as,{settings:e.settings,run:l})]})]}):f(h,{style:d.waiting,testID:"clock-waiting",children:f(at,{centered:true,children:"Waiting for the app's clock\u2026"})})}function Qi({snapshot:e}){let{virtual:t,real:r}=V(e),n=ar(e),o=e.mode!=="real",i=Ti(t-r),s=e.mode==="frozen"?" \xB7 Frozen":o&&e.rate!==1?` \xB7 ${Or(e)}`:"";return S(h,{style:d.hero,children:[f(g,{style:[d.heroTime,o?d.heroTimeActive:null],testID:"clock-hero-time",accessibilityLabel:`App clock ${fe(t)}`,children:fe(t)}),f(g,{style:d.heroDate,testID:"clock-hero-date",children:Ai(t)}),f(h,{testID:"clock-status",accessibilityLabel:`Clock status: ${n.label}${o?`, ${i}`:""}`,children:f(g,{style:[d.heroStatus,o?d.heroStatusActive:null],testID:"clock-offset",children:o?`${i}${s}`:"Real time"})})]})}var Sr=36e5,ct=24*Sr,es=[{ms:Sr,unit:"hour"},{ms:ct,unit:"day"},{ms:7*ct,unit:"week"},{ms:30*ct,unit:"month"}];function ts({run:e}){return f($e,{style:d.jumpBar,children:es.map((t,r)=>S(F,{testID:Si(t.ms),accessibilityRole:"button",accessibilityLabel:`Jump ahead one ${t.unit}`,activeOpacity:.6,onPress:()=>e("shift",{by:t.ms}),style:[d.jump,r>0?d.jumpDivider:null],children:[f(g,{style:d.jumpAmount,children:"+1"}),f(g,{style:d.jumpUnit,children:t.unit})]},t.unit))})}function $r({title:e,value:t,open:r,onPress:n,testID:o}){return S(F,{testID:o,accessibilityRole:"button",accessibilityLabel:e,accessibilityState:{expanded:r},activeOpacity:.6,onPress:n,style:d.row,children:[f(g,{style:d.rowTitle,children:e}),S(h,{style:d.rowRight,children:[t,f(h,{style:r?d.chevronOpen:null,children:f(Li,{size:16,color:y.color.textTertiary})})]})]})}function rs({snapshot:e}){let{virtual:t}=V(e,1e3);return f(g,{style:[d.rowValue,d.tabular],numberOfLines:1,children:Te(t,false)})}function Ir({label:e,onPress:t,testID:r,destructive:n,disabled:o,accessibilityLabel:i}){return f(F,{testID:r,accessibilityRole:"button",accessibilityLabel:i??e,accessibilityState:{disabled:!!o},activeOpacity:.6,disabled:o,onPress:t,style:[d.row,o?d.rowDisabled:null],children:f(g,{style:[d.actionLabel,n?d.actionDestructive:null],children:e})})}var ns=xt.filter(e=>["midnight","month-end","year-end"].includes(e.id));function os({snapshot:e,run:t,onDone:r}){let[n,o]=st(""),{virtual:i}=V(e,1e3),s=()=>n.trim()||sr(i),a=e.mode==="frozen",l=c=>{t("setTime",{time:c,freeze:a}),r()};return S(h,{style:d.editor,children:[S(h,{style:d.inputRow,children:[f(gt,{testID:"clock-time-input",accessibilityLabel:"Date and time",value:n,onChangeText:o,placeholder:sr(i),placeholderTextColor:y.color.placeholder,autoCapitalize:"none",autoCorrect:false,returnKeyType:"done",onSubmitEditing:()=>l(s()),style:d.input}),f(Pi,{label:"Set",testID:"clock-time-apply",accessibilityLabel:"Set this time",size:"md",variant:"primary",fullWidth:false,onPress:()=>l(s())})]}),f(g,{style:d.hint,children:"Year-month-day and 24-hour time, or +3d, -2h"}),f(h,{style:d.presets,children:ns.map(c=>f(Mi,{label:c.label,testID:`clock-preset-${c.id}`,onPress:()=>l(c.at(i,A))},c.id))})]})}var Rr=[{key:"1",label:"Normal"},{key:"10",label:"10\xD7"},{key:"60",label:"1 min/s"},{key:"3600",label:"1 hr/s"}];function Or(e){return e.mode==="real"||e.rate===1?"Normal":Rr.find(t=>Number(t.key)===e.rate)?.label??vt(e.rate)}function is({snapshot:e,run:t}){let r=e.mode==="real"?"1":String(e.rate);return S(h,{style:d.editor,children:[f(h,{style:d.segmentRow,children:f(_i,{tabs:Rr,activeKey:r,size:"sm",testIDPrefix:"clock-speed",onChange:n=>t("setRate",{rate:Number(n)})})}),f(g,{style:d.hint,children:"Taps, animations and timers keep real speed."})]})}var ss=[{key:"showChip",title:"Show Floating Clock"},{key:"persist",title:"Keep After Reload"}];function as({settings:e,run:t}){return f($e,{children:f(lt,{children:ss.map(r=>S(h,{style:d.row,children:[f(g,{style:d.rowTitle,children:r.title}),f(vr,{value:e[r.key],testID:`clock-setting-${r.key}`,accessibilityLabel:r.title,onValueChange:n=>t("updateSettings",{[r.key]:n})})]},r.key))})})}var d=Y.create({fill:{flex:1},content:{paddingHorizontal:y.gutter,paddingTop:8,gap:y.groupGap},waiting:{flex:1,alignItems:"center",justifyContent:"center",padding:24},hero:{alignItems:"center",paddingTop:12},heroTime:{color:y.color.text,fontSize:56,fontWeight:"200",fontVariant:["tabular-nums"],letterSpacing:1},heroTimeActive:{color:Ar},heroDate:{color:y.color.text,fontSize:17,fontWeight:"500",marginTop:2},heroStatus:{color:y.color.textTertiary,fontSize:y.font.caption,fontWeight:"500",marginTop:6},heroStatusActive:{color:y.color.textSecondary},jumpBar:{flexDirection:"row"},jump:{flex:1,alignItems:"center",paddingVertical:12},jumpDivider:{borderLeftWidth:Y.hairlineWidth,borderLeftColor:y.color.separator},jumpAmount:{color:Ar,fontSize:17,fontWeight:"600",fontVariant:["tabular-nums"]},jumpUnit:{color:y.color.textSecondary,fontSize:y.font.caption,marginTop:1},row:{flexDirection:"row",alignItems:"center",justifyContent:"space-between",gap:12,minHeight:50,paddingHorizontal:y.rowPadH,paddingVertical:10},rowDisabled:{opacity:.4},rowTitle:{color:y.color.text,fontSize:y.font.row},rowRight:{flexDirection:"row",alignItems:"center",gap:6,flexShrink:1},rowValue:{color:y.color.textSecondary,fontSize:y.font.row},tabular:{fontVariant:["tabular-nums"]},chevronOpen:{transform:[{rotate:"90deg"}]},actionLabel:{color:y.color.accent,fontSize:y.font.row},actionDestructive:{color:y.color.danger},editor:{paddingHorizontal:y.rowPadH,paddingBottom:14,gap:10},inputRow:{flexDirection:"row",alignItems:"center",gap:8},input:{flex:1,color:y.color.text,fontFamily:Fi,fontSize:15,backgroundColor:y.color.bg,borderRadius:y.radius.input,borderWidth:1,borderColor:y.color.border,paddingHorizontal:12,paddingVertical:8},hint:{color:y.color.textTertiary,fontSize:y.font.caption},presets:{flexDirection:"row",flexWrap:"wrap",gap:6},segmentRow:{flexDirection:"row"}});import{jsx as ls}from"react/jsx-runtime";var cs=kr.actions;async function us(e,t){let r=cs[e];if(!r)throw new Error(`Unknown clock action: ${e}`);return r(t)}function fs(){Ni("auto","buoy clock").catch(()=>{})}function Cr(){fr(()=>{nt(),ve()},[]);let[e,t]=zi($);return fr(()=>ce(()=>t($())),[]),ls(Tr,{snapshot:e,onAction:us,onReload:fs})}import{jsx as ds}from"react/jsx-runtime";var Dr=Ei({id:"clock",name:"CLOCK",description:"Travel to any date, freeze or speed up the app's clock",slot:"both",color:Ci,icon:({size:e,color:t})=>ds(Oi,{size:e,color:t}),component:Cr,modal:{subtitle:"override the app's date & time"}}),ps=Di(Dr);import{ClockToolIcon as hs,CLOCK_TOOL_ICON_COLOR as ms}from"@buoy-gg/shared-ui/web";var ys=typeof navigator<"u"&&navigator.product==="ReactNative";ys&&(oo(yt),Ri(),typeof ht<"u"&&ht&&nt());export{Se as CLOCK_CHIP_ID,ms as CLOCK_TOOL_ICON_COLOR,Cr as ClockBody,ur as ClockChip,hs as ClockToolIcon,Tr as ClockToolView,xt as TIME_PRESETS,nt as bootClock,kr as clockSyncAdapter,Dr as clockToolPreset,ps as createClockTool,yr as failNextRequest,te as formatDuration,et as freeze,$ as getClockSnapshot,we as getTokenReport,be as inspectToken,Zt as isClockOverridden,mr as jumpToTokenExpiry,Ii as openClockChip,Ee as parseDuration,fi as previewJump,T as realNow,rt as reset,tt as resume,Xt as setRate,Gt as setTime,Qe as shift,ve as startTokenWatch,br as stopTokenCheck,ce as subscribeClock,H as tokenFingerprint,Qt as updateSettings,V as useLiveClock,Kt as virtualNow,Le as withRealClock};
|
package/package.json
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@buoy-gg/clock",
|
|
3
|
+
"version": "7.0.42",
|
|
4
|
+
"description": "Clock override for React Native: travel to any date, freeze or speed up time, and jump ahead while firing due timers. Test expirations, countdowns and renewals without touching the device clock.",
|
|
5
|
+
"main": "lib/commonjs/index.js",
|
|
6
|
+
"module": "lib/module/index.js",
|
|
7
|
+
"types": "lib/typescript/index.d.ts",
|
|
8
|
+
"react-native": "lib/module/index.js",
|
|
9
|
+
"source": "src/index.tsx",
|
|
10
|
+
"files": [
|
|
11
|
+
"lib"
|
|
12
|
+
],
|
|
13
|
+
"sideEffects": [
|
|
14
|
+
"./src/index.tsx",
|
|
15
|
+
"./lib/commonjs/index.js",
|
|
16
|
+
"./lib/module/index.js",
|
|
17
|
+
"./lib/web/**/*.mjs"
|
|
18
|
+
],
|
|
19
|
+
"dependencies": {
|
|
20
|
+
"@buoy-gg/shared-ui": "^7.0.42"
|
|
21
|
+
},
|
|
22
|
+
"peerDependencies": {
|
|
23
|
+
"react": "*",
|
|
24
|
+
"react-native": "*",
|
|
25
|
+
"react-native-web": "^0.21.0",
|
|
26
|
+
"react-dom": ">=18"
|
|
27
|
+
},
|
|
28
|
+
"devDependencies": {
|
|
29
|
+
"@types/react": "^19.1.0",
|
|
30
|
+
"@types/react-native": "^0.73.0",
|
|
31
|
+
"typescript": "~5.8.3"
|
|
32
|
+
},
|
|
33
|
+
"react-native-builder-bob": {
|
|
34
|
+
"source": "src",
|
|
35
|
+
"output": "lib",
|
|
36
|
+
"targets": [
|
|
37
|
+
"commonjs",
|
|
38
|
+
"module",
|
|
39
|
+
[
|
|
40
|
+
"typescript",
|
|
41
|
+
{
|
|
42
|
+
"project": "tsconfig.build.json"
|
|
43
|
+
}
|
|
44
|
+
]
|
|
45
|
+
]
|
|
46
|
+
},
|
|
47
|
+
"repository": {
|
|
48
|
+
"type": "git",
|
|
49
|
+
"url": "https://github.com/Buoy-gg/buoy.git",
|
|
50
|
+
"directory": "packages/clock"
|
|
51
|
+
},
|
|
52
|
+
"bugs": {
|
|
53
|
+
"url": "https://github.com/LovesWorking/react-native-buoy/issues"
|
|
54
|
+
},
|
|
55
|
+
"homepage": "https://buoy.gg/buoy/latest/docs/tools/clock",
|
|
56
|
+
"publishConfig": {
|
|
57
|
+
"access": "public",
|
|
58
|
+
"tag": "latest"
|
|
59
|
+
},
|
|
60
|
+
"keywords": [
|
|
61
|
+
"react-native",
|
|
62
|
+
"expo",
|
|
63
|
+
"devtools",
|
|
64
|
+
"debugging",
|
|
65
|
+
"react-native-devtools",
|
|
66
|
+
"clock",
|
|
67
|
+
"time-travel",
|
|
68
|
+
"date",
|
|
69
|
+
"mock-date",
|
|
70
|
+
"fake-timers",
|
|
71
|
+
"testing"
|
|
72
|
+
],
|
|
73
|
+
"exports": {
|
|
74
|
+
".": {
|
|
75
|
+
"browser": {
|
|
76
|
+
"types": "./lib/typescript/index.d.ts",
|
|
77
|
+
"default": "./lib/web/index.mjs"
|
|
78
|
+
},
|
|
79
|
+
"import": {
|
|
80
|
+
"types": "./lib/typescript/index.d.ts",
|
|
81
|
+
"default": "./lib/module/index.js"
|
|
82
|
+
},
|
|
83
|
+
"require": {
|
|
84
|
+
"types": "./lib/typescript/index.d.ts",
|
|
85
|
+
"default": "./lib/commonjs/index.js"
|
|
86
|
+
}
|
|
87
|
+
},
|
|
88
|
+
"./web": {
|
|
89
|
+
"types": "./lib/typescript/index.d.ts",
|
|
90
|
+
"default": "./lib/web/index.mjs"
|
|
91
|
+
}
|
|
92
|
+
},
|
|
93
|
+
"peerDependenciesMeta": {
|
|
94
|
+
"react-native": {
|
|
95
|
+
"optional": true
|
|
96
|
+
},
|
|
97
|
+
"react-native-web": {
|
|
98
|
+
"optional": true
|
|
99
|
+
},
|
|
100
|
+
"react-dom": {
|
|
101
|
+
"optional": true
|
|
102
|
+
}
|
|
103
|
+
},
|
|
104
|
+
"scripts": {
|
|
105
|
+
"build": "bob build && pnpm run build:web",
|
|
106
|
+
"typecheck": "tsc --noEmit",
|
|
107
|
+
"clean": "rimraf lib",
|
|
108
|
+
"test": "pnpm run typecheck",
|
|
109
|
+
"postinstall": "echo \"Run pnpm build to compile this package\"",
|
|
110
|
+
"build:web": "node ../../scripts/build-web.mjs clock"
|
|
111
|
+
}
|
|
112
|
+
}
|