@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.
- package/CHANGELOG.md +39 -0
- package/README.md +5 -0
- package/dist/app-database-host.d.ts +1 -0
- package/dist/app-database-host.js +1 -0
- package/dist/browser-sync-security.d.ts +45 -0
- package/dist/browser-sync-security.js +189 -0
- package/dist/build-tools/vite.d.ts +15 -0
- package/dist/build-tools/vite.js +36 -0
- package/dist/cache.svelte.d.ts +1 -1
- package/dist/cache.svelte.js +4 -1
- package/dist/components/editor/editor.css +54 -2
- package/dist/components/editor/extensions/lint/lapis-lint-tooltip.svelte +18 -5
- package/dist/components/editor/extensions/lint/lint-tooltip-actions.d.ts +0 -2
- package/dist/components/editor/extensions/lint/lint-tooltip-actions.js +0 -14
- package/dist/components/editor/language-service/index.js +23 -2
- package/dist/components/icon/icon-list.svelte.d.ts +1 -1
- package/dist/components/select/select.svelte.d.ts +1 -1
- package/dist/context.svelte.d.ts +11 -1
- package/dist/context.svelte.js +38 -1
- package/dist/docs-api.d.ts +2 -0
- package/dist/docs-api.js +1 -0
- package/dist/generated/plugin-host-modules.schema.generated.d.ts +443 -13
- package/dist/generated/plugin-host-modules.schema.generated.js +970 -306
- package/dist/index.d.ts +5 -0
- package/dist/index.js +5 -0
- package/dist/language-service/manager.d.ts +5 -0
- package/dist/language-service/manager.js +58 -14
- package/dist/lapis-extension.d.ts +1 -1
- package/dist/lapis-extension.js +12 -0
- package/dist/nostr-signer.d.ts +68 -0
- package/dist/nostr-signer.js +49 -0
- package/dist/plugin-asset-server.d.ts +1 -0
- package/dist/plugin-asset-server.js +3 -0
- package/dist/plugin-capability-facade.d.ts +1 -1
- package/dist/plugin-capability-facade.js +6 -0
- package/dist/plugin-distribution/catalog-media.d.ts +4 -0
- package/dist/plugin-distribution/catalog-media.js +40 -0
- package/dist/plugin-distribution/download-stats.d.ts +4 -0
- package/dist/plugin-distribution/download-stats.js +19 -0
- package/dist/plugin-distribution/index.d.ts +4 -0
- package/dist/plugin-distribution/index.js +4 -0
- package/dist/plugin-distribution/installer.d.ts +3 -0
- package/dist/plugin-distribution/installer.js +26 -3
- package/dist/plugin-distribution/manager.d.ts +71 -5
- package/dist/plugin-distribution/manager.js +376 -37
- package/dist/plugin-distribution/nostr-registry-adapter.d.ts +29 -0
- package/dist/plugin-distribution/nostr-registry-adapter.js +152 -0
- package/dist/plugin-distribution/plugin-bundle-verifier.d.ts +43 -0
- package/dist/plugin-distribution/plugin-bundle-verifier.js +64 -1
- package/dist/plugin-distribution/plugin-bundle.d.ts +14 -0
- package/dist/plugin-distribution/plugin-bundle.js +46 -7
- package/dist/plugin-distribution/plugin-markdown.d.ts +6 -0
- package/dist/plugin-distribution/plugin-markdown.js +94 -0
- package/dist/plugin-distribution/registry-client.d.ts +6 -1
- package/dist/plugin-distribution/registry-client.js +32 -10
- package/dist/plugin-distribution/registry-source-state.d.ts +15 -0
- package/dist/plugin-distribution/registry-source-state.js +42 -0
- package/dist/plugin-distribution/schemas.d.ts +2511 -2824
- package/dist/plugin-distribution/schemas.js +111 -42
- package/dist/plugin-distribution/types.d.ts +116 -5
- package/dist/plugin-distribution-host.d.ts +4 -0
- package/dist/plugin-distribution-host.js +2 -0
- package/dist/plugin-install-progress.js +1 -1
- package/dist/plugin-manager.d.ts +3 -0
- package/dist/plugin-manager.js +21 -13
- package/dist/plugin-settings.d.ts +21 -0
- package/dist/plugin-settings.js +41 -0
- package/dist/plugin.d.ts +13 -0
- package/dist/plugin.js +56 -0
- package/dist/registry-schema/catalog-v1.d.ts +4143 -0
- package/dist/registry-schema/catalog-v1.js +172 -0
- package/dist/registry-schema/catalog-v2.d.ts +5275 -0
- package/dist/registry-schema/catalog-v2.js +137 -0
- package/dist/registry-schema/index.d.ts +1 -0
- package/dist/registry-schema/index.js +1 -0
- package/dist/registry-schema/release-notes.d.ts +5 -0
- package/dist/registry-schema/release-notes.js +21 -0
- package/dist/server-host.d.ts +28 -0
- package/dist/server-host.js +17 -0
- package/dist/storage/app-database.d.ts +37 -2
- package/dist/storage/app-database.js +41 -1
- package/dist/storage/browser-coordinated-app-database.d.ts +3 -1
- package/dist/storage/browser-coordinated-app-database.js +8 -0
- package/dist/storage/browser.d.ts +4 -1
- package/dist/storage/browser.js +84 -0
- package/dist/storage/desktop-native.d.ts +4 -2
- package/dist/storage/desktop-native.js +90 -1
- package/dist/storage/fs.d.ts +17 -0
- package/dist/storage/index.d.ts +1 -0
- package/dist/storage/index.js +1 -0
- package/dist/storage/memory-vault-adapter.d.ts +3 -1
- package/dist/storage/memory-vault-adapter.js +60 -0
- package/dist/storage/remote-app-database.d.ts +19 -0
- package/dist/storage/remote-app-database.js +130 -0
- package/dist/storage/task-projection.d.ts +2 -1
- package/dist/storage/task-projection.js +7 -2
- package/dist/storage/turso-app-database.d.ts +3 -1
- package/dist/storage/turso-app-database.js +45 -0
- package/dist/storage/vault-session.js +11 -0
- package/dist/storage/vault-state.d.ts +1 -1
- package/dist/storage/vault.svelte.d.ts +3 -1
- package/dist/storage/vault.svelte.js +76 -3
- package/dist/sync-host-security.d.ts +285 -0
- package/dist/sync-host-security.js +2237 -0
- package/dist/sync-host.d.ts +179 -0
- package/dist/sync-host.js +769 -0
- package/dist/workspace.svelte.d.ts +1 -1
- package/dist/workspace.svelte.js +1 -1
- package/package.json +48 -10
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { registryCatalogEntrySchema, registryCatalogDetailSchema, registryCatalogStatusSchema, registryImageReferenceSchema, registryReleaseSchema, registryReleaseChangelogSchema, } from "./catalog-v1.js";
|
|
3
|
+
export { registryCatalogStatusSchema, registryImageReferenceSchema, registryReleaseChangelogSchema, };
|
|
4
|
+
/** Authored variants remain optional; display fallbacks never rewrite metadata. */
|
|
5
|
+
export const registryImageSetSchema = z
|
|
6
|
+
.object({
|
|
7
|
+
preview: registryImageReferenceSchema.optional(),
|
|
8
|
+
full: registryImageReferenceSchema.optional(),
|
|
9
|
+
light: registryImageReferenceSchema.optional(),
|
|
10
|
+
dark: registryImageReferenceSchema.optional(),
|
|
11
|
+
})
|
|
12
|
+
.refine((images) => Object.values(images).some(Boolean), "At least one image variant is required");
|
|
13
|
+
export const registryMediaV2Schema = z.object({
|
|
14
|
+
alt: z.string().min(1),
|
|
15
|
+
images: registryImageSetSchema,
|
|
16
|
+
});
|
|
17
|
+
export const registryGalleryV2Schema = registryMediaV2Schema.extend({
|
|
18
|
+
id: z.string().min(1),
|
|
19
|
+
});
|
|
20
|
+
export const registryAppearanceV2Schema = z.object({
|
|
21
|
+
icon: z.string().min(1),
|
|
22
|
+
accent: z.string().min(1),
|
|
23
|
+
logo: registryMediaV2Schema.optional(),
|
|
24
|
+
});
|
|
25
|
+
export const registryReleaseV2Schema = registryReleaseSchema.omit({
|
|
26
|
+
releaseEventId: true,
|
|
27
|
+
manifestSha256: true,
|
|
28
|
+
releaseSequence: true,
|
|
29
|
+
});
|
|
30
|
+
export const registryCatalogV2EntrySchema = registryCatalogEntrySchema.extend({
|
|
31
|
+
schemaVersion: z.literal(2).optional(),
|
|
32
|
+
appearance: registryAppearanceV2Schema.optional(),
|
|
33
|
+
links: registryCatalogDetailSchema.shape.links,
|
|
34
|
+
});
|
|
35
|
+
export const registryCatalogV2IndexSchema = z.object({
|
|
36
|
+
schemaVersion: z.literal(2),
|
|
37
|
+
generatedAt: z.string().datetime({ offset: true }),
|
|
38
|
+
plugins: z.array(registryCatalogV2EntrySchema),
|
|
39
|
+
});
|
|
40
|
+
export const registryCatalogV2DetailSchema = registryCatalogDetailSchema.extend({
|
|
41
|
+
schemaVersion: z.literal(2),
|
|
42
|
+
appearance: registryAppearanceV2Schema.optional(),
|
|
43
|
+
media: z
|
|
44
|
+
.object({
|
|
45
|
+
banner: registryMediaV2Schema.optional(),
|
|
46
|
+
overview: registryMediaV2Schema.optional(),
|
|
47
|
+
})
|
|
48
|
+
.optional(),
|
|
49
|
+
gallery: z.array(registryGalleryV2Schema).optional(),
|
|
50
|
+
versions: z.record(z.string().min(1), registryReleaseV2Schema),
|
|
51
|
+
});
|
|
52
|
+
export function resolveRegistryMedia(media, variant = "preview") {
|
|
53
|
+
const images = media.images;
|
|
54
|
+
const reference = images[variant] ??
|
|
55
|
+
images.full ??
|
|
56
|
+
images.light ??
|
|
57
|
+
images.dark ??
|
|
58
|
+
images.preview;
|
|
59
|
+
if (!reference)
|
|
60
|
+
throw new Error("Media has no usable image variant");
|
|
61
|
+
return reference;
|
|
62
|
+
}
|
|
63
|
+
function record(value) {
|
|
64
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
65
|
+
throw new Error("Expected registry object");
|
|
66
|
+
return value;
|
|
67
|
+
}
|
|
68
|
+
function appearance(value) {
|
|
69
|
+
if (value === undefined)
|
|
70
|
+
return undefined;
|
|
71
|
+
const result = record(value);
|
|
72
|
+
if (result.logo === undefined)
|
|
73
|
+
return result;
|
|
74
|
+
const logo = record(result.logo);
|
|
75
|
+
return {
|
|
76
|
+
...result,
|
|
77
|
+
logo: logo.images ? logo : { alt: logo.alt, images: { full: logo } },
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
/** Call only after the source adapter has verified the original signed input. */
|
|
81
|
+
export function normalizeRegistryCatalogEntry(value) {
|
|
82
|
+
const entry = record(value);
|
|
83
|
+
const author = entry.author ?? record(entry.owner ?? {}).name;
|
|
84
|
+
return registryCatalogV2EntrySchema.parse({
|
|
85
|
+
...entry,
|
|
86
|
+
schemaVersion: 2,
|
|
87
|
+
appearance: appearance(entry.appearance),
|
|
88
|
+
status: entry.status ?? "active",
|
|
89
|
+
badges: entry.badges ?? [],
|
|
90
|
+
links: {
|
|
91
|
+
...(entry.links ?? {}),
|
|
92
|
+
...(!entry.links
|
|
93
|
+
?.documentation && typeof entry.readmeUrl === "string"
|
|
94
|
+
? { documentation: entry.readmeUrl }
|
|
95
|
+
: {}),
|
|
96
|
+
},
|
|
97
|
+
owner: entry.owner ?? {
|
|
98
|
+
name: author,
|
|
99
|
+
verified: entry.channel === "official",
|
|
100
|
+
},
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
export function normalizeRegistryCatalogIndex(value) {
|
|
104
|
+
const index = record(value);
|
|
105
|
+
if (index.schemaVersion !== 1 && index.schemaVersion !== 2)
|
|
106
|
+
throw new Error("Unsupported registry schema version");
|
|
107
|
+
if (!Array.isArray(index.plugins))
|
|
108
|
+
throw new Error("Expected registry plugin list");
|
|
109
|
+
return registryCatalogV2IndexSchema.parse({
|
|
110
|
+
...index,
|
|
111
|
+
schemaVersion: 2,
|
|
112
|
+
plugins: index.plugins.map(normalizeRegistryCatalogEntry),
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
export function normalizeRegistryCatalogDetail(value) {
|
|
116
|
+
const detail = record(value);
|
|
117
|
+
if (detail.schemaVersion !== 1 && detail.schemaVersion !== 2)
|
|
118
|
+
throw new Error("Unsupported registry schema version");
|
|
119
|
+
const owner = record(detail.owner ?? {});
|
|
120
|
+
return registryCatalogV2DetailSchema.parse({
|
|
121
|
+
...detail,
|
|
122
|
+
schemaVersion: 2,
|
|
123
|
+
author: detail.author ?? owner.name,
|
|
124
|
+
authorUrl: detail.authorUrl ?? owner.url,
|
|
125
|
+
status: detail.status ?? "active",
|
|
126
|
+
links: {
|
|
127
|
+
...(detail.links ?? {}),
|
|
128
|
+
...(!detail.links
|
|
129
|
+
?.documentation && typeof detail.readmeUrl === "string"
|
|
130
|
+
? { documentation: detail.readmeUrl }
|
|
131
|
+
: {}),
|
|
132
|
+
},
|
|
133
|
+
owner: { ...owner, verified: owner.verified ?? false },
|
|
134
|
+
appearance: appearance(detail.appearance),
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
export { registryChangelogFromMarkdown } from "./release-notes.js";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./catalog-v2.js";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./catalog-v2.js";
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export declare function registryChangelogFromMarkdown(name: string, version: string, markdown: string, override?: unknown): {
|
|
2
|
+
title: string;
|
|
3
|
+
description?: string | undefined;
|
|
4
|
+
tags?: ("security" | "fix" | "feature" | "improvement" | "breaking" | "deprecation" | "removal")[] | undefined;
|
|
5
|
+
} | undefined;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { registryReleaseChangelogSchema } from "./catalog-v1.js";
|
|
2
|
+
export function registryChangelogFromMarkdown(name, version, markdown, override) {
|
|
3
|
+
if (override !== undefined)
|
|
4
|
+
return registryReleaseChangelogSchema.parse(override);
|
|
5
|
+
const lines = markdown.split(/\r?\n/u);
|
|
6
|
+
const start = lines.findIndex((line) => {
|
|
7
|
+
const heading = /^##\s+\[?v?([^\]\s]+)\]?/u.exec(line);
|
|
8
|
+
return heading?.[1] === version;
|
|
9
|
+
});
|
|
10
|
+
if (start < 0)
|
|
11
|
+
return undefined;
|
|
12
|
+
const end = lines.findIndex((line, index) => index > start && /^##\s/u.test(line));
|
|
13
|
+
const description = lines
|
|
14
|
+
.slice(start + 1, end < 0 ? undefined : end)
|
|
15
|
+
.join("\n")
|
|
16
|
+
.trim();
|
|
17
|
+
return registryReleaseChangelogSchema.parse({
|
|
18
|
+
title: `${name} ${version}`,
|
|
19
|
+
...(description ? { description } : {}),
|
|
20
|
+
});
|
|
21
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { VaultProfile } from "./storage/vault-state";
|
|
2
|
+
export declare const LAPIS_SERVER_PROTOCOL_MAJOR = 1;
|
|
3
|
+
export type ServerVaultRole = "owner" | "editor" | "viewer";
|
|
4
|
+
export interface ServerVaultProfile extends VaultProfile {
|
|
5
|
+
kind: "server-hosted";
|
|
6
|
+
role: ServerVaultRole;
|
|
7
|
+
archived: boolean;
|
|
8
|
+
}
|
|
9
|
+
export interface ServerHostCapabilities {
|
|
10
|
+
appDatabase: true;
|
|
11
|
+
fileWatch: true;
|
|
12
|
+
languageService: true;
|
|
13
|
+
pluginAssets: true;
|
|
14
|
+
vaultResources: true;
|
|
15
|
+
ai: false;
|
|
16
|
+
terminal: false;
|
|
17
|
+
collaboration: false;
|
|
18
|
+
multiInstance: false;
|
|
19
|
+
}
|
|
20
|
+
export type ServerHostErrorCode = "UNAUTHENTICATED" | "FORBIDDEN" | "NOT_FOUND" | "CONFLICT" | "PRECONDITION_FAILED" | "INVALID_PATH" | "PROTOCOL_MISMATCH" | "RESYNC_REQUIRED" | "RATE_LIMITED" | "INTERNAL";
|
|
21
|
+
export declare class ServerHostError extends Error {
|
|
22
|
+
readonly code: ServerHostErrorCode;
|
|
23
|
+
readonly requestId?: string | undefined;
|
|
24
|
+
constructor(code: ServerHostErrorCode, message: string, requestId?: string | undefined);
|
|
25
|
+
}
|
|
26
|
+
export declare class VaultConflictError extends ServerHostError {
|
|
27
|
+
constructor(message?: string);
|
|
28
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export const LAPIS_SERVER_PROTOCOL_MAJOR = 1;
|
|
2
|
+
export class ServerHostError extends Error {
|
|
3
|
+
code;
|
|
4
|
+
requestId;
|
|
5
|
+
constructor(code, message, requestId) {
|
|
6
|
+
super(message);
|
|
7
|
+
this.code = code;
|
|
8
|
+
this.requestId = requestId;
|
|
9
|
+
this.name = "ServerHostError";
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
export class VaultConflictError extends ServerHostError {
|
|
13
|
+
constructor(message = "The vault file changed before it could be saved") {
|
|
14
|
+
super("CONFLICT", message);
|
|
15
|
+
this.name = "VaultConflictError";
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -3,7 +3,7 @@ import { type SearchQueryEvaluationOptions, type SearchQueryTextRangeOptions } f
|
|
|
3
3
|
import { type IndexProjectionDefinitionRecord, type IndexProjectionEdgeRecord, type IndexQuery, type IndexQueryResult, type IndexRelatedQuery, type IndexProjectionRowRecord, type IndexProjectionSourceRecord, type IndexProjectionValueRecord, type MarkProjectionSourceErrorInput, type ReplaceProjectionSourceInput } from "./index-projection";
|
|
4
4
|
import { type AppDatabaseLinkKind, type AppDatabaseTaskChildQuery, type AppDatabaseTaskQuery, type AppDatabaseTaskRecord } from "./task-projection";
|
|
5
5
|
export type { SearchEmbeddingProviderConfig, SearchEmbeddingRuntimeStatus, } from "./search-embedding-provider";
|
|
6
|
-
export type RuntimeTarget = "web-pwa" | "deno-desktop" | "test";
|
|
6
|
+
export type RuntimeTarget = "web-pwa" | "deno-desktop" | "deno-server" | "test";
|
|
7
7
|
export interface LocalSearchQueryEnhancementProviderConfig {
|
|
8
8
|
kind: "local-model";
|
|
9
9
|
queryExpansionModelId: string;
|
|
@@ -79,7 +79,7 @@ export interface AppDatabaseSearchIndexStats {
|
|
|
79
79
|
export declare function supportsSearchQueryEnhancementRuntime(runtimeTarget?: RuntimeTarget | null): boolean;
|
|
80
80
|
export type AppDatabaseKind = "turso-wasm" | "turso-native" | "memory";
|
|
81
81
|
export type AppDatabaseStorageMode = "local" | "synced" | "remote";
|
|
82
|
-
export type AppDatabaseTransport = "native" | "wasm-worker" | "broadcast-proxy" | "memory";
|
|
82
|
+
export type AppDatabaseTransport = "native" | "http-rpc" | "wasm-worker" | "broadcast-proxy" | "memory";
|
|
83
83
|
export type AppDatabaseRole = "direct" | "owner" | "proxy" | "blocked" | "test";
|
|
84
84
|
export interface AppDatabaseCapabilities {
|
|
85
85
|
nativeFullTextSearch: boolean;
|
|
@@ -264,6 +264,37 @@ export interface AppDatabaseChangeSet {
|
|
|
264
264
|
reset?: boolean;
|
|
265
265
|
committedAt: number;
|
|
266
266
|
}
|
|
267
|
+
/** A namespaced application-metadata row returned without exposing storage. */
|
|
268
|
+
export interface AppDatabaseMetaEntry<T = unknown> {
|
|
269
|
+
key: string;
|
|
270
|
+
value: T;
|
|
271
|
+
}
|
|
272
|
+
export interface AppDatabaseMetaScanQuery {
|
|
273
|
+
prefix: string;
|
|
274
|
+
after?: string;
|
|
275
|
+
limit?: number;
|
|
276
|
+
}
|
|
277
|
+
export interface AppDatabaseMetaScanPage<T = unknown> {
|
|
278
|
+
entries: AppDatabaseMetaEntry<T>[];
|
|
279
|
+
nextCursor?: string;
|
|
280
|
+
}
|
|
281
|
+
export interface AppDatabaseMetaCheck {
|
|
282
|
+
key: string;
|
|
283
|
+
exists?: boolean;
|
|
284
|
+
value?: unknown;
|
|
285
|
+
}
|
|
286
|
+
export interface AppDatabaseMetaMutation {
|
|
287
|
+
key: string;
|
|
288
|
+
value?: unknown;
|
|
289
|
+
delete?: boolean;
|
|
290
|
+
}
|
|
291
|
+
export interface AppDatabaseMetaTransaction {
|
|
292
|
+
checks?: AppDatabaseMetaCheck[];
|
|
293
|
+
mutations: AppDatabaseMetaMutation[];
|
|
294
|
+
}
|
|
295
|
+
export interface AppDatabaseMetaTransactionResult {
|
|
296
|
+
applied: boolean;
|
|
297
|
+
}
|
|
267
298
|
export type AppDatabaseChangeListener = (change: AppDatabaseChangeSet) => void;
|
|
268
299
|
export interface SearchDocumentRecord {
|
|
269
300
|
path: string;
|
|
@@ -591,6 +622,8 @@ export interface AppDatabase {
|
|
|
591
622
|
getSearchIndexStats(): Promise<AppDatabaseSearchIndexStats>;
|
|
592
623
|
getMeta<T = unknown>(key: string): Promise<T | undefined>;
|
|
593
624
|
setMeta(key: string, value: unknown): Promise<void>;
|
|
625
|
+
scanMeta<T = unknown>(query: AppDatabaseMetaScanQuery): Promise<AppDatabaseMetaScanPage<T>>;
|
|
626
|
+
transactMeta(transaction: AppDatabaseMetaTransaction): Promise<AppDatabaseMetaTransactionResult>;
|
|
594
627
|
getNotebookState(sourcePath: string): Promise<AppDatabaseNotebookState | undefined>;
|
|
595
628
|
setNotebookState(sourcePath: string, state: AppDatabaseNotebookState): Promise<void>;
|
|
596
629
|
deleteNotebookState(sourcePath: string): Promise<void>;
|
|
@@ -770,6 +803,8 @@ export declare class MemoryAppDatabase implements AppDatabase {
|
|
|
770
803
|
getSearchIndexStats(): Promise<AppDatabaseSearchIndexStats>;
|
|
771
804
|
getMeta<T = unknown>(key: string): Promise<T | undefined>;
|
|
772
805
|
setMeta(key: string, value: unknown): Promise<void>;
|
|
806
|
+
scanMeta<T = unknown>({ prefix, after, limit, }: AppDatabaseMetaScanQuery): Promise<AppDatabaseMetaScanPage<T>>;
|
|
807
|
+
transactMeta({ checks, mutations, }: AppDatabaseMetaTransaction): Promise<AppDatabaseMetaTransactionResult>;
|
|
773
808
|
getNotebookState(sourcePath: string): Promise<AppDatabaseNotebookState | undefined>;
|
|
774
809
|
setNotebookState(sourcePath: string, state: AppDatabaseNotebookState): Promise<void>;
|
|
775
810
|
deleteNotebookState(sourcePath: string): Promise<void>;
|
|
@@ -1047,9 +1047,49 @@ export class MemoryAppDatabase {
|
|
|
1047
1047
|
return clone(this.meta[key]);
|
|
1048
1048
|
}
|
|
1049
1049
|
async setMeta(key, value) {
|
|
1050
|
-
|
|
1050
|
+
if (value === undefined)
|
|
1051
|
+
delete this.meta[key];
|
|
1052
|
+
else
|
|
1053
|
+
this.meta[key] = clone(value);
|
|
1051
1054
|
this.emitChange(["meta"]);
|
|
1052
1055
|
}
|
|
1056
|
+
async scanMeta({ prefix, after, limit = 100, }) {
|
|
1057
|
+
const boundedLimit = Math.max(1, Math.min(500, Math.floor(limit)));
|
|
1058
|
+
const keys = Object.keys(this.meta)
|
|
1059
|
+
.filter((key) => key.startsWith(prefix) && (!after || key > after))
|
|
1060
|
+
.sort();
|
|
1061
|
+
const pageKeys = keys.slice(0, boundedLimit);
|
|
1062
|
+
return {
|
|
1063
|
+
entries: pageKeys.map((key) => ({
|
|
1064
|
+
key,
|
|
1065
|
+
value: clone(this.meta[key]),
|
|
1066
|
+
})),
|
|
1067
|
+
nextCursor: keys.length > pageKeys.length ? pageKeys.at(-1) : undefined,
|
|
1068
|
+
};
|
|
1069
|
+
}
|
|
1070
|
+
async transactMeta({ checks = [], mutations, }) {
|
|
1071
|
+
for (const check of checks) {
|
|
1072
|
+
const exists = Object.prototype.hasOwnProperty.call(this.meta, check.key);
|
|
1073
|
+
if (check.exists !== undefined && exists !== check.exists) {
|
|
1074
|
+
return { applied: false };
|
|
1075
|
+
}
|
|
1076
|
+
if ("value" in check &&
|
|
1077
|
+
JSON.stringify(this.meta[check.key]) !== JSON.stringify(check.value)) {
|
|
1078
|
+
return { applied: false };
|
|
1079
|
+
}
|
|
1080
|
+
}
|
|
1081
|
+
for (const mutation of mutations) {
|
|
1082
|
+
if (mutation.delete || mutation.value === undefined) {
|
|
1083
|
+
delete this.meta[mutation.key];
|
|
1084
|
+
}
|
|
1085
|
+
else {
|
|
1086
|
+
this.meta[mutation.key] = clone(mutation.value);
|
|
1087
|
+
}
|
|
1088
|
+
}
|
|
1089
|
+
if (mutations.length > 0)
|
|
1090
|
+
this.emitChange(["meta"]);
|
|
1091
|
+
return { applied: true };
|
|
1092
|
+
}
|
|
1053
1093
|
async getNotebookState(sourcePath) {
|
|
1054
1094
|
return this.getMeta(notebookStateMetaKey(sourcePath));
|
|
1055
1095
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { AppDatabase, AppDatabaseChangeListener, AppDatabaseDescriptor, AppDatabaseFileHistory, AppDatabaseIndexedFile, AppDatabaseIndexedFileManifestPage, AppDatabaseIndexedFileManifestQuery, AppDatabaseIndexedMetadataPage, AppDatabaseIndexedMetadataPageQuery, AppDatabaseIndexedMetadataQuery, AppDatabaseIndexedMetadataRow, AppDatabaseKind, AppDatabaseMetadataFacetQuery, AppDatabaseMetadataFacetRow, AppDatabaseMetadataLinkQuery, AppDatabaseMemoryCandidateInput, AppDatabaseMemoryCandidateQuery, AppDatabaseMemoryCandidateResult, AppDatabaseMemoryJobClaimInput, AppDatabaseMemoryJobRecord, AppDatabaseMemoryJobUpdateInput, AppDatabaseMemoryRecallSignalRecord, AppDatabaseMemorySourceRecord, AppDatabaseProvider, AppDatabaseNotificationRecord, AppDatabaseSearchIndexStats, AppDatabaseNotebookState, AppDatabaseSearchOptions, AppDatabaseSearchResult, AppDatabaseStoreFileHistoryRevisionInput, AppDatabaseStoreFileHistoryRevisionResult, MetadataCacheSnapshot, SearchDocumentRecord, SearchDocumentManifestPage, SearchDocumentManifestQuery, SearchEmbeddingProviderConfig, SearchEmbeddingRuntimeStatus, AppDatabaseLinkRecord } from "./app-database";
|
|
1
|
+
import type { AppDatabase, AppDatabaseChangeListener, AppDatabaseDescriptor, AppDatabaseFileHistory, AppDatabaseIndexedFile, AppDatabaseIndexedFileManifestPage, AppDatabaseIndexedFileManifestQuery, AppDatabaseIndexedMetadataPage, AppDatabaseIndexedMetadataPageQuery, AppDatabaseIndexedMetadataQuery, AppDatabaseIndexedMetadataRow, AppDatabaseKind, AppDatabaseMetadataFacetQuery, AppDatabaseMetadataFacetRow, AppDatabaseMetadataLinkQuery, AppDatabaseMemoryCandidateInput, AppDatabaseMemoryCandidateQuery, AppDatabaseMemoryCandidateResult, AppDatabaseMemoryJobClaimInput, AppDatabaseMemoryJobRecord, AppDatabaseMemoryJobUpdateInput, AppDatabaseMemoryRecallSignalRecord, AppDatabaseMemorySourceRecord, AppDatabaseMetaScanPage, AppDatabaseMetaScanQuery, AppDatabaseMetaTransaction, AppDatabaseMetaTransactionResult, AppDatabaseProvider, AppDatabaseNotificationRecord, AppDatabaseSearchIndexStats, AppDatabaseNotebookState, AppDatabaseSearchOptions, AppDatabaseSearchResult, AppDatabaseStoreFileHistoryRevisionInput, AppDatabaseStoreFileHistoryRevisionResult, MetadataCacheSnapshot, SearchDocumentRecord, SearchDocumentManifestPage, SearchDocumentManifestQuery, SearchEmbeddingProviderConfig, SearchEmbeddingRuntimeStatus, AppDatabaseLinkRecord } from "./app-database";
|
|
2
2
|
import type { AppDatabaseTaskChildQuery, AppDatabaseTaskQuery, AppDatabaseTaskRecord } from "./task-projection";
|
|
3
3
|
import { BrowserAppDatabaseCoordinator } from "./browser-app-database-coordination";
|
|
4
4
|
export type BrowserCoordinatedAppDatabaseMode = "turso-owner" | "turso-proxy";
|
|
@@ -36,6 +36,8 @@ export declare class BrowserCoordinatedAppDatabase implements AppDatabase {
|
|
|
36
36
|
getSearchIndexStats(): Promise<AppDatabaseSearchIndexStats>;
|
|
37
37
|
getMeta<T = unknown>(key: string): Promise<T | undefined>;
|
|
38
38
|
setMeta(key: string, value: unknown): Promise<void>;
|
|
39
|
+
scanMeta<T = unknown>(query: AppDatabaseMetaScanQuery): Promise<AppDatabaseMetaScanPage<T>>;
|
|
40
|
+
transactMeta(transaction: AppDatabaseMetaTransaction): Promise<AppDatabaseMetaTransactionResult>;
|
|
39
41
|
getNotebookState(sourcePath: string): Promise<AppDatabaseNotebookState | undefined>;
|
|
40
42
|
setNotebookState(sourcePath: string, state: AppDatabaseNotebookState): Promise<void>;
|
|
41
43
|
deleteNotebookState(sourcePath: string): Promise<void>;
|
|
@@ -16,6 +16,8 @@ const APP_DATABASE_RPC_METHODS = new Set([
|
|
|
16
16
|
"getSearchIndexStats",
|
|
17
17
|
"getMeta",
|
|
18
18
|
"setMeta",
|
|
19
|
+
"scanMeta",
|
|
20
|
+
"transactMeta",
|
|
19
21
|
"getNotebookState",
|
|
20
22
|
"setNotebookState",
|
|
21
23
|
"deleteNotebookState",
|
|
@@ -269,6 +271,12 @@ export class BrowserCoordinatedAppDatabase {
|
|
|
269
271
|
async setMeta(key, value) {
|
|
270
272
|
await this.invoke("setMeta", key, value);
|
|
271
273
|
}
|
|
274
|
+
async scanMeta(query) {
|
|
275
|
+
return this.invoke("scanMeta", query);
|
|
276
|
+
}
|
|
277
|
+
async transactMeta(transaction) {
|
|
278
|
+
return this.invoke("transactMeta", transaction);
|
|
279
|
+
}
|
|
272
280
|
async getNotebookState(sourcePath) {
|
|
273
281
|
return this.invoke("getNotebookState", sourcePath);
|
|
274
282
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { DataAdapter, DataWriteOptions, ListedFiles, Stat, AsyncResourceAdapter, VaultIdentityAdapter } from "./fs";
|
|
1
|
+
import type { DataAdapter, DataWriteOptions, AtomicDataWriteOptions, ListedFiles, Stat, AsyncResourceAdapter, VaultIdentityAdapter, VaultReadHandle } from "./fs";
|
|
2
2
|
import { ScopedVaultStore, type KeyValueStore, type VaultProfile } from "./vault-state";
|
|
3
3
|
export type BrowserFileSystemPermissionMode = "read" | "readwrite";
|
|
4
4
|
export type BrowserFileSystemPermissionState = "granted" | "denied" | "prompt";
|
|
@@ -15,6 +15,7 @@ export interface BrowserFileSystemWritableFileStream {
|
|
|
15
15
|
write(data: ArrayBuffer | Blob | string | Uint8Array): Promise<void>;
|
|
16
16
|
seek(position: number): Promise<void>;
|
|
17
17
|
close(): Promise<void>;
|
|
18
|
+
abort?(reason?: unknown): Promise<void>;
|
|
18
19
|
}
|
|
19
20
|
export interface BrowserFileSystemCreateWritableOptions {
|
|
20
21
|
keepExistingData?: boolean;
|
|
@@ -102,6 +103,8 @@ export declare class BrowserHandleVaultAdapter implements DataAdapter, VaultIden
|
|
|
102
103
|
stat(normalizedPath: string): Promise<Stat | null>;
|
|
103
104
|
read(normalizedPath: string): Promise<string>;
|
|
104
105
|
readBinary(normalizedPath: string): Promise<ArrayBuffer>;
|
|
106
|
+
openRead(normalizedPath: string): Promise<VaultReadHandle>;
|
|
107
|
+
atomicWrite(normalizedPath: string, source: ReadableStream<Uint8Array>, options?: AtomicDataWriteOptions): Promise<void>;
|
|
105
108
|
write(normalizedPath: string, data: string, options?: DataWriteOptions): Promise<void>;
|
|
106
109
|
writeBinary(normalizedPath: string, data: ArrayBuffer, options?: DataWriteOptions): Promise<void>;
|
|
107
110
|
private writeFile;
|
package/dist/storage/browser.js
CHANGED
|
@@ -405,6 +405,90 @@ export class BrowserHandleVaultAdapter {
|
|
|
405
405
|
return toArrayBuffer(await (await handle.getFile()).arrayBuffer());
|
|
406
406
|
});
|
|
407
407
|
}
|
|
408
|
+
async openRead(normalizedPath) {
|
|
409
|
+
const path = normalizeVaultPath(normalizedPath);
|
|
410
|
+
const file = await this.withHandleRetry(async () => {
|
|
411
|
+
const handle = await this.getHandle(path);
|
|
412
|
+
if (!handle || handle.kind !== "file")
|
|
413
|
+
throw createFsError("ENOENT", path);
|
|
414
|
+
return handle.getFile();
|
|
415
|
+
});
|
|
416
|
+
return {
|
|
417
|
+
size: file.size,
|
|
418
|
+
mtime: file.lastModified ?? Date.now(),
|
|
419
|
+
stream: ({ offset = 0, length, signal } = {}) => {
|
|
420
|
+
const start = Math.max(0, Math.min(file.size, Math.floor(offset)));
|
|
421
|
+
const end = Math.min(file.size, start + Math.max(0, Math.floor(length ?? file.size - start)));
|
|
422
|
+
const slice = file.slice(start, end);
|
|
423
|
+
const stream = typeof slice.stream === "function"
|
|
424
|
+
? slice.stream()
|
|
425
|
+
: new ReadableStream({
|
|
426
|
+
async start(controller) {
|
|
427
|
+
controller.enqueue(new Uint8Array(await slice.arrayBuffer()));
|
|
428
|
+
controller.close();
|
|
429
|
+
},
|
|
430
|
+
});
|
|
431
|
+
if (!signal)
|
|
432
|
+
return stream;
|
|
433
|
+
const reader = stream.getReader();
|
|
434
|
+
return new ReadableStream({
|
|
435
|
+
async pull(controller) {
|
|
436
|
+
if (signal.aborted) {
|
|
437
|
+
await reader.cancel(signal.reason);
|
|
438
|
+
controller.error(signal.reason ?? new DOMException("Aborted", "AbortError"));
|
|
439
|
+
return;
|
|
440
|
+
}
|
|
441
|
+
const next = await reader.read();
|
|
442
|
+
if (next.done)
|
|
443
|
+
controller.close();
|
|
444
|
+
else
|
|
445
|
+
controller.enqueue(next.value);
|
|
446
|
+
},
|
|
447
|
+
cancel(reason) {
|
|
448
|
+
return reader.cancel(reason);
|
|
449
|
+
},
|
|
450
|
+
});
|
|
451
|
+
},
|
|
452
|
+
};
|
|
453
|
+
}
|
|
454
|
+
async atomicWrite(normalizedPath, source, options = {}) {
|
|
455
|
+
const path = normalizeVaultPath(normalizedPath);
|
|
456
|
+
await this.withPathLock(path, () => this.withHandleRetry(async () => {
|
|
457
|
+
const [parent, name] = await this.getParentDirectory(path, { create: true });
|
|
458
|
+
const existing = await this.readStoredStat(path);
|
|
459
|
+
const handle = await parent.getFileHandle(name, { create: true });
|
|
460
|
+
const writable = await handle.createWritable({ keepExistingData: false });
|
|
461
|
+
const reader = source.getReader();
|
|
462
|
+
let size = 0;
|
|
463
|
+
try {
|
|
464
|
+
while (true) {
|
|
465
|
+
if (options.signal?.aborted) {
|
|
466
|
+
throw options.signal.reason ?? new DOMException("Aborted", "AbortError");
|
|
467
|
+
}
|
|
468
|
+
const next = await reader.read();
|
|
469
|
+
if (next.done)
|
|
470
|
+
break;
|
|
471
|
+
await writable.write(next.value);
|
|
472
|
+
size += next.value.byteLength;
|
|
473
|
+
}
|
|
474
|
+
await writable.close();
|
|
475
|
+
}
|
|
476
|
+
catch (error) {
|
|
477
|
+
await writable.abort?.(error).catch(() => undefined);
|
|
478
|
+
throw error;
|
|
479
|
+
}
|
|
480
|
+
finally {
|
|
481
|
+
reader.releaseLock();
|
|
482
|
+
}
|
|
483
|
+
const now = Date.now();
|
|
484
|
+
await this.writeStoredStat(path, {
|
|
485
|
+
type: "file",
|
|
486
|
+
ctime: options.ctime ?? existing?.ctime ?? now,
|
|
487
|
+
mtime: options.mtime ?? now,
|
|
488
|
+
size,
|
|
489
|
+
});
|
|
490
|
+
}));
|
|
491
|
+
}
|
|
408
492
|
async write(normalizedPath, data, options) {
|
|
409
493
|
await this.writeFile(normalizedPath, data, options);
|
|
410
494
|
}
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* `getNativeDesktopBridge()` / `hasNativeDesktopBridge()`.
|
|
7
7
|
*/
|
|
8
8
|
import type { AppDatabaseChangeSet, AppDatabaseNotificationSeverity } from "./app-database";
|
|
9
|
-
import type { ChangeEvent, AsyncResourceAdapter, DataWriteOptions, ListedFiles, NativeWatchAdapter, NativeWatchSubscription, Stat, VaultAdapter, VaultAdapterCapabilities, VaultIdentityAdapter, WatchErrorEvent, WatchOptions } from "./fs";
|
|
9
|
+
import type { ChangeEvent, AsyncResourceAdapter, DataWriteOptions, ListedFiles, NativeWatchAdapter, NativeWatchSubscription, Stat, VaultAdapter, VaultAdapterCapabilities, VaultReadHandle, AtomicDataWriteOptions, VaultIdentityAdapter, WatchErrorEvent, WatchOptions } from "./fs";
|
|
10
10
|
import { type KeyValueStore, type VaultProfile } from "./vault-state";
|
|
11
11
|
export type NativeDesktopRuntime = "deno-desktop";
|
|
12
12
|
export type NativeDesktopPlatformOs = "macos" | "windows" | "linux" | "unknown";
|
|
@@ -18,7 +18,7 @@ export interface NativeDesktopPlatformInfo {
|
|
|
18
18
|
readonly appVersion?: string;
|
|
19
19
|
readonly packaged?: boolean;
|
|
20
20
|
}
|
|
21
|
-
export type NativeDesktopCapabilityId = "resource" | "database" | "search" | "notebook" | "language-service" | "model" | "plugin-sidecar" | "plugin-assets" | "file-watch" | "notifications" | "file-system-actions" | "agent-runtime" | "terminal-runtime";
|
|
21
|
+
export type NativeDesktopCapabilityId = "resource" | "database" | "search" | "notebook" | "language-service" | "model" | "plugin-sidecar" | "plugin-assets" | "file-watch" | "notifications" | "file-system-actions" | "nostr-signer" | "agent-runtime" | "terminal-runtime" | "secure-storage";
|
|
22
22
|
export type NativeAgentProcessMessage = {
|
|
23
23
|
processId: string;
|
|
24
24
|
type: "stdout" | "stderr" | "exit";
|
|
@@ -151,6 +151,8 @@ export declare class NativeDesktopVaultAdapter implements VaultAdapter, VaultIde
|
|
|
151
151
|
stat(normalizedPath: string): Promise<Stat | null>;
|
|
152
152
|
read(normalizedPath: string): Promise<string>;
|
|
153
153
|
readBinary(normalizedPath: string): Promise<ArrayBuffer>;
|
|
154
|
+
openRead(normalizedPath: string): Promise<VaultReadHandle>;
|
|
155
|
+
atomicWrite(normalizedPath: string, source: ReadableStream<Uint8Array>, options?: AtomicDataWriteOptions): Promise<void>;
|
|
154
156
|
write(normalizedPath: string, data: string, options?: DataWriteOptions): Promise<void>;
|
|
155
157
|
writeBinary(normalizedPath: string, data: ArrayBuffer, options?: DataWriteOptions): Promise<void>;
|
|
156
158
|
append(normalizedPath: string, data: string, options?: DataWriteOptions): Promise<void>;
|
|
@@ -133,7 +133,15 @@ function createFsError(code, path) {
|
|
|
133
133
|
}
|
|
134
134
|
function toNativeError(error) {
|
|
135
135
|
if (error instanceof Error) {
|
|
136
|
-
|
|
136
|
+
const nativeError = error;
|
|
137
|
+
if (!nativeError.code) {
|
|
138
|
+
// Deno's binding serializes a native Error to text, then rejects with a
|
|
139
|
+
// fresh Error. Restore the same portable code handled for string errors.
|
|
140
|
+
const match = /^(?:Error:\s*)?([A-Z0-9_]+):\s*(.*)$/u.exec(nativeError.message);
|
|
141
|
+
if (match)
|
|
142
|
+
nativeError.code = match[1];
|
|
143
|
+
}
|
|
144
|
+
return nativeError;
|
|
137
145
|
}
|
|
138
146
|
const message = typeof error === "string" ? error : String(error);
|
|
139
147
|
const match = /^([A-Z0-9_]+):\s*(.*)$/u.exec(message);
|
|
@@ -276,6 +284,87 @@ export class NativeDesktopVaultAdapter {
|
|
|
276
284
|
});
|
|
277
285
|
return new Uint8Array(data).buffer;
|
|
278
286
|
}
|
|
287
|
+
async openRead(normalizedPath) {
|
|
288
|
+
const path = normalizeVaultPath(normalizedPath);
|
|
289
|
+
const rootPath = this.rootPath;
|
|
290
|
+
const stat = await this.stat(path);
|
|
291
|
+
if (!stat || stat.type !== "file")
|
|
292
|
+
throw createFsError("ENOENT", path);
|
|
293
|
+
return {
|
|
294
|
+
size: stat.size,
|
|
295
|
+
mtime: stat.mtime,
|
|
296
|
+
stream: ({ offset = 0, length, signal } = {}) => {
|
|
297
|
+
let cursor = Math.max(0, Math.min(stat.size, Math.floor(offset)));
|
|
298
|
+
const end = Math.min(stat.size, cursor + Math.max(0, Math.floor(length ?? stat.size - cursor)));
|
|
299
|
+
return new ReadableStream({
|
|
300
|
+
async pull(controller) {
|
|
301
|
+
if (signal?.aborted) {
|
|
302
|
+
controller.error(signal.reason ?? new DOMException("Aborted", "AbortError"));
|
|
303
|
+
return;
|
|
304
|
+
}
|
|
305
|
+
if (cursor >= end) {
|
|
306
|
+
controller.close();
|
|
307
|
+
return;
|
|
308
|
+
}
|
|
309
|
+
const data = await invokeNative("desktop_fs_read_range", {
|
|
310
|
+
rootPath,
|
|
311
|
+
normalizedPath: path,
|
|
312
|
+
offset: cursor,
|
|
313
|
+
length: Math.min(256 * 1024, end - cursor),
|
|
314
|
+
});
|
|
315
|
+
const bytes = Uint8Array.from(data);
|
|
316
|
+
if (bytes.byteLength === 0) {
|
|
317
|
+
controller.close();
|
|
318
|
+
return;
|
|
319
|
+
}
|
|
320
|
+
cursor += bytes.byteLength;
|
|
321
|
+
controller.enqueue(bytes);
|
|
322
|
+
},
|
|
323
|
+
});
|
|
324
|
+
},
|
|
325
|
+
};
|
|
326
|
+
}
|
|
327
|
+
async atomicWrite(normalizedPath, source, options = {}) {
|
|
328
|
+
const path = normalizeVaultPath(normalizedPath);
|
|
329
|
+
const operationId = await invokeNative("desktop_fs_atomic_write_begin", {
|
|
330
|
+
rootPath: this.rootPath,
|
|
331
|
+
normalizedPath: path,
|
|
332
|
+
options: { ctime: options.ctime, mtime: options.mtime },
|
|
333
|
+
});
|
|
334
|
+
const reader = source.getReader();
|
|
335
|
+
try {
|
|
336
|
+
while (true) {
|
|
337
|
+
if (options.signal?.aborted) {
|
|
338
|
+
throw options.signal.reason ?? new DOMException("Aborted", "AbortError");
|
|
339
|
+
}
|
|
340
|
+
const next = await reader.read();
|
|
341
|
+
if (next.done)
|
|
342
|
+
break;
|
|
343
|
+
await invokeNative("desktop_fs_atomic_write_chunk", {
|
|
344
|
+
rootPath: this.rootPath,
|
|
345
|
+
normalizedPath: path,
|
|
346
|
+
operationId,
|
|
347
|
+
data: [...next.value],
|
|
348
|
+
});
|
|
349
|
+
}
|
|
350
|
+
await invokeNative("desktop_fs_atomic_write_commit", {
|
|
351
|
+
rootPath: this.rootPath,
|
|
352
|
+
normalizedPath: path,
|
|
353
|
+
operationId,
|
|
354
|
+
});
|
|
355
|
+
}
|
|
356
|
+
catch (error) {
|
|
357
|
+
await invokeNative("desktop_fs_atomic_write_abort", {
|
|
358
|
+
rootPath: this.rootPath,
|
|
359
|
+
normalizedPath: path,
|
|
360
|
+
operationId,
|
|
361
|
+
}).catch(() => undefined);
|
|
362
|
+
throw error;
|
|
363
|
+
}
|
|
364
|
+
finally {
|
|
365
|
+
reader.releaseLock();
|
|
366
|
+
}
|
|
367
|
+
}
|
|
279
368
|
async write(normalizedPath, data, options) {
|
|
280
369
|
await invokeNative("desktop_fs_write_text", {
|
|
281
370
|
rootPath: this.rootPath,
|
package/dist/storage/fs.d.ts
CHANGED
|
@@ -24,6 +24,21 @@ export interface FileStats extends FileProperties {
|
|
|
24
24
|
size: number;
|
|
25
25
|
}
|
|
26
26
|
export type DataWriteOptions = Partial<FileProperties>;
|
|
27
|
+
export interface VaultReadStreamOptions {
|
|
28
|
+
offset?: number;
|
|
29
|
+
length?: number;
|
|
30
|
+
signal?: AbortSignal;
|
|
31
|
+
}
|
|
32
|
+
export interface VaultReadHandle {
|
|
33
|
+
size: number;
|
|
34
|
+
mtime: number;
|
|
35
|
+
stream(options?: VaultReadStreamOptions): ReadableStream<Uint8Array>;
|
|
36
|
+
}
|
|
37
|
+
export interface AtomicDataWriteOptions extends DataWriteOptions {
|
|
38
|
+
signal?: AbortSignal;
|
|
39
|
+
/** Opaque host-issued correlation used by the App's mutation broker. */
|
|
40
|
+
operationOrigin?: string;
|
|
41
|
+
}
|
|
27
42
|
export declare abstract class TAbstractFile {
|
|
28
43
|
parent: TFolder | null;
|
|
29
44
|
path: string;
|
|
@@ -140,6 +155,8 @@ export interface VaultAdapterCapabilities {
|
|
|
140
155
|
*/
|
|
141
156
|
export interface VaultAdapter extends DataAdapter {
|
|
142
157
|
getCapabilities?(): Partial<VaultAdapterCapabilities>;
|
|
158
|
+
openRead?(normalizedPath: string): Promise<VaultReadHandle>;
|
|
159
|
+
atomicWrite?(normalizedPath: string, source: ReadableStream<Uint8Array>, options?: AtomicDataWriteOptions): Promise<void>;
|
|
143
160
|
}
|
|
144
161
|
export interface VaultIdentityAdapter {
|
|
145
162
|
getVaultId(): string;
|