Skip to content

Commit b7eeecf

Browse files
committed
Publish nexis_wasm_plugin crate on release CI
Add a release.yml job and inputs to publish nexis_wasm_plugin via OIDC. Bump crate version and metadata, add the crate README, and update docs, examples, and RELEASING.md to document publishing steps.
1 parent c8ef350 commit b7eeecf

8 files changed

Lines changed: 178 additions & 1 deletion

File tree

.github/workflows/release.yml

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,11 @@ on:
1313
required: false
1414
default: true
1515
type: boolean
16+
publish_crate_nexis_wasm_plugin:
17+
description: "Publish nexis_wasm_plugin crate to crates.io"
18+
required: false
19+
default: true
20+
type: boolean
1621
publish_images:
1722
description: "Build and publish Docker images to GHCR"
1823
required: false
@@ -31,6 +36,7 @@ jobs:
3136
runs-on: ubuntu-latest
3237
outputs:
3338
sdk_ts: ${{ steps.set.outputs.sdk_ts }}
39+
crate_nexis_wasm_plugin: ${{ steps.set.outputs.crate_nexis_wasm_plugin }}
3440
image_rust_server: ${{ steps.set.outputs.image_rust_server }}
3541
image_control_api: ${{ steps.set.outputs.image_control_api }}
3642
image_dashboard_ui: ${{ steps.set.outputs.image_dashboard_ui }}
@@ -45,6 +51,8 @@ jobs:
4551
filters: |
4652
sdk_ts:
4753
- 'sdks/ts/**'
54+
crate_nexis_wasm_plugin:
55+
- 'plugins/rust/nexis_wasm_plugin/**'
4856
image_rust_server:
4957
- 'server/**'
5058
- 'plugins/**'
@@ -60,12 +68,14 @@ jobs:
6068
run: |
6169
if [[ "${GITHUB_REF}" == refs/tags/v* ]] || [[ "${GITHUB_EVENT_NAME}" == "workflow_dispatch" ]]; then
6270
sdk_ts=true
71+
crate_nexis_wasm_plugin=true
6372
image_rust_server=true
6473
image_control_api=true
6574
image_dashboard_ui=true
6675
image_web_demo=true
6776
else
6877
sdk_ts="${{ steps.filter.outputs.sdk_ts }}"
78+
crate_nexis_wasm_plugin="${{ steps.filter.outputs.crate_nexis_wasm_plugin }}"
6979
image_rust_server="${{ steps.filter.outputs.image_rust_server }}"
7080
image_control_api="${{ steps.filter.outputs.image_control_api }}"
7181
image_dashboard_ui="${{ steps.filter.outputs.image_dashboard_ui }}"
@@ -78,6 +88,7 @@ jobs:
7888
fi
7989
8090
echo "sdk_ts=${sdk_ts}" >> "$GITHUB_OUTPUT"
91+
echo "crate_nexis_wasm_plugin=${crate_nexis_wasm_plugin}" >> "$GITHUB_OUTPUT"
8192
echo "image_rust_server=${image_rust_server}" >> "$GITHUB_OUTPUT"
8293
echo "image_control_api=${image_control_api}" >> "$GITHUB_OUTPUT"
8394
echo "image_dashboard_ui=${image_dashboard_ui}" >> "$GITHUB_OUTPUT"
@@ -388,6 +399,46 @@ jobs:
388399
working-directory: sdks/ts
389400
run: npm publish --access public --provenance --tag ${{ steps.npm_tag.outputs.tag }}
390401

