@lapis-notes/api 0.1.0 → 0.1.3

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 (109) hide show
  1. package/CHANGELOG.md +39 -0
  2. package/README.md +5 -0
  3. package/dist/app-database-host.d.ts +1 -0
  4. package/dist/app-database-host.js +1 -0
  5. package/dist/browser-sync-security.d.ts +45 -0
  6. package/dist/browser-sync-security.js +189 -0
  7. package/dist/build-tools/vite.d.ts +15 -0
  8. package/dist/build-tools/vite.js +36 -0
  9. package/dist/cache.svelte.d.ts +1 -1
  10. package/dist/cache.svelte.js +4 -1
  11. package/dist/components/editor/editor.css +54 -2
  12. package/dist/components/editor/extensions/lint/lapis-lint-tooltip.svelte +18 -5
  13. package/dist/components/editor/extensions/lint/lint-tooltip-actions.d.ts +0 -2
  14. package/dist/components/editor/extensions/lint/lint-tooltip-actions.js +0 -14
  15. package/dist/components/editor/language-service/index.js +23 -2
  16. package/dist/components/icon/icon-list.svelte.d.ts +1 -1
  17. package/dist/components/select/select.svelte.d.ts +1 -1
  18. package/dist/context.svelte.d.ts +11 -1
  19. package/dist/context.svelte.js +38 -1
  20. package/dist/docs-api.d.ts +2 -0
  21. package/dist/docs-api.js +1 -0
  22. package/dist/generated/plugin-host-modules.schema.generated.d.ts +443 -13
  23. package/dist/generated/plugin-host-modules.schema.generated.js +970 -306
  24. package/dist/index.d.ts +5 -0
  25. package/dist/index.js +5 -0
  26. package/dist/language-service/manager.d.ts +5 -0
  27. package/dist/language-service/manager.js +58 -14
  28. package/dist/lapis-extension.d.ts +1 -1
  29. package/dist/lapis-extension.js +12 -0
  30. package/dist/nostr-signer.d.ts +68 -0
  31. package/dist/nostr-signer.js +49 -0
  32. package/dist/plugin-asset-server.d.ts +1 -0
  33. package/dist/plugin-asset-server.js +3 -0
  34. package/dist/plugin-capability-facade.d.ts +1 -1
  35. package/dist/plugin-capability-facade.js +6 -0
  36. package/dist/plugin-distribution/catalog-media.d.ts +4 -0
  37. package/dist/plugin-distribution/catalog-media.js +40 -0
  38. package/dist/plugin-distribution/download-stats.d.ts +4 -0
  39. package/dist/plugin-distribution/download-stats.js +19 -0
  40. package/dist/plugin-distribution/index.d.ts +4 -0
  41. package/dist/plugin-distribution/index.js +4 -0
  42. package/dist/plugin-distribution/installer.d.ts +3 -0
  43. package/dist/plugin-distribution/installer.js +26 -3
  44. package/dist/plugin-distribution/manager.d.ts +71 -5
  45. package/dist/plugin-distribution/manager.js +376 -37
  46. package/dist/plugin-distribution/nostr-registry-adapter.d.ts +29 -0
  47. package/dist/plugin-distribution/nostr-registry-adapter.js +152 -0
  48. package/dist/plugin-distribution/plugin-bundle-verifier.d.ts +43 -0
  49. package/dist/plugin-distribution/plugin-bundle-verifier.js +64 -1
  50. package/dist/plugin-distribution/plugin-bundle.d.ts +14 -0
  51. package/dist/plugin-distribution/plugin-bundle.js +46 -7
  52. package/dist/plugin-distribution/plugin-markdown.d.ts +6 -0
  53. package/dist/plugin-distribution/plugin-markdown.js +94 -0
  54. package/dist/plugin-distribution/registry-client.d.ts +6 -1
  55. package/dist/plugin-distribution/registry-client.js +32 -10
  56. package/dist/plugin-distribution/registry-source-state.d.ts +15 -0
  57. package/dist/plugin-distribution/registry-source-state.js +42 -0
  58. package/dist/plugin-distribution/schemas.d.ts +2511 -2824
  59. package/dist/plugin-distribution/schemas.js +111 -42
  60. package/dist/plugin-distribution/types.d.ts +116 -5
  61. package/dist/plugin-distribution-host.d.ts +4 -0
  62. package/dist/plugin-distribution-host.js +2 -0
  63. package/dist/plugin-install-progress.js +1 -1
  64. package/dist/plugin-manager.d.ts +3 -0
  65. package/dist/plugin-manager.js +21 -13
  66. package/dist/plugin-settings.d.ts +21 -0
  67. package/dist/plugin-settings.js +41 -0
  68. package/dist/plugin.d.ts +13 -0
  69. package/dist/plugin.js +56 -0
  70. package/dist/registry-schema/catalog-v1.d.ts +4143 -0
  71. package/dist/registry-schema/catalog-v1.js +172 -0
  72. package/dist/registry-schema/catalog-v2.d.ts +5275 -0
  73. package/dist/registry-schema/catalog-v2.js +137 -0
  74. package/dist/registry-schema/index.d.ts +1 -0
  75. package/dist/registry-schema/index.js +1 -0
  76. package/dist/registry-schema/release-notes.d.ts +5 -0
  77. package/dist/registry-schema/release-notes.js +21 -0
  78. package/dist/server-host.d.ts +28 -0
  79. package/dist/server-host.js +17 -0
  80. package/dist/storage/app-database.d.ts +37 -2
  81. package/dist/storage/app-database.js +41 -1
  82. package/dist/storage/browser-coordinated-app-database.d.ts +3 -1
  83. package/dist/storage/browser-coordinated-app-database.js +8 -0
  84. package/dist/storage/browser.d.ts +4 -1
  85. package/dist/storage/browser.js +84 -0
  86. package/dist/storage/desktop-native.d.ts +4 -2
  87. package/dist/storage/desktop-native.js +90 -1
  88. package/dist/storage/fs.d.ts +17 -0
  89. package/dist/storage/index.d.ts +1 -0
  90. package/dist/storage/index.js +1 -0
  91. package/dist/storage/memory-vault-adapter.d.ts +3 -1
  92. package/dist/storage/memory-vault-adapter.js +60 -0
  93. package/dist/storage/remote-app-database.d.ts +19 -0
  94. package/dist/storage/remote-app-database.js +130 -0
  95. package/dist/storage/task-projection.d.ts +2 -1
  96. package/dist/storage/task-projection.js +7 -2
  97. package/dist/storage/turso-app-database.d.ts +3 -1
  98. package/dist/storage/turso-app-database.js +45 -0
  99. package/dist/storage/vault-session.js +11 -0
  100. package/dist/storage/vault-state.d.ts +1 -1
  101. package/dist/storage/vault.svelte.d.ts +3 -1
  102. package/dist/storage/vault.svelte.js +76 -3
  103. package/dist/sync-host-security.d.ts +285 -0
  104. package/dist/sync-host-security.js +2237 -0
  105. package/dist/sync-host.d.ts +179 -0
  106. package/dist/sync-host.js +769 -0
  107. package/dist/workspace.svelte.d.ts +1 -1
  108. package/dist/workspace.svelte.js +1 -1
  109. package/package.json +48 -10
