toiljs 0.0.123 → 0.0.125
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/CHANGELOG.md +9 -0
- package/README.md +14 -10
- package/build/cli/.tsbuildinfo +1 -1
- package/build/cli/index.js +474 -230
- package/build/client/.tsbuildinfo +1 -1
- package/build/client/auth.d.ts +2 -0
- package/build/client/auth.js +7 -0
- package/build/compiler/.tsbuildinfo +1 -1
- package/build/compiler/generate.js +1 -1
- package/build/compiler/index.js +2 -0
- package/build/compiler/toil-docs.generated.js +13 -13
- package/build/devserver/.tsbuildinfo +1 -1
- package/build/devserver/daemon/index.d.ts +4 -0
- package/build/devserver/daemon/index.js +84 -2
- package/build/devserver/db/database.d.ts +11 -2
- package/build/devserver/db/database.js +227 -22
- package/build/devserver/db/limits.d.ts +6 -0
- package/build/devserver/db/limits.js +118 -0
- package/build/devserver/db/materialization.d.ts +4 -0
- package/build/devserver/db/materialization.js +25 -0
- package/build/devserver/db/types.d.ts +3 -0
- package/build/devserver/db/types.js +1 -0
- package/build/devserver/runtime/host.js +17 -0
- package/build/devserver/runtime/module.d.ts +4 -0
- package/build/devserver/runtime/module.js +47 -9
- package/build/devserver/wasm/envelope-window.d.ts +1 -0
- package/build/devserver/wasm/envelope-window.js +64 -0
- package/build/testing/.tsbuildinfo +1 -1
- package/package.json +3 -3
- package/server/auth/AuthController.ts +265 -61
- package/server/runtime/response.ts +12 -4
package/build/cli/index.js
CHANGED
|
@@ -650,11 +650,11 @@ var require_valid = __commonJS({
|
|
|
650
650
|
"node_modules/semver/functions/valid.js"(exports, module) {
|
|
651
651
|
"use strict";
|
|
652
652
|
var parse = require_parse();
|
|
653
|
-
var
|
|
653
|
+
var valid2 = (version2, options) => {
|
|
654
654
|
const v = parse(version2, options);
|
|
655
655
|
return v ? v.version : null;
|
|
656
656
|
};
|
|
657
|
-
module.exports =
|
|
657
|
+
module.exports = valid2;
|
|
658
658
|
}
|
|
659
659
|
});
|
|
660
660
|
|
|
@@ -871,8 +871,8 @@ var require_eq = __commonJS({
|
|
|
871
871
|
"node_modules/semver/functions/eq.js"(exports, module) {
|
|
872
872
|
"use strict";
|
|
873
873
|
var compare = require_compare();
|
|
874
|
-
var
|
|
875
|
-
module.exports =
|
|
874
|
+
var eq2 = (a2, b, loose) => compare(a2, b, loose) === 0;
|
|
875
|
+
module.exports = eq2;
|
|
876
876
|
}
|
|
877
877
|
});
|
|
878
878
|
|
|
@@ -910,7 +910,7 @@ var require_lte = __commonJS({
|
|
|
910
910
|
var require_cmp = __commonJS({
|
|
911
911
|
"node_modules/semver/functions/cmp.js"(exports, module) {
|
|
912
912
|
"use strict";
|
|
913
|
-
var
|
|
913
|
+
var eq2 = require_eq();
|
|
914
914
|
var neq = require_neq();
|
|
915
915
|
var gt = require_gt();
|
|
916
916
|
var gte = require_gte();
|
|
@@ -937,7 +937,7 @@ var require_cmp = __commonJS({
|
|
|
937
937
|
case "":
|
|
938
938
|
case "=":
|
|
939
939
|
case "==":
|
|
940
|
-
return
|
|
940
|
+
return eq2(a2, b, loose);
|
|
941
941
|
case "!=":
|
|
942
942
|
return neq(a2, b, loose);
|
|
943
943
|
case ">":
|
|
@@ -1584,7 +1584,7 @@ var require_satisfies = __commonJS({
|
|
|
1584
1584
|
"node_modules/semver/functions/satisfies.js"(exports, module) {
|
|
1585
1585
|
"use strict";
|
|
1586
1586
|
var Range = require_range();
|
|
1587
|
-
var
|
|
1587
|
+
var satisfies4 = (version2, range, options) => {
|
|
1588
1588
|
try {
|
|
1589
1589
|
range = new Range(range, options);
|
|
1590
1590
|
} catch (er) {
|
|
@@ -1592,7 +1592,7 @@ var require_satisfies = __commonJS({
|
|
|
1592
1592
|
}
|
|
1593
1593
|
return range.test(version2);
|
|
1594
1594
|
};
|
|
1595
|
-
module.exports =
|
|
1595
|
+
module.exports = satisfies4;
|
|
1596
1596
|
}
|
|
1597
1597
|
});
|
|
1598
1598
|
|
|
@@ -1728,14 +1728,14 @@ var require_valid2 = __commonJS({
|
|
|
1728
1728
|
"node_modules/semver/ranges/valid.js"(exports, module) {
|
|
1729
1729
|
"use strict";
|
|
1730
1730
|
var Range = require_range();
|
|
1731
|
-
var
|
|
1731
|
+
var validRange4 = (range, options) => {
|
|
1732
1732
|
try {
|
|
1733
1733
|
return new Range(range, options).range || "*";
|
|
1734
1734
|
} catch (er) {
|
|
1735
1735
|
return null;
|
|
1736
1736
|
}
|
|
1737
1737
|
};
|
|
1738
|
-
module.exports =
|
|
1738
|
+
module.exports = validRange4;
|
|
1739
1739
|
}
|
|
1740
1740
|
});
|
|
1741
1741
|
|
|
@@ -1747,7 +1747,7 @@ var require_outside = __commonJS({
|
|
|
1747
1747
|
var Comparator = require_comparator();
|
|
1748
1748
|
var { ANY } = Comparator;
|
|
1749
1749
|
var Range = require_range();
|
|
1750
|
-
var
|
|
1750
|
+
var satisfies4 = require_satisfies();
|
|
1751
1751
|
var gt = require_gt();
|
|
1752
1752
|
var lt = require_lt();
|
|
1753
1753
|
var lte = require_lte();
|
|
@@ -1774,7 +1774,7 @@ var require_outside = __commonJS({
|
|
|
1774
1774
|
default:
|
|
1775
1775
|
throw new TypeError('Must provide a hilo val of "<" or ">"');
|
|
1776
1776
|
}
|
|
1777
|
-
if (
|
|
1777
|
+
if (satisfies4(version2, range, options)) {
|
|
1778
1778
|
return false;
|
|
1779
1779
|
}
|
|
1780
1780
|
for (let i2 = 0; i2 < range.set.length; ++i2) {
|
|
@@ -1833,12 +1833,12 @@ var require_intersects = __commonJS({
|
|
|
1833
1833
|
"node_modules/semver/ranges/intersects.js"(exports, module) {
|
|
1834
1834
|
"use strict";
|
|
1835
1835
|
var Range = require_range();
|
|
1836
|
-
var
|
|
1836
|
+
var intersects2 = (r1, r2, options) => {
|
|
1837
1837
|
r1 = new Range(r1, options);
|
|
1838
1838
|
r2 = new Range(r2, options);
|
|
1839
1839
|
return r1.intersects(r2, options);
|
|
1840
1840
|
};
|
|
1841
|
-
module.exports =
|
|
1841
|
+
module.exports = intersects2;
|
|
1842
1842
|
}
|
|
1843
1843
|
});
|
|
1844
1844
|
|
|
@@ -1846,7 +1846,7 @@ var require_intersects = __commonJS({
|
|
|
1846
1846
|
var require_simplify = __commonJS({
|
|
1847
1847
|
"node_modules/semver/ranges/simplify.js"(exports, module) {
|
|
1848
1848
|
"use strict";
|
|
1849
|
-
var
|
|
1849
|
+
var satisfies4 = require_satisfies();
|
|
1850
1850
|
var compare = require_compare();
|
|
1851
1851
|
module.exports = (versions, range, options) => {
|
|
1852
1852
|
const set = [];
|
|
@@ -1854,7 +1854,7 @@ var require_simplify = __commonJS({
|
|
|
1854
1854
|
let prev = null;
|
|
1855
1855
|
const v = versions.sort((a2, b) => compare(a2, b, options));
|
|
1856
1856
|
for (const version2 of v) {
|
|
1857
|
-
const included =
|
|
1857
|
+
const included = satisfies4(version2, range, options);
|
|
1858
1858
|
if (included) {
|
|
1859
1859
|
prev = version2;
|
|
1860
1860
|
if (!first) {
|
|
@@ -1899,9 +1899,9 @@ var require_subset = __commonJS({
|
|
|
1899
1899
|
var Range = require_range();
|
|
1900
1900
|
var Comparator = require_comparator();
|
|
1901
1901
|
var { ANY } = Comparator;
|
|
1902
|
-
var
|
|
1902
|
+
var satisfies4 = require_satisfies();
|
|
1903
1903
|
var compare = require_compare();
|
|
1904
|
-
var
|
|
1904
|
+
var subset3 = (sub, dom, options = {}) => {
|
|
1905
1905
|
if (sub === dom) {
|
|
1906
1906
|
return true;
|
|
1907
1907
|
}
|
|
@@ -1967,15 +1967,15 @@ var require_subset = __commonJS({
|
|
|
1967
1967
|
return null;
|
|
1968
1968
|
}
|
|
1969
1969
|
}
|
|
1970
|
-
for (const
|
|
1971
|
-
if (gt && !
|
|
1970
|
+
for (const eq2 of eqSet) {
|
|
1971
|
+
if (gt && !satisfies4(eq2, String(gt), options)) {
|
|
1972
1972
|
return null;
|
|
1973
1973
|
}
|
|
1974
|
-
if (lt && !
|
|
1974
|
+
if (lt && !satisfies4(eq2, String(lt), options)) {
|
|
1975
1975
|
return null;
|
|
1976
1976
|
}
|
|
1977
1977
|
for (const c2 of dom) {
|
|
1978
|
-
if (!
|
|
1978
|
+
if (!satisfies4(eq2, String(c2), options)) {
|
|
1979
1979
|
return false;
|
|
1980
1980
|
}
|
|
1981
1981
|
}
|
|
@@ -2050,7 +2050,7 @@ var require_subset = __commonJS({
|
|
|
2050
2050
|
const comp = compare(a2.semver, b.semver, options);
|
|
2051
2051
|
return comp < 0 ? a2 : comp > 0 ? b : b.operator === "<" && a2.operator === "<=" ? b : a2;
|
|
2052
2052
|
};
|
|
2053
|
-
module.exports =
|
|
2053
|
+
module.exports = subset3;
|
|
2054
2054
|
}
|
|
2055
2055
|
});
|
|
2056
2056
|
|
|
@@ -2063,7 +2063,7 @@ var require_semver2 = __commonJS({
|
|
|
2063
2063
|
var SemVer = require_semver();
|
|
2064
2064
|
var identifiers = require_identifiers();
|
|
2065
2065
|
var parse = require_parse();
|
|
2066
|
-
var
|
|
2066
|
+
var valid2 = require_valid();
|
|
2067
2067
|
var clean2 = require_clean();
|
|
2068
2068
|
var inc = require_inc();
|
|
2069
2069
|
var diff = require_diff();
|
|
@@ -2079,7 +2079,7 @@ var require_semver2 = __commonJS({
|
|
|
2079
2079
|
var rsort = require_rsort();
|
|
2080
2080
|
var gt = require_gt();
|
|
2081
2081
|
var lt = require_lt();
|
|
2082
|
-
var
|
|
2082
|
+
var eq2 = require_eq();
|
|
2083
2083
|
var neq = require_neq();
|
|
2084
2084
|
var gte = require_gte();
|
|
2085
2085
|
var lte = require_lte();
|
|
@@ -2088,21 +2088,21 @@ var require_semver2 = __commonJS({
|
|
|
2088
2088
|
var truncate = require_truncate();
|
|
2089
2089
|
var Comparator = require_comparator();
|
|
2090
2090
|
var Range = require_range();
|
|
2091
|
-
var
|
|
2091
|
+
var satisfies4 = require_satisfies();
|
|
2092
2092
|
var toComparators = require_to_comparators();
|
|
2093
2093
|
var maxSatisfying = require_max_satisfying();
|
|
2094
2094
|
var minSatisfying = require_min_satisfying();
|
|
2095
2095
|
var minVersion2 = require_min_version();
|
|
2096
|
-
var
|
|
2096
|
+
var validRange4 = require_valid2();
|
|
2097
2097
|
var outside = require_outside();
|
|
2098
2098
|
var gtr = require_gtr();
|
|
2099
2099
|
var ltr = require_ltr();
|
|
2100
|
-
var
|
|
2100
|
+
var intersects2 = require_intersects();
|
|
2101
2101
|
var simplifyRange = require_simplify();
|
|
2102
|
-
var
|
|
2102
|
+
var subset3 = require_subset();
|
|
2103
2103
|
module.exports = {
|
|
2104
2104
|
parse,
|
|
2105
|
-
valid,
|
|
2105
|
+
valid: valid2,
|
|
2106
2106
|
clean: clean2,
|
|
2107
2107
|
inc,
|
|
2108
2108
|
diff,
|
|
@@ -2118,7 +2118,7 @@ var require_semver2 = __commonJS({
|
|
|
2118
2118
|
rsort,
|
|
2119
2119
|
gt,
|
|
2120
2120
|
lt,
|
|
2121
|
-
eq,
|
|
2121
|
+
eq: eq2,
|
|
2122
2122
|
neq,
|
|
2123
2123
|
gte,
|
|
2124
2124
|
lte,
|
|
@@ -2127,18 +2127,18 @@ var require_semver2 = __commonJS({
|
|
|
2127
2127
|
truncate,
|
|
2128
2128
|
Comparator,
|
|
2129
2129
|
Range,
|
|
2130
|
-
satisfies:
|
|
2130
|
+
satisfies: satisfies4,
|
|
2131
2131
|
toComparators,
|
|
2132
2132
|
maxSatisfying,
|
|
2133
2133
|
minSatisfying,
|
|
2134
2134
|
minVersion: minVersion2,
|
|
2135
|
-
validRange:
|
|
2135
|
+
validRange: validRange4,
|
|
2136
2136
|
outside,
|
|
2137
2137
|
gtr,
|
|
2138
2138
|
ltr,
|
|
2139
|
-
intersects,
|
|
2139
|
+
intersects: intersects2,
|
|
2140
2140
|
simplifyRange,
|
|
2141
|
-
subset:
|
|
2141
|
+
subset: subset3,
|
|
2142
2142
|
SemVer,
|
|
2143
2143
|
re: internalRe.re,
|
|
2144
2144
|
src: internalRe.src,
|
|
@@ -4149,7 +4149,7 @@ function scaffold(name, template, features, aiTools, images) {
|
|
|
4149
4149
|
oxlint: "^1.87.0",
|
|
4150
4150
|
"oxlint-tsgolint": "^7.0.2003",
|
|
4151
4151
|
prettier: "^3.9.9",
|
|
4152
|
-
toilscript: ">=0.1.
|
|
4152
|
+
toilscript: ">=0.1.64",
|
|
4153
4153
|
typescript: "^7.0.2"
|
|
4154
4154
|
};
|
|
4155
4155
|
for (const dep of requiredPackages(features).sort()) {
|
|
@@ -4525,9 +4525,9 @@ async function runCreate(opts2) {
|
|
|
4525
4525
|
name = answer.trim() || "my-toil-app";
|
|
4526
4526
|
}
|
|
4527
4527
|
}
|
|
4528
|
-
const
|
|
4529
|
-
if (
|
|
4530
|
-
cancel(
|
|
4528
|
+
const valid2 = isValidName(name);
|
|
4529
|
+
if (valid2 !== true) {
|
|
4530
|
+
cancel(valid2);
|
|
4531
4531
|
process.exit(1);
|
|
4532
4532
|
}
|
|
4533
4533
|
const targetDir = resolveProjectDir(opts2.cwd, name);
|
|
@@ -4838,9 +4838,9 @@ function runDb(action, fileArg, opts2) {
|
|
|
4838
4838
|
}
|
|
4839
4839
|
|
|
4840
4840
|
// src/cli/doctor.ts
|
|
4841
|
-
import
|
|
4842
|
-
import { createRequire } from "node:module";
|
|
4843
|
-
import
|
|
4841
|
+
import fs6 from "node:fs";
|
|
4842
|
+
import { createRequire as createRequire2 } from "node:module";
|
|
4843
|
+
import path7 from "node:path";
|
|
4844
4844
|
import { fileURLToPath as fileURLToPath3, pathToFileURL } from "node:url";
|
|
4845
4845
|
import {
|
|
4846
4846
|
loadConfig as loadConfig2,
|
|
@@ -5164,7 +5164,7 @@ function checkWasmBuilt(exists) {
|
|
|
5164
5164
|
fix: "Run your server build (toilscript) before toiljs start."
|
|
5165
5165
|
};
|
|
5166
5166
|
}
|
|
5167
|
-
var RPC_TOILSCRIPT_MIN = "0.1.
|
|
5167
|
+
var RPC_TOILSCRIPT_MIN = "0.1.64";
|
|
5168
5168
|
function checkRpcWiring(f) {
|
|
5169
5169
|
const missing = [];
|
|
5170
5170
|
if (!f.toilscriptOk) missing.push(`toilscript >=${RPC_TOILSCRIPT_MIN}`);
|
|
@@ -5250,10 +5250,240 @@ function hasFailures(summary) {
|
|
|
5250
5250
|
return summary.fail > 0;
|
|
5251
5251
|
}
|
|
5252
5252
|
|
|
5253
|
+
// src/cli/test-setup.ts
|
|
5254
|
+
import fs5 from "node:fs/promises";
|
|
5255
|
+
import path6 from "node:path";
|
|
5256
|
+
import { createRequire } from "node:module";
|
|
5257
|
+
var import_semver3 = __toESM(require_semver2(), 1);
|
|
5258
|
+
|
|
5259
|
+
// src/cli/testing-versions.ts
|
|
5260
|
+
var import_semver2 = __toESM(require_semver2(), 1);
|
|
5261
|
+
function isSupportedTestingRange(name, range) {
|
|
5262
|
+
const supported = TEST_DEPENDENCIES[name];
|
|
5263
|
+
return supported === void 0 || (0, import_semver2.validRange)(range) !== null && (0, import_semver2.subset)(range, supported);
|
|
5264
|
+
}
|
|
5265
|
+
function isTestingSource(range) {
|
|
5266
|
+
return /^(file:|workspace:|link:|git[+:]|https?:|github:|npm:)/.test(range);
|
|
5267
|
+
}
|
|
5268
|
+
|
|
5269
|
+
// src/cli/test-setup.ts
|
|
5270
|
+
async function findTestConfiguration(root) {
|
|
5271
|
+
const files = await fs5.readdir(root);
|
|
5272
|
+
const custom = files.find((file) => /^vitest\.config\.[cm]?[jt]s$/.test(file)) ?? files.find((file) => /^vite\.config\.[cm]?[jt]s$/.test(file));
|
|
5273
|
+
const source = custom === void 0 ? "" : await fs5.readFile(path6.join(root, custom), "utf8");
|
|
5274
|
+
const native = custom === void 0 || source.includes("from 'toiljs/vitest'") || source.includes('from "toiljs/vitest"');
|
|
5275
|
+
return { file: custom ?? null, native };
|
|
5276
|
+
}
|
|
5277
|
+
async function writeMissing(root, file, content) {
|
|
5278
|
+
const target = path6.join(root, file);
|
|
5279
|
+
await fs5.mkdir(path6.dirname(target), { recursive: true });
|
|
5280
|
+
try {
|
|
5281
|
+
await fs5.writeFile(target, content, { flag: "wx" });
|
|
5282
|
+
return true;
|
|
5283
|
+
} catch (error) {
|
|
5284
|
+
if (!(error instanceof Error) || !("code" in error) || error.code !== "EEXIST") throw error;
|
|
5285
|
+
return false;
|
|
5286
|
+
}
|
|
5287
|
+
}
|
|
5288
|
+
async function ensureTesting(root, repairVersions = false) {
|
|
5289
|
+
const pkgPath = path6.join(root, "package.json");
|
|
5290
|
+
const raw = JSON.parse(await fs5.readFile(pkgPath, "utf8"));
|
|
5291
|
+
if (raw === null || typeof raw !== "object" || Array.isArray(raw))
|
|
5292
|
+
throw new Error("toiljs test: package.json must contain an object.");
|
|
5293
|
+
const pkg = raw;
|
|
5294
|
+
for (const field of [pkg.scripts, pkg.dependencies, pkg.devDependencies]) {
|
|
5295
|
+
if (field !== void 0 && (field === null || typeof field !== "object" || Array.isArray(field) || Object.values(field).some((value) => typeof value !== "string")))
|
|
5296
|
+
throw new Error("toiljs test: package scripts and dependencies must be string maps.");
|
|
5297
|
+
}
|
|
5298
|
+
const config = await findTestConfiguration(root);
|
|
5299
|
+
const { native } = config;
|
|
5300
|
+
const changes = [];
|
|
5301
|
+
const skipped = [];
|
|
5302
|
+
let changed = false;
|
|
5303
|
+
let install = false;
|
|
5304
|
+
const require2 = createRequire(pkgPath);
|
|
5305
|
+
for (const [name, range] of Object.entries(TEST_DEPENDENCIES)) {
|
|
5306
|
+
for (const dependencies of [pkg.dependencies, pkg.devDependencies]) {
|
|
5307
|
+
const declared = dependencies?.[name];
|
|
5308
|
+
if (repairVersions && dependencies && declared && !isSupportedTestingRange(name, declared) && !isTestingSource(declared)) {
|
|
5309
|
+
dependencies[name] = range;
|
|
5310
|
+
changes.push(`package.json (${name} ${declared} -> ${range})`);
|
|
5311
|
+
changed = true;
|
|
5312
|
+
install = true;
|
|
5313
|
+
}
|
|
5314
|
+
}
|
|
5315
|
+
if (pkg.dependencies?.[name] === void 0 && pkg.devDependencies?.[name] === void 0) {
|
|
5316
|
+
pkg.devDependencies ??= {};
|
|
5317
|
+
pkg.devDependencies[name] = range;
|
|
5318
|
+
changes.push(`package.json (add ${name})`);
|
|
5319
|
+
changed = true;
|
|
5320
|
+
install = true;
|
|
5321
|
+
}
|
|
5322
|
+
try {
|
|
5323
|
+
require2.resolve(name);
|
|
5324
|
+
} catch {
|
|
5325
|
+
install = true;
|
|
5326
|
+
}
|
|
5327
|
+
}
|
|
5328
|
+
if (repairVersions) {
|
|
5329
|
+
const runnerRange = pkg.dependencies?.vitest ?? pkg.devDependencies?.vitest;
|
|
5330
|
+
const coverageDependencies = pkg.dependencies?.["@vitest/coverage-v8"] !== void 0 ? pkg.dependencies : pkg.devDependencies;
|
|
5331
|
+
if (runnerRange && isSupportedTestingRange("vitest", runnerRange) && coverageDependencies && (0, import_semver3.validRange)(coverageDependencies["@vitest/coverage-v8"] ?? "") !== null) {
|
|
5332
|
+
const installedRunner = await testVersion(require2, "vitest");
|
|
5333
|
+
const installedCoverage = await testVersion(
|
|
5334
|
+
require2,
|
|
5335
|
+
"@vitest/coverage-v8"
|
|
5336
|
+
);
|
|
5337
|
+
const target = installedRunner && installedCoverage && installedRunner !== installedCoverage && (0, import_semver3.satisfies)(installedRunner, runnerRange) ? installedRunner : (0, import_semver3.intersects)(coverageDependencies["@vitest/coverage-v8"], runnerRange) ? coverageDependencies["@vitest/coverage-v8"] : runnerRange;
|
|
5338
|
+
if (coverageDependencies["@vitest/coverage-v8"] !== target) {
|
|
5339
|
+
coverageDependencies["@vitest/coverage-v8"] = target;
|
|
5340
|
+
changes.push("package.json (align V8 coverage with Vitest)");
|
|
5341
|
+
changed = true;
|
|
5342
|
+
install = true;
|
|
5343
|
+
}
|
|
5344
|
+
if (installedRunner && installedCoverage && installedRunner !== installedCoverage)
|
|
5345
|
+
install = true;
|
|
5346
|
+
}
|
|
5347
|
+
}
|
|
5348
|
+
pkg.scripts ??= {};
|
|
5349
|
+
for (const [name, script] of Object.entries(TEST_SCRIPTS)) {
|
|
5350
|
+
if (pkg.scripts[name]?.trim()) continue;
|
|
5351
|
+
pkg.scripts[name] = script;
|
|
5352
|
+
changes.push(`package.json (add script ${name})`);
|
|
5353
|
+
changed = true;
|
|
5354
|
+
}
|
|
5355
|
+
if (changed) await fs5.writeFile(pkgPath, JSON.stringify(raw, null, 4) + "\n");
|
|
5356
|
+
if (config.file === null) {
|
|
5357
|
+
for (const [file, content] of Object.entries(testingFiles()))
|
|
5358
|
+
if (await writeMissing(root, file, content)) changes.push(file);
|
|
5359
|
+
}
|
|
5360
|
+
if (native) await includeTestTypes(root, config.file ?? "vitest.config.ts", changes, skipped);
|
|
5361
|
+
await ignoreTestReports(root, changes);
|
|
5362
|
+
return { install, native, changed: changes, skipped };
|
|
5363
|
+
}
|
|
5364
|
+
async function includeTestTypes(root, config, changes, skipped) {
|
|
5365
|
+
const file = path6.join(root, "tsconfig.json");
|
|
5366
|
+
let source;
|
|
5367
|
+
try {
|
|
5368
|
+
source = await fs5.readFile(file, "utf8");
|
|
5369
|
+
} catch (error) {
|
|
5370
|
+
if (error instanceof Error && "code" in error && error.code === "ENOENT") return;
|
|
5371
|
+
throw error;
|
|
5372
|
+
}
|
|
5373
|
+
try {
|
|
5374
|
+
const raw = JSON.parse(source);
|
|
5375
|
+
if (raw === null || typeof raw !== "object" || Array.isArray(raw))
|
|
5376
|
+
throw new Error("Expected an object");
|
|
5377
|
+
const parsed = raw;
|
|
5378
|
+
if (!isStringArray(parsed.include)) {
|
|
5379
|
+
skipped.push(
|
|
5380
|
+
"tsconfig.json: include tests and the Vitest config in your existing file selection."
|
|
5381
|
+
);
|
|
5382
|
+
return;
|
|
5383
|
+
}
|
|
5384
|
+
const include = parsed.include;
|
|
5385
|
+
const missing = ["tests", config].filter(
|
|
5386
|
+
(entry) => !include.includes(entry)
|
|
5387
|
+
);
|
|
5388
|
+
if (!missing.length) return;
|
|
5389
|
+
include.push(...missing);
|
|
5390
|
+
await fs5.writeFile(file, JSON.stringify(parsed, null, 4) + "\n");
|
|
5391
|
+
changes.push("tsconfig.json (include tests and Vitest config)");
|
|
5392
|
+
} catch {
|
|
5393
|
+
skipped.push(
|
|
5394
|
+
"tsconfig.json: include tests and the Vitest config manually; custom JSON was preserved."
|
|
5395
|
+
);
|
|
5396
|
+
}
|
|
5397
|
+
}
|
|
5398
|
+
async function ignoreTestReports(root, changes) {
|
|
5399
|
+
const file = path6.join(root, ".gitignore");
|
|
5400
|
+
let source = "";
|
|
5401
|
+
try {
|
|
5402
|
+
source = await fs5.readFile(file, "utf8");
|
|
5403
|
+
} catch (error) {
|
|
5404
|
+
if (!(error instanceof Error) || !("code" in error) || error.code !== "ENOENT") throw error;
|
|
5405
|
+
}
|
|
5406
|
+
const lines = source.split(/\r?\n/).map((line) => line.trim().replace(/\/$/, ""));
|
|
5407
|
+
const missing = ["coverage", ".vitest"].filter(
|
|
5408
|
+
(entry) => !lines.includes(entry) && !lines.includes("/" + entry)
|
|
5409
|
+
);
|
|
5410
|
+
if (!missing.length) return;
|
|
5411
|
+
await fs5.writeFile(
|
|
5412
|
+
file,
|
|
5413
|
+
source + (source && !source.endsWith("\n") ? "\n" : "") + missing.join("\n") + "\n"
|
|
5414
|
+
);
|
|
5415
|
+
changes.push(".gitignore (test reports)");
|
|
5416
|
+
}
|
|
5417
|
+
async function testVersion(require2, name) {
|
|
5418
|
+
try {
|
|
5419
|
+
const raw = JSON.parse(
|
|
5420
|
+
await fs5.readFile(require2.resolve(`${name}/package.json`), "utf8")
|
|
5421
|
+
);
|
|
5422
|
+
return raw !== null && typeof raw === "object" && "version" in raw && typeof raw.version === "string" ? raw.version : null;
|
|
5423
|
+
} catch {
|
|
5424
|
+
return null;
|
|
5425
|
+
}
|
|
5426
|
+
}
|
|
5427
|
+
function isStringArray(value) {
|
|
5428
|
+
return Array.isArray(value) && value.every((entry) => typeof entry === "string");
|
|
5429
|
+
}
|
|
5430
|
+
|
|
5431
|
+
// src/cli/testing-checks.ts
|
|
5432
|
+
var import_semver4 = __toESM(require_semver2(), 1);
|
|
5433
|
+
function checkTesting(facts) {
|
|
5434
|
+
const configured = Object.keys(TEST_DEPENDENCIES).some(
|
|
5435
|
+
(name) => facts.dependencies[name] !== void 0
|
|
5436
|
+
) || facts.configuration.file?.startsWith("vitest.config.") === true;
|
|
5437
|
+
const repair = "Run `toiljs doctor --fix`, then your package manager install (or `toiljs test` to install missing tooling).";
|
|
5438
|
+
const checks = Object.entries(TEST_DEPENDENCIES).map(([name, range]) => {
|
|
5439
|
+
const installed = facts.installed[name] ?? null;
|
|
5440
|
+
const declared = facts.dependencies[name];
|
|
5441
|
+
const ok = installed !== null && declared !== void 0 && (0, import_semver4.satisfies)(installed, range) && (isSupportedTestingRange(name, declared) || isTestingSource(declared));
|
|
5442
|
+
return {
|
|
5443
|
+
id: `testing:${name}`,
|
|
5444
|
+
label: name,
|
|
5445
|
+
status: ok ? "pass" : configured ? "fail" : "warn",
|
|
5446
|
+
detail: `${installed ?? "not installed"}; declared ${declared ?? "missing"} (requires ${range})`,
|
|
5447
|
+
fix: ok ? void 0 : repair
|
|
5448
|
+
};
|
|
5449
|
+
});
|
|
5450
|
+
const runner = facts.installed.vitest ?? null;
|
|
5451
|
+
const coverage = facts.installed["@vitest/coverage-v8"] ?? null;
|
|
5452
|
+
if (runner !== null && coverage !== null) {
|
|
5453
|
+
const match = (0, import_semver4.valid)(runner) !== null && (0, import_semver4.valid)(coverage) !== null && (0, import_semver4.eq)(runner, coverage);
|
|
5454
|
+
checks.push({
|
|
5455
|
+
id: "testing:coverage-match",
|
|
5456
|
+
label: "Vitest / V8 coverage versions",
|
|
5457
|
+
status: match ? "pass" : "fail",
|
|
5458
|
+
detail: `vitest ${runner}, @vitest/coverage-v8 ${coverage}`,
|
|
5459
|
+
fix: match ? void 0 : "Install matching versions of vitest and @vitest/coverage-v8; run `toiljs update --yes` to refresh both."
|
|
5460
|
+
});
|
|
5461
|
+
}
|
|
5462
|
+
const configPresent = facts.configuration.file !== null;
|
|
5463
|
+
checks.push({
|
|
5464
|
+
id: "testing:config",
|
|
5465
|
+
label: "Vitest configuration",
|
|
5466
|
+
status: configPresent ? "pass" : "warn",
|
|
5467
|
+
detail: configPresent ? `${facts.configuration.file} (${facts.configuration.native ? "toiljs preset" : "custom, preserved"})` : "missing",
|
|
5468
|
+
fix: configPresent ? void 0 : repair
|
|
5469
|
+
});
|
|
5470
|
+
const missing = Object.keys(TEST_SCRIPTS).filter(
|
|
5471
|
+
(name) => !facts.scripts[name]?.trim()
|
|
5472
|
+
);
|
|
5473
|
+
checks.push({
|
|
5474
|
+
id: "testing:scripts",
|
|
5475
|
+
label: "Unit, browser, watch, and coverage scripts",
|
|
5476
|
+
status: missing.length ? "warn" : "pass",
|
|
5477
|
+
detail: missing.length ? `missing ${missing.join(", ")}` : "configured",
|
|
5478
|
+
fix: missing.length ? repair : void 0
|
|
5479
|
+
});
|
|
5480
|
+
return checks;
|
|
5481
|
+
}
|
|
5482
|
+
|
|
5253
5483
|
// src/cli/doctor.ts
|
|
5254
5484
|
function readJsonObject(file) {
|
|
5255
5485
|
try {
|
|
5256
|
-
const parsed = JSON.parse(
|
|
5486
|
+
const parsed = JSON.parse(fs6.readFileSync(file, "utf8"));
|
|
5257
5487
|
return typeof parsed === "object" && parsed !== null ? parsed : null;
|
|
5258
5488
|
} catch {
|
|
5259
5489
|
return null;
|
|
@@ -5267,16 +5497,16 @@ function stringRecord(value) {
|
|
|
5267
5497
|
}
|
|
5268
5498
|
function readFile(file) {
|
|
5269
5499
|
try {
|
|
5270
|
-
return
|
|
5500
|
+
return fs6.readFileSync(file, "utf8");
|
|
5271
5501
|
} catch {
|
|
5272
5502
|
return null;
|
|
5273
5503
|
}
|
|
5274
5504
|
}
|
|
5275
5505
|
function writeFile(file, content) {
|
|
5276
|
-
|
|
5506
|
+
fs6.writeFileSync(file, content);
|
|
5277
5507
|
}
|
|
5278
5508
|
function isPackageInstalled(root, name) {
|
|
5279
|
-
const require2 =
|
|
5509
|
+
const require2 = createRequire2(path7.join(root, "package.json"));
|
|
5280
5510
|
for (const id of [`${name}/package.json`, name]) {
|
|
5281
5511
|
try {
|
|
5282
5512
|
require2.resolve(id);
|
|
@@ -5285,22 +5515,22 @@ function isPackageInstalled(root, name) {
|
|
|
5285
5515
|
}
|
|
5286
5516
|
}
|
|
5287
5517
|
for (let dir = root; ; ) {
|
|
5288
|
-
if (
|
|
5289
|
-
const parent =
|
|
5518
|
+
if (fs6.existsSync(path7.join(dir, "node_modules", name, "package.json"))) return true;
|
|
5519
|
+
const parent = path7.dirname(dir);
|
|
5290
5520
|
if (parent === dir) return false;
|
|
5291
5521
|
dir = parent;
|
|
5292
5522
|
}
|
|
5293
5523
|
}
|
|
5294
5524
|
function installedVersion(root, name) {
|
|
5295
|
-
const require2 =
|
|
5525
|
+
const require2 = createRequire2(path7.join(root, "package.json"));
|
|
5296
5526
|
let pkgPath = null;
|
|
5297
5527
|
try {
|
|
5298
5528
|
pkgPath = require2.resolve(`${name}/package.json`);
|
|
5299
5529
|
} catch {
|
|
5300
5530
|
for (let dir = root; pkgPath === null; ) {
|
|
5301
|
-
const candidate =
|
|
5302
|
-
if (
|
|
5303
|
-
const parent =
|
|
5531
|
+
const candidate = path7.join(dir, "node_modules", name, "package.json");
|
|
5532
|
+
if (fs6.existsSync(candidate)) pkgPath = candidate;
|
|
5533
|
+
const parent = path7.dirname(dir);
|
|
5304
5534
|
if (parent === dir) break;
|
|
5305
5535
|
dir = parent;
|
|
5306
5536
|
}
|
|
@@ -5312,7 +5542,7 @@ function installedVersion(root, name) {
|
|
|
5312
5542
|
function applyTypeScriptFix(root) {
|
|
5313
5543
|
const changed = [];
|
|
5314
5544
|
const skipped = [];
|
|
5315
|
-
const pkgPath =
|
|
5545
|
+
const pkgPath = path7.join(root, "package.json");
|
|
5316
5546
|
const pkg = readJsonObject(pkgPath);
|
|
5317
5547
|
if (pkg === null) return { changed, skipped };
|
|
5318
5548
|
let declared = false;
|
|
@@ -5350,14 +5580,14 @@ function looksLikeSemverRange(range) {
|
|
|
5350
5580
|
return /^\s*[v^~>=<]*\s*\d+\.\d+/.test(range);
|
|
5351
5581
|
}
|
|
5352
5582
|
function gatherRpcFacts(root) {
|
|
5353
|
-
const pkg = readJsonObject(
|
|
5583
|
+
const pkg = readJsonObject(path7.join(root, "package.json"));
|
|
5354
5584
|
const scripts = pkg ? stringRecord(pkg.scripts) : {};
|
|
5355
5585
|
const deps = {
|
|
5356
5586
|
...pkg ? stringRecord(pkg.dependencies) : {},
|
|
5357
5587
|
...pkg ? stringRecord(pkg.devDependencies) : {}
|
|
5358
5588
|
};
|
|
5359
|
-
const tsconfig = readJsonObject(
|
|
5360
|
-
const gitignore = readFile(
|
|
5589
|
+
const tsconfig = readJsonObject(path7.join(root, "tsconfig.json"));
|
|
5590
|
+
const gitignore = readFile(path7.join(root, ".gitignore"));
|
|
5361
5591
|
const buildServerWired = [scripts["build:server"], scripts["build"]].some(
|
|
5362
5592
|
(s) => typeof s === "string" && (s.includes("--rpcModule") || /\btoiljs\s+build\b/.test(s))
|
|
5363
5593
|
);
|
|
@@ -5376,7 +5606,7 @@ function gatherRpcFacts(root) {
|
|
|
5376
5606
|
function serverSources(root, toilconfig) {
|
|
5377
5607
|
const dirs = /* @__PURE__ */ new Set();
|
|
5378
5608
|
const entries = Array.isArray(toilconfig?.entries) ? toilconfig.entries.filter((e) => typeof e === "string") : [];
|
|
5379
|
-
for (const e of entries) dirs.add(
|
|
5609
|
+
for (const e of entries) dirs.add(path7.dirname(path7.resolve(root, e)));
|
|
5380
5610
|
const out2 = [];
|
|
5381
5611
|
const cap = 200;
|
|
5382
5612
|
const maxDepth = 16;
|
|
@@ -5384,13 +5614,13 @@ function serverSources(root, toilconfig) {
|
|
|
5384
5614
|
if (out2.length >= cap || depth > maxDepth) return;
|
|
5385
5615
|
let listing;
|
|
5386
5616
|
try {
|
|
5387
|
-
listing =
|
|
5617
|
+
listing = fs6.readdirSync(current, { withFileTypes: true });
|
|
5388
5618
|
} catch {
|
|
5389
5619
|
return;
|
|
5390
5620
|
}
|
|
5391
5621
|
for (const entry of listing) {
|
|
5392
5622
|
if (out2.length >= cap) break;
|
|
5393
|
-
const full =
|
|
5623
|
+
const full = path7.join(current, entry.name);
|
|
5394
5624
|
if (entry.isDirectory()) {
|
|
5395
5625
|
if (entry.name !== "node_modules") visit(full, depth + 1);
|
|
5396
5626
|
} else if (entry.name.endsWith(".ts") && !entry.name.endsWith(".d.ts")) {
|
|
@@ -5414,7 +5644,7 @@ function gatherRestFacts(root, toilconfig) {
|
|
|
5414
5644
|
return { hasControllers, dispatched };
|
|
5415
5645
|
}
|
|
5416
5646
|
function secretDefined(root, key) {
|
|
5417
|
-
const raw = readFile(
|
|
5647
|
+
const raw = readFile(path7.join(root, ".env.secrets"));
|
|
5418
5648
|
if (raw === null) return false;
|
|
5419
5649
|
return new RegExp(`^\\s*(?:export\\s+)?${key}\\s*=\\s*\\S`, "m").test(raw);
|
|
5420
5650
|
}
|
|
@@ -5431,21 +5661,21 @@ function gatherAuthFacts(root, toilconfig) {
|
|
|
5431
5661
|
function serverTsconfigPath(root, toilconfig) {
|
|
5432
5662
|
const dirs = /* @__PURE__ */ new Set();
|
|
5433
5663
|
const entries = Array.isArray(toilconfig?.entries) ? toilconfig.entries.filter((e) => typeof e === "string") : [];
|
|
5434
|
-
for (const e of entries) dirs.add(
|
|
5435
|
-
if (dirs.size === 0) dirs.add(
|
|
5664
|
+
for (const e of entries) dirs.add(path7.dirname(path7.resolve(root, e)));
|
|
5665
|
+
if (dirs.size === 0) dirs.add(path7.join(root, "server"));
|
|
5436
5666
|
for (const dir of dirs) {
|
|
5437
|
-
const p =
|
|
5438
|
-
if (
|
|
5667
|
+
const p = path7.join(dir, "tsconfig.json");
|
|
5668
|
+
if (fs6.existsSync(p)) return p;
|
|
5439
5669
|
}
|
|
5440
5670
|
return null;
|
|
5441
5671
|
}
|
|
5442
5672
|
function serverMigrationsExist(root, toilconfig) {
|
|
5443
5673
|
const dirs = /* @__PURE__ */ new Set();
|
|
5444
5674
|
const entries = Array.isArray(toilconfig?.entries) ? toilconfig.entries.filter((e) => typeof e === "string") : [];
|
|
5445
|
-
for (const e of entries) dirs.add(
|
|
5446
|
-
if (dirs.size === 0) dirs.add(
|
|
5675
|
+
for (const e of entries) dirs.add(path7.dirname(path7.resolve(root, e)));
|
|
5676
|
+
if (dirs.size === 0) dirs.add(path7.join(root, "server"));
|
|
5447
5677
|
for (const dir of dirs) {
|
|
5448
|
-
if (
|
|
5678
|
+
if (fs6.existsSync(path7.join(dir, "migrations"))) return true;
|
|
5449
5679
|
}
|
|
5450
5680
|
return false;
|
|
5451
5681
|
}
|
|
@@ -5460,7 +5690,7 @@ function tsconfigHasToilPlugin(tsconfig) {
|
|
|
5460
5690
|
function applyRpcFix(root) {
|
|
5461
5691
|
const changed = [];
|
|
5462
5692
|
const skipped = [];
|
|
5463
|
-
const pkgPath =
|
|
5693
|
+
const pkgPath = path7.join(root, "package.json");
|
|
5464
5694
|
const pkgRaw = readFile(pkgPath);
|
|
5465
5695
|
const pkg = pkgRaw !== null ? readJsonObject(pkgPath) : null;
|
|
5466
5696
|
if (pkg !== null) {
|
|
@@ -5499,7 +5729,7 @@ function applyRpcFix(root) {
|
|
|
5499
5729
|
} else if (pkgRaw !== null) {
|
|
5500
5730
|
skipped.push("package.json (unparseable)");
|
|
5501
5731
|
}
|
|
5502
|
-
const tsPath =
|
|
5732
|
+
const tsPath = path7.join(root, "tsconfig.json");
|
|
5503
5733
|
const tsRaw = readFile(tsPath);
|
|
5504
5734
|
const tsconfig = tsRaw !== null ? readJsonObject(tsPath) : null;
|
|
5505
5735
|
if (tsconfig !== null) {
|
|
@@ -5538,7 +5768,7 @@ function applyRpcFix(root) {
|
|
|
5538
5768
|
} else if (tsRaw !== null) {
|
|
5539
5769
|
skipped.push('tsconfig.json (JSON with comments, add "shared" + paths by hand)');
|
|
5540
5770
|
}
|
|
5541
|
-
const giPath =
|
|
5771
|
+
const giPath = path7.join(root, ".gitignore");
|
|
5542
5772
|
const giRaw = readFile(giPath);
|
|
5543
5773
|
if (giRaw === null) {
|
|
5544
5774
|
writeFile(giPath, `${RPC_GITIGNORE_LINE}
|
|
@@ -5550,21 +5780,21 @@ function applyRpcFix(root) {
|
|
|
5550
5780
|
`);
|
|
5551
5781
|
changed.push(".gitignore");
|
|
5552
5782
|
}
|
|
5553
|
-
const serverToilconfig = readJsonObject(
|
|
5783
|
+
const serverToilconfig = readJsonObject(path7.join(root, "toilconfig.json"));
|
|
5554
5784
|
if (serverToilconfig !== null) {
|
|
5555
5785
|
const entries = Array.isArray(serverToilconfig.entries) ? serverToilconfig.entries.filter(
|
|
5556
5786
|
(e) => typeof e === "string"
|
|
5557
5787
|
) : [];
|
|
5558
5788
|
const dirs = /* @__PURE__ */ new Set();
|
|
5559
|
-
for (const e of entries) dirs.add(
|
|
5560
|
-
if (dirs.size === 0) dirs.add(
|
|
5789
|
+
for (const e of entries) dirs.add(path7.dirname(path7.resolve(root, e)));
|
|
5790
|
+
if (dirs.size === 0) dirs.add(path7.join(root, "server"));
|
|
5561
5791
|
for (const dir of dirs) {
|
|
5562
|
-
const envPath =
|
|
5792
|
+
const envPath = path7.join(dir, "toil-server-env.d.ts");
|
|
5563
5793
|
if (readFile(envPath) !== TOIL_SERVER_ENV_DTS2) {
|
|
5564
5794
|
try {
|
|
5565
|
-
|
|
5795
|
+
fs6.mkdirSync(dir, { recursive: true });
|
|
5566
5796
|
writeFile(envPath, TOIL_SERVER_ENV_DTS2);
|
|
5567
|
-
changed.push(
|
|
5797
|
+
changed.push(path7.relative(root, envPath));
|
|
5568
5798
|
} catch {
|
|
5569
5799
|
}
|
|
5570
5800
|
}
|
|
@@ -5594,7 +5824,7 @@ function prettierPluginPresent(root, pkg) {
|
|
|
5594
5824
|
return true;
|
|
5595
5825
|
}
|
|
5596
5826
|
for (const name of PRETTIER_CONFIG_FILES) {
|
|
5597
|
-
const raw = readFile(
|
|
5827
|
+
const raw = readFile(path7.join(root, name));
|
|
5598
5828
|
if (raw !== null && PRETTIER_MENTION.test(raw)) return true;
|
|
5599
5829
|
}
|
|
5600
5830
|
return false;
|
|
@@ -5603,7 +5833,7 @@ function applyPrettierFix(root, pkg) {
|
|
|
5603
5833
|
const changed = [];
|
|
5604
5834
|
const skipped = [];
|
|
5605
5835
|
if (prettierPluginPresent(root, pkg)) return { changed, skipped };
|
|
5606
|
-
const pkgPath =
|
|
5836
|
+
const pkgPath = path7.join(root, "package.json");
|
|
5607
5837
|
const pkgConfig = pkg ? asRecord(pkg.prettier) : null;
|
|
5608
5838
|
if (pkgConfig !== null) {
|
|
5609
5839
|
const full = readJsonObject(pkgPath);
|
|
@@ -5619,7 +5849,7 @@ function applyPrettierFix(root, pkg) {
|
|
|
5619
5849
|
}
|
|
5620
5850
|
}
|
|
5621
5851
|
for (const name of [".prettierrc", ".prettierrc.json"]) {
|
|
5622
|
-
const filePath =
|
|
5852
|
+
const filePath = path7.join(root, name);
|
|
5623
5853
|
const raw = readFile(filePath);
|
|
5624
5854
|
if (raw === null) continue;
|
|
5625
5855
|
const obj = readJsonObject(filePath);
|
|
@@ -5635,13 +5865,13 @@ function applyPrettierFix(root, pkg) {
|
|
|
5635
5865
|
changed.push(name);
|
|
5636
5866
|
return { changed, skipped };
|
|
5637
5867
|
}
|
|
5638
|
-
const jsConfig = PRETTIER_CONFIG_FILES.find((name) => readFile(
|
|
5868
|
+
const jsConfig = PRETTIER_CONFIG_FILES.find((name) => readFile(path7.join(root, name)) !== null);
|
|
5639
5869
|
if (jsConfig) {
|
|
5640
5870
|
skipped.push(`${jsConfig} (add "${PRETTIER_PLUGIN}" to its plugins by hand)`);
|
|
5641
5871
|
return { changed, skipped };
|
|
5642
5872
|
}
|
|
5643
5873
|
writeFile(
|
|
5644
|
-
|
|
5874
|
+
path7.join(root, ".prettierrc.json"),
|
|
5645
5875
|
JSON.stringify({ plugins: [PRETTIER_PLUGIN] }, null, 4) + "\n"
|
|
5646
5876
|
);
|
|
5647
5877
|
changed.push(".prettierrc.json");
|
|
@@ -5655,7 +5885,7 @@ function applyServerEditorFix(root, toilconfig) {
|
|
|
5655
5885
|
const parsed = readJsonObject(tsPath);
|
|
5656
5886
|
if (parsed === null)
|
|
5657
5887
|
skipped.push(
|
|
5658
|
-
`${
|
|
5888
|
+
`${path7.relative(root, tsPath)} (remove legacy ts-plugin from JSONC manually)`
|
|
5659
5889
|
);
|
|
5660
5890
|
else if (tsconfigHasToilPlugin(parsed)) {
|
|
5661
5891
|
const co = asRecord(parsed.compilerOptions);
|
|
@@ -5667,12 +5897,12 @@ function applyServerEditorFix(root, toilconfig) {
|
|
|
5667
5897
|
if (plugins.length === 0) delete co.plugins;
|
|
5668
5898
|
else co.plugins = plugins;
|
|
5669
5899
|
writeFile(tsPath, JSON.stringify(parsed, null, 4) + "\n");
|
|
5670
|
-
changed.push(
|
|
5900
|
+
changed.push(path7.relative(root, tsPath));
|
|
5671
5901
|
}
|
|
5672
5902
|
}
|
|
5673
5903
|
}
|
|
5674
|
-
const vsPath =
|
|
5675
|
-
const vs =
|
|
5904
|
+
const vsPath = path7.join(root, ".vscode/settings.json");
|
|
5905
|
+
const vs = fs6.existsSync(vsPath) ? readJsonObject(vsPath) : {};
|
|
5676
5906
|
if (vs === null)
|
|
5677
5907
|
skipped.push(".vscode/settings.json (enable js/ts.experimental.useTsgo manually)");
|
|
5678
5908
|
else {
|
|
@@ -5681,7 +5911,7 @@ function applyServerEditorFix(root, toilconfig) {
|
|
|
5681
5911
|
delete vs["typescript.enablePromptUseWorkspaceTsdk"];
|
|
5682
5912
|
vs["js/ts.experimental.useTsgo"] = true;
|
|
5683
5913
|
if (JSON.stringify(vs) !== before) {
|
|
5684
|
-
|
|
5914
|
+
fs6.mkdirSync(path7.dirname(vsPath), { recursive: true });
|
|
5685
5915
|
writeFile(vsPath, JSON.stringify(vs, null, 4) + "\n");
|
|
5686
5916
|
changed.push(".vscode/settings.json");
|
|
5687
5917
|
}
|
|
@@ -5697,8 +5927,8 @@ async function checkNativeTypeScriptConfig(root) {
|
|
|
5697
5927
|
status: "fail",
|
|
5698
5928
|
detail: "Install TypeScript 7 before validating compiler configuration."
|
|
5699
5929
|
};
|
|
5700
|
-
const configPath =
|
|
5701
|
-
if (!
|
|
5930
|
+
const configPath = path7.join(root, "tsconfig.json");
|
|
5931
|
+
if (!fs6.existsSync(configPath))
|
|
5702
5932
|
return {
|
|
5703
5933
|
...check,
|
|
5704
5934
|
status: "fail",
|
|
@@ -5706,7 +5936,7 @@ async function checkNativeTypeScriptConfig(root) {
|
|
|
5706
5936
|
fix: "Create a tsconfig.json extending toiljs/tsconfig."
|
|
5707
5937
|
};
|
|
5708
5938
|
try {
|
|
5709
|
-
const apiPath =
|
|
5939
|
+
const apiPath = createRequire2(path7.join(root, "package.json")).resolve(
|
|
5710
5940
|
"typescript/unstable/sync"
|
|
5711
5941
|
);
|
|
5712
5942
|
const native = await import(pathToFileURL(apiPath).href);
|
|
@@ -5739,9 +5969,9 @@ async function checkNativeTypeScriptConfig(root) {
|
|
|
5739
5969
|
}
|
|
5740
5970
|
}
|
|
5741
5971
|
function checkLintMigration(root) {
|
|
5742
|
-
const pkg = readJsonObject(
|
|
5972
|
+
const pkg = readJsonObject(path7.join(root, "package.json"));
|
|
5743
5973
|
const script = asRecord(pkg?.scripts)?.lint;
|
|
5744
|
-
const config = readFile(
|
|
5974
|
+
const config = readFile(path7.join(root, "oxlint.config.ts")) ?? readFile(path7.join(root, ".oxlintrc.json")) ?? "";
|
|
5745
5975
|
const configured = config.includes("toiljs/oxlint") || /["']?typeAware["']?\s*:\s*true/.test(config);
|
|
5746
5976
|
const scriptOk = typeof script === "string" && /\boxlint\b/.test(script) && !/\beslint\b/.test(script) && (script.includes("--type-aware") || configured);
|
|
5747
5977
|
const installed = installedVersion(root, "oxlint") !== null && installedVersion(root, "oxlint-tsgolint") !== null;
|
|
@@ -5754,8 +5984,8 @@ function checkLintMigration(root) {
|
|
|
5754
5984
|
};
|
|
5755
5985
|
}
|
|
5756
5986
|
function frameworkMeta() {
|
|
5757
|
-
const pkgPath =
|
|
5758
|
-
|
|
5987
|
+
const pkgPath = path7.resolve(
|
|
5988
|
+
path7.dirname(fileURLToPath3(import.meta.url)),
|
|
5759
5989
|
"..",
|
|
5760
5990
|
"..",
|
|
5761
5991
|
"package.json"
|
|
@@ -5765,10 +5995,10 @@ function frameworkMeta() {
|
|
|
5765
5995
|
const peers = pkg ? stringRecord(pkg.peerDependencies) : {};
|
|
5766
5996
|
return { node: engines.node ?? ">=24.0.0", peers };
|
|
5767
5997
|
}
|
|
5768
|
-
var LOCKFILES = ["package-lock.json", "pnpm-lock.yaml", "yarn.lock", "bun.lockb"];
|
|
5998
|
+
var LOCKFILES = ["package-lock.json", "pnpm-lock.yaml", "yarn.lock", "bun.lock", "bun.lockb"];
|
|
5769
5999
|
function readEntry(clientAbsDir) {
|
|
5770
6000
|
for (const name of ["toil.tsx", "toil.jsx", "main.tsx", "main.jsx"]) {
|
|
5771
|
-
const source = readFile(
|
|
6001
|
+
const source = readFile(path7.join(clientAbsDir, name));
|
|
5772
6002
|
if (source !== null && /toiljs\/routes|\bmount\s*\(/.test(source)) return source;
|
|
5773
6003
|
}
|
|
5774
6004
|
return null;
|
|
@@ -5779,18 +6009,18 @@ function collectSources(root, dir, cap) {
|
|
|
5779
6009
|
if (out2.length >= cap) return;
|
|
5780
6010
|
let entries;
|
|
5781
6011
|
try {
|
|
5782
|
-
entries =
|
|
6012
|
+
entries = fs6.readdirSync(current, { withFileTypes: true });
|
|
5783
6013
|
} catch {
|
|
5784
6014
|
return;
|
|
5785
6015
|
}
|
|
5786
6016
|
for (const entry of entries) {
|
|
5787
6017
|
if (out2.length >= cap) break;
|
|
5788
|
-
const full =
|
|
6018
|
+
const full = path7.join(current, entry.name);
|
|
5789
6019
|
if (entry.isDirectory()) {
|
|
5790
6020
|
if (entry.name !== "node_modules") visit(full);
|
|
5791
6021
|
} else if (/\.(tsx|jsx)$/.test(entry.name)) {
|
|
5792
6022
|
const source = readFile(full);
|
|
5793
|
-
if (source !== null) out2.push({ path:
|
|
6023
|
+
if (source !== null) out2.push({ path: path7.relative(root, full), source });
|
|
5794
6024
|
}
|
|
5795
6025
|
}
|
|
5796
6026
|
};
|
|
@@ -5826,9 +6056,9 @@ function renderHuman(groups) {
|
|
|
5826
6056
|
process.stdout.write(out2.join("\n") + "\n");
|
|
5827
6057
|
}
|
|
5828
6058
|
async function runDoctor(opts2) {
|
|
5829
|
-
const root =
|
|
6059
|
+
const root = path7.resolve(opts2.root ?? opts2.cwd);
|
|
5830
6060
|
const meta = frameworkMeta();
|
|
5831
|
-
const projectPkg = readJsonObject(
|
|
6061
|
+
const projectPkg = readJsonObject(path7.join(root, "package.json"));
|
|
5832
6062
|
const deps = {
|
|
5833
6063
|
...projectPkg ? stringRecord(projectPkg.dependencies) : {},
|
|
5834
6064
|
...projectPkg ? stringRecord(projectPkg.devDependencies) : {}
|
|
@@ -5840,11 +6070,11 @@ async function runDoctor(opts2) {
|
|
|
5840
6070
|
} catch (err) {
|
|
5841
6071
|
configError = err instanceof Error ? err.message : String(err);
|
|
5842
6072
|
}
|
|
5843
|
-
const clientAbsDir = cfg ? cfg.clientAbsDir :
|
|
5844
|
-
const routesAbsDir = cfg ? cfg.routesAbsDir :
|
|
5845
|
-
const publicDir = cfg ? cfg.publicDir :
|
|
6073
|
+
const clientAbsDir = cfg ? cfg.clientAbsDir : path7.join(root, "client");
|
|
6074
|
+
const routesAbsDir = cfg ? cfg.routesAbsDir : path7.join(clientAbsDir, "routes");
|
|
6075
|
+
const publicDir = cfg ? cfg.publicDir : path7.join(clientAbsDir, "public");
|
|
5846
6076
|
const entrySource = readEntry(clientAbsDir);
|
|
5847
|
-
const indexHtml = readFile(
|
|
6077
|
+
const indexHtml = readFile(path7.join(publicDir, "index.html"));
|
|
5848
6078
|
const routes = scanRoutes(routesAbsDir);
|
|
5849
6079
|
const mainPatterns = routes.filter((r2) => r2.slot === void 0).map((r2) => r2.pattern);
|
|
5850
6080
|
const assetIssues = findRelativeAssets(collectSources(root, clientAbsDir, 200));
|
|
@@ -5857,14 +6087,14 @@ async function runDoctor(opts2) {
|
|
|
5857
6087
|
}
|
|
5858
6088
|
const ppPkg = preprocessorImported ? PREPROCESSOR_PKG[preprocessorImported] : null;
|
|
5859
6089
|
const preprocessorInstalled = ppPkg === null || ppPkg in deps;
|
|
5860
|
-
const toilconfig = readJsonObject(
|
|
6090
|
+
const toilconfig = readJsonObject(path7.join(root, "toilconfig.json"));
|
|
5861
6091
|
const serverPresent = toilconfig !== null;
|
|
5862
6092
|
let missingEntries = [];
|
|
5863
6093
|
let toilscriptInstalled = false;
|
|
5864
6094
|
let wasmExists = false;
|
|
5865
6095
|
if (toilconfig) {
|
|
5866
6096
|
const entries = Array.isArray(toilconfig.entries) ? toilconfig.entries.filter((e) => typeof e === "string") : [];
|
|
5867
|
-
missingEntries = entries.filter((e) => !
|
|
6097
|
+
missingEntries = entries.filter((e) => !fs6.existsSync(path7.join(root, e)));
|
|
5868
6098
|
toilscriptInstalled = isPackageInstalled(root, "toilscript");
|
|
5869
6099
|
const targets = typeof toilconfig.targets === "object" && toilconfig.targets !== null ? toilconfig.targets : {};
|
|
5870
6100
|
const outFiles = [];
|
|
@@ -5874,20 +6104,20 @@ async function runDoctor(opts2) {
|
|
|
5874
6104
|
if (typeof outFile === "string") outFiles.push(outFile);
|
|
5875
6105
|
}
|
|
5876
6106
|
}
|
|
5877
|
-
wasmExists = outFiles.some((f) =>
|
|
6107
|
+
wasmExists = outFiles.some((f) => fs6.existsSync(path7.join(root, f)));
|
|
5878
6108
|
if (!wasmExists && outFiles.length === 0) {
|
|
5879
6109
|
try {
|
|
5880
|
-
wasmExists =
|
|
6110
|
+
wasmExists = fs6.readdirSync(path7.join(root, "build", "server")).some((f) => f.endsWith(".wasm"));
|
|
5881
6111
|
} catch {
|
|
5882
6112
|
wasmExists = false;
|
|
5883
6113
|
}
|
|
5884
6114
|
}
|
|
5885
6115
|
}
|
|
5886
6116
|
const peerName = (n3) => checkPeer(n3, deps[n3] ?? null, meta.peers[n3] ?? "*");
|
|
5887
|
-
const peerChecks = Object.keys(meta.peers).filter((n3) => n3 !== "typescript").map(peerName);
|
|
6117
|
+
const peerChecks = Object.keys(meta.peers).filter((n3) => n3 !== "typescript" && !Object.hasOwn(TEST_DEPENDENCIES, n3)).map(peerName);
|
|
5888
6118
|
const typeScriptFix = opts2.fix ? applyTypeScriptFix(root) : null;
|
|
5889
6119
|
const declaredTypeScript = (() => {
|
|
5890
|
-
const pkg = readJsonObject(
|
|
6120
|
+
const pkg = readJsonObject(path7.join(root, "package.json"));
|
|
5891
6121
|
if (pkg === null) return deps.typescript ?? null;
|
|
5892
6122
|
const ranges = [
|
|
5893
6123
|
"dependencies",
|
|
@@ -5909,12 +6139,39 @@ async function runDoctor(opts2) {
|
|
|
5909
6139
|
const authFacts = gatherAuthFacts(root, toilconfig);
|
|
5910
6140
|
const prettierPresent = prettierPluginPresent(
|
|
5911
6141
|
root,
|
|
5912
|
-
readJsonObject(
|
|
6142
|
+
readJsonObject(path7.join(root, "package.json"))
|
|
5913
6143
|
);
|
|
5914
6144
|
const serverTsPath = serverPresent ? serverTsconfigPath(root, toilconfig) : null;
|
|
5915
6145
|
const serverTsParsed = serverTsPath ? readJsonObject(serverTsPath) : null;
|
|
5916
6146
|
const serverTsPluginPresent = serverTsPath === null || serverTsParsed === null ? false : tsconfigHasToilPlugin(serverTsParsed);
|
|
5917
|
-
|
|
6147
|
+
let testingFix = null;
|
|
6148
|
+
let testingChecks;
|
|
6149
|
+
try {
|
|
6150
|
+
if (opts2.fix && projectPkg !== null) testingFix = await ensureTesting(root, true);
|
|
6151
|
+
const testingPkg = readJsonObject(path7.join(root, "package.json"));
|
|
6152
|
+
testingChecks = checkTesting({
|
|
6153
|
+
dependencies: {
|
|
6154
|
+
...stringRecord(testingPkg?.dependencies),
|
|
6155
|
+
...stringRecord(testingPkg?.devDependencies)
|
|
6156
|
+
},
|
|
6157
|
+
scripts: stringRecord(testingPkg?.scripts),
|
|
6158
|
+
installed: Object.fromEntries(
|
|
6159
|
+
Object.keys(TEST_DEPENDENCIES).map((name) => [name, installedVersion(root, name)])
|
|
6160
|
+
),
|
|
6161
|
+
configuration: await findTestConfiguration(root)
|
|
6162
|
+
});
|
|
6163
|
+
} catch (error) {
|
|
6164
|
+
testingChecks = [
|
|
6165
|
+
{
|
|
6166
|
+
id: "testing:setup",
|
|
6167
|
+
label: "Testing setup",
|
|
6168
|
+
status: "fail",
|
|
6169
|
+
detail: error instanceof Error ? error.message : String(error),
|
|
6170
|
+
fix: "Repair package.json or unreadable test configuration, then run `toiljs doctor --fix`."
|
|
6171
|
+
}
|
|
6172
|
+
];
|
|
6173
|
+
}
|
|
6174
|
+
const applied = [typeScriptFix, rpcFix, prettierFix, editorFix, testingFix].filter(
|
|
5918
6175
|
(fix) => fix !== null
|
|
5919
6176
|
);
|
|
5920
6177
|
const serverFix = applied.length > 0 ? {
|
|
@@ -5931,7 +6188,7 @@ async function runDoctor(opts2) {
|
|
|
5931
6188
|
typeScriptCheck,
|
|
5932
6189
|
checkLintMigration(root),
|
|
5933
6190
|
await checkNativeTypeScriptConfig(root),
|
|
5934
|
-
checkPackageManager(LOCKFILES.filter((f) =>
|
|
6191
|
+
checkPackageManager(LOCKFILES.filter((f) => fs6.existsSync(path7.join(root, f))))
|
|
5935
6192
|
]
|
|
5936
6193
|
},
|
|
5937
6194
|
{
|
|
@@ -5940,13 +6197,13 @@ async function runDoctor(opts2) {
|
|
|
5940
6197
|
checkDir(
|
|
5941
6198
|
"client-dir",
|
|
5942
6199
|
"client/ directory",
|
|
5943
|
-
|
|
6200
|
+
fs6.existsSync(clientAbsDir),
|
|
5944
6201
|
"Create a client/ directory for your app."
|
|
5945
6202
|
),
|
|
5946
6203
|
checkDir(
|
|
5947
6204
|
"routes-dir",
|
|
5948
6205
|
"routes/ directory",
|
|
5949
|
-
|
|
6206
|
+
fs6.existsSync(routesAbsDir),
|
|
5950
6207
|
"Create client/routes/ and add an index.tsx."
|
|
5951
6208
|
),
|
|
5952
6209
|
checkRootElement(indexHtml),
|
|
@@ -5957,6 +6214,10 @@ async function runDoctor(opts2) {
|
|
|
5957
6214
|
checkDevScripts(projectPkg ? stringRecord(projectPkg.scripts) : {})
|
|
5958
6215
|
]
|
|
5959
6216
|
},
|
|
6217
|
+
{
|
|
6218
|
+
title: "Testing",
|
|
6219
|
+
checks: testingChecks
|
|
6220
|
+
},
|
|
5960
6221
|
{
|
|
5961
6222
|
title: "Config + assets",
|
|
5962
6223
|
checks: [
|
|
@@ -6017,8 +6278,8 @@ function renderFix(result) {
|
|
|
6017
6278
|
|
|
6018
6279
|
// src/cli/generate.ts
|
|
6019
6280
|
import { randomBytes as randomBytes3, timingSafeEqual } from "node:crypto";
|
|
6020
|
-
import
|
|
6021
|
-
import
|
|
6281
|
+
import fs7 from "node:fs";
|
|
6282
|
+
import path8 from "node:path";
|
|
6022
6283
|
import { parseEnv } from "node:util";
|
|
6023
6284
|
|
|
6024
6285
|
// node_modules/@noble/hashes/_u64.js
|
|
@@ -6931,10 +7192,10 @@ var ml_kem768 = /* @__PURE__ */ (() => mk(PARAMS[768]))();
|
|
|
6931
7192
|
var PRIVATE_KEYS = ["AUTH_SESSION_SECRET", "AUTH_OPRF_SEED", "AUTH_KEM_SK"];
|
|
6932
7193
|
var PUBLIC_KEY = "VITE_AUTH_KEM_PUBLIC_KEY";
|
|
6933
7194
|
function read(file) {
|
|
6934
|
-
const stat =
|
|
7195
|
+
const stat = fs7.lstatSync(file, { throwIfNoEntry: false });
|
|
6935
7196
|
if (!stat) return "";
|
|
6936
7197
|
if (!stat.isFile()) throw new Error(`Expected a regular file: ${file}`);
|
|
6937
|
-
return
|
|
7198
|
+
return fs7.readFileSync(file, "utf8");
|
|
6938
7199
|
}
|
|
6939
7200
|
function append(text2, lines) {
|
|
6940
7201
|
if (!lines.length) return text2;
|
|
@@ -6957,10 +7218,10 @@ function publicKeyFor(secret) {
|
|
|
6957
7218
|
}
|
|
6958
7219
|
function runGenerate(target, opts2 = {}) {
|
|
6959
7220
|
if (target !== "auth") throw new Error("Usage: toiljs generate auth [--root <dir>]");
|
|
6960
|
-
const root =
|
|
6961
|
-
const envFile =
|
|
6962
|
-
const secretsFile =
|
|
6963
|
-
const ignoreFile =
|
|
7221
|
+
const root = path8.resolve(opts2.root ?? process.cwd());
|
|
7222
|
+
const envFile = path8.join(root, ".env");
|
|
7223
|
+
const secretsFile = path8.join(root, ".env.secrets");
|
|
7224
|
+
const ignoreFile = path8.join(root, ".gitignore");
|
|
6964
7225
|
const envText = read(envFile);
|
|
6965
7226
|
const secretsText = read(secretsFile);
|
|
6966
7227
|
const ignoreText = read(ignoreFile);
|
|
@@ -6998,12 +7259,12 @@ function runGenerate(target, opts2 = {}) {
|
|
|
6998
7259
|
const publicAdditions = Object.hasOwn(env, PUBLIC_KEY) ? [] : [`${PUBLIC_KEY}=${publicKey}`];
|
|
6999
7260
|
const ignoreLines = new Set(ignoreText.split(/\r?\n/));
|
|
7000
7261
|
const ignoreAdditions = ["/.env", "/.env.secrets"].filter((line) => !ignoreLines.has(line));
|
|
7001
|
-
if (ignoreAdditions.length)
|
|
7002
|
-
if (
|
|
7262
|
+
if (ignoreAdditions.length) fs7.writeFileSync(ignoreFile, append(ignoreText, ignoreAdditions));
|
|
7263
|
+
if (fs7.existsSync(secretsFile)) fs7.chmodSync(secretsFile, 384);
|
|
7003
7264
|
if (additions.length)
|
|
7004
|
-
|
|
7265
|
+
fs7.writeFileSync(secretsFile, append(secretsText, additions), { mode: 384 });
|
|
7005
7266
|
if (publicAdditions.length)
|
|
7006
|
-
|
|
7267
|
+
fs7.writeFileSync(envFile, append(envText, publicAdditions), { mode: 384 });
|
|
7007
7268
|
process.stdout.write(
|
|
7008
7269
|
[
|
|
7009
7270
|
`Authentication keys ready in ${root}. Existing credentials were preserved.`,
|
|
@@ -7020,14 +7281,14 @@ function runGenerate(target, opts2 = {}) {
|
|
|
7020
7281
|
}
|
|
7021
7282
|
|
|
7022
7283
|
// src/cli/notify.ts
|
|
7023
|
-
import
|
|
7284
|
+
import fs9 from "node:fs";
|
|
7024
7285
|
import os from "node:os";
|
|
7025
|
-
import
|
|
7286
|
+
import path10 from "node:path";
|
|
7026
7287
|
import { fileURLToPath as fileURLToPath4 } from "node:url";
|
|
7027
7288
|
|
|
7028
7289
|
// src/cli/update.ts
|
|
7029
|
-
import
|
|
7030
|
-
import
|
|
7290
|
+
import fs8 from "node:fs";
|
|
7291
|
+
import path9 from "node:path";
|
|
7031
7292
|
|
|
7032
7293
|
// src/cli/updates.ts
|
|
7033
7294
|
function parseVersion2(v) {
|
|
@@ -7070,14 +7331,14 @@ function buildRows(upgraded, currentDeps) {
|
|
|
7070
7331
|
|
|
7071
7332
|
// src/cli/update.ts
|
|
7072
7333
|
function detectPackageManager2(root) {
|
|
7073
|
-
if (
|
|
7074
|
-
if (
|
|
7075
|
-
if (
|
|
7334
|
+
if (fs8.existsSync(path9.join(root, "pnpm-lock.yaml"))) return { name: "pnpm", ncuName: "pnpm" };
|
|
7335
|
+
if (fs8.existsSync(path9.join(root, "yarn.lock"))) return { name: "yarn", ncuName: "yarn" };
|
|
7336
|
+
if (fs8.existsSync(path9.join(root, "bun.lock")) || fs8.existsSync(path9.join(root, "bun.lockb")))
|
|
7076
7337
|
return { name: "bun", ncuName: "bun" };
|
|
7077
7338
|
return { name: "npm", ncuName: "npm" };
|
|
7078
7339
|
}
|
|
7079
7340
|
function readDependencies(pkgPath) {
|
|
7080
|
-
const parsed = JSON.parse(
|
|
7341
|
+
const parsed = JSON.parse(fs8.readFileSync(pkgPath, "utf8"));
|
|
7081
7342
|
if (typeof parsed !== "object" || parsed === null) return {};
|
|
7082
7343
|
const pkg = parsed;
|
|
7083
7344
|
const merge = (v) => {
|
|
@@ -7105,26 +7366,26 @@ function serverDirs(root) {
|
|
|
7105
7366
|
const dirs = /* @__PURE__ */ new Set();
|
|
7106
7367
|
try {
|
|
7107
7368
|
const parsed = JSON.parse(
|
|
7108
|
-
|
|
7369
|
+
fs8.readFileSync(path9.join(root, "toilconfig.json"), "utf8")
|
|
7109
7370
|
);
|
|
7110
7371
|
const entries = typeof parsed === "object" && parsed !== null && Array.isArray(parsed.entries) ? parsed.entries.filter(
|
|
7111
7372
|
(e) => typeof e === "string"
|
|
7112
7373
|
) : [];
|
|
7113
|
-
for (const e of entries) dirs.add(
|
|
7374
|
+
for (const e of entries) dirs.add(path9.dirname(path9.resolve(root, e)));
|
|
7114
7375
|
} catch {
|
|
7115
7376
|
}
|
|
7116
|
-
if (dirs.size === 0) dirs.add(
|
|
7377
|
+
if (dirs.size === 0) dirs.add(path9.join(root, "server"));
|
|
7117
7378
|
return [...dirs];
|
|
7118
7379
|
}
|
|
7119
7380
|
function ensureMigrationsDirs(root) {
|
|
7120
7381
|
const created = [];
|
|
7121
7382
|
for (const dir of serverDirs(root)) {
|
|
7122
|
-
if (!
|
|
7123
|
-
const migrations =
|
|
7124
|
-
if (
|
|
7125
|
-
|
|
7126
|
-
|
|
7127
|
-
created.push(
|
|
7383
|
+
if (!fs8.existsSync(dir)) continue;
|
|
7384
|
+
const migrations = path9.join(dir, "migrations");
|
|
7385
|
+
if (fs8.existsSync(migrations)) continue;
|
|
7386
|
+
fs8.mkdirSync(migrations, { recursive: true });
|
|
7387
|
+
fs8.writeFileSync(path9.join(migrations, "README.md"), MIGRATIONS_README);
|
|
7388
|
+
created.push(path9.relative(root, migrations) || "migrations");
|
|
7128
7389
|
}
|
|
7129
7390
|
return created;
|
|
7130
7391
|
}
|
|
@@ -7140,16 +7401,16 @@ function rowLine(row) {
|
|
|
7140
7401
|
function noteWithheld(names) {
|
|
7141
7402
|
note(
|
|
7142
7403
|
names.map((n3) => `${dim("-")} ${n3}`).join("\n") + "\n\n" + dim(
|
|
7143
|
-
"Held back:
|
|
7404
|
+
"Held back: compiler updates must stay within TypeScript 7; native testing updates must stay within the supported Vitest and WebdriverIO versions."
|
|
7144
7405
|
),
|
|
7145
7406
|
warn("Not upgraded")
|
|
7146
7407
|
);
|
|
7147
7408
|
}
|
|
7148
7409
|
var TARGETS = /* @__PURE__ */ new Set(["latest", "minor", "patch", "newest", "greatest"]);
|
|
7149
7410
|
async function runUpdate(opts2) {
|
|
7150
|
-
const root =
|
|
7151
|
-
const pkgPath =
|
|
7152
|
-
if (!
|
|
7411
|
+
const root = path9.resolve(opts2.root ?? opts2.cwd);
|
|
7412
|
+
const pkgPath = path9.join(root, "package.json");
|
|
7413
|
+
if (!fs8.existsSync(pkgPath)) {
|
|
7153
7414
|
throw new Error("No package.json here. Run from your project root or pass --root <dir>.");
|
|
7154
7415
|
}
|
|
7155
7416
|
const currentDeps = readDependencies(pkgPath);
|
|
@@ -7182,7 +7443,13 @@ async function runUpdate(opts2) {
|
|
|
7182
7443
|
return;
|
|
7183
7444
|
}
|
|
7184
7445
|
const upgraded = parseNcuJson(res.stdout);
|
|
7185
|
-
const
|
|
7446
|
+
const testConfig = await findTestConfiguration(root);
|
|
7447
|
+
const withheld = [
|
|
7448
|
+
...withheldUpgrades(upgraded),
|
|
7449
|
+
...Object.keys(upgraded).filter(
|
|
7450
|
+
(name) => testConfig.native && !isSupportedTestingRange(name, upgraded[name])
|
|
7451
|
+
)
|
|
7452
|
+
];
|
|
7186
7453
|
for (const name of withheld) delete upgraded[name];
|
|
7187
7454
|
if (!isSupportedTypeScriptRange(currentDeps.typescript ?? "") && !upgraded.typescript) {
|
|
7188
7455
|
const versions = await capture("npm", ["view", "typescript@7", "version", "--json"], root);
|
|
@@ -7199,7 +7466,20 @@ async function runUpdate(opts2) {
|
|
|
7199
7466
|
if (rows.length === 0) {
|
|
7200
7467
|
s.stop("Everything is up to date");
|
|
7201
7468
|
if (withheld.length > 0) noteWithheld(withheld);
|
|
7202
|
-
|
|
7469
|
+
if (opts2.yes) {
|
|
7470
|
+
const testing2 = await ensureTesting(root, true);
|
|
7471
|
+
if (testing2.changed.length) note(testing2.changed.join("\n"), "Testing setup");
|
|
7472
|
+
if (testing2.skipped.length) note(testing2.skipped.join("\n"), "Manual changes");
|
|
7473
|
+
if (testing2.install && !await installUpdates(pm.name, root)) return;
|
|
7474
|
+
outro(
|
|
7475
|
+
success(testing2.changed.length ? "Testing setup updated." : "Nothing to update.")
|
|
7476
|
+
);
|
|
7477
|
+
} else
|
|
7478
|
+
outro(
|
|
7479
|
+
success(
|
|
7480
|
+
"Nothing to update. Use `toiljs doctor --fix` or `toiljs update --yes` to add missing testing setup."
|
|
7481
|
+
)
|
|
7482
|
+
);
|
|
7203
7483
|
return;
|
|
7204
7484
|
}
|
|
7205
7485
|
s.stop(`${String(rows.length)} update${rows.length === 1 ? "" : "s"} available`);
|
|
@@ -7234,7 +7514,17 @@ async function runUpdate(opts2) {
|
|
|
7234
7514
|
outro(dim("No packages selected."));
|
|
7235
7515
|
return;
|
|
7236
7516
|
}
|
|
7237
|
-
|
|
7517
|
+
if (testConfig.native) {
|
|
7518
|
+
const paired = selected.find(
|
|
7519
|
+
(name) => name === "vitest" || name === "@vitest/coverage-v8"
|
|
7520
|
+
);
|
|
7521
|
+
if (paired) {
|
|
7522
|
+
const counterpart = paired === "vitest" ? "@vitest/coverage-v8" : "vitest";
|
|
7523
|
+
upgraded[counterpart] = upgraded[paired];
|
|
7524
|
+
if (!selected.includes(counterpart)) selected.push(counterpart);
|
|
7525
|
+
}
|
|
7526
|
+
}
|
|
7527
|
+
const pkg = JSON.parse(fs8.readFileSync(pkgPath, "utf8"));
|
|
7238
7528
|
const targetTypeScript = selected.includes("typescript") ? upgraded.typescript : currentDeps.typescript;
|
|
7239
7529
|
if (!targetTypeScript || !isSupportedTypeScriptRange(targetTypeScript)) {
|
|
7240
7530
|
throw new Error("Select the TypeScript 7 migration before installing updates.");
|
|
@@ -7260,23 +7550,30 @@ async function runUpdate(opts2) {
|
|
|
7260
7550
|
pkg.devDependencies = deps;
|
|
7261
7551
|
}
|
|
7262
7552
|
}
|
|
7263
|
-
|
|
7553
|
+
fs8.writeFileSync(pkgPath, JSON.stringify(pkg, null, 4) + "\n");
|
|
7264
7554
|
s.stop("package.json updated");
|
|
7265
|
-
|
|
7555
|
+
const testing = await ensureTesting(root, true);
|
|
7556
|
+
if (testing.changed.length) note(testing.changed.join("\n"), "Testing setup");
|
|
7557
|
+
if (testing.skipped.length) note(testing.skipped.join("\n"), "Manual changes");
|
|
7558
|
+
if (!await installUpdates(pm.name, root)) return;
|
|
7559
|
+
outro(
|
|
7560
|
+
success(`Updated ${String(selected.length)} package${selected.length === 1 ? "" : "s"}.`)
|
|
7561
|
+
);
|
|
7562
|
+
}
|
|
7563
|
+
async function installUpdates(pm, root) {
|
|
7564
|
+
note(dim(`Running ${pm} install\u2026`), "Install");
|
|
7266
7565
|
try {
|
|
7267
|
-
await run(pm
|
|
7566
|
+
await run(pm, ["install"], root, { stdio: "inherit" });
|
|
7268
7567
|
} catch {
|
|
7269
7568
|
outro(
|
|
7270
7569
|
danger(
|
|
7271
|
-
`${pm
|
|
7570
|
+
`${pm} install failed \u2014 package.json was updated to the new versions, but the install did not finish. Fix the error printed above, then run \`${pm} install\`.`
|
|
7272
7571
|
)
|
|
7273
7572
|
);
|
|
7274
7573
|
process.exitCode = 1;
|
|
7275
|
-
return;
|
|
7574
|
+
return false;
|
|
7276
7575
|
}
|
|
7277
|
-
|
|
7278
|
-
success(`Updated ${String(selected.length)} package${selected.length === 1 ? "" : "s"}.`)
|
|
7279
|
-
);
|
|
7576
|
+
return true;
|
|
7280
7577
|
}
|
|
7281
7578
|
|
|
7282
7579
|
// src/cli/version-check.ts
|
|
@@ -7351,8 +7648,8 @@ function findOutdated(latest, projectVersion, cliVersion, cliIsLocal, pm) {
|
|
|
7351
7648
|
var REGISTRY_URL = "https://registry.npmjs.org/toiljs/latest";
|
|
7352
7649
|
var FETCH_TIMEOUT_MS = 2e3;
|
|
7353
7650
|
function cacheFile() {
|
|
7354
|
-
const base = process.env.XDG_CACHE_HOME ??
|
|
7355
|
-
return
|
|
7651
|
+
const base = process.env.XDG_CACHE_HOME ?? path10.join(os.homedir(), ".cache");
|
|
7652
|
+
return path10.join(base, "toiljs", "update-check.json");
|
|
7356
7653
|
}
|
|
7357
7654
|
async function fetchLatest() {
|
|
7358
7655
|
const ctrl = new AbortController();
|
|
@@ -7378,22 +7675,22 @@ async function fetchLatest() {
|
|
|
7378
7675
|
async function resolveLatest() {
|
|
7379
7676
|
const file = cacheFile();
|
|
7380
7677
|
try {
|
|
7381
|
-
const cached = parseCheckCache(
|
|
7678
|
+
const cached = parseCheckCache(fs9.readFileSync(file, "utf8"));
|
|
7382
7679
|
if (cached && isCacheFresh(cached, Date.now())) return cached.latest;
|
|
7383
7680
|
} catch {
|
|
7384
7681
|
}
|
|
7385
7682
|
const latest = await fetchLatest();
|
|
7386
7683
|
try {
|
|
7387
|
-
|
|
7388
|
-
|
|
7684
|
+
fs9.mkdirSync(path10.dirname(file), { recursive: true });
|
|
7685
|
+
fs9.writeFileSync(file, JSON.stringify({ latest, checkedAt: Date.now() }));
|
|
7389
7686
|
} catch {
|
|
7390
7687
|
}
|
|
7391
7688
|
return latest;
|
|
7392
7689
|
}
|
|
7393
7690
|
function projectToiljsVersion(root) {
|
|
7394
7691
|
try {
|
|
7395
|
-
const raw =
|
|
7396
|
-
|
|
7692
|
+
const raw = fs9.readFileSync(
|
|
7693
|
+
path10.join(root, "node_modules", "toiljs", "package.json"),
|
|
7397
7694
|
"utf8"
|
|
7398
7695
|
);
|
|
7399
7696
|
const parsed = JSON.parse(raw);
|
|
@@ -7418,9 +7715,9 @@ async function notifyIfOutdated(rootArg) {
|
|
|
7418
7715
|
if (env.TOILJS_NO_UPDATE_CHECK || env.NO_UPDATE_NOTIFIER || env.CI) return;
|
|
7419
7716
|
const latest = await resolveLatest();
|
|
7420
7717
|
if (!latest) return;
|
|
7421
|
-
const root =
|
|
7422
|
-
const cliDir =
|
|
7423
|
-
const cliIsLocal = cliDir.startsWith(
|
|
7718
|
+
const root = path10.resolve(rootArg ?? process.cwd());
|
|
7719
|
+
const cliDir = path10.dirname(fileURLToPath4(import.meta.url));
|
|
7720
|
+
const cliIsLocal = cliDir.startsWith(path10.join(root, "node_modules") + path10.sep);
|
|
7424
7721
|
const rows = findOutdated(
|
|
7425
7722
|
latest,
|
|
7426
7723
|
projectToiljsVersion(root),
|
|
@@ -7435,62 +7732,9 @@ async function notifyIfOutdated(rootArg) {
|
|
|
7435
7732
|
}
|
|
7436
7733
|
|
|
7437
7734
|
// src/cli/test.ts
|
|
7438
|
-
import
|
|
7439
|
-
import
|
|
7440
|
-
import { createRequire as createRequire2 } from "node:module";
|
|
7735
|
+
import path11 from "node:path";
|
|
7736
|
+
import { createRequire as createRequire3 } from "node:module";
|
|
7441
7737
|
import { spawn as spawn2 } from "node:child_process";
|
|
7442
|
-
async function writeMissing(root, file, content) {
|
|
7443
|
-
const target = path10.join(root, file);
|
|
7444
|
-
await fs9.mkdir(path10.dirname(target), { recursive: true });
|
|
7445
|
-
try {
|
|
7446
|
-
await fs9.writeFile(target, content, { flag: "wx" });
|
|
7447
|
-
} catch (error) {
|
|
7448
|
-
if (!(error instanceof Error) || !("code" in error) || error.code !== "EEXIST") throw error;
|
|
7449
|
-
}
|
|
7450
|
-
}
|
|
7451
|
-
async function ensureTesting(root) {
|
|
7452
|
-
const pkgPath = path10.join(root, "package.json");
|
|
7453
|
-
const raw = JSON.parse(await fs9.readFile(pkgPath, "utf8"));
|
|
7454
|
-
if (raw === null || typeof raw !== "object" || Array.isArray(raw))
|
|
7455
|
-
throw new Error("toiljs test: package.json must contain an object.");
|
|
7456
|
-
const pkg = raw;
|
|
7457
|
-
for (const field of [pkg.scripts, pkg.dependencies, pkg.devDependencies]) {
|
|
7458
|
-
if (field !== void 0 && (field === null || typeof field !== "object" || Array.isArray(field) || Object.values(field).some((value) => typeof value !== "string")))
|
|
7459
|
-
throw new Error("toiljs test: package scripts and dependencies must be string maps.");
|
|
7460
|
-
}
|
|
7461
|
-
const files = await fs9.readdir(root);
|
|
7462
|
-
const custom = files.find((file) => /^vitest\.config\.[cm]?[jt]s$/.test(file)) ?? files.find((file) => /^vite\.config\.[cm]?[jt]s$/.test(file));
|
|
7463
|
-
const source = custom === void 0 ? "" : await fs9.readFile(path10.join(root, custom), "utf8");
|
|
7464
|
-
const native = custom === void 0 || source.includes("from 'toiljs/vitest'") || source.includes('from "toiljs/vitest"');
|
|
7465
|
-
let changed = false;
|
|
7466
|
-
let install = false;
|
|
7467
|
-
const require2 = createRequire2(pkgPath);
|
|
7468
|
-
for (const [name, range] of Object.entries(TEST_DEPENDENCIES)) {
|
|
7469
|
-
if (pkg.dependencies?.[name] === void 0 && pkg.devDependencies?.[name] === void 0) {
|
|
7470
|
-
pkg.devDependencies ??= {};
|
|
7471
|
-
pkg.devDependencies[name] = range;
|
|
7472
|
-
changed = true;
|
|
7473
|
-
install = true;
|
|
7474
|
-
}
|
|
7475
|
-
try {
|
|
7476
|
-
require2.resolve(name);
|
|
7477
|
-
} catch {
|
|
7478
|
-
install = true;
|
|
7479
|
-
}
|
|
7480
|
-
}
|
|
7481
|
-
pkg.scripts ??= {};
|
|
7482
|
-
for (const [name, script] of Object.entries(TEST_SCRIPTS)) {
|
|
7483
|
-
if (pkg.scripts[name] !== void 0) continue;
|
|
7484
|
-
pkg.scripts[name] = script;
|
|
7485
|
-
changed = true;
|
|
7486
|
-
}
|
|
7487
|
-
if (changed) await fs9.writeFile(pkgPath, JSON.stringify(raw, null, 4) + "\n");
|
|
7488
|
-
if (custom === void 0) {
|
|
7489
|
-
for (const [file, content] of Object.entries(testingFiles()))
|
|
7490
|
-
await writeMissing(root, file, content);
|
|
7491
|
-
}
|
|
7492
|
-
return { install, native };
|
|
7493
|
-
}
|
|
7494
7738
|
function parseTestArgs(args) {
|
|
7495
7739
|
let root;
|
|
7496
7740
|
let browser = false;
|
|
@@ -7512,7 +7756,7 @@ function parseTestArgs(args) {
|
|
|
7512
7756
|
return { root, browser, all, watch, arguments: forwarded };
|
|
7513
7757
|
}
|
|
7514
7758
|
async function runTest(options) {
|
|
7515
|
-
const root =
|
|
7759
|
+
const root = path11.resolve(options.root ?? process.cwd());
|
|
7516
7760
|
const setup = await ensureTesting(root);
|
|
7517
7761
|
if (setup.install) {
|
|
7518
7762
|
const pm = detectPackageManager2(root).name;
|
|
@@ -7522,9 +7766,9 @@ async function runTest(options) {
|
|
|
7522
7766
|
);
|
|
7523
7767
|
await run(pm, ["install"], root, { stdio: "inherit" });
|
|
7524
7768
|
}
|
|
7525
|
-
const require2 =
|
|
7526
|
-
const cli =
|
|
7527
|
-
|
|
7769
|
+
const require2 = createRequire3(path11.join(root, "package.json"));
|
|
7770
|
+
const cli = path11.join(
|
|
7771
|
+
path11.dirname(require2.resolve("vitest/package.json")),
|
|
7528
7772
|
"vitest.mjs"
|
|
7529
7773
|
);
|
|
7530
7774
|
const args = [cli, ...options.watch ? [] : ["run"]];
|
|
@@ -7677,7 +7921,7 @@ function printHelp() {
|
|
|
7677
7921
|
cmd("--watch", "test: watch for changes"),
|
|
7678
7922
|
cmd("--server", "build: build only the server (regenerate shared/server.ts + wasm)"),
|
|
7679
7923
|
cmd("--json", "doctor: machine-readable output"),
|
|
7680
|
-
cmd("--fix", "doctor:
|
|
7924
|
+
cmd("--fix", "doctor: repair testing, compiler, and server wiring"),
|
|
7681
7925
|
cmd("--target <t>", "update: latest | minor | patch | newest | greatest"),
|
|
7682
7926
|
cmd("-v, --version", "print the toiljs version"),
|
|
7683
7927
|
"",
|