@pracht/cli 1.2.2 → 1.3.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/CHANGELOG.md +20 -0
- package/dist/{build-DkP2ffu9.mjs → build-CiFKxDlE.mjs} +7 -3
- package/dist/{doctor-CwQJjJ83.mjs → doctor-pY1BYaFH.mjs} +1 -1
- package/dist/{generate-C9AMSGsv.mjs → generate-DqKWCmIu.mjs} +1 -1
- package/dist/index.mjs +5 -5
- package/dist/{inspect-MseHPU9s.mjs → inspect-vYYIN8Ju.mjs} +1 -1
- package/dist/{project-BdMiN3s7.mjs → project-CfxHKBzP.mjs} +33 -7
- package/dist/{verification-Dwf1ZuNn.mjs → verification-ClzkW6_q.mjs} +9 -8
- package/dist/{verify-o0G5Xuff.mjs → verify-eRkOdBaK.mjs} +1 -1
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,25 @@
|
|
|
1
1
|
# @pracht/cli
|
|
2
2
|
|
|
3
|
+
## 1.3.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#137](https://github.com/JoviDeCroock/pracht/pull/137) [`ac32c2c`](https://github.com/JoviDeCroock/pracht/commit/ac32c2cb9ce5e86a38cde1167269e368f41dea0e) Thanks [@JoviDeCroock](https://github.com/JoviDeCroock)! - Harden same-origin request checks and HTML head rendering, improve client prefetch/navigation behavior, fix cross-platform path handling, stream and conditionally revalidate Node static responses, de-document Cloudflare runtime ISG revalidation, and align starter/docs with the current CLI/runtime behavior.
|
|
8
|
+
|
|
9
|
+
- Updated dependencies [[`ac32c2c`](https://github.com/JoviDeCroock/pracht/commit/ac32c2cb9ce5e86a38cde1167269e368f41dea0e), [`49d6348`](https://github.com/JoviDeCroock/pracht/commit/49d6348bc984464cdb0e8c54c5ef9ba5cdec911e)]:
|
|
10
|
+
- @pracht/core@0.5.0
|
|
11
|
+
|
|
12
|
+
## 1.3.0
|
|
13
|
+
|
|
14
|
+
### Minor Changes
|
|
15
|
+
|
|
16
|
+
- [#133](https://github.com/JoviDeCroock/pracht/pull/133) [`f8c5c1f`](https://github.com/JoviDeCroock/pracht/commit/f8c5c1fe1a7c7b5d7accd8028e8c12929a218081) Thanks [@JoviDeCroock](https://github.com/JoviDeCroock)! - API routes now support catch-all segments (e.g. `src/api/files/[...path].ts` → `/api/files/*`), matching the existing page-routing convention. The matched rest-path is exposed on the route params as `"*"`. Previously `[...param]` was silently turned into a `:...param` dynamic segment with a broken name.
|
|
17
|
+
|
|
18
|
+
### Patch Changes
|
|
19
|
+
|
|
20
|
+
- Updated dependencies [[`f8c5c1f`](https://github.com/JoviDeCroock/pracht/commit/f8c5c1fe1a7c7b5d7accd8028e8c12929a218081)]:
|
|
21
|
+
- @pracht/core@0.4.0
|
|
22
|
+
|
|
3
23
|
## 1.2.2
|
|
4
24
|
|
|
5
25
|
### Patch Changes
|
|
@@ -3,6 +3,7 @@ import { t as readClientBuildAssets } from "./build-metadata-BOChHO8g.mjs";
|
|
|
3
3
|
import { defineCommand } from "citty";
|
|
4
4
|
import { cpSync, existsSync, mkdirSync, readdirSync, rmSync, writeFileSync } from "node:fs";
|
|
5
5
|
import { dirname, join, resolve } from "node:path";
|
|
6
|
+
import { pathToFileURL } from "node:url";
|
|
6
7
|
import { build } from "vite";
|
|
7
8
|
//#region src/build-shared.ts
|
|
8
9
|
const ROUTE_STATE_REQUEST_HEADER = "x-pracht-route-state-request";
|
|
@@ -145,7 +146,8 @@ var build_default = defineCommand({
|
|
|
145
146
|
root,
|
|
146
147
|
build: {
|
|
147
148
|
outDir: "dist/server",
|
|
148
|
-
|
|
149
|
+
rollupOptions: { input: "virtual:pracht/server" },
|
|
150
|
+
ssr: true
|
|
149
151
|
}
|
|
150
152
|
});
|
|
151
153
|
const serverEntry = resolve(root, "dist/server/server.js");
|
|
@@ -168,7 +170,7 @@ var build_default = defineCommand({
|
|
|
168
170
|
const publicDir = resolve(root, "public");
|
|
169
171
|
if (existsSync(publicDir)) cpSync(publicDir, clientDir, { recursive: true });
|
|
170
172
|
if (existsSync(serverEntry)) {
|
|
171
|
-
const serverMod = await import(serverEntry);
|
|
173
|
+
const serverMod = await import(pathToFileURL(serverEntry).href);
|
|
172
174
|
const { prerenderApp } = serverMod;
|
|
173
175
|
const { clientEntryUrl, cssManifest, jsManifest } = readClientBuildAssets(root);
|
|
174
176
|
const { pages, isgManifest } = await prerenderApp({
|
|
@@ -177,7 +179,8 @@ var build_default = defineCommand({
|
|
|
177
179
|
cssManifest,
|
|
178
180
|
jsManifest,
|
|
179
181
|
registry: serverMod.registry,
|
|
180
|
-
withISGManifest: true
|
|
182
|
+
withISGManifest: true,
|
|
183
|
+
concurrency: serverMod.prerenderConcurrency
|
|
181
184
|
});
|
|
182
185
|
const headersManifest = Object.fromEntries(pages.map((page) => [page.path, page.headers ?? {}]));
|
|
183
186
|
if (pages.length > 0) {
|
|
@@ -200,6 +203,7 @@ var build_default = defineCommand({
|
|
|
200
203
|
console.log(`\n ISG manifest → dist/server/isg-manifest.json (${Object.keys(isgManifest).length} route(s))\n`);
|
|
201
204
|
}
|
|
202
205
|
if (serverMod.buildTarget === "cloudflare") {
|
|
206
|
+
if (Object.keys(isgManifest).length > 0) console.warn("\n Warning: Cloudflare adapter currently serves prerendered ISG HTML as static assets and does not perform runtime revalidation. Use SSR/SSG on Cloudflare, or deploy ISG routes to Node until Cloudflare ISG support is added.\n");
|
|
203
207
|
console.log("\n Cloudflare worker → dist/server/server.js\n");
|
|
204
208
|
console.log(" Deploy with: wrangler deploy\n");
|
|
205
209
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { _ as requireEnum, a as readProjectConfig, c as resolveProjectPath, d as writeGeneratedFile, f as ensureTrailingNewline, g as quote, h as parseCommaList, l as resolveRouteModulePath, m as parseApiMethods, n as displayPath, o as resolveApiModulePath, s as resolvePagesRouteModulePath, t as assertFileExists, u as resolveScopedFile, v as requirePositiveInteger } from "./project-
|
|
1
|
+
import { _ as requireEnum, a as readProjectConfig, c as resolveProjectPath, d as writeGeneratedFile, f as ensureTrailingNewline, g as quote, h as parseCommaList, l as resolveRouteModulePath, m as parseApiMethods, n as displayPath, o as resolveApiModulePath, s as resolvePagesRouteModulePath, t as assertFileExists, u as resolveScopedFile, v as requirePositiveInteger } from "./project-CfxHKBzP.mjs";
|
|
2
2
|
import { a as toManifestModulePath, i as insertArrayItem, n as extractRegistryEntries, o as upsertObjectEntry, t as ensureCoreNamedImport } from "./manifest-Bs5hp3gA.mjs";
|
|
3
3
|
import { defineCommand } from "citty";
|
|
4
4
|
import { readFileSync, writeFileSync } from "node:fs";
|
package/dist/index.mjs
CHANGED
|
@@ -29,12 +29,12 @@ runMain(defineCommand({
|
|
|
29
29
|
description: "The pracht CLI"
|
|
30
30
|
},
|
|
31
31
|
subCommands: {
|
|
32
|
-
build: () => import("./build-
|
|
32
|
+
build: () => import("./build-CiFKxDlE.mjs").then((m) => m.default),
|
|
33
33
|
dev: () => import("./dev-BCFe3g38.mjs").then((m) => m.default),
|
|
34
|
-
doctor: () => import("./doctor-
|
|
35
|
-
generate: () => import("./generate-
|
|
36
|
-
inspect: () => import("./inspect-
|
|
37
|
-
verify: () => import("./verify-
|
|
34
|
+
doctor: () => import("./doctor-pY1BYaFH.mjs").then((m) => m.default),
|
|
35
|
+
generate: () => import("./generate-DqKWCmIu.mjs").then((m) => m.default),
|
|
36
|
+
inspect: () => import("./inspect-vYYIN8Ju.mjs").then((m) => m.default),
|
|
37
|
+
verify: () => import("./verify-eRkOdBaK.mjs").then((m) => m.default)
|
|
38
38
|
}
|
|
39
39
|
}));
|
|
40
40
|
//#endregion
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { t as HTTP_METHODS } from "./index.mjs";
|
|
2
2
|
import { t as readClientBuildAssets } from "./build-metadata-BOChHO8g.mjs";
|
|
3
|
-
import { a as readProjectConfig, c as resolveProjectPath, p as handleCliError } from "./project-
|
|
3
|
+
import { a as readProjectConfig, c as resolveProjectPath, p as handleCliError } from "./project-CfxHKBzP.mjs";
|
|
4
4
|
import { defineCommand } from "citty";
|
|
5
5
|
import { existsSync, readFileSync } from "node:fs";
|
|
6
6
|
import { resolve } from "node:path";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { n as PROJECT_DEFAULTS, t as HTTP_METHODS } from "./index.mjs";
|
|
2
2
|
import { existsSync, mkdirSync, readFileSync, readdirSync, writeFileSync } from "node:fs";
|
|
3
|
-
import { basename, dirname, relative, resolve } from "node:path";
|
|
3
|
+
import { basename, dirname, isAbsolute, relative, resolve } from "node:path";
|
|
4
4
|
//#region src/utils.ts
|
|
5
5
|
function quote(value) {
|
|
6
6
|
return JSON.stringify(value);
|
|
@@ -64,34 +64,47 @@ function resolveProjectPath(root, configPath) {
|
|
|
64
64
|
return resolve(root, `.${configPath}`);
|
|
65
65
|
}
|
|
66
66
|
function resolveScopedFile(root, configDir, fileName) {
|
|
67
|
-
|
|
67
|
+
assertSafePathSegment(fileName.replace(/\.(ts|tsx|js|jsx)$/, ""));
|
|
68
|
+
const baseDir = resolveProjectPath(root, configDir);
|
|
69
|
+
const filePath = resolve(baseDir, fileName);
|
|
70
|
+
assertInsideDirectory(baseDir, filePath);
|
|
71
|
+
return filePath;
|
|
68
72
|
}
|
|
69
73
|
function resolveRouteModulePath(project, routePath, extension) {
|
|
70
74
|
const segments = segmentsFromPath(routePath);
|
|
71
75
|
const relativePath = segments.length === 0 ? `index${extension}` : `${segments.join("/")}${extension}`;
|
|
76
|
+
const baseDir = resolveProjectPath(project.root, project.routesDir);
|
|
77
|
+
const absolutePath = resolve(baseDir, relativePath);
|
|
78
|
+
assertInsideDirectory(baseDir, absolutePath);
|
|
72
79
|
return {
|
|
73
|
-
absolutePath
|
|
80
|
+
absolutePath,
|
|
74
81
|
relativePath
|
|
75
82
|
};
|
|
76
83
|
}
|
|
77
84
|
function resolvePagesRouteModulePath(project, routePath, extension) {
|
|
78
85
|
const segments = segmentsFromPath(routePath);
|
|
79
86
|
const relativePath = segments.length === 0 ? `index${extension}` : `${segments.join("/")}${extension}`;
|
|
87
|
+
const baseDir = resolveProjectPath(project.root, project.pagesDir);
|
|
88
|
+
const absolutePath = resolve(baseDir, relativePath);
|
|
89
|
+
assertInsideDirectory(baseDir, absolutePath);
|
|
80
90
|
return {
|
|
81
|
-
absolutePath
|
|
91
|
+
absolutePath,
|
|
82
92
|
relativePath
|
|
83
93
|
};
|
|
84
94
|
}
|
|
85
95
|
function resolveApiModulePath(project, endpointPath) {
|
|
86
96
|
const segments = segmentsFromPath(endpointPath);
|
|
87
97
|
const relativePath = segments.length === 0 ? "index.ts" : `${segments.join("/")}.ts`;
|
|
98
|
+
const baseDir = resolveProjectPath(project.root, project.apiDir);
|
|
99
|
+
const absolutePath = resolve(baseDir, relativePath);
|
|
100
|
+
assertInsideDirectory(baseDir, absolutePath);
|
|
88
101
|
return {
|
|
89
|
-
absolutePath
|
|
102
|
+
absolutePath,
|
|
90
103
|
relativePath
|
|
91
104
|
};
|
|
92
105
|
}
|
|
93
106
|
function displayPath(root, filePath) {
|
|
94
|
-
return relative(root, filePath) || ".";
|
|
107
|
+
return (relative(root, filePath) || ".").replace(/\\/g, "/");
|
|
95
108
|
}
|
|
96
109
|
function writeGeneratedFile(filePath, source) {
|
|
97
110
|
if (existsSync(filePath)) throw new Error(`Refusing to overwrite existing file ${filePath}.`);
|
|
@@ -139,10 +152,23 @@ function normalizeConfigPath(value) {
|
|
|
139
152
|
}
|
|
140
153
|
function segmentsFromPath(path) {
|
|
141
154
|
return path.split("/").filter(Boolean).map((segment) => {
|
|
142
|
-
|
|
155
|
+
assertSafePathSegment(segment);
|
|
156
|
+
if (segment.startsWith(":")) {
|
|
157
|
+
const name = segment.endsWith("*") ? segment.slice(1, -1) : segment.slice(1);
|
|
158
|
+
assertSafePathSegment(name);
|
|
159
|
+
return segment.endsWith("*") ? `[...${name || "slug"}]` : `[${name}]`;
|
|
160
|
+
}
|
|
143
161
|
if (segment === "*") return "[...slug]";
|
|
144
162
|
return segment;
|
|
145
163
|
});
|
|
146
164
|
}
|
|
165
|
+
function assertSafePathSegment(segment) {
|
|
166
|
+
if (!segment || segment === "." || segment === ".." || segment.includes("/") || segment.includes("\\") || segment.includes("\0")) throw new Error(`Unsafe path segment: ${JSON.stringify(segment)}.`);
|
|
167
|
+
}
|
|
168
|
+
function assertInsideDirectory(baseDir, filePath) {
|
|
169
|
+
const relativePath = relative(baseDir, filePath);
|
|
170
|
+
if (relativePath === "" || !relativePath.startsWith("..") && !isAbsolute(relativePath)) return;
|
|
171
|
+
throw new Error(`Refusing to write outside ${baseDir}.`);
|
|
172
|
+
}
|
|
147
173
|
//#endregion
|
|
148
174
|
export { requireEnum as _, readProjectConfig as a, resolveProjectPath as c, writeGeneratedFile as d, ensureTrailingNewline as f, quote as g, parseCommaList as h, listFilesRecursively as i, resolveRouteModulePath as l, parseApiMethods as m, displayPath as n, resolveApiModulePath as o, handleCliError as p, hasPagesAppShell as r, resolvePagesRouteModulePath as s, assertFileExists as t, resolveScopedFile as u, requirePositiveInteger as v };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { a as readProjectConfig, c as resolveProjectPath, i as listFilesRecursively, n as displayPath, r as hasPagesAppShell } from "./project-
|
|
1
|
+
import { a as readProjectConfig, c as resolveProjectPath, i as listFilesRecursively, n as displayPath, r as hasPagesAppShell } from "./project-CfxHKBzP.mjs";
|
|
2
2
|
import { n as extractRegistryEntries, r as extractRelativeModulePaths } from "./manifest-Bs5hp3gA.mjs";
|
|
3
3
|
import { existsSync, readFileSync } from "node:fs";
|
|
4
|
-
import { basename, dirname, relative, resolve } from "node:path";
|
|
4
|
+
import { basename, dirname, isAbsolute, relative, resolve } from "node:path";
|
|
5
5
|
import { execFileSync } from "node:child_process";
|
|
6
6
|
//#region src/verification-helpers.ts
|
|
7
7
|
const CONFIG_FILE_NAMES = new Set([
|
|
@@ -22,7 +22,7 @@ function createCheck(status, message) {
|
|
|
22
22
|
}
|
|
23
23
|
function isWithinDirectory(filePath, directoryPath) {
|
|
24
24
|
const relativePath = relative(directoryPath, filePath);
|
|
25
|
-
return relativePath === "" || !relativePath.startsWith("..") && !relativePath
|
|
25
|
+
return relativePath === "" || !relativePath.startsWith("..") && !isAbsolute(relativePath);
|
|
26
26
|
}
|
|
27
27
|
function normalizePath(value) {
|
|
28
28
|
return value.replace(/\\/g, "/");
|
|
@@ -42,6 +42,7 @@ function resolveApiRoutePath(apiDir, file) {
|
|
|
42
42
|
relativePath = relativePath.replace(/\.(ts|tsx|js|jsx)$/, "");
|
|
43
43
|
if (relativePath === "index") relativePath = "";
|
|
44
44
|
else relativePath = relativePath.replace(/\/index$/, "");
|
|
45
|
+
relativePath = relativePath.replace(/\[\.\.\.[^\]]+\]/g, "*");
|
|
45
46
|
relativePath = relativePath.replace(/\[([^\]]+)\]/g, ":$1");
|
|
46
47
|
return normalizeRoutePath(relativePath ? `/api/${relativePath}` : "/api");
|
|
47
48
|
}
|
|
@@ -270,9 +271,9 @@ function collectChangedFiles(root) {
|
|
|
270
271
|
if (!record) continue;
|
|
271
272
|
if (record.includes(" -> ")) {
|
|
272
273
|
const [from, to] = record.split(" -> ");
|
|
273
|
-
addChangedFile(files,
|
|
274
|
-
addChangedFile(files,
|
|
275
|
-
} else addChangedFile(files,
|
|
274
|
+
addChangedFile(files, root, prefix, from);
|
|
275
|
+
addChangedFile(files, root, prefix, to);
|
|
276
|
+
} else addChangedFile(files, root, prefix, record);
|
|
276
277
|
}
|
|
277
278
|
return {
|
|
278
279
|
files: [...files],
|
|
@@ -285,11 +286,11 @@ function collectChangedFiles(root) {
|
|
|
285
286
|
};
|
|
286
287
|
}
|
|
287
288
|
}
|
|
288
|
-
function addChangedFile(files,
|
|
289
|
+
function addChangedFile(files, projectRoot, prefix, repoRelativePath) {
|
|
289
290
|
if (prefix && !repoRelativePath.startsWith(prefix)) return;
|
|
290
291
|
const projectRelativePath = prefix ? repoRelativePath.slice(prefix.length) : repoRelativePath;
|
|
291
292
|
if (!projectRelativePath) return;
|
|
292
|
-
files.add(resolve(
|
|
293
|
+
files.add(resolve(projectRoot, projectRelativePath));
|
|
293
294
|
}
|
|
294
295
|
function filterFrameworkFiles(project, files, packageJsonPath) {
|
|
295
296
|
const appFile = resolveProjectPath(project.root, project.appFile);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pracht/cli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.1",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"homepage": "https://github.com/JoviDeCroock/pracht/tree/main/packages/cli",
|
|
6
6
|
"bugs": {
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
},
|
|
28
28
|
"dependencies": {
|
|
29
29
|
"citty": "^0.1.6",
|
|
30
|
-
"@pracht/core": "0.
|
|
30
|
+
"@pracht/core": "0.5.0"
|
|
31
31
|
},
|
|
32
32
|
"scripts": {
|
|
33
33
|
"build": "tsdown"
|