@irtio/cli 0.1.0 → 0.2.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/dist/bundle.d.ts +9 -1
- package/dist/bundle.js +3 -1
- package/dist/chunk-BPE452KF.js +180 -0
- package/dist/{chunk-J3G6AUJY.js → chunk-I37DLT7K.js} +1 -1
- package/dist/{chunk-ZWCLCYCS.js → chunk-KRQUAEN2.js} +35 -6
- package/dist/{chunk-UYN5PWLT.js → chunk-NVUKSP5U.js} +3 -1
- package/dist/chunk-TQU6345E.js +36 -0
- package/dist/{deploy-4W6AYYEW.js → deploy-6OM3UYNL.js} +93 -15
- package/dist/{dev-BFWFWJ4J.js → dev-LOSTB4CD.js} +1095 -114
- package/dist/index.js +46 -10
- package/dist/init.d.ts +3 -0
- package/dist/init.js +236 -8
- package/dist/keys-KEKO3EJ6.js +174 -0
- package/dist/{login-US2YT5ZB.js → login-OV2EFNTJ.js} +26 -5
- package/dist/{logs-6GLBO3TP.js → logs-5OUDPAIX.js} +11 -3
- package/dist/{migrate-FQIDF747.js → migrate-3R6VRW4J.js} +7 -5
- package/dist/rollback-CLQVYFHW.js +122 -0
- package/dist/rooms-OJ3JLYHD.js +199 -0
- package/dist/simulate.d.ts +42 -1
- package/dist/simulate.js +129 -6
- package/dist/static-deploy-2LB6H54Y.js +199 -0
- package/dist/{whoami-5Q32SXFX.js → whoami-S73O6KJF.js} +2 -2
- package/package.json +9 -7
- package/dist/rooms-JXT3PRHN.js +0 -102
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
import {
|
|
2
|
+
STATIC_LIMITS,
|
|
3
|
+
staticPathProblem
|
|
4
|
+
} from "./chunk-BPE452KF.js";
|
|
5
|
+
import {
|
|
6
|
+
createApiClient,
|
|
7
|
+
isLoginRequired
|
|
8
|
+
} from "./chunk-I37DLT7K.js";
|
|
9
|
+
import {
|
|
10
|
+
resolveControlUrlForUser
|
|
11
|
+
} from "./chunk-NVUKSP5U.js";
|
|
12
|
+
|
|
13
|
+
// src/static-deploy.ts
|
|
14
|
+
import { existsSync } from "fs";
|
|
15
|
+
import { lstat, readFile, readdir } from "fs/promises";
|
|
16
|
+
import * as path from "path";
|
|
17
|
+
import pc from "picocolors";
|
|
18
|
+
function parseStaticDeployArgs(args) {
|
|
19
|
+
const parsed = {};
|
|
20
|
+
for (let i = 0; i < args.length; i++) {
|
|
21
|
+
const arg = args[i];
|
|
22
|
+
switch (arg) {
|
|
23
|
+
case "--static": {
|
|
24
|
+
const value = args[++i];
|
|
25
|
+
if (value === void 0) throw new Error("irtio deploy: --static needs a directory");
|
|
26
|
+
parsed.dir = value;
|
|
27
|
+
break;
|
|
28
|
+
}
|
|
29
|
+
case "--project": {
|
|
30
|
+
const value = args[++i];
|
|
31
|
+
if (value === void 0) throw new Error("irtio deploy: --project needs a value");
|
|
32
|
+
parsed.project = value;
|
|
33
|
+
break;
|
|
34
|
+
}
|
|
35
|
+
case "--url": {
|
|
36
|
+
const value = args[++i];
|
|
37
|
+
if (value === void 0) throw new Error("irtio deploy: --url needs a value");
|
|
38
|
+
parsed.url = value;
|
|
39
|
+
break;
|
|
40
|
+
}
|
|
41
|
+
case "--label": {
|
|
42
|
+
const value = args[++i];
|
|
43
|
+
if (value === void 0) throw new Error("irtio deploy: --label needs a value");
|
|
44
|
+
parsed.label = value;
|
|
45
|
+
break;
|
|
46
|
+
}
|
|
47
|
+
default:
|
|
48
|
+
throw new Error(`irtio deploy --static: unknown option ${JSON.stringify(arg)}`);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
if (parsed.dir === void 0) throw new Error("irtio deploy: --static needs a directory");
|
|
52
|
+
return parsed;
|
|
53
|
+
}
|
|
54
|
+
async function walkStaticDir(dir) {
|
|
55
|
+
const files = [];
|
|
56
|
+
const skipped = [];
|
|
57
|
+
async function walk(current, relBase) {
|
|
58
|
+
const entries = await readdir(current, { withFileTypes: true });
|
|
59
|
+
for (const entry of entries.sort((a, b) => a.name.localeCompare(b.name))) {
|
|
60
|
+
const abs = path.join(current, entry.name);
|
|
61
|
+
const rel = relBase === "" ? entry.name : `${relBase}/${entry.name}`;
|
|
62
|
+
if (entry.isSymbolicLink()) {
|
|
63
|
+
skipped.push(`${rel}: symlink (not followed)`);
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
if (entry.isDirectory()) {
|
|
67
|
+
await walk(abs, rel);
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
if (!entry.isFile()) {
|
|
71
|
+
skipped.push(`${rel}: not a regular file`);
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
const problem = staticPathProblem(rel);
|
|
75
|
+
if (problem !== void 0) {
|
|
76
|
+
skipped.push(`${rel}: ${problem}`);
|
|
77
|
+
continue;
|
|
78
|
+
}
|
|
79
|
+
const stat = await lstat(abs);
|
|
80
|
+
files.push({ rel, abs, size: stat.size });
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
await walk(dir, "");
|
|
84
|
+
return { files, skipped };
|
|
85
|
+
}
|
|
86
|
+
async function readIrtioJsonProject(cwd) {
|
|
87
|
+
const file = path.join(cwd, "irtio.json");
|
|
88
|
+
if (!existsSync(file)) return void 0;
|
|
89
|
+
let parsed;
|
|
90
|
+
try {
|
|
91
|
+
parsed = JSON.parse(await readFile(file, "utf8"));
|
|
92
|
+
} catch {
|
|
93
|
+
throw new Error(`irtio deploy: ${file} is not valid JSON`);
|
|
94
|
+
}
|
|
95
|
+
return typeof parsed.project === "string" && parsed.project.length > 0 ? parsed.project : void 0;
|
|
96
|
+
}
|
|
97
|
+
async function runStaticDeploy(options) {
|
|
98
|
+
const log = options.log ?? ((line) => console.log(line));
|
|
99
|
+
const cwd = path.resolve(options.cwd ?? process.cwd());
|
|
100
|
+
const dir = path.resolve(cwd, options.dir);
|
|
101
|
+
if (!existsSync(dir)) throw new Error(`irtio deploy: ${dir} does not exist`);
|
|
102
|
+
const project = options.project ?? await readIrtioJsonProject(cwd);
|
|
103
|
+
if (project === void 0) {
|
|
104
|
+
throw new Error(
|
|
105
|
+
"irtio deploy: no project id \u2014 pass --project or run from a project with irtio.json"
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
const { files, skipped } = await walkStaticDir(dir);
|
|
109
|
+
for (const line of skipped) log(pc.yellow(`skipped ${line}`));
|
|
110
|
+
if (files.length === 0) throw new Error(`irtio deploy: ${dir} has no files to upload`);
|
|
111
|
+
if (files.length > STATIC_LIMITS.maxFiles) {
|
|
112
|
+
throw new Error(
|
|
113
|
+
`irtio deploy: ${files.length} files exceeds the ${STATIC_LIMITS.maxFiles}-file limit (E_STATIC_TOO_MANY_FILES)`
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
const total = files.reduce((sum, f) => sum + f.size, 0);
|
|
117
|
+
if (total > STATIC_LIMITS.maxTotalBytes) {
|
|
118
|
+
throw new Error(
|
|
119
|
+
`irtio deploy: ${total} bytes exceeds the ${STATIC_LIMITS.maxTotalBytes}-byte limit (E_STATIC_TOTAL_TOO_LARGE)`
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
const oversize = files.find((f) => f.size > STATIC_LIMITS.maxFileBytes);
|
|
123
|
+
if (oversize) {
|
|
124
|
+
throw new Error(
|
|
125
|
+
`irtio deploy: ${oversize.rel} is ${oversize.size} bytes; the per-file limit is ${STATIC_LIMITS.maxFileBytes} (E_STATIC_FILE_TOO_LARGE)`
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
if (!files.some((f) => f.rel === "index.html")) {
|
|
129
|
+
log(
|
|
130
|
+
pc.yellow("note: no index.html at the top level \u2014 the site link will 404 until one exists")
|
|
131
|
+
);
|
|
132
|
+
}
|
|
133
|
+
const controlUrl = await resolveControlUrlForUser(options.controlUrl);
|
|
134
|
+
const client = options.client ?? await createApiClient(controlUrl);
|
|
135
|
+
const begin = await client.post(
|
|
136
|
+
`/v1/projects/${project}/static/begin`,
|
|
137
|
+
options.label !== void 0 ? { label: options.label } : {}
|
|
138
|
+
);
|
|
139
|
+
for (const file of files) {
|
|
140
|
+
const bytes = await readFile(file.abs);
|
|
141
|
+
await client.postBytes(
|
|
142
|
+
`/v1/projects/${project}/static/file?version=${begin.version}&path=${encodeURIComponent(file.rel)}`,
|
|
143
|
+
bytes
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
log(`uploaded ${files.length} files (${total} bytes) as v${begin.version}`);
|
|
147
|
+
const activated = await client.post(`/v1/projects/${project}/static/activate`, {
|
|
148
|
+
version: begin.version,
|
|
149
|
+
label: begin.label
|
|
150
|
+
});
|
|
151
|
+
if (activated.url !== void 0) {
|
|
152
|
+
log(pc.green(`live: ${activated.url}`));
|
|
153
|
+
} else {
|
|
154
|
+
log(
|
|
155
|
+
pc.green(
|
|
156
|
+
`activated ${activated.label} v${activated.version} (this control plane has no static domain configured; nothing serves it yet)`
|
|
157
|
+
)
|
|
158
|
+
);
|
|
159
|
+
}
|
|
160
|
+
return {
|
|
161
|
+
project,
|
|
162
|
+
label: activated.label,
|
|
163
|
+
version: activated.version,
|
|
164
|
+
files: files.length,
|
|
165
|
+
bytes: total,
|
|
166
|
+
...activated.url !== void 0 ? { url: activated.url } : {}
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
async function staticDeploy(args, deps = {}) {
|
|
170
|
+
const log = deps.log ?? ((line) => console.log(line));
|
|
171
|
+
const errorLog = deps.errorLog ?? ((line) => console.error(line));
|
|
172
|
+
try {
|
|
173
|
+
const parsed = parseStaticDeployArgs(args);
|
|
174
|
+
await runStaticDeploy({
|
|
175
|
+
dir: parsed.dir,
|
|
176
|
+
log,
|
|
177
|
+
...parsed.project !== void 0 ? { project: parsed.project } : {},
|
|
178
|
+
...parsed.url !== void 0 ? { controlUrl: parsed.url } : {},
|
|
179
|
+
...parsed.label !== void 0 ? { label: parsed.label } : {},
|
|
180
|
+
...deps.client !== void 0 ? { client: deps.client } : {},
|
|
181
|
+
...deps.cwd !== void 0 ? { cwd: deps.cwd } : {}
|
|
182
|
+
});
|
|
183
|
+
} catch (err) {
|
|
184
|
+
if (isLoginRequired(err)) {
|
|
185
|
+
errorLog(pc.red("not logged in"));
|
|
186
|
+
errorLog("run: irtio login");
|
|
187
|
+
process.exitCode = 1;
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
errorLog(pc.red(err instanceof Error ? err.message : String(err)));
|
|
191
|
+
process.exitCode = 1;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
export {
|
|
195
|
+
parseStaticDeployArgs,
|
|
196
|
+
runStaticDeploy,
|
|
197
|
+
staticDeploy,
|
|
198
|
+
walkStaticDir
|
|
199
|
+
};
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
2
|
createApiClient,
|
|
3
3
|
isLoginRequired
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-I37DLT7K.js";
|
|
5
5
|
import {
|
|
6
6
|
resolveControlUrlForUser
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-NVUKSP5U.js";
|
|
8
8
|
|
|
9
9
|
// src/whoami.ts
|
|
10
10
|
import pc from "picocolors";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@irtio/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "irtio CLI: local dev server, room scaffolding, bot simulation, deploy, logs and rooms",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"publishConfig": {
|
|
@@ -29,14 +29,16 @@
|
|
|
29
29
|
"esbuild": "^0.27.3",
|
|
30
30
|
"picocolors": "^1.1.1",
|
|
31
31
|
"ws": "^8.18.0",
|
|
32
|
-
"@irtio/bots": "0.
|
|
33
|
-
"@irtio/client": "0.
|
|
34
|
-
"@irtio/
|
|
35
|
-
"@irtio/
|
|
36
|
-
"@irtio/
|
|
37
|
-
"@irtio/server": "0.
|
|
32
|
+
"@irtio/bots": "0.2.0",
|
|
33
|
+
"@irtio/client": "0.2.0",
|
|
34
|
+
"@irtio/runtime": "0.2.0",
|
|
35
|
+
"@irtio/schema": "0.2.0",
|
|
36
|
+
"@irtio/protocol": "0.2.0",
|
|
37
|
+
"@irtio/server": "0.2.0"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
|
+
"@dimforge/rapier3d-compat": "0.20.0",
|
|
41
|
+
"@irtio/store": "0.0.0",
|
|
40
42
|
"@irtio/supervisor": "0.0.0"
|
|
41
43
|
},
|
|
42
44
|
"scripts": {
|
package/dist/rooms-JXT3PRHN.js
DELETED
|
@@ -1,102 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
createApiClient,
|
|
3
|
-
isLoginRequired
|
|
4
|
-
} from "./chunk-J3G6AUJY.js";
|
|
5
|
-
import {
|
|
6
|
-
resolveControlUrlForUser
|
|
7
|
-
} from "./chunk-UYN5PWLT.js";
|
|
8
|
-
|
|
9
|
-
// src/rooms.ts
|
|
10
|
-
import { existsSync } from "fs";
|
|
11
|
-
import { readFile } from "fs/promises";
|
|
12
|
-
import * as path from "path";
|
|
13
|
-
import pc from "picocolors";
|
|
14
|
-
function parseRoomsArgs(args) {
|
|
15
|
-
const parsed = {};
|
|
16
|
-
for (let i = 0; i < args.length; i++) {
|
|
17
|
-
const arg = args[i];
|
|
18
|
-
switch (arg) {
|
|
19
|
-
case "--project": {
|
|
20
|
-
const value = args[++i];
|
|
21
|
-
if (value === void 0) throw new Error("irtio rooms: --project needs a value");
|
|
22
|
-
parsed.project = value;
|
|
23
|
-
break;
|
|
24
|
-
}
|
|
25
|
-
case "--url": {
|
|
26
|
-
const value = args[++i];
|
|
27
|
-
if (value === void 0) throw new Error("irtio rooms: --url needs a value");
|
|
28
|
-
parsed.url = value;
|
|
29
|
-
break;
|
|
30
|
-
}
|
|
31
|
-
default:
|
|
32
|
-
throw new Error(`irtio rooms: unknown option ${JSON.stringify(arg)}`);
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
return parsed;
|
|
36
|
-
}
|
|
37
|
-
function statusColor(status) {
|
|
38
|
-
return status === "active" || status === "running" ? pc.green(status) : status === "draining" ? pc.yellow(status) : pc.dim(status);
|
|
39
|
-
}
|
|
40
|
-
function formatTable(rows) {
|
|
41
|
-
if (rows.length === 0) return [pc.dim("no rooms")];
|
|
42
|
-
const idWidth = Math.max(4, ...rows.map((r) => r.roomId.length));
|
|
43
|
-
const out = [pc.dim(`${"ROOM".padEnd(idWidth)} STATUS LAST SEEN`)];
|
|
44
|
-
for (const r of rows) {
|
|
45
|
-
out.push(
|
|
46
|
-
`${r.roomId.padEnd(idWidth)} ${statusColor(r.status).padEnd(10)} ${pc.dim(r.lastSeen)}`
|
|
47
|
-
);
|
|
48
|
-
}
|
|
49
|
-
return out;
|
|
50
|
-
}
|
|
51
|
-
async function runRooms(options) {
|
|
52
|
-
const log = options.log ?? ((line) => console.log(line));
|
|
53
|
-
const controlUrl = await resolveControlUrlForUser(options.controlUrl);
|
|
54
|
-
const client = options.client ?? await createApiClient(controlUrl);
|
|
55
|
-
const rows = await client.get(`/v1/projects/${options.project}/rooms`);
|
|
56
|
-
for (const line of formatTable(rows)) log(line);
|
|
57
|
-
return rows;
|
|
58
|
-
}
|
|
59
|
-
async function readIrtioJsonProject(cwd) {
|
|
60
|
-
const file = path.join(cwd, "irtio.json");
|
|
61
|
-
if (!existsSync(file)) return void 0;
|
|
62
|
-
let parsed;
|
|
63
|
-
try {
|
|
64
|
-
parsed = JSON.parse(await readFile(file, "utf8"));
|
|
65
|
-
} catch {
|
|
66
|
-
throw new Error(`irtio rooms: ${file} is not valid JSON`);
|
|
67
|
-
}
|
|
68
|
-
return typeof parsed.project === "string" && parsed.project.length > 0 ? parsed.project : void 0;
|
|
69
|
-
}
|
|
70
|
-
async function rooms(args, deps = {}) {
|
|
71
|
-
const log = deps.log ?? ((line) => console.log(line));
|
|
72
|
-
const errorLog = deps.errorLog ?? ((line) => console.error(line));
|
|
73
|
-
try {
|
|
74
|
-
const parsed = parseRoomsArgs(args);
|
|
75
|
-
const project = parsed.project ?? await readIrtioJsonProject(process.cwd());
|
|
76
|
-
if (project === void 0) {
|
|
77
|
-
throw new Error(
|
|
78
|
-
"irtio rooms: no project id \u2014 pass --project or run this from a project with irtio.json"
|
|
79
|
-
);
|
|
80
|
-
}
|
|
81
|
-
await runRooms({
|
|
82
|
-
project,
|
|
83
|
-
log,
|
|
84
|
-
...parsed.url !== void 0 ? { controlUrl: parsed.url } : {},
|
|
85
|
-
...deps.client !== void 0 ? { client: deps.client } : {}
|
|
86
|
-
});
|
|
87
|
-
} catch (err) {
|
|
88
|
-
if (isLoginRequired(err)) {
|
|
89
|
-
errorLog(pc.red("not logged in"));
|
|
90
|
-
errorLog("run: irtio login");
|
|
91
|
-
process.exitCode = 1;
|
|
92
|
-
return;
|
|
93
|
-
}
|
|
94
|
-
errorLog(pc.red(err instanceof Error ? err.message : String(err)));
|
|
95
|
-
process.exitCode = 1;
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
export {
|
|
99
|
-
parseRoomsArgs,
|
|
100
|
-
rooms,
|
|
101
|
-
runRooms
|
|
102
|
-
};
|