Server JavaScript API
Complete reference for the global varion object available in the server-side main.js of every JS resource. Every method and signature here is verified against the @varion/server typings contract (VarionServerApi) and the Node host.
A resource with type = "js" and a main entry is started by the platform automatically — no extra modules are required. See Server Scripting and resource.toml.
Resource Model
varionis the single global entry point. There are no imports; it is available directly at module scope.- Handler registration (
on,onClient,onRpc), timer creation,new VoiceChannel, blip/marker/checkpoint/colshape and entity factories must be called within a resource context — that is, during module load or inside a callback owned by the same resource. Calling outside a context throws. - Everything a resource creates (handlers, timers, world handles, entities, voice channels) is owned by it and released automatically on stop/restart. No manual teardown on unload is required.
varion.log('resource loaded');
varion.on('playerReady', (player) => {
player.spawn({ x: 215.76, y: -810.12, z: 30.73 }, 157, 0x705E61F2);
});Events (Local and Lifecycle)
| Method | Signature | Purpose |
|---|---|---|
varion.on | on(name, handler) | Subscribe to a built-in or local event. Multiple handlers per name are allowed |
varion.off | off(name, handler?) | Unsubscribe. Without handler, removes this resource's handlers for that event |
varion.emit | emit(name, ...args) | Emit a local in-process event. Delivered to on handlers on the same server, but not to clients |
The full list of 41 built-in server events with exact arguments is in Events & RPC — it is not duplicated here.
weaponDamage runs synchronously before authoritative health changes; its handler must be synchronous (false cancels the hit, a number replaces the damage, undefined accepts the original). All other events may be async.
varion.on('playerDeath', (player, killer, weaponHash) => {
varion.log(player.name, 'killed by', killer ? killer.name : 'world');
});Client Events and RPC
| Method | Signature | Purpose |
|---|---|---|
varion.onClient | onClient(name, (player, ...args) => void | Promise) | client -> server event. The first argument is a Player proxy, not a numeric id. Multiple handlers are allowed |
varion.offClient | offClient(name, handler?) | Unsubscribe from a client event |
varion.onRpc | onRpc(name, (player, ...args) => result | Promise) | client -> server RPC. Exactly one handler per name (re-registering replaces the previous). Client-initiated only. Async is supported |
varion.offRpc | offRpc(name, handler?) | Remove an RPC handler |
The first argument to onClient and onRpc is always a Player. An RPC return value (or resolved Promise) is sent to the client as the result; a thrown exception or rejected Promise reaches the client as an RPC error.
varion.onClient('chat:message', (player, message) => {
varion.emitAllClients('chat:addMessage', player.name, String(message));
});
varion.onRpc('inventory:get', async (player) => ({ owner: player.id, slots: 40 }));Emitting Events to Clients
| Method | Signature | Purpose |
|---|---|---|
varion.emitClient | emitClient(playerId, name, ...args) | Event to one player. The first argument is a numeric player id |
varion.emitAllClients | emitAllClients(name, ...args) | Event to all connected players |
player.emit | player.emit(name, ...args) | The same per-player emit through a Player proxy |
emitClient expects a numeric id. When you hold a Player object, use player.emit(...) or varion.emitClient(player.id, ...).
varion.emitClient(player.id, 'hud:show', true);
varion.emitAllClients('announce', 'server restarting');Logging
varion.log(...parts), varion.logWarning(...parts), varion.logError(...parts) — arguments are stringified, space-joined, and tagged with the resource name in the server output.
Players
| Method | Returns | Purpose |
|---|---|---|
varion.getPlayer(id) | Player | Player proxy by id. Always returns an object |
varion.getPlayers() | Player[] | All connected players |
varion.getPlayerCount() | number | Number of connected players |
The Player object: read-only id, type, valid, name, ip, ping; readable and writable health, armour, model, dimension, pos (a write is applied to the player immediately); methods spawn(pos, heading?, model?), kick(reason?), giveWeapon(weaponHash, ammo?), removeAllWeapons(), emit(name, ...args), and the metadata family (below). See Entities.
World: Time and Weather
varion.setTime(hour, minute)— set in-game time.varion.setWeather(weatherId)— set weather by id.
World Visuals
Every factory returns a { id, type, valid, destroy() } handle owned by the resource. Options objects carry the visual's fields (position, color, etc.).
| Method | Signature |
|---|---|
varion.createBlip | createBlip(options) |
varion.createRadiusBlip | createRadiusBlip(x, y, z, radius, color?, dimension?) |
varion.createAreaBlip | createAreaBlip(x, y, z, width, height, color?, dimension?) |
varion.createMarker | createMarker(options) |
varion.createCheckpoint | createCheckpoint(options) |
varion.createTextLabel | createTextLabel(options) |
const blip = varion.createRadiusBlip(215, -810, 30, 50, 5);
// ...later
blip.destroy();Colshapes
Seven factories; each returns a Colshape ({ id, type: 'colshape', valid, destroy() }). Enter/leave raise the entityEnterColshape / entityLeaveColshape events (and player variants) — see Events & RPC.
| Method | Signature |
|---|---|
varion.createColshape | createColshape(options) |
varion.createColshapeSphere | createColshapeSphere(x, y, z, radius, dimension?) |
varion.createColshapeBox | createColshapeBox(x, y, z, halfX, halfY, halfZ, dimension?) |
varion.createColshapeCylinder | createColshapeCylinder(x, y, z, radius, height, dimension?) |
varion.createColshapeCircle | createColshapeCircle(x, y, radius, dimension?) |
varion.createColshapeRectangle | createColshapeRectangle(x, y, halfX, halfY, dimension?) |
varion.createColshapePolygon | createColshapePolygon(points, minZ, maxZ, dimension?) |
points for a polygon is a flat number array [x0, y0, x1, y1, ...].
Entities (async)
| Method | Returns |
|---|---|
varion.createVehicle(model, pos, rot?) | Promise<Vehicle> |
varion.createPed(model, pos, rot?) | Promise<Ped> |
varion.createObject(model, pos, rot?) | Promise<ObjectEntity> |
All three are asynchronous: the server allocates the network id, so await the Promise to get the entity proxy. The proxy exposes id, type, valid, netOwner, destroy(), and the metadata family.
const car = await varion.createVehicle(varion.hash('adder'),
{ x: 220, y: -805, z: 30 }, { x: 0, y: 0, z: 0 });
car.setStreamSyncedMeta('plate', 'VARION');Voice Channels
varion.createVoiceChannel(spatial, maxDistance?) returns a VoiceChannel (equivalent to new varion.VoiceChannel(spatial, maxDistance)).
A VoiceChannel instance:
- Properties:
id,type,valid,isSpatial,maxDistance,players,playerCount(read-only);priority,filter(read/write). - Methods:
addPlayer(player),removePlayer(player),hasPlayer(player),isPlayerInChannel(player),isPlayerMuted(player),mutePlayer(player, muted?)(defaults totrue),unmutePlayer(player),setFilter(filterHash),destroy(). - Static:
VoiceChannel.all(all valid channels),VoiceChannel.getByID(id).
The player argument accepts a Player proxy or a numeric id.
const channel = varion.createVoiceChannel(true, 20);
channel.addPlayer(player);
channel.mutePlayer(player.id);Metadata
There are two storage levels.
Entity/player level (methods on a Player or Entity proxy):
| Method | Replication scope | Event |
|---|---|---|
setMeta(key, value) / setMeta(obj) | Server only, not replicated | metaChange |
setSyncedMeta(...) | All clients | syncedMetaChange |
setStreamSyncedMeta(...) | Clients currently streaming the entity | streamSyncedMetaChange |
Each set has paired get*, has*, delete*, and get*Keys.
Global level (methods on varion):
| Method | Replication scope | Event |
|---|---|---|
varion.setMeta(...) | Server only, not replicated | globalMetaChange |
varion.setSyncedMeta(...) | All clients | globalSyncedMetaChange |
varion.setGlobalMeta(...) | All clients | globalSyncedMetaChange |
varion.setSyncedMeta and varion.setGlobalMeta write to the same replicated store and both raise globalSyncedMetaChange — they are aliases. Only varion.setMeta uses a separate, server-only store that is not replicated. Paired get*/has*/delete*/get*Keys exist for all three families (...Meta, ...SyncedMeta, ...GlobalMeta). See Metadata.
Utilities
varion.getNetTime()—Promise<number>, milliseconds since server start (an async request to the platform).varion.hash(value)—number, JOAAT hash of a string (input is lowercased). Convenient for model and weapon hashes.
const now = await varion.getNetTime();
const model = varion.hash('adder');Resource Management
| Method | Returns | Purpose |
|---|---|---|
varion.getResourceConfig(name?) | object | The [config] table from resource.toml. Synchronous. Without name, the current resource (or the sole one) |
varion.hasResource(name) | boolean | Whether the resource is known |
varion.getAllResources() | ResourceInfo[] | All resources: { name, path, valid, started, config } |
varion.startResource(name) | void | Queue a start (fire-and-forget) |
varion.stopResource(name) | void | Queue a stop |
varion.restartResource(name) | void | Queue a restart |
varion.Resource.current | ResourceInfo | null | The current resource |
varion.Resource.get(name) | ResourceInfo | null | A resource by name |
varion.Resource.all | ResourceInfo[] | All resources |
getResourceConfig is synchronous — do not await it.
const cfg = varion.getResourceConfig();
if (cfg.debug) varion.log('debug mode');Timers
Timers are bound to the resource and cleared automatically on its stop/restart. The global setTimeout/setInterval/setImmediate in the host are also wrapped and behave the same way.
| Method | Purpose |
|---|---|
varion.setTimeout(callback, delay?, ...args) | One-shot timer, returns a handle |
varion.setInterval(callback, delay?, ...args) | Repeating timer, returns a handle |
varion.clearTimeout(handle) | Cancel a timer |
varion.clearInterval(handle) | Cancel an interval |
varion.nextTick(callback, ...args) | Run on the next tick (setImmediate) |
varion.everyTick(callback) | Run every tick (~16 ms) |
varion.clearEveryTick(handle) | Stop an everyTick |
Classes
varion.Vector3—new Vector3(x?, y?, z?)ornew Vector3(vectorLike); alengthproperty; adistanceTo(other)method.varion.RGBA—new RGBA(r = 255, g = 255, b = 255, a = 255).varion.VoiceChannel— constructornew VoiceChannel(isSpatial, maxDistance?); see the "Voice Channels" section.
const a = new varion.Vector3(0, 0, 72);
const b = new varion.Vector3({ x: 10, y: 0, z: 72 });
const d = a.distanceTo(b);
const red = new varion.RGBA(255, 0, 0, 255);Source Backing
This page is verified against sdk/Varion.Server/npm/@varion/server/index.d.ts (the VarionServerApi interface) and the Node host runtime server/host/varion-host.cjs. The list of built-in events is in Events & RPC.