402+
publish-crate-nexis-wasm-plugin:
403+
needs: [changes, validate]
404+
if: startsWith(github.ref, 'refs/tags/v') && (github.event_name == 'push' || inputs.publish_crate_nexis_wasm_plugin == true) && needs.changes.outputs.crate_nexis_wasm_plugin == 'true'
405+
runs-on: ubuntu-latest
406+
permissions:
407+
contents: read
408+
id-token: write
409+
environment: release
410+
steps:
411+
- uses: actions/checkout@v4
412+
- uses: dtolnay/rust-toolchain@1.89.0
413+
- name: Read crate version
414+
id: crate
415+
shell: bash
416+
run: |
417+
version="$(grep -m1 '^version = ' plugins/rust/nexis_wasm_plugin/Cargo.toml | sed -E 's/version = \"([^\"]+)\"/\1/')"
418+
echo "version=${version}" >> "$GITHUB_OUTPUT"
419+
- name: Check if crate version already exists on crates.io
420+
id: exists
421+
shell: bash
422+
run: |
423+
if curl -fsS "https://crates.io/api/v1/crates/nexis_wasm_plugin/${{ steps.crate.outputs.version }}" > /dev/null; then
424+
echo "already_published=true" >> "$GITHUB_OUTPUT"
425+
echo "nexis_wasm_plugin@${{ steps.crate.outputs.version }} is already published."
426+
else
427+
echo "already_published=false" >> "$GITHUB_OUTPUT"
428+
fi
429+
- name: Dry-run publish
430+
if: steps.exists.outputs.already_published != 'true'
431+
run: cargo publish --dry-run --locked --manifest-path plugins/rust/nexis_wasm_plugin/Cargo.toml
432+
- name: Authenticate with crates.io (trusted publishing)
433+
if: steps.exists.outputs.already_published != 'true'
434+
id: auth
435+
uses: rust-lang/crates-io-auth-action@v1
436+
- name: Publish crate to crates.io
437+
if: steps.exists.outputs.already_published != 'true'
438+
env:
439+
CARGO_REGISTRY_TOKEN: ${{ steps.auth.outputs.token }}
440+
run: cargo publish --locked --manifest-path plugins/rust/nexis_wasm_plugin/Cargo.toml
441+
391442
build-rust-server-binary:
392443
needs: validate
393444
if: startsWith(github.ref, 'refs/tags/v')

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
# NEXIS
22

