@telepath-computer/vault-server 0.4.2 → 0.5.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 +136 -83
- package/dist/src/cli.js +38 -20
- package/dist/src/cli.js.map +1 -1
- package/dist/src/notes.d.ts +12 -8
- package/dist/src/notes.js +76 -85
- package/dist/src/notes.js.map +1 -1
- package/dist/src/server.d.ts +42 -38
- package/dist/src/server.js +563 -411
- package/dist/src/server.js.map +1 -1
- package/package.json +6 -6
- package/skill/SKILL.md +116 -0
- package/dist/src/paths.d.ts +0 -8
- package/dist/src/paths.js +0 -44
- package/dist/src/paths.js.map +0 -1
package/README.md
CHANGED
|
@@ -1,44 +1,49 @@
|
|
|
1
1
|
# sv-vault
|
|
2
2
|
|
|
3
|
-
`sv-vault`
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
It follows Obsidian's conventions (YAML headers, wikilink references) but
|
|
8
|
-
never requires Obsidian itself: point it at any directory of markdown.
|
|
9
|
-
|
|
10
|
-
The URL space mirrors the vault: every file serves at its own path, and
|
|
11
|
-
dropping a markdown file's `.md` extension addresses it as structured JSON —
|
|
12
|
-
header parsed into fields, field references resolved. Directory URLs list records; a
|
|
13
|
-
WebSocket upgrade on `/` streams change events. `spec/vault/` at the repository root is the full contract;
|
|
14
|
-
this README shows the working surface.
|
|
3
|
+
`sv-vault` serves a directory over HTTP and WebSocket as files, directories,
|
|
4
|
+
and structured markdown records. It extends the `sv-files` protocol, so every
|
|
5
|
+
base file operation remains available while a markdown file also gains an
|
|
6
|
+
extensionless JSON resource.
|
|
15
7
|
|
|
16
8
|
## Install and run
|
|
17
9
|
|
|
18
|
-
Node.js 24 or later.
|
|
10
|
+
Node.js 24 or later is required.
|
|
19
11
|
|
|
20
12
|
```sh
|
|
21
13
|
npm install -g @telepath-computer/vault-server
|
|
22
|
-
sv-vault
|
|
23
|
-
sv-vault /path/to/vault
|
|
14
|
+
sv-vault
|
|
15
|
+
sv-vault /path/to/vault
|
|
24
16
|
```
|
|
25
17
|
|
|
26
|
-
|
|
18
|
+
The default address is `http://127.0.0.1:4747`. `--host` changes the bind
|
|
19
|
+
address and `--port` selects a port. Without `--port`, the server tries ports
|
|
20
|
+
4747 through 4846.
|
|
27
21
|
|
|
28
|
-
The server
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
call it directly.
|
|
22
|
+
The server has no authentication and allows HTTP requests from any origin.
|
|
23
|
+
Keep the default localhost binding unless another boundary protects the
|
|
24
|
+
service.
|
|
32
25
|
|
|
33
|
-
##
|
|
26
|
+
## Resources
|
|
34
27
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
28
|
+
Every visible regular file is available at its literal path with the complete
|
|
29
|
+
`sv-files` behavior: media types, ranges, validators, byte `PUT`, anchored text
|
|
30
|
+
`PATCH`, and `DELETE`. A markdown file also has a structured record at the path
|
|
31
|
+
without the final `.md` suffix.
|
|
32
|
+
|
|
33
|
+
For a path without a trailing slash, `GET` and `HEAD` select the first existing
|
|
34
|
+
resource in this order:
|
|
35
|
+
|
|
36
|
+
1. the exact regular file;
|
|
37
|
+
2. the record backed by `<path>.md`;
|
|
38
|
+
3. the exact directory;
|
|
39
|
+
4. `404 Not Found`.
|
|
40
40
|
|
|
41
|
-
A
|
|
41
|
+
A trailing slash selects only the exact directory. Use it whenever a directory
|
|
42
|
+
shares a name with a record. An exact regular file shadows the same-named
|
|
43
|
+
record, while a directory does not. Appending `.md` to a record URL addresses
|
|
44
|
+
its literal source file.
|
|
45
|
+
|
|
46
|
+
Record JSON has this shape:
|
|
42
47
|
|
|
43
48
|
```json
|
|
44
49
|
{
|
|
@@ -47,77 +52,125 @@ A record's JSON view:
|
|
|
47
52
|
"status": "open",
|
|
48
53
|
"contact": { "$type": "ref", "path": "contacts/jane-doe" }
|
|
49
54
|
},
|
|
50
|
-
"body": "
|
|
55
|
+
"body": "Text below the header.\n",
|
|
51
56
|
"links": [{ "path": "contacts/jane-doe", "field": "contact" }],
|
|
52
57
|
"updated": "2026-08-07T09:15:00.000Z"
|
|
53
58
|
}
|
|
54
59
|
```
|
|
55
60
|
|
|
56
|
-
`
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
"path": … }` — the target's API path, fetchable here — plus a `label` when
|
|
61
|
-
the link's rendered text differs. Prose inside
|
|
62
|
-
`body` serves as standard markdown — wikilinks come out as resolved
|
|
63
|
-
relative links, so any renderer navigates them against these same URLs.
|
|
64
|
-
`links` lists every resolved record link touching this record: outbound
|
|
65
|
-
entries name their target, while entries with `backlink: true` name their
|
|
66
|
-
source. `field` identifies the top-level header key; prose links omit it.
|
|
67
|
-
If the frontmatter is invalid, the whole file is returned as `body` with
|
|
68
|
-
empty `fields`, and the record carries `error: { "code":
|
|
69
|
-
"invalid_frontmatter", "message": "Frontmatter could not be parsed" }`.
|
|
70
|
-
|
|
71
|
-
## Query
|
|
72
|
-
|
|
73
|
-
A trailing slash lists a directory's records recursively as
|
|
74
|
-
`{ path, fields, body?, updated, error? }`; `body` remains beside `fields`,
|
|
75
|
-
while the single-record `links` list is omitted. There are no query parameters;
|
|
76
|
-
filter and sort in JS:
|
|
61
|
+
Record `GET` and `HEAD` responses, and the record bodies returned by successful
|
|
62
|
+
`PUT` and `PATCH`, use
|
|
63
|
+
`application/vnd.telepath.record+json; charset=utf-8`. A JSON asset at its
|
|
64
|
+
literal file path keeps its ordinary JSON media type.
|
|
77
65
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
66
|
+
`body` is omitted when no non-whitespace text is present. References in fields
|
|
67
|
+
are objects with `$type: "ref"`; fetch their `path` to follow them. `links`
|
|
68
|
+
contains resolved outgoing links and backlinks and appears only on a
|
|
69
|
+
single-record read. Invalid frontmatter produces empty `fields`, the entire
|
|
70
|
+
source as `body`, and `error.code: "invalid_frontmatter"`. A markdown file that
|
|
71
|
+
is not UTF-8 returns `422` at the record URL and remains readable at its raw
|
|
72
|
+
URL.
|
|
73
|
+
|
|
74
|
+
## Directory listings
|
|
75
|
+
|
|
76
|
+
A directory `GET`, with or without a trailing slash, returns the base envelope:
|
|
77
|
+
|
|
78
|
+
```json
|
|
79
|
+
{
|
|
80
|
+
"path": "projects",
|
|
81
|
+
"entries": [
|
|
82
|
+
{ "name": "archive", "type": "dir" },
|
|
83
|
+
{ "name": "diagram.png", "type": "file", "size": 18432, "modified": "2026-08-07T09:10:00.000Z" },
|
|
84
|
+
{
|
|
85
|
+
"name": "roadmap",
|
|
86
|
+
"type": "record",
|
|
87
|
+
"modified": "2026-08-07T09:15:00.000Z",
|
|
88
|
+
"fields": { "status": "open" },
|
|
89
|
+
"body": "Next milestone.\n"
|
|
90
|
+
}
|
|
91
|
+
]
|
|
92
|
+
}
|
|
83
93
|
```
|
|
84
94
|
|
|
85
|
-
|
|
95
|
+
Listings contain immediate children. Base `file`, `dir`, and `link` entries are
|
|
96
|
+
unchanged. A `record` entry contains the full single-record representation
|
|
97
|
+
without `links`: `path` becomes the extensionless `name` relative to the listed
|
|
98
|
+
directory, `updated` becomes `modified`, and `type` is `record`. `fields` is
|
|
99
|
+
always present. `body` and `error` follow the same omission rules as a
|
|
100
|
+
single-record read. Record entries have no `size`.
|
|
86
101
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
same kind of URL; the request body is the record's
|
|
91
|
-
`{ fields, body }` — the header object and the text below it, sent
|
|
92
|
-
separately as they are served. PATCH merge-patches `fields` (`null` deletes a
|
|
93
|
-
field) and replaces `body` only when that sibling key is present (`null`
|
|
94
|
-
removes it):
|
|
102
|
+
Entry names are sorted by JavaScript string order, then by `type` when names
|
|
103
|
+
match. Joining the envelope `path` and an entry `name` forms the resource URL;
|
|
104
|
+
append `/` to select a directory that shares a record name.
|
|
95
105
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
106
|
+
Query parameters do not change directory listings. Filtering, paging, search,
|
|
107
|
+
alternate sorting, and recursive traversal remain client work. Consumers of
|
|
108
|
+
the former recursive record dump walk `dir` entries and use each full `record`
|
|
109
|
+
entry in place as its directory is fetched. This one-level response does not
|
|
110
|
+
imply a future deeper representation.
|
|
111
|
+
|
|
112
|
+
## Mutations
|
|
113
|
+
|
|
114
|
+
Send record `PUT` and `PATCH` requests to the extensionless path with
|
|
115
|
+
`Content-Type: application/vnd.telepath.record+json`. Matching is
|
|
116
|
+
case-insensitive and permits media-type parameters. The body is
|
|
117
|
+
`{ "fields": <object>, "body": <string|null> }`; other keys are ignored.
|
|
118
|
+
|
|
119
|
+
`PATCH` applies JSON merge-patch semantics to `fields` and changes `body` only
|
|
120
|
+
when supplied. `PUT` replaces all fields and the body, creating parent
|
|
121
|
+
directories when required. Successful writes return the current record.
|
|
122
|
+
`DELETE` follows the same exact-file, record, then directory resolution order
|
|
123
|
+
as reads. Record writes are atomic and last-write-wins.
|
|
124
|
+
|
|
125
|
+
A `PUT` without the record media type writes bytes to the literal URL. For
|
|
126
|
+
`PUT` and `PATCH`, a literal `.md` path always uses the base file behavior. A
|
|
127
|
+
double-suffixed source such as `note.md.md` therefore has the readable and
|
|
128
|
+
deletable record URL `/note.md`, but record `PUT` and `PATCH` cannot target it.
|
|
129
|
+
If an exact regular file shadows a record URL, a record `PUT` or `PATCH`
|
|
130
|
+
returns `409`.
|
|
131
|
+
|
|
132
|
+
## Change stream
|
|
133
|
+
|
|
134
|
+
Open a WebSocket at `/` or at any existing slash-terminated directory URL. The
|
|
135
|
+
subscription is root-wide. Each message is a dirty signal:
|
|
136
|
+
|
|
137
|
+
```json
|
|
138
|
+
{ "type": "modified", "path": "journal/today" }
|
|
102
139
|
```
|
|
103
140
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
141
|
+
Types are `created`, `modified`, and `deleted`. A markdown source normally
|
|
142
|
+
signals its extensionless record path. When an exact regular file shadows that
|
|
143
|
+
record, the signal retains the literal `.md` path. Signals have no content,
|
|
144
|
+
history, cursor, or replay: connect, fetch initial state, refetch on messages,
|
|
145
|
+
and fetch again after reconnecting.
|
|
146
|
+
|
|
147
|
+
Dot-prefixed paths are absent from reads, listings, writes, and signals.
|
|
107
148
|
|
|
108
|
-
##
|
|
149
|
+
## Programmatic API
|
|
109
150
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
151
|
+
The package exports `VaultServer`. Its constructor accepts `root`,
|
|
152
|
+
`pingIntervalMs`, `linkFormat`, `bodyFormat`, `jsonLimit`, and `validate`.
|
|
153
|
+
Instances expose `ready`, `listen`, `close`, `url`, `port`, `app`, `server`,
|
|
154
|
+
`handleUpgrade`, the live `paths` iterable, and `configure({ linkFormat?,
|
|
155
|
+
bodyFormat? })`. `ready` includes both the base watcher and the initial record
|
|
156
|
+
index.
|
|
113
157
|
|
|
114
158
|
```js
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
159
|
+
import { VaultServer } from "@telepath-computer/vault-server";
|
|
160
|
+
|
|
161
|
+
const server = new VaultServer({ root: "/path/to/vault" });
|
|
162
|
+
await server.listen({ port: 4747 });
|
|
163
|
+
console.log(server.url);
|
|
120
164
|
```
|
|
121
165
|
|
|
122
|
-
|
|
123
|
-
|
|
166
|
+
## Confinement
|
|
167
|
+
|
|
168
|
+
Every request is confined beneath the resolved root, and symbolic links are
|
|
169
|
+
never served. The check is canonical-path check-then-act: a hostile local
|
|
170
|
+
process could replace an intermediate directory with a symbolic link between
|
|
171
|
+
the check and the operation. This race is not reachable through server
|
|
172
|
+
operations. Use kernel-enforced confinement when the threat model includes a
|
|
173
|
+
hostile local process. Hard links and bind mounts are outside this boundary.
|
|
174
|
+
|
|
175
|
+
The complete contract is in [`spec/vault/`](../../spec/vault/), read together
|
|
176
|
+
with [`spec/files/server.md`](../../spec/files/server.md).
|
package/dist/src/cli.js
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/** Parses the small CLI surface and starts sv-vault. */
|
|
3
3
|
import { realpathSync, readFileSync } from "node:fs";
|
|
4
|
-
import { stat } from "node:fs/promises";
|
|
4
|
+
import { realpath, stat } from "node:fs/promises";
|
|
5
|
+
import { homedir } from "node:os";
|
|
5
6
|
import { dirname, join, resolve } from "node:path";
|
|
6
7
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
7
8
|
import { VaultServer } from "./server.js";
|
|
8
9
|
const usage = `Usage: sv-vault [path] [options]
|
|
9
10
|
|
|
10
|
-
Serve
|
|
11
|
+
Serve a live vault as files and structured markdown records.
|
|
11
12
|
|
|
12
13
|
path vault root (default: current directory)
|
|
13
14
|
--host bind address (default: 127.0.0.1)
|
|
@@ -18,14 +19,14 @@ Serve an Obsidian vault — or any folder of markdown — as JSON over HTTP.
|
|
|
18
19
|
const version = readPackageVersion();
|
|
19
20
|
export function parseCliArguments(argumentsList) {
|
|
20
21
|
let host = "127.0.0.1";
|
|
21
|
-
let
|
|
22
|
+
let portText;
|
|
22
23
|
let vaultRoot;
|
|
23
24
|
for (let index = 0; index < argumentsList.length; index += 1) {
|
|
24
25
|
const argument = argumentsList[index];
|
|
25
26
|
if (argument === "--host")
|
|
26
27
|
host = requireValue(argumentsList, ++index, argument);
|
|
27
28
|
else if (argument === "--port")
|
|
28
|
-
|
|
29
|
+
portText = requireValue(argumentsList, ++index, argument);
|
|
29
30
|
else if (argument.startsWith("--"))
|
|
30
31
|
throw new CliArgumentError(`unknown argument ${argument}`, true);
|
|
31
32
|
else if (vaultRoot === undefined)
|
|
@@ -33,10 +34,18 @@ export function parseCliArguments(argumentsList) {
|
|
|
33
34
|
else
|
|
34
35
|
throw new CliArgumentError(`unknown argument ${argument}`, true);
|
|
35
36
|
}
|
|
36
|
-
if (
|
|
37
|
-
throw new CliArgumentError("port must be
|
|
37
|
+
if (portText !== undefined && !/^\d+$/.test(portText)) {
|
|
38
|
+
throw new CliArgumentError("port must be a decimal integer from 0 to 65535");
|
|
38
39
|
}
|
|
39
|
-
|
|
40
|
+
const port = portText === undefined ? undefined : Number(portText);
|
|
41
|
+
if (port !== undefined && port > 65_535) {
|
|
42
|
+
throw new CliArgumentError("port must be a decimal integer from 0 to 65535");
|
|
43
|
+
}
|
|
44
|
+
return {
|
|
45
|
+
host,
|
|
46
|
+
...(port === undefined ? {} : { port }),
|
|
47
|
+
vaultRoot: resolve(expandLeadingTilde(vaultRoot ?? process.cwd())),
|
|
48
|
+
};
|
|
40
49
|
}
|
|
41
50
|
export async function main(argumentsList = process.argv.slice(2)) {
|
|
42
51
|
if (argumentsList.includes("--help")) {
|
|
@@ -48,9 +57,10 @@ export async function main(argumentsList = process.argv.slice(2)) {
|
|
|
48
57
|
return;
|
|
49
58
|
}
|
|
50
59
|
const options = parseCliArguments(argumentsList);
|
|
51
|
-
|
|
60
|
+
const canonicalRoot = await canonicalDirectory(options.vaultRoot);
|
|
61
|
+
if (canonicalRoot === undefined)
|
|
52
62
|
throw new Error(`${options.vaultRoot} is not a directory`);
|
|
53
|
-
const vaultServer = new VaultServer({ root:
|
|
63
|
+
const vaultServer = new VaultServer({ root: canonicalRoot });
|
|
54
64
|
try {
|
|
55
65
|
await vaultServer.listen(options.port === undefined ? { host: options.host } : { host: options.host, port: options.port });
|
|
56
66
|
}
|
|
@@ -64,7 +74,7 @@ export async function main(argumentsList = process.argv.slice(2)) {
|
|
|
64
74
|
for (const path of vaultServer.paths)
|
|
65
75
|
if (path.endsWith(".md"))
|
|
66
76
|
recordCount += 1;
|
|
67
|
-
writeStartup(
|
|
77
|
+
writeStartup(canonicalRoot, vaultServer.url, recordCount);
|
|
68
78
|
const shutdown = () => {
|
|
69
79
|
void vaultServer.close().catch(() => undefined).then(() => { process.exitCode = 0; });
|
|
70
80
|
};
|
|
@@ -89,13 +99,29 @@ function requireValue(values, index, flag) {
|
|
|
89
99
|
throw new CliArgumentError(`${flag} requires a value`);
|
|
90
100
|
return value;
|
|
91
101
|
}
|
|
92
|
-
function
|
|
102
|
+
function expandLeadingTilde(path) {
|
|
103
|
+
if (path === "~")
|
|
104
|
+
return homedir();
|
|
105
|
+
if (path.startsWith("~/"))
|
|
106
|
+
return join(homedir(), path.slice(2));
|
|
107
|
+
return path;
|
|
108
|
+
}
|
|
109
|
+
async function canonicalDirectory(path) {
|
|
110
|
+
try {
|
|
111
|
+
const canonicalPath = await realpath(path);
|
|
112
|
+
return (await stat(canonicalPath)).isDirectory() ? canonicalPath : undefined;
|
|
113
|
+
}
|
|
114
|
+
catch {
|
|
115
|
+
return undefined;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
function writeStartup(vaultRoot, url, noteCount) {
|
|
93
119
|
const color = process.stdout.isTTY === true && process.env.NO_COLOR === undefined;
|
|
94
120
|
const bold = (value) => color ? `\x1b[1m${value}\x1b[22m` : value;
|
|
95
121
|
const dim = (value) => color ? `\x1b[2m${value}\x1b[22m` : value;
|
|
96
122
|
const cyan = (value) => color ? `\x1b[36m${value}\x1b[39m` : value;
|
|
97
123
|
const count = noteCount.toLocaleString("en-US");
|
|
98
|
-
process.stdout.write(`${bold("sv-vault")} ${version}\n${dim("vault:")} ${vaultRoot} ${dim(`(${count} records)`)}\n${dim("url:")} ${cyan(
|
|
124
|
+
process.stdout.write(`${bold("sv-vault")} ${version}\n${dim("vault:")} ${vaultRoot} ${dim(`(${count} records)`)}\n${dim("url:")} ${cyan(url)}\n`);
|
|
99
125
|
}
|
|
100
126
|
function writeError(error) {
|
|
101
127
|
const color = process.stderr.isTTY === true && process.env.NO_COLOR === undefined;
|
|
@@ -120,14 +146,6 @@ function readPackageVersion() {
|
|
|
120
146
|
directory = parent;
|
|
121
147
|
}
|
|
122
148
|
}
|
|
123
|
-
async function isDirectory(path) {
|
|
124
|
-
try {
|
|
125
|
-
return (await stat(path)).isDirectory();
|
|
126
|
-
}
|
|
127
|
-
catch {
|
|
128
|
-
return false;
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
149
|
function isErrorCode(error, code) {
|
|
132
150
|
return error !== null && typeof error === "object" && "code" in error && error.code === code;
|
|
133
151
|
}
|
package/dist/src/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../../src/cli.ts"],"names":[],"mappings":";AACA,wDAAwD;AACxD,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACrD,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../../src/cli.ts"],"names":[],"mappings":"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"}
|
package/dist/src/notes.d.ts
CHANGED
|
@@ -58,6 +58,14 @@ export declare class VaultIndex {
|
|
|
58
58
|
isRawBody(linkingNotePath: string): boolean;
|
|
59
59
|
add(absolutePath: string): void;
|
|
60
60
|
delete(absolutePath: string): void;
|
|
61
|
+
/** Remove one path and every indexed descendant after a file or directory deletion. */
|
|
62
|
+
deleteTree(absolutePath: string): void;
|
|
63
|
+
/** The URL path that can fetch this indexed file under the resolution ladder. */
|
|
64
|
+
apiPathFor(diskPath: string): string;
|
|
65
|
+
/** Whether a markdown source currently has an addressable structured-record view. */
|
|
66
|
+
isRecordPath(diskPath: string): boolean;
|
|
67
|
+
/** Whether any indexed file is nested beneath a directory-shaped path. */
|
|
68
|
+
hasDescendant(diskPath: string): boolean;
|
|
61
69
|
/** Read and cache a record after an add or change event. */
|
|
62
70
|
refresh(absolutePath: string): Promise<RefreshOutcome>;
|
|
63
71
|
/** Return a structured record entirely from cached data. */
|
|
@@ -66,8 +74,8 @@ export declare class VaultIndex {
|
|
|
66
74
|
updateFromNote(note: Pick<Note, "updated" | "error">, absolutePath: string, rawRecord: RecordContent, source: string): void;
|
|
67
75
|
/** Return this record's outbound links followed by links made to it. */
|
|
68
76
|
linksFor(linkingNotePath: string): LinkEntry[];
|
|
69
|
-
/** Return cached
|
|
70
|
-
|
|
77
|
+
/** Return one cached record in the listing form, or undefined when it has no record view. */
|
|
78
|
+
listingEntry(diskPath: string): ListingEntry | undefined;
|
|
71
79
|
/** Resolve a wikilink target against the indexed visible files. */
|
|
72
80
|
resolveReference(linkingNotePath: string, target: string): string | null;
|
|
73
81
|
/** Resolve an already vault-relative markdown target without suffix matching. */
|
|
@@ -90,12 +98,8 @@ export declare class InvalidReferenceError extends Error {
|
|
|
90
98
|
}
|
|
91
99
|
/** Return a record from the index's cached parsed data. */
|
|
92
100
|
export declare function readNote(_vaultRoot: string, absolutePath: string, index: VaultIndex): Promise<Note>;
|
|
93
|
-
/** Serialize
|
|
94
|
-
export declare function
|
|
95
|
-
/** Delete a note from disk. */
|
|
96
|
-
export declare function deleteNote(absolutePath: string, index: VaultIndex): Promise<void>;
|
|
97
|
-
/** List cached markdown note metadata beneath a vault-relative directory. */
|
|
98
|
-
export declare function listNotes(index: VaultIndex, directory: string): ListingEntry[];
|
|
101
|
+
/** Serialize a record for replacement through the base file-server atomic write. */
|
|
102
|
+
export declare function serializeNote(absolutePath: string, record: RecordContent, fieldPatch?: Fields, bodyTouched?: boolean, preservedBody?: string): Promise<string>;
|
|
99
103
|
/** Enforce the API-wide reservation of objects carrying $type. */
|
|
100
104
|
export declare function validateReferenceObjects(fields: Fields): void;
|
|
101
105
|
/**
|