@tensorix/metahub 0.1.10 → 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/README.md +19 -6
- package/README.zh-CN.md +7 -2
- package/dist/cli.js +22843 -18308
- package/dist/cli.js.map +87 -66
- package/dist/core/blobs-core.d.ts +106 -0
- package/dist/core/blobs-core.d.ts.map +1 -0
- package/dist/core/blobs.d.ts +100 -0
- package/dist/core/blobs.d.ts.map +1 -0
- package/dist/core/cache.d.ts +18 -1
- package/dist/core/cache.d.ts.map +1 -1
- package/dist/core/compact.d.ts +43 -0
- package/dist/core/compact.d.ts.map +1 -0
- package/dist/core/config.d.ts +6 -3
- package/dist/core/config.d.ts.map +1 -1
- package/dist/core/context.d.ts +4 -4
- package/dist/core/context.d.ts.map +1 -1
- package/dist/core/crdt.d.ts +54 -8
- package/dist/core/crdt.d.ts.map +1 -1
- package/dist/core/databases.d.ts +22 -8
- package/dist/core/databases.d.ts.map +1 -1
- package/dist/core/db.d.ts +1 -27
- package/dist/core/db.d.ts.map +1 -1
- package/dist/core/documents.d.ts +28 -15
- package/dist/core/documents.d.ts.map +1 -1
- package/dist/core/driver.d.ts +25 -0
- package/dist/core/driver.d.ts.map +1 -0
- package/dist/core/history.d.ts +99 -11
- package/dist/core/history.d.ts.map +1 -1
- package/dist/core/hlc.d.ts +3 -3
- package/dist/core/hlc.d.ts.map +1 -1
- package/dist/core/index.d.ts +1 -0
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/indexing.d.ts +4 -4
- package/dist/core/indexing.d.ts.map +1 -1
- package/dist/core/integrity.d.ts +1 -1
- package/dist/core/integrity.d.ts.map +1 -1
- package/dist/core/node.d.ts +2 -2
- package/dist/core/node.d.ts.map +1 -1
- package/dist/core/properties.d.ts +10 -9
- package/dist/core/properties.d.ts.map +1 -1
- package/dist/core/records.d.ts +13 -8
- package/dist/core/records.d.ts.map +1 -1
- package/dist/core/resolve.d.ts +4 -4
- package/dist/core/resolve.d.ts.map +1 -1
- package/dist/core/schema-init.d.ts +68 -0
- package/dist/core/schema-init.d.ts.map +1 -0
- package/dist/core/schema.d.ts +1 -1
- package/dist/core/schema.d.ts.map +1 -1
- package/dist/core/search.d.ts +3 -3
- package/dist/core/search.d.ts.map +1 -1
- package/dist/core/sites-core.d.ts +95 -0
- package/dist/core/sites-core.d.ts.map +1 -0
- package/dist/core/sites.d.ts +8 -58
- package/dist/core/sites.d.ts.map +1 -1
- package/dist/core/sqlcols.d.ts +4 -0
- package/dist/core/sqlcols.d.ts.map +1 -0
- package/dist/core/sync/auth.d.ts +5 -3
- package/dist/core/sync/auth.d.ts.map +1 -1
- package/dist/core/sync/blob-routes.d.ts +12 -0
- package/dist/core/sync/blob-routes.d.ts.map +1 -0
- package/dist/core/sync/client.d.ts +13 -3
- package/dist/core/sync/client.d.ts.map +1 -1
- package/dist/core/sync/e2ee.d.ts +24 -0
- package/dist/core/sync/e2ee.d.ts.map +1 -0
- package/dist/core/sync/enroll.d.ts +21 -0
- package/dist/core/sync/enroll.d.ts.map +1 -0
- package/dist/core/sync/peers-routes.d.ts.map +1 -1
- package/dist/core/sync/peers.d.ts +84 -11
- package/dist/core/sync/peers.d.ts.map +1 -1
- package/dist/core/sync/protocol.d.ts +5 -0
- package/dist/core/sync/protocol.d.ts.map +1 -1
- package/dist/core/sync/publisher-lease.d.ts +8 -0
- package/dist/core/sync/publisher-lease.d.ts.map +1 -0
- package/dist/core/sync/routes.d.ts.map +1 -1
- package/dist/core/sync/server.d.ts +11 -0
- package/dist/core/sync/server.d.ts.map +1 -1
- package/dist/core/sync/sites-serve.d.ts.map +1 -1
- package/dist/core/sync/storage-s3-bun.d.ts +26 -0
- package/dist/core/sync/storage-s3-bun.d.ts.map +1 -0
- package/dist/core/sync/storage.d.ts +170 -0
- package/dist/core/sync/storage.d.ts.map +1 -0
- package/dist/db-worker.js +384 -0
- package/dist/index.js +17250 -13920
- package/dist/index.js.map +47 -32
- package/dist/metahub-sdk.js +1 -0
- package/dist/mh-runtime.js +1 -0
- package/dist/sqlite3.wasm +0 -0
- package/dist/sw.js +1 -0
- package/dist/webui/server/assets.d.ts +8 -1
- package/dist/webui/server/assets.d.ts.map +1 -1
- package/dist/webui/server/icons.d.ts +4 -0
- package/dist/webui/server/icons.d.ts.map +1 -0
- package/dist/webui/server/routes.d.ts.map +1 -1
- package/dist/webui.js +68 -62
- package/package.json +6 -1
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import type { DbDriver } from "./driver.ts";
|
|
2
|
+
export declare const POLICY_ID = "default";
|
|
3
|
+
export type Redundancy = "all" | "any";
|
|
4
|
+
export interface BlobPolicy {
|
|
5
|
+
fullNodes: string[];
|
|
6
|
+
redundancy: Redundancy;
|
|
7
|
+
}
|
|
8
|
+
export interface CachedBlob {
|
|
9
|
+
hash: string;
|
|
10
|
+
size: number;
|
|
11
|
+
content_type: string | null;
|
|
12
|
+
last_access: number | null;
|
|
13
|
+
/** Node-local pin: 1 = never auto-evicted / cleared (does not sync). */
|
|
14
|
+
pinned: number;
|
|
15
|
+
/** 1 = bytes produced here, not yet flushed to a durable anchor — protected. */
|
|
16
|
+
pending: number;
|
|
17
|
+
/** Node-local: 1 = the last presence verify confirmed a designated anchor holds
|
|
18
|
+
* this blob (per redundancy). Drives isClearable; reset to 0 on policy change. */
|
|
19
|
+
anchored: number;
|
|
20
|
+
}
|
|
21
|
+
export interface CacheStats {
|
|
22
|
+
/** Total bytes currently held in the node-local cache. */
|
|
23
|
+
totalBytes: number;
|
|
24
|
+
/** Bytes safe to clear (durable on the required full set). */
|
|
25
|
+
clearableBytes: number;
|
|
26
|
+
/** Bytes that cannot be cleared (sole copy / no anchor / this is a full node). */
|
|
27
|
+
retainedBytes: number;
|
|
28
|
+
count: number;
|
|
29
|
+
clearableCount: number;
|
|
30
|
+
}
|
|
31
|
+
export declare function readPolicy(db: DbDriver): BlobPolicy;
|
|
32
|
+
/** Designate the full-blob anchors (synced workspace policy). Each entry is
|
|
33
|
+
* either a node id (a device that keeps everything) OR a bucket url `s3://…`
|
|
34
|
+
* (object storage as a durable full library). Bucket urls never match a node id,
|
|
35
|
+
* so isFullBlobNode()/isClearable() are unaffected — they're a visible guardrail. */
|
|
36
|
+
export declare const setFullNodes: (db: DbDriver, nodeIds: string[]) => void;
|
|
37
|
+
export declare const setRedundancy: (db: DbDriver, redundancy: Redundancy) => void;
|
|
38
|
+
/** Is `node` (default: this device) a designated full-blob library? */
|
|
39
|
+
export declare function isFullBlobNode(db: DbDriver, node?: string): boolean;
|
|
40
|
+
/**
|
|
41
|
+
* Whether this device may safely drop `hash`'s local bytes — a purely LOCAL,
|
|
42
|
+
* offline decision read from local flags. Clearable requires ALL of:
|
|
43
|
+
* 1. This node is not itself the full-blob library (a full node keeps everything).
|
|
44
|
+
* 2. The blob is not a `pending` production (bytes produced here, not yet flushed
|
|
45
|
+
* to an anchor) — the only locally-unique copy.
|
|
46
|
+
* 3. `anchored == 1`: the last presence verify confirmed a designated anchor holds
|
|
47
|
+
* this blob, per redundancy(any/all). Until a verify runs (or after a policy
|
|
48
|
+
* change resets it), anchored is 0 → nothing is clearable (conservative). This
|
|
49
|
+
* replaces the earlier coarse "an anchor is designated" floor with a per-blob,
|
|
50
|
+
* freshly-verified fact. See verifyAnchorPresence (blobs.ts) and
|
|
51
|
+
* docs/impl-context/22-blob-sync (D4, on-demand presence verify).
|
|
52
|
+
*/
|
|
53
|
+
export declare function isClearable(db: DbDriver, hash: string): boolean;
|
|
54
|
+
/** Record/clear the per-blob "a designated anchor verifiably holds this" flag. */
|
|
55
|
+
export declare function setAnchored(db: DbDriver, hash: string, anchored: boolean): void;
|
|
56
|
+
export declare function isAnchored(db: DbDriver, hash: string): boolean;
|
|
57
|
+
/** Drop every verified verdict (after a policy change) — forces a re-verify before
|
|
58
|
+
* anything is clearable again. Also clears the last-verified stamp. */
|
|
59
|
+
export declare function invalidateAnchored(db: DbDriver): void;
|
|
60
|
+
/** Epoch-ms of the last successful presence verify, or null if never / invalidated. */
|
|
61
|
+
export declare function readBlobVerifiedAt(db: DbDriver): number | null;
|
|
62
|
+
export declare function writeBlobVerifiedAt(db: DbDriver, ts: number): void;
|
|
63
|
+
/** Blob hashes referenced by a `/blob/<hash>` URL inside a markdown/text value. */
|
|
64
|
+
export declare function blobRefsIn(text: string | null): string[];
|
|
65
|
+
/**
|
|
66
|
+
* Every blob hash a live document or site still points at. Union of:
|
|
67
|
+
* - site_files rows stored as a blob (content = hash), and
|
|
68
|
+
* - `/blob/<hash>` references inside live doc_blocks markdown (doc images).
|
|
69
|
+
* Drives GC (orphan = not in this set) and a full node's byte acquisition.
|
|
70
|
+
*/
|
|
71
|
+
export declare function referencedHashes(db: DbDriver): Set<string>;
|
|
72
|
+
/** Record/refresh a blob's ledger row after its bytes land in the cache. */
|
|
73
|
+
/** Record/refresh a cached blob. `pending`: 1 for bytes PRODUCED here (must flush
|
|
74
|
+
* to an anchor before they're clearable), 0 for an ACQUIRED cache copy (already
|
|
75
|
+
* durable at its source). */
|
|
76
|
+
export declare function recordBlob(db: DbDriver, hash: string, size: number, contentType?: string | null, pending?: number): void;
|
|
77
|
+
/** Mark a blob flushed (0) or pending (1). Flush is set after the bytes are
|
|
78
|
+
* confirmed at the durable anchor (see blobs.ts blobMaintenance). */
|
|
79
|
+
export declare function setPending(db: DbDriver, hash: string, pending: boolean): void;
|
|
80
|
+
/** Bump last_access on a cache hit (LRU signal for stats/future eviction). */
|
|
81
|
+
export declare function touchBlob(db: DbDriver, hash: string): void;
|
|
82
|
+
export declare function forgetBlob(db: DbDriver, hash: string): void;
|
|
83
|
+
export declare function cachedBlobs(db: DbDriver): CachedBlob[];
|
|
84
|
+
/** Blobs produced here that are not yet flushed to a durable anchor (the upload
|
|
85
|
+
* worklist; steady state is empty). */
|
|
86
|
+
export declare function pendingBlobs(db: DbDriver): {
|
|
87
|
+
hash: string;
|
|
88
|
+
size: number;
|
|
89
|
+
}[];
|
|
90
|
+
/** Pin/unpin a cached blob (node-local; never synced). Returns true when a row
|
|
91
|
+
* was updated (false when the hash isn't in the ledger). */
|
|
92
|
+
export declare function setPinned(db: DbDriver, hash: string, pinned: boolean): boolean;
|
|
93
|
+
/** Is a cached blob pinned? (false when not in the ledger). */
|
|
94
|
+
export declare function isPinned(db: DbDriver, hash: string): boolean;
|
|
95
|
+
/** Recorded content type for a cached blob (null when unknown / not cached). */
|
|
96
|
+
export declare function blobContentType(db: DbDriver, hash: string): string | null;
|
|
97
|
+
export declare function cacheStats(db: DbDriver): CacheStats;
|
|
98
|
+
export interface KnownNode {
|
|
99
|
+
nodeId: string;
|
|
100
|
+
label: string | null;
|
|
101
|
+
self: boolean;
|
|
102
|
+
}
|
|
103
|
+
/** Distinct node ids this device knows about (self + outbound peers + grantees),
|
|
104
|
+
* for the "pick a full-blob device" selector in Settings / CLI. */
|
|
105
|
+
export declare function knownNodes(db: DbDriver): KnownNode[];
|
|
106
|
+
//# sourceMappingURL=blobs-core.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"blobs-core.d.ts","sourceRoot":"","sources":["../../src/core/blobs-core.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import type { DbDriver } from "./driver.ts";
|
|
2
|
+
export * from "./blobs-core.ts";
|
|
3
|
+
export interface KnownBucket {
|
|
4
|
+
url: string;
|
|
5
|
+
label: string | null;
|
|
6
|
+
bucket: string | null;
|
|
7
|
+
}
|
|
8
|
+
/** Attached object-storage buckets (s3 peers), for the "pick a full-blob anchor"
|
|
9
|
+
* selector in Settings. A bucket is a durable full-blob library but is NOT a node
|
|
10
|
+
* (1:N store-and-forward, no single node id), so it lives alongside knownNodes()
|
|
11
|
+
* rather than inside it — designated by its synthetic url, not a node_id. */
|
|
12
|
+
export declare function knownBuckets(db: DbDriver): KnownBucket[];
|
|
13
|
+
/**
|
|
14
|
+
* Resolve a blob's bytes by content hash: local cache → each enabled HTTP peer's
|
|
15
|
+
* `GET /blob/<hash>?local=1` (local=1 keeps the peer from re-resolving, so there
|
|
16
|
+
* are no fetch loops) → each attached bucket's `blobs/<hash>`. Content-addressed,
|
|
17
|
+
* so every source is verified by re-hashing and any source is interchangeable.
|
|
18
|
+
* The first verified hit is cached locally and returned; null when unreachable.
|
|
19
|
+
*/
|
|
20
|
+
export declare function resolveBlob(db: DbDriver, hash: string): Promise<Uint8Array | null>;
|
|
21
|
+
export interface VerifyResult {
|
|
22
|
+
/** Blobs confirmed durable on the anchor set (per redundancy) → clearable. */
|
|
23
|
+
anchoredCount: number;
|
|
24
|
+
anchoredBytes: number;
|
|
25
|
+
/** Designated anchors (bucket urls / device node ids) we could not reach to
|
|
26
|
+
* check. Under `all`, any unreachable anchor makes everything un-clearable. */
|
|
27
|
+
unreachable: string[];
|
|
28
|
+
/** Epoch-ms this verify ran. */
|
|
29
|
+
at: number;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Verify, right now, which locally-cached blobs a designated anchor durably holds,
|
|
33
|
+
* and record the per-blob `anchored` flag that `isClearable` reads. Buckets are
|
|
34
|
+
* checked with one paginated LIST (listBucketBlobHashes); device anchors with a
|
|
35
|
+
* `POST /api/blobs/has`. An anchor we can't reach (offline / no stored url+token /
|
|
36
|
+
* bad creds) goes into `unreachable` and is treated as NOT holding anything —
|
|
37
|
+
* conservative, so a transient outage defers clearing rather than risking loss.
|
|
38
|
+
*
|
|
39
|
+
* Redundancy: `any` → present on ≥1 reachable anchor; `all` → every designated
|
|
40
|
+
* anchor reachable AND holding it. Run on demand only (panel open / refresh /
|
|
41
|
+
* pre-eviction when over quota), never in the steady-state maintenance loop.
|
|
42
|
+
*/
|
|
43
|
+
export declare function verifyAnchorPresence(db: DbDriver): Promise<VerifyResult>;
|
|
44
|
+
export interface BlobMaintenanceResult {
|
|
45
|
+
/** Referenced blobs a full library pulled in this round. */
|
|
46
|
+
acquired: number;
|
|
47
|
+
/** Pending productions confirmed flushed to the bucket(s) this round. */
|
|
48
|
+
flushed: number;
|
|
49
|
+
/** Blobs auto-evicted to stay under the configured cache quota. */
|
|
50
|
+
evicted: number;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Background blob upkeep, run from the sync tick (throttled). Cheap in steady
|
|
54
|
+
* state — it only touches work that actually exists:
|
|
55
|
+
* 1. A full blob library pulls every referenced blob it is still MISSING
|
|
56
|
+
* (resolveBlob); self-limiting, a no-op once caught up.
|
|
57
|
+
* 2. This node flushes its own PENDING productions to each attached bucket, then
|
|
58
|
+
* marks them flushed (→ clearable). It iterates ONLY pending blobs (empty in
|
|
59
|
+
* steady state), so — unlike the old design — it does NOT re-read/encrypt/HEAD
|
|
60
|
+
* every already-uploaded blob each round.
|
|
61
|
+
* 3. Evicts to stay under the cache quota.
|
|
62
|
+
*/
|
|
63
|
+
export declare function blobMaintenance(db: DbDriver): Promise<BlobMaintenanceResult>;
|
|
64
|
+
export interface EvictResult {
|
|
65
|
+
evicted: number;
|
|
66
|
+
freedBytes: number;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Auto-evict clearable, unpinned blobs by least-recently-accessed order until the
|
|
70
|
+
* local cache total is at/under the low-water mark. No-op when quotaBytes <= 0
|
|
71
|
+
* (disabled) or the cache is already under quota. Only touches blobs `isClearable`
|
|
72
|
+
* marks safe (durable on the full set) and never a pinned blob — bytes stay
|
|
73
|
+
* re-fetchable, so this is loss-free.
|
|
74
|
+
*/
|
|
75
|
+
export declare function evictToQuota(db: DbDriver, quotaBytes: number): Promise<EvictResult>;
|
|
76
|
+
export interface ClearResult {
|
|
77
|
+
/** Blobs whose bytes were dropped. */
|
|
78
|
+
cleared: number;
|
|
79
|
+
/** Actual bytes freed on disk. */
|
|
80
|
+
freedBytes: number;
|
|
81
|
+
/** Blobs left in place (sole copy / no anchor / this is a full node). */
|
|
82
|
+
skipped: number;
|
|
83
|
+
}
|
|
84
|
+
export interface GcResult {
|
|
85
|
+
removed: number;
|
|
86
|
+
freedBytes: number;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Fold on-disk cache files into the blob_cache ledger so stats/clear/gc also see
|
|
90
|
+
* blobs written before the ledger existed. content_type is unknown for these
|
|
91
|
+
* (left null — serve falls back to the URL suffix).
|
|
92
|
+
*/
|
|
93
|
+
export declare function reconcileCache(db: DbDriver): void;
|
|
94
|
+
/** Drop the bytes of every locally-cached blob that is safe to clear (durable on
|
|
95
|
+
* the designated full set). Reference + hash stay in the oplog, re-fetchable. */
|
|
96
|
+
export declare function clearCache(db: DbDriver): Promise<ClearResult>;
|
|
97
|
+
/** Drop bytes for blobs no live site_files / doc image still references (true
|
|
98
|
+
* garbage, distinct from clearable cache). */
|
|
99
|
+
export declare function gcOrphans(db: DbDriver): Promise<GcResult>;
|
|
100
|
+
//# sourceMappingURL=blobs.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"blobs.d.ts","sourceRoot":"","sources":["../../src/core/blobs.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAsB5C,cAAc,iBAAiB,CAAC;AAEhC,MAAM,WAAW,WAAW;IAC1B,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB;AAED;;;8EAG8E;AAC9E,wBAAgB,YAAY,CAAC,EAAE,EAAE,QAAQ,GAAG,WAAW,EAAE,CAYxD;AAWD;;;;;;GAMG;AACH,wBAAsB,WAAW,CAAC,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAgCxF;AAID,MAAM,WAAW,YAAY;IAC3B,8EAA8E;IAC9E,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;IACtB;oFACgF;IAChF,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,gCAAgC;IAChC,EAAE,EAAE,MAAM,CAAC;CACZ;AAqBD;;;;;;;;;;;GAWG;AACH,wBAAsB,oBAAoB,CAAC,EAAE,EAAE,QAAQ,GAAG,OAAO,CAAC,YAAY,CAAC,CAoD9E;AAED,MAAM,WAAW,qBAAqB;IACpC,4DAA4D;IAC5D,QAAQ,EAAE,MAAM,CAAC;IACjB,yEAAyE;IACzE,OAAO,EAAE,MAAM,CAAC;IAChB,mEAAmE;IACnE,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,eAAe,CAAC,EAAE,EAAE,QAAQ,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAsClF;AAED,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;CACpB;AAMD;;;;;;GAMG;AACH,wBAAsB,YAAY,CAAC,EAAE,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CA4BzF;AAED,MAAM,WAAW,WAAW;IAC1B,sCAAsC;IACtC,OAAO,EAAE,MAAM,CAAC;IAChB,kCAAkC;IAClC,UAAU,EAAE,MAAM,CAAC;IACnB,yEAAyE;IACzE,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,QAAQ;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,EAAE,EAAE,QAAQ,GAAG,IAAI,CAiBjD;AAED;kFACkF;AAClF,wBAAsB,UAAU,CAAC,EAAE,EAAE,QAAQ,GAAG,OAAO,CAAC,WAAW,CAAC,CAgBnE;AAED;+CAC+C;AAC/C,wBAAsB,SAAS,CAAC,EAAE,EAAE,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,CAY/D"}
|
package/dist/core/cache.d.ts
CHANGED
|
@@ -4,7 +4,24 @@ export interface BlobInfo {
|
|
|
4
4
|
size: number;
|
|
5
5
|
}
|
|
6
6
|
export declare function blobPath(hash: string): string;
|
|
7
|
-
/**
|
|
7
|
+
/** Content key length: sha256 truncated to 128 bits (32 hex). Shorter keys keep
|
|
8
|
+
* doc markdown (``) readable; collision is negligible.
|
|
9
|
+
* Addressing stays length-agnostic, so legacy full 64-hex refs still resolve. */
|
|
10
|
+
export declare const BLOB_HASH_HEX = 32;
|
|
11
|
+
/** Full sha256 hex of the bytes. */
|
|
12
|
+
export declare function sha256Hex(bytes: Uint8Array): string;
|
|
13
|
+
/** Canonical content hash for new blobs: sha256 of the bytes, truncated. */
|
|
14
|
+
export declare function blobHash(bytes: Uint8Array): string;
|
|
15
|
+
/** Verify fetched bytes match a content reference of either length (canonical
|
|
16
|
+
* 32-hex or legacy 64-hex) — the ref is always a prefix of the full sha256. */
|
|
17
|
+
export declare function verifyBlobBytes(bytes: Uint8Array, hash: string): boolean;
|
|
18
|
+
/** Store bytes content-addressed under cache/. Returns its hash + path. */
|
|
8
19
|
export declare function putBlob(data: ArrayBuffer | Uint8Array | string): Promise<BlobInfo>;
|
|
9
20
|
export declare function getBlob(hash: string): Promise<Uint8Array | null>;
|
|
21
|
+
/** Store bytes under a GIVEN content hash (not recomputed) — for caching a blob
|
|
22
|
+
* fetched from a peer/bucket by its reference, which may be a legacy 64-hex hash
|
|
23
|
+
* that putBlob's truncation would not reproduce. Returns the byte length. */
|
|
24
|
+
export declare function putBlobAt(hash: string, bytes: Uint8Array): Promise<number>;
|
|
25
|
+
/** Remove a blob's bytes from the cache. Returns its size, or 0 if absent. */
|
|
26
|
+
export declare function deleteBlob(hash: string): Promise<number>;
|
|
10
27
|
//# sourceMappingURL=cache.d.ts.map
|
package/dist/core/cache.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../../src/core/cache.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAED,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE7C;AAED,
|
|
1
|
+
{"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../../src/core/cache.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAED,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE7C;AAED;;kFAEkF;AAClF,eAAO,MAAM,aAAa,KAAK,CAAC;AAEhC,oCAAoC;AACpC,wBAAgB,SAAS,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAInD;AAED,4EAA4E;AAC5E,wBAAgB,QAAQ,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAElD;AAED;gFACgF;AAChF,wBAAgB,eAAe,CAAC,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAExE;AAED,2EAA2E;AAC3E,wBAAsB,OAAO,CAAC,IAAI,EAAE,WAAW,GAAG,UAAU,GAAG,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC,CAWxF;AAED,wBAAsB,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAItE;AAED;;8EAE8E;AAC9E,wBAAsB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CAIhF;AAED,8EAA8E;AAC9E,wBAAsB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAM9D"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { Database } from "bun:sqlite";
|
|
2
|
+
export interface CompactResult {
|
|
3
|
+
/** HLC cutoff actually used — history at or before this collapses to a baseline. */
|
|
4
|
+
cutoff: string;
|
|
5
|
+
deleted_changes: number;
|
|
6
|
+
kept_changes: number;
|
|
7
|
+
blobs_deleted: number;
|
|
8
|
+
blob_bytes_freed: number;
|
|
9
|
+
db_bytes_before: number;
|
|
10
|
+
db_bytes_after: number;
|
|
11
|
+
dry_run: boolean;
|
|
12
|
+
}
|
|
13
|
+
export interface CompactOptions {
|
|
14
|
+
/** Keep full history for this many days; 0 keeps only the head state. */
|
|
15
|
+
keepDays: number;
|
|
16
|
+
/** Report what would be removed without changing anything. */
|
|
17
|
+
dryRun?: boolean;
|
|
18
|
+
/** Run VACUUM afterwards to return the freed pages to the filesystem. */
|
|
19
|
+
vacuum?: boolean;
|
|
20
|
+
/** Test hook: "now" in epoch millis. */
|
|
21
|
+
now?: number;
|
|
22
|
+
}
|
|
23
|
+
export declare function compactOplog(db: Database, opts: CompactOptions): CompactResult;
|
|
24
|
+
/**
|
|
25
|
+
* Delete cache blobs no longer referenced by any remaining oplog value, a
|
|
26
|
+
* materialized site file, or a `/blob/<hash>` doc image reference. Conservative:
|
|
27
|
+
* only files named like a content hash (canonical 32-hex or legacy 64-hex) are
|
|
28
|
+
* candidates; anything else in the cache dir is left alone.
|
|
29
|
+
*/
|
|
30
|
+
export declare function gcBlobs(db: Database, opts?: {
|
|
31
|
+
dryRun?: boolean;
|
|
32
|
+
}): {
|
|
33
|
+
deleted: number;
|
|
34
|
+
bytes: number;
|
|
35
|
+
};
|
|
36
|
+
/** Dry-run quick stats for doctor: total oplog rows and how many compaction
|
|
37
|
+
* with the given window would remove. */
|
|
38
|
+
export declare function compactEstimate(db: Database, keepDays: number, now?: number): {
|
|
39
|
+
total_changes: number;
|
|
40
|
+
compactable_changes: number;
|
|
41
|
+
db_bytes: number;
|
|
42
|
+
};
|
|
43
|
+
//# sourceMappingURL=compact.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compact.d.ts","sourceRoot":"","sources":["../../src/core/compact.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AA0B3C,MAAM,WAAW,aAAa;IAC5B,oFAAoF;IACpF,MAAM,EAAE,MAAM,CAAC;IACf,eAAe,EAAE,MAAM,CAAC;IACxB,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,gBAAgB,EAAE,MAAM,CAAC;IACzB,eAAe,EAAE,MAAM,CAAC;IACxB,cAAc,EAAE,MAAM,CAAC;IACvB,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,cAAc;IAC7B,yEAAyE;IACzE,QAAQ,EAAE,MAAM,CAAC;IACjB,8DAA8D;IAC9D,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,yEAAyE;IACzE,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,wCAAwC;IACxC,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAqBD,wBAAgB,YAAY,CAAC,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,cAAc,GAAG,aAAa,CAkD9E;AAED;;;;;GAKG;AACH,wBAAgB,OAAO,CACrB,EAAE,EAAE,QAAQ,EACZ,IAAI,GAAE;IAAE,MAAM,CAAC,EAAE,OAAO,CAAA;CAAO,GAC9B;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CA2DpC;AAED;0CAC0C;AAC1C,wBAAgB,eAAe,CAC7B,EAAE,EAAE,QAAQ,EACZ,QAAQ,EAAE,MAAM,EAChB,GAAG,SAAa,GACf;IAAE,aAAa,EAAE,MAAM,CAAC;IAAC,mBAAmB,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAa1E"}
|
package/dist/core/config.d.ts
CHANGED
|
@@ -1,14 +1,17 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { DbDriver } from "./driver.ts";
|
|
2
2
|
export interface ServerConfig {
|
|
3
3
|
host: string;
|
|
4
4
|
port: number;
|
|
5
5
|
/** Auto-sync poll interval in ms; <= 0 disables the timer. */
|
|
6
6
|
syncIntervalMs: number;
|
|
7
7
|
autoSync: boolean;
|
|
8
|
+
/** Local blob cache quota in bytes. When the cache exceeds it, the sync tick
|
|
9
|
+
* auto-evicts clearable, unpinned blobs (LRU). <= 0 disables eviction. */
|
|
10
|
+
blobCacheQuotaBytes: number;
|
|
8
11
|
}
|
|
9
12
|
export declare const DEFAULT_CONFIG: ServerConfig;
|
|
10
13
|
/** Persisted server config, falling back to DEFAULT_CONFIG per field. */
|
|
11
|
-
export declare function getServerConfig(db:
|
|
14
|
+
export declare function getServerConfig(db: DbDriver): ServerConfig;
|
|
12
15
|
/** Persist a partial config update. Only provided fields are written. */
|
|
13
|
-
export declare function setServerConfig(db:
|
|
16
|
+
export declare function setServerConfig(db: DbDriver, partial: Partial<ServerConfig>): ServerConfig;
|
|
14
17
|
//# sourceMappingURL=config.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/core/config.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/core/config.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAS5C,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,8DAA8D;IAC9D,cAAc,EAAE,MAAM,CAAC;IACvB,QAAQ,EAAE,OAAO,CAAC;IAClB;+EAC2E;IAC3E,mBAAmB,EAAE,MAAM,CAAC;CAC7B;AAED,eAAO,MAAM,cAAc,EAAE,YAM5B,CAAC;AAeF,yEAAyE;AACzE,wBAAgB,eAAe,CAAC,EAAE,EAAE,QAAQ,GAAG,YAAY,CAc1D;AAED,yEAAyE;AACzE,wBAAgB,eAAe,CAAC,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,CAAC,YAAY,CAAC,GAAG,YAAY,CAS1F"}
|
package/dist/core/context.d.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { DbDriver } from "./driver.ts";
|
|
2
2
|
import { type DatabaseRow } from "./databases.ts";
|
|
3
3
|
/**
|
|
4
4
|
* The current database, or null. Validated on read: if it points at a database
|
|
5
5
|
* that no longer exists (deleted, or gone after a snapshot restore), the stale
|
|
6
6
|
* pointer is cleared and null returned — no coupling to delete/restore paths.
|
|
7
7
|
*/
|
|
8
|
-
export declare function getCurrentDatabase(db:
|
|
9
|
-
export declare function setCurrentDatabase(db:
|
|
10
|
-
export declare function clearCurrentDatabase(db:
|
|
8
|
+
export declare function getCurrentDatabase(db: DbDriver): DatabaseRow | null;
|
|
9
|
+
export declare function setCurrentDatabase(db: DbDriver, id: string): void;
|
|
10
|
+
export declare function clearCurrentDatabase(db: DbDriver): void;
|
|
11
11
|
//# sourceMappingURL=context.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../src/core/context.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../src/core/context.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAe,KAAK,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAO/D;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,EAAE,EAAE,QAAQ,GAAG,WAAW,GAAG,IAAI,CAWnE;AAED,wBAAgB,kBAAkB,CAAC,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,GAAG,IAAI,CAIjE;AAED,wBAAgB,oBAAoB,CAAC,EAAE,EAAE,QAAQ,GAAG,IAAI,CAEvD"}
|
package/dist/core/crdt.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { DbDriver } from "./driver.ts";
|
|
2
2
|
export interface Change {
|
|
3
3
|
hlc: string;
|
|
4
4
|
node_id: string;
|
|
@@ -6,6 +6,29 @@ export interface Change {
|
|
|
6
6
|
row_id: string;
|
|
7
7
|
col: string;
|
|
8
8
|
value: string | null;
|
|
9
|
+
txn?: string | null;
|
|
10
|
+
}
|
|
11
|
+
/** Oplog SELECT list, locked to the Change interface (also reused by history). */
|
|
12
|
+
export declare const CHANGE_COLS: readonly ["hlc", "node_id", "dataset", "row_id", "col", "value", "txn"];
|
|
13
|
+
export declare const CHANGE_SELECT: string;
|
|
14
|
+
/**
|
|
15
|
+
* Run `fn` with all emits stamped with one shared txn id. Nested calls keep the
|
|
16
|
+
* outermost group (a revert that calls updateDocument is ONE revision). `label`
|
|
17
|
+
* prefixes the id ("repair:", "revert:") so history can classify the source.
|
|
18
|
+
*/
|
|
19
|
+
export declare function withChangeGroup<T>(label: string | null, fn: () => T): T;
|
|
20
|
+
/** Wrap a mutator so its body runs inside one change group. */
|
|
21
|
+
export declare function grouped<A extends unknown[], R>(fn: (...args: A) => R, label?: string | null): (...args: A) => R;
|
|
22
|
+
/** Outcome of applying one change to the oplog. `inserted` reports whether the
|
|
23
|
+
* oplog actually gained a NEW row (false when we already had this exact change —
|
|
24
|
+
* the INSERT OR IGNORE was a no-op); it is the honest "did we receive new data"
|
|
25
|
+
* signal, distinct from `winner` (whether this change now wins its register and
|
|
26
|
+
* was materialized). Re-applying a change we already hold still returns
|
|
27
|
+
* `winner:true` if it's the current max-HLC, so callers that want progress (not
|
|
28
|
+
* re-materialization) must key off `inserted`. */
|
|
29
|
+
export interface ApplyResult {
|
|
30
|
+
inserted: boolean;
|
|
31
|
+
winner: boolean;
|
|
9
32
|
}
|
|
10
33
|
/**
|
|
11
34
|
* Record a change in the oplog (idempotent) and, if it is the latest write for
|
|
@@ -13,23 +36,46 @@ export interface Change {
|
|
|
13
36
|
* of the order changes are applied, because the winner is recomputed as the max
|
|
14
37
|
* HLC over the full oplog for that register.
|
|
15
38
|
*/
|
|
16
|
-
export declare function applyChange(db:
|
|
39
|
+
export declare function applyChange(db: DbDriver, c: Change): ApplyResult;
|
|
17
40
|
/** Apply a local write: assign a fresh HLC, append to oplog, materialize. */
|
|
18
|
-
export declare function emit(db:
|
|
41
|
+
export declare function emit(db: DbDriver, dataset: string, rowId: string, col: string, value: unknown): Change;
|
|
19
42
|
/** Apply multiple local field writes to the same row. */
|
|
20
|
-
export declare function emitFields(db:
|
|
21
|
-
/** Apply remote changes from a sync peer (advances clock, then merges).
|
|
22
|
-
|
|
43
|
+
export declare function emitFields(db: DbDriver, dataset: string, rowId: string, fields: Record<string, unknown>): Change[];
|
|
44
|
+
/** Apply remote changes from a sync peer (advances clock, then merges). Returns
|
|
45
|
+
* the number of changes that were NEW to our oplog (rows actually inserted) —
|
|
46
|
+
* the honest "received" count. Re-ingesting data we already hold returns 0, so
|
|
47
|
+
* this is a reliable progress signal for the auto-sync backoff (a round that
|
|
48
|
+
* only re-reads known data must not count as activity). */
|
|
49
|
+
export declare function ingest(db: DbDriver, changes: Change[]): number;
|
|
23
50
|
/** All oplog changes with HLC strictly greater than `since` (test/debug helper). */
|
|
24
|
-
export declare function changesSince(db:
|
|
51
|
+
export declare function changesSince(db: DbDriver, since: string): Change[];
|
|
25
52
|
export interface ChangeBatch {
|
|
26
53
|
changes: Change[];
|
|
27
54
|
cursor: number;
|
|
28
55
|
}
|
|
56
|
+
export interface ChangesAfterOpts {
|
|
57
|
+
/** Max rows to return — pagination for large pulls (initial hydration). */
|
|
58
|
+
limit?: number;
|
|
59
|
+
/** Datasets to omit (partial replicas, e.g. a phone skipping site_files). */
|
|
60
|
+
excludeDatasets?: string[];
|
|
61
|
+
/**
|
|
62
|
+
* Return only changes this node produced itself. Storage-sync (see
|
|
63
|
+
* sync/storage.ts) publishes each node's own ops under its own bucket prefix,
|
|
64
|
+
* so it must not re-upload ops it merely ingested from peers. The cursor still
|
|
65
|
+
* advances over the filtered-out rows (high-water on exhaustion), so ingested
|
|
66
|
+
* ops are skipped once, not rescanned every round.
|
|
67
|
+
*/
|
|
68
|
+
onlyNode?: string;
|
|
69
|
+
}
|
|
29
70
|
/**
|
|
30
71
|
* Changes inserted after `seq` (a local rowid), in insertion order, plus the
|
|
31
72
|
* new high-water cursor. Used for replication: insertion order never skips a
|
|
32
73
|
* change even when clocks are skewed.
|
|
74
|
+
*
|
|
75
|
+
* With `limit`, the cursor stops at the last returned row so the next pull
|
|
76
|
+
* resumes there; when the scan is exhausted (fewer rows than the limit, or no
|
|
77
|
+
* limit) the cursor jumps to the table's high-water rowid so excluded-dataset
|
|
78
|
+
* tails aren't rescanned every round.
|
|
33
79
|
*/
|
|
34
|
-
export declare function changesAfterSeq(db:
|
|
80
|
+
export declare function changesAfterSeq(db: DbDriver, seq: number, opts?: ChangesAfterOpts): ChangeBatch;
|
|
35
81
|
//# sourceMappingURL=crdt.d.ts.map
|
package/dist/core/crdt.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"crdt.d.ts","sourceRoot":"","sources":["../../src/core/crdt.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"crdt.d.ts","sourceRoot":"","sources":["../../src/core/crdt.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAW5C,MAAM,WAAW,MAAM;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACrB;AAED,kFAAkF;AAClF,eAAO,MAAM,WAAW,yEAA0E,CAAC;AAEnG,eAAO,MAAM,aAAa,QAAyB,CAAC;AAMpD;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,CAQvE;AAED,+DAA+D;AAC/D,wBAAgB,OAAO,CAAC,CAAC,SAAS,OAAO,EAAE,EAAE,CAAC,EAC5C,EAAE,EAAE,CAAC,GAAG,IAAI,EAAE,CAAC,KAAK,CAAC,EACrB,KAAK,GAAE,MAAM,GAAG,IAAW,GAC1B,CAAC,GAAG,IAAI,EAAE,CAAC,KAAK,CAAC,CAEnB;AAkJD;;;;;;mDAMmD;AACnD,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,EAAE,OAAO,CAAC;CACjB;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,EAAE,EAAE,QAAQ,EAAE,CAAC,EAAE,MAAM,GAAG,WAAW,CAiBhE;AAED,6EAA6E;AAC7E,wBAAgB,IAAI,CAClB,EAAE,EAAE,QAAQ,EACZ,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,EACb,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,OAAO,GACb,MAAM,CAaR;AAED,yDAAyD;AACzD,wBAAgB,UAAU,CACxB,EAAE,EAAE,QAAQ,EACZ,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC9B,MAAM,EAAE,CAMV;AAED;;;;4DAI4D;AAC5D,wBAAgB,MAAM,CAAC,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,MAAM,CAW9D;AAED,oFAAoF;AACpF,wBAAgB,YAAY,CAAC,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAIlE;AAED,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,gBAAgB;IAC/B,2EAA2E;IAC3E,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,6EAA6E;IAC7E,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAC3B;;;;;;OAMG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;;;;GASG;AACH,wBAAgB,eAAe,CAC7B,EAAE,EAAE,QAAQ,EACZ,GAAG,EAAE,MAAM,EACX,IAAI,GAAE,gBAAqB,GAC1B,WAAW,CAkCb"}
|
package/dist/core/databases.d.ts
CHANGED
|
@@ -1,19 +1,33 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { DbDriver } from "./driver.ts";
|
|
2
2
|
export interface DatabaseRow {
|
|
3
3
|
id: string;
|
|
4
4
|
name: string;
|
|
5
5
|
icon: string | null;
|
|
6
6
|
created_hlc: string;
|
|
7
7
|
}
|
|
8
|
-
export declare
|
|
8
|
+
export declare const DATABASE_COLS: readonly ["id", "name", "icon", "created_hlc"];
|
|
9
|
+
export declare const createDatabase: (db: DbDriver, opts: {
|
|
9
10
|
name: string;
|
|
10
11
|
icon?: string;
|
|
11
|
-
})
|
|
12
|
-
export declare
|
|
12
|
+
}) => DatabaseRow;
|
|
13
|
+
export declare const updateDatabase: (db: DbDriver, id: string, fields: {
|
|
13
14
|
name?: string;
|
|
14
15
|
icon?: string | null;
|
|
15
|
-
})
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
}) => DatabaseRow;
|
|
17
|
+
/**
|
|
18
|
+
* Copy a database whole — name, icon, every property (type/config/position
|
|
19
|
+
* preserved) and every record (in order, cells carried via an old→new property
|
|
20
|
+
* id map, so duplicate property names copy losslessly). A relation column
|
|
21
|
+
* pointing back at the *source* database is remapped to the copy so it stays
|
|
22
|
+
* self-referential; relations to other databases keep their target.
|
|
23
|
+
* `name`/`icon` override the defaults; the locale "copy" suffix is the
|
|
24
|
+
* caller's job. All emits share one txn, so the copy syncs as one revision.
|
|
25
|
+
*/
|
|
26
|
+
export declare const duplicateDatabase: (db: DbDriver, id: string, opts?: {
|
|
27
|
+
name?: string;
|
|
28
|
+
icon?: string;
|
|
29
|
+
} | undefined) => DatabaseRow;
|
|
30
|
+
export declare function getDatabase(db: DbDriver, id: string): DatabaseRow | null;
|
|
31
|
+
export declare function listDatabases(db: DbDriver): DatabaseRow[];
|
|
32
|
+
export declare const deleteDatabase: (db: DbDriver, id: string) => boolean;
|
|
19
33
|
//# sourceMappingURL=databases.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"databases.d.ts","sourceRoot":"","sources":["../../src/core/databases.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"databases.d.ts","sourceRoot":"","sources":["../../src/core/databases.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAQ5C,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,eAAO,MAAM,aAAa,gDAAiD,CAAC;AAI5E,eAAO,MAAM,cAAc;UAEX,MAAM;WAAS,MAAM;iBAOnC,CAAC;AAEH,eAAO,MAAM,cAAc;WAGR,MAAM;WAAS,MAAM,GAAG,IAAI;iBAM7C,CAAC;AAEH;;;;;;;;GAQG;AACH,eAAO,MAAM,iBAAiB;WAGb,MAAM;WAAS,MAAM;6BAwBpC,CAAC;AAEH,wBAAgB,WAAW,CAAC,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI,CAIxE;AAED,wBAAgB,aAAa,CAAC,EAAE,EAAE,QAAQ,GAAG,WAAW,EAAE,CAIzD;AAED,eAAO,MAAM,cAAc,uCAqBzB,CAAC"}
|
package/dist/core/db.d.ts
CHANGED
|
@@ -1,32 +1,6 @@
|
|
|
1
1
|
import { Database } from "bun:sqlite";
|
|
2
|
+
export { runSchema, ftsAvailable, migrateRecords, migratePeers, migrateDocBlocks, migrateDocuments, migrateOplog, initSchema, } from "./schema-init.ts";
|
|
2
3
|
export declare function ensureDirs(): void;
|
|
3
|
-
export declare function runSchema(db: Database): void;
|
|
4
|
-
export declare function ftsAvailable(db: Database): boolean;
|
|
5
|
-
/**
|
|
6
|
-
* Migrate legacy EAV records (record_values: one row per cell) to the JSON
|
|
7
|
-
* layout (records.data: one row per record). Idempotent — keyed off schema
|
|
8
|
-
* shape, no version flag. A no-op for fresh databases.
|
|
9
|
-
*/
|
|
10
|
-
export declare function migrateRecords(db: Database): void;
|
|
11
|
-
/**
|
|
12
|
-
* Add the peer-pairing columns to a legacy `peers` table (token/label/node_id/
|
|
13
|
-
* enabled/last_sync_at/last_status/last_error). Idempotent — guarded per column,
|
|
14
|
-
* never drops the table so existing replication cursors survive.
|
|
15
|
-
*/
|
|
16
|
-
export declare function migratePeers(db: Database): void;
|
|
17
|
-
/**
|
|
18
|
-
* Add the `blank_after` column to a legacy `doc_blocks` table. Idempotent —
|
|
19
|
-
* guarded by hasColumn; existing blocks default to 0 (canonical single-blank-line
|
|
20
|
-
* separators), so the migration never changes an existing document's body.
|
|
21
|
-
*/
|
|
22
|
-
export declare function migrateDocBlocks(db: Database): void;
|
|
23
|
-
/**
|
|
24
|
-
* Add the `order_key` column to a legacy `documents` table and backfill it.
|
|
25
|
-
* Idempotent — guarded by hasColumn; backfill only touches rows with a NULL key,
|
|
26
|
-
* assigning per-parent fractional indices in current created_hlc order, so the
|
|
27
|
-
* displayed document order is unchanged until the user first drags something.
|
|
28
|
-
*/
|
|
29
|
-
export declare function migrateDocuments(db: Database): void;
|
|
30
4
|
/** Open (and migrate) the on-disk metahub database for the resolved home. */
|
|
31
5
|
export declare function openMetahub(): Database;
|
|
32
6
|
//# sourceMappingURL=db.d.ts.map
|
package/dist/core/db.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"db.d.ts","sourceRoot":"","sources":["../../src/core/db.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAOtC,
|
|
1
|
+
{"version":3,"file":"db.d.ts","sourceRoot":"","sources":["../../src/core/db.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAOtC,OAAO,EACL,SAAS,EACT,YAAY,EACZ,cAAc,EACd,YAAY,EACZ,gBAAgB,EAChB,gBAAgB,EAChB,YAAY,EACZ,UAAU,GACX,MAAM,kBAAkB,CAAC;AAE1B,wBAAgB,UAAU,IAAI,IAAI,CAGjC;AAED,6EAA6E;AAC7E,wBAAgB,WAAW,IAAI,QAAQ,CAMtC"}
|
package/dist/core/documents.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { DbDriver } from "./driver.ts";
|
|
2
2
|
export interface DocumentRow {
|
|
3
3
|
id: string;
|
|
4
4
|
title: string;
|
|
@@ -9,35 +9,48 @@ export interface DocumentRow {
|
|
|
9
9
|
order_key: string | null;
|
|
10
10
|
}
|
|
11
11
|
export type DocumentSummary = Omit<DocumentRow, "body">;
|
|
12
|
+
export declare const DOCUMENT_COLS: readonly ["id", "title", "body", "database_id", "parent_id", "created_hlc", "order_key"];
|
|
12
13
|
/** Max HLC over a document's own register and all its blocks — a read/edit token. */
|
|
13
|
-
export declare function documentVersion(db:
|
|
14
|
-
export declare
|
|
14
|
+
export declare function documentVersion(db: DbDriver, id: string): string;
|
|
15
|
+
export declare const createDocument: (db: DbDriver, opts: {
|
|
15
16
|
title: string;
|
|
16
17
|
body?: string;
|
|
17
18
|
database_id?: string;
|
|
18
19
|
parent_id?: string;
|
|
19
|
-
})
|
|
20
|
-
export declare function getDocument(db:
|
|
21
|
-
export declare function listDocuments(db:
|
|
20
|
+
}) => DocumentRow;
|
|
21
|
+
export declare function getDocument(db: DbDriver, id: string): DocumentRow | null;
|
|
22
|
+
export declare function listDocuments(db: DbDriver, opts?: {
|
|
22
23
|
database_id?: string;
|
|
23
24
|
parent_id?: string;
|
|
24
25
|
}): DocumentSummary[];
|
|
25
26
|
/** Backfill order_key for every parent group that has un-keyed live documents. */
|
|
26
|
-
export declare
|
|
27
|
+
export declare const backfillDocumentOrderKeys: (db: DbDriver) => void;
|
|
27
28
|
/**
|
|
28
29
|
* Move a document next to / into another, atomically updating both its parent
|
|
29
30
|
* and its order_key. `into` nests it as the last child of `targetId`;
|
|
30
31
|
* `before`/`after` re-orders (and reparents if needed) among the target's siblings.
|
|
31
32
|
*/
|
|
32
|
-
export declare
|
|
33
|
-
|
|
33
|
+
export declare const moveDocument: (db: DbDriver, id: string, targetId: string, where: "before" | "after" | "into") => DocumentRow;
|
|
34
|
+
/**
|
|
35
|
+
* Copy a document — title, every block (verbatim, with fresh block ids so the
|
|
36
|
+
* copy edits independently) and its `database_id`/`parent_id`. The copy lands
|
|
37
|
+
* right after its source in the same sibling scope. Blocks are cloned at the
|
|
38
|
+
* block level (not via a markdown round-trip) so empty list items / blank-line
|
|
39
|
+
* runs survive losslessly. `title`/`parentId` override the defaults; the locale
|
|
40
|
+
* "copy" suffix is the caller's job. `created_hlc` is the copy's own birth time.
|
|
41
|
+
*/
|
|
42
|
+
export declare const duplicateDocument: (db: DbDriver, id: string, opts?: {
|
|
43
|
+
title?: string;
|
|
44
|
+
parentId?: string | null;
|
|
45
|
+
} | undefined) => DocumentRow;
|
|
46
|
+
export declare const updateDocument: (db: DbDriver, id: string, fields: {
|
|
34
47
|
title?: string;
|
|
35
48
|
body?: string;
|
|
36
49
|
database_id?: string;
|
|
37
50
|
parent_id?: string | null;
|
|
38
51
|
}, opts?: {
|
|
39
52
|
ifMatch?: string;
|
|
40
|
-
})
|
|
53
|
+
} | undefined) => DocumentRow;
|
|
41
54
|
export interface EditDocResult {
|
|
42
55
|
id: string;
|
|
43
56
|
changed: boolean;
|
|
@@ -50,13 +63,13 @@ export interface EditDocResult {
|
|
|
50
63
|
* cannot author it without current content, and drift surfaces as "not found".
|
|
51
64
|
* `ifMatch` is an optional staleness backstop (a version from documentVersion).
|
|
52
65
|
*/
|
|
53
|
-
export declare
|
|
66
|
+
export declare const editDocument: (db: DbDriver, id: string, opts: {
|
|
54
67
|
old: string;
|
|
55
68
|
new: string;
|
|
56
69
|
replaceAll?: boolean;
|
|
57
70
|
ifMatch?: string;
|
|
58
|
-
})
|
|
59
|
-
export declare
|
|
60
|
-
export declare
|
|
61
|
-
export declare
|
|
71
|
+
}) => EditDocResult;
|
|
72
|
+
export declare const appendDocument: (db: DbDriver, id: string, body: string) => EditDocResult;
|
|
73
|
+
export declare const prependDocument: (db: DbDriver, id: string, body: string) => EditDocResult;
|
|
74
|
+
export declare const deleteDocument: (db: DbDriver, id: string) => boolean;
|
|
62
75
|
//# sourceMappingURL=documents.d.ts.map
|