@s2script/sdk 0.32.0 → 0.34.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -148,6 +148,43 @@ and records which member versions each release pinned. Make the workspace root t
148
148
  - A plugin already published **before** it joined a bundle must be republished at a new version
149
149
  from the bundle's workspace, so that its registry entry carries the claim.
150
150
 
151
+ #### Several bundles in one workspace
152
+
153
+ To combine several bundled monorepos (say a TTT and a Jailbreak, each its own bundle) into one
154
+ parent repo with one `.changeset/` and one release, make the parent the only workspace and list
155
+ each bundle's directory under `s2script.workspace.bundles`:
156
+
157
+ ```json
158
+ {
159
+ "name": "@edge/servers",
160
+ "private": true,
161
+ "workspaces": ["ttt/plugins/*", "ttt/packages/*", "jb/plugins/*", "jb/packages/*"],
162
+ "s2script": {
163
+ "workspace": { "plugins": ["ttt/plugins/*", "jb/plugins/*"], "bundles": ["ttt", "jb"] }
164
+ }
165
+ }
166
+ ```
167
+
168
+ Each listed directory keeps a package.json that describes its bundle and nothing else:
169
+
170
+ ```json
171
+ {
172
+ "name": "@edge/jailbreak",
173
+ "version": "1.0.0",
174
+ "s2script": { "kind": "bundle", "bundle": { "optional": ["@edge/jailbreak-gangperks"] } }
175
+ }
176
+ ```
177
+
178
+ - A bundle's **members** are the non-private plugins under its directory. A plugin under no listed
179
+ directory is published on its own, in no bundle.
180
+ - The descriptor must **not** keep `s2script.workspace` (s2s would stop there and treat it as a
181
+ separate workspace) and must not itself be a workspace package. Drop the child's own
182
+ `workspaces`, lockfile and `.changeset/` too: npm and changesets only read the parent's.
183
+ - **`s2s version`** at the parent bumps each bundle by the largest bump among its own members, and
184
+ `s2s deploy` publishes every bundle after its members. A member that fails to publish holds back
185
+ only its own bundle.
186
+ - The root and a listed directory cannot both be bundles, and bundle directories cannot nest.
187
+
151
188
  The membership claim travels in the registry upload only — the `.s2sp` manifest the runtime loads
152
189
  is unchanged, and the runtime has no notion of bundles.
153
190
 
package/clients.d.ts CHANGED
@@ -73,6 +73,94 @@ export declare class Client {
73
73
  * client.fakeCommand("say hello"); // as though the player typed it
74
74
  */
75
75
  fakeCommand(cmd: string): boolean;
76
+ /**
77
+ * Ask this client for its own value of a cvar (SourceMod `QueryClientConVar`). The client
78
+ * answers over the network, so this resolves on a later frame.
79
+ *
80
+ * Resolves `null` when no query was sent (a bot, a disconnected client, a name that is empty or
81
+ * contains whitespace, or a build where the reply hook is unavailable) or when the client
82
+ * disconnects or has not answered within 15 seconds. `value` is `""` unless `status` is `"ok"`.
83
+ *
84
+ * The value is what the client reports. A modified client can report anything, so treat it as a
85
+ * hint, not proof.
86
+ *
87
+ * @example
88
+ * const reply = await client.queryConVar("cl_interp_ratio");
89
+ * if (reply?.status === "ok") console.log(`${client.name}: ${reply.value}`);
90
+ */
91
+ queryConVar(name: string): Promise<ConVarQueryResult | null>;
92
+ /**
93
+ * Set this client's own copy of a replicated cvar without touching the server's value
94
+ * (SourceMod `SendConVarValue`). The client applies it only to cvars the server is allowed to
95
+ * replicate; the next server-side change to that cvar overwrites it. Booleans send `"1"`/`"0"`.
96
+ *
97
+ * Returns `false` for a bot, a disconnected client or an empty name.
98
+ *
99
+ * @example
100
+ * client.replicateConVar("sv_cheats", true); // client-side only, e.g. for a practice HUD
101
+ */
102
+ replicateConVar(name: string, value: string | number | boolean): boolean;
103
+ /**
104
+ * One snapshot of this client's network counters, read from the engine's net channel
105
+ * (SourceMod `GetClientLatency`, `GetClientAvgLoss`, `GetClientAvgChoke`, `GetClientAvgData`,
106
+ * `GetClientAvgPackets`, `GetClientTime`, `IsClientTimingOut` and `GetClientDataRate` in one
107
+ * call). Read it again for fresh values; nothing in it updates on its own.
108
+ *
109
+ * Returns `null` for a bot (bots have no net channel), a disconnected client, or a server build
110
+ * whose net-channel layout this build has not been verified against.
111
+ *
112
+ * @example
113
+ * const stats = client.netStats();
114
+ * if (stats) console.log(`${client.name}: ${Math.round(stats.avgLatency * 1000)} ms, ` +
115
+ * `${(stats.avgLoss.incoming * 100).toFixed(1)}% loss`);
116
+ */
117
+ netStats(): ClientNetStats | null;
118
+ }
119
+ /** A value measured separately for each direction, as seen from the server. */
120
+ export interface NetFlowPair {
121
+ /** Server to client. */
122
+ outgoing: number;
123
+ /** Client to server. */
124
+ incoming: number;
125
+ }
126
+ /** What {@link Client.netStats} returns. Times are in seconds. */
127
+ export interface ClientNetStats {
128
+ /** Average packet latency. */
129
+ avgLatency: number;
130
+ /** The engine's current round-trip estimate: more accurate than `avgLatency`, but jittery. */
131
+ engineLatency: number;
132
+ /** Average packet loss, from 0 to 1. */
133
+ avgLoss: NetFlowPair;
134
+ /** Average choke, from 0 to 1. */
135
+ avgChoke: NetFlowPair;
136
+ /** Average data rate in bytes per second. */
137
+ avgData: NetFlowPair;
138
+ /** Average packets per second. */
139
+ avgPackets: NetFlowPair;
140
+ /** Bytes sent or received since the client connected. */
141
+ totalData: NetFlowPair;
142
+ /** Packets sent or received since the client connected. */
143
+ totalPackets: NetFlowPair;
144
+ /** How long the client has been connected. */
145
+ timeConnected: number;
146
+ /** Time since the last packet from the client arrived. */
147
+ timeSinceLastReceived: number;
148
+ /** Whether the channel is about to time out. */
149
+ isTimingOut: boolean;
150
+ /** The send data rate the channel is allowed, in bytes per second. */
151
+ dataRate: number;
152
+ }
153
+ /**
154
+ * How a client answered {@link Client.queryConVar}: `"ok"` (value is set), `"notFound"` (no such
155
+ * cvar), `"notValid"` (the name is a command, not a cvar), `"protected"` (the client refused to
156
+ * reveal it), or `"unknown"` for a status this build does not recognise.
157
+ */
158
+ export type ConVarQueryStatus = "ok" | "notFound" | "notValid" | "protected" | "unknown";
159
+ /** The client's answer to {@link Client.queryConVar}. */
160
+ export interface ConVarQueryResult {
161
+ status: ConVarQueryStatus;
162
+ /** The client's value, or `""` when `status` is not `"ok"`. */
163
+ value: string;
76
164
  }
77
165
  /**
78
166
  * Look up connected clients by slot or enumerate them all.