create-eigen-game 0.12.1 → 0.13.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/cli.d.ts CHANGED
@@ -1 +1,2 @@
1
1
  #!/usr/bin/env node
2
+ export {};
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Where the engine range emitted into a scaffolded project comes from.
3
+ *
4
+ * Its own module because the two branches below execute in different worlds,
5
+ * one only inside this repository and the other only inside a published tarball,
6
+ * and a function whose published-only path never runs in CI is a function that
7
+ * is not tested. `src/index.ts` uses it; the package `exports` map does not
8
+ * expose it, so it is internal despite being importable by the tests.
9
+ */
10
+ /** The dependency whose version the scaffolder emits into the generated server. */
11
+ export declare const ENGINE_PACKAGE = "@eigeninteractive/server";
12
+ /**
13
+ * The engine range for a scaffolded project, from this package's own
14
+ * `@eigeninteractive/server` devDependency.
15
+ *
16
+ * That number is not maintained by anyone: it is the version CI compiled the
17
+ * templates against, because `pnpm -r typecheck` runs
18
+ * `tsc -p templates/worker/tsconfig.json` inside this workspace. Emitting
19
+ * anything else would mean shipping templates paired with an engine no build
20
+ * ever saw.
21
+ *
22
+ * It replaced a derivation from this package's OWN version, which was correct
23
+ * only while `create-eigen-game` sat in the `fixed` changesets group, and that
24
+ * membership is what forced an engine-wide release for every scaffolder-only
25
+ * change. Reading the dependency keeps the guarantee and drops the coupling.
26
+ *
27
+ * Two branches, because the same manifest reads differently in the two places
28
+ * this runs:
29
+ *
30
+ * - **Published tarball**: pnpm rewrites `workspace:*` to the exact version
31
+ * while packing, so the manifest already states it (`"0.2.0"`), and no
32
+ * sibling package exists on disk to consult.
33
+ * - **This workspace**: the manifest still says `workspace:*`, which names no
34
+ * version, so the sibling package is read directly.
35
+ *
36
+ * @param declared the raw `@eigeninteractive/server` devDependency value
37
+ * @param readSiblingVersion consulted only for the `workspace:` protocol
38
+ */
39
+ export declare function engineRange(declared: string | undefined, readSiblingVersion: () => string | undefined): string;
package/dist/index.d.ts CHANGED
@@ -1,13 +1,7 @@
1
- /** What the Firebase step managed to settle, and what it left for the console. */
2
- interface FirebaseLink {
3
- /** The project now in `wrangler.jsonc`, or null when FlutterFire recorded none. */
4
- projectId: string | null;
5
- /** The OAuth web client now in `app-config.json`, or null when Google sign-in is not enabled yet. */
6
- googleWebClientId: string | null;
7
- }
8
-
9
- type PackageManager = "npm" | "pnpm";
10
- type Runner = (command: string, args: string[], cwd: string) => void;
1
+ import { type FirebaseLink } from "./link-firebase.js";
2
+ export type { FirebaseLink } from "./link-firebase.js";
3
+ export type PackageManager = "npm" | "pnpm";
4
+ export type Runner = (command: string, args: string[], cwd: string) => void;
11
5
  /**
12
6
  * Where a scaffold says what it is doing, so that presentation belongs to the
13
7
  * caller and this module only has to name things.
@@ -17,7 +11,7 @@ type Runner = (command: string, args: string[], cwd: string) => void;
17
11
  * substitutes one that captures each step's output and shows it only if the
18
12
  * step fails.
19
13
  */
