@s2script/sdk 0.18.0 → 0.20.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/dist/cli.js +119 -6
- package/package.json +1 -1
- package/ws.d.ts +21 -2
package/dist/cli.js
CHANGED
|
@@ -3769,6 +3769,12 @@ function generatedDeclarationFiles(pluginDir) {
|
|
|
3769
3769
|
const gd = join7(pluginDir, ".s2script", "gamedata.d.ts");
|
|
3770
3770
|
return existsSync6(gd) ? [gd] : [];
|
|
3771
3771
|
}
|
|
3772
|
+
function gamePackageDeclarationFiles(pkg, packagesDir) {
|
|
3773
|
+
const deps = { ...pkg.dependencies ?? {}, ...pkg.devDependencies ?? {} };
|
|
3774
|
+
if (!("@s2script/cs2" in deps)) return [];
|
|
3775
|
+
const hooks = join7(packagesDir, "cs2", "hooks.generated.d.ts");
|
|
3776
|
+
return existsSync6(hooks) ? [hooks] : [];
|
|
3777
|
+
}
|
|
3772
3778
|
function declaredModules(dtsFiles) {
|
|
3773
3779
|
const out = /* @__PURE__ */ new Set();
|
|
3774
3780
|
for (const f of dtsFiles) {
|
|
@@ -3837,7 +3843,8 @@ function typecheckPlugin(pluginDir, opts) {
|
|
|
3837
3843
|
entry,
|
|
3838
3844
|
join7(packagesDir, "sdk", "globals.d.ts"),
|
|
3839
3845
|
...localDts,
|
|
3840
|
-
...generatedDeclarationFiles(absDir)
|
|
3846
|
+
...generatedDeclarationFiles(absDir),
|
|
3847
|
+
...gamePackageDeclarationFiles(pkg, packagesDir)
|
|
3841
3848
|
];
|
|
3842
3849
|
const tmp = mkdtempSync(join7(tmpdir(), "s2tc-"));
|
|
3843
3850
|
try {
|
|
@@ -8528,7 +8535,7 @@ async function run8(argv2) {
|
|
|
8528
8535
|
}
|
|
8529
8536
|
|
|
8530
8537
|
// src/commands/codegen.ts
|
|
8531
|
-
import { dirname as dirname6, join as
|
|
8538
|
+
import { dirname as dirname6, join as join28 } from "node:path";
|
|
8532
8539
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
8533
8540
|
|
|
8534
8541
|
// src/schemagen/gen.ts
|
|
@@ -9406,9 +9413,102 @@ function runGenNav(repoRoot2, opts) {
|
|
|
9406
9413
|
return { wrappers: model.wrappers.length, fields, drift };
|
|
9407
9414
|
}
|
|
9408
9415
|
|
|
9416
|
+
// src/hookgen/gen.ts
|
|
9417
|
+
import { readFileSync as readFileSync22, writeFileSync as writeFileSync17 } from "node:fs";
|
|
9418
|
+
import { join as join27 } from "node:path";
|
|
9419
|
+
|
|
9420
|
+
// src/hookgen/model.ts
|
|
9421
|
+
function capitalize(name) {
|
|
9422
|
+
return name.length === 0 ? name : name.charAt(0).toUpperCase() + name.slice(1);
|
|
9423
|
+
}
|
|
9424
|
+
function buildHookModel(hooks) {
|
|
9425
|
+
const byNs = /* @__PURE__ */ new Map();
|
|
9426
|
+
for (const name of Object.keys(hooks).sort()) {
|
|
9427
|
+
const decl = hooks[name] ?? {};
|
|
9428
|
+
const ns = decl.expose?.ctx;
|
|
9429
|
+
if (!ns) continue;
|
|
9430
|
+
const paramNames = decl.params ?? [];
|
|
9431
|
+
const mutableSet = new Set(decl.mutable ?? []);
|
|
9432
|
+
const params = paramNames.map((p) => ({ name: p, mutable: mutableSet.has(p) }));
|
|
9433
|
+
const receiverAs = decl.receiver?.kind === "entity" ? decl.receiver.as ?? null : null;
|
|
9434
|
+
const list = byNs.get(ns) ?? [];
|
|
9435
|
+
list.push({ name, viewIface: `${capitalize(name)}View`, params, receiverAs });
|
|
9436
|
+
byNs.set(ns, list);
|
|
9437
|
+
}
|
|
9438
|
+
return Array.from(byNs.keys()).sort().map((ns) => ({ ns, ctxIface: `Ctx${capitalize(ns)}`, hooks: byNs.get(ns) }));
|
|
9439
|
+
}
|
|
9440
|
+
|
|
9441
|
+
// src/hookgen/emit-dts.ts
|
|
9442
|
+
var HEADER6 = "// GENERATED by `s2script gen-hooks` from gamedata/cs2/game.cs2.jsonc's `hooks` \u2014 DO NOT EDIT.";
|
|
9443
|
+
function emitViewIface(h2) {
|
|
9444
|
+
const out = [`export interface ${h2.viewIface} {`];
|
|
9445
|
+
for (const p of h2.params) {
|
|
9446
|
+
const mod = p.mutable ? "" : "readonly ";
|
|
9447
|
+
out.push(` ${mod}${p.name}: number;`);
|
|
9448
|
+
}
|
|
9449
|
+
if (h2.receiverAs !== null) {
|
|
9450
|
+
out.push(` readonly ${h2.receiverAs}: EntityRef | null;`);
|
|
9451
|
+
}
|
|
9452
|
+
out.push("}", "");
|
|
9453
|
+
return out;
|
|
9454
|
+
}
|
|
9455
|
+
function emitHookDts(model) {
|
|
9456
|
+
const out = [
|
|
9457
|
+
HEADER6,
|
|
9458
|
+
'import type { HookResultValue } from "@s2script/sdk/events";',
|
|
9459
|
+
'import type { EntityRef } from "@s2script/sdk/entity";',
|
|
9460
|
+
""
|
|
9461
|
+
];
|
|
9462
|
+
for (const { hooks } of model) {
|
|
9463
|
+
for (const h2 of hooks) {
|
|
9464
|
+
out.push(...emitViewIface(h2));
|
|
9465
|
+
}
|
|
9466
|
+
}
|
|
9467
|
+
for (const { ctxIface, hooks } of model) {
|
|
9468
|
+
out.push(`export interface ${ctxIface} {`);
|
|
9469
|
+
for (const h2 of hooks) {
|
|
9470
|
+
out.push(` ${h2.name}(handler: (view: ${h2.viewIface}) => HookResultValue | void): void;`);
|
|
9471
|
+
}
|
|
9472
|
+
out.push("}", "");
|
|
9473
|
+
}
|
|
9474
|
+
out.push('declare module "@s2script/sdk/plugin" {');
|
|
9475
|
+
out.push(" interface PluginContext {");
|
|
9476
|
+
for (const { ns, ctxIface } of model) {
|
|
9477
|
+
out.push(` readonly ${ns}: ${ctxIface};`);
|
|
9478
|
+
}
|
|
9479
|
+
out.push(" }");
|
|
9480
|
+
out.push("}");
|
|
9481
|
+
return out.join("\n") + "\n";
|
|
9482
|
+
}
|
|
9483
|
+
|
|
9484
|
+
// src/hookgen/gen.ts
|
|
9485
|
+
var GAMEDATA_PATH = "gamedata/cs2/game.cs2.jsonc";
|
|
9486
|
+
var DTS_OUT4 = "packages/cs2/hooks.generated.d.ts";
|
|
9487
|
+
function runGenHooks(repoRoot2, opts) {
|
|
9488
|
+
const raw = readFileSync22(join27(repoRoot2, GAMEDATA_PATH), "utf8");
|
|
9489
|
+
const gd = JSON.parse(stripJsonComments(raw));
|
|
9490
|
+
const hooks = gd.hooks ?? {};
|
|
9491
|
+
const model = buildHookModel(hooks);
|
|
9492
|
+
const dts = emitHookDts(model);
|
|
9493
|
+
const drift = [];
|
|
9494
|
+
const abs = join27(repoRoot2, DTS_OUT4);
|
|
9495
|
+
if (opts.check) {
|
|
9496
|
+
let cur = "";
|
|
9497
|
+
try {
|
|
9498
|
+
cur = readFileSync22(abs, "utf8");
|
|
9499
|
+
} catch {
|
|
9500
|
+
}
|
|
9501
|
+
if (cur !== dts) drift.push(DTS_OUT4);
|
|
9502
|
+
} else {
|
|
9503
|
+
writeFileSync17(abs, dts);
|
|
9504
|
+
}
|
|
9505
|
+
const hookCount = model.reduce((n3, ns) => n3 + ns.hooks.length, 0);
|
|
9506
|
+
return { hooks: hookCount, drift };
|
|
9507
|
+
}
|
|
9508
|
+
|
|
9409
9509
|
// src/commands/codegen.ts
|
|
9410
9510
|
function repoRoot() {
|
|
9411
|
-
return
|
|
9511
|
+
return join28(dirname6(fileURLToPath3(import.meta.url)), "..", "..", "..");
|
|
9412
9512
|
}
|
|
9413
9513
|
async function run9(kind, argv2) {
|
|
9414
9514
|
const root = repoRoot();
|
|
@@ -9437,7 +9537,7 @@ async function run9(kind, argv2) {
|
|
|
9437
9537
|
} else {
|
|
9438
9538
|
console.log(`gen-events: wrote ${r2.events} events`);
|
|
9439
9539
|
}
|
|
9440
|
-
} else {
|
|
9540
|
+
} else if (kind === "nav") {
|
|
9441
9541
|
const r2 = runGenNav(root, { check });
|
|
9442
9542
|
if (check) {
|
|
9443
9543
|
if (r2.drift.length) {
|
|
@@ -9449,6 +9549,18 @@ async function run9(kind, argv2) {
|
|
|
9449
9549
|
} else {
|
|
9450
9550
|
console.log(`gen-nav: wrote ${r2.wrappers} wrappers, ${r2.fields} fields`);
|
|
9451
9551
|
}
|
|
9552
|
+
} else {
|
|
9553
|
+
const r2 = runGenHooks(root, { check });
|
|
9554
|
+
if (check) {
|
|
9555
|
+
if (r2.drift.length) {
|
|
9556
|
+
console.error(`FAIL: generated files out of date \u2014 run \`s2s gen-hooks\`:
|
|
9557
|
+
${r2.drift.join("\n ")}`);
|
|
9558
|
+
process.exit(1);
|
|
9559
|
+
}
|
|
9560
|
+
console.log(`hook codegen up to date (${r2.hooks} hooks)`);
|
|
9561
|
+
} else {
|
|
9562
|
+
console.log(`gen-hooks: wrote ${r2.hooks} hooks`);
|
|
9563
|
+
}
|
|
9452
9564
|
}
|
|
9453
9565
|
}
|
|
9454
9566
|
|
|
@@ -9464,7 +9576,8 @@ var COMMANDS = [
|
|
|
9464
9576
|
{ name: "config", summary: "Emit a plugin's default config file(s)", run: run8 },
|
|
9465
9577
|
{ name: "gen-schema", summary: "Regenerate schema accessors", run: (a2) => run9("schema", a2) },
|
|
9466
9578
|
{ name: "gen-events", summary: "Regenerate the event catalog", run: (a2) => run9("events", a2) },
|
|
9467
|
-
{ name: "gen-nav", summary: "Regenerate nav accessors", run: (a2) => run9("nav", a2) }
|
|
9579
|
+
{ name: "gen-nav", summary: "Regenerate nav accessors", run: (a2) => run9("nav", a2) },
|
|
9580
|
+
{ name: "gen-hooks", summary: "Regenerate the ctx hook augmentation", run: (a2) => run9("hooks", a2) }
|
|
9468
9581
|
];
|
|
9469
9582
|
function find(name) {
|
|
9470
9583
|
if (name === "publish") return COMMANDS.find((c2) => c2.name === "deploy");
|
|
@@ -9487,7 +9600,7 @@ var argv = process.argv.slice(2);
|
|
|
9487
9600
|
var command = argv[0];
|
|
9488
9601
|
function usage() {
|
|
9489
9602
|
console.error(
|
|
9490
|
-
"Usage:\n s2s create [path] [--game cs2|none] [--name <pkg>] [--template minimal] [--library]\n [--install npm|pnpm|yarn|bun|none] [--no-install] [-y]\n s2s create --workspace <dir>\n s2s build [dir|workspace root] [--filter <pattern>]... [--stamp-version <v>]\n [--packages-dir <path>]\n s2s login [--token s2s_\u2026] [--registry <url>]\n s2s deploy [dir|workspace root] [--filter <pattern>]... [--dry-run] [--yes|--ci]\n [--registry <url>] [--packages-dir <path>]\n s2s version [dir] [--since <ref>]\n s2s add <pkg>[@range] [--dir <plugin>] [--registry <url>]\n s2s install [name[@range]...] [--file <path>] [--dir <plugins dir>] [--registry <url>]\n s2s config gen <plugin.s2sp...> --out <dir>\n s2s gen-schema [--check]\n s2s gen-events [--check]\n s2s gen-nav [--check]\n\nEnv: S2SCRIPT_REGISTRY_URL S2SCRIPT_TOKEN (CI deploy)"
|
|
9603
|
+
"Usage:\n s2s create [path] [--game cs2|none] [--name <pkg>] [--template minimal] [--library]\n [--install npm|pnpm|yarn|bun|none] [--no-install] [-y]\n s2s create --workspace <dir>\n s2s build [dir|workspace root] [--filter <pattern>]... [--stamp-version <v>]\n [--packages-dir <path>]\n s2s login [--token s2s_\u2026] [--registry <url>]\n s2s deploy [dir|workspace root] [--filter <pattern>]... [--dry-run] [--yes|--ci]\n [--registry <url>] [--packages-dir <path>]\n s2s version [dir] [--since <ref>]\n s2s add <pkg>[@range] [--dir <plugin>] [--registry <url>]\n s2s install [name[@range]...] [--file <path>] [--dir <plugins dir>] [--registry <url>]\n s2s config gen <plugin.s2sp...> --out <dir>\n s2s gen-schema [--check]\n s2s gen-events [--check]\n s2s gen-nav [--check]\n s2s gen-hooks [--check]\n\nEnv: S2SCRIPT_REGISTRY_URL S2SCRIPT_TOKEN (CI deploy)"
|
|
9491
9604
|
);
|
|
9492
9605
|
}
|
|
9493
9606
|
if (!command) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@s2script/sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.20.0",
|
|
4
4
|
"license": "MIT OR Apache-2.0",
|
|
5
5
|
"description": "s2script SDK — the builtin capability types (imported as @s2script/sdk/entity, …) plus the `s2s` CLI for building Source 2 / CS2 plugins.",
|
|
6
6
|
"type": "module",
|
package/ws.d.ts
CHANGED
|
@@ -13,17 +13,36 @@ export interface WebSocket {
|
|
|
13
13
|
/** Close the connection. */
|
|
14
14
|
close(): void;
|
|
15
15
|
}
|
|
16
|
+
/** Options for {@link WebSocket.connect}. */
|
|
17
|
+
export interface WebSocketInit {
|
|
18
|
+
/**
|
|
19
|
+
* Extra headers to send on the opening handshake — the usual reason being a
|
|
20
|
+
* credential the server requires, e.g. `Authorization: Bearer <token>`.
|
|
21
|
+
*
|
|
22
|
+
* Headers the handshake owns are refused, and the connect rejects rather than
|
|
23
|
+
* silently dropping them: `Host`, `Connection`, `Upgrade`, any
|
|
24
|
+
* `Sec-WebSocket-*`, `Content-Length`, `Transfer-Encoding`. Values containing
|
|
25
|
+
* control characters are refused for the same reason.
|
|
26
|
+
*/
|
|
27
|
+
headers?: Record<string, string>;
|
|
28
|
+
}
|
|
29
|
+
|
|
16
30
|
/** Entry point for opening WebSocket connections. */
|
|
17
31
|
export declare const WebSocket: {
|
|
18
32
|
/**
|
|
19
33
|
* Connect to a WebSocket server (`wss://` for TLS) off the game thread.
|
|
20
34
|
* @returns Resolves on the open handshake with the live {@link WebSocket} handle.
|
|
21
|
-
* @throws Rejects on connect failure (bad URL, refused, TLS/handshake error).
|
|
35
|
+
* @throws Rejects on connect failure (bad URL, refused, TLS/handshake error, or a refused header).
|
|
22
36
|
* @example
|
|
23
37
|
* import { WebSocket } from "@s2script/sdk/ws";
|
|
24
38
|
* const ws = await WebSocket.connect("wss://ws.postman-echo.com/raw");
|
|
25
39
|
* ws.onMessage((data) => { console.log("echo:", data); ws.close(); });
|
|
26
40
|
* ws.send("hello-from-s2script");
|
|
41
|
+
* @example
|
|
42
|
+
* // A server that authenticates the handshake rather than the first frame.
|
|
43
|
+
* const ws = await WebSocket.connect("wss://maul.example/v2/ws", {
|
|
44
|
+
* headers: { Authorization: `Bearer ${jwt}` },
|
|
45
|
+
* });
|
|
27
46
|
*/
|
|
28
|
-
connect(url: string): Promise<WebSocket>;
|
|
47
|
+
connect(url: string, init?: WebSocketInit): Promise<WebSocket>;
|
|
29
48
|
};
|