@scenar/cli 0.1.20 → 0.2.1
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/example-bundle/assets/index-BLQ14SEo.js +147 -0
- package/example-bundle/assets/logo-f-5LjVqJ.png +0 -0
- package/example-bundle/assets/style-Dnzx_jUO.css +1 -0
- package/example-bundle/index.html +13 -0
- package/example-bundle/pack-manifest.json +36 -0
- package/example-bundle/scenario.json +9 -0
- package/package.json +17 -5
- package/src/__tests__/pack-generate-embed-entry.test.ts +59 -6
- package/src/__tests__/publish-command.test.ts +46 -0
- package/src/__tests__/publish-flow.test.ts +220 -0
- package/src/__tests__/read-viewport.test.ts +45 -0
- package/src/__tests__/run-publish.test.ts +92 -0
- package/src/__tests__/serve-command.test.ts +44 -0
- package/src/__tests__/serve-request-path.test.ts +67 -0
- package/src/__tests__/serve-static-server.test.ts +88 -0
- package/src/__tests__/try-command.test.ts +21 -0
- package/src/api.d.ts +31 -0
- package/src/api.d.ts.map +1 -0
- package/src/api.js +28 -0
- package/src/api.js.map +1 -0
- package/src/api.ts +55 -0
- package/src/bundle/read-viewport.d.ts +23 -0
- package/src/bundle/read-viewport.d.ts.map +1 -0
- package/src/bundle/read-viewport.js +25 -0
- package/src/bundle/read-viewport.js.map +1 -0
- package/src/bundle/read-viewport.ts +36 -0
- package/src/commands/deploy.d.ts.map +1 -1
- package/src/commands/deploy.js +8 -24
- package/src/commands/deploy.js.map +1 -1
- package/src/commands/deploy.ts +10 -28
- package/src/commands/narrate.d.ts.map +1 -1
- package/src/commands/narrate.js +39 -170
- package/src/commands/narrate.js.map +1 -1
- package/src/commands/narrate.ts +48 -289
- package/src/commands/pack.d.ts.map +1 -1
- package/src/commands/pack.js +12 -112
- package/src/commands/pack.js.map +1 -1
- package/src/commands/pack.ts +12 -128
- package/src/commands/publish.d.ts +3 -0
- package/src/commands/publish.d.ts.map +1 -0
- package/src/commands/publish.js +64 -0
- package/src/commands/publish.js.map +1 -0
- package/src/commands/publish.ts +86 -0
- package/src/commands/render.d.ts.map +1 -1
- package/src/commands/render.js +12 -194
- package/src/commands/render.js.map +1 -1
- package/src/commands/render.ts +19 -286
- package/src/commands/serve.d.ts +3 -0
- package/src/commands/serve.d.ts.map +1 -0
- package/src/commands/serve.js +91 -0
- package/src/commands/serve.js.map +1 -0
- package/src/commands/serve.ts +112 -0
- package/src/commands/try.d.ts +3 -0
- package/src/commands/try.d.ts.map +1 -0
- package/src/commands/try.js +99 -0
- package/src/commands/try.js.map +1 -0
- package/src/commands/try.ts +122 -0
- package/src/index.d.ts.map +1 -1
- package/src/index.js +6 -0
- package/src/index.js.map +1 -1
- package/src/index.ts +6 -0
- package/src/narrate/run-narrate.d.ts +43 -0
- package/src/narrate/run-narrate.d.ts.map +1 -0
- package/src/narrate/run-narrate.js +174 -0
- package/src/narrate/run-narrate.js.map +1 -0
- package/src/narrate/run-narrate.ts +298 -0
- package/src/pack/generate-embed-entry.d.ts +11 -0
- package/src/pack/generate-embed-entry.d.ts.map +1 -1
- package/src/pack/generate-embed-entry.js +81 -10
- package/src/pack/generate-embed-entry.js.map +1 -1
- package/src/pack/generate-embed-entry.ts +81 -10
- package/src/pack/run-pack.d.ts +34 -0
- package/src/pack/run-pack.d.ts.map +1 -0
- package/src/pack/run-pack.js +117 -0
- package/src/pack/run-pack.js.map +1 -0
- package/src/pack/run-pack.ts +163 -0
- package/src/publish/github.d.ts +11 -0
- package/src/publish/github.d.ts.map +1 -0
- package/src/publish/github.js +197 -0
- package/src/publish/github.js.map +1 -0
- package/src/publish/github.ts +216 -0
- package/src/publish/publish-flow.d.ts +110 -0
- package/src/publish/publish-flow.d.ts.map +1 -0
- package/src/publish/publish-flow.js +117 -0
- package/src/publish/publish-flow.js.map +1 -0
- package/src/publish/publish-flow.ts +199 -0
- package/src/publish/run-publish.d.ts +41 -0
- package/src/publish/run-publish.d.ts.map +1 -0
- package/src/publish/run-publish.js +77 -0
- package/src/publish/run-publish.js.map +1 -0
- package/src/publish/run-publish.ts +131 -0
- package/src/render/run-render.d.ts +31 -0
- package/src/render/run-render.d.ts.map +1 -0
- package/src/render/run-render.js +196 -0
- package/src/render/run-render.js.map +1 -0
- package/src/render/run-render.ts +287 -0
- package/src/serve/request-path.d.ts +23 -0
- package/src/serve/request-path.d.ts.map +1 -0
- package/src/serve/request-path.js +52 -0
- package/src/serve/request-path.js.map +1 -0
- package/src/serve/request-path.ts +55 -0
- package/src/serve/run-serve.d.ts +31 -0
- package/src/serve/run-serve.d.ts.map +1 -0
- package/src/serve/run-serve.js +35 -0
- package/src/serve/run-serve.js.map +1 -0
- package/src/serve/run-serve.ts +68 -0
- package/src/serve/static-server.d.ts +38 -0
- package/src/serve/static-server.d.ts.map +1 -0
- package/src/serve/static-server.js +91 -0
- package/src/serve/static-server.js.map +1 -0
- package/src/serve/static-server.ts +118 -0
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { createServer } from "node:http";
|
|
2
|
+
import { createReadStream } from "node:fs";
|
|
3
|
+
import { stat } from "node:fs/promises";
|
|
4
|
+
import { resolve, sep } from "node:path";
|
|
5
|
+
import { contentTypeFor, resolveStaticPath } from "./request-path.js";
|
|
6
|
+
/**
|
|
7
|
+
* Create (but do not start) an HTTP server that serves a packed bundle as a
|
|
8
|
+
* static site. Only GET/HEAD are allowed; every response carries the bundle
|
|
9
|
+
* contract's canonical content type and `Cache-Control: no-cache` (a local
|
|
10
|
+
* preview should always reflect the latest pack, never a stale asset).
|
|
11
|
+
*
|
|
12
|
+
* No CSP or other security headers are emitted: that envelope is the serving
|
|
13
|
+
* edge's responsibility (and is enforced + tested in scenar-cloud). A local
|
|
14
|
+
* preview deliberately matches the headerless behaviour of a plain static host
|
|
15
|
+
* such as GitHub Pages — the other Phase 1 target — so what you see locally is
|
|
16
|
+
* what a `scenar publish` visitor sees.
|
|
17
|
+
*/
|
|
18
|
+
export function createBundleServer(rootDir) {
|
|
19
|
+
const root = resolve(rootDir);
|
|
20
|
+
return createServer((req, res) => {
|
|
21
|
+
void serveRequest(root, req, res).catch(() => {
|
|
22
|
+
if (!res.headersSent)
|
|
23
|
+
res.writeHead(500, { "content-type": "text/plain" });
|
|
24
|
+
res.end("Internal Server Error");
|
|
25
|
+
});
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
async function serveRequest(root, req, res) {
|
|
29
|
+
if (req.method !== "GET" && req.method !== "HEAD") {
|
|
30
|
+
res.writeHead(405, { allow: "GET, HEAD", "content-type": "text/plain" });
|
|
31
|
+
res.end("Method Not Allowed");
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
const relativePath = resolveStaticPath(req.url ?? "/");
|
|
35
|
+
if (relativePath === null) {
|
|
36
|
+
res.writeHead(400, { "content-type": "text/plain" });
|
|
37
|
+
res.end("Bad Request");
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
const absolutePath = resolve(root, relativePath);
|
|
41
|
+
// Defence in depth: the resolved path must stay within the bundle root even
|
|
42
|
+
// if resolveStaticPath ever let something through.
|
|
43
|
+
if (absolutePath !== root && !absolutePath.startsWith(root + sep)) {
|
|
44
|
+
res.writeHead(403, { "content-type": "text/plain" });
|
|
45
|
+
res.end("Forbidden");
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
const info = await stat(absolutePath).catch(() => null);
|
|
49
|
+
if (!info || !info.isFile()) {
|
|
50
|
+
res.writeHead(404, { "content-type": "text/plain" });
|
|
51
|
+
res.end("Not Found");
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
res.writeHead(200, {
|
|
55
|
+
"content-type": contentTypeFor(relativePath),
|
|
56
|
+
"content-length": info.size,
|
|
57
|
+
"cache-control": "no-cache",
|
|
58
|
+
});
|
|
59
|
+
if (req.method === "HEAD") {
|
|
60
|
+
res.end();
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
createReadStream(absolutePath).pipe(res);
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Start an HTTP server for a packed bundle and resolve once it is listening.
|
|
67
|
+
* Rejects if the port is already in use (the caller surfaces a clear message).
|
|
68
|
+
*/
|
|
69
|
+
export function startBundleServer(options) {
|
|
70
|
+
const host = options.host ?? "localhost";
|
|
71
|
+
const server = createBundleServer(options.rootDir);
|
|
72
|
+
return new Promise((resolvePromise, reject) => {
|
|
73
|
+
const onError = (error) => reject(error);
|
|
74
|
+
server.once("error", onError);
|
|
75
|
+
server.listen(options.port, host, () => {
|
|
76
|
+
server.removeListener("error", onError);
|
|
77
|
+
const address = server.address();
|
|
78
|
+
const port = typeof address === "object" && address ? address.port : options.port;
|
|
79
|
+
// Wildcard binds are not dialable hostnames; advertise localhost instead.
|
|
80
|
+
const displayHost = host === "0.0.0.0" || host === "::" ? "localhost" : host;
|
|
81
|
+
resolvePromise({
|
|
82
|
+
url: `http://${displayHost}:${port}/`,
|
|
83
|
+
port,
|
|
84
|
+
close: () => new Promise((done, fail) => {
|
|
85
|
+
server.close((err) => (err ? fail(err) : done()));
|
|
86
|
+
}),
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=static-server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"static-server.js","sourceRoot":"","sources":["../../../src/serve/static-server.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { createServer, type IncomingMessage, type Server, type ServerResponse } from "node:http";
|
|
2
|
+
import { createReadStream } from "node:fs";
|
|
3
|
+
import { stat } from "node:fs/promises";
|
|
4
|
+
import { resolve, sep } from "node:path";
|
|
5
|
+
import { contentTypeFor, resolveStaticPath } from "./request-path.js";
|
|
6
|
+
|
|
7
|
+
/** A running bundle server: where it is reachable and how to stop it. */
|
|
8
|
+
export interface BundleServerHandle {
|
|
9
|
+
/** The base URL the bundle is served at (e.g. http://localhost:4173/). */
|
|
10
|
+
readonly url: string;
|
|
11
|
+
/** The port the server actually bound (useful when port 0 was requested). */
|
|
12
|
+
readonly port: number;
|
|
13
|
+
/** Stop accepting connections and release the port. */
|
|
14
|
+
close(): Promise<void>;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/** Options for {@link startBundleServer}. */
|
|
18
|
+
export interface StartBundleServerOptions {
|
|
19
|
+
/** Bundle directory to serve (a `scenar pack` output). */
|
|
20
|
+
readonly rootDir: string;
|
|
21
|
+
/** Port to bind; 0 lets the OS pick a free one (handy in tests). */
|
|
22
|
+
readonly port: number;
|
|
23
|
+
/** Host/interface to bind. Defaults to "localhost". */
|
|
24
|
+
readonly host?: string;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Create (but do not start) an HTTP server that serves a packed bundle as a
|
|
29
|
+
* static site. Only GET/HEAD are allowed; every response carries the bundle
|
|
30
|
+
* contract's canonical content type and `Cache-Control: no-cache` (a local
|
|
31
|
+
* preview should always reflect the latest pack, never a stale asset).
|
|
32
|
+
*
|
|
33
|
+
* No CSP or other security headers are emitted: that envelope is the serving
|
|
34
|
+
* edge's responsibility (and is enforced + tested in scenar-cloud). A local
|
|
35
|
+
* preview deliberately matches the headerless behaviour of a plain static host
|
|
36
|
+
* such as GitHub Pages — the other Phase 1 target — so what you see locally is
|
|
37
|
+
* what a `scenar publish` visitor sees.
|
|
38
|
+
*/
|
|
39
|
+
export function createBundleServer(rootDir: string): Server {
|
|
40
|
+
const root = resolve(rootDir);
|
|
41
|
+
return createServer((req, res) => {
|
|
42
|
+
void serveRequest(root, req, res).catch(() => {
|
|
43
|
+
if (!res.headersSent) res.writeHead(500, { "content-type": "text/plain" });
|
|
44
|
+
res.end("Internal Server Error");
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
async function serveRequest(root: string, req: IncomingMessage, res: ServerResponse): Promise<void> {
|
|
50
|
+
if (req.method !== "GET" && req.method !== "HEAD") {
|
|
51
|
+
res.writeHead(405, { allow: "GET, HEAD", "content-type": "text/plain" });
|
|
52
|
+
res.end("Method Not Allowed");
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const relativePath = resolveStaticPath(req.url ?? "/");
|
|
57
|
+
if (relativePath === null) {
|
|
58
|
+
res.writeHead(400, { "content-type": "text/plain" });
|
|
59
|
+
res.end("Bad Request");
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const absolutePath = resolve(root, relativePath);
|
|
64
|
+
// Defence in depth: the resolved path must stay within the bundle root even
|
|
65
|
+
// if resolveStaticPath ever let something through.
|
|
66
|
+
if (absolutePath !== root && !absolutePath.startsWith(root + sep)) {
|
|
67
|
+
res.writeHead(403, { "content-type": "text/plain" });
|
|
68
|
+
res.end("Forbidden");
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const info = await stat(absolutePath).catch(() => null);
|
|
73
|
+
if (!info || !info.isFile()) {
|
|
74
|
+
res.writeHead(404, { "content-type": "text/plain" });
|
|
75
|
+
res.end("Not Found");
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
res.writeHead(200, {
|
|
80
|
+
"content-type": contentTypeFor(relativePath),
|
|
81
|
+
"content-length": info.size,
|
|
82
|
+
"cache-control": "no-cache",
|
|
83
|
+
});
|
|
84
|
+
if (req.method === "HEAD") {
|
|
85
|
+
res.end();
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
createReadStream(absolutePath).pipe(res);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Start an HTTP server for a packed bundle and resolve once it is listening.
|
|
93
|
+
* Rejects if the port is already in use (the caller surfaces a clear message).
|
|
94
|
+
*/
|
|
95
|
+
export function startBundleServer(options: StartBundleServerOptions): Promise<BundleServerHandle> {
|
|
96
|
+
const host = options.host ?? "localhost";
|
|
97
|
+
const server = createBundleServer(options.rootDir);
|
|
98
|
+
|
|
99
|
+
return new Promise<BundleServerHandle>((resolvePromise, reject) => {
|
|
100
|
+
const onError = (error: Error) => reject(error);
|
|
101
|
+
server.once("error", onError);
|
|
102
|
+
server.listen(options.port, host, () => {
|
|
103
|
+
server.removeListener("error", onError);
|
|
104
|
+
const address = server.address();
|
|
105
|
+
const port = typeof address === "object" && address ? address.port : options.port;
|
|
106
|
+
// Wildcard binds are not dialable hostnames; advertise localhost instead.
|
|
107
|
+
const displayHost = host === "0.0.0.0" || host === "::" ? "localhost" : host;
|
|
108
|
+
resolvePromise({
|
|
109
|
+
url: `http://${displayHost}:${port}/`,
|
|
110
|
+
port,
|
|
111
|
+
close: () =>
|
|
112
|
+
new Promise<void>((done, fail) => {
|
|
113
|
+
server.close((err) => (err ? fail(err) : done()));
|
|
114
|
+
}),
|
|
115
|
+
});
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
}
|