20
- interface Reporter {
14
+ export interface Reporter {
21
15
  /** Runs `body` as one named step. Its subprocesses can be captured. */
22
16
  step<T>(label: string, body: () => T): T;
23
17
  /**
@@ -42,12 +36,12 @@ interface Reporter {
42
36
  * with `RangeError: Invalid string length`. Supplying the default its check
43
37
  * misses is better than giving up the drawing.
44
38
  */
45
- declare function normaliseTerminalWidth(stream: {
39
+ export declare function normaliseTerminalWidth(stream: {
46
40
  isTTY?: boolean;
47
41
  columns?: number;
48
42
  }): void;
49
43
  /** Runs every step plainly, which is what a library caller gets by default. */
50
- declare const plainReporter: Reporter;
44
+ export declare const plainReporter: Reporter;
51
45
  /**
52
46
  * The runner a scaffold uses when the caller has not supplied one: it asks the
53
47
  * reporter whether the terminal is spoken for.
@@ -57,8 +51,8 @@ declare const plainReporter: Reporter;
57
51
  * handed to the reporter: on success so it can discard them, and on failure
58
52
  * so the reason survives.
59
53
  */
60
- declare function capturingRunner(reporter: Reporter): Runner;
61
- interface ScaffoldOptions {
54
+ export declare function capturingRunner(reporter: Reporter): Runner;
55
+ export interface ScaffoldOptions {
62
56
  directory: string;
63
57
  org?: string;
64
58
  packageManager?: PackageManager;
@@ -107,8 +101,8 @@ interface ScaffoldOptions {
107
101
  * than guess. `failed` has already warned by the time it is returned, and
108
102
  * carries no advice of its own.
109
103
  */
110
- type GitOutcome = "committed" | "existing" | "skipped" | "failed";
111
- interface ScaffoldResult {
104
+ export type GitOutcome = "committed" | "existing" | "skipped" | "failed";
105
+ export interface ScaffoldResult {
112
106
  root: string;
113
107
  name: string;
114
108
  git: GitOutcome;
@@ -132,10 +126,10 @@ interface ScaffoldResult {
132
126
  * the *prefix*, not the whole identifier, which is the part worth seeing
133
127
  * before answering: Google Play makes it permanent at first upload.
134
128
  */
135
- declare function applicationId(directory: string, org?: string): string;
136
- declare function detectPackageManager(userAgent?: string | undefined): PackageManager | undefined;
137
- declare function decodeUtf8(bytes: Buffer): string | undefined;
138
- interface AddContinuousIntegrationOptions {
129
+ export declare function applicationId(directory: string, org?: string): string;
130
+ export declare function detectPackageManager(userAgent?: string | undefined): PackageManager | undefined;
131
+ export declare function decodeUtf8(bytes: Buffer): string | undefined;
132
+ export interface AddContinuousIntegrationOptions {
139
133
  directory: string;
140
134
  /** Overrides the manager recorded in the project's own package.json. */
141
135
  packageManager?: PackageManager;
@@ -147,23 +141,23 @@ interface AddContinuousIntegrationOptions {
147
141
  * long as its author likes, then gain the same PR gate and signed release
148
142
  * pipeline a `--ci` scaffold would have produced.
149
143
  */
150
- declare function addContinuousIntegration(options: AddContinuousIntegrationOptions): {
144
+ export declare function addContinuousIntegration(options: AddContinuousIntegrationOptions): {
151
145
  root: string;
152
146
  files: string[];
153
147
  };
154
148
  /** Asks a command a question. `ok` is "ran and succeeded"; a tool that is not installed and one that fails are both `false`, because neither can be used. */
155
- type Probe = (command: string, args: string[]) => {
149
+ export type Probe = (command: string, args: string[]) => {
156
150
  ok: boolean;
157
151
  stdout: string;
158
152
  };
159
153
  /** One thing standing between this machine and a configured Firebase project, and the single command that clears it. */
160
- interface FirebaseProblem {
154
+ export interface FirebaseProblem {
161
155
  /** Said as a sentence fragment, so it reads after "Firebase is not set up here:". */
162
156
  reason: string;
163
157
  /** The one command that fixes this, and nothing else. */
164
158
  fix: string;
165
159
  }
166
- type FirebaseReadiness = {
160
+ export type FirebaseReadiness = {
167
161
  ready: true;
168
162
  } | {
169
163
  ready: false;
@@ -189,7 +183,7 @@ type FirebaseReadiness = {
189
183
  * that errors or grows a different output shape is left to the command that
190
184
  * actually needs the credentials.
191
185
  */
192
- declare function firebaseReadiness(probe?: Probe): FirebaseReadiness;
186
+ export declare function firebaseReadiness(probe?: Probe): FirebaseReadiness;
193
187
  /**
194
188
  * Whether the scaffold would land inside a repository that already exists.
195
189
  *
@@ -222,8 +216,6 @@ declare function firebaseReadiness(probe?: Probe): FirebaseReadiness;
222
216
  * the last one. {@link scaffoldGame} asks it again, for callers that are not
223
217
  * the CLI.
224
218
  */
225
- declare function destinationProblem(directory: string): string | undefined;
226
- declare function insideWorkTree(directory: string, probe?: Probe): boolean;
227
- declare function scaffoldGame(options: ScaffoldOptions): ScaffoldResult;
228
-
229
- export { type AddContinuousIntegrationOptions, type FirebaseLink, type FirebaseProblem, type FirebaseReadiness, type GitOutcome, type PackageManager, type Probe, type Reporter, type Runner, type ScaffoldOptions, type ScaffoldResult, addContinuousIntegration, applicationId, capturingRunner, decodeUtf8, destinationProblem, detectPackageManager, firebaseReadiness, insideWorkTree, normaliseTerminalWidth, plainReporter, scaffoldGame };
219
+ export declare function destinationProblem(directory: string): string | undefined;
220
+ export declare function insideWorkTree(directory: string, probe?: Probe): boolean;
221
+ export declare function scaffoldGame(options: ScaffoldOptions): ScaffoldResult;
@@ -0,0 +1,28 @@
1
+ /** What the Firebase step managed to settle, and what it left for the console. */
2
+ export interface FirebaseLink {
3
+ /** The project now in `wrangler.jsonc`, or null when FlutterFire recorded none. */
4
+ projectId: string | null;
5
+ /** The OAuth web client now in `app-config.json`, or null when Google sign-in is not enabled yet. */
6
+ googleWebClientId: string | null;
7
+ }
8
+ /**
9
+ * The project FlutterFire recorded for the Dart output this app uses.
10
+ *
11
+ * `firebase.json` is FlutterFire's own record rather than something this
12
+ * scaffold writes, so it is read defensively: a shape that does not match is
13
+ * treated as "not configured", which is the same answer as a run that never
14
+ * happened.
15
+ */
16
+ export declare function configuredProject(appRoot: string): string | null;
17
+ /**
18
+ * The OAuth web client id that `configure_firebase` copied into
19
+ * `app-config.json`, when there was one to copy.
20
+ *
21
+ * Empty is an ordinary outcome rather than a failure. Firebase creates that
22
+ * client when the Google sign-in provider is enabled, which is a console
23
+ * action no CLI can perform, so a project that has never had it enabled has
24
+ * nothing to offer here.
25
+ */
26
+ export declare function configuredWebClientId(appRoot: string): string | null;
27
+ /** What the Firebase step settled, for the summary to report. */
28
+ export declare function readFirebaseLink(root: string): FirebaseLink;
@@ -0,0 +1,79 @@
1
+ /**
2
+ * Every question this CLI asks, in one module so the wording lives together
3
+ * and can be asserted. `cli.ts` is the bin entry and runs `main` on import,
4
+ * which makes anything defined there untestable.
5
+ *
6
+ * The organization prompt is the reason this drops to `@clack/core` rather
7
+ * than using `@clack/prompts`' `text`. The suffix: `flutter create --org X
8
+ * --project-name Y` derives `X.Y`, so the organization is a *prefix*, and the
9
+ * reliable way to say so is to render the rest of the identifier, dimmed,
10
+ * while it is being typed. `text` has no hook for that; a custom `TextPrompt`
11
+ * render returns a string, so it does.
12
+ *
13
+ * Everything else comes from `@clack/prompts` rather than being drawn here.
14
+ * Its symbols are exported for exactly this, and they are not constants: each
15
+ * falls back to ASCII on a terminal that cannot show the box-drawing
16
+ * characters, which a hand-typed `│` cannot do.
17
+ */
18
+ import type { Readable, Writable } from "node:stream";
19
+ import type { PackageManager } from "./index.js";
20
+ /**
21
+ * Where a question reads its answer from. Parameters for the same reason every
22
+ * clack prompt takes them: a prompt is otherwise the one part of a CLI that
23
+ * cannot be driven by a test.
24
+ */
25
+ export interface Io {
26
+ input?: Readable;
27
+ output?: Writable;
28
+ }
29
+ /**
30
+ * Two or more dot-separated Java identifiers. `flutter create --org` accepts
31
+ * anything and defers the complaint to Gradle, which reports it as a manifest
32
+ * error in a generated file, so `com.example-games` costs a full scaffold and
33
+ * a first build before anyone learns that a hyphen is not legal in a package
34
+ * segment.
35
+ */
36
+ export declare const ORG: RegExp;
37
+ /** The default, which an empty answer accepts. */
38
+ export declare const DEFAULT_ORG = "com.example";
39
+ /** A `com.acme.chess` answer to a game called `chess`, which yields `com.acme.chess.chess`. */
40
+ export declare function repeatsGameName(org: string, game: string): boolean;
41
+ /** The organization implied by an answer that already ends in the game name. */
42
+ export declare function withoutGameName(org: string): string | undefined;
43
+ /**
44
+ * Asks, with the game name rendered dimmed after the cursor so the shape of
45
+ * the answer is visible while it is being given.
46
+ *
47
+ * Returns the organization, `undefined` for the default, or `null` when
48
+ * cancelled.
49
+ *
50
+ * `input` and `output` default to this process's, and are parameters for the
51
+ * same reason every clack prompt takes them: a prompt is otherwise the one
52
+ * part of a CLI that cannot be driven by a test.
53
+ */
54
+ export declare function askForOrg(game: string, registering: boolean, io?: Io): Promise<string | undefined | null>;
55
+ /**
56
+ * Asked only when {@link firebaseReadiness} found something missing, and
57
+ * defaulted to "no" because the honest answer usually is: the tools are two
58
+ * commands away, and the alternative is an app that throws at launch until
59
+ * they are installed anyway.
60
+ */
61
+ export declare function askToScaffoldWithoutFirebase(io?: Io): Promise<boolean | null>;
62
+ /** Defaulted to yes: the scaffold is a few hundred generated files, and a commit is what makes the first `git diff` the first game change rather than all of them. */
63
+ export declare function askForGit(io?: Io): Promise<boolean | null>;
64
+ /**
65
+ * Defaulted to no, and the hint says why rather than leaving it as an
66
+ * arbitrary-looking choice: `release.yml` needs an upload keystore and a Play
67
+ * service account, so a project that takes the workflows before it has either
68
+ * gets a red `main` from its first push.
69
+ */
70
+ export declare function askForWorkflows(io?: Io): Promise<boolean | null>;
71
+ /**
72
+ * The package manager, asked only when nothing else could say.
73
+ *
74
+ * `npm create` and `pnpm create` both set `npm_config_user_agent`, so this is
75
+ * reached by the paths that do not: a global install, or running the binary
76
+ * directly. Rare, but it decides what every generated script says, and the old
77
+ * silent fallback to pnpm was a guess printed into a project's package.json.
78
+ */
79
+ export declare function askForPackageManager(io?: Io): Promise<PackageManager | null>;
@@ -0,0 +1,26 @@
1
+ /**
2
+ * The closing summary, and the only output of a scaffold anyone reads.
3
+ *
4
+ * A run drives several tools with plenty to say, so where the project went,
5
+ * what to edit, and what to run are worth restating at the bottom. Returned in
6
+ * pieces rather than as one block, because the CLI renders each in a different
7
+ * shape: the outcomes as status lines, the commands as a boxed note, the
8
+ * destination as the closing line.
9
+ *
10
+ * Its own module so it can be asserted: `cli.ts` is the bin entry and runs
11
+ * `main` on import, which makes anything defined there untestable. The package
12
+ * `exports` map does not expose this, so it is internal despite being
13
+ * importable by the tests.
14
+ */
15
+ import type { PackageManager, ScaffoldResult } from "./index.js";
16
+ export interface Summary {
17
+ /** What became of the repository and of Firebase, when there is something to say. */
18
+ status: string[];
19
+ /** The commands worth having, as one block. */
20
+ next: string;
21
+ /** One-line asides, after the block. */
22
+ footnotes: string[];
23
+ /** The closing line. */
24
+ headline: string;
25
+ }
26
+ export declare function summarise(result: ScaffoldResult, manager: PackageManager, workflows: boolean): Summary;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-eigen-game",
3
- "version": "0.12.1",
3
+ "version": "0.13.0",
4
4
  "license": "MIT",
5
5
  "description": "Scaffold an EigenInteractive game Worker and Flutter app without cloning the engine repositories.",
6
6
  "type": "module",
@@ -25,13 +25,13 @@
25
25
  "devDependencies": {
26
26
  "@types/node": "^26.1.1",
27
27
  "tsup": "^8.5.1",
28
- "typescript": "^5.9.3",
28
+ "typescript": "~6.0.2",
29
29
  "vitest": "^4.1.10",
30
30
  "wrangler": "^4.110.0",
31
31
  "zod": "^4.4.3",
32
- "@eigeninteractive/rules": "0.5.0",
33
- "@eigeninteractive/server": "0.5.0",
34
- "@eigeninteractive/testkit": "0.5.0"
32
+ "@eigeninteractive/rules": "0.5.1",
33
+ "@eigeninteractive/testkit": "0.5.1",
34
+ "@eigeninteractive/server": "0.5.1"
35
35
  },
36
36
  "engines": {
37
37
  "node": ">=22"
@@ -48,7 +48,7 @@
48
48
  "url": "https://github.com/eigeninteractive/eigen-platform/issues"
49
49
  },
50
50
  "scripts": {
51
- "build": "tsup src/index.ts src/cli.ts --format esm --dts --sourcemap --clean",
51
+ "build": "tsup src/index.ts src/cli.ts --format esm --sourcemap --clean && tsc -p tsconfig.build.json",
52
52
  "test": "vitest run",
53
53
  "typecheck": "tsc --noEmit -p tsconfig.json && tsc --noEmit -p templates/worker/tsconfig.json"
54
54
  }
@@ -46,7 +46,7 @@
46
46
  "devDependencies": {
47
47
  "@eigeninteractive/testkit": "{{ENGINE_VERSION}}",
48
48
  "@types/node": "^26.1.1",
49
- "typescript": "^5.9.3",
49
+ "typescript": "~6.0.2",
50
50
  "vitest": "^4.1.10",
51
51
  "wrangler": "^4.110.0"
52
52
  }