obsidian-mcp-server 3.7.0 → 3.7.2
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/AGENTS.md +31 -11
- package/CLAUDE.md +31 -11
- package/Dockerfile +10 -3
- package/README.md +30 -91
- package/changelog/3.7.x/3.7.1.md +40 -0
- package/changelog/3.7.x/3.7.2.md +34 -0
- package/dist/config/server-config.js +1 -1
- package/dist/config/server-config.js.map +1 -1
- package/dist/index.js +13 -32
- package/dist/index.js.map +1 -1
- package/dist/instructions.d.ts +20 -0
- package/dist/instructions.d.ts.map +1 -0
- package/dist/instructions.js +40 -0
- package/dist/instructions.js.map +1 -0
- package/dist/mcp-server/tools/definitions/_shared/markdown.d.ts +14 -0
- package/dist/mcp-server/tools/definitions/_shared/markdown.d.ts.map +1 -0
- package/dist/mcp-server/tools/definitions/_shared/markdown.js +17 -0
- package/dist/mcp-server/tools/definitions/_shared/markdown.js.map +1 -0
- package/dist/mcp-server/tools/definitions/_shared/suggest-paths.d.ts +39 -0
- package/dist/mcp-server/tools/definitions/_shared/suggest-paths.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/_shared/suggest-paths.js +63 -2
- package/dist/mcp-server/tools/definitions/_shared/suggest-paths.js.map +1 -1
- package/dist/mcp-server/tools/definitions/index.d.ts +127 -116
- package/dist/mcp-server/tools/definitions/index.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/obsidian-append-to-note.tool.d.ts +6 -0
- package/dist/mcp-server/tools/definitions/obsidian-append-to-note.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/obsidian-append-to-note.tool.js +15 -6
- package/dist/mcp-server/tools/definitions/obsidian-append-to-note.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/obsidian-delete-note.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/obsidian-delete-note.tool.js +5 -4
- package/dist/mcp-server/tools/definitions/obsidian-delete-note.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/obsidian-execute-command.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/obsidian-execute-command.tool.js +2 -1
- package/dist/mcp-server/tools/definitions/obsidian-execute-command.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/obsidian-get-note.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/obsidian-get-note.tool.js +51 -40
- package/dist/mcp-server/tools/definitions/obsidian-get-note.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/obsidian-list-commands.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/obsidian-list-commands.tool.js +7 -4
- package/dist/mcp-server/tools/definitions/obsidian-list-commands.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/obsidian-list-notes.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/obsidian-list-notes.tool.js +7 -6
- package/dist/mcp-server/tools/definitions/obsidian-list-notes.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/obsidian-list-tags.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/obsidian-list-tags.tool.js +3 -2
- package/dist/mcp-server/tools/definitions/obsidian-list-tags.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/obsidian-manage-frontmatter.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/obsidian-manage-frontmatter.tool.js +13 -9
- package/dist/mcp-server/tools/definitions/obsidian-manage-frontmatter.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/obsidian-manage-tags.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/obsidian-manage-tags.tool.js +9 -5
- package/dist/mcp-server/tools/definitions/obsidian-manage-tags.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/obsidian-open-in-ui.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/obsidian-open-in-ui.tool.js +2 -1
- package/dist/mcp-server/tools/definitions/obsidian-open-in-ui.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/obsidian-patch-note.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/obsidian-patch-note.tool.js +5 -4
- package/dist/mcp-server/tools/definitions/obsidian-patch-note.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/obsidian-replace-in-note.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/obsidian-replace-in-note.tool.js +12 -4
- package/dist/mcp-server/tools/definitions/obsidian-replace-in-note.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/obsidian-search-notes.tool.d.ts +26 -2
- package/dist/mcp-server/tools/definitions/obsidian-search-notes.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/obsidian-search-notes.tool.js +61 -34
- package/dist/mcp-server/tools/definitions/obsidian-search-notes.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/obsidian-write-note.tool.d.ts +5 -0
- package/dist/mcp-server/tools/definitions/obsidian-write-note.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/obsidian-write-note.tool.js +24 -6
- package/dist/mcp-server/tools/definitions/obsidian-write-note.tool.js.map +1 -1
- package/dist/services/obsidian/frontmatter-ops.d.ts +15 -1
- package/dist/services/obsidian/frontmatter-ops.d.ts.map +1 -1
- package/dist/services/obsidian/frontmatter-ops.js +55 -10
- package/dist/services/obsidian/frontmatter-ops.js.map +1 -1
- package/dist/services/obsidian/jsonlogic-evaluator.d.ts +83 -0
- package/dist/services/obsidian/jsonlogic-evaluator.d.ts.map +1 -0
- package/dist/services/obsidian/jsonlogic-evaluator.js +192 -0
- package/dist/services/obsidian/jsonlogic-evaluator.js.map +1 -0
- package/dist/services/obsidian/jsonlogic-worker.d.ts +53 -0
- package/dist/services/obsidian/jsonlogic-worker.d.ts.map +1 -0
- package/dist/services/obsidian/jsonlogic-worker.js +237 -0
- package/dist/services/obsidian/jsonlogic-worker.js.map +1 -0
- package/dist/services/obsidian/obsidian-service.d.ts +56 -8
- package/dist/services/obsidian/obsidian-service.d.ts.map +1 -1
- package/dist/services/obsidian/obsidian-service.js +254 -48
- package/dist/services/obsidian/obsidian-service.js.map +1 -1
- package/dist/services/obsidian/path-policy.d.ts +33 -5
- package/dist/services/obsidian/path-policy.d.ts.map +1 -1
- package/dist/services/obsidian/path-policy.js +99 -17
- package/dist/services/obsidian/path-policy.js.map +1 -1
- package/dist/services/obsidian/types.d.ts +12 -3
- package/dist/services/obsidian/types.d.ts.map +1 -1
- package/manifest.json +2 -2
- package/package.json +20 -15
- package/server.json +5 -5
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Server-side JSONLogic evaluation for searches scoped by
|
|
3
|
+
* OBSIDIAN_READ_PATHS. The caller's tree runs here, on a worker thread, over
|
|
4
|
+
* the readable notes alone, instead of upstream over the whole vault: no hit,
|
|
5
|
+
* result, or error reads a note outside the read scope. The notes' link
|
|
6
|
+
* fields arrive cut to readable entries, but which note a link resolves to is
|
|
7
|
+
* still Obsidian's vault-wide resolution (#165).
|
|
8
|
+
*
|
|
9
|
+
* Every evaluation is bounded — tree depth, work budgets the worker enforces
|
|
10
|
+
* (per note for what each note's evaluation builds, per search for what kept
|
|
11
|
+
* results hold past a 1,024-character allowance each), and a wall-clock
|
|
12
|
+
* deadline — and an evaluation past a bound fails with `logic_too_costly`
|
|
13
|
+
* rather than holding the process. A note nested too deep to hand to the
|
|
14
|
+
* worker fails with `note_too_deep`.
|
|
15
|
+
*
|
|
16
|
+
* @module services/obsidian/jsonlogic-evaluator
|
|
17
|
+
*/
|
|
18
|
+
import { Worker } from 'node:worker_threads';
|
|
19
|
+
import { serializationError, validationError } from '@cyanheads/mcp-ts-core/errors';
|
|
20
|
+
/**
|
|
21
|
+
* Deepest object/array nesting a tree may have. The plugin evaluates every
|
|
22
|
+
* shape to at least 5,000 levels; this stays well under the depth at which
|
|
23
|
+
* Node's structured clone overflows the stack handing a tree to the worker
|
|
24
|
+
* (about 3,500 levels).
|
|
25
|
+
*/
|
|
26
|
+
export const MAX_TREE_DEPTH = 1_000;
|
|
27
|
+
/**
|
|
28
|
+
* Work units kept results may hold across one search, every batch included
|
|
29
|
+
* (see the worker's `chargeKept`). A result whose JSON is at most 1,024
|
|
30
|
+
* characters is kept free, whatever its note; a larger one pays for what its
|
|
31
|
+
* JSON holds beyond its own note's JSON. Kept results live until the search
|
|
32
|
+
* answers, so this bounds what an evaluation retains, since Bun ignores the
|
|
33
|
+
* worker's `resourceLimits`. What a note's evaluation builds and drops is
|
|
34
|
+
* bounded per note by {@link NOTE_BUILD_UNITS}; evaluation steps that build
|
|
35
|
+
* nothing are bounded by {@link EVALUATION_DEADLINE_MS}, so a tree that only
|
|
36
|
+
* tests note fields spends nothing however many notes it reads.
|
|
37
|
+
*/
|
|
38
|
+
export const KEPT_RESULT_UNITS = 10_000_000;
|
|
39
|
+
/**
|
|
40
|
+
* Work units one note's evaluation may build beyond the note's own size (see
|
|
41
|
+
* the worker's `charge`): the size of every value `merge`, `cat`, or `map`
|
|
42
|
+
* builds and of every value an operator places in an array literal. The
|
|
43
|
+
* allowance resets for each note, since what an evaluation builds is dropped
|
|
44
|
+
* when it ends, so a tree that builds from every note of a broad scope is
|
|
45
|
+
* bounded by its largest note rather than by the scope's total. Adding the
|
|
46
|
+
* note's own size means one copy of a note always fits, at any size a batch
|
|
47
|
+
* carries; the fixed part leaves room for dozens of copies of a 200 KB note
|
|
48
|
+
* while holding what one evaluation can allocate to the note plus
|
|
49
|
+
* 10,000,000 units.
|
|
50
|
+
*/
|
|
51
|
+
export const NOTE_BUILD_UNITS = 10_000_000;
|
|
52
|
+
/** Wall-clock ceiling on one search's evaluation, across its batches, worker startup included. */
|
|
53
|
+
export const EVALUATION_DEADLINE_MS = 10_000;
|
|
54
|
+
/**
|
|
55
|
+
* The worker's module, next to this one: `.js` in the build, `.ts` when the
|
|
56
|
+
* test suite runs the source, which both Bun and Node load directly.
|
|
57
|
+
*/
|
|
58
|
+
const WORKER_URL = new URL(`./jsonlogic-worker.${import.meta.url.endsWith('.ts') ? 'ts' : 'js'}`, import.meta.url);
|
|
59
|
+
/**
|
|
60
|
+
* Whether the plugin would read note bodies for `logic`: its own rule, a
|
|
61
|
+
* substring test for `"content"` on the tree's JSON. A tree without it sees
|
|
62
|
+
* `content` as `""` upstream, so a scoped fetch mirrors the same rule to keep
|
|
63
|
+
* results identical — and it is conservative, firing on the word anywhere.
|
|
64
|
+
*/
|
|
65
|
+
export function readsContent(logic) {
|
|
66
|
+
return JSON.stringify(logic).includes('"content"');
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Reject a tree nested deeper than {@link MAX_TREE_DEPTH} before it reaches
|
|
70
|
+
* anything recursive (serialization, the worker hand-off, evaluation).
|
|
71
|
+
*/
|
|
72
|
+
export function assertTreeDepth(logic) {
|
|
73
|
+
if (nestingDepth(logic, MAX_TREE_DEPTH) > MAX_TREE_DEPTH) {
|
|
74
|
+
throw tooCostly(`The JSONLogic tree nests deeper than ${MAX_TREE_DEPTH.toLocaleString('en-US')} levels.`);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Deepest object/array nesting in `value`, which is level 1, measured until
|
|
79
|
+
* it passes `limit`. Iterative, so it measures data too deep for any
|
|
80
|
+
* recursive walk.
|
|
81
|
+
*/
|
|
82
|
+
function nestingDepth(value, limit = Number.POSITIVE_INFINITY) {
|
|
83
|
+
let deepest = 0;
|
|
84
|
+
const pending = [[value, 1]];
|
|
85
|
+
while (pending.length > 0 && deepest <= limit) {
|
|
86
|
+
const [node, depth] = pending.pop();
|
|
87
|
+
if (node === null || typeof node !== 'object')
|
|
88
|
+
continue;
|
|
89
|
+
deepest = Math.max(deepest, depth);
|
|
90
|
+
for (const child of Object.values(node))
|
|
91
|
+
pending.push([child, depth + 1]);
|
|
92
|
+
}
|
|
93
|
+
return deepest;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* One search's evaluation of `logic`. `evaluate` takes the readable notes in
|
|
97
|
+
* vault order, all at once or in successive batches; the budget for kept
|
|
98
|
+
* results and the deadline span every batch, and each note's build allowance
|
|
99
|
+
* is its own, so batching changes memory use, not results.
|
|
100
|
+
* Each call returns the batch's hits as the plugin's search would: a hit for
|
|
101
|
+
* every truthy result, results shaped by a JSON round trip. It throws
|
|
102
|
+
* `logic_invalid` when the tree fails on a note, `logic_too_costly` past
|
|
103
|
+
* either budget or the deadline, `note_too_deep` for a note the worker
|
|
104
|
+
* hand-off cannot carry, and the abort reason when `signal` aborts first.
|
|
105
|
+
*/
|
|
106
|
+
export function createJsonLogicEvaluation(logic, opts = {}) {
|
|
107
|
+
const { signal, deadlineMs = EVALUATION_DEADLINE_MS } = opts;
|
|
108
|
+
let keptUnitsLeft = KEPT_RESULT_UNITS;
|
|
109
|
+
let msLeft = deadlineMs;
|
|
110
|
+
const pastDeadline = () => tooCostly(`Evaluating the JSONLogic tree over the readable notes ran past ${deadlineMs / 1000} s.`);
|
|
111
|
+
return {
|
|
112
|
+
async evaluate(notes) {
|
|
113
|
+
if (notes.length === 0)
|
|
114
|
+
return [];
|
|
115
|
+
signal?.throwIfAborted();
|
|
116
|
+
if (msLeft <= 0)
|
|
117
|
+
throw pastDeadline();
|
|
118
|
+
const started = performance.now();
|
|
119
|
+
const response = await runWorker({ logic, notes, keptUnits: keptUnitsLeft, noteUnits: NOTE_BUILD_UNITS }, msLeft, pastDeadline, signal);
|
|
120
|
+
msLeft -= performance.now() - started;
|
|
121
|
+
if (response.ok) {
|
|
122
|
+
keptUnitsLeft = response.keptUnitsLeft;
|
|
123
|
+
return response.hits.map((hit) => ({
|
|
124
|
+
filename: hit.filename,
|
|
125
|
+
result: JSON.parse(hit.json),
|
|
126
|
+
}));
|
|
127
|
+
}
|
|
128
|
+
throw failureError(response);
|
|
129
|
+
},
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
function failureError(response) {
|
|
133
|
+
const cause = new Error(response.detail);
|
|
134
|
+
switch (response.failure) {
|
|
135
|
+
case 'invalid_regexp':
|
|
136
|
+
return validationError('A `regexp` operand in the JSONLogic tree did not compile. `regexp` takes `[PATTERN, VALUE]` — with the operands reversed, the note field is compiled as the pattern.', { reason: 'logic_invalid' }, { cause });
|
|
137
|
+
case 'invalid':
|
|
138
|
+
return validationError('The JSONLogic tree could not be evaluated.', { reason: 'logic_invalid' }, { cause });
|
|
139
|
+
case 'over_note_budget':
|
|
140
|
+
return tooCostly(`Evaluating the JSONLogic tree on one readable note built more than the per-note work budget of ${NOTE_BUILD_UNITS.toLocaleString('en-US')} units beyond that note's own size.`);
|
|
141
|
+
case 'over_kept_budget':
|
|
142
|
+
return tooCostly(`The JSONLogic tree's results over the readable notes held more than the search's work budget of ${KEPT_RESULT_UNITS.toLocaleString('en-US')} units: each result over 1,024 characters pays for what it holds beyond its own note's size.`);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
/** One worker per batch, terminated however it ends. */
|
|
146
|
+
async function runWorker(request, deadlineMs, pastDeadline, signal) {
|
|
147
|
+
const worker = new Worker(WORKER_URL);
|
|
148
|
+
const { promise, resolve, reject } = Promise.withResolvers();
|
|
149
|
+
const timer = setTimeout(() => reject(pastDeadline()), deadlineMs);
|
|
150
|
+
const onAbort = () => reject(signal?.reason);
|
|
151
|
+
signal?.addEventListener('abort', onAbort, { once: true });
|
|
152
|
+
worker.once('message', resolve);
|
|
153
|
+
worker.once('error', reject);
|
|
154
|
+
worker.once('exit', (code) => reject(new Error(`JSONLogic worker exited with code ${code} before answering`)));
|
|
155
|
+
try {
|
|
156
|
+
worker.postMessage(request);
|
|
157
|
+
}
|
|
158
|
+
catch (err) {
|
|
159
|
+
// Rejected before the await below takes the promise, so the exit `terminate` raises settles nothing.
|
|
160
|
+
reject(handOffError(err, request.notes));
|
|
161
|
+
}
|
|
162
|
+
try {
|
|
163
|
+
return await promise;
|
|
164
|
+
}
|
|
165
|
+
finally {
|
|
166
|
+
clearTimeout(timer);
|
|
167
|
+
signal?.removeEventListener('abort', onAbort);
|
|
168
|
+
await worker.terminate();
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Why `postMessage` refused a batch. Structured clone recurses, so data
|
|
173
|
+
* nested deep enough overflows the stack: about 3,500 levels under Node,
|
|
174
|
+
* tens of thousands under Bun. The tree is held to {@link MAX_TREE_DEPTH},
|
|
175
|
+
* so the deepest note is the one that did not fit. Any other refusal is
|
|
176
|
+
* returned as it came.
|
|
177
|
+
*/
|
|
178
|
+
function handOffError(err, notes) {
|
|
179
|
+
if (!(err instanceof RangeError))
|
|
180
|
+
return err;
|
|
181
|
+
let deepest = { path: '', levels: 0 };
|
|
182
|
+
for (const note of notes) {
|
|
183
|
+
const levels = nestingDepth(note);
|
|
184
|
+
if (levels > deepest.levels)
|
|
185
|
+
deepest = { path: note.path, levels };
|
|
186
|
+
}
|
|
187
|
+
return serializationError(`The readable note "${deepest.path}" holds data nested ${deepest.levels.toLocaleString('en-US')} levels deep, too deep for the server to hand to its evaluator.`, { reason: 'note_too_deep', path: deepest.path }, { cause: err });
|
|
188
|
+
}
|
|
189
|
+
function tooCostly(message) {
|
|
190
|
+
return validationError(message, { reason: 'logic_too_costly' });
|
|
191
|
+
}
|
|
192
|
+
//# sourceMappingURL=jsonlogic-evaluator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jsonlogic-evaluator.js","sourceRoot":"","sources":["../../../src/services/obsidian/jsonlogic-evaluator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAC7C,OAAO,EAAE,kBAAkB,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAIpF;;;;;GAKG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,KAAK,CAAC;AAEpC;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,UAAU,CAAC;AAE5C;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,UAAU,CAAC;AAE3C,kGAAkG;AAClG,MAAM,CAAC,MAAM,sBAAsB,GAAG,MAAM,CAAC;AAE7C;;;GAGG;AACH,MAAM,UAAU,GAAG,IAAI,GAAG,CACxB,sBAAsB,OAAO,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,EACrE,OAAO,IAAI,CAAC,GAAG,CAChB,CAAC;AAEF;;;;;GAKG;AACH,MAAM,UAAU,YAAY,CAAC,KAAc;IACzC,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;AACrD,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,eAAe,CAAC,KAAc;IAC5C,IAAI,YAAY,CAAC,KAAK,EAAE,cAAc,CAAC,GAAG,cAAc,EAAE,CAAC;QACzD,MAAM,SAAS,CACb,wCAAwC,cAAc,CAAC,cAAc,CAAC,OAAO,CAAC,UAAU,CACzF,CAAC;IACJ,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,SAAS,YAAY,CAAC,KAAc,EAAE,KAAK,GAAG,MAAM,CAAC,iBAAiB;IACpE,IAAI,OAAO,GAAG,CAAC,CAAC;IAChB,MAAM,OAAO,GAA6B,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC;IACvD,OAAO,OAAO,CAAC,MAAM,GAAG,CAAC,IAAI,OAAO,IAAI,KAAK,EAAE,CAAC;QAC9C,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,GAAG,OAAO,CAAC,GAAG,EAAuB,CAAC;QACzD,IAAI,IAAI,KAAK,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ;YAAE,SAAS;QACxD,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;QACnC,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC;YAAE,OAAO,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC;IAC5E,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,yBAAyB,CACvC,KAAc,EACd,IAAI,GAA8D,EAAE;IAEpE,MAAM,EAAE,MAAM,EAAE,UAAU,GAAG,sBAAsB,EAAE,GAAG,IAAI,CAAC;IAC7D,IAAI,aAAa,GAAG,iBAAiB,CAAC;IACtC,IAAI,MAAM,GAAG,UAAU,CAAC;IACxB,MAAM,YAAY,GAAG,GAAG,EAAE,CACxB,SAAS,CACP,kEAAkE,UAAU,GAAG,IAAI,KAAK,CACzF,CAAC;IACJ,OAAO;QACL,KAAK,CAAC,QAAQ,CAAC,KAAK;YAClB,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;gBAAE,OAAO,EAAE,CAAC;YAClC,MAAM,EAAE,cAAc,EAAE,CAAC;YACzB,IAAI,MAAM,IAAI,CAAC;gBAAE,MAAM,YAAY,EAAE,CAAC;YACtC,MAAM,OAAO,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;YAClC,MAAM,QAAQ,GAAG,MAAM,SAAS,CAC9B,EAAE,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,aAAa,EAAE,SAAS,EAAE,gBAAgB,EAAE,EACvE,MAAM,EACN,YAAY,EACZ,MAAM,CACP,CAAC;YACF,MAAM,IAAI,WAAW,CAAC,GAAG,EAAE,GAAG,OAAO,CAAC;YACtC,IAAI,QAAQ,CAAC,EAAE,EAAE,CAAC;gBAChB,aAAa,GAAG,QAAQ,CAAC,aAAa,CAAC;gBACvC,OAAO,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;oBACjC,QAAQ,EAAE,GAAG,CAAC,QAAQ;oBACtB,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC;iBAC7B,CAAC,CAAC,CAAC;YACN,CAAC;YACD,MAAM,YAAY,CAAC,QAAQ,CAAC,CAAC;QAC/B,CAAC;KACF,CAAC;AACJ,CAAC;AAED,SAAS,YAAY,CAAC,QAAoD;IACxE,MAAM,KAAK,GAAG,IAAI,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IACzC,QAAQ,QAAQ,CAAC,OAAO,EAAE,CAAC;QACzB,KAAK,gBAAgB;YACnB,OAAO,eAAe,CACpB,sKAAsK,EACtK,EAAE,MAAM,EAAE,eAAe,EAAE,EAC3B,EAAE,KAAK,EAAE,CACV,CAAC;QACJ,KAAK,SAAS;YACZ,OAAO,eAAe,CACpB,4CAA4C,EAC5C,EAAE,MAAM,EAAE,eAAe,EAAE,EAC3B,EAAE,KAAK,EAAE,CACV,CAAC;QACJ,KAAK,kBAAkB;YACrB,OAAO,SAAS,CACd,kGAAkG,gBAAgB,CAAC,cAAc,CAAC,OAAO,CAAC,qCAAqC,CAChL,CAAC;QACJ,KAAK,kBAAkB;YACrB,OAAO,SAAS,CACd,mGAAmG,iBAAiB,CAAC,cAAc,CAAC,OAAO,CAAC,8FAA8F,CAC3O,CAAC;IACN,CAAC;AACH,CAAC;AAED,wDAAwD;AACxD,KAAK,UAAU,SAAS,CACtB,OAA0B,EAC1B,UAAkB,EAClB,YAAyB,EACzB,MAA+B;IAE/B,MAAM,MAAM,GAAG,IAAI,MAAM,CAAC,UAAU,CAAC,CAAC;IACtC,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,aAAa,EAAsB,CAAC;IACjF,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,YAAY,EAAE,CAAC,EAAE,UAAU,CAAC,CAAC;IACnE,MAAM,OAAO,GAAG,GAAG,EAAE,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7C,MAAM,EAAE,gBAAgB,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;IAC3D,MAAM,CAAC,IAAI,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;IAChC,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IAC7B,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE,CAC3B,MAAM,CAAC,IAAI,KAAK,CAAC,qCAAqC,IAAI,mBAAmB,CAAC,CAAC,CAChF,CAAC;IACF,IAAI,CAAC;QACH,MAAM,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;IAC9B,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,qGAAqG;QACrG,MAAM,CAAC,YAAY,CAAC,GAAG,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC;IAC3C,CAAC;IACD,IAAI,CAAC;QACH,OAAO,MAAM,OAAO,CAAC;IACvB,CAAC;YAAS,CAAC;QACT,YAAY,CAAC,KAAK,CAAC,CAAC;QACpB,MAAM,EAAE,mBAAmB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QAC9C,MAAM,MAAM,CAAC,SAAS,EAAE,CAAC;IAC3B,CAAC;AACH,CAAC;AAED;;;;;;GAMG;AACH,SAAS,YAAY,CAAC,GAAY,EAAE,KAA6B;IAC/D,IAAI,CAAC,CAAC,GAAG,YAAY,UAAU,CAAC;QAAE,OAAO,GAAG,CAAC;IAC7C,IAAI,OAAO,GAAG,EAAE,IAAI,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC;IACtC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,MAAM,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;QAClC,IAAI,MAAM,GAAG,OAAO,CAAC,MAAM;YAAE,OAAO,GAAG,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC;IACrE,CAAC;IACD,OAAO,kBAAkB,CACvB,sBAAsB,OAAO,CAAC,IAAI,uBAAuB,OAAO,CAAC,MAAM,CAAC,cAAc,CAAC,OAAO,CAAC,iEAAiE,EAChK,EAAE,MAAM,EAAE,eAAe,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,EAC/C,EAAE,KAAK,EAAE,GAAG,EAAE,CACf,CAAC;AACJ,CAAC;AAED,SAAS,SAAS,CAAC,OAAe;IAChC,OAAO,eAAe,CAAC,OAAO,EAAE,EAAE,MAAM,EAAE,kBAAkB,EAAE,CAAC,CAAC;AAClE,CAAC"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Worker-thread entry that evaluates a caller's JSONLogic tree
|
|
3
|
+
* against note contexts, for searches scoped by OBSIDIAN_READ_PATHS. Runs the
|
|
4
|
+
* operator set the Local REST API plugin runs (json-logic-js 2.0.5 plus its
|
|
5
|
+
* `glob` and `regexp`), with the plugin's hit test and JSON-shaped results, so
|
|
6
|
+
* a scoped search answers as the plugin would over the same notes.
|
|
7
|
+
*
|
|
8
|
+
* Off the main thread so a slow tree cannot hold the event loop: the evaluator
|
|
9
|
+
* terminates this worker at its deadline, which also stops a native regex
|
|
10
|
+
* mid-backtrack. Memory is bounded here by work budgets, since Bun ignores
|
|
11
|
+
* `resourceLimits`: one per note for what its evaluation builds and drops,
|
|
12
|
+
* and one across the search for what kept results hold past a
|
|
13
|
+
* 1,024-character allowance each.
|
|
14
|
+
*
|
|
15
|
+
* Imports only packages and builtins, never sibling modules: under Node the
|
|
16
|
+
* test suite loads this file from source, where `./x.js` specifiers do not
|
|
17
|
+
* resolve to `.ts`.
|
|
18
|
+
*
|
|
19
|
+
* @module services/obsidian/jsonlogic-worker
|
|
20
|
+
*/
|
|
21
|
+
/** A note as the plugin's JSONLogic search evaluates it, link fields already scoped. */
|
|
22
|
+
export interface NoteContext {
|
|
23
|
+
path: string;
|
|
24
|
+
[field: string]: unknown;
|
|
25
|
+
}
|
|
26
|
+
export interface EvaluationRequest {
|
|
27
|
+
/** Work units left for kept results, across every batch of the search; see {@link chargeKept}. */
|
|
28
|
+
keptUnits: number;
|
|
29
|
+
logic: unknown;
|
|
30
|
+
notes: NoteContext[];
|
|
31
|
+
/** Work units each note's evaluation may build beyond the note's own size; see {@link charge}. */
|
|
32
|
+
noteUnits: number;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* How an evaluation ended. `json` is the hit's result serialized as the
|
|
36
|
+
* plugin's response would carry it; `keptUnitsLeft` carries into the next
|
|
37
|
+
* batch.
|
|
38
|
+
*/
|
|
39
|
+
export type EvaluationResponse = {
|
|
40
|
+
ok: true;
|
|
41
|
+
hits: Array<{
|
|
42
|
+
filename: string;
|
|
43
|
+
json: string;
|
|
44
|
+
}>;
|
|
45
|
+
keptUnitsLeft: number;
|
|
46
|
+
} | {
|
|
47
|
+
ok: false;
|
|
48
|
+
failure: 'invalid' | 'invalid_regexp' | BudgetFailure;
|
|
49
|
+
detail: string;
|
|
50
|
+
};
|
|
51
|
+
type BudgetFailure = 'over_note_budget' | 'over_kept_budget';
|
|
52
|
+
export {};
|
|
53
|
+
//# sourceMappingURL=jsonlogic-worker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jsonlogic-worker.d.ts","sourceRoot":"","sources":["../../../src/services/obsidian/jsonlogic-worker.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAMH,wFAAwF;AACxF,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;CAC1B;AAED,MAAM,WAAW,iBAAiB;IAChC,kGAAkG;IAClG,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,OAAO,CAAC;IACf,KAAK,EAAE,WAAW,EAAE,CAAC;IACrB,kGAAkG;IAClG,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;;GAIG;AACH,MAAM,MAAM,kBAAkB,GAC1B;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,KAAK,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAAC,aAAa,EAAE,MAAM,CAAA;CAAE,GACpF;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,OAAO,EAAE,SAAS,GAAG,gBAAgB,GAAG,aAAa,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAEzF,KAAK,aAAa,GAAG,kBAAkB,GAAG,kBAAkB,CAAC"}
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Worker-thread entry that evaluates a caller's JSONLogic tree
|
|
3
|
+
* against note contexts, for searches scoped by OBSIDIAN_READ_PATHS. Runs the
|
|
4
|
+
* operator set the Local REST API plugin runs (json-logic-js 2.0.5 plus its
|
|
5
|
+
* `glob` and `regexp`), with the plugin's hit test and JSON-shaped results, so
|
|
6
|
+
* a scoped search answers as the plugin would over the same notes.
|
|
7
|
+
*
|
|
8
|
+
* Off the main thread so a slow tree cannot hold the event loop: the evaluator
|
|
9
|
+
* terminates this worker at its deadline, which also stops a native regex
|
|
10
|
+
* mid-backtrack. Memory is bounded here by work budgets, since Bun ignores
|
|
11
|
+
* `resourceLimits`: one per note for what its evaluation builds and drops,
|
|
12
|
+
* and one across the search for what kept results hold past a
|
|
13
|
+
* 1,024-character allowance each.
|
|
14
|
+
*
|
|
15
|
+
* Imports only packages and builtins, never sibling modules: under Node the
|
|
16
|
+
* test suite loads this file from source, where `./x.js` specifiers do not
|
|
17
|
+
* resolve to `.ts`.
|
|
18
|
+
*
|
|
19
|
+
* @module services/obsidian/jsonlogic-worker
|
|
20
|
+
*/
|
|
21
|
+
import { parentPort } from 'node:worker_threads';
|
|
22
|
+
import globToRegExp from 'glob-to-regexp';
|
|
23
|
+
import jsonLogic from 'json-logic-js';
|
|
24
|
+
/** Thrown when a work budget runs out; never caught by json-logic-js, which has no try. */
|
|
25
|
+
class BudgetExhausted extends Error {
|
|
26
|
+
failure;
|
|
27
|
+
constructor(failure) {
|
|
28
|
+
super(failure);
|
|
29
|
+
this.failure = failure;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
/** Units the current note's evaluation may still build; reset for every note. */
|
|
33
|
+
let noteUnitsLeft = 0;
|
|
34
|
+
/** Units kept results may still hold, across the whole search. */
|
|
35
|
+
let keptUnitsLeft = 0;
|
|
36
|
+
/**
|
|
37
|
+
* Spend `units` of the current note's budget, which bounds the memory one
|
|
38
|
+
* note's evaluation allocates; the deadline bounds time. The budget is the
|
|
39
|
+
* note's own {@link weight} plus `noteUnits`, so a tree can always build a
|
|
40
|
+
* copy of what the note holds, and it resets for the next note: what one
|
|
41
|
+
* note's evaluation builds is dropped when it ends, unless it is kept, which
|
|
42
|
+
* {@link chargeKept} bounds across the search. Only what a tree builds is
|
|
43
|
+
* charged, at its {@link weight}: `merge` and `cat` before they build, a `map`
|
|
44
|
+
* result, and the elements operators placed in an array literal
|
|
45
|
+
* ({@link literalWeight}). Every other step allocates no more than its
|
|
46
|
+
* operands already hold — comparisons, `var`, `in`, `missing`, `some` / `all`
|
|
47
|
+
* / `none`, arithmetic, `substr`, `glob`, and `regexp` return a primitive, a
|
|
48
|
+
* reference, or a string conversion of a value that was charged, is the
|
|
49
|
+
* note's, or is written in the tree; `filter` returns part of its input, and
|
|
50
|
+
* `if`, `and`, `or`, and `reduce` return a value another step produced — so
|
|
51
|
+
* evaluation steps cost nothing. Charging what is built bounds what a tree
|
|
52
|
+
* can allocate, including by multiplying references to one large string, and
|
|
53
|
+
* so bounds every later string conversion of what it built.
|
|
54
|
+
*/
|
|
55
|
+
function charge(units) {
|
|
56
|
+
noteUnitsLeft -= units;
|
|
57
|
+
if (noteUnitsLeft < 0)
|
|
58
|
+
throw new BudgetExhausted('over_note_budget');
|
|
59
|
+
}
|
|
60
|
+
/** Spend `units` of the search's budget for kept results, which outlive their note's evaluation. */
|
|
61
|
+
function chargeKept(units) {
|
|
62
|
+
keptUnitsLeft -= units;
|
|
63
|
+
if (keptUnitsLeft < 0)
|
|
64
|
+
throw new BudgetExhausted('over_kept_budget');
|
|
65
|
+
}
|
|
66
|
+
/** Length of a plain object's string conversion, `[object Object]`. */
|
|
67
|
+
const OBJECT_STRING_CHARS = 15;
|
|
68
|
+
/**
|
|
69
|
+
* Size of a value in work units, counted until it passes `limit`: one per
|
|
70
|
+
* node plus the length of the node's own string conversion — a string's
|
|
71
|
+
* length, `String(value).length` for a number, boolean, `null`, or
|
|
72
|
+
* `undefined`, and {@link OBJECT_STRING_CHARS} plus its keys' lengths for an
|
|
73
|
+
* object. An array converts to its elements joined by commas, which the
|
|
74
|
+
* per-node unit covers, so no value converts to a string longer than its
|
|
75
|
+
* weight. Iterative, because a `reduce` can nest values deeper than the call
|
|
76
|
+
* stack.
|
|
77
|
+
*/
|
|
78
|
+
function weight(value, limit) {
|
|
79
|
+
let total = 0;
|
|
80
|
+
const pending = [value];
|
|
81
|
+
while (pending.length > 0 && total <= limit) {
|
|
82
|
+
const next = pending.pop();
|
|
83
|
+
total += 1;
|
|
84
|
+
if (typeof next === 'string')
|
|
85
|
+
total += next.length;
|
|
86
|
+
// Pushed one by one: spreading a long array overruns the argument limit.
|
|
87
|
+
else if (Array.isArray(next))
|
|
88
|
+
for (const item of next)
|
|
89
|
+
pending.push(item);
|
|
90
|
+
else if (next !== null && typeof next === 'object') {
|
|
91
|
+
total += OBJECT_STRING_CHARS;
|
|
92
|
+
for (const [key, field] of Object.entries(next)) {
|
|
93
|
+
total += key.length;
|
|
94
|
+
pending.push(field);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
else
|
|
98
|
+
total += String(next).length;
|
|
99
|
+
}
|
|
100
|
+
return total;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Size of the array an array literal just built, in work units. An element
|
|
104
|
+
* written in the tree — a primitive, or an array literal charged at its own
|
|
105
|
+
* application — adds nothing: its slot and a literal string's length are
|
|
106
|
+
* bounded by the request, and the string is shared rather than copied. An
|
|
107
|
+
* element an operator produced pays its full {@link weight}.
|
|
108
|
+
*/
|
|
109
|
+
function literalWeight(logic, built) {
|
|
110
|
+
let total = 0;
|
|
111
|
+
for (let i = 0; i < logic.length && total <= noteUnitsLeft; i++) {
|
|
112
|
+
const element = logic[i];
|
|
113
|
+
if (element !== null && typeof element === 'object' && !Array.isArray(element)) {
|
|
114
|
+
total += weight(built[i], noteUnitsLeft - total);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
return total;
|
|
118
|
+
}
|
|
119
|
+
const baseApply = jsonLogic.apply;
|
|
120
|
+
/**
|
|
121
|
+
* json-logic-js recurses through `jsonLogic.apply`, so this wrapper sees every
|
|
122
|
+
* application. A `map` result is charged its size: mapping over a long array
|
|
123
|
+
* to a constant multiplies references to it without building anything the
|
|
124
|
+
* other charges see.
|
|
125
|
+
*/
|
|
126
|
+
jsonLogic.apply = (logic, data) => {
|
|
127
|
+
const result = baseApply(logic, data);
|
|
128
|
+
if (Array.isArray(logic))
|
|
129
|
+
charge(literalWeight(logic, result));
|
|
130
|
+
else if (isMap(logic))
|
|
131
|
+
charge(weight(result, noteUnitsLeft));
|
|
132
|
+
return result;
|
|
133
|
+
};
|
|
134
|
+
/** A `map` application, by json-logic-js's own test: an object with one key. */
|
|
135
|
+
function isMap(logic) {
|
|
136
|
+
return (logic !== null &&
|
|
137
|
+
typeof logic === 'object' &&
|
|
138
|
+
Object.hasOwn(logic, 'map') &&
|
|
139
|
+
Object.keys(logic).length === 1);
|
|
140
|
+
}
|
|
141
|
+
/** The plugin's two operators, as Local REST API 5.x registers them: pattern first, `false` for a non-string operand. */
|
|
142
|
+
jsonLogic.add_operation('glob', (pattern, field) => typeof field === 'string' && typeof pattern === 'string'
|
|
143
|
+
? globToRegExp(pattern).test(field)
|
|
144
|
+
: false);
|
|
145
|
+
jsonLogic.add_operation('regexp', (pattern, field) => typeof field === 'string' && typeof pattern === 'string'
|
|
146
|
+
? new RegExp(pattern).test(field)
|
|
147
|
+
: false);
|
|
148
|
+
/** json-logic-js's `log` writes to stdout, which is the JSON-RPC stream under stdio. Same value, no write. */
|
|
149
|
+
jsonLogic.add_operation('log', (value) => value);
|
|
150
|
+
/**
|
|
151
|
+
* json-logic-js's `var`, reading own properties only: inherited properties are
|
|
152
|
+
* out of reach, and own properties still cover every note field, array index,
|
|
153
|
+
* and `length`.
|
|
154
|
+
*/
|
|
155
|
+
jsonLogic.add_operation('var', function (key, fallback) {
|
|
156
|
+
const notFound = fallback === undefined ? null : fallback;
|
|
157
|
+
if (key === undefined || key === '' || key === null)
|
|
158
|
+
return this;
|
|
159
|
+
let data = this;
|
|
160
|
+
for (const segment of String(key).split('.')) {
|
|
161
|
+
if (data === null || data === undefined || !Object.hasOwn(Object(data), segment)) {
|
|
162
|
+
return notFound;
|
|
163
|
+
}
|
|
164
|
+
data = data[segment];
|
|
165
|
+
if (data === undefined)
|
|
166
|
+
return notFound;
|
|
167
|
+
}
|
|
168
|
+
return data;
|
|
169
|
+
});
|
|
170
|
+
/** Stock `merge` and `cat`, charged before they build, so an oversized value is never allocated. */
|
|
171
|
+
jsonLogic.add_operation('merge', (...args) => {
|
|
172
|
+
for (const arg of args)
|
|
173
|
+
charge(weight(arg, noteUnitsLeft));
|
|
174
|
+
return args.reduce((all, next) => all.concat(next), []);
|
|
175
|
+
});
|
|
176
|
+
jsonLogic.add_operation('cat', (...args) => {
|
|
177
|
+
for (const arg of args)
|
|
178
|
+
charge(weight(arg, noteUnitsLeft));
|
|
179
|
+
return args.join('');
|
|
180
|
+
});
|
|
181
|
+
/** The plugin's hit test: `null`/`undefined`, `[]`, and `{}` drop a note. */
|
|
182
|
+
function isTruthy(value) {
|
|
183
|
+
if (value === undefined || value === null)
|
|
184
|
+
return false;
|
|
185
|
+
if (Array.isArray(value))
|
|
186
|
+
return value.length > 0;
|
|
187
|
+
if (typeof value === 'object')
|
|
188
|
+
return Object.keys(value).length > 0;
|
|
189
|
+
return Boolean(value);
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Serialized characters a kept result may hold with no charge, whatever its
|
|
193
|
+
* note's size, so ordinary results skip the comparison below.
|
|
194
|
+
*/
|
|
195
|
+
const FREE_RESULT_CHARS = 1_024;
|
|
196
|
+
/**
|
|
197
|
+
* Evaluate `request.logic` against each note in order, as the plugin's search
|
|
198
|
+
* loop does, each note with a fresh budget for what it builds. A kept result
|
|
199
|
+
* is held until the search answers. One whose JSON is at most
|
|
200
|
+
* {@link FREE_RESULT_CHARS} is free; a larger one pays the search's budget for
|
|
201
|
+
* whatever it holds beyond its own note's serialized size: a result drawn
|
|
202
|
+
* from the note stays free, while one repeating the tree's large constants on
|
|
203
|
+
* every note is bounded across the search.
|
|
204
|
+
*/
|
|
205
|
+
function evaluate(request) {
|
|
206
|
+
keptUnitsLeft = request.keptUnits;
|
|
207
|
+
const hits = [];
|
|
208
|
+
for (const note of request.notes) {
|
|
209
|
+
noteUnitsLeft = request.noteUnits + weight(note, Number.POSITIVE_INFINITY);
|
|
210
|
+
try {
|
|
211
|
+
const result = jsonLogic.apply(request.logic, note);
|
|
212
|
+
if (!isTruthy(result))
|
|
213
|
+
continue;
|
|
214
|
+
const json = JSON.stringify(result);
|
|
215
|
+
if (json.length > FREE_RESULT_CHARS) {
|
|
216
|
+
chargeKept(Math.max(0, json.length - JSON.stringify(note).length));
|
|
217
|
+
}
|
|
218
|
+
hits.push({ filename: note.path, json });
|
|
219
|
+
}
|
|
220
|
+
catch (err) {
|
|
221
|
+
if (err instanceof BudgetExhausted) {
|
|
222
|
+
return { ok: false, failure: err.failure, detail: 'work budget exhausted' };
|
|
223
|
+
}
|
|
224
|
+
const detail = err instanceof Error ? err.message : String(err);
|
|
225
|
+
return {
|
|
226
|
+
ok: false,
|
|
227
|
+
failure: /invalid regular expression/i.test(detail) ? 'invalid_regexp' : 'invalid',
|
|
228
|
+
detail,
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
return { ok: true, hits, keptUnitsLeft };
|
|
233
|
+
}
|
|
234
|
+
parentPort?.once('message', (request) => {
|
|
235
|
+
parentPort?.postMessage(evaluate(request));
|
|
236
|
+
});
|
|
237
|
+
//# sourceMappingURL=jsonlogic-worker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jsonlogic-worker.js","sourceRoot":"","sources":["../../../src/services/obsidian/jsonlogic-worker.ts"],"names":[],"mappings":"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"}
|
|
@@ -8,7 +8,7 @@ import type { Context } from '@cyanheads/mcp-ts-core';
|
|
|
8
8
|
import { type Dispatcher, type RequestInit, fetch as undiciFetch } from 'undici';
|
|
9
9
|
import { type ServerConfig } from '../../config/server-config.js';
|
|
10
10
|
import { PathPolicy } from './path-policy.js';
|
|
11
|
-
import type { DocumentMap, FileListing, NoteJson, NoteTarget, ObsidianCommand, ObsidianTag, OmnisearchHit, PatchInstruction, StructuredSearchHit, TextSearchHit, VaultStatus } from './types.js';
|
|
11
|
+
import type { DocumentMap, FileListing, NoteJson, NoteTarget, ObsidianCommand, ObsidianTag, OmnisearchHit, PatchInstruction, PathTarget, StructuredSearchHit, TextSearchHit, VaultStatus } from './types.js';
|
|
12
12
|
type UndiciResponse = Awaited<ReturnType<typeof undiciFetch>>;
|
|
13
13
|
/**
|
|
14
14
|
* The HTTP fetch contract this service depends on. Defaults to undici's
|
|
@@ -35,7 +35,7 @@ export declare class ObsidianService {
|
|
|
35
35
|
* `fetch`, which honors the constructed TLS dispatcher in production.
|
|
36
36
|
*/
|
|
37
37
|
constructor(config: ServerConfig, fetchImpl?: ObsidianFetch);
|
|
38
|
-
/** Path-policy accessor
|
|
38
|
+
/** Path-policy accessor for tools that filter results or check scope themselves. */
|
|
39
39
|
get policy(): PathPolicy;
|
|
40
40
|
/** Resolved Omnisearch URL (derived from baseUrl or OBSIDIAN_OMNISEARCH_URL override). */
|
|
41
41
|
get omnisearchUrl(): string;
|
|
@@ -64,11 +64,27 @@ export declare class ObsidianService {
|
|
|
64
64
|
getNoteContent(ctx: Context, target: NoteTarget): Promise<string>;
|
|
65
65
|
getNoteJson(ctx: Context, target: NoteTarget): Promise<NoteJson>;
|
|
66
66
|
/**
|
|
67
|
-
*
|
|
68
|
-
*
|
|
69
|
-
*
|
|
67
|
+
* Pin `target` to the note it names right now. A path target comes back as
|
|
68
|
+
* sent; an `active` or `periodic` target is resolved upstream (read-gated)
|
|
69
|
+
* and comes back as a path target for that note, so every later call acts on
|
|
70
|
+
* the same file however the target moves in between.
|
|
71
|
+
*/
|
|
72
|
+
resolveTarget(ctx: Context, target: NoteTarget): Promise<PathTarget>;
|
|
73
|
+
/**
|
|
74
|
+
* `target` as a path target for `path`, the note a read of `target` returned.
|
|
75
|
+
* A path target already names its note and comes back as sent. A pinned
|
|
76
|
+
* `active` / `periodic` target carries the target's label as `resolvedFrom`,
|
|
77
|
+
* the identifier `no_active_file` and `periodic_not_found` use, so a
|
|
78
|
+
* `path_forbidden` denial on it names the target rather than the note.
|
|
79
|
+
*/
|
|
80
|
+
pinTarget(target: NoteTarget, path: string): PathTarget;
|
|
81
|
+
/**
|
|
82
|
+
* The note's headings, block ids, and frontmatter field names. An `active` /
|
|
83
|
+
* `periodic` target is resolved once (read-gated, a denial named by the
|
|
84
|
+
* target's label) and the map read from the resolved `/vault/` path, which
|
|
85
|
+
* the plugin's `/active/` and `/periodic/…` routes delegate to anyway, so the
|
|
86
|
+
* map describes the note the resolution returned even if the target moves.
|
|
70
87
|
*/
|
|
71
|
-
resolvePath(ctx: Context, target: NoteTarget): Promise<string>;
|
|
72
88
|
getDocumentMap(ctx: Context, target: NoteTarget): Promise<DocumentMap>;
|
|
73
89
|
writeNote(ctx: Context, target: NoteTarget, content: string, contentType?: 'markdown' | 'json'): Promise<void>;
|
|
74
90
|
appendToNote(ctx: Context, target: NoteTarget, content: string, contentType?: 'markdown' | 'json'): Promise<void>;
|
|
@@ -109,8 +125,8 @@ export declare class ObsidianService {
|
|
|
109
125
|
/**
|
|
110
126
|
* Vault tags with usage counts, hierarchical parents included. Unscoped, the
|
|
111
127
|
* plugin's `/tags/` with its occurrence counts. That payload carries no
|
|
112
|
-
* per-note attribution, so under OBSIDIAN_READ_PATHS the tags are
|
|
113
|
-
*
|
|
128
|
+
* per-note attribution, so under OBSIDIAN_READ_PATHS the tags are read from
|
|
129
|
+
* the readable notes' contexts instead (one upstream search, no bodies), and
|
|
114
130
|
* each one counts the readable notes carrying it or a tag nested under it.
|
|
115
131
|
*/
|
|
116
132
|
listTags(ctx: Context): Promise<ObsidianTag[]>;
|
|
@@ -127,7 +143,39 @@ export declare class ObsidianService {
|
|
|
127
143
|
* failure.
|
|
128
144
|
*/
|
|
129
145
|
searchText(ctx: Context, query: string, contextLength?: number): Promise<TextSearchHit[]>;
|
|
146
|
+
/**
|
|
147
|
+
* JSONLogic search. Unscoped, the tree goes to the plugin unchanged. Under
|
|
148
|
+
* OBSIDIAN_READ_PATHS the plugin would evaluate it against every note in
|
|
149
|
+
* the vault, so the tree stays here instead: the readable notes' contexts
|
|
150
|
+
* are fetched and the tree is evaluated over those alone
|
|
151
|
+
* (`createJsonLogicEvaluation`), the way the plugin evaluates it. No hit,
|
|
152
|
+
* result, or error then reads a note outside the read scope; which note a
|
|
153
|
+
* link resolves to is still Obsidian's vault-wide resolution, so `links`,
|
|
154
|
+
* `backlinks`, and `unresolvedLinks` can change when a note outside the
|
|
155
|
+
* scope is created or removed.
|
|
156
|
+
*
|
|
157
|
+
* The plugin hands a tree note bodies only when its JSON holds the string
|
|
158
|
+
* `"content"` (`readsContent`); such a tree gets them here too, fetched
|
|
159
|
+
* and evaluated in batches of at most `CONTENT_BATCH_BYTES` so a broad
|
|
160
|
+
* scope never holds every readable body at once.
|
|
161
|
+
*/
|
|
130
162
|
searchJsonLogic(ctx: Context, logic: Record<string, unknown>): Promise<StructuredSearchHit[]>;
|
|
163
|
+
/**
|
|
164
|
+
* A JSONLogic search for a caller paging through its hits `pageSize` at a
|
|
165
|
+
* time. Unscoped, it is `searchJsonLogic`. Under OBSIDIAN_READ_PATHS a call
|
|
166
|
+
* without `walk` evaluates fresh and, when the hits run past one page,
|
|
167
|
+
* stores the full ordered hit list under a new walk id, returned as `walk`;
|
|
168
|
+
* a call naming that id with the same tree is served from the stored list
|
|
169
|
+
* without evaluating. The store belongs to this service, whose read scope
|
|
170
|
+
* is fixed at construction, so a list is only read under the scope that
|
|
171
|
+
* produced it. Anything else — an expired, evicted, or unknown id, or a
|
|
172
|
+
* different tree — evaluates fresh, and a call cancelled before it answers
|
|
173
|
+
* stores nothing.
|
|
174
|
+
*/
|
|
175
|
+
pageJsonLogic(ctx: Context, logic: Record<string, unknown>, walk: string | undefined, pageSize: number): Promise<{
|
|
176
|
+
hits: StructuredSearchHit[];
|
|
177
|
+
walk?: string;
|
|
178
|
+
}>;
|
|
131
179
|
/**
|
|
132
180
|
* One-shot startup probe for the Omnisearch plugin's HTTP endpoint. Returns
|
|
133
181
|
* `true` only when the response is `HTTP 200`, declares `application/json`,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"obsidian-service.d.ts","sourceRoot":"","sources":["../../../src/services/obsidian/obsidian-service.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AAatD,OAAO,EAAS,KAAK,UAAU,EAAE,KAAK,WAAW,EAAE,KAAK,IAAI,WAAW,EAAE,MAAM,QAAQ,CAAC;AACxF,OAAO,EAAmB,KAAK,YAAY,EAAE,MAAM,2BAA2B,CAAC;
|
|
1
|
+
{"version":3,"file":"obsidian-service.d.ts","sourceRoot":"","sources":["../../../src/services/obsidian/obsidian-service.ts"],"names":[],"mappings":"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"}
|