# Game backend API

`GameSdk.backend()` is a thin client for the game's deployed backend. It does
not add room, matchmaking, leaderboard, or state semantics.

```ts
await sdk.ready();
const backend = sdk.backend();
const profile = await backend.get('/api/profile');
await backend.post('/api/profile', { displayName: 'Ada' });
```

The path must be relative to the current Runtime origin and start with `/`.
The host context and URL contract are unchanged: `runtimeUrl`, `gameId`, and
the existing `launchToken` are used. The SDK sends the launch ticket as a
Bearer token and the Runtime verifies the game claim before proxying to the
active backend version.

Backend errors are raised as `BackendRequestError` with `status` and `data`.
The SDK never exposes SQL or Redis credentials to a game page.

The same backend can expose HTTP and WebSocket endpoints. HTTP is for request
and response operations; WebSocket is for server-pushed events or low-latency
session traffic. The SDK obtains the launch ticket and performs the Runtime
handshake, so game code only handles typed messages:

```ts
const socket = await backend.connect('/events');
const unsubscribe = socket.onMessage(message => renderEvent(message));
socket.send({ type: 'subscribe', channel: 'match' });
// unsubscribe(); socket.close();
```

A backend project can use the server contract from the same package:

```ts
import { defineGameBackend } from '@qingzhenghust/game-sdk/server';

export default defineGameBackend(async (request, ctx) => {
  const rows = await ctx.sql.query('select * from profiles where user_id = $1', [ctx.identity.userId]);
  return Response.json({ rows });
});
```

For a dual-protocol backend, declare both handlers explicitly. The manifest
records `http`, `websocket`, or `http-websocket` automatically:

```ts
export default defineGameBackend({
  http: async (request, ctx) => Response.json({ ok: true }),
  websocket: async (socket, ctx) => {
    socket.send({ type: 'ready', userId: ctx.identity.userId });
    socket.onMessage(message => socket.send({ type: 'ack', message }));
  },
});
```
# Declarative data backends

Use a `kind: "data"` backend when a game only needs migrations and bounded CRUD. It runs on the shared Data Plane and does not create a game Runner Pod.

```ts
await sdk.ready();
const messages = sdk.data().collection<Message, {content: string}>('messages');
const created = await messages.create({content: 'hello'});
const page = await messages.list({limit: 20, sort: 'created_at', order: 'desc'});
await messages.update(created.id, {content: 'edited'}, {expectedVersion: created.version});
await messages.delete(created.id, {expectedVersion: created.version + 1});
```

Collections, writable fields, public/owner reads, filters and sort fields are declared in `backend/manifest.json`. The server derives identity fields from the launch ticket. Games cannot submit SQL, arbitrary table names, storage credentials or Redis keys.
