@lapis-notes/api 0.1.4 → 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/CHANGELOG.md +193 -0
- package/README.md +19 -0
- package/dist/__tests__/fixtures/indexed-mutations.json +6862 -0
- package/dist/__tests__/fixtures/memory-storage.json +309 -0
- package/dist/__tests__/fixtures/native-facade-contract.json +3224 -0
- package/dist/__tests__/fixtures/projection-query.json +195 -0
- package/dist/__tests__/fixtures/projection-values.json +60 -0
- package/dist/__tests__/fixtures/search-preparation.json +1513 -0
- package/dist/__tests__/fixtures/search-retrieval.json +15409 -0
- package/dist/__tests__/fixtures/search-semantic-model.json +3691 -0
- package/dist/__tests__/fixtures/search-semantic-retrieval.json +6603 -0
- package/dist/__tests__/fixtures/search-storage.json +409 -0
- package/dist/__tests__/fixtures/task-projection.json +428 -0
- package/dist/__tests__/indexed-mutation-support.js +262 -0
- package/dist/__tests__/projection-query-support.js +40 -0
- package/dist/__tests__/search-retrieval-support.js +47 -0
- package/dist/app-database-host.d.ts +1 -0
- package/dist/app-shell-plugin-persistence.d.ts +3 -2
- package/dist/app-shell-plugin-persistence.js +37 -3
- package/dist/cache.svelte.d.ts +8 -1
- package/dist/cache.svelte.js +103 -5
- package/dist/command.svelte.js +29 -2
- package/dist/components/editor/editor.css +4 -0
- package/dist/components/editor/editor.svelte +21 -9
- package/dist/components/editor/embedded-editor-surface.js +3 -1
- package/dist/components/editor/inline-title-alignment.d.ts +3 -0
- package/dist/components/editor/inline-title-alignment.js +57 -0
- package/dist/configuration.svelte.d.ts +270 -206
- package/dist/configuration.svelte.js +161 -86
- package/dist/context.svelte.d.ts +21 -3
- package/dist/context.svelte.js +63 -20
- package/dist/diagnostics.d.ts +8 -0
- package/dist/diagnostics.js +6 -0
- package/dist/editor-save-context.d.ts +12 -1
- package/dist/editor-save-context.js +32 -1
- package/dist/editor-view-registry.d.ts +10 -0
- package/dist/editor-view-registry.js +44 -4
- package/dist/editor.svelte.js +128 -37
- package/dist/embed-registry.d.ts +10 -0
- package/dist/embed-registry.js +15 -0
- package/dist/file-editing-failures.d.ts +2 -0
- package/dist/file-editing-failures.js +29 -0
- package/dist/file-editing-native-issues.d.ts +19 -0
- package/dist/file-editing-native-issues.js +65 -0
- package/dist/file-editing-sessions.d.ts +56 -8
- package/dist/file-editing-sessions.js +185 -15
- package/dist/file-manager.d.ts +8 -1
- package/dist/file-manager.js +37 -3
- package/dist/file-state-store.d.ts +5 -0
- package/dist/file-state-store.js +34 -0
- package/dist/file-text-conflicts.d.ts +25 -0
- package/dist/file-text-conflicts.js +35 -0
- package/dist/file-text-mutation.d.ts +13 -0
- package/dist/file-text-mutation.js +100 -0
- package/dist/file-text-persistence.d.ts +36 -0
- package/dist/file-text-persistence.js +234 -0
- package/dist/file-text-state-writer.d.ts +34 -0
- package/dist/file-text-state-writer.js +183 -0
- package/dist/files-configuration.d.ts +20 -0
- package/dist/files-configuration.js +47 -0
- package/dist/generated/plugin-host-modules.schema.generated.d.ts +87 -37
- package/dist/generated/plugin-host-modules.schema.generated.js +102 -37
- package/dist/glob.d.ts +3 -0
- package/dist/glob.js +2 -1
- package/dist/icons/changes.d.ts +3 -0
- package/dist/icons/changes.js +16 -0
- package/dist/icons/index.d.ts +5 -1
- package/dist/icons/index.js +44 -3
- package/dist/icons/registry.d.ts +35 -0
- package/dist/icons/registry.js +154 -0
- package/dist/icons/safe-svg.d.ts +2 -0
- package/dist/icons/safe-svg.js +44 -0
- package/dist/index.d.ts +5 -1
- package/dist/index.js +3 -1
- package/dist/lapis-extension.d.ts +6 -2
- package/dist/lapis-extension.js +2 -0
- package/dist/metadata.svelte.js +45 -2
- package/dist/native-background-indexing.d.ts +48 -0
- package/dist/native-background-indexing.js +208 -0
- package/dist/native-database-protocol.d.ts +29 -0
- package/dist/native-database-protocol.js +1 -0
- package/dist/native-editing-intent-lease.d.ts +17 -0
- package/dist/native-editing-intent-lease.js +188 -0
- package/dist/native-editing-intents-protocol.d.ts +70 -0
- package/dist/native-editing-intents-protocol.js +1 -0
- package/dist/native-editing-intents.d.ts +8 -0
- package/dist/native-editing-intents.js +1 -0
- package/dist/native-editing-problems.d.ts +3 -0
- package/dist/native-editing-problems.js +180 -0
- package/dist/native-editing-recovery.d.ts +24 -0
- package/dist/native-editing-recovery.js +198 -0
- package/dist/native-editing-session.d.ts +51 -0
- package/dist/native-editing-session.js +251 -0
- package/dist/native-history-index-protocol.d.ts +80 -0
- package/dist/native-history-index-protocol.js +1 -0
- package/dist/native-history-index.d.ts +6 -0
- package/dist/native-history-index.js +1 -0
- package/dist/native-indexing-protocol.d.ts +63 -0
- package/dist/native-indexing-protocol.js +1 -0
- package/dist/native-participant-protocol.d.ts +67 -0
- package/dist/native-participant-protocol.js +3 -0
- package/dist/native-queue-protocol.d.ts +73 -0
- package/dist/native-queue-protocol.js +3 -0
- package/dist/native-tasks-protocol.d.ts +264 -0
- package/dist/native-tasks-protocol.js +1 -0
- package/dist/native-tasks.d.ts +35 -0
- package/dist/native-tasks.js +79 -0
- package/dist/native-turn-protocol.d.ts +81 -0
- package/dist/native-turn-protocol.js +1 -0
- package/dist/native-turns.d.ts +29 -0
- package/dist/native-turns.js +2 -0
- package/dist/plugin-asset-server.js +3 -2
- package/dist/plugin-dependency-resolver.d.ts +1 -1
- package/dist/plugin-distribution/compatibility.d.ts +1 -1
- package/dist/plugin-distribution/compatibility.js +10 -5
- package/dist/plugin-distribution/installed-plugin-state.js +2 -1
- package/dist/plugin-distribution/installer.d.ts +6 -0
- package/dist/plugin-distribution/installer.js +90 -37
- package/dist/plugin-distribution/manager.d.ts +4 -1
- package/dist/plugin-distribution/manager.js +12 -5
- package/dist/plugin-distribution/registry-cache.js +2 -1
- package/dist/plugin-distribution/registry-source-state.js +2 -1
- package/dist/plugin-distribution/schemas.d.ts +26 -8
- package/dist/plugin-distribution/schemas.js +2 -1
- package/dist/plugin-distribution/types.d.ts +4 -0
- package/dist/plugin-manager.d.ts +20 -4
- package/dist/plugin-manager.js +228 -64
- package/dist/plugin-runtime-entry.d.ts +1 -1
- package/dist/plugin-runtime-entry.js +16 -0
- package/dist/plugin.d.ts +18 -2
- package/dist/plugin.js +93 -39
- package/dist/registry-schema/catalog-v1.d.ts +60 -9
- package/dist/registry-schema/catalog-v1.js +2 -1
- package/dist/registry-schema/catalog-v2.d.ts +60 -9
- package/dist/registry-schema/catalog-v2.js +1 -1
- package/dist/search-result-provider.d.ts +95 -0
- package/dist/search-result-provider.js +42 -0
- package/dist/status-bar.svelte.d.ts +26 -20
- package/dist/status-bar.svelte.js +1 -0
- package/dist/storage/app-database.d.ts +6 -2
- package/dist/storage/app-database.js +41 -34
- package/dist/storage/desktop-native.d.ts +5 -3
- package/dist/storage/desktop-native.js +59 -6
- package/dist/storage/directory-watcher.d.ts +27 -0
- package/dist/storage/directory-watcher.js +201 -0
- package/dist/storage/fs.d.ts +14 -27
- package/dist/storage/fs.js +2 -168
- package/dist/storage/index-projection.js +33 -15
- package/dist/storage/memory-vault-adapter.d.ts +2 -0
- package/dist/storage/memory-vault-adapter.js +14 -1
- package/dist/storage/path.d.ts +6 -2
- package/dist/storage/path.js +8 -2
- package/dist/storage/projection-query-candidates.d.ts +3 -0
- package/dist/storage/projection-query-candidates.js +69 -0
- package/dist/storage/remote-app-database.d.ts +2 -2
- package/dist/storage/remote-app-database.js +1 -1
- package/dist/storage/runtime.d.ts +3 -0
- package/dist/storage/runtime.js +3 -0
- package/dist/storage/search-embedding-record.d.ts +3 -0
- package/dist/storage/search-embedding-record.js +18 -0
- package/dist/storage/turso-app-database.d.ts +2 -0
- package/dist/storage/turso-app-database.js +67 -30
- package/dist/storage/vault-listing.d.ts +3 -0
- package/dist/storage/vault-listing.js +36 -0
- package/dist/storage/vault-reconciliation.d.ts +19 -0
- package/dist/storage/vault-reconciliation.js +137 -0
- package/dist/storage/vault-session.d.ts +8 -0
- package/dist/storage/vault-session.js +10 -2
- package/dist/storage/vault.svelte.d.ts +53 -4
- package/dist/storage/vault.svelte.js +223 -87
- package/dist/sync-host.d.ts +12 -3
- package/dist/sync-host.js +5 -1
- package/dist/vault-change-views.d.ts +4 -0
- package/dist/vault-change-views.js +43 -0
- package/dist/vault-changes.d.ts +37 -0
- package/dist/vault-changes.js +228 -0
- package/dist/view.svelte.d.ts +182 -149
- package/dist/view.svelte.js +11 -2
- package/dist/workspace-close-guard.d.ts +3 -0
- package/dist/workspace-close-guard.js +35 -0
- package/dist/workspace-host-internal.js +10 -2
- package/dist/workspace-layout-normalizer.d.ts +4 -2
- package/dist/workspace-layout-normalizer.js +5 -5
- package/dist/workspace-view-document.d.ts +3 -0
- package/dist/workspace-view-document.js +12 -0
- package/dist/workspace.svelte.d.ts +13 -2
- package/dist/workspace.svelte.js +371 -82
- package/package.json +45 -8
package/dist/storage/fs.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { basename, joinPath, normalizePath } from "./path";
|
|
1
|
+
import { basename, normalizePath } from "./path";
|
|
3
2
|
export class TAbstractFile {
|
|
4
3
|
parent;
|
|
5
4
|
path;
|
|
@@ -76,172 +75,7 @@ export class TFolder extends TAbstractFile {
|
|
|
76
75
|
return this.parent === null;
|
|
77
76
|
}
|
|
78
77
|
}
|
|
79
|
-
|
|
80
|
-
const vaultAdapter = adapter;
|
|
81
|
-
return (typeof vaultAdapter.watch === "function" &&
|
|
82
|
-
vaultAdapter.getCapabilities?.().nativeWatch === true);
|
|
83
|
-
}
|
|
84
|
-
export class DirectoryWatcher extends EventDispatcher {
|
|
85
|
-
adapter;
|
|
86
|
-
pollingInterval;
|
|
87
|
-
watchers = new Map();
|
|
88
|
-
constructor(adapter, pollingInterval = 5000) {
|
|
89
|
-
super();
|
|
90
|
-
this.adapter = adapter;
|
|
91
|
-
this.pollingInterval = pollingInterval;
|
|
92
|
-
}
|
|
93
|
-
watch(path, options = {}) {
|
|
94
|
-
if (Array.isArray(path)) {
|
|
95
|
-
path.forEach((p) => this.watch(p));
|
|
96
|
-
return;
|
|
97
|
-
}
|
|
98
|
-
path = normalizePath(path);
|
|
99
|
-
const watcherOptions = {
|
|
100
|
-
recursive: options.recursive || false,
|
|
101
|
-
interval: options.interval || this.pollingInterval,
|
|
102
|
-
lastSnapshot: null,
|
|
103
|
-
timeout: null,
|
|
104
|
-
nativeSubscription: null,
|
|
105
|
-
};
|
|
106
|
-
this.watchers.set(path, watcherOptions);
|
|
107
|
-
if (isNativeWatchAdapter(this.adapter)) {
|
|
108
|
-
watcherOptions.nativeSubscription =
|
|
109
|
-
this.adapter.watch(path, options, (event) => {
|
|
110
|
-
const normalizedEvent = event.type === "error"
|
|
111
|
-
? { ...event, path: this.toEventPath(event.path) }
|
|
112
|
-
: { ...event, path: this.toEventPath(event.path) };
|
|
113
|
-
this.dispatch("all", normalizedEvent);
|
|
114
|
-
if (normalizedEvent.type === "error") {
|
|
115
|
-
this.dispatch("error", {
|
|
116
|
-
error: normalizedEvent.error,
|
|
117
|
-
path: normalizedEvent.path,
|
|
118
|
-
});
|
|
119
|
-
return;
|
|
120
|
-
}
|
|
121
|
-
this.dispatch(normalizedEvent.type, normalizedEvent.path);
|
|
122
|
-
}) ?? null;
|
|
123
|
-
return {
|
|
124
|
-
close: () => this.unwatch(path),
|
|
125
|
-
};
|
|
126
|
-
}
|
|
127
|
-
this.takeSnapshot(path, watcherOptions.recursive).then((snapshot) => {
|
|
128
|
-
watcherOptions.lastSnapshot = snapshot;
|
|
129
|
-
watcherOptions.timeout = setInterval(() => {
|
|
130
|
-
this.checkForChanges(path, watcherOptions);
|
|
131
|
-
}, watcherOptions.interval);
|
|
132
|
-
});
|
|
133
|
-
return {
|
|
134
|
-
close: () => this.unwatch(path),
|
|
135
|
-
};
|
|
136
|
-
}
|
|
137
|
-
unwatch(path) {
|
|
138
|
-
path = normalizePath(path);
|
|
139
|
-
const watcher = this.watchers.get(path);
|
|
140
|
-
if (!watcher) {
|
|
141
|
-
return;
|
|
142
|
-
}
|
|
143
|
-
watcher.nativeSubscription?.close();
|
|
144
|
-
if (watcher.timeout) {
|
|
145
|
-
clearInterval(watcher.timeout);
|
|
146
|
-
}
|
|
147
|
-
this.watchers.delete(path);
|
|
148
|
-
}
|
|
149
|
-
close() {
|
|
150
|
-
for (const path of this.watchers.keys()) {
|
|
151
|
-
this.unwatch(path);
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
async takeSnapshot(path, recursive) {
|
|
155
|
-
path = normalizePath(path);
|
|
156
|
-
const snapshot = new Map();
|
|
157
|
-
try {
|
|
158
|
-
const stats = await this.adapter.stat(path);
|
|
159
|
-
if (!stats)
|
|
160
|
-
return snapshot;
|
|
161
|
-
snapshot.set(this.toEventPath(path), stats);
|
|
162
|
-
if (stats.type === "folder") {
|
|
163
|
-
const { files, folders } = await this.adapter.list(path);
|
|
164
|
-
for (const file of files) {
|
|
165
|
-
const entryPath = joinPath(path, file);
|
|
166
|
-
const entryStats = await this.adapter.stat(entryPath);
|
|
167
|
-
if (!entryStats)
|
|
168
|
-
continue;
|
|
169
|
-
snapshot.set(this.toEventPath(entryPath), entryStats);
|
|
170
|
-
}
|
|
171
|
-
if (!recursive)
|
|
172
|
-
return snapshot;
|
|
173
|
-
for (const folder of folders) {
|
|
174
|
-
const entryPath = joinPath(path, folder);
|
|
175
|
-
const subSnapshot = await this.takeSnapshot(entryPath, recursive);
|
|
176
|
-
for (const [subPath, subStats] of subSnapshot.entries()) {
|
|
177
|
-
snapshot.set(subPath, subStats);
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
catch (error) {
|
|
183
|
-
console.error("fs:watch", error);
|
|
184
|
-
this.trigger("error", { error, path });
|
|
185
|
-
this.trigger("all", { type: "error", path, error });
|
|
186
|
-
}
|
|
187
|
-
return snapshot;
|
|
188
|
-
}
|
|
189
|
-
toEventPath(path) {
|
|
190
|
-
path = normalizePath(path);
|
|
191
|
-
return path === "/" ? "/" : path.replace(/^\/+/, "");
|
|
192
|
-
}
|
|
193
|
-
async checkForChanges(path, watcherOptions) {
|
|
194
|
-
path = normalizePath(path);
|
|
195
|
-
try {
|
|
196
|
-
const newSnapshot = await this.takeSnapshot(path, watcherOptions.recursive);
|
|
197
|
-
if (watcherOptions.lastSnapshot) {
|
|
198
|
-
const changes = this.diffSnapshot(watcherOptions.lastSnapshot, newSnapshot);
|
|
199
|
-
for (const change of changes) {
|
|
200
|
-
this.dispatch(change.type, change.path);
|
|
201
|
-
this.dispatch("all", change);
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
watcherOptions.lastSnapshot = newSnapshot;
|
|
205
|
-
}
|
|
206
|
-
catch (err) {
|
|
207
|
-
const error = err;
|
|
208
|
-
if (error.code === "ENOENT") {
|
|
209
|
-
this.dispatch("delete", path);
|
|
210
|
-
this.dispatch("all", { type: "delete", path });
|
|
211
|
-
if (this.watchers.has(path)) {
|
|
212
|
-
this.unwatch(path);
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
else {
|
|
216
|
-
console.error("fs:watch", error);
|
|
217
|
-
this.dispatch("error", { error, path });
|
|
218
|
-
this.trigger("all", { type: "error", path, error });
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
diffSnapshot(oldSnapshot, newSnapshot) {
|
|
223
|
-
const changes = [];
|
|
224
|
-
for (const [path, stats] of newSnapshot) {
|
|
225
|
-
if (!oldSnapshot.has(path)) {
|
|
226
|
-
changes.push({ type: "create", path });
|
|
227
|
-
}
|
|
228
|
-
else {
|
|
229
|
-
const oldStats = oldSnapshot.get(path);
|
|
230
|
-
if (oldStats.mtime !== stats.mtime ||
|
|
231
|
-
oldStats.size !== stats.size ||
|
|
232
|
-
oldStats.type !== stats.type) {
|
|
233
|
-
changes.push({ type: "modify", path });
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
for (const path of oldSnapshot.keys()) {
|
|
238
|
-
if (!newSnapshot.has(path)) {
|
|
239
|
-
changes.push({ type: "delete", path });
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
|
-
return changes;
|
|
243
|
-
}
|
|
244
|
-
}
|
|
78
|
+
export { DirectoryWatcher } from "./directory-watcher";
|
|
245
79
|
export class FileCache {
|
|
246
80
|
capacity;
|
|
247
81
|
cache;
|
|
@@ -83,7 +83,9 @@ export function fieldValue(data, field) {
|
|
|
83
83
|
function scalarOf(value) {
|
|
84
84
|
if (value === undefined)
|
|
85
85
|
return undefined;
|
|
86
|
-
if (value === null ||
|
|
86
|
+
if (value === null ||
|
|
87
|
+
typeof value === "string" ||
|
|
88
|
+
typeof value === "number") {
|
|
87
89
|
return value;
|
|
88
90
|
}
|
|
89
91
|
if (typeof value === "boolean")
|
|
@@ -161,20 +163,22 @@ function afterCursor(sortValues, rowId, after, orderBy) {
|
|
|
161
163
|
for (let index = 0; index < length; index += 1) {
|
|
162
164
|
const spec = orderBy[index] ?? { field: "id", direction: "asc" };
|
|
163
165
|
const direction = spec.direction === "desc" ? -1 : 1;
|
|
164
|
-
const
|
|
166
|
+
const left = sortValues[index] ?? null;
|
|
167
|
+
const right = cursor.values[index] ?? null;
|
|
168
|
+
const comparison = compareScalars(left, right);
|
|
165
169
|
if (comparison === 0)
|
|
166
170
|
continue;
|
|
171
|
+
if (spec.nulls && (left == null || right == null)) {
|
|
172
|
+
return left == null ? spec.nulls === "last" : spec.nulls === "first";
|
|
173
|
+
}
|
|
167
174
|
return comparison * direction > 0;
|
|
168
175
|
}
|
|
169
|
-
return rowId >
|
|
176
|
+
return rowId.localeCompare(cursor.rowId) > 0;
|
|
170
177
|
}
|
|
171
178
|
export function selectProjectionRow(data, select) {
|
|
172
179
|
if (!select?.length)
|
|
173
180
|
return data;
|
|
174
|
-
|
|
175
|
-
for (const field of select)
|
|
176
|
-
picked[field] = data[field];
|
|
177
|
-
return picked;
|
|
181
|
+
return Object.fromEntries(select.map((field) => [field, fieldValue(data, field)]));
|
|
178
182
|
}
|
|
179
183
|
export function evaluateProjectionQuery(rows, query, revision, indexStatus) {
|
|
180
184
|
const orderBy = query.orderBy ?? [];
|
|
@@ -186,7 +190,8 @@ export function evaluateProjectionQuery(rows, query, revision, indexStatus) {
|
|
|
186
190
|
if (comparison !== 0) {
|
|
187
191
|
if (spec.nulls === "first" && fieldValue(left.data, spec.field) == null)
|
|
188
192
|
return -1;
|
|
189
|
-
if (spec.nulls === "first" &&
|
|
193
|
+
if (spec.nulls === "first" &&
|
|
194
|
+
fieldValue(right.data, spec.field) == null)
|
|
190
195
|
return 1;
|
|
191
196
|
if (spec.nulls === "last" && fieldValue(left.data, spec.field) == null)
|
|
192
197
|
return 1;
|
|
@@ -253,7 +258,11 @@ export function indexedValuesForRow(projectionId, row, fields) {
|
|
|
253
258
|
return values;
|
|
254
259
|
}
|
|
255
260
|
export function compileProjectionQuerySql(projectionId, query, definition) {
|
|
256
|
-
const args = [
|
|
261
|
+
const args = [
|
|
262
|
+
projectionId,
|
|
263
|
+
definition.schemaVersion,
|
|
264
|
+
definition.configHash,
|
|
265
|
+
];
|
|
257
266
|
const where = query.includeStale
|
|
258
267
|
? "r.projection_id = ? AND s.schema_version = ? AND s.config_hash = ?"
|
|
259
268
|
: `r.projection_id = ?
|
|
@@ -280,14 +289,18 @@ export function compileProjectionQuerySql(projectionId, query, definition) {
|
|
|
280
289
|
};
|
|
281
290
|
}
|
|
282
291
|
function jsonExtract(field) {
|
|
283
|
-
return `json_extract(r.data_json, '$.${field.replaceAll("'", "''")}')`;
|
|
292
|
+
return `json_extract(r.data_json, '$.${JSON.stringify(field).replaceAll("'", "''")}')`;
|
|
284
293
|
}
|
|
285
294
|
function compileFilterSql(filter, args) {
|
|
286
295
|
switch (filter.op) {
|
|
287
296
|
case "and":
|
|
288
|
-
return filter.operands
|
|
297
|
+
return (filter.operands
|
|
298
|
+
.map((operand) => `(${compileFilterSql(operand, args)})`)
|
|
299
|
+
.join(" AND ") || "1");
|
|
289
300
|
case "or":
|
|
290
|
-
return filter.operands
|
|
301
|
+
return (filter.operands
|
|
302
|
+
.map((operand) => `(${compileFilterSql(operand, args)})`)
|
|
303
|
+
.join(" OR ") || "0");
|
|
291
304
|
case "not":
|
|
292
305
|
return `NOT (${compileFilterSql(filter.operand, args)})`;
|
|
293
306
|
case "exists":
|
|
@@ -297,9 +310,14 @@ function compileFilterSql(filter, args) {
|
|
|
297
310
|
case "in": {
|
|
298
311
|
if (filter.values.length === 0)
|
|
299
312
|
return "0";
|
|
300
|
-
const
|
|
301
|
-
|
|
302
|
-
|
|
313
|
+
const values = filter.values.filter((value) => value != null);
|
|
314
|
+
const placeholders = values.map(() => "?").join(", ");
|
|
315
|
+
args.push(...values);
|
|
316
|
+
const expr = jsonExtract(filter.field);
|
|
317
|
+
const member = values.length ? `${expr} IN (${placeholders})` : "0";
|
|
318
|
+
return values.length !== filter.values.length
|
|
319
|
+
? `(${expr} IS NULL OR ${member})`
|
|
320
|
+
: member;
|
|
303
321
|
}
|
|
304
322
|
case "compare": {
|
|
305
323
|
const expr = jsonExtract(filter.field);
|
|
@@ -27,6 +27,8 @@ export declare class MemoryVaultAdapter implements VaultAdapter, VaultIdentityAd
|
|
|
27
27
|
openRead(path: string): Promise<VaultReadHandle>;
|
|
28
28
|
atomicWrite(path: string, source: ReadableStream<Uint8Array>, options?: AtomicDataWriteOptions): Promise<void>;
|
|
29
29
|
write(path: string, data: string, options?: DataWriteOptions): Promise<void>;
|
|
30
|
+
/** Compare and mutate synchronously before yielding to another memory writer. */
|
|
31
|
+
writeTextIfUnchanged(path: string, data: string, expected: string | null, options?: DataWriteOptions): Promise<void>;
|
|
30
32
|
writeBinary(path: string, data: ArrayBuffer, options?: DataWriteOptions): Promise<void>;
|
|
31
33
|
append(path: string, data: string, options?: DataWriteOptions): Promise<void>;
|
|
32
34
|
appendBinary(path: string, data: ArrayBuffer, options?: DataWriteOptions): Promise<void>;
|
|
@@ -67,6 +67,7 @@ export class MemoryVaultAdapter {
|
|
|
67
67
|
nativeWatch: false,
|
|
68
68
|
resourceUrls: false,
|
|
69
69
|
systemTrash: false,
|
|
70
|
+
conditionalTextWrite: true,
|
|
70
71
|
};
|
|
71
72
|
}
|
|
72
73
|
async exists(path) {
|
|
@@ -134,7 +135,7 @@ export class MemoryVaultAdapter {
|
|
|
134
135
|
try {
|
|
135
136
|
while (true) {
|
|
136
137
|
if (options.signal?.aborted) {
|
|
137
|
-
throw options.signal.reason ?? new DOMException("Aborted", "AbortError");
|
|
138
|
+
throw (options.signal.reason ?? new DOMException("Aborted", "AbortError"));
|
|
138
139
|
}
|
|
139
140
|
const next = await reader.read();
|
|
140
141
|
if (next.done)
|
|
@@ -157,6 +158,18 @@ export class MemoryVaultAdapter {
|
|
|
157
158
|
async write(path, data, options) {
|
|
158
159
|
await this.#writeValue(path, data, options);
|
|
159
160
|
}
|
|
161
|
+
/** Compare and mutate synchronously before yielding to another memory writer. */
|
|
162
|
+
async writeTextIfUnchanged(path, data, expected, options) {
|
|
163
|
+
if (expected !== null && typeof expected !== "string")
|
|
164
|
+
throw fsError("EINVAL", path);
|
|
165
|
+
const normalized = this.#path(path);
|
|
166
|
+
const stored = this.#files.get(normalized);
|
|
167
|
+
if (stored
|
|
168
|
+
? typeof stored.data !== "string" || stored.data !== expected
|
|
169
|
+
: expected !== null)
|
|
170
|
+
throw fsError("ECONFLICT", normalized);
|
|
171
|
+
return this.#writeValue(normalized, data, options);
|
|
172
|
+
}
|
|
160
173
|
async writeBinary(path, data, options) {
|
|
161
174
|
await this.#writeValue(path, data, options);
|
|
162
175
|
}
|
package/dist/storage/path.d.ts
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
/** Shared vault-local state default for every Lapis application host. */
|
|
2
|
+
export declare const DEFAULT_APP_STATE_DIRECTORY = ".lapis";
|
|
3
|
+
/** Resolve an application-owned path beneath the shared state directory. */
|
|
4
|
+
export declare function appStatePath(...parts: string[]): string;
|
|
1
5
|
/**
|
|
2
6
|
* Normalize a vault-style path by removing redundant segments and separators.
|
|
3
7
|
*
|
|
@@ -12,8 +16,8 @@ export declare function basename(path: string): string;
|
|
|
12
16
|
/**
|
|
13
17
|
* Returns whether a vault path belongs to Lapis' portable internal data.
|
|
14
18
|
*
|
|
15
|
-
* Internal data can occur beneath any folder-scoped feature root. Callers
|
|
16
|
-
*
|
|
19
|
+
* Internal data can occur beneath any folder-scoped feature root. Callers that
|
|
20
|
+
* present ordinary vault content should hide these paths, while explicit
|
|
17
21
|
* storage and indexing operations remain free to address them directly.
|
|
18
22
|
*
|
|
19
23
|
* @public
|
package/dist/storage/path.js
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
/** Shared vault-local state default for every Lapis application host. */
|
|
2
|
+
export const DEFAULT_APP_STATE_DIRECTORY = ".lapis";
|
|
3
|
+
/** Resolve an application-owned path beneath the shared state directory. */
|
|
4
|
+
export function appStatePath(...parts) {
|
|
5
|
+
return joinPath(DEFAULT_APP_STATE_DIRECTORY, ...parts);
|
|
6
|
+
}
|
|
1
7
|
/**
|
|
2
8
|
* Normalize a vault-style path by removing redundant segments and separators.
|
|
3
9
|
*
|
|
@@ -66,8 +72,8 @@ export function basename(path) {
|
|
|
66
72
|
/**
|
|
67
73
|
* Returns whether a vault path belongs to Lapis' portable internal data.
|
|
68
74
|
*
|
|
69
|
-
* Internal data can occur beneath any folder-scoped feature root. Callers
|
|
70
|
-
*
|
|
75
|
+
* Internal data can occur beneath any folder-scoped feature root. Callers that
|
|
76
|
+
* present ordinary vault content should hide these paths, while explicit
|
|
71
77
|
* storage and indexing operations remain free to address them directly.
|
|
72
78
|
*
|
|
73
79
|
* @public
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/** SQL narrows only what its scalar semantics can prove; the AST remains final. */
|
|
2
|
+
export function projectionQueryCandidates(query) {
|
|
3
|
+
return {
|
|
4
|
+
where: query.where ? candidate(query.where).filter : undefined,
|
|
5
|
+
includeStale: query.includeStale,
|
|
6
|
+
};
|
|
7
|
+
}
|
|
8
|
+
function candidate(filter) {
|
|
9
|
+
switch (filter.op) {
|
|
10
|
+
case "and":
|
|
11
|
+
case "or": {
|
|
12
|
+
const branches = filter.operands.map(candidate);
|
|
13
|
+
const exact = branches.every((branch) => branch.exact);
|
|
14
|
+
if (filter.op === "or" && branches.some((branch) => !branch.filter)) {
|
|
15
|
+
return { exact };
|
|
16
|
+
}
|
|
17
|
+
return {
|
|
18
|
+
filter: {
|
|
19
|
+
op: filter.op,
|
|
20
|
+
operands: branches.flatMap((branch) => branch.filter ? [branch.filter] : []),
|
|
21
|
+
},
|
|
22
|
+
exact,
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
case "not": {
|
|
26
|
+
const child = candidate(filter.operand);
|
|
27
|
+
return child.exact
|
|
28
|
+
? {
|
|
29
|
+
filter: {
|
|
30
|
+
op: "not",
|
|
31
|
+
operand: child.filter ?? { op: "and", operands: [] },
|
|
32
|
+
},
|
|
33
|
+
exact: true,
|
|
34
|
+
}
|
|
35
|
+
: { exact: false };
|
|
36
|
+
}
|
|
37
|
+
case "exists":
|
|
38
|
+
case "not-exists":
|
|
39
|
+
return { filter, exact: true };
|
|
40
|
+
case "in": {
|
|
41
|
+
if (!filter.values.length)
|
|
42
|
+
return { filter: { op: "or", operands: [] }, exact: true };
|
|
43
|
+
if (filter.values.every((value) => value == null)) {
|
|
44
|
+
return {
|
|
45
|
+
filter: { op: "not-exists", field: filter.field },
|
|
46
|
+
exact: true,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
return filter.values.some((value) => value == null)
|
|
50
|
+
? { exact: false }
|
|
51
|
+
: { filter: { op: "exists", field: filter.field }, exact: false };
|
|
52
|
+
}
|
|
53
|
+
case "compare": {
|
|
54
|
+
if (filter.value == null) {
|
|
55
|
+
if (filter.comparison === "eq" || filter.comparison === "ne")
|
|
56
|
+
return { filter, exact: true };
|
|
57
|
+
return {
|
|
58
|
+
filter: filter.comparison === "lt" || filter.comparison === "lte"
|
|
59
|
+
? { op: "exists", field: filter.field }
|
|
60
|
+
: { op: "or", operands: [] },
|
|
61
|
+
exact: true,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
return filter.comparison === "ne"
|
|
65
|
+
? { exact: false }
|
|
66
|
+
: { filter: { op: "exists", field: filter.field }, exact: false };
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
1
|
+
import { z } from "zod/v3";
|
|
2
2
|
import type { AppDatabase } from "./app-database";
|
|
3
3
|
export declare const REMOTE_APP_DATABASE_MAX_ARGUMENTS = 4;
|
|
4
4
|
export declare const REMOTE_APP_DATABASE_MAX_MESSAGE_BYTES: number;
|
|
5
5
|
export declare const REMOTE_APP_DATABASE_METHODS: readonly ["migrate", "beginSearchIndexingBatch", "endSearchIndexingBatch", "configureSearchEmbeddingProvider", "getSearchEmbeddingProvider", "getSearchEmbeddingRuntimeStatus", "getSearchIndexStats", "getMeta", "setMeta", "scanMeta", "transactMeta", "getNotebookState", "setNotebookState", "deleteNotebookState", "loadMetadataSnapshot", "saveMetadataSnapshot", "getFileHistory", "storeFileHistoryRevision", "listNotifications", "upsertNotification", "markNotificationRead", "clearNotification", "clearAllNotifications", "getMemorySourceState", "listMemorySourceStates", "upsertMemorySourceState", "deleteMemorySourceState", "upsertMemoryCandidate", "queryMemoryCandidates", "deleteMemoryCandidatesByConversation", "recordMemoryRecallSignal", "listMemoryRecallSignals", "claimMemoryJob", "updateMemoryJob", "listMemoryJobs", "clearMemoryDerivedState", "getChangeRevision", "upsertIndexedFile", "getIndexedFile", "listIndexedFileManifest", "queryIndexedMetadata", "queryIndexedMetadataPage", "queryMetadataFacets", "queryMetadataLinks", "deleteIndexedFile", "renameIndexedFile", "upsertSearchDocument", "deleteSearchDocument", "getSearchDocument", "listSearchDocumentManifest", "listSearchDocuments", "rebuildSearchIndex", "searchDocuments", "searchDocumentPaths", "upsertTaskProjection", "deleteTaskProjection", "queryTasks", "getTaskRow", "listChildLinks", "listTaskDescendants", "registerProjectionDefinition", "unregisterProjectionDefinition", "replaceProjectionSource", "markProjectionSourceError", "deleteProjectionSource", "queryProjection", "getProjectionRow", "queryRelated"];
|
|
6
6
|
export type RemoteAppDatabaseMethod = (typeof REMOTE_APP_DATABASE_METHODS)[number];
|
|
7
|
-
export type RemoteAppDatabaseArgs<Method extends RemoteAppDatabaseMethod> = AppDatabase[Method] extends (...args: infer Args) => unknown ? Args : never;
|
|
7
|
+
export type RemoteAppDatabaseArgs<Method extends RemoteAppDatabaseMethod> = Method extends RemoteAppDatabaseMethod ? AppDatabase[Method] extends (...args: infer Args) => unknown ? Args : never : never;
|
|
8
8
|
export type RemoteAppDatabaseResult<Method extends RemoteAppDatabaseMethod> = AppDatabase[Method] extends (...args: never[]) => infer Result ? Awaited<Result> : never;
|
|
9
9
|
export type RemoteAppDatabaseDomain = "lifecycle" | "metadata" | "search" | "history" | "notifications" | "memory" | "tasks" | "projections";
|
|
10
10
|
export interface RemoteAppDatabaseContractEntry<Method extends RemoteAppDatabaseMethod> {
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
/** Application host identity, independent of optional database/model services. */
|
|
2
|
+
export type RuntimeTarget = "web-pwa" | "deno-desktop" | "tauri-desktop" | "node-server" | "rust-server" | "deno-server" | "test";
|
|
3
|
+
export declare function isNativeDesktopRuntime(runtime?: RuntimeTarget | null): runtime is "deno-desktop" | "tauri-desktop";
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { SearchDocumentRecord } from "./app-database";
|
|
2
|
+
import type { SearchEmbeddingProviderConfig } from "./search-embedding-provider";
|
|
3
|
+
export declare function rebindSearchDocument(document: SearchDocumentRecord, config: SearchEmbeddingProviderConfig | null): SearchDocumentRecord;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export function rebindSearchDocument(document, config) {
|
|
2
|
+
const copy = JSON.parse(JSON.stringify(document));
|
|
3
|
+
if (!config || !copy.chunks?.length)
|
|
4
|
+
return copy;
|
|
5
|
+
copy.chunks = copy.chunks.map((chunk) => chunk.text.trim().length
|
|
6
|
+
? {
|
|
7
|
+
...chunk,
|
|
8
|
+
embedding: {
|
|
9
|
+
status: "pending",
|
|
10
|
+
modelId: config.modelId ?? "lapis/token-hash-v0",
|
|
11
|
+
modelVersion: config.modelVersion,
|
|
12
|
+
dimensions: config.dimensions,
|
|
13
|
+
dirty: true,
|
|
14
|
+
},
|
|
15
|
+
}
|
|
16
|
+
: chunk);
|
|
17
|
+
return copy;
|
|
18
|
+
}
|
|
@@ -32,6 +32,7 @@ export declare class TursoAppDatabase implements AppDatabase {
|
|
|
32
32
|
readonly kind: Extract<AppDatabaseKind, "turso-native" | "turso-wasm">;
|
|
33
33
|
private connection;
|
|
34
34
|
private opened;
|
|
35
|
+
private closeTask;
|
|
35
36
|
private nativeFullTextSearch;
|
|
36
37
|
private nativeVectorSearch;
|
|
37
38
|
private searchEmbeddingProviderConfig;
|
|
@@ -47,6 +48,7 @@ export declare class TursoAppDatabase implements AppDatabase {
|
|
|
47
48
|
beginSearchIndexingBatch(): Promise<void>;
|
|
48
49
|
endSearchIndexingBatch(): Promise<void>;
|
|
49
50
|
configureSearchEmbeddingProvider(provider: SearchEmbeddingProviderConfig | null): Promise<void>;
|
|
51
|
+
private configureSearchProviderImmediately;
|
|
50
52
|
getSearchEmbeddingProvider(): Promise<SearchEmbeddingProviderConfig | null>;
|
|
51
53
|
getSearchEmbeddingRuntimeStatus(): Promise<SearchEmbeddingRuntimeStatus | null>;
|
|
52
54
|
getSearchIndexStats(): Promise<AppDatabaseSearchIndexStats>;
|