@lapis-notes/api 0.1.4 → 0.2.1

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.
Files changed (188) hide show
  1. package/CHANGELOG.md +206 -0
  2. package/README.md +21 -2
  3. package/dist/__tests__/fixtures/indexed-mutations.json +6862 -0
  4. package/dist/__tests__/fixtures/memory-storage.json +309 -0
  5. package/dist/__tests__/fixtures/native-facade-contract.json +3224 -0
  6. package/dist/__tests__/fixtures/projection-query.json +195 -0
  7. package/dist/__tests__/fixtures/projection-values.json +60 -0
  8. package/dist/__tests__/fixtures/search-preparation.json +1513 -0
  9. package/dist/__tests__/fixtures/search-retrieval.json +15409 -0
  10. package/dist/__tests__/fixtures/search-semantic-model.json +3691 -0
  11. package/dist/__tests__/fixtures/search-semantic-retrieval.json +6603 -0
  12. package/dist/__tests__/fixtures/search-storage.json +409 -0
  13. package/dist/__tests__/fixtures/task-projection.json +428 -0
  14. package/dist/__tests__/indexed-mutation-support.js +262 -0
  15. package/dist/__tests__/projection-query-support.js +40 -0
  16. package/dist/__tests__/search-retrieval-support.js +47 -0
  17. package/dist/app-database-host.d.ts +1 -0
  18. package/dist/app-shell-plugin-persistence.d.ts +3 -2
  19. package/dist/app-shell-plugin-persistence.js +37 -3
  20. package/dist/cache.svelte.d.ts +8 -1
  21. package/dist/cache.svelte.js +103 -5
  22. package/dist/command.svelte.js +29 -2
  23. package/dist/components/editor/editor.css +4 -0
  24. package/dist/components/editor/editor.svelte +21 -9
  25. package/dist/components/editor/embedded-editor-surface.js +3 -1
  26. package/dist/components/editor/inline-title-alignment.d.ts +3 -0
  27. package/dist/components/editor/inline-title-alignment.js +57 -0
  28. package/dist/configuration.svelte.d.ts +270 -206
  29. package/dist/configuration.svelte.js +161 -86
  30. package/dist/context.svelte.d.ts +21 -3
  31. package/dist/context.svelte.js +63 -20
  32. package/dist/diagnostics.d.ts +8 -0
  33. package/dist/diagnostics.js +6 -0
  34. package/dist/editor-save-context.d.ts +12 -1
  35. package/dist/editor-save-context.js +32 -1
  36. package/dist/editor-view-registry.d.ts +10 -0
  37. package/dist/editor-view-registry.js +44 -4
  38. package/dist/editor.svelte.js +128 -37
  39. package/dist/embed-registry.d.ts +10 -0
  40. package/dist/embed-registry.js +15 -0
  41. package/dist/file-editing-failures.d.ts +2 -0
  42. package/dist/file-editing-failures.js +29 -0
  43. package/dist/file-editing-native-issues.d.ts +19 -0
  44. package/dist/file-editing-native-issues.js +65 -0
  45. package/dist/file-editing-sessions.d.ts +56 -8
  46. package/dist/file-editing-sessions.js +185 -15
  47. package/dist/file-manager.d.ts +8 -1
  48. package/dist/file-manager.js +37 -3
  49. package/dist/file-state-store.d.ts +5 -0
  50. package/dist/file-state-store.js +34 -0
  51. package/dist/file-text-conflicts.d.ts +25 -0
  52. package/dist/file-text-conflicts.js +35 -0
  53. package/dist/file-text-mutation.d.ts +13 -0
  54. package/dist/file-text-mutation.js +100 -0
  55. package/dist/file-text-persistence.d.ts +36 -0
  56. package/dist/file-text-persistence.js +234 -0
  57. package/dist/file-text-state-writer.d.ts +34 -0
  58. package/dist/file-text-state-writer.js +183 -0
  59. package/dist/files-configuration.d.ts +20 -0
  60. package/dist/files-configuration.js +47 -0
  61. package/dist/generated/plugin-host-modules.schema.generated.d.ts +87 -37
  62. package/dist/generated/plugin-host-modules.schema.generated.js +102 -37
  63. package/dist/glob.d.ts +3 -0
  64. package/dist/glob.js +2 -1
  65. package/dist/icons/changes.d.ts +3 -0
  66. package/dist/icons/changes.js +16 -0
  67. package/dist/icons/index.d.ts +5 -1
  68. package/dist/icons/index.js +44 -3
  69. package/dist/icons/registry.d.ts +35 -0
  70. package/dist/icons/registry.js +154 -0
  71. package/dist/icons/safe-svg.d.ts +2 -0
  72. package/dist/icons/safe-svg.js +44 -0
  73. package/dist/index.d.ts +5 -1
  74. package/dist/index.js +3 -1
  75. package/dist/lapis-extension.d.ts +6 -2
  76. package/dist/lapis-extension.js +2 -0
  77. package/dist/metadata.svelte.js +45 -2
  78. package/dist/native-background-indexing.d.ts +48 -0
  79. package/dist/native-background-indexing.js +208 -0
  80. package/dist/native-database-protocol.d.ts +29 -0
  81. package/dist/native-database-protocol.js +1 -0
  82. package/dist/native-editing-intent-lease.d.ts +17 -0
  83. package/dist/native-editing-intent-lease.js +188 -0
  84. package/dist/native-editing-intents-protocol.d.ts +70 -0
  85. package/dist/native-editing-intents-protocol.js +1 -0
  86. package/dist/native-editing-intents.d.ts +8 -0
  87. package/dist/native-editing-intents.js +1 -0
  88. package/dist/native-editing-problems.d.ts +3 -0
  89. package/dist/native-editing-problems.js +180 -0
  90. package/dist/native-editing-recovery.d.ts +24 -0
  91. package/dist/native-editing-recovery.js +198 -0
  92. package/dist/native-editing-session.d.ts +51 -0
  93. package/dist/native-editing-session.js +251 -0
  94. package/dist/native-history-index-protocol.d.ts +80 -0
  95. package/dist/native-history-index-protocol.js +1 -0
  96. package/dist/native-history-index.d.ts +6 -0
  97. package/dist/native-history-index.js +1 -0
  98. package/dist/native-indexing-protocol.d.ts +63 -0
  99. package/dist/native-indexing-protocol.js +1 -0
  100. package/dist/native-participant-protocol.d.ts +67 -0
  101. package/dist/native-participant-protocol.js +3 -0
  102. package/dist/native-queue-protocol.d.ts +73 -0
  103. package/dist/native-queue-protocol.js +3 -0
  104. package/dist/native-tasks-protocol.d.ts +264 -0
  105. package/dist/native-tasks-protocol.js +1 -0
  106. package/dist/native-tasks.d.ts +35 -0
  107. package/dist/native-tasks.js +79 -0
  108. package/dist/native-turn-protocol.d.ts +81 -0
  109. package/dist/native-turn-protocol.js +1 -0
  110. package/dist/native-turns.d.ts +29 -0
  111. package/dist/native-turns.js +2 -0
  112. package/dist/plugin-asset-server.js +3 -2
  113. package/dist/plugin-dependency-resolver.d.ts +1 -1
  114. package/dist/plugin-distribution/compatibility.d.ts +1 -1
  115. package/dist/plugin-distribution/compatibility.js +10 -5
  116. package/dist/plugin-distribution/installed-plugin-state.js +2 -1
  117. package/dist/plugin-distribution/installer.d.ts +6 -0
  118. package/dist/plugin-distribution/installer.js +90 -37
  119. package/dist/plugin-distribution/manager.d.ts +4 -1
  120. package/dist/plugin-distribution/manager.js +12 -5
  121. package/dist/plugin-distribution/registry-cache.js +2 -1
  122. package/dist/plugin-distribution/registry-source-state.js +2 -1
  123. package/dist/plugin-distribution/schemas.d.ts +26 -8
  124. package/dist/plugin-distribution/schemas.js +2 -1
  125. package/dist/plugin-distribution/types.d.ts +4 -0
  126. package/dist/plugin-manager.d.ts +20 -4
  127. package/dist/plugin-manager.js +228 -64
  128. package/dist/plugin-runtime-entry.d.ts +1 -1
  129. package/dist/plugin-runtime-entry.js +16 -0
  130. package/dist/plugin.d.ts +18 -2
  131. package/dist/plugin.js +93 -39
  132. package/dist/registry-schema/catalog-v1.d.ts +60 -9
  133. package/dist/registry-schema/catalog-v1.js +2 -1
  134. package/dist/registry-schema/catalog-v2.d.ts +60 -9
  135. package/dist/registry-schema/catalog-v2.js +1 -1
  136. package/dist/search-result-provider.d.ts +95 -0
  137. package/dist/search-result-provider.js +42 -0
  138. package/dist/status-bar.svelte.d.ts +26 -20
  139. package/dist/status-bar.svelte.js +1 -0
  140. package/dist/storage/app-database.d.ts +6 -2
  141. package/dist/storage/app-database.js +41 -34
  142. package/dist/storage/desktop-native.d.ts +5 -3
  143. package/dist/storage/desktop-native.js +59 -6
  144. package/dist/storage/directory-watcher.d.ts +27 -0
  145. package/dist/storage/directory-watcher.js +201 -0
  146. package/dist/storage/fs.d.ts +14 -27
  147. package/dist/storage/fs.js +2 -168
  148. package/dist/storage/index-projection.js +33 -15
  149. package/dist/storage/memory-vault-adapter.d.ts +2 -0
  150. package/dist/storage/memory-vault-adapter.js +14 -1
  151. package/dist/storage/path.d.ts +6 -2
  152. package/dist/storage/path.js +8 -2
  153. package/dist/storage/projection-query-candidates.d.ts +3 -0
  154. package/dist/storage/projection-query-candidates.js +69 -0
  155. package/dist/storage/remote-app-database.d.ts +2 -2
  156. package/dist/storage/remote-app-database.js +1 -1
  157. package/dist/storage/runtime.d.ts +3 -0
  158. package/dist/storage/runtime.js +3 -0
  159. package/dist/storage/search-embedding-record.d.ts +3 -0
  160. package/dist/storage/search-embedding-record.js +18 -0
  161. package/dist/storage/turso-app-database.d.ts +2 -0
  162. package/dist/storage/turso-app-database.js +67 -30
  163. package/dist/storage/vault-listing.d.ts +3 -0
  164. package/dist/storage/vault-listing.js +36 -0
  165. package/dist/storage/vault-reconciliation.d.ts +19 -0
  166. package/dist/storage/vault-reconciliation.js +137 -0
  167. package/dist/storage/vault-session.d.ts +8 -0
  168. package/dist/storage/vault-session.js +10 -2
  169. package/dist/storage/vault.svelte.d.ts +53 -4
  170. package/dist/storage/vault.svelte.js +223 -87
  171. package/dist/sync-host.d.ts +12 -3
  172. package/dist/sync-host.js +5 -1
  173. package/dist/vault-change-views.d.ts +4 -0
  174. package/dist/vault-change-views.js +43 -0
  175. package/dist/vault-changes.d.ts +37 -0
  176. package/dist/vault-changes.js +228 -0
  177. package/dist/view.svelte.d.ts +182 -149
  178. package/dist/view.svelte.js +11 -2
  179. package/dist/workspace-close-guard.d.ts +3 -0
  180. package/dist/workspace-close-guard.js +35 -0
  181. package/dist/workspace-host-internal.js +10 -2
  182. package/dist/workspace-layout-normalizer.d.ts +4 -2
  183. package/dist/workspace-layout-normalizer.js +5 -5
  184. package/dist/workspace-view-document.d.ts +3 -0
  185. package/dist/workspace-view-document.js +12 -0
  186. package/dist/workspace.svelte.d.ts +13 -2
  187. package/dist/workspace.svelte.js +371 -82
  188. package/package.json +45 -8
