diff --git a/Cargo.lock b/Cargo.lock index 62fd160..0385644 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -195,7 +195,7 @@ source = "git+https://github.com/stack-sh/compiler.git?rev=4a18fac42afc2256a1bb3 [[package]] name = "stack-engine" -version = "0.4.0" +version = "0.5.0" dependencies = [ "roxmltree", "serde", @@ -208,7 +208,7 @@ dependencies = [ [[package]] name = "stack-engine-wasm" -version = "0.4.0" +version = "0.5.0" dependencies = [ "js-sys", "serde", @@ -228,8 +228,8 @@ dependencies = [ [[package]] name = "stack-theme" -version = "0.3.0" -source = "git+https://github.com/stack-sh/theme.git?rev=5dbe41326370260cfc6b72d4aab4470318d66dab#5dbe41326370260cfc6b72d4aab4470318d66dab" +version = "0.4.0" +source = "git+https://github.com/stack-sh/theme.git?rev=2347315e6e86ab9d2708e05fd3f9b5f3d87e1241#2347315e6e86ab9d2708e05fd3f9b5f3d87e1241" dependencies = [ "serde", "serde_json", diff --git a/Cargo.toml b/Cargo.toml index ddc55bf..d3b1e96 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,4 +15,4 @@ serde_json = "=1.0.151" sha2 = "=0.11.0" stack-compiler = { git = "https://github.com/stack-sh/compiler.git", rev = "4a18fac42afc2256a1bb3a6ff13d12d732a391e7" } stack-formatter = { path = "crates/stack-formatter" } -stack-theme = { git = "https://github.com/stack-sh/theme.git", rev = "5dbe41326370260cfc6b72d4aab4470318d66dab" } +stack-theme = { git = "https://github.com/stack-sh/theme.git", rev = "2347315e6e86ab9d2708e05fd3f9b5f3d87e1241" } diff --git a/README.md b/README.md index 50a9015..6a32457 100644 --- a/README.md +++ b/README.md @@ -45,7 +45,7 @@ cargo doc --workspace --no-deps `stack-engine` exposes byte-oriented `format`, `check`, and `render` methods through an engine bound to the embedded or a caller-provided validated catalog. `ProviderPack::new` accepts a typed user-imported manifest and caller-owned SVG strings, verifies exact asset hashes and safe SVG structure, and computes a deterministic content revision before `Engine::with_provider_packs` can resolve namespaced IDs. Every normal output carries engine, authored language, theme catalog version, and theme catalog revision metadata. User-source failures stay in ordered portable diagnostics. Invalid provided catalogs or provider packs and violated normalized pipeline invariants use a separate operational-error channel. Checks and renders resolve the requested theme and provider packs, validate deterministic integer geometry, and route ordered edges outside node interiors. Missing themes and icons produce source-mapped `STK6001` and `STK5001` warnings while a fallback SVG remains available. An unsatisfied authored order hint produces `STK4001` at its source-map range; a satisfied hint does not. -The renderer emits fixed-dimension standalone SVG with embedded catalog or provider icons, local marker references, escaped authored text, accessible title and description metadata, and no script, event handler, external URL, host font measurement, or runtime I/O. Provider artwork preserves the authored node `kind`; each render returns the exact used-asset notices and writes provider ID, icon IDs, and pack revision into SVG metadata. The bundled catalog provides the first-party explicit icon identifiers `api`, `web`, `mobile`, `desktop`, `server`, `container`, `cluster`, `cloud`, `scheduler`, `webhook`, `identity`, and `observability` in every core theme. Canonical SVG snapshots are byte-stable and parsed by `scripts/validate-svg.py`; set `UPDATE_STACK_SNAPSHOTS=1` only when intentionally regenerating them. CI also executes one exact numeric geometry fixture in both the native suite and a WASI build. +The renderer emits fixed-dimension standalone SVG with embedded catalog or provider icons, local marker references, escaped authored text, accessible title and description metadata, and no script, event handler, external URL, host font measurement, or runtime I/O. Provider artwork preserves the authored node `kind`; each render returns the exact used-asset notices and writes provider ID, icon IDs, and pack revision into SVG metadata. The bundled catalog provides 30 first-party explicit icon identifiers in every core theme: `api`, `web`, `mobile`, `desktop`, `server`, `container`, `cluster`, `cloud`, `scheduler`, `webhook`, `identity`, `observability`, `gateway`, `load-balancer`, `dns`, `cdn`, `firewall`, `network`, `event`, `stream`, `search`, `analytics`, `repository`, `pipeline`, `secret`, `document`, `task`, `chat`, `email`, and `ai`. Canonical SVG snapshots are byte-stable and parsed by `scripts/validate-svg.py`; set `UPDATE_STACK_SNAPSHOTS=1` only when intentionally regenerating them. CI also executes one exact numeric geometry fixture in both the native suite and a WASI build. The npm package exports synchronous `format`, `check`, `render`, `checkWithProviderPacks`, and `renderWithProviderPacks` functions after asynchronous module initialization. Provider-pack operations accept JSON-compatible local manifest and SVG data; they never discover a path or initiate a request. Each operation accepts `string | Uint8Array` source and returns a specific typed result with camel-case metadata and portable diagnostics. Diagnostics preserve the compiler's primary range, ordered `expected` values, corrective help, and related source locations. Invalid UTF-8 remains a normal `STK1001` result. Unsupported JavaScript input types and internal operational failures throw at the adapter boundary. Shared fixtures exercise native and WebAssembly provider resolution. Artifact validation audits WebAssembly imports and package contents; browser consumers retain responsibility for loading the module and performing any DOM, filesystem, network, or clock work. diff --git a/THIRD_PARTY_LICENSES.md b/THIRD_PARTY_LICENSES.md index 8831ff6..f907e24 100644 --- a/THIRD_PARTY_LICENSES.md +++ b/THIRD_PARTY_LICENSES.md @@ -5,7 +5,7 @@ | Component | Revision | License | Source | Notes | | --- | --- | --- | --- | --- | | `stack-compiler` | `4a18fac42afc2256a1bb3a6ff13d12d732a391e7` | Apache-2.0 | | Unmodified Rust dependency; its license and notice obligations apply to distributions that include it. | -| `stack-theme` | `5dbe41326370260cfc6b72d4aab4470318d66dab` | Apache-2.0 | | Unmodified Rust dependency with repository-authored core assets and the asset-free provider-pack contract. | +| `stack-theme` | `2347315e6e86ab9d2708e05fd3f9b5f3d87e1241` | Apache-2.0 | | Unmodified Rust dependency with repository-authored core assets and the asset-free provider-pack contract. | | `roxmltree` | `0.21.1` | MIT OR Apache-2.0 | | Parses caller-owned processed provider SVG before allowlisted in-memory embedding. | | `sha2`, `digest`, `block-buffer`, `crypto-common`, `hybrid-array`, `const-oid`, `typenum` | `0.11.0`, `0.11.3`, `0.12.1`, `0.2.2`, `0.4.14`, `0.10.2`, `1.20.1` | MIT OR Apache-2.0 | | Verifies provider asset hashes and computes deterministic provider-pack revisions. | | `libc` / `cpufeatures` | `0.2.189`, `0.3.1` | MIT OR Apache-2.0 | , | Target-specific SHA-256 acceleration support. | @@ -35,6 +35,6 @@ | `wasm-bindgen-cli` | `0.2.127` | MIT OR Apache-2.0 | | Version-matched build tool; not shipped in the npm package. | | `typescript` | `7.0.2` | Apache-2.0 | | Type-check tool; not shipped in the npm package. | -No third-party visual asset is bundled in a Stack Engine distribution. The bundled fallback and 12 explicit icons are Stack-authored Apache-2.0 assets from `stack-theme`. The npm package includes this inventory and the Apache-2.0, MIT, and Unicode-3.0 license texts required by its compiled dependency choices. +No third-party visual asset is bundled in a Stack Engine distribution. The bundled fallback and 30 explicit icons are Stack-authored Apache-2.0 assets from `stack-theme`. The npm package includes this inventory and the Apache-2.0, MIT, and Unicode-3.0 license texts required by its compiled dependency choices. Before publishing a native library, binary-derived artifact, or WASM package, this inventory must list the shipped dependencies and assets, their pinned versions, exact licenses, required license texts, attribution, modifications, and redistribution conditions. Build-only dependencies that are not shipped should be distinguished from distributed code. diff --git a/crates/stack-engine-wasm/Cargo.toml b/crates/stack-engine-wasm/Cargo.toml index 4b29a64..3aec4b3 100644 --- a/crates/stack-engine-wasm/Cargo.toml +++ b/crates/stack-engine-wasm/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "stack-engine-wasm" -version = "0.4.0" +version = "0.5.0" edition.workspace = true rust-version.workspace = true license.workspace = true diff --git a/crates/stack-engine/Cargo.toml b/crates/stack-engine/Cargo.toml index 26eaa83..424cc0b 100644 --- a/crates/stack-engine/Cargo.toml +++ b/crates/stack-engine/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "stack-engine" -version = "0.4.0" +version = "0.5.0" edition.workspace = true rust-version.workspace = true license.workspace = true diff --git a/crates/stack-engine/src/lib.rs b/crates/stack-engine/src/lib.rs index cf71961..7c625e0 100644 --- a/crates/stack-engine/src/lib.rs +++ b/crates/stack-engine/src/lib.rs @@ -614,7 +614,7 @@ mod tests { output.metadata.language_version, Some(LanguageVersion { major: 1, minor: 0 }) ); - assert_eq!(output.metadata.theme_catalog_version, "0.3.0"); + assert_eq!(output.metadata.theme_catalog_version, "0.4.0"); assert_eq!( output.metadata.theme_catalog_revision, stack_theme::CATALOG_REVISION @@ -638,12 +638,30 @@ mod tests { ("webhook", "Webhook endpoint"), ("identity", "Identity and access"), ("observability", "Observability system"), + ("gateway", "Network gateway"), + ("load-balancer", "Load balancer"), + ("dns", "Domain name service"), + ("cdn", "Content delivery network"), + ("firewall", "Network firewall"), + ("network", "Network topology"), + ("event", "Discrete event"), + ("stream", "Event stream"), + ("search", "Search service"), + ("analytics", "Analytics system"), + ("repository", "Source code repository"), + ("pipeline", "Delivery pipeline"), + ("secret", "Secret or credential"), + ("document", "Document or knowledge base"), + ("task", "Task or issue tracker"), + ("chat", "Chat or messaging tool"), + ("email", "Email delivery"), + ("ai", "Artificial intelligence system"), ]; let catalog = stack_theme::catalog(); - assert_eq!(catalog.catalog_version, "0.3.0"); + assert_eq!(catalog.catalog_version, "0.4.0"); assert_eq!( stack_theme::CATALOG_REVISION, - "sha256:e4eaad0813fcfef4a203e861909ff38833270646f9097155974c7c92108c5b1e" + "sha256:9cb3de8b504acbf22c93cea5fbea66be50f38734dc1dee18b9cab7084082cc1f" ); for theme in &catalog.themes { for (identifier, subject) in expected_icons { @@ -657,18 +675,18 @@ mod tests { } } - let source = b"stack 1.0 diagram \"Core icon\" { theme dark node gateway \"Gateway\" { kind service detail \"Public API\" icon \"api\" } }"; + let source = b"stack 1.0 diagram \"Core icon\" { theme dark node gateway \"Gateway\" { kind service detail \"Public API\" icon \"gateway\" } }"; let checked = Engine::bundled().check(source)?; let rendered = Engine::bundled().render(source)?; assert!(checked.diagnostics.is_empty()); assert!(rendered.diagnostics.is_empty()); - assert_eq!(rendered.metadata.theme_catalog_version, "0.3.0"); + assert_eq!(rendered.metadata.theme_catalog_version, "0.4.0"); assert_eq!( rendered.metadata.theme_catalog_revision, stack_theme::CATALOG_REVISION ); let svg = rendered.svg.ok_or("explicit icon render produced no SVG")?; - assert!(svg.contains("data-icon-id=\"api\"")); + assert!(svg.contains("data-icon-id=\"gateway\"")); assert!(!svg.contains("data-icon-id=\"kind-external\"")); Ok(()) } diff --git a/crates/stack-engine/tests/fixtures/explicit-core-icon.stack b/crates/stack-engine/tests/fixtures/explicit-core-icon.stack index 4eb9c9e..188aaaf 100644 --- a/crates/stack-engine/tests/fixtures/explicit-core-icon.stack +++ b/crates/stack-engine/tests/fixtures/explicit-core-icon.stack @@ -6,6 +6,6 @@ diagram "Core icon" { node gateway "Gateway" { kind service detail "Public API" - icon "api" + icon "gateway" } } diff --git a/crates/stack-engine/tests/render_snapshots.rs b/crates/stack-engine/tests/render_snapshots.rs index 648fc7b..d4973fa 100644 --- a/crates/stack-engine/tests/render_snapshots.rs +++ b/crates/stack-engine/tests/render_snapshots.rs @@ -53,13 +53,13 @@ fn explicit_core_icon_matches_standalone_svg_snapshot() -> Result<(), Box - + Complete semantics Architecture diagram with 10 nodes, 3 groups, and 8 relationships. - stack-engine 0.4.0; language 1.0; theme 0.3.0 at sha256:e4eaad0813fcfef4a203e861909ff38833270646f9097155974c7c92108c5b1e + stack-engine 0.5.0; language 1.0; theme 0.4.0 at sha256:9cb3de8b504acbf22c93cea5fbea66be50f38734dc1dee18b9cab7084082cc1f diff --git a/crates/stack-engine/tests/snapshots/render/default-normalization.svg b/crates/stack-engine/tests/snapshots/render/default-normalization.svg index bb1fd5b..c8d7383 100644 --- a/crates/stack-engine/tests/snapshots/render/default-normalization.svg +++ b/crates/stack-engine/tests/snapshots/render/default-normalization.svg @@ -1,8 +1,8 @@ - + Default normalization Architecture diagram with 2 nodes, 0 groups, and 1 relationship. - stack-engine 0.4.0; language 1.0; theme 0.3.0 at sha256:e4eaad0813fcfef4a203e861909ff38833270646f9097155974c7c92108c5b1e + stack-engine 0.5.0; language 1.0; theme 0.4.0 at sha256:9cb3de8b504acbf22c93cea5fbea66be50f38734dc1dee18b9cab7084082cc1f diff --git a/crates/stack-engine/tests/snapshots/render/explicit-core-icon.svg b/crates/stack-engine/tests/snapshots/render/explicit-core-icon.svg index a3b67f6..c817a2c 100644 --- a/crates/stack-engine/tests/snapshots/render/explicit-core-icon.svg +++ b/crates/stack-engine/tests/snapshots/render/explicit-core-icon.svg @@ -1,8 +1,8 @@ - + Core icon Architecture diagram with 1 node, 0 groups, and 0 relationships. - stack-engine 0.4.0; language 1.0; theme 0.3.0 at sha256:e4eaad0813fcfef4a203e861909ff38833270646f9097155974c7c92108c5b1e + stack-engine 0.5.0; language 1.0; theme 0.4.0 at sha256:9cb3de8b504acbf22c93cea5fbea66be50f38734dc1dee18b9cab7084082cc1f @@ -18,7 +18,8 @@ Gateway: Public API - + Gateway Public API diff --git a/docs/dependency-audit.md b/docs/dependency-audit.md index 709b78a..12ba520 100644 --- a/docs/dependency-audit.md +++ b/docs/dependency-audit.md @@ -8,7 +8,7 @@ Audit date: 2026-09-04 - `stack-compiler` at `4a18fac42afc2256a1bb3a6ff13d12d732a391e7` for byte decoding, parsing, validation, normalized IR, source maps, and compiler diagnostics; - the workspace-local `stack-formatter` for canonical source output; -- `stack-theme` at `5dbe41326370260cfc6b72d4aab4470318d66dab` for the `0.3.0` embedded core catalog, 12 provider-neutral explicit icons, the local-only provider-pack contract, SVG bytes, deterministic font metrics, catalog version, and catalog revision; +- `stack-theme` at `2347315e6e86ab9d2708e05fd3f9b5f3d87e1241` for the `0.4.0` embedded core catalog, 30 provider-neutral explicit icons, the local-only provider-pack contract, SVG bytes, deterministic font metrics, catalog version, and catalog revision; - `roxmltree`, `serde_json`, and `sha2` for pure in-memory provider manifest serialization, processed-asset hash verification, pack revision computation, and defensive SVG validation. Vendor asset bytes are not included. `stack-engine-wasm` adds `serde`, `serde_json`, and the asset-free `stack-theme` types for its serializable native parity model and local provider-pack input, plus, only on `wasm32`, version-matched `wasm-bindgen` and `js-sys` for the JavaScript ABI, typed-array input, JSON-compatible local data, and plain object construction. It does not use `web-sys` or a WASI target. diff --git a/package-lock.json b/package-lock.json index 92a739a..329c72b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "stack-engine-workspace", - "version": "0.4.0", + "version": "0.5.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "stack-engine-workspace", - "version": "0.4.0", + "version": "0.5.0", "workspaces": [ "packages/engine" ], @@ -395,7 +395,7 @@ }, "packages/engine": { "name": "@stack-sh/engine", - "version": "0.4.0", + "version": "0.5.0", "license": "Apache-2.0" } } diff --git a/package.json b/package.json index 432c2f8..f08c0f5 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "stack-engine-workspace", "private": true, - "version": "0.4.0", + "version": "0.5.0", "workspaces": [ "packages/engine" ], diff --git a/packages/engine/README.md b/packages/engine/README.md index d72a816..de56fe6 100644 --- a/packages/engine/README.md +++ b/packages/engine/README.md @@ -18,4 +18,4 @@ Each operation is synchronous after module initialization and accepts either a J The package does not read files, contact a network service, inspect the DOM, observe a clock, or measure host fonts. Consumers own module loading and all host I/O. -The bundled catalog resolves `api`, `web`, `mobile`, `desktop`, `server`, `container`, `cluster`, `cloud`, `scheduler`, `webhook`, `identity`, and `observability` as first-party explicit icons in the `default`, `light`, and `dark` themes. Missing authored icon identifiers still produce `STK5001` and render the theme's fallback icon. +The bundled catalog resolves 30 first-party explicit icons in the `default`, `light`, and `dark` themes: `api`, `web`, `mobile`, `desktop`, `server`, `container`, `cluster`, `cloud`, `scheduler`, `webhook`, `identity`, `observability`, `gateway`, `load-balancer`, `dns`, `cdn`, `firewall`, `network`, `event`, `stream`, `search`, `analytics`, `repository`, `pipeline`, `secret`, `document`, `task`, `chat`, `email`, and `ai`. Missing authored icon identifiers still produce `STK5001` and render the theme's fallback icon. diff --git a/packages/engine/THIRD_PARTY_LICENSES.md b/packages/engine/THIRD_PARTY_LICENSES.md index 640f104..8c73a28 100644 --- a/packages/engine/THIRD_PARTY_LICENSES.md +++ b/packages/engine/THIRD_PARTY_LICENSES.md @@ -5,7 +5,7 @@ | Component | Version / revision | Selected license | Source | | --- | --- | --- | --- | | `stack-compiler` | `4a18fac42afc2256a1bb3a6ff13d12d732a391e7` | Apache-2.0 | | -| `stack-theme` | `5dbe41326370260cfc6b72d4aab4470318d66dab` | Apache-2.0 | | +| `stack-theme` | `2347315e6e86ab9d2708e05fd3f9b5f3d87e1241` | Apache-2.0 | | | `roxmltree` | `0.21.1` | Apache-2.0 | | | `sha2`, `digest`, `block-buffer`, `crypto-common`, `hybrid-array`, `const-oid`, `typenum` | `0.11.0`, `0.11.3`, `0.12.1`, `0.2.2`, `0.4.14`, `0.10.2`, `1.20.1` | Apache-2.0 | | | `libc` / `cpufeatures` | `0.2.189`, `0.3.1` | Apache-2.0 | , | diff --git a/packages/engine/package.json b/packages/engine/package.json index 04d1ff8..24ff5ef 100644 --- a/packages/engine/package.json +++ b/packages/engine/package.json @@ -1,6 +1,6 @@ { "name": "@stack-sh/engine", - "version": "0.4.0", + "version": "0.5.0", "description": "Browser WebAssembly adapter for Stack diagram operations", "type": "module", "license": "Apache-2.0", diff --git a/scripts/validate-svg.py b/scripts/validate-svg.py index b19c230..ab0528a 100644 --- a/scripts/validate-svg.py +++ b/scripts/validate-svg.py @@ -87,11 +87,11 @@ def main() -> None: "bidirectional", "association", } - assert values(explicit_icon, "data-icon-id") == {"api"} - assert explicit_icon.attrib.get("data-theme-version") == "0.3.0" + assert values(explicit_icon, "data-icon-id") == {"gateway"} + assert explicit_icon.attrib.get("data-theme-version") == "0.4.0" assert ( explicit_icon.attrib.get("data-theme-revision") - == "sha256:e4eaad0813fcfef4a203e861909ff38833270646f9097155974c7c92108c5b1e" + == "sha256:9cb3de8b504acbf22c93cea5fbea66be50f38734dc1dee18b9cab7084082cc1f" ) diff --git a/tests/fixtures/operation-cases.json b/tests/fixtures/operation-cases.json index 887a0d2..3ce7a90 100644 --- a/tests/fixtures/operation-cases.json +++ b/tests/fixtures/operation-cases.json @@ -17,7 +17,7 @@ "name": "explicit-core-icon-string", "input": { "kind": "string", - "value": "stack 1.0\ndiagram \"Core icon\" {\n theme dark\n node gateway \"Gateway\" {\n kind service\n detail \"Public API\"\n icon \"api\"\n }\n}\n" + "value": "stack 1.0\ndiagram \"Core icon\" {\n theme dark\n node gateway \"Gateway\" {\n kind service\n detail \"Public API\"\n icon \"gateway\"\n }\n}\n" } }, { diff --git a/tests/wasm.test.mjs b/tests/wasm.test.mjs index 5201307..7799ee5 100644 --- a/tests/wasm.test.mjs +++ b/tests/wasm.test.mjs @@ -81,7 +81,7 @@ test("browser diagnostics preserve actionable compiler guidance", () => { ); assert.ok(actionable); assert.equal(actionable.render.svg, null); - assert.equal(actionable.check.metadata.engineVersion, "0.4.0"); + assert.equal(actionable.check.metadata.engineVersion, "0.5.0"); assert.deepEqual(actionable.check.diagnostics[0], { code: "STK2002", severity: "error", @@ -103,13 +103,13 @@ test("browser rendering resolves the bundled explicit core icon", () => { assert.ok(explicitIcon); assert.deepEqual(explicitIcon.check.diagnostics, []); assert.deepEqual(explicitIcon.render.diagnostics, []); - assert.equal(explicitIcon.render.metadata.engineVersion, "0.4.0"); - assert.equal(explicitIcon.render.metadata.themeCatalogVersion, "0.3.0"); + assert.equal(explicitIcon.render.metadata.engineVersion, "0.5.0"); + assert.equal(explicitIcon.render.metadata.themeCatalogVersion, "0.4.0"); assert.equal( explicitIcon.render.metadata.themeCatalogRevision, - "sha256:e4eaad0813fcfef4a203e861909ff38833270646f9097155974c7c92108c5b1e", + "sha256:9cb3de8b504acbf22c93cea5fbea66be50f38734dc1dee18b9cab7084082cc1f", ); - assert.match(explicitIcon.render.svg, /data-icon-id="api"/); + assert.match(explicitIcon.render.svg, /data-icon-id="gateway"/); assert.doesNotMatch(explicitIcon.render.svg, /data-icon-id="kind-external"/); });