Перейти к содержимому

Raw Lua reference (node.raw.*)

Generated from sdk/api.toml by sdk/tools/apigen.py docs. Do not edit; edit the schema.

node.raw is the 1:1 mirror of the C ABI inside a resource’s Lua state – one function per C entry, ids in, tables out. The API a resource is written against is Lua API reference (node); this page is the layer underneath it, kept reachable as the escape hatch and as the map between a Lua name and its C entry. Signatures read node.name(params) -> result; a ? marks an optional parameter or a result that can be nil. Result shapes are MEASURED against a live server (array<...>, record{keys}), not declared. Where a description shared with the C reference says “returns 0 on success” or “-1 when”, the Lua binding returns the shape shown in the signature instead: boolean for a status, nil for a miss. Functions marked Lua only have no C counterpart.

  • Console and logging – log, logWarn, logError, logTag, logCustom, logRaw, setLogSink, setConsoleTitle
  • Server: info, settings, time and metrics – getServerName, getMap, getServerVersion, getPort, getMaxPlayers, getMaxCars, getServerUptime, getUnixTime, setMaxCars, setMaxPlayers, setServerName, getMetrics, isNodeGrabEnabled, getTime
  • Players – getPlayerCount, getPlayerName, isPlayerConnected, getPlayerPing, getPlayerIp, getPlayers, getPlayerEndpoint, getPlayerPosition, getPlayerVehicle, getPlayerInputs, getPlayerFocus, getPlayerHeadPose, getPlayerCamera, getPlayerSession
  • Roles, kicks and bans – kickPlayer, setPlayerRole, getPlayerRole, banPlayer, banIp, unbanIp, isBanned, getBans, banAccount, unbanAccount, isAccountBanned
  • Strict session: install verification and the camera rule – verifyPlayer, setPlayerStrict
  • Vehicles: registry and records – getVehicleCount, getPlayerVehicles, getVehicle, getVehicles, getVehicleOccupants
  • Vehicles: state, live and cached – getVehicleElectrics, getVehicleConfig, getVehicleCouplers, getVehiclePowertrain, getVehicleEngine, getVehicleControllers, getWorldSnapshot, getVehicleConfigHash, getVehicleDamage, getVehicleTransform, getVehicleControls, getVehicleInputs, getVehicleNodes, getVehicleBreakGroups, getVehiclePaints, getVehicleSync, getVehicleTransforms
  • Vehicles: control – deleteVehicle, deleteAllVehicles, setVehicleCoupler, unseatPlayer, swapPlayers, resyncVehicle, resyncPlayer, spawnVehicle, triggerVehicle, getVehicleLock, setVehicleLock, seatPlayer
  • Vehicle tags – setVehicleTag, getVehicleTag, removeVehicleTag, getVehicleTags, getVehiclesByTag, getVehiclesByTags
  • Visibility: relay filter and groups – invalidateRelayCache, setPlayerGroup, setVehicleGroup, getPlayerGroup, getVehicleGroup
  • Events: subscribe and emit – emitClient, emitAll, on, off, emitOthers
  • Module channel (binary) – sendModule, onModule, offModule
  • Inter-resource bus – emitResource, onResource, offResource
  • Timers and scheduling – setTimeout, setInterval, clearTimer, setImmediate
  • Coroutines and background jobs – job, async, sleep, wait, yield, await
  • HTTP – httpGet, httpPost, httpRequest
  • Files, sandboxed – readFile, writeFile, writeFileAsync, listFiles
  • Persistent storage – storageSet, storageGet, storageDelete
  • Database (PostgreSQL) – pgEnabled, pgReady, pgQuery, pgTxBegin, pgTxQuery, pgTxEnd, pgNullSentinel, pgQueryWait, pgTxBeginWait, pgTxQueryWait, pgTxEndWait
  • Crypto and JSON – sha256, hmac, randomBytes, jsonEncode, jsonDecode
  • Resources: lifecycle – reloadResource, getManifest

Writing to the server console. Every line is tagged; a resource’s plain node.log carries the resource’s own name as the tag, node.logTag uses one of the server’s known tags, node.logCustom a tag of your own in a chosen colour. A log sink lets a resource observe every line the server prints (asynchronously, on the plugin worker).

Arguments: msg: string
C: log_info

Prints msg to the server console under this resource’s own tag, at the info level. node.logWarn and node.logError are the two other levels; node.logTag logs under one of the server’s tags instead of yours.

Arguments: msg: string
C: log_warn

Logs msg under this resource’s tag at the warning level (the console’s Warn colour). Same as node.logTag(“Warn”, msg) but keeps your resource as the tag.

Arguments: msg: string
C: log_error

Logs msg under this resource’s tag at the error level (the console’s Error colour). Same as node.logTag(“Error”, msg) but keeps your resource as the tag.

Arguments: tag: string, msg: string
C: log_tag

Logs msg under one of the server’s own console tags – Core, Net, Res, Mods, Module, Join, Leave, Kick, Veh, Warn, Error, Debug (case-insensitive) – in the house format HH:MM:SS Tag > msg with that tag’s colour. An unknown tag falls back to Module. Use “Warn” and “Error” for the coloured levels, since node.log itself logs at info.

Arguments: tag: string, rgb: number, msg: string
C: log_custom

Logs msg under a tag of your own in a chosen colour. rgb is 0xRRGGBB (0xFF8800); the server maps it to the nearest ANSI-256 colour, so the exact shade depends on the terminal. Keep the tag at six characters or fewer to preserve the column alignment.

Arguments: text: string
C: log_raw

Writes text to the console as-is: no timestamp, no tag, one line per call. It may contain ANSI escapes; the copy written to logs/server.log has them stripped.

Arguments: fn: any
C: set_log_sink

Observes every line the server logs as fn(tag, level, msg), asynchronously on the worker thread. Unlike the C set_log_sink it cannot suppress a line (Lua never runs on the logging thread). One sink per resource; nil clears it.

Arguments: title: string
C: set_console_title

Sets the console window title (SetConsoleTitle on Windows, an OSC escape elsewhere when the terminal supports ANSI; otherwise nothing happens).

Read the server’s identity (name, map, version, port, limits), change the runtime limits and the name, read time, and pull the metrics snapshot. Limit changes apply to the next check – a connecting player, a spawn request – and never kick anyone retroactively.

Arguments: none
C: get_server_name
Note: [General] Name

The server’s name ([General] Name in server.toml, or whatever setServerName set last).

Arguments: none
C: get_map
Note: [General] Map

The map the server runs ([General] Map), as the client-facing level path.

Arguments: none
C: get_server_version
Note: e.g. “3.9.3”

The server’s version string, e.g. “3.9.3”.

Arguments: none
C: get_port
Note: TCP+UDP listening port

The port the server listens on (TCP and UDP share it).

Arguments: none
C: get_max_players
Note: [General] MaxPlayers

The player limit currently enforced ([General] MaxPlayers, or setMaxPlayers).

Arguments: none
C: get_max_cars
Note: [General] MaxCars

