typebulb 0.4.5 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -2
- package/dist/index.js +205 -32
- package/package.json +8 -3
package/README.md
CHANGED
|
@@ -42,8 +42,8 @@ npm install -g typebulb
|
|
|
42
42
|
## Usage
|
|
43
43
|
|
|
44
44
|
```
|
|
45
|
-
typebulb
|
|
46
|
-
typebulb
|
|
45
|
+
typebulb [file.bulb.md] Run a bulb (defaults to .bulb.md in cwd)
|
|
46
|
+
typebulb check [file.bulb.md] Type-check a bulb without running it
|
|
47
47
|
typebulb --no-watch <file> Disable hot reload
|
|
48
48
|
typebulb --port 3333 <file> Custom port
|
|
49
49
|
typebulb --no-open <file> Don't auto-open browser
|
|
@@ -58,9 +58,11 @@ typebulb --version Show version
|
|
|
58
58
|
- **CLI logging** — `tb.server.log(...)` prints to the CLI's stdout
|
|
59
59
|
- **Env files** — `.env` and `.env.local` auto-loaded from cwd
|
|
60
60
|
- **Server mode** — `--server` runs only the `**server.ts**` section in Node, skipping the web server. Bulbs with only `**server.ts**` (no `**code.tsx**`) use this mode automatically.
|
|
61
|
+
- **Type-check without running** — `typebulb check <file>` runs `tsc --noEmit` against the bulb and exits non-zero on errors. Useful for AI editors / CI.
|
|
61
62
|
- **Filesystem access** — `tb.fs.read()` and `tb.fs.write()` for local files
|
|
62
63
|
- **Hot reload** — Recompiles on save and refreshes the browser (on by default; disable with `--no-watch`)
|
|
63
64
|
- **Package resolution** — Client dependencies are automatically resolved by generating import maps (same resolver as typebulb.com). Server dependencies are automatically installed via npm.
|
|
65
|
+
- **Local caching** — Resolver metadata and CDN package bytes are cached under `~/.typebulb/cache/`, so repeat runs don't re-hit the network and warm runs work offline.
|
|
64
66
|
- **AI calls** — `tb.ai()` for general-purpose AI (chatbots, agents, experiments). `tb.models()` lists available models. Set API keys in `.env` (see below).
|
|
65
67
|
|
|
66
68
|
## AI Setup
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,178 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import*as
|
|
3
|
-
`),t=0;if(e[t]?.trim()!=="---")return null;t++;let r=[];for(;t<e.length&&e[t]?.trim()!=="---";)r.push(e[t]),t++;if(e[t]?.trim()!=="---")return null;t++;let
|
|
4
|
-
`))}else t++}return{frontmatter:s,files:o}}catch{return null}}function De(n){let e={};for(let t of n){let r=t.indexOf(":");if(r===-1)continue;let s=t.slice(0,r).trim(),o=t.slice(r+1).trim();switch(s){case"format":e.format=o;break;case"name":e.name=Be(o);break}}return!e.format?.startsWith("typebulb")||!e.name?null:e}function Be(n){return n.startsWith('"')&&n.endsWith('"')?n.slice(1,-1).replace(/\\"/g,'"'):n.startsWith("'")&&n.endsWith("'")?n.slice(1,-1):n}function J(n){let e=t=>n.files.get(Ce[t].path)||"";return{name:n.frontmatter.name,code:e("code"),css:e("css"),html:e("html"),config:e("config"),notes:e("notes"),data:e("data"),infer:e("infer"),insight:e("insight"),server:e("server")}}function Ne(n){try{return JSON.parse(n),!0}catch{}return!!(/^\s*<[\s\S]*>/.test(n)||/^---\s*$/m.test(n)||/^\w[\w\s]*:[ \t]/m.test(n))}function le(n){let e=n.trim();return e?Ne(e)?[e]:n.split(/\n\n\n+/).map(t=>t.trim()).filter(Boolean):[]}function z(n){if(!n.trim())return{};try{return JSON.parse(n)}catch{return{}}}import{transform as pe}from"sucrase";function je(n,e){try{let{code:t}=pe(n,{transforms:["typescript","jsx"],jsxRuntime:"automatic",jsxImportSource:e.jsxImportSource||"react",production:!0});return{code:t}}catch(t){return{code:"",error:String(t)}}}function de(n,e={}){return je(n,e)}function ue(n){try{let{code:e}=pe(n,{transforms:["typescript"]});return{code:e}}catch(e){return{code:"",error:String(e)}}}var $="https://esm.sh",C="https://cdn.jsdelivr.net/npm/",K="https://data.jsdelivr.com/v1/package/npm/";function fe(n){let e=(n||"").replace(/^\/+/,"").replace(/\/+$/,"");return e?e.split("/"):[]}var g=class n{constructor(e,t,r){let s=typeof e=="string"?n.parse(e):e;this.name=s.name,this.version=k(t??s.version),this.subpath=k(r??s.subpath)}static parse(e){let t=fe(e||"");if(!t.length)return new n({name:""});if(t[0].startsWith("@")){let s=t[0],[o,i]=me(t[1]??""),c=k(t.slice(2).join("/"));return new n({name:`${s}/${o}`,version:i,subpath:c})}else{let[s,o]=me(t[0]),i=k(t.slice(1).join("/"));return new n({name:s,version:o,subpath:i})}}static fromUrl(e){try{let t=new URL(e),r=new URL($).host,s=new URL(C).host;if(t.host===r){let o=fe(t.pathname.replace(/^\/v\d+\//,"/"));if(!o.length)return;let i=o[0].startsWith("@")?`${o[0]}/${o[1]??""}`:o[0];return n.parse(i)}if(t.host===s){let o=t.pathname.split("/npm/")[1];if(!o)return;let i=o.split("/")[0]||"";return n.parse(i)}return}catch{return}}static versionFromUrl(e){return n.fromUrl(e)?.version}format(){let e=this.version?`${this.name}@${this.version}`:this.name;return this.subpath?`${e}/${this.subpath}`:e}root(){return this.name}static rootOf(e){return n.parse(e).name}withVersion(e){return new n({name:this.name,version:k(e),subpath:this.subpath})}withPreferredVersion(e,t){let r=e||t;return r?this.withVersion(r):this}static isBare(e){if(!e||e.startsWith(".")||e.startsWith("/"))return!1;let t=e.toLowerCase();return!t.startsWith("http://")&&!t.startsWith("https://")}},k=n=>n&&n.length?n:void 0,me=n=>{let e=n.indexOf("@");return e<0?[n,void 0]:[n.slice(0,e),k(n.slice(e+1))]};async function v(n){try{return await n()}catch{return}}var D=class{constructor(e,t){this.cache=e,this.http=t,this.esmHost=$,this.jsDelivrBase=C,this.jsDelivrMeta=K,this.pinMs=1e4,this.versionsIndexMs=1440*60*1e3,this.metaTtlMs=10080*60*1e3,this.pinCache=new Map}normalizeRelative(e){let t=e||"";return t.startsWith("./")?t.slice(2):t.replace(/^\/+/,"")}ensureLeadingDotSlash(e){return e.startsWith("./")?e:`./${e}`}baseDir(e){let t=typeof e=="string"?new g(e):e;return`${this.jsDelivrBase}${t.name}${t.version?`@${t.version}`:""}/`}file(e,t){return new URL(this.normalizeRelative(t),this.baseDir(e)).toString()}packageJson(e){return this.file(e,"package.json")}buildEsmUrl(e,t={}){let{target:r="es2022",bundle:s=!1,external:o}=t,i=new URLSearchParams({target:r});return s&&i.append("bundle",""),o?.length&&i.append("external",o.join(",")),`${this.esmHost}/${e}?${i.toString()}`}async pinEsmUrl(e,t="es2022"){let r=this.buildEsmUrl(e,{target:t}),s=await v(()=>this.http.head(r));return s?.ok?s.url||r:void 0}async resolveExactVersion(e){let t=Date.now(),r=this.pinCache.get(e);if(r&&t-r.ts<this.pinMs)return r.value;let s=await this.tryResolveFromUrls([this.buildEsmUrl(e),`${this.esmHost}/${e}`]);return this.pinCache.set(e,{value:s,ts:t}),s}async tryResolveFromUrls(e){for(let t of e){let r=await v(()=>this.http.head(t)),s=this.parseVersionFromUrl(r?.url||t);if(s)return s}}async fetchVersionsIndex(e){if(await this.cache.isNegative(e))return;let t=await this.cache.getIndex(e);if(t&&Date.now()-t.updatedAt<this.versionsIndexMs)return{versions:t.versions,distTags:t.distTags};let r=await v(()=>this.http.getJson(`${this.jsDelivrMeta}${encodeURIComponent(e)}`));if(!r?.versions?.length){await this.cache.recordNegative(e);return}await this.cache.clearNegative(e);let s=r.distTags&&Object.keys(r.distTags).length?r.distTags:void 0;return await this.cache.setIndex(e,r.versions,s),r}parseVersionFromUrl(e){let t=g.fromUrl(e)?.version;return t&&/\d+\.\d+\.\d+/.test(t)?t:void 0}async fetchPackageMeta(e,t){let r=await this.cache.getMeta(e,t);if(r&&Date.now()-r.updatedAt<this.metaTtlMs){let{dependencies:a,peerDependencies:l,peerDependenciesMeta:u}=r;return{name:e,version:t,dependencies:a,peerDependencies:l,peerDependenciesMeta:u}}let s=this.packageJson(new g(`${e}@${t}`)),o=await v(()=>this.http.getJson(s));if(!o)return;let i=a=>a&&Object.keys(a).length?a:void 0,c=i(o.dependencies),d=i(o.peerDependencies),f=i(o.peerDependenciesMeta);return await this.cache.setMeta(e,t,c,d,f),{name:e,version:t,dependencies:c,peerDependencies:d,peerDependenciesMeta:f}}};var he=n=>n.startsWith("@types/"),B=n=>Object.keys(n?.peerDependencies||{}).filter(e=>!he(e)),Y=n=>Object.keys(n?.dependencies||{}).filter(e=>!he(e)),Fe=n=>B(n).filter(e=>!n?.peerDependenciesMeta?.[e]?.optional),N=class{constructor(e){this.cdn=e}async resolve(e,t){let r=await this.fetchMeta(e),{allRoots:s,autoAddedPeers:o}=await this.expandWithPeers(r,t),i=this.computeFlags(s);return{allRoots:s,flags:i,autoAddedPeers:o}}async fetchMeta(e){return Promise.all(e.map(async({name:t,version:r})=>({name:t,version:r,meta:await this.cdn.fetchPackageMeta(t,r)})))}async expandWithPeers(e,t){let r=new Map(e.map(o=>[o.name,o])),s=[];for(let o of e)for(let i of Fe(o.meta))!r.has(i)&&!s.some(c=>c.name===i)&&s.push({name:i,requiredBy:o.name});for(let{name:o,requiredBy:i}of s)try{let c=await t(o),d=await this.cdn.fetchPackageMeta(o,c);r.set(o,{name:o,version:c,meta:d})}catch(c){console.warn(`[typebulb] Failed to resolve peer "${o}" for "${i}":`,c)}return{allRoots:[...r.values()],autoAddedPeers:s.filter(o=>r.has(o.name))}}computeFlags(e){let t=new Set(e.flatMap(o=>B(o.meta))),r=new Map;for(let o of e)for(let i of Y(o.meta))r.set(i,(r.get(i)||0)+1);let s=new Set([...r.entries()].filter(([,o])=>o>=2).map(([o])=>o));return new Map(e.map(o=>[o.name,{isPeerRoot:t.has(o.name),hasPeers:B(o.meta).length>0,isSharedDep:s.has(o.name)}]))}};var j=class{constructor(e,t,r){this.cache=e,this.cdn=t,this.semver=r}selectVersionFromIndex(e,t,r){return this.semver.selectBestVersion(e,{range:t,distTags:r})}async learnExactVersion(e){let t=await v(()=>this.cdn.fetchVersionsIndex(e));if(t?.versions?.length){let r=this.semver.selectBestVersion(t.versions,{distTags:t.distTags});if(r)return r}return this.cdn.resolveExactVersion(e)}async resolveExactForRoot(e,t){if(!t)return this.learnExactVersion(e);let r=await this.cache.getPinnedExact(e,t);if(r){if(this.semver.isExactVersion(r))return r;console.warn("[versionResolver] Rejecting invalid cached version for",e,":",r)}let s=await v(()=>this.cdn.fetchVersionsIndex(e));if(s?.versions?.length){let i=this.selectVersionFromIndex(s.versions,t,s.distTags);if(i){if(this.semver.isExactVersion(i))return await this.cache.setPinnedExact(e,t,i),i}else{console.warn("[versionResolver] Invalidating stale versions cache for",e,"- range",t,"not satisfied"),await this.cache.invalidateVersionsCache(e);let c=await v(()=>this.cdn.fetchVersionsIndex(e));if(c?.versions?.length){let d=this.selectVersionFromIndex(c.versions,t,c.distTags);if(d&&this.semver.isExactVersion(d))return await this.cache.setPinnedExact(e,t,d),d}}}let o=await this.cdn.resolveExactVersion(`${e}@${t}`);if(o&&this.semver.isExactVersion(o))return await this.cache.setPinnedExact(e,t,o),o}async effectivePackage(e,t){let r=new g(e),s=r.root(),o=t[s],i=o?await v(()=>this.cache.getPinnedExact(s,o))??await v(()=>this.resolveExactForRoot(s,o)):void 0;return{effectivePackage:i?r.withVersion(i).format():e,root:s,range:o,pinned:i}}};import{init as Ue,parse as Le}from"es-module-lexer";var T=class n{constructor(e,t,r,s){this.version=e,this.cdn=t,this.peer=r,this.cache=s}extractImportsSync(e){let t=new Set;for(let r of n.importPatterns){r.lastIndex=0;for(let s of e.matchAll(r))g.isBare(s[1])&&t.add(s[1])}return Array.from(t)}async extractImports(e){let t=new Set,r=s=>{g.isBare(s)&&t.add(s)};try{await Ue;let[s]=Le(e);s.forEach(o=>r(e.slice(o.s,o.e).trim()))}catch{return this.extractImportsSync(e)}return Array.from(t)}async buildImportMap(e,t){let r=await this.extractImports(e),s=[...new Set(r.map(g.rootOf))],o=await Promise.all(s.map(async a=>({name:a,version:await this.resolveVersion(a,t)}))),{allRoots:i,flags:c,autoAddedPeers:d}=await this.peer.resolve(o,a=>this.resolveVersion(a,t)),f=this.buildEntries([...r,...d.map(a=>a.name)],i,c,t);return{importMap:{imports:Object.fromEntries(f)},prefetchUrls:f.map(([,a])=>a)}}async resolveVersion(e,t){let r=t[e],s=await this.version.resolveExactForRoot(e,r);if(!s){let o=r?`${e}@${r}`:e,i=await v(()=>this.cdn.pinEsmUrl(o));if(!i)throw new Error(`Cannot resolve version for ${e} - network may be unavailable.`);s=g.versionFromUrl(i),s&&r&&await v(()=>this.cache.setPinnedExact(e,r,s))}if(!s)throw new Error(`Cannot resolve version for ${e}`);return s}buildEntries(e,t,r,s){let o=new Map(t.map(p=>[p.name,p])),i=p=>{let m=o.get(g.rootOf(p));return new g(p).withPreferredVersion(m.version,s[m.name]).format()},c=new Set([...r.entries()].filter(([,p])=>p.isPeerRoot||p.isSharedDep).map(([p])=>p)),d=new Set(e.filter(p=>p!==g.rootOf(p)).map(g.rootOf)),f=[],a=new Set,l=new Set(e.filter(p=>p===g.rootOf(p))),u=new Set;for(let p of e){let m=g.rootOf(p),P=o.get(m),{isPeerRoot:x,hasPeers:R,isSharedDep:A}=r.get(m),H=d.has(m),I=p!==m,Me=!(x||A)&&(H||!R),G=this.singletonDepsOf(P,c),ce=I&&l.has(m);ce&&u.add(m);let $e=ce?[...G,m]:G.length?G:void 0;f.push([p,this.cdn.buildEsmUrl(i(p),{bundle:Me,external:$e})]),a.add(p)}let h=new Set([...c,...u]);for(let p of h)o.has(p)&&(a.has(p)||f.push([p,this.cdn.buildEsmUrl(i(p),{})]),f.push([`${p}/`,`${this.cdn.esmHost}/${i(p)}/`]));return f}singletonDepsOf(e,t){return[...new Set([...B(e.meta),...Y(e.meta)])].filter(r=>t.has(r))}};T.importPatterns=[/\bimport\s+(?:[^'";]*?from\s*)?['"]([^'"]+)['"]/g,/\bexport\s+[^'";]*?from\s*['"]([^'"]+)['"]/g];import{gt as ge,satisfies as Ve,maxSatisfying as X,major as He,prerelease as We,rsort as Je,valid as qe}from"semver";var q=class{cmp(e,t){return e===t?0:ge(e,t)?1:ge(t,e)?-1:0}satisfies(e,t){return!e||!e.trim()?!0:!!Ve(t,e,{includePrerelease:!0})}pickMaxSatisfying(e,t){if(!e?.length)return;let r=X(e,t,{includePrerelease:!0});return r===null?void 0:r}pickLatest(e){return e?.length?Je(e)[0]:void 0}selectBestVersion(e,t){if(!e?.length)return;let r=t?.range?.trim()||"*",s=t?.preferStable??!0,o=t?.distTags?.latest;if(o&&e.includes(o)&&this.satisfies(r,o))return o;if(s){let c=X(e,r,{includePrerelease:!1});if(c)return c}return X(e,r,{includePrerelease:!0})??void 0}majorOf(e){return He(e)}isPrerelease(e){return We(e)!==null}isExactVersion(e){return qe(e)!==null}},Z=new q;function ye(n,e){let t=new D(n,e),r=new N(t),s=new j(n,t,Z);return{packageService:new T(s,t,r,n),versionResolver:s,cdnClient:t,peerResolver:r}}var Q=class{pins=new Map;indexes=new Map;negatives=new Set;meta=new Map;async getPinnedExact(e,t){return this.pins.get(`${e}@${t}`)}async setPinnedExact(e,t,r){this.pins.set(`${e}@${t}`,r)}async getIndex(e){return this.indexes.get(e)}async setIndex(e,t,r){this.indexes.set(e,{versions:t,distTags:r,updatedAt:Date.now()})}async invalidateVersionsCache(e){this.indexes.delete(e)}async isNegative(e){return this.negatives.has(e)}async recordNegative(e){this.negatives.add(e)}async clearNegative(e){this.negatives.delete(e)}async getMeta(e,t){return this.meta.get(`${e}@${t}`)}async setMeta(e,t,r,s,o){this.meta.set(`${e}@${t}`,{dependencies:r,peerDependencies:s,peerDependenciesMeta:o,updatedAt:Date.now()})}},Ge={async getJson(n){try{let e=await fetch(n,{redirect:"follow"});return e.ok?await e.json():void 0}catch{return}},async head(n){try{let e=await fetch(n,{method:"HEAD",redirect:"follow"});return{ok:e.ok,url:e.url}}catch{return}}},ze=new Q,{packageService:we,versionResolver:rr,cdnClient:sr,peerResolver:nr}=ye(ze,Ge);var ve=`
|
|
2
|
+
import*as E from"fs/promises";import{readFileSync as pn}from"fs";import*as b from"path";import{pathToFileURL as un}from"url";import{execFile as mn,spawn as fn}from"child_process";import{promisify as hn}from"util";import{EventEmitter as pt}from"events";var ir={code:{path:"code.tsx",language:"typescript"},css:{path:"styles.css",language:"css"},html:{path:"index.html",language:"html"},config:{path:"config.json",language:"json"},notes:{path:"notes.md",language:"markdown"},data:{path:"data.txt",language:"text"},infer:{path:"infer.md",language:"markdown"},insight:{path:"insight.json",language:"json"},server:{path:"server.ts",language:"typescript"}};function ft(s){try{let e=s.split(`
|
|
3
|
+
`),t=0;if(e[t]?.trim()!=="---")return null;t++;let r=[];for(;t<e.length&&e[t]?.trim()!=="---";)r.push(e[t]),t++;if(e[t]?.trim()!=="---")return null;t++;let n=or(r);if(!n)return null;let i=new Map;for(;t<e.length;){let a=e[t]?.trim()?.match(/^\*\*(.+)\*\*$/);if(a){let c=a[1].trim();for(t++;t<e.length&&e[t]?.trim()==="";)t++;let d=e[t]?.match(/^(`{3,})(\w*)\s*$/);if(!d){t++;continue}let u=d[1];t++;let f=[];for(;t<e.length&&!e[t]?.match(new RegExp(`^${u}\\s*$`));)f.push(e[t]),t++;t++,i.set(c,f.join(`
|
|
4
|
+
`))}else t++}return{frontmatter:n,files:i}}catch{return null}}function or(s){let e={};for(let t of s){let r=t.indexOf(":");if(r===-1)continue;let n=t.slice(0,r).trim(),i=t.slice(r+1).trim();switch(n){case"format":e.format=i;break;case"name":e.name=ar(i);break}}return!e.format?.startsWith("typebulb")||!e.name?null:e}function ar(s){return s.startsWith('"')&&s.endsWith('"')?s.slice(1,-1).replace(/\\"/g,'"'):s.startsWith("'")&&s.endsWith("'")?s.slice(1,-1):s}function ht(s){let e=t=>s.files.get(ir[t].path)||"";return{name:s.frontmatter.name,code:e("code"),css:e("css"),html:e("html"),config:e("config"),notes:e("notes"),data:e("data"),infer:e("infer"),insight:e("insight"),server:e("server")}}function cr(s){try{return JSON.parse(s),!0}catch{}return!!(/^\s*<[\s\S]*>/.test(s)||/^---\s*$/m.test(s)||/^\w[\w\s]*:[ \t]/m.test(s))}function gt(s){let e=s.trim();return e?cr(e)?[e]:s.split(/\n\n\n+/).map(t=>t.trim()).filter(Boolean):[]}function yt(s){if(!s.trim())return{};try{return JSON.parse(s)}catch{return{}}}import{transform as lr}from"sucrase";function Be(s,e={}){let t=e.serverOnly?["typescript"]:["typescript","jsx"];try{let{code:r}=lr(s,{transforms:t,jsxRuntime:"automatic",jsxImportSource:e.jsxImportSource||"react",production:!0});return{code:r}}catch(r){return{code:"",error:String(r)}}}var ne="https://esm.sh",se="https://cdn.jsdelivr.net/npm/",Le="https://data.jsdelivr.com/v1/package/npm/";function wt(s){let e=(s||"").replace(/^\/+/,"").replace(/\/+$/,"");return e?e.split("/"):[]}var g=class s{constructor(e,t,r){let n=typeof e=="string"?s.parse(e):e;this.name=n.name,this.version=q(t??n.version),this.subpath=q(r??n.subpath)}static parse(e){let t=wt(e||"");if(!t.length)return new s({name:""});if(t[0].startsWith("@")){let n=t[0],[i,o]=vt(t[1]??""),a=q(t.slice(2).join("/"));return new s({name:`${n}/${i}`,version:o,subpath:a})}else{let[n,i]=vt(t[0]),o=q(t.slice(1).join("/"));return new s({name:n,version:i,subpath:o})}}static fromUrl(e){try{let t=new URL(e),r=new URL(ne).host,n=new URL(se).host;if(t.host===r){let i=wt(t.pathname.replace(/^\/v\d+\//,"/"));if(!i.length)return;let o=i[0].startsWith("@")?`${i[0]}/${i[1]??""}`:i[0];return s.parse(o)}if(t.host===n){let i=t.pathname.split("/npm/")[1];if(!i)return;let o=i.split("/")[0]||"";return s.parse(o)}return}catch{return}}static versionFromUrl(e){return s.fromUrl(e)?.version}format(){let e=this.version?`${this.name}@${this.version}`:this.name;return this.subpath?`${e}/${this.subpath}`:e}root(){return this.name}static rootOf(e){return s.parse(e).name}withVersion(e){return new s({name:this.name,version:q(e),subpath:this.subpath})}withPreferredVersion(e,t){let r=e||t;return r?this.withVersion(r):this}static isBare(e){if(!e||e.startsWith(".")||e.startsWith("/"))return!1;let t=e.toLowerCase();return!t.startsWith("http://")&&!t.startsWith("https://")}},q=s=>s&&s.length?s:void 0,vt=s=>{let e=s.indexOf("@");return e<0?[s,void 0]:[s.slice(0,e),q(s.slice(e+1))]};async function x(s){try{return await s()}catch{return}}var ie=class{constructor(e,t){this.cache=e,this.http=t,this.esmHost=ne,this.jsDelivrBase=se,this.jsDelivrMeta=Le,this.pinMs=1e4,this.versionsIndexMs=1440*60*1e3,this.metaTtlMs=10080*60*1e3,this.pinCache=new Map}normalizeRelative(e){let t=e||"";return t.startsWith("./")?t.slice(2):t.replace(/^\/+/,"")}ensureLeadingDotSlash(e){return e.startsWith("./")?e:`./${e}`}baseDir(e){let t=typeof e=="string"?new g(e):e;return`${this.jsDelivrBase}${t.name}${t.version?`@${t.version}`:""}/`}file(e,t){return new URL(this.normalizeRelative(t),this.baseDir(e)).toString()}packageJson(e){return this.file(e,"package.json")}buildEsmUrl(e,t={}){let{target:r="es2022",bundle:n=!1,external:i}=t,o=new URLSearchParams({target:r});return n&&o.append("bundle",""),i?.length&&o.append("external",i.join(",")),`${this.esmHost}/${e}?${o.toString()}`}async pinEsmUrl(e,t="es2022"){let r=this.buildEsmUrl(e,{target:t}),n=await x(()=>this.http.head(r));return n?.ok?n.url||r:void 0}async resolveExactVersion(e){let t=Date.now(),r=this.pinCache.get(e);if(r&&t-r.ts<this.pinMs)return r.value;let n=await this.tryResolveFromUrls([this.buildEsmUrl(e),`${this.esmHost}/${e}`]);return this.pinCache.set(e,{value:n,ts:t}),n}async tryResolveFromUrls(e){for(let t of e){let r=await x(()=>this.http.head(t)),n=this.parseVersionFromUrl(r?.url||t);if(n)return n}}async fetchVersionsIndex(e){if(await this.cache.isNegative(e))return;let t=await this.cache.getIndex(e);if(t&&Date.now()-t.updatedAt<this.versionsIndexMs)return{versions:t.versions,distTags:t.distTags};let r=await x(()=>this.http.getJson(`${this.jsDelivrMeta}${encodeURIComponent(e)}`));if(!r?.versions?.length){await this.cache.recordNegative(e);return}await this.cache.clearNegative(e);let n=r.distTags&&Object.keys(r.distTags).length?r.distTags:void 0;return await this.cache.setIndex(e,r.versions,n),r}parseVersionFromUrl(e){let t=g.fromUrl(e)?.version;return t&&/\d+\.\d+\.\d+/.test(t)?t:void 0}async fetchPackageMeta(e,t){let r=await this.cache.getMeta(e,t);if(r&&Date.now()-r.updatedAt<this.metaTtlMs){let{dependencies:u,peerDependencies:f,peerDependenciesMeta:h}=r;return{name:e,version:t,dependencies:u,peerDependencies:f,peerDependenciesMeta:h}}let n=this.packageJson(new g(`${e}@${t}`)),i=await x(()=>this.http.getJson(n));if(!i)return;let o=u=>u&&Object.keys(u).length?u:void 0,a=o(i.dependencies),c=o(i.peerDependencies),d=o(i.peerDependenciesMeta);return await this.cache.setMeta(e,t,a,c,d),{name:e,version:t,dependencies:a,peerDependencies:c,peerDependenciesMeta:d}}};var bt=s=>s.startsWith("@types/"),oe=s=>Object.keys(s?.peerDependencies||{}).filter(e=>!bt(e)),We=s=>Object.keys(s?.dependencies||{}).filter(e=>!bt(e)),dr=s=>oe(s).filter(e=>!s?.peerDependenciesMeta?.[e]?.optional),ae=class{constructor(e){this.cdn=e}async resolve(e,t){let r=await this.fetchMeta(e),{allRoots:n,autoAddedPeers:i}=await this.expandWithPeers(r,t),o=this.computeFlags(n);return{allRoots:n,flags:o,autoAddedPeers:i}}async fetchMeta(e){return Promise.all(e.map(async({name:t,version:r})=>({name:t,version:r,meta:await this.cdn.fetchPackageMeta(t,r)})))}async expandWithPeers(e,t){let r=new Map(e.map(i=>[i.name,i])),n=[];for(let i of e)for(let o of dr(i.meta))!r.has(o)&&!n.some(a=>a.name===o)&&n.push({name:o,requiredBy:i.name});for(let{name:i,requiredBy:o}of n)try{let a=await t(i),c=await this.cdn.fetchPackageMeta(i,a);r.set(i,{name:i,version:a,meta:c})}catch(a){console.warn(`[typebulb] Failed to resolve peer "${i}" for "${o}":`,a)}return{allRoots:[...r.values()],autoAddedPeers:n.filter(i=>r.has(i.name))}}computeFlags(e){let t=new Set(e.flatMap(i=>oe(i.meta))),r=new Map;for(let i of e)for(let o of We(i.meta))r.set(o,(r.get(o)||0)+1);let n=new Set([...r.entries()].filter(([,i])=>i>=2).map(([i])=>i));return new Map(e.map(i=>[i.name,{isPeerRoot:t.has(i.name),hasPeers:oe(i.meta).length>0,isSharedDep:n.has(i.name)}]))}};var ce=class{constructor(e,t,r){this.cache=e,this.cdn=t,this.semver=r}selectVersionFromIndex(e,t,r){return this.semver.selectBestVersion(e,{range:t,distTags:r})}async learnExactVersion(e){let t=await x(()=>this.cdn.fetchVersionsIndex(e));if(t?.versions?.length){let r=this.semver.selectBestVersion(t.versions,{distTags:t.distTags});if(r)return r}return this.cdn.resolveExactVersion(e)}async resolveExactForRoot(e,t){if(!t)return this.learnExactVersion(e);let r=await this.cache.getPinnedExact(e,t);if(r){if(this.semver.isExactVersion(r))return r;console.warn("[versionResolver] Rejecting invalid cached version for",e,":",r)}let n=await x(()=>this.cdn.fetchVersionsIndex(e));if(n?.versions?.length){let o=this.selectVersionFromIndex(n.versions,t,n.distTags);if(o){if(this.semver.isExactVersion(o))return await this.cache.setPinnedExact(e,t,o),o}else{console.warn("[versionResolver] Invalidating stale versions cache for",e,"- range",t,"not satisfied"),await this.cache.invalidateVersionsCache(e);let a=await x(()=>this.cdn.fetchVersionsIndex(e));if(a?.versions?.length){let c=this.selectVersionFromIndex(a.versions,t,a.distTags);if(c&&this.semver.isExactVersion(c))return await this.cache.setPinnedExact(e,t,c),c}}}let i=await this.cdn.resolveExactVersion(`${e}@${t}`);if(i&&this.semver.isExactVersion(i))return await this.cache.setPinnedExact(e,t,i),i}async effectivePackage(e,t){let r=new g(e),n=r.root(),i=t[n],o=i?await x(()=>this.cache.getPinnedExact(n,i))??await x(()=>this.resolveExactForRoot(n,i)):void 0;return{effectivePackage:o?r.withVersion(o).format():e,root:n,range:i,pinned:o}}};import{init as pr,parse as ur}from"es-module-lexer";var z=class s{constructor(e,t,r,n){this.version=e,this.cdn=t,this.peer=r,this.cache=n}extractImportsSync(e){let t=new Set;for(let r of s.importPatterns){r.lastIndex=0;for(let n of e.matchAll(r))g.isBare(n[1])&&t.add(n[1])}return Array.from(t)}async extractImports(e){let t=new Set,r=n=>{g.isBare(n)&&t.add(n)};try{await pr;let[n]=ur(e);n.forEach(i=>r(e.slice(i.s,i.e).trim()))}catch{return this.extractImportsSync(e)}return Array.from(t)}async buildImportMap(e,t){let r=await this.extractImports(e),n=[...new Set(r.map(g.rootOf))],i=await Promise.all(n.map(async u=>({name:u,version:await this.resolveVersion(u,t)}))),{allRoots:o,flags:a,autoAddedPeers:c}=await this.peer.resolve(i,u=>this.resolveVersion(u,t)),d=this.buildEntries([...r,...c.map(u=>u.name)],o,a,t);return{importMap:{imports:Object.fromEntries(d)},prefetchUrls:d.map(([,u])=>u)}}async resolveVersion(e,t){let r=t[e],n=await this.version.resolveExactForRoot(e,r);if(!n){let i=r?`${e}@${r}`:e,o=await x(()=>this.cdn.pinEsmUrl(i));if(!o)throw new Error(`Cannot resolve version for ${e} - network may be unavailable.`);n=g.versionFromUrl(o),n&&r&&await x(()=>this.cache.setPinnedExact(e,r,n))}if(!n)throw new Error(`Cannot resolve version for ${e}`);return n}buildEntries(e,t,r,n){let i=new Map(t.map(l=>[l.name,l])),o=l=>{let m=i.get(g.rootOf(l));return new g(l).withPreferredVersion(m.version,n[m.name]).format()},a=new Set([...r.entries()].filter(([,l])=>l.isPeerRoot||l.isSharedDep).map(([l])=>l)),c=new Set(e.filter(l=>l!==g.rootOf(l)).map(g.rootOf)),d=[],u=new Set,f=new Set(e.filter(l=>l===g.rootOf(l))),h=new Set;for(let l of e){let m=g.rootOf(l),w=i.get(m),{isPeerRoot:y,hasPeers:A,isSharedDep:$}=r.get(m),_=c.has(m),re=l!==m,Se=!(y||$)&&(_||!A),O=this.singletonDepsOf(w,a),mt=re&&f.has(m);mt&&h.add(m);let sr=mt?[...O,m]:O.length?O:void 0;d.push([l,this.cdn.buildEsmUrl(o(l),{bundle:Se,external:sr})]),u.add(l)}let p=new Set([...a,...h]);for(let l of p)i.has(l)&&(u.has(l)||d.push([l,this.cdn.buildEsmUrl(o(l),{})]),d.push([`${l}/`,`${this.cdn.esmHost}/${o(l)}/`]));return d}singletonDepsOf(e,t){return[...new Set([...oe(e.meta),...We(e.meta)])].filter(r=>t.has(r))}};z.importPatterns=[/\bimport\s+(?:[^'";]*?from\s*)?['"]([^'"]+)['"]/g,/\bexport\s+[^'";]*?from\s*['"]([^'"]+)['"]/g];import{gt as xt,satisfies as mr,maxSatisfying as Ve,major as fr,prerelease as hr,rsort as gr,valid as yr}from"semver";var Re=class{cmp(e,t){return e===t?0:xt(e,t)?1:xt(t,e)?-1:0}satisfies(e,t){return!e||!e.trim()?!0:!!mr(t,e,{includePrerelease:!0})}pickMaxSatisfying(e,t){if(!e?.length)return;let r=Ve(e,t,{includePrerelease:!0});return r===null?void 0:r}pickLatest(e){return e?.length?gr(e)[0]:void 0}selectBestVersion(e,t){if(!e?.length)return;let r=t?.range?.trim()||"*",n=t?.preferStable??!0,i=t?.distTags?.latest;if(i&&e.includes(i)&&this.satisfies(r,i))return i;if(n){let a=Ve(e,r,{includePrerelease:!1});if(a)return a}return Ve(e,r,{includePrerelease:!0})??void 0}majorOf(e){return fr(e)}isPrerelease(e){return hr(e)!==null}isExactVersion(e){return yr(e)!==null}},B=new Re;function Pt(s,e){let t=new ie(s,e),r=new ae(t),n=new ce(s,t,B);return{packageService:new z(n,t,r,s),versionResolver:n,cdnClient:t,peerResolver:r}}import*as Nt from"fs/promises";import*as T from"path";var Je=[{name:"es5"},{name:"es2015.core"},{name:"es2015.collection"},{name:"es2015.promise"},{name:"es2015.iterable"},{name:"es2015.symbol"},{name:"es2015.symbol.wellknown"},{name:"es2015.generator"},{name:"es2015.proxy"},{name:"es2015.reflect"},{name:"es2016.array.include"},{name:"es2016.intl"},{name:"es2017.object"},{name:"es2017.string"},{name:"es2017.sharedmemory"},{name:"es2017.typedarrays"},{name:"es2017.date"},{name:"es2017.intl"},{name:"es2018.asynciterable"},{name:"es2018.asyncgenerator"},{name:"es2018.promise"},{name:"es2018.regexp"},{name:"es2018.intl"},{name:"es2019.array"},{name:"es2019.object"},{name:"es2019.string"},{name:"es2019.symbol"},{name:"es2019.intl"},{name:"es2020.bigint"},{name:"es2020.promise"},{name:"es2020.string"},{name:"es2020.sharedmemory"},{name:"es2020.date"},{name:"es2020.number"},{name:"es2020.symbol.wellknown"},{name:"es2020.intl"},{name:"es2021.promise"},{name:"es2021.string"},{name:"es2021.weakref"},{name:"es2021.intl"},{name:"es2022.array"},{name:"es2022.object"},{name:"es2022.error"},{name:"es2022.string"},{name:"es2022.regexp"},{name:"es2022.intl"},{name:"es2023.array"},{name:"es2023.collection"},{name:"es2023.intl",since:"5.5"},{name:"es2024.arraybuffer",since:"5.5"},{name:"es2024.collection",since:"5.5"},{name:"es2024.object",since:"5.5"},{name:"es2024.promise",since:"5.5"},{name:"es2024.regexp",since:"5.5"},{name:"es2024.sharedmemory",since:"5.5"},{name:"es2024.string",since:"5.5"},{name:"esnext.array",since:"5.5"},{name:"esnext.collection"},{name:"esnext.decorators"},{name:"esnext.disposable"},{name:"esnext.error",since:"5.5"},{name:"esnext.float16",since:"5.5"},{name:"esnext.iterator",since:"5.5"},{name:"esnext.object"},{name:"esnext.promise"},{name:"esnext.sharedmemory",since:"5.5"},{name:"esnext.intl"}],He=[{name:"dom"},{name:"dom.iterable"},{name:"dom.asynciterable"}];var St=`
|
|
5
|
+
/**
|
|
6
|
+
* Get raw data chunk from the Data tab.
|
|
7
|
+
* @param index - Chunk index (0-based). Separate chunks with 2 blank lines.
|
|
8
|
+
*/
|
|
9
|
+
data(index: number): string;
|
|
10
|
+
/**
|
|
11
|
+
* Get data chunk parsed as JSON (handles JSON-ish with unquoted keys).
|
|
12
|
+
* @param index - Chunk index (0-based)
|
|
13
|
+
* @throws If chunk is not valid JSON/JSON-ish
|
|
14
|
+
*/
|
|
15
|
+
json<T = unknown>(index: number): T;`,Rt=`
|
|
16
|
+
/**
|
|
17
|
+
* Get the insight data produced by the inference layer.
|
|
18
|
+
*
|
|
19
|
+
* Returns the parsed JSON from insight.json, populated by the inference LLM.
|
|
20
|
+
* Use a type parameter to get typed access to the insight data.
|
|
21
|
+
*
|
|
22
|
+
* @returns The parsed insight JSON, or undefined if no insight is available
|
|
23
|
+
*/
|
|
24
|
+
insight<T = unknown>(): T | undefined;`,Et=`
|
|
25
|
+
/**
|
|
26
|
+
* General-purpose AI call.
|
|
27
|
+
*
|
|
28
|
+
* @param options - Messages, system prompt, optional provider/model override
|
|
29
|
+
* @returns Promise resolving to { text: string }
|
|
30
|
+
* @throws On rate limit, network error, or provider error
|
|
31
|
+
*/
|
|
32
|
+
ai(options: {
|
|
33
|
+
messages: Array<{ role: "user" | "assistant"; content: string }>;
|
|
34
|
+
system?: string;
|
|
35
|
+
/** Reasoning depth hint (0=min, 1=low, 2=med, 3=max). Mapped to provider-specific parameters (e.g. Anthropic adaptive thinking, OpenAI reasoning effort). Default: 0. */
|
|
36
|
+
reasoning?: 0 | 1 | 2 | 3;
|
|
37
|
+
provider?: string;
|
|
38
|
+
model?: string;
|
|
39
|
+
/** Enable/disable web search. Default: on for BYOK, always off for free model. */
|
|
40
|
+
webSearch?: boolean;
|
|
41
|
+
}): Promise<{ text: string }>;`,kt=`
|
|
42
|
+
/**
|
|
43
|
+
* Returns AI models available to the current user.
|
|
44
|
+
* Models are filtered by the user's configured API keys.
|
|
45
|
+
* If no keys are configured, returns only the courtesy model.
|
|
46
|
+
*/
|
|
47
|
+
models(): Promise<Array<{
|
|
48
|
+
/** Provider protocol: "anthropic", "openai", "gemini", "openrouter" */
|
|
49
|
+
provider: string;
|
|
50
|
+
/** Model identifier, e.g. "claude-sonnet-4-6" */
|
|
51
|
+
name: string;
|
|
52
|
+
/** Human-readable display name, e.g. "Sonnet 4.6" */
|
|
53
|
+
friendlyName: string;
|
|
54
|
+
/** Provider display name, e.g. "Anthropic" */
|
|
55
|
+
providerName: string;
|
|
56
|
+
}>>;`,Tt=`
|
|
57
|
+
/**
|
|
58
|
+
* The mode this bulb is running in.
|
|
59
|
+
*
|
|
60
|
+
* - \`'local'\` \u2014 Running via the typebulb CLI
|
|
61
|
+
* - \`'editor'\` \u2014 Running in the typebulb.com editor
|
|
62
|
+
* - \`'published'\` \u2014 Running as a published/standalone bulb on typebulb.com
|
|
63
|
+
*/
|
|
64
|
+
mode: 'local' | 'editor' | 'published';`,Ct=`
|
|
65
|
+
/**
|
|
66
|
+
* Local filesystem access (CLI only).
|
|
67
|
+
*
|
|
68
|
+
* Paths are resolved relative to the directory containing the bulb file.
|
|
69
|
+
* Throws in editor/published mode.
|
|
70
|
+
*/
|
|
71
|
+
fs: {
|
|
72
|
+
/** Read a file as UTF-8 text. Path is relative to the bulb's directory. */
|
|
73
|
+
read(path: string): Promise<string>;
|
|
74
|
+
/** Write UTF-8 text to a file. Creates parent directories if needed. */
|
|
75
|
+
write(path: string, content: string): Promise<boolean>;
|
|
76
|
+
};`,wr=`
|
|
77
|
+
/**
|
|
78
|
+
* Server-side function proxy. The built-in \`log\` prints to CLI stdout
|
|
79
|
+
* (falls back to console.log on web). On the server side, this object only
|
|
80
|
+
* exposes \`log\` \u2014 server-to-server calls are not supported.
|
|
81
|
+
*/
|
|
82
|
+
server: {
|
|
83
|
+
log(...args: any[]): Promise<void>;
|
|
84
|
+
};`,vr=`
|
|
85
|
+
/**
|
|
86
|
+
* Async value inspector for tensor-like objects.
|
|
87
|
+
*
|
|
88
|
+
* Materializes lazy values (like GPU tensors) and logs them with metadata.
|
|
89
|
+
* Handles objects with \`.js()\`, \`.data()\`, \`.array()\`, \`.arraySync()\`, etc.
|
|
90
|
+
*
|
|
91
|
+
* @remarks
|
|
92
|
+
* - Always use \`await\` - materialization may be async (GPU\u2192CPU readback)
|
|
93
|
+
* - Large values are truncated (max 1000 elements)
|
|
94
|
+
* - Promises are logged as \`[Promise]\` (not awaited - could hang)
|
|
95
|
+
*/
|
|
96
|
+
dump(...args: any[]): Promise<void>;
|
|
97
|
+
/**
|
|
98
|
+
* Trigger inference to generate new insight data.
|
|
99
|
+
*
|
|
100
|
+
* Opens a confirmation modal showing the data to be analyzed, then streams
|
|
101
|
+
* the inference result. On success, updates the insight so subsequent
|
|
102
|
+
* \`tb.insight()\` calls return the new value.
|
|
103
|
+
*
|
|
104
|
+
* @param opts - Options for inference
|
|
105
|
+
* @param opts.data - Data to pre-populate in the modal (string or array of strings). If omitted, modal opens with empty textarea for user to paste.
|
|
106
|
+
* @returns Promise that resolves with the parsed insight JSON
|
|
107
|
+
* @throws If inference is already in progress, or on network/parse/rate limit errors
|
|
108
|
+
*/
|
|
109
|
+
infer<T = unknown>(opts?: { data?: string | string[] }): Promise<T>;
|
|
110
|
+
/**
|
|
111
|
+
* Get the current inference state.
|
|
112
|
+
*
|
|
113
|
+
* @returns 'idle' | 'running' | 'complete' | 'error'
|
|
114
|
+
*/
|
|
115
|
+
inferenceState(): 'idle' | 'running' | 'complete' | 'error';
|
|
116
|
+
/**
|
|
117
|
+
* Set a data chunk for the next inference call.
|
|
118
|
+
*
|
|
119
|
+
* Use this to programmatically set data that will be sent when \`tb.infer()\` is called
|
|
120
|
+
* without the \`data\` option.
|
|
121
|
+
*
|
|
122
|
+
* @param index - The chunk index (0-based)
|
|
123
|
+
* @param content - The content for this chunk
|
|
124
|
+
*/
|
|
125
|
+
setData(index: number, content: string): void;
|
|
126
|
+
/**
|
|
127
|
+
* Proxy a CDN URL through the sandbox origin for Web Worker/WASM same-origin loading.
|
|
128
|
+
*
|
|
129
|
+
* In the sandbox, prepends \`/proxy/\` so the URL is served from the same origin.
|
|
130
|
+
* Outside the sandbox (exported HTML, CLI), returns the URL unchanged.
|
|
131
|
+
*
|
|
132
|
+
* @param url - Full HTTPS URL to an allowlisted CDN (esm.sh, unpkg.com, cdn.jsdelivr.net, cdnjs.cloudflare.com)
|
|
133
|
+
* @returns The proxied URL (sandbox) or the original URL (standalone/CLI)
|
|
134
|
+
*/
|
|
135
|
+
proxy(url: string): string;
|
|
136
|
+
/**
|
|
137
|
+
* Copy text to clipboard.
|
|
138
|
+
* Must be called synchronously within a user gesture (click/keydown).
|
|
139
|
+
* @returns true if successful, false otherwise
|
|
140
|
+
*/
|
|
141
|
+
copy(text: string): Promise<boolean>;
|
|
142
|
+
/**
|
|
143
|
+
* Get the canonical URL of this bulb.
|
|
144
|
+
*
|
|
145
|
+
* Returns the parent typebulb.com URL (including path, query, and \`#tb=\` fragment),
|
|
146
|
+
* resolving correctly from inside the cross-origin sandbox iframe.
|
|
147
|
+
* Use this instead of \`location.href\` or \`document.referrer\`.
|
|
148
|
+
*
|
|
149
|
+
* @returns The full canonical URL
|
|
150
|
+
*/
|
|
151
|
+
url(): Promise<string>;`,br=`
|
|
152
|
+
/**
|
|
153
|
+
* Server-side function proxy.
|
|
154
|
+
*
|
|
155
|
+
* In the CLI, calls exported functions from the \`**server.ts**\` section.
|
|
156
|
+
* \`tb.server.log(...)\` is a built-in that prints to CLI stdout (falls back to console.log on web).
|
|
157
|
+
* User exports override built-ins of the same name.
|
|
158
|
+
*/
|
|
159
|
+
server: Record<string, (...args: any[]) => Promise<any>>;`,Ge=`
|
|
160
|
+
/**
|
|
161
|
+
* Typebulb utilities namespace.
|
|
162
|
+
* Type \`tb.\` to discover available helpers.
|
|
163
|
+
*/
|
|
164
|
+
declare const tb: {${St}${vr}${Rt}${br}${Et}${Ct}${kt}${Tt}
|
|
165
|
+
};
|
|
166
|
+
`,qe=`
|
|
167
|
+
/**
|
|
168
|
+
* Typebulb utilities namespace (server-side).
|
|
169
|
+
* Type \`tb.\` to discover available helpers.
|
|
170
|
+
*/
|
|
171
|
+
declare const tb: {${St}${Rt}${Et}${Ct}${wr}${kt}${Tt}
|
|
172
|
+
};
|
|
173
|
+
`;var L=class{constructor(e){this.store=e}async isNegative(e){let t=await Ee(()=>this.store.get(e));return!!t&&t.until>Date.now()}async recordNegative(e){let r=((await Ee(()=>this.store.get(e)))?.attempts||0)+1;await Ee(()=>this.store.set(e,{until:Date.now()+xr(r),attempts:r}))}async clearNegative(e){await Ee(()=>this.store.delete(e))}};function xr(s){return Math.min(9e5*Math.pow(2,Math.max(0,s-1)),864e5)}async function Ee(s){try{return await s()}catch{return}}import Tr from"p-limit";import{resolve as _t}from"resolve.exports";var K=class{constructor(e){this.fetchDts=e}fetchDtsText(e){return this.tryUrls([e])}async tryUrls(e){for(let t of e){let r=await this.fetchDts(t);if(r&&(this.looksLikeDts(r.dts)||/\.(d\.ts|d\.mts)(?:[?#].*)?$/i.test(r.url)||/[?&]dts(?:[&#]|$)/i.test(r.url)))return r}}looksLikeDts(e){return/^\s*export\s*\{\s*\}\s*;?\s*$/m.test(e)?!0:/declare\s+(module|namespace|class|interface|function|const|var|let)/.test(e)||/interface\s+\w+/.test(e)||/type\s+\w+\s*=/.test(e)}};var F={maxRelativeTypeRefs:500,maxBareDeps:8,maxBareDepth:3,prefetchConcurrency:4,negativeTtlMs:1e4},le=["index.d.ts","index.d.mts"],de=/\.d\.(ts|mts)$/i;function ze(s){if(de.test(s))return!0;try{return new URL(s,"file://").search.includes("dts")}catch{return s.includes("?")&&s.includes("dts")}}function ke(s){return[`${s}.d.ts`,`${s}.d.mts`]}async function pe(s,{retries:e=2,timeoutMs:t=15e3,init:r}={}){for(let n=0;n<=e;n++){let i=new AbortController,o=setTimeout(()=>i.abort(),t);try{let a=await fetch(s,{...r,signal:i.signal});if(Pr(a.status)&&n<e)continue;return a}catch{if(n<e)continue;return}finally{clearTimeout(o)}}}function Pr(s){return s===408||s===429||s>=500&&s<600}var ue=class extends K{constructor(e,t){super(e),this.cdnClient=t}async loadPackageAtVersionedRoot(e,t){let r=this.cdnClient.packageJson(new g({name:e,version:t})),n=await pe(r);if(!n?.ok)return;let i;try{i=await n.json()}catch{return}if(i)return{pkg:i,baseDir:this.cdnClient.baseDir(new g({name:e,version:t??i.version})),version:t}}extractPathFromResult(e){if(typeof e=="string")return e;if(Array.isArray(e))return e.find(t=>typeof t=="string")}async tryUntilSuccess(e,t){for(let r of e){let n=await t(r);if(n)return n}}async resolveFromSelected(e,t){if(e.kind==="types"){let n=this.cdnClient.normalizeRelative(e.path);if(!n||n==="/"||n===".")return this.tryUntilSuccess([...le],t);if(!de.test(n)){let i=await this.tryUntilSuccess(this.declarationCandidatesFor(n),t);if(i)return i}return t(n)}let r=this.declarationCandidatesFor(e.path);return this.tryUntilSuccess([...le,...r],t)}toResolutionResult(e){return{kind:de.test(e)?"types":"probe",path:e}}resolveExportsPath(e,t){let r=t||".",n=e;try{let i=this.extractPathFromResult(_t(n,r,{conditions:["types"]}));if(i)return i}catch{}try{return this.extractPathFromResult(_t(n,r,{browser:!0,conditions:["import","default","module","browser","node"]}))}catch{return}}async resolve(e){try{let t=g.parse(e),{pkg:r,baseDir:n}=await this.loadPackageAtVersionedRoot(t.name,t.version)||{};if(!r||!n)return;let i={name:t.name,version:t.version},o=new g(i).format(),a=new g({...i,subpath:t.subpath}).format(),c=f=>this.fetchCandidateFrom(n,t.name,f);if(t.subpath){let f=this.cdnClient.ensureLeadingDotSlash(t.subpath),h=this.resolveExportsPath(r,f);if(h){let l=await this.resolveFromSelected(this.toResolutionResult(h),c);if(l)return{...l,resolvedPkg:a}}let p=await this.tryUntilSuccess(this.declarationCandidatesFor(f),c);if(p)return{...p,resolvedPkg:a}}let d=r.types??r.typings;if(d){let f=await this.resolveFromSelected({kind:"types",path:d},c);if(f)return{...f,resolvedPkg:o}}let u=this.resolveExportsPath(r,".");if(u){let f=await this.resolveFromSelected(this.toResolutionResult(u),c);if(f)return{...f,resolvedPkg:o}}return}catch{return}}async fetchCandidateFrom(e,t,r){let n=this.cdnClient.normalizeRelative(r),i=new URL(n,e).toString(),o=await this.fetchDtsText(i);return o?{dts:o.dts,url:o.url,resolvedPkg:t}:void 0}declarationCandidatesFor(e){if(!e||e==="./"||e==="/")return[...le];let t=e.replace(/\.(mjs|cjs|js|mts|cts|ts)$/i,""),r=ke(t),n=t.endsWith("/")?t:`${t}/`;return r.push(...ke(`${n}index`)),r}};import{gunzipSync as Sr}from"fflate";var Y=class{async fetchAndExtract(e,t){let r=this.getTarballUrl(e,t),n=await pe(r,{timeoutMs:3e4});if(!n?.ok)return new Map;let i=new Uint8Array(await n.arrayBuffer());return this.extractDtsFiles(i)}getTarballUrl(e,t){return`https://registry.npmjs.org/${e.replace("/","%2F")}/-/${e.split("/").pop()}-${t}.tgz`}normalizeTarPath(e){let t=e.replace(/^package\//,""),r=t.indexOf("/");return r>0?t.substring(r+1):t}extractDtsFiles(e){let t=new Map;try{let r=Sr(e),n=new TextDecoder("utf-8"),i=0;for(;i<r.length-512;){let o=r.slice(i,i+512);if(o[0]===0)break;let a=o.slice(0,100),c=a.indexOf(0),d=n.decode(a.slice(0,c>0?c:100)).trim(),u=o.slice(124,136),f=n.decode(u).trim().replace(/\0/g,""),h=parseInt(f,8)||0,p=String.fromCharCode(o[156]);if(i+=512,(p==="0"||p==="\0")&&(d.endsWith(".d.ts")||d.endsWith(".d.mts"))){let l=r.slice(i,i+h);t.set(this.normalizeTarPath(d),n.decode(l))}i+=Math.ceil(h/512)*512}}catch{}return t}},Rr=new Y;var me=class extends K{constructor(e,t,r,n=new Y){super(e),this.cdnClient=t,this.cache=r,this.tarballFetcher=n}typesNameCandidates(e){let t=e.startsWith("@")?e.slice(1).replace("/","__"):e;return t.includes(".")?[t,t.split(".").join("-"),t.split(".").join("")]:[t]}selectTypesVersion(e,t,r){try{if(r){let i=B.majorOf(r),o=e.filter(a=>B.majorOf(a)===i);if(o.length)return o.sort((a,c)=>B.cmp(c,a))[0]}let n=t?.latest;return n&&e.includes(n)?n:e[0]}catch{return e[0]}}async fetchFromVersionedRoot(e,t){let r=new g(e),n=r.version;if(!n)return;let i;try{i=await this.tarballFetcher.fetchAndExtract(r.name,n)}catch{return}if(!i||i.size===0)return;for(let[a,c]of i.entries()){let d=this.cdnClient.file(e,a);try{await this.cache.setCachedFile(d,c)}catch{}}let o=t.subpath?[t.subpath+".d.ts",t.subpath+"/index.d.ts"]:["index.d.ts"];for(let a of o){let c=i.get(a);if(c)return{dts:c,url:this.cdnClient.file(e,a),resolvedPkg:t.subpath?new g(t).format():t.name}}}async resolve(e){let t=g.parse(e);if(t.name)for(let r of this.typesNameCandidates(t.name)){let n=`@types/${r}`,i;try{i=await this.cdnClient.fetchVersionsIndex(n)}catch{continue}if(!i?.versions?.length)continue;let o=this.selectTypesVersion(i.versions,i.distTags,t.version),a=await this.fetchFromVersionedRoot(`${n}@${o}`,t);if(a)return a}}};var fe=class{collectRelativeTypeRefs(e){return this.collectRefs(e).filter(t=>t.startsWith("./")||t.startsWith("../"))}collectBareModuleRefs(e){return this.collectRefs(e).filter(t=>this.isBare(t))}collectRefs(e){let t=new Set,r=(n,i)=>(t.add(n[i]),null);return this.matchAll(e,/(import|export)\s+[^'"\n]*from\s*['"]([^'"\n]+)['"]/,n=>r(n,2)),this.matchAll(e,/export\s*\*\s*from\s*['"]([^'"\n]+)['"]/,n=>r(n,1)),Array.from(t)}matchAll(e,t,r){let n=[];try{let i=new RegExp(t.source,"g"),o;for(;o=i.exec(e);){let a=r(o);a!==null&&n.push(a)}}catch{}return n}isBare(e){return!(e.startsWith("./")||e.startsWith("../")||e.startsWith("file:")||e.startsWith("http://")||e.startsWith("https://"))}};var It="file:///node_modules",he=class{constructor(){this.epoch=0,this.listeners=new Set}getEpoch(){return this.epoch}bumpEpoch(){this.epoch+=1;for(let e of this.listeners)try{e(this.epoch)}catch{}return this.epoch}onEpochChange(e){return this.listeners.add(e),()=>{this.listeners.delete(e)}}epochDir(){return`__tsepoch_${this.epoch}`}pathForMain(e){return`${It}/${this.epochDir()}/${e}/index.d.ts`}pathFor(e,t){let r=Er(t);return`${It}/${this.epochDir()}/${e}/${r}`}};function Er(s){let e=s||"";return e.startsWith("./")?e.slice(2):e.replace(/^\/+/,"")}import{LRUCache as kr}from"lru-cache";function Ke(s){let e=new kr({ttl:1e4,max:500}),t=new Map;return async function(n){try{if(await s.isNegative(n))return;let i=e.get(n);if(i&&Date.now()-i<1e4)return;let o=await s.getCachedFile(n);if(o)return{dts:o,url:n};let a=t.get(n);if(a)return a;let c=(async()=>{let d=await fetch(n,{cache:"no-store"});if(!d.ok){d.status===404&&(e.set(n,Date.now()),await s.recordNegative(n));return}let u=await d.text(),f=d.url||n;return await s.clearNegative(n),await s.setCachedFile(f,u),{dts:u,url:f}})();return t.set(n,c),await c.finally(()=>t.delete(n))}catch{return}}}var Te=class{constructor(e){this.inFlight=new Map,this.scanner=new fe,this.cache=e.cache,this.cdnClient=e.cdnClient,this.versionResolver=e.versionResolver,this.packageService=e.packageService,this.fetchDts=Ke(e.cache),this.typescriptProvider=new ue(this.fetchDts,e.cdnClient),this.definitelyTypedProvider=new me(this.fetchDts,e.cdnClient,e.cache),this.virtualFs=new he}withInFlight(e,t){let r=this.inFlight.get(e);if(r)return r;let n=t().finally(()=>this.inFlight.delete(e));return this.inFlight.set(e,n),n}invalidate(){this.virtualFs.bumpEpoch(),this.inFlight.clear()}capArray(e,t){return e.length<=t?e:e.slice(0,t)}pushFileIfNew(e,t,r){e.some(n=>n.path===t)||e.push({path:t,content:r})}createStubDef(e){let t=this.virtualFs.pathForMain(e);return{pkg:e,mainPath:t,files:[{path:t,content:"export const _shim: any; export default _shim;"}],shims:[{module:e,path:t}]}}async trySubpathWithRootFallback(e,t){let r=new g(e);return r.subpath?this.fetchRootDts(r.name,t):void 0}async fetchViaProviders(e){for(let t of[this.typescriptProvider,this.definitelyTypedProvider])try{let r=await t.resolve(e);if(r?.dts)return r}catch{}}subpathsMatch(e,t){return new g(e).subpath===new g(t).subpath}async fetchRootDts(e,t){let{effectivePackage:r,root:n,pinned:i}=await this.versionResolver.effectivePackage(e,t),o=await this.cache.getCachedDts(r);if(o?.content){let c=o.url??this.cdnClient.file(i?`${n}@${i}`:n,"index.d.ts");return{dts:o.content,url:c,resolvedPkg:r}}let a;try{a=await this.fetchViaProviders(r)}catch{return}if(!(!a?.dts||!a.url)){try{await this.cache.setCachedFile(a.url,a.dts)}catch{}if(this.subpathsMatch(r,a.resolvedPkg||r)){try{await this.cache.setCachedDts(r,a.dts,a.url)}catch{}return a}}}extractPackageRootUrl(e){let t=e.pathname.match(/^(.+@[^/]+\/)/);return t?new URL(t[1],e.origin):new URL("./",e)}toVirtualPath(e,t,r){let n=t.pathname.startsWith(e.pathname)?t.pathname.slice(e.pathname.length):`__deps__/${encodeURIComponent(t.toString()).replace(/%/g,"_")}.d.ts`;return this.virtualFs.pathFor(r,n)}computeEntryPath(e,t){if(!e)return{mainPath:this.virtualFs.pathForMain(t),packageRootUrl:void 0};let r=new URL(e),n=this.extractPackageRootUrl(r);return{mainPath:this.toVirtualPath(n,r,t),packageRootUrl:n}}async expandRelativeRefs(e,t,r,n,i=new Set,o){if(!i.has(t)&&(i.add(t),!(i.size>F.maxRelativeTypeRefs)))try{let a=new URL(t),c=new URL("./",a);o??(o=this.extractPackageRootUrl(a));let d=this.capArray(this.scanner.collectRelativeTypeRefs(e),F.maxRelativeTypeRefs);for(let u of d)await this.tryRelativeRef(u,c,o,r,n,i)}catch{}}async tryRelativeRef(e,t,r,n,i,o){try{let a=new URL(e,t),c=a.pathname+a.search,d=ze(c)?[c]:this.typescriptProvider.declarationCandidatesFor(c);for(let u of d){let h=new URL(u,a).toString();if(o.has(h))return;let p=await this.fetchDts(h);if(p?.dts){let l=this.toVirtualPath(r,new URL(p.url),n);this.pushFileIfNew(i,l,p.dts),await this.expandRelativeRefs(p.dts,p.url,n,i,o,r);return}}}catch{}}isDifferentPackage(e,t){return e===t?!1:new g(e).name!==new g(t).name}async prefetchBareDeps(e,t,r,n,i){try{let o=this.capArray(this.scanner.collectBareModuleRefs(e),F.maxBareDeps).filter(d=>this.isDifferentPackage(d,t));if(!o.length)return;let a=new Set([t]),c=Tr(F.prefetchConcurrency);await Promise.all(o.map(d=>c(()=>this.prefetchBareDepsRecursive(d,r,n,F.maxBareDepth,a,i).catch(()=>{}))))}catch{}}async prefetchBareDepsRecursive(e,t,r,n,i,o){if(n<=0||i.has(e))return;i.add(e);let a=await this.fetchRootDts(e,o);if(!a?.dts)return;let c=a.resolvedPkg||e,d=this.virtualFs.pathForMain(c);this.pushFileIfNew(t,d,a.dts),r.push({module:e,path:d}),a.url&&await this.expandRelativeRefs(a.dts,a.url,c,t);let u=this.capArray(this.scanner.collectBareModuleRefs(a.dts),F.maxBareDeps).filter(f=>!i.has(f));for(let f of u)await this.prefetchBareDepsRecursive(f,t,r,n-1,i,o)}async resolve(e,t,r){let n=await this.packageService.extractImports(e),i=r?[...n,...r]:n;return(await Promise.all(i.map(a=>this.resolveOne(a,t)))).filter(a=>!!a)}async resolveOne(e,t){let{effectivePackage:r}=await this.versionResolver.effectivePackage(e,t);return this.withInFlight(r,async()=>{let n=await this.fetchRootDts(e,t)??await this.trySubpathWithRootFallback(e,t);return n?this.buildDefFromContent(e,n,n.resolvedPkg||e,t):this.createStubDef(e)})}async buildDefFromContent(e,t,r,n){let{dts:i,url:o,resolvedPkg:a}=t,c=new g(a||r),d=c.version?`${c.name}@${c.version}`:c.name,{mainPath:u,packageRootUrl:f}=this.computeEntryPath(o,d),h=[{path:u,content:i}],p=[];o&&await this.expandRelativeRefs(i,o,d,h,void 0,f);let l=h.map(y=>y.content).join(`
|
|
174
|
+
`);await this.prefetchBareDeps(l,d,h,p,n);let m=c.format(),w=e===m?[e]:[e,m];return p.push(...w.map(y=>({module:y,path:u}))),{pkg:e,mainPath:u,files:h,shims:p}}};function Ye(s){return new Te(s)}import*as I from"fs/promises";import*as M from"path";import*as Mt from"os";import*as Xe from"fs/promises";import*as Dt from"crypto";function k(s){return Dt.createHash("sha1").update(s).digest("hex")}async function W(s){try{return JSON.parse(await Xe.readFile(s,"utf8"))}catch{return}}async function Ce(s){try{return await Xe.readFile(s,"utf8")}catch{return}}var At=1,j=M.join(Mt.homedir(),".typebulb","cache"),ge=M.join(j,"packages"),ye=M.join(j,"proxy"),_e=M.join(j,"dts"),Cr=M.join(j,"emit"),Qe;function v(){return Qe||(Qe=_r()),Qe}function Ie(s,e){return M.join(Cr,k(s),e)}async function _r(){await I.mkdir(j,{recursive:!0});let s=M.join(j,"version.json");if((await Ir(s))?.version===At)return;let t=await I.readdir(j).catch(()=>[]);await Promise.all(t.map(r=>I.rm(M.join(j,r),{recursive:!0,force:!0}))),await I.writeFile(s,JSON.stringify({version:At})+`
|
|
175
|
+
`,"utf8")}async function Ir(s){try{let e=await I.readFile(s,"utf8");return JSON.parse(e)}catch{return}}import*as N from"fs/promises";import*as Ot from"path";async function P(s,e){await N.mkdir(Ot.dirname(s),{recursive:!0});let t=`${s}.tmp-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2,8)}`;await N.writeFile(t,e,"utf8"),await N.rename(t,s).catch(async r=>{throw await N.rm(t,{force:!0}).catch(()=>{}),r})}var X=class{constructor(e){this.filePath=e}mem;loadPromise;load(){return this.mem?Promise.resolve(this.mem):(this.loadPromise||(this.loadPromise=W(this.filePath).then(e=>(this.mem=new Map(Object.entries(e??{})),this.mem))),this.loadPromise)}async get(e){return(await this.load()).get(e)}async set(e,t){let r=await this.load();r.set(e,t),await this.persist(r)}async delete(e){let t=await this.load();t.delete(e)&&await this.persist(t)}async persist(e){await P(this.filePath,JSON.stringify(Object.fromEntries(e)))}};var Ze=T.join(ge,"indexes"),Ft=T.join(ge,"pinned"),Dr=T.join(ge,"meta"),Ar=T.join(ge,"negative.json"),Q=Symbol("missing"),Ae=class{pinnedMem=new Map;indexMem=new Map;metaMem=new Map;negativeCache=new L(new X(Ar));async getPinnedExact(e,t){let r=`${e}@${t}`,n=this.pinnedMem.get(r);if(n!==void 0)return n===Q?void 0:n;await v();let i=await Ce(T.join(Ft,k(r)+".txt"));return this.pinnedMem.set(r,i??Q),i}async setPinnedExact(e,t,r){let n=`${e}@${t}`;this.pinnedMem.set(n,r),await v(),await P(T.join(Ft,k(n)+".txt"),r)}async getIndex(e){let t=this.indexMem.get(e);if(t!==void 0)return t===Q?void 0:t;await v();let r=await W(T.join(Ze,De(e)+".json"));return this.indexMem.set(e,r??Q),r}async setIndex(e,t,r){let n={versions:t,distTags:r,updatedAt:Date.now()};this.indexMem.set(e,n),await v(),await P(T.join(Ze,De(e)+".json"),JSON.stringify(n))}async invalidateVersionsCache(e){this.indexMem.delete(e),await Nt.rm(T.join(Ze,De(e)+".json"),{force:!0})}async isNegative(e){return await v(),this.negativeCache.isNegative(e)}async recordNegative(e){await v(),await this.negativeCache.recordNegative(e)}async clearNegative(e){await this.negativeCache.clearNegative(e)}async getMeta(e,t){let r=`${e}@${t}`,n=this.metaMem.get(r);if(n!==void 0)return n===Q?void 0:n;await v();let i=await W(jt(e,t));return this.metaMem.set(r,i??Q),i}async setMeta(e,t,r,n,i){let o={dependencies:r,peerDependencies:n,peerDependenciesMeta:i,updatedAt:Date.now()};this.metaMem.set(`${e}@${t}`,o),await v(),await P(jt(e,t),JSON.stringify(o))}};function jt(s,e){return T.join(Dr,De(s),encodeURIComponent(e)+".json")}function De(s){return s.replace(/\//g,"__")}var Mr={async getJson(s){try{let e=await fetch(s,{redirect:"follow"});return e.ok?await e.json():void 0}catch{return}},async head(s){try{let e=await fetch(s,{method:"HEAD",redirect:"follow"});return{ok:e.ok,url:e.url}}catch{return}}},Or=new Ae,{packageService:Me,versionResolver:$t,cdnClient:Ut,peerResolver:fi}=Pt(Or,Mr);var Bt=`
|
|
5
176
|
(() => {
|
|
6
177
|
// JSON parser (handles jsonish - unquoted keys)
|
|
7
178
|
const parseJson = (str) => {
|
|
@@ -149,14 +320,14 @@ import*as w from"fs/promises";import{readFileSync as it,existsSync as Ie}from"fs
|
|
|
149
320
|
};
|
|
150
321
|
}
|
|
151
322
|
})();
|
|
152
|
-
`;function
|
|
323
|
+
`;function Lt(s){let{name:e,code:t,css:r,html:n,data:i,insight:o,importMap:a,watch:c}=s,d=n.trim()||'<div id="app"></div>',u=h=>h.replace(/<\/script/gi,"<\\/script"),f={imports:jr(a.imports)};return`<!DOCTYPE html>
|
|
153
324
|
<html>
|
|
154
325
|
<head>
|
|
155
326
|
<meta charset="utf-8">
|
|
156
327
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
157
|
-
<title>${
|
|
328
|
+
<title>${Fr(e)} - typebulb</title>
|
|
158
329
|
<script type="importmap">
|
|
159
|
-
${JSON.stringify(
|
|
330
|
+
${JSON.stringify(f,null,2)}
|
|
160
331
|
</script>
|
|
161
332
|
<style>
|
|
162
333
|
/* Reset and base styles */
|
|
@@ -168,40 +339,42 @@ ${r}
|
|
|
168
339
|
</style>
|
|
169
340
|
</head>
|
|
170
341
|
<body>
|
|
171
|
-
${
|
|
342
|
+
${d}
|
|
172
343
|
|
|
173
|
-
${
|
|
174
|
-
${
|
|
175
|
-
${
|
|
344
|
+
${i.length>0?`<script>window.__TB_DATA__ = ${u(JSON.stringify(i))};</script>`:""}
|
|
345
|
+
${o?`<script>window.__TB_INSIGHT__ = ${u(JSON.stringify(o))};</script>`:""}
|
|
346
|
+
${c?"<script>window.__TYPEBULB_WATCH__ = true;</script>":""}
|
|
176
347
|
|
|
177
348
|
<script>
|
|
178
|
-
${
|
|
349
|
+
${Bt}
|
|
179
350
|
</script>
|
|
180
351
|
|
|
181
352
|
<script type="module">
|
|
182
|
-
${
|
|
353
|
+
${u(t)}
|
|
183
354
|
</script>
|
|
184
355
|
</body>
|
|
185
|
-
</html>`}function
|
|
356
|
+
</html>`}function Fr(s){return s.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""")}function jr(s){let e={};for(let[t,r]of Object.entries(s))e[t]=r.startsWith("https://")?"/proxy/"+r:r;return e}import{Hono as $r}from"hono";import{serve as Ur}from"@hono/node-server";import{streamSSE as Br}from"hono/streaming";import*as ee from"fs/promises";import*as J from"path";var S=class extends Error{constructor(e,t="unknown",r=!1){super(e),this.code=t,this.retryable=r}},C=class{getPath(e,t){return this.path}parseStreamChunk(e){return this.checkAndThrowError(e),this.parseProviderStreamChunk(e)}isReasoningEnabled(e){return e?.reasoning!==void 0&&e.reasoning>0}extractSystemMessages(e,t=`
|
|
186
357
|
|
|
187
|
-
`){let r=e.filter(
|
|
358
|
+
`){let r=e.filter(n=>n.role==="system").map(n=>n.content);return{system:r.length?r.join(t):void 0,conversationMessages:e.filter(n=>n.role!=="system")}}parseJsonError(e,t,r=!1){if(!e)return{message:`HTTP ${t}`};try{let n=JSON.parse(e);if(n.error&&typeof n.error=="object"){let i={message:n.error.message||`HTTP ${t}`,type:n.error.type};return r&&(i.code=n.error.code),i}return n.message?{message:n.message}:{message:e}}catch{return{message:e}}}checkAndThrowError(e){if("type"in e&&e.type==="error"&&"message"in e){let t=e.message,r=e.code||"unknown",n=!!e.retryable;throw new S(t,r,n)}if("error"in e&&e.error){let t=this.extractErrorMessage(e.error);throw new S(t)}}extractErrorMessage(e){if(typeof e=="string")try{let t=JSON.parse(e);return t.error?.message||t.message||e}catch{return e}return typeof e=="object"&&e!==null?e.message||JSON.stringify(e):`${this.providerName} returned an error`}};var we=class extends C{constructor(){super(...arguments),this.providerName="Anthropic",this.defaultBaseUrl="https://api.anthropic.com",this.path="/v1/messages"}buildHeaders(e){return{"x-api-key":e,"anthropic-version":"2023-06-01","Content-Type":"application/json",Accept:"application/json"}}buildPayload(e,t,r,n){let{system:i,conversationMessages:o}=this.extractSystemMessages(e),a={model:t,max_tokens:this.getMaxTokens(t),messages:o,stream:n};if(r?.webSearch!==!1&&(a.tools=[{type:"web_search_20250305",name:"web_search"}]),i&&(a.system=i),this.isReasoningEnabled(r)){let c=r.reasoning;if(this.isModernModel(t)){let d={0:"low",1:"low",2:"medium",3:"high"};a.thinking={type:"adaptive"},a.output_config={effort:d[c]}}else{let d={0:0,1:2048,2:4096,3:8192};a.thinking={type:"enabled",budget_tokens:d[c]}}}return a}parseError(e,t){return this.parseJsonError(e,t)}parseNonStreamingResponse(e){if(!this.isAnthropicResponse(e))return{text:""};let t=e.content.filter(n=>n.type==="text").map(n=>n.text).join(""),r=e.content.filter(n=>n.type==="thinking").map(n=>n.thinking).join(`
|
|
188
359
|
|
|
189
|
-
`);return{text:t,reasoning:r||void 0}}parseProviderStreamChunk(e){if(!("type"in e))return null;switch(e.type){case"content_block_delta":return e.delta.type==="text_delta"?{text:e.delta.text||""}:e.delta.type==="thinking_delta"?{reasoning:e.delta.thinking||""}:null;case"message_start":case"content_block_start":case"content_block_stop":case"message_delta":case"message_stop":case"ping":return null;default:return null}}isAnthropicResponse(e){return"content"in e&&Array.isArray(e.content)&&"type"in e&&e.type==="message"}isModernModel(e){let t=e.match(/^claude-\w+-(\d+)-(\d+)/);return!!t&&(+t[1]>4||+t[1]==4&&+t[2]>=6)}getMaxTokens(e){return this.isModernModel(e)?64e3:32e3}};var
|
|
190
|
-
`)),!t&&
|
|
360
|
+
`);return{text:t,reasoning:r||void 0}}parseProviderStreamChunk(e){if(!("type"in e))return null;switch(e.type){case"content_block_delta":return e.delta.type==="text_delta"?{text:e.delta.text||""}:e.delta.type==="thinking_delta"?{reasoning:e.delta.thinking||""}:null;case"message_start":case"content_block_start":case"content_block_stop":case"message_delta":case"message_stop":case"ping":return null;default:return null}}isAnthropicResponse(e){return"content"in e&&Array.isArray(e.content)&&"type"in e&&e.type==="message"}isModernModel(e){let t=e.match(/^claude-\w+-(\d+)-(\d+)/);return!!t&&(+t[1]>4||+t[1]==4&&+t[2]>=6)}getMaxTokens(e){return this.isModernModel(e)?64e3:32e3}};var ve=class extends C{constructor(){super(...arguments),this.providerName="OpenAI",this.defaultBaseUrl="https://api.openai.com",this.path="/v1/responses",this.effortMap={0:"minimal",1:"low",2:"medium",3:"high"}}buildHeaders(e){return{Authorization:`Bearer ${e}`,"Content-Type":"application/json",Accept:"application/json"}}buildPayload(e,t,r,n){let i=this.convertMessagesToInput(e),o={model:t,input:i,stream:n};return r?.webSearch!==!1&&(o.tools=[{type:"web_search"}]),this.isReasoningEnabled(r)&&(o.reasoning={effort:this.effortMap[r.reasoning],summary:"auto"}),o}parseError(e,t){return this.parseJsonError(e,t,!0)}parseNonStreamingResponse(e){if(!this.isResponsesApiResponse(e))return{text:""};let t=e.output_text||"",r;if(e.output&&Array.isArray(e.output))for(let n of e.output)n.type==="reasoning"&&n.summary&&(r=n.summary.map(i=>i.text).join(`
|
|
361
|
+
`)),!t&&n.type==="message"&&n.content&&(t=n.content.filter(i=>i.type==="output_text").map(i=>i.text).join(""));return{text:t,reasoning:r}}parseProviderStreamChunk(e){if(!this.isResponsesApiEvent(e))return null;switch(e.type){case"error":return null;case"response.failed":{let n=e.response?.error,i=n?.message||"Response failed",o=n?.code==="insufficient_quota"||n?.code==="rate_limit_exceeded";throw new S(i,o?"rate_limit":"unknown",o)}case"response.output_text.delta":return{text:e.delta};case"response.reasoning_summary_text.delta":return{reasoning:e.delta};case"response.created":case"response.in_progress":case"response.output_item.added":case"response.output_item.done":case"response.content_part.added":case"response.content_part.done":case"response.output_text.done":case"response.output_text.annotation.added":case"response.reasoning_summary_text.done":case"response.completed":case"response.web_search_call.in_progress":case"response.web_search_call.searching":case"response.web_search_call.completed":return null;default:return null}}convertMessagesToInput(e){return e.map(t=>t.role==="system"?`System: ${t.content}`:t.role==="user"?`User: ${t.content}`:t.role==="assistant"?`Assistant: ${t.content}`:t.content).join(`
|
|
191
362
|
|
|
192
|
-
`)}isResponsesApiEvent(e){return"type"in e&&typeof e.type=="string"}isResponsesApiResponse(e){return"object"in e&&e.object==="response"}};var
|
|
193
|
-
`),
|
|
194
|
-
`)[0],type:
|
|
363
|
+
`)}isResponsesApiEvent(e){return"type"in e&&typeof e.type=="string"}isResponsesApiResponse(e){return"object"in e&&e.object==="response"}};var be=class extends C{constructor(){super(...arguments),this.providerName="Gemini",this.defaultBaseUrl="https://generativelanguage.googleapis.com",this.path="/v1beta/models"}getPath(e,t){return`/v1beta/models/${e}:${t?"streamGenerateContent":"generateContent"}${t?"?alt=sse":""}`}buildHeaders(e){return{"Content-Type":"application/json","x-goog-api-key":e}}buildPayload(e,t,r,n){let{system:i,conversationMessages:o}=this.extractSystemMessages(e,`
|
|
364
|
+
`),c={contents:o.map(d=>({role:d.role==="assistant"?"model":"user",parts:[{text:d.content}]}))};return r?.webSearch!==!1&&(c.tools=[{google_search:{}}]),i&&(c.systemInstruction={role:"system",parts:[{text:i}]}),this.isReasoningEnabled(r)&&(c.generationConfig={temperature:.7+r.reasoning*.1}),c}parseError(e,t){if(!e)return{message:`HTTP ${t}`};try{let r=JSON.parse(e),n=Array.isArray(r)?r[0]?.error:r?.error;return n&&typeof n=="object"?{message:(n.message||`HTTP ${t}`).split(`
|
|
365
|
+
`)[0],type:n.status,code:n.code?.toString()}:r.message?{message:r.message}:{message:e}}catch{return{message:e}}}parseNonStreamingResponse(e){if(this.checkGeminiError(e),!this.isGeminiResponse(e))return{text:"",status:"failed",error:"Invalid response format"};let t=this.extractText(e)||"",r=e.candidates?.[0]?.finishReason,n="complete";return r==="MAX_TOKENS"?n="interrupted":(r==="SAFETY"||r==="RECITATION")&&(n="failed"),{text:t,status:n}}parseProviderStreamChunk(e){if(this.checkGeminiError(e),!this.isGeminiResponse(e))return null;let t=this.extractText(e);return t?{text:t}:null}isGeminiResponse(e){return typeof e=="object"&&e!==null&&"candidates"in e&&Array.isArray(e.candidates)}extractText(e){let t=e.candidates?.[0];if(t?.content?.parts)return t.content.parts.map(r=>r.text).filter(Boolean).join("")}checkGeminiError(e){if(typeof e=="object"&&e!==null&&"error"in e){let t=e.error,r;if(typeof t=="string")r=t;else if(typeof t=="object"&&t!==null){let n=t;r=n.message||n.status||"Gemini returned an error"}else r="Gemini returned an error";throw new S(r)}if(this.isGeminiResponse(e)&&e.promptFeedback?.blockReason){let t=e.promptFeedback.blockReason;throw new S(`Prompt blocked: ${t}`)}}};var xe=class extends C{constructor(){super(...arguments),this.providerName="OpenRouter",this.defaultBaseUrl="https://openrouter.ai/api",this.path="/api/v1/chat/completions",this.effortMap={0:"low",1:"low",2:"medium",3:"high"}}buildHeaders(e,t){let r={Authorization:`Bearer ${e}`,"x-api-key":e,"Content-Type":"application/json",Accept:"application/json","X-Title":"Typebulb"};return t&&(r["HTTP-Referer"]=t,r.Referer=t,r.Origin=t),r}buildPayload(e,t,r,n){let i={model:t,messages:e,stream:n};return r?.webSearch===!0&&(i.plugins=[{id:"web"}]),this.isReasoningEnabled(r)&&(i.reasoning={effort:this.effortMap[r.reasoning]}),i}parseError(e,t){return this.parseJsonError(e,t,!0)}parseNonStreamingResponse(e){if(!this.hasChoices(e))return{text:""};let t=e.choices[0],r=t?.message?.content??t?.text??"",n=t?.message?.reasoning??e.reasoning;return{text:r,reasoning:n}}parseProviderStreamChunk(e){if(!this.hasChoices(e))return null;let t=e.choices[0];if(!t)return null;let r=t.delta||t.message;if(!r)return null;let n=r.content||void 0,i=r.reasoning||void 0;return!n&&!i?null:{text:n,reasoning:i}}hasChoices(e){return typeof e=="object"&&e!==null&&"choices"in e&&Array.isArray(e.choices)}};var Nr=new Map([["openai",new ve],["openrouter",new xe],["anthropic",new we],["gemini",new be]]);function V(s){let e=Nr.get(s);if(!e)throw new Error(`Unsupported protocol: ${s}`);return e}async function et(s,e){let t=V(s.protocol),r=t.getPath(e.model,e.stream),n=new URL(r,s.baseUrl).toString(),i=t.buildHeaders(s.apiKey,e.origin),o=t.buildPayload(e.messages,e.model,{reasoning:e.reasoning,webSearch:e.webSearch},e.stream);return e.modifyPayload?.(o),fetch(n,{method:"POST",headers:i,body:JSON.stringify(o),signal:e.signal})}async function tt(s,e){let t=V(e),r=await s.text().catch(()=>""),{message:n}=t.parseError(r,s.status),i=s.status,o="unknown";return i===429?o="rate_limit":i===413&&(o="context_exceeded"),{code:o,message:n,retryable:i===429}}function Wt(s){let e=s.indexOf(`\r
|
|
195
366
|
\r
|
|
196
|
-
`),t=
|
|
367
|
+
`),t=s.indexOf(`
|
|
197
368
|
|
|
198
|
-
`);return e!==-1&&(t===-1||e<t)?{pos:e,len:4}:t!==-1?{pos:t,len:2}:{pos:-1,len:0}}function
|
|
199
|
-
`).trim();if(!r)return null;if(r==="[DONE]")return"done";try{return JSON.parse(r)}catch{return null}}async function
|
|
369
|
+
`);return e!==-1&&(t===-1||e<t)?{pos:e,len:4}:t!==-1?{pos:t,len:2}:{pos:-1,len:0}}function rt(s){let t=s.split(/\r?\n/).filter(n=>n.startsWith("data:"));if(!t.length)return null;let r=t.map(n=>n.replace(/^data:\s?/,"")).join(`
|
|
370
|
+
`).trim();if(!r)return null;if(r==="[DONE]")return"done";try{return JSON.parse(r)}catch{return null}}async function Vt(s,e,t){let r=new TextDecoder,n="",i=!1,o=t?new Promise((a,c)=>{t.aborted&&c(new Error("Aborted")),t.addEventListener("abort",()=>c(new Error("Aborted")),{once:!0})}):null;for(;;){let a=o?await Promise.race([s.read(),o]):await s.read(),{done:c,value:d}=a;if(c){if(n.trim()){let h=rt(n);h!==null&&h!=="done"&&e(h)}break}i=!0,n+=r.decode(d,{stream:!0});let{pos:u,len:f}=Wt(n);for(;u!==-1;){let h=n.slice(0,u);n=n.slice(u+f);let p=rt(h);if(p==="done"){n="";break}p!==null&&e(p),{pos:u,len:f}=Wt(n)}}return{receivedAnyData:i}}async function nt(s,e){let t=e??(s.headers.get("X-Provider-Protocol")||"openai"),r=V(t);if(!s.body)throw new Error("Response body is missing");let n=s.body.getReader(),i="";return await Vt(n,o=>{let a=r.parseStreamChunk(o);a?.text&&(i+=a.text)}),i}import*as st from"fs/promises";import*as Pe from"path";var Oe=class{async get(e){let t=k(e),r=Pe.join(ye,t+".bin"),n=Pe.join(ye,t+".json");try{let[i,o]=await Promise.all([st.readFile(r),st.readFile(n,"utf8")]),a=JSON.parse(o);return{body:i,contentType:a.contentType,cacheControl:a.cacheControl}}catch{return}}async set(e,t){await v();let r=k(e),n=Pe.join(ye,r+".bin"),i=Pe.join(ye,r+".json"),o={url:e,contentType:t.contentType,cacheControl:t.cacheControl};await Promise.all([P(n,t.body),P(i,JSON.stringify(o))])}};async function Gt(s){let{getHtml:e,basePath:t,port:r,reloadEmitter:n,getServerExports:i}=s,o=new $r;o.use("*",async(p,l)=>{await l(),p.res.headers.set("Cross-Origin-Opener-Policy","same-origin"),p.res.headers.set("Cross-Origin-Embedder-Policy","credentialless")}),o.get("/",p=>p.html(e())),o.post("/__fs/read",async p=>{try{let{path:l}=await p.req.json(),m=Ht(l,t),w=await ee.readFile(m,"utf-8");return p.json({content:w})}catch(l){let m=l instanceof Error?l.message:"Unknown error";return p.json({error:m},400)}}),o.post("/__fs/write",async p=>{try{let{path:l,content:m}=await p.req.json(),w=Ht(l,t);return await ee.mkdir(J.dirname(w),{recursive:!0}),await ee.writeFile(w,m,"utf-8"),p.json({success:!0})}catch(l){let m=l instanceof Error?l.message:"Unknown error";return p.json({error:m},400)}});let a={log:console.log};o.post("/__api/:name",async p=>{try{let l=i?.(),m=p.req.param("name"),w=l?.[m]??a[m];if(!w||typeof w!="function")return p.json({error:`API function '${m}' not found`},404);let{args:y}=await p.req.json(),A=await w(...y||[]);return p.json({result:A})}catch(l){let m=l instanceof Error?l.message:"Unknown error";return p.json({error:m},500)}}),o.post("/__ai",async p=>{try{let{messages:l,system:m,reasoning:w,provider:y,model:A,webSearch:$}=await p.req.json();if(!l||!Array.isArray(l)||l.length===0)return p.json({message:"messages array is required",code:"unknown",retryable:!1},400);let _=Lr(y,A);if(typeof _=="string")return p.json({message:_,code:"unknown",retryable:!1},400);let re=[...m?[{role:"system",content:m}]:[],...l.map(O=>({role:O.role,content:O.content}))],U=await et(_,{model:_.model,messages:re,stream:!0,reasoning:w??0,webSearch:$??!0});if(!U.ok){let O=await tt(U,_.protocol);return p.json(O,U.status)}let Se=await nt(U,_.protocol);return Se||console.warn("[tb.ai] Empty response from provider"),p.json({text:Se})}catch(l){if(l instanceof S)return p.json({message:l.message,code:l.code,retryable:l.retryable},500);let m=l instanceof Error?l.message:"Unknown error";return p.json({message:m,code:"unknown",retryable:!1},500)}}),o.get("/__models",async p=>{try{let l=await Jr();return p.json(l)}catch{return p.json([],200)}});let c=["esm.sh","unpkg.com","cdn.jsdelivr.net","cdnjs.cloudflare.com"],d=new Oe;o.get("/proxy/*",async p=>{let l=new URL(p.req.url),w=(l.pathname+l.search).slice(7),y=w.lastIndexOf("https://");return y===-1?p.text("Invalid proxy URL",400):u(p,w.slice(y))});async function u(p,l){let m;try{m=new URL(l)}catch{return p.text("Invalid URL",400)}if(m.protocol!=="https:")return p.text("HTTPS only",400);if(!c.includes(m.hostname))return p.text("Host not allowed",403);let w=await d.get(l);if(w)return new Response(w.body,{status:200,headers:it(w.contentType,w.cacheControl)});try{let y=await fetch(l,{headers:{Accept:p.req.header("Accept")||"*/*"},redirect:"follow"});if(!y.ok)return p.text(`Upstream ${y.status}`,y.status);let A=y.headers.get("Content-Type")||void 0,$=y.headers.get("Cache-Control")||void 0;if(y.body){let[_,re]=y.body.tee();return(async()=>{try{let U=await new Response(re).arrayBuffer();await d.set(l,{body:Buffer.from(U),contentType:A,cacheControl:$})}catch{}})(),new Response(_,{status:y.status,headers:it(A,$)})}return new Response(null,{status:y.status,headers:it(A,$)})}catch(y){return p.text(`Proxy fetch failed: ${y instanceof Error?y.message:y}`,502)}}n&&o.get("/__reload",p=>Br(p,async l=>{let m=()=>{l.writeSSE({event:"reload",data:""})};for(n.on("reload",m),l.onAbort(()=>{n.removeListener("reload",m)});;)await l.sleep(3e4)}));let f=/^\/(v\d+\/|@[^/]+\/[^@/]+@|[^@/]+@)/;o.notFound(async p=>{if(p.req.method!=="GET")return p.text("Not Found",404);let l=new URL(p.req.url);return f.test(l.pathname)?u(p,"https://esm.sh"+l.pathname+l.search):p.text("Not Found",404)});let h=Ur({fetch:o.fetch,port:r});return{port:r,close:()=>h.close()}}var qt={anthropic:"ANTHROPIC_API_KEY",openai:"OPENAI_API_KEY",gemini:"GOOGLE_API_KEY",openrouter:"OPENROUTER_API_KEY"};function Lr(s,e){let t=s??process.env.TB_AI_PROVIDER,r=e??process.env.TB_AI_MODEL;if(!t)return"No provider specified. Set TB_AI_PROVIDER in your .env file or pass provider in the tb.ai() call.";if(!r)return"No model specified. Set TB_AI_MODEL in your .env file or pass model in the tb.ai() call.";let n;try{n=V(t)}catch{return`Unknown provider '${t}'.`}let i=qt[t],o=process.env[i];return o?{apiKey:o,baseUrl:n.defaultBaseUrl,protocol:t,model:r,isFreeModel:!1}:`No API key for '${t}'. Set ${i} in your .env file.`}var Wr="https://api.typebulb.com/api/models",Vr=1440*60*1e3,Z=null;async function Jr(){if(!Z||Date.now()-Z.fetchedAt>Vr){let s=await fetch(Wr);if(!s.ok)return Z?Jt(Z.models):[];Z={models:await s.json(),fetchedAt:Date.now()}}return Jt(Z.models)}function Jt(s){let e=new Set(Object.entries(qt).filter(([,t])=>!!process.env[t]).map(([t])=>t));return s.filter(t=>e.has(t.provider))}function it(s,e){let t=new Headers;return s&&t.set("Content-Type",s),e&&t.set("Cache-Control",e),t.set("Access-Control-Allow-Origin","*"),t.set("Cross-Origin-Resource-Policy","cross-origin"),t}function Ht(s,e){let t=J.resolve(e,s),r=J.normalize(e);if(!J.normalize(t).startsWith(r))throw new Error("Path traversal detected - access denied");return t}async function ot(s){let e=await import("net");return new Promise(t=>{let r=e.createServer();r.listen(s,()=>{let n=r.address(),i=typeof n=="object"&&n?n.port:s;r.close(()=>t(i))}),r.on("error",()=>{t(ot(s+1))})})}import Hr from"open";async function zt(s){await Hr(s)}import Gr from"chokidar";function at(s){let{bulbPath:e,emitter:t}=s,r=Gr.watch(e,{persistent:!0,ignoreInitial:!0,awaitWriteFinish:{stabilityThreshold:100,pollInterval:50}});return r.on("change",()=>{t.emit("reload")}),()=>r.close()}import*as D from"fs/promises";import*as H from"path";import*as te from"path";var qr=te.join(_e,"pkg"),zr=te.join(_e,"files"),Kr=te.join(_e,"negative.json"),je=class{pkgMem=new Map;fileMem=new Map;negativeCache=new L(new X(Kr));async getCachedDts(e){if(this.pkgMem.has(e))return this.pkgMem.get(e);await v();let t=await W(Kt(e));return this.pkgMem.set(e,t),t}async setCachedDts(e,t,r){let n={content:t,url:r};this.pkgMem.set(e,n),await Fe(async()=>{await v(),await P(Kt(e),JSON.stringify(n))})}async getCachedFile(e){if(this.fileMem.has(e))return this.fileMem.get(e);await v();let t=await Ce(Yt(e));return this.fileMem.set(e,t),t}async setCachedFile(e,t){this.fileMem.set(e,t),await Fe(async()=>{await v(),await P(Yt(e),t)})}isNegative(e){return this.negativeCache.isNegative(e)}async recordNegative(e){await Fe(async()=>{await v(),await this.negativeCache.recordNegative(e)})}clearNegative(e){return Fe(()=>this.negativeCache.clearNegative(e))}};async function Fe(s){try{await s()}catch{}}function Kt(s){return te.join(qr,k(s)+".json")}function Yt(s){return te.join(zr,k(s)+".txt")}var ct;function Yr(){return ct||(ct=Ye({cache:new je,cdnClient:Ut,packageService:Me,versionResolver:$t})),ct}var Xt="file:///node_modules/";async function Qt(s){let e=Ie(s.emitKey,"typecheck");await v(),await D.rm(e,{recursive:!0,force:!0}),await D.mkdir(e,{recursive:!0});let t=en(s.jsxImportSource,s.dependencies),r=await Yr().resolve(s.code,s.dependencies,t),n=new Set;for(let a of r)for(let c of a.files){let d=lt(c.path);if(!d||n.has(d))continue;n.add(d);let u=H.join(e,"node_modules",d);await D.mkdir(H.dirname(u),{recursive:!0}),await D.writeFile(u,c.content,"utf8")}let i={};for(let a of r)for(let c of a.shims){let d=lt(c.path);d&&(i[c.module]=[`./node_modules/${d}`])}for(let a of r){let c=lt(a.mainPath);c&&(i[a.pkg]=[`./node_modules/${c}`])}let o=Xr(s.jsxImportSource,i);return await D.writeFile(H.join(e,"tsconfig.json"),JSON.stringify(o,null,2)+`
|
|
371
|
+
`,"utf8"),await D.writeFile(H.join(e,"code.tsx"),s.code,"utf8"),await D.writeFile(H.join(e,"tb.d.ts"),Ge,"utf8"),{dir:e}}function Xr(s,e){return{compilerOptions:{target:"es2023",module:"esnext",moduleResolution:"bundler",lib:Qr([...Je,...He]),jsx:"react-jsx",jsxImportSource:s??"react",strict:!0,noEmit:!0,skipLibCheck:!0,esModuleInterop:!0,allowSyntheticDefaultImports:!0,forceConsistentCasingInFileNames:!0,baseUrl:".",paths:e},include:["code.tsx","tb.d.ts"]}}function Qr(s){return s.filter(e=>!e.since).map(e=>Zr(e.name))}function Zr(s){return s.split(".").map(e=>/^es\d+$/i.test(e)?e.toUpperCase():e==="dom"?"DOM":e==="esnext"?"ESNext":e.charAt(0).toUpperCase()+e.slice(1)).join(".")}function en(s,e){let t=s??("react"in e?"react":void 0);return t?[`${t}/jsx-runtime`,`${t}/jsx-dev-runtime`]:[]}function lt(s){if(!s.startsWith(Xt))return;let e=s.slice(Xt.length),t=e.indexOf("/");if(!(t<0))return e.slice(t+1)}import*as R from"fs/promises";import*as G from"path";import{existsSync as an}from"fs";import*as Ne from"fs/promises";import*as dt from"path";import{existsSync as Zt}from"fs";import{execFile as tn}from"child_process";import{promisify as rn}from"util";var nn=rn(tn);async function $e(s,e){let t=s.filter(n=>!sn(n,e));if(t.length===0)return;await Ne.mkdir(e,{recursive:!0});let r=dt.join(e,"package.json");Zt(r)||await Ne.writeFile(r,JSON.stringify({name:"typebulb-server",private:!0})),console.log(` Installing: ${t.join(", ")}`),await nn("npm",["install","--no-audit","--no-fund",...t],{cwd:e,shell:!0})}function sn(s,e){return Zt(dt.join(e,"node_modules",on(s)))}function on(s){if(s.startsWith("@")){let t=s.indexOf("/");if(t<0)return s;let r=s.indexOf("@",t+1);return r<0?s:s.slice(0,r)}let e=s.indexOf("@");return e<0?s:s.slice(0,e)}var cn="^22";async function er(s){let e=Ie(s.emitKey,"typecheck-server");await v(),await R.rm(e,{recursive:!0,force:!0}),await R.mkdir(e,{recursive:!0});let t=G.join(s.bulbDir,".typebulb");await $e([`@types/node@${cn}`],t);let r=G.join(t,"node_modules"),n=G.join(e,"node_modules");return await dn(r,n),await R.writeFile(G.join(e,"server.ts"),s.server,"utf8"),await R.writeFile(G.join(e,"tb.d.ts"),qe,"utf8"),await R.writeFile(G.join(e,"tsconfig.json"),JSON.stringify(ln(),null,2)+`
|
|
372
|
+
`,"utf8"),{dir:e}}function ln(){return{compilerOptions:{target:"es2023",module:"esnext",moduleResolution:"node",lib:["ES2023"],types:["node"],strict:!0,noEmit:!0,skipLibCheck:!0,esModuleInterop:!0,allowSyntheticDefaultImports:!0,forceConsistentCasingInFileNames:!0},include:["server.ts","tb.d.ts"]}}async function dn(s,e){if(!an(s)){await R.mkdir(e,{recursive:!0});return}await R.rm(e,{recursive:!0,force:!0});let t=process.platform==="win32"?"junction":"dir";await R.symlink(s,e,t)}var Io=hn(mn),gn="0.5.0";function yn(s){let e={subcommand:"run",file:"",port:3e3,watch:!0,open:!0,server:!1,help:!1,version:!1};s[0]==="check"&&(e.subcommand="check",s=s.slice(1));for(let t=0;t<s.length;t++){let r=s[t];if(r==="--help"||r==="-h")e.help=!0;else if(r==="--version"||r==="-V")e.version=!0;else if(r==="--no-watch")e.watch=!1;else if(r==="--no-open")e.open=!1;else if(r==="--server")e.server=!0;else if(r==="--port"||r==="-p"){let n=s[++t],i=parseInt(n,10);isNaN(i)&&(console.error(`Invalid port: ${n}`),process.exit(1)),e.port=i}else r.startsWith("-")||(e.file=r)}return e}function wn(){console.log(`
|
|
200
373
|
typebulb - Local bulb runner for Typebulb
|
|
201
374
|
|
|
202
375
|
Usage:
|
|
203
|
-
typebulb
|
|
204
|
-
typebulb
|
|
376
|
+
typebulb [file.bulb.md] Run a bulb (defaults to .bulb.md in cwd)
|
|
377
|
+
typebulb check [file.bulb.md] Type-check a bulb without running it
|
|
205
378
|
|
|
206
379
|
Options:
|
|
207
380
|
--no-watch Disable hot reload (watch is on by default)
|
|
@@ -243,11 +416,11 @@ Examples:
|
|
|
243
416
|
typebulb my-editor.bulb.md
|
|
244
417
|
typebulb --no-watch --port 8080 my-editor.bulb.md
|
|
245
418
|
typebulb .
|
|
246
|
-
`)}async function
|
|
247
|
-
`)){let
|
|
248
|
-
`);let r=new
|
|
249
|
-
${
|
|
250
|
-
`),
|
|
251
|
-
`);let u;if(
|
|
252
|
-
`)}catch(
|
|
253
|
-
Shutting down...`),
|
|
419
|
+
`)}async function vn(s){let t=(await E.readdir(s)).find(r=>r.endsWith(".bulb.md"));return t?b.join(s,t):null}function rr(){ut([".env",".env.local"],process.cwd(),!0)}function ut(s,e,t=!1){for(let r of s){let n=b.resolve(e,r);try{let i=pn(n,"utf-8");for(let o of i.split(`
|
|
420
|
+
`)){let a=o.trim();if(!a||a.startsWith("#"))continue;let c=a.indexOf("=");if(c===-1)continue;let d=a.slice(0,c).trim(),u=a.slice(c+1).trim();(u.startsWith('"')&&u.endsWith('"')||u.startsWith("'")&&u.endsWith("'"))&&(u=u.slice(1,-1)),process.env[d]??=u}}catch{t||console.warn(` Warning: env file not found: ${r}`)}}}function bn(s){let e=new Set,t=/\bimport\s+(?:[\s\S]*?\s+from\s+)?['"]([^./][^'"]*)['"]/g,r;for(;r=t.exec(s);){let n=r[1];if(n.startsWith("node:"))continue;let i=n.startsWith("@")?n.split("/").slice(0,2).join("/"):n.split("/")[0];e.add(i)}return[...e]}async function nr(s,e){let t=Be(s,{serverOnly:!0});if(t.error)throw new Error(`Server compilation error: ${t.error}`);let r=b.join(e,".typebulb");await E.mkdir(r,{recursive:!0});let n=bn(t.code);n.length>0&&await $e(n,r);let i=b.join(r,"server.mjs");return await E.writeFile(i,t.code,"utf-8"),await import(`${un(i).href}?t=${Date.now()}`)}async function Ue(s){let e=await E.readFile(s,"utf-8"),t=ft(e);if(!t)throw new Error("Invalid .bulb.md file format");let r=ht(t);return{bulb:r,config:yt(r.config)}}async function tr(s,e){let{bulb:t,config:r}=await Ue(s),n=gt(t.data),i=Be(t.code,{jsxImportSource:r.jsxImportSource});i.error&&console.error("Compilation error:",i.error);let{importMap:o}=await Me.buildImportMap(i.code,r.dependencies??{}),a=Lt({name:t.name,code:i.code,css:t.css,html:t.html,data:n,insight:t.insight,importMap:o,watch:e}),c=b.dirname(s);r.env?.length&&ut(r.env,c);let d=null;return t.server&&(d=await nr(t.server,c)),{html:a,bulb:t,serverExports:d}}async function xn(s){let{bulb:e,config:t}=await Ue(s);!e.code&&!e.server&&(console.error("Bulb has neither **code.tsx** nor **server.ts**; nothing to check."),process.exit(1));let r=[];if(e.code){let{dir:i}=await Qt({code:e.code,dependencies:t.dependencies??{},jsxImportSource:t.jsxImportSource,emitKey:s});r.push({role:"client",dir:i})}if(e.server){let{dir:i}=await er({server:e.server,bulbDir:b.dirname(s),emitKey:s});r.push({role:"server",dir:i})}let n=!1;for(let{role:i,dir:o}of r){let{stdout:a,exitCode:c}=await Pn(o);for(let d of a.split(/\r?\n/))d.trim()&&console.log(`${i} ${d}`);c!==0&&(n=!0)}n&&process.exit(1)}function Pn(s){return new Promise(e=>{let t=fn("npx",["tsc","--noEmit"],{cwd:s,shell:!0}),r="";t.stdout?.on("data",n=>{r+=n.toString()}),t.stderr?.on("data",n=>{r+=n.toString()}),t.on("close",n=>e({stdout:r,exitCode:n??1}))})}async function Sn(s,e){rr();let t=async()=>{let{bulb:r,config:n}=await Ue(s),i=b.dirname(s);n.env?.length&&ut(n.env,i),await nr(r.server,i)};if(console.log(`Running ${b.basename(s)}...`),await t(),e){console.log(`Watching for changes...
|
|
421
|
+
`);let r=new pt;r.on("reload",async()=>{try{console.log("Re-running..."),await t()}catch(n){console.error("Error:",n)}}),at({bulbPath:s,emitter:r})}}async function Rn(){let s=yn(process.argv.slice(2));s.version&&(console.log(`typebulb ${gn}`),process.exit(0)),s.help&&(wn(),process.exit(0));let e;if(!s.file||s.file==="."){let h=await vn(process.cwd());h||(console.error("No .bulb.md file found in current directory"),process.exit(1)),e=h}else e=b.resolve(s.file);try{await E.access(e)}catch{console.error(`File not found: ${e}`),process.exit(1)}if(e.endsWith(".bulb.md")||(console.error("File must have .bulb.md extension"),process.exit(1)),s.subcommand==="check"){await xn(e);return}try{let{bulb:h}=await Ue(e);if(h.server&&(!h.code||s.server)){await Sn(e,s.watch);return}}catch{}let t=process.cwd(),r=s.watch?new pt:void 0;rr(),console.log(`Loading ${b.basename(e)}...`);let{html:n,bulb:i,serverExports:o}=await tr(e,s.watch),a=await ot(s.port),c=await Gt({getHtml:()=>n,basePath:t,port:a,reloadEmitter:r,getServerExports:()=>o}),d=`http://localhost:${a}`;console.log(`
|
|
422
|
+
${i.name}`),console.log(` ${d}
|
|
423
|
+
`),s.watch&&console.log(` Watching for changes...
|
|
424
|
+
`);let u;if(s.watch&&r){let h=new pt;h.on("reload",async()=>{try{console.log("Recompiling...");let p=await tr(e,!0);n=p.html,o=p.serverExports,r.emit("reload"),console.log(`Done. Browser reloading...
|
|
425
|
+
`)}catch(p){console.error("Compile error:",p)}}),u=at({bulbPath:e,emitter:h})}s.open&&await zt(d);let f=async()=>{console.log(`
|
|
426
|
+
Shutting down...`),c.close(),u?.();let h=b.join(b.dirname(e),".typebulb","server.mjs");await E.rm(h,{force:!0}).catch(()=>{}),process.exit(0)};process.on("SIGINT",f),process.on("SIGTERM",f)}Rn().catch(s=>{console.error("Error:",s.message),process.exit(1)});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "typebulb",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "Local bulb runner CLI for Typebulb",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"engines": { "node": ">=18" },
|
|
@@ -16,14 +16,18 @@
|
|
|
16
16
|
"build": "tsc --build && node esbuild.config.mjs",
|
|
17
17
|
"clean": "rimraf dist .tsbuild",
|
|
18
18
|
"dev": "tsc --build && node dist/index.js",
|
|
19
|
-
"prepublishOnly": "rimraf dist && node esbuild.config.mjs"
|
|
19
|
+
"prepublishOnly": "rimraf dist && tsc --build && node esbuild.config.mjs"
|
|
20
20
|
},
|
|
21
21
|
"dependencies": {
|
|
22
22
|
"@hono/node-server": "^1.14.1",
|
|
23
23
|
"chokidar": "^4.0.3",
|
|
24
24
|
"es-module-lexer": "^1.7.0",
|
|
25
|
+
"fflate": "^0.8.2",
|
|
25
26
|
"hono": "^4.7.5",
|
|
27
|
+
"lru-cache": "^11.2.2",
|
|
26
28
|
"open": "^10.1.0",
|
|
29
|
+
"p-limit": "^7.2.0",
|
|
30
|
+
"resolve.exports": "^2.0.3",
|
|
27
31
|
"semver": "^7.7.3",
|
|
28
32
|
"sucrase": "^3.35.0"
|
|
29
33
|
},
|
|
@@ -33,6 +37,7 @@
|
|
|
33
37
|
"@typebulb/shared-types": "workspace:*",
|
|
34
38
|
"esbuild": "^0.27.3",
|
|
35
39
|
"rimraf": "^6.0.1",
|
|
36
|
-
"typebulb-resolver": "workspace:*"
|
|
40
|
+
"typebulb-resolver": "workspace:*",
|
|
41
|
+
"typebulb-dts": "workspace:*"
|
|
37
42
|
}
|
|
38
43
|
}
|