@@ -2,6 +2,7 @@ export * from "./fs";
2
2
  export * from "./memory-vault-adapter";
3
3
  export * from "./blob-store";
4
4
  export * from "./app-database";
5
+ export * from "./remote-app-database";
5
6
  export * from "./task-projection";
6
7
  export * from "./index-projection";
7
8
  export * from "./turso-app-database";
@@ -2,6 +2,7 @@ export * from "./fs";
2
2
  export * from "./memory-vault-adapter";
3
3
  export * from "./blob-store";
4
4
  export * from "./app-database";
5
+ export * from "./remote-app-database";
5
6
  export * from "./task-projection";
6
7
  export * from "./index-projection";
7
8
  export * from "./turso-app-database";
@@ -1,4 +1,4 @@
1
- import type { DataWriteOptions, ListedFiles, Stat, VaultAdapter, VaultAdapterCapabilities, VaultIdentityAdapter } from "./fs";
1
+ import type { DataWriteOptions, AtomicDataWriteOptions, ListedFiles, Stat, VaultAdapter, VaultAdapterCapabilities, VaultIdentityAdapter, VaultReadHandle } from "./fs";
2
2
  export type MemoryVaultClock = number | (() => number);
3
3
  export interface MemoryVaultAdapterOptions {
4
4
  name?: string;
@@ -24,6 +24,8 @@ export declare class MemoryVaultAdapter implements VaultAdapter, VaultIdentityAd
24
24
  stat(path: string): Promise<Stat | null>;
25
25
  read(path: string): Promise<string>;
26
26
  readBinary(path: string): Promise<ArrayBuffer>;
27
+ openRead(path: string): Promise<VaultReadHandle>;
28
+ atomicWrite(path: string, source: ReadableStream<Uint8Array>, options?: AtomicDataWriteOptions): Promise<void>;
27
29
  write(path: string, data: string, options?: DataWriteOptions): Promise<void>;
28
30
  writeBinary(path: string, data: ArrayBuffer, options?: DataWriteOptions): Promise<void>;
29
31
  append(path: string, data: string, options?: DataWriteOptions): Promise<void>;
@@ -94,6 +94,66 @@ export class MemoryVaultAdapter {
94
94
  ? toArrayBuffer(new TextEncoder().encode(value))
95
95
  : value.slice(0);
96
96
  }
97
+ async openRead(path) {
98
+ const normalized = this.#path(path);
99
+ const value = this.#files.get(normalized);
100
+ if (!value)
101
+ throw fsError("ENOENT", normalized);
102
+ const bytes = typeof value.data === "string"
103
+ ? new TextEncoder().encode(value.data)
104
+ : new Uint8Array(value.data.slice(0));
105
+ return {
106
+ size: bytes.byteLength,
107
+ mtime: value.stat.mtime,
108
+ stream: ({ offset = 0, length, signal } = {}) => {
109
+ const start = Math.max(0, Math.min(bytes.byteLength, Math.floor(offset)));
110
+ const end = Math.min(bytes.byteLength, start + Math.max(0, Math.floor(length ?? bytes.byteLength - start)));
111
+ let cursor = start;
112
+ return new ReadableStream({
113
+ pull(controller) {
114
+ if (signal?.aborted) {
115
+ controller.error(signal.reason ?? new DOMException("Aborted", "AbortError"));
116
+ return;
117
+ }
118
+ if (cursor >= end) {
119
+ controller.close();
120
+ return;
121
+ }
122
+ const next = Math.min(end, cursor + 64 * 1024);
123
+ controller.enqueue(bytes.slice(cursor, next));
124
+ cursor = next;
125
+ },
126
+ });
127
+ },
128
+ };
129
+ }
130
+ async atomicWrite(path, source, options = {}) {
131
+ const reader = source.getReader();
132
+ const chunks = [];
133
+ let size = 0;
134
+ try {
135
+ while (true) {
136
+ if (options.signal?.aborted) {
137
+ throw options.signal.reason ?? new DOMException("Aborted", "AbortError");
138
+ }
139
+ const next = await reader.read();
140
+ if (next.done)
141
+ break;
142
+ chunks.push(next.value);
143
+ size += next.value.byteLength;
144
+ }
145
+ }
146
+ finally {
147
+ reader.releaseLock();
148
+ }
149
+ const bytes = new Uint8Array(size);
150
+ let offset = 0;
151
+ for (const chunk of chunks) {
152
+ bytes.set(chunk, offset);
153
+ offset += chunk.byteLength;
154
+ }
155
+ await this.writeBinary(path, bytes.buffer, options);
156
+ }
97
157
  async write(path, data, options) {
98
158
  await this.#writeValue(path, data, options);
99
159
  }
@@ -0,0 +1,19 @@
1
+ import { z } from "zod";
2
+ import type { AppDatabase } from "./app-database";
3
+ export declare const REMOTE_APP_DATABASE_MAX_ARGUMENTS = 4;
4
+ export declare const REMOTE_APP_DATABASE_MAX_MESSAGE_BYTES: number;
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
+ 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;
8
+ export type RemoteAppDatabaseResult<Method extends RemoteAppDatabaseMethod> = AppDatabase[Method] extends (...args: never[]) => infer Result ? Awaited<Result> : never;
9
+ export type RemoteAppDatabaseDomain = "lifecycle" | "metadata" | "search" | "history" | "notifications" | "memory" | "tasks" | "projections";
10
+ export interface RemoteAppDatabaseContractEntry<Method extends RemoteAppDatabaseMethod> {
11
+ readonly method: Method;
12
+ readonly domain: RemoteAppDatabaseDomain;
13
+ readonly input: z.ZodType<RemoteAppDatabaseArgs<Method>>;
14
+ readonly output: z.ZodType<RemoteAppDatabaseResult<Method>>;
15
+ }
16
+ export declare const REMOTE_APP_DATABASE_CONTRACT: { readonly [Method in RemoteAppDatabaseMethod]: RemoteAppDatabaseContractEntry<Method>; };
17
+ export declare function isRemoteAppDatabaseMethod(value: unknown): value is RemoteAppDatabaseMethod;
18
+ export declare function parseRemoteAppDatabaseArgs<Method extends RemoteAppDatabaseMethod>(method: Method, value: unknown): RemoteAppDatabaseArgs<Method>;
19
+ export declare function parseRemoteAppDatabaseResult<Method extends RemoteAppDatabaseMethod>(method: Method, value: unknown): RemoteAppDatabaseResult<Method>;
@@ -0,0 +1,130 @@
1
+ import { z } from "zod";
2
+ export const REMOTE_APP_DATABASE_MAX_ARGUMENTS = 4;
3
+ export const REMOTE_APP_DATABASE_MAX_MESSAGE_BYTES = 32 * 1024 * 1024;
4
+ export const REMOTE_APP_DATABASE_METHODS = [
5
+ "migrate",
6
+ "beginSearchIndexingBatch",
7
+ "endSearchIndexingBatch",
8
+ "configureSearchEmbeddingProvider",
9
+ "getSearchEmbeddingProvider",
10
+ "getSearchEmbeddingRuntimeStatus",
11
+ "getSearchIndexStats",
12
+ "getMeta",
13
+ "setMeta",
14
+ "scanMeta",
15
+ "transactMeta",
16
+ "getNotebookState",
17
+ "setNotebookState",
18
+ "deleteNotebookState",
19
+ "loadMetadataSnapshot",
20
+ "saveMetadataSnapshot",
21
+ "getFileHistory",
22
+ "storeFileHistoryRevision",
23
+ "listNotifications",
24
+ "upsertNotification",
25
+ "markNotificationRead",
26
+ "clearNotification",
27
+ "clearAllNotifications",
28
+ "getMemorySourceState",
29
+ "listMemorySourceStates",
30
+ "upsertMemorySourceState",
31
+ "deleteMemorySourceState",
32
+ "upsertMemoryCandidate",
33
+ "queryMemoryCandidates",
34
+ "deleteMemoryCandidatesByConversation",
35
+ "recordMemoryRecallSignal",
36
+ "listMemoryRecallSignals",
37
+ "claimMemoryJob",
38
+ "updateMemoryJob",
39
+ "listMemoryJobs",
40
+ "clearMemoryDerivedState",
41
+ "getChangeRevision",
42
+ "upsertIndexedFile",
43
+ "getIndexedFile",
44
+ "listIndexedFileManifest",
45
+ "queryIndexedMetadata",
46
+ "queryIndexedMetadataPage",
47
+ "queryMetadataFacets",
48
+ "queryMetadataLinks",
49
+ "deleteIndexedFile",
50
+ "renameIndexedFile",
51
+ "upsertSearchDocument",
52
+ "deleteSearchDocument",
53
+ "getSearchDocument",
54
+ "listSearchDocumentManifest",
55
+ "listSearchDocuments",
56
+ "rebuildSearchIndex",
57
+ "searchDocuments",
58
+ "searchDocumentPaths",
59
+ "upsertTaskProjection",
60
+ "deleteTaskProjection",
61
+ "queryTasks",
62
+ "getTaskRow",
63
+ "listChildLinks",
64
+ "listTaskDescendants",
65
+ "registerProjectionDefinition",
66
+ "unregisterProjectionDefinition",
67
+ "replaceProjectionSource",
68
+ "markProjectionSourceError",
69
+ "deleteProjectionSource",
70
+ "queryProjection",
71
+ "getProjectionRow",
72
+ "queryRelated",
73
+ ];
74
+ const remoteMethodSet = new Set(REMOTE_APP_DATABASE_METHODS);
75
+ function jsonBytes(value) {
76
+ const json = JSON.stringify(value);
77
+ return typeof json === "string"
78
+ ? new TextEncoder().encode(json).byteLength
79
+ : 0;
80
+ }
81
+ function isBoundedJson(value) {
82
+ try {
83
+ return jsonBytes(value) <= REMOTE_APP_DATABASE_MAX_MESSAGE_BYTES;
84
+ }
85
+ catch {
86
+ return false;
87
+ }
88
+ }
89
+ function methodDomain(method) {
90
+ if (/memory/iu.test(method))
91
+ return "memory";
92
+ if (/notification/iu.test(method))
93
+ return "notifications";
94
+ if (/history/iu.test(method))
95
+ return "history";
96
+ if (/task|childLinks/iu.test(method))
97
+ return "tasks";
98
+ if (/projection|related/iu.test(method))
99
+ return "projections";
100
+ if (/search/iu.test(method))
101
+ return "search";
102
+ if (method === "migrate" ||
103
+ method === "beginSearchIndexingBatch" ||
104
+ method === "endSearchIndexingBatch" ||
105
+ method === "getChangeRevision" ||
106
+ method === "clearMemoryDerivedState") {
107
+ return "lifecycle";
108
+ }
109
+ return "metadata";
110
+ }
111
+ function contractEntry(method) {
112
+ return {
113
+ method,
114
+ domain: methodDomain(method),
115
+ input: z.custom((value) => Array.isArray(value) &&
116
+ value.length <= REMOTE_APP_DATABASE_MAX_ARGUMENTS &&
117
+ isBoundedJson(value), "Invalid or oversized AppDatabase arguments"),
118
+ output: z.custom((value) => value === undefined || isBoundedJson(value), "Invalid or oversized AppDatabase result"),
119
+ };
120
+ }
121
+ export const REMOTE_APP_DATABASE_CONTRACT = Object.fromEntries(REMOTE_APP_DATABASE_METHODS.map((method) => [method, contractEntry(method)]));
122
+ export function isRemoteAppDatabaseMethod(value) {
123
+ return typeof value === "string" && remoteMethodSet.has(value);
124
+ }
125
+ export function parseRemoteAppDatabaseArgs(method, value) {
126
+ return REMOTE_APP_DATABASE_CONTRACT[method].input.parse(value);
127
+ }
128
+ export function parseRemoteAppDatabaseResult(method, value) {
129
+ return REMOTE_APP_DATABASE_CONTRACT[method].output.parse(value);
130
+ }
@@ -1,5 +1,5 @@
1
1
  import { PUBLIC_TASKS_PROJECTION_ID, PUBLIC_TASK_OCCURRENCES_PROJECTION_ID, type IndexFieldDefinition, type IndexQuery } from "./index-projection";
2
- export declare const TASK_PROJECTION_VERSION = 3;
2
+ export declare const TASK_PROJECTION_VERSION = 4;
3
3
  export declare const TASK_OCCURRENCE_PROJECTION_VERSION = 1;
4
4
  export { PUBLIC_TASKS_PROJECTION_ID, PUBLIC_TASK_OCCURRENCES_PROJECTION_ID };
5
5
  export declare const TASK_PROJECTION_FIELDS: Record<string, IndexFieldDefinition>;
@@ -91,6 +91,7 @@ export interface AppDatabaseTaskRecord {
91
91
  kind: AppDatabaseTaskKind;
92
92
  title: string;
93
93
  status: AppDatabaseTaskStatus;
94
+ priority?: "low" | "medium" | "high" | null;
94
95
  inbox: boolean;
95
96
  startKind: AppDatabaseTaskStartKind;
96
97
  startDate?: string | null;
@@ -1,5 +1,5 @@
1
1
  import { PUBLIC_TASKS_PROJECTION_ID, PUBLIC_TASK_OCCURRENCES_PROJECTION_ID, and, eq, gt, isNull, lt, lte, or, } from "./index-projection";
2
- export const TASK_PROJECTION_VERSION = 3;
2
+ export const TASK_PROJECTION_VERSION = 4;
3
3
  export const TASK_OCCURRENCE_PROJECTION_VERSION = 1;
4
4
  export { PUBLIC_TASKS_PROJECTION_ID, PUBLIC_TASK_OCCURRENCES_PROJECTION_ID };
5
5
  export const TASK_PROJECTION_FIELDS = {
@@ -8,6 +8,7 @@ export const TASK_PROJECTION_FIELDS = {
8
8
  kind: { type: "string", indexed: true },
9
9
  title: { type: "string", indexed: true, sortable: true },
10
10
  status: { type: "string", indexed: true, sortable: true },
11
+ priority: { type: "string", indexed: true, sortable: true },
11
12
  inbox: { type: "boolean", indexed: true },
12
13
  startKind: { type: "string", indexed: true },
13
14
  startDate: { type: "date", indexed: true, sortable: true },
@@ -148,7 +149,11 @@ export function taskQueryToIndexQuery(query = {}) {
148
149
  }
149
150
  }
150
151
  return {
151
- where: clauses.length === 1 ? clauses[0] : clauses.length ? and(...clauses) : undefined,
152
+ where: clauses.length === 1
153
+ ? clauses[0]
154
+ : clauses.length
155
+ ? and(...clauses)
156
+ : undefined,
152
157
  limit: query.limit,
153
158
  };
154
159
  }
@@ -1,4 +1,4 @@
1
- import { type AppDatabase, type AppDatabaseChangeListener, type AppDatabaseDescriptor, type AppDatabaseFileHistory, type AppDatabaseIndexedFile, type AppDatabaseIndexedFileManifestPage, type AppDatabaseIndexedFileManifestQuery, type AppDatabaseIndexedMetadataPage, type AppDatabaseIndexedMetadataPageQuery, type AppDatabaseIndexedMetadataQuery, type AppDatabaseIndexedMetadataRow, type AppDatabaseKind, type AppDatabaseLinkRecord, type AppDatabaseMetadataFacetQuery, type AppDatabaseMetadataFacetRow, type AppDatabaseMetadataLinkQuery, type AppDatabaseMemoryCandidateInput, type AppDatabaseMemoryCandidateQuery, type AppDatabaseMemoryCandidateResult, type AppDatabaseMemoryJobClaimInput, type AppDatabaseMemoryJobRecord, type AppDatabaseMemoryJobUpdateInput, type AppDatabaseMemoryRecallSignalRecord, type AppDatabaseMemorySourceRecord, type AppDatabaseNotebookState, type AppDatabaseNotificationRecord, type AppDatabaseOpenContext, type AppDatabaseProvider, type AppDatabaseSearchIndexStats, type AppDatabaseSearchOptions, type AppDatabaseSearchResult, type AppDatabaseStoreFileHistoryRevisionInput, type AppDatabaseStoreFileHistoryRevisionResult, type MetadataCacheSnapshot, type SearchDocumentRecord, type SearchDocumentManifestPage, type SearchDocumentManifestQuery, type SearchEmbeddingProviderConfig } from "./app-database";
1
+ import { type AppDatabase, type AppDatabaseChangeListener, type AppDatabaseDescriptor, type AppDatabaseFileHistory, type AppDatabaseIndexedFile, type AppDatabaseIndexedFileManifestPage, type AppDatabaseIndexedFileManifestQuery, type AppDatabaseIndexedMetadataPage, type AppDatabaseIndexedMetadataPageQuery, type AppDatabaseIndexedMetadataQuery, type AppDatabaseIndexedMetadataRow, type AppDatabaseKind, type AppDatabaseLinkRecord, type AppDatabaseMetadataFacetQuery, type AppDatabaseMetadataFacetRow, type AppDatabaseMetadataLinkQuery, type AppDatabaseMemoryCandidateInput, type AppDatabaseMemoryCandidateQuery, type AppDatabaseMemoryCandidateResult, type AppDatabaseMemoryJobClaimInput, type AppDatabaseMemoryJobRecord, type AppDatabaseMemoryJobUpdateInput, type AppDatabaseMemoryRecallSignalRecord, type AppDatabaseMemorySourceRecord, type AppDatabaseMetaScanPage, type AppDatabaseMetaScanQuery, type AppDatabaseMetaTransaction, type AppDatabaseMetaTransactionResult, type AppDatabaseNotebookState, type AppDatabaseNotificationRecord, type AppDatabaseOpenContext, type AppDatabaseProvider, type AppDatabaseSearchIndexStats, type AppDatabaseSearchOptions, type AppDatabaseSearchResult, type AppDatabaseStoreFileHistoryRevisionInput, type AppDatabaseStoreFileHistoryRevisionResult, type MetadataCacheSnapshot, type SearchDocumentRecord, type SearchDocumentManifestPage, type SearchDocumentManifestQuery, type SearchEmbeddingProviderConfig } from "./app-database";
2
2
  import { type IndexProjectionDefinitionRecord, type IndexQuery, type IndexQueryResult, type IndexRelatedQuery, type MarkProjectionSourceErrorInput, type ReplaceProjectionSourceInput } from "./index-projection";
3
3
  import type { AppDatabaseTaskChildQuery, AppDatabaseTaskQuery, AppDatabaseTaskRecord } from "./task-projection";
4
4
  import { type SearchEmbeddingRuntimeStatus } from "./search-embedding-provider";
@@ -52,6 +52,8 @@ export declare class TursoAppDatabase implements AppDatabase {
52
52
  getSearchIndexStats(): Promise<AppDatabaseSearchIndexStats>;
53
53
  getMeta<T = unknown>(key: string): Promise<T | undefined>;
54
54
  setMeta(key: string, value: unknown): Promise<void>;
55
+ scanMeta<T = unknown>({ prefix, after, limit, }: AppDatabaseMetaScanQuery): Promise<AppDatabaseMetaScanPage<T>>;
56
+ transactMeta({ checks, mutations, }: AppDatabaseMetaTransaction): Promise<AppDatabaseMetaTransactionResult>;
55
57
  getNotebookState(sourcePath: string): Promise<AppDatabaseNotebookState | undefined>;
56
58
  setNotebookState(sourcePath: string, state: AppDatabaseNotebookState): Promise<void>;
57
59
  deleteNotebookState(sourcePath: string): Promise<void>;
@@ -735,6 +735,10 @@ export class TursoAppDatabase {
735
735
  : undefined;
736
736
  }
737
737
  async setMeta(key, value) {
738
+ if (value === undefined) {
739
+ await this.commit([{ sql: "DELETE FROM app_meta WHERE key = ?", args: [key] }], ["meta"]);
740
+ return;
741
+ }
738
742
  await this.commit([
739
743
  {
740
744
  sql: `INSERT INTO app_meta (key, value_json) VALUES (?, ?)
@@ -743,6 +747,47 @@ export class TursoAppDatabase {
743
747
  },
744
748
  ], ["meta"]);
745
749
  }
750
+ async scanMeta({ prefix, after, limit = 100, }) {
751
+ const boundedLimit = Math.max(1, Math.min(500, Math.floor(limit)));
752
+ const rows = await this.requireConnection().all(`SELECT key, value_json FROM app_meta
753
+ WHERE substr(key, 1, ?) = ? AND key > ?
754
+ ORDER BY key ASC LIMIT ?`, prefix.length, prefix, after ?? prefix, boundedLimit + 1);
755
+ const pageRows = rows.slice(0, boundedLimit);
756
+ return {
757
+ entries: pageRows.map((row) => ({
758
+ key: row.key,
759
+ value: parseJson(row.value_json, undefined),
760
+ })),
761
+ nextCursor: rows.length > pageRows.length ? pageRows.at(-1)?.key : undefined,
762
+ };
763
+ }
764
+ async transactMeta({ checks = [], mutations, }) {
765
+ const committed = this.commitQueue.then(async () => {
766
+ for (const check of checks) {
767
+ const row = await this.requireConnection().get("SELECT value_json FROM app_meta WHERE key = ?", check.key);
768
+ if (check.exists !== undefined && Boolean(row) !== check.exists) {
769
+ return { applied: false };
770
+ }
771
+ if ("value" in check &&
772
+ JSON.stringify(row ? parseJson(row.value_json, undefined) : undefined) !== JSON.stringify(check.value)) {
773
+ return { applied: false };
774
+ }
775
+ }
776
+ const statements = mutations.map((mutation) => mutation.delete || mutation.value === undefined
777
+ ? { sql: "DELETE FROM app_meta WHERE key = ?", args: [mutation.key] }
778
+ : {
779
+ sql: `INSERT INTO app_meta (key, value_json) VALUES (?, ?)
780
+ ON CONFLICT(key) DO UPDATE SET value_json = excluded.value_json`,
781
+ args: [mutation.key, JSON.stringify(mutation.value)],
782
+ });
783
+ if (statements.length > 0) {
784
+ await this.commitImmediately(statements, ["meta"]);
785
+ }
786
+ return { applied: true };
787
+ });
788
+ this.commitQueue = committed.then(() => undefined, () => undefined);
789
+ return committed;
790
+ }
746
791
  async getNotebookState(sourcePath) {
747
792
  return this.getMeta(notebookStateMetaKey(sourcePath));
748
793
  }
@@ -138,6 +138,17 @@ async function createPreferredAppDatabase(vaultId, runtime, provider) {
138
138
  });
139
139
  return { appDatabase: database, state: readyState(database, false) };
140
140
  }
141
+ if (runtime === "deno-server") {
142
+ if (!provider) {
143
+ throw new Error("deno-server requires an AppDatabaseProvider");
144
+ }
145
+ const database = await provider.open({
146
+ vaultId,
147
+ runtime,
148
+ role: "direct",
149
+ });
150
+ return { appDatabase: database, state: readyState(database, false) };
151
+ }
141
152
  if (runtime === "web-pwa") {
142
153
  return createBrowserAppDatabase(vaultId, provider ?? new TursoWasmAppDatabaseProvider());
143
154
  }
@@ -1,6 +1,6 @@
1
1
  import type { DataAdapter } from "./fs";
2
2
  import { type UseStore } from "./keyval";
3
- export type VaultStorageKind = "opfs" | "file-system-access" | "desktop-folder";
3
+ export type VaultStorageKind = "opfs" | "file-system-access" | "desktop-folder" | "server-hosted";
4
4
  export type BootstrapAppearanceMode = "dark" | "light" | "system";
5
5
  export interface VaultProfileDemoMetadata {
6
6
  source: "e2e-vault";
@@ -103,7 +103,9 @@ export declare class Vault extends EventDispatcher<{
103
103
  * children
104
104
  * @public
105
105
  */
106
- delete(file: TAbstractFile, force?: boolean): Promise<void>;
106
+ delete(file: TAbstractFile, force?: boolean, context?: {
107
+ operationOrigin?: string;
108
+ }): Promise<void>;
107
109
  trash(file: TAbstractFile, system?: boolean): Promise<void>;
108
110
  /**
109
111
  * Read a plaintext file that is stored inside the vault, directly from disk.
@@ -260,7 +260,7 @@ export class Vault extends EventDispatcher {
260
260
  * children
261
261
  * @public
262
262
  */
263
- delete(file, force) {
263
+ delete(file, force, context = {}) {
264
264
  const remove = file instanceof TFolder
265
265
  ? this.adapter.rmdir(file.path, force ?? true)
266
266
  : this.adapter.remove(file.path);
@@ -282,7 +282,7 @@ export class Vault extends EventDispatcher {
282
282
  }
283
283
  this.cache.invalidate(file.path);
284
284
  this.dispatch("delete", file);
285
- this.dispatch("all", "delete", file, { force });
285
+ this.dispatch("all", "delete", file, { force, ...context });
286
286
  });
287
287
  }
288
288
  trash(file, system = true) {
@@ -334,6 +334,79 @@ export class Vault extends EventDispatcher {
334
334
  readBinary(file) {
335
335
  return this.adapter.readBinary(file.path);
336
336
  }
337
+ /** Open a stable streamed snapshot of a file when the adapter supports it. */
338
+ async openRead(file) {
339
+ const adapter = this.adapter;
340
+ if (adapter.openRead)
341
+ return adapter.openRead(file.path);
342
+ const data = new Uint8Array(await adapter.readBinary(file.path));
343
+ return {
344
+ size: data.byteLength,
345
+ mtime: file.stat.mtime,
346
+ stream: ({ offset = 0, length, signal } = {}) => {
347
+ const start = Math.max(0, Math.min(data.byteLength, Math.floor(offset)));
348
+ const end = Math.min(data.byteLength, start + Math.max(0, Math.floor(length ?? data.byteLength - start)));
349
+ return new ReadableStream({
350
+ start(controller) {
351
+ if (signal?.aborted) {
352
+ controller.error(signal.reason ?? new DOMException("Aborted", "AbortError"));
353
+ return;
354
+ }
355
+ controller.enqueue(data.slice(start, end));
356
+ controller.close();
357
+ },
358
+ });
359
+ },
360
+ };
361
+ }
362
+ /** Stream a file into the adapter's atomic or strongest safe replacement path. */
363
+ async atomicWrite(path, source, options = {}) {
364
+ path = this.getPath(path);
365
+ const existed = this.getFileByPath(path);
366
+ const adapter = this.adapter;
367
+ if (adapter.atomicWrite) {
368
+ await adapter.atomicWrite(path, source, options);
369
+ }
370
+ else {
371
+ const reader = source.getReader();
372
+ const chunks = [];
373
+ let size = 0;
374
+ try {
375
+ while (true) {
376
+ if (options.signal?.aborted) {
377
+ throw options.signal.reason ?? new DOMException("Aborted", "AbortError");
378
+ }
379
+ const next = await reader.read();
380
+ if (next.done)
381
+ break;
382
+ chunks.push(next.value);
383
+ size += next.value.byteLength;
384
+ }
385
+ }
386
+ finally {
387
+ reader.releaseLock();
388
+ }
389
+ const data = new Uint8Array(size);
390
+ let offset = 0;
391
+ for (const chunk of chunks) {
392
+ data.set(chunk, offset);
393
+ offset += chunk.byteLength;
394
+ }
395
+ await adapter.writeBinary(path, data.buffer, options);
396
+ }
397
+ this.files = await this.loadPath("/", {});
398
+ this.rebuildFileNameIndex();
399
+ const file = this.getFileByPath(path);
400
+ if (!file)
401
+ throw new Error(`Unable to write file: ${path}`);
402
+ this.cache.invalidate(path);
403
+ const event = existed ? "modify" : "create";
404
+ this.dispatch(event, file);
405
+ this.dispatch("all", event, file, {
406
+ operationOrigin: options.operationOrigin,
407
+ });
408
+ return file;
409
+ }
337
410
  /**
338
411
  * Rename or move a file. To ensure links are automatically renamed, use
339
412
  * {@link FileManager.renameFile} instead.
@@ -364,7 +437,7 @@ export class Vault extends EventDispatcher {
364
437
  if (newFile) {
365
438
  this.cache.rename(file.path, newFile.path);
366
439
  this.dispatch("rename", newFile, oldPath);
367
- this.dispatch("all", "rename", file, { oldPath });
440
+ this.dispatch("all", "rename", newFile, { oldPath });
368
441
  }
369
442
  else {
370
443
  console.warn(`Failed to rename file: ${file.path}`);