The per-player vehicle limit currently enforced ([General] MaxCars, or setMaxCars).

Arguments: none
C: get_server_uptime

Seconds since the server started (monotonic, fractional).

Arguments: none
C: get_unix_time

Current unix time in whole seconds. node.getTime has the fractional part.

Arguments: n: number
C: set_max_cars

Changes the per-player vehicle limit live. Enforced on the NEXT spawn request; nobody’s existing cars are deleted. Returns false for a negative value.

Arguments: n: number
C: set_max_players

Changes the player limit live. Enforced on the NEXT connect; nobody is kicked. Returns false for a negative value.

Arguments: name: string
C: set_server_name

Changes the name the server reports. Returns false for an empty name.

node.raw.getMetrics() -> record{connections,net,players,plugin,unixTime,uptime,vehicles}

Заголовок раздела «node.raw.getMetrics() -> record{connections,net,players,plugin,unixTime,uptime,vehicles}»

Arguments: none
C: get_metrics_json

A snapshot of live server metrics as a table: players, vehicles, uptime, unixTime, net (TCP/UDP packet counters, flood kicks), connections (the connection limiter), plugin (worker queue depth, timer and async task counts). Cheap enough to poll from a timer for a status page.

Arguments: none
C: is_node_grab_enabled

true when the experimental node grabber is enabled in server.toml ([Experimental] NodeGrab). Even then every grab still needs an explicit allow from the fail-closed vehicleNodeGrabRequest.

Arguments: none
Lua only.

Unix time in seconds with sub-second precision (a float). node.getUnixTime returns whole seconds.

Who is connected, what they are called, where they are and what they sit in. Player ids are small integers assigned at connect and REUSED after a disconnect, so never keep one across a playerLeft. Every getter returns nil (Lua) / a failure code (C) for an id that is not connected.

Arguments: none
C: get_player_count

How many players are connected right now.

Arguments: playerId: number
C: get_player_name

The player’s display name, or nil when no player has that id.

Arguments: playerId: number
C: is_player_connected

true while a player with this id is connected. Ids are reused after a disconnect, so this cannot tell you whether it is the SAME player you saw earlier – keep the name or IP for that.

Arguments: playerId: number
C: get_player_ping

Seconds since the last keepalive arrived from the player (a float), or nil for an unknown id. This is a connection-freshness metric, not a round-trip latency: 0-1 for a healthy client, growing while the client stalls.

Arguments: playerId: number
C: get_player_ip

The player’s remote IP as text (“1.2.3.4”; an IPv4-mapped IPv6 address arrives as plain dotted v4, an IPv6 one as-is), or nil for an unknown id. The basis for banIp and for keying anything you persist about a player.

Arguments: none
C: get_players_json

Every connected player as an array of {id, name}. An array rather than a map keyed by id, so the shape is the same in every language.

Arguments: playerId: number
C: get_player_endpoint_json

The player’s remote endpoint as {ip, port}, or nil for an unknown id.

Arguments: playerId: number
C: get_player_position_json

The player’s last known position as {x, y, z}, taken from the vehicle it occupies in any role or from its walking avatar, or nil when the player is unknown or no position snapshot has arrived yet.

Arguments: playerId: number
C: get_player_vehicle_json

The single vehicle the player occupies, as {gid, role} with role “driver” or “passenger”, or nil when the player is on foot or unknown.

node.raw.getPlayerInputs(playerId) -> record{axes,axesAgeSeconds,controls,controlsAgeSeconds,vehicle}

Заголовок раздела «node.raw.getPlayerInputs(playerId) -> record{axes,axesAgeSeconds,controls,controlsAgeSeconds,vehicle}»

Arguments: playerId: number
C: get_player_inputs_json

Everything the player is pressing, in one table: { vehicle = the gid they drive, controls = { steering, throttle, brake, clutch, parkingBrake, gear? } (nil until the first snapshot), controlsAgeSeconds, axes = { name = value, … } (extra/modded axes; empty when none), axesAgeSeconds }. Controls come from the position snapshot at 60 Hz, axes from the delta-gated Inputs stream. Only a driver’s inputs reach the server: nil when the player is on foot or a passenger.

Arguments: playerId: number
C: get_player_focus_json

Where the player is looking from: { pos = { x, y, z }, ageSeconds } – the head/camera position when the client streams a head pose, otherwise the position of the vehicle it drives. This is the point the server’s distance-based relay filter uses for the player. nil for an unknown player or one that has not sent a position yet.

node.raw.getPlayerHeadPose(playerId) -> record{ageSeconds,freeCamera,pos,rot}

Заголовок раздела «node.raw.getPlayerHeadPose(playerId) -> record{ageSeconds,freeCamera,pos,rot}»

Arguments: playerId: number
C: get_player_head_pose_json

The player’s last camera/head pose: { pos = { x, y, z }, rot = { x, y, z, w } (a quaternion), freeCamera (true while flying the free camera), ageSeconds }. Streamed at about 10 Hz. nil for an unknown player or one that has not sent a pose yet.

Arguments: playerId: number
C: get_player_camera_json

Which vehicle the player’s camera is on – its own, or the one it spectates: { vehicle = gid or -1, ageSeconds } from the client’s last camera report, plus denied = true when the session is strict (setPlayerStrict) and the server refused to relay that report because its target is not a vehicle the player occupies (the field is absent otherwise; ABI 1.12). nil for an unknown player or one that has not reported yet.

node.raw.getPlayerSession(playerId) -> record{accountRoles,connectedSeconds,focusAgeSeconds,guest,id,identifiers,ip,name,pingSeconds,port,role,synced,udpConnected,unicycle,vehicle,vehicles,verified}

Заголовок раздела «node.raw.getPlayerSession(playerId) -> record{accountRoles,connectedSeconds,focusAgeSeconds,guest,id,identifiers,ip,name,pingSeconds,port,role,synced,udpConnected,unicycle,vehicle,vehicles,verified}»

Arguments: playerId: number
C: get_player_session_json

Everything about the connection in one table: { id, name, ip, port, connectedSeconds, synced (finished joining), udpConnected (the UDP channel is up – false means positions are falling back to TCP), pingSeconds (since the last keepalive), unicycle (the walking avatar’s gid or -1), vehicle (the gid occupied or -1), role (“driver”, “passenger” or “none”), vehicles (how many it drives), focusAgeSeconds (-1 when no position was ever seen), verified (true when the join ticket was redeemed with the directory – the name is then the account’s username or the guest name the directory minted, not something the player typed), guest (no account behind the name), accountId (the directory’s account id, nil for a guest), accountRoles (the directory’s role string such as “ADM”, “” for a guest), identifiers (what the directory knows the player by: “nodemp:<id>”, “discord:<id>”, “ip:<addr>”; empty when unverified) }. nil for an unknown player.

