@deskwork/core 0.15.0 → 0.17.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/doctor/rules/legacy-stage-artifact-path.d.ts +28 -0
- package/dist/doctor/rules/legacy-stage-artifact-path.d.ts.map +1 -0
- package/dist/doctor/rules/legacy-stage-artifact-path.js +232 -0
- package/dist/doctor/rules/legacy-stage-artifact-path.js.map +1 -0
- package/dist/doctor/rules/legacy-stage-artifact-path.ts +285 -0
- package/dist/doctor/runner.d.ts.map +1 -1
- package/dist/doctor/runner.js +2 -0
- package/dist/doctor/runner.js.map +1 -1
- package/dist/entry/annotations.d.ts +38 -3
- package/dist/entry/annotations.d.ts.map +1 -1
- package/dist/entry/annotations.js +164 -3
- package/dist/entry/annotations.js.map +1 -1
- package/dist/entry/approve.d.ts +21 -4
- package/dist/entry/approve.d.ts.map +1 -1
- package/dist/entry/approve.js +74 -7
- package/dist/entry/approve.js.map +1 -1
- package/dist/entry/snapshot.d.ts +51 -0
- package/dist/entry/snapshot.d.ts.map +1 -0
- package/dist/entry/snapshot.js +95 -0
- package/dist/entry/snapshot.js.map +1 -0
- package/dist/ingest-derive.d.ts +1 -1
- package/dist/ingest-derive.d.ts.map +1 -1
- package/dist/ingest-derive.js +10 -7
- package/dist/ingest-derive.js.map +1 -1
- package/dist/ingest-id.d.ts +33 -0
- package/dist/ingest-id.d.ts.map +1 -0
- package/dist/ingest-id.js +60 -0
- package/dist/ingest-id.js.map +1 -0
- package/dist/ingest.d.ts.map +1 -1
- package/dist/ingest.js +23 -0
- package/dist/ingest.js.map +1 -1
- package/dist/iterate/iterate.d.ts.map +1 -1
- package/dist/iterate/iterate.js +37 -25
- package/dist/iterate/iterate.js.map +1 -1
- package/dist/review/types.d.ts +56 -1
- package/dist/review/types.d.ts.map +1 -1
- package/dist/review/types.js.map +1 -1
- package/dist/schema/draft-annotation.d.ts +108 -24
- package/dist/schema/draft-annotation.d.ts.map +1 -1
- package/dist/schema/draft-annotation.js +23 -0
- package/dist/schema/draft-annotation.js.map +1 -1
- package/dist/schema/journal-events.d.ts +240 -104
- package/dist/schema/journal-events.d.ts.map +1 -1
- package/dist/scrapbook/crud-at-dir.d.ts +47 -0
- package/dist/scrapbook/crud-at-dir.d.ts.map +1 -0
- package/dist/scrapbook/crud-at-dir.js +114 -0
- package/dist/scrapbook/crud-at-dir.js.map +1 -0
- package/dist/scrapbook/crud-slug.d.ts +33 -0
- package/dist/scrapbook/crud-slug.d.ts.map +1 -0
- package/dist/scrapbook/crud-slug.js +99 -0
- package/dist/scrapbook/crud-slug.js.map +1 -0
- package/dist/scrapbook/format.d.ts +10 -0
- package/dist/scrapbook/format.d.ts.map +1 -0
- package/dist/scrapbook/format.js +41 -0
- package/dist/scrapbook/format.js.map +1 -0
- package/dist/scrapbook/listing.d.ts +94 -0
- package/dist/scrapbook/listing.d.ts.map +1 -0
- package/dist/scrapbook/listing.js +167 -0
- package/dist/scrapbook/listing.js.map +1 -0
- package/dist/scrapbook/paths.d.ts +115 -0
- package/dist/scrapbook/paths.d.ts.map +1 -0
- package/dist/scrapbook/paths.js +149 -0
- package/dist/scrapbook/paths.js.map +1 -0
- package/dist/scrapbook/read.d.ts +54 -0
- package/dist/scrapbook/read.d.ts.map +1 -0
- package/dist/scrapbook/read.js +62 -0
- package/dist/scrapbook/read.js.map +1 -0
- package/dist/scrapbook/seed.d.ts +19 -0
- package/dist/scrapbook/seed.d.ts.map +1 -0
- package/dist/scrapbook/seed.js +46 -0
- package/dist/scrapbook/seed.js.map +1 -0
- package/dist/scrapbook/types.d.ts +44 -0
- package/dist/scrapbook/types.d.ts.map +1 -0
- package/dist/scrapbook/types.js +11 -0
- package/dist/scrapbook/types.js.map +1 -0
- package/dist/scrapbook/validation.d.ts +28 -0
- package/dist/scrapbook/validation.d.ts.map +1 -0
- package/dist/scrapbook/validation.js +98 -0
- package/dist/scrapbook/validation.js.map +1 -0
- package/dist/scrapbook.d.ts +43 -277
- package/dist/scrapbook.d.ts.map +1 -1
- package/dist/scrapbook.js +42 -535
- package/dist/scrapbook.js.map +1 -1
- package/package.json +5 -1
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Scrapbook validation + classification helpers.
|
|
3
|
+
*
|
|
4
|
+
* Slug + filename validation runs at every fs entry point; a `..` or
|
|
5
|
+
* absolute path that slips through here would let a malicious request
|
|
6
|
+
* read or write outside the scrapbook tree. The route layer relies on
|
|
7
|
+
* these helpers for traversal protection.
|
|
8
|
+
*/
|
|
9
|
+
import { extname } from 'node:path';
|
|
10
|
+
// ---------------------------------------------------------------------------
|
|
11
|
+
// Slug + path validation
|
|
12
|
+
// ---------------------------------------------------------------------------
|
|
13
|
+
/**
|
|
14
|
+
* A single slug segment — kebab-case lowercase. Used both for flat
|
|
15
|
+
* slugs and as the building block of hierarchical paths.
|
|
16
|
+
*/
|
|
17
|
+
const SLUG_SEGMENT_RE = /^[a-z0-9][a-z0-9-]*$/;
|
|
18
|
+
/**
|
|
19
|
+
* A full slug path — one or more `/`-separated kebab-case segments.
|
|
20
|
+
* Accepts both legacy flat slugs ("scsi-over-wifi") and hierarchical
|
|
21
|
+
* paths ("the-outbound/characters/strivers"). No leading or trailing
|
|
22
|
+
* slash; no empty segments.
|
|
23
|
+
*/
|
|
24
|
+
const SLUG_RE = /^[a-z0-9][a-z0-9-]*(\/[a-z0-9][a-z0-9-]*)*$/;
|
|
25
|
+
const FILENAME_RE = /^[a-zA-Z0-9._-][a-zA-Z0-9._ -]*$/;
|
|
26
|
+
export function assertSlug(slug) {
|
|
27
|
+
if (!SLUG_RE.test(slug)) {
|
|
28
|
+
throw new Error(`invalid slug "${slug}" — must match ${SLUG_RE}`);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Split a hierarchical slug into its segments. Each segment is a
|
|
33
|
+
* standalone kebab-case identifier.
|
|
34
|
+
*/
|
|
35
|
+
export function slugSegments(slug) {
|
|
36
|
+
return slug.split('/');
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* True if a slug refers to a nested entry (has at least one `/`).
|
|
40
|
+
*/
|
|
41
|
+
export function isNestedSlug(slug) {
|
|
42
|
+
return slug.includes('/');
|
|
43
|
+
}
|
|
44
|
+
// `SLUG_SEGMENT_RE` is exported for callers that need to validate one
|
|
45
|
+
// segment at a time (e.g. when assembling a path interactively).
|
|
46
|
+
export { SLUG_SEGMENT_RE };
|
|
47
|
+
export function assertFilename(name) {
|
|
48
|
+
if (!name || name === '.' || name === '..') {
|
|
49
|
+
throw new Error(`invalid filename "${name}"`);
|
|
50
|
+
}
|
|
51
|
+
if (name.includes('/') || name.includes('\\') || name.includes('\0')) {
|
|
52
|
+
throw new Error(`filename may not contain path separators: "${name}"`);
|
|
53
|
+
}
|
|
54
|
+
if (name.startsWith('.')) {
|
|
55
|
+
// Dotfiles are suspicious for a dev-only operator UI. Reject.
|
|
56
|
+
throw new Error(`filename may not start with a dot: "${name}"`);
|
|
57
|
+
}
|
|
58
|
+
if (!FILENAME_RE.test(name)) {
|
|
59
|
+
throw new Error(`filename may only contain [A-Za-z0-9._ -]: "${name}"`);
|
|
60
|
+
}
|
|
61
|
+
if (name.length > 200) {
|
|
62
|
+
throw new Error(`filename too long (> 200 chars): "${name}"`);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
// ---------------------------------------------------------------------------
|
|
66
|
+
// Type classification
|
|
67
|
+
// ---------------------------------------------------------------------------
|
|
68
|
+
export function classify(filename) {
|
|
69
|
+
const ext = extname(filename).toLowerCase();
|
|
70
|
+
switch (ext) {
|
|
71
|
+
case '.md':
|
|
72
|
+
case '.markdown':
|
|
73
|
+
return 'md';
|
|
74
|
+
case '.json':
|
|
75
|
+
case '.jsonl':
|
|
76
|
+
return 'json';
|
|
77
|
+
case '.js':
|
|
78
|
+
case '.mjs':
|
|
79
|
+
case '.cjs':
|
|
80
|
+
case '.ts':
|
|
81
|
+
case '.tsx':
|
|
82
|
+
case '.mts':
|
|
83
|
+
return 'js';
|
|
84
|
+
case '.png':
|
|
85
|
+
case '.jpg':
|
|
86
|
+
case '.jpeg':
|
|
87
|
+
case '.gif':
|
|
88
|
+
case '.webp':
|
|
89
|
+
case '.svg':
|
|
90
|
+
return 'img';
|
|
91
|
+
case '.txt':
|
|
92
|
+
case '.log':
|
|
93
|
+
return 'txt';
|
|
94
|
+
default:
|
|
95
|
+
return 'other';
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
//# sourceMappingURL=validation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validation.js","sourceRoot":"","sources":["../../src/scrapbook/validation.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAGpC,8EAA8E;AAC9E,yBAAyB;AACzB,8EAA8E;AAE9E;;;GAGG;AACH,MAAM,eAAe,GAAG,sBAAsB,CAAC;AAE/C;;;;;GAKG;AACH,MAAM,OAAO,GAAG,6CAA6C,CAAC;AAC9D,MAAM,WAAW,GAAG,kCAAkC,CAAC;AAEvD,MAAM,UAAU,UAAU,CAAC,IAAY;IACrC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QACxB,MAAM,IAAI,KAAK,CAAC,iBAAiB,IAAI,kBAAkB,OAAO,EAAE,CAAC,CAAC;IACpE,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,YAAY,CAAC,IAAY;IACvC,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;AACzB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,YAAY,CAAC,IAAY;IACvC,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;AAC5B,CAAC;AAED,sEAAsE;AACtE,iEAAiE;AACjE,OAAO,EAAE,eAAe,EAAE,CAAC;AAE3B,MAAM,UAAU,cAAc,CAAC,IAAY;IACzC,IAAI,CAAC,IAAI,IAAI,IAAI,KAAK,GAAG,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;QAC3C,MAAM,IAAI,KAAK,CAAC,qBAAqB,IAAI,GAAG,CAAC,CAAC;IAChD,CAAC;IACD,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QACrE,MAAM,IAAI,KAAK,CAAC,8CAA8C,IAAI,GAAG,CAAC,CAAC;IACzE,CAAC;IACD,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QACzB,8DAA8D;QAC9D,MAAM,IAAI,KAAK,CAAC,uCAAuC,IAAI,GAAG,CAAC,CAAC;IAClE,CAAC;IACD,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QAC5B,MAAM,IAAI,KAAK,CACb,+CAA+C,IAAI,GAAG,CACvD,CAAC;IACJ,CAAC;IACD,IAAI,IAAI,CAAC,MAAM,GAAG,GAAG,EAAE,CAAC;QACtB,MAAM,IAAI,KAAK,CAAC,qCAAqC,IAAI,GAAG,CAAC,CAAC;IAChE,CAAC;AACH,CAAC;AAED,8EAA8E;AAC9E,sBAAsB;AACtB,8EAA8E;AAE9E,MAAM,UAAU,QAAQ,CAAC,QAAgB;IACvC,MAAM,GAAG,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC,WAAW,EAAE,CAAC;IAC5C,QAAQ,GAAG,EAAE,CAAC;QACZ,KAAK,KAAK,CAAC;QACX,KAAK,WAAW;YACd,OAAO,IAAI,CAAC;QACd,KAAK,OAAO,CAAC;QACb,KAAK,QAAQ;YACX,OAAO,MAAM,CAAC;QAChB,KAAK,KAAK,CAAC;QACX,KAAK,MAAM,CAAC;QACZ,KAAK,MAAM,CAAC;QACZ,KAAK,KAAK,CAAC;QACX,KAAK,MAAM,CAAC;QACZ,KAAK,MAAM;YACT,OAAO,IAAI,CAAC;QACd,KAAK,MAAM,CAAC;QACZ,KAAK,MAAM,CAAC;QACZ,KAAK,OAAO,CAAC;QACb,KAAK,MAAM,CAAC;QACZ,KAAK,OAAO,CAAC;QACb,KAAK,MAAM;YACT,OAAO,KAAK,CAAC;QACf,KAAK,MAAM,CAAC;QACZ,KAAK,MAAM;YACT,OAAO,KAAK,CAAC;QACf;YACE,OAAO,OAAO,CAAC;IACnB,CAAC;AACH,CAAC"}
|
package/dist/scrapbook.d.ts
CHANGED
|
@@ -4,286 +4,52 @@
|
|
|
4
4
|
* research, and references attached to an in-flight article. Committed
|
|
5
5
|
* to git alongside the article; not baked to the public site.
|
|
6
6
|
*
|
|
7
|
-
* Responsibilities
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* -
|
|
12
|
-
* -
|
|
7
|
+
* Responsibilities (split across sibling modules under `scrapbook/`
|
|
8
|
+
* per #202; this file is a barrel re-export so existing
|
|
9
|
+
* `import from '@deskwork/core/scrapbook'` sites stay unchanged):
|
|
10
|
+
*
|
|
11
|
+
* - `scrapbook/types.ts` — public types
|
|
12
|
+
* - `scrapbook/validation.ts` — slug + filename validation, classify
|
|
13
|
+
* - `scrapbook/paths.ts` — public (entry-aware + path-aware) +
|
|
14
|
+
* private (slug-template) resolvers
|
|
15
|
+
* - `scrapbook/listing.ts` — list + count
|
|
16
|
+
* - `scrapbook/read.ts` — read primitives
|
|
17
|
+
* - `scrapbook/crud-at-dir.ts` — entry-aware CRUD primitives (post-#191)
|
|
18
|
+
* - `scrapbook/crud-slug.ts` — INTERNAL slug-template CRUD primitives
|
|
19
|
+
* - `scrapbook/seed.ts` — plan-time scaffolding
|
|
20
|
+
* - `scrapbook/format.ts` — UI formatters
|
|
21
|
+
*
|
|
22
|
+
* Public API surface (#192 — slug-template mutators are NO LONGER
|
|
23
|
+
* exported; callers go through `scrapbookDirForEntry` + the `*AtDir`
|
|
24
|
+
* family instead):
|
|
25
|
+
*
|
|
26
|
+
* - Types: `ScrapbookItemKind`, `ScrapbookItem`, `ScrapbookSummary`,
|
|
27
|
+
* `ScrapbookLocation`, `SECRET_SUBDIR`
|
|
28
|
+
* - Validation: `assertSlug`, `assertFilename`, `slugSegments`,
|
|
29
|
+
* `isNestedSlug`, `SLUG_SEGMENT_RE`, `classify`
|
|
30
|
+
* - Paths: `scrapbookDirAtPath`, `scrapbookDirForEntry`,
|
|
31
|
+
* `scrapbookFilePathAtDir`
|
|
32
|
+
* - Listing: `listScrapbook`, `listScrapbookAtDir`,
|
|
33
|
+
* `listScrapbookForEntry`, `countScrapbook`, `countScrapbookForEntry`
|
|
34
|
+
* - Read: `readScrapbookFile`, `readScrapbookFileAtDir`,
|
|
35
|
+
* `readScrapbookFileForEntry`
|
|
36
|
+
* - CRUD: `createScrapbookMarkdownAtDir`, `saveScrapbookFileAtDir`,
|
|
37
|
+
* `renameScrapbookFileAtDir`, `deleteScrapbookFileAtDir`,
|
|
38
|
+
* `writeScrapbookUploadAtDir`
|
|
39
|
+
* - Seed: `seedScrapbookReadme`
|
|
40
|
+
* - Format: `formatRelativeTime`, `formatSize`
|
|
13
41
|
*
|
|
14
42
|
* The API endpoints that wrap these helpers should 404 in PROD; this
|
|
15
43
|
* library contains no PROD check of its own (enforcement stays at the
|
|
16
44
|
* endpoint boundary).
|
|
17
45
|
*/
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
export
|
|
22
|
-
export
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
}
|
|
28
|
-
export interface ScrapbookSummary {
|
|
29
|
-
site: string;
|
|
30
|
-
/**
|
|
31
|
-
* The scrapbook's location identifier — a slug for entries tied to a
|
|
32
|
-
* calendar row, or any directory path within `contentDir` for
|
|
33
|
-
* scrapbooks that hang off purely organizational nodes (e.g. an
|
|
34
|
-
* intermediate project directory that isn't itself a calendar entry).
|
|
35
|
-
*/
|
|
36
|
-
slug: string;
|
|
37
|
-
dir: string;
|
|
38
|
-
exists: boolean;
|
|
39
|
-
/** Files at the top of `scrapbook/` (public/published-side notes). */
|
|
40
|
-
items: ScrapbookItem[];
|
|
41
|
-
/**
|
|
42
|
-
* Files inside `scrapbook/secret/` — never to be published. Operators
|
|
43
|
-
* can drop research, drafts, or sensitive notes here knowing the host
|
|
44
|
-
* project's content collection patterns won't pick them up.
|
|
45
|
-
*/
|
|
46
|
-
secretItems: ScrapbookItem[];
|
|
47
|
-
}
|
|
48
|
-
/** Well-known subdirectory name for editorially-private scrapbook items. */
|
|
49
|
-
export declare const SECRET_SUBDIR = "secret";
|
|
50
|
-
/**
|
|
51
|
-
* A single slug segment — kebab-case lowercase. Used both for flat
|
|
52
|
-
* slugs and as the building block of hierarchical paths.
|
|
53
|
-
*/
|
|
54
|
-
declare const SLUG_SEGMENT_RE: RegExp;
|
|
55
|
-
export declare function assertSlug(slug: string): void;
|
|
56
|
-
/**
|
|
57
|
-
* Split a hierarchical slug into its segments. Each segment is a
|
|
58
|
-
* standalone kebab-case identifier.
|
|
59
|
-
*/
|
|
60
|
-
export declare function slugSegments(slug: string): string[];
|
|
61
|
-
/**
|
|
62
|
-
* True if a slug refers to a nested entry (has at least one `/`).
|
|
63
|
-
*/
|
|
64
|
-
export declare function isNestedSlug(slug: string): boolean;
|
|
65
|
-
export { SLUG_SEGMENT_RE };
|
|
66
|
-
export declare function assertFilename(name: string): void;
|
|
67
|
-
/**
|
|
68
|
-
* Resolve the scrapbook directory for (site, slug) and ensure the
|
|
69
|
-
* return path stays inside the site's content directory.
|
|
70
|
-
* Doesn't require the directory to exist.
|
|
71
|
-
*/
|
|
72
|
-
export declare function scrapbookDir(projectRoot: string, config: DeskworkConfig, site: string, slug: string): string;
|
|
73
|
-
/**
|
|
74
|
-
* Resolve the scrapbook directory for an arbitrary path under the site's
|
|
75
|
-
* content directory. Used by Phase 19c+ callers (e.g. the studio) that
|
|
76
|
-
* already know the fs-relative path of an organizational or tracked node
|
|
77
|
-
* and don't want to re-derive it through the slug regex. The path may
|
|
78
|
-
* contain `/` segments; no `..` or absolute paths allowed.
|
|
79
|
-
*
|
|
80
|
-
* Path-shape validation matches `assertSlug` since the on-disk layout
|
|
81
|
-
* is the same shape — kebab-case segments separated by `/`. Different
|
|
82
|
-
* helper, same constraint.
|
|
83
|
-
*/
|
|
84
|
-
export declare function scrapbookDirAtPath(projectRoot: string, config: DeskworkConfig, site: string, relPath: string): string;
|
|
85
|
-
/**
|
|
86
|
-
* Resolve the scrapbook directory for a tracked calendar entry.
|
|
87
|
-
*
|
|
88
|
-
* Derives the scrapbook location from the parent directory of the
|
|
89
|
-
* entry's content file (located via `findEntryFile`, which prefers the
|
|
90
|
-
* frontmatter-id index over the slug template). Falls back to today's
|
|
91
|
-
* slug-based addressing for entries that haven't been bound to
|
|
92
|
-
* frontmatter yet (pre-doctor state).
|
|
93
|
-
*
|
|
94
|
-
* Refactor-proof: when the operator renames an entry's directory on
|
|
95
|
-
* disk, the next request rebuilds the index and the scrapbook now
|
|
96
|
-
* lives at the new path automatically.
|
|
97
|
-
*
|
|
98
|
-
* @param entry Calendar entry — `id` preferred (Phase 19+); `slug` is
|
|
99
|
-
* used both as the legacy fallback and to locate the
|
|
100
|
-
* `<dirname>/scrapbook/` when the entry has no id yet.
|
|
101
|
-
* @param index Optional pre-built index (per-request memoization). When
|
|
102
|
-
* omitted, this function builds one.
|
|
103
|
-
*/
|
|
104
|
-
export declare function scrapbookDirForEntry(projectRoot: string, config: DeskworkConfig, site: string, entry: {
|
|
105
|
-
id?: string;
|
|
106
|
-
slug: string;
|
|
107
|
-
}, index?: ContentIndex): string;
|
|
108
|
-
/** Options that select between the public scrapbook root and `secret/`. */
|
|
109
|
-
export interface ScrapbookLocation {
|
|
110
|
-
/** When true, the file lives under `scrapbook/secret/`. Default: false. */
|
|
111
|
-
secret?: boolean;
|
|
112
|
-
}
|
|
113
|
-
/**
|
|
114
|
-
* Resolve a filename INSIDE a scrapbook dir and return the absolute
|
|
115
|
-
* path. Throws if the resolved path escapes the scrapbook dir (guards
|
|
116
|
-
* against `..` sequences that slipped through assertFilename).
|
|
117
|
-
*
|
|
118
|
-
* When `opts.secret` is true, the returned path is rooted at
|
|
119
|
-
* `<scrapbook>/secret/<filename>` instead of `<scrapbook>/<filename>`.
|
|
120
|
-
*/
|
|
121
|
-
export declare function scrapbookFilePath(projectRoot: string, config: DeskworkConfig, site: string, slug: string, filename: string, opts?: ScrapbookLocation): string;
|
|
122
|
-
/**
|
|
123
|
-
* Resolve a filename inside an already-resolved scrapbook directory.
|
|
124
|
-
* Mirrors `listScrapbookAtDir` — used by callers that have already
|
|
125
|
-
* resolved the on-disk dir via `scrapbookDirForEntry` (id-driven) or
|
|
126
|
-
* `scrapbookDirAtPath` (fs-path-driven) and don't want to re-derive
|
|
127
|
-
* through the slug template.
|
|
128
|
-
*
|
|
129
|
-
* Same security guards as `scrapbookFilePath`:
|
|
130
|
-
* - `assertFilename` blocks dotfiles / `..` / absolute paths in the filename
|
|
131
|
-
* - the `startsWith(dir + '/')` containment check blocks any traversal
|
|
132
|
-
* that slipped through (so `secret/` always sits inside the top-level
|
|
133
|
-
* scrapbook dir)
|
|
134
|
-
*
|
|
135
|
-
* The slug-shape validator is bypassed because the caller has already
|
|
136
|
-
* proven the directory exists in the content tree by other means.
|
|
137
|
-
*/
|
|
138
|
-
export declare function scrapbookFilePathAtDir(scrapbookDirAbs: string, filename: string, opts?: ScrapbookLocation): string;
|
|
139
|
-
export declare function classify(filename: string): ScrapbookItemKind;
|
|
140
|
-
/**
|
|
141
|
-
* List the items in a scrapbook, sorted newest-mtime first. Returns
|
|
142
|
-
* both public items (top-level files) and secret items (files inside
|
|
143
|
-
* `scrapbook/secret/`). Subdirectories at the top level OTHER than
|
|
144
|
-
* `secret/` are ignored — deskwork doesn't recurse into arbitrary
|
|
145
|
-
* trees inside a scrapbook.
|
|
146
|
-
*/
|
|
147
|
-
export declare function listScrapbook(projectRoot: string, config: DeskworkConfig, site: string, slug: string): ScrapbookSummary;
|
|
148
|
-
/**
|
|
149
|
-
* List a scrapbook by absolute directory path. Used by callers that
|
|
150
|
-
* have already resolved the on-disk path via `scrapbookDirForEntry`
|
|
151
|
-
* (id-driven) or `scrapbookDirAtPath` (fs-path-driven) and don't want
|
|
152
|
-
* to re-derive through the slug template. The `slug` parameter is only
|
|
153
|
-
* used to populate the returned summary's identifier field — it does
|
|
154
|
-
* not influence path resolution.
|
|
155
|
-
*
|
|
156
|
-
* Internal primitive shared by `listScrapbook` (slug-based) and
|
|
157
|
-
* `listScrapbookForEntry` (id-driven).
|
|
158
|
-
*/
|
|
159
|
-
export declare function listScrapbookAtDir(site: string, slug: string, dir: string): ScrapbookSummary;
|
|
160
|
-
/**
|
|
161
|
-
* List scrapbook items for a tracked calendar entry. Resolves the
|
|
162
|
-
* scrapbook directory via the content index when available (id binding),
|
|
163
|
-
* falling back to slug-based addressing for entries that haven't been
|
|
164
|
-
* bound to frontmatter yet (pre-doctor state).
|
|
165
|
-
*
|
|
166
|
-
* Mirrors the shape of `countScrapbookForEntry`. Used by the studio
|
|
167
|
-
* review-page drawer + content-detail panel so writingcontrol-shape
|
|
168
|
-
* entries (where the file path diverges from the slug template) list
|
|
169
|
-
* items at the correct on-disk location.
|
|
170
|
-
*
|
|
171
|
-
* @param entry Calendar entry — `id` preferred; `slug` is both the
|
|
172
|
-
* legacy fallback and the disambiguator the underlying
|
|
173
|
-
* resolver uses when the index is incomplete.
|
|
174
|
-
* @param index Optional pre-built per-request index. When omitted, the
|
|
175
|
-
* resolver builds one on demand.
|
|
176
|
-
*/
|
|
177
|
-
export declare function listScrapbookForEntry(projectRoot: string, config: DeskworkConfig, site: string, entry: {
|
|
178
|
-
id?: string;
|
|
179
|
-
slug: string;
|
|
180
|
-
}, index?: ContentIndex): ScrapbookSummary;
|
|
181
|
-
/**
|
|
182
|
-
* Total item count (public + secret). Used by the studio chip for the
|
|
183
|
-
* badge — operators want a single "has scrapbook content" signal that
|
|
184
|
-
* counts everything attached to this entry.
|
|
185
|
-
*
|
|
186
|
-
* Slug-based addressing: resolves `<contentDir>/<slug>/scrapbook/`. For
|
|
187
|
-
* entries whose on-disk path doesn't match the slug template (e.g.
|
|
188
|
-
* writingcontrol-shape projects where slug `the-outbound` lives at
|
|
189
|
-
* `projects/the-outbound/index.md`), use `countScrapbookForEntry`
|
|
190
|
-
* instead — it derives the path from the bound file via the content
|
|
191
|
-
* index.
|
|
192
|
-
*/
|
|
193
|
-
export declare function countScrapbook(projectRoot: string, config: DeskworkConfig, site: string, slug: string): number;
|
|
194
|
-
/**
|
|
195
|
-
* Count scrapbook items for a tracked calendar entry. Resolves the
|
|
196
|
-
* scrapbook directory via the content index when available (id binding),
|
|
197
|
-
* falling back to slug-based addressing for entries that haven't been
|
|
198
|
-
* bound to frontmatter yet (pre-doctor state).
|
|
199
|
-
*
|
|
200
|
-
* Mirrors the shape of `scrapbookDirForEntry` — same resolver, same
|
|
201
|
-
* legacy-slug fallback. Used by the studio dashboard chip so writing-
|
|
202
|
-
* control-shape entries (where the file path diverges from the slug
|
|
203
|
-
* template) report the correct count.
|
|
204
|
-
*
|
|
205
|
-
* @param entry Calendar entry — `id` preferred (Phase 19+); `slug` is
|
|
206
|
-
* both the legacy fallback and the disambiguator the
|
|
207
|
-
* underlying resolver uses when the index is incomplete.
|
|
208
|
-
* @param index Optional pre-built per-request index. When omitted, the
|
|
209
|
-
* resolver builds one on demand.
|
|
210
|
-
*/
|
|
211
|
-
export declare function countScrapbookForEntry(projectRoot: string, config: DeskworkConfig, site: string, entry: {
|
|
212
|
-
id?: string;
|
|
213
|
-
slug: string;
|
|
214
|
-
}, index?: ContentIndex): number;
|
|
215
|
-
export declare function readScrapbookFile(projectRoot: string, config: DeskworkConfig, site: string, slug: string, filename: string, opts?: ScrapbookLocation): {
|
|
216
|
-
name: string;
|
|
217
|
-
kind: ScrapbookItemKind;
|
|
218
|
-
size: number;
|
|
219
|
-
mtime: string;
|
|
220
|
-
content: Buffer;
|
|
221
|
-
};
|
|
222
|
-
/**
|
|
223
|
-
* Read a scrapbook file given the absolute scrapbook directory. Used
|
|
224
|
-
* by callers that have already resolved the on-disk dir via
|
|
225
|
-
* `scrapbookDirForEntry` (id-driven) or `scrapbookDirAtPath`
|
|
226
|
-
* (fs-path-driven) and don't want to re-derive through the slug
|
|
227
|
-
* template. Mirrors the listing-side primitive `listScrapbookAtDir`.
|
|
228
|
-
*
|
|
229
|
-
* Same security guards as `readScrapbookFile` (filename validation +
|
|
230
|
-
* path-traversal containment) via `scrapbookFilePathAtDir`.
|
|
231
|
-
*/
|
|
232
|
-
export declare function readScrapbookFileAtDir(scrapbookDirAbs: string, filename: string, opts?: ScrapbookLocation): {
|
|
233
|
-
name: string;
|
|
234
|
-
kind: ScrapbookItemKind;
|
|
235
|
-
size: number;
|
|
236
|
-
mtime: string;
|
|
237
|
-
content: Buffer;
|
|
238
|
-
};
|
|
239
|
-
/**
|
|
240
|
-
* Read a scrapbook file for a tracked calendar entry. Mirrors
|
|
241
|
-
* `listScrapbookForEntry` / `countScrapbookForEntry` — id-driven
|
|
242
|
-
* resolution via `scrapbookDirForEntry`, slug fallback for pre-bound
|
|
243
|
-
* entries. Used by the studio's `/api/dev/scrapbook-file?entryId=...`
|
|
244
|
-
* variant so projects whose feature-doc layout doesn't match the
|
|
245
|
-
* kebab-case slug template (e.g. `docs/<version>/<status>/<feature>/`)
|
|
246
|
-
* can still serve scrapbook assets — `scrapbookDirAtPath`'s slug
|
|
247
|
-
* validator would otherwise reject any path with dots or uppercase
|
|
248
|
-
* segments.
|
|
249
|
-
*
|
|
250
|
-
* Same security guards as the slug-shape variant: `assertFilename`
|
|
251
|
-
* blocks dotfiles / `..` / absolute paths in the filename; the
|
|
252
|
-
* `startsWith(dir + '/')` containment check blocks any traversal that
|
|
253
|
-
* slipped through.
|
|
254
|
-
*/
|
|
255
|
-
export declare function readScrapbookFileForEntry(projectRoot: string, config: DeskworkConfig, site: string, entry: {
|
|
256
|
-
id?: string;
|
|
257
|
-
slug: string;
|
|
258
|
-
}, filename: string, opts?: ScrapbookLocation, index?: ContentIndex): {
|
|
259
|
-
name: string;
|
|
260
|
-
kind: ScrapbookItemKind;
|
|
261
|
-
size: number;
|
|
262
|
-
mtime: string;
|
|
263
|
-
content: Buffer;
|
|
264
|
-
};
|
|
265
|
-
/**
|
|
266
|
-
* Create a new markdown note in the scrapbook. Creates the scrapbook
|
|
267
|
-
* dir (and `secret/` subdir, if needed) if it doesn't exist. Refuses
|
|
268
|
-
* to overwrite existing files.
|
|
269
|
-
*/
|
|
270
|
-
export declare function createScrapbookMarkdown(projectRoot: string, config: DeskworkConfig, site: string, slug: string, filename: string, body: string, opts?: ScrapbookLocation): ScrapbookItem;
|
|
271
|
-
/** Overwrite an existing file's contents. Refuses if the file is absent. */
|
|
272
|
-
export declare function saveScrapbookFile(projectRoot: string, config: DeskworkConfig, site: string, slug: string, filename: string, body: string | Buffer, opts?: ScrapbookLocation): ScrapbookItem;
|
|
273
|
-
export declare function renameScrapbookFile(projectRoot: string, config: DeskworkConfig, site: string, slug: string, oldName: string, newName: string, opts?: ScrapbookLocation): ScrapbookItem;
|
|
274
|
-
export declare function deleteScrapbookFile(projectRoot: string, config: DeskworkConfig, site: string, slug: string, filename: string, opts?: ScrapbookLocation): void;
|
|
275
|
-
/**
|
|
276
|
-
* Seed a scrapbook's `README.md` at plan time. Idempotent — if the
|
|
277
|
-
* README already exists, returns null without touching it. Used by
|
|
278
|
-
* the plan skill so every Planned article gets a scrapbook home with
|
|
279
|
-
* a template that names the article and invites receipts.
|
|
280
|
-
*/
|
|
281
|
-
export declare function seedScrapbookReadme(projectRoot: string, config: DeskworkConfig, site: string, slug: string, title: string): ScrapbookItem | null;
|
|
282
|
-
/**
|
|
283
|
-
* Write an uploaded file into the scrapbook. Filename + content come
|
|
284
|
-
* from the multipart body upstream; we validate and persist.
|
|
285
|
-
*/
|
|
286
|
-
export declare function writeScrapbookUpload(projectRoot: string, config: DeskworkConfig, site: string, slug: string, filename: string, content: Buffer, opts?: ScrapbookLocation): ScrapbookItem;
|
|
287
|
-
export declare function formatRelativeTime(iso: string, now?: Date): string;
|
|
288
|
-
export declare function formatSize(bytes: number): string;
|
|
46
|
+
export type { ScrapbookItem, ScrapbookItemKind, ScrapbookLocation, ScrapbookSummary, } from './scrapbook/types.ts';
|
|
47
|
+
export { SECRET_SUBDIR } from './scrapbook/types.ts';
|
|
48
|
+
export { assertFilename, assertSlug, classify, isNestedSlug, SLUG_SEGMENT_RE, slugSegments, } from './scrapbook/validation.ts';
|
|
49
|
+
export { scrapbookDirAtPath, scrapbookDirForEntry, scrapbookFilePathAtDir, } from './scrapbook/paths.ts';
|
|
50
|
+
export { countScrapbook, countScrapbookForEntry, listScrapbook, listScrapbookAtDir, listScrapbookForEntry, } from './scrapbook/listing.ts';
|
|
51
|
+
export { readScrapbookFile, readScrapbookFileAtDir, readScrapbookFileForEntry, } from './scrapbook/read.ts';
|
|
52
|
+
export { createScrapbookMarkdownAtDir, deleteScrapbookFileAtDir, renameScrapbookFileAtDir, saveScrapbookFileAtDir, writeScrapbookUploadAtDir, } from './scrapbook/crud-at-dir.ts';
|
|
53
|
+
export { seedScrapbookReadme } from './scrapbook/seed.ts';
|
|
54
|
+
export { formatRelativeTime, formatSize } from './scrapbook/format.ts';
|
|
289
55
|
//# sourceMappingURL=scrapbook.d.ts.map
|
package/dist/scrapbook.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scrapbook.d.ts","sourceRoot":"","sources":["../src/scrapbook.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"scrapbook.d.ts","sourceRoot":"","sources":["../src/scrapbook.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AAEH,YAAY,EACV,aAAa,EACb,iBAAiB,EACjB,iBAAiB,EACjB,gBAAgB,GACjB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAErD,OAAO,EACL,cAAc,EACd,UAAU,EACV,QAAQ,EACR,YAAY,EACZ,eAAe,EACf,YAAY,GACb,MAAM,2BAA2B,CAAC;AAEnC,OAAO,EACL,kBAAkB,EAClB,oBAAoB,EACpB,sBAAsB,GACvB,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EACL,cAAc,EACd,sBAAsB,EACtB,aAAa,EACb,kBAAkB,EAClB,qBAAqB,GACtB,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EACL,iBAAiB,EACjB,sBAAsB,EACtB,yBAAyB,GAC1B,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EACL,4BAA4B,EAC5B,wBAAwB,EACxB,wBAAwB,EACxB,sBAAsB,EACtB,yBAAyB,GAC1B,MAAM,4BAA4B,CAAC;AAEpC,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAE1D,OAAO,EAAE,kBAAkB,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC"}
|