diff --git a/component-model/examples/composing-section-examples/composition.wac b/component-model/examples/composing-section-examples/composition.wac new file mode 100644 index 00000000..8eb5acdd --- /dev/null +++ b/component-model/examples/composing-section-examples/composition.wac @@ -0,0 +1,14 @@ +//composition.wac +// Provide a package name for the resulting composition +package docs:composition; + +// Instantiate the regex-impl component that implements the `regex` world. +// Bind this instance's exports to the local name `regex`. +let regex = new docs:regex-impl { }; + +// Instantiate the validator-impl component which implements the `validator` world +// and imports the match interface from the regex component. +let validator = new docs:validator-impl { match: regex.match, ... }; + +// Export all remaining exports of the validator instance +export validator...; diff --git a/component-model/examples/composing-section-examples/http-service.wit b/component-model/examples/composing-section-examples/http-service.wit new file mode 100644 index 00000000..b05e6e02 --- /dev/null +++ b/component-model/examples/composing-section-examples/http-service.wit @@ -0,0 +1,5 @@ +package foo:wasi-http-service; + +world target-world { + include wasi:http/proxy@0.2.3; +} diff --git a/component-model/examples/composing-section-examples/regex.wit b/component-model/examples/composing-section-examples/regex.wit new file mode 100644 index 00000000..9aa2d2ac --- /dev/null +++ b/component-model/examples/composing-section-examples/regex.wit @@ -0,0 +1,10 @@ +// component 'regex' +package docs:regex@0.1.0; + +interface match { + first-match: func(regex: string, text: string) -> string; +} + +world regex { + export match; +} diff --git a/component-model/examples/composing-section-examples/validator.wit b/component-model/examples/composing-section-examples/validator.wit new file mode 100644 index 00000000..65972fb9 --- /dev/null +++ b/component-model/examples/composing-section-examples/validator.wit @@ -0,0 +1,11 @@ +// component `validator` +package docs:validator@0.1.0; + +interface validator { + validate-text: func(text: string) -> string; +} + +world validator { + export validator; + import docs:regex/match@0.1.0; +} diff --git a/component-model/src/composing-and-distributing.md b/component-model/src/composing-and-distributing.md index 8a351668..12998ab1 100644 --- a/component-model/src/composing-and-distributing.md +++ b/component-model/src/composing-and-distributing.md @@ -1,3 +1,5 @@ # Composing and Distributing Components -The component model defines how components interface to each other and to hosts. This section describes how to work with components - from authoring them in custom code or by composing existing components, through to using them in applications and distributing them via registries. +The component model defines how components interface to each other and to hosts. +This section describes how to work with components: from authoring them in custom code or by composing existing components, +to using them in applications and distributing them via registries. diff --git a/component-model/src/composing-and-distributing/composing.md b/component-model/src/composing-and-distributing/composing.md index 168cb3fc..dad522e6 100644 --- a/component-model/src/composing-and-distributing/composing.md +++ b/component-model/src/composing-and-distributing/composing.md @@ -1,115 +1,157 @@ # Composing Components -Because the WebAssembly component model packages code in a portable binary format, and provides machine-readable interfaces in [WIT](../design/wit.md) with a standardised ABI (Application Binary Interface), it enables applications and components to work together, no matter what languages they were originally written in. In the same way that, for example, a Rust package (crate) can be compiled together with other Rust code to create a higher-level library or an application, a Wasm component can be linked with other components. - -> Component model interoperation is more convenient and expressive than language-specific foreign function interfaces. A typical C FFI involves language-specific types, so it is not possible to link between arbitrary languages without at least some C-language wrapping or conversion. The component model, by contrast, provides a common way of expressing interfaces, and a standard binary representation of those interfaces. So if an import and an export have the same shape, they fit together directly. +The WebAssembly component model enables applications and components to work together, +no matter what languages they were originally written in. +The component model accomplishes this by packaging code in a portable binary format +and providing machine-readable interfaces in [WIT](../design/wit.md) +with a standardised Application Binary Interface (ABI). +In the same way that, for example, a Rust package (crate) can be compiled together with other Rust code +to create a higher-level library or an application, a WebAssembly component can be composed with other components. + +> Component model interoperation is more convenient and expressive than language-specific foreign function interfaces (FFIs). +> A typical C FFI involves language-specific types, so it is not possible to link between arbitrary languages +> without at least some C-language wrapping or conversion. +> The component model, by contrast, provides a common way of expressing interfaces, +> and a standard binary representation of those interfaces. +> So if an import and an export have the same shape, they fit together directly. ## What is composition? -When you compose components, you wire up the imports of one "primary" component to the exports of one or more other "dependency" components, creating a new component. The new component, like the original components, is a `.wasm` file, and its interface is defined as: +When you compose components, you wire up the imports of one _primary_ component +to the exports of one or more other _dependency_ components, creating a new component. +The new component, like the original components, is a `.wasm` file, and its interface is defined as follows: -* The new component _exports_ the same exports as the primary component -* The new component _does not export_ the exports of the dependencies -* The new component _imports_ all the imports of the dependency components -* The new component _imports_ any imports of the primary component imports that the dependencies didn't satisfy -* If several components import the same interface, the new component imports that interface - it doesn't "remember" that the import was declared in several different places +* The new component _exports_ the same exports as the primary component. +* The new component _does not export_ the exports of the dependency components. +* The new component _imports_ all the imports of the dependency components. +* The new component _imports_ any imports of the primary component + that the dependencies didn't satisfy. +* If several components import the same interface, + the new component imports that interface—it doesn't "remember" + that the import was declared in several different places. For example, consider two components with the following worlds: ```wit -// component `validator` -package docs:validator@0.1.0; - -interface validator { - validate-text: func(text: string) -> string; -} - -world validator { - export validator; - import docs:regex/match@0.1.0; -} +{{#include ../../examples/composing-section-examples/validator.wit}} ``` ```wit -// component 'regex' -package docs:regex@0.1.0; - -interface match { - first-match: func(regex: string, text: string) -> string; -} - -world regex { - export match; -} +{{#include ../../examples/composing-section-examples/regex.wit}} ``` -If we compose `validator` with `regex`, `validator`'s import of `docs:regex/match@0.1.0` is wired up to `regex`'s export of `match`. The net result is that the composed component exports `docs:validator/validator@0.1.0` and has no imports. The composed component does _not_ export `docs:regex/match@0.1.0` - that has become an internal implementation detail of the composed component. - -Component composition tools are in their early stages right now. Here are some tips to avoid or diagnose errors: - -* Composition happens at the level of interfaces. If the initial component directly imports functions, then composition will fail. If composition reports an error such as "component `path/to/component` has a non-instance import named ``" then check that all imports and exports are defined by interfaces. -* Composition is asymmetrical. It is not just "gluing components together" - it takes a primary component which has imports, and satisfies its imports using dependency components. For example, composing an implementation of `validator` with an implementation of `regex` makes sense because `validator` has a dependency that `regex` can satisfy; doing it the other way round doesn't work, because `regex` doesn't have any dependencies, let alone ones that `validator` can satisfy. -* Composition cares about interface versions, and current tools are inconsistent about when they infer or inject versions. For example, if a Rust component exports `test:mypackage`, `cargo component build` will decorate this with the crate version, e.g. `test:mypackage@0.1.0`. If another Rust component _imports_ an interface from `test:mypackage`, that won't match `test:mypackage@0.1.0`. You can use [`wasm-tools component wit`](https://github.com/bytecodealliance/wasm-tools/tree/main/crates/wit-component) to view the imports and exports embedded in the `.wasm` files and check whether they match up. +In this example, `validator` is the primary component +and `regex` is a dependency component. +If we compose `validator` with `regex`, `validator`'s import of `docs:regex/match@0.1.0` +is wired up to `regex`'s export of `match`. +The net result is that the composed component exports `docs:validator/validator@0.1.0` and has no imports. +The composed component does _not_ export `docs:regex/match@0.1.0`: that has become an internal implementation detail of the composed component. + +Component composition tools are in their early stages right now. +Here are some tips to avoid or diagnose errors: + +* Composition happens at the level of interfaces. + If the initial component directly imports functions, then composition will fail. + If composition reports an error such as + "component `path/to/component` has a non-instance import named ``", + then check that all imports and exports are defined by interfaces. +* Composition is asymmetrical. It is not just "gluing components together"—it takes a primary component + that has imports, and satisfies its imports using dependency components. + For example, composing an implementation of `validator` with an implementation of `regex` makes sense + because `validator` has a dependency that `regex` can satisfy; doing it the other way around doesn't work, + because `regex` doesn't have any dependencies, let alone ones that `validator` can satisfy. +* Composition cares about interface versions, and current tools are inconsistent about + when they infer or inject versions. + For example, if a Rust component exports `test:mypackage`, + `cargo component build` will decorate this with the crate version, e.g. `test:mypackage@0.1.0`. + If another Rust component _imports_ an interface from `test:mypackage`, that won't match `test:mypackage@0.1.0`. + You can use [`wasm-tools component wit`](https://github.com/bytecodealliance/wasm-tools/tree/main/crates/wit-component) + to view the imports and exports embedded in the `.wasm` files and check whether they match up. ## Composing components with WAC -You can use the [WAC](https://github.com/bytecodealliance/wac) CLI to compose components at the command line. +You can use the [WebAssembly Compositions (WAC)](https://github.com/bytecodealliance/wac) CLI +to compose components at the command line. -To perform quick and simple compositions, use the `wac plug` command. `wac plug` satisfies the import of a "socket" component by plugging a "plug" component's export into the socket. For example, a component that implements the [`validator` world above](#what-is-composition) needs to satisfy it's `match` import. It is a socket. While a component that implements the `regex` world, exports the `match` interface, and can be used as a plug. `wac plug` can plug a regex component's export into the validator component's import, creating a resultant composition: +To perform quick and simple compositions, use the `wac plug` command. +`wac plug` satisfies the import of a "socket" component by plugging a "plug" component's export into the socket. +The socket component is the primary component, while the plug components are dependency components. +For example, a component that implements the [`validator` world above](#what-is-composition) +needs to satisfy its `match` import. It is a socket. +On the other hand, a component that implements the `regex` world exports the `match` interface, +and can be used as a plug. +`wac plug` can plug a regex component's export into the validator component's import, +creating a resultant composition: ```sh wac plug validator-component.wasm --plug regex-component.wasm -o composed.wasm ``` -A component can also be composed with two components it depends on. +A component can also be composed with more than component that it depends on. ```sh wac plug path/to/component.wasm --plug path/to/dep1.wasm --plug path/to/dep2.wasm -o composed.wasm ``` -Here `component.wasm` is the component that imports interfaces from `dep1.wasm` and `dep2.wasm`, which export them. The composed component, with those dependencies satisfied and tucked away inside it, is saved to `composed.wasm`. +Here `component.wasm` is the component that imports interfaces from `dep1.wasm` and `dep2.wasm`, +which export interfaces. +The composed component, with those dependencies satisfied and tucked away inside it, is saved to `composed.wasm`. -The `plug` syntax doesn't cover transitive dependencies. If, for example, `dep1.wasm` has unsatisfied imports that you want to satisfy from `dep3.wasm`, you'd need to be deliberate about the order of your composition. You could compose `dep1.wasm` with `dep3.wasm` first, then refer to that composed component instead of `dep1.wasm`. However, this doesn't scale to lots of transitive dependencies, which is why the WAC language was created. +The `plug` syntax doesn't cover transitive dependencies. +If, for example, `dep1.wasm` has unsatisfied imports that you want to satisfy from `dep3.wasm`, +you'd need to be deliberate about the order of your composition. +You could compose `dep1.wasm` with `dep3.wasm` first, then refer to that composed component instead of `dep1.wasm`. +However, this doesn't scale to lots of transitive dependencies, which is why the WAC language was created. ### Advanced composition with the WAC language -`wac plug` is a convenience to achieve a common pattern in component compositions like above. However, composition can be arbitrarily complicated. In cases where `wac plug` is not sufficient, the [WAC language](https://github.com/bytecodealliance/wac/blob/main/LANGUAGE.md) can give us the ability to create arbitrarily complex compositions. +`wac plug` is a convenience to achieve a common pattern in component compositions like the ones above. +However, composition can be arbitrarily complicated. +In cases where `wac plug` is not sufficient, the [WAC language](https://github.com/bytecodealliance/wac/blob/main/LANGUAGE.md) +gives us the ability to create arbitrarily complex compositions. -In a WAC file, you use the WAC language to describe a composition. For example, the following is a WAC file that could be used to create that validator component from [earlier](#what-is-composition). +In a WAC file, you use the WAC language to describe a composition. +For example, the following is a WAC file that could be used to create the validator component from [earlier](#what-is-composition). ``` -//composition.wac -// Provide a package name for the resulting composition -package docs:composition; - -// Instantiate the regex-impl component that implements the `regex` world. Bind this instance's exports to the local name `regex`. -let regex = new docs:regex-impl { }; - -// Instantiate the validator-impl component which implements the `validator` world and imports the match interface from the regex component. -let validator = new docs:validator-impl { match: regex.match, ... }; - -// Export all remaining exports of the validator instance -export validator...; +{{#include ../../examples/composing-section-examples/composition.wac}} ``` -Then, `wac compose` can be used to compose the components, passing in the paths to the components. Alternatively, you can place the components in a `deps` directory with an expected structure, and in the near future, you will be able to pull in components from registries. See the [`wac` documentation](https://github.com/bytecodealliance/wac) for more details. +Then, `wac compose` can be used to compose the components, using the `--dep` flag to specify +the relationships between component names and `.wasm` files: ```sh -wac compose --dep docs:regex-impl=regex-component.wasm --dep docs:validator-impl=validator-component.wasm -o composed.wasm composition.wac +wac compose --dep docs:regex-impl=regex-component.wasm \ + --dep docs:validator-impl=validator-component.wasm \ + -o composed.wasm \ + composition.wac ``` -For an in depth description about how to use the wac tool, you can check out the [wac language index](https://github.com/bytecodealliance/wac/blob/main/LANGUAGE.md) and [examples](https://github.com/bytecodealliance/wac/tree/main/examples). +Alternatively, you can place the components in a `deps` directory with an expected structure, +and in the near future, you will be able to pull in components from registries. +See the [`wac` documentation](https://github.com/bytecodealliance/wac) for more details. + +For an in-depth description about how to use the `wac` tool, +you can check out the [WAC language index](https://github.com/bytecodealliance/wac/blob/main/LANGUAGE.md) +and [examples](https://github.com/bytecodealliance/wac/tree/main/examples). ## Composing components with a visual interface You can compose components visually using the builder app at [wasmbuilder.app](https://wasmbuilder.app/). -1. Use the Add Component Button to upload the `.wasm` component files you want to compose. The components appear in the sidebar. +1. Use the "Add Component" button to upload the `.wasm` component files you want to compose. + The components appear in the sidebar. -2. Drag the components onto the canvas. You'll see imports listed on the left of each component, and exports on the right. +2. Drag the components onto the canvas. + You'll see imports listed on the left of each component, and exports on the right. -3. Click the box in the top left to choose the 'primary' component, that is, the one whose exports will be preserved. (The clickable area is quite small - wait for the cursor to change from a hand to a pointer.) +3. Click the box in the top left to choose the 'primary' component, that is, + the one whose exports will be preserved. + (The clickable area is quite small—wait for the cursor to change from a hand to a pointer.) -4. To fulfil one of the primary component's imports with a dependency's export, drag from the "I" icon next to the export to the "I" item next to the import. (Again, the clickable area is quite small - wait for the cursor to change from a hand to a cross.) +4. To fulfil one of the primary component's imports with a dependency's export, + drag from the "I" icon next to the export to the "I" item next to the import. + (Again, the clickable area is quite small—wait for the cursor to change from a hand to a cross.) -5. When you have connected all the imports and exports that you want, click the Download Component button to download the composed component as a `.wasm` file. +5. When you have connected all the imports and exports that you want, + click the Download Component button to download the composed component as a `.wasm` file. diff --git a/component-model/src/composing-and-distributing/distributing.md b/component-model/src/composing-and-distributing/distributing.md index 1b7142a0..1d9c919a 100644 --- a/component-model/src/composing-and-distributing/distributing.md +++ b/component-model/src/composing-and-distributing/distributing.md @@ -1,80 +1,115 @@ # Distributing and Fetching Components and WIT -Modern applications rely extensively on third-party packages - so extensively that distributing packages is almost an industry in itself. Traditionally, these have been specific to a language. For example, JavaScript developers are used to using packages from NPM, and Rust developers use `crates.io`. Some runtimes support binary distribution and linking, enabling limited cross-language interop; for example, Maven packages can be written in any language that targets the Java runtime. Services like this are variously referred to as "package managers" or "registries." - -Publishing and distribution are not defined by the core component model, but form important part of the component ecosystem. For example, if you're writing JavaScript, and want to pull in a highly optimised machine learning algorithm written in C and compiled to Wasm, you can pull it from a registry, ideally just as easily as you would add a NPM package from the NPM registry. - -You can get involved with improving the packaging and hosting of Wasm components by joining the [Bytecode Alliance Packaging Special Interest Group (SIG)](https://github.com/bytecodealliance/governance/blob/main/SIGs/sig-packaging/proposal.md). +Modern applications rely extensively on third-party packages—so extensively +that distributing packages is almost an industry in itself. +Traditionally, package distribution services have been specific to a single programming language. +For example, JavaScript developers are used to using packages from NPM, +and Rust developers use `crates.io`. +Some runtimes support binary distribution and linking, enabling limited cross-language interoperability: +for example, Maven packages can be written in any language that targets the Java runtime. +Services like this are variously referred to as "package managers" or "registries." + +Publishing and distribution are not defined by the core component model, +but they form an important part of the component ecosystem. +For example, if you're writing JavaScript, and want to pull in a highly optimised machine learning algorithm +written in C and compiled to Wasm, you can pull it from a registry, +ideally just as easily as you would add an NPM package from the NPM registry. + +You can get involved with improving the packaging and hosting of WebAssembly components +by joining the [Bytecode Alliance Packaging Special Interest Group (SIG)](https://github.com/bytecodealliance/governance/blob/main/SIGs/sig-packaging/proposal.md). ## The `wkg` Registry Tool -The [`wasm-pkg-tools` project](https://github.com/bytecodealliance/wasm-pkg-tools) enables fetching and publishing Wasm components to OCI registries. It contains a `wkg` CLI tool that eases distributing and fetching components and WIT packages. The usual way of using `wkg` is to address packages by their package name, i.e. `example:adder@1.0.0`. When using `wkg` this way, you don't need to know about the physical location of the package, as the `wkg` configuration handles that for you. If you need to, though, you can also use `wkg` to work with OCI artifacts directly, addressing them by OCI references when using the `wkg oci` subcommand. +The [`wasm-pkg-tools` project](https://github.com/bytecodealliance/wasm-pkg-tools) +enables fetching and publishing WebAssembly components to +[Open Container Initiative](https://opencontainers.org/) (OCI) registries. + +`wasm-pkg-tools` contains a `wkg` CLI tool that eases distributing and fetching components and WIT packages. +The usual way of using `wkg` is to address packages by their names: for example, `example:adder@1.0.0`. +When using `wkg` this way, you don't need to know about the physical location of the package, +as the `wkg` configuration handles that for you. +If you need to, though, you can also use `wkg` to work with OCI artifacts directly, +addressing them by OCI references when using the `wkg oci` subcommand. `wkg` contains several subcommand: -- `wkg oci` - pushes/pulls Wasm artifacts to/from any OCI registry -- `wkg publish` - publish components or WIT packages by package name -- `wkg get` - pulls components or WIT packages by package name -- `wkg wit` - commands for interacting with WIT files and dependencies -- `wkg config` - interact with the `wkg` configuration +- `wkg oci`: pushes/pulls WebAssembly artifacts to/from any OCI registry +- `wkg publish`: publishes components or WIT packages by package name +- `wkg get`: pulls components or WIT packages by package name +- `wkg wit`: interacts with WIT files and dependencies +- `wkg config`: interacts with the `wkg` configuration The following sections detail a subset of actions that can be performed with `wkg`. ## `wkg` Configuration Files -When you use most `wkg` commands (`wkg oci` being the exception), you don't interact with physical locations, only with package names. The `wkg` configuration file is used to map package naming to physical location. It provides the ability to configure: - -- The default registry for packages in a given namespace. For example, the location for `wasi` packages such as `wasi:clocks` or `wasi:http`. -- Registry overrides for specific packages, or packages not stored in the same place as the rest of their namespace. For example, if `wasi:key-value` were stored in a different registry from other `wasi` packages. -- The default registry for all packages not listed in one of the previous sections - -The configuration file also includes credentials for private registries, or for pushing to registries where you have permission, and other configuration options. See the [`wkg` docs for more configuration options](https://github.com/bytecodealliance/wasm-pkg-tools?tab=readme-ov-file#configuration). - -For example, to fetch WASI packages, such as `wasi:clocks` and `wasi:http`, you can add a line under the `namespace_registries` section for the `wasi` namespace. Specifically, the example below configures `wkg` to fetch WASI packages from the [WebAssembly OCI GitHub Container Registry](https://github.com/orgs/WebAssembly/packages), where the latest interfaces are published upon WASI releases. To edit your `wkg` config file, run `wkg config --edit`. - -> Remember, all package names consist of the a namespace field followed by the package field. The package name `wasi:clocks` has a namespace of `wasi` and package field of `clocks`. In this way, the following configuration ensures that `wkg` will know to route fetches and publishes of any `wasi:` to the configured location. +When you use most `wkg` commands (`wkg oci` being the exception), +you don't interact with physical locations, only with package names. +The `wkg` configuration file is used to map package names to physical locations. +It provides the ability to configure: + +- The default registry for packages in a given namespace: for example, + the location for `wasi` packages such as `wasi:clocks` or `wasi:http`. +- Registry overrides for specific packages that are not stored in the same place as the rest of their namespaces. + For example, an override would be used if `wasi:key-value` were stored in a different registry + from other `wasi` packages. +- The default registry for all packages not listed in one of the previous sections. + +The configuration file also includes credentials for private registries, +or for pushing to registries where you have permission, and other configuration options. +See the [`wkg` docs for more configuration options](https://github.com/bytecodealliance/wasm-pkg-tools?tab=readme-ov-file#configuration). + +For example, to fetch WASI packages, such as `wasi:clocks` and `wasi:http`, +you can add a line under the `namespace_registries` section for the `wasi` namespace. +Specifically, the example below configures `wkg` to fetch WASI packages from the [WebAssembly OCI GitHub Container Registry](https://github.com/orgs/WebAssembly/packages), +where the latest interfaces are published upon WASI releases. +To edit your `wkg` config file, run `wkg config --edit`. + +> Remember, all package names consist of a namespace field followed by a package field. +> For example, the package name `wasi:clocks` has a namespace field of `wasi` and package field of `clocks`. +> In this way, the following configuration ensures that `wkg` will know to route fetches and publishes +> of any `wasi:` to the configured location. ```toml # $XDG_CONFIG_HOME/wasm-pkg/config.toml default_registry = "ghcr.io" [namespace_registries] -# Tell wkg that packages with the `wasi` namespace are in an OCI registry under ghcr.io/webassembly +# Tell wkg that packages with the `wasi` namespace are in an OCI registry +# under ghcr.io/webassembly wasi = { registry = "wasi", metadata = { preferredProtocol = "oci", "oci" = {registry = "ghcr.io", namespacePrefix = "webassembly/" } } } ``` -As a more generic example, The following configuration, instructs `wkg` to use [ttl.sh](https://ttl.sh/) OCI registry for all packages with the `docs` namespace. +As a more generic example, the following configuration instructs `wkg` to use +the [ttl.sh](https://ttl.sh/) OCI registry for all packages with the `docs` namespace. ```toml # $XDG_CONFIG_HOME/wasm-pkg/config.toml default_registry = "ghcr.io" [namespace_registries] -# Instruct wkg to use the OCI protocol to fetch packages with the `foo` namespace from ttl.sh/wasm-components -docs = { registry = "docs-registry", metadata = { preferredProtocol = "oci", "oci" = {registry = "ttl.sh", namespacePrefix = "wasm-components/" } } } +# Instruct wkg to use the OCI protocol to fetch packages with the `docs` namespace from ttl.sh/wasm-components +docs = { registry = "docs", metadata = { preferredProtocol = "oci", "oci" = {registry = "ttl.sh", namespacePrefix = "wasm-components/" } } } ``` -> Note: the registry name can be referenced in the `package_registry_overrides` section of the `wkg` config to provide overrides for specific packages of a namespace. +> Note: the registry name can be referenced in the `package_registry_overrides` section of the `wkg` config +> to provide overrides for specific packages of a namespace. ## Distributing WIT and Components by Package Name with `wkg publish` -Once you've [configured `wkg`](#wkg-configuration-files) to know where to publish packages to, you can use the `wkg publish` command to publish *components* or *interfaces* to be consumed by others. +Once you've [configured `wkg`](#wkg-configuration-files) to specify where to publish packages to, +you can use the `wkg publish` command to publish *components* or *interfaces* to be consumed by others. Imagine you have defined the following `adder` world in WIT: ```wit -package docs:adder@0.1.0; - -interface add { - add: func(a: u32, b: u32) -> u32; -} - -world adder { - export add; -} +{{#include ../../examples/tutorial/wit/adder/world.wit}} ``` -You can publish this *WIT* using `wkg` by wrapping it up as a Wasm component. Yes, you heard that right! We are packaging WIT as Wasm. +You can publish this *WIT* using `wkg` by wrapping it up as a Wasm component. +Yes, you heard that right! We are packaging WIT as Wasm. +If you've saved this world file in a directory called `tutorial/wit/adder`, +you can execute: ```sh # Package the contents of add WIT directory as Wasm @@ -83,7 +118,9 @@ wkg wit build --wit-dir tutorial/wit/adder wkg publish docs:adder@0.1.0.wasm ``` -If you had configured `wkg` as described in the [`wkg` configuration section](#wkg-configuration-files), this would publish the component to `ttl.sh/wasm-components/docs/adder:0.1.0`. This WIT can then be fetched using `wkg get`, specifying the format `wit`: +If you had configured `wkg` as described in the [`wkg` configuration section](#wkg-configuration-files), +this would publish the component to `ttl.sh/wasm-components/docs/adder:0.1.0`. +This WIT can then be fetched using `wkg get`, specifying the format `wit`: ```sh wkg get --format wit docs:adder@0.1.0 --output adder.wit @@ -95,7 +132,7 @@ Instead of publishing the WIT interface, you could publish the built component b wkg publish adder.wasm --package docs:adder@0.1.0 ``` -You can then fetch the component by running: +You could then fetch the component by running: ```sh wkg get docs:adder@0.1.0 --output adder.wasm @@ -103,9 +140,11 @@ wkg get docs:adder@0.1.0 --output adder.wasm ## More Generic Operations with `wkg oci` -The `wkg oci` subcommand enables pushing/pulling Wasm artifacts to/from any OCI registry. Unlike `wkg publish` and `wkg get`, providing the WIT package is not required. +The `wkg oci` subcommand enables pushing and pulling Wasm artifacts to or from any OCI registry. +Unlike with `wkg publish` and `wkg get`, providing the WIT package is not required. -To push a component to an OCI registry, use `wkg oci pull`. The example below pushes a component to a GitHub Container Registry. +To push a component to an OCI registry, use `wkg oci pull`. +The example below pushes a component to a GitHub Container Registry. ```sh wkg oci push ghcr.io/user/component:0.1.0 component.wasm @@ -119,20 +158,22 @@ wkg oci pull ghcr.io/user/component:0.1.0 -o component.wasm ## Fetching WIT Package Dependencies using `wkg` -Sometimes fetching a single package is not sufficient because it depends on other packages. For example, the following world describes a simple Wasm service which requires `wasi:http/proxy`: +Sometimes fetching a single package is not sufficient because it depends on other packages. +For example, the following world describes a simple Wasm service that requires `wasi:http/proxy`: ```wit -package foo:wasi-http-service; - -world target-world { - include wasi:http/proxy@0.2.3; -} +{{#include ../../examples/composing-section-examples/http-service.wit}} ``` -You may be tempted to simply get the `wasi:http` package with `wkg get --format wit wasi:http@0.2.3 -o wit/deps/http/`. However, `wasi:http` depends on other WASI packages such as `wasi:clocks` and `wasi:io`. To make sure to fetch a package and all its dependencies, use `wkg wit fetch`, which will read the package containing the world(s) you have defined in the given wit directory (`wit` by default). It will then fetch the -dependencies and write them to the `deps` directory along with a lock file. +You may be tempted to simply get the `wasi:http` package with +`wkg get --format wit wasi:http@0.2.3 -o wit/deps/http/`. +However, `wasi:http` depends on other WASI packages such as `wasi:clocks` and `wasi:io`. +To make sure to fetch a package and all its dependencies, use `wkg wit fetch`, +which will read the package containing the world(s) you have defined in the given WIT directory (`wit` by default). +It will then fetch the dependencies and write them to the `deps` subdirectory along with a lock file. +(The lock file specifies the exact version of each dependency that will be used in your project.) -After placing the above file in `./wit`, run the following to fetch the dependencies: +After saving the above file as `./wit/world.wit`, run the following command to fetch the dependencies: ```sh wkg wit fetch @@ -155,4 +196,4 @@ wit └── world.wit ``` -Now, you can use the language toolchain of your choice to generate bindings and create your component. \ No newline at end of file +Now, you can use the language toolchain of your choice to generate bindings and create your component.