Roles are per-session strings a plugin assigns and reads back (they are cleared at disconnect and mean nothing to the server itself; the client shows a role’s tag next to the name). Kicks disconnect with a reason. Bans are by IP, persist in bans.json across restarts, and refuse FUTURE connects – banning an IP does not drop an existing session; banPlayer does both.

Arguments: playerId: number, reason: string
C: kick_player

Disconnects the player, showing it the reason. Returns false when no player has that id. The disconnect itself completes asynchronously; playerLeft fires when it does.

Arguments: playerId: number, role: string
C: set_player_role

Assigns a per-session role string, shown by the client as a tag next to the name and readable back with getPlayerRole. Cleared at disconnect. An empty string clears it. Returns false when the player does not exist.

Arguments: playerId: number
C: get_player_role

The role set by setPlayerRole, nil for an unknown player, “” when none was set.

Arguments: playerId: number, reason?: string?
C: ban_player

Bans the player’s IP (persisted in bans.json) and kicks the player with the reason. Returns false when the player does not exist.

Arguments: ip: string, reason?: string?
C: ban_ip

Bans FUTURE connects from the IP; an existing session from it stays connected. Returns false for an unparsable IP.

Arguments: ip: string
C: unban_ip

Lifts a ban. Returns false when the IP was not banned.

Arguments: ip: string
C: is_ip_banned

true while the IP is banned.

Arguments: none
C: get_bans_json

Every current ban as an array of {ip, account, reason, at (unix seconds), name (the player’s name when banned in-session, “” for a bare banIp)}. An IP ban has ip set and account nil; an account ban has account set (the directory’s account id) and ip “”.

Arguments: accountId: number, reason?: string?
C: ban_account

Bans a directory account for future joins, whatever address it comes from; an existing session stays connected (use Player:ban() to do both). Only a server announcing to a directory can tell accounts apart – without one every player is an unverified guest and this bans nobody. Returns false for a negative id.

Arguments: accountId: number
C: unban_account

Lifts an account ban. Returns false when the account was not banned.

Arguments: accountId: number
C: is_account_banned

true while the account is banned on this server.

The server-side half of a strict session (ABI 1.12). Every join already runs the game-install check that [General] VerifyGame asks for: the player’s launcher helper compares the install with the game’s own manifest at level size (file lengths), scripts (plus a hash of the game’s lua/ and ui/), full (hash everything, archives included – slow, an audit) or strict (the archive tables of contents against the server’s reference manifest, the whole game root, the user folder), and the server judges the report – a mismatch is a kick unless VerifyGame is off. That report reaches plugins as the playerVerifyReported notification, after the verdict. player_verify asks the helper to run the check again in the middle of the session, at a level of the plugin’s choosing; the answer arrives as another playerVerifyReported. player_set_strict marks a session strict on the server, which changes one relay rule: Vehicle::Camera frames FROM the strict player that target a vehicle it does not drive or occupy are refused – not relayed – so a strict client cannot follow other people’s cars with its camera; a refused report still fires playerCameraChanged and shows up in get_player_camera_json with “denied”: true. Frames from other players to the strict player are unaffected. The check runs on the player’s machine, by a launcher the player could patch: it catches damaged installs and casual edits, and it is not a security boundary.

Contract for the server side (what the generated bindings and the prelude rely on): playerVerifyReported is dispatched like playerSeatChanged – the three-argument notification form with global_id -1 and the report as JSON – for the join-time report and for every mid-session one, after the server’s own verdict; player_verify counts a request as pending for 60 s from the moment it was sent, report or no report, and answers -3 inside that window – the check every join runs does not count, so a player_verify from a playerJoined handler goes out at once; get_player_camera_json writes “denied”: true only for a refused frame of the player’s own and leaves the key out otherwise, so the record’s shape is unchanged for everyone else.

Arguments: playerId: number, level: number
C: player_verify

Asks the player’s launcher helper to re-check the game install at level 1 (size), 2 (scripts), 3 (full) or 4 (strict); the result arrives as the playerVerifyReported event, after the server’s own verdict on it. Returns 0 when the request went out, -1 unknown player, -2 the level is not available for this player (launcher too old, or strict without a reference manifest on this server), -3 a request to this player is still pending (one per player per 60 s; the check every join runs does not count, so a call from a playerJoined handler goes out at once). The public Player:verify takes the level as a string and turns these into true / nil, reason.

Arguments: playerId: number, on: number
C: player_set_strict

Marks the player’s session strict (on = 1) or lifts the mark (0): a Vehicle::Camera frame from the player that targets a vehicle it does not occupy is then refused (not relayed; frames from others to it are unaffected), and the refused report shows up in getPlayerCamera with denied = true. Returns false when the player does not exist. on is a number here, as in C; the public Player:setStrict takes a boolean.

The vehicle registry: global ids, who spawned and who drives each one, the occupants, and the full JSON record. Global ids are unique for the life of the server process. A vehicle’s spawner may be a player or -1 for a server-spawned one; its sync AUTHORITY is the client that simulates it and is not necessarily the spawner.

Arguments: none
C: get_vehicle_count

How many vehicles are in the registry, unicycles (players on foot) included.

Arguments: playerId: number
C: get_player_vehicles

Global ids of the vehicles the player spawned or is driving, as an array (empty for an unknown player). Up to 512.

node.raw.getVehicle(globalId) -> record{authority,configHash,damageBlobCounter,damageBlobSize,damageCounter,driver,id,idleSeconds,isUnicycle,lockMode,lockWhitelist,name,passengers,spawner,spawnerOnline,tags}?

Заголовок раздела «node.raw.getVehicle(globalId) -> record{authority,configHash,damageBlobCounter,damageBlobSize,damageCounter,driver,id,idleSeconds,isUnicycle,lockMode,lockWhitelist,name,passengers,spawner,spawnerOnline,tags}?»

Arguments: globalId: number
C: get_vehicle_json

The complete vehicle record: id, spawner (player id, -1 for server-spawned), driver (-1 when empty), authority (the client simulating it), isUnicycle, name, idleSeconds, passengers (array of player ids), spawnerOnline, lockMode, lockWhitelist, configHash, damageCounter, damageBlobCounter, damageBlobSize, tags (key -> value). nil for an unknown vehicle.

node.raw.getVehicles() -> array<record{authority,configHash,damageBlobCounter,damageBlobSize,damageCounter,driver,id,idleSeconds,isUnicycle,lockMode,lockWhitelist,name,passengers,spawner,spawnerOnline,tags}>

Заголовок раздела «node.raw.getVehicles() -> array<record{authority,configHash,damageBlobCounter,damageBlobSize,damageCounter,driver,id,idleSeconds,isUnicycle,lockMode,lockWhitelist,name,passengers,spawner,spawnerOnline,tags}>»

Arguments: none
C: get_vehicles_json

Every vehicle’s record (the shape node.getVehicle returns) as an array. Unicycles included – filter on isUnicycle for cars only.

Arguments: globalId: number
C: get_vehicle_occupants_json

Who is in the vehicle, driver first, as an array of {playerId, role}. Empty for an empty or unknown vehicle.

