@rayfold/cli 0.1.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/LICENSE +202 -0
- package/NOTICE +10 -0
- package/README.md +27 -0
- package/import-graphql.js +201 -0
- package/import-graphql.js.map +1 -0
- package/import-openapi.js +302 -0
- package/import-openapi.js.map +1 -0
- package/main.js +442 -0
- package/main.js.map +1 -0
- package/mock.js +184 -0
- package/mock.js.map +1 -0
- package/package.json +48 -0
- package/report.js +171 -0
- package/report.js.map +1 -0
package/main.js
ADDED
|
@@ -0,0 +1,442 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExtension) || function (path, preserveJsx) {
|
|
3
|
+
if (typeof path === "string" && /^\.\.?\//.test(path)) {
|
|
4
|
+
return path.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function (m, tsx, d, ext, cm) {
|
|
5
|
+
return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : (d + ext + "." + cm.toLowerCase() + "js");
|
|
6
|
+
});
|
|
7
|
+
}
|
|
8
|
+
return path;
|
|
9
|
+
};
|
|
10
|
+
/** rayfold CLI: check | lock | hash | explain | gen | shapes | import | mock | lsp | dev */
|
|
11
|
+
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
12
|
+
import { resolve } from "node:path";
|
|
13
|
+
import { pathToFileURL } from "node:url";
|
|
14
|
+
import { canonicalShape, diffSchemas, generateJava, generateKotlin, generateTypeScript, isBreaking, RayfoldSchemaError, RayfoldSyntaxError, loadSchema, parseSchemaText, parseShapeText, printSchemaText, shapeIdOf, validateIR, } from "@rayfold/schema";
|
|
15
|
+
import { checkWiring, estimateCost, defaultShape, pushableFilter, hasPolicy } from "@rayfold/server";
|
|
16
|
+
import { annotation, baseName, fieldsOf, typeRefToString, exprToString } from "@rayfold/schema";
|
|
17
|
+
function usage() {
|
|
18
|
+
console.error(`rayfold <command>
|
|
19
|
+
|
|
20
|
+
check <schema.rayfold> [--against <old.rayfold|rayfold.lock.json>] [--strict] validate; report breaking changes
|
|
21
|
+
check <schema.rayfold> --unused <usage.json> [--since 30d] members no client asked for
|
|
22
|
+
check <schema.rayfold> --resolvers <module> do the resolvers cover the schema?
|
|
23
|
+
lock <schema.rayfold> [--out rayfold.lock.json] record ordinals + hash
|
|
24
|
+
hash <schema.rayfold> print the schema hash
|
|
25
|
+
explain <schema.rayfold> <op> [--shape "{...}"] [--args '{...}'] plan: cost, depth, loaders per level, policy pushdown
|
|
26
|
+
gen ts|kotlin|java <schema.rayfold> [--out file] [--package pkg] [--class Name] generate TypeScript types, Kotlin data classes or Java records
|
|
27
|
+
shapes <schema.rayfold> <shape-file> print shape ids for each line
|
|
28
|
+
import openapi|graphql <file> [--out schema.rayfold] a schema from an OpenAPI document or a GraphQL SDL
|
|
29
|
+
mock <schema.rayfold> [--port 4500] serve the schema with made-up data, and the explorer
|
|
30
|
+
lsp language server for .rayfold, over stdio
|
|
31
|
+
dev <example-dir> [--port 4400] run a server + explorer`);
|
|
32
|
+
process.exit(2);
|
|
33
|
+
}
|
|
34
|
+
function flag(args, name) {
|
|
35
|
+
const i = args.indexOf(name);
|
|
36
|
+
return i >= 0 ? args[i + 1] : undefined;
|
|
37
|
+
}
|
|
38
|
+
function loadFile(path) {
|
|
39
|
+
const text = readFileSync(resolve(path), "utf8");
|
|
40
|
+
return loadSchema(text);
|
|
41
|
+
}
|
|
42
|
+
function loadOld(path) {
|
|
43
|
+
if (path.endsWith(".json"))
|
|
44
|
+
return JSON.parse(readFileSync(resolve(path), "utf8")).ir;
|
|
45
|
+
return loadFile(path).ir;
|
|
46
|
+
}
|
|
47
|
+
/** `30d`, `12h`, `90m`, `45s` as milliseconds. */
|
|
48
|
+
function windowOf(text) {
|
|
49
|
+
const m = /^(\d+)([dhms])$/.exec(text.trim());
|
|
50
|
+
if (!m)
|
|
51
|
+
throw new Error(`--since expects a window such as 30d, 12h or 90m, not ${text}`);
|
|
52
|
+
return Number(m[1]) * { d: 86_400_000, h: 3_600_000, m: 60_000, s: 1000 }[m[2]];
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Members no client asked for inside the window, and the clients still asking for members already deprecated.
|
|
56
|
+
* The snapshot comes from a running server, so "unused" means "no traffic was seen", never "unreachable".
|
|
57
|
+
*/
|
|
58
|
+
function printUnused(ir, entries, windowMs, now) {
|
|
59
|
+
const fresh = entries.filter((e) => Date.parse(e.lastSeen) >= now - windowMs);
|
|
60
|
+
const usedOps = new Set(fresh.filter((e) => !e.path).map((e) => e.op));
|
|
61
|
+
const usedPaths = new Set(fresh.filter((e) => e.path).map((e) => e.path));
|
|
62
|
+
const clientsOf = (path) => [...new Set(fresh.filter((e) => e.path === path).map((e) => e.client || "(unnamed)"))].sort();
|
|
63
|
+
let unused = 0;
|
|
64
|
+
for (const op of Object.values(ir.ops)) {
|
|
65
|
+
if (usedOps.has(op.name))
|
|
66
|
+
continue;
|
|
67
|
+
unused++;
|
|
68
|
+
console.log(`unused ${op.name}(): no traffic`);
|
|
69
|
+
}
|
|
70
|
+
for (const t of Object.values(ir.types)) {
|
|
71
|
+
if (t.builtin || !("fields" in t) || t.kind === "input" || t.kind === "error" || t.kind === "event")
|
|
72
|
+
continue;
|
|
73
|
+
for (const f of t.fields) {
|
|
74
|
+
const path = `${t.name}.${f.name}`;
|
|
75
|
+
if (usedPaths.has(path)) {
|
|
76
|
+
if (annotation(f, "deprecated"))
|
|
77
|
+
console.log(`still used ${path}: ${clientsOf(path).join(", ")}`);
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
unused++;
|
|
81
|
+
console.log(`unused ${path}: no traffic`);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
const clients = new Set(fresh.map((e) => e.client || "(unnamed)"));
|
|
85
|
+
const stale = entries.length - fresh.length;
|
|
86
|
+
console.log(`\n${unused} member${unused === 1 ? "" : "s"} with no traffic from ${clients.size} client${clients.size === 1 ? "" : "s"}; ${stale} record${stale === 1 ? "" : "s"} older than the window.`);
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* The resolvers a module offers: an object named `resolvers`, the default export, or a factory that makes one. A
|
|
90
|
+
* factory is called with no arguments, which is enough to read its keys; whatever it needs belongs inside a handler.
|
|
91
|
+
*/
|
|
92
|
+
function resolversFrom(module) {
|
|
93
|
+
const candidates = [module["resolvers"], module["default"], ...Object.entries(module).filter(([k]) => /resolvers$/i.test(k)).map(([, v]) => v)];
|
|
94
|
+
for (const candidate of candidates) {
|
|
95
|
+
if (typeof candidate === "function")
|
|
96
|
+
return candidate();
|
|
97
|
+
if (candidate && typeof candidate === "object")
|
|
98
|
+
return candidate;
|
|
99
|
+
}
|
|
100
|
+
throw new Error("no resolvers found: export `resolvers`, a default export, or a function that returns them");
|
|
101
|
+
}
|
|
102
|
+
function printChanges(changes) {
|
|
103
|
+
const order = { breaking: 0, warning: 1, compatible: 2 };
|
|
104
|
+
for (const c of [...changes].sort((a, b) => order[a.level] - order[b.level])) {
|
|
105
|
+
const tag = c.level === "breaking" ? "BREAKING" : c.level === "warning" ? "warning " : "ok ";
|
|
106
|
+
console.log(`${tag} ${c.at}: ${c.message} [${c.code}]`);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
async function main(argv) {
|
|
110
|
+
const [cmd, ...rest] = argv;
|
|
111
|
+
switch (cmd) {
|
|
112
|
+
case "check": {
|
|
113
|
+
const path = rest[0];
|
|
114
|
+
if (!path)
|
|
115
|
+
usage();
|
|
116
|
+
const source = readFileSync(resolve(path), "utf8");
|
|
117
|
+
const { findingsFor, renderFinding, syntaxFinding } = await import("./report.js");
|
|
118
|
+
let loaded;
|
|
119
|
+
try {
|
|
120
|
+
loaded = loadSchema(source);
|
|
121
|
+
}
|
|
122
|
+
catch (e) {
|
|
123
|
+
if (e instanceof RayfoldSchemaError) {
|
|
124
|
+
// the text parsed, so there is an IR to read the likely fix out of
|
|
125
|
+
let ir;
|
|
126
|
+
try {
|
|
127
|
+
ir = parseSchemaText(source);
|
|
128
|
+
}
|
|
129
|
+
catch {
|
|
130
|
+
ir = undefined;
|
|
131
|
+
}
|
|
132
|
+
for (const finding of findingsFor(source, e.diagnostics)) {
|
|
133
|
+
console.error(renderFinding(path, source, finding, ir));
|
|
134
|
+
console.error("");
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
else if (e instanceof RayfoldSyntaxError) {
|
|
138
|
+
console.error(renderFinding(path, source, syntaxFinding(e)));
|
|
139
|
+
}
|
|
140
|
+
else
|
|
141
|
+
console.error(String(e.message));
|
|
142
|
+
return 1;
|
|
143
|
+
}
|
|
144
|
+
for (const finding of findingsFor(source, loaded.warnings)) {
|
|
145
|
+
console.log(renderFinding(path, source, finding, loaded.ir));
|
|
146
|
+
console.log("");
|
|
147
|
+
}
|
|
148
|
+
const wiring = flag(rest, "--resolvers");
|
|
149
|
+
if (wiring) {
|
|
150
|
+
let resolvers;
|
|
151
|
+
try {
|
|
152
|
+
resolvers = resolversFrom((await import(__rewriteRelativeImportExtension(pathToFileURL(resolve(wiring)).href))));
|
|
153
|
+
}
|
|
154
|
+
catch (e) {
|
|
155
|
+
console.error(`${wiring}: ${String(e.message)}`);
|
|
156
|
+
return 1;
|
|
157
|
+
}
|
|
158
|
+
const findings = findingsFor(source, checkWiring(loaded.ir, resolvers));
|
|
159
|
+
for (const finding of findings) {
|
|
160
|
+
console.log(renderFinding(path, source, finding, loaded.ir));
|
|
161
|
+
console.log("");
|
|
162
|
+
}
|
|
163
|
+
const errors = findings.filter((f) => f.severity === "error").length;
|
|
164
|
+
if (errors) {
|
|
165
|
+
console.error(`FAILED: ${errors} operation${errors === 1 ? "" : "s"} or field${errors === 1 ? "" : "s"} the resolvers do not cover`);
|
|
166
|
+
return 1;
|
|
167
|
+
}
|
|
168
|
+
const ops = Object.keys(loaded.ir.ops).length;
|
|
169
|
+
console.log(`OK: the resolvers cover all ${ops} operation${ops === 1 ? "" : "s"} and every field that takes arguments`);
|
|
170
|
+
return 0;
|
|
171
|
+
}
|
|
172
|
+
const unused = flag(rest, "--unused");
|
|
173
|
+
if (unused) {
|
|
174
|
+
let entries;
|
|
175
|
+
try {
|
|
176
|
+
entries = JSON.parse(readFileSync(resolve(unused), "utf8"));
|
|
177
|
+
if (!Array.isArray(entries))
|
|
178
|
+
throw new Error("expected a list of usage records");
|
|
179
|
+
}
|
|
180
|
+
catch (e) {
|
|
181
|
+
console.error(`${unused}: ${String(e.message)}`);
|
|
182
|
+
return 1;
|
|
183
|
+
}
|
|
184
|
+
try {
|
|
185
|
+
printUnused(loaded.ir, entries, windowOf(flag(rest, "--since") ?? "30d"), Date.now());
|
|
186
|
+
}
|
|
187
|
+
catch (e) {
|
|
188
|
+
console.error(String(e.message));
|
|
189
|
+
return 2;
|
|
190
|
+
}
|
|
191
|
+
return 0;
|
|
192
|
+
}
|
|
193
|
+
const against = flag(rest, "--against") ?? (existsSync("rayfold.lock.json") ? "rayfold.lock.json" : undefined);
|
|
194
|
+
if (against) {
|
|
195
|
+
const changes = diffSchemas(loadOld(against), loaded.ir);
|
|
196
|
+
printChanges(changes);
|
|
197
|
+
const strict = rest.includes("--strict");
|
|
198
|
+
if (isBreaking(changes) || (strict && changes.some((c) => c.level === "warning"))) {
|
|
199
|
+
console.log(`\n${loaded.ir ? "" : ""}FAILED: breaking changes against ${against}`);
|
|
200
|
+
return 1;
|
|
201
|
+
}
|
|
202
|
+
console.log(`\nOK: compatible with ${against} (${changes.length} change${changes.length === 1 ? "" : "s"})`);
|
|
203
|
+
}
|
|
204
|
+
else
|
|
205
|
+
console.log(`OK: ${path} is valid (hash ${loaded.hash.slice(0, 12)})`);
|
|
206
|
+
return 0;
|
|
207
|
+
}
|
|
208
|
+
case "lock": {
|
|
209
|
+
const path = rest[0];
|
|
210
|
+
if (!path)
|
|
211
|
+
usage();
|
|
212
|
+
const loaded = loadFile(path);
|
|
213
|
+
const out = flag(rest, "--out") ?? "rayfold.lock.json";
|
|
214
|
+
const lock = { rayfold: "0.1", hash: loaded.hash, ir: loaded.ir, lockedAt: new Date().toISOString() };
|
|
215
|
+
writeFileSync(out, JSON.stringify(lock, null, 2) + "\n");
|
|
216
|
+
console.log(`wrote ${out} (hash ${loaded.hash.slice(0, 12)})`);
|
|
217
|
+
return 0;
|
|
218
|
+
}
|
|
219
|
+
case "hash": {
|
|
220
|
+
const path = rest[0];
|
|
221
|
+
if (!path)
|
|
222
|
+
usage();
|
|
223
|
+
console.log(loadFile(path).hash);
|
|
224
|
+
return 0;
|
|
225
|
+
}
|
|
226
|
+
case "explain": {
|
|
227
|
+
const [path, opName] = rest;
|
|
228
|
+
if (!path || !opName)
|
|
229
|
+
usage();
|
|
230
|
+
const { ir } = loadFile(path);
|
|
231
|
+
const op = ir.ops[opName];
|
|
232
|
+
if (!op) {
|
|
233
|
+
console.error(`Unknown operation ${opName}`);
|
|
234
|
+
return 1;
|
|
235
|
+
}
|
|
236
|
+
const shapeText = flag(rest, "--shape");
|
|
237
|
+
const args = JSON.parse(flag(rest, "--args") ?? "{}");
|
|
238
|
+
const shape = shapeText ? parseShapeText(shapeText) : defaultShape(ir, op.returns);
|
|
239
|
+
const est = estimateCost(ir, op, args, shape);
|
|
240
|
+
console.log(`${op.kind} ${op.name}(): cost ${est.cost}, depth ${est.depth}, ${est.fields} field${est.fields === 1 ? "" : "s"}`);
|
|
241
|
+
console.log(`shape: ${canonicalShape(shape, (t, v) => ir.views[`${t}.${v}`])}`);
|
|
242
|
+
console.log(`policy: ${hasPolicy(op.annotations, op.kind === "command" ? "write" : "read") ? "op-level policy" : "none"}`);
|
|
243
|
+
console.log("plan:");
|
|
244
|
+
const walk = (t, s, level) => {
|
|
245
|
+
const name = baseName(t);
|
|
246
|
+
const def = ir.types[name];
|
|
247
|
+
if (!def || !("fields" in def))
|
|
248
|
+
return;
|
|
249
|
+
const fs = fieldsOf(ir, t) ?? [];
|
|
250
|
+
const pf = pushableFilter(def.annotations);
|
|
251
|
+
const pol = hasPolicy(def.annotations, "read") ? (pf ? ` [policy pushed down: ${exprToString(pf)}]` : " [policy post-filtered]") : "";
|
|
252
|
+
console.log(`${" ".repeat(level)}level ${level}: ${typeRefToString(t)}${pol}`);
|
|
253
|
+
for (const it of s.items) {
|
|
254
|
+
if (it.kind !== "field")
|
|
255
|
+
continue;
|
|
256
|
+
const f = fs.find((x) => x.name === it.name);
|
|
257
|
+
if (!f)
|
|
258
|
+
continue;
|
|
259
|
+
const scalar = ir.types[baseName(f.type)]?.kind === "scalar" || ir.types[baseName(f.type)]?.kind === "enum";
|
|
260
|
+
const load = annotation(f, "load");
|
|
261
|
+
const builtin = ir.types[name]?.builtin;
|
|
262
|
+
const mode = scalar || builtin ? "property" : load && load.args["value"]?.$ident === "single" ? "loader (single, per parent)" : "loader (batch, 1 call)";
|
|
263
|
+
const fp = f.annotations.some((a) => a.name === "allow" || a.name === "deny") ? " [field policy]" : "";
|
|
264
|
+
const lazy = annotation(f, "lazy") && !it.eager ? " [deferred]" : "";
|
|
265
|
+
console.log(`${" ".repeat(level + 1)}${it.alias ?? it.name}: ${mode}${fp}${lazy}`);
|
|
266
|
+
if (!scalar)
|
|
267
|
+
walk(f.type, it.shape ?? defaultShape(ir, f.type), level + 1);
|
|
268
|
+
}
|
|
269
|
+
};
|
|
270
|
+
walk(op.returns, shape, 0);
|
|
271
|
+
return 0;
|
|
272
|
+
}
|
|
273
|
+
case "gen": {
|
|
274
|
+
const [lang, path] = rest;
|
|
275
|
+
if (!path)
|
|
276
|
+
usage();
|
|
277
|
+
const { ir } = loadFile(path);
|
|
278
|
+
let text;
|
|
279
|
+
if (lang === "ts")
|
|
280
|
+
text = generateTypeScript(ir);
|
|
281
|
+
else if (lang === "kotlin")
|
|
282
|
+
text = generateKotlin(ir, { pkg: flag(rest, "--package") ?? "dev.rayfold.generated" });
|
|
283
|
+
else if (lang === "java")
|
|
284
|
+
text = generateJava(ir, { pkg: flag(rest, "--package") ?? "dev.rayfold.generated", className: flag(rest, "--class") ?? "RayfoldSchema" });
|
|
285
|
+
else {
|
|
286
|
+
console.error(`Unsupported target ${lang} (ts, kotlin, java)`);
|
|
287
|
+
return 1;
|
|
288
|
+
}
|
|
289
|
+
const out = flag(rest, "--out");
|
|
290
|
+
if (out) {
|
|
291
|
+
writeFileSync(out, text);
|
|
292
|
+
console.log(`wrote ${out}`);
|
|
293
|
+
}
|
|
294
|
+
else
|
|
295
|
+
process.stdout.write(text);
|
|
296
|
+
return 0;
|
|
297
|
+
}
|
|
298
|
+
case "shapes": {
|
|
299
|
+
const [path, file] = rest;
|
|
300
|
+
if (!path || !file)
|
|
301
|
+
usage();
|
|
302
|
+
const { ir } = loadFile(path);
|
|
303
|
+
const views = (t, v) => ir.views[`${t}.${v}`];
|
|
304
|
+
const lines = readFileSync(resolve(file), "utf8").split(/\r?\n/).filter((l) => l.trim());
|
|
305
|
+
const map = {};
|
|
306
|
+
for (const l of lines) {
|
|
307
|
+
const canon = canonicalShape(parseShapeText(l), views);
|
|
308
|
+
map[shapeIdOf(canon)] = canon;
|
|
309
|
+
}
|
|
310
|
+
console.log(JSON.stringify(map, null, 2));
|
|
311
|
+
return 0;
|
|
312
|
+
}
|
|
313
|
+
case "import": {
|
|
314
|
+
const [source, path] = rest;
|
|
315
|
+
if (!source || !path)
|
|
316
|
+
usage();
|
|
317
|
+
let imported;
|
|
318
|
+
try {
|
|
319
|
+
const text = readFileSync(resolve(path), "utf8");
|
|
320
|
+
if (source === "openapi") {
|
|
321
|
+
const { irFromOpenApi } = await import("./import-openapi.js");
|
|
322
|
+
imported = irFromOpenApi(JSON.parse(text));
|
|
323
|
+
}
|
|
324
|
+
else if (source === "graphql") {
|
|
325
|
+
const { irFromGraphql } = await import("./import-graphql.js");
|
|
326
|
+
imported = await irFromGraphql(text);
|
|
327
|
+
}
|
|
328
|
+
else {
|
|
329
|
+
console.error(`Unsupported source ${source} (openapi, graphql)`);
|
|
330
|
+
return 1;
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
catch (e) {
|
|
334
|
+
console.error(String(e.message));
|
|
335
|
+
return 1;
|
|
336
|
+
}
|
|
337
|
+
const text = printSchemaText(imported.ir);
|
|
338
|
+
const out = flag(rest, "--out");
|
|
339
|
+
if (out) {
|
|
340
|
+
writeFileSync(out, text);
|
|
341
|
+
console.log(`wrote ${out}`);
|
|
342
|
+
}
|
|
343
|
+
else
|
|
344
|
+
process.stdout.write(text);
|
|
345
|
+
// what the source could not say, on stderr, so the schema on stdout stays a schema
|
|
346
|
+
for (const note of imported.notes)
|
|
347
|
+
console.error(`note ${note}`);
|
|
348
|
+
return 0;
|
|
349
|
+
}
|
|
350
|
+
case "mock": {
|
|
351
|
+
const path = rest[0];
|
|
352
|
+
if (!path)
|
|
353
|
+
usage();
|
|
354
|
+
const port = Number(flag(rest, "--port") ?? 4500);
|
|
355
|
+
const { ir, hash } = loadFile(path);
|
|
356
|
+
const { mockResolvers } = await import("./mock.js");
|
|
357
|
+
const srv = await import("@rayfold/server");
|
|
358
|
+
const { createExplorerHandler } = await import("@rayfold/explorer");
|
|
359
|
+
const server = srv.createRayfoldServer({ schema: ir, resolvers: mockResolvers(ir) });
|
|
360
|
+
// a mock signs you in: it exists to answer, not to refuse
|
|
361
|
+
const handler = srv.createHttpHandler(server, { cors: "*", viewer: () => ({ id: "u1", role: "admin" }) });
|
|
362
|
+
const explorer = createExplorerHandler({ endpoint: "/rayfold", title: "Rayfold mock" });
|
|
363
|
+
const { createServer } = await import("node:http");
|
|
364
|
+
const http = createServer((req, res) => {
|
|
365
|
+
if (explorer(req, res))
|
|
366
|
+
return;
|
|
367
|
+
if ((req.url ?? "/").startsWith("/rayfold"))
|
|
368
|
+
return void handler(req, res);
|
|
369
|
+
res.writeHead(302, { location: "/rayfold/explorer" }).end();
|
|
370
|
+
});
|
|
371
|
+
srv.attachWebSocket(http, server, { viewer: () => ({ id: "u1", role: "admin" }) });
|
|
372
|
+
await new Promise((ready) => http.listen(port, ready));
|
|
373
|
+
console.log(`Rayfold mock of ${path} (schema ${hash.slice(0, 12)})`);
|
|
374
|
+
console.log(` HTTP http://localhost:${port}/rayfold`);
|
|
375
|
+
console.log(` Explorer http://localhost:${port}/rayfold/explorer`);
|
|
376
|
+
console.log(` the same call always gives the same answer`);
|
|
377
|
+
await new Promise(() => { });
|
|
378
|
+
return 0;
|
|
379
|
+
}
|
|
380
|
+
case "lsp": {
|
|
381
|
+
const { serveStdio } = await import("@rayfold/lsp");
|
|
382
|
+
// runs until the editor sends `exit` or closes the pipe
|
|
383
|
+
await new Promise((done) => serveStdio(process.stdin, process.stdout, { onExit: done }));
|
|
384
|
+
return 0;
|
|
385
|
+
}
|
|
386
|
+
case "dev": {
|
|
387
|
+
const dir = rest[0];
|
|
388
|
+
if (!dir)
|
|
389
|
+
usage();
|
|
390
|
+
const port = Number(flag(rest, "--port") ?? 4400);
|
|
391
|
+
const mod = (await import(__rewriteRelativeImportExtension(pathToFileURL(resolve(dir, "src/index.ts")).href)));
|
|
392
|
+
if (!mod.createBookstore) {
|
|
393
|
+
console.error("dev expects an example exporting createBookstore()");
|
|
394
|
+
return 1;
|
|
395
|
+
}
|
|
396
|
+
const srv = await import("@rayfold/server");
|
|
397
|
+
const { server } = mod.createBookstore();
|
|
398
|
+
const { createExplorerHandler } = await import("@rayfold/explorer");
|
|
399
|
+
const viewer = (req) => {
|
|
400
|
+
const a = req.headers.authorization ?? new URL(req.url ?? "/", "http://x").searchParams.get("auth") ?? undefined;
|
|
401
|
+
if (a === "Bearer admin")
|
|
402
|
+
return { id: "u9", role: "admin" };
|
|
403
|
+
if (a?.startsWith("Bearer "))
|
|
404
|
+
return { id: a.slice(7), role: "customer" };
|
|
405
|
+
return null;
|
|
406
|
+
};
|
|
407
|
+
const rayfoldHandler = srv.createHttpHandler(server, { cors: "*", viewer });
|
|
408
|
+
const mcpHandler = srv.createMcpHandler(server, { viewer });
|
|
409
|
+
const explorer = createExplorerHandler({ endpoint: "/rayfold", title: "Rayfold dev" });
|
|
410
|
+
const { createServer } = await import("node:http");
|
|
411
|
+
const http = createServer((req, res) => {
|
|
412
|
+
void (async () => {
|
|
413
|
+
if (explorer(req, res))
|
|
414
|
+
return; // before the endpoint: the page lives under its path
|
|
415
|
+
if ((req.url ?? "/").startsWith("/rayfold"))
|
|
416
|
+
return rayfoldHandler(req, res);
|
|
417
|
+
if (await mcpHandler(req, res))
|
|
418
|
+
return;
|
|
419
|
+
res.writeHead(302, { location: "/rayfold/explorer" }).end();
|
|
420
|
+
})();
|
|
421
|
+
});
|
|
422
|
+
srv.attachWebSocket(http, server, { viewer });
|
|
423
|
+
await new Promise((r) => http.listen(port, r));
|
|
424
|
+
console.log(`Rayfold dev server: http://localhost:${port}/`);
|
|
425
|
+
console.log(` Explorer http://localhost:${port}/rayfold/explorer`);
|
|
426
|
+
console.log(` HTTP http://localhost:${port}/rayfold (POST/QUERY batches, GET /rayfold/{op}, /rayfold/manifest)`);
|
|
427
|
+
console.log(` WebSocket ws://localhost:${port}/rayfold/ws (subprotocol rayfold.0.1)`);
|
|
428
|
+
console.log(` MCP http://localhost:${port}/mcp (Streamable HTTP, ${srv.MCP_PROTOCOL_VERSION})`);
|
|
429
|
+
console.log(` schema ${server.hash.slice(0, 12)}`);
|
|
430
|
+
await new Promise(() => { });
|
|
431
|
+
return 0;
|
|
432
|
+
}
|
|
433
|
+
default:
|
|
434
|
+
usage();
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
main(process.argv.slice(2)).then((code) => process.exit(code), (e) => {
|
|
438
|
+
console.error(e instanceof Error ? e.message : String(e));
|
|
439
|
+
process.exit(1);
|
|
440
|
+
});
|
|
441
|
+
export { validateIR };
|
|
442
|
+
//# sourceMappingURL=main.js.map
|
package/main.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"main.js","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":"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","sourcesContent":["#!/usr/bin/env node\n/** rayfold CLI: check | lock | hash | explain | gen | shapes | import | mock | lsp | dev */\nimport { existsSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\nimport { pathToFileURL } from \"node:url\";\nimport {\n canonicalShape,\n diffSchemas,\n generateJava,\n generateKotlin,\n generateTypeScript,\n isBreaking,\n RayfoldSchemaError,\n RayfoldSyntaxError,\n loadSchema,\n parseSchemaText,\n parseShapeText,\n printSchemaText,\n shapeIdOf,\n validateIR,\n type Change,\n type RayfoldSchemaIR,\n} from \"@rayfold/schema\";\nimport { checkWiring, estimateCost, defaultShape, pushableFilter, hasPolicy, type Resolvers, type UsageEntry } from \"@rayfold/server\";\nimport { annotation, baseName, fieldsOf, typeRefToString, type TypeRef, exprToString } from \"@rayfold/schema\";\n\ninterface Lock {\n rayfold: \"0.1\";\n hash: string;\n ir: RayfoldSchemaIR;\n lockedAt: string;\n}\n\nfunction usage(): never {\n console.error(`rayfold <command>\n\n check <schema.rayfold> [--against <old.rayfold|rayfold.lock.json>] [--strict] validate; report breaking changes\n check <schema.rayfold> --unused <usage.json> [--since 30d] members no client asked for\n check <schema.rayfold> --resolvers <module> do the resolvers cover the schema?\n lock <schema.rayfold> [--out rayfold.lock.json] record ordinals + hash\n hash <schema.rayfold> print the schema hash\n explain <schema.rayfold> <op> [--shape \"{...}\"] [--args '{...}'] plan: cost, depth, loaders per level, policy pushdown\n gen ts|kotlin|java <schema.rayfold> [--out file] [--package pkg] [--class Name] generate TypeScript types, Kotlin data classes or Java records\n shapes <schema.rayfold> <shape-file> print shape ids for each line\n import openapi|graphql <file> [--out schema.rayfold] a schema from an OpenAPI document or a GraphQL SDL\n mock <schema.rayfold> [--port 4500] serve the schema with made-up data, and the explorer\n lsp language server for .rayfold, over stdio\n dev <example-dir> [--port 4400] run a server + explorer`);\n process.exit(2);\n}\n\nfunction flag(args: string[], name: string): string | undefined {\n const i = args.indexOf(name);\n return i >= 0 ? args[i + 1] : undefined;\n}\n\nfunction loadFile(path: string): ReturnType<typeof loadSchema> {\n const text = readFileSync(resolve(path), \"utf8\");\n return loadSchema(text);\n}\n\nfunction loadOld(path: string): RayfoldSchemaIR {\n if (path.endsWith(\".json\")) return (JSON.parse(readFileSync(resolve(path), \"utf8\")) as Lock).ir;\n return loadFile(path).ir;\n}\n\n/** `30d`, `12h`, `90m`, `45s` as milliseconds. */\nfunction windowOf(text: string): number {\n const m = /^(\\d+)([dhms])$/.exec(text.trim());\n if (!m) throw new Error(`--since expects a window such as 30d, 12h or 90m, not ${text}`);\n return Number(m[1]) * { d: 86_400_000, h: 3_600_000, m: 60_000, s: 1000 }[m[2] as \"d\" | \"h\" | \"m\" | \"s\"];\n}\n\n/**\n * Members no client asked for inside the window, and the clients still asking for members already deprecated.\n * The snapshot comes from a running server, so \"unused\" means \"no traffic was seen\", never \"unreachable\".\n */\nfunction printUnused(ir: RayfoldSchemaIR, entries: UsageEntry[], windowMs: number, now: number): void {\n const fresh = entries.filter((e) => Date.parse(e.lastSeen) >= now - windowMs);\n const usedOps = new Set(fresh.filter((e) => !e.path).map((e) => e.op));\n const usedPaths = new Set(fresh.filter((e) => e.path).map((e) => e.path));\n const clientsOf = (path: string) => [...new Set(fresh.filter((e) => e.path === path).map((e) => e.client || \"(unnamed)\"))].sort();\n\n let unused = 0;\n for (const op of Object.values(ir.ops)) {\n if (usedOps.has(op.name)) continue;\n unused++;\n console.log(`unused ${op.name}(): no traffic`);\n }\n for (const t of Object.values(ir.types)) {\n if (t.builtin || !(\"fields\" in t) || t.kind === \"input\" || t.kind === \"error\" || t.kind === \"event\") continue;\n for (const f of t.fields) {\n const path = `${t.name}.${f.name}`;\n if (usedPaths.has(path)) {\n if (annotation(f, \"deprecated\")) console.log(`still used ${path}: ${clientsOf(path).join(\", \")}`);\n continue;\n }\n unused++;\n console.log(`unused ${path}: no traffic`);\n }\n }\n const clients = new Set(fresh.map((e) => e.client || \"(unnamed)\"));\n const stale = entries.length - fresh.length;\n console.log(`\\n${unused} member${unused === 1 ? \"\" : \"s\"} with no traffic from ${clients.size} client${clients.size === 1 ? \"\" : \"s\"}; ${stale} record${stale === 1 ? \"\" : \"s\"} older than the window.`);\n}\n\n/**\n * The resolvers a module offers: an object named `resolvers`, the default export, or a factory that makes one. A\n * factory is called with no arguments, which is enough to read its keys; whatever it needs belongs inside a handler.\n */\nfunction resolversFrom(module: Record<string, unknown>): Resolvers {\n const candidates = [module[\"resolvers\"], module[\"default\"], ...Object.entries(module).filter(([k]) => /resolvers$/i.test(k)).map(([, v]) => v)];\n for (const candidate of candidates) {\n if (typeof candidate === \"function\") return (candidate as () => Resolvers)();\n if (candidate && typeof candidate === \"object\") return candidate as Resolvers;\n }\n throw new Error(\"no resolvers found: export `resolvers`, a default export, or a function that returns them\");\n}\n\nfunction printChanges(changes: Change[]): void {\n const order = { breaking: 0, warning: 1, compatible: 2 };\n for (const c of [...changes].sort((a, b) => order[a.level] - order[b.level])) {\n const tag = c.level === \"breaking\" ? \"BREAKING\" : c.level === \"warning\" ? \"warning \" : \"ok \";\n console.log(`${tag} ${c.at}: ${c.message} [${c.code}]`);\n }\n}\n\nasync function main(argv: string[]): Promise<number> {\n const [cmd, ...rest] = argv;\n switch (cmd) {\n case \"check\": {\n const path = rest[0];\n if (!path) usage();\n const source = readFileSync(resolve(path), \"utf8\");\n const { findingsFor, renderFinding, syntaxFinding } = await import(\"./report.ts\");\n let loaded;\n try {\n loaded = loadSchema(source);\n } catch (e) {\n if (e instanceof RayfoldSchemaError) {\n // the text parsed, so there is an IR to read the likely fix out of\n let ir: RayfoldSchemaIR | undefined;\n try {\n ir = parseSchemaText(source);\n } catch {\n ir = undefined;\n }\n for (const finding of findingsFor(source, e.diagnostics)) {\n console.error(renderFinding(path, source, finding, ir));\n console.error(\"\");\n }\n } else if (e instanceof RayfoldSyntaxError) {\n console.error(renderFinding(path, source, syntaxFinding(e)));\n } else console.error(String((e as Error).message));\n return 1;\n }\n for (const finding of findingsFor(source, loaded.warnings)) {\n console.log(renderFinding(path, source, finding, loaded.ir));\n console.log(\"\");\n }\n const wiring = flag(rest, \"--resolvers\");\n if (wiring) {\n let resolvers: Resolvers;\n try {\n resolvers = resolversFrom((await import(pathToFileURL(resolve(wiring)).href)) as Record<string, unknown>);\n } catch (e) {\n console.error(`${wiring}: ${String((e as Error).message)}`);\n return 1;\n }\n const findings = findingsFor(source, checkWiring(loaded.ir, resolvers));\n for (const finding of findings) {\n console.log(renderFinding(path, source, finding, loaded.ir));\n console.log(\"\");\n }\n const errors = findings.filter((f) => f.severity === \"error\").length;\n if (errors) {\n console.error(`FAILED: ${errors} operation${errors === 1 ? \"\" : \"s\"} or field${errors === 1 ? \"\" : \"s\"} the resolvers do not cover`);\n return 1;\n }\n const ops = Object.keys(loaded.ir.ops).length;\n console.log(`OK: the resolvers cover all ${ops} operation${ops === 1 ? \"\" : \"s\"} and every field that takes arguments`);\n return 0;\n }\n const unused = flag(rest, \"--unused\");\n if (unused) {\n let entries: UsageEntry[];\n try {\n entries = JSON.parse(readFileSync(resolve(unused), \"utf8\")) as UsageEntry[];\n if (!Array.isArray(entries)) throw new Error(\"expected a list of usage records\");\n } catch (e) {\n console.error(`${unused}: ${String((e as Error).message)}`);\n return 1;\n }\n try {\n printUnused(loaded.ir, entries, windowOf(flag(rest, \"--since\") ?? \"30d\"), Date.now());\n } catch (e) {\n console.error(String((e as Error).message));\n return 2;\n }\n return 0;\n }\n const against = flag(rest, \"--against\") ?? (existsSync(\"rayfold.lock.json\") ? \"rayfold.lock.json\" : undefined);\n if (against) {\n const changes = diffSchemas(loadOld(against), loaded.ir);\n printChanges(changes);\n const strict = rest.includes(\"--strict\");\n if (isBreaking(changes) || (strict && changes.some((c) => c.level === \"warning\"))) {\n console.log(`\\n${loaded.ir ? \"\" : \"\"}FAILED: breaking changes against ${against}`);\n return 1;\n }\n console.log(`\\nOK: compatible with ${against} (${changes.length} change${changes.length === 1 ? \"\" : \"s\"})`);\n } else console.log(`OK: ${path} is valid (hash ${loaded.hash.slice(0, 12)})`);\n return 0;\n }\n case \"lock\": {\n const path = rest[0];\n if (!path) usage();\n const loaded = loadFile(path);\n const out = flag(rest, \"--out\") ?? \"rayfold.lock.json\";\n const lock: Lock = { rayfold: \"0.1\", hash: loaded.hash, ir: loaded.ir, lockedAt: new Date().toISOString() };\n writeFileSync(out, JSON.stringify(lock, null, 2) + \"\\n\");\n console.log(`wrote ${out} (hash ${loaded.hash.slice(0, 12)})`);\n return 0;\n }\n case \"hash\": {\n const path = rest[0];\n if (!path) usage();\n console.log(loadFile(path).hash);\n return 0;\n }\n case \"explain\": {\n const [path, opName] = rest;\n if (!path || !opName) usage();\n const { ir } = loadFile(path);\n const op = ir.ops[opName];\n if (!op) {\n console.error(`Unknown operation ${opName}`);\n return 1;\n }\n const shapeText = flag(rest, \"--shape\");\n const args = JSON.parse(flag(rest, \"--args\") ?? \"{}\") as Record<string, unknown>;\n const shape = shapeText ? parseShapeText(shapeText) : defaultShape(ir, op.returns);\n const est = estimateCost(ir, op, args, shape);\n console.log(`${op.kind} ${op.name}(): cost ${est.cost}, depth ${est.depth}, ${est.fields} field${est.fields === 1 ? \"\" : \"s\"}`);\n console.log(`shape: ${canonicalShape(shape, (t, v) => ir.views[`${t}.${v}`])}`);\n console.log(`policy: ${hasPolicy(op.annotations, op.kind === \"command\" ? \"write\" : \"read\") ? \"op-level policy\" : \"none\"}`);\n console.log(\"plan:\");\n const walk = (t: TypeRef, s: typeof shape, level: number): void => {\n const name = baseName(t);\n const def = ir.types[name];\n if (!def || !(\"fields\" in def)) return;\n const fs = fieldsOf(ir, t) ?? [];\n const pf = pushableFilter(def.annotations);\n const pol = hasPolicy(def.annotations, \"read\") ? (pf ? ` [policy pushed down: ${exprToString(pf)}]` : \" [policy post-filtered]\") : \"\";\n console.log(`${\" \".repeat(level)}level ${level}: ${typeRefToString(t)}${pol}`);\n for (const it of s.items) {\n if (it.kind !== \"field\") continue;\n const f = fs.find((x) => x.name === it.name);\n if (!f) continue;\n const scalar = ir.types[baseName(f.type)]?.kind === \"scalar\" || ir.types[baseName(f.type)]?.kind === \"enum\";\n const load = annotation(f, \"load\");\n const builtin = ir.types[name]?.builtin;\n const mode = scalar || builtin ? \"property\" : load && (load.args[\"value\"] as { $ident?: string })?.$ident === \"single\" ? \"loader (single, per parent)\" : \"loader (batch, 1 call)\";\n const fp = f.annotations.some((a) => a.name === \"allow\" || a.name === \"deny\") ? \" [field policy]\" : \"\";\n const lazy = annotation(f, \"lazy\") && !it.eager ? \" [deferred]\" : \"\";\n console.log(`${\" \".repeat(level + 1)}${it.alias ?? it.name}: ${mode}${fp}${lazy}`);\n if (!scalar) walk(f.type, it.shape ?? defaultShape(ir, f.type), level + 1);\n }\n };\n walk(op.returns, shape, 0);\n return 0;\n }\n case \"gen\": {\n const [lang, path] = rest;\n if (!path) usage();\n const { ir } = loadFile(path);\n let text: string;\n if (lang === \"ts\") text = generateTypeScript(ir);\n else if (lang === \"kotlin\") text = generateKotlin(ir, { pkg: flag(rest, \"--package\") ?? \"dev.rayfold.generated\" });\n else if (lang === \"java\") text = generateJava(ir, { pkg: flag(rest, \"--package\") ?? \"dev.rayfold.generated\", className: flag(rest, \"--class\") ?? \"RayfoldSchema\" });\n else {\n console.error(`Unsupported target ${lang} (ts, kotlin, java)`);\n return 1;\n }\n const out = flag(rest, \"--out\");\n if (out) {\n writeFileSync(out, text);\n console.log(`wrote ${out}`);\n } else process.stdout.write(text);\n return 0;\n }\n case \"shapes\": {\n const [path, file] = rest;\n if (!path || !file) usage();\n const { ir } = loadFile(path);\n const views = (t: string, v: string) => ir.views[`${t}.${v}`];\n const lines = readFileSync(resolve(file), \"utf8\").split(/\\r?\\n/).filter((l) => l.trim());\n const map: Record<string, string> = {};\n for (const l of lines) {\n const canon = canonicalShape(parseShapeText(l), views);\n map[shapeIdOf(canon)] = canon;\n }\n console.log(JSON.stringify(map, null, 2));\n return 0;\n }\n case \"import\": {\n const [source, path] = rest;\n if (!source || !path) usage();\n let imported;\n try {\n const text = readFileSync(resolve(path), \"utf8\");\n if (source === \"openapi\") {\n const { irFromOpenApi } = await import(\"./import-openapi.ts\");\n imported = irFromOpenApi(JSON.parse(text) as Record<string, unknown>);\n } else if (source === \"graphql\") {\n const { irFromGraphql } = await import(\"./import-graphql.ts\");\n imported = await irFromGraphql(text);\n } else {\n console.error(`Unsupported source ${source} (openapi, graphql)`);\n return 1;\n }\n } catch (e) {\n console.error(String((e as Error).message));\n return 1;\n }\n const text = printSchemaText(imported.ir);\n const out = flag(rest, \"--out\");\n if (out) {\n writeFileSync(out, text);\n console.log(`wrote ${out}`);\n } else process.stdout.write(text);\n // what the source could not say, on stderr, so the schema on stdout stays a schema\n for (const note of imported.notes) console.error(`note ${note}`);\n return 0;\n }\n case \"mock\": {\n const path = rest[0];\n if (!path) usage();\n const port = Number(flag(rest, \"--port\") ?? 4500);\n const { ir, hash } = loadFile(path);\n const { mockResolvers } = await import(\"./mock.ts\");\n const srv = await import(\"@rayfold/server\");\n const { createExplorerHandler } = await import(\"@rayfold/explorer\");\n const server = srv.createRayfoldServer({ schema: ir, resolvers: mockResolvers(ir) });\n // a mock signs you in: it exists to answer, not to refuse\n const handler = srv.createHttpHandler(server, { cors: \"*\", viewer: () => ({ id: \"u1\", role: \"admin\" }) });\n const explorer = createExplorerHandler({ endpoint: \"/rayfold\", title: \"Rayfold mock\" });\n const { createServer } = await import(\"node:http\");\n const http = createServer((req, res) => {\n if (explorer(req, res)) return;\n if ((req.url ?? \"/\").startsWith(\"/rayfold\")) return void handler(req, res);\n res.writeHead(302, { location: \"/rayfold/explorer\" }).end();\n });\n srv.attachWebSocket(http, server, { viewer: () => ({ id: \"u1\", role: \"admin\" }) });\n await new Promise<void>((ready) => http.listen(port, ready));\n console.log(`Rayfold mock of ${path} (schema ${hash.slice(0, 12)})`);\n console.log(` HTTP http://localhost:${port}/rayfold`);\n console.log(` Explorer http://localhost:${port}/rayfold/explorer`);\n console.log(` the same call always gives the same answer`);\n await new Promise(() => {});\n return 0;\n }\n case \"lsp\": {\n const { serveStdio } = await import(\"@rayfold/lsp\");\n // runs until the editor sends `exit` or closes the pipe\n await new Promise<void>((done) => serveStdio(process.stdin, process.stdout, { onExit: done }));\n return 0;\n }\n case \"dev\": {\n const dir = rest[0];\n if (!dir) usage();\n const port = Number(flag(rest, \"--port\") ?? 4400);\n const mod = (await import(pathToFileURL(resolve(dir, \"src/index.ts\")).href)) as { createBookstore?: () => { server: import(\"@rayfold/server\").RayfoldServer } };\n if (!mod.createBookstore) {\n console.error(\"dev expects an example exporting createBookstore()\");\n return 1;\n }\n const srv = await import(\"@rayfold/server\");\n const { server } = mod.createBookstore();\n const { createExplorerHandler } = await import(\"@rayfold/explorer\");\n const viewer = (req: import(\"node:http\").IncomingMessage) => {\n const a = req.headers.authorization ?? new URL(req.url ?? \"/\", \"http://x\").searchParams.get(\"auth\") ?? undefined;\n if (a === \"Bearer admin\") return { id: \"u9\", role: \"admin\" };\n if (a?.startsWith(\"Bearer \")) return { id: a.slice(7), role: \"customer\" };\n return null;\n };\n const rayfoldHandler = srv.createHttpHandler(server, { cors: \"*\", viewer });\n const mcpHandler = srv.createMcpHandler(server, { viewer });\n const explorer = createExplorerHandler({ endpoint: \"/rayfold\", title: \"Rayfold dev\" });\n const { createServer } = await import(\"node:http\");\n const http = createServer((req, res) => {\n void (async () => {\n if (explorer(req, res)) return; // before the endpoint: the page lives under its path\n if ((req.url ?? \"/\").startsWith(\"/rayfold\")) return rayfoldHandler(req, res);\n if (await mcpHandler(req, res)) return;\n res.writeHead(302, { location: \"/rayfold/explorer\" }).end();\n })();\n });\n srv.attachWebSocket(http, server, { viewer });\n await new Promise<void>((r) => http.listen(port, r));\n console.log(`Rayfold dev server: http://localhost:${port}/`);\n console.log(` Explorer http://localhost:${port}/rayfold/explorer`);\n console.log(` HTTP http://localhost:${port}/rayfold (POST/QUERY batches, GET /rayfold/{op}, /rayfold/manifest)`);\n console.log(` WebSocket ws://localhost:${port}/rayfold/ws (subprotocol rayfold.0.1)`);\n console.log(` MCP http://localhost:${port}/mcp (Streamable HTTP, ${srv.MCP_PROTOCOL_VERSION})`);\n console.log(` schema ${server.hash.slice(0, 12)}`);\n await new Promise(() => {});\n return 0;\n }\n default:\n usage();\n }\n}\n\nmain(process.argv.slice(2)).then(\n (code) => process.exit(code),\n (e) => {\n console.error(e instanceof Error ? e.message : String(e));\n process.exit(1);\n },\n);\n\nexport { validateIR };\n"]}
|