@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.
@@ -1,14 +1,24 @@
1
1
  import {
2
+ HelpRequested,
2
3
  createApiClient,
3
- isLoginRequired
4
- } from "./chunk-I37DLT7K.js";
5
- import {
4
+ helpFor,
5
+ helpRequested,
6
+ isLoginRequired,
6
7
  resolveControlUrlForUser
7
- } from "./chunk-NVUKSP5U.js";
8
+ } from "./chunk-TV66QHFP.js";
8
9
 
9
10
  // src/whoami.ts
10
11
  import pc from "picocolors";
12
+ var USAGE = `usage: irtio whoami [--url <control>]
13
+
14
+ Prints the identity your stored credential resolves to, and the control plane it was asked.
15
+
16
+ options:
17
+ --url <control> the control plane to ask (default: your stored login)
18
+ -h, --help print this
19
+ `;
11
20
  function parseWhoamiArgs(args) {
21
+ if (helpRequested(args)) throw helpFor(USAGE);
12
22
  const parsed = {};
13
23
  for (let i = 0; i < args.length; i++) {
14
24
  const arg = args[i];
@@ -46,6 +56,10 @@ async function whoami(args, deps = {}) {
46
56
  ...deps.client !== void 0 ? { client: deps.client } : {}
47
57
  });
48
58
  } catch (err) {
59
+ if (err instanceof HelpRequested) {
60
+ log(err.usage);
61
+ return;
62
+ }
49
63
  if (isLoginRequired(err)) {
50
64
  errorLog(pc.red("not logged in"));
51
65
  errorLog("run: irtio login");
@@ -57,6 +71,7 @@ async function whoami(args, deps = {}) {
57
71
  }
58
72
  }
59
73
  export {
74
+ USAGE,
60
75
  parseWhoamiArgs,
61
76
  runWhoami,
62
77
  whoami
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@irtio/cli",
3
- "version": "0.5.0",
3
+ "version": "0.5.2",
4
4
  "description": "irtio CLI: local dev server, room scaffolding, bot simulation, deploy, logs and rooms",
5
5
  "license": "MIT",
6
6
  "publishConfig": {
@@ -29,17 +29,18 @@
29
29
  "esbuild": "^0.27.3",
30
30
  "picocolors": "^1.1.1",
31
31
  "ws": "^8.18.0",
32
- "@irtio/bots": "0.5.0",
33
- "@irtio/client": "0.5.0",
34
- "@irtio/protocol": "0.5.0",
35
- "@irtio/runtime": "0.5.0",
36
- "@irtio/schema": "0.5.0",
37
- "@irtio/server": "0.5.0"
32
+ "@irtio/bots": "0.5.2",
33
+ "@irtio/client": "0.5.2",
34
+ "@irtio/protocol": "0.5.2",
35
+ "@irtio/runtime": "0.5.2",
36
+ "@irtio/schema": "0.5.2",
37
+ "@irtio/server": "0.5.2"
38
38
  },
39
39
  "devDependencies": {
40
+ "@types/ws": "^8.5.13",
40
41
  "@dimforge/rapier3d-compat": "0.20.0",
41
- "@irtio/supervisor": "0.0.0",
42
- "@irtio/store": "0.0.0"
42
+ "@irtio/store": "0.0.0",
43
+ "@irtio/supervisor": "0.0.0"
43
44
  },
44
45
  "scripts": {
45
46
  "build": "tsup",
@@ -1,85 +0,0 @@
1
- import {
2
- readCredential
3
- } from "./chunk-NVUKSP5U.js";
4
-
5
- // src/api-client.ts
6
- var ApiClientError = class extends Error {
7
- name = "ApiClientError";
8
- status;
9
- code;
10
- changes;
11
- hint;
12
- constructor(status, body) {
13
- super(body.message);
14
- this.status = status;
15
- this.code = body.code;
16
- this.changes = body.changes;
17
- this.hint = body.hint;
18
- }
19
- };
20
- var NotLoggedInError = class extends Error {
21
- constructor(controlUrl) {
22
- super(`not logged in to ${controlUrl} \u2014 run: irtio login`);
23
- this.controlUrl = controlUrl;
24
- }
25
- controlUrl;
26
- name = "NotLoggedInError";
27
- };
28
- async function createApiClient(controlUrl) {
29
- const credential = await readCredential(controlUrl);
30
- if (!credential) throw new NotLoggedInError(controlUrl);
31
- return createApiClientWithToken(controlUrl, credential.token);
32
- }
33
- function createApiClientWithToken(controlUrl, token) {
34
- async function request(method, path, init = {}) {
35
- const headers = {
36
- Authorization: `Bearer ${token}`,
37
- Accept: "application/json"
38
- };
39
- let requestBody;
40
- if (init.bytes !== void 0) {
41
- headers["content-type"] = "application/octet-stream";
42
- requestBody = init.bytes;
43
- } else if (init.body !== void 0) {
44
- headers["content-type"] = "application/json";
45
- requestBody = JSON.stringify(init.body);
46
- }
47
- const response = await fetch(`${controlUrl}${path}`, {
48
- method,
49
- headers,
50
- ...requestBody !== void 0 ? { body: requestBody } : {}
51
- });
52
- const text = await response.text();
53
- const parsed = text.length > 0 ? JSON.parse(text) : void 0;
54
- if (!response.ok) {
55
- const body = parsed !== void 0 && typeof parsed === "object" && parsed !== null && "code" in parsed && "message" in parsed ? parsed : {
56
- code: "E_UNKNOWN",
57
- message: text || `${method} ${path} failed with ${response.status}`
58
- };
59
- throw new ApiClientError(response.status, body);
60
- }
61
- return parsed;
62
- }
63
- return {
64
- controlUrl,
65
- get(path, query) {
66
- const qs = query ? Object.entries(query).filter((e) => e[1] !== void 0).map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(v)}`).join("&") : "";
67
- return request("GET", qs ? `${path}?${qs}` : path);
68
- },
69
- post(path, body) {
70
- return request("POST", path, { body });
71
- },
72
- postBytes(path, bytes) {
73
- return request("POST", path, { bytes });
74
- }
75
- };
76
- }
77
- function isLoginRequired(err) {
78
- return err instanceof NotLoggedInError || err instanceof ApiClientError && err.status === 401;
79
- }
80
-
81
- export {
82
- ApiClientError,
83
- createApiClient,
84
- isLoginRequired
85
- };
@@ -1,61 +0,0 @@
1
- // src/credentials.ts
2
- import { existsSync } from "fs";
3
- import { chmod, mkdir, readFile, writeFile } from "fs/promises";
4
- import * as os from "os";
5
- import * as path from "path";
6
- function credentialsPath() {
7
- if (process.env.IRT_CREDENTIALS_FILE) return process.env.IRT_CREDENTIALS_FILE;
8
- if (process.platform === "win32") {
9
- const appData = process.env.APPDATA ?? path.join(os.homedir(), "AppData", "Roaming");
10
- return path.join(appData, "irtio", "credentials.json");
11
- }
12
- return path.join(os.homedir(), ".config", "irtio", "credentials.json");
13
- }
14
- async function readCredentials() {
15
- const file = credentialsPath();
16
- if (!existsSync(file)) return {};
17
- try {
18
- const raw = await readFile(file, "utf8");
19
- const parsed = JSON.parse(raw);
20
- if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) return {};
21
- return parsed;
22
- } catch {
23
- return {};
24
- }
25
- }
26
- async function readCredential(controlUrl) {
27
- const all = await readCredentials();
28
- return all[controlUrl];
29
- }
30
- async function writeCredential(controlUrl, credential) {
31
- const file = credentialsPath();
32
- await mkdir(path.dirname(file), { recursive: true });
33
- const all = await readCredentials();
34
- all[controlUrl] = credential;
35
- await writeFile(file, `${JSON.stringify(all, null, 2)}
36
- `, { mode: 384 });
37
- await chmod(file, 384).catch(() => {
38
- });
39
- return file;
40
- }
41
- var DEFAULT_CONTROL_URL = "https://control.irt.io";
42
- function resolveControlUrl(flag) {
43
- return flag ?? process.env.IRT_CONTROL_URL ?? DEFAULT_CONTROL_URL;
44
- }
45
- async function resolveControlUrlForUser(flag) {
46
- const explicit = flag ?? process.env.IRT_CONTROL_URL;
47
- if (explicit !== void 0) return explicit;
48
- const all = await readCredentials();
49
- const now = Date.now();
50
- const live = Object.entries(all).filter(([, cred]) => new Date(cred.expiresAt).getTime() > now).map(([url]) => url);
51
- const urls = live.length > 0 ? live : Object.keys(all);
52
- return urls.length === 1 ? urls[0] : DEFAULT_CONTROL_URL;
53
- }
54
-
55
- export {
56
- credentialsPath,
57
- readCredential,
58
- writeCredential,
59
- resolveControlUrl,
60
- resolveControlUrlForUser
61
- };