EngineCallsThe calls this plugin declares. The base interface is EMPTY — s2s build generates
.s2script/gamedata.d.ts, which augments this from your gamedata's calls section.
@s2script/sdk/unsafe
Call or detour an engine function the framework does not wrap. Declare it in gamedata/functions.jsonc and bind with Engine.function — s2s build derives engine:calls / engine:hooks. Validated at load; optional bindings degrade with structured status. Operator allow-list still default-deny.
import { EngineCalls } from "@s2script/sdk/unsafe";Author-time types ship in the npm package; the engine injects the runtime at plugin load.
Add @s2script/sdk to your plugin's dependencies.
Generated from the shipped type definitions.
EngineCallsThe calls this plugin declares. The base interface is EMPTY — s2s build generates
.s2script/gamedata.d.ts, which augments this from your gamedata's calls section.
EngineHooksThe inbound hooks this plugin declares. The base interface is EMPTY — s2s build generates
.s2script/hooks.d.ts, which augments this from your gamedata's hooks section.
EngineFunctionsGenerated bindings augment this map from gamedata/functions.jsonc.
FunctionStatusreadonly canonicalId: stringreadonly availability: 'available' | 'unavailable'readonly reason: string | nullreadonly hookObservation: 'not-requested' | 'pending' | 'active' | 'failed'readonly provenance: {
readonly archiveHash: string;
readonly baseContractHash: string;
readonly appliedOverrides: readonly { readonly path: string; readonly sha256: string }[];
readonly finalTargetHash: string;
readonly resolverReceipt: string;
readonly required: boolean;
}Disposabledispose(): booleanFunctionSubscriptionreadonly status: 'pending' | 'active' | 'failed' | 'disposed'readonly reason: string | nulldispose(): booleanEnginePlugin-declared engine calls and inbound hooks, resolved from this plugin's own gamedata.
import { Engine } from "@s2script/sdk/unsafe";
// Resolve ONCE at load — null means the descriptor failed a load-time gate.
const ignite = Engine.call("ignite");
if (!ignite) console.log(`unavailable: ${Engine.status("ignite")}`);
const onFoo = Engine.hook("onFoo");
if (onFoo) onFoo((view) => { view.reason = 0; });function<K extends keyof EngineFunctions>(name: K): EngineFunctions[K]call<K extends keyof EngineCalls>(name: K): EngineCalls[K] | nullnull when its descriptor failed a load-time gate (signature miss,
validator rejection, slot outside .text, missing platform entry, or the plugin is not
operator-allow-listed). Guard once at load; the returned function is a plain callable.status(name: string): string"available" when it resolved. For diagnostics/operator reports.hook<K extends keyof EngineHooks>(name: K): EngineHooks[K] | nullnull when its descriptor failed a load-time
gate (same class of reasons as Engine.call, plus a missing validate or an unknown
thunk shape). Guard once at load; the returned function records the handler and lazily
installs the detour. The owner is always the calling plugin — you cannot subscribe to
another plugin's hook through this factory (game-package hooks are the @s2script/cs2 exports such as players and gameRules).hookStatus(name: string): string"available" when it resolved.