@omgbase/core 0.19.0 → 0.23.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/src/core/ids.d.ts +1 -1
- package/dist/src/core/ingest.d.ts +2 -0
- package/dist/src/core/ingest.js +13 -0
- package/dist/src/core/read/document.d.ts +13 -9
- package/dist/src/core/read/document.js +18 -8
- package/dist/src/core/store/archive.d.ts +196 -0
- package/dist/src/core/store/archive.js +606 -0
- package/dist/src/core/store/gc.d.ts +37 -4
- package/dist/src/core/store/gc.js +62 -28
- package/dist/src/core/store/rebuild.d.ts +2 -0
- package/dist/src/core/store/rebuild.js +8 -2
- package/dist/src/core/store/retention.d.ts +138 -0
- package/dist/src/core/store/retention.js +409 -0
- package/dist/src/core/store/schema.d.ts +3 -2
- package/dist/src/core/store/schema.js +30 -4
- package/dist/src/core/store/size.d.ts +24 -2
- package/dist/src/core/store/size.js +33 -3
- package/dist/src/core/store/store.d.ts +1 -0
- package/dist/src/core/store/store.js +53 -1
- package/dist/src/graph/history.d.ts +2 -0
- package/dist/src/graph/history.js +8 -4
- package/dist/src/index.d.ts +3 -1
- package/dist/src/index.js +3 -0
- package/dist/src/mcp/arguments.d.ts +10 -2
- package/dist/src/mcp/arguments.js +37 -3
- package/dist/src/mcp/errors.d.ts +1 -1
- package/dist/src/mcp/errors.js +4 -0
- package/dist/src/mcp/reference.d.ts +1 -1
- package/dist/src/mcp/reference.js +58 -8
- package/dist/src/mcp/server.js +51 -24
- package/dist/src/mutate/effects.d.ts +23 -5
- package/dist/src/mutate/effects.js +111 -22
- package/dist/src/mutate/known-ids.d.ts +19 -0
- package/dist/src/mutate/known-ids.js +47 -7
- package/dist/src/mutate/ops.d.ts +1 -0
- package/dist/src/mutate/ops.js +20 -1
- package/dist/src/mutate/select.d.ts +0 -11
- package/dist/src/mutate/select.js +33 -9
- package/dist/src/oqx-js/context.d.ts +9 -2
- package/dist/src/oqx-js/context.js +92 -30
- package/dist/src/oqx-js/dates.d.ts +105 -0
- package/dist/src/oqx-js/dates.js +427 -0
- package/dist/src/oqx-js/names.d.ts +40 -0
- package/dist/src/oqx-js/names.js +358 -0
- package/dist/src/oqx-js/planner.d.ts +3 -3
- package/dist/src/oqx-js/planner.js +30 -11
- package/dist/src/oqx-js/root-row.d.ts +15 -4
- package/dist/src/oqx-js/root-row.js +18 -10
- package/dist/src/oqx-js/run.d.ts +19 -1
- package/dist/src/oqx-js/run.js +97 -13
- package/dist/src/oqx-js/sql/translate.js +1 -1
- package/dist/src/spec-versions.d.ts +5 -5
- package/dist/src/spec-versions.js +4 -4
- package/dist/src/sync/observe.js +9 -3
- package/package.json +2 -2
package/dist/src/core/ids.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export type IdPrefix = "d" | "b" | "c" | "r" | "x" | "col" | "cp" | "e" | "rp" | "v" | "src";
|
|
1
|
+
export type IdPrefix = "d" | "b" | "c" | "r" | "x" | "col" | "cp" | "e" | "rp" | "v" | "src" | "s";
|
|
2
2
|
export declare function randomSuffix(len?: number): string;
|
|
3
3
|
/** A replacement id generator (spec/store §2.2): given a prefix, return the whole id. */
|
|
4
4
|
export type IdMinter = (prefix: IdPrefix) => string;
|
|
@@ -10,6 +10,8 @@ export interface DispositionRow {
|
|
|
10
10
|
matcherV: string | null;
|
|
11
11
|
detail: Record<string, unknown>;
|
|
12
12
|
}
|
|
13
|
+
/** spec/store §5.4 step 10 (14.2): which verdicts the store persists — every kind but `same`. */
|
|
14
|
+
export declare function persistsDisposition(kind: string): boolean;
|
|
13
15
|
export interface ResolvedEdgeRow {
|
|
14
16
|
srcDoc: string;
|
|
15
17
|
srcBlock: string | null;
|
package/dist/src/core/ingest.js
CHANGED
|
@@ -13,6 +13,10 @@ import { flattenFrontmatter, flattenComputed, writeDocProperties } from "./store
|
|
|
13
13
|
import { maintainEdges, adoptPhantoms } from "./store/edges.js";
|
|
14
14
|
import { parse as parseYaml } from "yaml";
|
|
15
15
|
import { adapterForPath } from "../format/index.js";
|
|
16
|
+
/** spec/store §5.4 step 10 (14.2): which verdicts the store persists — every kind but `same`. */
|
|
17
|
+
export function persistsDisposition(kind) {
|
|
18
|
+
return kind !== "same";
|
|
19
|
+
}
|
|
16
20
|
/** The parse step of ingest, exported so a batch caller can parse + reconcile
|
|
17
21
|
* every document of a checkpoint BEFORE committing any (the cross-document
|
|
18
22
|
* phase needs all per-doc results first) and hand the tree back via
|
|
@@ -279,10 +283,19 @@ export function ingestInto(db, repoId, path, content, opts) {
|
|
|
279
283
|
const dispositions = resolved.dispositions.length > 0 || opts.resolveIds
|
|
280
284
|
? resolved.dispositions
|
|
281
285
|
: rows.map((r) => ({ blockId: r.blockId, kind: "inserted", confidence: null, reason: null, matcherV: null, detail: {} }));
|
|
286
|
+
// spec/store §5.4 step 10 (14.2): a `same` verdict is not persisted. The
|
|
287
|
+
// matcher (and the known-id resolver) still produce one per untouched block
|
|
288
|
+
// — the outcome counts them — but the table records what CHANGED, so a
|
|
289
|
+
// block's `updated_at` (MAX commit ts over its `block_changes`) and its
|
|
290
|
+
// `blocks_history` are the block's own changes, not its siblings'. Every
|
|
291
|
+
// other kind — the first revision's `inserted` rows the mint oracle (§2.1)
|
|
292
|
+
// depends on included — is written as before.
|
|
282
293
|
const insDisp = db.prepare(`INSERT OR IGNORE INTO dispositions (commit_id, block_id, kind, confidence, reason, matcher_v, detail)
|
|
283
294
|
VALUES (?, ?, ?, ?, ?, ?, ?)`);
|
|
284
295
|
const bc = db.prepare("INSERT OR IGNORE INTO block_changes (block_id, commit_id, kind) VALUES (?, ?, ?)");
|
|
285
296
|
for (const d of dispositions) {
|
|
297
|
+
if (!persistsDisposition(d.kind))
|
|
298
|
+
continue;
|
|
286
299
|
insDisp.run(commitId, d.blockId, d.kind, d.confidence, d.reason, d.matcherV, JSON.stringify(d.detail));
|
|
287
300
|
bc.run(d.blockId, commitId, d.kind);
|
|
288
301
|
}
|
|
@@ -76,6 +76,15 @@ export declare function docsReadMany(store: Store, repoId: string, refs: string[
|
|
|
76
76
|
includeIds?: boolean;
|
|
77
77
|
budgetTokens?: number;
|
|
78
78
|
}): DocsReadManyResult;
|
|
79
|
+
/**
|
|
80
|
+
* `docs_read { at }` / `docs_read_at` (spec/surface §2, 4.7): the document AS
|
|
81
|
+
* OF a revision. No `properties`: the properties table is current-state only
|
|
82
|
+
* (`spec/properties`), and recomputing the bag from the reconstructed bytes is
|
|
83
|
+
* not yet a one-call affair of the format layer (the inline fields come out of
|
|
84
|
+
* the ingest's node projection) — so the time-travel read carries the bytes
|
|
85
|
+
* and nothing it would have to guess at (through 4.6 `docs_read_at` returned
|
|
86
|
+
* the CURRENT bag flagged `propertiesAreCurrent: true`).
|
|
87
|
+
*/
|
|
79
88
|
export interface DocsReadAtResult {
|
|
80
89
|
id: string;
|
|
81
90
|
/** The path as of that revision, in the reference form. */
|
|
@@ -88,14 +97,6 @@ export interface DocsReadAtResult {
|
|
|
88
97
|
* rendered_hash — a byte-faithful round-trip. False flags the fidelity gap
|
|
89
98
|
* described below (doc-level trivia may differ for an old revision). */
|
|
90
99
|
renderedHashMatch: boolean;
|
|
91
|
-
/**
|
|
92
|
-
* Properties as they are CURRENTLY (not at `rev`): the properties table is
|
|
93
|
-
* current-state only (properties-table), so historical property values are
|
|
94
|
-
* not recoverable. Included as best-effort context, flagged by
|
|
95
|
-
* `propertiesAreCurrent: true`.
|
|
96
|
-
*/
|
|
97
|
-
properties: Record<string, Record<string, unknown>>;
|
|
98
|
-
propertiesAreCurrent: true;
|
|
99
100
|
}
|
|
100
101
|
/**
|
|
101
102
|
* Whole-document TIME-TRAVEL read: reconstruct a document's full file bytes AS
|
|
@@ -105,7 +106,10 @@ export interface DocsReadAtResult {
|
|
|
105
106
|
* IN ORDER — but sourced from the revision's Merkle `root_tree` instead of the
|
|
106
107
|
* live `blocks` table. Returns null when the doc is missing, or when `revId`
|
|
107
108
|
* does not name a revision of this document (so the caller can raise a clean
|
|
108
|
-
* not-found error).
|
|
109
|
+
* not-found error). An ARCHIVED revision (spec/store §7 "Retention", 15.0)
|
|
110
|
+
* reads through its segment, attached on demand; when the segment is not
|
|
111
|
+
* recorded or not on disk this throws `RevisionArchived` (the surface's
|
|
112
|
+
* `revision_archived`).
|
|
109
113
|
*
|
|
110
114
|
* FIDELITY CAVEAT: `leading_trivia` and `frontmatter_trivia` are stored ONLY on
|
|
111
115
|
* the current `docs` row, NOT per-revision (see schema.ts — the `docs` row is
|
|
@@ -2,6 +2,7 @@ import { findDoc, findDocByRef, loadDocBlocks } from "./reader.js";
|
|
|
2
2
|
import { docPropertiesGrouped } from "../store/properties.js";
|
|
3
3
|
import { sha256 } from "../hash.js";
|
|
4
4
|
import { referencePath } from "../paths.js";
|
|
5
|
+
import { revisionBody } from "../store/archive.js";
|
|
5
6
|
function blob(db, hash) {
|
|
6
7
|
const row = db.prepare("SELECT bytes FROM blobs WHERE hash = ?").get(hash);
|
|
7
8
|
return row ? row.bytes.toString("utf8") : "";
|
|
@@ -154,7 +155,10 @@ export function docsReadMany(store, repoId, refs, opts = {}) {
|
|
|
154
155
|
* IN ORDER — but sourced from the revision's Merkle `root_tree` instead of the
|
|
155
156
|
* live `blocks` table. Returns null when the doc is missing, or when `revId`
|
|
156
157
|
* does not name a revision of this document (so the caller can raise a clean
|
|
157
|
-
* not-found error).
|
|
158
|
+
* not-found error). An ARCHIVED revision (spec/store §7 "Retention", 15.0)
|
|
159
|
+
* reads through its segment, attached on demand; when the segment is not
|
|
160
|
+
* recorded or not on disk this throws `RevisionArchived` (the surface's
|
|
161
|
+
* `revision_archived`).
|
|
158
162
|
*
|
|
159
163
|
* FIDELITY CAVEAT: `leading_trivia` and `frontmatter_trivia` are stored ONLY on
|
|
160
164
|
* the current `docs` row, NOT per-revision (see schema.ts — the `docs` row is
|
|
@@ -174,25 +178,33 @@ export function readDocumentAtRevision(store, docId, revId) {
|
|
|
174
178
|
.get(docId);
|
|
175
179
|
if (!doc)
|
|
176
180
|
return null;
|
|
177
|
-
|
|
181
|
+
// The revision's bodies: the store's for a live revision, its segment's for
|
|
182
|
+
// an archived one (spec/store §6.2 "through a segment", 15.0 — `prefix` is
|
|
183
|
+
// the attached alias; an unavailable segment throws RevisionArchived).
|
|
184
|
+
const rev = revisionBody(store, revId, docId);
|
|
178
185
|
if (!rev)
|
|
179
186
|
return null;
|
|
187
|
+
const at = (table) => `${rev.prefix}${table}`;
|
|
188
|
+
const blobAt = (hash) => {
|
|
189
|
+
const row = db.prepare(`SELECT bytes FROM ${at("blobs")} WHERE hash = ?`).get(hash);
|
|
190
|
+
return row ? row.bytes.toString("utf8") : "";
|
|
191
|
+
};
|
|
180
192
|
const out = [doc.leading_trivia];
|
|
181
193
|
// Frontmatter blob for THIS revision (per-revision), then the doc-level
|
|
182
194
|
// separator (best-effort — see fidelity caveat).
|
|
183
195
|
if (rev.frontmatter_blob)
|
|
184
|
-
out.push(
|
|
196
|
+
out.push(blobAt(rev.frontmatter_blob) + (doc.frontmatter_trivia ?? ""));
|
|
185
197
|
// Top-level blocks in tree order, from THIS revision's Merkle root tree node.
|
|
186
198
|
// A container's raw already holds its children verbatim, so we deliberately do
|
|
187
199
|
// NOT recurse into childTreeHashHex (mirrors reconstructContent's
|
|
188
200
|
// parent_block IS NULL walk). An absent tree node yields empty body bytes.
|
|
189
|
-
const node = db.prepare(
|
|
201
|
+
const node = db.prepare(`SELECT entries FROM ${at("tree_nodes")} WHERE hash = ?`).get(rev.root_tree);
|
|
190
202
|
if (node) {
|
|
191
203
|
const entries = JSON.parse(node.entries);
|
|
192
204
|
for (const [, rawHashHex, , , , triviaHashHex] of entries) {
|
|
193
|
-
out.push(
|
|
205
|
+
out.push(blobAt(Buffer.from(rawHashHex, "hex")));
|
|
194
206
|
if (triviaHashHex)
|
|
195
|
-
out.push(
|
|
207
|
+
out.push(blobAt(Buffer.from(triviaHashHex, "hex")));
|
|
196
208
|
}
|
|
197
209
|
}
|
|
198
210
|
const content = out.join("");
|
|
@@ -204,8 +216,6 @@ export function readDocumentAtRevision(store, docId, revId) {
|
|
|
204
216
|
rev: revId,
|
|
205
217
|
raw: content,
|
|
206
218
|
renderedHashMatch,
|
|
207
|
-
properties: surfaceProperties(docPropertiesGrouped(db, docId)),
|
|
208
|
-
propertiesAreCurrent: true,
|
|
209
219
|
};
|
|
210
220
|
}
|
|
211
221
|
//# sourceMappingURL=document.js.map
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
import type { Store } from "./store.js";
|
|
2
|
+
import { type EvaluateOptions, type RetentionPlan, type RetentionPolicy } from "./retention.js";
|
|
3
|
+
/** spec/store/archive.sql, verbatim — the segment's DDL. */
|
|
4
|
+
export declare const ARCHIVE_DDL = "-- ---- an archive segment (spec/store \u00A77 \"Retention\", 15.0) --------------------\n-- One file per `history export`, never appended: the bodies of the revisions\n-- the retention policy squashed, self-contained (every blob and tree node\n-- reachable from them), plus copies of their revision, commit, disposition and\n-- block-change rows, and one manifest row. The same DDL subset as schema.sql\n-- minus the foreign keys (a segment holds no repos or docs rows).\nCREATE TABLE IF NOT EXISTS manifest (\n segment_id TEXT PRIMARY KEY,\n repo_id TEXT NOT NULL,\n created_at TEXT NOT NULL,\n policy TEXT NOT NULL,\n seq_lo INTEGER NOT NULL,\n seq_hi INTEGER NOT NULL,\n revision_count INTEGER NOT NULL,\n previous_segment TEXT,\n schema_user_version INTEGER NOT NULL\n);\n\nCREATE TABLE IF NOT EXISTS revisions (\n rev_id TEXT PRIMARY KEY,\n doc_id TEXT NOT NULL,\n seq INTEGER NOT NULL,\n root_tree BLOB NOT NULL,\n frontmatter_blob BLOB,\n rendered_hash BLOB NOT NULL,\n path TEXT NOT NULL,\n commit_id TEXT NOT NULL,\n UNIQUE (doc_id, seq)\n);\n\nCREATE TABLE IF NOT EXISTS commits (\n commit_id TEXT PRIMARY KEY,\n repo_id TEXT NOT NULL,\n seq INTEGER NOT NULL,\n ts TEXT NOT NULL,\n origin TEXT NOT NULL CHECK (origin IN ('api','observed','import','projection')),\n actor TEXT,\n reason TEXT,\n checkpoint_id TEXT,\n ops TEXT\n);\n\nCREATE TABLE IF NOT EXISTS blobs (\n hash BLOB PRIMARY KEY,\n bytes BLOB NOT NULL,\n size INTEGER NOT NULL\n);\n\nCREATE TABLE IF NOT EXISTS tree_nodes (\n hash BLOB PRIMARY KEY,\n entries TEXT NOT NULL\n);\n\nCREATE TABLE IF NOT EXISTS dispositions (\n commit_id TEXT NOT NULL,\n block_id TEXT NOT NULL,\n kind TEXT NOT NULL CHECK (kind IN\n ('same','edited','moved','edited_moved','inserted','deleted',\n 'split_from','merged_into','copied_from','resurrected','bulk_rewrite')),\n confidence REAL,\n reason TEXT,\n matcher_v TEXT,\n detail TEXT NOT NULL DEFAULT '{}',\n PRIMARY KEY (commit_id, block_id, kind)\n);\n\nCREATE TABLE IF NOT EXISTS block_changes (\n block_id TEXT NOT NULL,\n commit_id TEXT NOT NULL,\n kind TEXT NOT NULL,\n PRIMARY KEY (block_id, commit_id, kind)\n);\n";
|
|
5
|
+
/** The file suffix every segment carries. */
|
|
6
|
+
export declare const ARCHIVE_SUFFIX = ".omgarchive.db";
|
|
7
|
+
/** The default directory under `.omgbase/`. */
|
|
8
|
+
export declare const ARCHIVE_DIR = "archives";
|
|
9
|
+
/** `<repo_id>-<seq_lo>-<seq_hi>-<segment_id>.omgarchive.db` */
|
|
10
|
+
export declare function segmentFileName(repoId: string, seqLo: number, seqHi: number, segmentId: string): string;
|
|
11
|
+
/** The parts a segment file name carries, or null when the name is not one. */
|
|
12
|
+
export declare function parseSegmentFileName(name: string): {
|
|
13
|
+
repoId: string;
|
|
14
|
+
seqLo: number;
|
|
15
|
+
seqHi: number;
|
|
16
|
+
segmentId: string;
|
|
17
|
+
} | null;
|
|
18
|
+
export interface Manifest {
|
|
19
|
+
segment_id: string;
|
|
20
|
+
repo_id: string;
|
|
21
|
+
created_at: string;
|
|
22
|
+
policy: RetentionPolicy;
|
|
23
|
+
seq_lo: number;
|
|
24
|
+
seq_hi: number;
|
|
25
|
+
revision_count: number;
|
|
26
|
+
previous_segment: string | null;
|
|
27
|
+
schema_user_version: number;
|
|
28
|
+
}
|
|
29
|
+
/** A read of an archived revision whose segment is not recorded, or recorded but not on disk (spec/surface: `revision_archived`). */
|
|
30
|
+
export declare class RevisionArchived extends Error {
|
|
31
|
+
readonly rev: string;
|
|
32
|
+
readonly archive: string;
|
|
33
|
+
readonly path: string | null;
|
|
34
|
+
constructor(rev: string, archive: string, path: string | null);
|
|
35
|
+
}
|
|
36
|
+
/** Not an archive segment, or one of another repository. */
|
|
37
|
+
export declare class NotASegment extends Error {
|
|
38
|
+
readonly path: string;
|
|
39
|
+
constructor(path: string, detail: string);
|
|
40
|
+
}
|
|
41
|
+
/** Open a segment read-only and return its manifest; `NotASegment` when the file is not one. */
|
|
42
|
+
export declare function readManifest(path: string): Manifest;
|
|
43
|
+
export interface ArchiveRow {
|
|
44
|
+
segment_id: string;
|
|
45
|
+
repo_id: string;
|
|
46
|
+
path: string;
|
|
47
|
+
seq_lo: number;
|
|
48
|
+
seq_hi: number;
|
|
49
|
+
created_at: string;
|
|
50
|
+
revision_count: number;
|
|
51
|
+
bytes: number;
|
|
52
|
+
}
|
|
53
|
+
export interface AttachedSegment {
|
|
54
|
+
segment_id: string;
|
|
55
|
+
path: string;
|
|
56
|
+
seq_lo: number;
|
|
57
|
+
seq_hi: number;
|
|
58
|
+
revision_count: number;
|
|
59
|
+
bytes: number;
|
|
60
|
+
}
|
|
61
|
+
export interface AttachResult {
|
|
62
|
+
attached: AttachedSegment[];
|
|
63
|
+
/** Files in a directory that are not this repository's segments. */
|
|
64
|
+
skipped: number;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* `omg history attach <file|dir>`: record a segment (idempotent — a known
|
|
68
|
+
* segment's path is re-recorded) or every `.omgarchive.db` of a directory
|
|
69
|
+
* whose manifest `repo_id` is this repository's. A single file of another
|
|
70
|
+
* repository or a non-segment is `NotASegment`; in a directory they are skipped.
|
|
71
|
+
*/
|
|
72
|
+
export declare function attachArchive(store: Store, repoId: string, target: string): AttachResult;
|
|
73
|
+
/**
|
|
74
|
+
* `omg history detach <segment_id|path>`: forget a segment. The revisions it
|
|
75
|
+
* holds keep their `archive` pointer; reading one is `revision_archived` until
|
|
76
|
+
* the segment is attached again. Returns the id, or null when nothing matched.
|
|
77
|
+
*/
|
|
78
|
+
export declare function detachArchive(store: Store, repoId: string, ref: string): string | null;
|
|
79
|
+
/**
|
|
80
|
+
* A segment's state (spec/store §7 "Retention"): recorded and on disk
|
|
81
|
+
* (`attached`), recorded but not on disk (`missing`); or unrecorded under the
|
|
82
|
+
* archives directory — `pending` (complete, its revisions still live: the
|
|
83
|
+
* crash rule finishes it on the next `export --prune`), `detached` (complete
|
|
84
|
+
* and squashed: `attach` brings it back), `stale` (some of its revisions live,
|
|
85
|
+
* some not: it belongs to another store or predates a different squash).
|
|
86
|
+
*/
|
|
87
|
+
export type ArchiveState = "attached" | "missing" | "pending" | "detached" | "stale";
|
|
88
|
+
export interface ArchiveListing extends AttachedSegment {
|
|
89
|
+
created_at: string;
|
|
90
|
+
state: ArchiveState;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* `omg history list`: the repository's recorded segments by `seq_lo` then id,
|
|
94
|
+
* followed by the unrecorded complete segments found in `dest`, by file name.
|
|
95
|
+
*/
|
|
96
|
+
export declare function listArchives(store: Store, repoId: string, opts?: {
|
|
97
|
+
dest?: string;
|
|
98
|
+
}): ArchiveListing[];
|
|
99
|
+
export interface UnrecordedSegment {
|
|
100
|
+
path: string;
|
|
101
|
+
state: "pending" | "detached" | "stale";
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* The complete segments of this repository under `dest` that no `archives`
|
|
105
|
+
* row records, by file name, each classified by its revisions: all live →
|
|
106
|
+
* `pending` (the crash rule's input), all archived → `detached`, else `stale`.
|
|
107
|
+
*/
|
|
108
|
+
export declare function unrecordedSegments(store: Store, repoId: string, dest: string): UnrecordedSegment[];
|
|
109
|
+
export declare function archiveAlias(segmentId: string): string;
|
|
110
|
+
/**
|
|
111
|
+
* The table prefix a revision's bodies are read under: `""` for a live
|
|
112
|
+
* revision, `"<alias>."` for an archived one whose segment is attached on
|
|
113
|
+
* demand (and verified to be the segment it claims). `RevisionArchived` when
|
|
114
|
+
* the segment is not recorded or not on disk.
|
|
115
|
+
*/
|
|
116
|
+
export declare function archivePrefix(store: Store, rev: {
|
|
117
|
+
rev_id: string;
|
|
118
|
+
archive: string | null;
|
|
119
|
+
}): string;
|
|
120
|
+
export interface RevisionBody {
|
|
121
|
+
rev_id: string;
|
|
122
|
+
doc_id: string;
|
|
123
|
+
path: string;
|
|
124
|
+
rendered_hash: Buffer;
|
|
125
|
+
root_tree: Buffer;
|
|
126
|
+
frontmatter_blob: Buffer | null;
|
|
127
|
+
/** `""` or `"<alias>."` — where `tree_nodes` and `blobs` for this revision live. */
|
|
128
|
+
prefix: string;
|
|
129
|
+
archived: boolean;
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* A revision's row with its bodies resolved: a live revision's from the store,
|
|
133
|
+
* an archived one's from its segment (attached on demand). `undefined` when
|
|
134
|
+
* `revId` is not a revision (of `docId`, when given); `RevisionArchived` when
|
|
135
|
+
* its segment is unavailable.
|
|
136
|
+
*/
|
|
137
|
+
export declare function revisionBody(store: Store, revId: string, docId?: string): RevisionBody | undefined;
|
|
138
|
+
export interface SegmentInfo {
|
|
139
|
+
id: string;
|
|
140
|
+
path: string;
|
|
141
|
+
seq_lo: number;
|
|
142
|
+
seq_hi: number;
|
|
143
|
+
created_at: string;
|
|
144
|
+
revision_count: number;
|
|
145
|
+
/** The file's size on disk. */
|
|
146
|
+
bytes: number;
|
|
147
|
+
previous_segment: string | null;
|
|
148
|
+
}
|
|
149
|
+
export interface SquashResult {
|
|
150
|
+
revisions: number;
|
|
151
|
+
/** Commits every revision of which is archived: their dispositions and block changes moved. */
|
|
152
|
+
commits: number;
|
|
153
|
+
dispositions: number;
|
|
154
|
+
block_changes: number;
|
|
155
|
+
}
|
|
156
|
+
export interface ExportResult {
|
|
157
|
+
plan: RetentionPlan;
|
|
158
|
+
/** null when nothing was to archive (no file written). */
|
|
159
|
+
segment: SegmentInfo | null;
|
|
160
|
+
/** An unrecorded complete segment was finished instead of writing a new one (the crash rule). */
|
|
161
|
+
reused: boolean;
|
|
162
|
+
/** null without `prune`. */
|
|
163
|
+
squashed: SquashResult | null;
|
|
164
|
+
/** null without `prune`. */
|
|
165
|
+
gc: {
|
|
166
|
+
blobs: number;
|
|
167
|
+
tree_nodes: number;
|
|
168
|
+
} | null;
|
|
169
|
+
}
|
|
170
|
+
export interface ExportOptions extends EvaluateOptions {
|
|
171
|
+
/** The directory the segment is written to (created when missing). */
|
|
172
|
+
dest: string;
|
|
173
|
+
/** Squash the store after the segment is durable. */
|
|
174
|
+
prune: boolean;
|
|
175
|
+
}
|
|
176
|
+
/** An unrecorded segment under `dest` names both live and non-live revisions (it predates another squash, or belongs elsewhere). */
|
|
177
|
+
export declare class StaleSegment extends Error {
|
|
178
|
+
readonly path: string;
|
|
179
|
+
readonly rev: string;
|
|
180
|
+
constructor(path: string, rev: string);
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* `omg history export [--prune]`: evaluate the policy, write ONE new segment
|
|
184
|
+
* for the revisions to archive (or finish an unrecorded one — the crash
|
|
185
|
+
* rule), and with `prune` squash the store. Nothing to archive → no file,
|
|
186
|
+
* `segment: null`.
|
|
187
|
+
*/
|
|
188
|
+
export declare function exportHistory(store: Store, repoId: string, opts: ExportOptions): ExportResult;
|
|
189
|
+
/** The archived-history figures the size report carries (spec/store §7 "Size", 15.0). */
|
|
190
|
+
export declare function archivedSummary(store: Store): {
|
|
191
|
+
revisions: number;
|
|
192
|
+
segments: number;
|
|
193
|
+
bytes: number;
|
|
194
|
+
};
|
|
195
|
+
/** The file name of a segment path, for messages and fixtures. */
|
|
196
|
+
export declare function segmentBasename(path: string): string;
|