@johnhenry/sitefile 0.0.0-stage → 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +152 -0
- package/LICENSE +21 -0
- package/README.md +513 -2
- package/lib/src/archive-writers.d.ts +31 -0
- package/lib/src/archive-writers.js +197 -0
- package/lib/src/attest.d.ts +126 -0
- package/lib/src/attest.js +220 -0
- package/lib/src/bake.d.ts +74 -0
- package/lib/src/bake.js +372 -0
- package/lib/src/base-image.d.ts +76 -0
- package/lib/src/base-image.js +138 -0
- package/lib/src/build-args.d.ts +26 -0
- package/lib/src/build-args.js +164 -0
- package/lib/src/cache-limit.d.ts +54 -0
- package/lib/src/cache-limit.js +239 -0
- package/lib/src/casefold-data.d.ts +2 -0
- package/lib/src/casefold-data.js +217 -0
- package/lib/src/cbor.d.ts +39 -0
- package/lib/src/cbor.js +174 -0
- package/lib/src/checklinks.d.ts +42 -0
- package/lib/src/checklinks.js +120 -0
- package/lib/src/cli/bake.d.ts +2 -0
- package/lib/src/cli/bake.js +179 -0
- package/lib/src/cli/build-image.d.ts +21 -0
- package/lib/src/cli/build-image.js +42 -0
- package/lib/src/cli/cache.d.ts +8 -0
- package/lib/src/cli/cache.js +119 -0
- package/lib/src/cli/common.d.ts +29 -0
- package/lib/src/cli/common.js +100 -0
- package/lib/src/cli/git-context.d.ts +18 -0
- package/lib/src/cli/git-context.js +48 -0
- package/lib/src/cli/images.d.ts +6 -0
- package/lib/src/cli/images.js +285 -0
- package/lib/src/cli/index.d.ts +10 -0
- package/lib/src/cli/index.js +95 -0
- package/lib/src/cli/network.d.ts +34 -0
- package/lib/src/cli/network.js +56 -0
- package/lib/src/cli/outdated.d.ts +5 -0
- package/lib/src/cli/outdated.js +99 -0
- package/lib/src/cli/registry.d.ts +2 -0
- package/lib/src/cli/registry.js +127 -0
- package/lib/src/cli/serve-worker.d.ts +2 -0
- package/lib/src/cli/serve-worker.js +42 -0
- package/lib/src/cli/servers.d.ts +15 -0
- package/lib/src/cli/servers.js +467 -0
- package/lib/src/cli/vendor.d.ts +2 -0
- package/lib/src/cli/vendor.js +97 -0
- package/lib/src/cli/watch.d.ts +26 -0
- package/lib/src/cli/watch.js +81 -0
- package/lib/src/cli.d.ts +12 -0
- package/lib/src/cli.js +522 -0
- package/lib/src/csv.d.ts +27 -0
- package/lib/src/csv.js +117 -0
- package/lib/src/deflate.d.ts +76 -0
- package/lib/src/deflate.js +604 -0
- package/lib/src/digest.d.ts +3 -0
- package/lib/src/digest.js +7 -0
- package/lib/src/errors.d.ts +56 -0
- package/lib/src/errors.js +29 -0
- package/lib/src/executor.d.ts +393 -0
- package/lib/src/executor.js +2201 -0
- package/lib/src/explain.d.ts +64 -0
- package/lib/src/explain.js +445 -0
- package/lib/src/export-formats.d.ts +23 -0
- package/lib/src/export-formats.js +63 -0
- package/lib/src/exporter.d.ts +103 -0
- package/lib/src/exporter.js +676 -0
- package/lib/src/fingerprint.d.ts +40 -0
- package/lib/src/fingerprint.js +168 -0
- package/lib/src/frontmatter.d.ts +22 -0
- package/lib/src/frontmatter.js +45 -0
- package/lib/src/index.d.ts +13 -0
- package/lib/src/index.js +13 -0
- package/lib/src/language/ast.d.ts +360 -0
- package/lib/src/language/ast.js +57 -0
- package/lib/src/language/parser.d.ts +3 -0
- package/lib/src/language/parser.js +612 -0
- package/lib/src/language/scanner.d.ts +110 -0
- package/lib/src/language/scanner.js +449 -0
- package/lib/src/language/validate.d.ts +13 -0
- package/lib/src/language/validate.js +367 -0
- package/lib/src/links.d.ts +79 -0
- package/lib/src/links.js +583 -0
- package/lib/src/lint.d.ts +10 -0
- package/lib/src/lint.js +223 -0
- package/lib/src/markdown.d.ts +29 -0
- package/lib/src/markdown.js +612 -0
- package/lib/src/media.d.ts +82 -0
- package/lib/src/media.js +650 -0
- package/lib/src/memo.d.ts +57 -0
- package/lib/src/memo.js +93 -0
- package/lib/src/oci.d.ts +178 -0
- package/lib/src/oci.js +380 -0
- package/lib/src/outdated.d.ts +46 -0
- package/lib/src/outdated.js +195 -0
- package/lib/src/pages.d.ts +10 -0
- package/lib/src/pages.js +54 -0
- package/lib/src/paths.d.ts +39 -0
- package/lib/src/paths.js +101 -0
- package/lib/src/planner.d.ts +297 -0
- package/lib/src/planner.js +410 -0
- package/lib/src/plugins/cache.d.ts +96 -0
- package/lib/src/plugins/cache.js +325 -0
- package/lib/src/plugins/exec.d.ts +51 -0
- package/lib/src/plugins/exec.js +144 -0
- package/lib/src/plugins/host.d.ts +75 -0
- package/lib/src/plugins/host.js +277 -0
- package/lib/src/plugins/wasm.d.ts +23 -0
- package/lib/src/plugins/wasm.js +249 -0
- package/lib/src/profile.d.ts +42 -0
- package/lib/src/profile.js +68 -0
- package/lib/src/ref.d.ts +40 -0
- package/lib/src/ref.js +79 -0
- package/lib/src/registry-auth.d.ts +32 -0
- package/lib/src/registry-auth.js +151 -0
- package/lib/src/registry-cache.d.ts +71 -0
- package/lib/src/registry-cache.js +333 -0
- package/lib/src/registry-ops.d.ts +51 -0
- package/lib/src/registry-ops.js +248 -0
- package/lib/src/registry.d.ts +115 -0
- package/lib/src/registry.js +524 -0
- package/lib/src/render.d.ts +134 -0
- package/lib/src/render.js +576 -0
- package/lib/src/resources/archive.d.ts +11 -0
- package/lib/src/resources/archive.js +306 -0
- package/lib/src/resources/bundle-data.d.ts +16 -0
- package/lib/src/resources/bundle-data.js +50 -0
- package/lib/src/resources/convert.d.ts +12 -0
- package/lib/src/resources/convert.js +63 -0
- package/lib/src/resources/documents.d.ts +35 -0
- package/lib/src/resources/documents.js +122 -0
- package/lib/src/resources/git.d.ts +103 -0
- package/lib/src/resources/git.js +720 -0
- package/lib/src/resources/https.d.ts +74 -0
- package/lib/src/resources/https.js +413 -0
- package/lib/src/resources/ignore.d.ts +33 -0
- package/lib/src/resources/ignore.js +119 -0
- package/lib/src/resources/local.d.ts +64 -0
- package/lib/src/resources/local.js +248 -0
- package/lib/src/resources/lockfile.d.ts +52 -0
- package/lib/src/resources/lockfile.js +172 -0
- package/lib/src/resources/netpolicy.d.ts +6 -0
- package/lib/src/resources/netpolicy.js +82 -0
- package/lib/src/resources/network.d.ts +70 -0
- package/lib/src/resources/network.js +304 -0
- package/lib/src/resources/types.d.ts +69 -0
- package/lib/src/resources/types.js +13 -0
- package/lib/src/resources/vendor.d.ts +94 -0
- package/lib/src/resources/vendor.js +296 -0
- package/lib/src/resources/wbn-reader.d.ts +44 -0
- package/lib/src/resources/wbn-reader.js +302 -0
- package/lib/src/schema.d.ts +25 -0
- package/lib/src/schema.js +169 -0
- package/lib/src/secrets.d.ts +21 -0
- package/lib/src/secrets.js +103 -0
- package/lib/src/serve-rules.d.ts +29 -0
- package/lib/src/serve-rules.js +123 -0
- package/lib/src/server.d.ts +45 -0
- package/lib/src/server.js +246 -0
- package/lib/src/servers.d.ts +85 -0
- package/lib/src/servers.js +225 -0
- package/lib/src/site.d.ts +60 -0
- package/lib/src/site.js +169 -0
- package/lib/src/store.d.ts +151 -0
- package/lib/src/store.js +596 -0
- package/lib/src/tree.d.ts +50 -0
- package/lib/src/tree.js +134 -0
- package/lib/src/values.d.ts +7 -0
- package/lib/src/values.js +37 -0
- package/lib/src/vendor.d.ts +19 -0
- package/lib/src/vendor.js +145 -0
- package/lib/src/watch.d.ts +44 -0
- package/lib/src/watch.js +137 -0
- package/lib/src/wbn.d.ts +26 -0
- package/lib/src/wbn.js +241 -0
- package/lib/src/yaml.d.ts +34 -0
- package/lib/src/yaml.js +562 -0
- package/package.json +59 -4
package/lib/src/site.js
ADDED
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
// Site files: sitemap.xml, an Atom feed, _redirects and _headers (SITEMAP, FEED,
|
|
2
|
+
// REDIRECT, HEADER; docs/LANGUAGE.md "Site files"). Ported as rust/src/site.rs:
|
|
3
|
+
// both must produce the same bytes and messages.
|
|
4
|
+
import { SitefileError } from './errors.js';
|
|
5
|
+
/** ASCII whitespace, other control characters, and DEL. */
|
|
6
|
+
const SPACE_OR_CONTROL = /[\u0000- \u007f]/;
|
|
7
|
+
/** Control characters other than tab. */
|
|
8
|
+
const CONTROL = /[\u0000-\u0008\u000a-\u001f\u007f]/;
|
|
9
|
+
/** An RFC 9110 token (header names). */
|
|
10
|
+
const TOKEN = /^[!#$%&'*+\-.^_`|~0-9A-Za-z]+$/;
|
|
11
|
+
/**
|
|
12
|
+
* Check a SITEMAP/FEED `BASE`: an absolute http(s) URL with a host and no credentials,
|
|
13
|
+
* query, fragment, whitespace or control characters. Returns it without trailing slashes.
|
|
14
|
+
*/
|
|
15
|
+
export function checkBaseUrl(raw, what, span) {
|
|
16
|
+
const m = /^https?:\/\/([^/]*)/i.exec(raw);
|
|
17
|
+
if (!m || m[1] === '' || m[1].includes('@') || /[\u0000- \u007f?#]/.test(raw)) {
|
|
18
|
+
throw new SitefileError('E_VALIDATION', `${what} '${raw}' must be an absolute http(s) URL such as https://example.com (no credentials, query or fragment)`, span);
|
|
19
|
+
}
|
|
20
|
+
return raw.replace(/\/+$/, '');
|
|
21
|
+
}
|
|
22
|
+
/** `<base><path>` with each segment percent-encoded; `…/index.html` becomes its directory URL `…/`. */
|
|
23
|
+
export function pageUrl(base, path) {
|
|
24
|
+
const p = path.endsWith('/index.html') ? path.slice(0, -'index.html'.length) : path;
|
|
25
|
+
return base + p.split('/').map(encodeURIComponent).join('/');
|
|
26
|
+
}
|
|
27
|
+
/** Escape text for XML content and attribute values; characters XML 1.0 forbids become U+FFFD. */
|
|
28
|
+
export function xmlEscape(s) {
|
|
29
|
+
return s.replace(/[&<>"'\u0000-\u0008\u000b\u000c\u000e-\u001f]/g, (c) => c === '&' ? '&' : c === '<' ? '<' : c === '>' ? '>' : c === '"' ? '"' : c === "'" ? ''' : '�');
|
|
30
|
+
}
|
|
31
|
+
function utf8Compare(a, b) {
|
|
32
|
+
return Buffer.compare(Buffer.from(a, 'utf8'), Buffer.from(b, 'utf8'));
|
|
33
|
+
}
|
|
34
|
+
/** sitemaps.org XML for every `.html` file in the tree except `/404.html`, sorted by path. */
|
|
35
|
+
export function sitemapXml(tree, base) {
|
|
36
|
+
const paths = tree
|
|
37
|
+
.entries()
|
|
38
|
+
.map(([p]) => p)
|
|
39
|
+
.filter((p) => p.endsWith('.html') && p !== '/404.html')
|
|
40
|
+
.sort(utf8Compare);
|
|
41
|
+
let out = '<?xml version="1.0" encoding="UTF-8"?>\n<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">\n';
|
|
42
|
+
for (const p of paths)
|
|
43
|
+
out += ` <url><loc>${xmlEscape(pageUrl(base, p))}</loc></url>\n`;
|
|
44
|
+
return out + '</urlset>\n';
|
|
45
|
+
}
|
|
46
|
+
function daysFromCivil(y, m, d) {
|
|
47
|
+
const yy = m <= 2 ? y - 1 : y;
|
|
48
|
+
const era = Math.floor(yy / 400);
|
|
49
|
+
const yoe = yy - era * 400;
|
|
50
|
+
const doy = Math.floor((153 * (m + (m > 2 ? -3 : 9)) + 2) / 5) + d - 1;
|
|
51
|
+
const doe = yoe * 365 + Math.floor(yoe / 4) - Math.floor(yoe / 100) + doy;
|
|
52
|
+
return era * 146097 + doe - 719468;
|
|
53
|
+
}
|
|
54
|
+
function daysInMonth(y, m) {
|
|
55
|
+
if (m === 2)
|
|
56
|
+
return (y % 4 === 0 && y % 100 !== 0) || y % 400 === 0 ? 29 : 28;
|
|
57
|
+
return [4, 6, 9, 11].includes(m) ? 30 : 31;
|
|
58
|
+
}
|
|
59
|
+
/** `YYYY-MM-DD` (midnight UTC) or an RFC 3339 date-time; undefined when it is neither. */
|
|
60
|
+
export function parseFeedDate(s) {
|
|
61
|
+
const m = /^(\d{4})-(\d{2})-(\d{2})(?:[Tt ](\d{2}):(\d{2})(?::(\d{2})(\.\d+)?)?([Zz]|[+-]\d{2}:\d{2}))?$/.exec(s);
|
|
62
|
+
if (!m)
|
|
63
|
+
return undefined;
|
|
64
|
+
const [y, mo, d] = [Number(m[1]), Number(m[2]), Number(m[3])];
|
|
65
|
+
if (mo < 1 || mo > 12 || d < 1 || d > daysInMonth(y, mo))
|
|
66
|
+
return undefined;
|
|
67
|
+
const date = `${m[1]}-${m[2]}-${m[3]}`;
|
|
68
|
+
if (m[4] === undefined)
|
|
69
|
+
return { text: `${date}T00:00:00Z`, seconds: daysFromCivil(y, mo, d) * 86400, fraction: '000000000' };
|
|
70
|
+
const [h, mi, sec] = [Number(m[4]), Number(m[5]), Number(m[6] ?? '0')];
|
|
71
|
+
if (h > 23 || mi > 59 || sec > 59)
|
|
72
|
+
return undefined;
|
|
73
|
+
const zone = m[8].toUpperCase();
|
|
74
|
+
let offset = 0;
|
|
75
|
+
if (zone !== 'Z') {
|
|
76
|
+
const [oh, om] = [Number(zone.slice(1, 3)), Number(zone.slice(4, 6))];
|
|
77
|
+
if (oh > 23 || om > 59)
|
|
78
|
+
return undefined;
|
|
79
|
+
offset = (zone[0] === '-' ? -1 : 1) * (oh * 3600 + om * 60);
|
|
80
|
+
}
|
|
81
|
+
const frac = m[7] ?? '';
|
|
82
|
+
const text = `${date}T${m[4]}:${m[5]}:${m[6] ?? '00'}${frac}${zone}`;
|
|
83
|
+
const seconds = daysFromCivil(y, mo, d) * 86400 + h * 3600 + mi * 60 + sec - offset;
|
|
84
|
+
return { text, seconds, fraction: (frac.slice(1) + '000000000').slice(0, 9) };
|
|
85
|
+
}
|
|
86
|
+
function newer(a, b) {
|
|
87
|
+
return a.seconds > b.seconds || (a.seconds === b.seconds && a.fraction > b.fraction);
|
|
88
|
+
}
|
|
89
|
+
/** Atom 1.0. The feed's id is its own URL; each entry's id is its link. */
|
|
90
|
+
export function atomXml(feed) {
|
|
91
|
+
let updated;
|
|
92
|
+
for (const e of feed.entries)
|
|
93
|
+
if (!updated || newer(e.date, updated))
|
|
94
|
+
updated = e.date;
|
|
95
|
+
const x = xmlEscape;
|
|
96
|
+
let out = '<?xml version="1.0" encoding="utf-8"?>\n<feed xmlns="http://www.w3.org/2005/Atom">\n';
|
|
97
|
+
out += ` <title>${x(feed.title)}</title>\n`;
|
|
98
|
+
out += ` <link href="${x(feed.siteUrl)}"/>\n`;
|
|
99
|
+
out += ` <link rel="self" href="${x(feed.selfUrl)}"/>\n`;
|
|
100
|
+
out += ` <id>${x(feed.selfUrl)}</id>\n`;
|
|
101
|
+
out += ` <updated>${updated?.text ?? '1970-01-01T00:00:00Z'}</updated>\n`;
|
|
102
|
+
for (const e of feed.entries) {
|
|
103
|
+
out += ' <entry>\n';
|
|
104
|
+
out += ` <title>${x(e.title)}</title>\n`;
|
|
105
|
+
out += ` <link href="${x(e.url)}"/>\n`;
|
|
106
|
+
out += ` <id>${x(e.url)}</id>\n`;
|
|
107
|
+
out += ` <updated>${e.date.text}</updated>\n`;
|
|
108
|
+
if (e.author !== undefined)
|
|
109
|
+
out += ` <author><name>${x(e.author)}</name></author>\n`;
|
|
110
|
+
if (e.summary !== undefined)
|
|
111
|
+
out += ` <summary>${x(e.summary)}</summary>\n`;
|
|
112
|
+
if (e.content !== undefined)
|
|
113
|
+
out += ` <content type="html">${x(e.content)}</content>\n`;
|
|
114
|
+
out += ' </entry>\n';
|
|
115
|
+
}
|
|
116
|
+
return out + '</feed>\n';
|
|
117
|
+
}
|
|
118
|
+
/** Check a REDIRECT source (`from`) or HEADER pattern: an absolute path with no spaces or control characters. */
|
|
119
|
+
export function checkSitePath(raw, what, span) {
|
|
120
|
+
if (SPACE_OR_CONTROL.test(raw))
|
|
121
|
+
throw new SitefileError('E_VALIDATION', `${what} must not contain spaces or control characters`, span);
|
|
122
|
+
if (!raw.startsWith('/'))
|
|
123
|
+
throw new SitefileError('E_VALIDATION', `${what} '${raw}' must be an absolute path starting with '/'`, span);
|
|
124
|
+
return raw;
|
|
125
|
+
}
|
|
126
|
+
/** Check a REDIRECT target: an absolute path or an http(s) URL. */
|
|
127
|
+
export function checkRedirectTarget(raw, span) {
|
|
128
|
+
if (SPACE_OR_CONTROL.test(raw))
|
|
129
|
+
throw new SitefileError('E_VALIDATION', 'REDIRECT target must not contain spaces or control characters', span);
|
|
130
|
+
if (!raw.startsWith('/') && !/^https?:\/\/[^/]/i.test(raw)) {
|
|
131
|
+
throw new SitefileError('E_VALIDATION', `REDIRECT target '${raw}' must be an absolute path or an http(s) URL`, span);
|
|
132
|
+
}
|
|
133
|
+
return raw;
|
|
134
|
+
}
|
|
135
|
+
export function checkHeaderName(raw, span) {
|
|
136
|
+
if (SPACE_OR_CONTROL.test(raw))
|
|
137
|
+
throw new SitefileError('E_VALIDATION', 'HEADER name must not contain spaces or control characters', span);
|
|
138
|
+
if (!TOKEN.test(raw)) {
|
|
139
|
+
throw new SitefileError('E_VALIDATION', `HEADER name '${raw}' is not a valid header name (letters, digits and !#$%&'*+-.^_\`|~)`, span);
|
|
140
|
+
}
|
|
141
|
+
return raw;
|
|
142
|
+
}
|
|
143
|
+
/** The header value: trimmed of spaces and tabs; non-empty, no control characters other than tab. */
|
|
144
|
+
export function checkHeaderValue(raw, name, span) {
|
|
145
|
+
if (CONTROL.test(raw))
|
|
146
|
+
throw new SitefileError('E_VALIDATION', `HEADER ${name}: the value must not contain control characters (CR, LF, …)`, span);
|
|
147
|
+
const v = raw.replace(/^[ \t]+|[ \t]+$/g, '');
|
|
148
|
+
if (v === '')
|
|
149
|
+
throw new SitefileError('E_VALIDATION', `HEADER ${name}: the value is empty`, span);
|
|
150
|
+
return v;
|
|
151
|
+
}
|
|
152
|
+
/** `/_redirects` in the Netlify / Cloudflare Pages format: `from to status`, one per line, in source order. */
|
|
153
|
+
export function redirectsFile(rules) {
|
|
154
|
+
return rules.map((r) => `${r.from} ${r.to} ${r.status}\n`).join('');
|
|
155
|
+
}
|
|
156
|
+
/** `/_headers`: one block per path pattern (in order of first use), its headers indented in source order. */
|
|
157
|
+
export function headersFile(rules) {
|
|
158
|
+
const blocks = new Map();
|
|
159
|
+
for (const r of rules) {
|
|
160
|
+
const b = blocks.get(r.pattern) ?? [];
|
|
161
|
+
b.push(` ${r.name}: ${r.value}\n`);
|
|
162
|
+
blocks.set(r.pattern, b);
|
|
163
|
+
}
|
|
164
|
+
let out = '';
|
|
165
|
+
for (const [pattern, lines] of blocks)
|
|
166
|
+
out += `${pattern}\n${lines.join('')}`;
|
|
167
|
+
return out;
|
|
168
|
+
}
|
|
169
|
+
//# sourceMappingURL=site.js.map
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import type { Readable } from 'node:stream';
|
|
2
|
+
import { type Referrer, type ReferrerDescriptor } from './attest.js';
|
|
3
|
+
import { type OciOptions, type ParsedConfig, type ParsedManifest } from './oci.js';
|
|
4
|
+
import { type ImageRef } from './ref.js';
|
|
5
|
+
import type { Tree } from './tree.js';
|
|
6
|
+
/**
|
|
7
|
+
* The local image store IS an OCI image layout (image-spec v1.1) at $SITEFILE_HOME (default ~/.sitefile):
|
|
8
|
+
*
|
|
9
|
+
* oci-layout {"imageLayoutVersion":"1.0.0"}
|
|
10
|
+
* index.json image index. Each entry is a manifest descriptor; tags are entries annotated
|
|
11
|
+
* org.opencontainers.image.ref.name = "name:tag". An image with no tag is a
|
|
12
|
+
* "dangling" entry without that annotation. dev.sitefile.created records when
|
|
13
|
+
* the image was first stored (bookkeeping only; no digest depends on it).
|
|
14
|
+
* blobs/sha256/<hex> manifest, config and layer blobs (identical layers share a blob)
|
|
15
|
+
* referrers/sha256/<hex> attestations of image <hex> (`build -t --provenance/--sbom`): an OCI image
|
|
16
|
+
* index of artifact manifests whose subject is that image (their blobs are in blobs/)
|
|
17
|
+
* servers/ site server state and logs (see servers.ts)
|
|
18
|
+
* lock advisory lock for mutations
|
|
19
|
+
*
|
|
20
|
+
* IMAGE ID = the manifest digest. All writes are temp file + rename, mutations hold the lock, and every
|
|
21
|
+
* blob is digest-verified when read (corruption is E_STORE).
|
|
22
|
+
*/
|
|
23
|
+
export interface ImageSummary {
|
|
24
|
+
/** Full `sha256:<hex>` image ID (the manifest digest). */
|
|
25
|
+
readonly id: string;
|
|
26
|
+
readonly tags: readonly string[];
|
|
27
|
+
/** When the image was first stored. */
|
|
28
|
+
readonly created: string;
|
|
29
|
+
readonly files: number;
|
|
30
|
+
/** Total bytes of the site's files (uncompressed). */
|
|
31
|
+
readonly size: number;
|
|
32
|
+
}
|
|
33
|
+
export interface ImageDetails extends ImageSummary {
|
|
34
|
+
readonly manifest: ParsedManifest;
|
|
35
|
+
readonly config: ParsedConfig;
|
|
36
|
+
readonly root: string;
|
|
37
|
+
/** Compressed layer size in bytes. */
|
|
38
|
+
readonly layerSize: number;
|
|
39
|
+
}
|
|
40
|
+
export declare function resolveStoreHome(env?: NodeJS.ProcessEnv): string;
|
|
41
|
+
export declare function shortId(id: string): string;
|
|
42
|
+
export declare class Store {
|
|
43
|
+
readonly home: string;
|
|
44
|
+
private constructor();
|
|
45
|
+
/** The store at `home` if one exists there (nothing is created). */
|
|
46
|
+
static openExisting(home?: string): Promise<Store | undefined>;
|
|
47
|
+
static open(home?: string): Promise<Store>;
|
|
48
|
+
private blobFile;
|
|
49
|
+
/** Run `fn` holding the store lock (an exclusive lock file; stale locks are broken). */
|
|
50
|
+
withLock<T>(fn: () => Promise<T>): Promise<T>;
|
|
51
|
+
private lockIsStale;
|
|
52
|
+
private writeAtomic;
|
|
53
|
+
private readIndex;
|
|
54
|
+
/** Normalize (one dangling entry per untagged image, none for tagged ones), sort, write. */
|
|
55
|
+
private writeIndex;
|
|
56
|
+
/** `name:tag` → image ID. */
|
|
57
|
+
refs(): Promise<Record<string, string>>;
|
|
58
|
+
/** Read a blob and verify its digest (and size when given). */
|
|
59
|
+
readBlob(digest: string, size?: number): Promise<Uint8Array>;
|
|
60
|
+
private putBlob;
|
|
61
|
+
/**
|
|
62
|
+
* Mark a blob as just used (its mtime is the recency the size limit goes by, see cache-limit.ts;
|
|
63
|
+
* atime is often disabled). Never fails.
|
|
64
|
+
*/
|
|
65
|
+
touchBlob(digest: string): Promise<void>;
|
|
66
|
+
/** True when the blob exists with the given size (content is verified when it was written). */
|
|
67
|
+
hasBlob(digest: string, size?: number): Promise<boolean>;
|
|
68
|
+
/** Stream a stored blob (for upload); write-time verification means no re-hash here. */
|
|
69
|
+
blobStream(digest: string): Readable;
|
|
70
|
+
/**
|
|
71
|
+
* Store a blob from a stream, verifying its size and sha256 while it is written (to a temp file
|
|
72
|
+
* that is renamed into place only when both match). `maxBytes` bounds what is accepted.
|
|
73
|
+
*/
|
|
74
|
+
importBlob(digest: string, size: number, source: AsyncIterable<Uint8Array>, maxBytes?: number): Promise<void>;
|
|
75
|
+
/** Store a small blob (manifest, config, index) given its bytes; the digest is computed. */
|
|
76
|
+
putSmallBlob(bytes: Uint8Array): Promise<string>;
|
|
77
|
+
/**
|
|
78
|
+
* Register a pulled image manifest (all its blobs must already be stored): it becomes an index
|
|
79
|
+
* entry, optionally tagged with `key` (replacing that tag's previous target).
|
|
80
|
+
*/
|
|
81
|
+
addManifest(manifestBytes: Uint8Array, tagRef?: ImageRef, now?: Date): Promise<string>;
|
|
82
|
+
/** Whether an image with this manifest digest is in the index. */
|
|
83
|
+
hasImage(id: string): Promise<boolean>;
|
|
84
|
+
/** Store a tree as an OCI image (idempotent: identical content and options give the same ID). Untagged. */
|
|
85
|
+
addImage(tree: Tree, options?: OciOptions, now?: Date): Promise<{
|
|
86
|
+
id: string;
|
|
87
|
+
created: boolean;
|
|
88
|
+
}>;
|
|
89
|
+
/** Manifest and config of an image, digest-verified (not its layer). */
|
|
90
|
+
details(id: string): Promise<ImageDetails>;
|
|
91
|
+
/**
|
|
92
|
+
* Load an image's files (under its root, or under `o.root`), verifying manifest, config, layer digest
|
|
93
|
+
* and diff_id. `o.origin` is what the files' origins and error messages name (default `image:<short id>`).
|
|
94
|
+
*/
|
|
95
|
+
loadTree(id: string, o?: {
|
|
96
|
+
readonly origin?: string;
|
|
97
|
+
readonly root?: string;
|
|
98
|
+
}): Promise<Tree>;
|
|
99
|
+
/**
|
|
100
|
+
* The image as a standalone OCI layout Tree (for `save`), optionally annotated with a tag.
|
|
101
|
+
* Includes every layer, so an image built on a BASE is self-contained.
|
|
102
|
+
*/
|
|
103
|
+
layoutOf(id: string, refName?: string): Promise<Tree>;
|
|
104
|
+
private referrersFile;
|
|
105
|
+
/** Descriptors of the attestations stored for image `id` (none: empty). */
|
|
106
|
+
referrerDescriptors(id: string): Promise<ReferrerDescriptor[]>;
|
|
107
|
+
/** The attestations stored for image `id`, with their blobs (digest-verified). */
|
|
108
|
+
referrers(id: string): Promise<Referrer[]>;
|
|
109
|
+
/**
|
|
110
|
+
* Attach attestations to stored image `id`: their blobs are written, and each replaces a stored
|
|
111
|
+
* attestation with the same predicate type (others are kept).
|
|
112
|
+
*/
|
|
113
|
+
putReferrers(id: string, referrers: readonly Referrer[]): Promise<void>;
|
|
114
|
+
/** Blob hexes of the attestations of `id` (manifests, configs, layers); unreadable ones count as none. */
|
|
115
|
+
private referrerBlobHexes;
|
|
116
|
+
/** Every stored image, newest first. */
|
|
117
|
+
list(): Promise<ImageSummary[]>;
|
|
118
|
+
private idsWithPrefix;
|
|
119
|
+
/** Resolve a reference or (short) image ID to a full image ID. */
|
|
120
|
+
resolve(input: string): Promise<string>;
|
|
121
|
+
/** Point `name:tag` at an image (replacing any previous target). Returns the `name:tag` key. */
|
|
122
|
+
tag(id: string, ref: ImageRef): Promise<string>;
|
|
123
|
+
/**
|
|
124
|
+
* `rmi`: remove a tag, or an image by ID. The image leaves the index when no tag references it
|
|
125
|
+
* (blobs are reclaimed by `prune`). Removing by ID while several tags point at it needs `force`.
|
|
126
|
+
*/
|
|
127
|
+
removeImage(input: string, force?: boolean): Promise<{
|
|
128
|
+
untagged: string[];
|
|
129
|
+
deleted: string | undefined;
|
|
130
|
+
}>;
|
|
131
|
+
/**
|
|
132
|
+
* What the size limit may evict: `live` holds the blob hexes of tagged images (never evicted),
|
|
133
|
+
* `untagged` each untagged image with the blobs it uses. An unreadable tagged manifest throws
|
|
134
|
+
* (its blobs are unknown, so nothing may be evicted).
|
|
135
|
+
*/
|
|
136
|
+
gcView(): Promise<{
|
|
137
|
+
live: Set<string>;
|
|
138
|
+
untagged: Array<{
|
|
139
|
+
id: string;
|
|
140
|
+
blobs: string[];
|
|
141
|
+
}>;
|
|
142
|
+
}>;
|
|
143
|
+
/** Remove an untagged image from the index, with its attestation list (its blobs stay). The caller holds the lock. */
|
|
144
|
+
dropUntaggedLocked(id: string): Promise<void>;
|
|
145
|
+
/** Drop untagged images from the index, then delete every blob no remaining image uses. */
|
|
146
|
+
prune(): Promise<{
|
|
147
|
+
manifests: number;
|
|
148
|
+
blobs: number;
|
|
149
|
+
bytes: number;
|
|
150
|
+
}>;
|
|
151
|
+
}
|