From afea78b7fcff3558117e910379f97a2f7bf0c056 Mon Sep 17 00:00:00 2001 From: Scott Andrews Date: Fri, 13 Nov 2026 02:52:39 +0000 Subject: [PATCH] Lots of navigation and layout refinements Dropping /repos as it's now redundant with the namespace pages. Signed-off-by: Scott Andrews --- README.md | 16 +- .../cli-stderr-to-stdout/0.1.0/metadata.json | 1 + .../cli-stderr-to-stdout/0.1.1/metadata.json | 1 + .../cli-stderr-to-stdout/0.2.0/metadata.json | 1 + .../0.2.1-dev/metadata.json | 20 +- .../cli-stdout-to-stderr/0.1.0/metadata.json | 1 + .../cli-stdout-to-stderr/0.1.1/metadata.json | 1 + .../cli-stdout-to-stderr/0.2.0/metadata.json | 1 + .../0.2.1-dev/metadata.json | 20 +- index/componentized/cli/0.2.0/metadata.json | 1 + .../componentized/cli/0.2.1-dev/metadata.json | 10 +- .../0.1.0/metadata.json | 1 + .../component-http-loader/0.1.0/metadata.json | 1 + .../component-oci-loader/0.1.0/metadata.json | 1 + .../0.1.0/metadata.json | 1 + .../component-path-loader/0.1.0/metadata.json | 1 + .../component-wac-loader/0.1.0/metadata.json | 1 + .../component-wit-tools/0.1.0/metadata.json | 1 + .../component/0.1.0/metadata.json | 1 + .../config-defaults/0.1.0/metadata.json | 1 + .../config-defaults/0.2.0/metadata.json | 1 + .../config-defaults/0.2.1/metadata.json | 1 + .../config-empty/0.1.0/metadata.json | 1 + .../config-empty/0.2.0/metadata.json | 1 + .../config-empty/0.2.1/metadata.json | 1 + .../0.1.0/metadata.json | 1 + .../0.2.0/metadata.json | 1 + .../0.2.1/metadata.json | 1 + .../config-overlay/0.1.0/metadata.json | 1 + .../config-overlay/0.2.0/metadata.json | 1 + .../config-overlay/0.2.1/metadata.json | 1 + .../config-remap/0.1.0/metadata.json | 1 + .../config-remap/0.2.0/metadata.json | 1 + .../config-remap/0.2.1/metadata.json | 1 + .../config-scope/0.1.0/metadata.json | 1 + .../config-scope/0.2.0/metadata.json | 1 + .../config-scope/0.2.1/metadata.json | 1 + .../constants-atomics/0.2.0/metadata.json | 1 + .../constants-config/0.1.0/metadata.json | 1 + .../constants-config/0.1.1/metadata.json | 1 + .../constants-config/0.2.0/metadata.json | 1 + .../constants-factory/0.1.0/metadata.json | 1 + .../constants-factory/0.1.1/metadata.json | 1 + .../constants-factory/0.2.0/metadata.json | 1 + .../constants-math/0.1.0/metadata.json | 1 + .../constants-math/0.1.1/metadata.json | 1 + .../constants-math/0.2.0/metadata.json | 1 + .../constants-random/0.2.0/metadata.json | 1 + .../constants-types/0.1.0/metadata.json | 1 + .../constants-types/0.1.1/metadata.json | 1 + .../constants-types/0.2.0/metadata.json | 1 + .../constants/0.1.0/metadata.json | 1 + .../constants/0.1.1/metadata.json | 1 + .../constants/0.2.0/metadata.json | 1 + .../filesystem-chroot/0.1.0/metadata.json | 1 + .../filesystem-chroot/0.2.0/metadata.json | 1 + .../filesystem-chroot/0.2.1/metadata.json | 1 + .../http-client/0.1.0/metadata.json | 1 + .../http-gate-client/0.1.0/metadata.json | 1 + .../http-gate-handler/0.1.0/metadata.json | 1 + .../http-gate/0.1.0/metadata.json | 1 + .../http-latch-defer-all/0.1.0/metadata.json | 1 + .../0.1.0/metadata.json | 1 + .../0.1.0/metadata.json | 1 + .../http-latch-deny-all/0.1.0/metadata.json | 1 + .../0.1.0/metadata.json | 1 + .../http-latch-dry-run/0.1.0/metadata.json | 1 + .../0.1.0/metadata.json | 1 + .../0.1.0/metadata.json | 1 + .../http-latch-method/0.1.0/metadata.json | 1 + .../http-latch-n2/0.1.0/metadata.json | 1 + .../http-latch-n3/0.1.0/metadata.json | 1 + .../http-latch-n4/0.1.0/metadata.json | 1 + .../http-latch-n5/0.1.0/metadata.json | 1 + .../0.1.0/metadata.json | 1 + .../0.1.0/metadata.json | 1 + .../http-latch-scheme/0.1.0/metadata.json | 1 + .../http-latch-trace/0.1.0/metadata.json | 1 + .../http-status-codes/0.1.0/metadata.json | 1 + .../http-trace-client/0.1.0/metadata.json | 1 + .../0.1.0/metadata.json | 1 + .../http-trace-handler/0.1.0/metadata.json | 1 + .../http-trace-types/0.1.0/metadata.json | 1 + .../http-trace/0.1.0/metadata.json | 1 + index/componentized/http/0.1.0/metadata.json | 1 + .../logging-levels/0.1.0/metadata.json | 1 + .../logging-levels/0.2.0/metadata.json | 1 + .../logging-levels/0.2.1/metadata.json | 1 + .../logging-levels/0.3.0/metadata.json | 1 + .../logging-levels/0.3.1/metadata.json | 1 + .../logging-to-stderr/0.3.1/metadata.json | 1 + .../logging-to-stdout/0.1.0/metadata.json | 1 + .../logging-to-stdout/0.2.0/metadata.json | 1 + .../logging-to-stdout/0.2.1/metadata.json | 1 + .../logging-to-stdout/0.3.0/metadata.json | 1 + .../logging-to-stdout/0.3.1/metadata.json | 1 + .../componentized/logging/0.3.0/metadata.json | 1 + .../componentized/logging/0.3.1/metadata.json | 1 + .../oci-client/0.1.0/metadata.json | 1 + .../oci-media-types/0.1.0/metadata.json | 1 + index/componentized/oci/0.1.0/metadata.json | 1 + .../0.0.4/metadata.json | 1 + .../0.0.4/metadata.json | 1 + .../0.0.4/metadata.json | 1 + .../0.0.4/metadata.json | 1 + .../0.0.4/metadata.json | 1 + .../0.0.4/metadata.json | 1 + .../0.0.4/metadata.json | 1 + .../0.0.4/metadata.json | 1 + .../0.0.4/metadata.json | 1 + .../0.0.4/metadata.json | 1 + .../0.0.4/metadata.json | 1 + .../services/0.0.4/metadata.json | 1 + .../0.1.0/metadata.json | 1 + .../sockets-gate-types/0.1.0/metadata.json | 1 + .../sockets-gate/0.1.0/metadata.json | 1 + .../0.1.0/metadata.json | 1 + .../0.1.0/metadata.json | 1 + .../0.1.0/metadata.json | 1 + .../sockets-latch-cidr/0.1.0/metadata.json | 1 + .../0.1.0/metadata.json | 1 + .../0.1.0/metadata.json | 1 + .../0.1.0/metadata.json | 1 + .../0.1.0/metadata.json | 1 + .../0.1.0/metadata.json | 1 + .../0.1.0/metadata.json | 1 + .../0.1.0/metadata.json | 1 + .../0.1.0/metadata.json | 1 + .../0.1.0/metadata.json | 1 + .../0.1.0/metadata.json | 1 + .../0.1.0/metadata.json | 1 + .../0.1.0/metadata.json | 1 + .../0.1.0/metadata.json | 1 + .../0.1.0/metadata.json | 1 + .../0.1.0/metadata.json | 1 + .../sockets-latch-dry-run/0.1.0/metadata.json | 1 + .../0.1.0/metadata.json | 1 + .../sockets-latch-n2/0.1.0/metadata.json | 1 + .../sockets-latch-n3/0.1.0/metadata.json | 1 + .../sockets-latch-n4/0.1.0/metadata.json | 1 + .../sockets-latch-n5/0.1.0/metadata.json | 1 + .../sockets-latch-trace/0.1.0/metadata.json | 1 + .../0.1.0/metadata.json | 1 + .../sockets-trace-types/0.1.0/metadata.json | 1 + .../sockets-trace/0.1.0/metadata.json | 1 + .../componentized/sockets/0.1.0/metadata.json | 1 + .../static-config-factory/0.1.0/metadata.json | 1 + .../static-config-factory/0.2.0/metadata.json | 1 + .../static-config-factory/0.3.0/metadata.json | 1 + .../static-config/0.3.0/metadata.json | 1 + .../valkey-as-keyvalue/0.1.0/metadata.json | 1 + .../valkey-as-keyvalue/0.1.1/metadata.json | 1 + .../valkey-as-keyvalue/0.2.0/metadata.json | 1 + .../valkey-as-keyvalue/0.2.1/metadata.json | 1 + .../valkey-as-keyvalue/0.2.2/metadata.json | 1 + .../valkey-cli/0.1.0/metadata.json | 1 + .../valkey-cli/0.1.1/metadata.json | 1 + .../valkey-cli/0.2.0/metadata.json | 1 + .../valkey-cli/0.2.1/metadata.json | 1 + .../valkey-cli/0.2.2/metadata.json | 1 + .../valkey-client/0.1.0/metadata.json | 1 + .../valkey-client/0.1.1/metadata.json | 1 + .../valkey-client/0.2.0/metadata.json | 1 + .../valkey-client/0.2.1/metadata.json | 1 + .../valkey-client/0.2.2/metadata.json | 1 + .../0.1.1/metadata.json | 1 + .../0.2.0/metadata.json | 1 + .../0.2.1/metadata.json | 1 + .../0.2.2/metadata.json | 1 + .../componentized/valkey/0.1.0/metadata.json | 1 + .../componentized/valkey/0.1.1/metadata.json | 1 + .../componentized/valkey/0.2.0/metadata.json | 1 + .../componentized/valkey/0.2.1/metadata.json | 1 + .../componentized/valkey/0.2.2/metadata.json | 1 + index/wasi/cli/0.2.12/metadata.json | 1 + index/wasi/cli/0.2.3/metadata.json | 1 + index/wasi/cli/0.2.6/metadata.json | 1 + index/wasi/cli/0.3.0/metadata.json | 1 + index/wasi/clocks/0.2.12/metadata.json | 1 + index/wasi/clocks/0.2.3/metadata.json | 1 + index/wasi/clocks/0.2.6/metadata.json | 1 + index/wasi/clocks/0.3.0/metadata.json | 1 + index/wasi/filesystem/0.2.12/metadata.json | 1 + index/wasi/filesystem/0.2.3/metadata.json | 1 + index/wasi/filesystem/0.2.6/metadata.json | 1 + index/wasi/filesystem/0.3.0/metadata.json | 1 + index/wasi/http/0.2.3/metadata.json | 1 + index/wasi/http/0.2.6/metadata.json | 1 + index/wasi/http/0.3.0/metadata.json | 1 + index/wasi/io/0.2.12/metadata.json | 1 + index/wasi/io/0.2.3/metadata.json | 1 + index/wasi/io/0.2.6/metadata.json | 1 + index/wasi/random/0.2.12/metadata.json | 1 + index/wasi/random/0.2.3/metadata.json | 1 + index/wasi/random/0.2.6/metadata.json | 1 + index/wasi/random/0.3.0/metadata.json | 1 + index/wasi/sockets/0.2.12/metadata.json | 1 + index/wasi/sockets/0.2.3/metadata.json | 1 + index/wasi/sockets/0.2.6/metadata.json | 1 + index/wasi/sockets/0.3.0/metadata.json | 1 + .../everything/0.1.0/metadata.json | 29 + .../kitchen-sink/everything/0.1.0/world.wit | 16 + .../everything/0.2.0-dev/metadata.json | 29 + .../everything/0.2.0-dev/world.wit | 16 + .../kitchen-sink/extras/0.1.0/metadata.json | 25 + samples/kitchen-sink/extras/0.1.0/package.wit | 23 + .../kitchen-sink/types/0.1.0/metadata.json | 19 + samples/kitchen-sink/types/0.1.0/package.wit | 242 ++++++ src/data.rs | 8 + src/http.rs | 22 + src/main.rs | 10 +- src/scan.rs | 118 +++ src/site.rs | 767 ++++++++++++++---- static/copy.js | 70 ++ static/head.js | 37 + static/pivot.js | 138 ++++ static/style.css | 183 ++++- static/toc.js | 23 +- templates/base.html | 13 +- templates/index.html | 6 +- templates/interface.html | 23 +- templates/macros.html | 80 +- templates/namespace.html | 66 +- templates/repo.html | 53 -- templates/repos.html | 9 - templates/version.html | 86 +- 226 files changed, 2010 insertions(+), 363 deletions(-) create mode 100644 samples/kitchen-sink/everything/0.1.0/metadata.json create mode 100644 samples/kitchen-sink/everything/0.1.0/world.wit create mode 100644 samples/kitchen-sink/everything/0.2.0-dev/metadata.json create mode 100644 samples/kitchen-sink/everything/0.2.0-dev/world.wit create mode 100644 samples/kitchen-sink/extras/0.1.0/metadata.json create mode 100644 samples/kitchen-sink/extras/0.1.0/package.wit create mode 100644 samples/kitchen-sink/types/0.1.0/metadata.json create mode 100644 samples/kitchen-sink/types/0.1.0/package.wit create mode 100644 static/copy.js create mode 100644 static/head.js create mode 100644 static/pivot.js delete mode 100644 templates/repo.html delete mode 100644 templates/repos.html diff --git a/README.md b/README.md index 626daf3..cae0646 100644 --- a/README.md +++ b/README.md @@ -16,8 +16,9 @@ A directory of the Wasm components and WIT interfaces published by the Component - A release is immutable, so it is indexed once. - A dev tag moves with each build. It is re-indexed whenever its digest changes, until its release is published. 3. It then indexes the package versions those releases depend on, transitively, even when they are pre-releases, e.g. `wasi:logging@0.1.0-draft`. Each dependency's registry host comes from the wkg config, [`.config/wasm-pkg/config.toml`](.config/wasm-pkg/config.toml). The host's `/.well-known/wasm-pkg/registry.json` then gives the OCI repository, e.g. `wasi` → `wasi.dev` → `ghcr.io/webassembly/wasi/*`. As in wkg, `package_registry_overrides` takes precedence over `namespace_registries`, which takes precedence over `default_registry`. A mapping may also carry the registry metadata inline. To index the dependencies of a new namespace, add its registry to the config. -4. `directory build` renders the committed index as a static site. Versions are grouped by the repository they're built from, which comes from their `org.opencontainers.image.source` annotation. A repository releases its interface package and components together, with the same version, so `/repos/{owner}/{repo}/{version}/` lists everything the repository released at that version. -5. The site is built only from the committed index, never from the registry. +4. `directory build` renders the committed index as a static site. Versions are grouped by the repository they're built from, which comes from their `org.opencontainers.image.source` annotation. A repository releases its interface package and components together, with the same version, so a namespace's page lists each repository's packages at one version, switching between its versions in place, and each package's page links the others its repository released with it. +5. `directory scan` also links each stable version to the GitHub release of its source repository tagged with the version, `v0.3.1` or else `0.3.1`. When the version records the commit it was built from, the tag must be that commit. A release published after its packages is linked by a later scan. +6. The site is built only from the committed index, never from the registry. The id of a WIT package is the package it declares, e.g. `ghcr.io/componentized/logging` holds `componentized:logging`. A component's id comes from its repository path, e.g. `ghcr.io/componentized/logging/levels` is `componentized:logging-levels`. @@ -27,7 +28,7 @@ The index is committed in [`index/`](index), one directory per version: ``` index/{namespace}/{name}/{version}/ - metadata.json # kind, origin, OCI location and digests, annotations, imports, exports, dependencies + metadata.json # kind, origin, OCI location and digests, annotations, imports, exports, dependencies, GitHub release package.wit # a WIT package, its main package only world.wit # a component's world, its main package only ``` @@ -68,6 +69,15 @@ python3 -m http.server -d _site `cargo run -- scan --help` lists the other options, e.g. `--config` for a different wkg config. +## Samples + +[`samples/`](samples) holds synthetic packages, laid out like the index, that exercise every WIT feature and keyword so the site's rendering of each can be checked: the `kitchen-sink` namespace, at [`/kitchen-sink/`](https://directory.componentized.dev/kitchen-sink/). They aren't published to any registry. + +- Their `metadata.json` has `"origin": "synthetic"`. A component's imports and exports are derived from its WIT at build time, so its metadata needn't list them. +- `directory build` renders their pages apart from the index's: no page of the index lists, counts, searches or links them, while their own pages link each other. Each page notes it's a synthetic sample, is kept out of search engines and has no pull commands. +- A sample must be synthetic and keep to a namespace the index doesn't hold, and the index can't hold a synthetic version; the build fails otherwise. +- `scan` never reads them. `--samples` builds from another directory. + ## Workflows - [`scan.yaml`](.github/workflows/scan.yaml) runs every hour, on demand, and on a `release` repository dispatch. It commits the new versions to `main`, then deploys the site. A push made with the `GITHUB_TOKEN` doesn't start other workflows, so the scan calls `pages.yaml` itself. diff --git a/index/componentized/cli-stderr-to-stdout/0.1.0/metadata.json b/index/componentized/cli-stderr-to-stdout/0.1.0/metadata.json index 9830c88..5b351cd 100644 --- a/index/componentized/cli-stderr-to-stdout/0.1.0/metadata.json +++ b/index/componentized/cli-stderr-to-stdout/0.1.0/metadata.json @@ -37,5 +37,6 @@ "version": "0.2.3" } ], + "release": "https://github.com/componentized/cli/releases/tag/v0.1.0", "indexed_at": "2026-11-11T23:44:14Z" } diff --git a/index/componentized/cli-stderr-to-stdout/0.1.1/metadata.json b/index/componentized/cli-stderr-to-stdout/0.1.1/metadata.json index 514a1a0..492fc34 100644 --- a/index/componentized/cli-stderr-to-stdout/0.1.1/metadata.json +++ b/index/componentized/cli-stderr-to-stdout/0.1.1/metadata.json @@ -37,5 +37,6 @@ "version": "0.2.6" } ], + "release": "https://github.com/componentized/cli/releases/tag/v0.1.1", "indexed_at": "2026-11-11T23:44:15Z" } diff --git a/index/componentized/cli-stderr-to-stdout/0.2.0/metadata.json b/index/componentized/cli-stderr-to-stdout/0.2.0/metadata.json index c6d51a5..85ebf59 100644 --- a/index/componentized/cli-stderr-to-stdout/0.2.0/metadata.json +++ b/index/componentized/cli-stderr-to-stdout/0.2.0/metadata.json @@ -42,5 +42,6 @@ "version": "0.3.0" } ], + "release": "https://github.com/componentized/cli/releases/tag/v0.2.0", "indexed_at": "2026-11-11T23:44:15Z" } diff --git a/index/componentized/cli-stderr-to-stdout/0.2.1-dev/metadata.json b/index/componentized/cli-stderr-to-stdout/0.2.1-dev/metadata.json index 2ff4718..f3af87d 100644 --- a/index/componentized/cli-stderr-to-stdout/0.2.1-dev/metadata.json +++ b/index/componentized/cli-stderr-to-stdout/0.2.1-dev/metadata.json @@ -7,26 +7,26 @@ "registry": "ghcr.io", "repository": "componentized/cli/stderr-to-stdout", "tag": "0.2.1-dev", - "digest": "sha256:7dee9e37b0d0be1075c984026407a97fa8cf524171393b5dbce900dc3db0bf73", - "layer_digest": "sha256:b61f911611b488d47afd796b5fea50c692e5a72481f54b7e0b6292517ed3dee1", - "size": 20488 + "digest": "sha256:df67f64c5488bf2acc352315e4d94f505fa955b270619cdb366383d49199a260", + "layer_digest": "sha256:f3598658d88a39a9e05a9960c9840fca85d4afac5391310954c9a9d75bb60cc7", + "size": 20545 }, "debug": { "registry": "ghcr.io", "repository": "componentized/cli/stderr-to-stdout", "tag": "0.2.1-dev_debug", - "digest": "sha256:31a7042269b2308d3b31677901ea58b674e3487a88fe3b6ea0ab653ac7d8f3bd", - "layer_digest": "sha256:fab95161592a207370abb65e1f853a3b53359910e369194464c91aecc1a73d43", - "size": 40379 + "digest": "sha256:9b33cd688856052d22147ef8581604781d6cc65041bd8d3b0e836617d324eb13", + "layer_digest": "sha256:338ae4c0bed7b69b75ba2b8d461c528c5e5fd33e85068677dd1877a21c7bf009", + "size": 40496 }, - "created": "2026-11-09T16:58:22.881775536Z", + "created": "2026-11-13T00:13:35.483369326Z", "annotations": { "org.opencontainers.image.description": "Redirects stderr's output stream to stdout.", "org.opencontainers.image.licenses": "Apache-2.0", - "org.opencontainers.image.revision": "c54ebd8f414e6381162daf2d6c0f634f3b1d73a1", + "org.opencontainers.image.revision": "42b075f70d614b7eb885dc562efcc126732d5633", "org.opencontainers.image.source": "https://github.com/componentized/cli.git", "org.opencontainers.image.title": "componentized:cli-stderr-to-stdout", - "org.opencontainers.image.url": "https://github.com/componentized/cli/tree/c54ebd8f414e6381162daf2d6c0f634f3b1d73a1/components/stderr-to-stdout", + "org.opencontainers.image.url": "https://github.com/componentized/cli/tree/42b075f70d614b7eb885dc562efcc126732d5633/components/stderr-to-stdout", "org.opencontainers.image.version": "0.2.1-dev" }, "imports": [ @@ -42,5 +42,5 @@ "version": "0.3.0" } ], - "indexed_at": "2026-11-12T00:11:49Z" + "indexed_at": "2026-11-13T01:22:04Z" } diff --git a/index/componentized/cli-stdout-to-stderr/0.1.0/metadata.json b/index/componentized/cli-stdout-to-stderr/0.1.0/metadata.json index e5ebd32..3cb0fe1 100644 --- a/index/componentized/cli-stdout-to-stderr/0.1.0/metadata.json +++ b/index/componentized/cli-stdout-to-stderr/0.1.0/metadata.json @@ -37,5 +37,6 @@ "version": "0.2.3" } ], + "release": "https://github.com/componentized/cli/releases/tag/v0.1.0", "indexed_at": "2026-11-11T23:44:15Z" } diff --git a/index/componentized/cli-stdout-to-stderr/0.1.1/metadata.json b/index/componentized/cli-stdout-to-stderr/0.1.1/metadata.json index 82a4ff8..59ded10 100644 --- a/index/componentized/cli-stdout-to-stderr/0.1.1/metadata.json +++ b/index/componentized/cli-stdout-to-stderr/0.1.1/metadata.json @@ -37,5 +37,6 @@ "version": "0.2.6" } ], + "release": "https://github.com/componentized/cli/releases/tag/v0.1.1", "indexed_at": "2026-11-11T23:44:16Z" } diff --git a/index/componentized/cli-stdout-to-stderr/0.2.0/metadata.json b/index/componentized/cli-stdout-to-stderr/0.2.0/metadata.json index 59bbd60..0b1f434 100644 --- a/index/componentized/cli-stdout-to-stderr/0.2.0/metadata.json +++ b/index/componentized/cli-stdout-to-stderr/0.2.0/metadata.json @@ -42,5 +42,6 @@ "version": "0.3.0" } ], + "release": "https://github.com/componentized/cli/releases/tag/v0.2.0", "indexed_at": "2026-11-11T23:44:16Z" } diff --git a/index/componentized/cli-stdout-to-stderr/0.2.1-dev/metadata.json b/index/componentized/cli-stdout-to-stderr/0.2.1-dev/metadata.json index 8268850..3eb8f47 100644 --- a/index/componentized/cli-stdout-to-stderr/0.2.1-dev/metadata.json +++ b/index/componentized/cli-stdout-to-stderr/0.2.1-dev/metadata.json @@ -7,26 +7,26 @@ "registry": "ghcr.io", "repository": "componentized/cli/stdout-to-stderr", "tag": "0.2.1-dev", - "digest": "sha256:d3eb85c03d1d734a1b383147a72dfbed2d17c5d9b70b353649ea523ad3f1f443", - "layer_digest": "sha256:47e18eaf4f924c83416ed868991409f3e4296e55e22935bbc9ed910de617f144", - "size": 20488 + "digest": "sha256:63fa579d3e4cd0ea0123eb4632df6a4efce52945db5cf15c6625eb6e2b74ef9f", + "layer_digest": "sha256:03b6d85d3ae6d00491b37bd6df90ec415a32c4c5992812c7c333ea8aaded50c6", + "size": 20545 }, "debug": { "registry": "ghcr.io", "repository": "componentized/cli/stdout-to-stderr", "tag": "0.2.1-dev_debug", - "digest": "sha256:cf9b9c192787ab7ce5b09f845864f722c141c25c8c084e14df988358a4c41653", - "layer_digest": "sha256:d8b54a83ab498083977f0595ebb3c1d8acc3378f1a28480899fcef00ac06536e", - "size": 40435 + "digest": "sha256:f08f8e3678c233d5daccfed03ed1dcd263b5ef248062aafe00507ade5cc47499", + "layer_digest": "sha256:e9899fc979f5b954eff811dce557e4a60dbadac0b52012f63ae93a4b3acb88ca", + "size": 40496 }, - "created": "2026-11-09T16:58:38.665527524Z", + "created": "2026-11-13T00:13:57.355257283Z", "annotations": { "org.opencontainers.image.description": "Redirects stdout's output stream to stderr.", "org.opencontainers.image.licenses": "Apache-2.0", - "org.opencontainers.image.revision": "c54ebd8f414e6381162daf2d6c0f634f3b1d73a1", + "org.opencontainers.image.revision": "42b075f70d614b7eb885dc562efcc126732d5633", "org.opencontainers.image.source": "https://github.com/componentized/cli.git", "org.opencontainers.image.title": "componentized:cli-stdout-to-stderr", - "org.opencontainers.image.url": "https://github.com/componentized/cli/tree/c54ebd8f414e6381162daf2d6c0f634f3b1d73a1/components/stdout-to-stderr", + "org.opencontainers.image.url": "https://github.com/componentized/cli/tree/42b075f70d614b7eb885dc562efcc126732d5633/components/stdout-to-stderr", "org.opencontainers.image.version": "0.2.1-dev" }, "imports": [ @@ -42,5 +42,5 @@ "version": "0.3.0" } ], - "indexed_at": "2026-11-12T00:11:50Z" + "indexed_at": "2026-11-13T01:22:05Z" } diff --git a/index/componentized/cli/0.2.0/metadata.json b/index/componentized/cli/0.2.0/metadata.json index 23d574a..3d346d1 100644 --- a/index/componentized/cli/0.2.0/metadata.json +++ b/index/componentized/cli/0.2.0/metadata.json @@ -27,5 +27,6 @@ "version": "0.3.0" } ], + "release": "https://github.com/componentized/cli/releases/tag/v0.2.0", "indexed_at": "2026-11-11T23:44:14Z" } diff --git a/index/componentized/cli/0.2.1-dev/metadata.json b/index/componentized/cli/0.2.1-dev/metadata.json index fb4bc33..5670920 100644 --- a/index/componentized/cli/0.2.1-dev/metadata.json +++ b/index/componentized/cli/0.2.1-dev/metadata.json @@ -7,18 +7,18 @@ "registry": "ghcr.io", "repository": "componentized/cli", "tag": "0.2.1-dev", - "digest": "sha256:ad6f8b82997e2564d87325c041c5f3474398a91ed261a935d4b83d67695e1735", + "digest": "sha256:9714fd50724105886278d9410165f9e8d5880a083642cc8aa5baacb9a9127806", "layer_digest": "sha256:f3d93daa91935626b3b2de8076c5405c5981e6c19d0075fcaeedfd42eeb816ff", "size": 498 }, - "created": "2026-11-09T16:58:13.853946569Z", + "created": "2026-11-13T00:13:24.903690127Z", "annotations": { "org.opencontainers.image.description": "A collection of utility components that remix wasi:cli types and interfaces.", "org.opencontainers.image.licenses": "Apache-2.0", - "org.opencontainers.image.revision": "c54ebd8f414e6381162daf2d6c0f634f3b1d73a1", + "org.opencontainers.image.revision": "42b075f70d614b7eb885dc562efcc126732d5633", "org.opencontainers.image.source": "https://github.com/componentized/cli.git", "org.opencontainers.image.title": "componentized:cli", - "org.opencontainers.image.url": "https://github.com/componentized/cli/tree/c54ebd8f414e6381162daf2d6c0f634f3b1d73a1", + "org.opencontainers.image.url": "https://github.com/componentized/cli/tree/42b075f70d614b7eb885dc562efcc126732d5633", "org.opencontainers.image.version": "0.2.1-dev" }, "dependencies": [ @@ -27,5 +27,5 @@ "version": "0.3.0" } ], - "indexed_at": "2026-11-12T00:11:48Z" + "indexed_at": "2026-11-13T01:22:04Z" } diff --git a/index/componentized/component-filesystem-loader/0.1.0/metadata.json b/index/componentized/component-filesystem-loader/0.1.0/metadata.json index 32216cd..3e0a4f4 100644 --- a/index/componentized/component-filesystem-loader/0.1.0/metadata.json +++ b/index/componentized/component-filesystem-loader/0.1.0/metadata.json @@ -47,5 +47,6 @@ "version": "0.3.0" } ], + "release": "https://github.com/componentized/component/releases/tag/v0.1.0", "indexed_at": "2026-11-11T23:44:17Z" } diff --git a/index/componentized/component-http-loader/0.1.0/metadata.json b/index/componentized/component-http-loader/0.1.0/metadata.json index e2599d5..020983e 100644 --- a/index/componentized/component-http-loader/0.1.0/metadata.json +++ b/index/componentized/component-http-loader/0.1.0/metadata.json @@ -46,5 +46,6 @@ "version": "0.1.0" } ], + "release": "https://github.com/componentized/component/releases/tag/v0.1.0", "indexed_at": "2026-11-11T23:44:18Z" } diff --git a/index/componentized/component-oci-loader/0.1.0/metadata.json b/index/componentized/component-oci-loader/0.1.0/metadata.json index 9fedadd..58f60a6 100644 --- a/index/componentized/component-oci-loader/0.1.0/metadata.json +++ b/index/componentized/component-oci-loader/0.1.0/metadata.json @@ -52,5 +52,6 @@ "version": "0.3.0" } ], + "release": "https://github.com/componentized/component/releases/tag/v0.1.0", "indexed_at": "2026-11-11T23:44:18Z" } diff --git a/index/componentized/component-path-loader-router/0.1.0/metadata.json b/index/componentized/component-path-loader-router/0.1.0/metadata.json index ac751aa..d510099 100644 --- a/index/componentized/component-path-loader-router/0.1.0/metadata.json +++ b/index/componentized/component-path-loader-router/0.1.0/metadata.json @@ -44,5 +44,6 @@ "version": "0.1.0" } ], + "release": "https://github.com/componentized/component/releases/tag/v0.1.0", "indexed_at": "2026-11-11T23:44:19Z" } diff --git a/index/componentized/component-path-loader/0.1.0/metadata.json b/index/componentized/component-path-loader/0.1.0/metadata.json index 59a9666..08dc616 100644 --- a/index/componentized/component-path-loader/0.1.0/metadata.json +++ b/index/componentized/component-path-loader/0.1.0/metadata.json @@ -63,5 +63,6 @@ "version": "0.3.0" } ], + "release": "https://github.com/componentized/component/releases/tag/v0.1.0", "indexed_at": "2026-11-11T23:44:19Z" } diff --git a/index/componentized/component-wac-loader/0.1.0/metadata.json b/index/componentized/component-wac-loader/0.1.0/metadata.json index 9e56bff..6341560 100644 --- a/index/componentized/component-wac-loader/0.1.0/metadata.json +++ b/index/componentized/component-wac-loader/0.1.0/metadata.json @@ -41,5 +41,6 @@ "version": "0.1.0" } ], + "release": "https://github.com/componentized/component/releases/tag/v0.1.0", "indexed_at": "2026-11-11T23:44:20Z" } diff --git a/index/componentized/component-wit-tools/0.1.0/metadata.json b/index/componentized/component-wit-tools/0.1.0/metadata.json index de23953..771495f 100644 --- a/index/componentized/component-wit-tools/0.1.0/metadata.json +++ b/index/componentized/component-wit-tools/0.1.0/metadata.json @@ -41,5 +41,6 @@ "version": "0.1.0" } ], + "release": "https://github.com/componentized/component/releases/tag/v0.1.0", "indexed_at": "2026-11-11T23:44:20Z" } diff --git a/index/componentized/component/0.1.0/metadata.json b/index/componentized/component/0.1.0/metadata.json index 3b10b05..282ebdd 100644 --- a/index/componentized/component/0.1.0/metadata.json +++ b/index/componentized/component/0.1.0/metadata.json @@ -21,5 +21,6 @@ "org.opencontainers.image.url": "https://github.com/componentized/component/tree/60a42310d899e65248acf584221ba444607251f0", "org.opencontainers.image.version": "v0.1.0" }, + "release": "https://github.com/componentized/component/releases/tag/v0.1.0", "indexed_at": "2026-11-11T23:44:17Z" } diff --git a/index/componentized/config-defaults/0.1.0/metadata.json b/index/componentized/config-defaults/0.1.0/metadata.json index ee0420f..692f751 100644 --- a/index/componentized/config-defaults/0.1.0/metadata.json +++ b/index/componentized/config-defaults/0.1.0/metadata.json @@ -33,5 +33,6 @@ "version": "0.2.0-draft" } ], + "release": "https://github.com/componentized/config/releases/tag/v0.1.0", "indexed_at": "2026-11-11T23:44:21Z" } diff --git a/index/componentized/config-defaults/0.2.0/metadata.json b/index/componentized/config-defaults/0.2.0/metadata.json index be66fc5..0fe9d60 100644 --- a/index/componentized/config-defaults/0.2.0/metadata.json +++ b/index/componentized/config-defaults/0.2.0/metadata.json @@ -33,5 +33,6 @@ "version": "0.2.0-rc.1" } ], + "release": "https://github.com/componentized/config/releases/tag/v0.2.0", "indexed_at": "2026-11-11T23:44:21Z" } diff --git a/index/componentized/config-defaults/0.2.1/metadata.json b/index/componentized/config-defaults/0.2.1/metadata.json index a9fa513..934cb37 100644 --- a/index/componentized/config-defaults/0.2.1/metadata.json +++ b/index/componentized/config-defaults/0.2.1/metadata.json @@ -33,5 +33,6 @@ "version": "0.2.0-rc.1" } ], + "release": "https://github.com/componentized/config/releases/tag/v0.2.1", "indexed_at": "2026-11-11T23:44:21Z" } diff --git a/index/componentized/config-empty/0.1.0/metadata.json b/index/componentized/config-empty/0.1.0/metadata.json index 5caddf2..69727a5 100644 --- a/index/componentized/config-empty/0.1.0/metadata.json +++ b/index/componentized/config-empty/0.1.0/metadata.json @@ -29,5 +29,6 @@ "version": "0.2.0-draft" } ], + "release": "https://github.com/componentized/config/releases/tag/v0.1.0", "indexed_at": "2026-11-11T23:44:22Z" } diff --git a/index/componentized/config-empty/0.2.0/metadata.json b/index/componentized/config-empty/0.2.0/metadata.json index 9e03ac1..7d3f07a 100644 --- a/index/componentized/config-empty/0.2.0/metadata.json +++ b/index/componentized/config-empty/0.2.0/metadata.json @@ -29,5 +29,6 @@ "version": "0.2.0-rc.1" } ], + "release": "https://github.com/componentized/config/releases/tag/v0.2.0", "indexed_at": "2026-11-11T23:44:22Z" } diff --git a/index/componentized/config-empty/0.2.1/metadata.json b/index/componentized/config-empty/0.2.1/metadata.json index 6f5ff00..9c32cc8 100644 --- a/index/componentized/config-empty/0.2.1/metadata.json +++ b/index/componentized/config-empty/0.2.1/metadata.json @@ -29,5 +29,6 @@ "version": "0.2.0-rc.1" } ], + "release": "https://github.com/componentized/config/releases/tag/v0.2.1", "indexed_at": "2026-11-11T23:44:22Z" } diff --git a/index/componentized/config-from-environment/0.1.0/metadata.json b/index/componentized/config-from-environment/0.1.0/metadata.json index 2efb30a..ae842ed 100644 --- a/index/componentized/config-from-environment/0.1.0/metadata.json +++ b/index/componentized/config-from-environment/0.1.0/metadata.json @@ -36,5 +36,6 @@ "version": "0.2.0-draft" } ], + "release": "https://github.com/componentized/config/releases/tag/v0.1.0", "indexed_at": "2026-11-11T23:44:22Z" } diff --git a/index/componentized/config-from-environment/0.2.0/metadata.json b/index/componentized/config-from-environment/0.2.0/metadata.json index bc9676f..b1ed18f 100644 --- a/index/componentized/config-from-environment/0.2.0/metadata.json +++ b/index/componentized/config-from-environment/0.2.0/metadata.json @@ -36,5 +36,6 @@ "version": "0.2.0-rc.1" } ], + "release": "https://github.com/componentized/config/releases/tag/v0.2.0", "indexed_at": "2026-11-11T23:44:23Z" } diff --git a/index/componentized/config-from-environment/0.2.1/metadata.json b/index/componentized/config-from-environment/0.2.1/metadata.json index 717816e..d7c7406 100644 --- a/index/componentized/config-from-environment/0.2.1/metadata.json +++ b/index/componentized/config-from-environment/0.2.1/metadata.json @@ -36,5 +36,6 @@ "version": "0.2.0-rc.1" } ], + "release": "https://github.com/componentized/config/releases/tag/v0.2.1", "indexed_at": "2026-11-11T23:44:23Z" } diff --git a/index/componentized/config-overlay/0.1.0/metadata.json b/index/componentized/config-overlay/0.1.0/metadata.json index 443400a..a30c4fc 100644 --- a/index/componentized/config-overlay/0.1.0/metadata.json +++ b/index/componentized/config-overlay/0.1.0/metadata.json @@ -33,5 +33,6 @@ "version": "0.2.0-draft" } ], + "release": "https://github.com/componentized/config/releases/tag/v0.1.0", "indexed_at": "2026-11-11T23:44:23Z" } diff --git a/index/componentized/config-overlay/0.2.0/metadata.json b/index/componentized/config-overlay/0.2.0/metadata.json index 7697f07..4fd9a49 100644 --- a/index/componentized/config-overlay/0.2.0/metadata.json +++ b/index/componentized/config-overlay/0.2.0/metadata.json @@ -33,5 +33,6 @@ "version": "0.2.0-rc.1" } ], + "release": "https://github.com/componentized/config/releases/tag/v0.2.0", "indexed_at": "2026-11-11T23:44:23Z" } diff --git a/index/componentized/config-overlay/0.2.1/metadata.json b/index/componentized/config-overlay/0.2.1/metadata.json index 1e0cd2c..c3111e1 100644 --- a/index/componentized/config-overlay/0.2.1/metadata.json +++ b/index/componentized/config-overlay/0.2.1/metadata.json @@ -33,5 +33,6 @@ "version": "0.2.0-rc.1" } ], + "release": "https://github.com/componentized/config/releases/tag/v0.2.1", "indexed_at": "2026-11-11T23:44:24Z" } diff --git a/index/componentized/config-remap/0.1.0/metadata.json b/index/componentized/config-remap/0.1.0/metadata.json index 9a34217..af16fab 100644 --- a/index/componentized/config-remap/0.1.0/metadata.json +++ b/index/componentized/config-remap/0.1.0/metadata.json @@ -33,5 +33,6 @@ "version": "0.2.0-draft" } ], + "release": "https://github.com/componentized/config/releases/tag/v0.1.0", "indexed_at": "2026-11-11T23:44:24Z" } diff --git a/index/componentized/config-remap/0.2.0/metadata.json b/index/componentized/config-remap/0.2.0/metadata.json index ce3a3ba..efa65f1 100644 --- a/index/componentized/config-remap/0.2.0/metadata.json +++ b/index/componentized/config-remap/0.2.0/metadata.json @@ -33,5 +33,6 @@ "version": "0.2.0-rc.1" } ], + "release": "https://github.com/componentized/config/releases/tag/v0.2.0", "indexed_at": "2026-11-11T23:44:24Z" } diff --git a/index/componentized/config-remap/0.2.1/metadata.json b/index/componentized/config-remap/0.2.1/metadata.json index 931067d..0699c1a 100644 --- a/index/componentized/config-remap/0.2.1/metadata.json +++ b/index/componentized/config-remap/0.2.1/metadata.json @@ -33,5 +33,6 @@ "version": "0.2.0-rc.1" } ], + "release": "https://github.com/componentized/config/releases/tag/v0.2.1", "indexed_at": "2026-11-11T23:44:25Z" } diff --git a/index/componentized/config-scope/0.1.0/metadata.json b/index/componentized/config-scope/0.1.0/metadata.json index bfb689f..7a6f7b2 100644 --- a/index/componentized/config-scope/0.1.0/metadata.json +++ b/index/componentized/config-scope/0.1.0/metadata.json @@ -33,5 +33,6 @@ "version": "0.2.0-draft" } ], + "release": "https://github.com/componentized/config/releases/tag/v0.1.0", "indexed_at": "2026-11-11T23:44:25Z" } diff --git a/index/componentized/config-scope/0.2.0/metadata.json b/index/componentized/config-scope/0.2.0/metadata.json index 5e6aa63..978936b 100644 --- a/index/componentized/config-scope/0.2.0/metadata.json +++ b/index/componentized/config-scope/0.2.0/metadata.json @@ -33,5 +33,6 @@ "version": "0.2.0-rc.1" } ], + "release": "https://github.com/componentized/config/releases/tag/v0.2.0", "indexed_at": "2026-11-11T23:44:25Z" } diff --git a/index/componentized/config-scope/0.2.1/metadata.json b/index/componentized/config-scope/0.2.1/metadata.json index 224066a..16fec88 100644 --- a/index/componentized/config-scope/0.2.1/metadata.json +++ b/index/componentized/config-scope/0.2.1/metadata.json @@ -33,5 +33,6 @@ "version": "0.2.0-rc.1" } ], + "release": "https://github.com/componentized/config/releases/tag/v0.2.1", "indexed_at": "2026-11-11T23:44:25Z" } diff --git a/index/componentized/constants-atomics/0.2.0/metadata.json b/index/componentized/constants-atomics/0.2.0/metadata.json index f805171..a173278 100644 --- a/index/componentized/constants-atomics/0.2.0/metadata.json +++ b/index/componentized/constants-atomics/0.2.0/metadata.json @@ -30,5 +30,6 @@ "version": "0.2.0" } ], + "release": "https://github.com/componentized/constants/releases/tag/v0.2.0", "indexed_at": "2026-11-11T23:44:27Z" } diff --git a/index/componentized/constants-config/0.1.0/metadata.json b/index/componentized/constants-config/0.1.0/metadata.json index 48ec0fc..8e600c0 100644 --- a/index/componentized/constants-config/0.1.0/metadata.json +++ b/index/componentized/constants-config/0.1.0/metadata.json @@ -45,5 +45,6 @@ "version": "0.2.0-rc.1" } ], + "release": "https://github.com/componentized/constants/releases/tag/v0.1.0", "indexed_at": "2026-11-11T23:44:27Z" } diff --git a/index/componentized/constants-config/0.1.1/metadata.json b/index/componentized/constants-config/0.1.1/metadata.json index 08b380b..0faf996 100644 --- a/index/componentized/constants-config/0.1.1/metadata.json +++ b/index/componentized/constants-config/0.1.1/metadata.json @@ -45,5 +45,6 @@ "version": "0.2.0-rc.1" } ], + "release": "https://github.com/componentized/constants/releases/tag/v0.1.1", "indexed_at": "2026-11-11T23:44:28Z" } diff --git a/index/componentized/constants-config/0.2.0/metadata.json b/index/componentized/constants-config/0.2.0/metadata.json index 6fae9a9..29330c4 100644 --- a/index/componentized/constants-config/0.2.0/metadata.json +++ b/index/componentized/constants-config/0.2.0/metadata.json @@ -45,5 +45,6 @@ "version": "0.2.0-rc.1" } ], + "release": "https://github.com/componentized/constants/releases/tag/v0.2.0", "indexed_at": "2026-11-11T23:44:28Z" } diff --git a/index/componentized/constants-factory/0.1.0/metadata.json b/index/componentized/constants-factory/0.1.0/metadata.json index 616b11e..dc11ce9 100644 --- a/index/componentized/constants-factory/0.1.0/metadata.json +++ b/index/componentized/constants-factory/0.1.0/metadata.json @@ -46,5 +46,6 @@ "version": "0.1.0" } ], + "release": "https://github.com/componentized/constants/releases/tag/v0.1.0", "indexed_at": "2026-11-11T23:44:28Z" } diff --git a/index/componentized/constants-factory/0.1.1/metadata.json b/index/componentized/constants-factory/0.1.1/metadata.json index 9112f80..d96fbf0 100644 --- a/index/componentized/constants-factory/0.1.1/metadata.json +++ b/index/componentized/constants-factory/0.1.1/metadata.json @@ -46,5 +46,6 @@ "version": "0.1.1" } ], + "release": "https://github.com/componentized/constants/releases/tag/v0.1.1", "indexed_at": "2026-11-11T23:44:29Z" } diff --git a/index/componentized/constants-factory/0.2.0/metadata.json b/index/componentized/constants-factory/0.2.0/metadata.json index 6c17d2e..9496cf6 100644 --- a/index/componentized/constants-factory/0.2.0/metadata.json +++ b/index/componentized/constants-factory/0.2.0/metadata.json @@ -46,5 +46,6 @@ "version": "0.2.0" } ], + "release": "https://github.com/componentized/constants/releases/tag/v0.2.0", "indexed_at": "2026-11-11T23:44:29Z" } diff --git a/index/componentized/constants-math/0.1.0/metadata.json b/index/componentized/constants-math/0.1.0/metadata.json index 0ccf9ed..162a8be 100644 --- a/index/componentized/constants-math/0.1.0/metadata.json +++ b/index/componentized/constants-math/0.1.0/metadata.json @@ -30,5 +30,6 @@ "version": "0.1.0" } ], + "release": "https://github.com/componentized/constants/releases/tag/v0.1.0", "indexed_at": "2026-11-11T23:44:30Z" } diff --git a/index/componentized/constants-math/0.1.1/metadata.json b/index/componentized/constants-math/0.1.1/metadata.json index 46408b5..2d562a8 100644 --- a/index/componentized/constants-math/0.1.1/metadata.json +++ b/index/componentized/constants-math/0.1.1/metadata.json @@ -30,5 +30,6 @@ "version": "0.1.1" } ], + "release": "https://github.com/componentized/constants/releases/tag/v0.1.1", "indexed_at": "2026-11-11T23:44:30Z" } diff --git a/index/componentized/constants-math/0.2.0/metadata.json b/index/componentized/constants-math/0.2.0/metadata.json index ba9ddb9..e0e8c7b 100644 --- a/index/componentized/constants-math/0.2.0/metadata.json +++ b/index/componentized/constants-math/0.2.0/metadata.json @@ -30,5 +30,6 @@ "version": "0.2.0" } ], + "release": "https://github.com/componentized/constants/releases/tag/v0.2.0", "indexed_at": "2026-11-11T23:44:30Z" } diff --git a/index/componentized/constants-random/0.2.0/metadata.json b/index/componentized/constants-random/0.2.0/metadata.json index fcc3dc6..8ceb161 100644 --- a/index/componentized/constants-random/0.2.0/metadata.json +++ b/index/componentized/constants-random/0.2.0/metadata.json @@ -30,5 +30,6 @@ "version": "0.2.0" } ], + "release": "https://github.com/componentized/constants/releases/tag/v0.2.0", "indexed_at": "2026-11-11T23:44:30Z" } diff --git a/index/componentized/constants-types/0.1.0/metadata.json b/index/componentized/constants-types/0.1.0/metadata.json index db9a056..6a6a893 100644 --- a/index/componentized/constants-types/0.1.0/metadata.json +++ b/index/componentized/constants-types/0.1.0/metadata.json @@ -39,5 +39,6 @@ "version": "0.1.0" } ], + "release": "https://github.com/componentized/constants/releases/tag/v0.1.0", "indexed_at": "2026-11-11T23:44:31Z" } diff --git a/index/componentized/constants-types/0.1.1/metadata.json b/index/componentized/constants-types/0.1.1/metadata.json index 282b59c..2e40d82 100644 --- a/index/componentized/constants-types/0.1.1/metadata.json +++ b/index/componentized/constants-types/0.1.1/metadata.json @@ -39,5 +39,6 @@ "version": "0.1.1" } ], + "release": "https://github.com/componentized/constants/releases/tag/v0.1.1", "indexed_at": "2026-11-11T23:44:31Z" } diff --git a/index/componentized/constants-types/0.2.0/metadata.json b/index/componentized/constants-types/0.2.0/metadata.json index 75acd6f..741f7c3 100644 --- a/index/componentized/constants-types/0.2.0/metadata.json +++ b/index/componentized/constants-types/0.2.0/metadata.json @@ -39,5 +39,6 @@ "version": "0.2.0" } ], + "release": "https://github.com/componentized/constants/releases/tag/v0.2.0", "indexed_at": "2026-11-11T23:44:31Z" } diff --git a/index/componentized/constants/0.1.0/metadata.json b/index/componentized/constants/0.1.0/metadata.json index d82ed41..2aadb96 100644 --- a/index/componentized/constants/0.1.0/metadata.json +++ b/index/componentized/constants/0.1.0/metadata.json @@ -31,5 +31,6 @@ "version": "0.2.0-rc.1" } ], + "release": "https://github.com/componentized/constants/releases/tag/v0.1.0", "indexed_at": "2026-11-11T23:44:26Z" } diff --git a/index/componentized/constants/0.1.1/metadata.json b/index/componentized/constants/0.1.1/metadata.json index f3014db..8eb28fb 100644 --- a/index/componentized/constants/0.1.1/metadata.json +++ b/index/componentized/constants/0.1.1/metadata.json @@ -31,5 +31,6 @@ "version": "0.2.0-rc.1" } ], + "release": "https://github.com/componentized/constants/releases/tag/v0.1.1", "indexed_at": "2026-11-11T23:44:26Z" } diff --git a/index/componentized/constants/0.2.0/metadata.json b/index/componentized/constants/0.2.0/metadata.json index 71a18d5..11cc273 100644 --- a/index/componentized/constants/0.2.0/metadata.json +++ b/index/componentized/constants/0.2.0/metadata.json @@ -31,5 +31,6 @@ "version": "0.2.0-rc.1" } ], + "release": "https://github.com/componentized/constants/releases/tag/v0.2.0", "indexed_at": "2026-11-11T23:44:26Z" } diff --git a/index/componentized/filesystem-chroot/0.1.0/metadata.json b/index/componentized/filesystem-chroot/0.1.0/metadata.json index 08e99d7..7aaff79 100644 --- a/index/componentized/filesystem-chroot/0.1.0/metadata.json +++ b/index/componentized/filesystem-chroot/0.1.0/metadata.json @@ -50,5 +50,6 @@ "version": "0.2.3" } ], + "release": "https://github.com/componentized/filesystem/releases/tag/v0.1.0", "indexed_at": "2026-11-11T23:44:32Z" } diff --git a/index/componentized/filesystem-chroot/0.2.0/metadata.json b/index/componentized/filesystem-chroot/0.2.0/metadata.json index b73a673..80a58d1 100644 --- a/index/componentized/filesystem-chroot/0.2.0/metadata.json +++ b/index/componentized/filesystem-chroot/0.2.0/metadata.json @@ -50,5 +50,6 @@ "version": "0.2.3" } ], + "release": "https://github.com/componentized/filesystem/releases/tag/v0.2.0", "indexed_at": "2026-11-11T23:44:32Z" } diff --git a/index/componentized/filesystem-chroot/0.2.1/metadata.json b/index/componentized/filesystem-chroot/0.2.1/metadata.json index f4d9d96..2212275 100644 --- a/index/componentized/filesystem-chroot/0.2.1/metadata.json +++ b/index/componentized/filesystem-chroot/0.2.1/metadata.json @@ -50,5 +50,6 @@ "version": "0.2.6" } ], + "release": "https://github.com/componentized/filesystem/releases/tag/v0.2.1", "indexed_at": "2026-11-11T23:44:32Z" } diff --git a/index/componentized/http-client/0.1.0/metadata.json b/index/componentized/http-client/0.1.0/metadata.json index 3a0b3cc..682c5ba 100644 --- a/index/componentized/http-client/0.1.0/metadata.json +++ b/index/componentized/http-client/0.1.0/metadata.json @@ -51,5 +51,6 @@ "version": "0.3.0" } ], + "release": "https://github.com/componentized/http/releases/tag/v0.1.0", "indexed_at": "2026-11-11T23:44:34Z" } diff --git a/index/componentized/http-gate-client/0.1.0/metadata.json b/index/componentized/http-gate-client/0.1.0/metadata.json index 9d3e206..ae75ac3 100644 --- a/index/componentized/http-gate-client/0.1.0/metadata.json +++ b/index/componentized/http-gate-client/0.1.0/metadata.json @@ -52,5 +52,6 @@ "version": "0.1.0-draft" } ], + "release": "https://github.com/componentized/http/releases/tag/v0.1.0", "indexed_at": "2026-11-11T23:44:35Z" } diff --git a/index/componentized/http-gate-handler/0.1.0/metadata.json b/index/componentized/http-gate-handler/0.1.0/metadata.json index 92505a0..20b0595 100644 --- a/index/componentized/http-gate-handler/0.1.0/metadata.json +++ b/index/componentized/http-gate-handler/0.1.0/metadata.json @@ -52,5 +52,6 @@ "version": "0.1.0-draft" } ], + "release": "https://github.com/componentized/http/releases/tag/v0.1.0", "indexed_at": "2026-11-11T23:44:36Z" } diff --git a/index/componentized/http-gate/0.1.0/metadata.json b/index/componentized/http-gate/0.1.0/metadata.json index 45e7f1a..2f60f58 100644 --- a/index/componentized/http-gate/0.1.0/metadata.json +++ b/index/componentized/http-gate/0.1.0/metadata.json @@ -54,5 +54,6 @@ "version": "0.1.0-draft" } ], + "release": "https://github.com/componentized/http/releases/tag/v0.1.0", "indexed_at": "2026-11-11T23:44:35Z" } diff --git a/index/componentized/http-latch-defer-all/0.1.0/metadata.json b/index/componentized/http-latch-defer-all/0.1.0/metadata.json index d0c4df0..3108b69 100644 --- a/index/componentized/http-latch-defer-all/0.1.0/metadata.json +++ b/index/componentized/http-latch-defer-all/0.1.0/metadata.json @@ -45,5 +45,6 @@ "version": "0.3.0" } ], + "release": "https://github.com/componentized/http/releases/tag/v0.1.0", "indexed_at": "2026-11-11T23:44:36Z" } diff --git a/index/componentized/http-latch-delegate-client/0.1.0/metadata.json b/index/componentized/http-latch-delegate-client/0.1.0/metadata.json index a19e009..0c091e2 100644 --- a/index/componentized/http-latch-delegate-client/0.1.0/metadata.json +++ b/index/componentized/http-latch-delegate-client/0.1.0/metadata.json @@ -46,5 +46,6 @@ "version": "0.3.0" } ], + "release": "https://github.com/componentized/http/releases/tag/v0.1.0", "indexed_at": "2026-11-11T23:44:37Z" } diff --git a/index/componentized/http-latch-delegate-handler/0.1.0/metadata.json b/index/componentized/http-latch-delegate-handler/0.1.0/metadata.json index e900b5e..e0ffc19 100644 --- a/index/componentized/http-latch-delegate-handler/0.1.0/metadata.json +++ b/index/componentized/http-latch-delegate-handler/0.1.0/metadata.json @@ -46,5 +46,6 @@ "version": "0.3.0" } ], + "release": "https://github.com/componentized/http/releases/tag/v0.1.0", "indexed_at": "2026-11-11T23:44:37Z" } diff --git a/index/componentized/http-latch-deny-all/0.1.0/metadata.json b/index/componentized/http-latch-deny-all/0.1.0/metadata.json index f8b823e..b33df94 100644 --- a/index/componentized/http-latch-deny-all/0.1.0/metadata.json +++ b/index/componentized/http-latch-deny-all/0.1.0/metadata.json @@ -45,5 +45,6 @@ "version": "0.3.0" } ], + "release": "https://github.com/componentized/http/releases/tag/v0.1.0", "indexed_at": "2026-11-11T23:44:38Z" } diff --git a/index/componentized/http-latch-deny-random/0.1.0/metadata.json b/index/componentized/http-latch-deny-random/0.1.0/metadata.json index e35c413..3c05bfe 100644 --- a/index/componentized/http-latch-deny-random/0.1.0/metadata.json +++ b/index/componentized/http-latch-deny-random/0.1.0/metadata.json @@ -60,5 +60,6 @@ "version": "0.3.0" } ], + "release": "https://github.com/componentized/http/releases/tag/v0.1.0", "indexed_at": "2026-11-11T23:44:38Z" } diff --git a/index/componentized/http-latch-dry-run/0.1.0/metadata.json b/index/componentized/http-latch-dry-run/0.1.0/metadata.json index 1592505..41b3c16 100644 --- a/index/componentized/http-latch-dry-run/0.1.0/metadata.json +++ b/index/componentized/http-latch-dry-run/0.1.0/metadata.json @@ -51,5 +51,6 @@ "version": "0.1.0-draft" } ], + "release": "https://github.com/componentized/http/releases/tag/v0.1.0", "indexed_at": "2026-11-11T23:44:38Z" } diff --git a/index/componentized/http-latch-method-readonly-config/0.1.0/metadata.json b/index/componentized/http-latch-method-readonly-config/0.1.0/metadata.json index 2392795..8091e83 100644 --- a/index/componentized/http-latch-method-readonly-config/0.1.0/metadata.json +++ b/index/componentized/http-latch-method-readonly-config/0.1.0/metadata.json @@ -38,5 +38,6 @@ "version": "0.2.0-rc.1" } ], + "release": "https://github.com/componentized/http/releases/tag/v0.1.0", "indexed_at": "2026-11-11T23:44:40Z" } diff --git a/index/componentized/http-latch-method-readonly/0.1.0/metadata.json b/index/componentized/http-latch-method-readonly/0.1.0/metadata.json index 5dc4eaa..4236ec2 100644 --- a/index/componentized/http-latch-method-readonly/0.1.0/metadata.json +++ b/index/componentized/http-latch-method-readonly/0.1.0/metadata.json @@ -50,5 +50,6 @@ "version": "0.1.0-draft" } ], + "release": "https://github.com/componentized/http/releases/tag/v0.1.0", "indexed_at": "2026-11-11T23:44:39Z" } diff --git a/index/componentized/http-latch-method/0.1.0/metadata.json b/index/componentized/http-latch-method/0.1.0/metadata.json index 63788cb..2b94052 100644 --- a/index/componentized/http-latch-method/0.1.0/metadata.json +++ b/index/componentized/http-latch-method/0.1.0/metadata.json @@ -55,5 +55,6 @@ "version": "0.1.0-draft" } ], + "release": "https://github.com/componentized/http/releases/tag/v0.1.0", "indexed_at": "2026-11-11T23:44:39Z" } diff --git a/index/componentized/http-latch-n2/0.1.0/metadata.json b/index/componentized/http-latch-n2/0.1.0/metadata.json index 67577f7..4041196 100644 --- a/index/componentized/http-latch-n2/0.1.0/metadata.json +++ b/index/componentized/http-latch-n2/0.1.0/metadata.json @@ -47,5 +47,6 @@ "version": "0.3.0" } ], + "release": "https://github.com/componentized/http/releases/tag/v0.1.0", "indexed_at": "2026-11-11T23:44:40Z" } diff --git a/index/componentized/http-latch-n3/0.1.0/metadata.json b/index/componentized/http-latch-n3/0.1.0/metadata.json index 691ff31..b49258c 100644 --- a/index/componentized/http-latch-n3/0.1.0/metadata.json +++ b/index/componentized/http-latch-n3/0.1.0/metadata.json @@ -48,5 +48,6 @@ "version": "0.3.0" } ], + "release": "https://github.com/componentized/http/releases/tag/v0.1.0", "indexed_at": "2026-11-11T23:44:41Z" } diff --git a/index/componentized/http-latch-n4/0.1.0/metadata.json b/index/componentized/http-latch-n4/0.1.0/metadata.json index 0f9e5c8..81c7ccc 100644 --- a/index/componentized/http-latch-n4/0.1.0/metadata.json +++ b/index/componentized/http-latch-n4/0.1.0/metadata.json @@ -49,5 +49,6 @@ "version": "0.3.0" } ], + "release": "https://github.com/componentized/http/releases/tag/v0.1.0", "indexed_at": "2026-11-11T23:44:41Z" } diff --git a/index/componentized/http-latch-n5/0.1.0/metadata.json b/index/componentized/http-latch-n5/0.1.0/metadata.json index 1576343..3c8b1a1 100644 --- a/index/componentized/http-latch-n5/0.1.0/metadata.json +++ b/index/componentized/http-latch-n5/0.1.0/metadata.json @@ -50,5 +50,6 @@ "version": "0.3.0" } ], + "release": "https://github.com/componentized/http/releases/tag/v0.1.0", "indexed_at": "2026-11-11T23:44:42Z" } diff --git a/index/componentized/http-latch-scheme-httpsonly-config/0.1.0/metadata.json b/index/componentized/http-latch-scheme-httpsonly-config/0.1.0/metadata.json index b162747..6f19406 100644 --- a/index/componentized/http-latch-scheme-httpsonly-config/0.1.0/metadata.json +++ b/index/componentized/http-latch-scheme-httpsonly-config/0.1.0/metadata.json @@ -38,5 +38,6 @@ "version": "0.2.0-rc.1" } ], + "release": "https://github.com/componentized/http/releases/tag/v0.1.0", "indexed_at": "2026-11-11T23:44:43Z" } diff --git a/index/componentized/http-latch-scheme-httpsonly/0.1.0/metadata.json b/index/componentized/http-latch-scheme-httpsonly/0.1.0/metadata.json index baedc8f..23b05ce 100644 --- a/index/componentized/http-latch-scheme-httpsonly/0.1.0/metadata.json +++ b/index/componentized/http-latch-scheme-httpsonly/0.1.0/metadata.json @@ -50,5 +50,6 @@ "version": "0.1.0-draft" } ], + "release": "https://github.com/componentized/http/releases/tag/v0.1.0", "indexed_at": "2026-11-11T23:44:42Z" } diff --git a/index/componentized/http-latch-scheme/0.1.0/metadata.json b/index/componentized/http-latch-scheme/0.1.0/metadata.json index 1c56397..3fee8eb 100644 --- a/index/componentized/http-latch-scheme/0.1.0/metadata.json +++ b/index/componentized/http-latch-scheme/0.1.0/metadata.json @@ -55,5 +55,6 @@ "version": "0.1.0-draft" } ], + "release": "https://github.com/componentized/http/releases/tag/v0.1.0", "indexed_at": "2026-11-11T23:44:42Z" } diff --git a/index/componentized/http-latch-trace/0.1.0/metadata.json b/index/componentized/http-latch-trace/0.1.0/metadata.json index 3f8d7b0..6118d39 100644 --- a/index/componentized/http-latch-trace/0.1.0/metadata.json +++ b/index/componentized/http-latch-trace/0.1.0/metadata.json @@ -51,5 +51,6 @@ "version": "0.1.0-draft" } ], + "release": "https://github.com/componentized/http/releases/tag/v0.1.0", "indexed_at": "2026-11-11T23:44:43Z" } diff --git a/index/componentized/http-status-codes/0.1.0/metadata.json b/index/componentized/http-status-codes/0.1.0/metadata.json index 0018676..5ec8971 100644 --- a/index/componentized/http-status-codes/0.1.0/metadata.json +++ b/index/componentized/http-status-codes/0.1.0/metadata.json @@ -38,5 +38,6 @@ "version": "0.1.0" } ], + "release": "https://github.com/componentized/http/releases/tag/v0.1.0", "indexed_at": "2026-11-11T23:44:44Z" } diff --git a/index/componentized/http-trace-client/0.1.0/metadata.json b/index/componentized/http-trace-client/0.1.0/metadata.json index 8e3e375..23a93c9 100644 --- a/index/componentized/http-trace-client/0.1.0/metadata.json +++ b/index/componentized/http-trace-client/0.1.0/metadata.json @@ -53,5 +53,6 @@ "version": "0.1.0-draft" } ], + "release": "https://github.com/componentized/http/releases/tag/v0.1.0", "indexed_at": "2026-11-11T23:44:45Z" } diff --git a/index/componentized/http-trace-componentized-client/0.1.0/metadata.json b/index/componentized/http-trace-componentized-client/0.1.0/metadata.json index 0d16183..55e05ca 100644 --- a/index/componentized/http-trace-componentized-client/0.1.0/metadata.json +++ b/index/componentized/http-trace-componentized-client/0.1.0/metadata.json @@ -46,5 +46,6 @@ "version": "0.1.0-draft" } ], + "release": "https://github.com/componentized/http/releases/tag/v0.1.0", "indexed_at": "2026-11-11T23:44:45Z" } diff --git a/index/componentized/http-trace-handler/0.1.0/metadata.json b/index/componentized/http-trace-handler/0.1.0/metadata.json index 11e245f..032ad0b 100644 --- a/index/componentized/http-trace-handler/0.1.0/metadata.json +++ b/index/componentized/http-trace-handler/0.1.0/metadata.json @@ -53,5 +53,6 @@ "version": "0.1.0-draft" } ], + "release": "https://github.com/componentized/http/releases/tag/v0.1.0", "indexed_at": "2026-11-11T23:44:45Z" } diff --git a/index/componentized/http-trace-types/0.1.0/metadata.json b/index/componentized/http-trace-types/0.1.0/metadata.json index dc88e13..9453f00 100644 --- a/index/componentized/http-trace-types/0.1.0/metadata.json +++ b/index/componentized/http-trace-types/0.1.0/metadata.json @@ -51,5 +51,6 @@ "version": "0.1.0-draft" } ], + "release": "https://github.com/componentized/http/releases/tag/v0.1.0", "indexed_at": "2026-11-11T23:44:46Z" } diff --git a/index/componentized/http-trace/0.1.0/metadata.json b/index/componentized/http-trace/0.1.0/metadata.json index 9e92f0d..7acc875 100644 --- a/index/componentized/http-trace/0.1.0/metadata.json +++ b/index/componentized/http-trace/0.1.0/metadata.json @@ -55,5 +55,6 @@ "version": "0.1.0-draft" } ], + "release": "https://github.com/componentized/http/releases/tag/v0.1.0", "indexed_at": "2026-11-11T23:44:44Z" } diff --git a/index/componentized/http/0.1.0/metadata.json b/index/componentized/http/0.1.0/metadata.json index b4fdf4c..ac9af66 100644 --- a/index/componentized/http/0.1.0/metadata.json +++ b/index/componentized/http/0.1.0/metadata.json @@ -31,5 +31,6 @@ "version": "0.3.0" } ], + "release": "https://github.com/componentized/http/releases/tag/v0.1.0", "indexed_at": "2026-11-11T23:44:34Z" } diff --git a/index/componentized/logging-levels/0.1.0/metadata.json b/index/componentized/logging-levels/0.1.0/metadata.json index f353eb0..ee70a4f 100644 --- a/index/componentized/logging-levels/0.1.0/metadata.json +++ b/index/componentized/logging-levels/0.1.0/metadata.json @@ -37,5 +37,6 @@ "version": "0.1.0-draft" } ], + "release": "https://github.com/componentized/logging/releases/tag/v0.1.0", "indexed_at": "2026-11-11T23:43:35Z" } diff --git a/index/componentized/logging-levels/0.2.0/metadata.json b/index/componentized/logging-levels/0.2.0/metadata.json index 484de30..b16ae58 100644 --- a/index/componentized/logging-levels/0.2.0/metadata.json +++ b/index/componentized/logging-levels/0.2.0/metadata.json @@ -37,5 +37,6 @@ "version": "0.1.0-draft" } ], + "release": "https://github.com/componentized/logging/releases/tag/v0.2.0", "indexed_at": "2026-11-11T23:43:35Z" } diff --git a/index/componentized/logging-levels/0.2.1/metadata.json b/index/componentized/logging-levels/0.2.1/metadata.json index 97a6b8c..d6c45ab 100644 --- a/index/componentized/logging-levels/0.2.1/metadata.json +++ b/index/componentized/logging-levels/0.2.1/metadata.json @@ -37,5 +37,6 @@ "version": "0.1.0-draft" } ], + "release": "https://github.com/componentized/logging/releases/tag/v0.2.1", "indexed_at": "2026-11-11T23:43:35Z" } diff --git a/index/componentized/logging-levels/0.3.0/metadata.json b/index/componentized/logging-levels/0.3.0/metadata.json index 2ae33b4..988eed4 100644 --- a/index/componentized/logging-levels/0.3.0/metadata.json +++ b/index/componentized/logging-levels/0.3.0/metadata.json @@ -46,5 +46,6 @@ "version": "0.1.0-draft" } ], + "release": "https://github.com/componentized/logging/releases/tag/v0.3.0", "indexed_at": "2026-11-11T23:43:35Z" } diff --git a/index/componentized/logging-levels/0.3.1/metadata.json b/index/componentized/logging-levels/0.3.1/metadata.json index 806a321..5bd9965 100644 --- a/index/componentized/logging-levels/0.3.1/metadata.json +++ b/index/componentized/logging-levels/0.3.1/metadata.json @@ -46,5 +46,6 @@ "version": "0.1.0-draft" } ], + "release": "https://github.com/componentized/logging/releases/tag/v0.3.1", "indexed_at": "2026-11-11T23:43:36Z" } diff --git a/index/componentized/logging-to-stderr/0.3.1/metadata.json b/index/componentized/logging-to-stderr/0.3.1/metadata.json index 9e9c077..8e3215e 100644 --- a/index/componentized/logging-to-stderr/0.3.1/metadata.json +++ b/index/componentized/logging-to-stderr/0.3.1/metadata.json @@ -51,5 +51,6 @@ "version": "0.1.0-draft" } ], + "release": "https://github.com/componentized/logging/releases/tag/v0.3.1", "indexed_at": "2026-11-11T23:43:36Z" } diff --git a/index/componentized/logging-to-stdout/0.1.0/metadata.json b/index/componentized/logging-to-stdout/0.1.0/metadata.json index a928dcf..6a1a5ab 100644 --- a/index/componentized/logging-to-stdout/0.1.0/metadata.json +++ b/index/componentized/logging-to-stdout/0.1.0/metadata.json @@ -47,5 +47,6 @@ "version": "0.1.0-draft" } ], + "release": "https://github.com/componentized/logging/releases/tag/v0.1.0", "indexed_at": "2026-11-11T23:43:36Z" } diff --git a/index/componentized/logging-to-stdout/0.2.0/metadata.json b/index/componentized/logging-to-stdout/0.2.0/metadata.json index 25c12bb..550485d 100644 --- a/index/componentized/logging-to-stdout/0.2.0/metadata.json +++ b/index/componentized/logging-to-stdout/0.2.0/metadata.json @@ -47,5 +47,6 @@ "version": "0.1.0-draft" } ], + "release": "https://github.com/componentized/logging/releases/tag/v0.2.0", "indexed_at": "2026-11-11T23:43:37Z" } diff --git a/index/componentized/logging-to-stdout/0.2.1/metadata.json b/index/componentized/logging-to-stdout/0.2.1/metadata.json index efdd3cd..cc33bfc 100644 --- a/index/componentized/logging-to-stdout/0.2.1/metadata.json +++ b/index/componentized/logging-to-stdout/0.2.1/metadata.json @@ -47,5 +47,6 @@ "version": "0.1.0-draft" } ], + "release": "https://github.com/componentized/logging/releases/tag/v0.2.1", "indexed_at": "2026-11-11T23:43:37Z" } diff --git a/index/componentized/logging-to-stdout/0.3.0/metadata.json b/index/componentized/logging-to-stdout/0.3.0/metadata.json index 27bd7c9..32e19ff 100644 --- a/index/componentized/logging-to-stdout/0.3.0/metadata.json +++ b/index/componentized/logging-to-stdout/0.3.0/metadata.json @@ -51,5 +51,6 @@ "version": "0.1.0-draft" } ], + "release": "https://github.com/componentized/logging/releases/tag/v0.3.0", "indexed_at": "2026-11-11T23:43:37Z" } diff --git a/index/componentized/logging-to-stdout/0.3.1/metadata.json b/index/componentized/logging-to-stdout/0.3.1/metadata.json index 9d4833a..c7aadbc 100644 --- a/index/componentized/logging-to-stdout/0.3.1/metadata.json +++ b/index/componentized/logging-to-stdout/0.3.1/metadata.json @@ -51,5 +51,6 @@ "version": "0.1.0-draft" } ], + "release": "https://github.com/componentized/logging/releases/tag/v0.3.1", "indexed_at": "2026-11-11T23:43:38Z" } diff --git a/index/componentized/logging/0.3.0/metadata.json b/index/componentized/logging/0.3.0/metadata.json index 00df495..b7b868e 100644 --- a/index/componentized/logging/0.3.0/metadata.json +++ b/index/componentized/logging/0.3.0/metadata.json @@ -27,5 +27,6 @@ "version": "0.1.0-draft" } ], + "release": "https://github.com/componentized/logging/releases/tag/v0.3.0", "indexed_at": "2026-11-11T23:43:34Z" } diff --git a/index/componentized/logging/0.3.1/metadata.json b/index/componentized/logging/0.3.1/metadata.json index 224d54f..66890c1 100644 --- a/index/componentized/logging/0.3.1/metadata.json +++ b/index/componentized/logging/0.3.1/metadata.json @@ -27,5 +27,6 @@ "version": "0.1.0-draft" } ], + "release": "https://github.com/componentized/logging/releases/tag/v0.3.1", "indexed_at": "2026-11-11T23:43:34Z" } diff --git a/index/componentized/oci-client/0.1.0/metadata.json b/index/componentized/oci-client/0.1.0/metadata.json index 833a4af..585bd2a 100644 --- a/index/componentized/oci-client/0.1.0/metadata.json +++ b/index/componentized/oci-client/0.1.0/metadata.json @@ -51,5 +51,6 @@ "version": "0.3.0" } ], + "release": "https://github.com/componentized/oci/releases/tag/v0.1.0", "indexed_at": "2026-11-11T23:44:47Z" } diff --git a/index/componentized/oci-media-types/0.1.0/metadata.json b/index/componentized/oci-media-types/0.1.0/metadata.json index b07d6e5..817d6ab 100644 --- a/index/componentized/oci-media-types/0.1.0/metadata.json +++ b/index/componentized/oci-media-types/0.1.0/metadata.json @@ -30,5 +30,6 @@ "version": "0.1.0" } ], + "release": "https://github.com/componentized/oci/releases/tag/v0.1.0", "indexed_at": "2026-11-11T23:44:48Z" } diff --git a/index/componentized/oci/0.1.0/metadata.json b/index/componentized/oci/0.1.0/metadata.json index cf33052..6b001f2 100644 --- a/index/componentized/oci/0.1.0/metadata.json +++ b/index/componentized/oci/0.1.0/metadata.json @@ -27,5 +27,6 @@ "version": "0.3.0" } ], + "release": "https://github.com/componentized/oci/releases/tag/v0.1.0", "indexed_at": "2026-11-11T23:44:47Z" } diff --git a/index/componentized/services-credential-config/0.0.4/metadata.json b/index/componentized/services-credential-config/0.0.4/metadata.json index fd87293..ddc85d4 100644 --- a/index/componentized/services-credential-config/0.0.4/metadata.json +++ b/index/componentized/services-credential-config/0.0.4/metadata.json @@ -37,5 +37,6 @@ "version": "0.2.0-rc.1" } ], + "release": "https://github.com/componentized/services/releases/tag/v0.0.4", "indexed_at": "2026-11-11T23:44:49Z" } diff --git a/index/componentized/services-filesystem-credential-admin/0.0.4/metadata.json b/index/componentized/services-filesystem-credential-admin/0.0.4/metadata.json index d44d220..55618fb 100644 --- a/index/componentized/services-filesystem-credential-admin/0.0.4/metadata.json +++ b/index/componentized/services-filesystem-credential-admin/0.0.4/metadata.json @@ -74,5 +74,6 @@ "version": "0.2.6" } ], + "release": "https://github.com/componentized/services/releases/tag/v0.0.4", "indexed_at": "2026-11-11T23:44:51Z" } diff --git a/index/componentized/services-filesystem-credential-store/0.0.4/metadata.json b/index/componentized/services-filesystem-credential-store/0.0.4/metadata.json index 7b63bb5..e610788 100644 --- a/index/componentized/services-filesystem-credential-store/0.0.4/metadata.json +++ b/index/componentized/services-filesystem-credential-store/0.0.4/metadata.json @@ -79,5 +79,6 @@ "version": "0.2.6" } ], + "release": "https://github.com/componentized/services/releases/tag/v0.0.4", "indexed_at": "2026-11-11T23:44:52Z" } diff --git a/index/componentized/services-filesystem-lifecycle/0.0.4/metadata.json b/index/componentized/services-filesystem-lifecycle/0.0.4/metadata.json index a42f019..4ebed54 100644 --- a/index/componentized/services-filesystem-lifecycle/0.0.4/metadata.json +++ b/index/componentized/services-filesystem-lifecycle/0.0.4/metadata.json @@ -75,5 +75,6 @@ "version": "0.2.6" } ], + "release": "https://github.com/componentized/services/releases/tag/v0.0.4", "indexed_at": "2026-11-11T23:44:53Z" } diff --git a/index/componentized/services-keyvalue-credential-admin/0.0.4/metadata.json b/index/componentized/services-keyvalue-credential-admin/0.0.4/metadata.json index 31d95bd..c22a830 100644 --- a/index/componentized/services-keyvalue-credential-admin/0.0.4/metadata.json +++ b/index/componentized/services-keyvalue-credential-admin/0.0.4/metadata.json @@ -41,5 +41,6 @@ "version": "0.2.0-draft2" } ], + "release": "https://github.com/componentized/services/releases/tag/v0.0.4", "indexed_at": "2026-11-11T23:44:54Z" } diff --git a/index/componentized/services-keyvalue-credential-store/0.0.4/metadata.json b/index/componentized/services-keyvalue-credential-store/0.0.4/metadata.json index 1373b2a..73f4345 100644 --- a/index/componentized/services-keyvalue-credential-store/0.0.4/metadata.json +++ b/index/componentized/services-keyvalue-credential-store/0.0.4/metadata.json @@ -41,5 +41,6 @@ "version": "0.2.0-draft2" } ], + "release": "https://github.com/componentized/services/releases/tag/v0.0.4", "indexed_at": "2026-11-11T23:44:56Z" } diff --git a/index/componentized/services-lifecycle-host-cli/0.0.4/metadata.json b/index/componentized/services-lifecycle-host-cli/0.0.4/metadata.json index ed06a58..fdae59d 100644 --- a/index/componentized/services-lifecycle-host-cli/0.0.4/metadata.json +++ b/index/componentized/services-lifecycle-host-cli/0.0.4/metadata.json @@ -54,5 +54,6 @@ "version": "0.2.6" } ], + "release": "https://github.com/componentized/services/releases/tag/v0.0.4", "indexed_at": "2026-11-11T23:44:57Z" } diff --git a/index/componentized/services-lifecycle-host-http/0.0.4/metadata.json b/index/componentized/services-lifecycle-host-http/0.0.4/metadata.json index bddde8f..a081f14 100644 --- a/index/componentized/services-lifecycle-host-http/0.0.4/metadata.json +++ b/index/componentized/services-lifecycle-host-http/0.0.4/metadata.json @@ -48,5 +48,6 @@ "version": "0.1.0-draft" } ], + "release": "https://github.com/componentized/services/releases/tag/v0.0.4", "indexed_at": "2026-11-11T23:44:58Z" } diff --git a/index/componentized/services-valkey-lifecycle/0.0.4/metadata.json b/index/componentized/services-valkey-lifecycle/0.0.4/metadata.json index cf19b8f..a0bb255 100644 --- a/index/componentized/services-valkey-lifecycle/0.0.4/metadata.json +++ b/index/componentized/services-valkey-lifecycle/0.0.4/metadata.json @@ -65,5 +65,6 @@ "version": "0.2.6" } ], + "release": "https://github.com/componentized/services/releases/tag/v0.0.4", "indexed_at": "2026-11-11T23:44:59Z" } diff --git a/index/componentized/services-webhook-credential-admin/0.0.4/metadata.json b/index/componentized/services-webhook-credential-admin/0.0.4/metadata.json index 5d3d12b..bf8ca26 100644 --- a/index/componentized/services-webhook-credential-admin/0.0.4/metadata.json +++ b/index/componentized/services-webhook-credential-admin/0.0.4/metadata.json @@ -47,5 +47,6 @@ "version": "0.2.6" } ], + "release": "https://github.com/componentized/services/releases/tag/v0.0.4", "indexed_at": "2026-11-11T23:45:01Z" } diff --git a/index/componentized/services-webhook-credential-store/0.0.4/metadata.json b/index/componentized/services-webhook-credential-store/0.0.4/metadata.json index 271a16c..690a356 100644 --- a/index/componentized/services-webhook-credential-store/0.0.4/metadata.json +++ b/index/componentized/services-webhook-credential-store/0.0.4/metadata.json @@ -49,5 +49,6 @@ "version": "0.2.6" } ], + "release": "https://github.com/componentized/services/releases/tag/v0.0.4", "indexed_at": "2026-11-11T23:45:02Z" } diff --git a/index/componentized/services/0.0.4/metadata.json b/index/componentized/services/0.0.4/metadata.json index 5585fa2..ff38fd4 100644 --- a/index/componentized/services/0.0.4/metadata.json +++ b/index/componentized/services/0.0.4/metadata.json @@ -49,5 +49,6 @@ "version": "0.2.6" } ], + "release": "https://github.com/componentized/services/releases/tag/v0.0.4", "indexed_at": "2026-11-11T23:44:48Z" } diff --git a/index/componentized/sockets-gate-ip-name-lookup/0.1.0/metadata.json b/index/componentized/sockets-gate-ip-name-lookup/0.1.0/metadata.json index b0c4d3d..4b2fa72 100644 --- a/index/componentized/sockets-gate-ip-name-lookup/0.1.0/metadata.json +++ b/index/componentized/sockets-gate-ip-name-lookup/0.1.0/metadata.json @@ -52,5 +52,6 @@ "version": "0.3.0" } ], + "release": "https://github.com/componentized/sockets/releases/tag/v0.1.0", "indexed_at": "2026-11-11T23:45:03Z" } diff --git a/index/componentized/sockets-gate-types/0.1.0/metadata.json b/index/componentized/sockets-gate-types/0.1.0/metadata.json index 74e328e..4e0a062 100644 --- a/index/componentized/sockets-gate-types/0.1.0/metadata.json +++ b/index/componentized/sockets-gate-types/0.1.0/metadata.json @@ -56,5 +56,6 @@ "version": "0.3.0" } ], + "release": "https://github.com/componentized/sockets/releases/tag/v0.1.0", "indexed_at": "2026-11-11T23:45:04Z" } diff --git a/index/componentized/sockets-gate/0.1.0/metadata.json b/index/componentized/sockets-gate/0.1.0/metadata.json index c2d3ff1..d4df4c8 100644 --- a/index/componentized/sockets-gate/0.1.0/metadata.json +++ b/index/componentized/sockets-gate/0.1.0/metadata.json @@ -58,5 +58,6 @@ "version": "0.3.0" } ], + "release": "https://github.com/componentized/sockets/releases/tag/v0.1.0", "indexed_at": "2026-11-11T23:45:03Z" } diff --git a/index/componentized/sockets-latch-cidr-bind/0.1.0/metadata.json b/index/componentized/sockets-latch-cidr-bind/0.1.0/metadata.json index 323f5d0..b3cb08a 100644 --- a/index/componentized/sockets-latch-cidr-bind/0.1.0/metadata.json +++ b/index/componentized/sockets-latch-cidr-bind/0.1.0/metadata.json @@ -55,5 +55,6 @@ "version": "0.3.0" } ], + "release": "https://github.com/componentized/sockets/releases/tag/v0.1.0", "indexed_at": "2026-11-11T23:45:05Z" } diff --git a/index/componentized/sockets-latch-cidr-egress/0.1.0/metadata.json b/index/componentized/sockets-latch-cidr-egress/0.1.0/metadata.json index d97b6b8..8920b34 100644 --- a/index/componentized/sockets-latch-cidr-egress/0.1.0/metadata.json +++ b/index/componentized/sockets-latch-cidr-egress/0.1.0/metadata.json @@ -55,5 +55,6 @@ "version": "0.3.0" } ], + "release": "https://github.com/componentized/sockets/releases/tag/v0.1.0", "indexed_at": "2026-11-11T23:45:05Z" } diff --git a/index/componentized/sockets-latch-cidr-ingress/0.1.0/metadata.json b/index/componentized/sockets-latch-cidr-ingress/0.1.0/metadata.json index 32a5336..1f6fc78 100644 --- a/index/componentized/sockets-latch-cidr-ingress/0.1.0/metadata.json +++ b/index/componentized/sockets-latch-cidr-ingress/0.1.0/metadata.json @@ -55,5 +55,6 @@ "version": "0.3.0" } ], + "release": "https://github.com/componentized/sockets/releases/tag/v0.1.0", "indexed_at": "2026-11-11T23:45:06Z" } diff --git a/index/componentized/sockets-latch-cidr/0.1.0/metadata.json b/index/componentized/sockets-latch-cidr/0.1.0/metadata.json index baf1b87..92dea2c 100644 --- a/index/componentized/sockets-latch-cidr/0.1.0/metadata.json +++ b/index/componentized/sockets-latch-cidr/0.1.0/metadata.json @@ -55,5 +55,6 @@ "version": "0.3.0" } ], + "release": "https://github.com/componentized/sockets/releases/tag/v0.1.0", "indexed_at": "2026-11-11T23:45:04Z" } diff --git a/index/componentized/sockets-latch-defer-all/0.1.0/metadata.json b/index/componentized/sockets-latch-defer-all/0.1.0/metadata.json index 336ecc9..99b4601 100644 --- a/index/componentized/sockets-latch-defer-all/0.1.0/metadata.json +++ b/index/componentized/sockets-latch-defer-all/0.1.0/metadata.json @@ -45,5 +45,6 @@ "version": "0.3.0" } ], + "release": "https://github.com/componentized/sockets/releases/tag/v0.1.0", "indexed_at": "2026-11-11T23:45:06Z" } diff --git a/index/componentized/sockets-latch-delegate-tcp/0.1.0/metadata.json b/index/componentized/sockets-latch-delegate-tcp/0.1.0/metadata.json index 542e6ac..bd6a7c8 100644 --- a/index/componentized/sockets-latch-delegate-tcp/0.1.0/metadata.json +++ b/index/componentized/sockets-latch-delegate-tcp/0.1.0/metadata.json @@ -46,5 +46,6 @@ "version": "0.3.0" } ], + "release": "https://github.com/componentized/sockets/releases/tag/v0.1.0", "indexed_at": "2026-11-11T23:45:06Z" } diff --git a/index/componentized/sockets-latch-delegate-udp/0.1.0/metadata.json b/index/componentized/sockets-latch-delegate-udp/0.1.0/metadata.json index 7de3ea9..addf22e 100644 --- a/index/componentized/sockets-latch-delegate-udp/0.1.0/metadata.json +++ b/index/componentized/sockets-latch-delegate-udp/0.1.0/metadata.json @@ -46,5 +46,6 @@ "version": "0.3.0" } ], + "release": "https://github.com/componentized/sockets/releases/tag/v0.1.0", "indexed_at": "2026-11-11T23:45:07Z" } diff --git a/index/componentized/sockets-latch-deny-all/0.1.0/metadata.json b/index/componentized/sockets-latch-deny-all/0.1.0/metadata.json index f62462f..34ef222 100644 --- a/index/componentized/sockets-latch-deny-all/0.1.0/metadata.json +++ b/index/componentized/sockets-latch-deny-all/0.1.0/metadata.json @@ -45,5 +45,6 @@ "version": "0.3.0" } ], + "release": "https://github.com/componentized/sockets/releases/tag/v0.1.0", "indexed_at": "2026-11-11T23:45:07Z" } diff --git a/index/componentized/sockets-latch-deny-bind/0.1.0/metadata.json b/index/componentized/sockets-latch-deny-bind/0.1.0/metadata.json index 822fe56..0eff8a1 100644 --- a/index/componentized/sockets-latch-deny-bind/0.1.0/metadata.json +++ b/index/componentized/sockets-latch-deny-bind/0.1.0/metadata.json @@ -45,5 +45,6 @@ "version": "0.3.0" } ], + "release": "https://github.com/componentized/sockets/releases/tag/v0.1.0", "indexed_at": "2026-11-11T23:45:08Z" } diff --git a/index/componentized/sockets-latch-deny-connect-unless-lookup-address/0.1.0/metadata.json b/index/componentized/sockets-latch-deny-connect-unless-lookup-address/0.1.0/metadata.json index bd26a20..43b861f 100644 --- a/index/componentized/sockets-latch-deny-connect-unless-lookup-address/0.1.0/metadata.json +++ b/index/componentized/sockets-latch-deny-connect-unless-lookup-address/0.1.0/metadata.json @@ -45,5 +45,6 @@ "version": "0.3.0" } ], + "release": "https://github.com/componentized/sockets/releases/tag/v0.1.0", "indexed_at": "2026-11-11T23:45:09Z" } diff --git a/index/componentized/sockets-latch-deny-connect/0.1.0/metadata.json b/index/componentized/sockets-latch-deny-connect/0.1.0/metadata.json index e6b0a70..664479d 100644 --- a/index/componentized/sockets-latch-deny-connect/0.1.0/metadata.json +++ b/index/componentized/sockets-latch-deny-connect/0.1.0/metadata.json @@ -45,5 +45,6 @@ "version": "0.3.0" } ], + "release": "https://github.com/componentized/sockets/releases/tag/v0.1.0", "indexed_at": "2026-11-11T23:45:08Z" } diff --git a/index/componentized/sockets-latch-deny-ip-name-lookup-config/0.1.0/metadata.json b/index/componentized/sockets-latch-deny-ip-name-lookup-config/0.1.0/metadata.json index fc386d1..c7c0df3 100644 --- a/index/componentized/sockets-latch-deny-ip-name-lookup-config/0.1.0/metadata.json +++ b/index/componentized/sockets-latch-deny-ip-name-lookup-config/0.1.0/metadata.json @@ -38,5 +38,6 @@ "version": "0.2.0-rc.1" } ], + "release": "https://github.com/componentized/sockets/releases/tag/v0.1.0", "indexed_at": "2026-11-11T23:45:09Z" } diff --git a/index/componentized/sockets-latch-deny-ip-name-lookup/0.1.0/metadata.json b/index/componentized/sockets-latch-deny-ip-name-lookup/0.1.0/metadata.json index 0d0c302..f6db78c 100644 --- a/index/componentized/sockets-latch-deny-ip-name-lookup/0.1.0/metadata.json +++ b/index/componentized/sockets-latch-deny-ip-name-lookup/0.1.0/metadata.json @@ -50,5 +50,6 @@ "version": "0.3.0" } ], + "release": "https://github.com/componentized/sockets/releases/tag/v0.1.0", "indexed_at": "2026-11-11T23:45:09Z" } diff --git a/index/componentized/sockets-latch-deny-ipv4/0.1.0/metadata.json b/index/componentized/sockets-latch-deny-ipv4/0.1.0/metadata.json index 2f23c26..907ffa2 100644 --- a/index/componentized/sockets-latch-deny-ipv4/0.1.0/metadata.json +++ b/index/componentized/sockets-latch-deny-ipv4/0.1.0/metadata.json @@ -45,5 +45,6 @@ "version": "0.3.0" } ], + "release": "https://github.com/componentized/sockets/releases/tag/v0.1.0", "indexed_at": "2026-11-11T23:45:10Z" } diff --git a/index/componentized/sockets-latch-deny-ipv6/0.1.0/metadata.json b/index/componentized/sockets-latch-deny-ipv6/0.1.0/metadata.json index afe4336..a8cd7df 100644 --- a/index/componentized/sockets-latch-deny-ipv6/0.1.0/metadata.json +++ b/index/componentized/sockets-latch-deny-ipv6/0.1.0/metadata.json @@ -45,5 +45,6 @@ "version": "0.3.0" } ], + "release": "https://github.com/componentized/sockets/releases/tag/v0.1.0", "indexed_at": "2026-11-11T23:45:10Z" } diff --git a/index/componentized/sockets-latch-deny-private-networks-cidr-config/0.1.0/metadata.json b/index/componentized/sockets-latch-deny-private-networks-cidr-config/0.1.0/metadata.json index 25da214..ce46050 100644 --- a/index/componentized/sockets-latch-deny-private-networks-cidr-config/0.1.0/metadata.json +++ b/index/componentized/sockets-latch-deny-private-networks-cidr-config/0.1.0/metadata.json @@ -38,5 +38,6 @@ "version": "0.2.0-rc.1" } ], + "release": "https://github.com/componentized/sockets/releases/tag/v0.1.0", "indexed_at": "2026-11-11T23:45:11Z" } diff --git a/index/componentized/sockets-latch-deny-random/0.1.0/metadata.json b/index/componentized/sockets-latch-deny-random/0.1.0/metadata.json index e933a22..9380308 100644 --- a/index/componentized/sockets-latch-deny-random/0.1.0/metadata.json +++ b/index/componentized/sockets-latch-deny-random/0.1.0/metadata.json @@ -60,5 +60,6 @@ "version": "0.3.0" } ], + "release": "https://github.com/componentized/sockets/releases/tag/v0.1.0", "indexed_at": "2026-11-11T23:45:11Z" } diff --git a/index/componentized/sockets-latch-deny-tcp/0.1.0/metadata.json b/index/componentized/sockets-latch-deny-tcp/0.1.0/metadata.json index 4d16890..3562364 100644 --- a/index/componentized/sockets-latch-deny-tcp/0.1.0/metadata.json +++ b/index/componentized/sockets-latch-deny-tcp/0.1.0/metadata.json @@ -45,5 +45,6 @@ "version": "0.3.0" } ], + "release": "https://github.com/componentized/sockets/releases/tag/v0.1.0", "indexed_at": "2026-11-11T23:45:12Z" } diff --git a/index/componentized/sockets-latch-deny-udp/0.1.0/metadata.json b/index/componentized/sockets-latch-deny-udp/0.1.0/metadata.json index e8fd844..2402f5c 100644 --- a/index/componentized/sockets-latch-deny-udp/0.1.0/metadata.json +++ b/index/componentized/sockets-latch-deny-udp/0.1.0/metadata.json @@ -45,5 +45,6 @@ "version": "0.3.0" } ], + "release": "https://github.com/componentized/sockets/releases/tag/v0.1.0", "indexed_at": "2026-11-11T23:45:12Z" } diff --git a/index/componentized/sockets-latch-dry-run/0.1.0/metadata.json b/index/componentized/sockets-latch-dry-run/0.1.0/metadata.json index 4858844..5e7db5a 100644 --- a/index/componentized/sockets-latch-dry-run/0.1.0/metadata.json +++ b/index/componentized/sockets-latch-dry-run/0.1.0/metadata.json @@ -51,5 +51,6 @@ "version": "0.3.0" } ], + "release": "https://github.com/componentized/sockets/releases/tag/v0.1.0", "indexed_at": "2026-11-11T23:45:12Z" } diff --git a/index/componentized/sockets-latch-ip-name-lookup-glob/0.1.0/metadata.json b/index/componentized/sockets-latch-ip-name-lookup-glob/0.1.0/metadata.json index 7ffa426..82ec194 100644 --- a/index/componentized/sockets-latch-ip-name-lookup-glob/0.1.0/metadata.json +++ b/index/componentized/sockets-latch-ip-name-lookup-glob/0.1.0/metadata.json @@ -55,5 +55,6 @@ "version": "0.3.0" } ], + "release": "https://github.com/componentized/sockets/releases/tag/v0.1.0", "indexed_at": "2026-11-11T23:45:13Z" } diff --git a/index/componentized/sockets-latch-n2/0.1.0/metadata.json b/index/componentized/sockets-latch-n2/0.1.0/metadata.json index 9c9bc80..ec84882 100644 --- a/index/componentized/sockets-latch-n2/0.1.0/metadata.json +++ b/index/componentized/sockets-latch-n2/0.1.0/metadata.json @@ -47,5 +47,6 @@ "version": "0.3.0" } ], + "release": "https://github.com/componentized/sockets/releases/tag/v0.1.0", "indexed_at": "2026-11-11T23:45:13Z" } diff --git a/index/componentized/sockets-latch-n3/0.1.0/metadata.json b/index/componentized/sockets-latch-n3/0.1.0/metadata.json index c0a5867..9bd18fa 100644 --- a/index/componentized/sockets-latch-n3/0.1.0/metadata.json +++ b/index/componentized/sockets-latch-n3/0.1.0/metadata.json @@ -48,5 +48,6 @@ "version": "0.3.0" } ], + "release": "https://github.com/componentized/sockets/releases/tag/v0.1.0", "indexed_at": "2026-11-11T23:45:14Z" } diff --git a/index/componentized/sockets-latch-n4/0.1.0/metadata.json b/index/componentized/sockets-latch-n4/0.1.0/metadata.json index c944dfe..f15c0df 100644 --- a/index/componentized/sockets-latch-n4/0.1.0/metadata.json +++ b/index/componentized/sockets-latch-n4/0.1.0/metadata.json @@ -49,5 +49,6 @@ "version": "0.3.0" } ], + "release": "https://github.com/componentized/sockets/releases/tag/v0.1.0", "indexed_at": "2026-11-11T23:45:14Z" } diff --git a/index/componentized/sockets-latch-n5/0.1.0/metadata.json b/index/componentized/sockets-latch-n5/0.1.0/metadata.json index d80d82d..5b07b15 100644 --- a/index/componentized/sockets-latch-n5/0.1.0/metadata.json +++ b/index/componentized/sockets-latch-n5/0.1.0/metadata.json @@ -50,5 +50,6 @@ "version": "0.3.0" } ], + "release": "https://github.com/componentized/sockets/releases/tag/v0.1.0", "indexed_at": "2026-11-11T23:45:15Z" } diff --git a/index/componentized/sockets-latch-trace/0.1.0/metadata.json b/index/componentized/sockets-latch-trace/0.1.0/metadata.json index 6310056..83d1b5a 100644 --- a/index/componentized/sockets-latch-trace/0.1.0/metadata.json +++ b/index/componentized/sockets-latch-trace/0.1.0/metadata.json @@ -51,5 +51,6 @@ "version": "0.3.0" } ], + "release": "https://github.com/componentized/sockets/releases/tag/v0.1.0", "indexed_at": "2026-11-11T23:45:15Z" } diff --git a/index/componentized/sockets-trace-ip-name-lookup/0.1.0/metadata.json b/index/componentized/sockets-trace-ip-name-lookup/0.1.0/metadata.json index d24c188..c03f29a 100644 --- a/index/componentized/sockets-trace-ip-name-lookup/0.1.0/metadata.json +++ b/index/componentized/sockets-trace-ip-name-lookup/0.1.0/metadata.json @@ -47,5 +47,6 @@ "version": "0.3.0" } ], + "release": "https://github.com/componentized/sockets/releases/tag/v0.1.0", "indexed_at": "2026-11-11T23:45:17Z" } diff --git a/index/componentized/sockets-trace-types/0.1.0/metadata.json b/index/componentized/sockets-trace-types/0.1.0/metadata.json index 4c60252..d2ad613 100644 --- a/index/componentized/sockets-trace-types/0.1.0/metadata.json +++ b/index/componentized/sockets-trace-types/0.1.0/metadata.json @@ -51,5 +51,6 @@ "version": "0.3.0" } ], + "release": "https://github.com/componentized/sockets/releases/tag/v0.1.0", "indexed_at": "2026-11-11T23:45:17Z" } diff --git a/index/componentized/sockets-trace/0.1.0/metadata.json b/index/componentized/sockets-trace/0.1.0/metadata.json index 82cb4d9..323125e 100644 --- a/index/componentized/sockets-trace/0.1.0/metadata.json +++ b/index/componentized/sockets-trace/0.1.0/metadata.json @@ -53,5 +53,6 @@ "version": "0.3.0" } ], + "release": "https://github.com/componentized/sockets/releases/tag/v0.1.0", "indexed_at": "2026-11-11T23:45:16Z" } diff --git a/index/componentized/sockets/0.1.0/metadata.json b/index/componentized/sockets/0.1.0/metadata.json index f9e3fd5..c1f7c4c 100644 --- a/index/componentized/sockets/0.1.0/metadata.json +++ b/index/componentized/sockets/0.1.0/metadata.json @@ -31,5 +31,6 @@ "version": "0.3.0" } ], + "release": "https://github.com/componentized/sockets/releases/tag/v0.1.0", "indexed_at": "2026-11-11T23:45:02Z" } diff --git a/index/componentized/static-config-factory/0.1.0/metadata.json b/index/componentized/static-config-factory/0.1.0/metadata.json index 12dee8e..4851c78 100644 --- a/index/componentized/static-config-factory/0.1.0/metadata.json +++ b/index/componentized/static-config-factory/0.1.0/metadata.json @@ -28,5 +28,6 @@ "version": null } ], + "release": "https://github.com/componentized/static-config/releases/tag/v0.1.0", "indexed_at": "2026-11-11T23:45:18Z" } diff --git a/index/componentized/static-config-factory/0.2.0/metadata.json b/index/componentized/static-config-factory/0.2.0/metadata.json index 7d07582..6cbad32 100644 --- a/index/componentized/static-config-factory/0.2.0/metadata.json +++ b/index/componentized/static-config-factory/0.2.0/metadata.json @@ -28,5 +28,6 @@ "version": null } ], + "release": "https://github.com/componentized/static-config/releases/tag/v0.2.0", "indexed_at": "2026-11-11T23:45:19Z" } diff --git a/index/componentized/static-config-factory/0.3.0/metadata.json b/index/componentized/static-config-factory/0.3.0/metadata.json index eb29d71..a1b721e 100644 --- a/index/componentized/static-config-factory/0.3.0/metadata.json +++ b/index/componentized/static-config-factory/0.3.0/metadata.json @@ -45,5 +45,6 @@ "version": "0.3.0" } ], + "release": "https://github.com/componentized/static-config/releases/tag/v0.3.0", "indexed_at": "2026-11-11T23:45:19Z" } diff --git a/index/componentized/static-config/0.3.0/metadata.json b/index/componentized/static-config/0.3.0/metadata.json index 640e759..d10bef5 100644 --- a/index/componentized/static-config/0.3.0/metadata.json +++ b/index/componentized/static-config/0.3.0/metadata.json @@ -27,5 +27,6 @@ "version": "0.1.0" } ], + "release": "https://github.com/componentized/static-config/releases/tag/v0.3.0", "indexed_at": "2026-11-11T23:45:18Z" } diff --git a/index/componentized/valkey-as-keyvalue/0.1.0/metadata.json b/index/componentized/valkey-as-keyvalue/0.1.0/metadata.json index e219e53..843ac90 100644 --- a/index/componentized/valkey-as-keyvalue/0.1.0/metadata.json +++ b/index/componentized/valkey-as-keyvalue/0.1.0/metadata.json @@ -44,5 +44,6 @@ "version": "0.2.0-draft2" } ], + "release": "https://github.com/componentized/valkey/releases/tag/v0.1.0", "indexed_at": "2026-11-11T23:45:21Z" } diff --git a/index/componentized/valkey-as-keyvalue/0.1.1/metadata.json b/index/componentized/valkey-as-keyvalue/0.1.1/metadata.json index 8ba65d9..047a406 100644 --- a/index/componentized/valkey-as-keyvalue/0.1.1/metadata.json +++ b/index/componentized/valkey-as-keyvalue/0.1.1/metadata.json @@ -44,5 +44,6 @@ "version": "0.2.0-draft2" } ], + "release": "https://github.com/componentized/valkey/releases/tag/v0.1.1", "indexed_at": "2026-11-11T23:45:21Z" } diff --git a/index/componentized/valkey-as-keyvalue/0.2.0/metadata.json b/index/componentized/valkey-as-keyvalue/0.2.0/metadata.json index 1e74f48..d67a705 100644 --- a/index/componentized/valkey-as-keyvalue/0.2.0/metadata.json +++ b/index/componentized/valkey-as-keyvalue/0.2.0/metadata.json @@ -44,5 +44,6 @@ "version": "0.2.0-draft2" } ], + "release": "https://github.com/componentized/valkey/releases/tag/v0.2.0", "indexed_at": "2026-11-11T23:45:22Z" } diff --git a/index/componentized/valkey-as-keyvalue/0.2.1/metadata.json b/index/componentized/valkey-as-keyvalue/0.2.1/metadata.json index 18a04f8..c59ab63 100644 --- a/index/componentized/valkey-as-keyvalue/0.2.1/metadata.json +++ b/index/componentized/valkey-as-keyvalue/0.2.1/metadata.json @@ -44,5 +44,6 @@ "version": "0.2.0-draft2" } ], + "release": "https://github.com/componentized/valkey/releases/tag/v0.2.1", "indexed_at": "2026-11-11T23:45:22Z" } diff --git a/index/componentized/valkey-as-keyvalue/0.2.2/metadata.json b/index/componentized/valkey-as-keyvalue/0.2.2/metadata.json index 5c1eadc..e40f83e 100644 --- a/index/componentized/valkey-as-keyvalue/0.2.2/metadata.json +++ b/index/componentized/valkey-as-keyvalue/0.2.2/metadata.json @@ -44,5 +44,6 @@ "version": "0.2.0-draft2" } ], + "release": "https://github.com/componentized/valkey/releases/tag/v0.2.2", "indexed_at": "2026-11-11T23:45:22Z" } diff --git a/index/componentized/valkey-cli/0.1.0/metadata.json b/index/componentized/valkey-cli/0.1.0/metadata.json index cc47b05..f606315 100644 --- a/index/componentized/valkey-cli/0.1.0/metadata.json +++ b/index/componentized/valkey-cli/0.1.0/metadata.json @@ -73,5 +73,6 @@ "version": "0.2.3" } ], + "release": "https://github.com/componentized/valkey/releases/tag/v0.1.0", "indexed_at": "2026-11-11T23:45:23Z" } diff --git a/index/componentized/valkey-cli/0.1.1/metadata.json b/index/componentized/valkey-cli/0.1.1/metadata.json index bbd1467..3d32e2a 100644 --- a/index/componentized/valkey-cli/0.1.1/metadata.json +++ b/index/componentized/valkey-cli/0.1.1/metadata.json @@ -68,5 +68,6 @@ "version": "0.2.3" } ], + "release": "https://github.com/componentized/valkey/releases/tag/v0.1.1", "indexed_at": "2026-11-11T23:45:23Z" } diff --git a/index/componentized/valkey-cli/0.2.0/metadata.json b/index/componentized/valkey-cli/0.2.0/metadata.json index 776b85a..b004c0b 100644 --- a/index/componentized/valkey-cli/0.2.0/metadata.json +++ b/index/componentized/valkey-cli/0.2.0/metadata.json @@ -69,5 +69,6 @@ "version": "0.2.3" } ], + "release": "https://github.com/componentized/valkey/releases/tag/v0.2.0", "indexed_at": "2026-11-11T23:45:23Z" } diff --git a/index/componentized/valkey-cli/0.2.1/metadata.json b/index/componentized/valkey-cli/0.2.1/metadata.json index 0a67cae..3e3fcbf 100644 --- a/index/componentized/valkey-cli/0.2.1/metadata.json +++ b/index/componentized/valkey-cli/0.2.1/metadata.json @@ -63,5 +63,6 @@ "version": "0.2.6" } ], + "release": "https://github.com/componentized/valkey/releases/tag/v0.2.1", "indexed_at": "2026-11-11T23:45:24Z" } diff --git a/index/componentized/valkey-cli/0.2.2/metadata.json b/index/componentized/valkey-cli/0.2.2/metadata.json index 0dd8e17..9d5609a 100644 --- a/index/componentized/valkey-cli/0.2.2/metadata.json +++ b/index/componentized/valkey-cli/0.2.2/metadata.json @@ -63,5 +63,6 @@ "version": "0.2.6" } ], + "release": "https://github.com/componentized/valkey/releases/tag/v0.2.2", "indexed_at": "2026-11-11T23:45:24Z" } diff --git a/index/componentized/valkey-client/0.1.0/metadata.json b/index/componentized/valkey-client/0.1.0/metadata.json index c94528d..02ac8dc 100644 --- a/index/componentized/valkey-client/0.1.0/metadata.json +++ b/index/componentized/valkey-client/0.1.0/metadata.json @@ -60,5 +60,6 @@ "version": "0.2.3" } ], + "release": "https://github.com/componentized/valkey/releases/tag/v0.1.0", "indexed_at": "2026-11-11T23:45:24Z" } diff --git a/index/componentized/valkey-client/0.1.1/metadata.json b/index/componentized/valkey-client/0.1.1/metadata.json index 282603e..a02b366 100644 --- a/index/componentized/valkey-client/0.1.1/metadata.json +++ b/index/componentized/valkey-client/0.1.1/metadata.json @@ -60,5 +60,6 @@ "version": "0.2.3" } ], + "release": "https://github.com/componentized/valkey/releases/tag/v0.1.1", "indexed_at": "2026-11-11T23:45:25Z" } diff --git a/index/componentized/valkey-client/0.2.0/metadata.json b/index/componentized/valkey-client/0.2.0/metadata.json index 5e5dadf..08a6580 100644 --- a/index/componentized/valkey-client/0.2.0/metadata.json +++ b/index/componentized/valkey-client/0.2.0/metadata.json @@ -60,5 +60,6 @@ "version": "0.2.3" } ], + "release": "https://github.com/componentized/valkey/releases/tag/v0.2.0", "indexed_at": "2026-11-11T23:45:25Z" } diff --git a/index/componentized/valkey-client/0.2.1/metadata.json b/index/componentized/valkey-client/0.2.1/metadata.json index aad9d29..65c8b0c 100644 --- a/index/componentized/valkey-client/0.2.1/metadata.json +++ b/index/componentized/valkey-client/0.2.1/metadata.json @@ -60,5 +60,6 @@ "version": "0.2.6" } ], + "release": "https://github.com/componentized/valkey/releases/tag/v0.2.1", "indexed_at": "2026-11-11T23:45:25Z" } diff --git a/index/componentized/valkey-client/0.2.2/metadata.json b/index/componentized/valkey-client/0.2.2/metadata.json index 4cf1413..4624a5c 100644 --- a/index/componentized/valkey-client/0.2.2/metadata.json +++ b/index/componentized/valkey-client/0.2.2/metadata.json @@ -60,5 +60,6 @@ "version": "0.2.6" } ], + "release": "https://github.com/componentized/valkey/releases/tag/v0.2.2", "indexed_at": "2026-11-11T23:45:26Z" } diff --git a/index/componentized/valkey-sample-http-incrementor/0.1.1/metadata.json b/index/componentized/valkey-sample-http-incrementor/0.1.1/metadata.json index a1892d9..bc99861 100644 --- a/index/componentized/valkey-sample-http-incrementor/0.1.1/metadata.json +++ b/index/componentized/valkey-sample-http-incrementor/0.1.1/metadata.json @@ -44,5 +44,6 @@ "version": "0.2.0-draft2" } ], + "release": "https://github.com/componentized/valkey/releases/tag/v0.1.1", "indexed_at": "2026-11-11T23:45:26Z" } diff --git a/index/componentized/valkey-sample-http-incrementor/0.2.0/metadata.json b/index/componentized/valkey-sample-http-incrementor/0.2.0/metadata.json index 106eadb..db6a4a7 100644 --- a/index/componentized/valkey-sample-http-incrementor/0.2.0/metadata.json +++ b/index/componentized/valkey-sample-http-incrementor/0.2.0/metadata.json @@ -44,5 +44,6 @@ "version": "0.2.0-draft2" } ], + "release": "https://github.com/componentized/valkey/releases/tag/v0.2.0", "indexed_at": "2026-11-11T23:45:27Z" } diff --git a/index/componentized/valkey-sample-http-incrementor/0.2.1/metadata.json b/index/componentized/valkey-sample-http-incrementor/0.2.1/metadata.json index c4da158..8769030 100644 --- a/index/componentized/valkey-sample-http-incrementor/0.2.1/metadata.json +++ b/index/componentized/valkey-sample-http-incrementor/0.2.1/metadata.json @@ -44,5 +44,6 @@ "version": "0.2.0-draft2" } ], + "release": "https://github.com/componentized/valkey/releases/tag/v0.2.1", "indexed_at": "2026-11-11T23:45:27Z" } diff --git a/index/componentized/valkey-sample-http-incrementor/0.2.2/metadata.json b/index/componentized/valkey-sample-http-incrementor/0.2.2/metadata.json index 9d65fa8..36ea349 100644 --- a/index/componentized/valkey-sample-http-incrementor/0.2.2/metadata.json +++ b/index/componentized/valkey-sample-http-incrementor/0.2.2/metadata.json @@ -44,5 +44,6 @@ "version": "0.2.0-draft2" } ], + "release": "https://github.com/componentized/valkey/releases/tag/v0.2.2", "indexed_at": "2026-11-11T23:45:27Z" } diff --git a/index/componentized/valkey/0.1.0/metadata.json b/index/componentized/valkey/0.1.0/metadata.json index 8ebc467..3fe4bb0 100644 --- a/index/componentized/valkey/0.1.0/metadata.json +++ b/index/componentized/valkey/0.1.0/metadata.json @@ -20,5 +20,6 @@ "org.opencontainers.image.title": "interface", "org.opencontainers.image.version": "v0.1.0" }, + "release": "https://github.com/componentized/valkey/releases/tag/v0.1.0", "indexed_at": "2026-11-11T23:45:20Z" } diff --git a/index/componentized/valkey/0.1.1/metadata.json b/index/componentized/valkey/0.1.1/metadata.json index 4c52d00..4552f85 100644 --- a/index/componentized/valkey/0.1.1/metadata.json +++ b/index/componentized/valkey/0.1.1/metadata.json @@ -20,5 +20,6 @@ "org.opencontainers.image.title": "interface", "org.opencontainers.image.version": "v0.1.1" }, + "release": "https://github.com/componentized/valkey/releases/tag/v0.1.1", "indexed_at": "2026-11-11T23:45:20Z" } diff --git a/index/componentized/valkey/0.2.0/metadata.json b/index/componentized/valkey/0.2.0/metadata.json index f385609..230828c 100644 --- a/index/componentized/valkey/0.2.0/metadata.json +++ b/index/componentized/valkey/0.2.0/metadata.json @@ -20,5 +20,6 @@ "org.opencontainers.image.title": "interface", "org.opencontainers.image.version": "v0.2.0" }, + "release": "https://github.com/componentized/valkey/releases/tag/v0.2.0", "indexed_at": "2026-11-11T23:45:20Z" } diff --git a/index/componentized/valkey/0.2.1/metadata.json b/index/componentized/valkey/0.2.1/metadata.json index 813b18d..33649d5 100644 --- a/index/componentized/valkey/0.2.1/metadata.json +++ b/index/componentized/valkey/0.2.1/metadata.json @@ -20,5 +20,6 @@ "org.opencontainers.image.title": "interface", "org.opencontainers.image.version": "v0.2.1" }, + "release": "https://github.com/componentized/valkey/releases/tag/v0.2.1", "indexed_at": "2026-11-11T23:45:20Z" } diff --git a/index/componentized/valkey/0.2.2/metadata.json b/index/componentized/valkey/0.2.2/metadata.json index 3fd0fc2..a3d6f27 100644 --- a/index/componentized/valkey/0.2.2/metadata.json +++ b/index/componentized/valkey/0.2.2/metadata.json @@ -20,5 +20,6 @@ "org.opencontainers.image.title": "interface", "org.opencontainers.image.version": "v0.2.2" }, + "release": "https://github.com/componentized/valkey/releases/tag/v0.2.2", "indexed_at": "2026-11-11T23:45:21Z" } diff --git a/index/wasi/cli/0.2.12/metadata.json b/index/wasi/cli/0.2.12/metadata.json index f22a187..c1d2450 100644 --- a/index/wasi/cli/0.2.12/metadata.json +++ b/index/wasi/cli/0.2.12/metadata.json @@ -41,5 +41,6 @@ "version": "0.2.12" } ], + "release": "https://github.com/WebAssembly/WASI/releases/tag/v0.2.12", "indexed_at": "2026-11-12T00:13:37Z" } diff --git a/index/wasi/cli/0.2.3/metadata.json b/index/wasi/cli/0.2.3/metadata.json index e9ac21a..a56801d 100644 --- a/index/wasi/cli/0.2.3/metadata.json +++ b/index/wasi/cli/0.2.3/metadata.json @@ -41,5 +41,6 @@ "version": "0.2.3" } ], + "release": "https://github.com/WebAssembly/WASI/releases/tag/v0.2.3", "indexed_at": "2026-11-11T23:43:38Z" } diff --git a/index/wasi/cli/0.2.6/metadata.json b/index/wasi/cli/0.2.6/metadata.json index c4f3cda..1a9ef46 100644 --- a/index/wasi/cli/0.2.6/metadata.json +++ b/index/wasi/cli/0.2.6/metadata.json @@ -41,5 +41,6 @@ "version": "0.2.6" } ], + "release": "https://github.com/WebAssembly/WASI/releases/tag/v0.2.6", "indexed_at": "2026-11-11T23:43:38Z" } diff --git a/index/wasi/cli/0.3.0/metadata.json b/index/wasi/cli/0.3.0/metadata.json index c249419..8689ac1 100644 --- a/index/wasi/cli/0.3.0/metadata.json +++ b/index/wasi/cli/0.3.0/metadata.json @@ -37,5 +37,6 @@ "version": "0.3.0" } ], + "release": "https://github.com/WebAssembly/WASI/releases/tag/v0.3.0", "indexed_at": "2026-11-11T23:43:38Z" } diff --git a/index/wasi/clocks/0.2.12/metadata.json b/index/wasi/clocks/0.2.12/metadata.json index 2155d24..e8d1972 100644 --- a/index/wasi/clocks/0.2.12/metadata.json +++ b/index/wasi/clocks/0.2.12/metadata.json @@ -25,5 +25,6 @@ "version": "0.2.12" } ], + "release": "https://github.com/WebAssembly/WASI/releases/tag/v0.2.12", "indexed_at": "2026-11-12T00:13:38Z" } diff --git a/index/wasi/clocks/0.2.3/metadata.json b/index/wasi/clocks/0.2.3/metadata.json index fd8cf82..b5dd238 100644 --- a/index/wasi/clocks/0.2.3/metadata.json +++ b/index/wasi/clocks/0.2.3/metadata.json @@ -25,5 +25,6 @@ "version": "0.2.3" } ], + "release": "https://github.com/WebAssembly/WASI/releases/tag/v0.2.3", "indexed_at": "2026-11-11T23:43:39Z" } diff --git a/index/wasi/clocks/0.2.6/metadata.json b/index/wasi/clocks/0.2.6/metadata.json index dd87b23..a605b01 100644 --- a/index/wasi/clocks/0.2.6/metadata.json +++ b/index/wasi/clocks/0.2.6/metadata.json @@ -25,5 +25,6 @@ "version": "0.2.6" } ], + "release": "https://github.com/WebAssembly/WASI/releases/tag/v0.2.6", "indexed_at": "2026-11-11T23:43:39Z" } diff --git a/index/wasi/clocks/0.3.0/metadata.json b/index/wasi/clocks/0.3.0/metadata.json index 038f9d9..0463f46 100644 --- a/index/wasi/clocks/0.3.0/metadata.json +++ b/index/wasi/clocks/0.3.0/metadata.json @@ -19,5 +19,6 @@ "org.opencontainers.image.url": "https://wasi.dev", "org.opencontainers.image.version": "0.3.0" }, + "release": "https://github.com/WebAssembly/WASI/releases/tag/v0.3.0", "indexed_at": "2026-11-11T23:43:39Z" } diff --git a/index/wasi/filesystem/0.2.12/metadata.json b/index/wasi/filesystem/0.2.12/metadata.json index 3668151..58dab40 100644 --- a/index/wasi/filesystem/0.2.12/metadata.json +++ b/index/wasi/filesystem/0.2.12/metadata.json @@ -29,5 +29,6 @@ "version": "0.2.12" } ], + "release": "https://github.com/WebAssembly/WASI/releases/tag/v0.2.12", "indexed_at": "2026-11-12T00:13:38Z" } diff --git a/index/wasi/filesystem/0.2.3/metadata.json b/index/wasi/filesystem/0.2.3/metadata.json index d5b3c26..9e8e2fd 100644 --- a/index/wasi/filesystem/0.2.3/metadata.json +++ b/index/wasi/filesystem/0.2.3/metadata.json @@ -29,5 +29,6 @@ "version": "0.2.3" } ], + "release": "https://github.com/WebAssembly/WASI/releases/tag/v0.2.3", "indexed_at": "2026-11-11T23:43:41Z" } diff --git a/index/wasi/filesystem/0.2.6/metadata.json b/index/wasi/filesystem/0.2.6/metadata.json index 40f9071..9aef904 100644 --- a/index/wasi/filesystem/0.2.6/metadata.json +++ b/index/wasi/filesystem/0.2.6/metadata.json @@ -29,5 +29,6 @@ "version": "0.2.6" } ], + "release": "https://github.com/WebAssembly/WASI/releases/tag/v0.2.6", "indexed_at": "2026-11-11T23:43:41Z" } diff --git a/index/wasi/filesystem/0.3.0/metadata.json b/index/wasi/filesystem/0.3.0/metadata.json index 4fc1d27..ca0fe55 100644 --- a/index/wasi/filesystem/0.3.0/metadata.json +++ b/index/wasi/filesystem/0.3.0/metadata.json @@ -25,5 +25,6 @@ "version": "0.3.0" } ], + "release": "https://github.com/WebAssembly/WASI/releases/tag/v0.3.0", "indexed_at": "2026-11-11T23:43:41Z" } diff --git a/index/wasi/http/0.2.3/metadata.json b/index/wasi/http/0.2.3/metadata.json index 3f61aaa..ab184d0 100644 --- a/index/wasi/http/0.2.3/metadata.json +++ b/index/wasi/http/0.2.3/metadata.json @@ -37,5 +37,6 @@ "version": "0.2.3" } ], + "release": "https://github.com/WebAssembly/WASI/releases/tag/v0.2.3", "indexed_at": "2026-11-11T23:45:29Z" } diff --git a/index/wasi/http/0.2.6/metadata.json b/index/wasi/http/0.2.6/metadata.json index b215a2e..99c561b 100644 --- a/index/wasi/http/0.2.6/metadata.json +++ b/index/wasi/http/0.2.6/metadata.json @@ -37,5 +37,6 @@ "version": "0.2.6" } ], + "release": "https://github.com/WebAssembly/WASI/releases/tag/v0.2.6", "indexed_at": "2026-11-11T23:45:29Z" } diff --git a/index/wasi/http/0.3.0/metadata.json b/index/wasi/http/0.3.0/metadata.json index 7102f81..9917cf4 100644 --- a/index/wasi/http/0.3.0/metadata.json +++ b/index/wasi/http/0.3.0/metadata.json @@ -33,5 +33,6 @@ "version": "0.3.0" } ], + "release": "https://github.com/WebAssembly/WASI/releases/tag/v0.3.0", "indexed_at": "2026-11-11T23:45:29Z" } diff --git a/index/wasi/io/0.2.12/metadata.json b/index/wasi/io/0.2.12/metadata.json index b4d96a9..f274c37 100644 --- a/index/wasi/io/0.2.12/metadata.json +++ b/index/wasi/io/0.2.12/metadata.json @@ -19,5 +19,6 @@ "org.opencontainers.image.url": "https://wasi.dev", "org.opencontainers.image.version": "0.2.12" }, + "release": "https://github.com/WebAssembly/WASI/releases/tag/v0.2.12", "indexed_at": "2026-11-12T00:13:38Z" } diff --git a/index/wasi/io/0.2.3/metadata.json b/index/wasi/io/0.2.3/metadata.json index 9e4d2f9..6303dd0 100644 --- a/index/wasi/io/0.2.3/metadata.json +++ b/index/wasi/io/0.2.3/metadata.json @@ -19,5 +19,6 @@ "org.opencontainers.image.url": "https://wasi.dev", "org.opencontainers.image.version": "0.2.3" }, + "release": "https://github.com/WebAssembly/WASI/releases/tag/v0.2.3", "indexed_at": "2026-11-11T23:43:40Z" } diff --git a/index/wasi/io/0.2.6/metadata.json b/index/wasi/io/0.2.6/metadata.json index b668f66..23da130 100644 --- a/index/wasi/io/0.2.6/metadata.json +++ b/index/wasi/io/0.2.6/metadata.json @@ -19,5 +19,6 @@ "org.opencontainers.image.url": "https://wasi.dev", "org.opencontainers.image.version": "0.2.6" }, + "release": "https://github.com/WebAssembly/WASI/releases/tag/v0.2.6", "indexed_at": "2026-11-11T23:43:40Z" } diff --git a/index/wasi/random/0.2.12/metadata.json b/index/wasi/random/0.2.12/metadata.json index 4ff156b..030b8b8 100644 --- a/index/wasi/random/0.2.12/metadata.json +++ b/index/wasi/random/0.2.12/metadata.json @@ -19,5 +19,6 @@ "org.opencontainers.image.url": "https://wasi.dev", "org.opencontainers.image.version": "0.2.12" }, + "release": "https://github.com/WebAssembly/WASI/releases/tag/v0.2.12", "indexed_at": "2026-11-12T00:13:39Z" } diff --git a/index/wasi/random/0.2.3/metadata.json b/index/wasi/random/0.2.3/metadata.json index 8350e76..0cef5cf 100644 --- a/index/wasi/random/0.2.3/metadata.json +++ b/index/wasi/random/0.2.3/metadata.json @@ -19,5 +19,6 @@ "org.opencontainers.image.url": "https://wasi.dev", "org.opencontainers.image.version": "0.2.3" }, + "release": "https://github.com/WebAssembly/WASI/releases/tag/v0.2.3", "indexed_at": "2026-11-11T23:43:41Z" } diff --git a/index/wasi/random/0.2.6/metadata.json b/index/wasi/random/0.2.6/metadata.json index ff628db..1ca1a97 100644 --- a/index/wasi/random/0.2.6/metadata.json +++ b/index/wasi/random/0.2.6/metadata.json @@ -19,5 +19,6 @@ "org.opencontainers.image.url": "https://wasi.dev", "org.opencontainers.image.version": "0.2.6" }, + "release": "https://github.com/WebAssembly/WASI/releases/tag/v0.2.6", "indexed_at": "2026-11-11T23:43:42Z" } diff --git a/index/wasi/random/0.3.0/metadata.json b/index/wasi/random/0.3.0/metadata.json index be5963b..a7cd592 100644 --- a/index/wasi/random/0.3.0/metadata.json +++ b/index/wasi/random/0.3.0/metadata.json @@ -19,5 +19,6 @@ "org.opencontainers.image.url": "https://wasi.dev", "org.opencontainers.image.version": "0.3.0" }, + "release": "https://github.com/WebAssembly/WASI/releases/tag/v0.3.0", "indexed_at": "2026-11-11T23:43:42Z" } diff --git a/index/wasi/sockets/0.2.12/metadata.json b/index/wasi/sockets/0.2.12/metadata.json index dc70a39..65a3cd4 100644 --- a/index/wasi/sockets/0.2.12/metadata.json +++ b/index/wasi/sockets/0.2.12/metadata.json @@ -29,5 +29,6 @@ "version": "0.2.12" } ], + "release": "https://github.com/WebAssembly/WASI/releases/tag/v0.2.12", "indexed_at": "2026-11-12T00:13:40Z" } diff --git a/index/wasi/sockets/0.2.3/metadata.json b/index/wasi/sockets/0.2.3/metadata.json index 7ccca1c..3d45936 100644 --- a/index/wasi/sockets/0.2.3/metadata.json +++ b/index/wasi/sockets/0.2.3/metadata.json @@ -29,5 +29,6 @@ "version": "0.2.3" } ], + "release": "https://github.com/WebAssembly/WASI/releases/tag/v0.2.3", "indexed_at": "2026-11-11T23:43:42Z" } diff --git a/index/wasi/sockets/0.2.6/metadata.json b/index/wasi/sockets/0.2.6/metadata.json index 7b2fade..742df78 100644 --- a/index/wasi/sockets/0.2.6/metadata.json +++ b/index/wasi/sockets/0.2.6/metadata.json @@ -29,5 +29,6 @@ "version": "0.2.6" } ], + "release": "https://github.com/WebAssembly/WASI/releases/tag/v0.2.6", "indexed_at": "2026-11-11T23:43:42Z" } diff --git a/index/wasi/sockets/0.3.0/metadata.json b/index/wasi/sockets/0.3.0/metadata.json index dc7b3f2..41e9136 100644 --- a/index/wasi/sockets/0.3.0/metadata.json +++ b/index/wasi/sockets/0.3.0/metadata.json @@ -25,5 +25,6 @@ "version": "0.3.0" } ], + "release": "https://github.com/WebAssembly/WASI/releases/tag/v0.3.0", "indexed_at": "2026-11-11T23:43:43Z" } diff --git a/samples/kitchen-sink/everything/0.1.0/metadata.json b/samples/kitchen-sink/everything/0.1.0/metadata.json new file mode 100644 index 0000000..ca668e6 --- /dev/null +++ b/samples/kitchen-sink/everything/0.1.0/metadata.json @@ -0,0 +1,29 @@ +{ + "package": "kitchen-sink:everything", + "version": "0.1.0", + "kind": "component", + "origin": "synthetic", + "oci": { + "registry": "synthetic.invalid", + "repository": "kitchen-sink/everything", + "tag": "0.1.0", + "digest": "sha256:0000000000000000000000000000000000000000000000000000000000000000", + "layer_digest": "sha256:0000000000000000000000000000000000000000000000000000000000000000", + "size": 0 + }, + "created": "2026-11-12T00:00:00Z", + "annotations": { + "org.opencontainers.image.description": "A component that imports and exports each kind of world item. Synthetic: not published to any registry." + }, + "dependencies": [ + { + "package": "kitchen-sink:types", + "version": "0.1.0" + }, + { + "package": "kitchen-sink:extras", + "version": "0.1.0" + } + ], + "indexed_at": "2026-11-12T00:00:00Z" +} diff --git a/samples/kitchen-sink/everything/0.1.0/world.wit b/samples/kitchen-sink/everything/0.1.0/world.wit new file mode 100644 index 0000000..76113c6 --- /dev/null +++ b/samples/kitchen-sink/everything/0.1.0/world.wit @@ -0,0 +1,16 @@ +package root:component; + +world root { + import kitchen-sink:types/primitives@0.1.0; + import pictures: kitchen-sink:types/resources@0.1.0; + import inline: interface { + ping: func() -> bool; + } + import log: func(message: string); + import sleep: async func(ms: u64); + + export kitchen-sink:extras/greeter@0.1.0; + export kitchen-sink:types/concurrency@0.1.0; + export run: func(args: list) -> result; + export serve: async func() -> result<_, string>; +} diff --git a/samples/kitchen-sink/everything/0.2.0-dev/metadata.json b/samples/kitchen-sink/everything/0.2.0-dev/metadata.json new file mode 100644 index 0000000..13756ec --- /dev/null +++ b/samples/kitchen-sink/everything/0.2.0-dev/metadata.json @@ -0,0 +1,29 @@ +{ + "package": "kitchen-sink:everything", + "version": "0.2.0-dev", + "kind": "component", + "origin": "synthetic", + "oci": { + "registry": "synthetic.invalid", + "repository": "kitchen-sink/everything", + "tag": "0.2.0-dev", + "digest": "sha256:0000000000000000000000000000000000000000000000000000000000000000", + "layer_digest": "sha256:0000000000000000000000000000000000000000000000000000000000000000", + "size": 0 + }, + "created": "2026-11-12T00:00:00Z", + "annotations": { + "org.opencontainers.image.description": "A development build of the component. Synthetic: not published to any registry." + }, + "dependencies": [ + { + "package": "kitchen-sink:types", + "version": "0.1.0" + }, + { + "package": "kitchen-sink:extras", + "version": "0.1.0" + } + ], + "indexed_at": "2026-11-12T00:00:00Z" +} diff --git a/samples/kitchen-sink/everything/0.2.0-dev/world.wit b/samples/kitchen-sink/everything/0.2.0-dev/world.wit new file mode 100644 index 0000000..76113c6 --- /dev/null +++ b/samples/kitchen-sink/everything/0.2.0-dev/world.wit @@ -0,0 +1,16 @@ +package root:component; + +world root { + import kitchen-sink:types/primitives@0.1.0; + import pictures: kitchen-sink:types/resources@0.1.0; + import inline: interface { + ping: func() -> bool; + } + import log: func(message: string); + import sleep: async func(ms: u64); + + export kitchen-sink:extras/greeter@0.1.0; + export kitchen-sink:types/concurrency@0.1.0; + export run: func(args: list) -> result; + export serve: async func() -> result<_, string>; +} diff --git a/samples/kitchen-sink/extras/0.1.0/metadata.json b/samples/kitchen-sink/extras/0.1.0/metadata.json new file mode 100644 index 0000000..1714915 --- /dev/null +++ b/samples/kitchen-sink/extras/0.1.0/metadata.json @@ -0,0 +1,25 @@ +{ + "package": "kitchen-sink:extras", + "version": "0.1.0", + "kind": "interface", + "origin": "synthetic", + "oci": { + "registry": "synthetic.invalid", + "repository": "kitchen-sink/extras", + "tag": "0.1.0", + "digest": "sha256:0000000000000000000000000000000000000000000000000000000000000000", + "layer_digest": "sha256:0000000000000000000000000000000000000000000000000000000000000000", + "size": 0 + }, + "created": "2026-11-12T00:00:00Z", + "annotations": { + "org.opencontainers.image.description": "Uses and includes items from another package. Synthetic: not published to any registry." + }, + "dependencies": [ + { + "package": "kitchen-sink:types", + "version": "0.1.0" + } + ], + "indexed_at": "2026-11-12T00:00:00Z" +} diff --git a/samples/kitchen-sink/extras/0.1.0/package.wit b/samples/kitchen-sink/extras/0.1.0/package.wit new file mode 100644 index 0000000..2d089ab --- /dev/null +++ b/samples/kitchen-sink/extras/0.1.0/package.wit @@ -0,0 +1,23 @@ +/// Uses and includes items from another package. +/// +/// A synthetic package: it isn't published to any registry. +package kitchen-sink:extras@0.1.0; + +/// Uses types from another package, one under a new name. +interface greeter { + use kitchen-sink:types/shapes@0.1.0.{point, direction as heading}; + use kitchen-sink:types/resources@0.1.0.{canvas}; + + /// Greets a point, facing a heading. + greet: func(name: string, at: point, facing: heading) -> string; + /// Draws a greeting. + draw: func(on: borrow, name: string); +} + +/// Includes a world from another package, and imports one of its interfaces. +world greeting { + include kitchen-sink:types/base@0.1.0; + import kitchen-sink:types/gates@0.1.0; + + export greeter; +} diff --git a/samples/kitchen-sink/types/0.1.0/metadata.json b/samples/kitchen-sink/types/0.1.0/metadata.json new file mode 100644 index 0000000..e1ff80a --- /dev/null +++ b/samples/kitchen-sink/types/0.1.0/metadata.json @@ -0,0 +1,19 @@ +{ + "package": "kitchen-sink:types", + "version": "0.1.0", + "kind": "interface", + "origin": "synthetic", + "oci": { + "registry": "synthetic.invalid", + "repository": "kitchen-sink/types", + "tag": "0.1.0", + "digest": "sha256:0000000000000000000000000000000000000000000000000000000000000000", + "layer_digest": "sha256:0000000000000000000000000000000000000000000000000000000000000000", + "size": 0 + }, + "created": "2026-11-12T00:00:00Z", + "annotations": { + "org.opencontainers.image.description": "Every kind of WIT type, function and gate. Synthetic: not published to any registry." + }, + "indexed_at": "2026-11-12T00:00:00Z" +} diff --git a/samples/kitchen-sink/types/0.1.0/package.wit b/samples/kitchen-sink/types/0.1.0/package.wit new file mode 100644 index 0000000..4fa619e --- /dev/null +++ b/samples/kitchen-sink/types/0.1.0/package.wit @@ -0,0 +1,242 @@ +/// Every kind of WIT type, function and gate, to check how the directory renders each one. +/// +/// A synthetic package: it isn't published to any registry. +package kitchen-sink:types@0.1.0; + +/// Each primitive type, by an alias of its own. +interface primitives { + type a-bool = bool; + type an-s8 = s8; + type an-s16 = s16; + type an-s32 = s32; + type an-s64 = s64; + type a-u8 = u8; + type a-u16 = u16; + type a-u32 = u32; + type a-u64 = u64; + type an-f32 = f32; + type an-f64 = f64; + type a-char = char; + type a-string = string; +} + +/// The generic types, alone and nested. +interface containers { + use primitives.{a-u8, a-string as text}; + + type bytes = list; + type rgba = list; + type pair = tuple; + type maybe = option; + type lookup = map>; + type nested = option>>>; + + type no-payload = result; + type ok-only = result; + type err-only = result<_, text>; + type ok-and-err = result; +} + +/// Records, variants, enums and flags. +interface shapes { + use containers.{pair, maybe}; + + /// A point on a plane. + record point { + /// Across. + x: f64, + /// Down. + y: f64, + } + + /// A record of other types. + record labeled { + label: maybe, + at: point, + tags: list, + pair: pair, + } + + record empty-ish { + only: bool, + } + + /// A shape, with or without a payload. + variant shape { + /// A point has no size. + dot, + circle(f64), + rectangle(tuple), + polygon(list), + } + + /// The cardinal directions. + enum direction { + north, + east, + south, + west, + } + + /// A file's permissions. + flags permissions { + read, + write, + execute, + } + + /// An alias of an alias. + type heading = direction; + + /** A block comment documents too. */ + area: func(s: shape) -> f64; + /// A keyword as a name, escaped with `%`. + turn: func(%from: direction, quarter-turns: s8) -> direction; + allowed: func(have: permissions, want: permissions) -> bool; +} + +/// Resources and each kind of function on them. +interface resources { + use shapes.{point}; + + /// A resource with no functions. + resource token; + + /// A resource with every kind of member. + resource canvas { + /// Makes an empty canvas. + constructor(width: u32, height: u32); + + /// A method. + plot: func(at: point, color: list); + /// A method that borrows another canvas. + copy-from: func(other: borrow) -> result<_, string>; + /// A method that hands back a resource it owns. + snapshot: func() -> own; + /// An async method. + render: async func() -> list; + + /// A static function. + open: static func(path: string) -> result; + /// A static async function. + load: static async func(url: string) -> result; + + /// A property with a getter and a setter. + title: get() -> string; + title: set(value: string); + /// A property with a getter alone. + area: get() -> u64; + /// A static property. + max-size: static get() -> u32; + max-size: static set(value: u32) -> result<_, string>; + } + + /// A free function taking and returning resources. + merge: func(a: own, b: borrow) -> canvas; + /// A free function that names the resource without `own`. + issue: func() -> token; +} + +/// Futures, streams and error contexts, and async functions. +interface concurrency { + use resources.{canvas}; + + type signal = future; + type eventually = future>; + type ticks = stream; + type bytes = stream; + type frames = stream; + type failure = error-context; + + /// An async function. + fetch: async func(url: string) -> result, error-context>; + /// A function that returns a stream and a future of its end. + watch: func(path: string) -> tuple, future>; + /// A function with neither params nor results. + tick: func(); + /// An async function with neither params nor results. + wait: async func(); +} + +/// Features gated by version and by feature. +@since(version = 0.1.0) +interface gates { + @since(version = 0.1.0) + record since-record { + value: u32, + } + + @unstable(feature = experimental) + record unstable-record { + value: u32, + } + + @since(version = 0.1.0) + @deprecated(version = 0.1.0) + record deprecated-record { + value: u32, + } + + @unstable(feature = experimental) + resource unstable-resource { + @unstable(feature = experimental) + constructor(); + @unstable(feature = experimental) + poke: func(); + } + + @since(version = 0.1.0) + stable: func(); + @unstable(feature = experimental) + unstable: func(); + @since(version = 0.1.0) + @deprecated(version = 0.1.0) + deprecated: func(); +} + +/// Imports each kind of world item. +world base { + /// An interface, by its path in the package. + import primitives; + /// An interface under a name of its own. + import pictures: resources; + /// An inline interface. + import inline: interface { + use shapes.{point}; + + ping: func(at: point) -> bool; + } + /// A function. + import log: func(message: string); + /// An async function. + import sleep: async func(ms: u64); + /// A property of the world. + import volume: get() -> u8; + import volume: set(value: u8); + + /// A type used from an interface into the world. + use shapes.{direction}; + /// A type defined in the world. + type compass = direction; + /// A world-level resource. + resource session { + constructor(); + end: func(); + } + + export concurrency; + export run: func(args: list) -> result; +} + +/// Includes another world, renaming one of its items. +world extended { + include base with { log as trace } + + @unstable(feature = experimental) + import gates; + + export serve: async func() -> result<_, string>; +} + +/// A world with nothing in it. +world empty {} diff --git a/src/data.rs b/src/data.rs index 8b95499..40ea2e8 100644 --- a/src/data.rs +++ b/src/data.rs @@ -31,6 +31,9 @@ pub enum Origin { Release, /// A version a release depends on, e.g. a WASI pre-release. Dependency, + /// A sample made up to show how each WIT feature renders, e.g. the `kitchen-sink` + /// namespace. It's in `samples/`, never the index, and isn't published to any registry. + Synthetic, } #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] @@ -94,6 +97,11 @@ pub struct Metadata { pub exports: Vec, #[serde(default, skip_serializing_if = "Vec::is_empty")] pub dependencies: Vec, + /// The GitHub release of the version in its source repository, tagged with the version, e.g. + /// `https://github.com/componentized/logging/releases/tag/v0.3.1`. A scan looks for it until + /// it's found, as a release can be published after its packages. + #[serde(default, skip_serializing_if = "Option::is_none")] + pub release: Option, pub indexed_at: String, } diff --git a/src/http.rs b/src/http.rs index d424847..33a05d2 100644 --- a/src/http.rs +++ b/src/http.rs @@ -302,6 +302,28 @@ impl GitHub { Self { client, token } } + /// GETs a single resource, `None` when the endpoint answers 403 or 404. + pub fn get(&self, path: &str) -> Result> { + let url = format!("https://api.github.com{path}"); + let mut request = self + .client + .get(&url) + .header(ACCEPT, "application/vnd.github+json") + .header("X-GitHub-Api-Version", "2022-11-28"); + if let Some(token) = &self.token { + request = request.header(AUTHORIZATION, format!("Bearer {token}")); + } + let response = request.send()?; + match response.status() { + StatusCode::NOT_FOUND + | StatusCode::FORBIDDEN + | StatusCode::UNAUTHORIZED + | StatusCode::UNPROCESSABLE_ENTITY => Ok(None), + status if !status.is_success() => bail!("GET {url}: {status}"), + _ => Ok(Some(response.json()?)), + } + } + /// GETs every page of a list endpoint, `None` when the endpoint answers 403 or 404. pub fn list(&self, path: &str) -> Result>> { let mut items = Vec::new(); diff --git a/src/main.rs b/src/main.rs index 9859be1..cedc9a6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -53,6 +53,10 @@ enum Command { /// The URL the site is served from, for canonical links #[arg(long, default_value = "https://directory.componentized.dev")] base_url: String, + /// Synthetic packages, laid out like the index, whose pages are rendered but not listed, + /// counted or linked from the index's pages + #[arg(long, default_value = "samples")] + samples: PathBuf, }, } @@ -73,6 +77,10 @@ fn main() -> Result<()> { only, registries: config::Config::load(&config)?, }), - Command::Build { out, base_url } => site::build(&cli.data, &out, &base_url), + Command::Build { + out, + base_url, + samples, + } => site::build(&cli.data, &samples, &out, &base_url), } } diff --git a/src/scan.rs b/src/scan.rs index 6cee56d..afb7a45 100644 --- a/src/scan.rs +++ b/src/scan.rs @@ -62,6 +62,9 @@ pub fn run(options: &Options) -> Result<()> { scanner.dependencies()?; trim_nested(&options.root)?; refresh_items(&options.root)?; + if let Err(err) = refresh_releases(&options.root, &github) { + scanner.fail("the GitHub releases".to_string(), err); + } eprintln!("indexed {} new versions", scanner.added.len()); for added in &scanner.added { @@ -73,6 +76,91 @@ pub fn run(options: &Options) -> Result<()> { Ok(()) } +/// Links each stable version to the GitHub release of its source repository tagged with the +/// version, `v0.3.1` or else `0.3.1`. A repository's releases are listed once, and only while one +/// of its stable versions has no release recorded: a release can be published after its packages +/// are indexed. Dev versions have no releases. A repository that isn't on GitHub, or whose releases +/// can't be listed, e.g. without a token past the rate limit, is skipped. +/// +/// A version that records the commit it was built from is linked only when the release's tag is +/// that commit: a repository can tag versions of something else, e.g. `wasmCloud/wasmCloud` tags +/// its host's versions, not those of the `wasmcloud:keyvalue` package it publishes. +fn refresh_releases(root: &std::path::Path, github: &GitHub) -> Result<()> { + #[derive(Deserialize)] + struct Release { + tag_name: String, + html_url: String, + #[serde(default)] + draft: bool, + } + #[derive(Deserialize)] + struct Commit { + sha: String, + } + + let stored = data::load(root)?; + // the versions still without a release, by the repository they're built from + let mut pending: std::collections::BTreeMap> = Default::default(); + for stored in &stored { + let meta = &stored.metadata; + if meta.release.is_some() || version::stable(&meta.version).is_none() { + continue; + } + let Some(repo) = meta.annotation("source").and_then(github_repo) else { + continue; + }; + pending.entry(repo).or_default().push(stored); + } + let mut linked = 0; + for (repo, versions) in pending { + let Some(releases) = github.list::(&format!("/repos/{repo}/releases"))? else { + continue; + }; + let tags: HashMap<&str, &str> = releases + .iter() + .filter(|release| !release.draft) + .map(|release| (release.tag_name.as_str(), release.html_url.as_str())) + .collect(); + for stored in versions { + let version = &stored.metadata.version; + let tagged = format!("v{version}"); + let Some((tag, url)) = [tagged.as_str(), version.as_str()] + .into_iter() + .find_map(|tag| tags.get(tag).map(|url| (tag, *url))) + else { + continue; + }; + if let Some(revision) = stored.metadata.annotation("revision") { + let revision = revision.trim_end_matches("+dirty"); + let commit = github.get::(&format!("/repos/{repo}/commits/{tag}"))?; + if !commit.is_some_and(|commit| commit.sha.starts_with(revision)) { + continue; + } + } + let mut metadata = stored.metadata.clone(); + metadata.release = Some(url.to_string()); + data::write(root, &metadata, &stored.wit)?; + linked += 1; + } + } + if linked > 0 { + eprintln!("linked {linked} indexed versions to their GitHub releases"); + } + Ok(()) +} + +/// The `owner/repo` of a source repository on GitHub, e.g. `componentized/logging` for +/// `https://github.com/componentized/logging.git`. +fn github_repo(source: &str) -> Option { + let path = source + .trim_end_matches('/') + .trim_end_matches(".git") + .strip_prefix("https://github.com/")?; + let (owner, repo) = path.split_once('/')?; + (!owner.is_empty() && !repo.is_empty() && !repo.contains('/')) + .then(|| format!("{owner}/{repo}")) +} + /// Re-derives the imports and exports of the indexed components from their stored WIT, updating /// metadata written by an older scan, e.g. before named imports recorded the interface they alias. fn refresh_items(root: &std::path::Path) -> Result<()> { @@ -457,6 +545,7 @@ impl Scanner<'_> { imports: decoded.imports, exports: decoded.exports, dependencies: decoded.dependencies, + release: None, indexed_at: chrono::Utc::now().to_rfc3339_opts(chrono::SecondsFormat::Secs, true), }; let dir = data::write(&self.options.root, &metadata, &decoded.wit)?; @@ -501,3 +590,32 @@ impl Scanner<'_> { )) } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn finds_the_github_repository_of_a_source() { + for source in [ + "https://github.com/componentized/logging", + "https://github.com/componentized/logging.git", + "https://github.com/componentized/logging/", + ] { + assert_eq!( + github_repo(source).as_deref(), + Some("componentized/logging"), + "{source}" + ); + } + assert_eq!( + github_repo("https://gitlab.com/componentized/logging"), + None + ); + assert_eq!(github_repo("https://github.com/componentized"), None); + assert_eq!( + github_repo("https://github.com/componentized/logging/tree/main"), + None + ); + } +} diff --git a/src/site.rs b/src/site.rs index c055e38..16be46f 100644 --- a/src/site.rs +++ b/src/site.rs @@ -151,14 +151,6 @@ struct Repo { } impl Repo { - fn url(&self) -> String { - format!("/repos/{}/", self.key) - } - - fn version_url(&self, version: &str) -> String { - format!("/repos/{}/{version}/", self.key) - } - /// A dev version is superseded once the repository releases its version. fn superseded(&self, version: &str) -> bool { version::release_of(version) @@ -174,21 +166,20 @@ impl Repo { } } -pub fn build(root: &Path, out: &Path, base_url: &str) -> Result<()> { - let mut entries = Vec::new(); +pub fn build(root: &Path, samples: &Path, out: &Path, base_url: &str) -> Result<()> { let stored = data::load(root)?; - let loader = Loader::new(&stored); - for (index, stored) in stored.iter().enumerate() { - let (resolve, pkg) = loader.resolve(index)?; - entries.push(Entry { - meta: stored.metadata.clone(), - nested: resolve::has_nested(&stored.wit), - resolve, - pkg, - }); + if let Some(sample) = stored + .iter() + .find(|s| s.metadata.origin == Origin::Synthetic) + { + bail!( + "{} is synthetic, it belongs in the samples rather than the index", + sample.dir.display() + ); } let updated = last_indexed(stored.iter().map(|s| s.metadata.indexed_at.as_str())); - let site = Site::new(entries); + let site = Site::new(entries(&stored)?); + let samples = load_samples(samples, &site)?; prepare(out)?; let mut env = environment()?; @@ -213,6 +204,9 @@ pub fn build(root: &Path, out: &Path, base_url: &str) -> Result<()> { search => fingerprint(include_str!("../static/search.js")), theme => fingerprint(include_str!("../static/theme.js")), toc => fingerprint(include_str!("../static/toc.js")), + pivot => fingerprint(include_str!("../static/pivot.js")), + head => fingerprint(include_str!("../static/head.js")), + copy => fingerprint(include_str!("../static/copy.js")), }, ); @@ -229,6 +223,9 @@ pub fn build(root: &Path, out: &Path, base_url: &str) -> Result<()> { write_file(out, "search.js", include_str!("../static/search.js"))?; write_file(out, "theme.js", include_str!("../static/theme.js"))?; write_file(out, "toc.js", include_str!("../static/toc.js"))?; + write_file(out, "pivot.js", include_str!("../static/pivot.js"))?; + write_file(out, "head.js", include_str!("../static/head.js"))?; + write_file(out, "copy.js", include_str!("../static/copy.js"))?; write_file(out, "search.json", &serde_json::to_string(&site.search())?)?; write_file( out, @@ -245,26 +242,79 @@ pub fn build(root: &Path, out: &Path, base_url: &str) -> Result<()> { "404.html", &env.get_template("404.html")?.render(ctx! {})?, )?; - write_file( - out, - "repos/index.html", - &env.get_template("repos.html")?.render(site.repos_page())?, - )?; - for repo in site.repos.values() { - for (at, (version, _)) in repo.versions.iter().enumerate() { - let page = env - .get_template("repo.html")? - .render(site.repo_page(repo, at))?; - write_file( - out, - &format!("{}index.html", repo.version_url(version)), - &page, - )?; - if at == repo.latest() { - write_file(out, &format!("{}index.html", repo.url()), &page)?; - } + render_packages(&site, &env, out)?; + eprintln!( + "rendered {} packages, {} versions to {}", + site.packages.len(), + site.entries.len(), + out.display() + ); + if let Some(samples) = samples { + // the samples are a site of their own, so the index's pages never list, count or link + // them, while their pages are published like any other + let mut env = env.clone(); + env.add_global("synthetic", true); + render_packages(&samples, &env, out)?; + eprintln!( + "rendered {} synthetic sample packages, {} versions", + samples.packages.len(), + samples.entries.len() + ); + } + Ok(()) +} + +/// Resolves each stored version for rendering. +fn entries(stored: &[data::Stored]) -> Result> { + let loader = Loader::new(stored); + let mut entries = Vec::new(); + for (index, stored) in stored.iter().enumerate() { + let (resolve, pkg) = loader.resolve(index)?; + entries.push(Entry { + meta: stored.metadata.clone(), + nested: resolve::has_nested(&stored.wit), + resolve, + pkg, + }); + } + Ok(entries) +} + +/// Loads the synthetic samples as a site of their own, `None` when there are none. +fn load_samples(dir: &Path, site: &Site) -> Result> { + let stored = data::load(dir)?; + if stored.is_empty() { + return Ok(None); + } + for sample in &stored { + if sample.metadata.origin != Origin::Synthetic { + bail!( + "{} is in the samples, but its origin isn't synthetic", + sample.dir.display() + ); + } + let namespace = data::split_id(&sample.metadata.package).map_or("", |(ns, _)| ns); + if site.entries.iter().any(|e| e.namespace() == namespace) { + bail!( + "{} is in the {namespace} namespace, which the index holds as well", + sample.dir.display() + ); } } + let mut entries = entries(&stored)?; + // a component's imports and exports come from its WIT, as a scan derives them for the index + for entry in &mut entries { + if entry.meta.kind == Kind::Component { + let (imports, exports) = decode::component_items(&entry.resolve, entry.pkg)?; + entry.meta.imports = imports; + entry.meta.exports = exports; + } + } + Ok(Some(Site::new(entries))) +} + +/// Renders the page of each namespace, package version and interface of a site. +fn render_packages(site: &Site, env: &Environment, out: &Path) -> Result<()> { for (namespace, ctx) in site.namespaces() { write_file( out, @@ -292,12 +342,6 @@ pub fn build(root: &Path, out: &Path, base_url: &str) -> Result<()> { } } } - eprintln!( - "rendered {} packages, {} versions to {}", - site.packages.len(), - site.entries.len(), - out.display() - ); Ok(()) } @@ -368,33 +412,84 @@ fn environment() -> Result> { include_str!("../templates/interface.html"), ), ("404.html", include_str!("../templates/404.html")), - ("repos.html", include_str!("../templates/repos.html")), - ("repo.html", include_str!("../templates/repo.html")), ] { env.add_template(name, source)?; } Ok(env) } -fn markdown(src: &str) -> String { +/// Renders markdown docs that sit under a heading of the page at level `under`, e.g. 3 for the docs +/// of a type under its `

