-
Notifications
You must be signed in to change notification settings - Fork 0
Development
Working on steamwand itself. For using the published package, start at Getting Started.
pnpm installNode 18 or newer, pnpm 10. There is no native build step: the only runtime
dependency is koffi, and the steam_api redistributables are committed under
runtime/.
scripts/
generate.ts binding generator (steam_api.json -> src/generated)
smoke.ts read-only live smoke, 30 checks over 10 interfaces
workbench.ts local web UI over the whole binding
workbench.html its single-page front end
src/
index.ts init(), the Steam class, the public exports
api/
errors.ts SteamResultError, SteamInitError, eResultName
guards.ts the ok() and must() throw helpers the layers share
workshop.ts the curated workshop layer
stats.ts achievements and per-user stats
cloud.ts Steam Cloud files
leaderboards.ts find or create, upload, download
lobbies.ts lobby create/join/data/chat/search
runtime/
native.ts koffi library load, core exports, lazy func() cache
dispatch.ts manual dispatch pump, call results, SteamApiCallError
platform.ts platform detection, lib path, callback pack
struct.ts offset-table struct decoding
types.ts SteamParamStringArray_t and stringArray()
generated/ GENERATED, committed, never hand-edited
runtime/
win64/steam_api64.dll linux64/libsteam_api.so osx/libsteam_api.dylib
test/
offsets.test.ts offline layout regression
live/workshop.live.test.ts full workshop round trip
live/curated.live.test.ts stats, cloud, leaderboards, lobbies
sdk.lock.json which SDK the generated output came from
Handwritten code is everything under src/ except src/generated/. To change
generated output, change scripts/generate.ts and regenerate: see
Regenerating.
sdk/ and steamworks_sdk_*.zip are gitignored. The SDK must never be
committed.
| Script | Command | Needs |
|---|---|---|
pnpm build |
tsc -p tsconfig.build.json |
nothing |
pnpm typecheck |
tsc --noEmit |
nothing |
pnpm test |
vitest run |
nothing |
pnpm generate |
tsx scripts/generate.ts |
a local SDK at ./sdk or $STEAMWORKS_SDK
|
pnpm smoke |
tsx scripts/smoke.ts |
a running, logged-in Steam client |
pnpm test:live |
cross-env STEAM_LIVE=1 vitest run test/live |
a running, logged-in Steam client |
pnpm workbench |
tsx scripts/workbench.ts |
a running, logged-in Steam client |
tsconfig.json covers src, scripts, and test, so pnpm typecheck sees
everything. tsconfig.build.json narrows the input to src and emits dist/
with declarations. The published package ships dist, runtime, README.md,
and LICENSE.
pnpm testtest/offsets.test.ts is the offline regression net. It pins both the win64
and posix offsets of the workshop struct set and the five workshop callback
ids. It needs no Steam client and runs in CI on all three platforms. If an SDK
bump moves an offset, this is what tells you.
pnpm test:liveBoth live files are guarded by describe.skipIf(!process.env.STEAM_LIVE), so
pnpm test walks over them silently. pnpm test:live sets STEAM_LIVE=1 and
runs both on Spacewar (appid 480).
test/live/workshop.live.test.ts is the full workshop round trip: init, create
a private throwaway item, upload content and default-language text, submit a
German translation through SetItemUpdateLanguage, query both languages back,
check the item appears in the user's item list, then delete it. afterAll
deletes the item even when a test fails, so it does not leave workshop garbage
behind. The upload steps have 120 second timeouts.
test/live/curated.live.test.ts covers the other four layers: the achievement
schema and display text, the current player count and the global percentages,
one cloud file written, read back, listed and deleted, the quota reads, a
leaderboard lookup that accepts either the found or the null path, and one
lobby created, written to, chatted in and left. It touches nothing durable: one
temporary cloud file and one private throwaway lobby, both cleaned up, and it
neither unlocks an achievement nor uploads a score.
pnpm smokeRead-only. One call per argument and return shape (string, bool, float,
uint64, out buffer, call result, struct decode) across 10 interfaces. It
prints PASS or FAIL per check and exits non-zero on any failure. Use it to
confirm a regenerated binding still talks to Steam. Note that a few checks
assert against the machine's own library (an installed Crusader Kings III, a
known workshop item), so a fresh machine can report failures that are not
steamwand's fault.
Keep tests focused. The offset tests exist because a silent offset shift would decode garbage; do not add broad snapshot tests over generated output.
pnpm workbenchThen open http://localhost:4879. The server binds 127.0.0.1 only. It is a
manual test bench over the whole binding: initialize under any app id, list
every generated interface and its methods, call any method with typed
arguments ("123n" becomes a bigint, a string array becomes a
SteamParamStringArray_t, { "buf": 260 } becomes an out buffer), await a
call result and decode it with any layout, watch any callback by struct name,
and drive the curated workshop layer.
The workshop panel performs real, destructive actions. createItem
creates a real workshop item on your account, submitUpdate uploads and
publishes, and deleteItem deletes permanently. Use appid 480 and private
visibility while testing.
One app id per process: after close, restart the workbench rather than
initializing again.
.github/workflows/ci.yml runs on pushes to main and on every pull request.
Matrix: windows-latest, ubuntu-latest, macos-latest, with
fail-fast: false, pnpm 10, Node 22, pnpm install --frozen-lockfile. Then:
pnpm typecheck
pnpm test
pnpm build
Live tests are deliberately not in CI: they need a logged-in Steam client, which a runner does not have. The three-platform matrix is what keeps the posix layouts honest.
Publishing is tag-driven. .github/workflows/publish.yml triggers on tags
matching v*.
-
Bump
versioninpackage.jsonand commit it. -
Tag and push:
git tag v0.1.1 && git push origin v0.1.1
The workflow runs on ubuntu-latest with Node 24, does
pnpm install --frozen-lockfile, pnpm typecheck, pnpm test, pnpm build,
then npm publish --access public. It uses npm OIDC trusted publishing
(permissions: id-token: write), so there is no NPM_TOKEN secret to rotate.
The package name is steamwand.js.
These pages live in the wiki repository, not in the main repository. Clone it and edit the files directly:
git clone https://github.com/JDeffner/steamwand.js.wiki.gitOne file is one page. Home.md is the landing page, _Sidebar.md is the
navigation. Links between pages use the page name with no extension, for
example [Core API](Core-API). Commit and push, and the change is live.