@@ -1,5 +1,4 @@
1
- import { EventDispatcher } from "../events";
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
- function isNativeWatchAdapter(adapter) {
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 || typeof value === "string" || typeof value === "number") {
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 comparison = compareScalars(sortValues[index] ?? null, cursor.values[index] ?? null);
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 > cursor.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
- const picked = {};
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" && fieldValue(right.data, spec.field) == null)
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 = [projectionId, definition.schemaVersion, definition.configHash];
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.map((operand) => `(${compileFilterSql(operand, args)})`).join(" AND ");
297
+ return (filter.operands
298
+ .map((operand) => `(${compileFilterSql(operand, args)})`)
299
+ .join(" AND ") || "1");
289
300
  case "or":
290
- return filter.operands.map((operand) => `(${compileFilterSql(operand, args)})`).join(" OR ");
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 placeholders = filter.values.map(() => "?").join(", ");
301
- args.push(...filter.values);
302
- return `${jsonExtract(filter.field)} IN (${placeholders})`;
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
  }
@@ -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
- * that present ordinary vault content should hide these paths, while explicit
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
@@ -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
- * that present ordinary vault content should hide these paths, while explicit
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,3 @@
1
+ import type { IndexQuery } from "./index-projection";
2
+ /** SQL narrows only what its scalar semantics can prove; the AST remains final. */
3
+ export declare function projectionQueryCandidates(query: IndexQuery): IndexQuery;
@@ -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> {
@@ -1,4 +1,4 @@
1
- import { z } from "zod";
1
+ import { z } from "zod/v3";
2
2
  export const REMOTE_APP_DATABASE_MAX_ARGUMENTS = 4;
3
3
  export const REMOTE_APP_DATABASE_MAX_MESSAGE_BYTES = 32 * 1024 * 1024;
4
4
  export const REMOTE_APP_DATABASE_METHODS = [
@@ -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
+ export function isNativeDesktopRuntime(runtime) {
2
+ return runtime === "deno-desktop" || runtime === "tauri-desktop";
3
+ }
@@ -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>;