typebulb 0.17.3 → 0.17.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -185,6 +185,7 @@ npm install -g typebulb
185
185
  | `tb.infer()` | One-shot LLM call driven by the `infer.md` block | ❌ | ❌ |
186
186
 
187
187
  - **❌ (embedded):** the call throws `"not available in an embedded bulb"` — an embed is a client-only sandboxed iframe with **no persistent storage** either (`localStorage`, `IndexedDB`, cookies, same-origin Workers all fail), so keep state in memory. `tb.mode === 'embedded'` lets a bulb detect this and self-adjust.
188
+ - **`tb.proxy` only rewrites allow-listed CDNs** — `esm.sh`, `unpkg.com`, `cdn.jsdelivr.net`, `cdnjs.cloudflare.com`; any other host 403s. Serve a WASM/worker asset (a tesseract or ffmpeg core, a pdf.js worker) from one of these.
188
189
 
189
190
  ## Portability back to typebulb.com
190
191
 
@@ -258,6 +259,7 @@ Run a bulb **once** and let hot reload drive the loop.
258
259
  - **The frontmatter `name:` is the bulb's title** — a few words, not a sentence — and the filename should be its slug (`name: Counter` → `counter.bulb.md`), saved in the project's **`typebulbs/`** folder.
259
260
  - **A bulb's working files belong beside it**, in a folder named for its slug. `tb.fs`/`server.ts` paths are relative to the launch dir (cwd), not the bulb's folder — so run from the project root and prefix the bulb's path: `typebulbs/counter/…`, not a bare `counter/…`.
260
261
  - **Self-testing a local bulb** — To confirm a bulb works, run it, instrument with `tb.server.log(...)` (prints to the server's stdout, captured in the log — and works **even on a Restricted bulb**), and read it back with `typebulb logs`. That's the loop to verify behaviour without asking the user to copy-paste console output. `tb.fs.write(...)` is handy for dumping large outputs.
262
+ - **Self-testing client code** — to drive the *browser* side, gate the work behind `tb.onMessage(m => { if (m === 'selftest') run() })`, trigger it with `typebulb send <file> selftest --wait`, and read `run()`'s `tb.server.log(...)` back the same way. The client-side counterpart to instrumenting `server.ts`.
261
263
  - **Testing a `server.ts` export directly** — `typebulb call <file> <fn> [arg…]` boots `server.ts`, invokes one export, and prints its return as JSON to stdout (logs/errors to stderr, so `… | jq` works). Args after `<fn>` are JSON-or-string; `--args '<json-array>'` (or `--args -` for stdin) escapes tricky quoting. Needs `--trust`.
262
264
  - **Mount to the container your `index.html` declares.** The corpus convention is `<div id="root"></div>` with `createRoot(document.getElementById("root")!)`.
263
265
  - **All imports at the top of `code.tsx`, and every bare import declared in `config.json` `dependencies`.** Bare imports (`react`, `d3`, `three`, …) resolve from a CDN — no install step — but declaring them is **required, not optional**: an import missing from `dependencies` is a lint error that fails `npx typebulb check` *and* refuses to run. Declaring is also what pins versions and lets `check` fetch type defs (without it you get errors like `TS2875: react/jsx-runtime`). So a bulb with imports must carry a `config.json` with a matching `dependencies` entry for each.
@@ -1114,15 +1114,21 @@ const something = require('module-name') // NOT SUPPORTED!
1114
1114
  // URL
1115
1115
  url: () => Promise.resolve(location.href),
1116
1116
 
1117
- // Proxy: rewrite CDN URLs to the local server's /proxy/. Relative on purpose \u2014
1118
- // it resolves against the served page on the CLI, and against the host page
1119
- // inside a srcdoc embed, where location.origin is the string "null".
1117
+ // Proxy: rewrite CDN URLs to the local server's /proxy/. Absolute when we have a
1118
+ // real origin (the CLI page, or a broken-out bulb) so the URL also works from a
1119
+ // worker's importScripts, which rejects a root-relative path. Relative in a
1120
+ // null-origin srcdoc embed, where prefixing the "null" origin would yield the
1121
+ // broken string null/proxy/... ; there the relative path resolves against the
1122
+ // host page. Absolute and root-relative are equivalent for every other consumer
1123
+ // (fetch, new Worker, script src) when there is one real origin, so this only
1124
+ // adds the importScripts case and changes nothing else.
1120
1125
  proxy: (url) => {
1121
1126
  if (!url) return url;
1122
1127
  const i = url.lastIndexOf('https://');
1123
1128
  const clean = i !== -1 ? url.slice(i) : url;
1124
1129
  if (!clean.startsWith('https://')) return url;
1125
- return '/proxy/' + clean;
1130
+ const rel = '/proxy/' + clean;
1131
+ return location.origin && location.origin !== 'null' ? location.origin + rel : rel;
1126
1132
  },
1127
1133
 
1128
1134
  // Server API - call functions from **server.ts**. Returns the hybrid call object: await it for