@streetui/cli 1.0.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/LICENSE +21 -0
- package/README.md +262 -0
- package/dist/bin.cjs +894 -0
- package/dist/bin.cjs.map +1 -0
- package/dist/bin.js +892 -0
- package/dist/bin.js.map +1 -0
- package/dist/create-bin.cjs +896 -0
- package/dist/create-bin.cjs.map +1 -0
- package/dist/create-bin.js +894 -0
- package/dist/create-bin.js.map +1 -0
- package/dist/index.cjs +953 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +354 -0
- package/dist/index.d.ts +354 -0
- package/dist/index.js +908 -0
- package/dist/index.js.map +1 -0
- package/package.json +59 -0
- package/templates/basic/README.md +39 -0
- package/templates/basic/_gitignore +15 -0
- package/templates/basic/_package.json +26 -0
- package/templates/basic/public/styles.css +40 -0
- package/templates/basic/src/app.ts +62 -0
- package/templates/basic/src/main.ts +39 -0
- package/templates/basic/src/server.ts +40 -0
- package/templates/basic/streetui.config.ts +6 -0
- package/templates/basic/tsconfig.json +16 -0
- package/templates/ssr/README.md +47 -0
- package/templates/ssr/_gitignore +15 -0
- package/templates/ssr/_package.json +26 -0
- package/templates/ssr/public/favicon.svg +4 -0
- package/templates/ssr/public/styles.css +61 -0
- package/templates/ssr/src/app.ts +135 -0
- package/templates/ssr/src/main.ts +53 -0
- package/templates/ssr/src/server.ts +47 -0
- package/templates/ssr/streetui.config.ts +14 -0
- package/templates/ssr/tsconfig.json +16 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,354 @@
|
|
|
1
|
+
import { IncomingMessage, ServerResponse, Server } from 'node:http';
|
|
2
|
+
|
|
3
|
+
interface Logger {
|
|
4
|
+
info(message: string): void;
|
|
5
|
+
success(message: string): void;
|
|
6
|
+
warn(message: string): void;
|
|
7
|
+
error(message: string): void;
|
|
8
|
+
plain(message: string): void;
|
|
9
|
+
}
|
|
10
|
+
/** The default logger writes to stdout/stderr with a `streetui` prefix. */
|
|
11
|
+
declare function createLogger(prefix?: string): Logger;
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* A tiny, dependency-free argument parser tailored to the StreetUI CLI.
|
|
15
|
+
*
|
|
16
|
+
* It intentionally supports only what the CLI actually uses — a leading command
|
|
17
|
+
* word, positional arguments, boolean flags, and a handful of value options
|
|
18
|
+
* (`--port`, `--host`, `--template`, `--dir`). Unknown flags are collected so a
|
|
19
|
+
* command can reject them with a useful message rather than silently ignoring
|
|
20
|
+
* them (Phase 14: no options that are ignored).
|
|
21
|
+
*/
|
|
22
|
+
interface ParsedArgs {
|
|
23
|
+
/** The command word, e.g. `create` / `dev` / `build` / `start`. */
|
|
24
|
+
readonly command: string | undefined;
|
|
25
|
+
/** Positional arguments after the command (e.g. the project name). */
|
|
26
|
+
readonly positionals: readonly string[];
|
|
27
|
+
/** `--help` / `-h` anywhere. */
|
|
28
|
+
readonly help: boolean;
|
|
29
|
+
/** `--version` / `-v` anywhere. */
|
|
30
|
+
readonly version: boolean;
|
|
31
|
+
/** `--port <n>` (validated as an integer, else `undefined`). */
|
|
32
|
+
readonly port: number | undefined;
|
|
33
|
+
/** `--host <h>`. */
|
|
34
|
+
readonly host: string | undefined;
|
|
35
|
+
/** `--template <name>` (project template for `create`). */
|
|
36
|
+
readonly template: string | undefined;
|
|
37
|
+
/** `--dir <path>` project directory override. */
|
|
38
|
+
readonly dir: string | undefined;
|
|
39
|
+
/** Any flags we do not recognise, reported verbatim (without leading `--`). */
|
|
40
|
+
readonly unknown: readonly string[];
|
|
41
|
+
}
|
|
42
|
+
/** Parse `process.argv.slice(2)`-style tokens into a `ParsedArgs`. */
|
|
43
|
+
declare function parseArgs(argv: readonly string[]): ParsedArgs;
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* StreetUI project configuration (Phase 9). The config is intentionally tiny:
|
|
47
|
+
* every field has a sensible default so `streetui.config.ts` is optional. A
|
|
48
|
+
* project with no config file still builds and runs.
|
|
49
|
+
*
|
|
50
|
+
* The file is authored as TypeScript (`streetui.config.ts`) and compiled with
|
|
51
|
+
* esbuild to a temporary ESM module before import, so we never depend on the
|
|
52
|
+
* host having a TS loader registered.
|
|
53
|
+
*/
|
|
54
|
+
/** User-facing configuration shape (all fields optional). */
|
|
55
|
+
interface StreetUIConfig {
|
|
56
|
+
/** Dev server / preview port. Default 3000. */
|
|
57
|
+
readonly port?: number;
|
|
58
|
+
/** Host to bind. Default 'localhost'. */
|
|
59
|
+
readonly host?: string;
|
|
60
|
+
/** Client/browser entry, relative to project root. Default 'src/main.ts'. */
|
|
61
|
+
readonly clientEntry?: string;
|
|
62
|
+
/** Server entry used for SSR, relative to project root. Default 'src/server.ts'. */
|
|
63
|
+
readonly serverEntry?: string;
|
|
64
|
+
/** Output directory for `build`. Default 'dist'. */
|
|
65
|
+
readonly outDir?: string;
|
|
66
|
+
/** Static assets directory copied verbatim. Default 'public'. */
|
|
67
|
+
readonly publicDir?: string;
|
|
68
|
+
}
|
|
69
|
+
/** Fully-resolved config: every field present, all paths absolute. */
|
|
70
|
+
interface ResolvedConfig {
|
|
71
|
+
readonly root: string;
|
|
72
|
+
readonly port: number;
|
|
73
|
+
readonly host: string;
|
|
74
|
+
readonly clientEntry: string;
|
|
75
|
+
readonly serverEntry: string;
|
|
76
|
+
readonly outDir: string;
|
|
77
|
+
readonly publicDir: string;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Identity helper that gives config authors type-checking and autocomplete.
|
|
81
|
+
* It returns its argument unchanged — the value matters, not the call.
|
|
82
|
+
*/
|
|
83
|
+
declare function defineConfig(config: StreetUIConfig): StreetUIConfig;
|
|
84
|
+
/** Absolute path of the first config file present in `root`, or undefined. */
|
|
85
|
+
declare function findConfigFile(root: string): string | undefined;
|
|
86
|
+
/**
|
|
87
|
+
* Load and fully resolve configuration for the project rooted at `root`.
|
|
88
|
+
* Missing config file → all defaults. Every returned path is absolute.
|
|
89
|
+
*/
|
|
90
|
+
declare function loadConfig(root: string): Promise<ResolvedConfig>;
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Environment variables (Phase 10). The rule is simple and safe by default:
|
|
94
|
+
* only variables whose names begin with `STREETUI_PUBLIC_` are exposed to the
|
|
95
|
+
* browser bundle. Everything else stays on the server, so secrets in the
|
|
96
|
+
* process environment cannot leak into client-side JavaScript.
|
|
97
|
+
*
|
|
98
|
+
* `NODE_ENV` is always defined (as the build mode) so app code can branch on
|
|
99
|
+
* development vs production.
|
|
100
|
+
*/
|
|
101
|
+
/** Prefix that marks an env var as safe to ship to the browser. */
|
|
102
|
+
declare const PUBLIC_ENV_PREFIX = "STREETUI_PUBLIC_";
|
|
103
|
+
/**
|
|
104
|
+
* Build the esbuild `define` map for the CLIENT bundle: `NODE_ENV` plus every
|
|
105
|
+
* `STREETUI_PUBLIC_*` variable, each stringified as a compile-time constant.
|
|
106
|
+
* Server-only variables are deliberately excluded.
|
|
107
|
+
*/
|
|
108
|
+
declare function clientEnvDefine(mode: 'development' | 'production', env?: NodeJS.ProcessEnv): Record<string, string>;
|
|
109
|
+
/** Names of the public variables currently visible (for logging/diagnostics). */
|
|
110
|
+
declare function publicEnvNames(env?: NodeJS.ProcessEnv): string[];
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Project resolution and validation (Phase 17). Before `dev`, `build`, or
|
|
114
|
+
* `start` do any real work, we confirm the working directory actually looks
|
|
115
|
+
* like a StreetUI project and fail with a clear, actionable message otherwise —
|
|
116
|
+
* never a cryptic stack trace.
|
|
117
|
+
*/
|
|
118
|
+
|
|
119
|
+
/** A validated StreetUI project ready for a command to act on. */
|
|
120
|
+
interface ResolvedProject {
|
|
121
|
+
/** Absolute project root. */
|
|
122
|
+
readonly root: string;
|
|
123
|
+
/** Parsed package.json. */
|
|
124
|
+
readonly packageJson: PackageJson;
|
|
125
|
+
/** Fully-resolved configuration (defaults applied). */
|
|
126
|
+
readonly config: ResolvedConfig;
|
|
127
|
+
}
|
|
128
|
+
interface PackageJson {
|
|
129
|
+
readonly name?: string;
|
|
130
|
+
readonly version?: string;
|
|
131
|
+
readonly type?: string;
|
|
132
|
+
readonly dependencies?: Record<string, string>;
|
|
133
|
+
readonly devDependencies?: Record<string, string>;
|
|
134
|
+
readonly scripts?: Record<string, string>;
|
|
135
|
+
readonly [key: string]: unknown;
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Resolve + validate the project rooted at `cwd` (or `--dir`). Throws a
|
|
139
|
+
* `CliError` with a helpful suggestion for every failure mode Phase 17 lists:
|
|
140
|
+
* missing package.json, not a StreetUI project, invalid config, missing entry.
|
|
141
|
+
*/
|
|
142
|
+
declare function resolveProject(cwd: string, options?: {
|
|
143
|
+
requireEntry?: boolean;
|
|
144
|
+
}): Promise<ResolvedProject>;
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Production build (Phase 7). Two esbuild passes over the project's real
|
|
148
|
+
* entries — a browser bundle for hydration and a Node bundle for SSR — plus a
|
|
149
|
+
* copy of the public directory. No separate production rendering system: the
|
|
150
|
+
* same DSL → compile → renderer pipeline the app already uses is bundled as-is.
|
|
151
|
+
*/
|
|
152
|
+
|
|
153
|
+
/** Where each artifact lands under the configured `outDir`. */
|
|
154
|
+
interface BuildOutput {
|
|
155
|
+
readonly clientDir: string;
|
|
156
|
+
readonly serverDir: string;
|
|
157
|
+
readonly clientBundle: string;
|
|
158
|
+
readonly serverBundle: string;
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Run the production build for `project`. Returns the output layout on success;
|
|
162
|
+
* throws a `CliError` carrying formatted diagnostics on failure. When
|
|
163
|
+
* `serverEntry` is absent the server pass is skipped (client-only project).
|
|
164
|
+
*/
|
|
165
|
+
declare function buildProject(project: ResolvedProject, mode?: 'development' | 'production'): Promise<BuildOutput>;
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* `streetui dev` (Phase 5). Builds the project once, then watches for changes
|
|
169
|
+
* with esbuild's incremental context API and rebuilds only what changed —
|
|
170
|
+
* avoiding a full cold build per keystroke (Phase 27). On each successful
|
|
171
|
+
* rebuild connected browsers are told to reload; build errors are printed with
|
|
172
|
+
* real source positions and never crash the server.
|
|
173
|
+
*/
|
|
174
|
+
|
|
175
|
+
interface DevOptions {
|
|
176
|
+
readonly project: ResolvedProject;
|
|
177
|
+
readonly logger: Logger;
|
|
178
|
+
readonly host?: string;
|
|
179
|
+
readonly port?: number;
|
|
180
|
+
}
|
|
181
|
+
/** Handle returned so callers (and tests) can shut the dev server down. */
|
|
182
|
+
interface DevServer {
|
|
183
|
+
readonly url: string;
|
|
184
|
+
stop(): Promise<void>;
|
|
185
|
+
}
|
|
186
|
+
/** Start the dev server. Resolves once it is listening; keep the handle to stop. */
|
|
187
|
+
declare function runDev(options: DevOptions): Promise<DevServer>;
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* The StreetUI HTTP server (Phases 5 & 8). Built on Node's standard `node:http`
|
|
191
|
+
* — no Express, no third-party server. It serves the built client assets as
|
|
192
|
+
* static files and delegates every other request to the project's server
|
|
193
|
+
* bundle, which exports a `render(request)` function producing full HTML.
|
|
194
|
+
*
|
|
195
|
+
* The same server backs both `dev` (with live-reload injection) and `start`
|
|
196
|
+
* (production). Dev-only behaviour is gated behind the `reload` option.
|
|
197
|
+
*/
|
|
198
|
+
|
|
199
|
+
/** The contract a project's server entry must satisfy. */
|
|
200
|
+
interface RenderRequest {
|
|
201
|
+
readonly url: string;
|
|
202
|
+
readonly method: string;
|
|
203
|
+
readonly headers: Record<string, string | string[] | undefined>;
|
|
204
|
+
}
|
|
205
|
+
interface RenderResult {
|
|
206
|
+
readonly html: string;
|
|
207
|
+
readonly status?: number;
|
|
208
|
+
readonly headers?: Record<string, string>;
|
|
209
|
+
}
|
|
210
|
+
type RenderFn = (request: RenderRequest) => RenderResult | Promise<RenderResult>;
|
|
211
|
+
interface ServeOptions {
|
|
212
|
+
readonly clientDir: string;
|
|
213
|
+
readonly serverBundle: string;
|
|
214
|
+
readonly host: string;
|
|
215
|
+
readonly port: number;
|
|
216
|
+
/** When set, HTML responses get a live-reload snippet + an SSE endpoint. */
|
|
217
|
+
readonly reload?: ReloadHub;
|
|
218
|
+
/**
|
|
219
|
+
* Dev mode: re-import the server bundle on every request so edits are picked
|
|
220
|
+
* up without restarting. In production the bundle is loaded once.
|
|
221
|
+
*/
|
|
222
|
+
readonly devMode?: boolean;
|
|
223
|
+
}
|
|
224
|
+
/** A running server plus the resolved address and a stop handle. */
|
|
225
|
+
interface RunningServer {
|
|
226
|
+
readonly server: Server;
|
|
227
|
+
readonly url: string;
|
|
228
|
+
close(): Promise<void>;
|
|
229
|
+
}
|
|
230
|
+
/** Live-reload coordination for dev: tracks SSE clients and pushes events. */
|
|
231
|
+
declare class ReloadHub {
|
|
232
|
+
private readonly clients;
|
|
233
|
+
static readonly PATH = "/__streetui_reload";
|
|
234
|
+
/** The snippet injected before `</body>` so the page listens for reloads. */
|
|
235
|
+
static readonly snippet: string;
|
|
236
|
+
handle(_req: IncomingMessage, res: ServerResponse): void;
|
|
237
|
+
/** Tell every connected browser to reload. */
|
|
238
|
+
triggerReload(): void;
|
|
239
|
+
closeAll(): void;
|
|
240
|
+
}
|
|
241
|
+
/** Start the HTTP server and resolve once it is actually listening. */
|
|
242
|
+
declare function startServer(options: ServeOptions): Promise<RunningServer>;
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* `streetui start` (Phase 8). Serves an existing production build. If the build
|
|
246
|
+
* output is missing we build it first, so `start` on a fresh checkout still
|
|
247
|
+
* works. Uses the standard Node HTTP server from `serve.ts`.
|
|
248
|
+
*/
|
|
249
|
+
|
|
250
|
+
interface StartOptions {
|
|
251
|
+
readonly project: ResolvedProject;
|
|
252
|
+
readonly logger: Logger;
|
|
253
|
+
/** Overrides for the configured host/port (from --host/--port). */
|
|
254
|
+
readonly host?: string;
|
|
255
|
+
readonly port?: number;
|
|
256
|
+
}
|
|
257
|
+
/** Build (if needed) and serve the production output. Resolves once listening. */
|
|
258
|
+
declare function runStart(options: StartOptions): Promise<RunningServer>;
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* Template registry (Phases 3, 11, 12). Templates are real files shipped inside
|
|
262
|
+
* the CLI package under `templates/<name>/`. They are copied verbatim at
|
|
263
|
+
* scaffold time, with two transforms: a small set of placeholder tokens are
|
|
264
|
+
* substituted, and files prefixed `_` are un-prefixed (so `_gitignore` becomes
|
|
265
|
+
* `.gitignore` and `_package.json` becomes `package.json` — npm would otherwise
|
|
266
|
+
* mangle those names on publish).
|
|
267
|
+
*/
|
|
268
|
+
/** Available starter templates. */
|
|
269
|
+
type TemplateName = 'basic' | 'ssr';
|
|
270
|
+
|
|
271
|
+
/**
|
|
272
|
+
* `streetui create` / `npm create streetui` (Phase 3). Scaffolds a real,
|
|
273
|
+
* working StreetUI project from a shipped template. No network access, no
|
|
274
|
+
* post-install magic — just a recursive copy with placeholder substitution.
|
|
275
|
+
*/
|
|
276
|
+
|
|
277
|
+
interface CreateOptions {
|
|
278
|
+
/** Target directory (relative or absolute). */
|
|
279
|
+
readonly targetDir: string;
|
|
280
|
+
/** Template to use; defaults to the SSR starter. */
|
|
281
|
+
readonly template?: string;
|
|
282
|
+
/** StreetUI package version the generated project should depend on. */
|
|
283
|
+
readonly frameworkVersion: string;
|
|
284
|
+
readonly logger: Logger;
|
|
285
|
+
}
|
|
286
|
+
interface CreateResult {
|
|
287
|
+
readonly root: string;
|
|
288
|
+
readonly template: TemplateName;
|
|
289
|
+
readonly files: readonly string[];
|
|
290
|
+
}
|
|
291
|
+
/**
|
|
292
|
+
* Scaffold a new project. Validates the template and the (empty) target, copies
|
|
293
|
+
* the tree, and returns the created root + file list. Throws `CliError` on any
|
|
294
|
+
* user-facing problem.
|
|
295
|
+
*/
|
|
296
|
+
declare function createProject(options: CreateOptions): Promise<CreateResult>;
|
|
297
|
+
|
|
298
|
+
/**
|
|
299
|
+
* Developer-facing diagnostics. Two rules govern everything here (Phase 6, 19,
|
|
300
|
+
* 22): be USEFUL and be TRUTHFUL. We only print a source position when the
|
|
301
|
+
* underlying tool (esbuild / Node) actually gives us one, and we never dress up
|
|
302
|
+
* a failure as anything other than what it is.
|
|
303
|
+
*/
|
|
304
|
+
/**
|
|
305
|
+
* A CLI-level error carrying a human-readable explanation and, optionally, a
|
|
306
|
+
* concrete suggestion. Throwing this (instead of a bare `Error`) lets the top
|
|
307
|
+
* level render a clean message rather than a raw stack trace for expected
|
|
308
|
+
* user mistakes (Phase 17).
|
|
309
|
+
*/
|
|
310
|
+
declare class CliError extends Error {
|
|
311
|
+
readonly suggestion: string | undefined;
|
|
312
|
+
/** Process exit code to use when this error reaches the top level. */
|
|
313
|
+
readonly exitCode: number;
|
|
314
|
+
constructor(message: string, options?: {
|
|
315
|
+
suggestion?: string;
|
|
316
|
+
exitCode?: number;
|
|
317
|
+
});
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
/**
|
|
321
|
+
* `@streetui/cli` public entry. Exposes the programmatic API used by the
|
|
322
|
+
* executables and the tests, and implements `runCli` — the command dispatcher
|
|
323
|
+
* that turns argv into one of `create` / `dev` / `build` / `start` (plus
|
|
324
|
+
* `--help` / `--version`). The CLI only orchestrates the existing StreetUI
|
|
325
|
+
* pipeline; it is not a framework layer of its own.
|
|
326
|
+
*/
|
|
327
|
+
|
|
328
|
+
/** The CLI version, read from the compiled package. Kept in one place. */
|
|
329
|
+
declare const CLI_VERSION = "1.0.0";
|
|
330
|
+
/** Options for `runCli`, all injectable so tests can drive it in-process. */
|
|
331
|
+
interface RunCliOptions {
|
|
332
|
+
/** Working directory the command acts on. Defaults to `process.cwd()`. */
|
|
333
|
+
readonly cwd?: string;
|
|
334
|
+
/** Logger sink. Defaults to the branded stdout logger. */
|
|
335
|
+
readonly logger?: Logger;
|
|
336
|
+
/**
|
|
337
|
+
* When true, `dev` and `start` return their running handle instead of
|
|
338
|
+
* blocking forever. Tests set this; the real binary leaves it false.
|
|
339
|
+
*/
|
|
340
|
+
readonly returnServer?: boolean;
|
|
341
|
+
}
|
|
342
|
+
/** Result of a command: an exit code plus any long-lived handle for tests. */
|
|
343
|
+
interface RunCliResult {
|
|
344
|
+
readonly exitCode: number;
|
|
345
|
+
readonly server?: {
|
|
346
|
+
url: string;
|
|
347
|
+
stop: () => Promise<void>;
|
|
348
|
+
};
|
|
349
|
+
}
|
|
350
|
+
/** Dispatch a parsed command line. Never throws for expected errors — it maps
|
|
351
|
+
* `CliError` to an exit code and a logged message instead. */
|
|
352
|
+
declare function runCli(argv: readonly string[], options?: RunCliOptions): Promise<RunCliResult>;
|
|
353
|
+
|
|
354
|
+
export { type BuildOutput, CLI_VERSION, CliError, type CreateResult, type DevServer, type Logger, PUBLIC_ENV_PREFIX, ReloadHub, type RenderFn, type RenderRequest, type RenderResult, type ResolvedConfig, type ResolvedProject, type RunCliOptions, type RunCliResult, type StreetUIConfig, buildProject, clientEnvDefine, createLogger, createProject, defineConfig, findConfigFile, loadConfig, parseArgs, publicEnvNames, resolveProject, runCli, runDev, runStart, startServer };
|