What the server knows about a vehicle’s state. LIVE state (transform, controls) comes from the last position/state snapshot the authority sent and is a few ticks old. CACHED state (config, couplers, powertrain, engine, controllers, electrics, damage) is the merge of everything relayed so far and is what a late joiner receives. Config hash is the FNV-1a-32 marker clients echo so the server can spot a desynced config.

Arguments: globalId: number
C: get_vehicle_electrics_json

The vehicle’s current electrics – lights, signals, gauges, the merged view of every electrics delta relayed so far – as a table, or nil when the vehicle does not exist or nothing has arrived yet.

Arguments: globalId: number
C: get_vehicle_config_json

The vehicle’s current spawn/edit configuration as a table – exactly the JSON a joiner receives inside Vehicle::Spawn (jbm, vcf, …) – or nil for an unknown vehicle.

Arguments: globalId: number
C: get_vehicle_couplers_json

The merged coupler/door state as an array of coupler entries in the client Coupler schema (one per known coupler), or nil for an unknown vehicle.

Arguments: globalId: number
C: get_vehicle_powertrain_json

The merged powertrain device state as a table, or nil while nothing has arrived (or the merged store was invalidated by an unknown schema).

Arguments: globalId: number
C: get_vehicle_engine_json

The merged engine device state as a table, or nil while nothing has arrived.

Arguments: globalId: number
C: get_vehicle_controllers_json

The merged controller-call map as a table of “controller|function” -> the last call (the same shape node.triggerVehicle takes), or nil for an unknown vehicle.

Arguments: none
C: get_world_snapshot_json

One bulk read of the world: {time = unix seconds, players = [{id, name, ip, vehicle, role, pos = {x, y, z} or nil}], vehicles = [{id, spawner, driver, authority, unicycle, pos, rot, vel}]}. The read for radars, maps and dashboards – one call instead of a loop of getters.

Arguments: globalId: number
C: get_vehicle_config_hash

The vehicle’s config marker: FNV-1a-32 over the cached config JSON bytes exactly as Spawn and Resync send them – what clients echo in their periodic ConfigHash reports, so a mismatch means that client’s config diverged. nil for an unknown vehicle.

node.raw.getVehicleDamage(globalId) -> record{blob,blobCounter,counter,size}?

Заголовок раздела «node.raw.getVehicleDamage(globalId) -> record{blob,blobCounter,counter,size}?»

Arguments: globalId: number
C: get_vehicle_damage_json

Damage telemetry: {counter (the authority-reported damage version), blobCounter (the version the stored blob was made at), size (0 = pristine), blob (the raw damage bytes as a binary string, or nil when pristine)}. nil for an unknown vehicle.

node.raw.getVehicleTransform(globalId) -> record{ageSeconds,angVel,hasControls,paused,ping,pos,rot,seq,teleport,time,transitioning,vel,velocityStep}?

Заголовок раздела «node.raw.getVehicleTransform(globalId) -> record{ageSeconds,angVel,hasControls,paused,ping,pos,rot,seq,teleport,time,transitioning,vel,velocityStep}?»

Arguments: globalId: number
C: get_vehicle_transform_json

Kinematics from the last position snapshot: {pos = {x, y, z}, rot (a quaternion {x, y, z, w}), vel, angVel, time, ping, seq, paused, transitioning, teleport, velocityStep, hasControls, ageSeconds}. Velocities in m/s, angular velocity in rad/s, time and ping the sender’s own timers in seconds, ageSeconds since the server accepted the snapshot. teleport and velocityStep are the sender’s step flags for this snapshot – a reset, a recovery, a server teleport – so a plugin tracking movement can tell a jump from driving; hasControls says whether getVehicleControls has meaningful values for it. nil while no snapshot arrived. A few ticks old by construction.

node.raw.getVehicleControls(globalId) -> record{brake,clutch,parkingBrake,steering,throttle}?

Заголовок раздела «node.raw.getVehicleControls(globalId) -> record{brake,clutch,parkingBrake,steering,throttle}?»

Arguments: globalId: number
C: get_vehicle_controls_json

Driving inputs from the same snapshot: {steering, throttle, brake, clutch, parkingBrake, gear?} – gear a number for manual boxes, a letter for automatics (“P”, “R”, “N”, “D”, “S”, “2”, “1”, “M3”) when the sender reported one. nil while no snapshot arrived.

Arguments: globalId: number
C: get_vehicle_inputs_json

The driver’s extra input axes: { axes = { name = value, … }, ageSeconds }. Only axes that are NOT in the position snapshot travel here (modded or extra inputs; steering, throttle, brake, clutch, parking brake and gear are getVehicleControls). The stream is delta-gated – an axis is sent only when it changes – and merged on the server, so this is the current set, not the last delta; ageSeconds is since the last change arrived. nil when the vehicle is unknown or no axes were ever sent (a stock car sends none).

Arguments: globalId: number
C: get_vehicle_nodes_json

The last node-position packet the vehicle’s authority sent, decoded as it was sent (the client’s nodemp.sync.nodes schema – deformation / node positions). Intermittent: it arrives when the client decides the deformation changed enough. nil when none arrived yet.

Arguments: globalId: number
C: get_vehicle_break_groups_json

The names of every break group reported broken on the vehicle (bumpers, glass, parts that detach), merged from the delta stream into the current set. Empty array for an intact car that has reported; nil when the vehicle is unknown or nothing arrived yet.

Arguments: globalId: number
C: get_vehicle_paints_json

The vehicle’s paints: an array of paint layers in the client vcf.paints schema (baseColor and the material fields), taken from the cached config, into which every Paint packet is merged. Empty for a config without paints; nil for an unknown vehicle. The same data sits at getVehicleConfig(gid).vcf.paints – this is the direct read.

node.raw.getVehicleSync(globalId) -> record{authority,authorityAgeSeconds,configChangedAgeSeconds,hasPos,idleSeconds,posAgeSeconds,posSeq,seatEpoch,spawnedAgeSeconds}

Заголовок раздела «node.raw.getVehicleSync(globalId) -> record{authority,authorityAgeSeconds,configChangedAgeSeconds,hasPos,idleSeconds,posAgeSeconds,posSeq,seatEpoch,spawnedAgeSeconds}»

Arguments: globalId: number
C: get_vehicle_sync_json

How alive the vehicle’s sync is: { authority (the player simulating it, -1 none), authorityAgeSeconds (since its last accepted position packet or its assignment; the heartbeat the server’s grace/release logic reads), seatEpoch (bumped on every seat or authority change), spawnedAgeSeconds, idleSeconds (0 while someone drives), configChangedAgeSeconds (since the last edit/paint/spawn), hasPos, posAgeSeconds, posSeq }. The record for a ‘why is this car frozen’ tool. nil for an unknown vehicle.

node.raw.getVehicleTransforms() -> array<record{ageSeconds,angVel,hasControls,id,paused,ping,pos,rot,seq,teleport,time,transitioning,vel,velocityStep}>