3+
[![npm version](https://img.shields.io/npm/v/%40triformine%2Fnexis-sdk?logo=npm&label=npm)](https://www.npmjs.com/package/@triformine/nexis-sdk)
4+
35
Nexis is an open-source, engine-agnostic multiplayer backend platform with:
46

57
- a Rust data plane for realtime gameplay traffic

RELEASING.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ This document defines the release process for Nexis.
1616
- `server/Cargo.toml` workspace version
1717
- `sdks/ts/package.json`
1818
- `dashboard/control-api/package.json`
19+
- `plugins/rust/nexis_wasm_plugin/Cargo.toml`
1920
3. Update `CHANGELOG.md`.
2021
4. Run quality gates:
2122
- `cargo test --manifest-path server/Cargo.toml`
@@ -24,6 +25,7 @@ This document defines the release process for Nexis.
2425
- `bun test` in `dashboard/control-api`
2526
- `bunx tsc --noEmit` in `dashboard/control-api`
2627
- `bun run build` in `docs-site`
28+
- `cargo publish --dry-run --manifest-path plugins/rust/nexis_wasm_plugin/Cargo.toml`
2729
5. Validate stack (locally or CI compose-smoke):
2830
- `docker compose -f infra/docker-compose.yml up -d --build --wait`
2931
- `bun infra/smoke.ts`
@@ -56,6 +58,32 @@ On tag push (`v*`) it:
5658
- `ghcr.io/<owner>/web-demo:<tag>`
5759
- plus `:latest`
5860
3. publishes `@triformine/nexis-sdk` to npm
61+
4. publishes `nexis_wasm_plugin` to crates.io
62+
63+
## crates.io Publish (`nexis_wasm_plugin`)
64+
65+
`release.yml` publishes this crate automatically on tag pushes (`v*`) using
66+
crates.io trusted publishing (OIDC).
67+
68+
One-time setup on crates.io:
69+
70+
1. Open crate settings for `nexis_wasm_plugin`.
71+
2. Add trusted publisher:
72+
- Provider: `GitHub Actions`
73+
- Organization/user: `TriForMine`
74+
- Repository: `nexis`
75+
- Workflow filename: `release.yml`
76+
3. Save configuration.
77+
78+
Manual fallback:
79+
80+
1. Run dry-run:
81+
- `cargo publish --dry-run --manifest-path plugins/rust/nexis_wasm_plugin/Cargo.toml`
82+
2. Publish:
83+
- `cargo publish --manifest-path plugins/rust/nexis_wasm_plugin/Cargo.toml`
84+
3. Verify:
85+
- <https://crates.io/crates/nexis_wasm_plugin>
86+
- <https://docs.rs/nexis_wasm_plugin>
5987

6088
## npm Trusted Publishing (OIDC)
6189

docs-site/content/docs/guides/plugins.mdx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,14 @@ Best when:
3232

3333
Configured through `NEXIS_WASM_ROOM_PLUGINS`.
3434

35+
Rust plugin authors can use the helper crate published on crates.io:
36+
37+
```toml
38+
[dependencies]
39+
nexis_wasm_plugin = "0.1.5"
40+
serde_json = "1"
41+
```
42+
3543
## Message contract inside plugins
3644

3745
Room message payload in plugin `on_message`:

examples/wasm-plugins/README.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,16 @@ This example uses Nexis' Rust helper crate:
1010

1111
so plugin authors write normal Rust handlers instead of raw ABI exports.
1212

13+
For external projects, depend on crates.io:
14+
15+
```toml
16+
[dependencies]
17+
nexis_wasm_plugin = "0.1.5"
18+
serde_json = "1"
19+
```
20+
21+
Inside this monorepo example, we keep a local path dependency for development.
22+
1323
Build:
1424

1525
```bash

plugins/rust/nexis_wasm_plugin/Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

plugins/rust/nexis_wasm_plugin/Cargo.toml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,22 @@
22
name = "nexis_wasm_plugin"
33
version = "0.1.5"
44
edition = "2021"
5+
rust-version = "1.89"
56
license = "Apache-2.0"
7+
description = "Rust helper crate for authoring Nexis runtime-loaded WASM room plugins."
8+
readme = "README.md"
9+
repository = "https://github.com/TriForMine/nexis"
10+
homepage = "https://triformine.github.io/nexis/"
11+
documentation = "https://docs.rs/nexis_wasm_plugin"
12+
keywords = ["nexis", "multiplayer", "wasm", "plugin"]
13+
categories = ["api-bindings", "game-development", "wasm"]
614
authors = ["TriForMine <quentin@triformine.dev>"]
715

816
[lib]
917
path = "src/lib.rs"
1018

1119
[dependencies]
1220
serde_json = "1"
21+
22+
[package.metadata.docs.rs]
23+
targets = ["wasm32-unknown-unknown"]
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
# nexis_wasm_plugin
2+
3+
Rust helper crate for building Nexis runtime-loaded WASM room plugins.
4+
5+
This crate gives plugin authors:
6+
7+
- a `RoomPlugin` trait with lifecycle hooks
8+
- a `PluginOutput` type for returning state and optional events
9+
- an `export_plugin!` macro that exports the host ABI functions
10+
11+
## Install
12+
13+
```toml
14+
[dependencies]
15+
nexis_wasm_plugin = "0.1.5"
16+
serde_json = "1"
17+
```
18+
19+
## Minimal Plugin
20+
21+
```rust
22+
use nexis_wasm_plugin::{export_plugin, PluginOutput, RoomPlugin};
23+
use serde_json::{json, Value};
24+
25+
#[derive(Default)]
26+
struct CounterPlugin;
27+
28+
impl RoomPlugin for CounterPlugin {
29+
fn initial_state(&self) -> Value {
30+
json!({ "counter": 0 })
31+
}
32+
33+
fn on_message(&self, state: &Value, input: &Value) -> PluginOutput {
34+
if input.get("type").and_then(Value::as_str) == Some("inc") {
35+
let by = input
36+
.get("data")
37+
.and_then(|data| data.get("by"))
38+
.and_then(Value::as_i64)
39+
.unwrap_or(1);
40+
let current = state.get("counter").and_then(Value::as_i64).unwrap_or(0);
41+
let next = current + by;
42+
return PluginOutput::state_with_event(
43+
json!({ "counter": next }),
44+
json!({ "type": "counter.updated", "data": { "counter": next } }),
45+
);
46+
}
47+
48+
PluginOutput::state(state.clone())
49+
}
50+
}
51+
52+
export_plugin!(CounterPlugin);
53+
```
54+
55+
## Build for Nexis Runtime
56+
57+
```bash
58+
rustup target add wasm32-unknown-unknown
59+
cargo build --target wasm32-unknown-unknown --release
60+
```
61+
62+
Use the generated `.wasm` in `NEXIS_WASM_ROOM_PLUGINS`.
63+
64+
## Compatibility
65+
66+
`nexis_wasm_plugin` follows Nexis `0.x` compatibility policy: APIs can evolve between minor releases.
67+
Pin and test before upgrading.

0 commit comments

Comments
 (0)