@irtio/cli 0.5.1 → 0.6.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.
Files changed (38) hide show
  1. package/dist/api.d.ts +52 -0
  2. package/dist/api.js +15 -0
  3. package/dist/bundle.js +1 -1
  4. package/dist/{static-deploy-BP3MDXCP.js → chunk-3HQMVCYA.js} +89 -48
  5. package/dist/chunk-DKWG7MGO.js +93 -0
  6. package/dist/{chunk-KRQUAEN2.js → chunk-OTSFRVJN.js} +12 -6
  7. package/dist/{chunk-I37DLT7K.js → chunk-RNAH5T4W.js} +14 -3
  8. package/dist/chunk-RQSJZWQC.js +452 -0
  9. package/dist/{chunk-NVUKSP5U.js → chunk-UPHQM6NZ.js} +12 -1
  10. package/dist/chunk-ZD4ND6X6.js +31 -0
  11. package/dist/chunk-ZK5JLUD4.js +94 -0
  12. package/dist/credentials.d.ts +61 -0
  13. package/dist/credentials.js +20 -0
  14. package/dist/delete-project-VENS2B44.js +118 -0
  15. package/dist/deploy.d.ts +149 -0
  16. package/dist/deploy.js +567 -0
  17. package/dist/{dev-7UZZGE4U.js → dev-QM26ONKS.js} +3095 -294
  18. package/dist/index.js +113 -28
  19. package/dist/init.d.ts +2 -1
  20. package/dist/init.js +42 -1
  21. package/dist/{keys-KEKO3EJ6.js → keys-JHLMEGRA.js} +49 -18
  22. package/dist/leaderboard-SYPSBPS3.js +352 -0
  23. package/dist/{login-OV2EFNTJ.js → login-2M73HBZT.js} +25 -1
  24. package/dist/{logs-5OUDPAIX.js → logs-2W7CPZO5.js} +42 -17
  25. package/dist/{migrate-UD245ULI.js → migrate-T3DZJREY.js} +44 -19
  26. package/dist/ratings-VG32WFDG.js +297 -0
  27. package/dist/{rollback-CLQVYFHW.js → rollback-SO74MVZV.js} +41 -17
  28. package/dist/{rooms-OJ3JLYHD.js → rooms-VI33P4RA.js} +73 -20
  29. package/dist/simulate.d.ts +215 -3
  30. package/dist/simulate.js +865 -64
  31. package/dist/static-deploy-KOWFKWZA.js +19 -0
  32. package/dist/status-HF3ZEKB7.js +219 -0
  33. package/dist/usage-4G23QXCH.js +213 -0
  34. package/dist/{whoami-S73O6KJF.js → whoami-KTMTQNHM.js} +21 -2
  35. package/package.json +24 -7
  36. package/dist/chunk-BPE452KF.js +0 -180
  37. package/dist/chunk-D7CDJRFF.js +0 -24
  38. package/dist/deploy-YVCVDVMS.js +0 -396
