@deskwork/studio 0.14.1 → 0.16.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/dist/components/scrapbook-item.d.ts +20 -0
- package/dist/components/scrapbook-item.d.ts.map +1 -1
- package/dist/components/scrapbook-item.js +21 -2
- package/dist/components/scrapbook-item.js.map +1 -1
- package/dist/pages/dashboard/affordances.d.ts.map +1 -1
- package/dist/pages/dashboard/affordances.js +13 -1
- package/dist/pages/dashboard/affordances.js.map +1 -1
- package/dist/pages/dashboard/affordances.ts +13 -1
- package/dist/pages/dashboard/press-queue.d.ts +16 -0
- package/dist/pages/dashboard/press-queue.d.ts.map +1 -0
- package/dist/pages/dashboard/press-queue.js +91 -0
- package/dist/pages/dashboard/press-queue.js.map +1 -0
- package/dist/pages/dashboard/press-queue.ts +112 -0
- package/dist/pages/dashboard.d.ts.map +1 -1
- package/dist/pages/dashboard.js +2 -0
- package/dist/pages/dashboard.js.map +1 -1
- package/dist/pages/dashboard.ts +2 -0
- package/dist/pages/entry-review/decision-strip.d.ts.map +1 -1
- package/dist/pages/entry-review/decision-strip.js +10 -2
- package/dist/pages/entry-review/decision-strip.js.map +1 -1
- package/dist/pages/entry-review/index.d.ts.map +1 -1
- package/dist/pages/entry-review/index.js +7 -4
- package/dist/pages/entry-review/index.js.map +1 -1
- package/dist/pages/help.js +11 -11
- package/dist/pages/help.js.map +1 -1
- package/dist/pages/help.ts +11 -11
- package/dist/pages/review-scrapbook-drawer.d.ts.map +1 -1
- package/dist/pages/review-scrapbook-drawer.js +10 -1
- package/dist/pages/review-scrapbook-drawer.js.map +1 -1
- package/dist/pages/review-scrapbook-drawer.ts +11 -1
- package/dist/pages/scrapbook/dispatch.d.ts +50 -0
- package/dist/pages/scrapbook/dispatch.d.ts.map +1 -0
- package/dist/pages/scrapbook/dispatch.js +104 -0
- package/dist/pages/scrapbook/dispatch.js.map +1 -0
- package/dist/pages/scrapbook/image-readers.d.ts +24 -0
- package/dist/pages/scrapbook/image-readers.d.ts.map +1 -0
- package/dist/pages/scrapbook/image-readers.js +135 -0
- package/dist/pages/scrapbook/image-readers.js.map +1 -0
- package/dist/pages/scrapbook/index.d.ts +21 -0
- package/dist/pages/scrapbook/index.d.ts.map +1 -0
- package/dist/pages/scrapbook/index.js +96 -0
- package/dist/pages/scrapbook/index.js.map +1 -0
- package/dist/pages/scrapbook/render.d.ts +68 -0
- package/dist/pages/scrapbook/render.d.ts.map +1 -0
- package/dist/pages/scrapbook/render.js +315 -0
- package/dist/pages/scrapbook/render.js.map +1 -0
- package/dist/pages/scrapbook/text-helpers.d.ts +40 -0
- package/dist/pages/scrapbook/text-helpers.d.ts.map +1 -0
- package/dist/pages/scrapbook/text-helpers.js +92 -0
- package/dist/pages/scrapbook/text-helpers.js.map +1 -0
- package/dist/pages/scrapbook/types.d.ts +26 -0
- package/dist/pages/scrapbook/types.d.ts.map +1 -0
- package/dist/pages/scrapbook/types.js +12 -0
- package/dist/pages/scrapbook/types.js.map +1 -0
- package/dist/pages/scrapbook.d.ts +8 -8
- package/dist/pages/scrapbook.d.ts.map +1 -1
- package/dist/pages/scrapbook.js +8 -600
- package/dist/pages/scrapbook.js.map +1 -1
- package/dist/pages/scrapbook.ts +11 -660
- package/dist/routes/api.d.ts.map +1 -1
- package/dist/routes/api.js +102 -140
- package/dist/routes/api.js.map +1 -1
- package/dist/routes/entry-annotation-body.d.ts +29 -0
- package/dist/routes/entry-annotation-body.d.ts.map +1 -1
- package/dist/routes/entry-annotation-body.js +80 -0
- package/dist/routes/entry-annotation-body.js.map +1 -1
- package/dist/routes/scrapbook-file.d.ts +17 -9
- package/dist/routes/scrapbook-file.d.ts.map +1 -1
- package/dist/routes/scrapbook-file.js +48 -15
- package/dist/routes/scrapbook-file.js.map +1 -1
- package/dist/routes/scrapbook-mutation-dispatch.d.ts +29 -0
- package/dist/routes/scrapbook-mutation-dispatch.d.ts.map +1 -0
- package/dist/routes/scrapbook-mutation-dispatch.js +63 -0
- package/dist/routes/scrapbook-mutation-dispatch.js.map +1 -0
- package/dist/routes/scrapbook-mutation-envelope.d.ts +93 -0
- package/dist/routes/scrapbook-mutation-envelope.d.ts.map +1 -0
- package/dist/routes/scrapbook-mutation-envelope.js +147 -0
- package/dist/routes/scrapbook-mutation-envelope.js.map +1 -0
- package/dist/routes/scrapbook-mutations.d.ts +25 -7
- package/dist/routes/scrapbook-mutations.d.ts.map +1 -1
- package/dist/routes/scrapbook-mutations.js +67 -92
- package/dist/routes/scrapbook-mutations.js.map +1 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +16 -2
- package/dist/server.js.map +1 -1
- package/package.json +2 -2
package/dist/pages/help.js
CHANGED
|
@@ -232,7 +232,7 @@ function renderStudioSection() {
|
|
|
232
232
|
<h4>Calendar panels</h4>
|
|
233
233
|
<p>Six on-pipeline columns: <em>Ideas · Planned · Outlining · Drafting · Final · Published</em>, plus parking-lot panels for <em>Blocked</em> and <em>Cancelled</em>. Each row shows slug, title, the per-stage iteration counter (<code>iterationByStage</code>), a file-present dot for the current stage's primary artifact, and any review state.</p>
|
|
234
234
|
<h4>Next-move column</h4>
|
|
235
|
-
<p>Per row, the studio surfaces
|
|
235
|
+
<p>Per row, the studio surfaces a button that copies the corresponding skill command to your clipboard — paste into a Claude Code chat to run. <code>approve →</code> copies <code>/deskwork:approve <slug></code>. <code>publish →</code> copies <code>/deskwork:publish <slug></code>. <code>block</code> / <code>cancel</code> / <code>induct</code> appear contextually and copy their own commands. The state-machine work happens in the skill, not in the studio (see <code>THESIS.md</code> Consequence 2).</p>
|
|
236
236
|
<h4>Shortform coverage matrix</h4>
|
|
237
237
|
<p>For each <em>Published</em> entry, a row of platform cells (reddit, linkedin, youtube, instagram). Shaded cells are covered by a DistributionRecord; empty cells surface the exact <code>/deskwork:shortform-start</code> command to copy.</p>
|
|
238
238
|
<h4>Voice-drift signal</h4>
|
|
@@ -241,13 +241,13 @@ function renderStudioSection() {
|
|
|
241
241
|
<div class="eh-panel">
|
|
242
242
|
<p class="eh-panel-head">Secondary surfaces</p>
|
|
243
243
|
<h4>Entry review</h4>
|
|
244
|
-
<p><code>/dev/editorial-review/entry/<uuid></code>. The current-stage artifact (idea.md, plan.md, outline.md, or index.md) renders inside the review surface. Select text for a margin note; double-click anywhere to edit the markdown in place
|
|
244
|
+
<p><code>/dev/editorial-review/entry/<uuid></code>. The current-stage artifact (idea.md, plan.md, outline.md, or index.md) renders inside the review surface. Select text for a margin note; double-click anywhere to edit the markdown in place. The fixed strip's Approve / Iterate / (Reject — disabled, see <a href="https://github.com/audiocontrol-org/deskwork/issues/173">#173</a>) buttons COPY the corresponding skill command (<code>/deskwork:approve <slug></code>, etc.) to your clipboard — paste into a Claude Code chat to run. The skill reads marginalia, applies editorial judgment, edits the file (when iterating), advances state. The review is keyed by entry uuid, not workflow id.</p>
|
|
245
245
|
<h4>Shortform review</h4>
|
|
246
246
|
<p><code>/dev/editorial-review-shortform</code>. Cards grouped by platform. Each card has a version header, an editable textarea, and save · approve · iterate · reject controls.</p>
|
|
247
247
|
<h4>Keyboard</h4>
|
|
248
|
-
<p>In the studio: <kbd>1</kbd>–<kbd>6</kbd> jump to on-pipeline columns. In an entry review: <kbd>e</kbd> / double-click toggles edit mode; <kbd>a</kbd>
|
|
248
|
+
<p>In the studio: <kbd>1</kbd>–<kbd>6</kbd> jump to on-pipeline columns. In an entry review: <kbd>e</kbd> / double-click toggles edit mode; <kbd>a</kbd> <kbd>a</kbd> copies the approve command to clipboard; <kbd>i</kbd> <kbd>i</kbd> copies the iterate command; <kbd>j</kbd>/<kbd>k</kbd> step through margin notes; <kbd>?</kbd> shows a full shortcuts overlay.</p>
|
|
249
249
|
<h4>Polling</h4>
|
|
250
|
-
<p>Both routes poll every 8–10 seconds when idle.
|
|
250
|
+
<p>Both routes poll every 8–10 seconds when idle. After you paste the iterate command into Claude Code and the skill writes a new version, the new artifact shows up in the browser without a manual reload.</p>
|
|
251
251
|
</div>
|
|
252
252
|
</div>
|
|
253
253
|
</section>`);
|
|
@@ -261,22 +261,22 @@ const RUNTHROUGH_STEPS = [
|
|
|
261
261
|
{
|
|
262
262
|
title: 'Iterate the idea',
|
|
263
263
|
op: 'browser then terminal',
|
|
264
|
-
body: unsafe('<p>Open <code>/dev/editorial-review/entry/<uuid></code>. Leave margin notes on <code>idea.md</code>. Click <em>Iterate</em>;
|
|
264
|
+
body: unsafe('<p>Open <code>/dev/editorial-review/entry/<uuid></code>. Leave margin notes on <code>idea.md</code>. Click <em>Iterate</em>; the studio copies <code>/deskwork:iterate <slug></code> to your clipboard — paste into a Claude Code chat to run. The skill reads your marginalia, revises <code>idea.md</code> in the site voice, writes the next version, bumps <code>iterationByStage.Ideas</code>.</p>'),
|
|
265
265
|
},
|
|
266
266
|
{
|
|
267
267
|
title: 'Approve into Planned',
|
|
268
268
|
op: 'browser or terminal',
|
|
269
|
-
body: unsafe('<p>Click <em>Approve</em> on the review surface
|
|
269
|
+
body: unsafe('<p>Click <em>Approve</em> on the review surface — the studio copies <code>/deskwork:approve <slug></code> to your clipboard. Paste into a Claude Code chat. The skill graduates the stage to <em>Planned</em>, seeds <code>plan.md</code> from <code>idea.md</code>, and starts <code>iterationByStage.Planned</code> at 0.</p>'),
|
|
270
270
|
},
|
|
271
271
|
{
|
|
272
272
|
title: 'Plan, then outline, then draft',
|
|
273
273
|
op: 'browser then terminal',
|
|
274
|
-
body: unsafe('<p>Same loop at each stage. <
|
|
274
|
+
body: unsafe('<p>Same loop at each stage. Click <em>Iterate</em> in the studio to copy the iterate command; the agent runs the skill, which revises the current-stage artifact (<code>plan.md</code>, then <code>outline.md</code>, then <code>index.md</code>). Click <em>Approve</em> to copy the approve command; the skill graduates by exactly one stage. There is no “approve but stay.”</p>'),
|
|
275
275
|
},
|
|
276
276
|
{
|
|
277
277
|
title: 'Approve into Final',
|
|
278
278
|
op: 'browser or terminal',
|
|
279
|
-
body: unsafe('<p>When the Drafting <code>index.md</code> is good,
|
|
279
|
+
body: unsafe('<p>When the Drafting <code>index.md</code> is good, click <em>Approve</em> once more (copies the command; paste into Claude Code). Stage becomes <em>Final</em>. The same <code>index.md</code> is the artifact at Final — Final is the “ready to publish” stage, not a separate file.</p>'),
|
|
280
280
|
},
|
|
281
281
|
{
|
|
282
282
|
title: 'Publish',
|
|
@@ -342,8 +342,8 @@ function renderReferenceSection() {
|
|
|
342
342
|
<dl>
|
|
343
343
|
<dt><kbd>e</kbd> / dbl-click</dt><dd>toggle edit mode</dd>
|
|
344
344
|
<dt>select text</dt><dd>leave a margin note</dd>
|
|
345
|
-
<dt><kbd>a</kbd></dt><dd>approve
|
|
346
|
-
<dt><kbd>i</kbd></dt><dd>iterate
|
|
345
|
+
<dt><kbd>a</kbd> <kbd>a</kbd></dt><dd>copy <code>/deskwork:approve <slug></code> to clipboard</dd>
|
|
346
|
+
<dt><kbd>i</kbd> <kbd>i</kbd></dt><dd>copy <code>/deskwork:iterate <slug></code> to clipboard</dd>
|
|
347
347
|
<dt><kbd>b</kbd></dt><dd>block — out of pipeline, resumable</dd>
|
|
348
348
|
<dt><kbd>j</kbd> / <kbd>k</kbd></dt><dd>step through margin notes</dd>
|
|
349
349
|
<dt><kbd>?</kbd></dt><dd>shortcuts overlay</dd>
|
|
@@ -401,7 +401,7 @@ function renderReferenceSection() {
|
|
|
401
401
|
<dl>
|
|
402
402
|
<dt>404 on /dev/*</dt><dd>the dev routes only run when <code>deskwork-studio</code> is up. Start it with the documented launch command.</dd>
|
|
403
403
|
<dt>nothing to review</dt><dd>capture an entry first: <code>/deskwork:add "Title"</code>, then visit <code>/dev/editorial-review/entry/<uuid></code>.</dd>
|
|
404
|
-
<dt>iterate doesn't trigger</dt><dd>the
|
|
404
|
+
<dt>iterate doesn't trigger</dt><dd>the studio's <em>Iterate</em> button copies <code>/deskwork:iterate <slug></code> to your clipboard — paste into a Claude Code chat to run. The skill does the writing; the studio doesn't mutate state on its own.</dd>
|
|
405
405
|
<dt>calendar.md drift</dt><dd>run <code>/deskwork:doctor</code>. The sidecar is truth — calendar.md is regenerated from it.</dd>
|
|
406
406
|
</dl>
|
|
407
407
|
</div>
|
package/dist/pages/help.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"help.js","sourceRoot":"","sources":["../../src/pages/help.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"help.js","sourceRoot":"","sources":["../../src/pages/help.ts"],"names":[],"mappings":"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"}
|
package/dist/pages/help.ts
CHANGED
|
@@ -250,7 +250,7 @@ function renderStudioSection(): RawHtml {
|
|
|
250
250
|
<h4>Calendar panels</h4>
|
|
251
251
|
<p>Six on-pipeline columns: <em>Ideas · Planned · Outlining · Drafting · Final · Published</em>, plus parking-lot panels for <em>Blocked</em> and <em>Cancelled</em>. Each row shows slug, title, the per-stage iteration counter (<code>iterationByStage</code>), a file-present dot for the current stage's primary artifact, and any review state.</p>
|
|
252
252
|
<h4>Next-move column</h4>
|
|
253
|
-
<p>Per row, the studio surfaces
|
|
253
|
+
<p>Per row, the studio surfaces a button that copies the corresponding skill command to your clipboard — paste into a Claude Code chat to run. <code>approve →</code> copies <code>/deskwork:approve <slug></code>. <code>publish →</code> copies <code>/deskwork:publish <slug></code>. <code>block</code> / <code>cancel</code> / <code>induct</code> appear contextually and copy their own commands. The state-machine work happens in the skill, not in the studio (see <code>THESIS.md</code> Consequence 2).</p>
|
|
254
254
|
<h4>Shortform coverage matrix</h4>
|
|
255
255
|
<p>For each <em>Published</em> entry, a row of platform cells (reddit, linkedin, youtube, instagram). Shaded cells are covered by a DistributionRecord; empty cells surface the exact <code>/deskwork:shortform-start</code> command to copy.</p>
|
|
256
256
|
<h4>Voice-drift signal</h4>
|
|
@@ -259,13 +259,13 @@ function renderStudioSection(): RawHtml {
|
|
|
259
259
|
<div class="eh-panel">
|
|
260
260
|
<p class="eh-panel-head">Secondary surfaces</p>
|
|
261
261
|
<h4>Entry review</h4>
|
|
262
|
-
<p><code>/dev/editorial-review/entry/<uuid></code>. The current-stage artifact (idea.md, plan.md, outline.md, or index.md) renders inside the review surface. Select text for a margin note; double-click anywhere to edit the markdown in place
|
|
262
|
+
<p><code>/dev/editorial-review/entry/<uuid></code>. The current-stage artifact (idea.md, plan.md, outline.md, or index.md) renders inside the review surface. Select text for a margin note; double-click anywhere to edit the markdown in place. The fixed strip's Approve / Iterate / (Reject — disabled, see <a href="https://github.com/audiocontrol-org/deskwork/issues/173">#173</a>) buttons COPY the corresponding skill command (<code>/deskwork:approve <slug></code>, etc.) to your clipboard — paste into a Claude Code chat to run. The skill reads marginalia, applies editorial judgment, edits the file (when iterating), advances state. The review is keyed by entry uuid, not workflow id.</p>
|
|
263
263
|
<h4>Shortform review</h4>
|
|
264
264
|
<p><code>/dev/editorial-review-shortform</code>. Cards grouped by platform. Each card has a version header, an editable textarea, and save · approve · iterate · reject controls.</p>
|
|
265
265
|
<h4>Keyboard</h4>
|
|
266
|
-
<p>In the studio: <kbd>1</kbd>–<kbd>6</kbd> jump to on-pipeline columns. In an entry review: <kbd>e</kbd> / double-click toggles edit mode; <kbd>a</kbd>
|
|
266
|
+
<p>In the studio: <kbd>1</kbd>–<kbd>6</kbd> jump to on-pipeline columns. In an entry review: <kbd>e</kbd> / double-click toggles edit mode; <kbd>a</kbd> <kbd>a</kbd> copies the approve command to clipboard; <kbd>i</kbd> <kbd>i</kbd> copies the iterate command; <kbd>j</kbd>/<kbd>k</kbd> step through margin notes; <kbd>?</kbd> shows a full shortcuts overlay.</p>
|
|
267
267
|
<h4>Polling</h4>
|
|
268
|
-
<p>Both routes poll every 8–10 seconds when idle.
|
|
268
|
+
<p>Both routes poll every 8–10 seconds when idle. After you paste the iterate command into Claude Code and the skill writes a new version, the new artifact shows up in the browser without a manual reload.</p>
|
|
269
269
|
</div>
|
|
270
270
|
</div>
|
|
271
271
|
</section>`);
|
|
@@ -280,22 +280,22 @@ const RUNTHROUGH_STEPS: ReadonlyArray<{ title: string; op: string; body: RawHtml
|
|
|
280
280
|
{
|
|
281
281
|
title: 'Iterate the idea',
|
|
282
282
|
op: 'browser then terminal',
|
|
283
|
-
body: unsafe('<p>Open <code>/dev/editorial-review/entry/<uuid></code>. Leave margin notes on <code>idea.md</code>. Click <em>Iterate</em>;
|
|
283
|
+
body: unsafe('<p>Open <code>/dev/editorial-review/entry/<uuid></code>. Leave margin notes on <code>idea.md</code>. Click <em>Iterate</em>; the studio copies <code>/deskwork:iterate <slug></code> to your clipboard — paste into a Claude Code chat to run. The skill reads your marginalia, revises <code>idea.md</code> in the site voice, writes the next version, bumps <code>iterationByStage.Ideas</code>.</p>'),
|
|
284
284
|
},
|
|
285
285
|
{
|
|
286
286
|
title: 'Approve into Planned',
|
|
287
287
|
op: 'browser or terminal',
|
|
288
|
-
body: unsafe('<p>Click <em>Approve</em> on the review surface
|
|
288
|
+
body: unsafe('<p>Click <em>Approve</em> on the review surface — the studio copies <code>/deskwork:approve <slug></code> to your clipboard. Paste into a Claude Code chat. The skill graduates the stage to <em>Planned</em>, seeds <code>plan.md</code> from <code>idea.md</code>, and starts <code>iterationByStage.Planned</code> at 0.</p>'),
|
|
289
289
|
},
|
|
290
290
|
{
|
|
291
291
|
title: 'Plan, then outline, then draft',
|
|
292
292
|
op: 'browser then terminal',
|
|
293
|
-
body: unsafe('<p>Same loop at each stage. <
|
|
293
|
+
body: unsafe('<p>Same loop at each stage. Click <em>Iterate</em> in the studio to copy the iterate command; the agent runs the skill, which revises the current-stage artifact (<code>plan.md</code>, then <code>outline.md</code>, then <code>index.md</code>). Click <em>Approve</em> to copy the approve command; the skill graduates by exactly one stage. There is no “approve but stay.”</p>'),
|
|
294
294
|
},
|
|
295
295
|
{
|
|
296
296
|
title: 'Approve into Final',
|
|
297
297
|
op: 'browser or terminal',
|
|
298
|
-
body: unsafe('<p>When the Drafting <code>index.md</code> is good,
|
|
298
|
+
body: unsafe('<p>When the Drafting <code>index.md</code> is good, click <em>Approve</em> once more (copies the command; paste into Claude Code). Stage becomes <em>Final</em>. The same <code>index.md</code> is the artifact at Final — Final is the “ready to publish” stage, not a separate file.</p>'),
|
|
299
299
|
},
|
|
300
300
|
{
|
|
301
301
|
title: 'Publish',
|
|
@@ -365,8 +365,8 @@ function renderReferenceSection(): RawHtml {
|
|
|
365
365
|
<dl>
|
|
366
366
|
<dt><kbd>e</kbd> / dbl-click</dt><dd>toggle edit mode</dd>
|
|
367
367
|
<dt>select text</dt><dd>leave a margin note</dd>
|
|
368
|
-
<dt><kbd>a</kbd></dt><dd>approve
|
|
369
|
-
<dt><kbd>i</kbd></dt><dd>iterate
|
|
368
|
+
<dt><kbd>a</kbd> <kbd>a</kbd></dt><dd>copy <code>/deskwork:approve <slug></code> to clipboard</dd>
|
|
369
|
+
<dt><kbd>i</kbd> <kbd>i</kbd></dt><dd>copy <code>/deskwork:iterate <slug></code> to clipboard</dd>
|
|
370
370
|
<dt><kbd>b</kbd></dt><dd>block — out of pipeline, resumable</dd>
|
|
371
371
|
<dt><kbd>j</kbd> / <kbd>k</kbd></dt><dd>step through margin notes</dd>
|
|
372
372
|
<dt><kbd>?</kbd></dt><dd>shortcuts overlay</dd>
|
|
@@ -424,7 +424,7 @@ function renderReferenceSection(): RawHtml {
|
|
|
424
424
|
<dl>
|
|
425
425
|
<dt>404 on /dev/*</dt><dd>the dev routes only run when <code>deskwork-studio</code> is up. Start it with the documented launch command.</dd>
|
|
426
426
|
<dt>nothing to review</dt><dd>capture an entry first: <code>/deskwork:add "Title"</code>, then visit <code>/dev/editorial-review/entry/<uuid></code>.</dd>
|
|
427
|
-
<dt>iterate doesn't trigger</dt><dd>the
|
|
427
|
+
<dt>iterate doesn't trigger</dt><dd>the studio's <em>Iterate</em> button copies <code>/deskwork:iterate <slug></code> to your clipboard — paste into a Claude Code chat to run. The skill does the writing; the studio doesn't mutate state on its own.</dd>
|
|
428
428
|
<dt>calendar.md drift</dt><dd>run <code>/deskwork:doctor</code>. The sidecar is truth — calendar.md is regenerated from it.</dd>
|
|
429
429
|
</dl>
|
|
430
430
|
</div>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"review-scrapbook-drawer.d.ts","sourceRoot":"","sources":["../../src/pages/review-scrapbook-drawer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAYH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AACjE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAOtD,OAAO,EAA4B,KAAK,OAAO,EAAE,MAAM,WAAW,CAAC;AAqFnE,wBAAgB,qBAAqB,CACnC,GAAG,EAAE,aAAa,EAClB,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,aAAa,GAAG,IAAI,EAC3B,IAAI,EAAE,MAAM,EACZ,KAAK,CAAC,EAAE,YAAY,GACnB,OAAO,
|
|
1
|
+
{"version":3,"file":"review-scrapbook-drawer.d.ts","sourceRoot":"","sources":["../../src/pages/review-scrapbook-drawer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAYH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AACjE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAOtD,OAAO,EAA4B,KAAK,OAAO,EAAE,MAAM,WAAW,CAAC;AAqFnE,wBAAgB,qBAAqB,CACnC,GAAG,EAAE,aAAa,EAClB,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,aAAa,GAAG,IAAI,EAC3B,IAAI,EAAE,MAAM,EACZ,KAAK,CAAC,EAAE,YAAY,GACnB,OAAO,CAuET"}
|
|
@@ -101,6 +101,15 @@ export function renderScrapbookDrawer(ctx, site, entry, slug, index) {
|
|
|
101
101
|
const secretItems = summary?.secretItems ?? [];
|
|
102
102
|
const total = items.length + secretItems.length;
|
|
103
103
|
const loader = makeInlineTextLoader(ctx, site, entry, slug, index);
|
|
104
|
+
// #205: prefer entry-aware addressing for the "open viewer ↗" link
|
|
105
|
+
// when this drawer renders for a tracked calendar entry. The standalone
|
|
106
|
+
// viewer's server route resolves the listing via `scrapbookDirForEntry`
|
|
107
|
+
// when `entryId` is present, matching the entry-aware mutation API.
|
|
108
|
+
// Falls back to slug-template addressing when the entry has no id
|
|
109
|
+
// binding (pre-doctor entries, legacy / organizational paths).
|
|
110
|
+
const viewerAddress = entry !== null && entry.id !== undefined && entry.id !== ''
|
|
111
|
+
? { site, path: slug, entryId: entry.id }
|
|
112
|
+
: { site, path: slug };
|
|
104
113
|
return unsafe(html `
|
|
105
114
|
<aside class="er-scrapbook-drawer" data-scrapbook-drawer aria-label="Scrapbook for this entry">
|
|
106
115
|
<header class="er-scrapbook-drawer-handle" data-drawer-toggle role="button" tabindex="0"
|
|
@@ -110,7 +119,7 @@ export function renderScrapbookDrawer(ctx, site, entry, slug, index) {
|
|
|
110
119
|
<span class="er-scrapbook-drawer-peek" aria-hidden="true">
|
|
111
120
|
${unsafe(renderPeek(items, secretItems))}
|
|
112
121
|
</span>
|
|
113
|
-
<a class="er-scrapbook-drawer-open" href="${scrapbookViewerUrl(
|
|
122
|
+
<a class="er-scrapbook-drawer-open" href="${scrapbookViewerUrl(viewerAddress)}"
|
|
114
123
|
title="Open the standalone scrapbook viewer"
|
|
115
124
|
onclick="event.stopPropagation()">open viewer ↗</a>
|
|
116
125
|
<button class="er-scrapbook-drawer-toggle" type="button" data-drawer-toggle
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"review-scrapbook-drawer.js","sourceRoot":"","sources":["../../src/pages/review-scrapbook-drawer.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"review-scrapbook-drawer.js","sourceRoot":"","sources":["../../src/pages/review-scrapbook-drawer.ts"],"names":[],"mappings":"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"}
|
|
@@ -156,6 +156,16 @@ export function renderScrapbookDrawer(
|
|
|
156
156
|
const secretItems = summary?.secretItems ?? [];
|
|
157
157
|
const total = items.length + secretItems.length;
|
|
158
158
|
const loader = makeInlineTextLoader(ctx, site, entry, slug, index);
|
|
159
|
+
// #205: prefer entry-aware addressing for the "open viewer ↗" link
|
|
160
|
+
// when this drawer renders for a tracked calendar entry. The standalone
|
|
161
|
+
// viewer's server route resolves the listing via `scrapbookDirForEntry`
|
|
162
|
+
// when `entryId` is present, matching the entry-aware mutation API.
|
|
163
|
+
// Falls back to slug-template addressing when the entry has no id
|
|
164
|
+
// binding (pre-doctor entries, legacy / organizational paths).
|
|
165
|
+
const viewerAddress: { site: string; path: string; entryId?: string } =
|
|
166
|
+
entry !== null && entry.id !== undefined && entry.id !== ''
|
|
167
|
+
? { site, path: slug, entryId: entry.id }
|
|
168
|
+
: { site, path: slug };
|
|
159
169
|
|
|
160
170
|
return unsafe(html`
|
|
161
171
|
<aside class="er-scrapbook-drawer" data-scrapbook-drawer aria-label="Scrapbook for this entry">
|
|
@@ -166,7 +176,7 @@ export function renderScrapbookDrawer(
|
|
|
166
176
|
<span class="er-scrapbook-drawer-peek" aria-hidden="true">
|
|
167
177
|
${unsafe(renderPeek(items, secretItems))}
|
|
168
178
|
</span>
|
|
169
|
-
<a class="er-scrapbook-drawer-open" href="${scrapbookViewerUrl(
|
|
179
|
+
<a class="er-scrapbook-drawer-open" href="${scrapbookViewerUrl(viewerAddress)}"
|
|
170
180
|
title="Open the standalone scrapbook viewer"
|
|
171
181
|
onclick="event.stopPropagation()">open viewer ↗</a>
|
|
172
182
|
<button class="er-scrapbook-drawer-toggle" type="button" data-drawer-toggle
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Scrapbook page listing dispatch — entry-aware vs slug-template
|
|
3
|
+
* resolution. Mirrors the post-#191 envelope/dispatch split for
|
|
4
|
+
* mutations: dispatch chooses the addressing mode, render stays free
|
|
5
|
+
* of the resolution branch.
|
|
6
|
+
*/
|
|
7
|
+
import { type ScrapbookSummary } from '@deskwork/core/scrapbook';
|
|
8
|
+
import type { StudioContext } from '../../routes/api.ts';
|
|
9
|
+
/**
|
|
10
|
+
* Error class surfaced by the page route to translate into HTTP status
|
|
11
|
+
* codes (`server.ts` maps these onto 400/404 responses).
|
|
12
|
+
*/
|
|
13
|
+
export declare class ScrapbookPageError extends Error {
|
|
14
|
+
readonly status: 400 | 404;
|
|
15
|
+
constructor(message: string, status: 400 | 404);
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* #168 Phase 34 ship-pass — when the scrapbook path matches a tracked
|
|
19
|
+
* calendar entry with a stamped UUID, return the entry's id so the aside
|
|
20
|
+
* can render a "← back to review" link AND the client can address
|
|
21
|
+
* mutations via `entryId` (#191 fix). Returns null when no entry matches
|
|
22
|
+
* (organizational subdirs, ad-hoc paths, or pre-doctor entries lacking
|
|
23
|
+
* an id) — the link is then omitted and mutations fall back to slug-
|
|
24
|
+
* template addressing.
|
|
25
|
+
*
|
|
26
|
+
* Failures (calendar absent, parse error) fall through to null so a
|
|
27
|
+
* transient calendar issue never blocks the scrapbook render.
|
|
28
|
+
*/
|
|
29
|
+
export declare function lookupEntryId(ctx: StudioContext, site: string, path: string): string | null;
|
|
30
|
+
/**
|
|
31
|
+
* #205 — listing + dir-resolution dispatch. Two addressing modes:
|
|
32
|
+
*
|
|
33
|
+
* - Entry-id mode: `entryId` is validated as a UUID, the sidecar is
|
|
34
|
+
* read, and the listing resolves via `listScrapbookForEntry` so
|
|
35
|
+
* non-kebab-case entries (feature-doc layouts, dotted version
|
|
36
|
+
* segments, etc.) read items from the entry's artifact-parent
|
|
37
|
+
* `scrapbook/` directory. Symmetric to the entry-aware mutation API.
|
|
38
|
+
* - Slug mode: legacy / organizational paths under the site's content
|
|
39
|
+
* dir. Resolves via `scrapbookDirAtPath` + `listScrapbook` (the
|
|
40
|
+
* pre-#205 behavior).
|
|
41
|
+
*
|
|
42
|
+
* Returns the resolved `scrapbookDir` (absolute) plus the listing
|
|
43
|
+
* summary so the caller threads both through to render helpers.
|
|
44
|
+
*/
|
|
45
|
+
export declare function resolveListing(ctx: StudioContext, site: string, path: string, entryId: string | null): Promise<{
|
|
46
|
+
scrapbookDir: string;
|
|
47
|
+
result: ScrapbookSummary;
|
|
48
|
+
resolvedEntryId: string | null;
|
|
49
|
+
}>;
|
|
50
|
+
//# sourceMappingURL=dispatch.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dispatch.d.ts","sourceRoot":"","sources":["../../../src/pages/scrapbook/dispatch.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,OAAO,EAKL,KAAK,gBAAgB,EACtB,MAAM,0BAA0B,CAAC;AAGlC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEzD;;;GAGG;AACH,qBAAa,kBAAmB,SAAQ,KAAK;IAC3C,QAAQ,CAAC,MAAM,EAAE,GAAG,GAAG,GAAG,CAAC;gBACf,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,GAAG,GAAG;CAK/C;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,aAAa,CAC3B,GAAG,EAAE,aAAa,EAClB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,GACX,MAAM,GAAG,IAAI,CAYf;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,cAAc,CAClC,GAAG,EAAE,aAAa,EAClB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,GAAG,IAAI,GACrB,OAAO,CAAC;IAAE,YAAY,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,gBAAgB,CAAC;IAAC,eAAe,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAAC,CA0C7F"}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Scrapbook page listing dispatch — entry-aware vs slug-template
|
|
3
|
+
* resolution. Mirrors the post-#191 envelope/dispatch split for
|
|
4
|
+
* mutations: dispatch chooses the addressing mode, render stays free
|
|
5
|
+
* of the resolution branch.
|
|
6
|
+
*/
|
|
7
|
+
import { existsSync } from 'node:fs';
|
|
8
|
+
import { readCalendar } from '@deskwork/core/calendar';
|
|
9
|
+
import { findEntry } from '@deskwork/core/calendar-mutations';
|
|
10
|
+
import { resolveCalendarPath } from '@deskwork/core/paths';
|
|
11
|
+
import { listScrapbook, listScrapbookForEntry, scrapbookDirAtPath, scrapbookDirForEntry, } from '@deskwork/core/scrapbook';
|
|
12
|
+
import { readSidecar } from '@deskwork/core/sidecar';
|
|
13
|
+
import { UUID_RE } from "../../routes/scrapbook-mutation-envelope.js";
|
|
14
|
+
/**
|
|
15
|
+
* Error class surfaced by the page route to translate into HTTP status
|
|
16
|
+
* codes (`server.ts` maps these onto 400/404 responses).
|
|
17
|
+
*/
|
|
18
|
+
export class ScrapbookPageError extends Error {
|
|
19
|
+
status;
|
|
20
|
+
constructor(message, status) {
|
|
21
|
+
super(message);
|
|
22
|
+
this.status = status;
|
|
23
|
+
this.name = 'ScrapbookPageError';
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* #168 Phase 34 ship-pass — when the scrapbook path matches a tracked
|
|
28
|
+
* calendar entry with a stamped UUID, return the entry's id so the aside
|
|
29
|
+
* can render a "← back to review" link AND the client can address
|
|
30
|
+
* mutations via `entryId` (#191 fix). Returns null when no entry matches
|
|
31
|
+
* (organizational subdirs, ad-hoc paths, or pre-doctor entries lacking
|
|
32
|
+
* an id) — the link is then omitted and mutations fall back to slug-
|
|
33
|
+
* template addressing.
|
|
34
|
+
*
|
|
35
|
+
* Failures (calendar absent, parse error) fall through to null so a
|
|
36
|
+
* transient calendar issue never blocks the scrapbook render.
|
|
37
|
+
*/
|
|
38
|
+
export function lookupEntryId(ctx, site, path) {
|
|
39
|
+
if (!(site in ctx.config.sites))
|
|
40
|
+
return null;
|
|
41
|
+
try {
|
|
42
|
+
const calendarPath = resolveCalendarPath(ctx.projectRoot, ctx.config, site);
|
|
43
|
+
if (!existsSync(calendarPath))
|
|
44
|
+
return null;
|
|
45
|
+
const cal = readCalendar(calendarPath);
|
|
46
|
+
const entry = findEntry(cal, path);
|
|
47
|
+
if (!entry || !entry.id)
|
|
48
|
+
return null;
|
|
49
|
+
return entry.id;
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* #205 — listing + dir-resolution dispatch. Two addressing modes:
|
|
57
|
+
*
|
|
58
|
+
* - Entry-id mode: `entryId` is validated as a UUID, the sidecar is
|
|
59
|
+
* read, and the listing resolves via `listScrapbookForEntry` so
|
|
60
|
+
* non-kebab-case entries (feature-doc layouts, dotted version
|
|
61
|
+
* segments, etc.) read items from the entry's artifact-parent
|
|
62
|
+
* `scrapbook/` directory. Symmetric to the entry-aware mutation API.
|
|
63
|
+
* - Slug mode: legacy / organizational paths under the site's content
|
|
64
|
+
* dir. Resolves via `scrapbookDirAtPath` + `listScrapbook` (the
|
|
65
|
+
* pre-#205 behavior).
|
|
66
|
+
*
|
|
67
|
+
* Returns the resolved `scrapbookDir` (absolute) plus the listing
|
|
68
|
+
* summary so the caller threads both through to render helpers.
|
|
69
|
+
*/
|
|
70
|
+
export async function resolveListing(ctx, site, path, entryId) {
|
|
71
|
+
if (entryId !== null) {
|
|
72
|
+
if (!UUID_RE.test(entryId)) {
|
|
73
|
+
throw new ScrapbookPageError(`invalid entryId`, 400);
|
|
74
|
+
}
|
|
75
|
+
let entry;
|
|
76
|
+
try {
|
|
77
|
+
entry = await readSidecar(ctx.projectRoot, entryId);
|
|
78
|
+
}
|
|
79
|
+
catch (e) {
|
|
80
|
+
// readSidecar throws "sidecar not found" with ENOENT; map to 404.
|
|
81
|
+
const reason = e instanceof Error ? e.message : String(e);
|
|
82
|
+
if (/sidecar not found/i.test(reason)) {
|
|
83
|
+
throw new ScrapbookPageError(reason, 404);
|
|
84
|
+
}
|
|
85
|
+
throw e;
|
|
86
|
+
}
|
|
87
|
+
const scrapbookDir = scrapbookDirForEntry(ctx.projectRoot, ctx.config, site, { id: entry.uuid, slug: entry.slug });
|
|
88
|
+
const result = listScrapbookForEntry(ctx.projectRoot, ctx.config, site, { id: entry.uuid, slug: entry.slug });
|
|
89
|
+
return { scrapbookDir, result, resolvedEntryId: entry.uuid };
|
|
90
|
+
}
|
|
91
|
+
// Slug-mode: legacy back-compat. listScrapbook returns
|
|
92
|
+
// { exists: false, items: [] } for missing dirs, so an empty
|
|
93
|
+
// scrapbook is not an error path. Real errors (slug validation,
|
|
94
|
+
// scrapbookDir resolution failures, FS permission issues)
|
|
95
|
+
// propagate to the studio's error handler.
|
|
96
|
+
const scrapbookDir = scrapbookDirAtPath(ctx.projectRoot, ctx.config, site, path);
|
|
97
|
+
const result = listScrapbook(ctx.projectRoot, ctx.config, site, path);
|
|
98
|
+
// Best-effort lookup so the back-link to the review surface still
|
|
99
|
+
// renders for slug-template entries that happen to match a calendar
|
|
100
|
+
// entry by slug.
|
|
101
|
+
const resolvedEntryId = lookupEntryId(ctx, site, path);
|
|
102
|
+
return { scrapbookDir, result, resolvedEntryId };
|
|
103
|
+
}
|
|
104
|
+
//# sourceMappingURL=dispatch.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dispatch.js","sourceRoot":"","sources":["../../../src/pages/scrapbook/dispatch.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Scrapbook image-format readers — pure functions on Buffer headers.
|
|
3
|
+
*
|
|
4
|
+
* Recognizes PNG, JPEG, WebP, and GIF; returns null for unrecognized
|
|
5
|
+
* signatures or truncated/malformed buffers. Used by the scrapbook
|
|
6
|
+
* card meta to render `{W} × {H}` next to the image kind chip.
|
|
7
|
+
*
|
|
8
|
+
* Each format is parsed from its file-header structure (no external
|
|
9
|
+
* dependency); each branch returns null on any unexpected byte rather
|
|
10
|
+
* than throwing, so a corrupt image still renders with empty meta.
|
|
11
|
+
*/
|
|
12
|
+
export interface ImageDimensions {
|
|
13
|
+
readonly width: number;
|
|
14
|
+
readonly height: number;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Read width × height from a buffer. Recognizes PNG, JPEG, WebP, and
|
|
18
|
+
* GIF; returns null for unrecognized signatures or truncated/malformed
|
|
19
|
+
* buffers.
|
|
20
|
+
*/
|
|
21
|
+
export declare function readImageDimensions(buf: Buffer): ImageDimensions | null;
|
|
22
|
+
export declare function readJpegDimensions(buf: Buffer): ImageDimensions | null;
|
|
23
|
+
export declare function readWebpDimensions(buf: Buffer): ImageDimensions | null;
|
|
24
|
+
//# sourceMappingURL=image-readers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"image-readers.d.ts","sourceRoot":"","sources":["../../../src/pages/scrapbook/image-readers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,GAAG,eAAe,GAAG,IAAI,CAiCvE;AAED,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,eAAe,GAAG,IAAI,CAoCtE;AAED,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,eAAe,GAAG,IAAI,CAyCtE"}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Scrapbook image-format readers — pure functions on Buffer headers.
|
|
3
|
+
*
|
|
4
|
+
* Recognizes PNG, JPEG, WebP, and GIF; returns null for unrecognized
|
|
5
|
+
* signatures or truncated/malformed buffers. Used by the scrapbook
|
|
6
|
+
* card meta to render `{W} × {H}` next to the image kind chip.
|
|
7
|
+
*
|
|
8
|
+
* Each format is parsed from its file-header structure (no external
|
|
9
|
+
* dependency); each branch returns null on any unexpected byte rather
|
|
10
|
+
* than throwing, so a corrupt image still renders with empty meta.
|
|
11
|
+
*/
|
|
12
|
+
/**
|
|
13
|
+
* Read width × height from a buffer. Recognizes PNG, JPEG, WebP, and
|
|
14
|
+
* GIF; returns null for unrecognized signatures or truncated/malformed
|
|
15
|
+
* buffers.
|
|
16
|
+
*/
|
|
17
|
+
export function readImageDimensions(buf) {
|
|
18
|
+
if (buf.length < 12)
|
|
19
|
+
return null;
|
|
20
|
+
// PNG: 89 50 4E 47 0D 0A 1A 0A then IHDR (chunk-length 4, "IHDR" 4,
|
|
21
|
+
// width 4, height 4 — width@16, height@20).
|
|
22
|
+
if (buf[0] === 0x89 && buf[1] === 0x50 && buf[2] === 0x4e && buf[3] === 0x47) {
|
|
23
|
+
if (buf.length < 24)
|
|
24
|
+
return null;
|
|
25
|
+
return { width: buf.readUInt32BE(16), height: buf.readUInt32BE(20) };
|
|
26
|
+
}
|
|
27
|
+
// GIF: "GIF87a" or "GIF89a" + logical screen descriptor (width LE @6,
|
|
28
|
+
// height LE @8).
|
|
29
|
+
if (buf[0] === 0x47 && buf[1] === 0x49 && buf[2] === 0x46 &&
|
|
30
|
+
buf[3] === 0x38 && (buf[4] === 0x37 || buf[4] === 0x39) && buf[5] === 0x61) {
|
|
31
|
+
if (buf.length < 10)
|
|
32
|
+
return null;
|
|
33
|
+
return { width: buf.readUInt16LE(6), height: buf.readUInt16LE(8) };
|
|
34
|
+
}
|
|
35
|
+
// JPEG: starts FF D8. Width/height live in a Start-Of-Frame marker
|
|
36
|
+
// (FF C0–CF, excluding DHT C4 / JPG C8 / DAC CC). Walk markers
|
|
37
|
+
// skipping their payloads until the SOF is found.
|
|
38
|
+
if (buf[0] === 0xff && buf[1] === 0xd8) {
|
|
39
|
+
return readJpegDimensions(buf);
|
|
40
|
+
}
|
|
41
|
+
// WebP: "RIFF" {size} "WEBP" then a chunk (VP8 / VP8L / VP8X).
|
|
42
|
+
if (buf[0] === 0x52 && buf[1] === 0x49 && buf[2] === 0x46 && buf[3] === 0x46 &&
|
|
43
|
+
buf[8] === 0x57 && buf[9] === 0x45 && buf[10] === 0x42 && buf[11] === 0x50) {
|
|
44
|
+
return readWebpDimensions(buf);
|
|
45
|
+
}
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
export function readJpegDimensions(buf) {
|
|
49
|
+
// Marker walk: skip FF D8 (SOI), then each marker is FF Xn followed
|
|
50
|
+
// by a 2-byte big-endian segment length (which includes its own 2
|
|
51
|
+
// bytes). The SOF segment's payload is: 1 byte precision, 2 bytes
|
|
52
|
+
// height, 2 bytes width (the rest is component info).
|
|
53
|
+
let i = 2;
|
|
54
|
+
while (i + 4 <= buf.length) {
|
|
55
|
+
if (buf[i] !== 0xff)
|
|
56
|
+
return null;
|
|
57
|
+
let marker = buf[i + 1] ?? 0;
|
|
58
|
+
// Skip fill bytes (0xff padding before the actual marker byte).
|
|
59
|
+
while (marker === 0xff && i + 2 < buf.length) {
|
|
60
|
+
i++;
|
|
61
|
+
marker = buf[i + 1] ?? 0;
|
|
62
|
+
}
|
|
63
|
+
i += 2;
|
|
64
|
+
// Standalone markers (no length): RST0–7 (D0–D7) and SOI/EOI/TEM.
|
|
65
|
+
if (marker === 0xd9 || marker === 0xd8 || marker === 0x01)
|
|
66
|
+
return null;
|
|
67
|
+
if (marker >= 0xd0 && marker <= 0xd7)
|
|
68
|
+
continue;
|
|
69
|
+
if (i + 2 > buf.length)
|
|
70
|
+
return null;
|
|
71
|
+
const segLen = buf.readUInt16BE(i);
|
|
72
|
+
// SOF markers carry the dimensions. Exclusions per JPEG spec:
|
|
73
|
+
// C4 (DHT — Huffman tables), C8 (JPG reserved), CC (DAC — arithmetic
|
|
74
|
+
// coding conditioning).
|
|
75
|
+
const isSof = marker >= 0xc0 && marker <= 0xcf &&
|
|
76
|
+
marker !== 0xc4 && marker !== 0xc8 && marker !== 0xcc;
|
|
77
|
+
if (isSof) {
|
|
78
|
+
if (i + 7 > buf.length)
|
|
79
|
+
return null;
|
|
80
|
+
return {
|
|
81
|
+
width: buf.readUInt16BE(i + 5),
|
|
82
|
+
height: buf.readUInt16BE(i + 3),
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
i += segLen;
|
|
86
|
+
}
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
export function readWebpDimensions(buf) {
|
|
90
|
+
// Three sub-formats (per RFC 6386 / VP8L spec / WebP container spec):
|
|
91
|
+
// - "VP8 " (lossy): header @20-22: signature 9D 01 2A, then
|
|
92
|
+
// 14-bit width LE @23, 14-bit height LE @25
|
|
93
|
+
// (each masked to 14 bits — top 2 bits are
|
|
94
|
+
// horizontal/vertical scale).
|
|
95
|
+
// - "VP8L" (lossless): header @20: signature 0x2F, then 32 bits
|
|
96
|
+
// packed: width-1 (14 bits) + height-1 (14
|
|
97
|
+
// bits) + alpha-flag + version (4 bits).
|
|
98
|
+
// - "VP8X" (extended): flags @20, reserved @21-23, width-1 (24
|
|
99
|
+
// bits LE) @24, height-1 (24 bits LE) @27.
|
|
100
|
+
// Need at least the RIFF header + chunk fourcc; per-variant length
|
|
101
|
+
// checks below cover the variant-specific payload sizes.
|
|
102
|
+
if (buf.length < 16)
|
|
103
|
+
return null;
|
|
104
|
+
const fourcc = buf.subarray(12, 16).toString('ascii');
|
|
105
|
+
if (fourcc === 'VP8 ') {
|
|
106
|
+
if (buf.length < 30)
|
|
107
|
+
return null;
|
|
108
|
+
if (buf[23] !== 0x9d || buf[24] !== 0x01 || buf[25] !== 0x2a)
|
|
109
|
+
return null;
|
|
110
|
+
const w = buf.readUInt16LE(26) & 0x3fff;
|
|
111
|
+
const h = buf.readUInt16LE(28) & 0x3fff;
|
|
112
|
+
return { width: w, height: h };
|
|
113
|
+
}
|
|
114
|
+
if (fourcc === 'VP8L') {
|
|
115
|
+
if (buf.length < 25)
|
|
116
|
+
return null;
|
|
117
|
+
if (buf[20] !== 0x2f)
|
|
118
|
+
return null;
|
|
119
|
+
// Read 4 bytes LE at offset 21, then unpack.
|
|
120
|
+
const packed = buf.readUInt32LE(21);
|
|
121
|
+
const widthMinus1 = packed & 0x3fff;
|
|
122
|
+
const heightMinus1 = (packed >>> 14) & 0x3fff;
|
|
123
|
+
return { width: widthMinus1 + 1, height: heightMinus1 + 1 };
|
|
124
|
+
}
|
|
125
|
+
if (fourcc === 'VP8X') {
|
|
126
|
+
if (buf.length < 30)
|
|
127
|
+
return null;
|
|
128
|
+
// 24-bit little-endian: low byte + (mid << 8) + (high << 16).
|
|
129
|
+
const w = ((buf[24] ?? 0) | ((buf[25] ?? 0) << 8) | ((buf[26] ?? 0) << 16)) + 1;
|
|
130
|
+
const h = ((buf[27] ?? 0) | ((buf[28] ?? 0) << 8) | ((buf[29] ?? 0) << 16)) + 1;
|
|
131
|
+
return { width: w, height: h };
|
|
132
|
+
}
|
|
133
|
+
return null;
|
|
134
|
+
}
|
|
135
|
+
//# sourceMappingURL=image-readers.js.map
|