@sightspool/sdk 0.3.0 → 0.4.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.
Files changed (37) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/README.md +111 -333
  3. package/SECURITY.md +16 -0
  4. package/dist/index.cjs +159 -1226
  5. package/dist/index.cjs.map +1 -1
  6. package/dist/index.d.cts +20 -41
  7. package/dist/index.d.ts +20 -41
  8. package/dist/index.js +160 -761
  9. package/dist/index.js.map +1 -1
  10. package/dist/release.json +21 -0
  11. package/dist/sdk.global.js +2 -59
  12. package/dist/sdk.global.js.map +1 -1
  13. package/dist/source.json +11 -0
  14. package/package.json +14 -12
  15. package/site/CNAME +1 -0
  16. package/site/demo.html +6 -0
  17. package/site/demo.js +27 -0
  18. package/site/index.html +74 -0
  19. package/site/release.js +20 -0
  20. package/site/releases/0.4.0/2acf3463db7571c459ca01a4516341891bb4c2ec6265962f494ca8b553cc0e9f/release.json +21 -0
  21. package/site/releases/0.4.0/2acf3463db7571c459ca01a4516341891bb4c2ec6265962f494ca8b553cc0e9f/sdk.global.js +3 -0
  22. package/site/releases/0.4.0/2acf3463db7571c459ca01a4516341891bb4c2ec6265962f494ca8b553cc0e9f/sdk.global.js.map +1 -0
  23. package/site/releases/0.4.0/2acf3463db7571c459ca01a4516341891bb4c2ec6265962f494ca8b553cc0e9f/source.json +11 -0
  24. package/site/releases/0.4.0/c21bee307a5c53e3ebb49d21f0f1ef2cce06a4483fa9824122bd6897ad6ca3ac/release.json +21 -0
  25. package/site/releases/0.4.0/c21bee307a5c53e3ebb49d21f0f1ef2cce06a4483fa9824122bd6897ad6ca3ac/sdk.global.js +3 -0
  26. package/site/releases/0.4.0/c21bee307a5c53e3ebb49d21f0f1ef2cce06a4483fa9824122bd6897ad6ca3ac/sdk.global.js.map +1 -0
  27. package/site/releases/0.4.0/c21bee307a5c53e3ebb49d21f0f1ef2cce06a4483fa9824122bd6897ad6ca3ac/source.json +11 -0
  28. package/site/styles.css +69 -0
  29. package/site/trust.html +36 -0
  30. package/dist/chunk-4PADVIIO.js +0 -41
  31. package/dist/chunk-4PADVIIO.js.map +0 -1
  32. package/dist/probe-BNGMQQ5C.js +0 -113
  33. package/dist/probe-BNGMQQ5C.js.map +0 -1
  34. package/dist/prompt-GDFYC75D.js +0 -139
  35. package/dist/prompt-GDFYC75D.js.map +0 -1
  36. package/dist/survey-CICJQ5VI.js +0 -145
  37. package/dist/survey-CICJQ5VI.js.map +0 -1
