#[derive(Clone, Copy, Debug)]
pub struct StorageContractDriver {
pub name: &'static str,
pub manifest_value: &'static str,
pub persists_across_processes: bool,
pub needs_database: bool,
pub needs_redis: bool,
}
pub const BUILTIN_STORAGE_DRIVERS: &[StorageContractDriver] = &[
StorageContractDriver {
name: "memory",
manifest_value: "memory",
persists_across_processes: false,
needs_database: false,
needs_redis: false,
},
StorageContractDriver {
name: "fs",
manifest_value: "fs",
persists_across_processes: true,
needs_database: false,
needs_redis: false,
},
StorageContractDriver {
name: "postgres",
manifest_value: "postgres",
persists_across_processes: true,
needs_database: true,
needs_redis: false,
},
StorageContractDriver {
name: "redis",
manifest_value: "redis",
persists_across_processes: true,
needs_database: false,
needs_redis: true,
},
];
pub const STORAGE_API_CONTRACT: &str = r#"
import { storage } from "./server/noxid-server.js";
const direct = storage("wo27-contract");
const isolated = storage("wo27-contract-isolated");
await direct.set("alpha", { value: 1 });
await direct.set("alphabet", 2);
await direct.set("beta", null);
await isolated.set("alpha", { isolated: true });
if ((await direct.get("alpha"))?.value !== 1) throw new Error("get/set did not round trip JSON");
if ((await isolated.get("alpha"))?.isolated !== true) throw new Error("namespaces aliased");
if (JSON.stringify(await direct.list("alpha")) !== JSON.stringify(["alpha", "alphabet"])) throw new Error("prefix list changed");
if (JSON.stringify(await direct.list()) !== JSON.stringify(["alpha", "alphabet", "beta"])) throw new Error("sorted list changed");
for (const [key, value] of [["high-\ud800", 1], ["low-\udfff", 2], ["\u001fnoxid:utf16:literal", 3]]) {
await direct.set(key, value);
if (await direct.get(key) !== value) throw new Error(`full JavaScript string key did not round trip: ${JSON.stringify(key)}`);
}
const unusual = await direct.list();
if (!["high-\ud800", "low-\udfff", "\u001fnoxid:utf16:literal"].every((key) => unusual.includes(key))) throw new Error(`full JavaScript string keys did not survive list: ${JSON.stringify(unusual)}`);
await direct.set("expired", true, { ttl: 0.01 });
await new Promise((resolve) => setTimeout(resolve, 30));
if (await direct.get("expired") !== null || (await direct.list()).includes("expired")) throw new Error("TTL did not expire on read/list");
if (!(await direct.delete("alphabet")) || await direct.delete("alphabet")) throw new Error("delete result changed");
await direct.set("persistent", { value: 7 });
process.exit(0);
"#;
pub fn persistence_check(expects_value: bool) -> String {
format!(
r#"import {{ storage }} from "./server/noxid-server.js";
const value = await storage("wo27-contract").get("persistent");
if ({expects_value} ? value?.value !== 7 : value !== null) throw new Error(`persistence changed: ${{JSON.stringify(value)}}`);
process.exit(0);
"#
)
}