tosijs-ui 1.6.17 → 1.6.19
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/CHANGELOG.md +48 -0
- package/dist/doc-browser.js +5 -1
- package/dist/doc-system/site/check-examples.d.ts +14 -0
- package/dist/doc-system/site/check-examples.js +97 -0
- package/dist/doc-system/site/dev-server.js +80 -12
- package/dist/doc-system/site/orchestrator.js +16 -0
- package/dist/doc-system/site/site-config.d.ts +22 -0
- package/dist/iife.js +3 -3
- package/dist/iife.js.map +5 -5
- package/dist/live-example/component.js +10 -5
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/llms.txt +3 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,53 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.6.19
|
|
4
|
+
|
|
5
|
+
Doc-system tooling; no component API changes.
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- **Build-time example transpile check.** Every executable live-example block
|
|
10
|
+
(`js` / `tjs` / `ts` / `test`) across the whole corpus is run through the front
|
|
11
|
+
half of the runtime pipeline — `rewriteImports` → transform → `new
|
|
12
|
+
AsyncFunction` — at build time, **without executing it**, so a block that can't
|
|
13
|
+
build (a syntax/import error, or illustrative code mistakenly tagged with an
|
|
14
|
+
executable language instead of the display-only `typescript`) **fails the build**
|
|
15
|
+
with the offending doc/block named, on every page — including fences hidden in
|
|
16
|
+
blockquotes and lists. TypeScript is transpiled with bun's own transpiler
|
|
17
|
+
(network-free). Opt out with `checkExamples: false`.
|
|
18
|
+
- **"One Source, Every Artifact"** doc page — how one corpus of doc-comments +
|
|
19
|
+
markdown projects into a static SEO site, a self-testing live playground with
|
|
20
|
+
in-browser TypeScript, an ePub/PDF, and an agent-debuggable page. Embeds a live
|
|
21
|
+
`<tosi-doc-system>` (the whole system running inside its own page).
|
|
22
|
+
|
|
23
|
+
### Fixed
|
|
24
|
+
|
|
25
|
+
- **A live example's build/exec failure is now a test failure whether or not it
|
|
26
|
+
defines `test` blocks.** So on any page the browser test runner loads, *all* of
|
|
27
|
+
its examples are checked for explosions — a no-test example that throws is
|
|
28
|
+
reported as a failed test — not just blocks with explicit assertions.
|
|
29
|
+
|
|
30
|
+
## 1.6.18
|
|
31
|
+
|
|
32
|
+
Doc-site tooling; no component API changes.
|
|
33
|
+
|
|
34
|
+
### Added
|
|
35
|
+
|
|
36
|
+
- **`haltijaDev` — give a coding agent eyes + hands on your running dev page.**
|
|
37
|
+
Set `haltijaDev: true` (or `HALTIJA_DEV=1`) and `bun start` injects a tiny
|
|
38
|
+
localhost-gated loader into served HTML — a runtime `import()` of a local
|
|
39
|
+
[haltija](https://github.com/tonioloewald/haltija) channel's `dev.js` — and
|
|
40
|
+
spins up (or reuses) a server-only channel (no Electron app) in `--both` mode:
|
|
41
|
+
HTTP 8700 for the `hj` CLI, HTTPS 8701 for the injected widget (so an HTTPS page
|
|
42
|
+
has no mixed-content). An agent can then read the live DOM, click/type, run JS,
|
|
43
|
+
and **screen-capture** the rendered page (`hj screenshot`, via `getDisplayMedia`
|
|
44
|
+
— click the 🖥 widget button once to grant the share). Because the loader is
|
|
45
|
+
pulled from the local server at runtime it is **never bundled** (zero build
|
|
46
|
+
bytes) and self-disables off-localhost, and because it's injected at serve time
|
|
47
|
+
it never touches the built output. Certs are mkcert-signed (already required for
|
|
48
|
+
the dev server's HTTPS), so no browser warning. Local dev only; off by default.
|
|
49
|
+
The channel tracks haltija's `@beta` dist-tag (where the WebRTC capture lives).
|
|
50
|
+
|
|
3
51
|
## 1.6.17
|
|
4
52
|
|
|
5
53
|
### Fixed
|
package/dist/doc-browser.js
CHANGED
|
@@ -1250,7 +1250,11 @@ export function createDocBrowser(options) {
|
|
|
1250
1250
|
if (isTestFrame)
|
|
1251
1251
|
return; // Don't run background tests in test iframe
|
|
1252
1252
|
backgroundTestsStarted = true;
|
|
1253
|
-
// Find all docs that have test blocks
|
|
1253
|
+
// Find all docs that have test blocks. (Pages with examples but no explicit
|
|
1254
|
+
// tests are covered cheaply at BUILD time by the transpile check —
|
|
1255
|
+
// src/doc-system/site/check-examples.ts — without loading them in a browser,
|
|
1256
|
+
// so the runner doesn't have to render every heavy page just to notice a
|
|
1257
|
+
// build error.)
|
|
1254
1258
|
const docsWithTests = docs.filter((doc) => doc.text.includes('```test'));
|
|
1255
1259
|
pagesWithTests = docsWithTests.length;
|
|
1256
1260
|
if (pagesWithTests > 0) {
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Doc } from './docs';
|
|
2
|
+
export interface ExampleProblem {
|
|
3
|
+
filename: string;
|
|
4
|
+
title: string;
|
|
5
|
+
lang: string;
|
|
6
|
+
error: string;
|
|
7
|
+
snippet: string;
|
|
8
|
+
}
|
|
9
|
+
/** Transpile-check every executable block in the corpus. Returns the problems. */
|
|
10
|
+
export declare function checkExamples(docs: Doc[], opts?: {
|
|
11
|
+
contextKeys?: string[];
|
|
12
|
+
}): Promise<ExampleProblem[]>;
|
|
13
|
+
/** Format problems for a build log. */
|
|
14
|
+
export declare function formatExampleProblems(problems: ExampleProblem[]): string;
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Build-time transpile check for live examples.
|
|
3
|
+
|
|
4
|
+
Every executable code block in the corpus (`js` / `tjs` / `ts` / `test`) is put
|
|
5
|
+
through the SAME front half of the runtime pipeline the live-example component
|
|
6
|
+
uses — `rewriteImports` → the tjs-lang transform → `new AsyncFunction(...)` — so a
|
|
7
|
+
block that can't build (a tjs/TS syntax error, an unsupported import, or
|
|
8
|
+
illustrative config mistakenly tagged with an executable language like `ts`
|
|
9
|
+
instead of the display-only `typescript`) fails the build *at authoring time*,
|
|
10
|
+
on every page, instead of silently rendering an error only when someone opens
|
|
11
|
+
that page. `html` / `css` and display-only languages (`typescript`, `json`, …)
|
|
12
|
+
are not executed, so they're skipped.
|
|
13
|
+
|
|
14
|
+
Build-time only (bun). Never import from browser code.
|
|
15
|
+
*/
|
|
16
|
+
import { marked } from 'marked';
|
|
17
|
+
import { rewriteImports, AsyncFunction, loadTransform } from '../../live-example/code-transform';
|
|
18
|
+
// The default live-example context (matches the IIFE globals the pages provide).
|
|
19
|
+
// A project that sets a custom `context` on its <tosi-doc-system> can pass its
|
|
20
|
+
// own keys; these are the tosijs-ui defaults.
|
|
21
|
+
const DEFAULT_CONTEXT_KEYS = ['tosijs', 'tosijs-ui'];
|
|
22
|
+
const EXECUTABLE = new Set(['js', 'tjs', 'ts', 'test']);
|
|
23
|
+
/** The bare dialect from a fence info string ('js#my-id' → 'js'); '' if none. */
|
|
24
|
+
function dialectOf(info) {
|
|
25
|
+
return (info ?? '').match(/^[a-z]+/)?.[0] ?? '';
|
|
26
|
+
}
|
|
27
|
+
/** Collect every fenced code block in a doc (recursing into lists/quotes). */
|
|
28
|
+
function collectCodeTokens(text) {
|
|
29
|
+
const out = [];
|
|
30
|
+
const walk = (tokens) => {
|
|
31
|
+
for (const t of tokens) {
|
|
32
|
+
if (t.type === 'code')
|
|
33
|
+
out.push({ lang: dialectOf(t.lang), text: t.text });
|
|
34
|
+
if (Array.isArray(t.tokens))
|
|
35
|
+
walk(t.tokens);
|
|
36
|
+
if (Array.isArray(t.items))
|
|
37
|
+
walk(t.items); // list items
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
walk(marked.lexer(text));
|
|
41
|
+
return out;
|
|
42
|
+
}
|
|
43
|
+
/** Transpile-check every executable block in the corpus. Returns the problems. */
|
|
44
|
+
export async function checkExamples(docs, opts = {}) {
|
|
45
|
+
const contextKeys = opts.contextKeys ?? DEFAULT_CONTEXT_KEYS;
|
|
46
|
+
const problems = [];
|
|
47
|
+
for (const doc of docs) {
|
|
48
|
+
for (const block of collectCodeTokens(doc.text)) {
|
|
49
|
+
if (!EXECUTABLE.has(block.lang))
|
|
50
|
+
continue;
|
|
51
|
+
// `test` blocks are conventional JS/TS, transpiled as plain js.
|
|
52
|
+
const dialect = block.lang === 'test' ? 'js' : block.lang;
|
|
53
|
+
try {
|
|
54
|
+
const rewritten = rewriteImports(block.text, contextKeys);
|
|
55
|
+
let js;
|
|
56
|
+
if (dialect === 'ts') {
|
|
57
|
+
// Use bun's own transpiler — network-free (the runtime `ts` path
|
|
58
|
+
// fetches the TypeScript compiler from a CDN, which can't run here).
|
|
59
|
+
// We only need to validate that the source builds, not reproduce tjs
|
|
60
|
+
// lowering exactly.
|
|
61
|
+
js = new Bun.Transpiler({ loader: 'ts' }).transformSync(rewritten);
|
|
62
|
+
}
|
|
63
|
+
else if (dialect === 'tjs') {
|
|
64
|
+
const transform = await loadTransform('tjs');
|
|
65
|
+
js = (await transform(rewritten, { transforms: ['typescript'] })).code;
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
js = rewritten; // `js` / `test` are already JS
|
|
69
|
+
}
|
|
70
|
+
// Syntax-validate the way the component does before running it.
|
|
71
|
+
// eslint-disable-next-line no-new
|
|
72
|
+
new AsyncFunction(js);
|
|
73
|
+
}
|
|
74
|
+
catch (err) {
|
|
75
|
+
problems.push({
|
|
76
|
+
filename: doc.filename,
|
|
77
|
+
title: doc.title,
|
|
78
|
+
lang: block.lang,
|
|
79
|
+
error: err.message || String(err),
|
|
80
|
+
snippet: block.text.split('\n').slice(0, 3).join('\n'),
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return problems;
|
|
86
|
+
}
|
|
87
|
+
/** Format problems for a build log. */
|
|
88
|
+
export function formatExampleProblems(problems) {
|
|
89
|
+
return problems
|
|
90
|
+
.map((p) => ` ✗ ${p.filename} (${p.lang}) — ${p.title}\n` +
|
|
91
|
+
` ${p.error}\n` +
|
|
92
|
+
p.snippet
|
|
93
|
+
.split('\n')
|
|
94
|
+
.map((l) => ` | ${l}`)
|
|
95
|
+
.join('\n'))
|
|
96
|
+
.join('\n\n');
|
|
97
|
+
}
|
|
@@ -21,6 +21,48 @@ async function killStrayServer(port) {
|
|
|
21
21
|
// No process on port, that's fine
|
|
22
22
|
}
|
|
23
23
|
}
|
|
24
|
+
/**
|
|
25
|
+
* Reuse-or-spawn a haltija dev-channel server (server-only, no desktop app) on
|
|
26
|
+
* `port` over HTTPS, so the loader injected into the dev pages has something to
|
|
27
|
+
* connect to. Best-effort: if the reachability check fails we still spawn, and
|
|
28
|
+
* if the spawn fails we just log — the injected loader degrades to a no-op, so
|
|
29
|
+
* dev startup is never blocked on haltija.
|
|
30
|
+
*/
|
|
31
|
+
async function ensureHaltijaChannel(port) {
|
|
32
|
+
const base = `https://localhost:${port}`;
|
|
33
|
+
const up = await fetch(`${base}/status`, {
|
|
34
|
+
// The 8701 cert is mkcert-signed, but don't let a TLS/availability hiccup
|
|
35
|
+
// in the probe stop us — we only care whether something is answering.
|
|
36
|
+
tls: { rejectUnauthorized: false },
|
|
37
|
+
})
|
|
38
|
+
.then((r) => r.ok)
|
|
39
|
+
.catch(() => false);
|
|
40
|
+
if (up) {
|
|
41
|
+
console.log(`Haltija dev-channel: reusing existing server at ${base}`);
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
console.log(`Haltija dev-channel: starting server-only channel (HTTP 8700 + HTTPS ${port}) …`);
|
|
45
|
+
try {
|
|
46
|
+
// --server = channel server only (no Electron desktop app). --both = HTTP on
|
|
47
|
+
// 8700 AND HTTPS on 8701: the injected loader/widget use HTTPS 8701 (so an
|
|
48
|
+
// HTTPS dev page has no mixed-content), while the `hj` CLI drives over its
|
|
49
|
+
// default HTTP 8700 — one server, both transports, shared state. HTTPS cert
|
|
50
|
+
// is mkcert-trusted. Output quiet so it doesn't drown the dev log.
|
|
51
|
+
// Track the `@beta` tag: in-browser (widget-mode) WebRTC screen capture —
|
|
52
|
+
// which makes the Electron app CI-only — landed in the beta channel, ahead
|
|
53
|
+
// of the `latest` dist-tag.
|
|
54
|
+
spawn(['bunx', 'haltija@beta', '--server', '--both'], {
|
|
55
|
+
stdout: 'ignore',
|
|
56
|
+
stderr: 'ignore',
|
|
57
|
+
});
|
|
58
|
+
console.log(`Haltija dev-channel ready — drive this page with \`hj\` (e.g. \`hj tree\`). ` +
|
|
59
|
+
`The widget appears when the channel is active (Option+Tab to toggle).`);
|
|
60
|
+
}
|
|
61
|
+
catch (err) {
|
|
62
|
+
console.warn(`Haltija dev-channel: could not start (${String(err)}). The page loader ` +
|
|
63
|
+
`will no-op until you run \`bunx haltija --server --https\` yourself.`);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
24
66
|
// The HTTPS dev server needs a cert in tls/. On a fresh clone/adopter there
|
|
25
67
|
// isn't one, so warn with the exact command rather than serving a broken
|
|
26
68
|
// server. We don't generate it automatically because it runs `mkcert -install`,
|
|
@@ -42,6 +84,18 @@ export async function devServer(config, opts = {}) {
|
|
|
42
84
|
const PUBLIC = path.resolve('./', config.outputDir ?? 'docs');
|
|
43
85
|
const isSPA = true;
|
|
44
86
|
const testMode = !!opts.test;
|
|
87
|
+
// Haltija dev-channel — give a coding agent eyes on the running page. Opt-in
|
|
88
|
+
// (config.haltijaDev or HALTIJA_DEV=1), never in test mode. The loader is a
|
|
89
|
+
// localhost-gated runtime import() of the local channel's dev.js, so haltija
|
|
90
|
+
// is never bundled and self-disables off-localhost; it's injected only at
|
|
91
|
+
// serve time (below), so it never lands in the built output.
|
|
92
|
+
const HALTIJA_HTTPS_PORT = 8701;
|
|
93
|
+
const haltijaDev = !testMode &&
|
|
94
|
+
(config.haltijaDev === true ||
|
|
95
|
+
process.env.HALTIJA_DEV === '1' ||
|
|
96
|
+
process.env.HALTIJA_DEV === 'true');
|
|
97
|
+
const HALTIJA_SNIPPET = `<script>/^localhost$|^127\\./.test(location.hostname)` +
|
|
98
|
+
`&&import('https://localhost:${HALTIJA_HTTPS_PORT}/dev.js')</script>`;
|
|
45
99
|
let testReportResolve;
|
|
46
100
|
// Source read/write for in-browser "edit page source" (config.editableSources).
|
|
47
101
|
// Local dev only — your machine, your files — so the lone guard is correctness:
|
|
@@ -91,7 +145,7 @@ export async function devServer(config, opts = {}) {
|
|
|
91
145
|
}
|
|
92
146
|
}
|
|
93
147
|
await killStrayServer(PORT);
|
|
94
|
-
function
|
|
148
|
+
function resolveFile(cfg) {
|
|
95
149
|
const basePath = path.join(cfg.directory, cfg.path);
|
|
96
150
|
const suffixes = ['', '.html', 'index.html'];
|
|
97
151
|
for (const suffix of suffixes) {
|
|
@@ -99,7 +153,7 @@ export async function devServer(config, opts = {}) {
|
|
|
99
153
|
const pathWithSuffix = path.join(basePath, suffix);
|
|
100
154
|
const stat = statSync(pathWithSuffix);
|
|
101
155
|
if (stat && stat.isFile()) {
|
|
102
|
-
return
|
|
156
|
+
return pathWithSuffix;
|
|
103
157
|
}
|
|
104
158
|
}
|
|
105
159
|
catch {
|
|
@@ -108,6 +162,21 @@ export async function devServer(config, opts = {}) {
|
|
|
108
162
|
}
|
|
109
163
|
return null;
|
|
110
164
|
}
|
|
165
|
+
// Serve a resolved file, injecting the haltija dev-channel loader into HTML
|
|
166
|
+
// pages when enabled. Serve-time only — the loader never touches the built
|
|
167
|
+
// output on disk, and non-HTML assets are streamed untouched.
|
|
168
|
+
async function respondFile(filePath) {
|
|
169
|
+
if (haltijaDev && filePath.endsWith('.html')) {
|
|
170
|
+
const html = await Bun.file(filePath).text();
|
|
171
|
+
const injected = html.includes('</body>')
|
|
172
|
+
? html.replace('</body>', `${HALTIJA_SNIPPET}</body>`)
|
|
173
|
+
: html + HALTIJA_SNIPPET;
|
|
174
|
+
return new Response(injected, {
|
|
175
|
+
headers: { 'Content-Type': 'text/html; charset=utf-8' },
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
return new Response(Bun.file(filePath));
|
|
179
|
+
}
|
|
111
180
|
async function handleTestReport(request) {
|
|
112
181
|
try {
|
|
113
182
|
const results = await request.json();
|
|
@@ -211,22 +280,21 @@ export async function devServer(config, opts = {}) {
|
|
|
211
280
|
}
|
|
212
281
|
if (reqPath === '/')
|
|
213
282
|
reqPath = '/index.html';
|
|
214
|
-
const
|
|
215
|
-
if (
|
|
216
|
-
return
|
|
283
|
+
const buildFile = resolveFile({ directory: PUBLIC, path: reqPath });
|
|
284
|
+
if (buildFile)
|
|
285
|
+
return await respondFile(buildFile);
|
|
217
286
|
if (isSPA) {
|
|
218
|
-
const
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
});
|
|
222
|
-
console.log(spaResponse);
|
|
223
|
-
if (spaResponse)
|
|
224
|
-
return spaResponse;
|
|
287
|
+
const spaFile = resolveFile({ directory: PUBLIC, path: '/index.html' });
|
|
288
|
+
if (spaFile)
|
|
289
|
+
return await respondFile(spaFile);
|
|
225
290
|
}
|
|
226
291
|
return new Response('File not found', { status: 404 });
|
|
227
292
|
},
|
|
228
293
|
});
|
|
229
294
|
console.log(`Listening on https://localhost:${PORT}`);
|
|
295
|
+
if (haltijaDev) {
|
|
296
|
+
await ensureHaltijaChannel(HALTIJA_HTTPS_PORT);
|
|
297
|
+
}
|
|
230
298
|
if (testMode) {
|
|
231
299
|
const testTimeout = 120_000;
|
|
232
300
|
const testResults = new Promise((resolve, reject) => {
|
|
@@ -16,6 +16,7 @@ import { existsSync, mkdirSync } from 'fs';
|
|
|
16
16
|
import { gzipSync } from 'zlib';
|
|
17
17
|
import { $ } from 'bun';
|
|
18
18
|
import { extractDocs } from './docs';
|
|
19
|
+
import { checkExamples, formatExampleProblems } from './check-examples';
|
|
19
20
|
import { ensureSections } from './sections';
|
|
20
21
|
import { generateLlmsTxt } from './make-llms-txt';
|
|
21
22
|
import { generateSite } from './generate-site';
|
|
@@ -68,6 +69,21 @@ export async function buildSite(config) {
|
|
|
68
69
|
sectionsDir: config.sectionsDir ?? 'src/docs',
|
|
69
70
|
reExtract: extract,
|
|
70
71
|
});
|
|
72
|
+
// Fail fast on any live example that can't build — a real syntax/import error,
|
|
73
|
+
// or illustrative code mistakenly tagged executable (`js`/`ts`/…) instead of
|
|
74
|
+
// display-only `typescript`. Runs on the whole corpus, so it catches breakage
|
|
75
|
+
// on pages the browser test never navigates to.
|
|
76
|
+
if (config.checkExamples !== false) {
|
|
77
|
+
const corpus = JSON.parse(await Bun.file(DOCS_JSON).text());
|
|
78
|
+
const problems = await checkExamples(corpus);
|
|
79
|
+
if (problems.length) {
|
|
80
|
+
throw new Error(`doc-site build: ${problems.length} live example(s) failed to build:\n\n` +
|
|
81
|
+
formatExampleProblems(problems) +
|
|
82
|
+
`\n\nFix the code, or — if a block is illustrative and not meant to run —` +
|
|
83
|
+
` tag it with a display-only language like \`typescript\` instead of` +
|
|
84
|
+
` \`js\`/\`ts\`. (Disable with checkExamples: false.)`);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
71
87
|
// Copy static-asset dirs into the web root.
|
|
72
88
|
const staticDirs = config.staticDirs ?? (existsSync('demo/static') ? ['demo/static'] : ['static']);
|
|
73
89
|
for (const dir of staticDirs) {
|
|
@@ -143,6 +143,15 @@ export interface SiteConfig {
|
|
|
143
143
|
* `sort: 'filename'` gives a folder of chapters natural order with no metadata.
|
|
144
144
|
*/
|
|
145
145
|
book?: BookManifest;
|
|
146
|
+
/**
|
|
147
|
+
* Fail the build when a live example can't transpile — a real syntax/import
|
|
148
|
+
* error, or illustrative code mistakenly tagged with an executable language
|
|
149
|
+
* (`js`/`ts`/`tjs`/`test`) instead of the display-only `typescript`. Catches it
|
|
150
|
+
* at build time, on every page, instead of only when someone opens that page.
|
|
151
|
+
* Default true; assumes the default `tosijs` / `tosijs-ui` example context —
|
|
152
|
+
* set false if your examples import from a custom `context` the check can't see.
|
|
153
|
+
*/
|
|
154
|
+
checkExamples?: boolean;
|
|
146
155
|
/** served web-root output dir, default 'docs' */
|
|
147
156
|
outputDir?: string;
|
|
148
157
|
/** dev-server port, default 8787 */
|
|
@@ -156,6 +165,19 @@ export interface SiteConfig {
|
|
|
156
165
|
* are confined to the repo root as correctness hygiene. Off by default; opt in.
|
|
157
166
|
*/
|
|
158
167
|
editableSources?: boolean;
|
|
168
|
+
/**
|
|
169
|
+
* Give a coding agent (Claude) eyes + hands on your running dev page via
|
|
170
|
+
* [haltija](https://github.com/tonioloewald/haltija). When on, the dev server
|
|
171
|
+
* injects a tiny localhost-gated loader into served HTML — a runtime
|
|
172
|
+
* `import()` of the local haltija channel's `dev.js` — and spins up (or reuses)
|
|
173
|
+
* a server-only HTTPS channel on port 8701. Because the loader is pulled from
|
|
174
|
+
* the local server at runtime, **haltija is never bundled** (zero build bytes)
|
|
175
|
+
* and self-disables off-localhost, and because injection happens at serve time
|
|
176
|
+
* it never touches the built output. Local dev only; off by default. Can also
|
|
177
|
+
* be toggled with `HALTIJA_DEV=1`. Requires mkcert (already needed for the dev
|
|
178
|
+
* server's HTTPS) so the 8701 cert is trusted with no browser warning.
|
|
179
|
+
*/
|
|
180
|
+
haltijaDev?: boolean;
|
|
159
181
|
}
|
|
160
182
|
/** Identity helper that gives a site config module full type-checking + IDE help. */
|
|
161
183
|
export declare function defineSiteConfig(config: SiteConfig): SiteConfig;
|