`. Their headings are moved to fit under it: the docs' top level +/// becomes `under + 1`, the levels below it follow, and none goes deeper than `

`. The WASI +/// docs, e.g., start a function's "Typical errors" with an `

`. +fn markdown(src: &str, under: usize) -> String { + use pulldown_cmark::{Event, HeadingLevel, Tag, TagEnd}; + let events: Vec<_> = pulldown_cmark::Parser::new(src).collect(); + let top = events + .iter() + .filter_map(|event| match event { + Event::Start(Tag::Heading { level, .. }) => Some(*level as usize), + _ => None, + }) + .min(); + let fit = |level: HeadingLevel| -> HeadingLevel { + let top = top.unwrap_or(level as usize); + HeadingLevel::try_from((level as usize - top + under + 1).min(6)).unwrap_or(level) + }; + let events = events.into_iter().map(|event| match event { + Event::Start(Tag::Heading { + level, + id, + classes, + attrs, + }) => Event::Start(Tag::Heading { + level: fit(level), + id, + classes, + attrs, + }), + Event::End(TagEnd::Heading(level)) => Event::End(TagEnd::Heading(fit(level))), + event => event, + }); let mut html = String::new(); - pulldown_cmark::html::push_html(&mut html, pulldown_cmark::Parser::new(src)); + pulldown_cmark::html::push_html(&mut html, events); html } -fn docs(docs: &wit_parser::Docs) -> String { - docs.contents.as_deref().map(markdown).unwrap_or_default() +/// Renders docs that sit under a heading of the page at level `under`, see [`markdown`]. +fn docs(docs: &wit_parser::Docs, under: usize) -> String { + docs.contents + .as_deref() + .map(|src| markdown(src, under)) + .unwrap_or_default() } fn summary(src: &str) -> String { src.split("\n\n").next().unwrap_or("").replace('\n', " ") } +/// The page of a commit of a repository on GitHub, e.g. +/// `https://github.com/componentized/cli/commit/465de9402d6d…`. `None` for another host, whose +/// commit pages differ. +fn commit_url(web: &str, revision: &str) -> Option { + web.starts_with("https://github.com/") + .then(|| format!("{web}/commit/{revision}")) +} + +/// A link to a GitHub release, labeled with its tag, e.g. `v0.3.1` for +/// `https://github.com/componentized/logging/releases/tag/v0.3.1`. +fn release_link(url: &str) -> minijinja::Value { + let tag = url.rsplit_once("/tag/").map_or(url, |(_, tag)| tag); + ctx! { url, tag } +} + /// The versions of one package, e.g. the dependents `componentized:logging-levels@0.3.1` and /// `componentized:logging-levels@0.3.0`. #[derive(Serialize, Debug, PartialEq)] struct VersionGroup { package: String, + /// The kind its icon shows, `interface`, `component` or `world`, set by [`Site::grouped`]. + kind: &'static str, /// Each version, labeled with the version alone, newest first. versions: Vec, } @@ -415,6 +510,7 @@ fn group_versions(links: Vec) -> Vec { Some(group) => group.versions.push(versioned), None => groups.push(VersionGroup { package, + kind: "", versions: vec![versioned], }), } @@ -469,8 +565,16 @@ struct RepoCard { struct WorldView { name: String, docs: String, - imports: Vec, - exports: Vec, + imports: Vec, + exports: Vec, +} + +/// An item a world imports or exports, with the kind its icon shows: `interface` or `func`. +#[derive(Serialize)] +struct WorldItemLink { + #[serde(flatten)] + link: Link, + kind: &'static str, } #[derive(Serialize)] @@ -482,6 +586,19 @@ struct InterfaceSummary { stability: Option, } +/// A choice in a breadcrumb's menu, e.g. another package of the namespace. +#[derive(Serialize)] +struct Pivot { + label: String, + url: String, + current: bool, + /// What the menu notes beside the label, e.g. a namespace's package count. + note: Option, + /// The kind of the choice the menu shows by its icon, e.g. `namespace`, `interface` or + /// `component`. + kind: Option<&'static str>, +} + #[derive(Serialize)] struct VersionLink { version: String, @@ -707,12 +824,25 @@ impl Site { self.repos.get(&key) } + /// Where a repository is listed: its section of its namespace's page, e.g. + /// `/componentized/#componentized/cli`. A repository's packages share a namespace. + fn repo_url(&self, repo: &Repo) -> String { + let namespace = repo + .versions + .iter() + .flat_map(|(_, members)| members) + .map(|i| self.entries[*i].namespace()) + .next() + .unwrap_or_default(); + format!("/{namespace}/#{}", repo.key) + } + fn repo_card(&self, repo: &Repo) -> RepoCard { let (version, members) = &repo.versions[repo.latest()]; let lead = &self.entries[members[0]]; RepoCard { key: repo.key.clone(), - url: repo.url(), + url: self.repo_url(repo), version: version.clone(), description: lead.description(), interfaces: members @@ -742,66 +872,6 @@ impl Site { .collect() } - fn repos_page(&self) -> minijinja::Value { - ctx! { repos => self.repo_cards() } - } - - fn repo_page(&self, repo: &Repo, at: usize) -> minijinja::Value { - let (version, members) = &repo.versions[at]; - let cards = |kind: Kind| -> Vec { - members - .iter() - .filter(|i| self.entries[**i].meta.kind == kind) - .map(|i| self.card(*i)) - .collect() - }; - let versions: Vec<_> = repo - .versions - .iter() - .enumerate() - // a superseded dev version is listed only on its own page - .filter(|(i, (v, _))| *i == at || !repo.superseded(v)) - .map(|(i, (v, members))| VersionLink { - version: v.clone(), - url: repo.version_url(v), - current: i == at, - stable: version::stable(v).is_some(), - date: members - .iter() - .map(|m| self.entries[*m].date()) - .min() - .unwrap_or_default(), - }) - .collect(); - let lead = &self.entries[members[0]].meta; - let revision = lead - .annotation("revision") - .map(|r| r.trim_end_matches("+dirty").to_string()); - let release = version::release_of(version) - .filter(|release| repo.versions.iter().any(|(v, _)| v == release)) - .map(|release| ctx! { version => release, url => repo.version_url(&release) }); - ctx! { - title => format!("{}@{version}", repo.key), - canonical => repo.version_url(version), - noindex => release.is_some(), - repo => ctx! { - key => repo.key, - url => repo.url(), - web => repo.web, - version, - stable => version::stable(version).is_some(), - dev => version::dev(version).is_some(), - superseded_by => release, - date => versions.iter().find(|v| v.current).map(|v| v.date.clone()), - revision => revision.as_ref().map(|r| r.chars().take(12).collect::()), - tree => revision.as_ref().map(|r| format!("{}/tree/{r}", repo.web)), - versions, - }, - interfaces => cards(Kind::Interface), - components => cards(Kind::Component), - } - } - fn listed(&self, index: usize) -> bool { self.superseded_by[index].is_none() } @@ -823,6 +893,17 @@ impl Site { } } + fn world_item_link(&self, item: &str) -> WorldItemLink { + WorldItemLink { + link: self.interface_link(item), + kind: if item.ends_with(": func") { + "func" + } else { + "interface" + }, + } + } + fn package_link(&self, package: &str, version: Option<&str>) -> Link { let label = match version { Some(version) => format!("{package}@{version}"), @@ -941,15 +1022,32 @@ impl Site { // the packages without a known repository last let mut groups: Vec<_> = groups.into_iter().collect(); groups.sort_by_key(|(key, _)| (key.is_none(), key.clone())); + // the interface packages, then the components, by name + let ordered = |mut members: Vec| -> Vec { + members.sort_by(|a, b| { + let (a, b) = (&self.entries[*a].meta, &self.entries[*b].meta); + (a.kind != Kind::Interface, &a.package) + .cmp(&(b.kind != Kind::Interface, &b.package)) + }); + members + }; + // the packages a group lists, as cards with their counts by kind + let listing = |members: &[usize]| { + let count = |kind| { + members + .iter() + .filter(|i| self.entries[**i].meta.kind == kind) + .count() + }; + ctx! { + interfaces => count(Kind::Interface), + components => count(Kind::Component), + cards => members.iter().map(|i| self.card(*i)).collect::>(), + } + }; let groups: Vec<_> = groups .into_iter() - .map(|(key, mut members)| { - // the interface packages, then the components, by name - members.sort_by(|a, b| { - let (a, b) = (&self.entries[*a].meta, &self.entries[*b].meta); - (a.kind != Kind::Interface, &a.package) - .cmp(&(b.kind != Kind::Interface, &b.package)) - }); + .map(|(key, members)| { let repo = key.as_ref().and_then(|key| self.repos.get(key)); // the repository's name, without the namespace when the namespace owns it, // e.g. `cli` for `componentized/cli` in `componentized` @@ -958,14 +1056,62 @@ impl Site { .unwrap_or(key) .to_string() }); + // a repository lists the packages it released together at one version, + // the latest at first, switching to each other version it released + // packages of this namespace at. A superseded dev version is left out, as + // it is on the repository's page. + let versions: Vec<_> = repo + .map(|repo| { + let latest = repo.latest(); + repo.versions + .iter() + .enumerate() + .filter(|(i, (v, _))| *i == latest || !repo.superseded(v)) + .filter_map(|(i, (version, members))| { + let members: Vec = members + .iter() + .copied() + .filter(|m| self.entries[*m].namespace() == namespace) + .collect(); + if members.is_empty() { + return None; + } + let date = members + .iter() + .map(|m| self.entries[*m].date()) + .min() + .unwrap_or_default(); + // the commit the version was built from + let revision = self.entries[members[0]] + .meta + .annotation("revision") + .map(|r| r.trim_end_matches("+dirty").to_string()); + Some(ctx! { + version, + // without scripts, a version is chosen from the + // repository's section + url => self.repo_url(repo), + current => i == latest, + date, + revision => revision.as_ref().map(|r| r.chars().take(7).collect::()), + release => members + .iter() + .find_map(|m| self.entries[*m].meta.release.as_deref()) + .map(release_link), + commit => revision.as_ref().and_then(|r| commit_url(&repo.web, r)), + listing => listing(&ordered(members)), + }) + }) + .collect() + }) + .unwrap_or_default(); + // the packages without a repository each at their own latest version + let listing = listing(&ordered(members)); ctx! { key, name, - url => repo.map(Repo::url), - version => repo.map(|repo| repo.versions[repo.latest()].0.clone()), - interfaces => members.iter().filter(|i| self.entries[**i].meta.kind == Kind::Interface).count(), - components => members.iter().filter(|i| self.entries[**i].meta.kind == Kind::Component).count(), - cards => members.into_iter().map(|i| self.card(i)).collect::>(), + versions, + listing, } }) .collect(); @@ -993,15 +1139,141 @@ impl Site { .collect() } + /// Each namespace, to switch to from a breadcrumb. + fn namespace_pivots(&self, current: &str) -> Vec { + self.namespace_counts() + .into_iter() + .map(|(namespace, count)| Pivot { + url: format!("/{namespace}/"), + current: namespace == current, + note: Some(format!( + "{count} package{}", + if count == 1 { "" } else { "s" } + )), + label: namespace, + kind: Some("namespace"), + }) + .collect() + } + + /// The packages of a version's namespace, to switch to from a breadcrumb. + fn package_pivots(&self, index: usize) -> Vec { + let entry = &self.entries[index]; + self.packages + .iter() + .filter_map(|(package, indexes)| { + let latest = &self.entries[*self.latest(indexes)?]; + (latest.namespace() == entry.namespace()).then(|| Pivot { + label: latest.name().to_string(), + url: latest.package_url(), + current: *package == entry.meta.package, + note: None, + kind: Some(match latest.meta.kind { + Kind::Interface => "interface", + Kind::Component => "component", + }), + }) + }) + .collect() + } + + /// Groups `package@version` links by package, as [`group_versions`] does, with the kind of + /// each: a world of a WIT package is labeled by its path, e.g. `wasi:http/proxy`, an indexed + /// package has its own kind, and a package that isn't indexed is a dependency, a WIT package. + fn grouped(&self, links: Vec) -> Vec { + let mut groups = group_versions(links); + for group in &mut groups { + group.kind = self.kind_of(&group.package); + } + groups + } + + /// The kind of a package, or of a world labeled by its path, e.g. `wasi:http/proxy`, for its + /// icon. A package that isn't indexed is a dependency, a WIT package. + fn kind_of(&self, package: &str) -> &'static str { + if package.contains('/') { + return "world"; + } + match self + .packages + .get(package) + .and_then(|indexes| indexes.first()) + .map(|i| self.entries[*i].meta.kind) + { + Some(Kind::Component) => "component", + _ => "interface", + } + } + + /// `package@version` links, each with the kind of its package, by label. + fn listed_packages(&self, mut links: Vec) -> Vec { + links.sort(); + links + .into_iter() + .map(|link| { + let package = link + .label + .rsplit_once('@') + .map_or(link.label.as_str(), |(package, _)| package); + ctx! { kind => self.kind_of(package), label => link.label, url => link.url } + }) + .collect() + } + + /// The other packages the repository of a version released with it, at the same version. + fn released_with(&self, index: usize) -> Vec { + let entry = &self.entries[index]; + let Some(repo) = self.repo_of(index) else { + return Vec::new(); + }; + repo.versions + .iter() + .find(|(version, _)| *version == entry.meta.version) + .map(|(_, members)| { + let mut others: Vec = + members.iter().copied().filter(|i| *i != index).collect(); + // the interface packages, then the components, by name + others.sort_by(|a, b| { + let (a, b) = (&self.entries[*a].meta, &self.entries[*b].meta); + (a.kind != Kind::Interface, &a.package) + .cmp(&(b.kind != Kind::Interface, &b.package)) + }); + others + .into_iter() + .map(|i| { + let other = &self.entries[i]; + Pivot { + label: other.meta.package.clone(), + url: other.url(), + current: false, + note: None, + kind: Some(match other.meta.kind { + Kind::Interface => "interface", + Kind::Component => "component", + }), + } + }) + .collect() + }) + .unwrap_or_default() + } + fn header(&self, index: usize) -> minijinja::Value { let entry = &self.entries[index]; let meta = &entry.meta; let source = meta .annotation("source") .map(|s| s.trim_end_matches(".git").to_string()); - let revision = meta + let full_revision = meta .annotation("revision") - .map(|r| r.chars().take(12).collect::()); + .map(|r| r.trim_end_matches("+dirty")); + let revision = full_revision.map(|r| r.chars().take(12).collect::()); + // the commit the version was built from, on GitHub, else the source's own link to it + let commit = entry + .repository() + .zip(full_revision) + .and_then(|((_, web), revision)| commit_url(&web, revision)) + .or_else(|| meta.annotation("url").map(str::to_string)); ctx! { id => entry.id(), package => meta.package, @@ -1022,13 +1294,17 @@ impl Site { date => entry.date(), license => meta.annotation("licenses"), source, - tree => meta.annotation("url"), + commit, repository => self.repo_of(index).map(|repo| ctx! { key => repo.key, - url => repo.version_url(&meta.version), + url => self.repo_url(repo), }), + released_with => self.released_with(index), + release => meta.release.as_ref().map(|url| release_link(url)), revision, versions => self.versions(index), + namespaces => self.namespace_pivots(entry.namespace()), + packages => self.package_pivots(index), } } @@ -1038,10 +1314,10 @@ impl Site { let resolve = &entry.resolve; let package = &resolve.packages[entry.pkg]; - let world_items = |items: &wit_parser::IndexMap| -> Result> { + let world_items = |items: &wit_parser::IndexMap| -> Result> { Ok(decode::world_items(resolve, items) .iter() - .map(|item| self.interface_link(item)) + .map(|item| self.world_item_link(item)) .collect()) }; let mut worlds = Vec::new(); @@ -1049,7 +1325,7 @@ impl Site { let world = &resolve.worlds[*id]; worlds.push(WorldView { name: name.clone(), - docs: docs(&world.docs), + docs: docs(&world.docs, 3), imports: world_items(&world.imports)?, exports: world_items(&world.exports)?, }); @@ -1073,12 +1349,12 @@ impl Site { let imports: Vec<_> = meta .imports .iter() - .map(|i| self.interface_link(i)) + .map(|i| self.world_item_link(i)) .collect(); let exports: Vec<_> = meta .exports .iter() - .map(|i| self.interface_link(i)) + .map(|i| self.world_item_link(i)) .collect(); let dependencies: Vec<_> = meta .dependencies @@ -1094,6 +1370,7 @@ impl Site { ctx! { reference => debug.reference(), pinned => debug.pinned(), + digest => debug.digest, size => human_size(debug.size), } }); @@ -1102,7 +1379,8 @@ impl Site { title => entry.id(), canonical => entry.url(), pkg => self.header(index), - docs => docs(&package.docs), + // the overview sits beside the page's h2 sections, as one of its own + docs => docs(&package.docs, 2), oci => ctx! { reference => meta.oci.reference(), pinned => meta.oci.pinned(), @@ -1114,8 +1392,10 @@ impl Site { interfaces, imports, exports, - dependencies => group_versions(dependencies), - dependents => group_versions(dependents), + // a version depends on one version of a package, or now and then on two, e.g. of + // `wasi:io`, each listed as it is + dependencies => self.listed_packages(dependencies), + dependents => self.grouped(dependents), wit => wit_html::package(resolve, entry.pkg, entry.nested)?, }) } @@ -1143,6 +1423,9 @@ impl Site { // a function, a freestanding one or one of a resource let func_member = |func: &wit_parser::Function| { + // a freestanding function's docs are under its h3, a resource's function is a member + // under the resource's h3 + let under = if func.kind.resource().is_some() { 4 } else { 3 }; let role = match func.kind { FunctionKind::Constructor(_) => Some("constructor"), FunctionKind::Static(_) | FunctionKind::AsyncStatic(_) => Some("static"), @@ -1156,7 +1439,7 @@ impl Site { _ => func.item_name().to_string(), }, ty: wit_html::signature(resolve, func, &link), - docs: docs(&func.docs), + docs: docs(&func.docs, under), stability: stability(&func.stability), role, modifiers: wit_html::modifiers(&func.kind), @@ -1188,7 +1471,8 @@ impl Site { ty: ty .map(|ty| wit_html::type_ref(resolve, ty, &link)) .unwrap_or_default(), - docs: docs(d), + // under the member of a type under its h3 + docs: docs(d, 4), stability: None, role: None, modifiers: Vec::new(), @@ -1276,9 +1560,9 @@ impl Site { kind: "use", used_kind: Some(used_kind), // the docs of the use, or else those of the type it uses - docs: match docs(&def.docs) { + docs: match docs(&def.docs, 3) { local if !local.is_empty() => local, - _ => docs(&origin_def.docs), + _ => docs(&origin_def.docs, 3), }, stability: stability(&def.stability), members, @@ -1296,7 +1580,7 @@ impl Site { name: type_name.clone(), kind, used_kind: None, - docs: docs(&def.docs), + docs: docs(&def.docs, 3), stability: stability(&def.stability), members, functions: resource_functions(*type_id), @@ -1314,7 +1598,34 @@ impl Site { iface => ctx! { name, id => iid, - docs => docs(&iface.docs), + // the other interfaces of the version, and this interface in each other version, + // or that version's page when it doesn't have the interface + siblings => entry + .interfaces() + .into_iter() + .map(|(other, _, _)| Pivot { + label: other.to_string(), + url: format!("{}{other}/", entry.url()), + current: other == name, + note: None, + kind: Some("interface"), + }) + .collect::>(), + versions => self + .versions(index) + .into_iter() + .map(|mut version| { + let has = self.packages[&entry.meta.package].iter().any(|i| { + self.entries[*i].meta.version == version.version + && self.entries[*i].interfaces().iter().any(|(n, _, _)| *n == name) + }); + if has { + version.url = format!("{}{name}/", version.url); + } + version + }) + .collect::>(), + docs => docs(&iface.docs, 2), stability => stability(&iface.stability), types, functions, @@ -1329,8 +1640,8 @@ impl Site { .collect(), )?, }, - imported_by => group_versions(self.imported_by.get(&iid).cloned().unwrap_or_default()), - exported_by => group_versions(self.exported_by.get(&iid).cloned().unwrap_or_default()), + imported_by => self.grouped(self.imported_by.get(&iid).cloned().unwrap_or_default()), + exported_by => self.grouped(self.exported_by.get(&iid).cloned().unwrap_or_default()), }) } } @@ -1360,6 +1671,7 @@ mod tests { imports: Vec::new(), exports: Vec::new(), dependencies: Vec::new(), + release: None, indexed_at: "2026-11-11T00:00:00Z".to_string(), } } @@ -1368,7 +1680,7 @@ mod tests { fn renders_cross_links() { let root = std::env::temp_dir().join(format!("directory-site-test-{}", std::process::id())); let _ = std::fs::remove_dir_all(&root); - let logging = "package wasi:logging@0.1.0-draft;\n\ninterface logging {\n /// A level.\n enum level { info, warn }\n @since(version = 0.0.1)\n @deprecated(version = 0.0.2)\n log: func(level: level, message: string);\n @unstable(feature = tracing)\n trace: func(message: string);\n}\n\ninterface consumer {\n use logging.{level};\n}\n"; + let logging = "package wasi:logging@0.1.0-draft;\n\ninterface logging {\n /// A level.\n enum level { info, warn }\n @since(version = 0.0.1)\n @deprecated(version = 0.0.2)\n log: func(level: level, message: string);\n @unstable(feature = tracing)\n trace: func(message: string);\n}\n\ninterface consumer {\n use logging.{level};\n}\n\nworld app {\n import logging;\n export run: func();\n}\n"; data::write( &root, &metadata( @@ -1390,6 +1702,11 @@ mod tests { "org.opencontainers.image.source".to_string(), "https://github.com/example/to.git".to_string(), ); + component.release = Some("https://github.com/example/to/releases/tag/v0.1.0".to_string()); + component.annotations.insert( + "org.opencontainers.image.revision".to_string(), + "0123456789abcdef0123456789abcdef01234567".to_string(), + ); component.imports = vec!["wasi:logging/logging@0.1.0-draft".to_string()]; component.exports = vec!["wasi:logging/logging@0.1.0-draft".to_string()]; component.dependencies = vec![Dependency { @@ -1408,12 +1725,13 @@ mod tests { } let out = root.join("_site"); - build(&root, &out, "https://example.com").unwrap(); + build(&root, &root.join("no-samples"), &out, "https://example.com").unwrap(); let read = |path: &str| std::fs::read_to_string(out.join(path)).unwrap(); let iface = read("wasi/logging/0.1.0-draft/logging/index.html"); assert!( - iface.contains("example:to-stdout"), + iface + .contains(r##"example:to-stdout"##), "imported by the component" ); assert!(iface.contains("A level.")); @@ -1432,6 +1750,13 @@ mod tests { "the cases of the used enum" ); assert!(consumer.contains(r#"