@@ -0,0 +1,118 @@
1
+ import {
2
+ HelpRequested,
3
+ helpFor,
4
+ helpRequested
5
+ } from "./chunk-ZD4ND6X6.js";
6
+ import {
7
+ createApiClient,
8
+ isLoginRequired
9
+ } from "./chunk-RNAH5T4W.js";
10
+ import {
11
+ resolveControlUrlForUser
12
+ } from "./chunk-UPHQM6NZ.js";
13
+
14
+ // src/delete-project.ts
15
+ import pc from "picocolors";
16
+ var USAGE = `usage: irtio delete-project <id> --yes [options]
17
+
18
+ Deletes a project and every record the control plane holds about it: origins, deployments,
19
+ signing secrets, rooms, player KV, leaderboard rows, logs, metrics and usage. This cannot be
20
+ undone. Stored
21
+ objects (bundles, saves, static files) are not deleted here; the platform sweeps orphans later.
22
+
23
+ A project whose tenant is currently live is refused; wait for its rooms to empty first.
24
+
25
+ options:
26
+ --yes actually delete. Without it the command only prints what would happen
27
+ --url <control> control plane (default: your stored login)
28
+ -h, --help print this
29
+ `;
30
+ function parseDeleteProjectArgs(args) {
31
+ if (helpRequested(args)) throw helpFor(USAGE);
32
+ let project;
33
+ let yes = false;
34
+ let url;
35
+ for (let i = 0; i < args.length; i++) {
36
+ const arg = args[i];
37
+ switch (arg) {
38
+ case "--yes":
39
+ yes = true;
40
+ break;
41
+ case "--url": {
42
+ const value = args[++i];
43
+ if (value === void 0) throw new Error("irtio delete-project: --url needs a value");
44
+ url = value;
45
+ break;
46
+ }
47
+ default:
48
+ if (arg.startsWith("-")) {
49
+ throw new Error(`irtio delete-project: unknown option ${JSON.stringify(arg)}`);
50
+ }
51
+ if (project !== void 0) {
52
+ throw new Error("irtio delete-project: takes exactly one project id");
53
+ }
54
+ project = arg;
55
+ }
56
+ }
57
+ if (project === void 0) {
58
+ throw new Error(
59
+ "irtio delete-project: needs a project id \u2014 it is never read from irtio.json, so the wrong directory cannot pick a victim"
60
+ );
61
+ }
62
+ return { project, yes, ...url !== void 0 ? { url } : {} };
63
+ }
64
+ async function runDeleteProject(options) {
65
+ const log = options.log ?? ((line) => console.log(line));
66
+ const controlUrl = await resolveControlUrlForUser(options.controlUrl);
67
+ const client = options.client ?? await createApiClient(controlUrl);
68
+ const project = await client.get(`/v1/projects/${options.project}`);
69
+ if (!options.yes) {
70
+ log(
71
+ `this would delete project ${pc.bold(project.id)} (${project.name}) and every record of it: origins, deployments, keys, rooms, player KV, leaderboard rows, logs, metrics and usage`
72
+ );
73
+ log(pc.dim("nothing was deleted. This cannot be undone once it runs"));
74
+ log(`to proceed: irtio delete-project ${project.id} --yes`);
75
+ return false;
76
+ }
77
+ await client.del(`/v1/projects/${project.id}`);
78
+ log(pc.green(`deleted project ${project.id} (${project.name})`));
79
+ log(
80
+ pc.dim(
81
+ "stored objects (bundles, saves, static files) are left for the orphan sweep; nothing serves them any more"
82
+ )
83
+ );
84
+ return true;
85
+ }
86
+ async function deleteProject(args, deps = {}) {
87
+ const log = deps.log ?? ((line) => console.log(line));
88
+ const errorLog = deps.errorLog ?? ((line) => console.error(line));
89
+ try {
90
+ const parsed = parseDeleteProjectArgs(args);
91
+ await runDeleteProject({
92
+ project: parsed.project,
93
+ yes: parsed.yes,
94
+ log,
95
+ ...parsed.url !== void 0 ? { controlUrl: parsed.url } : {},
96
+ ...deps.client !== void 0 ? { client: deps.client } : {}
97
+ });
98
+ } catch (err) {
99
+ if (err instanceof HelpRequested) {
100
+ log(err.usage);
101
+ return;
102
+ }
103
+ if (isLoginRequired(err)) {
104
+ errorLog(pc.red("not logged in"));
105
+ errorLog("run: irtio login");
106
+ process.exitCode = 1;
107
+ return;
108
+ }
109
+ errorLog(pc.red(err instanceof Error ? err.message : String(err)));
110
+ process.exitCode = 1;
111
+ }
112
+ }
113
+ export {
114
+ USAGE,
115
+ deleteProject,
116
+ parseDeleteProjectArgs,
117
+ runDeleteProject
118
+ };
@@ -0,0 +1,149 @@
1
+ import { SchemaChange } from '@irtio/schema';
2
+ import { ApiClient } from './api.js';
3
+ import { BundleOptions } from './bundle.js';
4
+
5
+ /**
6
+ * `irtio deploy --static <dir>` (week 13, O8/D35): upload a BUILT client directory to the
7
+ * project's `static/<project>/<version>/` prefix and flip the pointer. No build step — the
8
+ * developer brings a built directory ("Not in Week 13"). Refuses nothing silently: everything
9
+ * skipped is named with its reason, and every limit is a named error the caller could have seen
10
+ * coming (`STATIC_LIMITS`, the week-12 KV-limits shape).
11
+ */
12
+
13
+ interface RunStaticDeployResult {
14
+ readonly project: string;
15
+ readonly label: string;
16
+ readonly version: number;
17
+ readonly files: number;
18
+ readonly bytes: number;
19
+ readonly url?: string;
20
+ /** The origin the deploy added to the project's allow list, when the site has a URL. */
21
+ readonly origin?: string;
22
+ }
23
+
24
+ /**
25
+ * `irtio deploy`: bundle the room, classify the schema change against the last
26
+ * deployment, refuse anything breaking without a migration, and hand the bundle to the control
27
+ * plane through the artifact-upload + deployment-create handshake. The CLI never holds storage
28
+ * credentials — every byte goes up through `POST /v1/projects/:id/artifacts`.
29
+ *
30
+ * `bundleRoom` is reused verbatim, including for the migration file: `verify: false` skips
31
+ * its "default export is a RoomDefinition" check, which a migration module does not satisfy, so
32
+ * the same import-menu-enforced esbuild path bundles both without any change to `bundle.ts`.
33
+ * A migration only needs `MigrationState`/`MigrationHelpers` as *types* — `import type { ... }
34
+ * from '@irtio/runtime'` — which esbuild elides before the resolver plugin ever sees it, so the
35
+ * `@irtio/server` / `@irtio/schema` import fence is never in the migration author's way.
36
+ *
37
+ * `bundleRoom`'s public result deliberately does not expose the canonical schema JSON or the
38
+ * room's `project` id (`BundleResult` is `file`/`hash`/`schemaHash`/`mode`/`warnings` only), so
39
+ * once the bundle is verified this module re-imports the file it already wrote to read
40
+ * `def.schema.project` and `def.schema.canonical` directly, rather than changing `bundleRoom`'s
41
+ * contract for one caller.
42
+ */
43
+
44
+ interface DeployArgs {
45
+ readonly allowBreaking: boolean;
46
+ readonly project?: string;
47
+ readonly url?: string;
48
+ readonly room?: string;
49
+ readonly strategy?: 'drain' | 'migrate';
50
+ readonly name?: string;
51
+ readonly config?: string;
52
+ readonly noStatic?: boolean;
53
+ }
54
+ declare const USAGE = "usage: irtio deploy [options]\n irtio deploy --static [<dir>] [options]\n\nBundles the room, classifies the schema change against the last deployment, and uploads. A\nbreaking change is refused unless a migration covers it. With \"static\" in the project file the\nclient directory ships too, after the room.\n\noptions:\n --allow-breaking accept a breaking schema change that a migration covers\n --strategy drain|migrate drain (the default) lets running rooms finish on the old version;\n migrate moves live rooms onto the new one now\n --room <file> the room entry\n --project <id> project id (default: the project file)\n --name <name> the name a first deploy registers the project under\n --no-static deploy the room alone, even with \"static\" configured\n -c, --config <f> the project file to read (default irtio.json)\n --url <control> control plane (default: your stored login)\n -h, --help print this\n\nirtio deploy --static uploads a BUILT client directory and nothing else. It takes --label <label>\nplus --project, --name, --config and --url; the directory and label default to the project file.\n";
55
+ declare function parseDeployArgs(args: readonly string[]): DeployArgs;
56
+ interface RunDeployOptions {
57
+ readonly cwd?: string;
58
+ readonly allowBreaking?: boolean;
59
+ readonly project?: string;
60
+ /** The name to register a not-yet-existing project under. Otherwise the config file's `name`. */
61
+ readonly name?: string;
62
+ /** `-c/--config`: the project file to read, relative to `cwd`. Defaults to `irtio.json`. */
63
+ readonly config?: string;
64
+ /** `--no-static`: deploy the room only, leaving a configured static site as it is. */
65
+ readonly noStatic?: boolean;
66
+ readonly controlUrl?: string;
67
+ readonly room?: string;
68
+ /** Week 13 (D28): `migrate` moves live rooms onto the new version; default `drain`. */
69
+ readonly strategy?: 'drain' | 'migrate';
70
+ readonly irtioPackages?: BundleOptions['irtioPackages'];
71
+ readonly ask?: (question: string) => Promise<string>;
72
+ readonly log?: (line: string) => void;
73
+ /** @internal lets tests swap in a client bound to a fixed token instead of the credentials file. */
74
+ readonly client?: ApiClient;
75
+ }
76
+ interface RunDeployResult {
77
+ readonly project: string;
78
+ readonly version: number;
79
+ readonly url: string;
80
+ readonly draining: number;
81
+ readonly applied?: 'live' | 'pending';
82
+ readonly rooms?: readonly {
83
+ roomId: string;
84
+ outcome: string;
85
+ reason?: string;
86
+ }[];
87
+ /** Present when the project file configured a static site and this deploy shipped it too. */
88
+ readonly site?: RunStaticDeployResult;
89
+ }
90
+ /** The room entry, or undefined when the project has none. `--room` naming a missing file still
91
+ * throws: that is a typo, not a project without a room. */
92
+ declare function findRoomEntry(cwd: string, room: string | undefined): string | undefined;
93
+ /** Every room type a project declares, resolved to entry files. */
94
+ interface RoomTypeEntries {
95
+ /** The entry `resolveEntry` would have picked: what a plain roomId gets. */
96
+ readonly default: string;
97
+ /**
98
+ * Type name -> absolute entry, always including `DEFAULT_ROOM_TYPE`. A project with no
99
+ * `irtio/rooms/` directory has exactly one member, which is why its deploy is unchanged.
100
+ */
101
+ readonly types: Readonly<Record<string, string>>;
102
+ }
103
+ /**
104
+ * D58: resolve the project's room types.
105
+ *
106
+ * The default type is what a plain roomId means, so a project must always name one. `irtio/room.ts`
107
+ * (the pre-D58 single entry) stays the default when it is there, which is what keeps an existing
108
+ * project's deploy byte-identical after it grows an `irtio/rooms/` directory; otherwise
109
+ * `irtio/rooms/default.ts` is it. A project with `irtio/rooms/` and neither is refused rather than
110
+ * silently deploying types no plain roomId can reach.
111
+ *
112
+ * `room` (`--room`) replaces the default type's entry only. Extra types are a project layout fact,
113
+ * not something a flag naming one file can restate.
114
+ */
115
+ declare function findRoomTypes(cwd: string, room?: string): RoomTypeEntries;
116
+ /** The whole handshake. Throws on any refusal/error; `deploy()` turns that into exit 1. */
117
+ declare function runDeploy(options?: RunDeployOptions): Promise<RunDeployResult>;
118
+ /**
119
+ * Distinguishes an intentional refusal (already printed) from an unexpected throw.
120
+ *
121
+ * It carries the classification as well as printing it. For the CLI the printed lines are the
122
+ * whole story, but a non-terminal caller has no terminal to read: `@irtio/mcp` narrates this
123
+ * refusal into a tool result, and needs the same `changes` and `hint` the control plane's own 409
124
+ * carries. Without them the most informative failure in the whole deploy path arrives as the
125
+ * string "deploy refused", which is exactly the shape D40 says a tool result must never be.
126
+ *
127
+ * The no-argument form still works, so an older caller keeps compiling.
128
+ */
129
+ declare class DeployRefusedError extends Error {
130
+ readonly name = "DeployRefusedError";
131
+ /** The breaking changes that caused the refusal, as the classifier reported them. */
132
+ readonly changes: readonly SchemaChange[];
133
+ /** The remedy, verbatim: normally `run: irtio migrate create <name>`. */
134
+ readonly hint: string | undefined;
135
+ constructor(reason?: {
136
+ changes?: readonly SchemaChange[];
137
+ hint?: string;
138
+ });
139
+ }
140
+ /** Thin CLI entry. `deps` is a test seam (log/errorLog capture, an injected client/cwd/aliases). */
141
+ declare function deploy(args: readonly string[], deps?: {
142
+ log?: (line: string) => void;
143
+ errorLog?: (line: string) => void;
144
+ client?: ApiClient;
145
+ cwd?: string;
146
+ irtioPackages?: BundleOptions['irtioPackages'];
147
+ }): Promise<void>;
148
+
149
+ export { type DeployArgs, DeployRefusedError, type RoomTypeEntries, type RunDeployOptions, type RunDeployResult, USAGE, deploy, findRoomEntry, findRoomTypes, parseDeployArgs, runDeploy };