Заголовок раздела «node.raw.getVehicleTransforms() -> array<record{ageSeconds,angVel,hasControls,id,paused,ping,pos,rot,seq,teleport,time,transitioning,vel,velocityStep}>»

Arguments: none
C: get_vehicle_transforms_json

The positions table: every vehicle’s last kinematic snapshot in one array, each entry the shape of getVehicleTransform plus id, ascending by id. One lock, no per-vehicle copies – the read for a radar, a minimap or a replay recorder polling every tick. Vehicles that have not sent a position yet are absent; an empty array when none has.

Acting on vehicles from the server: delete, spawn ownerless vehicles, open and close couplers, seat, unseat and swap players, lock vehicles against new seat claims, execute a controller call on the sync authority, and resync a vehicle or a player. Server-driven seating bypasses locks; locks gate NEW client claims only and never evict anyone.

Arguments: globalId: number
C: delete_vehicle

Deletes the vehicle: every client removes it, it leaves the registry, and vehicleDeleted fires (asynchronously, on the worker). Returns false when there is no such vehicle.

Arguments: none
C: delete_all_vehicles

Deletes every vehicle in the world and returns how many that was. Players end up on foot.

Arguments: globalId: number, name: string, open: boolean
C: set_vehicle_coupler

Opens (true) or closes (false) the named advanced-coupler group – “doorFLCoupler”, “hood_latch_coupler” and the like – on EVERY client, the driver’s included, and merges the new state into the join-replay cache so late joiners see it. Returns false when the vehicle does not exist. This is the server-driven counterpart of a player pulling a door handle (vehicleCouplerRequest).

Arguments: playerId: number
C: unseat_player

Forces the player out of the vehicle it occupies as driver or passenger; it ends up on foot, the client spawning its unicycle as on a normal exit. Returns false when the player is already on foot or unknown.

Arguments: playerA: number, playerB: number
C: swap_players

Exchanges the two players’ seats – role AND vehicle – in one transaction, covering the whole driver/passenger/on-foot matrix: two drivers swap cars, a driver and a passenger of one car exchange roles, a seat and a pedestrian trade places. Returns false when either player is unknown or both are on foot.

Arguments: globalId: number, playerId?: number?
C: resync_vehicle

Re-sends the vehicle’s spawn and cached state to one player, or to everyone when playerId is omitted – the cure for a client whose copy diverged. Returns false for an unknown vehicle.

Arguments: playerId: number
C: resync_player

Re-sends EVERY vehicle’s spawn and cached state to one player – the cure for a client whose world diverged – and returns how many vehicle bundles were sent.

Arguments: configJson: string, ownerName?: string?
C: spawn_vehicle

Spawns an OWNERLESS vehicle (spawner -1, empty driver seat) and hands sync authority to the best available client. configJson is a JSON object in the client SpawnReq schema (jbm, vcf, pos, rot, …); ownerName is a display label. Returns the new global id, or nil when nobody can host it or the config is rejected.

Arguments: globalId: number, call: any
C: trigger_vehicle

Has the vehicle’s SYNC AUTHORITY execute one controller call – a table or a JSON object string in the Vehicle::Trigger schema {controllerName, functionName, variables…}. Skips vehicleTriggerRequest (the server never asks itself) and is never cached: the resulting state rides the normal sync. Returns false for an unknown vehicle or one without an authority.

Arguments: globalId: number
C: get_vehicle_lock_json

The vehicle’s lock as {mode, whitelist}: mode “unlocked”, “locked” or “driver-only”; whitelist the player ids always allowed in. nil for an unknown vehicle.

Arguments: globalId: number, mode: string, whitelist?: table?
C: set_vehicle_lock_named

Locks the vehicle against NEW client seat claims. mode is “unlocked”, “locked” or “driver-only” (case-insensitive; “driveronly”/“driver_only” accepted); whitelist is an array of up to 32 player ids that are always allowed (ignored for “unlocked”). Nobody already seated is evicted, and server-driven seating bypasses locks. Returns false for an unknown vehicle, an unknown mode or an over-limit whitelist.

Arguments: playerId: number, globalId: number, role?: string?
C: seat_player_role

Seats the player in the vehicle as “driver” (default) or “passenger”, bypassing locks; the previous driver, if any, becomes a passenger. Returns false when either does not exist or the player is not joined.

Key/value strings a plugin attaches to any vehicle. Tags survive edits, resets and respawns, ride the join replay to late joiners and are broadcast to every client on change (read-only client-side, readable via the vehicle record). Limits: key 1-64 bytes, value 1-256 bytes, 32 distinct keys per vehicle – a set that breaks a limit is rejected, never truncated.

Arguments: globalId: number, key: string, value: string
C: set_vehicle_tag

Sets or overwrites one tag on the vehicle. Returns false when the vehicle does not exist or a limit is broken: empty key or value, key over 64 bytes, value over 256 bytes, or a 33rd distinct key – rejected, never truncated. An empty value is not a legal tag; use removeVehicleTag. Fires vehicleTagsChanged and broadcasts the tag set to every client.

Arguments: globalId: number, key: string
C: get_vehicle_tag

The value of one tag, or nil when the vehicle or the tag does not exist.

Arguments: globalId: number, key: string
C: remove_vehicle_tag

Removes one tag. Returns true when it existed and was removed, false otherwise. Fires vehicleTagsChanged when it did.

Arguments: globalId: number
C: get_vehicle_tags_json

The vehicle’s whole tag set as a table of key -> value (the measured shape shows a sample key; it is a plain map), or nil when the vehicle does not exist. Also available as the tags field of node.getVehicle.

Arguments: key: string, value?: string?
C: get_vehicles_by_tag

Global ids (ascending) of every vehicle carrying the tag key – with any value, or exactly value when given. Empty array when none. For a several-pairs AND query use getVehiclesByTags.

Arguments: pairs: table
C: get_vehicles_by_tags

Global ids (ascending) of every vehicle whose tag set matches EVERY pair in the given table {key = value, …} – an AND query. Values may be strings or numbers (numbers compare as their string form); an empty table matches nothing.

Deciding who sees what. The relayRequest filter (formerly canRelay) answers, per (sender, receiver, packet category, subtype, vehicle), whether a packet is forwarded; verdicts are cached until invalidated. Visibility groups are the coarse form: a player only receives relays from players and vehicles in the same group (group 0 is everyone). The dimensions module is built on groups.

Arguments: none
C: invalidate_relay_cache

Drops every cached relayRequest verdict so the hooks are consulted again. Call it whenever the data your relayRequest hook reads has changed; until you do, the old answers stand. Thread-safe.

Arguments: playerId: number, group: number
C: set_player_group

Puts the player in a visibility group. Two things see each other only when their group numbers match, and 0 – the default – is the world everyone shares. That one rule covers parallel worlds, instanced races, private lobbies and spectator rooms. Takes effect on the next relayed packet; a player moving groups sees the other group’s vehicles disappear and its own appear.

Arguments: globalId: number, group: number
C: set_vehicle_group

