Complete SDK reference
Every public package entrypoint, with usage notes, exported symbols and compiler-generated TypeScript signatures. Each module links to the exact source revision used for this reference.
Reference: @silicon-jungle/inkwell-sdk@0.0.8. Check npm’s published versions before pinning a release; a source reference is not proof that a release has reached npm. Engine wrappers expose a subset of this JavaScript API—see engine integration instructions.
import { Inkwell } from '@silicon-jungle/inkwell-sdk'
// Or import only the module you need:
import { backend } from '@silicon-jungle/inkwell-sdk/backend'
// Server-only imports belong in the backend, not this browser bundle:
// import { defineBackend } from '@silicon-jungle/inkwell-sdk/server'One backend, generic messages and actions
These paired TypeScript modules demonstrate a public lobby, named cursor events, a reliable join action and a D1 visit record. They are type-checked against the reference SDK. Add your own rate limits, private-room authorization, rendering and reconnect UI for a real game.
Browser
import { Inkwell, BackendActionError } from '@silicon-jungle/inkwell-sdk'
type Protocol = {
clientEvents: { 'cursor.move': { x: number; y: number } }
serverEvents: { 'cursor.changed': { playerId: string; x: number; y: number } }
actions: { 'world.join': { input: { worldId: string }; output: { joined: string } } }
}
async function startGame() {
Inkwell.loading.progress(null)
const player = await Inkwell.player.get()
const connection = await Inkwell.backend.connect<Protocol>()
const unsubscribe = connection.on('cursor.changed', update => {
// Validate received data as needed, then update your game renderer.
console.log(update.playerId, update.x, update.y)
})
try {
const result = await connection.action('world.join', { worldId: 'lobby' })
console.log(player.displayName, result.joined)
} catch (error) {
unsubscribe()
connection.close()
if (error instanceof BackendActionError) console.warn(error.code)
throw error
}
// Inspect capabilities; fallback may be emulated rather than a datagram.
console.log(connection.transportKind, connection.capabilities.unreliable)
connection.sendUnreliable('cursor.move', { x: 10, y: 20 })
Inkwell.ready()
return () => { unsubscribe(); connection.close() }
}
// Call the returned cleanup function when leaving your scene.
startGame().then(cleanup => {
window.addEventListener('pagehide', cleanup, { once: true })
}).catch(() => Inkwell.loading.fail('Could not join the game. Please try again.'))Server
import { defineBackend, BackendActionFailure } from '@silicon-jungle/inkwell-sdk/server'
type Protocol = {
clientEvents: { 'cursor.move': { x: number; y: number } }
serverEvents: { 'cursor.changed': { playerId: string; x: number; y: number } }
actions: { 'world.join': { input: { worldId: string }; output: { joined: string } } }
}
// A single public lobby in one process. This is not a match-per-server API.
const joined = new Set<string>()
export default defineBackend<Protocol>({
async start({ database }) {
await database.query(
'CREATE TABLE IF NOT EXISTS visits (player_id TEXT PRIMARY KEY, last_seen TEXT NOT NULL)'
)
},
actions: {
async 'world.join'(input, connection, { database }) {
// TS types do not validate incoming JSON. Authorize private worlds here.
if (!input || input.worldId !== 'lobby')
throw new BackendActionFailure('invalid_world', 'Choose the public lobby.')
await database.query(
'INSERT INTO visits (player_id, last_seen) VALUES (?, ?) ON CONFLICT(player_id) DO UPDATE SET last_seen = excluded.last_seen',
[connection.identity.playerId, new Date().toISOString()]
)
joined.add(connection.id)
return { joined: 'lobby' }
},
},
messages: {
'cursor.move'(input, connection, context) {
if (!joined.has(connection.id) || !input ||
!Number.isFinite(input.x) || !Number.isFinite(input.y) ||
Math.abs(input.x) > 10000 || Math.abs(input.y) > 10000) return
context.broadcastUnreliable('cursor.changed', {
playerId: connection.identity.playerId, x: input.x, y: input.y,
}, { except: connection.id })
},
},
disconnect(connection) { joined.delete(connection.id) },
async fetch(request, { database }, identity) {
if (request.method !== 'GET' || new URL(request.url).pathname !== '/visit')
return new Response('Not found', { status: 404 })
const result = await database.query(
'SELECT last_seen FROM visits WHERE player_id = ?', [identity.playerId]
)
return Response.json(result.results[0] ?? null)
},
})Configure and deploy these modules. From the browser, Inkwell.backend.request('/visit') reads this player’s stored visit through the backend’s HTTP handler.
What the SDK does—and does not—authorize
Browser game services run through the source- and origin-checked host bridge. A game cannot choose another account, access platform direct messages, read the whole friends list, or receive creator API keys. Server credentials are game-scoped. Importing a server factory in browser code does not grant its permissions.
Share, reviews, favourites, follows, friend requests, platform DMs and account settings belong to the host UI, not the SDK facade. The invitation hooks in this source reference supply context and observe acceptance; they cannot send notifications or choose friends. Check matching platform and npm release availability before using them.
There is no built-in simulation, matchmaking queue, dedicated process per room, economy, payment API or cross-game inventory. Creators can implement game rules in their own backend using the generic primitives.
Platform capabilities and API boundaries · Packages, source and engine plugins