mirror of
https://github.com/storytold/designcraft.git
synced 2026-10-14 19:27:07 -04:00
File: file.serialize returns the file's bytes (base64) — web Save wrote corrupt documents
file.serialize returned {json: String::from_utf8_lossy(to_bytes(doc))},
but since M6.1 the native format is a zip (deflated document.json + raw
assets), not JSON text. from_utf8_lossy turns every invalid UTF-8
sequence into U+FFFD, so the result is not the file: on the web, File ›
Save downloads exactly those bytes (download_document), and the
downloaded .designcraft can't be opened again ("invalid Zip archive").
Agents calling file.serialize got the same unusable string.
Return {base64, bytes} like the other byte-producing commands
(file.exportIdml, file.exportPdf, snippet.export) and decode it in
download_document.
Test: serialized_document_opens_again.
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
This commit is contained in:
1 parent
5294c8f677
commit
01753f90f3
3 files changed
+18
-2
No files matched your search
@@ -41,7 +41,10 @@ pub fn specs() -> Vec<CommandSpec> {
|
||||
let dir = recovery_dir(s, p)?;
|
||||
Ok(json!({"opened": crate::recovery::open(s, &dir)?}))
|
||||
}),
|
||||
cmd!(query "file.serialize", "Serialize", [], None, "{} → {json}", has_doc, |s, _| Ok(json!({"json": String::from_utf8_lossy(&to_bytes(&s.doc()?.doc)).to_string()}))),
|
||||
cmd!(query "file.serialize", "Serialize", [], None, "{} → {base64, bytes} the .designcraft file", has_doc, |s, _| {
|
||||
let bytes = to_bytes(&s.doc()?.doc);
|
||||
Ok(json!({"base64": base64_encode(&bytes), "bytes": bytes.len()}))
|
||||
}),
|
||||
cmd!(noundo "file.close", "Close", ["File"], Some("Cmd+W"), "{index?}", has_doc, |s, p| {
|
||||
let i = p.get("index").and_then(Value::as_u64).map(|v| v as usize).or(s.active_index()).unwrap_or(0);
|
||||
s.close_document(i);
|
||||
|
||||
@@ -241,6 +241,19 @@ fn hyperlinks_and_bookmarks_reach_the_pdf() {
|
||||
assert_eq!(back.bookmarks.len(), 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn serialized_document_opens_again() {
|
||||
// The web app saves (downloads) what `file.serialize` returns: it must be the file's exact bytes.
|
||||
let mut s = session();
|
||||
s.execute("frame.create", &json!({"rect": [36, 36, 300, 200], "content": "text", "text": "Saved on the web"})).unwrap();
|
||||
let r = s.execute("file.serialize", &json!({})).unwrap();
|
||||
let bytes = cmd::base64_decode(r["base64"].as_str().expect("base64"));
|
||||
assert_eq!(bytes, cmd::to_bytes(&s.doc().unwrap().doc));
|
||||
s.execute("file.openBytes", &json!({"name": "copy", "base64": r["base64"]})).unwrap();
|
||||
let d = s.execute("document.inspect", &json!({})).unwrap();
|
||||
assert_eq!(d["stories"][0]["preview"], "Saved on the web");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn step_and_repeat_grid() {
|
||||
let mut s = session();
|
||||
|
||||
@@ -1325,7 +1325,7 @@ pub fn run_ui(app: &mut DesignApp, id: &str, p: &Value) -> Option<Result<Value,
|
||||
fn download_document(app: &mut DesignApp) -> Result<Value, String> {
|
||||
let name = app.session.active().map(|d| format!("{}.designcraft", d.doc.title)).ok_or("no document")?;
|
||||
let ser = app.run("file.serialize", json!({}))?;
|
||||
let bytes = ser.get("json").and_then(Value::as_str).unwrap_or_default().as_bytes().to_vec();
|
||||
let bytes = designcraft_engine::cmd::base64_decode(ser["base64"].as_str().unwrap_or_default());
|
||||
if let Some(download) = app.services.download.as_mut() {
|
||||
download(&name, &bytes);
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user