Puts the vehicle in a visibility group (0 = shared world). A packet about a vehicle belongs to the VEHICLE’s group, not its driver’s, because a car can be moved between worlds with someone in it. Forgotten when the vehicle is deleted.

Arguments: playerId: number
C: get_player_group

The player’s visibility group; 0 when never set or the player is unknown.

Arguments: globalId: number
C: get_vehicle_group

The vehicle’s visibility group; 0 when never set or there is no such vehicle.

The event system has three kinds of name. ENGINE events are camelCase builtins the server fires, named <subject><Verb-ed> (playerJoined, vehicleSpawned); the requests a handler can deny are named <subject><Action>Request (playerConnectRequest, vehicleSpawnRequest; relayRequest is the relay filter), and a handler that returns false denies the action. WIRE events are <domain>:<verb> strings a resource defines itself, sent with emitClient/emitAll and received from clients through the same node.on. One node.on covers all of them: the name decides the kind. The pre-1.2.0 names (playerJoin, onPlayerConnectRequest, canRelay, …) are deprecated aliases: they still subscribe to the same event and log one warning per resource per old name; they are removed in 2.0.

Arguments: playerId: number, event: string, data: string
C: emit_client

Sends a wire event to one player: event is a <domain>:<verb> name, data a string (by convention JSON – node.jsonEncode). Returns false when the player is not connected. The client receives it in any handler registered with node.on(event, fn) on its side.

Arguments: event: string, data: string
C: emit_all

Sends a wire event to every connected player, subject to the relayRequest filter and visibility groups like any relay.

Arguments: name: string, fn: function
C: register_client_event, register_builtin_event, register_cancellable_event, register_vehicle_event, register_relay_filter

Subscribes fn to an event by name. Builtin engine events (playerJoined, vehicleSpawned…), cancellable requests (…Request), vehicle notifications and the relayRequest hook are recognised by name; ANY other name is a wire event a client may send with node.emitServer. Handler arguments depend on the kind – see the events reference. Several handlers per name are fine, across resources too; each resource’s handlers are dropped when it unloads. This raw form appends: subscribing the same function twice registers it twice (it runs twice; off(name, fn) removes both). The public node.on replaces the first subscription instead. A deprecated alias (playerJoin, onVehicleSpawnRequest, canRelay, …) is mapped to its canonical name here too, with one warning per resource per old name; the public node.on maps it before the call reaches this layer.

Arguments: name: string, fn?: function?
C: unregister_client_event, unregister_builtin_event, unregister_cancellable_event, unregister_vehicle_event, unregister_relay_filter

Unsubscribes this resource’s handlers for the name – all of them, or only fn when given – and returns how many were removed. fn is matched by identity against what on() received, from any context, including coroutines (node.async, pg transaction bodies). A dispatch already in flight on the worker may still deliver one final call. A deprecated alias is mapped to its canonical name like in on() (the same once-per-resource warning), so either spelling removes what either spelling subscribed.

Arguments: exceptPlayerId: number, event: string, data: string
C: emit_others

Sends a wire event to every connected player except one – the player whose action you are relaying, typically. The fan-out is emitAll’s, with exceptPlayerId as the sender for the relay filter (relayRequest sees from = exceptPlayerId) and visibility groups. Returns false, and sends nothing, when exceptPlayerId is not a connected player. Before this the pattern was a loop over getPlayers with emitClient, which skipped the group filter emitAll applies.

A raw binary channel keyed by a u32 id, for native modules and their client counterparts that speak their own encoding. Nothing is parsed or logged; use it when JSON events are too slow or too loose. The dimensions module owns channel 0x44494D53 (“DIMS”).

Arguments: playerId: number, channel: number, data: string
C: send_module

One binary payload to one player on a u32 channel, or to everyone (relayRequest-respecting) when playerId is -1. data is an arbitrary binary string. Returns false when the player is not connected.

Arguments: channel: number, fn: function
C: register_module_channel

Subscribes fn(playerId, data) to inbound binary payloads clients send on the u32 channel. data is a binary string; nothing is parsed or logged.

Arguments: channel: number, fn?: function?
C: unregister_module_channel

Unsubscribes this resource’s handlers for the channel – all, or only fn – and returns how many were removed. A dispatch already in flight may deliver one final call.

Server-side publish/subscribe between resources (and native modules). Delivery is asynchronous on the plugin worker and includes the sender. This is how the chat resource asks the dimensions module which players share a room.

Arguments: name: string, data?: string?
C: emit_resource_event

Publishes a message on the inter-resource bus: every resource and native module subscribed to name receives (sourceResourceName, data) asynchronously on the worker – the sender included. data is a string (by convention JSON), “” when omitted.

Arguments: name: string, fn: function
C: register_resource_event

Subscribes fn(sourceResourceName, data) to bus messages published under name by any resource or native module (a native module appears as source “native”).

Arguments: name: string, fn?: function?
C: unregister_resource_event

Unsubscribes this resource’s bus handlers for name – all, or only fn – and returns how many were removed.

One-shot and repeating timers on the plugin worker thread – the same thread every handler runs on, so a timer callback never races a handler. setImmediate runs after the current batch of handlers.

Arguments: ms: number, fn: function
C: set_timeout

Runs fn once after ms milliseconds on the worker thread and returns a positive timer id for clearTimer. A pending timer never fires after the resource unloads or the server stops.

Arguments: ms: number, fn: function
C: set_interval

Runs fn every ms milliseconds on the worker thread until clearTimer, returning a positive timer id. A slow callback delays the next run; intervals do not stack.

Arguments: timerId: number
C: clear_timer

Cancels a timer from setTimeout or setInterval. Safe for an id that already fired or never existed. A callback mid-execution finishes; an interval will not fire again.

Arguments: fn: function
Lua only.

Runs fn on the worker as soon as the current batch of handlers has finished. Use it to act after every handler of the event you are in has seen it.

Two ways to not block the worker. node.async runs a function as a cooperative coroutine: node.sleep and node.wait suspend it while other handlers and the tick keep running (the FiveM Citizen.Wait model). node.job / node.await run a SELF-CONTAINED function on a background pool thread in a scratch Lua state, for real parallelism: no upvalues, no resource globals, JSON-serialisable arguments and result.

Arguments: workFn: function, args?: any, doneFn: function?
C: submit_job

Runs workFn(args) on a BACKGROUND pool thread in a fresh scratch Lua state – the resource state is never touched off-thread – and then doneFn(result, errMsg?) on the worker. workFn must be self-contained: no upvalues, no resource globals (it is dumped and reloaded into the scratch state); args and the result must be JSON-serialisable. Returns false if workFn could not be dumped. For linear code use node.await inside node.async.

Arguments: fn: function, ...: ...
Lua only.

Runs fn(…) as a cooperative coroutine on the worker thread and returns its task id. Inside it node.sleep, node.wait, node.await and node.yield suspend the coroutine WITHOUT blocking other handlers or the server tick. The task ends when fn returns or errors (the error is logged under the resource’s tag).

