diff --git a/.gitea/workflows/sdk-publish.yml b/.gitea/workflows/sdk-publish.yml new file mode 100644 index 00000000..9aaa5b9d --- /dev/null +++ b/.gitea/workflows/sdk-publish.yml @@ -0,0 +1,60 @@ +# Publish the TypeScript SDK (@punktfunk/host) to the Gitea npm registry +# (https://git.unom.io/api/packages/unom/npm/). +# +# Trigger: push a tag `sdk-vX.Y.Z` (must equal sdk/package.json "version"), or run manually. +# The SDK versions independently of the app's `v*` tags, so bumping the host doesn't republish it. +# +# Auth: REGISTRY_TOKEN — the same repo Actions secret docker.yml uses (a Gitea PAT with +# write:package scope). No new secret needed. +name: sdk-publish + +on: + push: + tags: ['sdk-v*'] + workflow_dispatch: + +jobs: + publish: + runs-on: ubuntu-24.04 + container: + image: oven/bun:1 + timeout-minutes: 15 + defaults: + run: + working-directory: sdk + steps: + # oven/bun's slim base ships neither git, a CA bundle, nor node — actions/checkout's HTTPS + # fetch needs git + ca-certificates, and the version-guard step below uses node. + - name: Install git + node + CA certs + working-directory: / + run: apt-get update && apt-get install -y --no-install-recommends ca-certificates git nodejs + + - uses: actions/checkout@v4 + + - name: Install dependencies + run: bun install --frozen-lockfile --ignore-scripts + + - name: Typecheck + run: bun run typecheck + + - name: Test + run: bun test + + - name: Build (dist/ JS + .d.ts) + run: bun run build + + - name: Tag matches package version + if: startsWith(github.ref, 'refs/tags/') + run: | + TAG="${GITHUB_REF_NAME#sdk-v}" + PKG="$(node -p "require('./package.json').version")" + test "$TAG" = "$PKG" || { echo "tag $GITHUB_REF_NAME does not match package version $PKG"; exit 1; } + + - name: Publish to Gitea registry + env: + NODE_AUTH_TOKEN: ${{ secrets.REGISTRY_TOKEN }} + run: | + test -n "$NODE_AUTH_TOKEN" || { echo "REGISTRY_TOKEN secret is empty"; exit 1; } + # .npmrc already maps the @punktfunk scope to the registry; append the auth line. + printf '//git.unom.io/api/packages/unom/npm/:_authToken=%s\n' "$NODE_AUTH_TOKEN" >> .npmrc + bun publish diff --git a/sdk/.npmrc b/sdk/.npmrc new file mode 100644 index 00000000..0b2cc1f5 --- /dev/null +++ b/sdk/.npmrc @@ -0,0 +1 @@ +@punktfunk:registry=https://git.unom.io/api/packages/unom/npm/ diff --git a/sdk/README.md b/sdk/README.md index dfb4a74f..574caf85 100644 --- a/sdk/README.md +++ b/sdk/README.md @@ -15,6 +15,31 @@ Two surfaces, one core: `effect/Schema` (REST shapes generated from the host's OpenAPI spec; event shapes mirroring the host's snapshot-tested wire format). +## Install + +Published to the unom [Gitea npm registry](https://git.unom.io/unom/-/packages). Point the +`@punktfunk` scope at it once — in your project's `.npmrc` (or `~/.npmrc`): + +```ini +@punktfunk:registry=https://git.unom.io/api/packages/unom/npm/ +``` + +Then install: + +```sh +bun add @punktfunk/host # or: npm i @punktfunk/host +``` + +`effect` is a **peer dependency** (auto-installed by bun / npm ≥ 7) — so the SDK and your own +`@punktfunk/host/effect` code share one Effect instance. + +If the registry requires authentication (private org, or from CI), add a token line with a Gitea +PAT that has `read:package`: + +```ini +//git.unom.io/api/packages/unom/npm/:_authToken=${NODE_AUTH_TOKEN} +``` + ## Quickstart ```ts @@ -66,6 +91,14 @@ A complexity ladder in [`examples/`](./examples) — start at the top: Examples 1–3 are the plain Promise facade and cover most automation; you only need example 4's Effect surface for composed, interruptible programs. Run any with `bun examples/.ts`. +Plus a real-world recipe: + +- [`virtualhere-dualsense.ts`](./examples/virtualhere-dualsense.ts) — **USB passthrough**: bind a + real DualSense (shared from the couch over [VirtualHere](https://www.virtualhere.com/)) to the + host for the length of each connection and release it after — full gyro, touchpad, adaptive + triggers and USB rumble instead of an emulated pad. Shows the `client.connected`/`disconnected` + bracket and clean release on `systemctl stop`. + ## Connection resolution `connect()` / `PunktfunkHostLive()` resolve, in order: diff --git a/sdk/bun.lock b/sdk/bun.lock index 07b1eccf..099f8110 100644 --- a/sdk/bun.lock +++ b/sdk/bun.lock @@ -4,18 +4,19 @@ "workspaces": { "": { "name": "@punktfunk/host", - "dependencies": { - "effect": "^4.0.0-beta.98", - }, "devDependencies": { "@effect/openapi-generator": "4.0.0-beta.98", "@effect/platform-node": "4.0.0-beta.98", "@types/bun": "^1.3.0", + "effect": "^4.0.0-beta.98", "typescript": "^5.9.3", }, "optionalDependencies": { "undici": "^7.0.0", }, + "peerDependencies": { + "effect": "^4.0.0-beta.98", + }, }, }, "packages": { diff --git a/sdk/package.json b/sdk/package.json index 0b82c0ee..6a3e85cf 100644 --- a/sdk/package.json +++ b/sdk/package.json @@ -3,21 +3,49 @@ "version": "0.1.0", "description": "TypeScript SDK for the punktfunk streaming host: typed management-API client + lifecycle event stream, built on Effect.", "type": "module", - "private": true, + "license": "MIT OR Apache-2.0", + "homepage": "https://git.unom.io/unom/punktfunk/src/branch/main/sdk", + "repository": { + "type": "git", + "url": "https://git.unom.io/unom/punktfunk.git", + "directory": "sdk" + }, + "bugs": { + "url": "https://git.unom.io/unom/punktfunk/issues" + }, + "keywords": ["punktfunk", "game-streaming", "automation", "sdk", "effect"], + "main": "./dist/index.js", + "types": "./dist/index.d.ts", "exports": { - ".": "./src/index.ts", - "./effect": "./src/effect.ts" + ".": { + "types": "./dist/index.d.ts", + "default": "./dist/index.js" + }, + "./effect": { + "types": "./dist/effect.d.ts", + "default": "./dist/effect.js" + } + }, + "bin": { + "punktfunk-scripting": "./dist/runner-cli.js" + }, + "files": ["dist", "README.md"], + "publishConfig": { + "registry": "https://git.unom.io/api/packages/unom/npm/" }, "scripts": { "gen": "openapigen --spec ../api/openapi.json --name Punktfunk --format httpclient > src/gen/punktfunk.ts", "typecheck": "tsc --noEmit", + "build": "tsc -p tsconfig.build.json", "test": "bun test", - "runner": "bun src/runner-cli.ts" + "runner": "bun src/runner-cli.ts", + "prepublishOnly": "bun run build" }, - "dependencies": { + "peerDependencies": { "effect": "^4.0.0-beta.98" }, "devDependencies": { + "effect": "^4.0.0-beta.98", "@effect/openapi-generator": "4.0.0-beta.98", "@effect/platform-node": "4.0.0-beta.98", "@types/bun": "^1.3.0", @@ -25,8 +53,5 @@ }, "optionalDependencies": { "undici": "^7.0.0" - }, - "bin": { - "punktfunk-scripting": "./src/runner-cli.ts" } } diff --git a/sdk/tsconfig.build.json b/sdk/tsconfig.build.json new file mode 100644 index 00000000..401be29b --- /dev/null +++ b/sdk/tsconfig.build.json @@ -0,0 +1,11 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "noEmit": false, + "declaration": true, + "outDir": "dist", + "rootDir": "src" + }, + "include": ["src"], + "exclude": ["src/**/*.test.ts"] +}