@irtio/cli 0.4.0 → 0.5.1
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-D7CDJRFF.js +24 -0
- package/dist/{deploy-6OM3UYNL.js → deploy-YVCVDVMS.js} +13 -3
- package/dist/index.js +12 -8
- package/dist/init.d.ts +6 -0
- package/dist/init.js +18 -6
- package/dist/{migrate-3R6VRW4J.js → migrate-UD245ULI.js} +6 -1
- package/dist/{static-deploy-LZXTDYNY.js → static-deploy-BP3MDXCP.js} +25 -0
- package/package.json +7 -7
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
// src/project-file.ts
|
|
2
|
+
import { existsSync } from "fs";
|
|
3
|
+
import { readFile } from "fs/promises";
|
|
4
|
+
import * as path from "path";
|
|
5
|
+
async function readIrtioJsonName(cwd, command) {
|
|
6
|
+
const file = path.join(cwd, "irtio.json");
|
|
7
|
+
if (!existsSync(file)) return void 0;
|
|
8
|
+
let parsed;
|
|
9
|
+
try {
|
|
10
|
+
parsed = JSON.parse(await readFile(file, "utf8"));
|
|
11
|
+
} catch (err) {
|
|
12
|
+
throw new Error(`${command}: ${file} is not valid JSON: ${String(err)}`);
|
|
13
|
+
}
|
|
14
|
+
const name = parsed?.name;
|
|
15
|
+
if (name === void 0) return void 0;
|
|
16
|
+
if (typeof name !== "string" || name.length === 0) {
|
|
17
|
+
throw new Error(`${command}: ${file} has a "name" that is not a non-empty string`);
|
|
18
|
+
}
|
|
19
|
+
return name;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export {
|
|
23
|
+
readIrtioJsonName
|
|
24
|
+
};
|
|
@@ -4,6 +4,9 @@ import {
|
|
|
4
4
|
import {
|
|
5
5
|
bundleRoom
|
|
6
6
|
} from "./chunk-KRQUAEN2.js";
|
|
7
|
+
import {
|
|
8
|
+
readIrtioJsonName
|
|
9
|
+
} from "./chunk-D7CDJRFF.js";
|
|
7
10
|
import {
|
|
8
11
|
ApiClientError,
|
|
9
12
|
createApiClient,
|
|
@@ -39,6 +42,14 @@ function parseDeployArgs(args) {
|
|
|
39
42
|
parsed.project = value;
|
|
40
43
|
break;
|
|
41
44
|
}
|
|
45
|
+
case "--name": {
|
|
46
|
+
const value = args[++i];
|
|
47
|
+
if (value === void 0 || value === "") {
|
|
48
|
+
throw new Error("irtio deploy: --name needs a value");
|
|
49
|
+
}
|
|
50
|
+
parsed.name = value;
|
|
51
|
+
break;
|
|
52
|
+
}
|
|
42
53
|
case "--url": {
|
|
43
54
|
const value = args[++i];
|
|
44
55
|
if (value === void 0) throw new Error("irtio deploy: --url needs a value");
|
|
@@ -193,9 +204,7 @@ async function runDeploy(options = {}) {
|
|
|
193
204
|
else throw err;
|
|
194
205
|
}
|
|
195
206
|
if (!projectExists) {
|
|
196
|
-
const
|
|
197
|
-
const answer = (await ask(`project ${projectId} does not exist yet \u2014 name it [${defaultName}]: `)).trim();
|
|
198
|
-
const name = answer.length > 0 ? answer : defaultName;
|
|
207
|
+
const name = options.name ?? await readIrtioJsonName(cwd, "irtio deploy") ?? path.basename(cwd);
|
|
199
208
|
await client.post("/v1/projects", { name, id: projectId });
|
|
200
209
|
log(pc.dim(`created project ${projectId} (${name})`));
|
|
201
210
|
}
|
|
@@ -356,6 +365,7 @@ async function deploy(args, deps = {}) {
|
|
|
356
365
|
allowBreaking: parsed.allowBreaking,
|
|
357
366
|
log,
|
|
358
367
|
...parsed.project !== void 0 ? { project: parsed.project } : {},
|
|
368
|
+
...parsed.name !== void 0 ? { name: parsed.name } : {},
|
|
359
369
|
...parsed.url !== void 0 ? { controlUrl: parsed.url } : {},
|
|
360
370
|
...parsed.room !== void 0 ? { room: parsed.room } : {},
|
|
361
371
|
...parsed.strategy !== void 0 ? { strategy: parsed.strategy } : {},
|
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
|
|
@@ -26,11 +28,13 @@ commands:
|
|
|
26
28
|
deploy [--allow-breaking] [--project <id>] bundle, classify the schema change against the
|
|
27
29
|
[--url <control>] [--room <file>] last deployment, and upload \u2014 refuses breaking
|
|
28
30
|
[--strategy drain|migrate] changes unless a migration covers them;
|
|
29
|
-
|
|
30
|
-
now (drain, the default, lets them finish)
|
|
31
|
+
[--name <name>] migrate moves LIVE rooms onto the new version
|
|
32
|
+
now (drain, the default, lets them finish).
|
|
33
|
+
A project that does not exist yet is created
|
|
34
|
+
as --name, else irtio.json's "name"
|
|
31
35
|
deploy --static <dir> [--project <id>] upload a BUILT client directory to the project's
|
|
32
36
|
[--label <label>] [--url <control>] static site and print the playable link
|
|
33
|
-
|
|
37
|
+
[--name <name>] (<label>.irt-serve.com; no build step)
|
|
34
38
|
migrate create <name> scaffold irtio/migrations/<n>_<name>.ts with the
|
|
35
39
|
live breaking changes quoted in its header
|
|
36
40
|
rollback <version> [--project <id>] re-promote deployment <version> and bring rooms
|
|
@@ -79,16 +83,16 @@ switch (command) {
|
|
|
79
83
|
}
|
|
80
84
|
case "deploy": {
|
|
81
85
|
if (args.includes("--static")) {
|
|
82
|
-
const { staticDeploy } = await import("./static-deploy-
|
|
86
|
+
const { staticDeploy } = await import("./static-deploy-BP3MDXCP.js");
|
|
83
87
|
await staticDeploy(args);
|
|
84
88
|
break;
|
|
85
89
|
}
|
|
86
|
-
const { deploy } = await import("./deploy-
|
|
90
|
+
const { deploy } = await import("./deploy-YVCVDVMS.js");
|
|
87
91
|
await deploy(args);
|
|
88
92
|
break;
|
|
89
93
|
}
|
|
90
94
|
case "migrate": {
|
|
91
|
-
const { migrate } = await import("./migrate-
|
|
95
|
+
const { migrate } = await import("./migrate-UD245ULI.js");
|
|
92
96
|
await migrate(args);
|
|
93
97
|
break;
|
|
94
98
|
}
|
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[];
|
package/dist/init.js
CHANGED
|
@@ -15,8 +15,17 @@ var DEFAULT_TICK_RATE = 20;
|
|
|
15
15
|
var DEFAULT_IDLE_MS = 3e4;
|
|
16
16
|
function parseInitArgs(args) {
|
|
17
17
|
const parsed = {};
|
|
18
|
-
for (
|
|
18
|
+
for (let i = 0; i < args.length; i++) {
|
|
19
|
+
const arg = args[i];
|
|
19
20
|
switch (arg) {
|
|
21
|
+
case "--name": {
|
|
22
|
+
const value = args[++i];
|
|
23
|
+
if (value === void 0 || value === "") {
|
|
24
|
+
throw new Error("irtio init: --name needs a value");
|
|
25
|
+
}
|
|
26
|
+
parsed.name = value;
|
|
27
|
+
break;
|
|
28
|
+
}
|
|
20
29
|
case "--physics":
|
|
21
30
|
parsed.physics = true;
|
|
22
31
|
break;
|
|
@@ -455,11 +464,13 @@ async function runInit(options = {}) {
|
|
|
455
464
|
}
|
|
456
465
|
const configFile = path.join(dir, "irtio.json");
|
|
457
466
|
let project = options.projectId ?? generateProjectId();
|
|
467
|
+
let name = options.name ?? (path.basename(dir) || "project");
|
|
458
468
|
if (existsSync(configFile)) {
|
|
459
469
|
try {
|
|
460
470
|
const existing = JSON.parse(await readFile(configFile, "utf8"));
|
|
461
471
|
if (typeof existing.project === "string" && existing.project !== "")
|
|
462
472
|
project = existing.project;
|
|
473
|
+
if (typeof existing.name === "string" && existing.name !== "") name = existing.name;
|
|
463
474
|
} catch {
|
|
464
475
|
}
|
|
465
476
|
}
|
|
@@ -469,14 +480,14 @@ async function runInit(options = {}) {
|
|
|
469
480
|
["irtio/world.ts", WORLD_TEMPLATE],
|
|
470
481
|
["irtio/room.ts", physicsRoomTemplate()],
|
|
471
482
|
["irtio/room.test.ts", PHYSICS_ROOM_TEST_TEMPLATE],
|
|
472
|
-
["irtio.json", `${JSON.stringify({ project }, null, 2)}
|
|
483
|
+
["irtio.json", `${JSON.stringify({ project, name }, null, 2)}
|
|
473
484
|
`]
|
|
474
485
|
] : [
|
|
475
486
|
["irtio/schema.ts", schemaTemplate(project)],
|
|
476
487
|
["irtio/rpc.ts", RPC_TEMPLATE],
|
|
477
488
|
["irtio/room.ts", roomTemplate(mode)],
|
|
478
489
|
["irtio/room.test.ts", ROOM_TEST_TEMPLATE],
|
|
479
|
-
["irtio.json", `${JSON.stringify({ project }, null, 2)}
|
|
490
|
+
["irtio.json", `${JSON.stringify({ project, name }, null, 2)}
|
|
480
491
|
`]
|
|
481
492
|
];
|
|
482
493
|
const created = [];
|
|
@@ -498,7 +509,7 @@ async function runInit(options = {}) {
|
|
|
498
509
|
if (skipped.length > 0) {
|
|
499
510
|
log(pc.yellow(`kept ${skipped.join(", ")} (already there \u2014 nothing was overwritten)`));
|
|
500
511
|
}
|
|
501
|
-
log(pc.dim(`project ${project} \xB7 ${mode} mode${physics ? " \xB7 physics" : ""}`));
|
|
512
|
+
log(pc.dim(`project ${project} (${name}) \xB7 ${mode} mode${physics ? " \xB7 physics" : ""}`));
|
|
502
513
|
const installCommand = packageJson === "absent" ? `npm i ${wantedDeps.join(" ")}` : "npm install # the irtio packages were added to your package.json";
|
|
503
514
|
for (const line of nextSteps(installCommand)) log(line);
|
|
504
515
|
if (physics) {
|
|
@@ -511,7 +522,7 @@ async function runInit(options = {}) {
|
|
|
511
522
|
log(" draw from room.render (predicted + interpolated), write intents via room.state.");
|
|
512
523
|
log("");
|
|
513
524
|
}
|
|
514
|
-
return { dir, project, mode, created, skipped, packageJson };
|
|
525
|
+
return { dir, project, name, mode, created, skipped, packageJson };
|
|
515
526
|
}
|
|
516
527
|
async function init(args) {
|
|
517
528
|
try {
|
|
@@ -519,7 +530,8 @@ async function init(args) {
|
|
|
519
530
|
await runInit({
|
|
520
531
|
...parsed.dir !== void 0 ? { dir: parsed.dir } : {},
|
|
521
532
|
...parsed.mode !== void 0 ? { mode: parsed.mode } : {},
|
|
522
|
-
...parsed.physics !== void 0 ? { physics: parsed.physics } : {}
|
|
533
|
+
...parsed.physics !== void 0 ? { physics: parsed.physics } : {},
|
|
534
|
+
...parsed.name !== void 0 ? { name: parsed.name } : {}
|
|
523
535
|
});
|
|
524
536
|
} catch (err) {
|
|
525
537
|
console.error(pc.red(err instanceof Error ? err.message : String(err)));
|
|
@@ -56,7 +56,12 @@ function resolveEntry(cwd, room) {
|
|
|
56
56
|
async function readIrtioJsonProject(cwd) {
|
|
57
57
|
const file = path.join(cwd, "irtio.json");
|
|
58
58
|
if (!existsSync(file)) return void 0;
|
|
59
|
-
|
|
59
|
+
let parsed;
|
|
60
|
+
try {
|
|
61
|
+
parsed = JSON.parse(await readFile(file, "utf8"));
|
|
62
|
+
} catch {
|
|
63
|
+
throw new Error(`irtio migrate: ${file} is not valid JSON`);
|
|
64
|
+
}
|
|
60
65
|
return typeof parsed.project === "string" && parsed.project.length > 0 ? parsed.project : void 0;
|
|
61
66
|
}
|
|
62
67
|
async function scanDirectoryVersion(cwd) {
|
|
@@ -1,8 +1,12 @@
|
|
|
1
|
+
import {
|
|
2
|
+
readIrtioJsonName
|
|
3
|
+
} from "./chunk-D7CDJRFF.js";
|
|
1
4
|
import {
|
|
2
5
|
STATIC_LIMITS,
|
|
3
6
|
staticPathProblem
|
|
4
7
|
} from "./chunk-BPE452KF.js";
|
|
5
8
|
import {
|
|
9
|
+
ApiClientError,
|
|
6
10
|
createApiClient,
|
|
7
11
|
isLoginRequired
|
|
8
12
|
} from "./chunk-I37DLT7K.js";
|
|
@@ -44,6 +48,14 @@ function parseStaticDeployArgs(args) {
|
|
|
44
48
|
parsed.label = value;
|
|
45
49
|
break;
|
|
46
50
|
}
|
|
51
|
+
case "--name": {
|
|
52
|
+
const value = args[++i];
|
|
53
|
+
if (value === void 0 || value === "") {
|
|
54
|
+
throw new Error("irtio deploy: --name needs a value");
|
|
55
|
+
}
|
|
56
|
+
parsed.name = value;
|
|
57
|
+
break;
|
|
58
|
+
}
|
|
47
59
|
default:
|
|
48
60
|
throw new Error(`irtio deploy --static: unknown option ${JSON.stringify(arg)}`);
|
|
49
61
|
}
|
|
@@ -94,6 +106,17 @@ async function readIrtioJsonProject(cwd) {
|
|
|
94
106
|
}
|
|
95
107
|
return typeof parsed.project === "string" && parsed.project.length > 0 ? parsed.project : void 0;
|
|
96
108
|
}
|
|
109
|
+
async function ensureProject(client, projectId, cwd, explicitName, log) {
|
|
110
|
+
try {
|
|
111
|
+
await client.get(`/v1/projects/${projectId}`);
|
|
112
|
+
return;
|
|
113
|
+
} catch (err) {
|
|
114
|
+
if (!(err instanceof ApiClientError && err.status === 404)) throw err;
|
|
115
|
+
}
|
|
116
|
+
const name = explicitName ?? await readIrtioJsonName(cwd, "irtio deploy") ?? path.basename(cwd);
|
|
117
|
+
await client.post("/v1/projects", { name, id: projectId });
|
|
118
|
+
log(pc.dim(`created project ${projectId} (${name})`));
|
|
119
|
+
}
|
|
97
120
|
async function runStaticDeploy(options) {
|
|
98
121
|
const log = options.log ?? ((line) => console.log(line));
|
|
99
122
|
const cwd = path.resolve(options.cwd ?? process.cwd());
|
|
@@ -132,6 +155,7 @@ async function runStaticDeploy(options) {
|
|
|
132
155
|
}
|
|
133
156
|
const controlUrl = await resolveControlUrlForUser(options.controlUrl);
|
|
134
157
|
const client = options.client ?? await createApiClient(controlUrl);
|
|
158
|
+
await ensureProject(client, project, cwd, options.name, log);
|
|
135
159
|
const begin = await client.post(
|
|
136
160
|
`/v1/projects/${project}/static/begin`,
|
|
137
161
|
options.label !== void 0 ? { label: options.label } : {}
|
|
@@ -181,6 +205,7 @@ async function staticDeploy(args, deps = {}) {
|
|
|
181
205
|
...parsed.project !== void 0 ? { project: parsed.project } : {},
|
|
182
206
|
...parsed.url !== void 0 ? { controlUrl: parsed.url } : {},
|
|
183
207
|
...parsed.label !== void 0 ? { label: parsed.label } : {},
|
|
208
|
+
...parsed.name !== void 0 ? { name: parsed.name } : {},
|
|
184
209
|
...deps.client !== void 0 ? { client: deps.client } : {},
|
|
185
210
|
...deps.cwd !== void 0 ? { cwd: deps.cwd } : {}
|
|
186
211
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@irtio/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.1",
|
|
4
4
|
"description": "irtio CLI: local dev server, room scaffolding, bot simulation, deploy, logs and rooms",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"publishConfig": {
|
|
@@ -29,12 +29,12 @@
|
|
|
29
29
|
"esbuild": "^0.27.3",
|
|
30
30
|
"picocolors": "^1.1.1",
|
|
31
31
|
"ws": "^8.18.0",
|
|
32
|
-
"@irtio/
|
|
33
|
-
"@irtio/
|
|
34
|
-
"@irtio/
|
|
35
|
-
"@irtio/
|
|
36
|
-
"@irtio/
|
|
37
|
-
"@irtio/server": "0.
|
|
32
|
+
"@irtio/client": "0.5.1",
|
|
33
|
+
"@irtio/protocol": "0.5.1",
|
|
34
|
+
"@irtio/bots": "0.5.1",
|
|
35
|
+
"@irtio/schema": "0.5.1",
|
|
36
|
+
"@irtio/runtime": "0.5.1",
|
|
37
|
+
"@irtio/server": "0.5.1"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
40
|
"@dimforge/rapier3d-compat": "0.20.0",
|