Arguments: ms: number
Lua only.

Suspends the CURRENT node.async coroutine for ms milliseconds. Only callable inside one: elsewhere Lua raises its standard “attempt to yield” error.

Arguments: msOrPredicate: number|function, intervalMs?: number?
Lua only.

A number sleeps like node.sleep. A function suspends the coroutine until it returns truthy, polled on the worker every intervalMs (default 50). Only callable inside node.async.

Arguments: none
Lua only.

Gives the worker back to other handlers and ticks for one turn, then resumes. For long loops inside node.async that MUST run on the worker because they touch live state – this is fairness, not parallelism; for CPU offload use node.await.

Arguments: workFn: function, args?: any?
Lua only.

The coroutine form of node.job: runs workFn(args) on a background pool thread in a fresh scratch Lua state and suspends the coroutine until it finishes, then returns the JSON-serialisable result, or nil plus an error message. Same rules as node.job: workFn must be self-contained (no upvalues, no resource globals). Only callable inside node.async. Other handlers and the tick keep running meanwhile: linear code, real parallelism.

Asynchronous HTTP requests from the background pool; the callback runs on the worker. Any method (GET, POST, PUT, PATCH, DELETE, HEAD, or a custom uppercase token). About 15 s timeout, 8 MB body cap, 5 redirects. TLS peer verification is OFF unless the hoster sets [Http] CaFile in server.toml (env NODE_HTTP_CA_FILE, server 1.2.0): then every https request verifies the chain against that CA bundle and the certificate’s name against the host, and a failure comes back as status -1 with the TLS error in body.

Arguments: url: string, headers?: any, callback: function?
C: http_request

GET url with optional headers (a table of header -> value); callback(status, body, headers) runs on the worker when the request completes: status is the HTTP status code, or -1 with the error text in body when the request failed (could not resolve or connect, TLS handshake or – with [Http] CaFile set – certificate verification, timeout, malformed response, body over the cap). Returns false if the request could not be queued (the background pool is full or shutting down); the callback then never runs. About 15 s timeout, 8 MB body cap, 5 redirects; TLS peer verification off unless [Http] CaFile is set. node.httpPost is the POST form, node.httpRequest takes any method.

Arguments: url: string, body: string, headers?: table?, callback: function?
Lua only.

POST body to url with optional headers (a table of header -> value); the callback receives (status, body, headers) on the worker: the HTTP status code, or -1 with the error text in body when the request failed, as for httpGet. Returns false if the request could not be queued (the callback then never runs). Same limits as httpGet: about 15 s timeout, 8 MB body cap, 5 redirects; TLS peer verification off unless [Http] CaFile is set.

Arguments: method: string, url: string, headers?: table?, body?: string?, callback: function?
Lua only.

The general form (server 1.2.0): method is a token of uppercase letters A-Z only, at most 16 – “GET”, “POST”, “PUT”, “PATCH”, “DELETE”, “HEAD” or a custom one; anything else comes back as status -1 “invalid HTTP method” (the public node.http.request upper-cases for you, this raw form does not) – url, headers (a table of header -> value, or nil), body (a string, or nil for none) and the callback(status, body, headers) on the worker: the HTTP status code, or -1 with the error text in body when the request failed, exactly as for httpGet/httpPost. A HEAD response has status and headers and an empty body. Returns false if the request could not be queued (the callback then never runs). Same limits: about 15 s timeout, 8 MB body cap, 5 redirects (a 301/302 answer to anything but GET/HEAD is re-issued as GET, a 303 always is); TLS peer verification off unless [Http] CaFile is set. httpGet and httpPost are this with the method fixed; the public node.http.request/put/patch/delete/head are built on it.

Reading, writing and listing files inside the resource’s own folder. Absolute paths and any .. step are rejected. Writes are synchronous unless writeFileAsync is used, which goes through the file-writer thread and coalesces with storage writes.

Arguments: path: string
Lua only.

Reads a file inside the resource’s folder; nil if it does not exist or the path escapes the sandbox (absolute paths and any .. step are rejected).

Arguments: path: string, data: string
Lua only.

Writes data to a file inside the resource’s folder, creating parent folders. Synchronous; false if the path is rejected or the write fails.

Arguments: path: string, data: string, cb?: function?
Lua only.

Like writeFile but the disk write happens off the worker on the file-writer thread, coalesced per path with storage writes; the optional cb(ok) runs back on the worker when it completes. Returns false only when the sandbox rejects the path – true means accepted, not written.

Arguments: path?: string?
Lua only.

Lists a folder inside the resource’s folder (the resource root when omitted): an array of {name, dir (boolean), size}; nil if the path is rejected or does not exist.

A per-resource JSON key/value store (storage/<resource>.json). Any JSON-serialisable Lua value; every mutation is flushed atomically, so the store survives a restart or a crash.

Arguments: key: string, value: any
C: storage_set

Stores value under key in this resource’s store (storage/<resource>.json). value is any JSON-serialisable Lua value – string, number, boolean, table; a table with consecutive integer keys is an array. Every mutation is flushed atomically. Returns false when the key is empty or the value cannot be encoded.

Arguments: key: string
C: storage_get

Reads the value stored under key, decoded back into a Lua value; nil when the key is absent.

Arguments: key: string
C: storage_delete

Removes key from this resource’s store. Returns false when it was not there.

Asynchronous, pooled access to the PostgreSQL the hoster points the server at ([Database] Url in server.toml, NODE_DATABASE_URL in the environment; empty = disabled). Parameterised statements ($1..$n) and transactions pinned to one connection, submitted from any thread and completed on the framework worker – the Lua thread never blocks on the database. Rows come back keyed by column name with Postgres types mapped to plain values; errors carry the SQLSTATE. The pool connects in the background and reconnects on its own; the server runs without a database and statements then fail with 08001. ABI 1.11; node.pg is the Lua face.

Contract for the server side of the Lua surface (what the prelude relies on): all eleven pg raw names – pgEnabled, pgReady, pgNullSentinel, pgQuery, pgQueryWait, pgTxBegin, pgTxBeginWait, pgTxQuery, pgTxQueryWait, pgTxEnd, pgTxEndWait – are bound unconditionally, database configured or not (the prelude calls raw.pgNullSentinel() at load; one missing binding breaks the prelude for every resource); pgQuery and pgTxQuery answer an unsupported value inside params with the -3 return, never by raising, so that the prelude’s “callback exactly once” holds; pgTxEnd and pgTxEndWait take commit as a Lua boolean; a handle the TxTimeoutMs rollback ended stays addressable until pgTxEnd is called on it, which answers tx_timeout and forgets it.

Arguments: none
C: pg_enabled

true when the server was configured with a database ([Database] Url); false means every node.pg call fails with err.code “pg_disabled”. Does not say whether a connection is up – that is pgReady.

Arguments: none
C: pg_ready

true while at least one pool connection is up. Statements issued while it is false fail at once with err.code “08001” (no connection) instead of waiting; the pool reconnects on its own.

