@soat/cli 0.5.3 → 0.5.5
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/bin/soat +3 -1
- package/dist/esm/index.js +278 -30
- package/package.json +7 -5
package/bin/soat
CHANGED
package/dist/esm/index.js
CHANGED
|
@@ -8,20 +8,21 @@ var __name = (target, value) => __defProp(target, "name", {
|
|
|
8
8
|
// src/index.ts
|
|
9
9
|
import { createHmac, timingSafeEqual } from "crypto";
|
|
10
10
|
import { createServer } from "http";
|
|
11
|
-
import
|
|
12
|
-
import
|
|
11
|
+
import * as nodePath from "path";
|
|
12
|
+
import { fileURLToPath } from "url";
|
|
13
13
|
import * as sdk from "@soat/sdk";
|
|
14
14
|
import { program } from "commander";
|
|
15
15
|
|
|
16
16
|
// package.json
|
|
17
17
|
var package_default = {
|
|
18
18
|
name: "@soat/cli",
|
|
19
|
-
version: "0.5.
|
|
19
|
+
version: "0.5.5",
|
|
20
20
|
type: "module",
|
|
21
21
|
scripts: {
|
|
22
22
|
generate: "tsx scripts/generate.ts",
|
|
23
|
-
lint: "eslint src",
|
|
24
|
-
|
|
23
|
+
lint: "eslint src tests",
|
|
24
|
+
test: "pnpm --filter @soat/sdk build && jest --config tests/unit/jest.config.ts --coverage=false",
|
|
25
|
+
typecheck: "tsc --noEmit && tsc --noEmit -p tests/tsconfig.json",
|
|
25
26
|
build: "pnpm generate && tsup"
|
|
26
27
|
},
|
|
27
28
|
dependencies: {
|
|
@@ -29,15 +30,16 @@ var package_default = {
|
|
|
29
30
|
"@inquirer/password": "^5.0.12",
|
|
30
31
|
"@soat/sdk": "workspace:*",
|
|
31
32
|
"@ttoss/logger": "^0.8.10",
|
|
32
|
-
commander: "^14.0.3"
|
|
33
|
+
commander: "^14.0.3",
|
|
34
|
+
"js-yaml": "^4.1.1"
|
|
33
35
|
},
|
|
34
36
|
devDependencies: {
|
|
35
37
|
"@ttoss/config": "^1.37.10",
|
|
38
|
+
"@ttoss/test-utils": "^4.2.10",
|
|
36
39
|
"@types/jest": "^30.0.0",
|
|
37
40
|
"@types/js-yaml": "^4.0.9",
|
|
38
41
|
"@types/node": "^24",
|
|
39
42
|
jest: "^30.3.0",
|
|
40
|
-
"js-yaml": "^4.1.1",
|
|
41
43
|
tsup: "^8.5.1",
|
|
42
44
|
tsx: "^4.21.0"
|
|
43
45
|
},
|
|
@@ -55,15 +57,246 @@ var package_default = {
|
|
|
55
57
|
}
|
|
56
58
|
};
|
|
57
59
|
|
|
58
|
-
// src/
|
|
60
|
+
// src/cli-wrappers/wrappers/agentFormations.ts
|
|
59
61
|
import * as fs from "fs";
|
|
62
|
+
import yaml from "js-yaml";
|
|
63
|
+
var FORMATION_COMMANDS = ["validate-agent-formation", "plan-agent-formation", "create-agent-formation", "update-agent-formation"];
|
|
64
|
+
var TEMPLATE_PATH_FLAG = "template-path";
|
|
65
|
+
var TEMPLATE_FILE_FLAG = "template-file";
|
|
66
|
+
var ENV_FILE_FLAG = "env-file";
|
|
67
|
+
var PARAMETER_FLAG = "parameter";
|
|
68
|
+
var TEMPLATE_FIELD = "template";
|
|
69
|
+
var PARAMETERS_FIELD = "parameters";
|
|
70
|
+
var parseEnvFile = /* @__PURE__ */__name(args => {
|
|
71
|
+
const {
|
|
72
|
+
envPath
|
|
73
|
+
} = args;
|
|
74
|
+
let content;
|
|
75
|
+
try {
|
|
76
|
+
content = fs.readFileSync(envPath, "utf8");
|
|
77
|
+
} catch {
|
|
78
|
+
throw new Error(`Unable to read env file: ${envPath}`);
|
|
79
|
+
}
|
|
80
|
+
const vars = {};
|
|
81
|
+
for (const rawLine of content.split(/\r?\n/)) {
|
|
82
|
+
const line = rawLine.trim();
|
|
83
|
+
if (!line || line.startsWith("#")) continue;
|
|
84
|
+
const withoutExport = line.startsWith("export ") ? line.slice("export ".length).trim() : line;
|
|
85
|
+
const eqIdx = withoutExport.indexOf("=");
|
|
86
|
+
if (eqIdx <= 0) continue;
|
|
87
|
+
const key = withoutExport.slice(0, eqIdx).trim();
|
|
88
|
+
let value = withoutExport.slice(eqIdx + 1).trim();
|
|
89
|
+
if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
|
|
90
|
+
value = value.slice(1, -1);
|
|
91
|
+
}
|
|
92
|
+
vars[key] = value;
|
|
93
|
+
}
|
|
94
|
+
return vars;
|
|
95
|
+
}, "parseEnvFile");
|
|
96
|
+
var readTemplateFromPath = /* @__PURE__ */__name(args => {
|
|
97
|
+
const {
|
|
98
|
+
templatePath
|
|
99
|
+
} = args;
|
|
100
|
+
let content;
|
|
101
|
+
try {
|
|
102
|
+
content = fs.readFileSync(templatePath, "utf8");
|
|
103
|
+
} catch {
|
|
104
|
+
throw new Error(`Unable to read template file: ${templatePath}`);
|
|
105
|
+
}
|
|
106
|
+
const trimmed = content.trim();
|
|
107
|
+
if (!trimmed) {
|
|
108
|
+
throw new Error(`Template file is empty: ${templatePath}`);
|
|
109
|
+
}
|
|
110
|
+
try {
|
|
111
|
+
return JSON.parse(trimmed);
|
|
112
|
+
} catch {}
|
|
113
|
+
try {
|
|
114
|
+
return yaml.load(trimmed);
|
|
115
|
+
} catch {
|
|
116
|
+
throw new Error(`Template file must contain valid JSON or YAML: ${templatePath}`);
|
|
117
|
+
}
|
|
118
|
+
}, "readTemplateFromPath");
|
|
119
|
+
var resolveEnvRef = /* @__PURE__ */__name(args => {
|
|
120
|
+
const {
|
|
121
|
+
value,
|
|
122
|
+
env
|
|
123
|
+
} = args;
|
|
124
|
+
const simple = /^\$([A-Za-z_][A-Za-z0-9_]*)$/.exec(value);
|
|
125
|
+
if (simple) {
|
|
126
|
+
const resolved = env[simple[1]];
|
|
127
|
+
if (resolved === void 0) {
|
|
128
|
+
throw new Error(`Missing environment variable: ${simple[1]}`);
|
|
129
|
+
}
|
|
130
|
+
return resolved;
|
|
131
|
+
}
|
|
132
|
+
const bracketed = /^\$\{([A-Za-z_][A-Za-z0-9_]*)\}$/.exec(value);
|
|
133
|
+
if (bracketed) {
|
|
134
|
+
const resolved = env[bracketed[1]];
|
|
135
|
+
if (resolved === void 0) {
|
|
136
|
+
throw new Error(`Missing environment variable: ${bracketed[1]}`);
|
|
137
|
+
}
|
|
138
|
+
return resolved;
|
|
139
|
+
}
|
|
140
|
+
return value;
|
|
141
|
+
}, "resolveEnvRef");
|
|
142
|
+
var agentFormationsWrapper = {
|
|
143
|
+
id: "agent-formations-wrapper",
|
|
144
|
+
commands: FORMATION_COMMANDS,
|
|
145
|
+
// eslint-disable-next-line complexity
|
|
146
|
+
apply: /* @__PURE__ */__name(({
|
|
147
|
+
context
|
|
148
|
+
}) => {
|
|
149
|
+
const forcedBody = {};
|
|
150
|
+
const flags = {
|
|
151
|
+
single: {
|
|
152
|
+
...context.parsedFlags.single
|
|
153
|
+
},
|
|
154
|
+
repeated: {
|
|
155
|
+
...context.parsedFlags.repeated
|
|
156
|
+
}
|
|
157
|
+
};
|
|
158
|
+
const templatePath = flags.single[TEMPLATE_PATH_FLAG];
|
|
159
|
+
const templateFile = flags.single[TEMPLATE_FILE_FLAG];
|
|
160
|
+
const templateInline = flags.single[TEMPLATE_FIELD];
|
|
161
|
+
const parametersInline = flags.single[PARAMETERS_FIELD];
|
|
162
|
+
const parameterValues = flags.repeated[PARAMETER_FLAG] ?? [];
|
|
163
|
+
const envFile = flags.single[ENV_FILE_FLAG];
|
|
164
|
+
if (templatePath && templateFile) {
|
|
165
|
+
throw new Error(`Use either --${TEMPLATE_PATH_FLAG} or --${TEMPLATE_FILE_FLAG}, not both.`);
|
|
166
|
+
}
|
|
167
|
+
const effectiveTemplatePath = templatePath ?? templateFile;
|
|
168
|
+
if (templateInline && effectiveTemplatePath) {
|
|
169
|
+
throw new Error(`Use either --${TEMPLATE_FIELD} or --${TEMPLATE_PATH_FLAG}, not both.`);
|
|
170
|
+
}
|
|
171
|
+
if (parametersInline && parameterValues.length > 0) {
|
|
172
|
+
throw new Error(`Use either --${PARAMETERS_FIELD} or repeatable --${PARAMETER_FLAG}, not both.`);
|
|
173
|
+
}
|
|
174
|
+
let envFileVars = {};
|
|
175
|
+
if (envFile) {
|
|
176
|
+
envFileVars = parseEnvFile({
|
|
177
|
+
envPath: envFile
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
const mergedEnv = {
|
|
181
|
+
...envFileVars,
|
|
182
|
+
...process.env
|
|
183
|
+
};
|
|
184
|
+
if (effectiveTemplatePath) {
|
|
185
|
+
forcedBody[TEMPLATE_FIELD] = readTemplateFromPath({
|
|
186
|
+
templatePath: effectiveTemplatePath
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
if (parameterValues.length > 0) {
|
|
190
|
+
const resolvedParameters = {};
|
|
191
|
+
for (const pair of parameterValues) {
|
|
192
|
+
const eqIdx = pair.indexOf("=");
|
|
193
|
+
if (eqIdx <= 0) {
|
|
194
|
+
throw new Error(`Invalid --${PARAMETER_FLAG} value "${pair}". Expected key=value.`);
|
|
195
|
+
}
|
|
196
|
+
const key = pair.slice(0, eqIdx).trim();
|
|
197
|
+
const rawValue = pair.slice(eqIdx + 1);
|
|
198
|
+
if (!key) {
|
|
199
|
+
throw new Error(`Invalid --${PARAMETER_FLAG} value "${pair}". Parameter key cannot be empty.`);
|
|
200
|
+
}
|
|
201
|
+
resolvedParameters[key] = resolveEnvRef({
|
|
202
|
+
value: rawValue,
|
|
203
|
+
env: mergedEnv
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
forcedBody[PARAMETERS_FIELD] = resolvedParameters;
|
|
207
|
+
}
|
|
208
|
+
delete flags.single[TEMPLATE_PATH_FLAG];
|
|
209
|
+
delete flags.single[TEMPLATE_FILE_FLAG];
|
|
210
|
+
delete flags.single[ENV_FILE_FLAG];
|
|
211
|
+
delete flags.single[PARAMETER_FLAG];
|
|
212
|
+
delete flags.repeated[PARAMETER_FLAG];
|
|
213
|
+
return {
|
|
214
|
+
flags,
|
|
215
|
+
forcedBody
|
|
216
|
+
};
|
|
217
|
+
}, "apply")
|
|
218
|
+
};
|
|
219
|
+
|
|
220
|
+
// src/cli-wrappers/flagParser.ts
|
|
221
|
+
var parseUnknownWithRepeats = /* @__PURE__ */__name(args => {
|
|
222
|
+
const {
|
|
223
|
+
cliArgs
|
|
224
|
+
} = args;
|
|
225
|
+
const single = {};
|
|
226
|
+
const repeated = {};
|
|
227
|
+
for (let i = 0; i < cliArgs.length; i++) {
|
|
228
|
+
const arg = cliArgs[i];
|
|
229
|
+
if (!arg?.startsWith("--")) continue;
|
|
230
|
+
const inlineSplitIdx = arg.indexOf("=");
|
|
231
|
+
const hasInlineValue = inlineSplitIdx > 2;
|
|
232
|
+
const key = hasInlineValue ? arg.slice(2, inlineSplitIdx) : arg.slice(2);
|
|
233
|
+
let value;
|
|
234
|
+
if (hasInlineValue) {
|
|
235
|
+
value = arg.slice(inlineSplitIdx + 1);
|
|
236
|
+
} else {
|
|
237
|
+
const next = cliArgs[i + 1];
|
|
238
|
+
if (next !== void 0 && !next.startsWith("--")) {
|
|
239
|
+
value = next;
|
|
240
|
+
i++;
|
|
241
|
+
} else {
|
|
242
|
+
value = "true";
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
single[key] = value;
|
|
246
|
+
if (!repeated[key]) {
|
|
247
|
+
repeated[key] = [];
|
|
248
|
+
}
|
|
249
|
+
repeated[key].push(value);
|
|
250
|
+
}
|
|
251
|
+
return {
|
|
252
|
+
single,
|
|
253
|
+
repeated
|
|
254
|
+
};
|
|
255
|
+
}, "parseUnknownWithRepeats");
|
|
256
|
+
|
|
257
|
+
// src/cli-wrappers/index.ts
|
|
258
|
+
var WRAPPERS = [agentFormationsWrapper];
|
|
259
|
+
var resolveWrapperForCommand = /* @__PURE__ */__name(args => {
|
|
260
|
+
const {
|
|
261
|
+
commandName
|
|
262
|
+
} = args;
|
|
263
|
+
return WRAPPERS.find(wrapper => {
|
|
264
|
+
return wrapper.commands.includes(commandName);
|
|
265
|
+
});
|
|
266
|
+
}, "resolveWrapperForCommand");
|
|
267
|
+
var applyWrapperForCommand = /* @__PURE__ */__name(args => {
|
|
268
|
+
const {
|
|
269
|
+
commandName,
|
|
270
|
+
route,
|
|
271
|
+
parsedFlags
|
|
272
|
+
} = args;
|
|
273
|
+
const wrapper = resolveWrapperForCommand({
|
|
274
|
+
commandName
|
|
275
|
+
});
|
|
276
|
+
if (!wrapper) {
|
|
277
|
+
return {
|
|
278
|
+
flags: parsedFlags,
|
|
279
|
+
forcedBody: {}
|
|
280
|
+
};
|
|
281
|
+
}
|
|
282
|
+
return wrapper.apply({
|
|
283
|
+
context: {
|
|
284
|
+
commandName,
|
|
285
|
+
route,
|
|
286
|
+
parsedFlags
|
|
287
|
+
}
|
|
288
|
+
});
|
|
289
|
+
}, "applyWrapperForCommand");
|
|
290
|
+
|
|
291
|
+
// src/config.ts
|
|
292
|
+
import * as fs2 from "fs";
|
|
60
293
|
import * as os from "os";
|
|
61
294
|
import * as path from "path";
|
|
62
295
|
import { createClient, createConfig } from "@soat/sdk";
|
|
63
296
|
var CONFIG_FILE = path.join(os.homedir(), ".soat", "config.json");
|
|
64
297
|
var readConfig = /* @__PURE__ */__name(() => {
|
|
65
298
|
try {
|
|
66
|
-
return JSON.parse(
|
|
299
|
+
return JSON.parse(fs2.readFileSync(CONFIG_FILE, "utf8"));
|
|
67
300
|
} catch {
|
|
68
301
|
return {};
|
|
69
302
|
}
|
|
@@ -71,10 +304,10 @@ var readConfig = /* @__PURE__ */__name(() => {
|
|
|
71
304
|
var writeProfile = /* @__PURE__ */__name((name, profile) => {
|
|
72
305
|
const config = readConfig();
|
|
73
306
|
config[name] = profile;
|
|
74
|
-
|
|
307
|
+
fs2.mkdirSync(path.dirname(CONFIG_FILE), {
|
|
75
308
|
recursive: true
|
|
76
309
|
});
|
|
77
|
-
|
|
310
|
+
fs2.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2));
|
|
78
311
|
}, "writeProfile");
|
|
79
312
|
var resolveClient = /* @__PURE__ */__name(profileName => {
|
|
80
313
|
const envBaseUrl = process.env["SOAT_BASE_URL"];
|
|
@@ -1058,23 +1291,6 @@ var toCanonical = /* @__PURE__ */__name(s => {
|
|
|
1058
1291
|
var kebabToSnake = /* @__PURE__ */__name(s => {
|
|
1059
1292
|
return s.replace(/-/g, "_");
|
|
1060
1293
|
}, "kebabToSnake");
|
|
1061
|
-
var parseUnknown = /* @__PURE__ */__name(args => {
|
|
1062
|
-
const result = {};
|
|
1063
|
-
for (let i = 0; i < args.length; i++) {
|
|
1064
|
-
const arg = args[i];
|
|
1065
|
-
if (arg?.startsWith("--")) {
|
|
1066
|
-
const key = arg.slice(2);
|
|
1067
|
-
const val = args[i + 1];
|
|
1068
|
-
if (val !== void 0 && !val.startsWith("--")) {
|
|
1069
|
-
result[key] = val;
|
|
1070
|
-
i++;
|
|
1071
|
-
} else {
|
|
1072
|
-
result[key] = "true";
|
|
1073
|
-
}
|
|
1074
|
-
}
|
|
1075
|
-
}
|
|
1076
|
-
return result;
|
|
1077
|
-
}, "parseUnknown");
|
|
1078
1294
|
var parseFlagValue = /* @__PURE__ */__name(value => {
|
|
1079
1295
|
const trimmed = value.trim();
|
|
1080
1296
|
if (trimmed.startsWith("{") || trimmed.startsWith("[") || trimmed === "true" || trimmed === "false" || trimmed === "null" || /^-?\d+(\.\d+)?$/.test(trimmed)) {
|
|
@@ -1104,6 +1320,11 @@ var resolveServiceClass = /* @__PURE__ */__name(serviceClassName => {
|
|
|
1104
1320
|
}, "resolveServiceClass");
|
|
1105
1321
|
program.name("soat").description("SOAT CLI").version(package_default.version).option("-p, --profile <name>", "config profile to use");
|
|
1106
1322
|
program.command("configure").description("Save credentials to a named profile (~/.soat/config.json)").option("-p, --profile <name>", "profile name", "default").action(async opts => {
|
|
1323
|
+
const [{
|
|
1324
|
+
default: input
|
|
1325
|
+
}, {
|
|
1326
|
+
default: password
|
|
1327
|
+
}] = await Promise.all([import("@inquirer/input"), import("@inquirer/password")]);
|
|
1107
1328
|
const baseUrl = await input({
|
|
1108
1329
|
message: "Base URL:"
|
|
1109
1330
|
});
|
|
@@ -1250,7 +1471,15 @@ program.argument("[command]", "API command in kebab-case (e.g. list-actors)").ar
|
|
|
1250
1471
|
}
|
|
1251
1472
|
const rawIdx = process.argv.indexOf(commandName);
|
|
1252
1473
|
const rawArgs = rawIdx >= 0 ? process.argv.slice(rawIdx + 1) : [];
|
|
1253
|
-
const
|
|
1474
|
+
const parsedFlags = parseUnknownWithRepeats({
|
|
1475
|
+
cliArgs: rawArgs
|
|
1476
|
+
});
|
|
1477
|
+
const wrapped = applyWrapperForCommand({
|
|
1478
|
+
commandName,
|
|
1479
|
+
route,
|
|
1480
|
+
parsedFlags
|
|
1481
|
+
});
|
|
1482
|
+
const flags = wrapped.flags.single;
|
|
1254
1483
|
const pathArgs = {};
|
|
1255
1484
|
const queryArgs = {};
|
|
1256
1485
|
const bodyArgs = {};
|
|
@@ -1287,6 +1516,9 @@ program.argument("[command]", "API command in kebab-case (e.g. list-actors)").ar
|
|
|
1287
1516
|
const callOpts = {
|
|
1288
1517
|
client
|
|
1289
1518
|
};
|
|
1519
|
+
if (Object.keys(wrapped.forcedBody).length) {
|
|
1520
|
+
Object.assign(bodyArgs, wrapped.forcedBody);
|
|
1521
|
+
}
|
|
1290
1522
|
if (Object.keys(pathArgs).length) callOpts["path"] = pathArgs;
|
|
1291
1523
|
if (Object.keys(queryArgs).length) callOpts["query"] = queryArgs;
|
|
1292
1524
|
if (Object.keys(bodyArgs).length) callOpts["body"] = bodyArgs;
|
|
@@ -1305,4 +1537,20 @@ program.argument("[command]", "API command in kebab-case (e.g. list-actors)").ar
|
|
|
1305
1537
|
}
|
|
1306
1538
|
console.log(JSON.stringify(result.data, null, 2));
|
|
1307
1539
|
});
|
|
1308
|
-
|
|
1540
|
+
var runCli = /* @__PURE__ */__name(async args => {
|
|
1541
|
+
const previousArgv = process.argv;
|
|
1542
|
+
process.argv = args;
|
|
1543
|
+
try {
|
|
1544
|
+
await program.parseAsync(args);
|
|
1545
|
+
} finally {
|
|
1546
|
+
process.argv = previousArgv;
|
|
1547
|
+
}
|
|
1548
|
+
}, "runCli");
|
|
1549
|
+
var isMainModule = (() => {
|
|
1550
|
+
if (!process.argv[1]) return false;
|
|
1551
|
+
return nodePath.resolve(process.argv[1]) === fileURLToPath(import.meta.url);
|
|
1552
|
+
})();
|
|
1553
|
+
if (isMainModule) {
|
|
1554
|
+
void runCli(process.argv);
|
|
1555
|
+
}
|
|
1556
|
+
export { runCli };
|
package/package.json
CHANGED
|
@@ -1,21 +1,22 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@soat/cli",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.5",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"dependencies": {
|
|
6
6
|
"@inquirer/input": "^5.0.12",
|
|
7
7
|
"@inquirer/password": "^5.0.12",
|
|
8
8
|
"@ttoss/logger": "^0.8.10",
|
|
9
9
|
"commander": "^14.0.3",
|
|
10
|
-
"
|
|
10
|
+
"js-yaml": "^4.1.1",
|
|
11
|
+
"@soat/sdk": "0.5.5"
|
|
11
12
|
},
|
|
12
13
|
"devDependencies": {
|
|
13
14
|
"@ttoss/config": "^1.37.10",
|
|
15
|
+
"@ttoss/test-utils": "^4.2.10",
|
|
14
16
|
"@types/jest": "^30.0.0",
|
|
15
17
|
"@types/js-yaml": "^4.0.9",
|
|
16
18
|
"@types/node": "^24",
|
|
17
19
|
"jest": "^30.3.0",
|
|
18
|
-
"js-yaml": "^4.1.1",
|
|
19
20
|
"tsup": "^8.5.1",
|
|
20
21
|
"tsx": "^4.21.0"
|
|
21
22
|
},
|
|
@@ -36,8 +37,9 @@
|
|
|
36
37
|
},
|
|
37
38
|
"scripts": {
|
|
38
39
|
"generate": "tsx scripts/generate.ts",
|
|
39
|
-
"lint": "eslint src",
|
|
40
|
-
"
|
|
40
|
+
"lint": "eslint src tests",
|
|
41
|
+
"test": "pnpm --filter @soat/sdk build && jest --config tests/unit/jest.config.ts --coverage=false",
|
|
42
|
+
"typecheck": "tsc --noEmit && tsc --noEmit -p tests/tsconfig.json",
|
|
41
43
|
"build": "pnpm generate && tsup"
|
|
42
44
|
}
|
|
43
45
|
}
|