Drop ids, staged writes and publish from the filesystem contract

This commit is contained in:
Danny Kim
2026-09-25 12:40:17 +09:00
parent 95a2b1a086
commit e3adbf0462
4 changed files with 11 additions and 39 deletions
+1 -1
View File
@@ -14,5 +14,5 @@ pub use exports::memona::filesystem::provider::{
}; };
pub use memona::filesystem::host::{ pub use memona::filesystem::host::{
Exchange, Header, HostError, LogLevel, Method, Request, Response, Setting, Exchange, Header, HostError, LogLevel, Method, Request, Response, Setting,
Tcp, Udp, bind, config, connect, http, invalidate_token, log, Tcp, Udp, bind, config, connect, http, log,
}; };
+10 -25
View File
@@ -74,9 +74,6 @@ interface host {
variant setting { text(string), secret(string), toggle(bool) } variant setting { text(string), secret(string), toggle(bool) }
/// Reads configuration or a session-only credential for this connection. /// Reads configuration or a session-only credential for this connection.
config: func(key: string) -> option<setting>; config: func(key: string) -> option<setting>;
/// Reports that the current access token was rejected. The host refreshes
/// it once; a second rejection surfaces to the caller as denied.
invalidate-token: func();
/// Emits a diagnostic event. Never include secrets or private document data. /// Emits a diagnostic event. Never include secrets or private document data.
log: func(level: log-level, message: string); log: func(level: log-level, message: string);
@@ -101,36 +98,28 @@ interface provider {
/// An opaque version token, at most 4096 UTF-8 bytes. /// An opaque version token, at most 4096 UTF-8 bytes.
type revision = string; type revision = string;
/// An opaque backend identity, at most 4096 UTF-8 bytes. The host never
/// parses, orders, or shows one, and never keeps one past the connection,
/// because a backend may reuse it.
type resource-id = string;
/// How one resource is named. A provider that hands out ids must accept /// How one resource is named: a path within the connection root.
/// them back; one that does not may reject every id as invalid-input. variant locator { path(string) }
variant locator { path(string), id(resource-id) }
/// Optional operations. False capabilities must return unsupported. /// Optional operations. False capabilities must return unsupported.
/// Conditional-write promises atomic create-only and revision comparisons, /// Conditional-write promises atomic create-only and revision comparisons.
/// and cannot be combined with staged-write, where nothing to compare /// Virtual-directories says a directory is only ever a prefix of something
/// exists until a publish lands. Virtual-directories says a directory is /// stored, as in a flat object store: the host then never offers to create
/// only ever a prefix of something stored, as in a flat object store: the /// an empty one, warns that removing the last child removes the folder,
/// host then never offers to create an empty one, warns that removing the /// and does not call a vanished folder an error. Such a provider may still
/// last child removes the folder, and does not call a vanished folder an /// accept mkdir by writing a marker, and must answer unsupported when
/// error. Such a provider may still accept mkdir by writing a marker, and /// asked to rename a directory.
/// must answer unsupported when asked to rename a directory.
record capabilities { record capabilities {
write: bool, mkdir: bool, rename: bool, remove: bool, write: bool, mkdir: bool, rename: bool, remove: bool,
conditional-write: bool, watch: bool, conditional-write: bool, watch: bool,
staged-write: bool, publishable: bool,
virtual-directories: bool, virtual-directories: bool,
} }
/// Byte length, an opaque revision, and a backend identity, each if known. /// Byte length and an opaque revision, each if known.
record file-info { record file-info {
kind: entry-kind, kind: entry-kind,
size: u64, size: u64,
revision: option<revision>, revision: option<revision>,
id: option<resource-id>,
} }
/// One child name, without slashes, dot segments, or control characters. /// One child name, without slashes, dot segments, or control characters.
record entry { name: string, info: file-info } record entry { name: string, info: file-info }
@@ -198,10 +187,6 @@ interface provider {
/// Polls for a bounded change page if the watch capability is present. No /// Polls for a bounded change page if the watch capability is present. No
/// background callback or persistent subscription is installed by the host. /// background callback or persistent subscription is installed by the host.
poll: func(cursor: option<string>) -> result<change-page, error-code>; poll: func(cursor: option<string>) -> result<change-page, error-code>;
/// Makes every staged write visible as one new root, if the publishable
/// capability is present, and names it, for example as a content
/// identifier. A none result means the publish needs another call.
publish: func() -> result<option<revision>, error-code>;
} }
/// Memona filesystem extension ABI 0.1.0, distributed as a WebAssembly component. /// Memona filesystem extension ABI 0.1.0, distributed as a WebAssembly component.
-12
View File
@@ -36,7 +36,6 @@ fn text(setting: Option<&Setting>) -> Option<String> {
fn route(target: &Locator) -> Result<String, ErrorCode> { fn route(target: &Locator) -> Result<String, ErrorCode> {
match target { match target {
Locator::Path(path) => Ok(path.clone()), Locator::Path(path) => Ok(path.clone()),
Locator::Id(_) => Err(ErrorCode::InvalidInput),
} }
} }
@@ -141,7 +140,6 @@ impl GuestWriter for FtpWriter {
kind: EntryKind::File, kind: EntryKind::File,
size: 0, size: 0,
revision: None, revision: None,
id: None,
})) }))
} }
} }
@@ -192,8 +190,6 @@ impl Guest for Ftp {
// promised without simulating one, which the contract forbids. // promised without simulating one, which the contract forbids.
conditional_write: false, conditional_write: false,
watch: false, watch: false,
staged_write: false,
publishable: false,
virtual_directories: false, virtual_directories: false,
}) })
} }
@@ -216,7 +212,6 @@ impl Guest for Ftp {
kind: EntryKind::Directory, kind: EntryKind::Directory,
size: 0, size: 0,
revision: None, revision: None,
id: None,
}); });
} }
with_control(|control| { with_control(|control| {
@@ -231,7 +226,6 @@ impl Guest for Ftp {
kind: EntryKind::File, kind: EntryKind::File,
size, size,
revision: None, revision: None,
id: None,
}); });
} }
let (code, _) = control.send(&format!("CWD {path}"))?; let (code, _) = control.send(&format!("CWD {path}"))?;
@@ -240,7 +234,6 @@ impl Guest for Ftp {
kind: EntryKind::Directory, kind: EntryKind::Directory,
size: 0, size: 0,
revision: None, revision: None,
id: None,
}) })
}) })
} }
@@ -309,7 +302,6 @@ impl Guest for Ftp {
kind: EntryKind::Directory, kind: EntryKind::Directory,
size: 0, size: 0,
revision: None, revision: None,
id: None,
}) })
} }
@@ -342,10 +334,6 @@ impl Guest for Ftp {
fn poll(_cursor: Option<String>) -> Result<ChangePage, ErrorCode> { fn poll(_cursor: Option<String>) -> Result<ChangePage, ErrorCode> {
Err(ErrorCode::Unsupported) Err(ErrorCode::Unsupported)
} }
fn publish() -> Result<Option<String>, ErrorCode> {
Err(ErrorCode::Unsupported)
}
} }
memona_plugin_sdk::export!(Ftp); memona_plugin_sdk::export!(Ftp);
-1
View File
@@ -35,7 +35,6 @@ pub fn machine_entry(line: &str) -> Option<Entry> {
kind, kind,
size, size,
revision: None, revision: None,
id: None,
}, },
}) })
} }