Arguments: sql: string, params: table, flags: number, cb: function
C: pg_query

The callback form under node.pg.query: queues sql with the params array ($1..$n; node.pg.NULL for NULL, booleans, integers, floats, strings, tables as JSON) and calls cb(result, err) on the worker – result = { rows, count, columns }, or nil with err = { code, message, detail?, hint?, constraint?, table? }. flags bit0 = no rows (exec). Returns 0 when queued, -1 disabled, -2 queue full, -3 bad params – a value inside params the driver cannot send (a function, a userdata other than the NULL sentinel, a string with a NUL, more than 1000 values) is answered by that -3, never by raising, so the prelude can promise “callback exactly once”; when it is not 0 the callback never runs. Prefer node.pg.query, which turns those codes into an err.

Arguments: cb: function
C: pg_tx_begin

The callback form of a transaction: cb(handle, err) on the worker – handle is the number pgTxQuery/pgTxEnd take, or nil with err = { code, message, … } when BEGIN failed. Returns 0 when queued, -1 disabled, -2 queue full; when it is not 0 the callback never runs. node.pg.tx is built on the suspending pgTxBeginWait instead.

Arguments: handle: number, sql: string, params: table, flags: number, cb: function
C: pg_tx_query

pgQuery inside the transaction handle from pgTxBegin: the same sql/params/flags/cb contract, on the reserved connection. Returns 0 when queued, -1 disabled, -2 queue full, -3 bad params or an unknown handle (never issued, or already ended); when it is not 0 the callback never runs. A handle the TxTimeoutMs rollback got to first is still known until pgTxEnd: the call queues and cb gets err.code “tx_timeout”.

Arguments: handle: number, commit: boolean, cb: function
C: pg_tx_end

COMMIT (commit = true) or ROLLBACK (false) the transaction and free its connection; cb(ok, err) on the worker – true, or nil with err when the COMMIT failed (Postgres rolled back; the transaction is over either way) or err.code “tx_timeout” when the TxTimeoutMs rollback got there first (the handle is forgotten either way). commit is a boolean, not 0/1. Returns 0 when queued, -1 disabled, -2 queue full, -3 unknown handle (never issued, or already ended); when it is not 0 the callback never runs.

Arguments: none
Lua only.

The value that stands for NULL inside a params array: one light userdata per server, which the pg bindings recognise by identity (a Lua nil inside the array would end it). The prelude calls this once at load and publishes it as node.pg.NULL; call it yourself only when working on node.raw directly. Bound unconditionally, like every pg raw name: it exists – and the sentinel is the same value – whether or not [Database] Url was configured, so that the prelude loads for every resource.

node.raw.pgQueryWait(sql, params, flags) -> record{rows,count,columns}?,record{code,message,detail,hint,constraint,table}?

Заголовок раздела «node.raw.pgQueryWait(sql, params, flags) -> record{rows,count,columns}?,record{code,message,detail,hint,constraint,table}?»

Arguments: sql: string, params: table, flags: number
Lua only.

The suspending form of pgQuery: only inside node.async – suspends the coroutine until the statement completes and returns result, or nil and err (the same two tables pgQuery hands its callback; a submit failure comes back as err.code pg_disabled/pg_queue_full/pg_params). Called outside a node.async task it raises “node.pg.query: callback required outside node.async”. This is what node.pg.query does without a callback.

node.raw.pgTxBeginWait() -> number?,record{code,message,detail,hint,constraint,table}?

Заголовок раздела «node.raw.pgTxBeginWait() -> number?,record{code,message,detail,hint,constraint,table}?»

Arguments: none
Lua only.

The suspending form of pgTxBegin: only inside node.async – reserves a connection, runs BEGIN and returns the transaction handle, or nil and err. The connection stays reserved until pgTxEnd/pgTxEndWait on the handle, or the [Database] TxTimeoutMs rollback. Called outside a node.async task it raises “node.pg.tx: callback required outside node.async”. node.pg.tx is built on this.

node.raw.pgTxQueryWait(handle, sql, params, flags) -> record{rows,count,columns}?,record{code,message,detail,hint,constraint,table}?

Заголовок раздела «node.raw.pgTxQueryWait(handle, sql, params, flags) -> record{rows,count,columns}?,record{code,message,detail,hint,constraint,table}?»

Arguments: handle: number, sql: string, params: table, flags: number
Lua only.

The suspending form of pgTxQuery: only inside node.async – runs sql on the transaction’s connection and returns result, or nil and err (code tx_timeout once the server rolled the transaction back – the handle stays known until pgTxEnd/pgTxEndWait; pg_params for a handle never issued or already ended). What tx:query and tx:exec call.

node.raw.pgTxEndWait(handle, commit) -> boolean?,record{code,message,detail,hint,constraint,table}?

Заголовок раздела «node.raw.pgTxEndWait(handle, commit) -> boolean?,record{code,message,detail,hint,constraint,table}?»

Arguments: handle: number, commit: boolean
Lua only.

The suspending form of pgTxEnd: only inside node.async – COMMIT (true) or ROLLBACK (false; commit is a boolean), frees the connection and returns true, or nil and err when the COMMIT failed (Postgres rolled back; the transaction is over either way) or with code tx_timeout when the server had already rolled the transaction back; the handle is forgotten in every case. What node.pg.tx calls when fn returns or raises.

SHA-256, HMAC-SHA256, cryptographic random bytes, and JSON encode/decode with a depth guard.

Arguments: data: string
C: sha256_hex

SHA-256 of data as a 64-character lower-case hex string.

Arguments: key: string, data: string
C: hmac_sha256_hex

HMAC-SHA256 of data under key, as a 64-character lower-case hex string.

Arguments: count: number
C: random_bytes

count cryptographically random bytes (1..65536) as a binary string; nil outside that range. Use node.sha256 on the result for a printable token.

Arguments: value: any
Lua only.

Encodes a Lua value as JSON. Tables with consecutive integer keys from 1 become arrays, other tables objects; functions and userdata are not encodable.

Arguments: text: string
Lua only.

Decodes JSON text into a Lua value; nil on a parse error or when nesting exceeds the depth guard. JSON null becomes nil.

Reloading a resource by name. The call returns accepted: the reload runs on the worker after the current handler returns, dropping the resource’s registrations, coroutines and state, then loading it again.

Arguments: name: string
C: reload_resource

Queues a reload of the named resource: its registrations, timers, coroutines and state are dropped and the resource is loaded again – on the worker, after the current handler returns, so a resource can reload itself. Returns true when the request was ACCEPTED, not when the reload finished; a name that is not loaded returns false.

Arguments: none
C: get_resource_manifest_json

This resource’s manifest, resource.toml, as a table: { name, version, type, server = { main }, client = { files, obfuscation }, config = the [config] table as written (an empty table when there is none) }. The way to give a resource settings without a config.lua and a dofile: put them under [config] and read node.getManifest().config. Read from disk on each call. nil only when the manifest cannot be parsed.