@@ -0,0 +1,74 @@
1
+ <!doctype html>
2
+ <html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Sightspool research SDK</title><link rel="stylesheet" href="styles.css"></head><body><main class="wrap"><nav aria-label="SDK documentation"><a href="index.html">SDK guide</a><a href="trust.html">Data &amp; security</a><a href="demo.html">Try the SDK</a><a href="https://github.com/sightspool/sdk">GitHub</a></nav><header><h1>@sightspool/sdk</h1></header>
3
+ <p>Embed Sightspool research in your product. The SDK invites website visitors and signed-in users into owner-approved research during User Hours, then opens Sightspool for consent and the interview. It does not capture page content, behavior, form values or analytics.</p>
4
+ <p>This is the <strong>0.4.0 research API</strong>, a deliberate change from the old capture SDK. Install the exact version below and review upgrades before deploying them. Old capture code and documentation are archived in <code>docs/legacy</code>.</p>
5
+ <p>Read the <a href="https://www.sightspool.com/sdk/data-security">data and security guide</a>, inspect the <a href="https://github.com/sightspool/sdk">public source</a>, or try the <a href="https://www.sightspool.com/sdk/demo">isolated SDK demo</a>.</p>
6
+ <h2>npm</h2>
7
+ <pre><code>npm install --save-exact @sightspool/sdk@0.4.0</code></pre>
8
+ <pre><code>import Sightspool from &#x27;@sightspool/sdk&#x27;
9
+
10
+ Sightspool.init({ key: &#x27;YOUR_GO_LIVE_WIDGET_UUID&#x27;, audience: &#x27;all_visitors&#x27; })
11
+ // Optional when a visitor signs in:
12
+ Sightspool.identify(currentUser.id)
13
+
14
+ // On logout (anonymous visitors remain eligible in all_visitors mode):
15
+ Sightspool.identify(null)
16
+
17
+ // When leaving the pages included in your research:
18
+ Sightspool.destroy()</code></pre>
19
+ <p>Choose an explicit <code>audience</code> matching the approved interview plan:</p>
20
+ <p>- <code>all_visitors</code>: anonymous website visitors and signed-in users. Initialize once on the relevant website pages. No identity or login is required; logout continues recruitment as a visitor. - <code>signed_in</code>: only users with a real signed-in session. Initialize in your authenticated app shell and call <code>identify(actualUserId)</code> after authentication resolves. Until then, no request or invitation is made. <code>identify(null)</code> immediately removes invitations on logout.</p>
21
+ <p>There is no default audience. Missing or invalid audience configuration stays idle. <code>identify</code> retains only whether an ID is present; the ID itself is not stored or transmitted. Do not invent IDs for visitors. This client setting controls display; it does not authenticate a participant or change the server-approved research cohort.</p>
22
+ <h2>Script tag</h2>
23
+ <p>For visitors, no authentication integration is needed:</p>
24
+ <pre><code>&lt;script async src=&quot;https://www.sightspool.com/sdk.global.js&quot;
25
+ data-sightspool-key=&quot;YOUR_GO_LIVE_WIDGET_UUID&quot;
26
+ data-sightspool-audience=&quot;all_visitors&quot;&gt;&lt;/script&gt;</code></pre>
27
+ <p>For signed-in-only research, listen for readiness before loading the SDK, then synchronize your actual session:</p>
28
+ <pre><code>&lt;script&gt;
29
+ let sightspoolUserId = null;
30
+ function syncSightspoolUser(userId) {
31
+ sightspoolUserId = userId;
32
+ window.Sightspool?.identify(userId);
33
+ }
34
+ window.addEventListener(&#x27;sightspool:ready&#x27;, () =&gt; {
35
+ window.Sightspool.identify(sightspoolUserId);
36
+ });
37
+ // Call syncSightspoolUser(actualUser.id) when authentication resolves.
38
+ // Call syncSightspoolUser(null) on logout.
39
+ &lt;/script&gt;
40
+ &lt;script async src=&quot;https://www.sightspool.com/sdk.global.js&quot;
41
+ data-sightspool-key=&quot;YOUR_GO_LIVE_WIDGET_UUID&quot;
42
+ data-sightspool-audience=&quot;signed_in&quot;&gt;&lt;/script&gt;</code></pre>
43
+ <p>Go live supplies the correct key and endpoint. Local keys belong to the local Sightspool database and cannot be paired with production. Script installs default to the origin serving the bundle; <code>data-sightspool-endpoint</code> overrides that for a CDN or self-hosted install. npm defaults to <code>https://www.sightspool.com</code>.</p>
44
+ <h2>API</h2>
45
+ <table><tr><th>Method</th><th>Behavior</th></tr><tr><td><code>init({ key, audience, endpoint? })</code></td><td>Start research for the explicit audience; UUID key required. Repeating the same configuration is idempotent. Changing it tears down the previous runtime.</td></tr><tr><td><code>identify(userId)</code></td><td>Enable signed-in eligibility; only its boolean presence stays locally. <code>null</code> clears it; signed-in-only invitations disappear, all-visitors recruitment continues.</td></tr><tr><td><code>pause()</code></td><td>Pause recruitment, abort the current request and remove the launcher.</td></tr><tr><td><code>resume()</code></td><td>Resume recruitment for the configured audience. Does not bypass approval or hours.</td></tr><tr><td><code>destroy()</code></td><td>Remove the launcher, listeners and polling. An already opened interview is not silently ended.</td></tr><tr><td><code>getStatus()</code></td><td><code>not_initialized</code>, <code>signed_out</code>, <code>paused</code>, <code>checking</code>, <code>unavailable</code>, <code>available</code> or <code>error</code>.</td></tr></table>
46
+ <p><code>pause</code> and <code>resume</code> are recruitment controls, not consent to record. Participants still review the offer, eligibility and recording consent in Sightspool. Owners approve the research setup separately. The backend remains authoritative for availability, capacity, signed offers and interview admission.</p>
47
+ <h2>React / Next.js</h2>
48
+ <p>Use a client component on the pages included in your research. Identity is optional for all visitors:</p>
49
+ <pre><code>&#x27;use client&#x27;
50
+ import { useEffect } from &#x27;react&#x27;
51
+ import Sightspool from &#x27;@sightspool/sdk&#x27;
52
+
53
+ export function Research({ userId = null }: { userId?: string | null }) {
54
+ useEffect(() =&gt; {
55
+ Sightspool.init({ key: &#x27;YOUR_GO_LIVE_WIDGET_UUID&#x27;, audience: &#x27;all_visitors&#x27; })
56
+ Sightspool.identify(userId)
57
+ return () =&gt; Sightspool.destroy()
58
+ }, [userId])
59
+ return null
60
+ }</code></pre>
61
+ <p>Optional <code>@sightspool/react</code> 0.2.0 provides <code>SightspoolProvider</code> and research hooks. It requires SDK 0.4.x; see <code>packages/react/README.md</code>. Use one instance per document.</p>
62
+ <h2>Privacy and verification</h2>
63
+ <p>The offer request contains only the public workspace key, a random per-workspace browser-session device token, and the operation name. No user ID, traits, auth secrets, DOM text or page URL is included. Requests use <code>credentials: &#x27;omit&#x27;</code>. Offer requests explicitly suppress the Referer header; Origin and ordinary network metadata still reach the service. No microphone or recording starts on initialization or launcher display.</p>
64
+ <p>Polling occurs at most once per 15-second interval while visible and eligible for the configured audience, plus explicit identity/resume/visibility changes. Only one request is in flight; requests time out after 10 seconds. Identity changes, pause, hidden tabs and destruction invalidate stale responses. Logout removes signed-in-only invitations; all-visitors mode refreshes as a visitor.</p>
65
+ <p>A connection receipt proves that the SDK contacted the configured server. It does not certify your app&#x27;s complete login/logout flow or a successful interview. Test anonymous visits, login, navigation, logout, slow loading and unmounting in both modes. Use Go live for server connection checks. A closed User Hours window can connect without an invitation. Do not fabricate approval or weaken an origin/CSP policy to make it show.</p>
66
+ <h2>Verified script releases</h2>
67
+ <p>Go live generates a versioned, content-addressed script URL with SHA-384 integrity, <code>crossorigin=&quot;anonymous&quot;</code> and <code>referrerpolicy=&quot;no-referrer&quot;</code>. Use those values together. The unversioned script examples above are a convenience URL whose contents can change. To pin a reviewed release, use Go live or the manifest linked from the data and security guide.</p>
68
+ <p>For self-hosting, copy the reviewed bundle and preserve its integrity value. Set <code>data-sightspool-endpoint</code> to the workspace Sightspool origin explicitly, because script auto-init otherwise defaults to the bundle host. Keep your own CSP and nonce requirements; allow only the required script host and Sightspool connection origin.</p>
69
+ <h2>Maintainers</h2>
70
+ <pre><code>pnpm install --frozen-lockfile
71
+ pnpm -r --include-workspace-root build
72
+ pnpm -r --include-workspace-root test
73
+ npm publish --dry-run</code></pre>
74
+ <p>The npm and browser builds share <code>src/research.ts</code>. The Sightspool app copies <code>sdk.global.js</code> from this package and serves <code>research-widget.js</code> as a byte-identical alias for recent internal snippets. Neither build imports the former capture engine. See <code>docs/research-sdk-transition.md</code> for release sequencing. Apache-2.0.</p></main></body></html>
@@ -0,0 +1,20 @@
1
+ (async () => {
2
+ const status = document.getElementById('release-status');
3
+ try {
4
+ const response = await fetch('release.json', {cache:'no-store', credentials:'omit'});
5
+ if (!response.ok) throw Error();
6
+ const release = await response.json();
7
+ if (!/^[a-f0-9]{64}$/.test(release.artifactId) || !/^\d+\.\d+\.\d+$/.test(release.version) || !/^[a-f0-9]{64}$/.test(release.bundle.sha256) || release.bundle.path !== `releases/${release.version}/${release.artifactId}/sdk.global.js`) throw Error();
8
+ status.textContent = `Review build ${release.version} · ${release.sourceDirty ? 'uncommitted source changes' : 'source snapshot recorded'}. Publication status must be checked separately.`;
9
+ const metrics = document.getElementById('release-metrics');
10
+ for (const [label,value] of [['Bundle',`${release.bundle.bytes.toLocaleString()} bytes · ${release.bundle.gzipBytes.toLocaleString()} bytes gzip`],['Runtime dependencies',String(release.runtimeDependencies.length)],['Source commit',release.sourceCommit]]) {
11
+ const dt=document.createElement('dt');dt.textContent=label;const dd=document.createElement('dd');dd.textContent=value;dd.className='hash';metrics.append(dt,dd);
12
+ }
13
+ const directory=release.bundle.path.slice(0,release.bundle.path.lastIndexOf('/')+1);
14
+ const links=document.getElementById('release-links');
15
+ for(const [label,path] of [['Download bundle',release.bundle.path],['Source snapshot',directory+'source.json'],['Release manifest',directory+'release.json']]) {
16
+ const a=document.createElement('a');a.href=path;a.textContent=label;links.append(a,document.createTextNode(' · '));
17
+ }
18
+ document.getElementById('release-json').textContent=JSON.stringify(release,null,2);
19
+ } catch { status.textContent='Release files are unavailable. Build the SDK documentation or check back after publication; no verified download is being offered here.'; }
20
+ })();
@@ -0,0 +1,21 @@
1
+ {
2
+ "schemaVersion": 1,
3
+ "package": "@sightspool/sdk",
4
+ "version": "0.4.0",
5
+ "sourceCommit": "17cd8c97479576076735bd08c0abb436a81d05f2",
6
+ "sourceDirty": false,
7
+ "artifactId": "2acf3463db7571c459ca01a4516341891bb4c2ec6265962f494ca8b553cc0e9f",
8
+ "bundle": {
9
+ "file": "sdk.global.js",
10
+ "path": "releases/0.4.0/2acf3463db7571c459ca01a4516341891bb4c2ec6265962f494ca8b553cc0e9f/sdk.global.js",
11
+ "sha256": "ed80800d20ddd91aebde61c355bb15918c0c5cbd712b91e13604795f2d2a8aa9",
12
+ "integrity": "sha384-kfq0QJNOieKKBsyznFRRW9kAaC5fcXvDzu56zgNsSzbXCVw2aReY66mlq8Fldy6K",
13
+ "bytes": 4902,
14
+ "gzipBytes": 2238
15
+ },
16
+ "source": {
17
+ "file": "source.json",
18
+ "sha256": "256cb05370871f78328d531aa567e9717cc977632e9ebe42bc4a30de1e0e5e46"
19
+ },
20
+ "runtimeDependencies": []
21
+ }
@@ -0,0 +1,3 @@
1
+ var Sightspool=(function(exports){'use strict';var y=Symbol.for("sightspool.research.runtime.v1"),v=()=>typeof window=="undefined"?null:window,l=()=>{var e;return (e=v())==null?void 0:e[y]},a=e=>e.audience==="all_visitors"||e.identified;function h(e){var t;(t=e.button)==null||t.remove(),e.button=null,e.offer=null;}function c(e){var t;e.generation+=1,(t=e.pending)==null||t.abort(),e.pending=null,h(e);}function r(e,t){e.status=t;}async function u(e){if(e.disposed||e.paused||!a(e)||e.pending||document.visibilityState!=="visible")return;let t=e.generation,i=new AbortController;e.pending=i;let d=window.setTimeout(()=>i.abort(),1e4);e.button||r(e,"checking");try{let s=await fetch(e.endpoint+"/widget-offer",{method:"POST",credentials:"omit",cache:"no-store",referrerPolicy:"no-referrer",headers:{"Content-Type":"application/json"},body:JSON.stringify({operation:"offer",key:e.key,device:e.device}),signal:i.signal});if(!s.ok)throw Error("offer unavailable");let n=await s.json();if(e.disposed||t!==e.generation||e.paused||!a(e))return;if(n.available!==!0||typeof n.offer!="string"||!n.offer){h(e),r(e,"unavailable");return}if(e.offer=n.offer,r(e,"available"),e.button)return;let o=document.createElement("button");o.type="button",o.textContent="Talk to the founder \xB7 5 min",o.setAttribute("aria-label","Sightspool: join a five-minute user interview"),o.style.cssText="position:fixed;bottom:20px;right:20px;z-index:2147483000;padding:14px 18px;border:0;border-radius:16px;background:#171717;color:white;font:500 14px system-ui;box-shadow:0 8px 30px #0003;cursor:pointer;max-width:calc(100vw - 40px)",o.onclick=()=>{try{if(e.disposed||e.paused||!a(e)||!e.offer)return;if(e.popup&&!e.popup.closed){e.popup.focus();return}let g=new URLSearchParams({offer:e.offer,device:e.device});e.popup=window.open(e.endpoint+"/interview-widget#"+g,"sightspool-interview","popup,width=520,height=760");}catch(g){}},e.button=o,document.body.appendChild(o);}catch(s){!e.disposed&&t===e.generation&&(h(e),r(e,"error"));}finally{window.clearTimeout(d),e.pending===i&&(e.pending=null);}}function m(e){try{let t=v();if(!t||!e||!/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(e.key)||e.audience!=="all_visitors"&&e.audience!=="signed_in")return;let i=new URL(e.endpoint||"https://www.sightspool.com");if(i.protocol!=="https:"&&!(i.protocol==="http:"&&["localhost","127.0.0.1","[::1]"].includes(i.hostname))||i.username||i.password)return;let d=l();if(d&&d.key===e.key&&d.endpoint===i.origin&&d.audience===e.audience)return;d&&f();let s="";try{s=sessionStorage.getItem("sightspool-widget-device:"+e.key)||"";}catch(o){}if(!/^ss_fcd_[A-Za-z0-9_-]{43}$/.test(s)){let o=crypto.getRandomValues(new Uint8Array(32));s="ss_fcd_"+btoa(String.fromCharCode(...o)).replaceAll("+","-").replaceAll("/","_").replace(/=+$/,"");try{sessionStorage.setItem("sightspool-widget-device:"+e.key,s);}catch(g){}}let n={key:e.key,endpoint:i.origin,audience:e.audience,identified:!1,paused:!1,disposed:!1,generation:0,device:s,offer:null,button:null,popup:null,pending:null,timer:0,visibility:()=>{},status:"signed_out"};t[y]=n,n.visibility=()=>{try{document.visibilityState==="visible"?u(n):(c(n),r(n,n.paused?"paused":a(n)?"unavailable":"signed_out"));}catch(o){}},document.addEventListener("visibilitychange",n.visibility),n.timer=window.setInterval(()=>{u(n);},15e3),a(n)&&u(n);}catch(t){}}function b(e){try{let t=l();if(!t)return;let i=typeof e=="string"&&e.trim().length>0;if(!i&&!t.identified){!t.paused&&a(t)&&u(t);return}c(t),t.identified=i,r(t,t.paused?"paused":a(t)?"unavailable":"signed_out"),a(t)&&!t.paused&&u(t);}catch(t){}}function w(){try{let e=l();e&&(e.paused=!0,c(e),r(e,"paused"));}catch(e){}}function x(){try{let e=l();e&&(e.paused=!1,a(e)||r(e,"signed_out"),u(e));}catch(e){}}function f(){try{let e=l();if(!e)return;e.disposed=!0,c(e),window.clearInterval(e.timer),document.removeEventListener("visibilitychange",e.visibility),delete v()[y];}catch(e){}}function S(){var e,t;try{return (t=(e=l())==null?void 0:e.status)!=null?t:"not_initialized"}catch(i){return "error"}}var p={init:m,identify:b,pause:w,resume:x,destroy:f,getStatus:S};var A=p;try{let e=document.currentScript,t=(e==null?void 0:e.dataset.sightspoolKey)||(e==null?void 0:e.dataset.key),i=e==null?void 0:e.dataset.sightspoolAudience;t&&(i==="all_visitors"||i==="signed_in")&&(p.init({key:t,audience:i,endpoint:(e==null?void 0:e.dataset.sightspoolEndpoint)||new URL(e.src).origin}),e!=null&&e.dataset.userId&&p.identify(e.dataset.userId)),window.SightspoolResearch=p,Promise.resolve().then(()=>window.dispatchEvent(new Event("sightspool:ready")));}catch(e){}
2
+ exports.default=A;exports.destroy=f;exports.getStatus=S;exports.identify=b;exports.init=m;exports.pause=w;exports.resume=x;Object.defineProperty(exports,'__esModule',{value:true});return exports;})({});//# sourceMappingURL=sdk.global.js.map
3
+ //# sourceMappingURL=sdk.global.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/research.ts","../src/index.ts","../src/browser.ts"],"names":["slot","host","current","_a","eligible","r","remove","invalidate","status","value","check","generation","request","timeout","response","result","button","hash","e","init","config","browser","url","previous","destroy","device","bytes","identify","userId","identified","pause","resume","getStatus","_b","src_default","browser_default","script","key","audience"],"mappings":"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","file":"sdk.global.js","sourcesContent":["export type SightspoolConfig = {\n /** Public workspace widget key from Go live (UUID, not an old pk_live key). */\n key: string;\n /** Match the approved research audience. No default that widens recruitment. */\n audience: \"all_visitors\" | \"signed_in\";\n /** Sightspool origin. Defaults to the hosted application. */\n endpoint?: string;\n};\nexport type ResearchStatus =\n | \"not_initialized\" | \"signed_out\" | \"paused\" | \"checking\"\n | \"unavailable\" | \"available\" | \"error\";\n\ntype Runtime = {\n key: string; endpoint: string; audience: SightspoolConfig[\"audience\"]; identified: boolean; paused: boolean;\n disposed: boolean; generation: number; device: string; offer: string | null;\n button: HTMLButtonElement | null; popup: Window | null;\n pending: AbortController | null; timer: number; visibility: () => void;\n status: ResearchStatus;\n};\nconst slot = Symbol.for(\"sightspool.research.runtime.v1\");\ntype Host = Window & { [slot]?: Runtime };\nconst host = (): Host | null => typeof window === \"undefined\" ? null : window as Host;\nconst current = () => host()?.[slot];\nconst eligible = (r: Runtime) => r.audience === \"all_visitors\" || r.identified;\n\nfunction remove(r: Runtime) {\n r.button?.remove(); r.button = null; r.offer = null;\n}\nfunction invalidate(r: Runtime) {\n r.generation += 1; r.pending?.abort(); r.pending = null; remove(r);\n}\nfunction status(r: Runtime, value: ResearchStatus) { r.status = value; }\n\nasync function check(r: Runtime) {\n if (r.disposed || r.paused || !eligible(r) || r.pending || document.visibilityState !== \"visible\") return;\n const generation = r.generation;\n const request = new AbortController();\n r.pending = request;\n const timeout = window.setTimeout(() => request.abort(), 10_000);\n if (!r.button) status(r, \"checking\");\n try {\n const response = await fetch(r.endpoint + \"/widget-offer\", {\n method: \"POST\", credentials: \"omit\", cache: \"no-store\", referrerPolicy: \"no-referrer\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ operation: \"offer\", key: r.key, device: r.device }),\n signal: request.signal,\n });\n if (!response.ok) throw Error(\"offer unavailable\");\n const result = await response.json();\n if (r.disposed || generation !== r.generation || r.paused || !eligible(r)) return;\n if (result.available !== true || typeof result.offer !== \"string\" || !result.offer) {\n remove(r); status(r, \"unavailable\"); return;\n }\n r.offer = result.offer;\n status(r, \"available\");\n if (r.button) return;\n const button = document.createElement(\"button\");\n button.type = \"button\";\n button.textContent = \"Talk to the founder · 5 min\";\n button.setAttribute(\"aria-label\", \"Sightspool: join a five-minute user interview\");\n button.style.cssText = \"position:fixed;bottom:20px;right:20px;z-index:2147483000;padding:14px 18px;border:0;border-radius:16px;background:#171717;color:white;font:500 14px system-ui;box-shadow:0 8px 30px #0003;cursor:pointer;max-width:calc(100vw - 40px)\";\n button.onclick = () => {\n try {\n if (r.disposed || r.paused || !eligible(r) || !r.offer) return;\n if (r.popup && !r.popup.closed) { r.popup.focus(); return; }\n const hash = new URLSearchParams({ offer: r.offer, device: r.device });\n r.popup = window.open(r.endpoint + \"/interview-widget#\" + hash, \"sightspool-interview\", \"popup,width=520,height=760\");\n } catch { /* Host pages remain usable if popups are blocked. */ }\n };\n r.button = button;\n document.body.appendChild(button);\n } catch {\n if (!r.disposed && generation === r.generation) { remove(r); status(r, \"error\"); }\n } finally {\n window.clearTimeout(timeout);\n if (r.pending === request) r.pending = null;\n }\n}\n\n/** Start research for the chosen audience. Signed-in-only waits for identify(). */\nexport function init(config: SightspoolConfig): void {\n try {\n const browser = host();\n if (!browser || !config || !/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(config.key)) return;\n if (config.audience !== \"all_visitors\" && config.audience !== \"signed_in\") return;\n const url = new URL(config.endpoint || \"https://www.sightspool.com\");\n if (url.protocol !== \"https:\" && !(url.protocol === \"http:\" && [\"localhost\", \"127.0.0.1\", \"[::1]\"].includes(url.hostname))) return;\n if (url.username || url.password) return;\n const previous = current();\n if (previous && previous.key === config.key && previous.endpoint === url.origin && previous.audience === config.audience) return;\n if (previous) destroy();\n let device = \"\";\n try { device = sessionStorage.getItem(\"sightspool-widget-device:\" + config.key) || \"\"; } catch {}\n if (!/^ss_fcd_[A-Za-z0-9_-]{43}$/.test(device)) {\n const bytes = crypto.getRandomValues(new Uint8Array(32));\n device = \"ss_fcd_\" + btoa(String.fromCharCode(...bytes)).replaceAll(\"+\", \"-\").replaceAll(\"/\", \"_\").replace(/=+$/, \"\");\n try { sessionStorage.setItem(\"sightspool-widget-device:\" + config.key, device); } catch {}\n }\n const r: Runtime = {\n key: config.key, endpoint: url.origin, audience: config.audience, identified: false, paused: false,\n disposed: false, generation: 0, device, offer: null, button: null,\n popup: null, pending: null, timer: 0, visibility: () => {}, status: \"signed_out\",\n };\n browser[slot] = r;\n r.visibility = () => {\n try {\n if (document.visibilityState === \"visible\") void check(r);\n else { invalidate(r); status(r, r.paused ? \"paused\" : eligible(r) ? \"unavailable\" : \"signed_out\"); }\n } catch {}\n };\n document.addEventListener(\"visibilitychange\", r.visibility);\n r.timer = window.setInterval(() => { void check(r); }, 15_000);\n if (eligible(r)) void check(r);\n } catch { /* Never throw into the host application. */ }\n}\n\n/** Only the presence of an ID is retained. The ID itself is never stored or sent. */\nexport function identify(userId: string | null | undefined): void {\n try {\n const r = current();\n if (!r) return;\n const identified = typeof userId === \"string\" && userId.trim().length > 0;\n if (!identified && !r.identified) { if (!r.paused && eligible(r)) void check(r); return; }\n invalidate(r);\n r.identified = identified;\n status(r, r.paused ? \"paused\" : eligible(r) ? \"unavailable\" : \"signed_out\");\n if (eligible(r) && !r.paused) void check(r);\n } catch {}\n}\nexport function pause(): void {\n try { const r = current(); if (r) { r.paused = true; invalidate(r); status(r, \"paused\"); } } catch {}\n}\nexport function resume(): void {\n try { const r = current(); if (r) { r.paused = false; if (!eligible(r)) status(r, \"signed_out\"); void check(r); } } catch {}\n}\n/** Stop recruitment and remove listeners/UI. Does not end an already opened interview. */\nexport function destroy(): void {\n try {\n const r = current();\n if (!r) return;\n r.disposed = true; invalidate(r);\n window.clearInterval(r.timer);\n document.removeEventListener(\"visibilitychange\", r.visibility);\n delete host()![slot];\n } catch {}\n}\nexport function getStatus(): ResearchStatus {\n try { return current()?.status ?? \"not_initialized\"; } catch { return \"error\"; }\n}\n","// Research is the public SDK. The former capture engine is parked.\nexport { init, identify, pause, resume, destroy, getStatus } from \"./research\";\nexport type { SightspoolConfig, ResearchStatus } from \"./research\";\nimport { init, identify, pause, resume, destroy, getStatus } from \"./research\";\nexport default { init, identify, pause, resume, destroy, getStatus };\n","import api from \"./index\";\nexport * from \"./index\";\nexport default api;\n\ntry {\n const script = document.currentScript as HTMLScriptElement | null;\n const key = script?.dataset.sightspoolKey || script?.dataset.key;\n const audience = script?.dataset.sightspoolAudience;\n if (key && (audience === \"all_visitors\" || audience === \"signed_in\")) {\n api.init({ key, audience, endpoint: script?.dataset.sightspoolEndpoint || new URL(script!.src).origin });\n if (script?.dataset.userId) api.identify(script.dataset.userId);\n }\n // The old research-widget URL is an alias of this bundle, not another runtime.\n (window as Window & { SightspoolResearch?: typeof api }).SightspoolResearch = api;\n Promise.resolve().then(() => window.dispatchEvent(new Event(\"sightspool:ready\")));\n} catch { /* Browser auto-init must not interrupt the client app. */ }\n"]}
@@ -0,0 +1,11 @@
1
+ {
2
+ "files": {
3
+ "src/index.ts": "// Research is the public SDK. The former capture engine is parked.\nexport { init, identify, pause, resume, destroy, getStatus } from \"./research\";\nexport type { SightspoolConfig, ResearchStatus } from \"./research\";\nimport { init, identify, pause, resume, destroy, getStatus } from \"./research\";\nexport default { init, identify, pause, resume, destroy, getStatus };\n",
4
+ "src/browser.ts": "import api from \"./index\";\nexport * from \"./index\";\nexport default api;\n\ntry {\n const script = document.currentScript as HTMLScriptElement | null;\n const key = script?.dataset.sightspoolKey || script?.dataset.key;\n const audience = script?.dataset.sightspoolAudience;\n if (key && (audience === \"all_visitors\" || audience === \"signed_in\")) {\n api.init({ key, audience, endpoint: script?.dataset.sightspoolEndpoint || new URL(script!.src).origin });\n if (script?.dataset.userId) api.identify(script.dataset.userId);\n }\n // The old research-widget URL is an alias of this bundle, not another runtime.\n (window as Window & { SightspoolResearch?: typeof api }).SightspoolResearch = api;\n Promise.resolve().then(() => window.dispatchEvent(new Event(\"sightspool:ready\")));\n} catch { /* Browser auto-init must not interrupt the client app. */ }\n",
5
+ "src/research.ts": "export type SightspoolConfig = {\n /** Public workspace widget key from Go live (UUID, not an old pk_live key). */\n key: string;\n /** Match the approved research audience. No default that widens recruitment. */\n audience: \"all_visitors\" | \"signed_in\";\n /** Sightspool origin. Defaults to the hosted application. */\n endpoint?: string;\n};\nexport type ResearchStatus =\n | \"not_initialized\" | \"signed_out\" | \"paused\" | \"checking\"\n | \"unavailable\" | \"available\" | \"error\";\n\ntype Runtime = {\n key: string; endpoint: string; audience: SightspoolConfig[\"audience\"]; identified: boolean; paused: boolean;\n disposed: boolean; generation: number; device: string; offer: string | null;\n button: HTMLButtonElement | null; popup: Window | null;\n pending: AbortController | null; timer: number; visibility: () => void;\n status: ResearchStatus;\n};\nconst slot = Symbol.for(\"sightspool.research.runtime.v1\");\ntype Host = Window & { [slot]?: Runtime };\nconst host = (): Host | null => typeof window === \"undefined\" ? null : window as Host;\nconst current = () => host()?.[slot];\nconst eligible = (r: Runtime) => r.audience === \"all_visitors\" || r.identified;\n\nfunction remove(r: Runtime) {\n r.button?.remove(); r.button = null; r.offer = null;\n}\nfunction invalidate(r: Runtime) {\n r.generation += 1; r.pending?.abort(); r.pending = null; remove(r);\n}\nfunction status(r: Runtime, value: ResearchStatus) { r.status = value; }\n\nasync function check(r: Runtime) {\n if (r.disposed || r.paused || !eligible(r) || r.pending || document.visibilityState !== \"visible\") return;\n const generation = r.generation;\n const request = new AbortController();\n r.pending = request;\n const timeout = window.setTimeout(() => request.abort(), 10_000);\n if (!r.button) status(r, \"checking\");\n try {\n const response = await fetch(r.endpoint + \"/widget-offer\", {\n method: \"POST\", credentials: \"omit\", cache: \"no-store\", referrerPolicy: \"no-referrer\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ operation: \"offer\", key: r.key, device: r.device }),\n signal: request.signal,\n });\n if (!response.ok) throw Error(\"offer unavailable\");\n const result = await response.json();\n if (r.disposed || generation !== r.generation || r.paused || !eligible(r)) return;\n if (result.available !== true || typeof result.offer !== \"string\" || !result.offer) {\n remove(r); status(r, \"unavailable\"); return;\n }\n r.offer = result.offer;\n status(r, \"available\");\n if (r.button) return;\n const button = document.createElement(\"button\");\n button.type = \"button\";\n button.textContent = \"Talk to the founder · 5 min\";\n button.setAttribute(\"aria-label\", \"Sightspool: join a five-minute user interview\");\n button.style.cssText = \"position:fixed;bottom:20px;right:20px;z-index:2147483000;padding:14px 18px;border:0;border-radius:16px;background:#171717;color:white;font:500 14px system-ui;box-shadow:0 8px 30px #0003;cursor:pointer;max-width:calc(100vw - 40px)\";\n button.onclick = () => {\n try {\n if (r.disposed || r.paused || !eligible(r) || !r.offer) return;\n if (r.popup && !r.popup.closed) { r.popup.focus(); return; }\n const hash = new URLSearchParams({ offer: r.offer, device: r.device });\n r.popup = window.open(r.endpoint + \"/interview-widget#\" + hash, \"sightspool-interview\", \"popup,width=520,height=760\");\n } catch { /* Host pages remain usable if popups are blocked. */ }\n };\n r.button = button;\n document.body.appendChild(button);\n } catch {\n if (!r.disposed && generation === r.generation) { remove(r); status(r, \"error\"); }\n } finally {\n window.clearTimeout(timeout);\n if (r.pending === request) r.pending = null;\n }\n}\n\n/** Start research for the chosen audience. Signed-in-only waits for identify(). */\nexport function init(config: SightspoolConfig): void {\n try {\n const browser = host();\n if (!browser || !config || !/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(config.key)) return;\n if (config.audience !== \"all_visitors\" && config.audience !== \"signed_in\") return;\n const url = new URL(config.endpoint || \"https://www.sightspool.com\");\n if (url.protocol !== \"https:\" && !(url.protocol === \"http:\" && [\"localhost\", \"127.0.0.1\", \"[::1]\"].includes(url.hostname))) return;\n if (url.username || url.password) return;\n const previous = current();\n if (previous && previous.key === config.key && previous.endpoint === url.origin && previous.audience === config.audience) return;\n if (previous) destroy();\n let device = \"\";\n try { device = sessionStorage.getItem(\"sightspool-widget-device:\" + config.key) || \"\"; } catch {}\n if (!/^ss_fcd_[A-Za-z0-9_-]{43}$/.test(device)) {\n const bytes = crypto.getRandomValues(new Uint8Array(32));\n device = \"ss_fcd_\" + btoa(String.fromCharCode(...bytes)).replaceAll(\"+\", \"-\").replaceAll(\"/\", \"_\").replace(/=+$/, \"\");\n try { sessionStorage.setItem(\"sightspool-widget-device:\" + config.key, device); } catch {}\n }\n const r: Runtime = {\n key: config.key, endpoint: url.origin, audience: config.audience, identified: false, paused: false,\n disposed: false, generation: 0, device, offer: null, button: null,\n popup: null, pending: null, timer: 0, visibility: () => {}, status: \"signed_out\",\n };\n browser[slot] = r;\n r.visibility = () => {\n try {\n if (document.visibilityState === \"visible\") void check(r);\n else { invalidate(r); status(r, r.paused ? \"paused\" : eligible(r) ? \"unavailable\" : \"signed_out\"); }\n } catch {}\n };\n document.addEventListener(\"visibilitychange\", r.visibility);\n r.timer = window.setInterval(() => { void check(r); }, 15_000);\n if (eligible(r)) void check(r);\n } catch { /* Never throw into the host application. */ }\n}\n\n/** Only the presence of an ID is retained. The ID itself is never stored or sent. */\nexport function identify(userId: string | null | undefined): void {\n try {\n const r = current();\n if (!r) return;\n const identified = typeof userId === \"string\" && userId.trim().length > 0;\n if (!identified && !r.identified) { if (!r.paused && eligible(r)) void check(r); return; }\n invalidate(r);\n r.identified = identified;\n status(r, r.paused ? \"paused\" : eligible(r) ? \"unavailable\" : \"signed_out\");\n if (eligible(r) && !r.paused) void check(r);\n } catch {}\n}\nexport function pause(): void {\n try { const r = current(); if (r) { r.paused = true; invalidate(r); status(r, \"paused\"); } } catch {}\n}\nexport function resume(): void {\n try { const r = current(); if (r) { r.paused = false; if (!eligible(r)) status(r, \"signed_out\"); void check(r); } } catch {}\n}\n/** Stop recruitment and remove listeners/UI. Does not end an already opened interview. */\nexport function destroy(): void {\n try {\n const r = current();\n if (!r) return;\n r.disposed = true; invalidate(r);\n window.clearInterval(r.timer);\n document.removeEventListener(\"visibilitychange\", r.visibility);\n delete host()![slot];\n } catch {}\n}\nexport function getStatus(): ResearchStatus {\n try { return current()?.status ?? \"not_initialized\"; } catch { return \"error\"; }\n}\n",
6
+ "tsup.config.ts": "import { defineConfig } from \"tsup\";\n\n// npm (ESM/CJS/types) and the script-tag bundle share the research runtime.\n// Parked capture modules are intentionally absent from both dependency graphs.\nexport default defineConfig([\n {\n entry: { index: \"src/index.ts\" },\n format: [\"esm\", \"cjs\"],\n dts: true,\n sourcemap: true,\n clean: true,\n treeshake: true,\n minify: false,\n target: \"es2018\",\n },\n {\n entry: { sdk: \"src/browser.ts\" },\n format: [\"iife\"],\n globalName: \"Sightspool\",\n sourcemap: true,\n minify: true,\n treeshake: true,\n target: \"es2018\",\n },\n]);\n",
7
+ "package.json": "{\n \"name\": \"@sightspool/sdk\",\n \"version\": \"0.4.0\",\n \"description\": \"Sightspool research SDK \\u2014 invite website visitors and signed-in users into approved user research.\",\n \"type\": \"module\",\n \"main\": \"./dist/index.cjs\",\n \"module\": \"./dist/index.js\",\n \"types\": \"./dist/index.d.ts\",\n \"exports\": {\n \".\": {\n \"types\": \"./dist/index.d.ts\",\n \"import\": \"./dist/index.js\",\n \"require\": \"./dist/index.cjs\"\n }\n },\n \"files\": [\n \"dist\",\n \"README.md\",\n \"LICENSE\",\n \"NOTICE\",\n \"site\",\n \"SECURITY.md\",\n \"CHANGELOG.md\"\n ],\n \"sideEffects\": false,\n \"license\": \"Apache-2.0\",\n \"author\": \"Sightspool\",\n \"homepage\": \"https://github.com/sightspool/sdk#readme\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/sightspool/sdk.git\"\n },\n \"bugs\": {\n \"url\": \"https://github.com/sightspool/sdk/issues\"\n },\n \"keywords\": [\n \"sightspool\",\n \"user-research\",\n \"research\",\n \"interviews\",\n \"sdk\"\n ],\n \"engines\": {\n \"node\": \">=18\"\n },\n \"packageManager\": \"pnpm@9.15.0\",\n \"publishConfig\": {\n \"access\": \"public\"\n },\n \"scripts\": {\n \"build\": \"tsup && node scripts/build-release.mjs\",\n \"type-check\": \"tsc --noEmit\",\n \"test\": \"tsc --noEmit && node --test __tests__/*.test.ts\",\n \"prepublishOnly\": \"pnpm run build\",\n \"test:release\": \"node scripts/verify-release.mjs && node --test scripts/release.test.mjs\",\n \"build:site\": \"node scripts/stage-site.mjs\"\n },\n \"devDependencies\": {\n \"@types/node\": \"^24.10.4\",\n \"tsup\": \"^8.5.0\",\n \"typescript\": \"^5.9.3\"\n }\n}\n",
8
+ "pnpm-lock.yaml": "lockfileVersion: '9.0'\n\nsettings:\n autoInstallPeers: true\n excludeLinksFromLockfile: false\n\nimporters:\n\n .:\n devDependencies:\n '@types/node':\n specifier: ^24.10.4\n version: 24.13.1\n tsup:\n specifier: ^8.5.0\n version: 8.5.1(typescript@5.9.3)\n typescript:\n specifier: ^5.9.3\n version: 5.9.3\n\n packages/react:\n devDependencies:\n '@sightspool/sdk':\n specifier: workspace:^\n version: link:../..\n '@types/react':\n specifier: ^19.0.0\n version: 19.2.17\n react:\n specifier: ^19.0.0\n version: 19.2.7\n tsup:\n specifier: ^8.5.0\n version: 8.5.1(typescript@5.9.3)\n typescript:\n specifier: ^5.9.3\n version: 5.9.3\n\npackages:\n\n '@esbuild/aix-ppc64@0.27.7':\n resolution: {integrity: sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg==}\n engines: {node: '>=18'}\n cpu: [ppc64]\n os: [aix]\n\n '@esbuild/android-arm64@0.27.7':\n resolution: {integrity: sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ==}\n engines: {node: '>=18'}\n cpu: [arm64]\n os: [android]\n\n '@esbuild/android-arm@0.27.7':\n resolution: {integrity: sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ==}\n engines: {node: '>=18'}\n cpu: [arm]\n os: [android]\n\n '@esbuild/android-x64@0.27.7':\n resolution: {integrity: sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg==}\n engines: {node: '>=18'}\n cpu: [x64]\n os: [android]\n\n '@esbuild/darwin-arm64@0.27.7':\n resolution: {integrity: sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw==}\n engines: {node: '>=18'}\n cpu: [arm64]\n os: [darwin]\n\n '@esbuild/darwin-x64@0.27.7':\n resolution: {integrity: sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ==}\n engines: {node: '>=18'}\n cpu: [x64]\n os: [darwin]\n\n '@esbuild/freebsd-arm64@0.27.7':\n resolution: {integrity: sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w==}\n engines: {node: '>=18'}\n cpu: [arm64]\n os: [freebsd]\n\n '@esbuild/freebsd-x64@0.27.7':\n resolution: {integrity: sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ==}\n engines: {node: '>=18'}\n cpu: [x64]\n os: [freebsd]\n\n '@esbuild/linux-arm64@0.27.7':\n resolution: {integrity: sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A==}\n engines: {node: '>=18'}\n cpu: [arm64]\n os: [linux]\n\n '@esbuild/linux-arm@0.27.7':\n resolution: {integrity: sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA==}\n engines: {node: '>=18'}\n cpu: [arm]\n os: [linux]\n\n '@esbuild/linux-ia32@0.27.7':\n resolution: {integrity: sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg==}\n engines: {node: '>=18'}\n cpu: [ia32]\n os: [linux]\n\n '@esbuild/linux-loong64@0.27.7':\n resolution: {integrity: sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q==}\n engines: {node: '>=18'}\n cpu: [loong64]\n os: [linux]\n\n '@esbuild/linux-mips64el@0.27.7':\n resolution: {integrity: sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw==}\n engines: {node: '>=18'}\n cpu: [mips64el]\n os: [linux]\n\n '@esbuild/linux-ppc64@0.27.7':\n resolution: {integrity: sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ==}\n engines: {node: '>=18'}\n cpu: [ppc64]\n os: [linux]\n\n '@esbuild/linux-riscv64@0.27.7':\n resolution: {integrity: sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ==}\n engines: {node: '>=18'}\n cpu: [riscv64]\n os: [linux]\n\n '@esbuild/linux-s390x@0.27.7':\n resolution: {integrity: sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw==}\n engines: {node: '>=18'}\n cpu: [s390x]\n os: [linux]\n\n '@esbuild/linux-x64@0.27.7':\n resolution: {integrity: sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA==}\n engines: {node: '>=18'}\n cpu: [x64]\n os: [linux]\n\n '@esbuild/netbsd-arm64@0.27.7':\n resolution: {integrity: sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w==}\n engines: {node: '>=18'}\n cpu: [arm64]\n os: [netbsd]\n\n '@esbuild/netbsd-x64@0.27.7':\n resolution: {integrity: sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw==}\n engines: {node: '>=18'}\n cpu: [x64]\n os: [netbsd]\n\n '@esbuild/openbsd-arm64@0.27.7':\n resolution: {integrity: sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A==}\n engines: {node: '>=18'}\n cpu: [arm64]\n os: [openbsd]\n\n '@esbuild/openbsd-x64@0.27.7':\n resolution: {integrity: sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg==}\n engines: {node: '>=18'}\n cpu: [x64]\n os: [openbsd]\n\n '@esbuild/openharmony-arm64@0.27.7':\n resolution: {integrity: sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw==}\n engines: {node: '>=18'}\n cpu: [arm64]\n os: [openharmony]\n\n '@esbuild/sunos-x64@0.27.7':\n resolution: {integrity: sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA==}\n engines: {node: '>=18'}\n cpu: [x64]\n os: [sunos]\n\n '@esbuild/win32-arm64@0.27.7':\n resolution: {integrity: sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA==}\n engines: {node: '>=18'}\n cpu: [arm64]\n os: [win32]\n\n '@esbuild/win32-ia32@0.27.7':\n resolution: {integrity: sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw==}\n engines: {node: '>=18'}\n cpu: [ia32]\n os: [win32]\n\n '@esbuild/win32-x64@0.27.7':\n resolution: {integrity: sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg==}\n engines: {node: '>=18'}\n cpu: [x64]\n os: [win32]\n\n '@jridgewell/gen-mapping@0.3.13':\n resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==}\n\n '@jridgewell/resolve-uri@3.1.2':\n resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==}\n engines: {node: '>=6.0.0'}\n\n '@jridgewell/sourcemap-codec@1.5.5':\n resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==}\n\n '@jridgewell/trace-mapping@0.3.31':\n resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==}\n\n '@rollup/rollup-android-arm-eabi@4.61.1':\n resolution: {integrity: sha512-JnBB8MdXj45cajvTuO5FmPlvFVJRQgvrz1uSEl3NwqFnReAPGwb8EanbGi4z2nRaqLzjJSv5/JmycoTKlRZxHA==}\n cpu: [arm]\n os: [android]\n\n '@rollup/rollup-android-arm64@4.61.1':\n resolution: {integrity: sha512-Jx2g7iSjw4AOT0HDPHM9RV3GNjRXwybWtSFZiZAYUTjUwjVrYIwq3kBf+LnhqJlzXFAqTAh2F7IGI+O568exPw==}\n cpu: [arm64]\n os: [android]\n\n '@rollup/rollup-darwin-arm64@4.61.1':\n resolution: {integrity: sha512-0F1L/Z3Eqv8mT2n3dCpeO8GcTvHvVqkP5/t6DMsn0KzhYVcg+s7Ncl5DS8qjKYEeio6Az0Gt6nyBORay5qIlCA==}\n cpu: [arm64]\n os: [darwin]\n\n '@rollup/rollup-darwin-x64@4.61.1':\n resolution: {integrity: sha512-qLttcH871ujY4YcVfUSShhOw+CsoTatYz8gRbHO7Bb92QH059/P0y5do1KMs41fY0BpD2x4AJH/gID0zFiqVKQ==}\n cpu: [x64]\n os: [darwin]\n\n '@rollup/rollup-freebsd-arm64@4.61.1':\n resolution: {integrity: sha512-fUI4RapGE0Oh3mb8mgfvC1O2nU1RpDZUKnDQm3xB1Ipg7C2wTs5Kstz7G2uWK99a8S2yTMq8/P4uycwNa0nJyw==}\n cpu: [arm64]\n os: [freebsd]\n\n '@rollup/rollup-freebsd-x64@4.61.1':\n resolution: {integrity: sha512-H5YrdvJaDtI/U9/emrD4b++xkvp3y/JvOe4rizHbxvkyMfRS/CiRYdji+Pl8D0brEaNFWUh1drQxgAGIl6Xudw==}\n cpu: [x64]\n os: [freebsd]\n\n '@rollup/rollup-linux-arm-gnueabihf@4.61.1':\n resolution: {integrity: sha512-Q8CBCCQtDFrYtXoeUXSrnFXKOnyUhx6bz+SkL6A0E7V8kAiCJ5pamq1WtbfpVGhR5TSpXY6ak3avmDc5fHTyJA==}\n cpu: [arm]\n os: [linux]\n\n '@rollup/rollup-linux-arm-musleabihf@4.61.1':\n resolution: {integrity: sha512-nwnhk1581l0FBVellGcVCAT0Oi06onEA3WB53sf01VO3I0UPBkMH9sXONYME2K0ovXcNayJfNtHfm6mpJElatQ==}\n cpu: [arm]\n os: [linux]\n\n '@rollup/rollup-linux-arm64-gnu@4.61.1':\n resolution: {integrity: sha512-x5Xr49hwt3hdW75UOZm3395YwwzPyauktslv29KpWL/T+vVAzoT3azLcTWv0eMciBNrx+DYjH4paehHoLpPvpg==}\n cpu: [arm64]\n os: [linux]\n\n '@rollup/rollup-linux-arm64-musl@4.61.1':\n resolution: {integrity: sha512-unMS3H73DpaoPyyEVPjGKleM/s0mkmsauTENpw4INQY8y4+IuLNjkueQ5QCtC0D3N38Y38yhAU8OoZ20S2Tm6w==}\n cpu: [arm64]\n os: [linux]\n\n '@rollup/rollup-linux-loong64-gnu@4.61.1':\n resolution: {integrity: sha512-zNZzGRnAhwjFEYmvphJRV5XaQGjs62cCmeYYHUT//NbvEnHauw+I85nGG+SiVg5ld4GX8D1IbKIX+ozITQnhMQ==}\n cpu: [loong64]\n os: [linux]\n\n '@rollup/rollup-linux-loong64-musl@4.61.1':\n resolution: {integrity: sha512-LdpWGL8X209B2SIvWjqlc8VZgM6PKfontSerGepuldQmHYrAOtnMCXeJkxXGbC+PPZVOuu5czJo7fNV6aeW8rQ==}\n cpu: [loong64]\n os: [linux]\n\n '@rollup/rollup-linux-ppc64-gnu@4.61.1':\n resolution: {integrity: sha512-EC5kTtNaNGOmbMGqar8dvJy6y/hg99GAwjfBz++pxZhQATXGcRjd6c5en5wcbru0vkRmiMGsQKdMJOOf6sza4g==}\n cpu: [ppc64]\n os: [linux]\n\n '@rollup/rollup-linux-ppc64-musl@4.61.1':\n resolution: {integrity: sha512-8hiwp6D4acEcNK78I4rP0/XtS1sknWIAMJBPdR4l6zUtyTm5KiTDr5bXmWt4foY7nAN7AThDHgkLIEZOWKbzWw==}\n cpu: [ppc64]\n os: [linux]\n\n '@rollup/rollup-linux-riscv64-gnu@4.61.1':\n resolution: {integrity: sha512-10dh/h/BqA7DuMPWSxkR8uks18FRwnwOEqr5zOTEl+NOwP/OMzKX8OFR/Of9xxDA7D5qef1Nzar5WDD2kCCr1g==}\n cpu: [riscv64]\n os: [linux]\n\n '@rollup/rollup-linux-riscv64-musl@4.61.1':\n resolution: {integrity: sha512-YKJ5lg35DP17gcAOggnihe+APw9HLyj1Xn7gsmGumBJAUDa6NGXNixJzmkWLhcK9TOuuyQjdamzvJefkO7qHZQ==}\n cpu: [riscv64]\n os: [linux]\n\n '@rollup/rollup-linux-s390x-gnu@4.61.1':\n resolution: {integrity: sha512-Mlil5G2Jj6a7B3LWGctg+XPL9vdXYuzCtNXfxOQ0nPjc2m6ueUktocPGH9bnAM0bNRKb/bAWTujUU7IJQdQA+g==}\n cpu: [s390x]\n os: [linux]\n\n '@rollup/rollup-linux-x64-gnu@4.61.1':\n resolution: {integrity: sha512-bVWIOIk6pV01p4CdUbPP7CJ/434z+OooYjDuFcR+44N35YvKUC66G8MGnvcWx5mWKW3g61J+t74l3Kj15Kwn2Q==}\n cpu: [x64]\n os: [linux]\n\n '@rollup/rollup-linux-x64-musl@4.61.1':\n resolution: {integrity: sha512-qy5pBvZbqNFheBz61R1rzsezjm0J7O2oNGoWtGoY89SZYLUfxAJTBAqDChqAIdB4rCiIbi9nF7yZ83GnNiLwSw==}\n cpu: [x64]\n os: [linux]\n\n '@rollup/rollup-openbsd-x64@4.61.1':\n resolution: {integrity: sha512-E83TXjI4zm0+5f2qO+UOudaCYIhYwpJ5jq6YCZNIZ+6CbfhKrkAGezeiASBL9ElxAxFsRS9ZhESv8mfnj6TKeg==}\n cpu: [x64]\n os: [openbsd]\n\n '@rollup/rollup-openharmony-arm64@4.61.1':\n resolution: {integrity: sha512-fbWnKqVkjrJN38vNe3ahkbk6iejS/3b0Nt7EEtPpE6RBacZcGXNKbzfHN3GUUlXOPghUg0j6XUGrtjX9z1sIvA==}\n cpu: [arm64]\n os: [openharmony]\n\n '@rollup/rollup-win32-arm64-msvc@4.61.1':\n resolution: {integrity: sha512-ArMl38iVAbk0New1ogihQNY6iphLi4ZaRsa037gUzv5yeKPY8TD3Dmy4x2RNC1VztU/uqm+G+/RwFrSka3Oy2g==}\n cpu: [arm64]\n os: [win32]\n\n '@rollup/rollup-win32-ia32-msvc@4.61.1':\n resolution: {integrity: sha512-0mYtjHS9ucAbcATycCNK9IGBk/cCe/ma7EmSLGZdsxnOA8cjRIyU04wDpVAD9NiOfLUR9KTxdiO53uOkherqjQ==}\n cpu: [ia32]\n os: [win32]\n\n '@rollup/rollup-win32-x64-gnu@4.61.1':\n resolution: {integrity: sha512-gK1iCEPfpoSG9wfBihXxvBMi8ZfcWffYkEsC/Eih+iFENTaewvNcrEQ69lIOWYO5pePHKLHHO7nq5AILGO/HQQ==}\n cpu: [x64]\n os: [win32]\n\n '@rollup/rollup-win32-x64-msvc@4.61.1':\n resolution: {integrity: sha512-X+zaP2x+j4RXGfbp/seSoRHWnPxzApilDszisZxbYH5C/jTxFhCtDNdPGZb9lJyYPs24wGxruPF7Y+sIXt9Gzw==}\n cpu: [x64]\n os: [win32]\n\n '@types/estree@1.0.9':\n resolution: {integrity: sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==}\n\n '@types/node@24.13.1':\n resolution: {integrity: sha512-RSpUJGmvsJ1ZeBehQZFhIdpsz+bIpES0nIQXko4Ybq+N+kX6XvOq3Jo+iJ82FWLdblFq85AsMikd3m35jgezYg==}\n\n '@types/react@19.2.17':\n resolution: {integrity: sha512-MXfmqaVPEVgkBT/aY0aGCkRWWtByiYQXo3xdQ8r5RzuFrPiRn8Gar2tQdXSUQ2GKV3bkXckek89V8wQBY2Q/Aw==}\n\n acorn@8.16.0:\n resolution: {integrity: sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==}\n engines: {node: '>=0.4.0'}\n hasBin: true\n\n any-promise@1.3.0:\n resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==}\n\n bundle-require@5.1.0:\n resolution: {integrity: sha512-3WrrOuZiyaaZPWiEt4G3+IffISVC9HYlWueJEBWED4ZH4aIAC2PnkdnuRrR94M+w6yGWn4AglWtJtBI8YqvgoA==}\n engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}\n peerDependencies:\n esbuild: '>=0.18'\n\n cac@6.7.14:\n resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==}\n engines: {node: '>=8'}\n\n chokidar@4.0.3:\n resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==}\n engines: {node: '>= 14.16.0'}\n\n commander@4.1.1:\n resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==}\n engines: {node: '>= 6'}\n\n confbox@0.1.8:\n resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==}\n\n consola@3.4.2:\n resolution: {integrity: sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==}\n engines: {node: ^14.18.0 || >=16.10.0}\n\n csstype@3.2.3:\n resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==}\n\n debug@4.4.3:\n resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==}\n engines: {node: '>=6.0'}\n peerDependencies:\n supports-color: '*'\n peerDependenciesMeta:\n supports-color:\n optional: true\n\n esbuild@0.27.7:\n resolution: {integrity: sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w==}\n engines: {node: '>=18'}\n hasBin: true\n\n fdir@6.5.0:\n resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==}\n engines: {node: '>=12.0.0'}\n peerDependencies:\n picomatch: ^3 || ^4\n peerDependenciesMeta:\n picomatch:\n optional: true\n\n fix-dts-default-cjs-exports@1.0.1:\n resolution: {integrity: sha512-pVIECanWFC61Hzl2+oOCtoJ3F17kglZC/6N94eRWycFgBH35hHx0Li604ZIzhseh97mf2p0cv7vVrOZGoqhlEg==}\n\n fsevents@2.3.3:\n resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}\n engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}\n os: [darwin]\n\n joycon@3.1.1:\n resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==}\n engines: {node: '>=10'}\n\n lilconfig@3.1.3:\n resolution: {integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==}\n engines: {node: '>=14'}\n\n lines-and-columns@1.2.4:\n resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==}\n\n load-tsconfig@0.2.5:\n resolution: {integrity: sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg==}\n engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}\n\n magic-string@0.30.21:\n resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==}\n\n mlly@1.8.2:\n resolution: {integrity: sha512-d+ObxMQFmbt10sretNDytwt85VrbkhhUA/JBGm1MPaWJ65Cl4wOgLaB1NYvJSZ0Ef03MMEU/0xpPMXUIQ29UfA==}\n\n ms@2.1.3:\n resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}\n\n mz@2.7.0:\n resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==}\n\n object-assign@4.1.1:\n resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==}\n engines: {node: '>=0.10.0'}\n\n pathe@2.0.3:\n resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==}\n\n picocolors@1.1.1:\n resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}\n\n picomatch@4.0.4:\n resolution: {integrity: sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==}\n engines: {node: '>=12'}\n\n pirates@4.0.7:\n resolution: {integrity: sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==}\n engines: {node: '>= 6'}\n\n pkg-types@1.3.1:\n resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==}\n\n postcss-load-config@6.0.1:\n resolution: {integrity: sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==}\n engines: {node: '>= 18'}\n peerDependencies:\n jiti: '>=1.21.0'\n postcss: '>=8.0.9'\n tsx: ^4.8.1\n yaml: ^2.4.2\n peerDependenciesMeta:\n jiti:\n optional: true\n postcss:\n optional: true\n tsx:\n optional: true\n yaml:\n optional: true\n\n react@19.2.7:\n resolution: {integrity: sha512-HNe9WslTbXmFK8o8cmwgAeJFSBvt1bPdHCVKtaaV+WlAN36mpT4hcRpwbf3fY56ar2oIXzsBpOAiIRHAdY0OlQ==}\n engines: {node: '>=0.10.0'}\n\n readdirp@4.1.2:\n resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==}\n engines: {node: '>= 14.18.0'}\n\n resolve-from@5.0.0:\n resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==}\n engines: {node: '>=8'}\n\n rollup@4.61.1:\n resolution: {integrity: sha512-I4KW6iuRpuu2uHBLraZ1wNZe0DP7lnRha+VJ9tNaYVaVgKhW0aI3h4RYnoRPeql0flHm/Co55b7snEDcOfOJrA==}\n engines: {node: '>=18.0.0', npm: '>=8.0.0'}\n hasBin: true\n\n source-map@0.7.6:\n resolution: {integrity: sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==}\n engines: {node: '>= 12'}\n\n sucrase@3.35.1:\n resolution: {integrity: sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==}\n engines: {node: '>=16 || 14 >=14.17'}\n hasBin: true\n\n thenify-all@1.6.0:\n resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==}\n engines: {node: '>=0.8'}\n\n thenify@3.3.1:\n resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==}\n\n tinyexec@0.3.2:\n resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==}\n\n tinyglobby@0.2.17:\n resolution: {integrity: sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==}\n engines: {node: '>=12.0.0'}\n\n tree-kill@1.2.2:\n resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==}\n hasBin: true\n\n ts-interface-checker@0.1.13:\n resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==}\n\n tsup@8.5.1:\n resolution: {integrity: sha512-xtgkqwdhpKWr3tKPmCkvYmS9xnQK3m3XgxZHwSUjvfTjp7YfXe5tT3GgWi0F2N+ZSMsOeWeZFh7ZZFg5iPhing==}\n engines: {node: '>=18'}\n hasBin: true\n peerDependencies:\n '@microsoft/api-extractor': ^7.36.0\n '@swc/core': ^1\n postcss: ^8.4.12\n typescript: '>=4.5.0'\n peerDependenciesMeta:\n '@microsoft/api-extractor':\n optional: true\n '@swc/core':\n optional: true\n postcss:\n optional: true\n typescript:\n optional: true\n\n typescript@5.9.3:\n resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==}\n engines: {node: '>=14.17'}\n hasBin: true\n\n ufo@1.6.4:\n resolution: {integrity: sha512-JFNbkD1Svwe0KvGi8GOeLcP4kAWQ609twvCdcHxq1oSL8svv39ZuSvajcD8B+5D0eL4+s1Is2D/O6KN3qcTeRA==}\n\n undici-types@7.18.2:\n resolution: {integrity: sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==}\n\nsnapshots:\n\n '@esbuild/aix-ppc64@0.27.7':\n optional: true\n\n '@esbuild/android-arm64@0.27.7':\n optional: true\n\n '@esbuild/android-arm@0.27.7':\n optional: true\n\n '@esbuild/android-x64@0.27.7':\n optional: true\n\n '@esbuild/darwin-arm64@0.27.7':\n optional: true\n\n '@esbuild/darwin-x64@0.27.7':\n optional: true\n\n '@esbuild/freebsd-arm64@0.27.7':\n optional: true\n\n '@esbuild/freebsd-x64@0.27.7':\n optional: true\n\n '@esbuild/linux-arm64@0.27.7':\n optional: true\n\n '@esbuild/linux-arm@0.27.7':\n optional: true\n\n '@esbuild/linux-ia32@0.27.7':\n optional: true\n\n '@esbuild/linux-loong64@0.27.7':\n optional: true\n\n '@esbuild/linux-mips64el@0.27.7':\n optional: true\n\n '@esbuild/linux-ppc64@0.27.7':\n optional: true\n\n '@esbuild/linux-riscv64@0.27.7':\n optional: true\n\n '@esbuild/linux-s390x@0.27.7':\n optional: true\n\n '@esbuild/linux-x64@0.27.7':\n optional: true\n\n '@esbuild/netbsd-arm64@0.27.7':\n optional: true\n\n '@esbuild/netbsd-x64@0.27.7':\n optional: true\n\n '@esbuild/openbsd-arm64@0.27.7':\n optional: true\n\n '@esbuild/openbsd-x64@0.27.7':\n optional: true\n\n '@esbuild/openharmony-arm64@0.27.7':\n optional: true\n\n '@esbuild/sunos-x64@0.27.7':\n optional: true\n\n '@esbuild/win32-arm64@0.27.7':\n optional: true\n\n '@esbuild/win32-ia32@0.27.7':\n optional: true\n\n '@esbuild/win32-x64@0.27.7':\n optional: true\n\n '@jridgewell/gen-mapping@0.3.13':\n dependencies:\n '@jridgewell/sourcemap-codec': 1.5.5\n '@jridgewell/trace-mapping': 0.3.31\n\n '@jridgewell/resolve-uri@3.1.2': {}\n\n '@jridgewell/sourcemap-codec@1.5.5': {}\n\n '@jridgewell/trace-mapping@0.3.31':\n dependencies:\n '@jridgewell/resolve-uri': 3.1.2\n '@jridgewell/sourcemap-codec': 1.5.5\n\n '@rollup/rollup-android-arm-eabi@4.61.1':\n optional: true\n\n '@rollup/rollup-android-arm64@4.61.1':\n optional: true\n\n '@rollup/rollup-darwin-arm64@4.61.1':\n optional: true\n\n '@rollup/rollup-darwin-x64@4.61.1':\n optional: true\n\n '@rollup/rollup-freebsd-arm64@4.61.1':\n optional: true\n\n '@rollup/rollup-freebsd-x64@4.61.1':\n optional: true\n\n '@rollup/rollup-linux-arm-gnueabihf@4.61.1':\n optional: true\n\n '@rollup/rollup-linux-arm-musleabihf@4.61.1':\n optional: true\n\n '@rollup/rollup-linux-arm64-gnu@4.61.1':\n optional: true\n\n '@rollup/rollup-linux-arm64-musl@4.61.1':\n optional: true\n\n '@rollup/rollup-linux-loong64-gnu@4.61.1':\n optional: true\n\n '@rollup/rollup-linux-loong64-musl@4.61.1':\n optional: true\n\n '@rollup/rollup-linux-ppc64-gnu@4.61.1':\n optional: true\n\n '@rollup/rollup-linux-ppc64-musl@4.61.1':\n optional: true\n\n '@rollup/rollup-linux-riscv64-gnu@4.61.1':\n optional: true\n\n '@rollup/rollup-linux-riscv64-musl@4.61.1':\n optional: true\n\n '@rollup/rollup-linux-s390x-gnu@4.61.1':\n optional: true\n\n '@rollup/rollup-linux-x64-gnu@4.61.1':\n optional: true\n\n '@rollup/rollup-linux-x64-musl@4.61.1':\n optional: true\n\n '@rollup/rollup-openbsd-x64@4.61.1':\n optional: true\n\n '@rollup/rollup-openharmony-arm64@4.61.1':\n optional: true\n\n '@rollup/rollup-win32-arm64-msvc@4.61.1':\n optional: true\n\n '@rollup/rollup-win32-ia32-msvc@4.61.1':\n optional: true\n\n '@rollup/rollup-win32-x64-gnu@4.61.1':\n optional: true\n\n '@rollup/rollup-win32-x64-msvc@4.61.1':\n optional: true\n\n '@types/estree@1.0.9': {}\n\n '@types/node@24.13.1':\n dependencies:\n undici-types: 7.18.2\n\n '@types/react@19.2.17':\n dependencies:\n csstype: 3.2.3\n\n acorn@8.16.0: {}\n\n any-promise@1.3.0: {}\n\n bundle-require@5.1.0(esbuild@0.27.7):\n dependencies:\n esbuild: 0.27.7\n load-tsconfig: 0.2.5\n\n cac@6.7.14: {}\n\n chokidar@4.0.3:\n dependencies:\n readdirp: 4.1.2\n\n commander@4.1.1: {}\n\n confbox@0.1.8: {}\n\n consola@3.4.2: {}\n\n csstype@3.2.3: {}\n\n debug@4.4.3:\n dependencies:\n ms: 2.1.3\n\n esbuild@0.27.7:\n optionalDependencies:\n '@esbuild/aix-ppc64': 0.27.7\n '@esbuild/android-arm': 0.27.7\n '@esbuild/android-arm64': 0.27.7\n '@esbuild/android-x64': 0.27.7\n '@esbuild/darwin-arm64': 0.27.7\n '@esbuild/darwin-x64': 0.27.7\n '@esbuild/freebsd-arm64': 0.27.7\n '@esbuild/freebsd-x64': 0.27.7\n '@esbuild/linux-arm': 0.27.7\n '@esbuild/linux-arm64': 0.27.7\n '@esbuild/linux-ia32': 0.27.7\n '@esbuild/linux-loong64': 0.27.7\n '@esbuild/linux-mips64el': 0.27.7\n '@esbuild/linux-ppc64': 0.27.7\n '@esbuild/linux-riscv64': 0.27.7\n '@esbuild/linux-s390x': 0.27.7\n '@esbuild/linux-x64': 0.27.7\n '@esbuild/netbsd-arm64': 0.27.7\n '@esbuild/netbsd-x64': 0.27.7\n '@esbuild/openbsd-arm64': 0.27.7\n '@esbuild/openbsd-x64': 0.27.7\n '@esbuild/openharmony-arm64': 0.27.7\n '@esbuild/sunos-x64': 0.27.7\n '@esbuild/win32-arm64': 0.27.7\n '@esbuild/win32-ia32': 0.27.7\n '@esbuild/win32-x64': 0.27.7\n\n fdir@6.5.0(picomatch@4.0.4):\n optionalDependencies:\n picomatch: 4.0.4\n\n fix-dts-default-cjs-exports@1.0.1:\n dependencies:\n magic-string: 0.30.21\n mlly: 1.8.2\n rollup: 4.61.1\n\n fsevents@2.3.3:\n optional: true\n\n joycon@3.1.1: {}\n\n lilconfig@3.1.3: {}\n\n lines-and-columns@1.2.4: {}\n\n load-tsconfig@0.2.5: {}\n\n magic-string@0.30.21:\n dependencies:\n '@jridgewell/sourcemap-codec': 1.5.5\n\n mlly@1.8.2:\n dependencies:\n acorn: 8.16.0\n pathe: 2.0.3\n pkg-types: 1.3.1\n ufo: 1.6.4\n\n ms@2.1.3: {}\n\n mz@2.7.0:\n dependencies:\n any-promise: 1.3.0\n object-assign: 4.1.1\n thenify-all: 1.6.0\n\n object-assign@4.1.1: {}\n\n pathe@2.0.3: {}\n\n picocolors@1.1.1: {}\n\n picomatch@4.0.4: {}\n\n pirates@4.0.7: {}\n\n pkg-types@1.3.1:\n dependencies:\n confbox: 0.1.8\n mlly: 1.8.2\n pathe: 2.0.3\n\n postcss-load-config@6.0.1:\n dependencies:\n lilconfig: 3.1.3\n\n react@19.2.7: {}\n\n readdirp@4.1.2: {}\n\n resolve-from@5.0.0: {}\n\n rollup@4.61.1:\n dependencies:\n '@types/estree': 1.0.9\n optionalDependencies:\n '@rollup/rollup-android-arm-eabi': 4.61.1\n '@rollup/rollup-android-arm64': 4.61.1\n '@rollup/rollup-darwin-arm64': 4.61.1\n '@rollup/rollup-darwin-x64': 4.61.1\n '@rollup/rollup-freebsd-arm64': 4.61.1\n '@rollup/rollup-freebsd-x64': 4.61.1\n '@rollup/rollup-linux-arm-gnueabihf': 4.61.1\n '@rollup/rollup-linux-arm-musleabihf': 4.61.1\n '@rollup/rollup-linux-arm64-gnu': 4.61.1\n '@rollup/rollup-linux-arm64-musl': 4.61.1\n '@rollup/rollup-linux-loong64-gnu': 4.61.1\n '@rollup/rollup-linux-loong64-musl': 4.61.1\n '@rollup/rollup-linux-ppc64-gnu': 4.61.1\n '@rollup/rollup-linux-ppc64-musl': 4.61.1\n '@rollup/rollup-linux-riscv64-gnu': 4.61.1\n '@rollup/rollup-linux-riscv64-musl': 4.61.1\n '@rollup/rollup-linux-s390x-gnu': 4.61.1\n '@rollup/rollup-linux-x64-gnu': 4.61.1\n '@rollup/rollup-linux-x64-musl': 4.61.1\n '@rollup/rollup-openbsd-x64': 4.61.1\n '@rollup/rollup-openharmony-arm64': 4.61.1\n '@rollup/rollup-win32-arm64-msvc': 4.61.1\n '@rollup/rollup-win32-ia32-msvc': 4.61.1\n '@rollup/rollup-win32-x64-gnu': 4.61.1\n '@rollup/rollup-win32-x64-msvc': 4.61.1\n fsevents: 2.3.3\n\n source-map@0.7.6: {}\n\n sucrase@3.35.1:\n dependencies:\n '@jridgewell/gen-mapping': 0.3.13\n commander: 4.1.1\n lines-and-columns: 1.2.4\n mz: 2.7.0\n pirates: 4.0.7\n tinyglobby: 0.2.17\n ts-interface-checker: 0.1.13\n\n thenify-all@1.6.0:\n dependencies:\n thenify: 3.3.1\n\n thenify@3.3.1:\n dependencies:\n any-promise: 1.3.0\n\n tinyexec@0.3.2: {}\n\n tinyglobby@0.2.17:\n dependencies:\n fdir: 6.5.0(picomatch@4.0.4)\n picomatch: 4.0.4\n\n tree-kill@1.2.2: {}\n\n ts-interface-checker@0.1.13: {}\n\n tsup@8.5.1(typescript@5.9.3):\n dependencies:\n bundle-require: 5.1.0(esbuild@0.27.7)\n cac: 6.7.14\n chokidar: 4.0.3\n consola: 3.4.2\n debug: 4.4.3\n esbuild: 0.27.7\n fix-dts-default-cjs-exports: 1.0.1\n joycon: 3.1.1\n picocolors: 1.1.1\n postcss-load-config: 6.0.1\n resolve-from: 5.0.0\n rollup: 4.61.1\n source-map: 0.7.6\n sucrase: 3.35.1\n tinyexec: 0.3.2\n tinyglobby: 0.2.17\n tree-kill: 1.2.2\n optionalDependencies:\n typescript: 5.9.3\n transitivePeerDependencies:\n - jiti\n - supports-color\n - tsx\n - yaml\n\n typescript@5.9.3: {}\n\n ufo@1.6.4: {}\n\n undici-types@7.18.2: {}\n",
9
+ "scripts/build-release.mjs": "import { readFileSync, writeFileSync } from 'node:fs';\nimport { createHash } from 'node:crypto';\nimport { gzipSync } from 'node:zlib';\nimport { execFileSync } from 'node:child_process';\nconst digest = (bytes, algorithm = 'sha256', encoding = 'hex') => createHash(algorithm).update(bytes).digest(encoding);\nconst pkg = JSON.parse(readFileSync('package.json', 'utf8'));\nconst bundle = readFileSync('dist/sdk.global.js');\nconst sourceFiles = ['src/index.ts', 'src/browser.ts', 'src/research.ts', 'tsup.config.ts', 'package.json', 'pnpm-lock.yaml', 'scripts/build-release.mjs'];\nconst files = Object.fromEntries(sourceFiles.map(path => [path, readFileSync(path, 'utf8')]));\nconst source = JSON.stringify({ files }, null, 2) + '\\n';\nconst sha256 = digest(bundle);\nconst sourceCommit = execFileSync('git', ['rev-parse', 'HEAD'], {encoding:'utf8'}).trim();\nconst sourceDirty = Boolean(execFileSync('git', ['status', '--porcelain', '--untracked-files=normal'], {encoding:'utf8'}).trim());\nconst artifactId = digest(JSON.stringify([pkg.version, sha256, digest(source), sourceCommit, sourceDirty]));\nconst manifest = {\n schemaVersion: 1, package: pkg.name, version: pkg.version,\n sourceCommit, sourceDirty, artifactId,\n bundle: { file: 'sdk.global.js', path: `releases/${pkg.version}/${artifactId}/sdk.global.js`, sha256,\n integrity: 'sha384-' + digest(bundle, 'sha384', 'base64'), bytes: bundle.length, gzipBytes: gzipSync(bundle).length },\n source: { file: 'source.json', sha256: digest(source) },\n runtimeDependencies: Object.keys(pkg.dependencies || {}),\n};\nwriteFileSync('dist/source.json', source);\nwriteFileSync('dist/release.json', JSON.stringify(manifest, null, 2) + '\\n');\nconsole.log(`Prepared ${pkg.name} ${pkg.version}: ${bundle.length} bytes, ${manifest.bundle.gzipBytes} gzip bytes. No publication performed.`);\n"
10
+ }
11
+ }
@@ -0,0 +1,21 @@
1
+ {
2
+ "schemaVersion": 1,
3
+ "package": "@sightspool/sdk",
4
+ "version": "0.4.0",
5
+ "sourceCommit": "83f3b2f3e21f9318bde55ff04bd8270999cbf6b1",
6
+ "sourceDirty": false,
7
+ "artifactId": "c21bee307a5c53e3ebb49d21f0f1ef2cce06a4483fa9824122bd6897ad6ca3ac",
8
+ "bundle": {
9
+ "file": "sdk.global.js",
10
+ "path": "releases/0.4.0/c21bee307a5c53e3ebb49d21f0f1ef2cce06a4483fa9824122bd6897ad6ca3ac/sdk.global.js",
11
+ "sha256": "ed80800d20ddd91aebde61c355bb15918c0c5cbd712b91e13604795f2d2a8aa9",
12
+ "integrity": "sha384-kfq0QJNOieKKBsyznFRRW9kAaC5fcXvDzu56zgNsSzbXCVw2aReY66mlq8Fldy6K",
13
+ "bytes": 4902,
14
+ "gzipBytes": 2238
15
+ },
16
+ "source": {
17
+ "file": "source.json",
18
+ "sha256": "256cb05370871f78328d531aa567e9717cc977632e9ebe42bc4a30de1e0e5e46"
19
+ },
20
+ "runtimeDependencies": []
21
+ }
@@ -0,0 +1,3 @@
1
+ var Sightspool=(function(exports){'use strict';var y=Symbol.for("sightspool.research.runtime.v1"),v=()=>typeof window=="undefined"?null:window,l=()=>{var e;return (e=v())==null?void 0:e[y]},a=e=>e.audience==="all_visitors"||e.identified;function h(e){var t;(t=e.button)==null||t.remove(),e.button=null,e.offer=null;}function c(e){var t;e.generation+=1,(t=e.pending)==null||t.abort(),e.pending=null,h(e);}function r(e,t){e.status=t;}async function u(e){if(e.disposed||e.paused||!a(e)||e.pending||document.visibilityState!=="visible")return;let t=e.generation,i=new AbortController;e.pending=i;let d=window.setTimeout(()=>i.abort(),1e4);e.button||r(e,"checking");try{let s=await fetch(e.endpoint+"/widget-offer",{method:"POST",credentials:"omit",cache:"no-store",referrerPolicy:"no-referrer",headers:{"Content-Type":"application/json"},body:JSON.stringify({operation:"offer",key:e.key,device:e.device}),signal:i.signal});if(!s.ok)throw Error("offer unavailable");let n=await s.json();if(e.disposed||t!==e.generation||e.paused||!a(e))return;if(n.available!==!0||typeof n.offer!="string"||!n.offer){h(e),r(e,"unavailable");return}if(e.offer=n.offer,r(e,"available"),e.button)return;let o=document.createElement("button");o.type="button",o.textContent="Talk to the founder \xB7 5 min",o.setAttribute("aria-label","Sightspool: join a five-minute user interview"),o.style.cssText="position:fixed;bottom:20px;right:20px;z-index:2147483000;padding:14px 18px;border:0;border-radius:16px;background:#171717;color:white;font:500 14px system-ui;box-shadow:0 8px 30px #0003;cursor:pointer;max-width:calc(100vw - 40px)",o.onclick=()=>{try{if(e.disposed||e.paused||!a(e)||!e.offer)return;if(e.popup&&!e.popup.closed){e.popup.focus();return}let g=new URLSearchParams({offer:e.offer,device:e.device});e.popup=window.open(e.endpoint+"/interview-widget#"+g,"sightspool-interview","popup,width=520,height=760");}catch(g){}},e.button=o,document.body.appendChild(o);}catch(s){!e.disposed&&t===e.generation&&(h(e),r(e,"error"));}finally{window.clearTimeout(d),e.pending===i&&(e.pending=null);}}function m(e){try{let t=v();if(!t||!e||!/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(e.key)||e.audience!=="all_visitors"&&e.audience!=="signed_in")return;let i=new URL(e.endpoint||"https://www.sightspool.com");if(i.protocol!=="https:"&&!(i.protocol==="http:"&&["localhost","127.0.0.1","[::1]"].includes(i.hostname))||i.username||i.password)return;let d=l();if(d&&d.key===e.key&&d.endpoint===i.origin&&d.audience===e.audience)return;d&&f();let s="";try{s=sessionStorage.getItem("sightspool-widget-device:"+e.key)||"";}catch(o){}if(!/^ss_fcd_[A-Za-z0-9_-]{43}$/.test(s)){let o=crypto.getRandomValues(new Uint8Array(32));s="ss_fcd_"+btoa(String.fromCharCode(...o)).replaceAll("+","-").replaceAll("/","_").replace(/=+$/,"");try{sessionStorage.setItem("sightspool-widget-device:"+e.key,s);}catch(g){}}let n={key:e.key,endpoint:i.origin,audience:e.audience,identified:!1,paused:!1,disposed:!1,generation:0,device:s,offer:null,button:null,popup:null,pending:null,timer:0,visibility:()=>{},status:"signed_out"};t[y]=n,n.visibility=()=>{try{document.visibilityState==="visible"?u(n):(c(n),r(n,n.paused?"paused":a(n)?"unavailable":"signed_out"));}catch(o){}},document.addEventListener("visibilitychange",n.visibility),n.timer=window.setInterval(()=>{u(n);},15e3),a(n)&&u(n);}catch(t){}}function b(e){try{let t=l();if(!t)return;let i=typeof e=="string"&&e.trim().length>0;if(!i&&!t.identified){!t.paused&&a(t)&&u(t);return}c(t),t.identified=i,r(t,t.paused?"paused":a(t)?"unavailable":"signed_out"),a(t)&&!t.paused&&u(t);}catch(t){}}function w(){try{let e=l();e&&(e.paused=!0,c(e),r(e,"paused"));}catch(e){}}function x(){try{let e=l();e&&(e.paused=!1,a(e)||r(e,"signed_out"),u(e));}catch(e){}}function f(){try{let e=l();if(!e)return;e.disposed=!0,c(e),window.clearInterval(e.timer),document.removeEventListener("visibilitychange",e.visibility),delete v()[y];}catch(e){}}function S(){var e,t;try{return (t=(e=l())==null?void 0:e.status)!=null?t:"not_initialized"}catch(i){return "error"}}var p={init:m,identify:b,pause:w,resume:x,destroy:f,getStatus:S};var A=p;try{let e=document.currentScript,t=(e==null?void 0:e.dataset.sightspoolKey)||(e==null?void 0:e.dataset.key),i=e==null?void 0:e.dataset.sightspoolAudience;t&&(i==="all_visitors"||i==="signed_in")&&(p.init({key:t,audience:i,endpoint:(e==null?void 0:e.dataset.sightspoolEndpoint)||new URL(e.src).origin}),e!=null&&e.dataset.userId&&p.identify(e.dataset.userId)),window.SightspoolResearch=p,Promise.resolve().then(()=>window.dispatchEvent(new Event("sightspool:ready")));}catch(e){}
2
+ exports.default=A;exports.destroy=f;exports.getStatus=S;exports.identify=b;exports.init=m;exports.pause=w;exports.resume=x;Object.defineProperty(exports,'__esModule',{value:true});return exports;})({});//# sourceMappingURL=sdk.global.js.map
3
+ //# sourceMappingURL=sdk.global.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/research.ts","../src/index.ts","../src/browser.ts"],"names":["slot","host","current","_a","eligible","r","remove","invalidate","status","value","check","generation","request","timeout","response","result","button","hash","e","init","config","browser","url","previous","destroy","device","bytes","identify","userId","identified","pause","resume","getStatus","_b","src_default","browser_default","script","key","audience"],"mappings":"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","file":"sdk.global.js","sourcesContent":["export type SightspoolConfig = {\n /** Public workspace widget key from Go live (UUID, not an old pk_live key). */\n key: string;\n /** Match the approved research audience. No default that widens recruitment. */\n audience: \"all_visitors\" | \"signed_in\";\n /** Sightspool origin. Defaults to the hosted application. */\n endpoint?: string;\n};\nexport type ResearchStatus =\n | \"not_initialized\" | \"signed_out\" | \"paused\" | \"checking\"\n | \"unavailable\" | \"available\" | \"error\";\n\ntype Runtime = {\n key: string; endpoint: string; audience: SightspoolConfig[\"audience\"]; identified: boolean; paused: boolean;\n disposed: boolean; generation: number; device: string; offer: string | null;\n button: HTMLButtonElement | null; popup: Window | null;\n pending: AbortController | null; timer: number; visibility: () => void;\n status: ResearchStatus;\n};\nconst slot = Symbol.for(\"sightspool.research.runtime.v1\");\ntype Host = Window & { [slot]?: Runtime };\nconst host = (): Host | null => typeof window === \"undefined\" ? null : window as Host;\nconst current = () => host()?.[slot];\nconst eligible = (r: Runtime) => r.audience === \"all_visitors\" || r.identified;\n\nfunction remove(r: Runtime) {\n r.button?.remove(); r.button = null; r.offer = null;\n}\nfunction invalidate(r: Runtime) {\n r.generation += 1; r.pending?.abort(); r.pending = null; remove(r);\n}\nfunction status(r: Runtime, value: ResearchStatus) { r.status = value; }\n\nasync function check(r: Runtime) {\n if (r.disposed || r.paused || !eligible(r) || r.pending || document.visibilityState !== \"visible\") return;\n const generation = r.generation;\n const request = new AbortController();\n r.pending = request;\n const timeout = window.setTimeout(() => request.abort(), 10_000);\n if (!r.button) status(r, \"checking\");\n try {\n const response = await fetch(r.endpoint + \"/widget-offer\", {\n method: \"POST\", credentials: \"omit\", cache: \"no-store\", referrerPolicy: \"no-referrer\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ operation: \"offer\", key: r.key, device: r.device }),\n signal: request.signal,\n });\n if (!response.ok) throw Error(\"offer unavailable\");\n const result = await response.json();\n if (r.disposed || generation !== r.generation || r.paused || !eligible(r)) return;\n if (result.available !== true || typeof result.offer !== \"string\" || !result.offer) {\n remove(r); status(r, \"unavailable\"); return;\n }\n r.offer = result.offer;\n status(r, \"available\");\n if (r.button) return;\n const button = document.createElement(\"button\");\n button.type = \"button\";\n button.textContent = \"Talk to the founder · 5 min\";\n button.setAttribute(\"aria-label\", \"Sightspool: join a five-minute user interview\");\n button.style.cssText = \"position:fixed;bottom:20px;right:20px;z-index:2147483000;padding:14px 18px;border:0;border-radius:16px;background:#171717;color:white;font:500 14px system-ui;box-shadow:0 8px 30px #0003;cursor:pointer;max-width:calc(100vw - 40px)\";\n button.onclick = () => {\n try {\n if (r.disposed || r.paused || !eligible(r) || !r.offer) return;\n if (r.popup && !r.popup.closed) { r.popup.focus(); return; }\n const hash = new URLSearchParams({ offer: r.offer, device: r.device });\n r.popup = window.open(r.endpoint + \"/interview-widget#\" + hash, \"sightspool-interview\", \"popup,width=520,height=760\");\n } catch { /* Host pages remain usable if popups are blocked. */ }\n };\n r.button = button;\n document.body.appendChild(button);\n } catch {\n if (!r.disposed && generation === r.generation) { remove(r); status(r, \"error\"); }\n } finally {\n window.clearTimeout(timeout);\n if (r.pending === request) r.pending = null;\n }\n}\n\n/** Start research for the chosen audience. Signed-in-only waits for identify(). */\nexport function init(config: SightspoolConfig): void {\n try {\n const browser = host();\n if (!browser || !config || !/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(config.key)) return;\n if (config.audience !== \"all_visitors\" && config.audience !== \"signed_in\") return;\n const url = new URL(config.endpoint || \"https://www.sightspool.com\");\n if (url.protocol !== \"https:\" && !(url.protocol === \"http:\" && [\"localhost\", \"127.0.0.1\", \"[::1]\"].includes(url.hostname))) return;\n if (url.username || url.password) return;\n const previous = current();\n if (previous && previous.key === config.key && previous.endpoint === url.origin && previous.audience === config.audience) return;\n if (previous) destroy();\n let device = \"\";\n try { device = sessionStorage.getItem(\"sightspool-widget-device:\" + config.key) || \"\"; } catch {}\n if (!/^ss_fcd_[A-Za-z0-9_-]{43}$/.test(device)) {\n const bytes = crypto.getRandomValues(new Uint8Array(32));\n device = \"ss_fcd_\" + btoa(String.fromCharCode(...bytes)).replaceAll(\"+\", \"-\").replaceAll(\"/\", \"_\").replace(/=+$/, \"\");\n try { sessionStorage.setItem(\"sightspool-widget-device:\" + config.key, device); } catch {}\n }\n const r: Runtime = {\n key: config.key, endpoint: url.origin, audience: config.audience, identified: false, paused: false,\n disposed: false, generation: 0, device, offer: null, button: null,\n popup: null, pending: null, timer: 0, visibility: () => {}, status: \"signed_out\",\n };\n browser[slot] = r;\n r.visibility = () => {\n try {\n if (document.visibilityState === \"visible\") void check(r);\n else { invalidate(r); status(r, r.paused ? \"paused\" : eligible(r) ? \"unavailable\" : \"signed_out\"); }\n } catch {}\n };\n document.addEventListener(\"visibilitychange\", r.visibility);\n r.timer = window.setInterval(() => { void check(r); }, 15_000);\n if (eligible(r)) void check(r);\n } catch { /* Never throw into the host application. */ }\n}\n\n/** Only the presence of an ID is retained. The ID itself is never stored or sent. */\nexport function identify(userId: string | null | undefined): void {\n try {\n const r = current();\n if (!r) return;\n const identified = typeof userId === \"string\" && userId.trim().length > 0;\n if (!identified && !r.identified) { if (!r.paused && eligible(r)) void check(r); return; }\n invalidate(r);\n r.identified = identified;\n status(r, r.paused ? \"paused\" : eligible(r) ? \"unavailable\" : \"signed_out\");\n if (eligible(r) && !r.paused) void check(r);\n } catch {}\n}\nexport function pause(): void {\n try { const r = current(); if (r) { r.paused = true; invalidate(r); status(r, \"paused\"); } } catch {}\n}\nexport function resume(): void {\n try { const r = current(); if (r) { r.paused = false; if (!eligible(r)) status(r, \"signed_out\"); void check(r); } } catch {}\n}\n/** Stop recruitment and remove listeners/UI. Does not end an already opened interview. */\nexport function destroy(): void {\n try {\n const r = current();\n if (!r) return;\n r.disposed = true; invalidate(r);\n window.clearInterval(r.timer);\n document.removeEventListener(\"visibilitychange\", r.visibility);\n delete host()![slot];\n } catch {}\n}\nexport function getStatus(): ResearchStatus {\n try { return current()?.status ?? \"not_initialized\"; } catch { return \"error\"; }\n}\n","// Research is the public SDK. The former capture engine is parked.\nexport { init, identify, pause, resume, destroy, getStatus } from \"./research\";\nexport type { SightspoolConfig, ResearchStatus } from \"./research\";\nimport { init, identify, pause, resume, destroy, getStatus } from \"./research\";\nexport default { init, identify, pause, resume, destroy, getStatus };\n","import api from \"./index\";\nexport * from \"./index\";\nexport default api;\n\ntry {\n const script = document.currentScript as HTMLScriptElement | null;\n const key = script?.dataset.sightspoolKey || script?.dataset.key;\n const audience = script?.dataset.sightspoolAudience;\n if (key && (audience === \"all_visitors\" || audience === \"signed_in\")) {\n api.init({ key, audience, endpoint: script?.dataset.sightspoolEndpoint || new URL(script!.src).origin });\n if (script?.dataset.userId) api.identify(script.dataset.userId);\n }\n // The old research-widget URL is an alias of this bundle, not another runtime.\n (window as Window & { SightspoolResearch?: typeof api }).SightspoolResearch = api;\n Promise.resolve().then(() => window.dispatchEvent(new Event(\"sightspool:ready\")));\n} catch { /* Browser auto-init must not interrupt the client app. */ }\n"]}
@@ -0,0 +1,11 @@
1
+ {
2
+ "files": {
3
+ "src/index.ts": "// Research is the public SDK. The former capture engine is parked.\nexport { init, identify, pause, resume, destroy, getStatus } from \"./research\";\nexport type { SightspoolConfig, ResearchStatus } from \"./research\";\nimport { init, identify, pause, resume, destroy, getStatus } from \"./research\";\nexport default { init, identify, pause, resume, destroy, getStatus };\n",
4
+ "src/browser.ts": "import api from \"./index\";\nexport * from \"./index\";\nexport default api;\n\ntry {\n const script = document.currentScript as HTMLScriptElement | null;\n const key = script?.dataset.sightspoolKey || script?.dataset.key;\n const audience = script?.dataset.sightspoolAudience;\n if (key && (audience === \"all_visitors\" || audience === \"signed_in\")) {\n api.init({ key, audience, endpoint: script?.dataset.sightspoolEndpoint || new URL(script!.src).origin });\n if (script?.dataset.userId) api.identify(script.dataset.userId);\n }\n // The old research-widget URL is an alias of this bundle, not another runtime.\n (window as Window & { SightspoolResearch?: typeof api }).SightspoolResearch = api;\n Promise.resolve().then(() => window.dispatchEvent(new Event(\"sightspool:ready\")));\n} catch { /* Browser auto-init must not interrupt the client app. */ }\n",
5
+ "src/research.ts": "export type SightspoolConfig = {\n /** Public workspace widget key from Go live (UUID, not an old pk_live key). */\n key: string;\n /** Match the approved research audience. No default that widens recruitment. */\n audience: \"all_visitors\" | \"signed_in\";\n /** Sightspool origin. Defaults to the hosted application. */\n endpoint?: string;\n};\nexport type ResearchStatus =\n | \"not_initialized\" | \"signed_out\" | \"paused\" | \"checking\"\n | \"unavailable\" | \"available\" | \"error\";\n\ntype Runtime = {\n key: string; endpoint: string; audience: SightspoolConfig[\"audience\"]; identified: boolean; paused: boolean;\n disposed: boolean; generation: number; device: string; offer: string | null;\n button: HTMLButtonElement | null; popup: Window | null;\n pending: AbortController | null; timer: number; visibility: () => void;\n status: ResearchStatus;\n};\nconst slot = Symbol.for(\"sightspool.research.runtime.v1\");\ntype Host = Window & { [slot]?: Runtime };\nconst host = (): Host | null => typeof window === \"undefined\" ? null : window as Host;\nconst current = () => host()?.[slot];\nconst eligible = (r: Runtime) => r.audience === \"all_visitors\" || r.identified;\n\nfunction remove(r: Runtime) {\n r.button?.remove(); r.button = null; r.offer = null;\n}\nfunction invalidate(r: Runtime) {\n r.generation += 1; r.pending?.abort(); r.pending = null; remove(r);\n}\nfunction status(r: Runtime, value: ResearchStatus) { r.status = value; }\n\nasync function check(r: Runtime) {\n if (r.disposed || r.paused || !eligible(r) || r.pending || document.visibilityState !== \"visible\") return;\n const generation = r.generation;\n const request = new AbortController();\n r.pending = request;\n const timeout = window.setTimeout(() => request.abort(), 10_000);\n if (!r.button) status(r, \"checking\");\n try {\n const response = await fetch(r.endpoint + \"/widget-offer\", {\n method: \"POST\", credentials: \"omit\", cache: \"no-store\", referrerPolicy: \"no-referrer\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ operation: \"offer\", key: r.key, device: r.device }),\n signal: request.signal,\n });\n if (!response.ok) throw Error(\"offer unavailable\");\n const result = await response.json();\n if (r.disposed || generation !== r.generation || r.paused || !eligible(r)) return;\n if (result.available !== true || typeof result.offer !== \"string\" || !result.offer) {\n remove(r); status(r, \"unavailable\"); return;\n }\n r.offer = result.offer;\n status(r, \"available\");\n if (r.button) return;\n const button = document.createElement(\"button\");\n button.type = \"button\";\n button.textContent = \"Talk to the founder · 5 min\";\n button.setAttribute(\"aria-label\", \"Sightspool: join a five-minute user interview\");\n button.style.cssText = \"position:fixed;bottom:20px;right:20px;z-index:2147483000;padding:14px 18px;border:0;border-radius:16px;background:#171717;color:white;font:500 14px system-ui;box-shadow:0 8px 30px #0003;cursor:pointer;max-width:calc(100vw - 40px)\";\n button.onclick = () => {\n try {\n if (r.disposed || r.paused || !eligible(r) || !r.offer) return;\n if (r.popup && !r.popup.closed) { r.popup.focus(); return; }\n const hash = new URLSearchParams({ offer: r.offer, device: r.device });\n r.popup = window.open(r.endpoint + \"/interview-widget#\" + hash, \"sightspool-interview\", \"popup,width=520,height=760\");\n } catch { /* Host pages remain usable if popups are blocked. */ }\n };\n r.button = button;\n document.body.appendChild(button);\n } catch {\n if (!r.disposed && generation === r.generation) { remove(r); status(r, \"error\"); }\n } finally {\n window.clearTimeout(timeout);\n if (r.pending === request) r.pending = null;\n }\n}\n\n/** Start research for the chosen audience. Signed-in-only waits for identify(). */\nexport function init(config: SightspoolConfig): void {\n try {\n const browser = host();\n if (!browser || !config || !/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(config.key)) return;\n if (config.audience !== \"all_visitors\" && config.audience !== \"signed_in\") return;\n const url = new URL(config.endpoint || \"https://www.sightspool.com\");\n if (url.protocol !== \"https:\" && !(url.protocol === \"http:\" && [\"localhost\", \"127.0.0.1\", \"[::1]\"].includes(url.hostname))) return;\n if (url.username || url.password) return;\n const previous = current();\n if (previous && previous.key === config.key && previous.endpoint === url.origin && previous.audience === config.audience) return;\n if (previous) destroy();\n let device = \"\";\n try { device = sessionStorage.getItem(\"sightspool-widget-device:\" + config.key) || \"\"; } catch {}\n if (!/^ss_fcd_[A-Za-z0-9_-]{43}$/.test(device)) {\n const bytes = crypto.getRandomValues(new Uint8Array(32));\n device = \"ss_fcd_\" + btoa(String.fromCharCode(...bytes)).replaceAll(\"+\", \"-\").replaceAll(\"/\", \"_\").replace(/=+$/, \"\");\n try { sessionStorage.setItem(\"sightspool-widget-device:\" + config.key, device); } catch {}\n }\n const r: Runtime = {\n key: config.key, endpoint: url.origin, audience: config.audience, identified: false, paused: false,\n disposed: false, generation: 0, device, offer: null, button: null,\n popup: null, pending: null, timer: 0, visibility: () => {}, status: \"signed_out\",\n };\n browser[slot] = r;\n r.visibility = () => {\n try {\n if (document.visibilityState === \"visible\") void check(r);\n else { invalidate(r); status(r, r.paused ? \"paused\" : eligible(r) ? \"unavailable\" : \"signed_out\"); }\n } catch {}\n };\n document.addEventListener(\"visibilitychange\", r.visibility);\n r.timer = window.setInterval(() => { void check(r); }, 15_000);\n if (eligible(r)) void check(r);\n } catch { /* Never throw into the host application. */ }\n}\n\n/** Only the presence of an ID is retained. The ID itself is never stored or sent. */\nexport function identify(userId: string | null | undefined): void {\n try {\n const r = current();\n if (!r) return;\n const identified = typeof userId === \"string\" && userId.trim().length > 0;\n if (!identified && !r.identified) { if (!r.paused && eligible(r)) void check(r); return; }\n invalidate(r);\n r.identified = identified;\n status(r, r.paused ? \"paused\" : eligible(r) ? \"unavailable\" : \"signed_out\");\n if (eligible(r) && !r.paused) void check(r);\n } catch {}\n}\nexport function pause(): void {\n try { const r = current(); if (r) { r.paused = true; invalidate(r); status(r, \"paused\"); } } catch {}\n}\nexport function resume(): void {\n try { const r = current(); if (r) { r.paused = false; if (!eligible(r)) status(r, \"signed_out\"); void check(r); } } catch {}\n}\n/** Stop recruitment and remove listeners/UI. Does not end an already opened interview. */\nexport function destroy(): void {\n try {\n const r = current();\n if (!r) return;\n r.disposed = true; invalidate(r);\n window.clearInterval(r.timer);\n document.removeEventListener(\"visibilitychange\", r.visibility);\n delete host()![slot];\n } catch {}\n}\nexport function getStatus(): ResearchStatus {\n try { return current()?.status ?? \"not_initialized\"; } catch { return \"error\"; }\n}\n",
6
+ "tsup.config.ts": "import { defineConfig } from \"tsup\";\n\n// npm (ESM/CJS/types) and the script-tag bundle share the research runtime.\n// Parked capture modules are intentionally absent from both dependency graphs.\nexport default defineConfig([\n {\n entry: { index: \"src/index.ts\" },\n format: [\"esm\", \"cjs\"],\n dts: true,\n sourcemap: true,\n clean: true,\n treeshake: true,\n minify: false,\n target: \"es2018\",\n },\n {\n entry: { sdk: \"src/browser.ts\" },\n format: [\"iife\"],\n globalName: \"Sightspool\",\n sourcemap: true,\n minify: true,\n treeshake: true,\n target: \"es2018\",\n },\n]);\n",
7
+ "package.json": "{\n \"name\": \"@sightspool/sdk\",\n \"version\": \"0.4.0\",\n \"description\": \"Sightspool research SDK \\u2014 invite website visitors and signed-in users into approved user research.\",\n \"type\": \"module\",\n \"main\": \"./dist/index.cjs\",\n \"module\": \"./dist/index.js\",\n \"types\": \"./dist/index.d.ts\",\n \"exports\": {\n \".\": {\n \"types\": \"./dist/index.d.ts\",\n \"import\": \"./dist/index.js\",\n \"require\": \"./dist/index.cjs\"\n }\n },\n \"files\": [\n \"dist\",\n \"README.md\",\n \"LICENSE\",\n \"NOTICE\",\n \"site\",\n \"SECURITY.md\",\n \"CHANGELOG.md\"\n ],\n \"sideEffects\": false,\n \"license\": \"Apache-2.0\",\n \"author\": \"Sightspool\",\n \"homepage\": \"https://github.com/sightspool/sdk#readme\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/sightspool/sdk.git\"\n },\n \"bugs\": {\n \"url\": \"https://github.com/sightspool/sdk/issues\"\n },\n \"keywords\": [\n \"sightspool\",\n \"user-research\",\n \"research\",\n \"interviews\",\n \"sdk\"\n ],\n \"engines\": {\n \"node\": \">=18\"\n },\n \"packageManager\": \"pnpm@9.15.0\",\n \"publishConfig\": {\n \"access\": \"public\"\n },\n \"scripts\": {\n \"build\": \"tsup && node scripts/build-release.mjs\",\n \"type-check\": \"tsc --noEmit\",\n \"test\": \"tsc --noEmit && node --test __tests__/*.test.ts\",\n \"prepublishOnly\": \"pnpm run build\",\n \"test:release\": \"node scripts/verify-release.mjs && node --test scripts/release.test.mjs\",\n \"build:site\": \"node scripts/stage-site.mjs\"\n },\n \"devDependencies\": {\n \"@types/node\": \"^24.10.4\",\n \"tsup\": \"^8.5.0\",\n \"typescript\": \"^5.9.3\"\n }\n}\n",
8
+ "pnpm-lock.yaml": "lockfileVersion: '9.0'\n\nsettings:\n autoInstallPeers: true\n excludeLinksFromLockfile: false\n\nimporters:\n\n .:\n devDependencies:\n '@types/node':\n specifier: ^24.10.4\n version: 24.13.1\n tsup:\n specifier: ^8.5.0\n version: 8.5.1(typescript@5.9.3)\n typescript:\n specifier: ^5.9.3\n version: 5.9.3\n\n packages/react:\n devDependencies:\n '@sightspool/sdk':\n specifier: workspace:^\n version: link:../..\n '@types/react':\n specifier: ^19.0.0\n version: 19.2.17\n react:\n specifier: ^19.0.0\n version: 19.2.7\n tsup:\n specifier: ^8.5.0\n version: 8.5.1(typescript@5.9.3)\n typescript:\n specifier: ^5.9.3\n version: 5.9.3\n\npackages:\n\n '@esbuild/aix-ppc64@0.27.7':\n resolution: {integrity: sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg==}\n engines: {node: '>=18'}\n cpu: [ppc64]\n os: [aix]\n\n '@esbuild/android-arm64@0.27.7':\n resolution: {integrity: sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ==}\n engines: {node: '>=18'}\n cpu: [arm64]\n os: [android]\n\n '@esbuild/android-arm@0.27.7':\n resolution: {integrity: sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ==}\n engines: {node: '>=18'}\n cpu: [arm]\n os: [android]\n\n '@esbuild/android-x64@0.27.7':\n resolution: {integrity: sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg==}\n engines: {node: '>=18'}\n cpu: [x64]\n os: [android]\n\n '@esbuild/darwin-arm64@0.27.7':\n resolution: {integrity: sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw==}\n engines: {node: '>=18'}\n cpu: [arm64]\n os: [darwin]\n\n '@esbuild/darwin-x64@0.27.7':\n resolution: {integrity: sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ==}\n engines: {node: '>=18'}\n cpu: [x64]\n os: [darwin]\n\n '@esbuild/freebsd-arm64@0.27.7':\n resolution: {integrity: sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w==}\n engines: {node: '>=18'}\n cpu: [arm64]\n os: [freebsd]\n\n '@esbuild/freebsd-x64@0.27.7':\n resolution: {integrity: sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ==}\n engines: {node: '>=18'}\n cpu: [x64]\n os: [freebsd]\n\n '@esbuild/linux-arm64@0.27.7':\n resolution: {integrity: sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A==}\n engines: {node: '>=18'}\n cpu: [arm64]\n os: [linux]\n\n '@esbuild/linux-arm@0.27.7':\n resolution: {integrity: sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA==}\n engines: {node: '>=18'}\n cpu: [arm]\n os: [linux]\n\n '@esbuild/linux-ia32@0.27.7':\n resolution: {integrity: sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg==}\n engines: {node: '>=18'}\n cpu: [ia32]\n os: [linux]\n\n '@esbuild/linux-loong64@0.27.7':\n resolution: {integrity: sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q==}\n engines: {node: '>=18'}\n cpu: [loong64]\n os: [linux]\n\n '@esbuild/linux-mips64el@0.27.7':\n resolution: {integrity: sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw==}\n engines: {node: '>=18'}\n cpu: [mips64el]\n os: [linux]\n\n '@esbuild/linux-ppc64@0.27.7':\n resolution: {integrity: sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ==}\n engines: {node: '>=18'}\n cpu: [ppc64]\n os: [linux]\n\n '@esbuild/linux-riscv64@0.27.7':\n resolution: {integrity: sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ==}\n engines: {node: '>=18'}\n cpu: [riscv64]\n os: [linux]\n\n '@esbuild/linux-s390x@0.27.7':\n resolution: {integrity: sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw==}\n engines: {node: '>=18'}\n cpu: [s390x]\n os: [linux]\n\n '@esbuild/linux-x64@0.27.7':\n resolution: {integrity: sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA==}\n engines: {node: '>=18'}\n cpu: [x64]\n os: [linux]\n\n '@esbuild/netbsd-arm64@0.27.7':\n resolution: {integrity: sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w==}\n engines: {node: '>=18'}\n cpu: [arm64]\n os: [netbsd]\n\n '@esbuild/netbsd-x64@0.27.7':\n resolution: {integrity: sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw==}\n engines: {node: '>=18'}\n cpu: [x64]\n os: [netbsd]\n\n '@esbuild/openbsd-arm64@0.27.7':\n resolution: {integrity: sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A==}\n engines: {node: '>=18'}\n cpu: [arm64]\n os: [openbsd]\n\n '@esbuild/openbsd-x64@0.27.7':\n resolution: {integrity: sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg==}\n engines: {node: '>=18'}\n cpu: [x64]\n os: [openbsd]\n\n '@esbuild/openharmony-arm64@0.27.7':\n resolution: {integrity: sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw==}\n engines: {node: '>=18'}\n cpu: [arm64]\n os: [openharmony]\n\n '@esbuild/sunos-x64@0.27.7':\n resolution: {integrity: sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA==}\n engines: {node: '>=18'}\n cpu: [x64]\n os: [sunos]\n\n '@esbuild/win32-arm64@0.27.7':\n resolution: {integrity: sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA==}\n engines: {node: '>=18'}\n cpu: [arm64]\n os: [win32]\n\n '@esbuild/win32-ia32@0.27.7':\n resolution: {integrity: sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw==}\n engines: {node: '>=18'}\n cpu: [ia32]\n os: [win32]\n\n '@esbuild/win32-x64@0.27.7':\n resolution: {integrity: sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg==}\n engines: {node: '>=18'}\n cpu: [x64]\n os: [win32]\n\n '@jridgewell/gen-mapping@0.3.13':\n resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==}\n\n '@jridgewell/resolve-uri@3.1.2':\n resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==}\n engines: {node: '>=6.0.0'}\n\n '@jridgewell/sourcemap-codec@1.5.5':\n resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==}\n\n '@jridgewell/trace-mapping@0.3.31':\n resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==}\n\n '@rollup/rollup-android-arm-eabi@4.61.1':\n resolution: {integrity: sha512-JnBB8MdXj45cajvTuO5FmPlvFVJRQgvrz1uSEl3NwqFnReAPGwb8EanbGi4z2nRaqLzjJSv5/JmycoTKlRZxHA==}\n cpu: [arm]\n os: [android]\n\n '@rollup/rollup-android-arm64@4.61.1':\n resolution: {integrity: sha512-Jx2g7iSjw4AOT0HDPHM9RV3GNjRXwybWtSFZiZAYUTjUwjVrYIwq3kBf+LnhqJlzXFAqTAh2F7IGI+O568exPw==}\n cpu: [arm64]\n os: [android]\n\n '@rollup/rollup-darwin-arm64@4.61.1':\n resolution: {integrity: sha512-0F1L/Z3Eqv8mT2n3dCpeO8GcTvHvVqkP5/t6DMsn0KzhYVcg+s7Ncl5DS8qjKYEeio6Az0Gt6nyBORay5qIlCA==}\n cpu: [arm64]\n os: [darwin]\n\n '@rollup/rollup-darwin-x64@4.61.1':\n resolution: {integrity: sha512-qLttcH871ujY4YcVfUSShhOw+CsoTatYz8gRbHO7Bb92QH059/P0y5do1KMs41fY0BpD2x4AJH/gID0zFiqVKQ==}\n cpu: [x64]\n os: [darwin]\n\n '@rollup/rollup-freebsd-arm64@4.61.1':\n resolution: {integrity: sha512-fUI4RapGE0Oh3mb8mgfvC1O2nU1RpDZUKnDQm3xB1Ipg7C2wTs5Kstz7G2uWK99a8S2yTMq8/P4uycwNa0nJyw==}\n cpu: [arm64]\n os: [freebsd]\n\n '@rollup/rollup-freebsd-x64@4.61.1':\n resolution: {integrity: sha512-H5YrdvJaDtI/U9/emrD4b++xkvp3y/JvOe4rizHbxvkyMfRS/CiRYdji+Pl8D0brEaNFWUh1drQxgAGIl6Xudw==}\n cpu: [x64]\n os: [freebsd]\n\n '@rollup/rollup-linux-arm-gnueabihf@4.61.1':\n resolution: {integrity: sha512-Q8CBCCQtDFrYtXoeUXSrnFXKOnyUhx6bz+SkL6A0E7V8kAiCJ5pamq1WtbfpVGhR5TSpXY6ak3avmDc5fHTyJA==}\n cpu: [arm]\n os: [linux]\n\n '@rollup/rollup-linux-arm-musleabihf@4.61.1':\n resolution: {integrity: sha512-nwnhk1581l0FBVellGcVCAT0Oi06onEA3WB53sf01VO3I0UPBkMH9sXONYME2K0ovXcNayJfNtHfm6mpJElatQ==}\n cpu: [arm]\n os: [linux]\n\n '@rollup/rollup-linux-arm64-gnu@4.61.1':\n resolution: {integrity: sha512-x5Xr49hwt3hdW75UOZm3395YwwzPyauktslv29KpWL/T+vVAzoT3azLcTWv0eMciBNrx+DYjH4paehHoLpPvpg==}\n cpu: [arm64]\n os: [linux]\n\n '@rollup/rollup-linux-arm64-musl@4.61.1':\n resolution: {integrity: sha512-unMS3H73DpaoPyyEVPjGKleM/s0mkmsauTENpw4INQY8y4+IuLNjkueQ5QCtC0D3N38Y38yhAU8OoZ20S2Tm6w==}\n cpu: [arm64]\n os: [linux]\n\n '@rollup/rollup-linux-loong64-gnu@4.61.1':\n resolution: {integrity: sha512-zNZzGRnAhwjFEYmvphJRV5XaQGjs62cCmeYYHUT//NbvEnHauw+I85nGG+SiVg5ld4GX8D1IbKIX+ozITQnhMQ==}\n cpu: [loong64]\n os: [linux]\n\n '@rollup/rollup-linux-loong64-musl@4.61.1':\n resolution: {integrity: sha512-LdpWGL8X209B2SIvWjqlc8VZgM6PKfontSerGepuldQmHYrAOtnMCXeJkxXGbC+PPZVOuu5czJo7fNV6aeW8rQ==}\n cpu: [loong64]\n os: [linux]\n\n '@rollup/rollup-linux-ppc64-gnu@4.61.1':\n resolution: {integrity: sha512-EC5kTtNaNGOmbMGqar8dvJy6y/hg99GAwjfBz++pxZhQATXGcRjd6c5en5wcbru0vkRmiMGsQKdMJOOf6sza4g==}\n cpu: [ppc64]\n os: [linux]\n\n '@rollup/rollup-linux-ppc64-musl@4.61.1':\n resolution: {integrity: sha512-8hiwp6D4acEcNK78I4rP0/XtS1sknWIAMJBPdR4l6zUtyTm5KiTDr5bXmWt4foY7nAN7AThDHgkLIEZOWKbzWw==}\n cpu: [ppc64]\n os: [linux]\n\n '@rollup/rollup-linux-riscv64-gnu@4.61.1':\n resolution: {integrity: sha512-10dh/h/BqA7DuMPWSxkR8uks18FRwnwOEqr5zOTEl+NOwP/OMzKX8OFR/Of9xxDA7D5qef1Nzar5WDD2kCCr1g==}\n cpu: [riscv64]\n os: [linux]\n\n '@rollup/rollup-linux-riscv64-musl@4.61.1':\n resolution: {integrity: sha512-YKJ5lg35DP17gcAOggnihe+APw9HLyj1Xn7gsmGumBJAUDa6NGXNixJzmkWLhcK9TOuuyQjdamzvJefkO7qHZQ==}\n cpu: [riscv64]\n os: [linux]\n\n '@rollup/rollup-linux-s390x-gnu@4.61.1':\n resolution: {integrity: sha512-Mlil5G2Jj6a7B3LWGctg+XPL9vdXYuzCtNXfxOQ0nPjc2m6ueUktocPGH9bnAM0bNRKb/bAWTujUU7IJQdQA+g==}\n cpu: [s390x]\n os: [linux]\n\n '@rollup/rollup-linux-x64-gnu@4.61.1':\n resolution: {integrity: sha512-bVWIOIk6pV01p4CdUbPP7CJ/434z+OooYjDuFcR+44N35YvKUC66G8MGnvcWx5mWKW3g61J+t74l3Kj15Kwn2Q==}\n cpu: [x64]\n os: [linux]\n\n '@rollup/rollup-linux-x64-musl@4.61.1':\n resolution: {integrity: sha512-qy5pBvZbqNFheBz61R1rzsezjm0J7O2oNGoWtGoY89SZYLUfxAJTBAqDChqAIdB4rCiIbi9nF7yZ83GnNiLwSw==}\n cpu: [x64]\n os: [linux]\n\n '@rollup/rollup-openbsd-x64@4.61.1':\n resolution: {integrity: sha512-E83TXjI4zm0+5f2qO+UOudaCYIhYwpJ5jq6YCZNIZ+6CbfhKrkAGezeiASBL9ElxAxFsRS9ZhESv8mfnj6TKeg==}\n cpu: [x64]\n os: [openbsd]\n\n '@rollup/rollup-openharmony-arm64@4.61.1':\n resolution: {integrity: sha512-fbWnKqVkjrJN38vNe3ahkbk6iejS/3b0Nt7EEtPpE6RBacZcGXNKbzfHN3GUUlXOPghUg0j6XUGrtjX9z1sIvA==}\n cpu: [arm64]\n os: [openharmony]\n\n '@rollup/rollup-win32-arm64-msvc@4.61.1':\n resolution: {integrity: sha512-ArMl38iVAbk0New1ogihQNY6iphLi4ZaRsa037gUzv5yeKPY8TD3Dmy4x2RNC1VztU/uqm+G+/RwFrSka3Oy2g==}\n cpu: [arm64]\n os: [win32]\n\n '@rollup/rollup-win32-ia32-msvc@4.61.1':\n resolution: {integrity: sha512-0mYtjHS9ucAbcATycCNK9IGBk/cCe/ma7EmSLGZdsxnOA8cjRIyU04wDpVAD9NiOfLUR9KTxdiO53uOkherqjQ==}\n cpu: [ia32]\n os: [win32]\n\n '@rollup/rollup-win32-x64-gnu@4.61.1':\n resolution: {integrity: sha512-gK1iCEPfpoSG9wfBihXxvBMi8ZfcWffYkEsC/Eih+iFENTaewvNcrEQ69lIOWYO5pePHKLHHO7nq5AILGO/HQQ==}\n cpu: [x64]\n os: [win32]\n\n '@rollup/rollup-win32-x64-msvc@4.61.1':\n resolution: {integrity: sha512-X+zaP2x+j4RXGfbp/seSoRHWnPxzApilDszisZxbYH5C/jTxFhCtDNdPGZb9lJyYPs24wGxruPF7Y+sIXt9Gzw==}\n cpu: [x64]\n os: [win32]\n\n '@types/estree@1.0.9':\n resolution: {integrity: sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==}\n\n '@types/node@24.13.1':\n resolution: {integrity: sha512-RSpUJGmvsJ1ZeBehQZFhIdpsz+bIpES0nIQXko4Ybq+N+kX6XvOq3Jo+iJ82FWLdblFq85AsMikd3m35jgezYg==}\n\n '@types/react@19.2.17':\n resolution: {integrity: sha512-MXfmqaVPEVgkBT/aY0aGCkRWWtByiYQXo3xdQ8r5RzuFrPiRn8Gar2tQdXSUQ2GKV3bkXckek89V8wQBY2Q/Aw==}\n\n acorn@8.16.0:\n resolution: {integrity: sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==}\n engines: {node: '>=0.4.0'}\n hasBin: true\n\n any-promise@1.3.0:\n resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==}\n\n bundle-require@5.1.0:\n resolution: {integrity: sha512-3WrrOuZiyaaZPWiEt4G3+IffISVC9HYlWueJEBWED4ZH4aIAC2PnkdnuRrR94M+w6yGWn4AglWtJtBI8YqvgoA==}\n engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}\n peerDependencies:\n esbuild: '>=0.18'\n\n cac@6.7.14:\n resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==}\n engines: {node: '>=8'}\n\n chokidar@4.0.3:\n resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==}\n engines: {node: '>= 14.16.0'}\n\n commander@4.1.1:\n resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==}\n engines: {node: '>= 6'}\n\n confbox@0.1.8:\n resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==}\n\n consola@3.4.2:\n resolution: {integrity: sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==}\n engines: {node: ^14.18.0 || >=16.10.0}\n\n csstype@3.2.3:\n resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==}\n\n debug@4.4.3:\n resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==}\n engines: {node: '>=6.0'}\n peerDependencies:\n supports-color: '*'\n peerDependenciesMeta:\n supports-color:\n optional: true\n\n esbuild@0.27.7:\n resolution: {integrity: sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w==}\n engines: {node: '>=18'}\n hasBin: true\n\n fdir@6.5.0:\n resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==}\n engines: {node: '>=12.0.0'}\n peerDependencies:\n picomatch: ^3 || ^4\n peerDependenciesMeta:\n picomatch:\n optional: true\n\n fix-dts-default-cjs-exports@1.0.1:\n resolution: {integrity: sha512-pVIECanWFC61Hzl2+oOCtoJ3F17kglZC/6N94eRWycFgBH35hHx0Li604ZIzhseh97mf2p0cv7vVrOZGoqhlEg==}\n\n fsevents@2.3.3:\n resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}\n engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}\n os: [darwin]\n\n joycon@3.1.1:\n resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==}\n engines: {node: '>=10'}\n\n lilconfig@3.1.3:\n resolution: {integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==}\n engines: {node: '>=14'}\n\n lines-and-columns@1.2.4:\n resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==}\n\n load-tsconfig@0.2.5:\n resolution: {integrity: sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg==}\n engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}\n\n magic-string@0.30.21:\n resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==}\n\n mlly@1.8.2:\n resolution: {integrity: sha512-d+ObxMQFmbt10sretNDytwt85VrbkhhUA/JBGm1MPaWJ65Cl4wOgLaB1NYvJSZ0Ef03MMEU/0xpPMXUIQ29UfA==}\n\n ms@2.1.3:\n resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}\n\n mz@2.7.0:\n resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==}\n\n object-assign@4.1.1:\n resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==}\n engines: {node: '>=0.10.0'}\n\n pathe@2.0.3:\n resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==}\n\n picocolors@1.1.1:\n resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}\n\n picomatch@4.0.4:\n resolution: {integrity: sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==}\n engines: {node: '>=12'}\n\n pirates@4.0.7:\n resolution: {integrity: sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==}\n engines: {node: '>= 6'}\n\n pkg-types@1.3.1:\n resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==}\n\n postcss-load-config@6.0.1:\n resolution: {integrity: sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==}\n engines: {node: '>= 18'}\n peerDependencies:\n jiti: '>=1.21.0'\n postcss: '>=8.0.9'\n tsx: ^4.8.1\n yaml: ^2.4.2\n peerDependenciesMeta:\n jiti:\n optional: true\n postcss:\n optional: true\n tsx:\n optional: true\n yaml:\n optional: true\n\n react@19.2.7:\n resolution: {integrity: sha512-HNe9WslTbXmFK8o8cmwgAeJFSBvt1bPdHCVKtaaV+WlAN36mpT4hcRpwbf3fY56ar2oIXzsBpOAiIRHAdY0OlQ==}\n engines: {node: '>=0.10.0'}\n\n readdirp@4.1.2:\n resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==}\n engines: {node: '>= 14.18.0'}\n\n resolve-from@5.0.0:\n resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==}\n engines: {node: '>=8'}\n\n rollup@4.61.1:\n resolution: {integrity: sha512-I4KW6iuRpuu2uHBLraZ1wNZe0DP7lnRha+VJ9tNaYVaVgKhW0aI3h4RYnoRPeql0flHm/Co55b7snEDcOfOJrA==}\n engines: {node: '>=18.0.0', npm: '>=8.0.0'}\n hasBin: true\n\n source-map@0.7.6:\n resolution: {integrity: sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==}\n engines: {node: '>= 12'}\n\n sucrase@3.35.1:\n resolution: {integrity: sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==}\n engines: {node: '>=16 || 14 >=14.17'}\n hasBin: true\n\n thenify-all@1.6.0:\n resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==}\n engines: {node: '>=0.8'}\n\n thenify@3.3.1:\n resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==}\n\n tinyexec@0.3.2:\n resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==}\n\n tinyglobby@0.2.17:\n resolution: {integrity: sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==}\n engines: {node: '>=12.0.0'}\n\n tree-kill@1.2.2:\n resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==}\n hasBin: true\n\n ts-interface-checker@0.1.13:\n resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==}\n\n tsup@8.5.1:\n resolution: {integrity: sha512-xtgkqwdhpKWr3tKPmCkvYmS9xnQK3m3XgxZHwSUjvfTjp7YfXe5tT3GgWi0F2N+ZSMsOeWeZFh7ZZFg5iPhing==}\n engines: {node: '>=18'}\n hasBin: true\n peerDependencies:\n '@microsoft/api-extractor': ^7.36.0\n '@swc/core': ^1\n postcss: ^8.4.12\n typescript: '>=4.5.0'\n peerDependenciesMeta:\n '@microsoft/api-extractor':\n optional: true\n '@swc/core':\n optional: true\n postcss:\n optional: true\n typescript:\n optional: true\n\n typescript@5.9.3:\n resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==}\n engines: {node: '>=14.17'}\n hasBin: true\n\n ufo@1.6.4:\n resolution: {integrity: sha512-JFNbkD1Svwe0KvGi8GOeLcP4kAWQ609twvCdcHxq1oSL8svv39ZuSvajcD8B+5D0eL4+s1Is2D/O6KN3qcTeRA==}\n\n undici-types@7.18.2:\n resolution: {integrity: sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==}\n\nsnapshots:\n\n '@esbuild/aix-ppc64@0.27.7':\n optional: true\n\n '@esbuild/android-arm64@0.27.7':\n optional: true\n\n '@esbuild/android-arm@0.27.7':\n optional: true\n\n '@esbuild/android-x64@0.27.7':\n optional: true\n\n '@esbuild/darwin-arm64@0.27.7':\n optional: true\n\n '@esbuild/darwin-x64@0.27.7':\n optional: true\n\n '@esbuild/freebsd-arm64@0.27.7':\n optional: true\n\n '@esbuild/freebsd-x64@0.27.7':\n optional: true\n\n '@esbuild/linux-arm64@0.27.7':\n optional: true\n\n '@esbuild/linux-arm@0.27.7':\n optional: true\n\n '@esbuild/linux-ia32@0.27.7':\n optional: true\n\n '@esbuild/linux-loong64@0.27.7':\n optional: true\n\n '@esbuild/linux-mips64el@0.27.7':\n optional: true\n\n '@esbuild/linux-ppc64@0.27.7':\n optional: true\n\n '@esbuild/linux-riscv64@0.27.7':\n optional: true\n\n '@esbuild/linux-s390x@0.27.7':\n optional: true\n\n '@esbuild/linux-x64@0.27.7':\n optional: true\n\n '@esbuild/netbsd-arm64@0.27.7':\n optional: true\n\n '@esbuild/netbsd-x64@0.27.7':\n optional: true\n\n '@esbuild/openbsd-arm64@0.27.7':\n optional: true\n\n '@esbuild/openbsd-x64@0.27.7':\n optional: true\n\n '@esbuild/openharmony-arm64@0.27.7':\n optional: true\n\n '@esbuild/sunos-x64@0.27.7':\n optional: true\n\n '@esbuild/win32-arm64@0.27.7':\n optional: true\n\n '@esbuild/win32-ia32@0.27.7':\n optional: true\n\n '@esbuild/win32-x64@0.27.7':\n optional: true\n\n '@jridgewell/gen-mapping@0.3.13':\n dependencies:\n '@jridgewell/sourcemap-codec': 1.5.5\n '@jridgewell/trace-mapping': 0.3.31\n\n '@jridgewell/resolve-uri@3.1.2': {}\n\n '@jridgewell/sourcemap-codec@1.5.5': {}\n\n '@jridgewell/trace-mapping@0.3.31':\n dependencies:\n '@jridgewell/resolve-uri': 3.1.2\n '@jridgewell/sourcemap-codec': 1.5.5\n\n '@rollup/rollup-android-arm-eabi@4.61.1':\n optional: true\n\n '@rollup/rollup-android-arm64@4.61.1':\n optional: true\n\n '@rollup/rollup-darwin-arm64@4.61.1':\n optional: true\n\n '@rollup/rollup-darwin-x64@4.61.1':\n optional: true\n\n '@rollup/rollup-freebsd-arm64@4.61.1':\n optional: true\n\n '@rollup/rollup-freebsd-x64@4.61.1':\n optional: true\n\n '@rollup/rollup-linux-arm-gnueabihf@4.61.1':\n optional: true\n\n '@rollup/rollup-linux-arm-musleabihf@4.61.1':\n optional: true\n\n '@rollup/rollup-linux-arm64-gnu@4.61.1':\n optional: true\n\n '@rollup/rollup-linux-arm64-musl@4.61.1':\n optional: true\n\n '@rollup/rollup-linux-loong64-gnu@4.61.1':\n optional: true\n\n '@rollup/rollup-linux-loong64-musl@4.61.1':\n optional: true\n\n '@rollup/rollup-linux-ppc64-gnu@4.61.1':\n optional: true\n\n '@rollup/rollup-linux-ppc64-musl@4.61.1':\n optional: true\n\n '@rollup/rollup-linux-riscv64-gnu@4.61.1':\n optional: true\n\n '@rollup/rollup-linux-riscv64-musl@4.61.1':\n optional: true\n\n '@rollup/rollup-linux-s390x-gnu@4.61.1':\n optional: true\n\n '@rollup/rollup-linux-x64-gnu@4.61.1':\n optional: true\n\n '@rollup/rollup-linux-x64-musl@4.61.1':\n optional: true\n\n '@rollup/rollup-openbsd-x64@4.61.1':\n optional: true\n\n '@rollup/rollup-openharmony-arm64@4.61.1':\n optional: true\n\n '@rollup/rollup-win32-arm64-msvc@4.61.1':\n optional: true\n\n '@rollup/rollup-win32-ia32-msvc@4.61.1':\n optional: true\n\n '@rollup/rollup-win32-x64-gnu@4.61.1':\n optional: true\n\n '@rollup/rollup-win32-x64-msvc@4.61.1':\n optional: true\n\n '@types/estree@1.0.9': {}\n\n '@types/node@24.13.1':\n dependencies:\n undici-types: 7.18.2\n\n '@types/react@19.2.17':\n dependencies:\n csstype: 3.2.3\n\n acorn@8.16.0: {}\n\n any-promise@1.3.0: {}\n\n bundle-require@5.1.0(esbuild@0.27.7):\n dependencies:\n esbuild: 0.27.7\n load-tsconfig: 0.2.5\n\n cac@6.7.14: {}\n\n chokidar@4.0.3:\n dependencies:\n readdirp: 4.1.2\n\n commander@4.1.1: {}\n\n confbox@0.1.8: {}\n\n consola@3.4.2: {}\n\n csstype@3.2.3: {}\n\n debug@4.4.3:\n dependencies:\n ms: 2.1.3\n\n esbuild@0.27.7:\n optionalDependencies:\n '@esbuild/aix-ppc64': 0.27.7\n '@esbuild/android-arm': 0.27.7\n '@esbuild/android-arm64': 0.27.7\n '@esbuild/android-x64': 0.27.7\n '@esbuild/darwin-arm64': 0.27.7\n '@esbuild/darwin-x64': 0.27.7\n '@esbuild/freebsd-arm64': 0.27.7\n '@esbuild/freebsd-x64': 0.27.7\n '@esbuild/linux-arm': 0.27.7\n '@esbuild/linux-arm64': 0.27.7\n '@esbuild/linux-ia32': 0.27.7\n '@esbuild/linux-loong64': 0.27.7\n '@esbuild/linux-mips64el': 0.27.7\n '@esbuild/linux-ppc64': 0.27.7\n '@esbuild/linux-riscv64': 0.27.7\n '@esbuild/linux-s390x': 0.27.7\n '@esbuild/linux-x64': 0.27.7\n '@esbuild/netbsd-arm64': 0.27.7\n '@esbuild/netbsd-x64': 0.27.7\n '@esbuild/openbsd-arm64': 0.27.7\n '@esbuild/openbsd-x64': 0.27.7\n '@esbuild/openharmony-arm64': 0.27.7\n '@esbuild/sunos-x64': 0.27.7\n '@esbuild/win32-arm64': 0.27.7\n '@esbuild/win32-ia32': 0.27.7\n '@esbuild/win32-x64': 0.27.7\n\n fdir@6.5.0(picomatch@4.0.4):\n optionalDependencies:\n picomatch: 4.0.4\n\n fix-dts-default-cjs-exports@1.0.1:\n dependencies:\n magic-string: 0.30.21\n mlly: 1.8.2\n rollup: 4.61.1\n\n fsevents@2.3.3:\n optional: true\n\n joycon@3.1.1: {}\n\n lilconfig@3.1.3: {}\n\n lines-and-columns@1.2.4: {}\n\n load-tsconfig@0.2.5: {}\n\n magic-string@0.30.21:\n dependencies:\n '@jridgewell/sourcemap-codec': 1.5.5\n\n mlly@1.8.2:\n dependencies:\n acorn: 8.16.0\n pathe: 2.0.3\n pkg-types: 1.3.1\n ufo: 1.6.4\n\n ms@2.1.3: {}\n\n mz@2.7.0:\n dependencies:\n any-promise: 1.3.0\n object-assign: 4.1.1\n thenify-all: 1.6.0\n\n object-assign@4.1.1: {}\n\n pathe@2.0.3: {}\n\n picocolors@1.1.1: {}\n\n picomatch@4.0.4: {}\n\n pirates@4.0.7: {}\n\n pkg-types@1.3.1:\n dependencies:\n confbox: 0.1.8\n mlly: 1.8.2\n pathe: 2.0.3\n\n postcss-load-config@6.0.1:\n dependencies:\n lilconfig: 3.1.3\n\n react@19.2.7: {}\n\n readdirp@4.1.2: {}\n\n resolve-from@5.0.0: {}\n\n rollup@4.61.1:\n dependencies:\n '@types/estree': 1.0.9\n optionalDependencies:\n '@rollup/rollup-android-arm-eabi': 4.61.1\n '@rollup/rollup-android-arm64': 4.61.1\n '@rollup/rollup-darwin-arm64': 4.61.1\n '@rollup/rollup-darwin-x64': 4.61.1\n '@rollup/rollup-freebsd-arm64': 4.61.1\n '@rollup/rollup-freebsd-x64': 4.61.1\n '@rollup/rollup-linux-arm-gnueabihf': 4.61.1\n '@rollup/rollup-linux-arm-musleabihf': 4.61.1\n '@rollup/rollup-linux-arm64-gnu': 4.61.1\n '@rollup/rollup-linux-arm64-musl': 4.61.1\n '@rollup/rollup-linux-loong64-gnu': 4.61.1\n '@rollup/rollup-linux-loong64-musl': 4.61.1\n '@rollup/rollup-linux-ppc64-gnu': 4.61.1\n '@rollup/rollup-linux-ppc64-musl': 4.61.1\n '@rollup/rollup-linux-riscv64-gnu': 4.61.1\n '@rollup/rollup-linux-riscv64-musl': 4.61.1\n '@rollup/rollup-linux-s390x-gnu': 4.61.1\n '@rollup/rollup-linux-x64-gnu': 4.61.1\n '@rollup/rollup-linux-x64-musl': 4.61.1\n '@rollup/rollup-openbsd-x64': 4.61.1\n '@rollup/rollup-openharmony-arm64': 4.61.1\n '@rollup/rollup-win32-arm64-msvc': 4.61.1\n '@rollup/rollup-win32-ia32-msvc': 4.61.1\n '@rollup/rollup-win32-x64-gnu': 4.61.1\n '@rollup/rollup-win32-x64-msvc': 4.61.1\n fsevents: 2.3.3\n\n source-map@0.7.6: {}\n\n sucrase@3.35.1:\n dependencies:\n '@jridgewell/gen-mapping': 0.3.13\n commander: 4.1.1\n lines-and-columns: 1.2.4\n mz: 2.7.0\n pirates: 4.0.7\n tinyglobby: 0.2.17\n ts-interface-checker: 0.1.13\n\n thenify-all@1.6.0:\n dependencies:\n thenify: 3.3.1\n\n thenify@3.3.1:\n dependencies:\n any-promise: 1.3.0\n\n tinyexec@0.3.2: {}\n\n tinyglobby@0.2.17:\n dependencies:\n fdir: 6.5.0(picomatch@4.0.4)\n picomatch: 4.0.4\n\n tree-kill@1.2.2: {}\n\n ts-interface-checker@0.1.13: {}\n\n tsup@8.5.1(typescript@5.9.3):\n dependencies:\n bundle-require: 5.1.0(esbuild@0.27.7)\n cac: 6.7.14\n chokidar: 4.0.3\n consola: 3.4.2\n debug: 4.4.3\n esbuild: 0.27.7\n fix-dts-default-cjs-exports: 1.0.1\n joycon: 3.1.1\n picocolors: 1.1.1\n postcss-load-config: 6.0.1\n resolve-from: 5.0.0\n rollup: 4.61.1\n source-map: 0.7.6\n sucrase: 3.35.1\n tinyexec: 0.3.2\n tinyglobby: 0.2.17\n tree-kill: 1.2.2\n optionalDependencies:\n typescript: 5.9.3\n transitivePeerDependencies:\n - jiti\n - supports-color\n - tsx\n - yaml\n\n typescript@5.9.3: {}\n\n ufo@1.6.4: {}\n\n undici-types@7.18.2: {}\n",
9
+ "scripts/build-release.mjs": "import { readFileSync, writeFileSync } from 'node:fs';\nimport { createHash } from 'node:crypto';\nimport { gzipSync } from 'node:zlib';\nimport { execFileSync } from 'node:child_process';\nconst digest = (bytes, algorithm = 'sha256', encoding = 'hex') => createHash(algorithm).update(bytes).digest(encoding);\nconst pkg = JSON.parse(readFileSync('package.json', 'utf8'));\nconst bundle = readFileSync('dist/sdk.global.js');\nconst sourceFiles = ['src/index.ts', 'src/browser.ts', 'src/research.ts', 'tsup.config.ts', 'package.json', 'pnpm-lock.yaml', 'scripts/build-release.mjs'];\nconst files = Object.fromEntries(sourceFiles.map(path => [path, readFileSync(path, 'utf8')]));\nconst source = JSON.stringify({ files }, null, 2) + '\\n';\nconst sha256 = digest(bundle);\nconst sourceCommit = execFileSync('git', ['rev-parse', 'HEAD'], {encoding:'utf8'}).trim();\nconst sourceDirty = Boolean(execFileSync('git', ['status', '--porcelain', '--untracked-files=normal'], {encoding:'utf8'}).trim());\nconst artifactId = digest(JSON.stringify([pkg.version, sha256, digest(source), sourceCommit, sourceDirty]));\nconst manifest = {\n schemaVersion: 1, package: pkg.name, version: pkg.version,\n sourceCommit, sourceDirty, artifactId,\n bundle: { file: 'sdk.global.js', path: `releases/${pkg.version}/${artifactId}/sdk.global.js`, sha256,\n integrity: 'sha384-' + digest(bundle, 'sha384', 'base64'), bytes: bundle.length, gzipBytes: gzipSync(bundle).length },\n source: { file: 'source.json', sha256: digest(source) },\n runtimeDependencies: Object.keys(pkg.dependencies || {}),\n};\nwriteFileSync('dist/source.json', source);\nwriteFileSync('dist/release.json', JSON.stringify(manifest, null, 2) + '\\n');\nconsole.log(`Prepared ${pkg.name} ${pkg.version}: ${bundle.length} bytes, ${manifest.bundle.gzipBytes} gzip bytes. No publication performed.`);\n"
10
+ }
11
+ }
@@ -0,0 +1,69 @@
1
+
2
+ :root {
3
+ --fg: #18181b;
4
+ --muted: #52525b;
5
+ --faint: #71717a;
6
+ --line: #e4e4e7;
7
+ --bg: #ffffff;
8
+ --code-bg: #f4f4f5;
9
+ --accent: #18181b;
10
+ --max: 760px;
11
+ }
12
+ * { box-sizing: border-box; }
13
+ html { -webkit-text-size-adjust: 100%; }
14
+ body {
15
+ margin: 0;
16
+ font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
17
+ color: var(--fg);
18
+ background: var(--bg);
19
+ line-height: 1.6;
20
+ font-size: 16px;
21
+ }
22
+ .wrap { max-width: var(--max); margin: 0 auto; padding: 48px 20px 96px; }
23
+ header { border-bottom: 1px solid var(--line); padding-bottom: 24px; margin-bottom: 8px; }
24
+ h1 { font-size: 30px; margin: 0 0 6px; letter-spacing: -0.02em; }
25
+ h2 { font-size: 22px; margin: 44px 0 12px; letter-spacing: -0.01em; }
26
+ h3 { font-size: 17px; margin: 28px 0 8px; }
27
+ p { margin: 12px 0; }
28
+ .lede { font-size: 18px; color: var(--muted); }
29
+ .status { font-size: 14px; color: var(--faint); margin-top: 14px; }
30
+ a { color: var(--accent); text-underline-offset: 2px; }
31
+ nav.links { display: flex; flex-wrap: wrap; gap: 8px 16px; margin: 16px 0 0; font-size: 14px; }
32
+ code { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: 0.88em;
33
+ background: var(--code-bg); padding: 1px 5px; border-radius: 4px; }
34
+ pre { background: var(--code-bg); border: 1px solid var(--line); border-radius: 10px;
35
+ padding: 14px 16px; overflow-x: auto; font-size: 13.5px; line-height: 1.5; }
36
+ pre code { background: none; padding: 0; font-size: inherit; }
37
+ table { border-collapse: collapse; width: 100%; margin: 14px 0; font-size: 14.5px; }
38
+ th, td { text-align: left; vertical-align: top; padding: 8px 10px; border-bottom: 1px solid var(--line); }
39
+ th { font-weight: 600; }
40
+ td code { white-space: nowrap; }
41
+ blockquote { margin: 16px 0; padding: 10px 16px; border-left: 3px solid var(--line);
42
+ color: var(--muted); background: #fafafa; border-radius: 0 8px 8px 0; }
43
+ .toc { font-size: 14px; color: var(--muted); margin: 24px 0 0; }
44
+ .toc a { margin-right: 14px; white-space: nowrap; }
45
+ footer { margin-top: 64px; padding-top: 20px; border-top: 1px solid var(--line);
46
+ font-size: 14px; color: var(--faint); }
47
+ hr { border: none; border-top: 1px solid var(--line); margin: 40px 0; }
48
+
49
+ :root { --accent:#75415f; --max:920px; --bg:#fcfafb; --code-bg:#f4eff2; }
50
+ html { scroll-behavior:smooth; }
51
+ .wrap { padding-top:32px; }
52
+ h1 { font-size:clamp(32px,5vw,48px); line-height:1.12; margin:24px 0 18px; }
53
+ h2 { scroll-margin-top:20px; }
54
+ pre { white-space:pre-wrap; overflow-wrap:anywhere; }
55
+ a:focus-visible,button:focus-visible,summary:focus-visible { outline:3px solid #75415f; outline-offset:4px; }
56
+ nav { display:flex;flex-wrap:wrap;gap:10px 24px; padding-bottom:18px; border-bottom:1px solid var(--line); }
57
+ .status,.note { padding:16px 20px; background:#f3ebf0; border:1px solid #ded0d9; border-radius:12px; color:#56344a; }
58
+ .cards { display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:16px;margin:24px 0; }
59
+ .card { padding:20px;border:1px solid var(--line);border-radius:14px;background:white; }
60
+ .card strong { display:block; margin-bottom:8px; }
61
+ .table-wrap { overflow-x:auto; }
62
+ table { width:100%; border-collapse:collapse; }
63
+ th,td { text-align:left;padding:14px 12px;vertical-align:top;border-bottom:1px solid var(--line); }
64
+ button,.button { background:var(--accent);color:white;border:0;border-radius:8px;padding:11px 16px;cursor:pointer;font:inherit;display:inline-block;text-decoration:none; }
65
+ button.secondary { color:var(--accent);background:#eee4eb; }
66
+ .controls { display:flex;flex-wrap:wrap;gap:10px;margin:20px 0; }
67
+ .muted {color:var(--muted);} .hash {word-break:break-all;font-size:13px;}
68
+ footer {margin-top:56px;padding-top:24px;border-top:1px solid var(--line);font-size:14px;}
69
+ @media(prefers-reduced-motion:reduce){html{scroll-behavior:auto;}}