from"#)); + // a world's imports and exports show the icon of their kind + let package = read("wasi/logging/0.1.0-draft/index.html"); + assert!( + package.contains(r##"

  • "##)); // a type in a signature links to its definition on the page assert_eq!( iface @@ -1454,6 +1779,14 @@ mod tests { ); assert!(read("search.json").contains("example:to-stdout")); + // a namespace lists a repository's packages at one version, the latest at first, and + // switches in place to each other version, leaving out a superseded dev build + let namespace = read("example/index.html"); + assert!(namespace.contains(r#"0.1.0"#)); + assert!(namespace.contains(r#"
    "#)); + assert!(namespace.contains(r#"
  • "#), + "the exports come from the WIT" + ); + assert!(read("sink/types/0.1.0/shapes/index.html").contains("Synthetic sample.")); + assert!(read("sink/index.html").contains("Synthetic sample.")); + // and no page of the index lists, counts or links them + for path in [ + "index.html", + "all/index.html", + "search.json", + "wasi/index.html", + "wasi/logging/0.1.0-draft/index.html", + "wasi/logging/0.1.0-draft/logging/index.html", + ] { + let page = read(path); + assert!(!page.contains("sink"), "{path} mentions the samples"); + assert!(!page.contains("Synthetic sample."), "{path}"); + } + + // a sample must be synthetic, and keep to a namespace of its own + let mut real = metadata("wasi:other", "0.1.0", Kind::Interface, Origin::Synthetic); + data::write(&samples, &real, "package wasi:other@0.1.0;\n").unwrap(); + let err = build(&index, &samples, &out, "https://example.com").unwrap_err(); + assert!(err.to_string().contains("which the index holds as well")); + real.origin = Origin::Release; + data::write(&samples, &real, "package wasi:other@0.1.0;\n").unwrap(); + let err = build(&index, &samples, &out, "https://example.com").unwrap_err(); + assert!(err.to_string().contains("isn't synthetic")); + std::fs::remove_dir_all(samples.join("wasi")).unwrap(); + // and the index holds no samples + data::write( + &index, + &sample, + "package root:component;\n\nworld root {}\n", + ) + .unwrap(); + let err = build(&index, &samples, &out, "https://example.com").unwrap_err(); + assert!(err.to_string().contains("belongs in the samples")); + + std::fs::remove_dir_all(&root).unwrap(); + } + + #[test] + fn fits_docs_headings_under_the_page() { + // the top level becomes the one under the page's heading, the levels below it follow + assert_eq!( + markdown("Text.\n\n# Errors\n\n## Timeouts\n", 3), + "

    Text.

    \n

    Errors

    \n
    Timeouts
    \n" + ); + // whatever level the docs start at + assert_eq!(markdown("### Errors\n", 2), "

    Errors

    \n"); + // and none deeper than h6 + assert_eq!( + markdown("# A\n\n## B\n\n### C\n", 4), + "
    A
    \n
    B
    \n
    C
    \n" + ); + assert_eq!(markdown("No headings.", 3), "

    No headings.

    \n"); + } + #[test] fn refuses_foreign_output() { let out = diff --git a/static/copy.js b/static/copy.js new file mode 100644 index 0000000..ac75d00 --- /dev/null +++ b/static/copy.js @@ -0,0 +1,70 @@ +// Copy buttons for the values worth pasting elsewhere: the pull commands, image references and +// digests, and WIT. Each `[data-copy]` element gets a button that copies its text, or the value of +// its `data-copy` attribute when it has one. A block, e.g. a `
    `, has its button in its upper
    +// right corner, outside its scrolling; an inline value has its button after it. Without this
    +// script the values are still there to select.
    +(() => {
    +  const targets = [...document.querySelectorAll("[data-copy]")];
    +  if (!targets.length) return;
    +
    +  const icon = (name) =>
    +    ``;
    +
    +  // announces a copy to a screen reader
    +  const status = document.createElement("span");
    +  status.className = "visually-hidden";
    +  status.setAttribute("role", "status");
    +  document.body.append(status);
    +
    +  const write = async (text) => {
    +    try {
    +      await navigator.clipboard.writeText(text);
    +      return true;
    +    } catch {
    +      // a browser without the clipboard API, or a page that isn't served securely
    +      const area = document.createElement("textarea");
    +      area.value = text;
    +      area.setAttribute("readonly", "");
    +      area.style.position = "fixed";
    +      area.style.opacity = "0";
    +      document.body.append(area);
    +      area.select();
    +      const copied = document.execCommand("copy");
    +      area.remove();
    +      return copied;
    +    }
    +  };
    +
    +  for (const target of targets) {
    +    const what = target.dataset.copyLabel || "Copy";
    +    const button = document.createElement("button");
    +    button.type = "button";
    +    button.className = "copy";
    +    button.title = what;
    +    button.setAttribute("aria-label", what);
    +    button.innerHTML = icon("copy") + icon("check");
    +
    +    let reset = 0;
    +    button.addEventListener("click", async () => {
    +      const text = target.dataset.copy || target.textContent.trim();
    +      const copied = await write(text);
    +      button.classList.toggle("copied", copied);
    +      status.textContent = copied ? "Copied" : "Couldn't copy";
    +      clearTimeout(reset);
    +      reset = setTimeout(() => {
    +        button.classList.remove("copied");
    +        status.textContent = "";
    +      }, 1500);
    +    });
    +
    +    if (getComputedStyle(target).display === "block" && target.tagName === "PRE") {
    +      const wrap = document.createElement("div");
    +      wrap.className = "copy-wrap";
    +      target.replaceWith(wrap);
    +      wrap.append(target, button);
    +    } else {
    +      target.after(button);
    +      target.parentElement.classList.add("copy-line");
    +    }
    +  }
    +})();
    diff --git a/static/head.js b/static/head.js
    new file mode 100644
    index 0000000..839ca1a
    --- /dev/null
    +++ b/static/head.js
    @@ -0,0 +1,37 @@
    +// Keeps the heights of what's pinned to the top of the window up to date for the page's CSS: the
    +// site's header, and the breadcrumbs and title of a package, interface or repository page. The
    +// sidebar, the contents and links to sections keep clear of both. The page head, once the page
    +// has scrolled under it, is marked as stuck, which draws a line under it.
    +(() => {
    +  const root = document.documentElement;
    +  const header = document.querySelector("header.site");
    +  const head = document.querySelector("[data-page-head]");
    +
    +  // a variable is only set when it changes: setting it restyles the page, and Safari on a phone
    +  // resizes the window as its toolbar shows and hides while scrolling
    +  const set = (name, value) => {
    +    if (root.style.getPropertyValue(name) !== value) root.style.setProperty(name, value);
    +  };
    +  const measure = () => {
    +    if (header) set("--site-header", `${header.offsetHeight}px`);
    +    // a page head is pinned only on a screen with room for it
    +    const pinned = head && getComputedStyle(head).position === "sticky";
    +    set("--page-head", pinned ? `${head.offsetHeight}px` : "0px");
    +    stick();
    +  };
    +  const stick = () => {
    +    if (!head || !header) return;
    +    const stuck =
    +      getComputedStyle(head).position === "sticky" &&
    +      head.getBoundingClientRect().top <= header.offsetHeight + 0.5 &&
    +      scrollY > 0;
    +    head.classList.toggle("stuck", stuck);
    +  };
    +
    +  const observer = new ResizeObserver(measure);
    +  if (header) observer.observe(header);
    +  if (head) observer.observe(head);
    +  addEventListener("resize", measure, { passive: true });
    +  addEventListener("scroll", stick, { passive: true });
    +  measure();
    +})();
    diff --git a/static/pivot.js b/static/pivot.js
    new file mode 100644
    index 0000000..af032d0
    --- /dev/null
    +++ b/static/pivot.js
    @@ -0,0 +1,138 @@
    +// The breadcrumbs that switch to another namespace, package, version or interface. Each is a
    +// 
    menu of links, so it works without this script, which closes the others when one +// opens, closes on Escape or a click elsewhere, moves through the links with the arrow keys, +// keeps the menu on screen, and adds a filter to a long menu. +(() => { + const pivots = [...document.querySelectorAll("[data-pivot]")]; + if (!pivots.length) return; + // a menu with more choices than this gets a filter + const FILTER_AT = 12; + + const links = (pivot) => + [...pivot.querySelectorAll(".pivot-menu a")].filter((a) => !a.closest("li").hidden); + + const close = (pivot, refocus) => { + if (!pivot.open) return; + pivot.open = false; + if (refocus) pivot.querySelector("summary").focus(); + }; + + for (const pivot of pivots) { + const menu = pivot.querySelector(".pivot-menu"); + const items = [...menu.querySelectorAll("li")]; + let filter = null; + + if (items.length > FILTER_AT) { + const what = + pivot.dataset.pivotWhat ?? pivot.querySelector("summary").title.replace(/^Switch /, ""); + const wrap = document.createElement("li"); + wrap.className = "pivot-filter"; + filter = document.createElement("input"); + filter.type = "search"; + filter.placeholder = `Filter ${items.length} ${what}s`; + filter.setAttribute("aria-label", `Filter the ${what}s`); + filter.autocomplete = "off"; + wrap.append(filter); + const empty = document.createElement("li"); + empty.className = "pivot-empty"; + empty.textContent = "No matches"; + empty.hidden = true; + menu.prepend(wrap); + menu.append(empty); + filter.addEventListener("input", () => { + const terms = filter.value.toLowerCase().split(/\s+/).filter(Boolean); + let shown = 0; + for (const item of items) { + const text = item.textContent.toLowerCase(); + item.hidden = !terms.every((t) => text.includes(t)); + if (!item.hidden) shown++; + } + empty.hidden = shown > 0; + }); + filter.addEventListener("keydown", (e) => { + if (e.key === "Enter") { + // follow the first match + const first = links(pivot)[0]; + if (first) (e.preventDefault(), first.click()); + } + }); + } + + pivot.addEventListener("toggle", () => { + if (!pivot.open) return; + for (const other of pivots) if (other !== pivot) close(other, false); + // keep the menu within the window + menu.style.left = ""; + const right = menu.getBoundingClientRect().right; + const overflow = right - (document.documentElement.clientWidth - 16); + if (overflow > 0) menu.style.left = `${-4 - overflow}px`; + // scroll the menu alone to its current choice: scrollIntoView, or focusing without + // preventScroll, would scroll the page as well + const current = menu.querySelector("[aria-current]"); + if (current) { + const item = current.getBoundingClientRect(); + const box = menu.getBoundingClientRect(); + if (item.bottom > box.bottom) menu.scrollTop += item.bottom - box.bottom + box.height / 2; + } + (filter ?? current ?? links(pivot)[0])?.focus({ preventScroll: true }); + }); + + // a version switch shows the section's panels for the chosen version, in place of following + // the link to that version's page + if (pivot.hasAttribute("data-pivot-switch")) { + const section = pivot.closest("section") ?? document; + const label = pivot.querySelector("[data-pivot-label]"); + menu.addEventListener("click", (e) => { + const link = e.target.closest("a[data-version]"); + if (!link || e.metaKey || e.ctrlKey || e.shiftKey || e.button > 0) return; + e.preventDefault(); + const version = link.dataset.version; + for (const panel of section.querySelectorAll("[data-version-panel]")) { + panel.hidden = panel.dataset.versionPanel !== version; + } + for (const a of menu.querySelectorAll("a[data-version]")) a.removeAttribute("aria-current"); + link.setAttribute("aria-current", "true"); + label.textContent = version; + close(pivot, true); + }); + } + + pivot.addEventListener("keydown", (e) => { + if (e.key === "Escape" && pivot.open) { + e.preventDefault(); + close(pivot, true); + return; + } + if (e.key !== "ArrowDown" && e.key !== "ArrowUp") return; + if (!pivot.open) { + if (e.target === pivot.querySelector("summary")) (e.preventDefault(), (pivot.open = true)); + return; + } + const all = links(pivot); + if (!all.length) return; + e.preventDefault(); + const at = all.indexOf(document.activeElement); + const next = + e.key === "ArrowDown" + ? all[at < 0 ? 0 : Math.min(at + 1, all.length - 1)] + : at <= 0 + ? (filter ?? all[0]) + : all[at - 1]; + next.focus({ preventScroll: true }); + // keep the focused choice in view within the menu + const item = next.getBoundingClientRect(); + const box = menu.getBoundingClientRect(); + if (item.top < box.top) menu.scrollTop -= box.top - item.top + 4; + else if (item.bottom > box.bottom) menu.scrollTop += item.bottom - box.bottom + 4; + }); + + // leaving the menu with the keyboard closes it + pivot.addEventListener("focusout", (e) => { + if (pivot.open && e.relatedTarget && !pivot.contains(e.relatedTarget)) close(pivot, false); + }); + } + + document.addEventListener("click", (e) => { + for (const pivot of pivots) if (!pivot.contains(e.target)) close(pivot, false); + }); +})(); diff --git a/static/style.css b/static/style.css index bfac317..d53260b 100644 --- a/static/style.css +++ b/static/style.css @@ -25,7 +25,14 @@ --badge-strength: 70%; --shadow-color: light-dark(rgb(0 0 0 / 0.12), rgb(0 0 0 / 0.5)); --mono: ui-monospace, "SF Mono", SFMono-Regular, Menlo, Consolas, monospace; + /* the heights of what's pinned to the top of the window, kept up to date by head.js: the site's + header, and a page's breadcrumbs and title */ + --site-header: 57px; + --page-head: 0px; + /* where a link to a section scrolls it to, clear of what's pinned */ + --anchor-offset: calc(var(--site-header) + var(--page-head) + 16px); } +html { scroll-padding-top: var(--anchor-offset); } :root[data-theme="light"] { color-scheme: light; } :root[data-theme="dark"] { color-scheme: dark; } @@ -48,6 +55,8 @@ h2 { font-size: 1.2rem; } h3 { font-size: 1rem; } h4 { font-size: 0.85rem; text-transform: uppercase; letter-spacing: 0.04em; color: var(--dim); } .dim { color: var(--dim); } +/* a date in the monospace font, so the dates in a list line up */ +time { font-family: var(--mono); font-size: 0.9em; font-variant-numeric: tabular-nums; } [hidden] { display: none !important; } .wrap { max-width: 1180px; margin: 0 auto; padding-inline: 16px; } @@ -61,7 +70,7 @@ header.site .wrap { display: flex; align-items: center; gap: 16px; min-height: 5 header nav { display: flex; gap: 16px; margin-left: auto; } header nav a { color: var(--dim); } .search { position: relative; flex: 1 1 260px; max-width: 460px; } -.search input, .filters input, .filters select, select.versions { +.search input, .filters input, .filters select { width: 100%; font: inherit; color: inherit; background: var(--bg); border: 1px solid var(--line); border-radius: 8px; padding: 7px 10px; } @@ -112,34 +121,72 @@ footer.site .footer-legal { grid-column: 1 / -1; max-width: none; margin: 8px 0 .card-head { display: flex; gap: 6px; align-items: center; flex-wrap: wrap; } .card .pkg { font-weight: 600; overflow-wrap: anywhere; } .card p { margin: 0; color: var(--dim); font-size: 0.9rem; flex: 1; display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; } -.card .meta { display: flex; gap: 12px; color: var(--dim); font-size: 0.8rem; font-variant-numeric: tabular-nums; } +.card .meta { display: flex; align-items: baseline; gap: 12px; color: var(--dim); font-size: 0.8rem; font-variant-numeric: tabular-nums; } .badge { font-size: 0.7rem; font-weight: 600; padding: 1px 7px; border-radius: 999px; text-transform: lowercase; white-space: nowrap; } .badge.component { color: var(--component); background: var(--component-soft); } .badge.interface { color: var(--interface); background: var(--interface-soft); } -.badge.repo { color: var(--accent); background: var(--accent-soft); } .badge.dep, .badge.pre { color: var(--dim); border: 1px solid var(--line); } .filters { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; margin-bottom: 16px; } .filters input { flex: 1 1 220px; width: auto; } .filters select { width: auto; } -.crumbs { margin-top: 20px; font-family: var(--mono); font-size: 0.85rem; color: var(--dim); } +/* a page's breadcrumbs and title, pinned under the site's header while the page scrolls under them */ +/* its space above is padding rather than margin, so it's pinned from the first pixel scrolled */ +.page-head { padding-top: 16px; background: var(--bg); } +@media (min-width: 701px) and (min-height: 560px) { + .page-head { position: sticky; top: var(--site-header); z-index: 9; } + /* once the page has scrolled under it, a line parts it from the page */ + .page-head.stuck { box-shadow: 0 1px 0 var(--line); } +} +.crumbs { font-family: var(--mono); font-size: 0.85rem; color: var(--dim); } .title-row { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; } .title-row h1 { margin: 0.3em 0; overflow-wrap: anywhere; } -select.versions { width: auto; margin-left: auto; font-family: var(--mono); font-size: 0.85rem; } + +/* a breadcrumb that switches to another namespace, package, version or interface */ +.crumbs { display: flex; flex-wrap: wrap; align-items: center; gap: 2px 6px; } +.pivot { position: relative; display: inline-block; } +.pivot > summary { + display: inline-flex; align-items: center; gap: 2px; list-style: none; cursor: pointer; + color: var(--accent); border-radius: 6px; padding: 1px 4px; margin: 0 -4px; +} +.pivot > summary::-webkit-details-marker { display: none; } +.pivot > summary:hover, .pivot[open] > summary { background: var(--accent-soft); } +.pivot > summary:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; } +.pivot-chevron { width: 14px; height: 14px; flex: none; transition: transform 0.15s; } +.pivot[open] .pivot-chevron { transform: rotate(180deg); } +.pivot-menu { + position: absolute; left: -4px; top: calc(100% + 6px); z-index: 20; margin: 0; padding: 4px; list-style: none; + /* as wide as its longest choice, rather than the breadcrumb it hangs from */ + width: max-content; min-width: 240px; max-width: min(600px, calc(100vw - 32px)); max-height: min(60vh, 420px); overflow-y: auto; + background: var(--panel); border: 1px solid var(--line); border-radius: 8px; box-shadow: 0 8px 24px var(--shadow-color); + font-size: 0.85rem; +} +.pivot-menu a { display: flex; justify-content: space-between; align-items: baseline; gap: 16px; padding: 5px 8px; border-radius: 6px; color: var(--text); } +.pivot-menu a code { font-size: 1em; overflow-wrap: anywhere; } +.pivot-menu a .kind-icon { width: 14px; height: 14px; margin-right: 6px; vertical-align: -2px; } +.pivot-menu a[aria-current] .kind-icon { color: currentColor; } +.pivot-menu a .dim { flex: none; } +.pivot-menu a span.dim { font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif; font-size: 0.9em; } +.pivot-menu a:hover, .pivot-menu a:focus-visible { background: var(--code-bg); text-decoration: none; outline: none; } +.pivot-menu a[aria-current] { background: var(--accent-soft); color: var(--accent); font-weight: 600; } +.pivot-menu li[hidden] { display: none; } +.pivot-filter { position: sticky; top: -4px; margin: -4px -4px 4px; padding: 4px; background: var(--panel); } +.pivot-filter input { width: 100%; font: inherit; color: inherit; background: var(--bg); border: 1px solid var(--line); border-radius: 6px; padding: 5px 8px; } +.pivot-filter input:focus { outline: 2px solid var(--accent); outline-offset: -1px; } +.pivot-empty { padding: 5px 8px; color: var(--dim); } .lede { font-size: 1.05rem; color: var(--dim); max-width: 70ch; margin-top: 0; } .notice { background: var(--interface-soft); border: 1px solid var(--line); border-radius: 8px; padding: 8px 12px; max-width: 70ch; } -.iface-title { font-size: 1.3rem; } +.notice.synthetic { margin-top: 16px; } .layout { display: grid; grid-template-columns: minmax(0, 1fr) 320px; gap: 32px; align-items: start; } -aside { position: sticky; top: 72px; font-size: 0.9rem; } +aside { position: sticky; top: calc(var(--site-header) + var(--page-head) + 16px); font-size: 0.9rem; } aside section { border-bottom: 1px solid var(--line); padding-bottom: 12px; } aside h3 { margin-top: 1.2em; font-size: 0.8rem; text-transform: uppercase; letter-spacing: 0.04em; color: var(--dim); } @media (max-width: 860px) { .layout { grid-template-columns: minmax(0, 1fr); } aside { position: static; } - select.versions { margin-left: 0; } } .facts { display: grid; grid-template-columns: auto minmax(0, 1fr); gap: 4px 12px; margin: 8px 0 0; } @@ -150,6 +197,29 @@ aside h3 { margin-top: 1.2em; font-size: 0.8rem; text-transform: uppercase; lett pre { background: var(--code-bg); border: 1px solid var(--line); border-radius: 8px; padding: 12px 14px; overflow-x: auto; } pre.cmd { padding: 8px 10px; font-size: 0.8rem; white-space: pre-wrap; overflow-wrap: anywhere; } pre.wit { line-height: 1.5; } + +/* a button that copies a value: in the corner of a block, outside its scrolling, or after an + inline value. Its icon turns to a check for a moment once it has copied. */ +.copy { + display: inline-flex; align-items: center; justify-content: center; flex: none; + width: 24px; height: 24px; padding: 0; border: 1px solid transparent; border-radius: 6px; + background: transparent; color: var(--dim); cursor: pointer; +} +.copy:hover { color: var(--text); background: var(--panel); border-color: var(--line); } +.copy:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; } +.copy-icon { width: 14px; height: 14px; fill: none; stroke: currentColor; stroke-width: 1.4; stroke-linecap: round; stroke-linejoin: round; } +.copy .copy-icon-check, .copy.copied .copy-icon-copy { display: none; } +.copy.copied .copy-icon-check { display: block; } +.copy.copied { color: var(--component); } +.copy-wrap { position: relative; } +.copy-wrap > .copy { position: absolute; top: 6px; right: 6px; background: var(--code-bg); } +.copy-wrap > .copy:hover { background: var(--panel); } +/* room for the button beside a command, which wraps */ +.copy-wrap > pre.cmd { padding-right: 36px; } +/* an inline value and its button share its line, the value giving way */ +.copy-line { display: flex; align-items: flex-start; gap: 4px; } +.copy-line > code { min-width: 0; } +.copy-line > .copy { width: 22px; height: 22px; margin-block: -3px; } .wit .k, .k { color: var(--k); } .wit .t { color: var(--t); } .wit .b { color: var(--b); } @@ -167,20 +237,61 @@ ul.links li { padding: 3px 0; overflow-wrap: anywhere; } ul.items li { padding: 6px 0; border-bottom: 1px solid var(--line); } ul.members li { padding: 6px 0 6px 12px; border-left: 2px solid var(--line); margin: 4px 0; } .members .docs, .item .docs { color: var(--dim); font-size: 0.9rem; } -.members .docs p, .item .docs p { margin: 2px 0; } +/* a paragraph break reads clearly apart from a wrapped line: the lines of a paragraph are set closer, + and paragraphs further apart */ +.docs { line-height: 1.45; } +/* a heading in docs, whatever its level, as a modest subheading of the docs it's in */ +.docs :is(h3, h4, h5, h6) { + font-size: 1em; font-weight: 650; color: var(--text); text-transform: none; letter-spacing: normal; + margin: 1.1em 0 0.4em; +} +.docs p, .docs ul, .docs ol, .docs pre { margin: 0.75em 0; } +.members .docs :where(p, ul, ol, pre), .item .docs :where(p, ul, ol, pre) { margin: 0.6em 0; } +.docs > :first-child { margin-top: 0; } +.docs > :last-child { margin-bottom: 0; } +/* a member's docs sit a little apart from its signature */ +ul.members li > .head + .docs { margin-top: 4px; } .c { color: var(--text); font-weight: 600; } -.item { padding: 4px 0 12px; border-bottom: 1px solid var(--line); scroll-margin-top: 72px; } +.item { padding: 4px 0 12px; border-bottom: 1px solid var(--line); } .item h3 { font-weight: 500; overflow-wrap: anywhere; } -.world { background: var(--panel); border: 1px solid var(--line); border-radius: 10px; padding: 4px 16px 12px; margin-bottom: 12px; scroll-margin-top: 72px; } +.world { background: var(--panel); border: 1px solid var(--line); border-radius: 10px; padding: 4px 16px 12px; margin-bottom: 12px; } .world h3 { margin-top: 0.8em; } .two { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; } @media (max-width: 600px) { .two { grid-template-columns: 1fr; } } .docs { max-width: 75ch; } -.versions-group summary { cursor: pointer; overflow-wrap: anywhere; } -.versions-group summary::marker { color: var(--dim); } -.versions-group > ul.links { padding-left: 18px; } +/* a group's package: its icon, its name wrapping in a column of its own, and its count at the end */ +/* a package opening a menu of its versions, its whole line the button */ +.pivot.pivot-group { display: block; } +.pivot.pivot-group > summary { display: block; margin: 0 -6px; padding: 2px 6px; color: var(--text); } +.pivot-group .pivot-chevron { align-self: flex-start; margin-top: 0.25em; color: var(--dim); } +.pivot-unlinked { display: block; padding: 5px 8px; color: var(--dim); } +ul.links.groups li { padding: 0; } +/* a version and its date at the end of its line, the whole row its link */ +.versions-list li { padding: 0; } +.version-row { + display: flex; justify-content: space-between; align-items: baseline; gap: 12px; + margin: 0 -6px; padding: 3px 6px; border-radius: 6px; color: inherit; +} +.version-row .version { min-width: 0; overflow-wrap: anywhere; } +.version-row > .dim { flex: none; } +a.version-row .version { color: var(--accent); } +a.version-row:hover, a.version-row:focus-visible { background: var(--code-bg); text-decoration: none; outline: none; } +a.version-row:hover .version { text-decoration: underline; } +/* the version on view, highlighted like the current choice of a menu */ +.version-row[aria-current] { background: var(--accent-soft); } +.version-row[aria-current] .version { color: var(--accent); font-weight: 600; } +.group-line { display: flex; align-items: baseline; gap: 6px; } +.group-line > .kind-icon { align-self: flex-start; margin: 0.2em 0 0; } +.group-line > code { flex: 1; min-width: 0; overflow-wrap: anywhere; } +/* the number of versions in a group, as a chip at the end of its package's line */ +.count-chip { + flex: none; display: inline-block; min-width: 1.6em; padding: 0 6px; border-radius: 999px; + border: 1px solid var(--line); background: var(--panel); color: var(--dim); + font-family: var(--mono); font-size: 0.75rem; line-height: 1.5; text-align: center; + font-variant-numeric: tabular-nums; vertical-align: 1px; +} .theme { position: relative; } .theme-button { @@ -216,9 +327,21 @@ ul.members li { padding: 6px 0 6px 12px; border-left: 2px solid var(--line); mar .gate.deprecated { color: var(--deprecated); background: var(--deprecated-soft); border-color: transparent; } .jump { display: flex; flex-wrap: wrap; gap: 6px 14px; margin: 4px 0 8px; font-family: var(--mono); font-size: 0.85rem; } -.group { margin-top: 28px; scroll-margin-top: 72px; } +.group { margin-top: 28px; } .group-head { display: flex; align-items: baseline; flex-wrap: wrap; gap: 4px 10px; margin-bottom: 10px; padding-bottom: 6px; border-bottom: 1px solid var(--line); } .group-head h2 { margin: 0; font-size: 1.1rem; } +.group-head .pivot { font-family: var(--mono); font-size: 0.85rem; } +/* a version's details, one size throughout */ +.group-version { font-size: 0.85rem; } +.group-version code, .group-version time { font-size: 1em; } +.group-head .count .kind-icon { width: 14px; height: 14px; margin-right: 3px; vertical-align: -2px; } +/* an icon for a detail beside it, a date, commit or release notes, in the detail's color */ +.meta-icon { + width: 14px; height: 14px; margin-right: 4px; vertical-align: -2px; flex: none; + fill: none; stroke: currentColor; stroke-width: 1.4; stroke-linecap: round; stroke-linejoin: round; +} +.group-details { margin-left: auto; } +.released-with .kind-icon, .packages .kind-icon { width: 14px; height: 14px; margin-right: 6px; vertical-align: -2px; } .fold { margin-top: 12px; } .fold > summary { @@ -242,7 +365,7 @@ ul.members li { padding: 6px 0 6px 12px; border-left: 2px solid var(--line); mar main.wrap.has-toc { max-width: 1440px; display: grid; grid-template-columns: 220px minmax(0, 1fr); gap: 32px; align-items: start; } .page { min-width: 0; } .toc { - position: sticky; top: 64px; max-height: calc(100vh - 72px); overflow-y: auto; overscroll-behavior: contain; + position: sticky; top: calc(var(--site-header) + 7px); max-height: calc(100vh - var(--site-header) - 15px); overflow-y: auto; overscroll-behavior: contain; padding: 20px 4px 24px 0; font-size: 0.85rem; scrollbar-width: thin; } .toc-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; margin-bottom: 8px; } @@ -273,6 +396,12 @@ main.wrap.has-toc { max-width: 1440px; display: grid; grid-template-columns: 220 :root[data-toc="collapsed"] .toc-head { justify-content: center; } :root[data-toc="collapsed"] .toc-toggle svg { transform: rotate(180deg); } +/* the right column's sections are listed in the contents only once it stacks under the content: + beside the content, it's always in view */ +@media (min-width: 1241px) { + .toc .toc-aside { display: none; } +} + /* beside a contents column, the right column of a page stacks under its content sooner */ @media (max-width: 1240px) { .has-toc .layout { grid-template-columns: minmax(0, 1fr); } @@ -305,6 +434,15 @@ main.wrap.has-toc { max-width: 1440px; display: grid; grid-template-columns: 220 .kind-icon.kind-resource { color: var(--n); } .kind-icon.kind-use { color: var(--k); } .kind-icon.kind-func { color: var(--f); } +.kind-icon.kind-world { color: var(--component); } +.kind-icon.kind-interface { color: var(--interface); } +.kind-icon.kind-component { color: var(--component); } +.kind-icon.kind-repo { color: var(--accent); } +.kind-icon.kind-namespace { color: var(--n); } +.namespaces a .kind-icon { width: 14px; height: 14px; margin-right: 4px; vertical-align: -2px; } +.card-head > .kind-icon { width: 15px; height: 15px; margin-right: 0; vertical-align: -2px; } +/* a heading's icon grows with its text */ +h1 > .kind-icon, h2 > .kind-icon, h3 > .kind-icon { width: 0.95em; height: 0.95em; vertical-align: -0.1em; margin-right: 0.35em; } .kind-icon.kind-variant circle, .kind-icon.kind-enum circle { fill: currentColor; stroke: none; } .toc a .kind-icon { width: 14px; height: 14px; margin-right: 5px; vertical-align: -2px; } .toc a[aria-current] .kind-icon { color: currentColor; } @@ -324,12 +462,11 @@ ul.members li > .kind-icon { margin-right: 4px; } .toc a .kind-icon-used .kind-icon { width: 14px; height: 14px; margin: 0; vertical-align: 0; } .toc a .kind-badge { width: 10px; height: 10px; } .toc a:hover .kind-badge { stroke: var(--code-bg); } -.toc a[aria-current] .kind-badge { stroke: var(--accent-soft); } +/* on the current entry, a badge takes the entry's color like its icon, blended toward the highlight */ +.toc a[aria-current] .kind-badge { stroke: var(--accent-soft); fill: color-mix(in srgb, currentColor var(--badge-strength), var(--accent-soft)); } /* a resource's functions sit closer under it than a section's entries */ .toc ol ol ol { margin: 0 0 4px 8px; } -.toc a .k { font-family: var(--mono); font-size: 0.95em; } -ul.members li[id] { scroll-margin-top: 72px; } /* a function's modifiers, as badges on the corners of its icon */ .kind-icon-badged { position: relative; display: inline-block; margin-right: 8px; vertical-align: -3px; line-height: 0; } @@ -341,17 +478,17 @@ ul.members li[id] { scroll-margin-top: 72px; } stroke: var(--bg); stroke-width: 3.2; stroke-linejoin: round; paint-order: stroke; } .fbadge-static { top: -5px; right: -5px; --mod: var(--n); } -.fbadge-async { bottom: -5px; right: -5px; --mod: var(--f); } +.fbadge-async { bottom: -5px; right: -5px; --mod: var(--b); } .fbadge-get, .fbadge-set, .fbadge-constructor { bottom: -5px; left: -5px; } .fbadge-get, .fbadge-set { --mod: var(--t); } .fbadge-constructor { --mod: var(--k); } -/* a lower left badge needs room before the icon */ -.kind-icon-badged:has(.fbadge-get, .fbadge-set, .fbadge-constructor) { margin-left: 4px; } +/* a lower left badge hangs into the padding before the icon, rather than pushing the icon and its + label out of line with the functions without one */ .toc a .kind-icon-badged { margin-right: 7px; vertical-align: -2px; } .toc a .kind-icon-badged .kind-icon { width: 14px; height: 14px; margin: 0; vertical-align: 0; } .toc a .fbadge { width: 10px; height: 10px; } .toc a:hover .fbadge { stroke: var(--code-bg); } -.toc a[aria-current] .fbadge { stroke: var(--accent-soft); } +.toc a[aria-current] .fbadge { stroke: var(--accent-soft); fill: color-mix(in srgb, currentColor var(--badge-strength), var(--accent-soft)); } .item .from { margin: -4px 0 6px; font-size: 0.85rem; color: var(--dim); } diff --git a/static/toc.js b/static/toc.js index ca83710..8ecffb0 100644 --- a/static/toc.js +++ b/static/toc.js @@ -52,14 +52,20 @@ .map((link) => [link, document.getElementById(decodeURIComponent(link.hash.slice(1)))]) .filter(([, target]) => target); let current = null; + // where a link to a section scrolls it to, below what's pinned to the top of the window + const offset = () => parseFloat(getComputedStyle(root).scrollPaddingTop) || 72; const spy = () => { let active = null; - for (const [link, target] of links) { - if (target.getBoundingClientRect().top <= 96) active = link; + // the right column's sections are left out while it's beside the content + const listed = links.filter( + ([link]) => getComputedStyle(link.closest(".toc-aside") ?? link).display !== "none", + ); + for (const [link, target] of listed) { + if (target.getBoundingClientRect().top <= offset() + 24) active = link; } // at the bottom of the page, the last sections can't scroll past the header - if (innerHeight + scrollY >= document.body.scrollHeight - 2 && links.length) { - const visible = links.filter(([, t]) => t.getBoundingClientRect().top < innerHeight); + if (innerHeight + scrollY >= document.body.scrollHeight - 2 && listed.length) { + const visible = listed.filter(([, t]) => t.getBoundingClientRect().top < innerHeight); if (visible.length) active = visible[visible.length - 1][0]; } if (active === current) return; @@ -67,7 +73,12 @@ active?.setAttribute("aria-current", "location"); current = active; if (active && !narrow.matches && toc.scrollHeight > toc.clientHeight) { - active.scrollIntoView({ block: "nearest" }); + // scroll the contents alone: scrollIntoView would scroll the page as well, which in Safari + // fights the reader's own scrolling + const box = toc.getBoundingClientRect(); + const item = active.getBoundingClientRect(); + if (item.top < box.top + 8) toc.scrollTop -= box.top + 8 - item.top; + else if (item.bottom > box.bottom - 8) toc.scrollTop += item.bottom - (box.bottom - 8); } }; let queued = false; @@ -83,5 +94,7 @@ }, { passive: true }, ); + // the right column moves beside or under the content as the window resizes + addEventListener("resize", spy, { passive: true }); spy(); })(); diff --git a/templates/base.html b/templates/base.html index 6cd9076..94033dc 100644 --- a/templates/base.html +++ b/templates/base.html @@ -1,3 +1,4 @@ +{% from "macros.html" import kind_sprite %} @@ -7,7 +8,7 @@ {% block title %}{% if title %}{{ title }} · {% endif %}Componentized Directory{% endblock %} - {% if noindex or (pkg and pkg.superseded_by) %}{% endif %} + {% if noindex or synthetic or (pkg and pkg.superseded_by) %}{% endif %} {% if canonical %}{% endif %} @@ -17,8 +18,12 @@ + + + + {{ kind_sprite() }}
    {% include "logo.svg" %}componentized/directory @@ -26,7 +31,6 @@ @@ -56,7 +60,10 @@
    {% block toc %}{% endblock %}
    {% endif %} -
    {% block main %}{% endblock %}
    +
    + {% if synthetic %}

    Synthetic sample. This package shows how the directory renders each WIT feature. It isn't published to any registry.

    {% endif %} + {% block main %}{% endblock %} +
    diff --git a/templates/index.html b/templates/index.html index 87680b8..dca696d 100644 --- a/templates/index.html +++ b/templates/index.html @@ -1,5 +1,5 @@ {% extends "base.html" %} -{% from "macros.html" import card, repo_card %} +{% from "macros.html" import card, repo_card, kind_icon %} {% block main %}

    Componentized Directory

    @@ -11,7 +11,7 @@

    Componentized Directory

    Interfaces
    {{ stats.interfaces }}
    Versions
    {{ stats.versions }}
    -

    {% for ns, count in namespaces %}{{ ns }} {{ count }}{% endfor %}

    +

    {% for ns, count in namespaces %}{{ kind_icon("namespace") }}{{ ns }} {{ count }}{% endfor %}

    @@ -20,7 +20,7 @@

    Recent releases

    -

    Repositories all

    +

    Repositories

    {% for r in repos %}{{ repo_card(r) }}{% endfor %}
    diff --git a/templates/interface.html b/templates/interface.html index 1744e15..d403b58 100644 --- a/templates/interface.html +++ b/templates/interface.html @@ -1,5 +1,5 @@ {% extends "base.html" %} -{% from "macros.html" import header, links, grouped, stability, kind_sprite, kind_icon, func_icon %} +{% from "macros.html" import header, links, grouped, stability, kind_icon, func_icon %} {% block description %}{{ iface.id }}{% endblock %} {% set toc = true %} {% block toc %} @@ -8,19 +8,18 @@ {% if iface.types %}
  • Types
      {% for t in iface.types %}
    1. {{ kind_icon(t.kind, t.used_kind) }}{{ t.name }} {%- if t.functions %} -
        {% for f in t.functions %}
      1. {{ func_icon(f.modifiers) }}{% if f.role == "constructor" %}constructor{% else %}{{ f.name }}{% endif %}
      2. {% endfor %}
      +
        {% for f in t.functions %}
      1. {{ func_icon(f.modifiers) }}{% if f.role == "constructor" %}constructor{% else %}{{ f.name }}{% endif %}
      2. {% endfor %}
      {%- endif %}
    2. {% endfor %}
  • {% endif %} {% if iface.functions %}
  • Functions
      {% for f in iface.functions %}
    1. {{ func_icon(f.modifiers) }}{{ f.name }}
    2. {% endfor %}
  • {% endif %}
  • WIT
  • -
  • Imported by
  • -
  • Exported by
  • +
  • Package
  • +
  • Imported by
  • +
  • Exported by
  • {% endblock %} {% block main %} -{{ kind_sprite() }} -{{ header(pkg) }} -

    interface {{ iface.name }} {{ iface.id }} {{ stability(iface.stability) }}

    +{{ header(pkg, iface) }}
    {% if iface.docs %}
    {{ iface.docs|safe }}
    {% endif %} @@ -62,10 +61,14 @@

    {{ func_icon(f.modifiers) }}

    WIT

    -
    {{ iface.wit|safe }}
    +
    {{ iface.wit|safe }}

    {% endblock %} diff --git a/templates/macros.html b/templates/macros.html index e9723f7..cdfb123 100644 --- a/templates/macros.html +++ b/templates/macros.html @@ -4,11 +4,25 @@ {% if items %}{% else %}

    {{ empty }}

    {% endif %} {% endmacro %} +{#- a world's imports or exports, each with the icon of its kind, an interface or a function #} +{% macro world_items(items, empty="None") %} +{% if items %}{% else %}

    {{ empty }}

    {% endif %} +{% endmacro %} + +{#- `package@version` links, each with its package's icon, e.g. a version's dependencies #} +{% macro packages(items, empty="None") %} +{% if items %}{% else %}

    {{ empty }}

    {% endif %} +{% endmacro %} + +{#- packages and their versions, e.g. a version's dependents. Each package opens a menu of its + versions, like a breadcrumb's; a version that isn't indexed is listed without a link. #} {% macro grouped(groups, empty="None") %} -{% if groups %}