@bluefields/cli 0.2.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/LICENSE +661 -0
- package/README.md +181 -0
- package/dist/anchor.d.ts +24 -0
- package/dist/anchor.js +48 -0
- package/dist/anchor.js.map +1 -0
- package/dist/attestation.d.ts +50 -0
- package/dist/attestation.js +90 -0
- package/dist/attestation.js.map +1 -0
- package/dist/bluefield.d.ts +180 -0
- package/dist/bluefield.js +382 -0
- package/dist/bluefield.js.map +1 -0
- package/dist/cli.d.ts +19 -0
- package/dist/cli.js +310 -0
- package/dist/cli.js.map +1 -0
- package/dist/constants.d.ts +28 -0
- package/dist/constants.js +30 -0
- package/dist/constants.js.map +1 -0
- package/dist/fs-storage.d.ts +20 -0
- package/dist/fs-storage.js +60 -0
- package/dist/fs-storage.js.map +1 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.js +20 -0
- package/dist/index.js.map +1 -0
- package/dist/keystore.d.ts +40 -0
- package/dist/keystore.js +77 -0
- package/dist/keystore.js.map +1 -0
- package/dist/mcp-server.d.ts +40 -0
- package/dist/mcp-server.js +252 -0
- package/dist/mcp-server.js.map +1 -0
- package/dist/paths.d.ts +52 -0
- package/dist/paths.js +77 -0
- package/dist/paths.js.map +1 -0
- package/dist/quiet.d.ts +11 -0
- package/dist/quiet.js +14 -0
- package/dist/quiet.js.map +1 -0
- package/dist/store.d.ts +46 -0
- package/dist/store.js +233 -0
- package/dist/store.js.map +1 -0
- package/package.json +63 -0
package/dist/cli.js
ADDED
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
3
|
+
/**
|
|
4
|
+
* `bf` — the Bluefield command line. A thin, dependency-free wrapper over the
|
|
5
|
+
* `@bluefields/cli` library. No arg-parsing dependency (a hand-rolled parser
|
|
6
|
+
* covers the small surface); no telemetry; no network beyond the fetch itself.
|
|
7
|
+
*
|
|
8
|
+
* Kept separate from `index.ts` so importing the library has no side effects
|
|
9
|
+
* and the binary runs reliably whether invoked as `node dist/cli.js` or via the
|
|
10
|
+
* `bf` bin symlink.
|
|
11
|
+
*/
|
|
12
|
+
import './quiet.js'; // MUST be first — silences engine logs before fetcher loads
|
|
13
|
+
import { readFileSync } from 'node:fs';
|
|
14
|
+
import process from 'node:process';
|
|
15
|
+
import { openBluefield } from './bluefield.js';
|
|
16
|
+
import { PROJECT_NAME, STANDARD_FULL } from './constants.js';
|
|
17
|
+
import { runMcpServer } from './mcp-server.js';
|
|
18
|
+
import { resolveStoreRoot, storePaths } from './paths.js';
|
|
19
|
+
const VERSION = '0.1.0';
|
|
20
|
+
/** Minimal argv parser: `--flag`, `--flag value`, `--flag=value`, positionals. */
|
|
21
|
+
export function parse(argv) {
|
|
22
|
+
const positionals = [];
|
|
23
|
+
const flags = new Map();
|
|
24
|
+
for (let i = 0; i < argv.length; i++) {
|
|
25
|
+
const a = argv[i];
|
|
26
|
+
if (a.startsWith('--')) {
|
|
27
|
+
const eq = a.indexOf('=');
|
|
28
|
+
if (eq !== -1) {
|
|
29
|
+
flags.set(a.slice(2, eq), a.slice(eq + 1));
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
const key = a.slice(2);
|
|
33
|
+
const next = argv[i + 1];
|
|
34
|
+
if (next !== undefined && !next.startsWith('--')) {
|
|
35
|
+
flags.set(key, next);
|
|
36
|
+
i += 1;
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
flags.set(key, true);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
positionals.push(a);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return { positionals, flags };
|
|
48
|
+
}
|
|
49
|
+
const out = (s) => process.stdout.write(`${s}\n`);
|
|
50
|
+
const err = (s) => process.stderr.write(`${s}\n`);
|
|
51
|
+
const json = (v) => out(JSON.stringify(v, null, 2));
|
|
52
|
+
function num(v, dflt) {
|
|
53
|
+
if (typeof v !== 'string')
|
|
54
|
+
return dflt;
|
|
55
|
+
const n = Number(v);
|
|
56
|
+
return Number.isFinite(n) ? n : dflt;
|
|
57
|
+
}
|
|
58
|
+
const HELP = `${PROJECT_NAME} — git for web data. Local-first, signed, offline.
|
|
59
|
+
|
|
60
|
+
Snapshots conform to the ${STANDARD_FULL}.
|
|
61
|
+
|
|
62
|
+
USAGE
|
|
63
|
+
bf scrape <url> [options] Capture a URL into the local store (signed)
|
|
64
|
+
bf log [url] [--limit N] Show snapshot history (all, or one URL)
|
|
65
|
+
bf diff <a> [b] Diff two snapshots (or last two of a URL)
|
|
66
|
+
bf watch <url> [options] Poll a URL and report changes
|
|
67
|
+
bf verify <ref> Verify a snapshot's content hash + signature
|
|
68
|
+
bf export <ref> [--out DIR] Export raw content + portable proof bundle
|
|
69
|
+
bf key Show this machine's public signing identity
|
|
70
|
+
bf where Print the resolved store + keys locations
|
|
71
|
+
bf mcp Run the local MCP server (stdio)
|
|
72
|
+
bf help | --version
|
|
73
|
+
|
|
74
|
+
A <ref> is a snapshot-id prefix (e.g. 3f9a2b) or a URL (its latest snapshot).
|
|
75
|
+
|
|
76
|
+
SCRAPE OPTIONS
|
|
77
|
+
--no-sign Do not sign the manifest
|
|
78
|
+
--extract Run structured extraction (needs ANTHROPIC_API_KEY)
|
|
79
|
+
--schema <file.json> JSON schema for structured extraction
|
|
80
|
+
--intent <text> One-sentence extraction hint
|
|
81
|
+
--anchor Best-effort transparency anchoring (no-op if absent)
|
|
82
|
+
|
|
83
|
+
DIFF OPTIONS --structured Diff extracted structured data (JSON Patch)
|
|
84
|
+
WATCH OPTIONS --interval <sec> (default 300) --times <n>
|
|
85
|
+
VERIFY OPTIONS --trust-embedded Trust the bundle's embedded key (TOFU)
|
|
86
|
+
GLOBAL --json Machine-readable output
|
|
87
|
+
|
|
88
|
+
STORAGE \$BF_HOME overrides the store; else nearest ./.bf; else ~/.bluefield.
|
|
89
|
+
Signing keys always live in ~/.bluefield/keys (0600). No telemetry.
|
|
90
|
+
`;
|
|
91
|
+
export async function main(argv) {
|
|
92
|
+
const [cmd, ...rest] = argv;
|
|
93
|
+
const { positionals, flags } = parse(rest);
|
|
94
|
+
const asJson = flags.has('json');
|
|
95
|
+
if (!cmd || cmd === 'help' || cmd === '--help' || flags.has('help')) {
|
|
96
|
+
out(HELP);
|
|
97
|
+
return 0;
|
|
98
|
+
}
|
|
99
|
+
if (cmd === '--version' || cmd === 'version') {
|
|
100
|
+
out(VERSION);
|
|
101
|
+
return 0;
|
|
102
|
+
}
|
|
103
|
+
if (cmd === 'where') {
|
|
104
|
+
const p = storePaths(resolveStoreRoot());
|
|
105
|
+
if (asJson)
|
|
106
|
+
json({ storeRoot: p.root, objects: p.objects, db: p.db, keys: p.keys });
|
|
107
|
+
else {
|
|
108
|
+
out(`store root : ${p.root}`);
|
|
109
|
+
out(`objects : ${p.objects}`);
|
|
110
|
+
out(`db : ${p.db}`);
|
|
111
|
+
out(`keys : ${p.keys}`);
|
|
112
|
+
}
|
|
113
|
+
return 0;
|
|
114
|
+
}
|
|
115
|
+
if (cmd === 'mcp') {
|
|
116
|
+
await runMcpServer();
|
|
117
|
+
return 0;
|
|
118
|
+
}
|
|
119
|
+
const bf = await openBluefield();
|
|
120
|
+
try {
|
|
121
|
+
switch (cmd) {
|
|
122
|
+
case 'scrape':
|
|
123
|
+
return await cmdScrape(bf, positionals, flags, asJson);
|
|
124
|
+
case 'log':
|
|
125
|
+
return await cmdLog(bf, positionals, flags, asJson);
|
|
126
|
+
case 'diff':
|
|
127
|
+
return await cmdDiff(bf, positionals, flags, asJson);
|
|
128
|
+
case 'watch':
|
|
129
|
+
return await cmdWatch(bf, positionals, flags, asJson);
|
|
130
|
+
case 'verify':
|
|
131
|
+
return await cmdVerify(bf, positionals, flags, asJson);
|
|
132
|
+
case 'export':
|
|
133
|
+
return await cmdExport(bf, positionals, flags, asJson);
|
|
134
|
+
case 'key': {
|
|
135
|
+
const id = bf.publicIdentity();
|
|
136
|
+
if (asJson)
|
|
137
|
+
json(id);
|
|
138
|
+
else {
|
|
139
|
+
out(`keyId: ${id.keyId}`);
|
|
140
|
+
out(`jwk : ${JSON.stringify(id.publicJwk)}`);
|
|
141
|
+
}
|
|
142
|
+
return 0;
|
|
143
|
+
}
|
|
144
|
+
default:
|
|
145
|
+
err(`unknown command: ${cmd}\n`);
|
|
146
|
+
out(HELP);
|
|
147
|
+
return 2;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
finally {
|
|
151
|
+
await bf.close();
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
async function cmdScrape(bf, pos, flags, asJson) {
|
|
155
|
+
const url = pos[0];
|
|
156
|
+
if (!url) {
|
|
157
|
+
err('usage: bf scrape <url> [options]');
|
|
158
|
+
return 2;
|
|
159
|
+
}
|
|
160
|
+
const schemaFlag = flags.get('schema');
|
|
161
|
+
const schema = typeof schemaFlag === 'string' ? JSON.parse(readFileSync(schemaFlag, 'utf8')) : null;
|
|
162
|
+
const intent = flags.get('intent');
|
|
163
|
+
const r = await bf.scrape(url, {
|
|
164
|
+
sign: !flags.has('no-sign'),
|
|
165
|
+
extract: flags.has('extract'),
|
|
166
|
+
schema,
|
|
167
|
+
intent: typeof intent === 'string' ? intent : null,
|
|
168
|
+
anchor: flags.has('anchor'),
|
|
169
|
+
});
|
|
170
|
+
if (asJson) {
|
|
171
|
+
json(r);
|
|
172
|
+
return r.ok ? 0 : 1;
|
|
173
|
+
}
|
|
174
|
+
if (!r.ok) {
|
|
175
|
+
err(`blocked: ${r.reason} (${r.url})`);
|
|
176
|
+
return 1;
|
|
177
|
+
}
|
|
178
|
+
out(`captured ${r.url}`);
|
|
179
|
+
out(` snapshot ${r.snapshotId}`);
|
|
180
|
+
out(` sha256 ${r.contentHash}`);
|
|
181
|
+
out(` signed ${r.signed ? 'yes' : 'no'} changed: ${r.changed ? 'yes' : 'no'}`);
|
|
182
|
+
if (r.extraction)
|
|
183
|
+
out(` extract ${r.extraction.extractionStatus}`);
|
|
184
|
+
if (r.anchor)
|
|
185
|
+
out(` anchor ${r.anchor.anchored ? 'yes' : `no — ${r.anchor.detail}`}`);
|
|
186
|
+
return 0;
|
|
187
|
+
}
|
|
188
|
+
async function cmdLog(bf, pos, flags, asJson) {
|
|
189
|
+
const rows = await bf.log(pos[0] ?? null, { limit: num(flags.get('limit'), 50) });
|
|
190
|
+
if (asJson) {
|
|
191
|
+
json(rows);
|
|
192
|
+
return 0;
|
|
193
|
+
}
|
|
194
|
+
if (rows.length === 0) {
|
|
195
|
+
out('(no snapshots yet)');
|
|
196
|
+
return 0;
|
|
197
|
+
}
|
|
198
|
+
for (const r of rows) {
|
|
199
|
+
out(`${r.snapshotId.slice(0, 8)} ${r.fetchedAt.toISOString()} ${String(r.responseStatus).padEnd(3)} ${r.signed ? '🔏' : ' '} ${r.contentHash.slice(0, 12)} ${r.url}`);
|
|
200
|
+
}
|
|
201
|
+
return 0;
|
|
202
|
+
}
|
|
203
|
+
async function cmdDiff(bf, pos, flags, asJson) {
|
|
204
|
+
const a = pos[0];
|
|
205
|
+
if (!a) {
|
|
206
|
+
err('usage: bf diff <refA> [refB] [--structured]');
|
|
207
|
+
return 2;
|
|
208
|
+
}
|
|
209
|
+
const d = await bf.diff(a, pos[1], { mode: flags.has('structured') ? 'structured' : 'content' });
|
|
210
|
+
if (asJson) {
|
|
211
|
+
json(d);
|
|
212
|
+
return d.identical ? 0 : 1;
|
|
213
|
+
}
|
|
214
|
+
out(`--- ${d.from.snapshotId.slice(0, 8)} ${d.from.fetchedAt.toISOString()}`);
|
|
215
|
+
out(`+++ ${d.to.snapshotId.slice(0, 8)} ${d.to.fetchedAt.toISOString()}`);
|
|
216
|
+
if (d.identical) {
|
|
217
|
+
out('(no changes)');
|
|
218
|
+
return 0;
|
|
219
|
+
}
|
|
220
|
+
out(`(${d.mode}) +${d.added} -${d.removed}`);
|
|
221
|
+
out(d.text);
|
|
222
|
+
return 1;
|
|
223
|
+
}
|
|
224
|
+
async function cmdWatch(bf, pos, flags, asJson) {
|
|
225
|
+
const url = pos[0];
|
|
226
|
+
if (!url) {
|
|
227
|
+
err('usage: bf watch <url> [--interval sec] [--times n]');
|
|
228
|
+
return 2;
|
|
229
|
+
}
|
|
230
|
+
const controller = new AbortController();
|
|
231
|
+
process.on('SIGINT', () => controller.abort());
|
|
232
|
+
const intervalMs = num(flags.get('interval'), 300) * 1000;
|
|
233
|
+
const times = flags.has('times') ? num(flags.get('times'), 1) : Number.POSITIVE_INFINITY;
|
|
234
|
+
if (!asJson)
|
|
235
|
+
out(`watching ${url} every ${intervalMs / 1000}s (Ctrl-C to stop)`);
|
|
236
|
+
await bf.watch(url, {
|
|
237
|
+
intervalMs,
|
|
238
|
+
times,
|
|
239
|
+
signal: controller.signal,
|
|
240
|
+
onTick: (r, i) => {
|
|
241
|
+
if (asJson) {
|
|
242
|
+
json({ iteration: i, ...r });
|
|
243
|
+
}
|
|
244
|
+
else if (r.ok) {
|
|
245
|
+
out(`[${new Date().toISOString()}] #${i} ${r.changed ? 'CHANGED' : 'unchanged'} ${r.contentHash.slice(0, 12)} ${r.snapshotId.slice(0, 8)}`);
|
|
246
|
+
}
|
|
247
|
+
else {
|
|
248
|
+
out(`[${new Date().toISOString()}] #${i} blocked: ${r.reason}`);
|
|
249
|
+
}
|
|
250
|
+
},
|
|
251
|
+
});
|
|
252
|
+
return 0;
|
|
253
|
+
}
|
|
254
|
+
async function cmdVerify(bf, pos, flags, asJson) {
|
|
255
|
+
const ref = pos[0];
|
|
256
|
+
if (!ref) {
|
|
257
|
+
err('usage: bf verify <ref> [--trust-embedded]');
|
|
258
|
+
return 2;
|
|
259
|
+
}
|
|
260
|
+
const v = await bf.verify(ref, { trustEmbedded: flags.has('trust-embedded') });
|
|
261
|
+
if (asJson) {
|
|
262
|
+
json(v);
|
|
263
|
+
return v.ok ? 0 : 1;
|
|
264
|
+
}
|
|
265
|
+
out(`${v.ok ? '✓ VERIFIED' : '✗ FAILED'} ${v.snapshotId?.slice(0, 8) ?? ''}`);
|
|
266
|
+
out(` content hash matches : ${v.contentHashMatches ? 'yes' : 'NO'}`);
|
|
267
|
+
out(` signature valid : ${v.signatureValid ? 'yes' : 'NO'}`);
|
|
268
|
+
out(` keyId : ${v.keyId}`);
|
|
269
|
+
if (!v.ok && v.detail)
|
|
270
|
+
out(` ${v.detail}`);
|
|
271
|
+
return v.ok ? 0 : 1;
|
|
272
|
+
}
|
|
273
|
+
async function cmdExport(bf, pos, flags, asJson) {
|
|
274
|
+
const ref = pos[0];
|
|
275
|
+
if (!ref) {
|
|
276
|
+
err('usage: bf export <ref> [--out dir]');
|
|
277
|
+
return 2;
|
|
278
|
+
}
|
|
279
|
+
const outDir = typeof flags.get('out') === 'string' ? flags.get('out') : '.';
|
|
280
|
+
const e = await bf.export(ref, outDir);
|
|
281
|
+
if (asJson)
|
|
282
|
+
json(e);
|
|
283
|
+
else {
|
|
284
|
+
out(`exported ${e.snapshotId}`);
|
|
285
|
+
out(` ${e.contentFile}`);
|
|
286
|
+
out(` ${e.bundleFile}`);
|
|
287
|
+
}
|
|
288
|
+
return 0;
|
|
289
|
+
}
|
|
290
|
+
/** Only auto-run when invoked as the entry point (not when imported by a test). */
|
|
291
|
+
function isMainEntry() {
|
|
292
|
+
const entry = process.argv[1];
|
|
293
|
+
if (!entry)
|
|
294
|
+
return false;
|
|
295
|
+
try {
|
|
296
|
+
return import.meta.url === new URL(`file://${entry}`).href || entry.endsWith('cli.js');
|
|
297
|
+
}
|
|
298
|
+
catch {
|
|
299
|
+
return false;
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
if (isMainEntry()) {
|
|
303
|
+
main(process.argv.slice(2))
|
|
304
|
+
.then((code) => process.exit(code))
|
|
305
|
+
.catch((e) => {
|
|
306
|
+
err(`error: ${e instanceof Error ? e.message : String(e)}`);
|
|
307
|
+
process.exit(1);
|
|
308
|
+
});
|
|
309
|
+
}
|
|
310
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Single source of truth for user-facing project + standard names.
|
|
3
|
+
*
|
|
4
|
+
* A rename is one edit HERE and nowhere else. Everything the CLI prints, and
|
|
5
|
+
* every default directory name,
|
|
6
|
+
* derives from these constants. Do NOT hard-code "Bluefield" / "BPM" anywhere
|
|
7
|
+
* else in the package — import from this module.
|
|
8
|
+
*/
|
|
9
|
+
/** Product name (the CLI, the library, the local store). */
|
|
10
|
+
export declare const PROJECT_NAME: "Bluefield";
|
|
11
|
+
/** Lowercase slug used for directories, env-var prefixes, and the bin name. */
|
|
12
|
+
export declare const PROJECT_SLUG: "bluefield";
|
|
13
|
+
/** The provenance standard the signed manifests conform to. */
|
|
14
|
+
export declare const STANDARD_NAME: "Bluefield Provenance Manifest";
|
|
15
|
+
/** Short abbreviation for the standard. */
|
|
16
|
+
export declare const STANDARD_ABBR: "BPM";
|
|
17
|
+
/** Convenience: "Bluefield Provenance Manifest / BPM". */
|
|
18
|
+
export declare const STANDARD_FULL: "Bluefield Provenance Manifest / BPM";
|
|
19
|
+
/** Default global home directory (under the user's home). */
|
|
20
|
+
export declare const HOME_DIR_NAME: ".bluefield";
|
|
21
|
+
/** Repo-local store directory name (git-style, walked up from cwd). */
|
|
22
|
+
export declare const LOCAL_DIR_NAME: ".bf";
|
|
23
|
+
/** Env var that overrides the store root outright. */
|
|
24
|
+
export declare const HOME_ENV: "BF_HOME";
|
|
25
|
+
/** Public repository URL. Referenced by the User-Agent below and by docs. */
|
|
26
|
+
export declare const REPO_URL: "https://github.com/danielvhofmann/bluefield";
|
|
27
|
+
/** User-Agent presented to origins for local captures. */
|
|
28
|
+
export declare const USER_AGENT: "Bluefield-CLI/0.1 (+local; https://github.com/danielvhofmann/bluefield)";
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
2
|
+
/**
|
|
3
|
+
* Single source of truth for user-facing project + standard names.
|
|
4
|
+
*
|
|
5
|
+
* A rename is one edit HERE and nowhere else. Everything the CLI prints, and
|
|
6
|
+
* every default directory name,
|
|
7
|
+
* derives from these constants. Do NOT hard-code "Bluefield" / "BPM" anywhere
|
|
8
|
+
* else in the package — import from this module.
|
|
9
|
+
*/
|
|
10
|
+
/** Product name (the CLI, the library, the local store). */
|
|
11
|
+
export const PROJECT_NAME = 'Bluefield';
|
|
12
|
+
/** Lowercase slug used for directories, env-var prefixes, and the bin name. */
|
|
13
|
+
export const PROJECT_SLUG = 'bluefield';
|
|
14
|
+
/** The provenance standard the signed manifests conform to. */
|
|
15
|
+
export const STANDARD_NAME = 'Bluefield Provenance Manifest';
|
|
16
|
+
/** Short abbreviation for the standard. */
|
|
17
|
+
export const STANDARD_ABBR = 'BPM';
|
|
18
|
+
/** Convenience: "Bluefield Provenance Manifest / BPM". */
|
|
19
|
+
export const STANDARD_FULL = `${STANDARD_NAME} / ${STANDARD_ABBR}`;
|
|
20
|
+
/** Default global home directory (under the user's home). */
|
|
21
|
+
export const HOME_DIR_NAME = `.${PROJECT_SLUG}`;
|
|
22
|
+
/** Repo-local store directory name (git-style, walked up from cwd). */
|
|
23
|
+
export const LOCAL_DIR_NAME = '.bf';
|
|
24
|
+
/** Env var that overrides the store root outright. */
|
|
25
|
+
export const HOME_ENV = 'BF_HOME';
|
|
26
|
+
/** Public repository URL. Referenced by the User-Agent below and by docs. */
|
|
27
|
+
export const REPO_URL = 'https://github.com/danielvhofmann/bluefield';
|
|
28
|
+
/** User-Agent presented to origins for local captures. */
|
|
29
|
+
export const USER_AGENT = `${PROJECT_NAME}-CLI/0.1 (+local; ${REPO_URL})`;
|
|
30
|
+
//# sourceMappingURL=constants.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA,6CAA6C;AAC7C;;;;;;;GAOG;AAEH,4DAA4D;AAC5D,MAAM,CAAC,MAAM,YAAY,GAAG,WAAoB,CAAC;AAEjD,+EAA+E;AAC/E,MAAM,CAAC,MAAM,YAAY,GAAG,WAAoB,CAAC;AAEjD,+DAA+D;AAC/D,MAAM,CAAC,MAAM,aAAa,GAAG,+BAAwC,CAAC;AAEtE,2CAA2C;AAC3C,MAAM,CAAC,MAAM,aAAa,GAAG,KAAc,CAAC;AAE5C,0DAA0D;AAC1D,MAAM,CAAC,MAAM,aAAa,GAAG,GAAG,aAAa,MAAM,aAAa,EAAW,CAAC;AAE5E,6DAA6D;AAC7D,MAAM,CAAC,MAAM,aAAa,GAAG,IAAI,YAAY,EAAW,CAAC;AAEzD,uEAAuE;AACvE,MAAM,CAAC,MAAM,cAAc,GAAG,KAAc,CAAC;AAE7C,sDAAsD;AACtD,MAAM,CAAC,MAAM,QAAQ,GAAG,SAAkB,CAAC;AAE3C,6EAA6E;AAC7E,MAAM,CAAC,MAAM,QAAQ,GAAG,6CAAsD,CAAC;AAE/E,0DAA0D;AAC1D,MAAM,CAAC,MAAM,UAAU,GAAG,GAAG,YAAY,qBAAqB,QAAQ,GAAY,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Filesystem `StorageAdapter` — the content-addressed "objects" store, the
|
|
3
|
+
* git-like heart of the local snapshot repository.
|
|
4
|
+
*
|
|
5
|
+
* Satisfies the exact `StorageAdapter` interface the engine's `fetchAndStore`
|
|
6
|
+
* injects, so the fetcher orchestration is reused verbatim: it just writes to
|
|
7
|
+
* `<store>/objects/<ab>/<sha256>` on the user's disk instead of R2. Content
|
|
8
|
+
* addressing means identical captures dedupe automatically and every object's
|
|
9
|
+
* name IS its SHA-256 — a built-in integrity check.
|
|
10
|
+
*
|
|
11
|
+
* Layout mirrors `buildR2Key` from `@bluefields/fetcher` (`content/<ab>/<sha>`)
|
|
12
|
+
* minus the `content/` prefix, which the on-disk `objects/` directory already
|
|
13
|
+
* provides.
|
|
14
|
+
*/
|
|
15
|
+
import type { StorageAdapter } from '@bluefields/fetcher';
|
|
16
|
+
/**
|
|
17
|
+
* Create a filesystem-backed storage adapter rooted at `objectsDir`
|
|
18
|
+
* (`<store>/objects`). The directory is created on demand.
|
|
19
|
+
*/
|
|
20
|
+
export declare function createFsStorageAdapter(objectsDir: string): StorageAdapter;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
2
|
+
/**
|
|
3
|
+
* Filesystem `StorageAdapter` — the content-addressed "objects" store, the
|
|
4
|
+
* git-like heart of the local snapshot repository.
|
|
5
|
+
*
|
|
6
|
+
* Satisfies the exact `StorageAdapter` interface the engine's `fetchAndStore`
|
|
7
|
+
* injects, so the fetcher orchestration is reused verbatim: it just writes to
|
|
8
|
+
* `<store>/objects/<ab>/<sha256>` on the user's disk instead of R2. Content
|
|
9
|
+
* addressing means identical captures dedupe automatically and every object's
|
|
10
|
+
* name IS its SHA-256 — a built-in integrity check.
|
|
11
|
+
*
|
|
12
|
+
* Layout mirrors `buildR2Key` from `@bluefields/fetcher` (`content/<ab>/<sha>`)
|
|
13
|
+
* minus the `content/` prefix, which the on-disk `objects/` directory already
|
|
14
|
+
* provides.
|
|
15
|
+
*/
|
|
16
|
+
import { createHash } from 'node:crypto';
|
|
17
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
18
|
+
import { join } from 'node:path';
|
|
19
|
+
import { buildR2Key } from '@bluefields/fetcher';
|
|
20
|
+
/**
|
|
21
|
+
* Create a filesystem-backed storage adapter rooted at `objectsDir`
|
|
22
|
+
* (`<store>/objects`). The directory is created on demand.
|
|
23
|
+
*/
|
|
24
|
+
export function createFsStorageAdapter(objectsDir) {
|
|
25
|
+
mkdirSync(objectsDir, { recursive: true });
|
|
26
|
+
const pathFor = (contentHash) => {
|
|
27
|
+
// buildR2Key validates the hash shape (64-char lowercase hex) and shards
|
|
28
|
+
// by the first two chars — reuse it so on-disk layout tracks the engine's.
|
|
29
|
+
const key = buildR2Key(contentHash); // content/<ab>/<sha>
|
|
30
|
+
const rel = key.slice('content/'.length); // <ab>/<sha>
|
|
31
|
+
return join(objectsDir, rel);
|
|
32
|
+
};
|
|
33
|
+
return {
|
|
34
|
+
async storeSnapshot(content) {
|
|
35
|
+
const contentHash = createHash('sha256').update(content).digest('hex');
|
|
36
|
+
const dest = pathFor(contentHash);
|
|
37
|
+
// Idempotent: identical content → identical path. Skip the write if the
|
|
38
|
+
// object already exists (dedup); this is what makes re-scraping an
|
|
39
|
+
// unchanged page cheap and keeps the store append-only-ish.
|
|
40
|
+
if (!existsSync(dest)) {
|
|
41
|
+
mkdirSync(join(dest, '..'), { recursive: true });
|
|
42
|
+
writeFileSync(dest, content, 'utf8');
|
|
43
|
+
}
|
|
44
|
+
return { contentHash, r2Key: buildR2Key(contentHash) };
|
|
45
|
+
},
|
|
46
|
+
async getSnapshot(contentHash) {
|
|
47
|
+
const src = pathFor(contentHash);
|
|
48
|
+
try {
|
|
49
|
+
return readFileSync(src, 'utf8');
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
throw new Error(`snapshot object not found: ${contentHash}`);
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
async hasSnapshot(contentHash) {
|
|
56
|
+
return existsSync(pathFor(contentHash));
|
|
57
|
+
},
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=fs-storage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fs-storage.js","sourceRoot":"","sources":["../src/fs-storage.ts"],"names":[],"mappings":"AAAA,6CAA6C;AAC7C;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC7E,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAGjC,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAEjD;;;GAGG;AACH,MAAM,UAAU,sBAAsB,CAAC,UAAkB;IACvD,SAAS,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAE3C,MAAM,OAAO,GAAG,CAAC,WAAmB,EAAU,EAAE;QAC9C,yEAAyE;QACzE,2EAA2E;QAC3E,MAAM,GAAG,GAAG,UAAU,CAAC,WAAW,CAAC,CAAC,CAAC,qBAAqB;QAC1D,MAAM,GAAG,GAAG,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,aAAa;QACvD,OAAO,IAAI,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC;IAC/B,CAAC,CAAC;IAEF,OAAO;QACL,KAAK,CAAC,aAAa,CAAC,OAAe;YACjC,MAAM,WAAW,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YACvE,MAAM,IAAI,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;YAClC,wEAAwE;YACxE,mEAAmE;YACnE,4DAA4D;YAC5D,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;gBACtB,SAAS,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;gBACjD,aAAa,CAAC,IAAI,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;YACvC,CAAC;YACD,OAAO,EAAE,WAAW,EAAE,KAAK,EAAE,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;QACzD,CAAC;QAED,KAAK,CAAC,WAAW,CAAC,WAAmB;YACnC,MAAM,GAAG,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;YACjC,IAAI,CAAC;gBACH,OAAO,YAAY,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;YACnC,CAAC;YAAC,MAAM,CAAC;gBACP,MAAM,IAAI,KAAK,CAAC,8BAA8B,WAAW,EAAE,CAAC,CAAC;YAC/D,CAAC;QACH,CAAC;QAED,KAAK,CAAC,WAAW,CAAC,WAAmB;YACnC,OAAO,UAAU,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC;QAC1C,CAAC;KACF,CAAC;AACJ,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @bluefields/cli — public library surface.
|
|
3
|
+
*
|
|
4
|
+
* `bf` on the command line is a thin wrapper over this library. Import it
|
|
5
|
+
* directly to embed a local-first, content-addressed, cryptographically
|
|
6
|
+
* signed web-snapshot store in your own program — no server required.
|
|
7
|
+
*
|
|
8
|
+
* import { openBluefield } from '@bluefields/cli';
|
|
9
|
+
* const bf = await openBluefield();
|
|
10
|
+
* const r = await bf.scrape('https://example.com');
|
|
11
|
+
* await bf.close();
|
|
12
|
+
*/
|
|
13
|
+
export { Bluefield, openBluefield, type OpenOptions, type ScrapeOptions, type ScrapeResult, type SnapshotSummary, type DiffResult, type VerifyResult, type ExportResult, } from './bluefield.js';
|
|
14
|
+
export { type AnchorResult, tryAnchor } from './anchor.js';
|
|
15
|
+
export { type LocalIdentity, loadOrCreateIdentity, defaultKeysDir } from './keystore.js';
|
|
16
|
+
export { type StorePaths, storePaths, resolveStoreRoot, globalHome, findLocalStore, } from './paths.js';
|
|
17
|
+
export { PROJECT_NAME, PROJECT_SLUG, STANDARD_NAME, STANDARD_ABBR, STANDARD_FULL, } from './constants.js';
|
|
18
|
+
export type { AttestationBundle, SignedManifest, Ed25519Jwk } from '@bluefields/attest';
|
|
19
|
+
export { signedManifestFromRow, toBundle, localTrustStore, writeBundleSidecar, readBundleSidecar, } from './attestation.js';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
2
|
+
/**
|
|
3
|
+
* @bluefields/cli — public library surface.
|
|
4
|
+
*
|
|
5
|
+
* `bf` on the command line is a thin wrapper over this library. Import it
|
|
6
|
+
* directly to embed a local-first, content-addressed, cryptographically
|
|
7
|
+
* signed web-snapshot store in your own program — no server required.
|
|
8
|
+
*
|
|
9
|
+
* import { openBluefield } from '@bluefields/cli';
|
|
10
|
+
* const bf = await openBluefield();
|
|
11
|
+
* const r = await bf.scrape('https://example.com');
|
|
12
|
+
* await bf.close();
|
|
13
|
+
*/
|
|
14
|
+
export { Bluefield, openBluefield, } from './bluefield.js';
|
|
15
|
+
export { tryAnchor } from './anchor.js';
|
|
16
|
+
export { loadOrCreateIdentity, defaultKeysDir } from './keystore.js';
|
|
17
|
+
export { storePaths, resolveStoreRoot, globalHome, findLocalStore, } from './paths.js';
|
|
18
|
+
export { PROJECT_NAME, PROJECT_SLUG, STANDARD_NAME, STANDARD_ABBR, STANDARD_FULL, } from './constants.js';
|
|
19
|
+
export { signedManifestFromRow, toBundle, localTrustStore, writeBundleSidecar, readBundleSidecar, } from './attestation.js';
|
|
20
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,6CAA6C;AAC7C;;;;;;;;;;;GAWG;AAEH,OAAO,EACL,SAAS,EACT,aAAa,GAQd,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAqB,SAAS,EAAE,MAAM,aAAa,CAAC;AAC3D,OAAO,EAAsB,oBAAoB,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AACzF,OAAO,EAEL,UAAU,EACV,gBAAgB,EAChB,UAAU,EACV,cAAc,GACf,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,YAAY,EACZ,YAAY,EACZ,aAAa,EACb,aAAa,EACb,aAAa,GACd,MAAM,gBAAgB,CAAC;AAExB,OAAO,EACL,qBAAqB,EACrB,QAAQ,EACR,eAAe,EACf,kBAAkB,EAClB,iBAAiB,GAClB,MAAM,kBAAkB,CAAC"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Local signing identity.
|
|
3
|
+
*
|
|
4
|
+
* On first use we generate a fresh Ed25519 keypair and persist it under
|
|
5
|
+
* `~/.bluefield/keys`:
|
|
6
|
+
* - `ed25519.key.jwk` — PRIVATE key, written 0600. NEVER logged or printed.
|
|
7
|
+
* - `ed25519.pub.jwk` — PUBLIC key + keyId, world-readable, safe to publish.
|
|
8
|
+
*
|
|
9
|
+
* The signer is `@bluefields/attest`'s `LocalEd25519Signer` — the same audited
|
|
10
|
+
* crypto core the server uses in dev/test — constructed from the persisted
|
|
11
|
+
* `KeyObject`. Custody here is a 0600 file rather than a KMS HSM: appropriate
|
|
12
|
+
* for a single-user local tool and clearly labelled as such. The keyId is the
|
|
13
|
+
* RFC-7638 JWK thumbprint of the public key, so it is stable and
|
|
14
|
+
* self-certifying.
|
|
15
|
+
*
|
|
16
|
+
* Security invariant: private key material must never reach a log line, a
|
|
17
|
+
* thrown error message, stdout, or a manifest. Only the public JWK and the
|
|
18
|
+
* keyId are ever surfaced. We generate the keypair here (rather than via
|
|
19
|
+
* `LocalEd25519Signer.generate`, which does not expose the private half) so
|
|
20
|
+
* the private JWK can be persisted without reaching into signer internals.
|
|
21
|
+
*/
|
|
22
|
+
import { type Ed25519Jwk, type Signer } from '@bluefields/attest';
|
|
23
|
+
/** The public half of the local identity — safe to share. */
|
|
24
|
+
export interface LocalIdentity {
|
|
25
|
+
signer: Signer;
|
|
26
|
+
publicJwk: Ed25519Jwk;
|
|
27
|
+
keyId: string;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Default keys directory: `~/.bluefield/keys` (never inside a project `.bf`).
|
|
31
|
+
* `BF_KEYS_DIR` relocates it for power users and tests; the default keeps the
|
|
32
|
+
* signing identity global and out of any shareable store.
|
|
33
|
+
*/
|
|
34
|
+
export declare function defaultKeysDir(env?: NodeJS.ProcessEnv): string;
|
|
35
|
+
/**
|
|
36
|
+
* Load the local signing identity, generating + persisting one on first use.
|
|
37
|
+
*
|
|
38
|
+
* @param keysDir Override the keys directory (tests pass a temp dir).
|
|
39
|
+
*/
|
|
40
|
+
export declare function loadOrCreateIdentity(keysDir?: string): LocalIdentity;
|
package/dist/keystore.js
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
2
|
+
/**
|
|
3
|
+
* Local signing identity.
|
|
4
|
+
*
|
|
5
|
+
* On first use we generate a fresh Ed25519 keypair and persist it under
|
|
6
|
+
* `~/.bluefield/keys`:
|
|
7
|
+
* - `ed25519.key.jwk` — PRIVATE key, written 0600. NEVER logged or printed.
|
|
8
|
+
* - `ed25519.pub.jwk` — PUBLIC key + keyId, world-readable, safe to publish.
|
|
9
|
+
*
|
|
10
|
+
* The signer is `@bluefields/attest`'s `LocalEd25519Signer` — the same audited
|
|
11
|
+
* crypto core the server uses in dev/test — constructed from the persisted
|
|
12
|
+
* `KeyObject`. Custody here is a 0600 file rather than a KMS HSM: appropriate
|
|
13
|
+
* for a single-user local tool and clearly labelled as such. The keyId is the
|
|
14
|
+
* RFC-7638 JWK thumbprint of the public key, so it is stable and
|
|
15
|
+
* self-certifying.
|
|
16
|
+
*
|
|
17
|
+
* Security invariant: private key material must never reach a log line, a
|
|
18
|
+
* thrown error message, stdout, or a manifest. Only the public JWK and the
|
|
19
|
+
* keyId are ever surfaced. We generate the keypair here (rather than via
|
|
20
|
+
* `LocalEd25519Signer.generate`, which does not expose the private half) so
|
|
21
|
+
* the private JWK can be persisted without reaching into signer internals.
|
|
22
|
+
*/
|
|
23
|
+
import { createPrivateKey, createPublicKey, generateKeyPairSync, } from 'node:crypto';
|
|
24
|
+
import { chmodSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
25
|
+
import { join } from 'node:path';
|
|
26
|
+
import { LocalEd25519Signer, exportPublicJwk, jwkThumbprint, } from '@bluefields/attest';
|
|
27
|
+
import { keysDir } from './paths.js';
|
|
28
|
+
const PRIVATE_FILE = 'ed25519.key.jwk';
|
|
29
|
+
const PUBLIC_FILE = 'ed25519.pub.jwk';
|
|
30
|
+
/**
|
|
31
|
+
* Default keys directory: `~/.bluefield/keys` (never inside a project `.bf`).
|
|
32
|
+
* `BF_KEYS_DIR` relocates it for power users and tests; the default keeps the
|
|
33
|
+
* signing identity global and out of any shareable store.
|
|
34
|
+
*/
|
|
35
|
+
export function defaultKeysDir(env = process.env) {
|
|
36
|
+
return keysDir(env);
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Load the local signing identity, generating + persisting one on first use.
|
|
40
|
+
*
|
|
41
|
+
* @param keysDir Override the keys directory (tests pass a temp dir).
|
|
42
|
+
*/
|
|
43
|
+
export function loadOrCreateIdentity(keysDir = defaultKeysDir()) {
|
|
44
|
+
const privPath = join(keysDir, PRIVATE_FILE);
|
|
45
|
+
const pubPath = join(keysDir, PUBLIC_FILE);
|
|
46
|
+
const storedPriv = tryReadJson(privPath);
|
|
47
|
+
if (storedPriv) {
|
|
48
|
+
const privateKey = createPrivateKey({ key: storedPriv, format: 'jwk' });
|
|
49
|
+
const publicKey = createPublicKey(privateKey);
|
|
50
|
+
const storedPub = tryReadJson(pubPath);
|
|
51
|
+
const keyId = storedPub?.kid ?? jwkThumbprint(publicKey);
|
|
52
|
+
const publicJwk = storedPub ?? exportPublicJwk(publicKey, keyId);
|
|
53
|
+
return { signer: new LocalEd25519Signer(privateKey, keyId), publicJwk, keyId };
|
|
54
|
+
}
|
|
55
|
+
// First run: generate, persist private 0600 + public sidecar.
|
|
56
|
+
const { publicKey, privateKey } = generateKeyPairSync('ed25519');
|
|
57
|
+
const keyId = jwkThumbprint(publicKey);
|
|
58
|
+
const publicJwk = exportPublicJwk(publicKey, keyId);
|
|
59
|
+
const privateJwk = privateKey.export({ format: 'jwk' });
|
|
60
|
+
mkdirSync(keysDir, { recursive: true, mode: 0o700 });
|
|
61
|
+
writeFileSync(privPath, `${JSON.stringify(privateJwk, null, 2)}\n`, { mode: 0o600 });
|
|
62
|
+
chmodSync(privPath, 0o600); // enforce even if umask widened the create mode
|
|
63
|
+
writeFileSync(pubPath, `${JSON.stringify(publicJwk, null, 2)}\n`, { mode: 0o644 });
|
|
64
|
+
return { signer: new LocalEd25519Signer(privateKey, keyId), publicJwk, keyId };
|
|
65
|
+
}
|
|
66
|
+
/** Read + parse a JSON file, returning null if it does not exist. */
|
|
67
|
+
function tryReadJson(path) {
|
|
68
|
+
let raw;
|
|
69
|
+
try {
|
|
70
|
+
raw = readFileSync(path, 'utf8');
|
|
71
|
+
}
|
|
72
|
+
catch {
|
|
73
|
+
return null; // ENOENT (first run) or unreadable — treat as absent
|
|
74
|
+
}
|
|
75
|
+
return JSON.parse(raw);
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=keystore.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"keystore.js","sourceRoot":"","sources":["../src/keystore.ts"],"names":[],"mappings":"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"}
|