@s2script/sdk 0.27.1 → 0.28.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 +51 -0
- package/dist/cli.js +415 -133
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -115,6 +115,57 @@ what lets a workspace hold a large first-party or in-house plugin suite that mus
|
|
|
115
115
|
public registry — build it, drop the `.s2sp`s into your own server, never `s2s deploy` it. (`s2s
|
|
116
116
|
deploy <dir>` on a single private plugin outside a workspace refuses the same way.)
|
|
117
117
|
|
|
118
|
+
### Bundles
|
|
119
|
+
|
|
120
|
+
A workspace whose plugins only make sense together (a game mode split into several plugins) can
|
|
121
|
+
publish as one **bundle**: the registry lists it as a single entry, installs it with one command,
|
|
122
|
+
and records which member versions each release pinned. Make the workspace root the bundle:
|
|
123
|
+
|
|
124
|
+
```json
|
|
125
|
+
{
|
|
126
|
+
"name": "@edge/jailbreak",
|
|
127
|
+
"version": "1.0.0",
|
|
128
|
+
"workspaces": ["plugins/*"],
|
|
129
|
+
"s2script": {
|
|
130
|
+
"kind": "bundle",
|
|
131
|
+
"workspace": { "plugins": ["plugins/*"] },
|
|
132
|
+
"bundle": { "optional": ["@edge/jailbreak-gangperks"] }
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
- **Members** are the workspace's non-private plugins, and must share the bundle's scope. A bundle
|
|
138
|
+
has no code of its own, so the root has no `main` and must not be `private`.
|
|
139
|
+
- **`s2s deploy`** at the root publishes the members first, each claiming the bundle, then the
|
|
140
|
+
bundle itself, pinning every member to the version just built. The plan shows it as the last row.
|
|
141
|
+
A bundle version already published with different member versions is refused before anything
|
|
142
|
+
uploads — bump it.
|
|
143
|
+
- **`s2s version`** bumps the bundle whenever a member is released, by the largest member bump.
|
|
144
|
+
- **`s2s install @edge/jailbreak`** installs the required members (and whatever they depend on);
|
|
145
|
+
`--with @edge/jailbreak-gangperks` adds an optional one. `s2s add` refuses a bundle: depend on a
|
|
146
|
+
member's interface instead.
|
|
147
|
+
- A plugin already published **before** it joined a bundle must be republished at a new version
|
|
148
|
+
from the bundle's workspace, so that its registry entry carries the claim.
|
|
149
|
+
|
|
150
|
+
The membership claim travels in the registry upload only — the `.s2sp` manifest the runtime loads
|
|
151
|
+
is unchanged, and the runtime has no notion of bundles.
|
|
152
|
+
|
|
153
|
+
## Publishing
|
|
154
|
+
|
|
155
|
+
`s2s deploy` builds the package and publishes it to the registry. Its page on s2script.com
|
|
156
|
+
is filled in from what you already keep beside your code:
|
|
157
|
+
|
|
158
|
+
- **README:** `README.md` next to `package.json` (found the way npm finds one, up to 100,000
|
|
159
|
+
characters). Each deploy that carries one replaces the page's README.
|
|
160
|
+
- **Source link:** package.json's standard `repository` field, in any npm form.
|
|
161
|
+
`{ "url": …, "directory": … }` links straight into a monorepo directory.
|
|
162
|
+
- **Config:** the `s2script.config` block, shown as a table of options with their defaults.
|
|
163
|
+
Options marked `"sensitive": true` keep their default off the page.
|
|
164
|
+
|
|
165
|
+
The README and `repository` travel with the deploy, not inside the `.s2sp`: the runtime never sees
|
|
166
|
+
them. A deploy without them leaves what the page already shows, so a README or link set on the
|
|
167
|
+
site stays until a deploy replaces it.
|
|
168
|
+
|
|
118
169
|
## Docs
|
|
119
170
|
|
|
120
171
|
**[s2script.com/docs](https://s2script.com/docs)** — getting started, guides, and the full API
|
package/dist/cli.js
CHANGED
|
@@ -600,7 +600,7 @@ var require_inc = __commonJS({
|
|
|
600
600
|
"../../node_modules/semver/functions/inc.js"(exports, module) {
|
|
601
601
|
"use strict";
|
|
602
602
|
var SemVer = require_semver();
|
|
603
|
-
var
|
|
603
|
+
var inc2 = (version, release, options, identifier, identifierBase) => {
|
|
604
604
|
if (typeof options === "string") {
|
|
605
605
|
identifierBase = identifier;
|
|
606
606
|
identifier = options;
|
|
@@ -615,7 +615,7 @@ var require_inc = __commonJS({
|
|
|
615
615
|
return null;
|
|
616
616
|
}
|
|
617
617
|
};
|
|
618
|
-
module.exports =
|
|
618
|
+
module.exports = inc2;
|
|
619
619
|
}
|
|
620
620
|
});
|
|
621
621
|
|
|
@@ -1989,7 +1989,7 @@ var require_semver2 = __commonJS({
|
|
|
1989
1989
|
var parse = require_parse();
|
|
1990
1990
|
var valid2 = require_valid();
|
|
1991
1991
|
var clean = require_clean();
|
|
1992
|
-
var
|
|
1992
|
+
var inc2 = require_inc();
|
|
1993
1993
|
var diff = require_diff();
|
|
1994
1994
|
var major2 = require_major();
|
|
1995
1995
|
var minor = require_minor();
|
|
@@ -2028,7 +2028,7 @@ var require_semver2 = __commonJS({
|
|
|
2028
2028
|
parse,
|
|
2029
2029
|
valid: valid2,
|
|
2030
2030
|
clean,
|
|
2031
|
-
inc,
|
|
2031
|
+
inc: inc2,
|
|
2032
2032
|
diff,
|
|
2033
2033
|
major: major2,
|
|
2034
2034
|
minor,
|
|
@@ -6143,11 +6143,110 @@ function formatRangeViolations(violations) {
|
|
|
6143
6143
|
` + lines.join("\n");
|
|
6144
6144
|
}
|
|
6145
6145
|
|
|
6146
|
+
// src/workspace/bundle.ts
|
|
6147
|
+
var MAX_BUNDLE_MEMBERS = 64;
|
|
6148
|
+
function isBundleWorkspace(ws) {
|
|
6149
|
+
return ws.pkg.s2script?.kind === "bundle";
|
|
6150
|
+
}
|
|
6151
|
+
function scopeOf(name) {
|
|
6152
|
+
if (!name.startsWith("@")) return null;
|
|
6153
|
+
const slash = name.indexOf("/");
|
|
6154
|
+
return slash > 1 ? name.slice(1, slash) : null;
|
|
6155
|
+
}
|
|
6156
|
+
function bundleProblems(ws) {
|
|
6157
|
+
if (!isBundleWorkspace(ws)) return [];
|
|
6158
|
+
const pkg = ws.pkg;
|
|
6159
|
+
const problems = [];
|
|
6160
|
+
const where2 = "package.json (workspace root)";
|
|
6161
|
+
if (typeof pkg.name !== "string" || pkg.name === "") {
|
|
6162
|
+
problems.push(`${where2}: a bundle needs a "name" \u2014 it is the bundle's registry name`);
|
|
6163
|
+
}
|
|
6164
|
+
if (typeof pkg.version !== "string" || pkg.version === "") {
|
|
6165
|
+
problems.push(`${where2}: a bundle needs a "version"`);
|
|
6166
|
+
}
|
|
6167
|
+
if (pkg.private === true) {
|
|
6168
|
+
problems.push(
|
|
6169
|
+
`${where2}: s2script.kind is "bundle" but the root is "private": true \u2014 a private root is never published; remove "private" or drop the bundle kind`
|
|
6170
|
+
);
|
|
6171
|
+
}
|
|
6172
|
+
if (pkg.main !== void 0 || pkg.s2script?.main !== void 0) {
|
|
6173
|
+
problems.push(`${where2}: a bundle has no code of its own \u2014 remove "main"`);
|
|
6174
|
+
}
|
|
6175
|
+
const members = ws.plugins.filter((p) => !p.private);
|
|
6176
|
+
if (members.length === 0) {
|
|
6177
|
+
problems.push(`${where2}: a bundle needs at least one non-private plugin in s2script.workspace.plugins`);
|
|
6178
|
+
}
|
|
6179
|
+
if (members.length > MAX_BUNDLE_MEMBERS) {
|
|
6180
|
+
problems.push(`${where2}: a bundle may have at most ${MAX_BUNDLE_MEMBERS} members (found ${members.length})`);
|
|
6181
|
+
}
|
|
6182
|
+
const bundleScope = typeof pkg.name === "string" ? scopeOf(pkg.name) : null;
|
|
6183
|
+
for (const m of members) {
|
|
6184
|
+
if (scopeOf(m.name) !== bundleScope) {
|
|
6185
|
+
problems.push(
|
|
6186
|
+
`${m.relDir}: ${m.name} cannot be a member of ${String(pkg.name)} \u2014 a bundle and its members must share a scope (the registry only accepts members with the same publisher)`
|
|
6187
|
+
);
|
|
6188
|
+
}
|
|
6189
|
+
}
|
|
6190
|
+
const raw = pkg.s2script?.bundle;
|
|
6191
|
+
let optional = [];
|
|
6192
|
+
if (raw !== void 0) {
|
|
6193
|
+
const block2 = raw;
|
|
6194
|
+
if (!block2 || typeof block2 !== "object" || Array.isArray(block2)) {
|
|
6195
|
+
problems.push(`${where2}: s2script.bundle must be an object`);
|
|
6196
|
+
} else if (block2.optional !== void 0) {
|
|
6197
|
+
if (!Array.isArray(block2.optional) || block2.optional.some((o) => typeof o !== "string")) {
|
|
6198
|
+
problems.push(`${where2}: s2script.bundle.optional must be an array of member names`);
|
|
6199
|
+
} else {
|
|
6200
|
+
optional = block2.optional;
|
|
6201
|
+
}
|
|
6202
|
+
}
|
|
6203
|
+
}
|
|
6204
|
+
const memberNames = new Set(members.map((m) => m.name));
|
|
6205
|
+
for (const name of optional) {
|
|
6206
|
+
if (!memberNames.has(name)) {
|
|
6207
|
+
problems.push(
|
|
6208
|
+
`${where2}: s2script.bundle.optional names ${JSON.stringify(name)}, which is not a non-private plugin of this workspace`
|
|
6209
|
+
);
|
|
6210
|
+
}
|
|
6211
|
+
}
|
|
6212
|
+
if (members.length > 0 && members.every((m) => optional.includes(m.name))) {
|
|
6213
|
+
problems.push(`${where2}: every member is optional \u2014 a bundle needs at least one required member`);
|
|
6214
|
+
}
|
|
6215
|
+
return problems;
|
|
6216
|
+
}
|
|
6217
|
+
function readBundle(ws) {
|
|
6218
|
+
if (!isBundleWorkspace(ws)) return null;
|
|
6219
|
+
const optional = ws.pkg.s2script.bundle?.optional ?? [];
|
|
6220
|
+
return {
|
|
6221
|
+
name: ws.pkg.name,
|
|
6222
|
+
version: ws.pkg.version,
|
|
6223
|
+
members: ws.plugins.filter((p) => !p.private),
|
|
6224
|
+
optional: new Set(optional)
|
|
6225
|
+
};
|
|
6226
|
+
}
|
|
6227
|
+
function bundleMembers(bundle) {
|
|
6228
|
+
const out = {};
|
|
6229
|
+
for (const m of bundle.members) {
|
|
6230
|
+
out[m.name] = bundle.optional.has(m.name) ? { version: m.version, optional: true } : { version: m.version };
|
|
6231
|
+
}
|
|
6232
|
+
return out;
|
|
6233
|
+
}
|
|
6234
|
+
function bundleManifest(bundle) {
|
|
6235
|
+
return { id: bundle.name, version: bundle.version, kind: "bundle", members: bundleMembers(bundle) };
|
|
6236
|
+
}
|
|
6237
|
+
function sameMembers(a2, b) {
|
|
6238
|
+
const ka = Object.keys(a2).sort();
|
|
6239
|
+
const kb = Object.keys(b).sort();
|
|
6240
|
+
if (ka.length !== kb.length || ka.some((k, i2) => k !== kb[i2])) return false;
|
|
6241
|
+
return ka.every((k) => a2[k].version === b[k].version && !!a2[k].optional === !!b[k].optional);
|
|
6242
|
+
}
|
|
6243
|
+
|
|
6146
6244
|
// src/workspace/preflight.ts
|
|
6147
6245
|
function preflightProblems(ws) {
|
|
6148
6246
|
const problems = [...indexInterfaces(ws.plugins).problems];
|
|
6149
6247
|
const violations = checkSiblingRanges(ws.plugins);
|
|
6150
6248
|
if (violations.length > 0) problems.push(formatRangeViolations(violations));
|
|
6249
|
+
problems.push(...bundleProblems(ws));
|
|
6151
6250
|
return problems;
|
|
6152
6251
|
}
|
|
6153
6252
|
function preflightWorkspace(ws) {
|
|
@@ -7736,7 +7835,7 @@ async function runWorkspace(argv2, root, interactive, filters, stampVersion) {
|
|
|
7736
7835
|
import { resolve as resolve15 } from "node:path";
|
|
7737
7836
|
|
|
7738
7837
|
// src/registry/deploy.ts
|
|
7739
|
-
import { readFileSync as readFileSync13 } from "node:fs";
|
|
7838
|
+
import { readdirSync as readdirSync4, readFileSync as readFileSync13 } from "node:fs";
|
|
7740
7839
|
import { resolve as resolve14 } from "node:path";
|
|
7741
7840
|
|
|
7742
7841
|
// src/types-pack.ts
|
|
@@ -7969,6 +8068,9 @@ var RegistryClient = class {
|
|
|
7969
8068
|
if (opts.types && opts.types.length) {
|
|
7970
8069
|
entries["types.tgz"] = new Uint8Array(opts.types);
|
|
7971
8070
|
}
|
|
8071
|
+
if (opts.readme && opts.readme.trim()) {
|
|
8072
|
+
entries["README.md"] = new TextEncoder().encode(opts.readme);
|
|
8073
|
+
}
|
|
7972
8074
|
const body = zipSync(entries, { level: 0 });
|
|
7973
8075
|
const res = await this.request("deploy", `${this.baseUrl}/api/v1/deploy`, {
|
|
7974
8076
|
method: "POST",
|
|
@@ -8005,10 +8107,12 @@ var RegistryClient = class {
|
|
|
8005
8107
|
const res = await this.request("meta", u4);
|
|
8006
8108
|
return this.json(res, "meta");
|
|
8007
8109
|
}
|
|
8008
|
-
|
|
8110
|
+
/** `withMembers`: optional members of a bundle root to install too (ignored for a plugin root). */
|
|
8111
|
+
async plan(name, range = "*", withMembers) {
|
|
8009
8112
|
const u4 = new URL(`${this.baseUrl}/api/v1/plan`);
|
|
8010
8113
|
u4.searchParams.set("name", name);
|
|
8011
8114
|
u4.searchParams.set("range", range);
|
|
8115
|
+
if (withMembers && withMembers.length > 0) u4.searchParams.set("with", withMembers.join(","));
|
|
8012
8116
|
const res = await this.request("plan", u4);
|
|
8013
8117
|
return this.json(res, "plan");
|
|
8014
8118
|
}
|
|
@@ -8029,6 +8133,23 @@ function assertDeployable(pkg, label) {
|
|
|
8029
8133
|
);
|
|
8030
8134
|
}
|
|
8031
8135
|
}
|
|
8136
|
+
var MAX_README_CHARS = 1e5;
|
|
8137
|
+
function readPackageReadme(pluginDir) {
|
|
8138
|
+
const names = readdirSync4(pluginDir).filter((n3) => /^readme(\.(md|markdown))?$/i.test(n3));
|
|
8139
|
+
if (names.length === 0) return null;
|
|
8140
|
+
const name = names.find((n3) => n3 === "README.md") ?? names.sort()[0];
|
|
8141
|
+
const text3 = readFileSync13(resolve14(pluginDir, name), "utf8").trim();
|
|
8142
|
+
if (!text3) return null;
|
|
8143
|
+
if (text3.length > MAX_README_CHARS) {
|
|
8144
|
+
throw new Error(
|
|
8145
|
+
`${name} is ${text3.length.toLocaleString("en-US")} characters; the registry accepts at most ${MAX_README_CHARS.toLocaleString("en-US")}. Shorten it, or link to longer docs from it.`
|
|
8146
|
+
);
|
|
8147
|
+
}
|
|
8148
|
+
return text3;
|
|
8149
|
+
}
|
|
8150
|
+
function withRegistryFields(manifest, pkg) {
|
|
8151
|
+
return pkg.repository === void 0 ? manifest : { ...manifest, repository: pkg.repository };
|
|
8152
|
+
}
|
|
8032
8153
|
function assembleDeployArchive(pluginDir, pkg, outPath) {
|
|
8033
8154
|
const absDir = resolve14(pluginDir);
|
|
8034
8155
|
if (packageKind(pkg) === "library") {
|
|
@@ -8038,7 +8159,13 @@ function assembleDeployArchive(pluginDir, pkg, outPath) {
|
|
|
8038
8159
|
throw new Error(`built archive missing manifest.json: ${outPath}`);
|
|
8039
8160
|
}
|
|
8040
8161
|
const manifest2 = JSON.parse(Buffer.from(manifestEntry2).toString("utf8"));
|
|
8041
|
-
return {
|
|
8162
|
+
return {
|
|
8163
|
+
manifest: withRegistryFields(manifest2, pkg),
|
|
8164
|
+
s2sp: null,
|
|
8165
|
+
lib,
|
|
8166
|
+
types: null,
|
|
8167
|
+
readme: readPackageReadme(absDir)
|
|
8168
|
+
};
|
|
8042
8169
|
}
|
|
8043
8170
|
const gate = assertPublishesTypes(pkg, absDir);
|
|
8044
8171
|
if (!gate.ok) throw new Error(`publish gate failed: ${gate.error}`);
|
|
@@ -8057,7 +8184,13 @@ function assembleDeployArchive(pluginDir, pkg, outPath) {
|
|
|
8057
8184
|
publishes: hasPublishes(manifest.publishes) ? manifest.publishes : void 0
|
|
8058
8185
|
});
|
|
8059
8186
|
}
|
|
8060
|
-
return {
|
|
8187
|
+
return {
|
|
8188
|
+
manifest: withRegistryFields(manifest, pkg),
|
|
8189
|
+
s2sp,
|
|
8190
|
+
lib: null,
|
|
8191
|
+
types,
|
|
8192
|
+
readme: readPackageReadme(absDir)
|
|
8193
|
+
};
|
|
8061
8194
|
}
|
|
8062
8195
|
async function deployPlugin(opts) {
|
|
8063
8196
|
const absDir = resolve14(opts.dir);
|
|
@@ -8070,13 +8203,13 @@ async function deployPlugin(opts) {
|
|
|
8070
8203
|
);
|
|
8071
8204
|
}
|
|
8072
8205
|
const outPath = packageKind(pkg) === "library" ? await buildLibrary(absDir, opts.packagesDir) : await buildPlugin(absDir, opts.packagesDir);
|
|
8073
|
-
const
|
|
8206
|
+
const archive = assembleDeployArchive(absDir, pkg, outPath);
|
|
8074
8207
|
const client = new RegistryClient({
|
|
8075
8208
|
baseUrl: opts.registryUrl || creds.registryUrl || defaultRegistryUrl(),
|
|
8076
8209
|
token: creds.token,
|
|
8077
8210
|
fetch: opts.fetch
|
|
8078
8211
|
});
|
|
8079
|
-
return client.deploy(
|
|
8212
|
+
return client.deploy(archive);
|
|
8080
8213
|
}
|
|
8081
8214
|
|
|
8082
8215
|
// src/workspace/deploy-all.ts
|
|
@@ -8134,7 +8267,7 @@ function formatPlan(plan) {
|
|
|
8134
8267
|
function isDuplicateVersionRejection(e) {
|
|
8135
8268
|
return e instanceof RegistryError && e.status === 409;
|
|
8136
8269
|
}
|
|
8137
|
-
async function uploadPlan(plan, built, client) {
|
|
8270
|
+
async function uploadPlan(plan, built, client, opts = {}) {
|
|
8138
8271
|
const results = [];
|
|
8139
8272
|
for (const entry of plan) {
|
|
8140
8273
|
if (entry.reason !== "PUBLISH") {
|
|
@@ -8149,6 +8282,7 @@ async function uploadPlan(plan, built, client) {
|
|
|
8149
8282
|
}
|
|
8150
8283
|
try {
|
|
8151
8284
|
const archive = assembleDeployArchive(b.plugin.dir, b.plugin.pkg, b.outPath);
|
|
8285
|
+
if (opts.bundle !== void 0) archive.manifest = { ...archive.manifest, bundle: opts.bundle };
|
|
8152
8286
|
const res = await client.deploy(archive);
|
|
8153
8287
|
results.push({ plugin: entry.plugin, status: "published", detail: res.reviewState });
|
|
8154
8288
|
} catch (e) {
|
|
@@ -8165,6 +8299,51 @@ async function uploadPlan(plan, built, client) {
|
|
|
8165
8299
|
}
|
|
8166
8300
|
return results;
|
|
8167
8301
|
}
|
|
8302
|
+
async function publishedMembers(client, name, version) {
|
|
8303
|
+
let meta;
|
|
8304
|
+
try {
|
|
8305
|
+
meta = await client.meta(name);
|
|
8306
|
+
} catch {
|
|
8307
|
+
return null;
|
|
8308
|
+
}
|
|
8309
|
+
const versions = meta.versions ?? [];
|
|
8310
|
+
const hit = versions.find((v) => v.version === version);
|
|
8311
|
+
return hit ? hit.members ?? {} : null;
|
|
8312
|
+
}
|
|
8313
|
+
async function planBundle(bundle, client) {
|
|
8314
|
+
const manifest = bundleManifest(bundle);
|
|
8315
|
+
const published = await publishedMembers(client, bundle.name, bundle.version);
|
|
8316
|
+
if (published === null) return { bundle, reason: "PUBLISH", manifest };
|
|
8317
|
+
if (!sameMembers(published, bundleMembers(bundle))) {
|
|
8318
|
+
throw new Error(
|
|
8319
|
+
`bundle ${bundle.name}@${bundle.version} is already published with different members \u2014 bump the bundle's version (\`s2s version\` does this when a member changes) and deploy again`
|
|
8320
|
+
);
|
|
8321
|
+
}
|
|
8322
|
+
return { bundle, reason: "skip (already published)", manifest };
|
|
8323
|
+
}
|
|
8324
|
+
function formatBundlePlan(entry) {
|
|
8325
|
+
const count = entry.bundle.members.length;
|
|
8326
|
+
return ` ${entry.bundle.name} ${entry.bundle.version} ${entry.reason} (bundle of ${count} plugin${count === 1 ? "" : "s"})`;
|
|
8327
|
+
}
|
|
8328
|
+
async function uploadBundle(entry, memberResults, client) {
|
|
8329
|
+
if (entry.reason !== "PUBLISH") return { bundle: entry.bundle, status: "skipped", detail: entry.reason };
|
|
8330
|
+
if (memberResults.some((r2) => r2.status === "failed")) {
|
|
8331
|
+
return { bundle: entry.bundle, status: "skipped", detail: "a member failed to publish" };
|
|
8332
|
+
}
|
|
8333
|
+
try {
|
|
8334
|
+
const res = await client.deploy({ manifest: entry.manifest });
|
|
8335
|
+
return { bundle: entry.bundle, status: "published", detail: res.reviewState };
|
|
8336
|
+
} catch (e) {
|
|
8337
|
+
if (isDuplicateVersionRejection(e)) {
|
|
8338
|
+
return {
|
|
8339
|
+
bundle: entry.bundle,
|
|
8340
|
+
status: "skipped",
|
|
8341
|
+
detail: "skip (already published; its members were not verified)"
|
|
8342
|
+
};
|
|
8343
|
+
}
|
|
8344
|
+
return { bundle: entry.bundle, status: "failed", detail: e instanceof Error ? e.message : String(e) };
|
|
8345
|
+
}
|
|
8346
|
+
}
|
|
8168
8347
|
|
|
8169
8348
|
// src/commands/deploy.ts
|
|
8170
8349
|
async function run2(argv2) {
|
|
@@ -8259,18 +8438,23 @@ async function runWorkspaceDeploy(opts) {
|
|
|
8259
8438
|
}
|
|
8260
8439
|
const { ordered, built, unpublishableLibraries } = builtPluginsFromOutcomes(ws, build3.outcomes);
|
|
8261
8440
|
const plan = await computePlan(ordered, (name, version) => isAlreadyPublished(client, name, version));
|
|
8441
|
+
const bundle = readBundle(ws);
|
|
8442
|
+
const bundleEntry = bundle ? await planBundle(bundle, client) : null;
|
|
8262
8443
|
label("plan:");
|
|
8263
8444
|
console.log(formatPlan(plan));
|
|
8445
|
+
if (bundleEntry) console.log(formatBundlePlan(bundleEntry));
|
|
8264
8446
|
if (unpublishableLibraries.length > 0) {
|
|
8265
8447
|
console.log(formatUnpublishableLibraries(unpublishableLibraries));
|
|
8266
8448
|
}
|
|
8267
|
-
const
|
|
8449
|
+
const bundlePublishes = bundleEntry?.reason === "PUBLISH" ? 1 : 0;
|
|
8450
|
+
const toPublish = publishCount(plan) + bundlePublishes;
|
|
8451
|
+
const noun = (n3) => `${n3} package${n3 === 1 ? "" : "s"}`;
|
|
8268
8452
|
if (toPublish === 0) {
|
|
8269
8453
|
label("nothing to publish");
|
|
8270
8454
|
return;
|
|
8271
8455
|
}
|
|
8272
8456
|
if (dryRun) {
|
|
8273
|
-
label(`dry run \u2014 ${toPublish}
|
|
8457
|
+
label(`dry run \u2014 ${noun(toPublish)} would publish, uploading nothing`);
|
|
8274
8458
|
return;
|
|
8275
8459
|
}
|
|
8276
8460
|
if (!creds?.token) {
|
|
@@ -8285,7 +8469,7 @@ async function runWorkspaceDeploy(opts) {
|
|
|
8285
8469
|
);
|
|
8286
8470
|
}
|
|
8287
8471
|
const proceed = await confirm2({
|
|
8288
|
-
message: `Publish ${toPublish}
|
|
8472
|
+
message: `Publish ${noun(toPublish)} to ${client.baseUrl}?`,
|
|
8289
8473
|
initialValue: false
|
|
8290
8474
|
});
|
|
8291
8475
|
if (!proceed) {
|
|
@@ -8293,7 +8477,7 @@ async function runWorkspaceDeploy(opts) {
|
|
|
8293
8477
|
process.exit(130);
|
|
8294
8478
|
}
|
|
8295
8479
|
}
|
|
8296
|
-
const results = await uploadPlan(plan, built, client);
|
|
8480
|
+
const results = await uploadPlan(plan, built, client, { bundle: bundle?.name });
|
|
8297
8481
|
let failures = 0;
|
|
8298
8482
|
for (const r2 of results) {
|
|
8299
8483
|
if (r2.status === "failed") failures++;
|
|
@@ -8304,8 +8488,18 @@ async function runWorkspaceDeploy(opts) {
|
|
|
8304
8488
|
console.log(line);
|
|
8305
8489
|
}
|
|
8306
8490
|
}
|
|
8491
|
+
if (bundleEntry) {
|
|
8492
|
+
const r2 = await uploadBundle(bundleEntry, results, client);
|
|
8493
|
+
if (r2.status === "failed") failures++;
|
|
8494
|
+
const line = `${r2.bundle.name}@${r2.bundle.version} (bundle): ${r2.status}${r2.detail ? ` (${r2.detail})` : ""}`;
|
|
8495
|
+
if (interactive) {
|
|
8496
|
+
(r2.status === "failed" ? log2.error : r2.status === "published" ? log2.success : log2.info)(line);
|
|
8497
|
+
} else {
|
|
8498
|
+
console.log(line);
|
|
8499
|
+
}
|
|
8500
|
+
}
|
|
8307
8501
|
if (failures > 0) {
|
|
8308
|
-
throw new Error(`${failures}
|
|
8502
|
+
throw new Error(`${noun(failures)} failed to publish`);
|
|
8309
8503
|
}
|
|
8310
8504
|
}
|
|
8311
8505
|
|
|
@@ -8314,7 +8508,7 @@ import { resolve as resolve16 } from "node:path";
|
|
|
8314
8508
|
|
|
8315
8509
|
// src/version/version.ts
|
|
8316
8510
|
import { existsSync as existsSync11 } from "node:fs";
|
|
8317
|
-
import { join as
|
|
8511
|
+
import { join as join18 } from "node:path";
|
|
8318
8512
|
|
|
8319
8513
|
// src/version/changesets.ts
|
|
8320
8514
|
var import_semver = __toESM(require_semver2(), 1);
|
|
@@ -8527,10 +8721,44 @@ function rewriteSiblingRanges(ws, releases, config) {
|
|
|
8527
8721
|
return { rewrites, skips, touchedFiles };
|
|
8528
8722
|
}
|
|
8529
8723
|
|
|
8724
|
+
// src/version/bundle-bump.ts
|
|
8725
|
+
var import_semver3 = __toESM(require_semver2(), 1);
|
|
8726
|
+
import { writeFileSync as writeFileSync7 } from "node:fs";
|
|
8727
|
+
import { join as join17 } from "node:path";
|
|
8728
|
+
var LEVEL = { none: 0, patch: 1, minor: 2, major: 3 };
|
|
8729
|
+
function plannedBundleBump(ws, releases) {
|
|
8730
|
+
const bundle = readBundle(ws);
|
|
8731
|
+
if (!bundle) return null;
|
|
8732
|
+
const members = new Set(bundle.members.map((m) => m.name));
|
|
8733
|
+
const memberReleases = releases.filter((r2) => members.has(r2.name) && r2.type !== "none");
|
|
8734
|
+
if (memberReleases.length === 0) return null;
|
|
8735
|
+
const type = memberReleases.reduce((t2, r2) => LEVEL[r2.type] > LEVEL[t2] ? r2.type : t2, "none");
|
|
8736
|
+
const to = (0, import_semver3.inc)(bundle.version, type);
|
|
8737
|
+
if (to === null) {
|
|
8738
|
+
throw new Error(`s2s version: the bundle's version ${JSON.stringify(bundle.version)} is not valid semver`);
|
|
8739
|
+
}
|
|
8740
|
+
return {
|
|
8741
|
+
name: bundle.name,
|
|
8742
|
+
from: bundle.version,
|
|
8743
|
+
to,
|
|
8744
|
+
type,
|
|
8745
|
+
because: memberReleases.map((r2) => `${r2.name}@${r2.newVersion}`)
|
|
8746
|
+
};
|
|
8747
|
+
}
|
|
8748
|
+
function bumpBundle(ws, releases) {
|
|
8749
|
+
const bump = plannedBundleBump(ws, releases);
|
|
8750
|
+
if (!bump) return { bump: null, touchedFiles: [] };
|
|
8751
|
+
const path = join17(ws.root, "package.json");
|
|
8752
|
+
const { json, indent, eol } = readJsonFile(path);
|
|
8753
|
+
json.version = bump.to;
|
|
8754
|
+
writeFileSync7(path, JSON.stringify(json, null, indent) + eol);
|
|
8755
|
+
return { bump, touchedFiles: [path] };
|
|
8756
|
+
}
|
|
8757
|
+
|
|
8530
8758
|
// src/version/version.ts
|
|
8531
8759
|
async function versionWorkspace(root, opts = {}) {
|
|
8532
8760
|
const ws = loadWorkspace(root);
|
|
8533
|
-
const configPath =
|
|
8761
|
+
const configPath = join18(ws.root, ".changeset", "config.json");
|
|
8534
8762
|
if (!existsSync11(configPath)) {
|
|
8535
8763
|
throw new Error(
|
|
8536
8764
|
`s2s version: ${configPath} does not exist \u2014 this workspace is not set up for changesets. Run \`npx changeset init\` at ${ws.root}.`
|
|
@@ -8545,13 +8773,15 @@ async function versionWorkspace(root, opts = {}) {
|
|
|
8545
8773
|
const plan = cs.assembleReleasePlan(changesets, mirror, config, preState);
|
|
8546
8774
|
const touchedFiles = await cs.applyReleasePlan(plan, real, config);
|
|
8547
8775
|
const ranges = rewriteSiblingRanges(ws, plan.releases, config);
|
|
8776
|
+
const bundle = bumpBundle(ws, plan.releases);
|
|
8548
8777
|
return {
|
|
8549
8778
|
root: ws.root,
|
|
8550
8779
|
changesetCount: changesets.length,
|
|
8551
8780
|
releases: plan.releases,
|
|
8552
8781
|
rewrites: ranges.rewrites,
|
|
8553
8782
|
skips: ranges.skips,
|
|
8554
|
-
|
|
8783
|
+
bundleBump: bundle.bump,
|
|
8784
|
+
touchedFiles: [...touchedFiles, ...ranges.touchedFiles, ...bundle.touchedFiles],
|
|
8555
8785
|
changesetsVersions: cs.versions
|
|
8556
8786
|
};
|
|
8557
8787
|
}
|
|
@@ -8587,6 +8817,10 @@ async function run3(argv2) {
|
|
|
8587
8817
|
for (const r2 of result.releases) {
|
|
8588
8818
|
lines.push(`${r2.name} ${r2.oldVersion} -> ${r2.newVersion} (${r2.type})`);
|
|
8589
8819
|
}
|
|
8820
|
+
if (result.bundleBump) {
|
|
8821
|
+
const b = result.bundleBump;
|
|
8822
|
+
lines.push(`${b.name} ${b.from} -> ${b.to} (${b.type}, bundle \u2014 follows ${b.because.join(", ")})`);
|
|
8823
|
+
}
|
|
8590
8824
|
for (const rw of result.rewrites) {
|
|
8591
8825
|
lines.push(`${rw.consumer} pluginDependencies[${rw.iface}] ${rw.from} -> ${rw.to}`);
|
|
8592
8826
|
}
|
|
@@ -8611,16 +8845,16 @@ import { resolve as resolve18 } from "node:path";
|
|
|
8611
8845
|
// src/registry/add.ts
|
|
8612
8846
|
import {
|
|
8613
8847
|
mkdirSync as mkdirSync6,
|
|
8614
|
-
writeFileSync as
|
|
8848
|
+
writeFileSync as writeFileSync10,
|
|
8615
8849
|
readFileSync as readFileSync17,
|
|
8616
8850
|
existsSync as existsSync13
|
|
8617
8851
|
} from "node:fs";
|
|
8618
|
-
import { join as
|
|
8852
|
+
import { join as join21, resolve as resolve17 } from "node:path";
|
|
8619
8853
|
import { gunzipSync } from "node:zlib";
|
|
8620
8854
|
|
|
8621
8855
|
// src/registry/npmrc.ts
|
|
8622
|
-
import { existsSync as existsSync12, readFileSync as readFileSync16, writeFileSync as
|
|
8623
|
-
import { join as
|
|
8856
|
+
import { existsSync as existsSync12, readFileSync as readFileSync16, writeFileSync as writeFileSync8 } from "node:fs";
|
|
8857
|
+
import { join as join19 } from "node:path";
|
|
8624
8858
|
function npmCompatRegistryUrl(registryUrl) {
|
|
8625
8859
|
return `${registryUrl.replace(/\/$/, "")}/npm/`;
|
|
8626
8860
|
}
|
|
@@ -8636,7 +8870,7 @@ function ensureScopeNpmrc(projectDir, packageName, registryUrl) {
|
|
|
8636
8870
|
const compat = npmCompatRegistryUrl(registryUrl);
|
|
8637
8871
|
const key = `@${scope}:registry`;
|
|
8638
8872
|
const line = `${key}=${compat}`;
|
|
8639
|
-
const npmrcPath =
|
|
8873
|
+
const npmrcPath = join19(projectDir, ".npmrc");
|
|
8640
8874
|
let existing = existsSync12(npmrcPath) ? readFileSync16(npmrcPath, "utf8") : "";
|
|
8641
8875
|
const lines = existing.split(/\r?\n/);
|
|
8642
8876
|
const idx = lines.findIndex((l2) => l2.trimStart().startsWith(`${key}=`) || l2.trimStart().startsWith(`${key} =`));
|
|
@@ -8647,13 +8881,13 @@ function ensureScopeNpmrc(projectDir, packageName, registryUrl) {
|
|
|
8647
8881
|
lines.push(line);
|
|
8648
8882
|
}
|
|
8649
8883
|
const out = lines.filter((l2, i2, a2) => !(l2 === "" && a2[i2 - 1] === "")).join("\n");
|
|
8650
|
-
|
|
8884
|
+
writeFileSync8(npmrcPath, out.endsWith("\n") ? out : out + "\n");
|
|
8651
8885
|
return line;
|
|
8652
8886
|
}
|
|
8653
8887
|
|
|
8654
8888
|
// src/registry/lib-extract.ts
|
|
8655
|
-
import { mkdirSync as mkdirSync5, writeFileSync as
|
|
8656
|
-
import { join as
|
|
8889
|
+
import { mkdirSync as mkdirSync5, writeFileSync as writeFileSync9 } from "node:fs";
|
|
8890
|
+
import { join as join20 } from "node:path";
|
|
8657
8891
|
var WANTED = /* @__PURE__ */ new Set(["index.js", "index.d.ts"]);
|
|
8658
8892
|
function extractLibArchive(s2lib, outDir, meta) {
|
|
8659
8893
|
const entries = unzipSync(new Uint8Array(s2lib));
|
|
@@ -8662,7 +8896,7 @@ function extractLibArchive(s2lib, outDir, meta) {
|
|
|
8662
8896
|
mkdirSync5(outDir, { recursive: true });
|
|
8663
8897
|
for (const [name, bytes] of Object.entries(entries)) {
|
|
8664
8898
|
if (!WANTED.has(name)) continue;
|
|
8665
|
-
|
|
8899
|
+
writeFileSync9(join20(outDir, name), Buffer.from(bytes));
|
|
8666
8900
|
}
|
|
8667
8901
|
let apiVersion = "1.x";
|
|
8668
8902
|
try {
|
|
@@ -8670,8 +8904,8 @@ function extractLibArchive(s2lib, outDir, meta) {
|
|
|
8670
8904
|
if (typeof m.apiVersion === "string") apiVersion = m.apiVersion;
|
|
8671
8905
|
} catch {
|
|
8672
8906
|
}
|
|
8673
|
-
|
|
8674
|
-
|
|
8907
|
+
writeFileSync9(
|
|
8908
|
+
join20(outDir, "package.json"),
|
|
8675
8909
|
JSON.stringify(
|
|
8676
8910
|
{ name: meta.name, version: meta.version, main: "index.js", types: "index.d.ts", s2script: { kind: "library", apiVersion } },
|
|
8677
8911
|
null,
|
|
@@ -8708,13 +8942,13 @@ function extractTypesTarball(tgz, outDir) {
|
|
|
8708
8942
|
if (!name || name.endsWith("/")) continue;
|
|
8709
8943
|
const base = name.replace(/^package\//, "");
|
|
8710
8944
|
if (base === "package.json") {
|
|
8711
|
-
|
|
8945
|
+
writeFileSync10(join21(outDir, "package.json"), content);
|
|
8712
8946
|
} else if (base === "api.d.ts" || base === "index.d.ts") {
|
|
8713
|
-
|
|
8947
|
+
writeFileSync10(join21(outDir, "index.d.ts"), content);
|
|
8714
8948
|
wroteContract = true;
|
|
8715
8949
|
}
|
|
8716
8950
|
}
|
|
8717
|
-
if (!wroteContract && !existsSync13(
|
|
8951
|
+
if (!wroteContract && !existsSync13(join21(outDir, "index.d.ts"))) {
|
|
8718
8952
|
throw new Error("types tarball missing package/api.d.ts (or index.d.ts)");
|
|
8719
8953
|
}
|
|
8720
8954
|
}
|
|
@@ -8732,16 +8966,21 @@ async function addPackage(opts) {
|
|
|
8732
8966
|
fetch: opts.fetch
|
|
8733
8967
|
});
|
|
8734
8968
|
const resolved = await client.resolve(name, range);
|
|
8969
|
+
if (resolved.kind === "bundle") {
|
|
8970
|
+
throw new Error(
|
|
8971
|
+
`${name} is a bundle \u2014 it groups plugins for install and has nothing to add to a plugin. Install it on a server with \`s2s install ${name}\`, or \`s2s add\` the member plugin whose interface you use.`
|
|
8972
|
+
);
|
|
8973
|
+
}
|
|
8735
8974
|
if (resolved.kind === "library") {
|
|
8736
8975
|
const s2lib = await client.downloadLib(name, resolved.version);
|
|
8737
|
-
const libDir =
|
|
8976
|
+
const libDir = join21(absDir, ".s2script", "libs", ...name.split("/"));
|
|
8738
8977
|
extractLibArchive(s2lib, libDir, { name, version: resolved.version });
|
|
8739
|
-
const pkgPath2 =
|
|
8978
|
+
const pkgPath2 = join21(absDir, "package.json");
|
|
8740
8979
|
const pkg2 = JSON.parse(readFileSync17(pkgPath2, "utf8"));
|
|
8741
8980
|
pkg2.s2script = pkg2.s2script ?? {};
|
|
8742
8981
|
pkg2.s2script.libraries = pkg2.s2script.libraries ?? {};
|
|
8743
8982
|
pkg2.s2script.libraries[name] = rangeForResolved(range, resolved.version);
|
|
8744
|
-
|
|
8983
|
+
writeFileSync10(pkgPath2, JSON.stringify(pkg2, null, 2) + "\n");
|
|
8745
8984
|
return {
|
|
8746
8985
|
kind: "library",
|
|
8747
8986
|
name: resolved.name,
|
|
@@ -8758,14 +8997,14 @@ async function addPackage(opts) {
|
|
|
8758
8997
|
throw new Error(`${name}@${resolved.version} has no types artifact (runtime-only package?)`);
|
|
8759
8998
|
}
|
|
8760
8999
|
const tgz = await client.downloadTypes(name, resolved.version);
|
|
8761
|
-
const typesDir =
|
|
9000
|
+
const typesDir = join21(absDir, ".s2script", "types", ...name.split("/"));
|
|
8762
9001
|
extractTypesTarball(tgz, typesDir);
|
|
8763
|
-
const pkgPath =
|
|
9002
|
+
const pkgPath = join21(absDir, "package.json");
|
|
8764
9003
|
const pkg = JSON.parse(readFileSync17(pkgPath, "utf8"));
|
|
8765
9004
|
pkg.s2script = pkg.s2script ?? {};
|
|
8766
9005
|
pkg.s2script.pluginDependencies = pkg.s2script.pluginDependencies ?? {};
|
|
8767
9006
|
pkg.s2script.pluginDependencies[name] = rangeForResolved(range, resolved.version);
|
|
8768
|
-
|
|
9007
|
+
writeFileSync10(pkgPath, JSON.stringify(pkg, null, 2) + "\n");
|
|
8769
9008
|
const registryUrl = opts.registryUrl || creds?.registryUrl || defaultRegistryUrl();
|
|
8770
9009
|
const npmrcLine = ensureScopeNpmrc(absDir, name, registryUrl);
|
|
8771
9010
|
return {
|
|
@@ -8847,8 +9086,8 @@ import { existsSync as existsSync15 } from "node:fs";
|
|
|
8847
9086
|
|
|
8848
9087
|
// src/registry/install.ts
|
|
8849
9088
|
import { createHash as createHash4 } from "node:crypto";
|
|
8850
|
-
import { mkdirSync as mkdirSync7, readFileSync as readFileSync18, writeFileSync as
|
|
8851
|
-
import { basename as basename2, join as
|
|
9089
|
+
import { mkdirSync as mkdirSync7, readFileSync as readFileSync18, writeFileSync as writeFileSync11, renameSync, existsSync as existsSync14 } from "node:fs";
|
|
9090
|
+
import { basename as basename2, join as join22, resolve as resolve19, sep as sep3 } from "node:path";
|
|
8852
9091
|
function parseManifest(input) {
|
|
8853
9092
|
if (!input || typeof input !== "object" || Array.isArray(input)) {
|
|
8854
9093
|
throw new Error("manifest must be a JSON object");
|
|
@@ -8858,11 +9097,26 @@ function parseManifest(input) {
|
|
|
8858
9097
|
throw new Error('manifest must have a "plugins" object (name -> version range)');
|
|
8859
9098
|
}
|
|
8860
9099
|
const out = {};
|
|
8861
|
-
|
|
8862
|
-
|
|
8863
|
-
|
|
9100
|
+
const withMembers = {};
|
|
9101
|
+
for (const [name, entry] of Object.entries(plugins)) {
|
|
9102
|
+
if (typeof entry === "string") {
|
|
9103
|
+
out[name] = entry;
|
|
9104
|
+
continue;
|
|
9105
|
+
}
|
|
9106
|
+
const obj2 = entry;
|
|
9107
|
+
if (!obj2 || typeof obj2 !== "object" || Array.isArray(obj2)) {
|
|
9108
|
+
throw new Error(`entry for ${name} must be a range string or { "range", "with" }`);
|
|
9109
|
+
}
|
|
9110
|
+
if (obj2.range !== void 0 && typeof obj2.range !== "string") {
|
|
9111
|
+
throw new Error(`range for ${name} must be a string`);
|
|
9112
|
+
}
|
|
9113
|
+
if (obj2.with !== void 0 && (!Array.isArray(obj2.with) || obj2.with.some((w) => typeof w !== "string"))) {
|
|
9114
|
+
throw new Error(`"with" for ${name} must be an array of optional member names`);
|
|
9115
|
+
}
|
|
9116
|
+
out[name] = obj2.range ?? "*";
|
|
9117
|
+
if (Array.isArray(obj2.with) && obj2.with.length > 0) withMembers[name] = obj2.with;
|
|
8864
9118
|
}
|
|
8865
|
-
return { plugins: out };
|
|
9119
|
+
return Object.keys(withMembers).length > 0 ? { plugins: out, with: withMembers } : { plugins: out };
|
|
8866
9120
|
}
|
|
8867
9121
|
function parseSpec2(spec) {
|
|
8868
9122
|
const at = spec.lastIndexOf("@");
|
|
@@ -8889,12 +9143,12 @@ function safeFilename(e) {
|
|
|
8889
9143
|
}
|
|
8890
9144
|
return base;
|
|
8891
9145
|
}
|
|
8892
|
-
async function resolveMerged(client, specs) {
|
|
9146
|
+
async function resolveMerged(client, specs, withMembers = {}) {
|
|
8893
9147
|
const chosen = /* @__PURE__ */ new Map();
|
|
8894
9148
|
const warnings = [];
|
|
8895
9149
|
const errors = [];
|
|
8896
9150
|
for (const [name, range] of Object.entries(specs)) {
|
|
8897
|
-
const plan = await client.plan(name, range);
|
|
9151
|
+
const plan = await client.plan(name, range, withMembers[name]);
|
|
8898
9152
|
if (plan.errors.length) {
|
|
8899
9153
|
errors.push(...plan.errors);
|
|
8900
9154
|
continue;
|
|
@@ -8920,7 +9174,7 @@ async function resolveMerged(client, specs) {
|
|
|
8920
9174
|
async function installPlan(opts) {
|
|
8921
9175
|
const log3 = opts.log ?? (() => {
|
|
8922
9176
|
});
|
|
8923
|
-
const { install, warnings, errors } = await resolveMerged(opts.client, opts.specs);
|
|
9177
|
+
const { install, warnings, errors } = await resolveMerged(opts.client, opts.specs, opts.with);
|
|
8924
9178
|
if (errors.length) throw new Error(`cannot resolve plugins:
|
|
8925
9179
|
- ${errors.join("\n - ")}`);
|
|
8926
9180
|
if (opts.reviewedOnly) {
|
|
@@ -8937,7 +9191,7 @@ async function installPlan(opts) {
|
|
|
8937
9191
|
throw new Error(`refusing ${e.name}@${e.version}: registry did not provide a sha256 to verify against`);
|
|
8938
9192
|
}
|
|
8939
9193
|
const filename = safeFilename(e);
|
|
8940
|
-
const dest = resolve19(
|
|
9194
|
+
const dest = resolve19(join22(opts.dir, filename));
|
|
8941
9195
|
if (dest !== dirResolved && !dest.startsWith(dirResolved + sep3)) {
|
|
8942
9196
|
throw new Error(`refusing ${e.name}@${e.version}: destination "${dest}" escapes plugins dir "${dirResolved}"`);
|
|
8943
9197
|
}
|
|
@@ -8966,7 +9220,7 @@ async function installPlan(opts) {
|
|
|
8966
9220
|
throw new Error(`sha256 mismatch for ${e.name}@${e.version}: expected ${e.sha256}, got ${got}`);
|
|
8967
9221
|
}
|
|
8968
9222
|
const tmp = `${dest}.${process.pid}.tmp`;
|
|
8969
|
-
|
|
9223
|
+
writeFileSync11(tmp, bytes);
|
|
8970
9224
|
renameSync(tmp, dest);
|
|
8971
9225
|
written.push(filename);
|
|
8972
9226
|
log3(`installed ${e.name}@${e.version} -> ${filename}`);
|
|
@@ -8980,8 +9234,25 @@ function loadManifestFile(path) {
|
|
|
8980
9234
|
|
|
8981
9235
|
// src/commands/install.ts
|
|
8982
9236
|
var AUTODETECT = "addons/s2script/plugins";
|
|
9237
|
+
function collectWith(argv2) {
|
|
9238
|
+
const out = [];
|
|
9239
|
+
for (let i2 = 0; i2 < argv2.length; i2++) {
|
|
9240
|
+
const arg = argv2[i2];
|
|
9241
|
+
if (arg.startsWith("--with=")) {
|
|
9242
|
+
if (arg.length > "--with=".length) out.push(arg.slice("--with=".length));
|
|
9243
|
+
continue;
|
|
9244
|
+
}
|
|
9245
|
+
if (arg !== "--with") continue;
|
|
9246
|
+
const value = argv2[i2 + 1];
|
|
9247
|
+
if (value === void 0 || value.startsWith("-")) {
|
|
9248
|
+
throw new Error("--with requires an optional member name (e.g. --with @edge/jailbreak-gangperks)");
|
|
9249
|
+
}
|
|
9250
|
+
out.push(value);
|
|
9251
|
+
}
|
|
9252
|
+
return out;
|
|
9253
|
+
}
|
|
8983
9254
|
async function run5(argv2) {
|
|
8984
|
-
const args = positionals(argv2, ["--dir", "--file", "--registry"]);
|
|
9255
|
+
const args = positionals(argv2, ["--dir", "--file", "--registry", "--with"]);
|
|
8985
9256
|
const file = parseFlag(argv2, "--file") ?? "s2script-plugins.json";
|
|
8986
9257
|
const registry = parseFlag(argv2, "--registry") || loadCredentials()?.registryUrl || defaultRegistryUrl();
|
|
8987
9258
|
const dryRun = hasFlag(argv2, "--dry-run");
|
|
@@ -8999,8 +9270,18 @@ async function run5(argv2) {
|
|
|
8999
9270
|
}
|
|
9000
9271
|
const client = new RegistryClient({ baseUrl: registry });
|
|
9001
9272
|
try {
|
|
9273
|
+
const withArgs = collectWith(argv2);
|
|
9002
9274
|
const manifest = loadManifestFile(resolve20(file));
|
|
9003
9275
|
const specs = mergeSpecs(manifest, args);
|
|
9276
|
+
const withMembers = { ...manifest.with ?? {} };
|
|
9277
|
+
if (withArgs.length > 0) {
|
|
9278
|
+
if (args.length !== 1) {
|
|
9279
|
+
throw new Error(
|
|
9280
|
+
`--with applies to exactly one bundle named on the command line (got ${args.length}) \u2014 for several bundles, use { "range", "with" } entries in ${file}`
|
|
9281
|
+
);
|
|
9282
|
+
}
|
|
9283
|
+
withMembers[parseSpec2(args[0]).name] = withArgs;
|
|
9284
|
+
}
|
|
9004
9285
|
if (Object.keys(specs).length === 0) {
|
|
9005
9286
|
console.error(
|
|
9006
9287
|
`Nothing to install. Add plugins to ${file} or pass names: s2s install rtv@^1.0.0`
|
|
@@ -9010,6 +9291,7 @@ async function run5(argv2) {
|
|
|
9010
9291
|
const res = await installPlan({
|
|
9011
9292
|
client,
|
|
9012
9293
|
specs,
|
|
9294
|
+
with: withMembers,
|
|
9013
9295
|
dir,
|
|
9014
9296
|
dryRun,
|
|
9015
9297
|
reviewedOnly,
|
|
@@ -9034,21 +9316,21 @@ import { resolve as resolve23 } from "node:path";
|
|
|
9034
9316
|
// src/create/create.ts
|
|
9035
9317
|
import {
|
|
9036
9318
|
mkdirSync as mkdirSync8,
|
|
9037
|
-
writeFileSync as
|
|
9319
|
+
writeFileSync as writeFileSync12,
|
|
9038
9320
|
existsSync as existsSync16,
|
|
9039
|
-
readdirSync as
|
|
9321
|
+
readdirSync as readdirSync5,
|
|
9040
9322
|
readFileSync as readFileSync19,
|
|
9041
9323
|
symlinkSync
|
|
9042
9324
|
} from "node:fs";
|
|
9043
|
-
import { dirname as dirname6, isAbsolute, join as
|
|
9325
|
+
import { dirname as dirname6, isAbsolute, join as join23, relative as relative2, resolve as resolve21, basename as basename3 } from "node:path";
|
|
9044
9326
|
import { spawnSync } from "node:child_process";
|
|
9045
9327
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
9046
9328
|
function readCliVersion() {
|
|
9047
9329
|
const here = dirname6(fileURLToPath2(import.meta.url));
|
|
9048
9330
|
const candidates = [
|
|
9049
|
-
|
|
9331
|
+
join23(here, "..", "package.json"),
|
|
9050
9332
|
// dist/cli.js → packages/sdk/package.json
|
|
9051
|
-
|
|
9333
|
+
join23(here, "..", "..", "package.json")
|
|
9052
9334
|
// src/create → packages/sdk/package.json
|
|
9053
9335
|
];
|
|
9054
9336
|
for (const p of candidates) {
|
|
@@ -9064,9 +9346,9 @@ function readCliVersion() {
|
|
|
9064
9346
|
function findLocalPackagesDir() {
|
|
9065
9347
|
const here = dirname6(fileURLToPath2(import.meta.url));
|
|
9066
9348
|
const candidates = [
|
|
9067
|
-
|
|
9349
|
+
join23(here, "..", ".."),
|
|
9068
9350
|
// dist/cli.js → packages
|
|
9069
|
-
|
|
9351
|
+
join23(here, "..", "..", "..")
|
|
9070
9352
|
// src/create → packages
|
|
9071
9353
|
];
|
|
9072
9354
|
for (const c2 of candidates) {
|
|
@@ -9083,7 +9365,7 @@ function defaultNameFromPath(dir, kind = "plugin") {
|
|
|
9083
9365
|
}
|
|
9084
9366
|
function assertEmptyTarget(targetPath) {
|
|
9085
9367
|
if (!existsSync16(targetPath)) return;
|
|
9086
|
-
const kids =
|
|
9368
|
+
const kids = readdirSync5(targetPath);
|
|
9087
9369
|
const meaningful = kids.filter((k) => k !== ".git");
|
|
9088
9370
|
if (meaningful.length) {
|
|
9089
9371
|
throw new Error(`target directory is not empty: ${targetPath}`);
|
|
@@ -9131,8 +9413,8 @@ function registryDevDeps(game, sdkVersion, resolve25 = resolvePublishedVersion)
|
|
|
9131
9413
|
function fileDevDeps(packagesDir, game) {
|
|
9132
9414
|
const deps = {};
|
|
9133
9415
|
for (const n3 of createPackageNames(game)) {
|
|
9134
|
-
const abs =
|
|
9135
|
-
if (!existsSync16(
|
|
9416
|
+
const abs = join23(packagesDir, n3);
|
|
9417
|
+
if (!existsSync16(join23(abs, "package.json"))) return void 0;
|
|
9136
9418
|
deps[`@s2script/${n3}`] = `file:${abs}`;
|
|
9137
9419
|
}
|
|
9138
9420
|
return deps;
|
|
@@ -9197,7 +9479,7 @@ function tsconfigJson() {
|
|
|
9197
9479
|
) + "\n";
|
|
9198
9480
|
}
|
|
9199
9481
|
function workspaceTsconfigJson(targetPath, workspaceRoot) {
|
|
9200
|
-
const rel = relative2(targetPath,
|
|
9482
|
+
const rel = relative2(targetPath, join23(workspaceRoot, "tsconfig.base.json")).replace(/\\/g, "/");
|
|
9201
9483
|
return JSON.stringify(
|
|
9202
9484
|
{
|
|
9203
9485
|
extends: rel.startsWith(".") ? rel : `./${rel}`,
|
|
@@ -9273,9 +9555,9 @@ dist/
|
|
|
9273
9555
|
`;
|
|
9274
9556
|
}
|
|
9275
9557
|
function linkLocalPackagesForNoInstall(targetPath, localPackagesDir) {
|
|
9276
|
-
const nm =
|
|
9558
|
+
const nm = join23(targetPath, "node_modules");
|
|
9277
9559
|
mkdirSync8(nm, { recursive: true });
|
|
9278
|
-
const dest =
|
|
9560
|
+
const dest = join23(nm, "@s2script");
|
|
9279
9561
|
if (!existsSync16(dest)) symlinkSync(localPackagesDir, dest);
|
|
9280
9562
|
}
|
|
9281
9563
|
function runInstall(dir, pm) {
|
|
@@ -9305,7 +9587,7 @@ async function createPlugin(opts = {}) {
|
|
|
9305
9587
|
);
|
|
9306
9588
|
}
|
|
9307
9589
|
let slug = workspaceRoot !== void 0 && opts.path !== void 0 ? assertBareSlug(opts.path) : opts.path;
|
|
9308
|
-
let targetPath = workspaceRoot === void 0 ? resolve21(opts.path ?? ".") : slug === void 0 ? void 0 :
|
|
9590
|
+
let targetPath = workspaceRoot === void 0 ? resolve21(opts.path ?? ".") : slug === void 0 ? void 0 : join23(workspaceRoot, "plugins", slug);
|
|
9309
9591
|
if (targetPath !== void 0) assertEmptyTarget(targetPath);
|
|
9310
9592
|
if (interactive) {
|
|
9311
9593
|
intro2("Create an s2script plugin");
|
|
@@ -9315,7 +9597,7 @@ async function createPlugin(opts = {}) {
|
|
|
9315
9597
|
slug = assertBareSlug(
|
|
9316
9598
|
await text2({ message: "Plugin name (directory under plugins/)", placeholder: "myplugin" })
|
|
9317
9599
|
);
|
|
9318
|
-
targetPath =
|
|
9600
|
+
targetPath = join23(workspaceRoot, "plugins", slug);
|
|
9319
9601
|
assertEmptyTarget(targetPath);
|
|
9320
9602
|
}
|
|
9321
9603
|
}
|
|
@@ -9378,37 +9660,37 @@ async function createPlugin(opts = {}) {
|
|
|
9378
9660
|
install = workspaceRoot !== void 0 ? "none" : install ?? (opts.noInstall ? "none" : "npm");
|
|
9379
9661
|
const finalTargetPath = targetPath;
|
|
9380
9662
|
const localPackagesDir = workspaceRoot === void 0 ? findLocalPackagesDir() : void 0;
|
|
9381
|
-
mkdirSync8(
|
|
9663
|
+
mkdirSync8(join23(finalTargetPath, "src"), { recursive: true });
|
|
9382
9664
|
if (workspaceRoot !== void 0) {
|
|
9383
|
-
|
|
9384
|
-
|
|
9385
|
-
|
|
9665
|
+
writeFileSync12(join23(finalTargetPath, "package.json"), minimalPackageJsonContent(name));
|
|
9666
|
+
writeFileSync12(
|
|
9667
|
+
join23(finalTargetPath, "tsconfig.json"),
|
|
9386
9668
|
workspaceTsconfigJson(finalTargetPath, workspaceRoot)
|
|
9387
9669
|
);
|
|
9388
9670
|
} else if (kind === "library") {
|
|
9389
9671
|
const version = readCliVersion();
|
|
9390
|
-
|
|
9391
|
-
|
|
9672
|
+
writeFileSync12(
|
|
9673
|
+
join23(finalTargetPath, "package.json"),
|
|
9392
9674
|
libraryPackageJsonContent(name, game, version, localPackagesDir)
|
|
9393
9675
|
);
|
|
9394
|
-
|
|
9395
|
-
|
|
9676
|
+
writeFileSync12(join23(finalTargetPath, "tsconfig.json"), tsconfigJson());
|
|
9677
|
+
writeFileSync12(join23(finalTargetPath, "eslint.config.mjs"), eslintConfig());
|
|
9396
9678
|
} else {
|
|
9397
9679
|
const version = readCliVersion();
|
|
9398
|
-
|
|
9399
|
-
|
|
9680
|
+
writeFileSync12(
|
|
9681
|
+
join23(finalTargetPath, "package.json"),
|
|
9400
9682
|
packageJsonContent(name, game, version, localPackagesDir)
|
|
9401
9683
|
);
|
|
9402
|
-
|
|
9403
|
-
|
|
9684
|
+
writeFileSync12(join23(finalTargetPath, "tsconfig.json"), tsconfigJson());
|
|
9685
|
+
writeFileSync12(join23(finalTargetPath, "eslint.config.mjs"), eslintConfig());
|
|
9404
9686
|
}
|
|
9405
9687
|
if (kind === "library") {
|
|
9406
|
-
|
|
9407
|
-
|
|
9688
|
+
writeFileSync12(join23(finalTargetPath, "src", "index.ts"), LIBRARY_ENTRY);
|
|
9689
|
+
writeFileSync12(join23(finalTargetPath, "src", "index.d.ts"), LIBRARY_TYPES);
|
|
9408
9690
|
} else {
|
|
9409
|
-
|
|
9691
|
+
writeFileSync12(join23(finalTargetPath, "src", "plugin.ts"), pluginSource(game));
|
|
9410
9692
|
}
|
|
9411
|
-
|
|
9693
|
+
writeFileSync12(join23(finalTargetPath, ".gitignore"), gitignore());
|
|
9412
9694
|
let installed = false;
|
|
9413
9695
|
if (workspaceRoot === void 0) {
|
|
9414
9696
|
if (install !== "none") {
|
|
@@ -9435,8 +9717,8 @@ async function createPlugin(opts = {}) {
|
|
|
9435
9717
|
}
|
|
9436
9718
|
|
|
9437
9719
|
// src/create/workspace.ts
|
|
9438
|
-
import { mkdirSync as mkdirSync9, writeFileSync as
|
|
9439
|
-
import { join as
|
|
9720
|
+
import { mkdirSync as mkdirSync9, writeFileSync as writeFileSync13 } from "node:fs";
|
|
9721
|
+
import { join as join24, resolve as resolve22 } from "node:path";
|
|
9440
9722
|
var ROOT_DEFAULT_GAME = "cs2";
|
|
9441
9723
|
var CHANGESETS_CLI_RANGE = "^2.29.5";
|
|
9442
9724
|
function defaultWorkspaceName(dir) {
|
|
@@ -9520,14 +9802,14 @@ async function createWorkspace(opts = {}) {
|
|
|
9520
9802
|
name = name ?? defaultWorkspaceName(targetPath);
|
|
9521
9803
|
const version = readCliVersion();
|
|
9522
9804
|
const localPackagesDir = findLocalPackagesDir();
|
|
9523
|
-
mkdirSync9(
|
|
9524
|
-
mkdirSync9(
|
|
9525
|
-
mkdirSync9(
|
|
9526
|
-
|
|
9527
|
-
|
|
9528
|
-
|
|
9529
|
-
|
|
9530
|
-
|
|
9805
|
+
mkdirSync9(join24(targetPath, "plugins"), { recursive: true });
|
|
9806
|
+
mkdirSync9(join24(targetPath, "packages"), { recursive: true });
|
|
9807
|
+
mkdirSync9(join24(targetPath, ".changeset"), { recursive: true });
|
|
9808
|
+
writeFileSync13(join24(targetPath, "package.json"), rootPackageJsonContent(name, version, localPackagesDir));
|
|
9809
|
+
writeFileSync13(join24(targetPath, "tsconfig.base.json"), tsconfigBaseJson());
|
|
9810
|
+
writeFileSync13(join24(targetPath, "eslint.config.mjs"), eslintConfig());
|
|
9811
|
+
writeFileSync13(join24(targetPath, ".changeset", "config.json"), changesetConfigJson());
|
|
9812
|
+
writeFileSync13(join24(targetPath, ".gitignore"), gitignore());
|
|
9531
9813
|
return { dir: targetPath, name };
|
|
9532
9814
|
}
|
|
9533
9815
|
|
|
@@ -9763,8 +10045,8 @@ async function run7(argv2) {
|
|
|
9763
10045
|
}
|
|
9764
10046
|
|
|
9765
10047
|
// src/config/gen.ts
|
|
9766
|
-
import { readFileSync as readFileSync20, writeFileSync as
|
|
9767
|
-
import { join as
|
|
10048
|
+
import { readFileSync as readFileSync20, writeFileSync as writeFileSync14, mkdirSync as mkdirSync10 } from "node:fs";
|
|
10049
|
+
import { join as join25 } from "node:path";
|
|
9768
10050
|
|
|
9769
10051
|
// src/config/config-path.ts
|
|
9770
10052
|
function configFileName(id) {
|
|
@@ -9811,8 +10093,8 @@ function genConfigFromManifest(manifest, outDir) {
|
|
|
9811
10093
|
const id = typeof manifest.id === "string" ? manifest.id : "";
|
|
9812
10094
|
if (!id) throw new Error("config gen: manifest declares config but has no id");
|
|
9813
10095
|
mkdirSync10(outDir, { recursive: true });
|
|
9814
|
-
const path =
|
|
9815
|
-
|
|
10096
|
+
const path = join25(outDir, configFileName(id));
|
|
10097
|
+
writeFileSync14(path, generateDefaultJsonc(config));
|
|
9816
10098
|
return path;
|
|
9817
10099
|
}
|
|
9818
10100
|
function genConfigForS2sp(s2spPath, outDir) {
|
|
@@ -9863,12 +10145,12 @@ async function run8(argv2) {
|
|
|
9863
10145
|
}
|
|
9864
10146
|
|
|
9865
10147
|
// src/commands/codegen.ts
|
|
9866
|
-
import { dirname as dirname7, join as
|
|
10148
|
+
import { dirname as dirname7, join as join30 } from "node:path";
|
|
9867
10149
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
9868
10150
|
|
|
9869
10151
|
// src/schemagen/gen.ts
|
|
9870
|
-
import { readFileSync as readFileSync21, writeFileSync as
|
|
9871
|
-
import { join as
|
|
10152
|
+
import { readFileSync as readFileSync21, writeFileSync as writeFileSync15 } from "node:fs";
|
|
10153
|
+
import { join as join26 } from "node:path";
|
|
9872
10154
|
|
|
9873
10155
|
// src/schemagen/model.ts
|
|
9874
10156
|
function enumMemberNames(enumName, members) {
|
|
@@ -10351,16 +10633,16 @@ var EMBED_PATH = "games/cs2/codegen-embedded.json";
|
|
|
10351
10633
|
var JS_OUT = "games/cs2/js/schema.generated.js";
|
|
10352
10634
|
var DTS_OUT = "packages/cs2/schema.generated.d.ts";
|
|
10353
10635
|
function runGenSchema(repoRoot2, opts) {
|
|
10354
|
-
const catalog = JSON.parse(readFileSync21(
|
|
10355
|
-
const list = JSON.parse(readFileSync21(
|
|
10636
|
+
const catalog = JSON.parse(readFileSync21(join26(repoRoot2, CATALOG_PATH), "utf8"));
|
|
10637
|
+
const list = JSON.parse(readFileSync21(join26(repoRoot2, LIST_PATH), "utf8"));
|
|
10356
10638
|
let embed = [];
|
|
10357
10639
|
try {
|
|
10358
|
-
embed = JSON.parse(readFileSync21(
|
|
10640
|
+
embed = JSON.parse(readFileSync21(join26(repoRoot2, EMBED_PATH), "utf8"));
|
|
10359
10641
|
} catch {
|
|
10360
10642
|
}
|
|
10361
10643
|
let enumCatalog = {};
|
|
10362
10644
|
try {
|
|
10363
|
-
enumCatalog = JSON.parse(readFileSync21(
|
|
10645
|
+
enumCatalog = JSON.parse(readFileSync21(join26(repoRoot2, ENUMS_PATH), "utf8"));
|
|
10364
10646
|
} catch {
|
|
10365
10647
|
}
|
|
10366
10648
|
const model = buildModel(catalog, list, embed, enumCatalog);
|
|
@@ -10371,7 +10653,7 @@ function runGenSchema(repoRoot2, opts) {
|
|
|
10371
10653
|
const drift = [];
|
|
10372
10654
|
const files = [[JS_OUT, js], [DTS_OUT, dts]];
|
|
10373
10655
|
for (const [rel, content] of files) {
|
|
10374
|
-
const abs =
|
|
10656
|
+
const abs = join26(repoRoot2, rel);
|
|
10375
10657
|
if (opts.check) {
|
|
10376
10658
|
let cur = "";
|
|
10377
10659
|
try {
|
|
@@ -10380,7 +10662,7 @@ function runGenSchema(repoRoot2, opts) {
|
|
|
10380
10662
|
}
|
|
10381
10663
|
if (cur !== content) drift.push(rel);
|
|
10382
10664
|
} else {
|
|
10383
|
-
|
|
10665
|
+
writeFileSync15(abs, content);
|
|
10384
10666
|
}
|
|
10385
10667
|
}
|
|
10386
10668
|
if (model.collisions.length) console.error(`gen-schema: ${model.collisions.length} name collision(s) \u2192 raw fallback:
|
|
@@ -10390,8 +10672,8 @@ function runGenSchema(repoRoot2, opts) {
|
|
|
10390
10672
|
}
|
|
10391
10673
|
|
|
10392
10674
|
// src/eventgen/gen.ts
|
|
10393
|
-
import { readFileSync as readFileSync22, writeFileSync as
|
|
10394
|
-
import { join as
|
|
10675
|
+
import { readFileSync as readFileSync22, writeFileSync as writeFileSync16 } from "node:fs";
|
|
10676
|
+
import { join as join27 } from "node:path";
|
|
10395
10677
|
|
|
10396
10678
|
// src/eventgen/model.ts
|
|
10397
10679
|
var TYPE_TO_GETTER = {
|
|
@@ -10476,11 +10758,11 @@ function emitEventDts(model) {
|
|
|
10476
10758
|
var CATALOG_PATH2 = "games/cs2/gamedata/event-catalog.json";
|
|
10477
10759
|
var DTS_OUT2 = "packages/cs2/events.generated.d.ts";
|
|
10478
10760
|
function runGenEvents(repoRoot2, opts) {
|
|
10479
|
-
const catalog = JSON.parse(readFileSync22(
|
|
10761
|
+
const catalog = JSON.parse(readFileSync22(join27(repoRoot2, CATALOG_PATH2), "utf8"));
|
|
10480
10762
|
const model = buildEventModel(catalog);
|
|
10481
10763
|
const dts = emitEventDts(model);
|
|
10482
10764
|
const drift = [];
|
|
10483
|
-
const abs =
|
|
10765
|
+
const abs = join27(repoRoot2, DTS_OUT2);
|
|
10484
10766
|
if (opts.check) {
|
|
10485
10767
|
let cur = "";
|
|
10486
10768
|
try {
|
|
@@ -10489,14 +10771,14 @@ function runGenEvents(repoRoot2, opts) {
|
|
|
10489
10771
|
}
|
|
10490
10772
|
if (cur !== dts) drift.push(DTS_OUT2);
|
|
10491
10773
|
} else {
|
|
10492
|
-
|
|
10774
|
+
writeFileSync16(abs, dts);
|
|
10493
10775
|
}
|
|
10494
10776
|
return { events: model.length, drift };
|
|
10495
10777
|
}
|
|
10496
10778
|
|
|
10497
10779
|
// src/navgen/gen.ts
|
|
10498
|
-
import { readFileSync as readFileSync23, writeFileSync as
|
|
10499
|
-
import { join as
|
|
10780
|
+
import { readFileSync as readFileSync23, writeFileSync as writeFileSync17 } from "node:fs";
|
|
10781
|
+
import { join as join28 } from "node:path";
|
|
10500
10782
|
|
|
10501
10783
|
// src/navgen/model.ts
|
|
10502
10784
|
var SUPPORTED_NAV_KINDS = /* @__PURE__ */ new Set([
|
|
@@ -10717,8 +10999,8 @@ var CATALOG_PATH3 = "games/cs2/gamedata/schema-catalog.json";
|
|
|
10717
10999
|
var JS_OUT2 = "games/cs2/js/nav.generated.js";
|
|
10718
11000
|
var DTS_OUT3 = "packages/cs2/nav.generated.d.ts";
|
|
10719
11001
|
function runGenNav(repoRoot2, opts) {
|
|
10720
|
-
const config = JSON.parse(readFileSync23(
|
|
10721
|
-
const catalog = JSON.parse(readFileSync23(
|
|
11002
|
+
const config = JSON.parse(readFileSync23(join28(repoRoot2, TARGETS_PATH), "utf8"));
|
|
11003
|
+
const catalog = JSON.parse(readFileSync23(join28(repoRoot2, CATALOG_PATH3), "utf8"));
|
|
10722
11004
|
const model = buildNavModel(config, catalog);
|
|
10723
11005
|
const js = emitNavJs(model);
|
|
10724
11006
|
const dts = emitNavDts(model);
|
|
@@ -10726,7 +11008,7 @@ function runGenNav(repoRoot2, opts) {
|
|
|
10726
11008
|
const drift = [];
|
|
10727
11009
|
const files = [[JS_OUT2, js], [DTS_OUT3, dts]];
|
|
10728
11010
|
for (const [rel, content] of files) {
|
|
10729
|
-
const abs =
|
|
11011
|
+
const abs = join28(repoRoot2, rel);
|
|
10730
11012
|
if (opts.check) {
|
|
10731
11013
|
let cur = "";
|
|
10732
11014
|
try {
|
|
@@ -10735,25 +11017,25 @@ function runGenNav(repoRoot2, opts) {
|
|
|
10735
11017
|
}
|
|
10736
11018
|
if (cur !== content) drift.push(rel);
|
|
10737
11019
|
} else {
|
|
10738
|
-
|
|
11020
|
+
writeFileSync17(abs, content);
|
|
10739
11021
|
}
|
|
10740
11022
|
}
|
|
10741
11023
|
return { wrappers: model.wrappers.length, fields: fields2, drift };
|
|
10742
11024
|
}
|
|
10743
11025
|
|
|
10744
11026
|
// src/hookgen/gen.ts
|
|
10745
|
-
import { readFileSync as readFileSync24, writeFileSync as
|
|
10746
|
-
import { join as
|
|
11027
|
+
import { readFileSync as readFileSync24, writeFileSync as writeFileSync18 } from "node:fs";
|
|
11028
|
+
import { join as join29 } from "node:path";
|
|
10747
11029
|
var GAMEDATA_PATH = "games/cs2/gamedata/game.cs2.jsonc";
|
|
10748
11030
|
var DTS_OUT4 = "packages/cs2/hooks.generated.d.ts";
|
|
10749
11031
|
function runGenHooks(repoRoot2, opts) {
|
|
10750
|
-
const raw = readFileSync24(
|
|
11032
|
+
const raw = readFileSync24(join29(repoRoot2, GAMEDATA_PATH), "utf8");
|
|
10751
11033
|
const gd = JSON.parse(stripJsonComments(raw));
|
|
10752
11034
|
const hooks = gd.hooks ?? {};
|
|
10753
11035
|
const model = buildHookModel(hooks);
|
|
10754
11036
|
const dts = emitHookDts(model);
|
|
10755
11037
|
const drift = [];
|
|
10756
|
-
const abs =
|
|
11038
|
+
const abs = join29(repoRoot2, DTS_OUT4);
|
|
10757
11039
|
if (opts.check) {
|
|
10758
11040
|
let cur = "";
|
|
10759
11041
|
try {
|
|
@@ -10762,7 +11044,7 @@ function runGenHooks(repoRoot2, opts) {
|
|
|
10762
11044
|
}
|
|
10763
11045
|
if (cur !== dts) drift.push(DTS_OUT4);
|
|
10764
11046
|
} else {
|
|
10765
|
-
|
|
11047
|
+
writeFileSync18(abs, dts);
|
|
10766
11048
|
}
|
|
10767
11049
|
const hookCount = model.reduce((n3, ns) => n3 + ns.hooks.length, 0);
|
|
10768
11050
|
return { hooks: hookCount, drift };
|
|
@@ -10770,7 +11052,7 @@ function runGenHooks(repoRoot2, opts) {
|
|
|
10770
11052
|
|
|
10771
11053
|
// src/commands/codegen.ts
|
|
10772
11054
|
function repoRoot() {
|
|
10773
|
-
return
|
|
11055
|
+
return join30(dirname7(fileURLToPath3(import.meta.url)), "..", "..", "..");
|
|
10774
11056
|
}
|
|
10775
11057
|
async function run9(kind, argv2) {
|
|
10776
11058
|
const root = repoRoot();
|
|
@@ -10858,8 +11140,8 @@ async function run10(argv2) {
|
|
|
10858
11140
|
}
|
|
10859
11141
|
|
|
10860
11142
|
// src/engine-functions/migrate-v1.ts
|
|
10861
|
-
import { closeSync, existsSync as existsSync17, linkSync, lstatSync as lstatSync2, mkdirSync as mkdirSync11, openSync, readFileSync as readFileSync26, readdirSync as
|
|
10862
|
-
import { dirname as dirname8, isAbsolute as isAbsolute2, join as
|
|
11143
|
+
import { closeSync, existsSync as existsSync17, linkSync, lstatSync as lstatSync2, mkdirSync as mkdirSync11, openSync, readFileSync as readFileSync26, readdirSync as readdirSync6, renameSync as renameSync2, unlinkSync, writeFileSync as writeFileSync19 } from "node:fs";
|
|
11144
|
+
import { dirname as dirname8, isAbsolute as isAbsolute2, join as join31, relative as relative3, resolve as resolve24, sep as sep4 } from "node:path";
|
|
10863
11145
|
import { createHash as createHash5, randomUUID } from "node:crypto";
|
|
10864
11146
|
import ts5 from "typescript";
|
|
10865
11147
|
var PLATFORM3 = "linuxsteamrt64";
|
|
@@ -10986,11 +11268,11 @@ function hookOf(name, value, signatures, errors) {
|
|
|
10986
11268
|
}
|
|
10987
11269
|
function sourceFiles(dir, pkg, errors) {
|
|
10988
11270
|
const result = /* @__PURE__ */ new Set();
|
|
10989
|
-
const src =
|
|
11271
|
+
const src = join31(dir, "src");
|
|
10990
11272
|
function walk(at) {
|
|
10991
11273
|
if (!existsSync17(at)) return;
|
|
10992
|
-
for (const item of
|
|
10993
|
-
const p =
|
|
11274
|
+
for (const item of readdirSync6(at, { withFileTypes: true })) {
|
|
11275
|
+
const p = join31(at, item.name);
|
|
10994
11276
|
if (item.isDirectory()) walk(p);
|
|
10995
11277
|
else if (item.isFile() && /\.[cm]?[jt]sx?$/.test(item.name)) result.add(p);
|
|
10996
11278
|
}
|
|
@@ -11013,7 +11295,7 @@ function sourceFiles(dir, pkg, errors) {
|
|
|
11013
11295
|
return;
|
|
11014
11296
|
}
|
|
11015
11297
|
const stem = base.replace(/\.[cm]?[jt]sx?$/, "");
|
|
11016
|
-
const candidates = [base, ...[".ts", ".tsx", ".js", ".jsx", ".mts", ".mjs", ".cts", ".cjs"].map((x) => stem + x), ...["index.ts", "index.tsx", "index.js", "index.jsx"].map((x) =>
|
|
11298
|
+
const candidates = [base, ...[".ts", ".tsx", ".js", ".jsx", ".mts", ".mjs", ".cts", ".cjs"].map((x) => stem + x), ...["index.ts", "index.tsx", "index.js", "index.jsx"].map((x) => join31(base, x))];
|
|
11017
11299
|
const found = candidates.find((p) => contained(dir, p) && existsSync17(p) && lstatSync2(p).isFile());
|
|
11018
11300
|
if (!found) {
|
|
11019
11301
|
errors.push(`${at}: unresolved local module ${JSON.stringify(spec)}`);
|
|
@@ -11184,12 +11466,12 @@ function scanSource(files, calls, hooks, report) {
|
|
|
11184
11466
|
}
|
|
11185
11467
|
function analyzeV1Migration(pluginDir, options = {}) {
|
|
11186
11468
|
const dir = resolve24(pluginDir);
|
|
11187
|
-
const destination =
|
|
11469
|
+
const destination = join31(dir, "gamedata", "functions.jsonc");
|
|
11188
11470
|
const report = { scope: SCOPE, package: dir, destination, entries: [], permissions: [], sourceReferences: [], generatedDeclarations: [], generatedDeclarationHashes: {}, recommendedEdits: [], ambiguities: [], filesChanged: [] };
|
|
11189
11471
|
if (pathExists(destination) && !options.force) report.ambiguities.push(`${destination}: destination already exists; use --force to replace it`);
|
|
11190
11472
|
let pkg;
|
|
11191
11473
|
try {
|
|
11192
|
-
pkg = parseFunctionFile(
|
|
11474
|
+
pkg = parseFunctionFile(join31(dir, "package.json"), readFileSync26(join31(dir, "package.json"), "utf8"));
|
|
11193
11475
|
} catch (e) {
|
|
11194
11476
|
report.ambiguities.push(`package.json: ${e.message}`);
|
|
11195
11477
|
return report;
|
|
@@ -11311,7 +11593,7 @@ function analyzeV1Migration(pluginDir, options = {}) {
|
|
|
11311
11593
|
}
|
|
11312
11594
|
}
|
|
11313
11595
|
report.output = author;
|
|
11314
|
-
report.generatedDeclarations = ["gamedata.d.ts", "hooks.d.ts"].map((n3) =>
|
|
11596
|
+
report.generatedDeclarations = ["gamedata.d.ts", "hooks.d.ts"].map((n3) => join31(dir, ".s2script", n3)).filter(existsSync17);
|
|
11315
11597
|
for (const file of report.generatedDeclarations) {
|
|
11316
11598
|
try {
|
|
11317
11599
|
report.generatedDeclarationHashes[file] = createHash5("sha256").update(readFileSync26(file)).digest("hex");
|
|
@@ -11333,12 +11615,12 @@ function migrateV1Package(pluginDir, options = {}) {
|
|
|
11333
11615
|
const report = analyzeV1Migration(pluginDir, options);
|
|
11334
11616
|
if (report.ambiguities.length || !report.output) return report;
|
|
11335
11617
|
const dest = report.destination;
|
|
11336
|
-
const temp =
|
|
11618
|
+
const temp = join31(dirname8(dest), `.functions.jsonc.${process.pid}.${randomUUID()}.tmp`);
|
|
11337
11619
|
try {
|
|
11338
11620
|
mkdirSync11(dirname8(dest), { recursive: true });
|
|
11339
11621
|
const fd2 = openSync(temp, "wx", 384);
|
|
11340
11622
|
try {
|
|
11341
|
-
|
|
11623
|
+
writeFileSync19(fd2, JSON.stringify(report.output, null, 2) + "\n");
|
|
11342
11624
|
} finally {
|
|
11343
11625
|
closeSync(fd2);
|
|
11344
11626
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@s2script/sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.28.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",
|