@irtio/cli 0.5.0 → 0.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chunk-32QTPKVT.js +93 -0
- package/dist/{static-deploy-LZXTDYNY.js → chunk-GBNHBWES.js} +95 -33
- package/dist/chunk-TV66QHFP.js +167 -0
- package/dist/{deploy-6OM3UYNL.js → deploy-3SABPL3T.js} +114 -55
- package/dist/{dev-7UZZGE4U.js → dev-QJOGXLKM.js} +164 -89
- package/dist/index.js +35 -18
- package/dist/init.d.ts +8 -1
- package/dist/init.js +43 -6
- package/dist/{keys-KEKO3EJ6.js → keys-XBORZAPI.js} +47 -20
- package/dist/{login-OV2EFNTJ.js → login-3EXB4CGX.js} +18 -1
- package/dist/{logs-5OUDPAIX.js → logs-2EOXLNWF.js} +40 -19
- package/dist/{migrate-3R6VRW4J.js → migrate-WUO2GBMX.js} +41 -15
- package/dist/{rollback-CLQVYFHW.js → rollback-GA6UY772.js} +39 -19
- package/dist/{rooms-OJ3JLYHD.js → rooms-B66LQIIF.js} +46 -19
- package/dist/simulate.d.ts +71 -2
- package/dist/simulate.js +196 -22
- package/dist/static-deploy-5TBH4VNA.js +17 -0
- package/dist/{whoami-S73O6KJF.js → whoami-CI5D5RCC.js} +19 -4
- package/package.json +10 -9
- package/dist/chunk-I37DLT7K.js +0 -85
- package/dist/chunk-NVUKSP5U.js +0 -61
package/dist/index.js
CHANGED
|
@@ -8,8 +8,10 @@ usage: irtio <command>
|
|
|
8
8
|
|
|
9
9
|
commands:
|
|
10
10
|
init [dir] [--tick|--event] scaffold irtio/schema.ts, rpc.ts, room.ts,
|
|
11
|
-
|
|
12
|
-
skip the one question it otherwise asks
|
|
11
|
+
[--name <name>] room.test.ts and irtio.json (--tick/--event
|
|
12
|
+
skip the one question it otherwise asks;
|
|
13
|
+
--name is the project name a first deploy
|
|
14
|
+
registers, default the directory)
|
|
13
15
|
dev [--room <file>] [--port <n>] [--no-watch] bundle the room file and run it locally
|
|
14
16
|
simulate [--bots <n>] [--seconds <n>] drive N real clients at a running room and
|
|
15
17
|
[--room <code>] [--url <ws://\u2026>] check the built-in invariants
|
|
@@ -18,7 +20,9 @@ commands:
|
|
|
18
20
|
[--misprediction-max <units>] fail the run if one correction snaps a
|
|
19
21
|
[--snaps-max <n>] prediction further than this, if more than
|
|
20
22
|
[--corrections-max <perSec>] <n> corrections fall outside the resim
|
|
21
|
-
|
|
23
|
+
[--overruns-max <n>] window, above this correction rate/bot, or
|
|
24
|
+
above this many server tick overruns.
|
|
25
|
+
exits 0 clean, 1 violation, 2 not performed
|
|
22
26
|
|
|
23
27
|
login [--url <control>] sign in to a control plane via the browser
|
|
24
28
|
whoami [--url <control>] print the identity the stored credential
|
|
@@ -26,11 +30,17 @@ commands:
|
|
|
26
30
|
deploy [--allow-breaking] [--project <id>] bundle, classify the schema change against the
|
|
27
31
|
[--url <control>] [--room <file>] last deployment, and upload \u2014 refuses breaking
|
|
28
32
|
[--strategy drain|migrate] changes unless a migration covers them;
|
|
29
|
-
|
|
30
|
-
now (drain, the default, lets them finish)
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
33
|
+
[--name <name>] [--no-static] migrate moves LIVE rooms onto the new version
|
|
34
|
+
now (drain, the default, lets them finish).
|
|
35
|
+
A project that does not exist yet is created
|
|
36
|
+
as --name, else irtio.json's "name".
|
|
37
|
+
With "static" in the project file the client
|
|
38
|
+
directory ships too; --no-static skips it
|
|
39
|
+
deploy --static [<dir>] [--project <id>] upload a BUILT client directory to the project's
|
|
40
|
+
[--label <label>] [--url <control>] static site and print the playable link, and
|
|
41
|
+
[--name <name>] nothing else (<label>.irt-serve.com; no build
|
|
42
|
+
step). Directory and label default to the
|
|
43
|
+
project file's "static"
|
|
34
44
|
migrate create <name> scaffold irtio/migrations/<n>_<name>.ts with the
|
|
35
45
|
live breaking changes quoted in its header
|
|
36
46
|
rollback <version> [--project <id>] re-promote deployment <version> and bring rooms
|
|
@@ -50,6 +60,13 @@ commands:
|
|
|
50
60
|
rooms saves <room> list a room's save generations, newest first
|
|
51
61
|
rooms restore <room> --save <id> bring a room back from a save \u2014 DISCARDS its
|
|
52
62
|
current state; stops the tenant if it is live
|
|
63
|
+
|
|
64
|
+
every command takes --help (or -h) and prints its own usage, which is the authority: the lines
|
|
65
|
+
above are a map, and the command's own help is generated next to the code that parses it.
|
|
66
|
+
|
|
67
|
+
every command that reads the project file takes -c/--config <file> to read a different one
|
|
68
|
+
(dev, deploy, deploy --static, migrate create, rollback, logs, rooms, keys). Default irtio.json;
|
|
69
|
+
the named file must exist. That is the test.irtio.json / prod.irtio.json pattern.
|
|
53
70
|
`;
|
|
54
71
|
switch (command) {
|
|
55
72
|
case "init": {
|
|
@@ -58,7 +75,7 @@ switch (command) {
|
|
|
58
75
|
break;
|
|
59
76
|
}
|
|
60
77
|
case "dev": {
|
|
61
|
-
const { dev } = await import("./dev-
|
|
78
|
+
const { dev } = await import("./dev-QJOGXLKM.js");
|
|
62
79
|
await dev(args);
|
|
63
80
|
break;
|
|
64
81
|
}
|
|
@@ -68,47 +85,47 @@ switch (command) {
|
|
|
68
85
|
break;
|
|
69
86
|
}
|
|
70
87
|
case "login": {
|
|
71
|
-
const { login } = await import("./login-
|
|
88
|
+
const { login } = await import("./login-3EXB4CGX.js");
|
|
72
89
|
await login(args);
|
|
73
90
|
break;
|
|
74
91
|
}
|
|
75
92
|
case "whoami": {
|
|
76
|
-
const { whoami } = await import("./whoami-
|
|
93
|
+
const { whoami } = await import("./whoami-CI5D5RCC.js");
|
|
77
94
|
await whoami(args);
|
|
78
95
|
break;
|
|
79
96
|
}
|
|
80
97
|
case "deploy": {
|
|
81
98
|
if (args.includes("--static")) {
|
|
82
|
-
const { staticDeploy } = await import("./static-deploy-
|
|
99
|
+
const { staticDeploy } = await import("./static-deploy-5TBH4VNA.js");
|
|
83
100
|
await staticDeploy(args);
|
|
84
101
|
break;
|
|
85
102
|
}
|
|
86
|
-
const { deploy } = await import("./deploy-
|
|
103
|
+
const { deploy } = await import("./deploy-3SABPL3T.js");
|
|
87
104
|
await deploy(args);
|
|
88
105
|
break;
|
|
89
106
|
}
|
|
90
107
|
case "migrate": {
|
|
91
|
-
const { migrate } = await import("./migrate-
|
|
108
|
+
const { migrate } = await import("./migrate-WUO2GBMX.js");
|
|
92
109
|
await migrate(args);
|
|
93
110
|
break;
|
|
94
111
|
}
|
|
95
112
|
case "rollback": {
|
|
96
|
-
const { rollback } = await import("./rollback-
|
|
113
|
+
const { rollback } = await import("./rollback-GA6UY772.js");
|
|
97
114
|
await rollback(args);
|
|
98
115
|
break;
|
|
99
116
|
}
|
|
100
117
|
case "keys": {
|
|
101
|
-
const { keys } = await import("./keys-
|
|
118
|
+
const { keys } = await import("./keys-XBORZAPI.js");
|
|
102
119
|
await keys(args);
|
|
103
120
|
break;
|
|
104
121
|
}
|
|
105
122
|
case "logs": {
|
|
106
|
-
const { logs } = await import("./logs-
|
|
123
|
+
const { logs } = await import("./logs-2EOXLNWF.js");
|
|
107
124
|
await logs(args);
|
|
108
125
|
break;
|
|
109
126
|
}
|
|
110
127
|
case "rooms": {
|
|
111
|
-
const { rooms } = await import("./rooms-
|
|
128
|
+
const { rooms } = await import("./rooms-B66LQIIF.js");
|
|
112
129
|
await rooms(args);
|
|
113
130
|
break;
|
|
114
131
|
}
|
package/dist/init.d.ts
CHANGED
|
@@ -21,6 +21,8 @@ interface InitArgs {
|
|
|
21
21
|
readonly mode?: RoomMode;
|
|
22
22
|
/** `--physics`: a Rapier room with a shared world-builder and client prediction (D22). */
|
|
23
23
|
readonly physics?: boolean;
|
|
24
|
+
/** `--name`: the project's display name. Defaults to the directory name. */
|
|
25
|
+
readonly name?: string;
|
|
24
26
|
}
|
|
25
27
|
interface RunInitOptions {
|
|
26
28
|
/** Where the project lives. Defaults to `process.cwd()`. */
|
|
@@ -28,6 +30,8 @@ interface RunInitOptions {
|
|
|
28
30
|
readonly dir?: string;
|
|
29
31
|
readonly mode?: RoomMode;
|
|
30
32
|
readonly physics?: boolean;
|
|
33
|
+
/** The project's display name, written to `irtio.json`. Defaults to the directory name. */
|
|
34
|
+
readonly name?: string;
|
|
31
35
|
/**
|
|
32
36
|
* Asks the one question. Injected so tests never touch a TTY; the default reads stdin when it
|
|
33
37
|
* is a TTY and otherwise takes the default answer rather than hanging in a pipeline.
|
|
@@ -41,6 +45,8 @@ interface InitResult {
|
|
|
41
45
|
/** Absolute path of the scaffolded project. */
|
|
42
46
|
readonly dir: string;
|
|
43
47
|
readonly project: string;
|
|
48
|
+
/** The name written to `irtio.json`; what the first deploy registers the project as. */
|
|
49
|
+
readonly name: string;
|
|
44
50
|
readonly mode: RoomMode;
|
|
45
51
|
/** Files written, relative to `dir`, in emit order. */
|
|
46
52
|
readonly created: readonly string[];
|
|
@@ -53,6 +59,7 @@ interface InitResult {
|
|
|
53
59
|
* `irtio init [dir] [--tick|--event]`. Hand-rolled like `parseDevArgs`: the CLI has no
|
|
54
60
|
* argument-parsing dependency and four flags do not earn one.
|
|
55
61
|
*/
|
|
62
|
+
declare const USAGE = "usage: irtio init [dir] [options]\n\nScaffolds irtio/schema.ts, irtio/rpc.ts, irtio/room.ts, irtio/room.test.ts and irtio.json.\nNothing that already exists is ever overwritten.\n\noptions:\n [dir] where to scaffold (default: here)\n --tick a tick room, without asking\n --event an event room, without asking\n --physics scaffold a physics room and its shared world builder\n --name <name> the project name a first deploy registers (default: the directory)\n -h, --help print this\n";
|
|
56
63
|
declare function parseInitArgs(args: readonly string[]): InitArgs;
|
|
57
64
|
/** `p_` + 16 hex characters: the project id *is* the public key, so it is not a secret. */
|
|
58
65
|
declare function generateProjectId(): string;
|
|
@@ -64,4 +71,4 @@ declare function runInit(options?: RunInitOptions): Promise<InitResult>;
|
|
|
64
71
|
/** Thin on purpose: parse, run, and turn a thrown message into an exit code. */
|
|
65
72
|
declare function init(args: readonly string[]): Promise<void>;
|
|
66
73
|
|
|
67
|
-
export { INIT_DEPENDENCIES, type InitArgs, type InitResult, type RoomMode, type RunInitOptions, generateProjectId, init, parseInitArgs, runInit };
|
|
74
|
+
export { INIT_DEPENDENCIES, type InitArgs, type InitResult, type RoomMode, type RunInitOptions, USAGE, generateProjectId, init, parseInitArgs, runInit };
|
package/dist/init.js
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
import {
|
|
2
|
+
HelpRequested,
|
|
3
|
+
helpFor,
|
|
4
|
+
helpRequested
|
|
5
|
+
} from "./chunk-TV66QHFP.js";
|
|
6
|
+
|
|
1
7
|
// src/init.ts
|
|
2
8
|
import { randomBytes } from "crypto";
|
|
3
9
|
import { existsSync } from "fs";
|
|
@@ -13,10 +19,33 @@ var INIT_DEPENDENCIES = [
|
|
|
13
19
|
];
|
|
14
20
|
var DEFAULT_TICK_RATE = 20;
|
|
15
21
|
var DEFAULT_IDLE_MS = 3e4;
|
|
22
|
+
var USAGE = `usage: irtio init [dir] [options]
|
|
23
|
+
|
|
24
|
+
Scaffolds irtio/schema.ts, irtio/rpc.ts, irtio/room.ts, irtio/room.test.ts and irtio.json.
|
|
25
|
+
Nothing that already exists is ever overwritten.
|
|
26
|
+
|
|
27
|
+
options:
|
|
28
|
+
[dir] where to scaffold (default: here)
|
|
29
|
+
--tick a tick room, without asking
|
|
30
|
+
--event an event room, without asking
|
|
31
|
+
--physics scaffold a physics room and its shared world builder
|
|
32
|
+
--name <name> the project name a first deploy registers (default: the directory)
|
|
33
|
+
-h, --help print this
|
|
34
|
+
`;
|
|
16
35
|
function parseInitArgs(args) {
|
|
36
|
+
if (helpRequested(args)) throw helpFor(USAGE);
|
|
17
37
|
const parsed = {};
|
|
18
|
-
for (
|
|
38
|
+
for (let i = 0; i < args.length; i++) {
|
|
39
|
+
const arg = args[i];
|
|
19
40
|
switch (arg) {
|
|
41
|
+
case "--name": {
|
|
42
|
+
const value = args[++i];
|
|
43
|
+
if (value === void 0 || value === "") {
|
|
44
|
+
throw new Error("irtio init: --name needs a value");
|
|
45
|
+
}
|
|
46
|
+
parsed.name = value;
|
|
47
|
+
break;
|
|
48
|
+
}
|
|
20
49
|
case "--physics":
|
|
21
50
|
parsed.physics = true;
|
|
22
51
|
break;
|
|
@@ -455,11 +484,13 @@ async function runInit(options = {}) {
|
|
|
455
484
|
}
|
|
456
485
|
const configFile = path.join(dir, "irtio.json");
|
|
457
486
|
let project = options.projectId ?? generateProjectId();
|
|
487
|
+
let name = options.name ?? (path.basename(dir) || "project");
|
|
458
488
|
if (existsSync(configFile)) {
|
|
459
489
|
try {
|
|
460
490
|
const existing = JSON.parse(await readFile(configFile, "utf8"));
|
|
461
491
|
if (typeof existing.project === "string" && existing.project !== "")
|
|
462
492
|
project = existing.project;
|
|
493
|
+
if (typeof existing.name === "string" && existing.name !== "") name = existing.name;
|
|
463
494
|
} catch {
|
|
464
495
|
}
|
|
465
496
|
}
|
|
@@ -469,14 +500,14 @@ async function runInit(options = {}) {
|
|
|
469
500
|
["irtio/world.ts", WORLD_TEMPLATE],
|
|
470
501
|
["irtio/room.ts", physicsRoomTemplate()],
|
|
471
502
|
["irtio/room.test.ts", PHYSICS_ROOM_TEST_TEMPLATE],
|
|
472
|
-
["irtio.json", `${JSON.stringify({ project }, null, 2)}
|
|
503
|
+
["irtio.json", `${JSON.stringify({ project, name }, null, 2)}
|
|
473
504
|
`]
|
|
474
505
|
] : [
|
|
475
506
|
["irtio/schema.ts", schemaTemplate(project)],
|
|
476
507
|
["irtio/rpc.ts", RPC_TEMPLATE],
|
|
477
508
|
["irtio/room.ts", roomTemplate(mode)],
|
|
478
509
|
["irtio/room.test.ts", ROOM_TEST_TEMPLATE],
|
|
479
|
-
["irtio.json", `${JSON.stringify({ project }, null, 2)}
|
|
510
|
+
["irtio.json", `${JSON.stringify({ project, name }, null, 2)}
|
|
480
511
|
`]
|
|
481
512
|
];
|
|
482
513
|
const created = [];
|
|
@@ -498,7 +529,7 @@ async function runInit(options = {}) {
|
|
|
498
529
|
if (skipped.length > 0) {
|
|
499
530
|
log(pc.yellow(`kept ${skipped.join(", ")} (already there \u2014 nothing was overwritten)`));
|
|
500
531
|
}
|
|
501
|
-
log(pc.dim(`project ${project} \xB7 ${mode} mode${physics ? " \xB7 physics" : ""}`));
|
|
532
|
+
log(pc.dim(`project ${project} (${name}) \xB7 ${mode} mode${physics ? " \xB7 physics" : ""}`));
|
|
502
533
|
const installCommand = packageJson === "absent" ? `npm i ${wantedDeps.join(" ")}` : "npm install # the irtio packages were added to your package.json";
|
|
503
534
|
for (const line of nextSteps(installCommand)) log(line);
|
|
504
535
|
if (physics) {
|
|
@@ -511,7 +542,7 @@ async function runInit(options = {}) {
|
|
|
511
542
|
log(" draw from room.render (predicted + interpolated), write intents via room.state.");
|
|
512
543
|
log("");
|
|
513
544
|
}
|
|
514
|
-
return { dir, project, mode, created, skipped, packageJson };
|
|
545
|
+
return { dir, project, name, mode, created, skipped, packageJson };
|
|
515
546
|
}
|
|
516
547
|
async function init(args) {
|
|
517
548
|
try {
|
|
@@ -519,15 +550,21 @@ async function init(args) {
|
|
|
519
550
|
await runInit({
|
|
520
551
|
...parsed.dir !== void 0 ? { dir: parsed.dir } : {},
|
|
521
552
|
...parsed.mode !== void 0 ? { mode: parsed.mode } : {},
|
|
522
|
-
...parsed.physics !== void 0 ? { physics: parsed.physics } : {}
|
|
553
|
+
...parsed.physics !== void 0 ? { physics: parsed.physics } : {},
|
|
554
|
+
...parsed.name !== void 0 ? { name: parsed.name } : {}
|
|
523
555
|
});
|
|
524
556
|
} catch (err) {
|
|
557
|
+
if (err instanceof HelpRequested) {
|
|
558
|
+
console.log(err.usage);
|
|
559
|
+
return;
|
|
560
|
+
}
|
|
525
561
|
console.error(pc.red(err instanceof Error ? err.message : String(err)));
|
|
526
562
|
process.exitCode = 1;
|
|
527
563
|
}
|
|
528
564
|
}
|
|
529
565
|
export {
|
|
530
566
|
INIT_DEPENDENCIES,
|
|
567
|
+
USAGE,
|
|
531
568
|
generateProjectId,
|
|
532
569
|
init,
|
|
533
570
|
parseInitArgs,
|
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
} from "./chunk-I37DLT7K.js";
|
|
2
|
+
readProjectConfig
|
|
3
|
+
} from "./chunk-32QTPKVT.js";
|
|
5
4
|
import {
|
|
5
|
+
createApiClient,
|
|
6
|
+
helpRequested,
|
|
7
|
+
isLoginRequired,
|
|
6
8
|
resolveControlUrlForUser
|
|
7
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-TV66QHFP.js";
|
|
8
10
|
|
|
9
11
|
// src/keys.ts
|
|
10
|
-
import
|
|
11
|
-
import
|
|
12
|
+
import "fs";
|
|
13
|
+
import "fs/promises";
|
|
12
14
|
import * as path from "path";
|
|
13
15
|
import pc from "picocolors";
|
|
14
16
|
|
|
@@ -22,17 +24,6 @@ function signJwt(secret, claims) {
|
|
|
22
24
|
}
|
|
23
25
|
|
|
24
26
|
// src/keys.ts
|
|
25
|
-
async function readIrtioJsonProject(cwd) {
|
|
26
|
-
const file = path.join(cwd, "irtio.json");
|
|
27
|
-
if (!existsSync(file)) return void 0;
|
|
28
|
-
let parsed;
|
|
29
|
-
try {
|
|
30
|
-
parsed = JSON.parse(await readFile(file, "utf8"));
|
|
31
|
-
} catch {
|
|
32
|
-
throw new Error(`irtio keys: ${file} is not valid JSON`);
|
|
33
|
-
}
|
|
34
|
-
return typeof parsed.project === "string" && parsed.project.length > 0 ? parsed.project : void 0;
|
|
35
|
-
}
|
|
36
27
|
function flagValue(args, flag) {
|
|
37
28
|
const i = args.indexOf(flag);
|
|
38
29
|
if (i === -1) return void 0;
|
|
@@ -40,11 +31,15 @@ function flagValue(args, flag) {
|
|
|
40
31
|
if (value === void 0) throw new Error(`irtio keys: ${flag} needs a value`);
|
|
41
32
|
return value;
|
|
42
33
|
}
|
|
34
|
+
function configFlag(args) {
|
|
35
|
+
return flagValue(args, "--config") ?? flagValue(args, "-c");
|
|
36
|
+
}
|
|
43
37
|
async function resolveProject(args) {
|
|
44
|
-
const
|
|
38
|
+
const config = await readProjectConfig(process.cwd(), "irtio keys", configFlag(args));
|
|
39
|
+
const project = flagValue(args, "--project") ?? config.project;
|
|
45
40
|
if (project === void 0) {
|
|
46
41
|
throw new Error(
|
|
47
|
-
|
|
42
|
+
`irtio keys: no project id \u2014 pass --project or run this from a project with ${path.basename(config.file)}`
|
|
48
43
|
);
|
|
49
44
|
}
|
|
50
45
|
return project;
|
|
@@ -88,9 +83,40 @@ async function runJwtSecretRetire(options) {
|
|
|
88
83
|
log(pc.green(`retired the oldest active secret; ${result.active} remain(s) active`));
|
|
89
84
|
log(pc.dim("tokens signed with the retired secret stop verifying at the next placement"));
|
|
90
85
|
}
|
|
86
|
+
var USAGE = `usage: irtio keys jwt-secret [retire] [options]
|
|
87
|
+
irtio keys jwt-mint --secret <s> --sub <playerId> [options]
|
|
88
|
+
|
|
89
|
+
jwt-secret mints a signing secret for the project. It is printed ONCE and never again. Running it
|
|
90
|
+
a second time starts a rotation, where both secrets verify; retire finishes one by dropping the
|
|
91
|
+
oldest.
|
|
92
|
+
|
|
93
|
+
jwt-mint signs a test token locally, with the documented recipe. The secret you pass never leaves
|
|
94
|
+
this machine.
|
|
95
|
+
|
|
96
|
+
jwt-secret options:
|
|
97
|
+
retire retire the oldest active secret for this issuer
|
|
98
|
+
--issuer <label> the issuer to mint or retire under
|
|
99
|
+
--project <id> project id (default: the project file)
|
|
100
|
+
-c, --config <f> the project file to read (default irtio.json)
|
|
101
|
+
--url <control> control plane (default: your stored login)
|
|
102
|
+
|
|
103
|
+
jwt-mint options:
|
|
104
|
+
--secret <s> the signing secret (required)
|
|
105
|
+
--sub <playerId> the player the token is for (required)
|
|
106
|
+
--iss <label> the issuer claim
|
|
107
|
+
--room <id> restrict the token to one room
|
|
108
|
+
--role <r> the role to join as
|
|
109
|
+
--ttl <sec> lifetime in seconds (default 3600)
|
|
110
|
+
|
|
111
|
+
-h, --help print this
|
|
112
|
+
`;
|
|
91
113
|
async function keys(args, deps = {}) {
|
|
92
114
|
const log = deps.log ?? ((line) => console.log(line));
|
|
93
115
|
const errorLog = deps.errorLog ?? ((line) => console.error(line));
|
|
116
|
+
if (helpRequested(args)) {
|
|
117
|
+
log(USAGE);
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
94
120
|
try {
|
|
95
121
|
const sub = args[0];
|
|
96
122
|
const rest = args.slice(1);
|
|
@@ -133,7 +159,7 @@ async function keys(args, deps = {}) {
|
|
|
133
159
|
const room = flagValue(rest, "--room");
|
|
134
160
|
const role = flagValue(rest, "--role");
|
|
135
161
|
const iss = flagValue(rest, "--iss") ?? DEFAULT_ISSUER;
|
|
136
|
-
const project = flagValue(rest, "--project") ?? await
|
|
162
|
+
const project = flagValue(rest, "--project") ?? (await readProjectConfig(process.cwd(), "irtio keys", configFlag(rest))).project;
|
|
137
163
|
if (project === void 0) {
|
|
138
164
|
throw new Error(
|
|
139
165
|
"irtio keys jwt-mint: --project is required (aud must name the project the token is for)"
|
|
@@ -168,6 +194,7 @@ async function keys(args, deps = {}) {
|
|
|
168
194
|
}
|
|
169
195
|
export {
|
|
170
196
|
DEFAULT_ISSUER,
|
|
197
|
+
USAGE,
|
|
171
198
|
keys,
|
|
172
199
|
runJwtSecret,
|
|
173
200
|
runJwtSecretRetire
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
|
+
HelpRequested,
|
|
2
3
|
credentialsPath,
|
|
4
|
+
helpFor,
|
|
5
|
+
helpRequested,
|
|
3
6
|
resolveControlUrl,
|
|
4
7
|
writeCredential
|
|
5
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-TV66QHFP.js";
|
|
6
9
|
|
|
7
10
|
// src/login.ts
|
|
8
11
|
import { spawn } from "child_process";
|
|
@@ -10,7 +13,16 @@ import { randomBytes } from "crypto";
|
|
|
10
13
|
import { createServer } from "http";
|
|
11
14
|
import pc from "picocolors";
|
|
12
15
|
var LOGIN_TIMEOUT_MS = 3 * 60 * 1e3;
|
|
16
|
+
var USAGE = `usage: irtio login [--url <control>]
|
|
17
|
+
|
|
18
|
+
Signs in to a control plane through your browser and stores the credential it hands back.
|
|
19
|
+
|
|
20
|
+
options:
|
|
21
|
+
--url <control> the control plane to sign in to (default: the last one you used)
|
|
22
|
+
-h, --help print this
|
|
23
|
+
`;
|
|
13
24
|
function parseLoginArgs(args) {
|
|
25
|
+
if (helpRequested(args)) throw helpFor(USAGE);
|
|
14
26
|
const parsed = {};
|
|
15
27
|
for (let i = 0; i < args.length; i++) {
|
|
16
28
|
const arg = args[i];
|
|
@@ -145,11 +157,16 @@ async function login(args) {
|
|
|
145
157
|
console.log(pc.dim(`control plane: ${result.controlUrl}`));
|
|
146
158
|
console.log(pc.dim(`credentials stored at ${result.file ?? credentialsPath()}`));
|
|
147
159
|
} catch (err) {
|
|
160
|
+
if (err instanceof HelpRequested) {
|
|
161
|
+
console.log(err.usage);
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
148
164
|
console.error(pc.red(err instanceof Error ? err.message : String(err)));
|
|
149
165
|
process.exitCode = 1;
|
|
150
166
|
}
|
|
151
167
|
}
|
|
152
168
|
export {
|
|
169
|
+
USAGE,
|
|
153
170
|
defaultOpenBrowser,
|
|
154
171
|
login,
|
|
155
172
|
parseLoginArgs,
|
|
@@ -1,18 +1,36 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
} from "./chunk-I37DLT7K.js";
|
|
2
|
+
readProjectConfig
|
|
3
|
+
} from "./chunk-32QTPKVT.js";
|
|
5
4
|
import {
|
|
5
|
+
HelpRequested,
|
|
6
|
+
createApiClient,
|
|
7
|
+
helpFor,
|
|
8
|
+
helpRequested,
|
|
9
|
+
isLoginRequired,
|
|
6
10
|
resolveControlUrlForUser
|
|
7
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-TV66QHFP.js";
|
|
8
12
|
|
|
9
13
|
// src/logs.ts
|
|
10
|
-
import
|
|
11
|
-
import
|
|
12
|
-
import
|
|
14
|
+
import "fs";
|
|
15
|
+
import "fs/promises";
|
|
16
|
+
import "path";
|
|
13
17
|
import pc from "picocolors";
|
|
14
18
|
var POLL_MS = 2e3;
|
|
19
|
+
var USAGE = `usage: irtio logs [options]
|
|
20
|
+
|
|
21
|
+
Tails a project's logs, oldest line first.
|
|
22
|
+
|
|
23
|
+
options:
|
|
24
|
+
--follow poll every 2s, threading the cursor so nothing repeats
|
|
25
|
+
--since <cursor> start after this cursor (a previous row's timestamp)
|
|
26
|
+
--room <id> narrow to one room's stream. __tenant is the tenant's own events
|
|
27
|
+
--project <id> project id (default: the project file)
|
|
28
|
+
-c, --config <f> the project file to read (default irtio.json)
|
|
29
|
+
--url <control> control plane (default: your stored login)
|
|
30
|
+
-h, --help print this
|
|
31
|
+
`;
|
|
15
32
|
function parseLogsArgs(args) {
|
|
33
|
+
if (helpRequested(args)) throw helpFor(USAGE);
|
|
16
34
|
const parsed = {
|
|
17
35
|
follow: false
|
|
18
36
|
};
|
|
@@ -40,6 +58,14 @@ function parseLogsArgs(args) {
|
|
|
40
58
|
parsed.project = value;
|
|
41
59
|
break;
|
|
42
60
|
}
|
|
61
|
+
case "-c":
|
|
62
|
+
case "--config": {
|
|
63
|
+
const value = args[++i];
|
|
64
|
+
if (value === void 0 || value === "")
|
|
65
|
+
throw new Error("irtio logs: --config needs a value");
|
|
66
|
+
parsed.config = value;
|
|
67
|
+
break;
|
|
68
|
+
}
|
|
43
69
|
case "--url": {
|
|
44
70
|
const value = args[++i];
|
|
45
71
|
if (value === void 0) throw new Error("irtio logs: --url needs a value");
|
|
@@ -81,23 +107,13 @@ async function runLogs(options) {
|
|
|
81
107
|
await new Promise((resolve) => setTimeout(resolve, options.pollMs ?? POLL_MS));
|
|
82
108
|
}
|
|
83
109
|
}
|
|
84
|
-
async function readIrtioJsonProject(cwd) {
|
|
85
|
-
const file = path.join(cwd, "irtio.json");
|
|
86
|
-
if (!existsSync(file)) return void 0;
|
|
87
|
-
let parsed;
|
|
88
|
-
try {
|
|
89
|
-
parsed = JSON.parse(await readFile(file, "utf8"));
|
|
90
|
-
} catch {
|
|
91
|
-
throw new Error(`irtio logs: ${file} is not valid JSON`);
|
|
92
|
-
}
|
|
93
|
-
return typeof parsed.project === "string" && parsed.project.length > 0 ? parsed.project : void 0;
|
|
94
|
-
}
|
|
95
110
|
async function logs(args, deps = {}) {
|
|
96
111
|
const log = deps.log ?? ((line) => console.log(line));
|
|
97
112
|
const errorLog = deps.errorLog ?? ((line) => console.error(line));
|
|
98
113
|
try {
|
|
99
114
|
const parsed = parseLogsArgs(args);
|
|
100
|
-
const
|
|
115
|
+
const config = await readProjectConfig(process.cwd(), "irtio logs", parsed.config);
|
|
116
|
+
const project = parsed.project ?? config.project;
|
|
101
117
|
if (project === void 0) {
|
|
102
118
|
throw new Error(
|
|
103
119
|
"irtio logs: no project id \u2014 pass --project or run this from a project with irtio.json"
|
|
@@ -113,6 +129,10 @@ async function logs(args, deps = {}) {
|
|
|
113
129
|
...deps.client !== void 0 ? { client: deps.client } : {}
|
|
114
130
|
});
|
|
115
131
|
} catch (err) {
|
|
132
|
+
if (err instanceof HelpRequested) {
|
|
133
|
+
log(err.usage);
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
116
136
|
if (isLoginRequired(err)) {
|
|
117
137
|
errorLog(pc.red("not logged in"));
|
|
118
138
|
errorLog("run: irtio login");
|
|
@@ -124,6 +144,7 @@ async function logs(args, deps = {}) {
|
|
|
124
144
|
}
|
|
125
145
|
}
|
|
126
146
|
export {
|
|
147
|
+
USAGE,
|
|
127
148
|
logs,
|
|
128
149
|
parseLogsArgs,
|
|
129
150
|
runLogs
|
|
@@ -2,16 +2,20 @@ import {
|
|
|
2
2
|
bundleRoom
|
|
3
3
|
} from "./chunk-KRQUAEN2.js";
|
|
4
4
|
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
} from "./chunk-I37DLT7K.js";
|
|
5
|
+
readProjectConfig
|
|
6
|
+
} from "./chunk-32QTPKVT.js";
|
|
8
7
|
import {
|
|
8
|
+
HelpRequested,
|
|
9
|
+
createApiClient,
|
|
10
|
+
helpFor,
|
|
11
|
+
helpRequested,
|
|
12
|
+
isLoginRequired,
|
|
9
13
|
resolveControlUrlForUser
|
|
10
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-TV66QHFP.js";
|
|
11
15
|
|
|
12
16
|
// src/migrate.ts
|
|
13
17
|
import { existsSync } from "fs";
|
|
14
|
-
import { mkdir, mkdtemp,
|
|
18
|
+
import { mkdir, mkdtemp, readdir, writeFile } from "fs/promises";
|
|
15
19
|
import { tmpdir } from "os";
|
|
16
20
|
import * as path from "path";
|
|
17
21
|
import { pathToFileURL } from "url";
|
|
@@ -23,7 +27,18 @@ import {
|
|
|
23
27
|
import pc from "picocolors";
|
|
24
28
|
var MIGRATIONS_DIR = "irtio/migrations";
|
|
25
29
|
var ROOM_CANDIDATES = ["irtio/room.ts", "irtio/room.js", "room.ts"];
|
|
30
|
+
var USAGE = `usage: irtio migrate create <name> [-c <file>]
|
|
31
|
+
|
|
32
|
+
Scaffolds irtio/migrations/<n>_<name>.ts, with the breaking changes against the live deployment
|
|
33
|
+
quoted in its header so the transform has something to answer.
|
|
34
|
+
|
|
35
|
+
options:
|
|
36
|
+
<name> a short name for the migration, e.g. rename-hp
|
|
37
|
+
-c, --config <f> the project file to read (default irtio.json)
|
|
38
|
+
-h, --help print this
|
|
39
|
+
`;
|
|
26
40
|
function parseMigrateArgs(args) {
|
|
41
|
+
if (helpRequested(args)) throw helpFor(USAGE);
|
|
27
42
|
const [sub, name, ...rest] = args;
|
|
28
43
|
if (sub !== "create") {
|
|
29
44
|
throw new Error(
|
|
@@ -35,9 +50,20 @@ function parseMigrateArgs(args) {
|
|
|
35
50
|
"irtio migrate create: a name is required, e.g. irtio migrate create rename-hp"
|
|
36
51
|
);
|
|
37
52
|
}
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
53
|
+
let config;
|
|
54
|
+
for (let i = 0; i < rest.length; i++) {
|
|
55
|
+
const arg = rest[i];
|
|
56
|
+
if (arg === "-c" || arg === "--config") {
|
|
57
|
+
const value = rest[++i];
|
|
58
|
+
if (value === void 0 || value === "") {
|
|
59
|
+
throw new Error("irtio migrate create: --config needs a value");
|
|
60
|
+
}
|
|
61
|
+
config = value;
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
throw new Error(`irtio migrate create: unexpected extra argument ${JSON.stringify(arg)}`);
|
|
65
|
+
}
|
|
66
|
+
return { command: "create", args: config === void 0 ? { name } : { name, config } };
|
|
41
67
|
}
|
|
42
68
|
function resolveEntry(cwd, room) {
|
|
43
69
|
if (room !== void 0) {
|
|
@@ -53,12 +79,6 @@ function resolveEntry(cwd, room) {
|
|
|
53
79
|
`irtio migrate create: no room file found in ${cwd} (looked for: ${ROOM_CANDIDATES.join(", ")})`
|
|
54
80
|
);
|
|
55
81
|
}
|
|
56
|
-
async function readIrtioJsonProject(cwd) {
|
|
57
|
-
const file = path.join(cwd, "irtio.json");
|
|
58
|
-
if (!existsSync(file)) return void 0;
|
|
59
|
-
const parsed = JSON.parse(await readFile(file, "utf8"));
|
|
60
|
-
return typeof parsed.project === "string" && parsed.project.length > 0 ? parsed.project : void 0;
|
|
61
|
-
}
|
|
62
82
|
async function scanDirectoryVersion(cwd) {
|
|
63
83
|
const dir = path.join(cwd, MIGRATIONS_DIR);
|
|
64
84
|
if (!existsSync(dir)) return 1;
|
|
@@ -115,7 +135,8 @@ async function runMigrateCreate(options) {
|
|
|
115
135
|
const cwd = path.resolve(options.cwd ?? process.cwd());
|
|
116
136
|
const log = options.log ?? ((line) => console.log(line));
|
|
117
137
|
const controlUrl = await resolveControlUrlForUser(options.controlUrl);
|
|
118
|
-
const
|
|
138
|
+
const config = await readProjectConfig(cwd, "irtio migrate", options.config);
|
|
139
|
+
const projectId = options.project ?? config.project;
|
|
119
140
|
let version;
|
|
120
141
|
let versionSource;
|
|
121
142
|
let previousSchemaJson;
|
|
@@ -191,6 +212,10 @@ async function migrate(args, deps = {}) {
|
|
|
191
212
|
...deps.client !== void 0 ? { client: deps.client } : {}
|
|
192
213
|
});
|
|
193
214
|
} catch (err) {
|
|
215
|
+
if (err instanceof HelpRequested) {
|
|
216
|
+
log(err.usage);
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
194
219
|
if (isLoginRequired(err)) {
|
|
195
220
|
errorLog(pc.red("not logged in"));
|
|
196
221
|
errorLog("run: irtio login");
|
|
@@ -202,6 +227,7 @@ async function migrate(args, deps = {}) {
|
|
|
202
227
|
}
|
|
203
228
|
}
|
|
204
229
|
export {
|
|
230
|
+
USAGE,
|
|
205
231
|
migrate,
|
|
206
232
|
parseMigrateArgs,
|
|
207
233
|
runMigrateCreate
|