vagejs 0.3.3 → 0.3.5
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/index.js +6 -0
- package/dist/deploy/cloudflare-workers.js +5 -2
- package/dist/deploy/github-pages.d.ts +7 -0
- package/dist/deploy/github-pages.js +20 -0
- package/dist/dev/server.js +7 -2
- package/dist/discovery/git-dates.js +5 -6
- package/package.json +1 -1
- package/templates/starter/AGENTS.md +3 -1
- package/templates/starter/package.json +1 -1
- package/templates/starter/vage.config.ts +2 -2
package/dist/cli/index.js
CHANGED
|
@@ -197,6 +197,12 @@ cli
|
|
|
197
197
|
throw new VageError(`Unknown --target "${target}". Use github-pages, cloudflare-workers or cloudflare-pages.`);
|
|
198
198
|
const { publish } = await import("../deploy/publish.js");
|
|
199
199
|
const pages = await import("../deploy/github-pages.js");
|
|
200
|
+
// Stop before pushing a site GitHub Pages would serve from a subfolder (its links would break).
|
|
201
|
+
const { gitRaw } = await import("../deploy/git.js");
|
|
202
|
+
const origin = opts.remote ?? (await gitRaw(path.resolve(opts.root), ["remote", "get-url", "origin"]).catch(() => undefined))?.stdout?.trim();
|
|
203
|
+
const subfolder = pages.pagesSubfolderProblem(config.site, origin);
|
|
204
|
+
if (subfolder)
|
|
205
|
+
throw new VageError(subfolder);
|
|
200
206
|
const result = await publish(opts.root, {
|
|
201
207
|
...opts,
|
|
202
208
|
extraFiles: (branch) => ({ [pages.PAGES_WORKFLOW]: pages.pagesWorkflow(branch) }),
|
|
@@ -178,7 +178,8 @@ export async function deployCloudflareWorkers(root, options) {
|
|
|
178
178
|
output = out(upload);
|
|
179
179
|
if (upload.code !== 0) {
|
|
180
180
|
// Only a Worker that doesn't exist yet gets a full deploy (which also attaches routes).
|
|
181
|
-
|
|
181
|
+
// wrangler 4.152 says "...a new version of a Worker that does not yet exist" (no code).
|
|
182
|
+
if (!/\b10007\b|worker[^\n]*(?:does not (?:yet )?exist|not found)/i.test(output))
|
|
182
183
|
return { status: "failure", worker, reason: failReason(upload.code, output) };
|
|
183
184
|
mode = "first-deploy";
|
|
184
185
|
const first = await wrangler("deploy");
|
|
@@ -211,7 +212,9 @@ export async function deployCloudflareWorkers(root, options) {
|
|
|
211
212
|
return { status: "success", worker, mode, versionId, pageUrl };
|
|
212
213
|
await sleep(3000);
|
|
213
214
|
}
|
|
214
|
-
|
|
215
|
+
// `site` may not point at this Worker yet (a new domain, or a typo): say where the Worker itself answers.
|
|
216
|
+
const own = workersDev && workersDev !== pageUrl ? ` The Worker itself is at ${workersDev}. If ${pageUrl} is your own domain, attach it to the Worker (routes or a custom domain in your wrangler config).` : "";
|
|
217
|
+
return { status: "unconfirmed", worker, mode, versionId, pageUrl, reason: `Deployed, but ${pageUrl} did not respond with 200 yet. Check it in a minute.${own}` };
|
|
215
218
|
}
|
|
216
219
|
finally {
|
|
217
220
|
if (tempDir)
|
|
@@ -31,3 +31,10 @@ export declare function confirmPagesDeployment(cwd: string, sha: string, options
|
|
|
31
31
|
sleep?: (ms: number) => Promise<void>;
|
|
32
32
|
findRunAttempts?: number;
|
|
33
33
|
}): Promise<DeployStatus>;
|
|
34
|
+
/**
|
|
35
|
+
* GitHub Pages serves a repository named anything but <owner>.github.io from a subfolder
|
|
36
|
+
* (https://owner.github.io/repo/). vagejs sites need the root of a domain (links like
|
|
37
|
+
* /about/ would point outside the site), so that only works with a custom domain.
|
|
38
|
+
* Returns the problem to show before anything is pushed, or undefined when it's fine.
|
|
39
|
+
*/
|
|
40
|
+
export declare function pagesSubfolderProblem(site: string | undefined, remote: string | undefined): string | undefined;
|
|
@@ -99,3 +99,23 @@ export async function confirmPagesDeployment(cwd, sha, options = {}) {
|
|
|
99
99
|
const pages = await run("gh", ["api", "repos/{owner}/{repo}/pages", "--jq", ".html_url"], cwd);
|
|
100
100
|
return { status: "success", runUrl, pageUrl: pages.code === 0 ? pages.stdout.trim() || undefined : undefined };
|
|
101
101
|
}
|
|
102
|
+
/**
|
|
103
|
+
* GitHub Pages serves a repository named anything but <owner>.github.io from a subfolder
|
|
104
|
+
* (https://owner.github.io/repo/). vagejs sites need the root of a domain (links like
|
|
105
|
+
* /about/ would point outside the site), so that only works with a custom domain.
|
|
106
|
+
* Returns the problem to show before anything is pushed, or undefined when it's fine.
|
|
107
|
+
*/
|
|
108
|
+
export function pagesSubfolderProblem(site, remote) {
|
|
109
|
+
const m = remote && /(?:^|[@/])github\.com[/:]([^/\s]+)\/([^/\s]+?)(?:\.git)?\/?$/i.exec(remote.trim());
|
|
110
|
+
if (!m || !site)
|
|
111
|
+
return undefined;
|
|
112
|
+
const [, owner, repo] = m;
|
|
113
|
+
if (repo.toLowerCase() === `${owner}.github.io`.toLowerCase())
|
|
114
|
+
return undefined;
|
|
115
|
+
if (!/\.github\.io$/i.test(new URL(site).hostname))
|
|
116
|
+
return undefined; // a custom domain serves the root
|
|
117
|
+
return (`GitHub Pages would serve this repository at https://${owner.toLowerCase()}.github.io/${repo}/, a subfolder, ` +
|
|
118
|
+
`but a vagejs site must be served from the root of a domain: links like /about/ would point outside the site. Either:\n` +
|
|
119
|
+
` - use your own domain: set site to it in vage.config.ts and add it in the repository under Settings → Pages → Custom domain, or\n` +
|
|
120
|
+
` - publish from a repository named ${owner}.github.io (set site to https://${owner.toLowerCase()}.github.io).`);
|
|
121
|
+
}
|
package/dist/dev/server.js
CHANGED
|
@@ -20,10 +20,11 @@ import { redirect } from "./preview.js";
|
|
|
20
20
|
*/
|
|
21
21
|
export async function startDevServer(root, options = {}) {
|
|
22
22
|
// Vite reports watcher paths with symlinks resolved, so compare against the real path.
|
|
23
|
+
// .native also expands Windows 8.3 short names (RUNNER~1 -> runneradmin).
|
|
23
24
|
root = path.resolve(root);
|
|
24
25
|
if (!fs.existsSync(root))
|
|
25
26
|
throw new VageError(`Project directory not found: ${root}`);
|
|
26
|
-
root = fs.realpathSync(root);
|
|
27
|
+
root = fs.realpathSync.native(root);
|
|
27
28
|
const pagesDir = path.join(root, "src", "pages");
|
|
28
29
|
const srcDir = path.join(root, "src") + path.sep;
|
|
29
30
|
const server = await createServer({
|
|
@@ -32,8 +33,12 @@ export async function startDevServer(root, options = {}) {
|
|
|
32
33
|
server: { port: options.port, strictPort: options.port !== undefined, host: options.host },
|
|
33
34
|
});
|
|
34
35
|
const load = viteLoader(server);
|
|
36
|
+
// Vite reports "C:/..." on Windows; compare normalized paths, ignoring case there.
|
|
37
|
+
const key = (file) => (process.platform === "win32" ? path.resolve(file).toLowerCase() : path.resolve(file));
|
|
38
|
+
const srcKey = key(srcDir.slice(0, -1)) + path.sep;
|
|
35
39
|
server.watcher.on("all", (_event, file) => {
|
|
36
|
-
|
|
40
|
+
const config = findConfigFile(root);
|
|
41
|
+
if (key(file).startsWith(srcKey) || (config && key(file) === key(config))) {
|
|
37
42
|
server.ws.send({ type: "full-reload", path: "*" });
|
|
38
43
|
}
|
|
39
44
|
});
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { execFileSync } from "node:child_process";
|
|
2
|
-
import fs from "node:fs";
|
|
3
2
|
import path from "node:path";
|
|
4
3
|
/**
|
|
5
4
|
* Last commit date (ISO) of every file under src/pages, from one `git log` call.
|
|
@@ -27,11 +26,11 @@ export function gitPageDates(root) {
|
|
|
27
26
|
if (git(["rev-parse", "--is-shallow-repository"]).trim() === "true") {
|
|
28
27
|
return { problem: "this is a shallow git clone, so every page would get the latest commit's date (in GitHub Actions, use actions/checkout with fetch-depth: 0)" };
|
|
29
28
|
}
|
|
30
|
-
|
|
31
|
-
//
|
|
32
|
-
|
|
29
|
+
// --relative: names relative to the project folder, with "/" on every system. Comparing
|
|
30
|
+
// absolute paths breaks on Windows (8.3 short names, drive-letter case) and needs
|
|
31
|
+
// realpath on macOS (/var -> /private/var).
|
|
33
32
|
// -z: NUL-separated, so file names with quotes, spaces or newlines come through exactly.
|
|
34
|
-
const out = git(["log", "-z", "--format=@@%cI", "--name-only", "--no-renames", "--",
|
|
33
|
+
const out = git(["log", "-z", "--format=@@%cI", "--name-only", "--no-renames", "--relative", "--", "src/pages"]);
|
|
35
34
|
const dates = new Map();
|
|
36
35
|
let current = "";
|
|
37
36
|
for (const raw of out.split("\0")) {
|
|
@@ -43,7 +42,7 @@ export function gitPageDates(root) {
|
|
|
43
42
|
if (header)
|
|
44
43
|
current = header[1];
|
|
45
44
|
if (name && current) {
|
|
46
|
-
const rel = path.
|
|
45
|
+
const rel = path.join(...name.split("/"));
|
|
47
46
|
if (!dates.has(rel))
|
|
48
47
|
dates.set(rel, current); // newest first: keep the first date seen
|
|
49
48
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vagejs",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.5",
|
|
4
4
|
"description": "A free static site generator for AI website development: Markdown pages with built-in SEO, llms.txt, checks, spam protection and safe deploys.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"static-site-generator",
|
|
@@ -144,7 +144,9 @@ Always ask the site owner before publishing or deploying. Show them the plan fir
|
|
|
144
144
|
|
|
145
145
|
After deploying, `npx vage indexnow --changed-since HEAD~1` (needs `integrations.indexNow.key`) tells IndexNow search engines about changed pages. It's a hint, not a guarantee of indexing; ask the owner first.
|
|
146
146
|
|
|
147
|
-
GitHub Pages needs a custom domain or a `<user>.github.io` repository, because vagejs does not support base paths yet.
|
|
147
|
+
GitHub Pages needs a custom domain or a `<user>.github.io` repository, because vagejs does not support base paths yet; `vage deploy` stops before pushing when the site would land in a subfolder.
|
|
148
|
+
|
|
149
|
+
Other static hosts (Vercel, Netlify and the like) work without a vagejs deploy command: build command `npm run build`, output folder `dist`, no framework preset. Config redirects become small forwarding pages there, and the `_headers` security headers apply only on Cloudflare.
|
|
148
150
|
`.github/workflows/ci.yml` runs check, build and audit on every push and PR, and uploads `dist/` as a downloadable preview artifact.
|
|
149
151
|
|
|
150
152
|
## Analytics and search reports
|
|
@@ -10,8 +10,8 @@ export default defineConfig({
|
|
|
10
10
|
seo: {
|
|
11
11
|
robots: {
|
|
12
12
|
// AI crawler policy is your decision; unset means the "*" rules apply.
|
|
13
|
-
// aiTraining: "disallow", // GPTBot, ClaudeBot, Google-Extended
|
|
14
|
-
// aiSearch: "allow", // OAI-SearchBot, Claude-SearchBot
|
|
13
|
+
// aiTraining: "disallow", // GPTBot, ClaudeBot, Google-Extended, Applebot-Extended
|
|
14
|
+
// aiSearch: "allow", // OAI-SearchBot, Claude-SearchBot, PerplexityBot
|
|
15
15
|
},
|
|
16
16
|
sitemap: true,
|
|
17
17
|
llmsTxt: { full: false },
|