More consistent document crate names (#4323)

* More consistent document crate names

* Fix fmt

* Fix ASCII art diagrams

* rename document-graph to document-graph-storage
This commit is contained in:
Timon
2026-07-15 14:25:12 +02:00
committed by GitHub
parent f0bb2edb3d
commit dc813e35fc
30 changed files with 121 additions and 116 deletions

34
Cargo.lock generated
View File

@@ -1298,9 +1298,9 @@ version = "0.0.0"
dependencies = [ dependencies = [
"core-types", "core-types",
"document-container", "document-container",
"document-graph-storage",
"futures", "futures",
"graph-craft", "graph-craft",
"graph-storage",
"graphene-resource", "graphene-resource",
"log", "log",
"rmp-serde", "rmp-serde",
@@ -1310,6 +1310,21 @@ dependencies = [
"thiserror 2.0.18", "thiserror 2.0.18",
] ]
[[package]]
name = "document-graph-storage"
version = "0.0.0"
dependencies = [
"blake3",
"core-types",
"graph-craft",
"graphene-resource",
"rmp-serde",
"rustc-hash 2.1.1",
"serde",
"serde_json",
"thiserror 2.0.18",
]
[[package]] [[package]]
name = "downcast-rs" name = "downcast-rs"
version = "1.2.1" version = "1.2.1"
@@ -2015,21 +2030,6 @@ dependencies = [
"winit", "winit",
] ]
[[package]]
name = "graph-storage"
version = "0.0.0"
dependencies = [
"blake3",
"core-types",
"graph-craft",
"graphene-resource",
"rmp-serde",
"rustc-hash 2.1.1",
"serde",
"serde_json",
"thiserror 2.0.18",
]
[[package]] [[package]]
name = "graphene-application-io" name = "graphene-application-io"
version = "0.1.0" version = "0.1.0"
@@ -2334,12 +2334,12 @@ dependencies = [
"derivative", "derivative",
"document-container", "document-container",
"document-format", "document-format",
"document-graph-storage",
"dyn-any", "dyn-any",
"env_logger", "env_logger",
"futures", "futures",
"glam", "glam",
"graph-craft", "graph-craft",
"graph-storage",
"graphene-hash", "graphene-hash",
"graphene-std", "graphene-std",
"graphite-proc-macros", "graphite-proc-macros",

View File

@@ -2,15 +2,15 @@
members = [ members = [
"desktop", "desktop",
"desktop/wrapper", "desktop/wrapper",
"desktop/ui",
"desktop/embedded-resources", "desktop/embedded-resources",
"desktop/bundle", "desktop/bundle",
"desktop/platform/linux", "desktop/platform/linux",
"desktop/platform/mac", "desktop/platform/mac",
"desktop/platform/win", "desktop/platform/win",
"desktop/ui", "document/format",
"document/graph-storage", "document/graph-storage",
"document/container", "document/container",
"document/document-format",
"editor", "editor",
"frontend/wrapper", "frontend/wrapper",
"libraries/dyn-any", "libraries/dyn-any",
@@ -92,8 +92,8 @@ repeat-nodes = { path = "node-graph/nodes/repeat" }
math-nodes = { path = "node-graph/nodes/math" } math-nodes = { path = "node-graph/nodes/math" }
path-bool-nodes = { path = "node-graph/nodes/path-bool" } path-bool-nodes = { path = "node-graph/nodes/path-bool" }
graph-craft = { path = "node-graph/graph-craft" } graph-craft = { path = "node-graph/graph-craft" }
graph-storage = { path = "document/graph-storage", default-features = false } document-format = { path = "document/format" }
document-format = { path = "document/document-format" } document-graph-storage = { path = "document/graph-storage", default-features = false }
document-container = { path = "document/container" } document-container = { path = "document/container" }
raster-nodes = { path = "node-graph/nodes/raster" } raster-nodes = { path = "node-graph/nodes/raster" }
graphene-std = { path = "node-graph/nodes/gstd" } graphene-std = { path = "node-graph/nodes/gstd" }

View File

@@ -1,16 +1,16 @@
[package] [package]
name = "document-format" name = "document-format"
description = "Typed handle for the .gdd document format, sitting over graph-storage and document-container" description = "Typed handle for the .gdd document format, sitting over document-graph-storage and document-container"
edition.workspace = true edition.workspace = true
version.workspace = true version.workspace = true
license.workspace = true license.workspace = true
authors.workspace = true authors.workspace = true
[features] [features]
# Runtime bridge: the editorstorage conversion methods (stage/commit from a `NodeNetwork`, # Runtime bridge: the editor <-> storage conversion methods (stage/commit from a `NodeNetwork`,
# `network_ids`, `declarations`). Off lets a standalone migration tool build without `graph-craft` # `network_ids`, `declarations`). Off lets a standalone migration tool build without `graph-craft`
# or `core-types`. Forwards to `graph-storage/conversion`. # or `core-types`. Forwards to `document-graph-storage/conversion`.
conversion = ["graph-storage/conversion", "dep:graph-craft", "dep:core-types"] conversion = ["document-graph-storage/conversion", "dep:graph-craft", "dep:core-types"]
# Compressed-archive export/open. Each forwards to the matching `document-container` feature and # Compressed-archive export/open. Each forwards to the matching `document-container` feature and
# gates that format's `ExportFormat` arm and sink. The folder/memory codec-free core needs neither. # gates that format's `ExportFormat` arm and sink. The folder/memory codec-free core needs neither.
zip = ["document-container/zip"] zip = ["document-container/zip"]
@@ -19,7 +19,7 @@ default = ["conversion", "zip", "xz"]
[dependencies] [dependencies]
document-container = { workspace = true } document-container = { workspace = true }
graph-storage = { workspace = true, default-features = false } document-graph-storage = { workspace = true, default-features = false }
graph-craft = { workspace = true, optional = true } graph-craft = { workspace = true, optional = true }
graphene-resource = { workspace = true } graphene-resource = { workspace = true }
core-types = { workspace = true, optional = true } core-types = { workspace = true, optional = true }

View File

@@ -5,8 +5,8 @@
use document_container::ContainerError; use document_container::ContainerError;
#[cfg(feature = "conversion")] #[cfg(feature = "conversion")]
use graph_storage::CommitError; use document_graph_storage::CommitError;
use graph_storage::CrdtError; use document_graph_storage::CrdtError;
use graphene_resource::ResourceHash; use graphene_resource::ResourceHash;
use crate::codec::CodecError; use crate::codec::CodecError;

View File

@@ -162,7 +162,7 @@ impl<L: Layout> Gdd<L> {
// below, so only the gap is loaded from the byte store here. // below, so only the gap is loaded from the byte store here.
let mut export_session = self.session.clone(); let mut export_session = self.session.clone();
let mut hashes_from_store: Vec<ResourceHash> = Vec::new(); let mut hashes_from_store: Vec<ResourceHash> = Vec::new();
let mut links_to_promote: Vec<graph_storage::ResourceId> = Vec::new(); let mut links_to_promote: Vec<document_graph_storage::ResourceId> = Vec::new();
for (id, entry) in &export_session.registry().resources { for (id, entry) in &export_session.registry().resources {
let Some(hash) = entry.hash else { continue }; let Some(hash) = entry.hash else { continue };
let embed = entry.has_embedded_source() || options.embed_all_resources; let embed = entry.has_embedded_source() || options.embed_all_resources;

View File

@@ -1,6 +1,6 @@
//! Typed handle for `.gdd` documents. //! Typed handle for `.gdd` documents.
//! //!
//! [`Gdd`] owns a [`graph_storage::Session`] plus a working-copy [`document_container::AnyContainer`]. //! [`Gdd`] owns a [`document_graph_storage::Session`] plus a working-copy [`document_container::AnyContainer`].
//! Mutations flow through `Gdd` to keep the session and the on-disk working copy mirrored. //! Mutations flow through `Gdd` to keep the session and the on-disk working copy mirrored.
//! Export is a separate, explicit operation — see [`export::ExportFormat`]. //! Export is a separate, explicit operation — see [`export::ExportFormat`].
//! //!
@@ -16,8 +16,8 @@ use std::path::Path;
use document_container::backends::folder::FolderBackend; use document_container::backends::folder::FolderBackend;
use document_container::{AnyContainer, AsyncContainer, ByteHolder, ContainerError}; use document_container::{AnyContainer, AsyncContainer, ByteHolder, ContainerError};
#[cfg(feature = "conversion")] #[cfg(feature = "conversion")]
use graph_storage::{CommitError, NodeMetadataSource}; use document_graph_storage::{CommitError, NodeMetadataSource};
use graph_storage::{Delta, HotOp, PeerId, Registry, Session}; use document_graph_storage::{Delta, HotOp, PeerId, Registry, Session};
#[cfg(feature = "conversion")] #[cfg(feature = "conversion")]
use graphene_resource::LoadResource; use graphene_resource::LoadResource;
use graphene_resource::ResourceHash; use graphene_resource::ResourceHash;
@@ -83,7 +83,7 @@ pub struct Gdd<L: Layout = GddV1Layout> {
pub(crate) view_settings: std::collections::BTreeMap<String, serde_json::Value>, pub(crate) view_settings: std::collections::BTreeMap<String, serde_json::Value>,
/// Per-network view settings (node-graph nav + previewing), keyed by stable [`NetworkId`]. Same per-peer /// Per-network view settings (node-graph nav + previewing), keyed by stable [`NetworkId`]. Same per-peer
/// `session.json` treatment as [`view_settings`](Self::view_settings), but scoped per network. /// `session.json` treatment as [`view_settings`](Self::view_settings), but scoped per network.
pub(crate) network_view_settings: std::collections::BTreeMap<graph_storage::NetworkId, std::collections::BTreeMap<String, serde_json::Value>>, pub(crate) network_view_settings: std::collections::BTreeMap<document_graph_storage::NetworkId, std::collections::BTreeMap<String, serde_json::Value>>,
} }
/// Native folder-backed convenience constructors. On wasm the editor builds an OPFS-backed /// Native folder-backed convenience constructors. On wasm the editor builds an OPFS-backed
@@ -261,19 +261,19 @@ impl<L: Layout> Gdd<L> {
} }
/// The per-network view settings read from `session.json` (node-graph nav + previewing), keyed by /// The per-network view settings read from `session.json` (node-graph nav + previewing), keyed by
/// [`NetworkId`](graph_storage::NetworkId). Opaque `ui::nav::*` / `ui::previewing` blobs the editor decodes. /// [`NetworkId`](document_graph_storage::NetworkId). Opaque `ui::nav::*` / `ui::previewing` blobs the editor decodes.
pub fn network_view_settings(&self) -> &std::collections::BTreeMap<graph_storage::NetworkId, std::collections::BTreeMap<String, serde_json::Value>> { pub fn network_view_settings(&self) -> &std::collections::BTreeMap<document_graph_storage::NetworkId, std::collections::BTreeMap<String, serde_json::Value>> {
&self.network_view_settings &self.network_view_settings
} }
/// Resolve each runtime `network_path` to its stable [`NetworkId`](graph_storage::NetworkId), so the /// Resolve each runtime `network_path` to its stable [`NetworkId`](document_graph_storage::NetworkId), so the
/// editor can key per-network, per-peer view state by a stable id. See [`Session::network_ids`]. /// editor can key per-network, per-peer view state by a stable id. See [`Session::network_ids`].
#[cfg(feature = "conversion")] #[cfg(feature = "conversion")]
pub fn network_ids<M: NodeMetadataSource>( pub fn network_ids<M: NodeMetadataSource>(
&self, &self,
network: &graph_craft::document::NodeNetwork, network: &graph_craft::document::NodeNetwork,
metadata: &M, metadata: &M,
) -> Result<std::collections::HashMap<Vec<core_types::uuid::NodeId>, graph_storage::NetworkId>, CommitError> { ) -> Result<std::collections::HashMap<Vec<core_types::uuid::NodeId>, document_graph_storage::NetworkId>, CommitError> {
self.session.network_ids(network, metadata) self.session.network_ids(network, metadata)
} }
@@ -292,17 +292,17 @@ impl<L: Layout> Gdd<L> {
(working, self.layout) (working, self.layout)
} }
/// Resolve the proto-node declarations referenced by the registry into a [`graph_storage::Declarations`] /// Resolve the proto-node declarations referenced by the registry into a [`document_graph_storage::Declarations`]
/// map, loading each `ProtoNode`'s bytes from `byte_store` (the global cache in the editor, the /// map, loading each `ProtoNode`'s bytes from `byte_store` (the global cache in the editor, the
/// working-copy container for standalone). Only resources referenced by `Implementation::ProtoNode` /// working-copy container for standalone). Only resources referenced by `Implementation::ProtoNode`
/// are visited, so image/font resources are skipped. Cold-path (open / `to_runtime`); async /// are visited, so image/font resources are skipped. Cold-path (open / `to_runtime`); async
/// because resource loads are. /// because resource loads are.
#[cfg(feature = "conversion")] #[cfg(feature = "conversion")]
pub async fn declarations(&self, byte_store: &dyn LoadResource) -> graph_storage::Declarations { pub async fn declarations(&self, byte_store: &dyn LoadResource) -> document_graph_storage::Declarations {
use graph_storage::Implementation; use document_graph_storage::Implementation;
let registry = self.session.registry(); let registry = self.session.registry();
let mut declarations = graph_storage::Declarations::new(); let mut declarations = document_graph_storage::Declarations::new();
for node in registry.node_instances.values() { for node in registry.node_instances.values() {
let Implementation::ProtoNode(id) = node.implementation() else { continue }; let Implementation::ProtoNode(id) = node.implementation() else { continue };
@@ -317,7 +317,7 @@ impl<L: Layout> Gdd<L> {
log::error!("Declaration bytes for {id} (hash {hash}) missing from byte store"); log::error!("Declaration bytes for {id} (hash {hash}) missing from byte store");
continue; continue;
}; };
match graph_storage::decode_declaration(resource.as_ref()) { match document_graph_storage::decode_declaration(resource.as_ref()) {
Ok(proto) => { Ok(proto) => {
declarations.insert(*id, proto); declarations.insert(*id, proto);
} }

View File

@@ -5,8 +5,8 @@
use document_container::AsyncContainer; use document_container::AsyncContainer;
#[cfg(feature = "conversion")] #[cfg(feature = "conversion")]
use graph_storage::NodeMetadataSource; use document_graph_storage::NodeMetadataSource;
use graph_storage::{HotOp, Rev, TimeStamp}; use document_graph_storage::{HotOp, Rev, TimeStamp};
#[cfg(feature = "conversion")] #[cfg(feature = "conversion")]
use graphene_resource::ResourceStorage; use graphene_resource::ResourceStorage;
@@ -200,7 +200,7 @@ impl<L: Layout> Gdd<L> {
/// Advance the published frontier to `rev` and persist it to `session.json`, so the silent/published /// Advance the published frontier to `rev` and persist it to `session.json`, so the silent/published
/// undo boundary survives a reopen. Called by the (future) broadcast transport as commits are shared. /// undo boundary survives a reopen. Called by the (future) broadcast transport as commits are shared.
pub fn publish_up_to(&mut self, rev: graph_storage::Rev) -> Result<(), Error> { pub fn publish_up_to(&mut self, rev: document_graph_storage::Rev) -> Result<(), Error> {
self.session.publish_up_to(rev); self.session.publish_up_to(rev);
self.persist_session_state() self.persist_session_state()
} }
@@ -209,7 +209,7 @@ impl<L: Layout> Gdd<L> {
/// enters the registry, history, or CRDT. /// enters the registry, history, or CRDT.
pub fn set_network_view_settings( pub fn set_network_view_settings(
&mut self, &mut self,
network_view_settings: std::collections::BTreeMap<graph_storage::NetworkId, std::collections::BTreeMap<String, serde_json::Value>>, network_view_settings: std::collections::BTreeMap<document_graph_storage::NetworkId, std::collections::BTreeMap<String, serde_json::Value>>,
) -> Result<(), Error> { ) -> Result<(), Error> {
self.network_view_settings = network_view_settings; self.network_view_settings = network_view_settings;
self.persist_session_state() self.persist_session_state()

View File

@@ -23,7 +23,7 @@ impl<L: Layout> Gdd<L> {
/// `DataSource::Embedded` source resolved to the content hash) through the session so the registry /// `DataSource::Embedded` source resolved to the content hash) through the session so the registry
/// records the resource and the entry replicates, then writes the bytes into the working copy's /// records the resource and the entry replicates, then writes the bytes into the working copy's
/// content-addressed store. The caller owns `id` allocation. /// content-addressed store. The caller owns `id` allocation.
pub fn add_resource(&mut self, id: graph_storage::ResourceId, bytes: &[u8]) -> Result<(), Error> { pub fn add_resource(&mut self, id: document_graph_storage::ResourceId, bytes: &[u8]) -> Result<(), Error> {
let hash = ResourceHash::from(bytes); let hash = ResourceHash::from(bytes);
self.working.write_non_blocking(&self.layout.resource_path(&hash), bytes)?; self.working.write_non_blocking(&self.layout.resource_path(&hash), bytes)?;
@@ -37,7 +37,7 @@ impl<L: Layout> Gdd<L> {
/// than buffering them. Folder backends use `fs::copy` (CoW on supported filesystems); other /// than buffering them. Folder backends use `fs::copy` (CoW on supported filesystems); other
/// backends fall back to read-then-write. Native-only: there is no filesystem source path on wasm. /// backends fall back to read-then-write. Native-only: there is no filesystem source path on wasm.
#[cfg(not(target_family = "wasm"))] #[cfg(not(target_family = "wasm"))]
pub fn add_resource_from_path(&mut self, id: graph_storage::ResourceId, hash: ResourceHash, src: &Path) -> Result<(), Error> { pub fn add_resource_from_path(&mut self, id: document_graph_storage::ResourceId, hash: ResourceHash, src: &Path) -> Result<(), Error> {
let dest_path = self.layout.resource_path(&hash); let dest_path = self.layout.resource_path(&hash);
if let AnyContainer::Folder(folder) = self.working.as_ref() { if let AnyContainer::Folder(folder) = self.working.as_ref() {
let full = folder.root().join(&dest_path); let full = folder.root().join(&dest_path);

View File

@@ -4,7 +4,7 @@
//! //!
//! Lives in `session.json`. Rewritten on retirement. //! Lives in `session.json`. Rewritten on retirement.
use graph_storage::{NetworkId, PeerId, Rev}; use document_graph_storage::{NetworkId, PeerId, Rev};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::collections::BTreeMap; use std::collections::BTreeMap;

View File

@@ -5,7 +5,7 @@
use document_container::AnyContainer; use document_container::AnyContainer;
use document_container::backends::memory::MemoryBackend; use document_container::backends::memory::MemoryBackend;
use document_format::{Codec, Error, GddV1, GddV1Layout, Layout, Manifest, io, manifest}; use document_format::{Codec, Error, GddV1, GddV1Layout, Layout, Manifest, io, manifest};
use graph_storage::{HotOp, Network, NetworkId, PeerId, ROOT_NETWORK, RegistryDelta, TimeStamp}; use document_graph_storage::{HotOp, Network, NetworkId, PeerId, ROOT_NETWORK, RegistryDelta, TimeStamp};
fn empty_container() -> AnyContainer { fn empty_container() -> AnyContainer {
AnyContainer::Memory(MemoryBackend::new()) AnyContainer::Memory(MemoryBackend::new())
@@ -416,8 +416,8 @@ fn export_carries_resources() {
#[test] #[test]
fn embed_all_resources_materializes_link_only_resource() { fn embed_all_resources_materializes_link_only_resource() {
use document_format::{ExportFormat, ExportOptions}; use document_format::{ExportFormat, ExportOptions};
use document_graph_storage::NoMetadata;
use graph_craft::application_io::resource::ResourceStorage; use graph_craft::application_io::resource::ResourceStorage;
use graph_storage::NoMetadata;
use graphene_resource::{DataSource, ResourceHash, ResourceId, ResourceRegistry}; use graphene_resource::{DataSource, ResourceHash, ResourceId, ResourceRegistry};
futures::executor::block_on(async { futures::executor::block_on(async {
@@ -483,8 +483,8 @@ fn embed_all_resources_materializes_link_only_resource() {
#[test] #[test]
fn export_materializes_embedded_resource_from_byte_store() { fn export_materializes_embedded_resource_from_byte_store() {
use document_format::{ExportFormat, ExportOptions}; use document_format::{ExportFormat, ExportOptions};
use document_graph_storage::NoMetadata;
use graph_craft::application_io::resource::ResourceStorage; use graph_craft::application_io::resource::ResourceStorage;
use graph_storage::NoMetadata;
use graphene_resource::{DataSource, ResourceHash, ResourceId, ResourceRegistry}; use graphene_resource::{DataSource, ResourceHash, ResourceId, ResourceRegistry};
futures::executor::block_on(async { futures::executor::block_on(async {
@@ -526,8 +526,8 @@ fn export_materializes_embedded_resource_from_byte_store() {
/// export, which previously failed at `embed_resource_sources` and fell back to the legacy blob. /// export, which previously failed at `embed_resource_sources` and fell back to the legacy blob.
#[test] #[test]
fn export_round_trips_unretired_hot_ops() { fn export_round_trips_unretired_hot_ops() {
use document_graph_storage::NoMetadata;
use graph_craft::application_io::resource::ResourceStorage; use graph_craft::application_io::resource::ResourceStorage;
use graph_storage::NoMetadata;
use graphene_resource::{DataSource, ResourceId, ResourceRegistry}; use graphene_resource::{DataSource, ResourceId, ResourceRegistry};
futures::executor::block_on(async { futures::executor::block_on(async {
@@ -602,10 +602,10 @@ fn create_in_records_default_codecs_in_manifest() {
/// persistence and retirement, so the `peer_users` mapping survives a reopen. /// persistence and retirement, so the `peer_users` mapping survives a reopen.
#[test] #[test]
fn first_commit_registers_peer_and_survives_reopen() { fn first_commit_registers_peer_and_survives_reopen() {
use document_graph_storage::{NoMetadata, UserId};
use graph_craft::application_io::resource::HashMapResourceStorage; use graph_craft::application_io::resource::HashMapResourceStorage;
use graph_craft::document::{DocumentNode, DocumentNodeImplementation, NodeInput, NodeNetwork}; use graph_craft::document::{DocumentNode, DocumentNodeImplementation, NodeInput, NodeNetwork};
use graph_craft::{ProtoNodeIdentifier, concrete}; use graph_craft::{ProtoNodeIdentifier, concrete};
use graph_storage::{NoMetadata, UserId};
use graphene_resource::ResourceRegistry; use graphene_resource::ResourceRegistry;
futures::executor::block_on(async { futures::executor::block_on(async {
@@ -674,10 +674,10 @@ fn persist_path_writes_at_manifest_declared_codec_paths() {
/// editor-shaped path (declaration bytes live in the resource store, not the Gdd container). /// editor-shaped path (declaration bytes live in the resource store, not the Gdd container).
#[test] #[test]
fn declarations_round_trip_through_byte_store() { fn declarations_round_trip_through_byte_store() {
use document_graph_storage::NoMetadata;
use graph_craft::application_io::resource::HashMapResourceStorage; use graph_craft::application_io::resource::HashMapResourceStorage;
use graph_craft::document::{DocumentNode, DocumentNodeImplementation, NodeInput, NodeNetwork}; use graph_craft::document::{DocumentNode, DocumentNodeImplementation, NodeInput, NodeNetwork};
use graph_craft::{ProtoNodeIdentifier, concrete}; use graph_craft::{ProtoNodeIdentifier, concrete};
use graph_storage::NoMetadata;
use graphene_resource::ResourceRegistry; use graphene_resource::ResourceRegistry;
const PROTO: &str = "graphene_core::ops::identity::IdentityNode"; const PROTO: &str = "graphene_core::ops::identity::IdentityNode";

View File

@@ -1,5 +1,5 @@
[package] [package]
name = "graph-storage" name = "document-graph-storage"
description = "Provides a delta based graph representation used in the Graphite file format" description = "Provides a delta based graph representation used in the Graphite file format"
edition.workspace = true edition.workspace = true
version.workspace = true version.workspace = true

View File

@@ -89,7 +89,7 @@ impl TryFrom<&NodeNetwork> for Registry {
pub type DeclarationBytes = HashMap<ResourceHash, Vec<u8>>; pub type DeclarationBytes = HashMap<ResourceHash, Vec<u8>>;
/// A `from_runtime` conversion result: the reference-only [`Registry`] plus the proto-node /// A `from_runtime` conversion result: the reference-only [`Registry`] plus the proto-node
/// declaration *bytes* it extracted, keyed by content hash. `graph-storage` doesn't own a byte /// declaration *bytes* it extracted, keyed by content hash. `document-graph-storage` doesn't own a byte
/// store, so the caller (the `Gdd`) persists these into its content store; the registry only holds /// store, so the caller (the `Gdd`) persists these into its content store; the registry only holds
/// the `ResourceId`/`ResourceHash` references. /// the `ResourceId`/`ResourceHash` references.
pub struct RuntimeConversion { pub struct RuntimeConversion {

View File

@@ -128,7 +128,7 @@ pub struct ExportSlot {
/// Content of a proto-node declaration. Stored as a content-addressed resource (serialized bytes /// Content of a proto-node declaration. Stored as a content-addressed resource (serialized bytes
/// keyed by `ResourceHash`, held by the `Gdd` byte store) and referenced from /// keyed by `ResourceHash`, held by the `Gdd` byte store) and referenced from
/// `Implementation::ProtoNode(ResourceId)`. `graph-storage` itself only holds the reference. /// `Implementation::ProtoNode(ResourceId)`. `document-graph-storage` itself only holds the reference.
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct ProtoNode { pub struct ProtoNode {
pub identifier: String, pub identifier: String,

View File

@@ -65,7 +65,7 @@ impl Session {
/// op as its own `Delta` on the local chain. One `clock.tick()` per op (strictly causal within /// op as its own `Delta` on the local chain. One `clock.tick()` per op (strictly causal within
/// a commit). Returns the new `Rev`s in commit order (empty if nothing changed) plus the /// a commit). Returns the new `Rev`s in commit order (empty if nothing changed) plus the
/// proto-node declaration bytes the conversion extracted, keyed by content hash, for the caller /// proto-node declaration bytes the conversion extracted, keyed by content hash, for the caller
/// to persist into its byte store (`graph-storage` itself is byte-unaware). /// to persist into its byte store (`document-graph-storage` itself is byte-unaware).
/// ///
/// Stages the diff as hot ops rather than retired deltas: each op is applied to the registry and /// Stages the diff as hot ops rather than retired deltas: each op is applied to the registry and
/// pushed onto the hot log. The caller persists the returned hot frames and then calls `retire` /// pushed onto the hot log. The caller persists the returned hot frames and then calls `retire`

View File

@@ -34,7 +34,7 @@ pub enum ConversionError {
/// Resolved proto-node declarations, keyed by the `ResourceId` that `Implementation::ProtoNode` /// Resolved proto-node declarations, keyed by the `ResourceId` that `Implementation::ProtoNode`
/// references. The caller resolves these from its byte store (`ResourceId` → `ResourceHash` → /// references. The caller resolves these from its byte store (`ResourceId` → `ResourceHash` →
/// stored `ProtoNode` bytes) before converting, since `graph-storage` holds only references. /// stored `ProtoNode` bytes) before converting, since `document-graph-storage` holds only references.
pub type Declarations = std::collections::HashMap<ResourceId, ProtoNode>; pub type Declarations = std::collections::HashMap<ResourceId, ProtoNode>;
impl Registry { impl Registry {

View File

@@ -19,8 +19,8 @@ gpu = ["interpreted-executor/gpu", "dep:wgpu-executor"]
# Local dependencies # Local dependencies
graphite-proc-macros = { workspace = true } graphite-proc-macros = { workspace = true }
graph-craft = { workspace = true } graph-craft = { workspace = true }
graph-storage = { workspace = true, features = ["conversion"] }
document-format = { workspace = true } document-format = { workspace = true }
document-graph-storage = { workspace = true, features = ["conversion"] }
document-container = { workspace = true } document-container = { workspace = true }
graphene-hash = { workspace = true } graphene-hash = { workspace = true }
interpreted-executor = { workspace = true } interpreted-executor = { workspace = true }

View File

@@ -4,7 +4,7 @@
use std::fmt::Write; use std::fmt::Write;
pub(crate) fn diff_registries(stored: &graph_storage::Registry, target: &graph_storage::Registry) -> String { pub(crate) fn diff_registries(stored: &document_graph_storage::Registry, target: &document_graph_storage::Registry) -> String {
let mut out = String::new(); let mut out = String::new();
let stored_node_ids: std::collections::BTreeSet<_> = stored.node_instances.keys().copied().collect(); let stored_node_ids: std::collections::BTreeSet<_> = stored.node_instances.keys().copied().collect();
@@ -91,7 +91,7 @@ pub(crate) fn diff_registries(stored: &graph_storage::Registry, target: &graph_s
out out
} }
fn diff_node(out: &mut String, stored: &graph_storage::Node, target: &graph_storage::Node) { fn diff_node(out: &mut String, stored: &document_graph_storage::Node, target: &document_graph_storage::Node) {
if stored.implementation() != target.implementation() { if stored.implementation() != target.implementation() {
let _ = writeln!(out, " implementation: stored={:?} target={:?}", stored.implementation(), target.implementation()); let _ = writeln!(out, " implementation: stored={:?} target={:?}", stored.implementation(), target.implementation());
} }
@@ -123,7 +123,7 @@ fn diff_node(out: &mut String, stored: &graph_storage::Node, target: &graph_stor
} }
} }
fn diff_network(out: &mut String, stored: &graph_storage::Network, target: &graph_storage::Network) { fn diff_network(out: &mut String, stored: &document_graph_storage::Network, target: &document_graph_storage::Network) {
if stored.exports.len() != target.exports.len() { if stored.exports.len() != target.exports.len() {
let _ = writeln!(out, " exports.len: stored={} target={}", stored.exports.len(), target.exports.len()); let _ = writeln!(out, " exports.len: stored={} target={}", stored.exports.len(), target.exports.len());
} }
@@ -144,13 +144,13 @@ fn diff_network(out: &mut String, stored: &graph_storage::Network, target: &grap
} }
/// Value-level resource comparison (same resolved hash, same source bodies keyed by `SourceKey`), /// Value-level resource comparison (same resolved hash, same source bodies keyed by `SourceKey`),
/// ignoring LWW timestamps. Mirrors `graph_storage`'s internal `resources_value_equal` for a single /// ignoring LWW timestamps. Mirrors `document_graph_storage`'s internal `resources_value_equal` for a single
/// entry, since that helper is crate-private and only operates over a whole store. /// entry, since that helper is crate-private and only operates over a whole store.
fn resource_value_equal(stored: &graph_storage::ResourceEntry, target: &graph_storage::ResourceEntry) -> bool { fn resource_value_equal(stored: &document_graph_storage::ResourceEntry, target: &document_graph_storage::ResourceEntry) -> bool {
stored.hash == target.hash && stored.sources.len() == target.sources.len() && stored.sources.iter().all(|(key, value)| target.source(key).is_some_and(|other| value.source == other.source)) stored.hash == target.hash && stored.sources.len() == target.sources.len() && stored.sources.iter().all(|(key, value)| target.source(key).is_some_and(|other| value.source == other.source))
} }
fn diff_resource(out: &mut String, stored: &graph_storage::ResourceEntry, target: &graph_storage::ResourceEntry) { fn diff_resource(out: &mut String, stored: &document_graph_storage::ResourceEntry, target: &document_graph_storage::ResourceEntry) {
if stored.hash != target.hash { if stored.hash != target.hash {
let _ = writeln!(out, " hash: stored={:?} target={:?}", stored.hash, target.hash); let _ = writeln!(out, " hash: stored={:?} target={:?}", stored.hash, target.hash);
} }
@@ -177,7 +177,7 @@ fn diff_resource(out: &mut String, stored: &graph_storage::ResourceEntry, target
} }
} }
fn diff_attributes(out: &mut String, label: &str, stored: &graph_storage::Attributes, target: &graph_storage::Attributes) { fn diff_attributes(out: &mut String, label: &str, stored: &document_graph_storage::Attributes, target: &document_graph_storage::Attributes) {
let stored_keys: std::collections::BTreeSet<_> = stored.keys().collect(); let stored_keys: std::collections::BTreeSet<_> = stored.keys().collect();
let target_keys: std::collections::BTreeSet<_> = target.keys().collect(); let target_keys: std::collections::BTreeSet<_> = target.keys().collect();
let missing: Vec<_> = target_keys.difference(&stored_keys).collect(); let missing: Vec<_> = target_keys.difference(&stored_keys).collect();

View File

@@ -1,8 +1,8 @@
use std::collections::VecDeque; use std::collections::VecDeque;
use std::collections::{BTreeMap, HashSet}; use std::collections::{BTreeMap, HashSet};
use document_graph_storage::Registry;
use graph_craft::application_io::resource::{ResourceId, ResourceRegistry, ResourceStorage}; use graph_craft::application_io::resource::{ResourceId, ResourceRegistry, ResourceStorage};
use graph_storage::Registry;
use super::utility_types::network_interface::NodeNetworkInterface; use super::utility_types::network_interface::NodeNetworkInterface;
use super::utility_types::network_interface::storage_metadata::{StorageMetadataView, collect_network_view_settings}; use super::utility_types::network_interface::storage_metadata::{StorageMetadataView, collect_network_view_settings};

View File

@@ -2049,7 +2049,7 @@ impl DocumentMessageHandler {
/// Restore `view_settings` map into the document. /// Restore `view_settings` map into the document.
pub fn apply_stored_document_settings(&mut self, view_settings: &std::collections::BTreeMap<String, serde_json::Value>) { pub fn apply_stored_document_settings(&mut self, view_settings: &std::collections::BTreeMap<String, serde_json::Value>) {
use graph_storage::attr::session::doc; use document_graph_storage::attr::session::doc;
fn decode<T: serde::de::DeserializeOwned>(view_settings: &std::collections::BTreeMap<String, serde_json::Value>, key: &str) -> Option<T> { fn decode<T: serde::de::DeserializeOwned>(view_settings: &std::collections::BTreeMap<String, serde_json::Value>, key: &str) -> Option<T> {
view_settings.get(key).and_then(|value| serde_json::from_value(value.clone()).ok()) view_settings.get(key).and_then(|value| serde_json::from_value(value.clone()).ok())

View File

@@ -6,7 +6,7 @@
use std::collections::HashMap; use std::collections::HashMap;
use graph_storage::{NodeMetadataSource, PeerId, Registry}; use document_graph_storage::{NodeMetadataSource, PeerId, Registry};
use super::test_support::{load_demo, node_paths}; use super::test_support::{load_demo, node_paths};
use crate::messages::portfolio::document::document_message_handler::DocumentMessageHandler; use crate::messages::portfolio::document::document_message_handler::DocumentMessageHandler;
@@ -34,7 +34,7 @@ fn editor_metadata_round_trip_against_demo() {
let (_converted_network, entries) = registry.to_runtime_with_metadata(&declarations).expect("to_runtime_with_metadata failed"); let (_converted_network, entries) = registry.to_runtime_with_metadata(&declarations).expect("to_runtime_with_metadata failed");
// Index emitted entries by their (network_path, local_id) address. // Index emitted entries by their (network_path, local_id) address.
let entries_by_address: HashMap<(Vec<NodeId>, NodeId), &graph_storage::NodeMetadataEntry> = entries.iter().map(|e| ((e.network_path.clone(), e.local_id), e)).collect(); let entries_by_address: HashMap<(Vec<NodeId>, NodeId), &document_graph_storage::NodeMetadataEntry> = entries.iter().map(|e| ((e.network_path.clone(), e.local_id), e)).collect();
let mut checked_any_position = false; let mut checked_any_position = false;
let mut checked_any_layer = false; let mut checked_any_layer = false;

View File

@@ -7,8 +7,8 @@
use document_container::AnyContainer; use document_container::AnyContainer;
use document_container::backends::memory::MemoryBackend; use document_container::backends::memory::MemoryBackend;
use document_format::{GddV1, GddV1Layout}; use document_format::{GddV1, GddV1Layout};
use document_graph_storage::{NodeMetadataSource, PeerId};
use graph_craft::application_io::resource::HashMapResourceStorage; use graph_craft::application_io::resource::HashMapResourceStorage;
use graph_storage::{NodeMetadataSource, PeerId};
use super::test_support::{RoundTrip, node_paths, round_trip_through_gdd}; use super::test_support::{RoundTrip, node_paths, round_trip_through_gdd};
use crate::messages::portfolio::document::document_message_handler::DocumentMessageHandler; use crate::messages::portfolio::document::document_message_handler::DocumentMessageHandler;
@@ -125,7 +125,7 @@ async fn recommit_after_open_is_stable() {
// that same peer for deterministic node-ID derivation. // that same peer for deterministic node-ID derivation.
let rebuilt_network = round_trip.rebuilt.document_network().clone(); let rebuilt_network = round_trip.rebuilt.document_network().clone();
let view = StorageMetadataView::new(&round_trip.rebuilt); let view = StorageMetadataView::new(&round_trip.rebuilt);
let reconverted = graph_storage::Registry::convert_from_runtime(&rebuilt_network, &view, &Default::default(), PeerId(1)).expect("re-convert from_runtime"); let reconverted = document_graph_storage::Registry::convert_from_runtime(&rebuilt_network, &view, &Default::default(), PeerId(1)).expect("re-convert from_runtime");
assert!( assert!(
round_trip.registry.value_equal(&reconverted.registry), round_trip.registry.value_equal(&reconverted.registry),
@@ -351,7 +351,7 @@ async fn live_undo_shadows_storage_cursor() {
#[tokio::test] #[tokio::test]
async fn round_trip_document_settings() { async fn round_trip_document_settings() {
use graph_storage::attr::session::doc; use document_graph_storage::attr::session::doc;
let mut editor = EditorTestUtils::create(); let mut editor = EditorTestUtils::create();
editor.new_document().await; editor.new_document().await;
@@ -382,7 +382,7 @@ async fn round_trip_document_settings() {
/// and reopens via `open_from_archive`, asserting the PTZ round-trips. /// and reopens via `open_from_archive`, asserting the PTZ round-trips.
#[tokio::test] #[tokio::test]
async fn gdd_archive_round_trips_view_settings() { async fn gdd_archive_round_trips_view_settings() {
use graph_storage::attr::session::doc; use document_graph_storage::attr::session::doc;
let byte_store = HashMapResourceStorage::new(); let byte_store = HashMapResourceStorage::new();
let mut gdd = GddV1::create_in(AnyContainer::Memory(MemoryBackend::new()), GddV1Layout, PeerId(1), 0xABCD, "test".into(), "test".into()) let mut gdd = GddV1::create_in(AnyContainer::Memory(MemoryBackend::new()), GddV1Layout, PeerId(1), 0xABCD, "test".into(), "test".into())
@@ -420,7 +420,7 @@ async fn gdd_archive_round_trips_view_settings() {
#[tokio::test] #[tokio::test]
async fn per_network_navigation_round_trips_via_session_not_registry() { async fn per_network_navigation_round_trips_via_session_not_registry() {
use crate::messages::portfolio::document::utility_types::network_interface::storage_metadata::{apply_network_view_settings, collect_network_view_settings, network_ids_from_entries}; use crate::messages::portfolio::document::utility_types::network_interface::storage_metadata::{apply_network_view_settings, collect_network_view_settings, network_ids_from_entries};
use graph_storage::attr::session::network; use document_graph_storage::attr::session::network;
let byte_store = HashMapResourceStorage::new(); let byte_store = HashMapResourceStorage::new();
@@ -449,7 +449,7 @@ async fn per_network_navigation_round_trips_via_session_not_registry() {
gdd.set_network_view_settings(network_view_settings).expect("set_network_view_settings"); gdd.set_network_view_settings(network_view_settings).expect("set_network_view_settings");
// The registry must NOT carry the node-graph nav (it's per-peer, not document content). // The registry must NOT carry the node-graph nav (it's per-peer, not document content).
let root_network = gdd.registry().networks.get(&graph_storage::ROOT_NETWORK).expect("root network in registry"); let root_network = gdd.registry().networks.get(&document_graph_storage::ROOT_NETWORK).expect("root network in registry");
assert!(!root_network.attributes.contains_key(network::NAV_PTZ), "node-graph nav must not be stored in the registry attributes"); assert!(!root_network.attributes.contains_key(network::NAV_PTZ), "node-graph nav must not be stored in the registry attributes");
// Reopen, rebuild the interface, and apply the persisted per-network view state. // Reopen, rebuild the interface, and apply the persisted per-network view state.
@@ -632,7 +632,7 @@ fn assert_cursor_matches_runtime(document: &DocumentMessageHandler, at: &str) {
let network = document.network_interface.document_network().clone(); let network = document.network_interface.document_network().clone();
let view = StorageMetadataView::new(&document.network_interface); let view = StorageMetadataView::new(&document.network_interface);
let target = graph_storage::Registry::convert_from_runtime(&network, &view, &document.resources.registry, peer).expect("from_runtime"); let target = document_graph_storage::Registry::convert_from_runtime(&network, &view, &document.resources.registry, peer).expect("from_runtime");
let stored = storage.registry(); let stored = storage.registry();

View File

@@ -5,9 +5,9 @@
use document_container::AnyContainer; use document_container::AnyContainer;
use document_container::backends::memory::MemoryBackend; use document_container::backends::memory::MemoryBackend;
use document_format::{GddV1, GddV1Layout}; use document_format::{GddV1, GddV1Layout};
use document_graph_storage::PeerId;
use graph_craft::application_io::resource::HashMapResourceStorage; use graph_craft::application_io::resource::HashMapResourceStorage;
use graph_craft::document::{DocumentNodeImplementation, NodeId}; use graph_craft::document::{DocumentNodeImplementation, NodeId};
use graph_storage::PeerId;
use crate::messages::portfolio::document::document_message_handler::DocumentMessageHandler; use crate::messages::portfolio::document::document_message_handler::DocumentMessageHandler;
use crate::messages::portfolio::document::utility_types::network_interface::NodeNetworkInterface; use crate::messages::portfolio::document::utility_types::network_interface::NodeNetworkInterface;
@@ -45,7 +45,7 @@ pub fn node_paths(interface: &NodeNetworkInterface) -> Vec<(Vec<NodeId>, NodeId)
/// storage, the reopened registry, and the reopened per-peer view settings (`ui::doc::*`). /// storage, the reopened registry, and the reopened per-peer view settings (`ui::doc::*`).
pub struct RoundTrip { pub struct RoundTrip {
pub rebuilt: NodeNetworkInterface, pub rebuilt: NodeNetworkInterface,
pub registry: graph_storage::Registry, pub registry: document_graph_storage::Registry,
pub view_settings: std::collections::BTreeMap<String, serde_json::Value>, pub view_settings: std::collections::BTreeMap<String, serde_json::Value>,
} }

View File

@@ -1,4 +1,4 @@
//! Bridge between `NodeNetworkInterface` and `graph-storage`'s `NodeMetadataSource` trait. //! Bridge between `NodeNetworkInterface` and `document-graph-storage`'s `NodeMetadataSource` trait.
//! Conversion round-trip tests live in `storage_metadata_tests`. //! Conversion round-trip tests live in `storage_metadata_tests`.
//! //!
//! The trait impl lives on the [`StorageMetadataView`] wrapper (not on `NodeNetworkInterface` //! The trait impl lives on the [`StorageMetadataView`] wrapper (not on `NodeNetworkInterface`
@@ -7,10 +7,10 @@
use std::collections::{BTreeMap, HashMap}; use std::collections::{BTreeMap, HashMap};
use document_graph_storage::attr::session;
use document_graph_storage::{InputMetadataEntry, NetworkMetadataEntry, NodeMetadataEntry, NodeMetadataSource, Position};
use glam::IVec2; use glam::IVec2;
use graph_craft::document::{DocumentNodeImplementation, NodeId, NodeNetwork}; use graph_craft::document::{DocumentNodeImplementation, NodeId, NodeNetwork};
use graph_storage::attr::session;
use graph_storage::{InputMetadataEntry, NetworkMetadataEntry, NodeMetadataEntry, NodeMetadataSource, Position};
use graphene_std::vector::style::RenderMode; use graphene_std::vector::style::RenderMode;
use super::memo_network::MemoNetwork; use super::memo_network::MemoNetwork;
@@ -41,7 +41,7 @@ pub struct DocumentSettings<'a> {
pub collapsed: &'a CollapsedLayers, pub collapsed: &'a CollapsedLayers,
} }
/// Adapts a `&NodeNetworkInterface` to `graph-storage`'s `NodeMetadataSource` (node/network metadata /// Adapts a `&NodeNetworkInterface` to `document-graph-storage`'s `NodeMetadataSource` (node/network metadata
/// only; document-level view settings live in `session.json`, not the registry). /// only; document-level view settings live in `session.json`, not the registry).
pub struct StorageMetadataView<'a> { pub struct StorageMetadataView<'a> {
interface: &'a NodeNetworkInterface, interface: &'a NodeNetworkInterface,
@@ -183,18 +183,18 @@ pub fn build_interface_from_storage(network: NodeNetwork, node_entries: Vec<Node
/// Build the runtime-`network_path` -> stable-`NetworkId` map from the `NetworkMetadataEntry`s that /// Build the runtime-`network_path` -> stable-`NetworkId` map from the `NetworkMetadataEntry`s that
/// `to_runtime_with_full_metadata` emits, so the open path can apply per-network view settings. /// `to_runtime_with_full_metadata` emits, so the open path can apply per-network view settings.
pub fn network_ids_from_entries(network_entries: &[NetworkMetadataEntry]) -> HashMap<Vec<NodeId>, graph_storage::NetworkId> { pub fn network_ids_from_entries(network_entries: &[NetworkMetadataEntry]) -> HashMap<Vec<NodeId>, document_graph_storage::NetworkId> {
network_entries.iter().map(|entry| (entry.network_path.clone(), entry.network_id)).collect() network_entries.iter().map(|entry| (entry.network_path.clone(), entry.network_id)).collect()
} }
/// Collect the per-network, per-peer view state (node-graph nav + previewing) from `interface` into a /// Collect the per-network, per-peer view state (node-graph nav + previewing) from `interface` into a
/// `session.json` map keyed by the stable storage [`NetworkId`](graph_storage::NetworkId), which /// `session.json` map keyed by the stable storage [`NetworkId`](document_graph_storage::NetworkId), which
/// `network_ids` resolves from each runtime `network_path`. Networks at their default nav with no preview /// `network_ids` resolves from each runtime `network_path`. Networks at their default nav with no preview
/// produce no entry. /// produce no entry.
pub fn collect_network_view_settings( pub fn collect_network_view_settings(
interface: &NodeNetworkInterface, interface: &NodeNetworkInterface,
network_ids: &HashMap<Vec<NodeId>, graph_storage::NetworkId>, network_ids: &HashMap<Vec<NodeId>, document_graph_storage::NetworkId>,
) -> BTreeMap<graph_storage::NetworkId, BTreeMap<String, serde_json::Value>> { ) -> BTreeMap<document_graph_storage::NetworkId, BTreeMap<String, serde_json::Value>> {
let mut out = BTreeMap::new(); let mut out = BTreeMap::new();
for (network_path, &network_id) in network_ids { for (network_path, &network_id) in network_ids {
@@ -240,12 +240,12 @@ pub fn collect_network_view_settings(
/// Apply persisted per-network view state (node-graph nav + previewing) from `session.json` onto /// Apply persisted per-network view state (node-graph nav + previewing) from `session.json` onto
/// `interface`. Inverse of [`collect_network_view_settings`]: `network_ids` resolves each runtime /// `interface`. Inverse of [`collect_network_view_settings`]: `network_ids` resolves each runtime
/// `network_path` to its [`NetworkId`](graph_storage::NetworkId), and the matching inner map is decoded /// `network_path` to its [`NetworkId`](document_graph_storage::NetworkId), and the matching inner map is decoded
/// back onto the network's navigation/previewing metadata. /// back onto the network's navigation/previewing metadata.
pub fn apply_network_view_settings( pub fn apply_network_view_settings(
interface: &mut NodeNetworkInterface, interface: &mut NodeNetworkInterface,
network_ids: &HashMap<Vec<NodeId>, graph_storage::NetworkId>, network_ids: &HashMap<Vec<NodeId>, document_graph_storage::NetworkId>,
network_view_settings: &BTreeMap<graph_storage::NetworkId, BTreeMap<String, serde_json::Value>>, network_view_settings: &BTreeMap<document_graph_storage::NetworkId, BTreeMap<String, serde_json::Value>>,
) { ) {
for (network_path, network_id) in network_ids { for (network_path, network_id) in network_ids {
let Some(settings) = network_view_settings.get(network_id) else { continue }; let Some(settings) = network_view_settings.get(network_id) else { continue };

View File

@@ -48,7 +48,12 @@ async fn build_per_document_container(path: Option<&std::path::Path>) -> Result<
/// Open the existing working copy at `path`, or create a fresh one bound to `peer` (in-memory when /// Open the existing working copy at `path`, or create a fresh one bound to `peer` (in-memory when
/// `path` is `None`). Returns the working copy plus whether it was reopened (vs freshly created); only a /// `path` is `None`). Returns the working copy plus whether it was reopened (vs freshly created); only a
/// reopen has independently-stored state worth comparing against the legacy load. /// reopen has independently-stored state worth comparing against the legacy load.
pub(super) async fn build_or_open_working_copy(path: Option<&std::path::Path>, peer: graph_storage::PeerId, document_uuid: u64, version: String) -> Result<(GddV1, bool), DocumentFormatError> { pub(super) async fn build_or_open_working_copy(
path: Option<&std::path::Path>,
peer: document_graph_storage::PeerId,
document_uuid: u64,
version: String,
) -> Result<(GddV1, bool), DocumentFormatError> {
let (container, exists) = build_per_document_container(path).await?; let (container, exists) = build_per_document_container(path).await?;
let gdd = if exists { let gdd = if exists {

View File

@@ -1896,7 +1896,7 @@ impl PortfolioMessageHandler {
) -> Message { ) -> Message {
let path = working_copy_root.map(|root| root.join(format!("{:016x}", document_id.0))); let path = working_copy_root.map(|root| root.join(format!("{:016x}", document_id.0)));
let editor_version = crate::application::GRAPHITE_GIT_COMMIT_HASH.to_string(); let editor_version = crate::application::GRAPHITE_GIT_COMMIT_HASH.to_string();
let peer = graph_storage::PeerId(generate_uuid()); let peer = document_graph_storage::PeerId(generate_uuid());
let future = async move { let future = async move {
let (gdd, reopened) = match build_or_open_working_copy(path.as_deref(), peer, document_id.0, editor_version).await { let (gdd, reopened) = match build_or_open_working_copy(path.as_deref(), peer, document_id.0, editor_version).await {

View File

@@ -211,7 +211,7 @@ The editor operates on its existing runtime types. Storage is a serialization la
│ to_runtime │ from_runtime │ to_runtime │ from_runtime
│ ▼ │ ▼
┌─────────────────────────────────────────┐ ┌─────────────────────────────────────────┐
│ Storage layer (graph-storage crate) │ Storage layer (document-graph-storage)
│ Registry, RegistryDelta, Document │ │ Registry, RegistryDelta, Document │
└─────────────────────────────────────────┘ └─────────────────────────────────────────┘
@@ -228,7 +228,7 @@ The editor operates on its existing runtime types. Storage is a serialization la
└─────────────────────────────────────────┘ └─────────────────────────────────────────┘
``` ```
The runtime is the source of truth during editing. Conversion runs on save, on load, and across the sync boundary when broadcasting or receiving ops. The editor-facing handle is `Session` (`graph_storage::Session`), and `Document` is internal. `Session::stage_from_runtime(&NodeNetwork, &dyn NodeMetadataSource)` is the entry point: it diffs the stored registry against a fresh conversion, ticks the clock once per emitted op, and applies each as a hot op on the hot log. The `Gdd` handle then persists the hot frames and retires them into durable history. The runtime is the source of truth during editing. Conversion runs on save, on load, and across the sync boundary when broadcasting or receiving ops. The editor-facing handle is `Session` (`document_graph_storage::Session`), and `Document` is internal. `Session::stage_from_runtime(&NodeNetwork, &dyn NodeMetadataSource)` is the entry point: it diffs the stored registry against a fresh conversion, ticks the clock once per emitted op, and applies each as a hot op on the hot log. The `Gdd` handle then persists the hot frames and retires them into durable history.
Staging and retirement are split so that one undo gesture maps to one retired gesture. The editor's undo unit is one legacy transaction boundary, but a single user action (for example, a tool drag) re-commits the runtime many times within one such boundary. So the editor *stages* on every commit (keeping the working registry and autosave current) and *retires the pending hot ops as one gesture* only at the undo-step boundary and before any undo/redo. (`commit_from_runtime`, which stages and retires atomically, remains for one-shot callers.) Solo editing thus flows through the same hot-op-then-retire path that collaboration uses, exercising it before any transport lands. Staging and retirement are split so that one undo gesture maps to one retired gesture. The editor's undo unit is one legacy transaction boundary, but a single user action (for example, a tool drag) re-commits the runtime many times within one such boundary. So the editor *stages* on every commit (keeping the working registry and autosave current) and *retires the pending hot ops as one gesture* only at the undo-step boundary and before any undo/redo. (`commit_from_runtime`, which stages and retires atomically, remains for one-shot callers.) Solo editing thus flows through the same hot-op-then-retire path that collaboration uses, exercising it before any transport lands.
@@ -236,30 +236,30 @@ Staging and retirement are split so that one undo gesture maps to one retired ge
A `.gdd` document is a collection of named byte payloads. A `Container` backend (loose folder, in-memory, OPFS in the browser) provides the path-keyed read/write surface. An `Archive` codec (zip, xz-compressed tarball) optionally encodes a container into a single byte stream for compact distribution. The same logical document can be saved as a loose folder for VCS-friendly checkouts or as an archive for shipping, without any change above the container layer. A `.gdd` document is a collection of named byte payloads. A `Container` backend (loose folder, in-memory, OPFS in the browser) provides the path-keyed read/write surface. An `Archive` codec (zip, xz-compressed tarball) optionally encodes a container into a single byte stream for compact distribution. The same logical document can be saved as a loose folder for VCS-friendly checkouts or as an archive for shipping, without any change above the container layer.
The two concerns live in downstream crates. `document-container` defines the `Container` and `AsyncContainer` traits, the backends, byte ownership (mmap regions, owned buffers, external file mmaps via `mmap-io`), and the `Archive` trait. `document-format` defines the typed `Gdd` handle, the layout (logical-payload-name to in-container path), the data codec (JSON or binary), the manifest, and the save/load orchestration. `graph-storage` itself stays disk-unaware. The two concerns live in downstream crates. `document-container` defines the `Container` and `AsyncContainer` traits, the backends, byte ownership (mmap regions, owned buffers, external file mmaps via `mmap-io`), and the `Archive` trait. `document-format` defines the typed `Gdd` handle, the layout (logical-payload-name to in-container path), the data codec (JSON or binary), the manifest, and the save/load orchestration. `document-graph-storage` itself stays disk-unaware.
``` ```
┌─────────────────────────────────┐ ┌─────────────────────────────────┐
editor editor
└─────────────────────────────────┘ └─────────────────────────────────┘
───────────────┐ ┌──────────────────────────────┐ ┌────────────────────────┐ ┌──────────────────────────────┐
graph-storage │ │ document-format │ │ document-graph-storage │ │ document-format │
│ (disk-unaware)│◀─│ Gdd handle, Layout, codec, │ │ (disk-unaware) │◀─│ Gdd handle, Layout, codec, │
───────────────┘ │ ExportOptions │ └────────────────────────┘ │ ExportOptions │
└──────────────────────────────┘ └──────────────────────────────┘
┌──────────────────────────────┐ ┌──────────────────────────────┐
│ document-container │ │ document-container │
│ Container backends + Archive│ │ Container backends + Archive│
│ codecs (folder, memory, │ │ codecs (folder, memory, │
│ OPFS / zip, xz) │ │ OPFS / zip, xz) │
└──────────────────────────────┘ └──────────────────────────────┘
``` ```
Arrows mean "depends on". The editor uses `Session` from `graph-storage` at runtime and `Gdd` from `document-format` on save/load. `document-format` serializes `graph-storage`'s types and delegates byte I/O to `document-container`. `graph-storage` and `document-container` are independent leaves. Arrows mean "depends on". The editor uses `Session` from `document-graph-storage` at runtime and `Gdd` from `document-format` on save/load. `document-format` serializes `document-graph-storage`'s types and delegates byte I/O to `document-container`. `document-graph-storage` and `document-container` are independent leaves.
A document contains: A document contains:
@@ -290,7 +290,7 @@ The `Gdd` handle owns the loaded bytes and exposes them as zero-copy slices. On
## Resources ## Resources
Everything content-addressable is a resource: raster images, fonts, embedded WASM, **and proto-node declarations**. The storage `Registry` holds `resources: ResourceStore` (references only). The bytes live in a content-addressed byte store keyed by `ResourceHash`, owned by the caller (the app-global cache in the editor, the `Gdd` container for standalone/export) rather than by `graph-storage`. Everything content-addressable is a resource: raster images, fonts, embedded WASM, **and proto-node declarations**. The storage `Registry` holds `resources: ResourceStore` (references only). The bytes live in a content-addressed byte store keyed by `ResourceHash`, owned by the caller (the app-global cache in the editor, the `Gdd` container for standalone/export) rather than by `document-graph-storage`.
```rs ```rs
pub type ResourceStore = HashMap<ResourceId, ResourceEntry>; pub type ResourceStore = HashMap<ResourceId, ResourceEntry>;
@@ -329,7 +329,7 @@ Migrations live in a dedicated crate so they are usable both from the editor and
- Each nested `NodeNetwork`'s `NetworkId` is derived from the owning node's path (blake3 of `(peer, path)` with a `"network"` domain tag), not assigned by a traversal counter. This makes it stable across a `to_runtime` then `from_runtime` round trip. That stability is load-bearing, because node paths (and thus node-ID hashes) include `NetworkId`s, so an unstable network ID would cascade into unstable node IDs and break re-commit after open. Aliasing (multiple nodes referencing the same network) is structurally supported by the storage model, since `Implementation::Network(NetworkId)` is a reference, but the converter does not exploit it yet. Aliasing is fixed at the runtime layer first, and the converter then preserves sharing without an explicit dedup pass. - Each nested `NodeNetwork`'s `NetworkId` is derived from the owning node's path (blake3 of `(peer, path)` with a `"network"` domain tag), not assigned by a traversal counter. This makes it stable across a `to_runtime` then `from_runtime` round trip. That stability is load-bearing, because node paths (and thus node-ID hashes) include `NetworkId`s, so an unstable network ID would cascade into unstable node IDs and break re-commit after open. Aliasing (multiple nodes referencing the same network) is structurally supported by the storage model, since `Implementation::Network(NetworkId)` is a reference, but the converter does not exploit it yet. Aliasing is fixed at the runtime layer first, and the converter then preserves sharing without an explicit dedup pass.
- Non-structural `DocumentNode` fields (`call_argument`, `context_features`, `visible`, `skip_deduplication`, and so on) become entries in the node's `attributes`. UI metadata from `DocumentNodeMetadata` (positions, display names, locked, pinned, and so on) flows through the same bucket under `ui::*` keys. - Non-structural `DocumentNode` fields (`call_argument`, `context_features`, `visible`, `skip_deduplication`, and so on) become entries in the node's `attributes`. UI metadata from `DocumentNodeMetadata` (positions, display names, locked, pinned, and so on) flows through the same bucket under `ui::*` keys.
`to_runtime` is the inverse. It rebuilds local IDs from the stashed attribute, restores typed fields from attribute values, follows `Implementation::Network` references to recursively materialize nested networks, and resolves `Implementation::ProtoNode(ResourceId)` against a `Declarations` map (`ResourceId` to `ProtoNode`) the caller supplies from its byte store. Since `graph-storage` is byte-unaware, `to_runtime` takes the resolved declarations as a parameter rather than reaching for bytes itself. `to_runtime` is the inverse. It rebuilds local IDs from the stashed attribute, restores typed fields from attribute values, follows `Implementation::Network` references to recursively materialize nested networks, and resolves `Implementation::ProtoNode(ResourceId)` against a `Declarations` map (`ResourceId` to `ProtoNode`) the caller supplies from its byte store. Since `document-graph-storage` is byte-unaware, `to_runtime` takes the resolved declarations as a parameter rather than reaching for bytes itself.
## Slots: inputs and exports ## Slots: inputs and exports