@deskwork/studio 0.9.5
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/dist/build-client-assets.d.ts +51 -0
- package/dist/build-client-assets.d.ts.map +1 -0
- package/dist/build-client-assets.js +341 -0
- package/dist/build-client-assets.js.map +1 -0
- package/dist/components/scrapbook-item.d.ts +108 -0
- package/dist/components/scrapbook-item.d.ts.map +1 -0
- package/dist/components/scrapbook-item.js +205 -0
- package/dist/components/scrapbook-item.js.map +1 -0
- package/dist/lib/editorial-skills-catalogue.d.ts +33 -0
- package/dist/lib/editorial-skills-catalogue.d.ts.map +1 -0
- package/dist/lib/editorial-skills-catalogue.js +211 -0
- package/dist/lib/editorial-skills-catalogue.js.map +1 -0
- package/dist/lib/override-render.d.ts +41 -0
- package/dist/lib/override-render.d.ts.map +1 -0
- package/dist/lib/override-render.js +80 -0
- package/dist/lib/override-render.js.map +1 -0
- package/dist/listen.d.ts +78 -0
- package/dist/listen.d.ts.map +1 -0
- package/dist/listen.js +155 -0
- package/dist/listen.js.map +1 -0
- package/dist/pages/chrome.d.ts +26 -0
- package/dist/pages/chrome.d.ts.map +1 -0
- package/dist/pages/chrome.js +50 -0
- package/dist/pages/chrome.js.map +1 -0
- package/dist/pages/content-detail.d.ts +14 -0
- package/dist/pages/content-detail.d.ts.map +1 -0
- package/dist/pages/content-detail.js +279 -0
- package/dist/pages/content-detail.js.map +1 -0
- package/dist/pages/content.d.ts +39 -0
- package/dist/pages/content.d.ts.map +1 -0
- package/dist/pages/content.js +414 -0
- package/dist/pages/content.js.map +1 -0
- package/dist/pages/dashboard.d.ts +32 -0
- package/dist/pages/dashboard.d.ts.map +1 -0
- package/dist/pages/dashboard.js +803 -0
- package/dist/pages/dashboard.js.map +1 -0
- package/dist/pages/help.d.ts +24 -0
- package/dist/pages/help.d.ts.map +1 -0
- package/dist/pages/help.js +433 -0
- package/dist/pages/help.js.map +1 -0
- package/dist/pages/html.d.ts +35 -0
- package/dist/pages/html.d.ts.map +1 -0
- package/dist/pages/html.js +73 -0
- package/dist/pages/html.js.map +1 -0
- package/dist/pages/index.d.ts +21 -0
- package/dist/pages/index.d.ts.map +1 -0
- package/dist/pages/index.js +174 -0
- package/dist/pages/index.js.map +1 -0
- package/dist/pages/layout.d.ts +33 -0
- package/dist/pages/layout.d.ts.map +1 -0
- package/dist/pages/layout.js +50 -0
- package/dist/pages/layout.js.map +1 -0
- package/dist/pages/review-scrapbook-drawer.d.ts +20 -0
- package/dist/pages/review-scrapbook-drawer.d.ts.map +1 -0
- package/dist/pages/review-scrapbook-drawer.js +98 -0
- package/dist/pages/review-scrapbook-drawer.js.map +1 -0
- package/dist/pages/review.d.ts +68 -0
- package/dist/pages/review.d.ts.map +1 -0
- package/dist/pages/review.js +434 -0
- package/dist/pages/review.js.map +1 -0
- package/dist/pages/scrapbook.d.ts +21 -0
- package/dist/pages/scrapbook.d.ts.map +1 -0
- package/dist/pages/scrapbook.js +250 -0
- package/dist/pages/scrapbook.js.map +1 -0
- package/dist/pages/shortform.d.ts +17 -0
- package/dist/pages/shortform.d.ts.map +1 -0
- package/dist/pages/shortform.js +142 -0
- package/dist/pages/shortform.js.map +1 -0
- package/dist/request-context.d.ts +52 -0
- package/dist/request-context.d.ts.map +1 -0
- package/dist/request-context.js +84 -0
- package/dist/request-context.js.map +1 -0
- package/dist/routes/api.d.ts +36 -0
- package/dist/routes/api.d.ts.map +1 -0
- package/dist/routes/api.js +175 -0
- package/dist/routes/api.js.map +1 -0
- package/dist/routes/scrapbook-file.d.ts +19 -0
- package/dist/routes/scrapbook-file.d.ts.map +1 -0
- package/dist/routes/scrapbook-file.js +77 -0
- package/dist/routes/scrapbook-file.js.map +1 -0
- package/dist/routes/scrapbook-mutations.d.ts +33 -0
- package/dist/routes/scrapbook-mutations.d.ts.map +1 -0
- package/dist/routes/scrapbook-mutations.js +310 -0
- package/dist/routes/scrapbook-mutations.js.map +1 -0
- package/dist/server.d.ts +52 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +581 -0
- package/dist/server.js.map +1 -0
- package/dist/tailscale.d.ts +63 -0
- package/dist/tailscale.d.ts.map +1 -0
- package/dist/tailscale.js +118 -0
- package/dist/tailscale.js.map +1 -0
- package/package.json +60 -0
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* On-startup esbuild for studio client modules.
|
|
3
|
+
*
|
|
4
|
+
* Phase 23e — the studio's HTTP listener calls
|
|
5
|
+
* `buildClientAssets({ pluginRoot })` once during boot, BEFORE accepting
|
|
6
|
+
* requests. The result of the build lands in
|
|
7
|
+
* `<pluginRoot>/.runtime-cache/dist/<name>.js`, mirroring what `build.ts`
|
|
8
|
+
* used to commit into `<pluginRoot>/public/dist/`. The `/static/dist/*`
|
|
9
|
+
* route serves from the runtime cache; URL surface is unchanged.
|
|
10
|
+
*
|
|
11
|
+
* Cache strategy: per-entry mtime check. For each `<name>.ts` under
|
|
12
|
+
* `<pluginRoot>/public/src/`, compare the source's mtime (and every
|
|
13
|
+
* file imported transitively, via esbuild's `metafile`) against the
|
|
14
|
+
* cached `<name>.js`. If the cache is newer than every input, skip the
|
|
15
|
+
* rebuild. Otherwise rebuild that single entry. Warm boots therefore
|
|
16
|
+
* avoid esbuild work entirely once `.runtime-cache/dist/` is populated.
|
|
17
|
+
*
|
|
18
|
+
* Concurrency safety (Issue #77):
|
|
19
|
+
* 1. Per-entry directory lock (`<outFile>.lock/`) serializes
|
|
20
|
+
* concurrent rebuilds across processes. mkdir is atomic on POSIX;
|
|
21
|
+
* the loser polls until the holder finishes (or the lock is
|
|
22
|
+
* deemed stale) and then re-checks the cache so it can skip the
|
|
23
|
+
* rebuild entirely if the holder produced a valid output.
|
|
24
|
+
* 2. Atomic writes: esbuild writes to `<outFile>.tmp.<pid>.<rand>`
|
|
25
|
+
* and we `rename()` to `<outFile>` once the build succeeds. The
|
|
26
|
+
* sidecar metafile follows the same `tmp + rename` pattern. A
|
|
27
|
+
* kill mid-build leaves either the prior valid output OR no
|
|
28
|
+
* output — never a half-written file.
|
|
29
|
+
* 3. Self-healing metafile reads: a missing/malformed sidecar is
|
|
30
|
+
* treated the same as "no metafile" — rebuild the entry. This
|
|
31
|
+
* prevents a corrupt sidecar from wedging boot.
|
|
32
|
+
*
|
|
33
|
+
* Failures throw with descriptive messages (per project rules — no
|
|
34
|
+
* silent fallbacks). The caller logs a status line.
|
|
35
|
+
*/
|
|
36
|
+
export interface BuildClientAssetsOptions {
|
|
37
|
+
/** Absolute path to plugins/deskwork-studio/. */
|
|
38
|
+
readonly pluginRoot: string;
|
|
39
|
+
}
|
|
40
|
+
export interface BuildSummary {
|
|
41
|
+
/** Number of entries that were re-bundled this run. */
|
|
42
|
+
readonly entriesBuilt: number;
|
|
43
|
+
/** Number of entries served from the existing cache. */
|
|
44
|
+
readonly entriesCached: number;
|
|
45
|
+
/** Total bytes across all output files (built + cached). */
|
|
46
|
+
readonly totalBytes: number;
|
|
47
|
+
/** Absolute output directory (`<pluginRoot>/.runtime-cache/dist/`). */
|
|
48
|
+
readonly outDir: string;
|
|
49
|
+
}
|
|
50
|
+
export declare function buildClientAssets(opts: BuildClientAssetsOptions): Promise<BuildSummary>;
|
|
51
|
+
//# sourceMappingURL=build-client-assets.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"build-client-assets.d.ts","sourceRoot":"","sources":["../src/build-client-assets.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAOH,MAAM,WAAW,wBAAwB;IACvC,iDAAiD;IACjD,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;CAC7B;AAED,MAAM,WAAW,YAAY;IAC3B,uDAAuD;IACvD,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,wDAAwD;IACxD,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,4DAA4D;IAC5D,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,uEAAuE;IACvE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAiBD,wBAAsB,iBAAiB,CACrC,IAAI,EAAE,wBAAwB,GAC7B,OAAO,CAAC,YAAY,CAAC,CAgCvB"}
|
|
@@ -0,0 +1,341 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* On-startup esbuild for studio client modules.
|
|
3
|
+
*
|
|
4
|
+
* Phase 23e — the studio's HTTP listener calls
|
|
5
|
+
* `buildClientAssets({ pluginRoot })` once during boot, BEFORE accepting
|
|
6
|
+
* requests. The result of the build lands in
|
|
7
|
+
* `<pluginRoot>/.runtime-cache/dist/<name>.js`, mirroring what `build.ts`
|
|
8
|
+
* used to commit into `<pluginRoot>/public/dist/`. The `/static/dist/*`
|
|
9
|
+
* route serves from the runtime cache; URL surface is unchanged.
|
|
10
|
+
*
|
|
11
|
+
* Cache strategy: per-entry mtime check. For each `<name>.ts` under
|
|
12
|
+
* `<pluginRoot>/public/src/`, compare the source's mtime (and every
|
|
13
|
+
* file imported transitively, via esbuild's `metafile`) against the
|
|
14
|
+
* cached `<name>.js`. If the cache is newer than every input, skip the
|
|
15
|
+
* rebuild. Otherwise rebuild that single entry. Warm boots therefore
|
|
16
|
+
* avoid esbuild work entirely once `.runtime-cache/dist/` is populated.
|
|
17
|
+
*
|
|
18
|
+
* Concurrency safety (Issue #77):
|
|
19
|
+
* 1. Per-entry directory lock (`<outFile>.lock/`) serializes
|
|
20
|
+
* concurrent rebuilds across processes. mkdir is atomic on POSIX;
|
|
21
|
+
* the loser polls until the holder finishes (or the lock is
|
|
22
|
+
* deemed stale) and then re-checks the cache so it can skip the
|
|
23
|
+
* rebuild entirely if the holder produced a valid output.
|
|
24
|
+
* 2. Atomic writes: esbuild writes to `<outFile>.tmp.<pid>.<rand>`
|
|
25
|
+
* and we `rename()` to `<outFile>` once the build succeeds. The
|
|
26
|
+
* sidecar metafile follows the same `tmp + rename` pattern. A
|
|
27
|
+
* kill mid-build leaves either the prior valid output OR no
|
|
28
|
+
* output — never a half-written file.
|
|
29
|
+
* 3. Self-healing metafile reads: a missing/malformed sidecar is
|
|
30
|
+
* treated the same as "no metafile" — rebuild the entry. This
|
|
31
|
+
* prevents a corrupt sidecar from wedging boot.
|
|
32
|
+
*
|
|
33
|
+
* Failures throw with descriptive messages (per project rules — no
|
|
34
|
+
* silent fallbacks). The caller logs a status line.
|
|
35
|
+
*/
|
|
36
|
+
import { build } from 'esbuild';
|
|
37
|
+
import { mkdir, readdir, readFile, rename, rm, stat, unlink, writeFile } from 'node:fs/promises';
|
|
38
|
+
import { randomBytes } from 'node:crypto';
|
|
39
|
+
import { join, resolve } from 'node:path';
|
|
40
|
+
const CACHE_DIR_NAME = '.runtime-cache';
|
|
41
|
+
const CACHE_OUT_SUBDIR = 'dist';
|
|
42
|
+
const LOCK_WAIT_MS = 30_000;
|
|
43
|
+
const LOCK_POLL_INITIAL_MS = 50;
|
|
44
|
+
const LOCK_POLL_MAX_MS = 500;
|
|
45
|
+
const LOCK_STALE_MS = 60_000;
|
|
46
|
+
export async function buildClientAssets(opts) {
|
|
47
|
+
const srcDir = resolve(opts.pluginRoot, 'public', 'src');
|
|
48
|
+
const outDir = resolve(opts.pluginRoot, CACHE_DIR_NAME, CACHE_OUT_SUBDIR);
|
|
49
|
+
const entries = await findEntries(srcDir);
|
|
50
|
+
if (entries.length === 0) {
|
|
51
|
+
throw new Error(`deskwork-studio: no .ts entries found in ${srcDir}; cannot build client assets`);
|
|
52
|
+
}
|
|
53
|
+
await mkdir(outDir, { recursive: true });
|
|
54
|
+
let entriesBuilt = 0;
|
|
55
|
+
let entriesCached = 0;
|
|
56
|
+
let totalBytes = 0;
|
|
57
|
+
for (const entryPath of entries) {
|
|
58
|
+
const decision = await decideEntry(entryPath, srcDir, outDir);
|
|
59
|
+
if (decision.rebuild) {
|
|
60
|
+
const result = await rebuildEntryWithLock(decision, srcDir, outDir);
|
|
61
|
+
totalBytes += result.bytes;
|
|
62
|
+
if (result.didBuild)
|
|
63
|
+
entriesBuilt += 1;
|
|
64
|
+
else
|
|
65
|
+
entriesCached += 1;
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
const cachedStat = await stat(decision.outFile);
|
|
69
|
+
totalBytes += cachedStat.size;
|
|
70
|
+
entriesCached += 1;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return { entriesBuilt, entriesCached, totalBytes, outDir };
|
|
74
|
+
}
|
|
75
|
+
async function findEntries(dir) {
|
|
76
|
+
let names;
|
|
77
|
+
try {
|
|
78
|
+
names = await readdir(dir);
|
|
79
|
+
}
|
|
80
|
+
catch (err) {
|
|
81
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
82
|
+
throw new Error(`deskwork-studio: cannot read client source dir ${dir}: ${reason}`);
|
|
83
|
+
}
|
|
84
|
+
const entries = [];
|
|
85
|
+
for (const name of names) {
|
|
86
|
+
if (!name.endsWith('.ts'))
|
|
87
|
+
continue;
|
|
88
|
+
const full = join(dir, name);
|
|
89
|
+
const info = await stat(full);
|
|
90
|
+
if (info.isFile())
|
|
91
|
+
entries.push(full);
|
|
92
|
+
}
|
|
93
|
+
entries.sort();
|
|
94
|
+
return entries;
|
|
95
|
+
}
|
|
96
|
+
async function decideEntry(entryPath, srcDir, outDir) {
|
|
97
|
+
const baseName = entryPath.slice(srcDir.length + 1).replace(/\.ts$/, '.js');
|
|
98
|
+
const outFile = join(outDir, baseName);
|
|
99
|
+
const cachedMtime = await safeMtime(outFile);
|
|
100
|
+
if (cachedMtime === null) {
|
|
101
|
+
return { entryPath, outFile, baseName, rebuild: true };
|
|
102
|
+
}
|
|
103
|
+
// First-pass cheap check: compare against just the entry's own mtime.
|
|
104
|
+
// If the entry source itself is newer than the cache, rebuild without
|
|
105
|
+
// bothering to walk imports. If not, fall through to the metafile-based
|
|
106
|
+
// transitive check (also handles imported-file edits).
|
|
107
|
+
const entryMtime = await safeMtime(entryPath);
|
|
108
|
+
if (entryMtime === null) {
|
|
109
|
+
throw new Error(`deskwork-studio: client entry vanished between readdir and stat: ${entryPath}`);
|
|
110
|
+
}
|
|
111
|
+
if (entryMtime > cachedMtime) {
|
|
112
|
+
return { entryPath, outFile, baseName, rebuild: true };
|
|
113
|
+
}
|
|
114
|
+
// Cache is at least as new as the entry. Check transitive imports via
|
|
115
|
+
// a sidecar metafile written on the previous build.
|
|
116
|
+
const metaPath = `${outFile}.meta.json`;
|
|
117
|
+
const metaMtime = await safeMtime(metaPath);
|
|
118
|
+
if (metaMtime === null) {
|
|
119
|
+
// No metafile — built by an older code path. Rebuild to populate it.
|
|
120
|
+
return { entryPath, outFile, baseName, rebuild: true };
|
|
121
|
+
}
|
|
122
|
+
const importPaths = await readMetafileInputs(metaPath, entryPath);
|
|
123
|
+
if (importPaths === null) {
|
|
124
|
+
// Stale or corrupt sidecar — rebuild this entry to self-heal.
|
|
125
|
+
// eslint-disable-next-line no-console
|
|
126
|
+
console.warn(`deskwork-studio: stale or corrupt metafile at ${metaPath} — rebuild`);
|
|
127
|
+
return { entryPath, outFile, baseName, rebuild: true };
|
|
128
|
+
}
|
|
129
|
+
for (const imp of importPaths) {
|
|
130
|
+
const impMtime = await safeMtime(imp);
|
|
131
|
+
if (impMtime === null)
|
|
132
|
+
continue; // file removed; rebuild will fail loudly if relevant
|
|
133
|
+
if (impMtime > cachedMtime) {
|
|
134
|
+
return { entryPath, outFile, baseName, rebuild: true };
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
return { entryPath, outFile, baseName, rebuild: false };
|
|
138
|
+
}
|
|
139
|
+
async function rebuildEntryWithLock(decision, srcDir, outDir) {
|
|
140
|
+
const lockPath = `${decision.outFile}.lock`;
|
|
141
|
+
const acquired = await acquireLock(lockPath);
|
|
142
|
+
if (!acquired.acquired) {
|
|
143
|
+
// Lock-wait timed out without us getting it. Re-check the cache:
|
|
144
|
+
// even if we never held the lock, the holder's output may now be
|
|
145
|
+
// valid (and our caller's `decideEntry` was a stale snapshot).
|
|
146
|
+
const recheck = await decideEntry(decision.entryPath, srcDir, outDir);
|
|
147
|
+
if (!recheck.rebuild) {
|
|
148
|
+
const cachedStat = await stat(decision.outFile);
|
|
149
|
+
return { bytes: cachedStat.size, didBuild: false };
|
|
150
|
+
}
|
|
151
|
+
throw new Error(`deskwork-studio: timed out waiting for build lock at ${lockPath}; remove it manually if stale`);
|
|
152
|
+
}
|
|
153
|
+
try {
|
|
154
|
+
// We hold the lock. Re-decide under the lock — another process may
|
|
155
|
+
// have finished its build while we waited. If the cache is now
|
|
156
|
+
// valid, skip the rebuild and report bytes from the cached file.
|
|
157
|
+
const recheck = await decideEntry(decision.entryPath, srcDir, outDir);
|
|
158
|
+
if (!recheck.rebuild) {
|
|
159
|
+
const cachedStat = await stat(decision.outFile);
|
|
160
|
+
return { bytes: cachedStat.size, didBuild: false };
|
|
161
|
+
}
|
|
162
|
+
const bytes = await rebuildEntry(decision);
|
|
163
|
+
return { bytes, didBuild: true };
|
|
164
|
+
}
|
|
165
|
+
finally {
|
|
166
|
+
await releaseLock(lockPath);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
async function acquireLock(lockPath) {
|
|
170
|
+
const deadline = Date.now() + LOCK_WAIT_MS;
|
|
171
|
+
let pollMs = LOCK_POLL_INITIAL_MS;
|
|
172
|
+
while (true) {
|
|
173
|
+
try {
|
|
174
|
+
await mkdir(lockPath, { recursive: false });
|
|
175
|
+
return { acquired: true };
|
|
176
|
+
}
|
|
177
|
+
catch (err) {
|
|
178
|
+
if (!isEexist(err))
|
|
179
|
+
throw err;
|
|
180
|
+
// Stale-lock recovery: if the lock dir is older than LOCK_STALE_MS,
|
|
181
|
+
// the holder probably crashed. Reap it and retry.
|
|
182
|
+
const lockMtime = await safeMtime(lockPath);
|
|
183
|
+
if (lockMtime !== null && Date.now() - lockMtime > LOCK_STALE_MS) {
|
|
184
|
+
// eslint-disable-next-line no-console
|
|
185
|
+
console.warn(`deskwork-studio: removing stale build lock at ${lockPath} (age=${Math.round((Date.now() - lockMtime) / 1000)}s)`);
|
|
186
|
+
try {
|
|
187
|
+
await rm(lockPath, { recursive: true, force: true });
|
|
188
|
+
}
|
|
189
|
+
catch {
|
|
190
|
+
// Another process may have just released it; loop back and try mkdir again.
|
|
191
|
+
}
|
|
192
|
+
continue;
|
|
193
|
+
}
|
|
194
|
+
if (Date.now() >= deadline) {
|
|
195
|
+
return { acquired: false };
|
|
196
|
+
}
|
|
197
|
+
await sleep(pollMs);
|
|
198
|
+
pollMs = Math.min(pollMs * 2, LOCK_POLL_MAX_MS);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
async function releaseLock(lockPath) {
|
|
203
|
+
try {
|
|
204
|
+
await rm(lockPath, { recursive: true, force: true });
|
|
205
|
+
}
|
|
206
|
+
catch {
|
|
207
|
+
// best-effort; nothing actionable here.
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
function isEexist(err) {
|
|
211
|
+
if (typeof err !== 'object' || err === null)
|
|
212
|
+
return false;
|
|
213
|
+
if (!('code' in err))
|
|
214
|
+
return false;
|
|
215
|
+
const code = err.code;
|
|
216
|
+
return code === 'EEXIST';
|
|
217
|
+
}
|
|
218
|
+
function sleep(ms) {
|
|
219
|
+
return new Promise((r) => {
|
|
220
|
+
setTimeout(r, ms);
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
function makeTmpPath(finalPath) {
|
|
224
|
+
const rand = randomBytes(6).toString('hex');
|
|
225
|
+
return `${finalPath}.tmp.${process.pid}.${rand}`;
|
|
226
|
+
}
|
|
227
|
+
async function rebuildEntry(decision) {
|
|
228
|
+
const tmpOutFile = makeTmpPath(decision.outFile);
|
|
229
|
+
const opts = {
|
|
230
|
+
entryPoints: [decision.entryPath],
|
|
231
|
+
outfile: tmpOutFile,
|
|
232
|
+
bundle: true,
|
|
233
|
+
format: 'esm',
|
|
234
|
+
target: 'es2022',
|
|
235
|
+
minify: false,
|
|
236
|
+
sourcemap: 'linked',
|
|
237
|
+
logLevel: 'warning',
|
|
238
|
+
metafile: true,
|
|
239
|
+
};
|
|
240
|
+
let result;
|
|
241
|
+
try {
|
|
242
|
+
result = await build(opts);
|
|
243
|
+
}
|
|
244
|
+
catch (err) {
|
|
245
|
+
// Best-effort cleanup of any partial tmp output.
|
|
246
|
+
await unlink(tmpOutFile).catch(() => undefined);
|
|
247
|
+
await unlink(`${tmpOutFile}.map`).catch(() => undefined);
|
|
248
|
+
throw err;
|
|
249
|
+
}
|
|
250
|
+
if (result.errors.length > 0) {
|
|
251
|
+
await unlink(tmpOutFile).catch(() => undefined);
|
|
252
|
+
await unlink(`${tmpOutFile}.map`).catch(() => undefined);
|
|
253
|
+
throw new Error(`deskwork-studio: esbuild reported ${result.errors.length} errors building ${decision.entryPath}`);
|
|
254
|
+
}
|
|
255
|
+
if (!result.metafile) {
|
|
256
|
+
await unlink(tmpOutFile).catch(() => undefined);
|
|
257
|
+
await unlink(`${tmpOutFile}.map`).catch(() => undefined);
|
|
258
|
+
throw new Error(`deskwork-studio: esbuild did not return a metafile for ${decision.entryPath}; cache check would be unsound`);
|
|
259
|
+
}
|
|
260
|
+
// Atomically promote the JS (and sourcemap, if present) to the final path.
|
|
261
|
+
await rename(tmpOutFile, decision.outFile);
|
|
262
|
+
// sourcemap path mirrors esbuild's `linked` behavior: <outfile>.map
|
|
263
|
+
const tmpMap = `${tmpOutFile}.map`;
|
|
264
|
+
const finalMap = `${decision.outFile}.map`;
|
|
265
|
+
if (await exists(tmpMap)) {
|
|
266
|
+
await rename(tmpMap, finalMap);
|
|
267
|
+
}
|
|
268
|
+
await writeMetafileAtomic(`${decision.outFile}.meta.json`, result.metafile);
|
|
269
|
+
const stats = await stat(decision.outFile);
|
|
270
|
+
return stats.size;
|
|
271
|
+
}
|
|
272
|
+
async function exists(path) {
|
|
273
|
+
try {
|
|
274
|
+
await stat(path);
|
|
275
|
+
return true;
|
|
276
|
+
}
|
|
277
|
+
catch {
|
|
278
|
+
return false;
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
async function safeMtime(path) {
|
|
282
|
+
try {
|
|
283
|
+
const info = await stat(path);
|
|
284
|
+
return info.mtimeMs;
|
|
285
|
+
}
|
|
286
|
+
catch {
|
|
287
|
+
return null;
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
async function writeMetafileAtomic(path, meta) {
|
|
291
|
+
const tmp = makeTmpPath(path);
|
|
292
|
+
const json = JSON.stringify({ inputs: Object.keys(meta.inputs) });
|
|
293
|
+
await writeFile(tmp, json, 'utf8');
|
|
294
|
+
await rename(tmp, path);
|
|
295
|
+
}
|
|
296
|
+
/**
|
|
297
|
+
* Returns the resolved import paths from the sidecar metafile.
|
|
298
|
+
* Returns `null` if the sidecar is missing, unreadable, malformed, or
|
|
299
|
+
* fails JSON.parse — the caller treats `null` as "rebuild this entry."
|
|
300
|
+
* This makes the cache self-healing: a corrupt sidecar (e.g. truncated
|
|
301
|
+
* by a kill mid-write) cannot wedge boot.
|
|
302
|
+
*/
|
|
303
|
+
async function readMetafileInputs(metaPath, entryPath) {
|
|
304
|
+
let raw;
|
|
305
|
+
try {
|
|
306
|
+
raw = await readFile(metaPath, 'utf8');
|
|
307
|
+
}
|
|
308
|
+
catch {
|
|
309
|
+
return null;
|
|
310
|
+
}
|
|
311
|
+
let parsed;
|
|
312
|
+
try {
|
|
313
|
+
parsed = JSON.parse(raw);
|
|
314
|
+
}
|
|
315
|
+
catch {
|
|
316
|
+
return null;
|
|
317
|
+
}
|
|
318
|
+
if (!isMetafileSidecar(parsed)) {
|
|
319
|
+
return null;
|
|
320
|
+
}
|
|
321
|
+
// esbuild metafile inputs are project-relative paths from cwd at build
|
|
322
|
+
// time. Resolve them relative to the entry's directory so the mtime
|
|
323
|
+
// checks work whether or not cwd has changed since the build.
|
|
324
|
+
const entryDir = entryPath.slice(0, entryPath.lastIndexOf('/'));
|
|
325
|
+
return parsed.inputs.map((rel) => resolve(entryDir, rel));
|
|
326
|
+
}
|
|
327
|
+
function isMetafileSidecar(value) {
|
|
328
|
+
if (typeof value !== 'object' || value === null)
|
|
329
|
+
return false;
|
|
330
|
+
if (!('inputs' in value))
|
|
331
|
+
return false;
|
|
332
|
+
const inputs = value.inputs;
|
|
333
|
+
if (!Array.isArray(inputs))
|
|
334
|
+
return false;
|
|
335
|
+
for (const item of inputs) {
|
|
336
|
+
if (typeof item !== 'string')
|
|
337
|
+
return false;
|
|
338
|
+
}
|
|
339
|
+
return true;
|
|
340
|
+
}
|
|
341
|
+
//# sourceMappingURL=build-client-assets.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"build-client-assets.js","sourceRoot":"","sources":["../src/build-client-assets.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared scrapbook-item renderer.
|
|
3
|
+
*
|
|
4
|
+
* Three studio surfaces consume this module:
|
|
5
|
+
*
|
|
6
|
+
* 1. Standalone scrapbook viewer — `pages/scrapbook.ts`
|
|
7
|
+
* 2. Review-page drawer (Phase 16c) — `pages/review.ts`
|
|
8
|
+
* 3. Bird's-eye content view detail panel (Phase 16d) — `pages/content.ts`
|
|
9
|
+
*
|
|
10
|
+
* Goal: the operator sees consistent in-browser preview behavior wherever
|
|
11
|
+
* a scrapbook item appears. The standalone viewer keeps its richer
|
|
12
|
+
* disclosure / edit / rename / delete affordances; the read-only views
|
|
13
|
+
* (review drawer, content-view detail panel) reuse the same kind chip,
|
|
14
|
+
* filename, size, mtime, and the same in-browser preview rules:
|
|
15
|
+
*
|
|
16
|
+
* - Image kinds (`png`, `jpg`, `jpeg`, `webp`, `gif`, `svg`)
|
|
17
|
+
* render an inline thumbnail with a small overlay action to view
|
|
18
|
+
* full-size; clicking opens the served file in a new tab. Both
|
|
19
|
+
* image and PDF surfaces use a read-only binary endpoint
|
|
20
|
+
* (`GET /api/dev/scrapbook-file`) that the studio adds for these
|
|
21
|
+
* read-only views — distinct from the (not-yet-ported) full
|
|
22
|
+
* scrapbook CRUD API.
|
|
23
|
+
* - PDF — embedded via `<iframe>` using the same binary endpoint. The
|
|
24
|
+
* browser renders it natively.
|
|
25
|
+
* - Plain text / JSON — inline-truncated `<pre>` preview. Operators
|
|
26
|
+
* can read the first ~10 lines without leaving the page; a "view
|
|
27
|
+
* full" link opens the standalone viewer where the full file
|
|
28
|
+
* is mounted.
|
|
29
|
+
* - Markdown — kept as a kind-only row. Markdown is the editable
|
|
30
|
+
* surface — operators jump to the standalone viewer to edit. Showing
|
|
31
|
+
* a raw markdown preview here would either duplicate the editor or
|
|
32
|
+
* misrepresent what double-click does on this surface.
|
|
33
|
+
* - Anything else — kind chip + a download link. The browser can't
|
|
34
|
+
* render it, so make that explicit.
|
|
35
|
+
*
|
|
36
|
+
* Inline previews for text + JSON come from the server side: the
|
|
37
|
+
* standalone viewer only loads body content on disclosure (lazy), but
|
|
38
|
+
* the read-only renderers want the preview embedded at server-render
|
|
39
|
+
* time so operators don't see a flash. Callers pass an
|
|
40
|
+
* `inlinePreviewLoader` that knows how to read the first N bytes of
|
|
41
|
+
* the file and return a string; this module composes the result into
|
|
42
|
+
* the row HTML.
|
|
43
|
+
*/
|
|
44
|
+
import { type ScrapbookItem } from '@deskwork/core/scrapbook';
|
|
45
|
+
import { type RawHtml } from '../pages/html.ts';
|
|
46
|
+
/** Scrapbook items addressed by site + path. */
|
|
47
|
+
export interface ScrapbookAddress {
|
|
48
|
+
site: string;
|
|
49
|
+
/**
|
|
50
|
+
* Hierarchical path of the scrapbook (e.g.
|
|
51
|
+
* `the-outbound/characters/strivers`). Same string the standalone
|
|
52
|
+
* viewer uses in its URL.
|
|
53
|
+
*/
|
|
54
|
+
path: string;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Read the first slice of a text/JSON scrapbook file for inline
|
|
58
|
+
* preview. Implementations must read at most `maxBytes` to keep the
|
|
59
|
+
* server render cheap. Returns `null` when the file isn't readable
|
|
60
|
+
* as text (the renderer falls back to a download link in that case).
|
|
61
|
+
*/
|
|
62
|
+
export type InlineTextLoader = (filename: string, maxBytes: number) => string | null;
|
|
63
|
+
export interface ScrapbookItemRendererOptions {
|
|
64
|
+
/**
|
|
65
|
+
* Maximum bytes to read for inline text/JSON preview. Defaults to
|
|
66
|
+
* 800 — small enough to keep the row tight, large enough for the
|
|
67
|
+
* operator to recognize the file's shape.
|
|
68
|
+
*/
|
|
69
|
+
inlinePreviewMaxBytes?: number;
|
|
70
|
+
/**
|
|
71
|
+
* Optional loader used by text/JSON kinds. Required if the caller
|
|
72
|
+
* wants those kinds to actually preview inline; without a loader
|
|
73
|
+
* they fall back to a kind-chip-only row.
|
|
74
|
+
*/
|
|
75
|
+
inlinePreviewLoader?: InlineTextLoader;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Build the URL to fetch a scrapbook file's raw bytes from the
|
|
79
|
+
* read-only binary endpoint. The endpoint is read-only by design —
|
|
80
|
+
* Phase 16's image / PDF previews need a stable URL, but full
|
|
81
|
+
* scrapbook CRUD remains in the standalone viewer's surface.
|
|
82
|
+
*/
|
|
83
|
+
export declare function scrapbookFileUrl(address: ScrapbookAddress, filename: string, opts?: {
|
|
84
|
+
secret?: boolean;
|
|
85
|
+
}): string;
|
|
86
|
+
/**
|
|
87
|
+
* Build the URL to the standalone scrapbook viewer for an address —
|
|
88
|
+
* the operator's "open scrapbook" jumping-off point.
|
|
89
|
+
*/
|
|
90
|
+
export declare function scrapbookViewerUrl(address: ScrapbookAddress): string;
|
|
91
|
+
/**
|
|
92
|
+
* Render a single scrapbook item as a read-only row for the review
|
|
93
|
+
* drawer or the content-view detail panel. Returns the row HTML wrapped
|
|
94
|
+
* in `unsafe(...)`.
|
|
95
|
+
*
|
|
96
|
+
* Visual posture: kind chip + filename + size + mtime, with an inline
|
|
97
|
+
* preview block beneath the row for kinds the browser can render in
|
|
98
|
+
* place (image thumbnail, text/JSON truncated, PDF embed). Markdown +
|
|
99
|
+
* unrenderable kinds keep a single-line row.
|
|
100
|
+
*/
|
|
101
|
+
export declare function renderReadOnlyScrapbookRow(address: ScrapbookAddress, item: ScrapbookItem, opts?: ScrapbookItemRendererOptions): RawHtml;
|
|
102
|
+
/**
|
|
103
|
+
* Render an empty-state row for a scrapbook drawer / panel that has
|
|
104
|
+
* no items. Shown faded so the operator still sees the section exists
|
|
105
|
+
* for this node.
|
|
106
|
+
*/
|
|
107
|
+
export declare function renderEmptyScrapbookRow(): RawHtml;
|
|
108
|
+
//# sourceMappingURL=scrapbook-item.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scrapbook-item.d.ts","sourceRoot":"","sources":["../../src/components/scrapbook-item.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0CG;AAEH,OAAO,EAGL,KAAK,aAAa,EAEnB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAgB,KAAK,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAM9D,gDAAgD;AAChD,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb;;;;OAIG;IACH,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;;;GAKG;AACH,MAAM,MAAM,gBAAgB,GAAG,CAC7B,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,KACb,MAAM,GAAG,IAAI,CAAC;AAEnB,MAAM,WAAW,4BAA4B;IAC3C;;;;OAIG;IACH,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B;;;;OAIG;IACH,mBAAmB,CAAC,EAAE,gBAAgB,CAAC;CACxC;AASD;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,gBAAgB,EACzB,QAAQ,EAAE,MAAM,EAChB,IAAI,GAAE;IAAE,MAAM,CAAC,EAAE,OAAO,CAAA;CAAO,GAC9B,MAAM,CAQR;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,gBAAgB,GAAG,MAAM,CAIpE;AA+DD;;;;;;;;;GASG;AACH,wBAAgB,0BAA0B,CACxC,OAAO,EAAE,gBAAgB,EACzB,IAAI,EAAE,aAAa,EACnB,IAAI,GAAE,4BAAiC,GACtC,OAAO,CA8DT;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,IAAI,OAAO,CAKjD"}
|