getfilepress 0.1.4 → 0.1.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/README.md +3 -1
- package/package.json +5 -4
- package/packages/app/localberth-port.ts +32 -0
- package/packages/app/vite.config.ts +6 -3
- package/packages/core/src/lib/default-headers.txt +10 -0
- package/packages/core/src/lib/headers.ts +21 -0
- package/packages/core/src/lib/server.ts +1 -0
- package/scripts/copy-path-mounts.mjs +22 -7
- package/scripts/ensure-lease.mjs +24 -0
package/README.md
CHANGED
|
@@ -73,6 +73,8 @@ pnpm build:www # → sites/getfilepress/build/
|
|
|
73
73
|
pnpm ship # build + Wrangler Pages deploy (project: getfilepress)
|
|
74
74
|
```
|
|
75
75
|
|
|
76
|
+
Two `filepress dev` processes share Vite **5173** unless you pin the port. With [LocalBerth](https://www.npmjs.com/package/localberth) 0.2+, `filepress dev` reads a named lease. Claim once; see [docs/LOCALBERTH.md](docs/LOCALBERTH.md).
|
|
77
|
+
|
|
76
78
|
## Site configuration
|
|
77
79
|
|
|
78
80
|
```ts
|
|
@@ -194,7 +196,7 @@ Body content in **Markdown**.
|
|
|
194
196
|
|
|
195
197
|
Pin the engine in the site `package.json` (`"getfilepress": "^0.1.3"` or `github:Catalyst-Forge-LLC/filepress#v0.1.3`). Do not use `link:` in CI. Set config `url` to the live origin.
|
|
196
198
|
|
|
197
|
-
Any other static host works the same way: publish `build/` as the web root.
|
|
199
|
+
Any other static host works the same way: publish `build/` as the web root. The build also writes a `_headers` file (HSTS, no framing, no wildcard CORS) for Cloudflare Pages; override it with `static/_headers`.
|
|
198
200
|
|
|
199
201
|
Full notes (including an agent checklist): [`docs/DEPLOY.md`](docs/DEPLOY.md) · product page: [getfilepress.com/deploy](https://getfilepress.com/deploy).
|
|
200
202
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "getfilepress",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.5",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"description": "FilePress — file-based Markdown blog engine. Link this package from a content-only site (config + posts), then run `filepress build`.",
|
|
@@ -36,6 +36,7 @@
|
|
|
36
36
|
"scripts/filepress.mjs",
|
|
37
37
|
"scripts/copy-path-mounts.mjs",
|
|
38
38
|
"scripts/create-site.mjs",
|
|
39
|
+
"scripts/ensure-lease.mjs",
|
|
39
40
|
"scripts/postinstall.mjs",
|
|
40
41
|
"scripts/link-embedded-packages.mjs",
|
|
41
42
|
"packages/core",
|
|
@@ -90,9 +91,9 @@
|
|
|
90
91
|
"build:www": "pnpm filepress build --site getfilepress",
|
|
91
92
|
"ship": "pnpm build:www && wrangler pages deploy sites/getfilepress/build --project-name getfilepress",
|
|
92
93
|
"deploy:www": "pnpm ship",
|
|
93
|
-
"dev": "pnpm filepress dev --site demo",
|
|
94
|
-
"dev:demo": "pnpm filepress dev --site demo",
|
|
95
|
-
"dev:www": "pnpm filepress dev --site getfilepress",
|
|
94
|
+
"dev": "node scripts/ensure-lease.mjs demo 5179 && pnpm filepress dev --site demo",
|
|
95
|
+
"dev:demo": "node scripts/ensure-lease.mjs demo 5179 && pnpm filepress dev --site demo",
|
|
96
|
+
"dev:www": "node scripts/ensure-lease.mjs getfilepress 5180 && pnpm filepress dev --site getfilepress",
|
|
96
97
|
"create-site": "node scripts/create-site.mjs",
|
|
97
98
|
"import": "node scripts/filepress.mjs import",
|
|
98
99
|
"pack:smoke": "node scripts/pack-smoke.mjs"
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
2
|
+
import { spawnSync } from 'node:child_process';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
|
|
5
|
+
/** `localberth get <name>` — undefined if the CLI or lease is missing. */
|
|
6
|
+
export function localberthGet(name: string): number | undefined {
|
|
7
|
+
const r = spawnSync('localberth', ['get', name], {
|
|
8
|
+
encoding: 'utf8',
|
|
9
|
+
timeout: 5000,
|
|
10
|
+
windowsHide: true,
|
|
11
|
+
shell: process.platform === 'win32'
|
|
12
|
+
});
|
|
13
|
+
if (r.status !== 0) return undefined;
|
|
14
|
+
const n = Number((r.stdout || '').trim());
|
|
15
|
+
return Number.isInteger(n) && n > 0 && n <= 65535 ? n : undefined;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/** FILEPRESS_LEASE, then site package.json name, then the site folder name. */
|
|
19
|
+
export function filepressLeaseName(siteRoot: string): string {
|
|
20
|
+
const fromEnv = process.env.FILEPRESS_LEASE?.trim();
|
|
21
|
+
if (fromEnv) return fromEnv;
|
|
22
|
+
const pkgPath = join(siteRoot, 'package.json');
|
|
23
|
+
if (existsSync(pkgPath)) {
|
|
24
|
+
try {
|
|
25
|
+
const name = JSON.parse(readFileSync(pkgPath, 'utf8')).name;
|
|
26
|
+
if (typeof name === 'string' && name.trim()) return name.trim();
|
|
27
|
+
} catch {
|
|
28
|
+
/* fall through */
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return siteRoot.replace(/[/\\]+$/, '').split(/[/\\]/).pop() || 'filepress';
|
|
32
|
+
}
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
} from './vite-plugin-critical-theme.ts';
|
|
11
11
|
import { geniePlugin } from './vite-plugin-genie.ts';
|
|
12
12
|
import { pathMountsPlugin } from './vite-plugin-path-mounts.ts';
|
|
13
|
+
import { filepressLeaseName, localberthGet } from './localberth-port.ts';
|
|
13
14
|
import type { PathMount } from '../core/src/lib/paths-shared.ts';
|
|
14
15
|
|
|
15
16
|
const appRoot = dirname(fileURLToPath(import.meta.url));
|
|
@@ -84,9 +85,11 @@ async function loadPathMounts(): Promise<PathMount[]> {
|
|
|
84
85
|
|
|
85
86
|
function resolvePort(): number | undefined {
|
|
86
87
|
const raw = process.env.FILEPRESS_PORT?.trim();
|
|
87
|
-
if (
|
|
88
|
-
|
|
89
|
-
|
|
88
|
+
if (raw) {
|
|
89
|
+
const n = Number(raw);
|
|
90
|
+
return Number.isInteger(n) && n > 0 && n <= 65535 ? n : undefined;
|
|
91
|
+
}
|
|
92
|
+
return localberthGet(filepressLeaseName(siteRoot));
|
|
90
93
|
}
|
|
91
94
|
|
|
92
95
|
const fixedPort = resolvePort();
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# Emitted by FilePress. Override by adding static/_headers in the site.
|
|
2
|
+
# Cloudflare Pages and Netlify read this file; it is not served as a page.
|
|
3
|
+
|
|
4
|
+
/*
|
|
5
|
+
Strict-Transport-Security: max-age=31536000
|
|
6
|
+
Content-Security-Policy: frame-ancestors 'none'
|
|
7
|
+
X-Frame-Options: DENY
|
|
8
|
+
X-Content-Type-Options: nosniff
|
|
9
|
+
Referrer-Policy: strict-origin-when-cross-origin
|
|
10
|
+
! Access-Control-Allow-Origin
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Default Cloudflare Pages / Netlify `_headers` for a FilePress build.
|
|
3
|
+
* A site-owned `static/_headers` wins: adapter-static copies it first, and
|
|
4
|
+
* we refuse to overwrite `build/_headers`.
|
|
5
|
+
*/
|
|
6
|
+
import { existsSync, readFileSync, writeFileSync } from 'node:fs';
|
|
7
|
+
import { dirname, join } from 'node:path';
|
|
8
|
+
import { fileURLToPath } from 'node:url';
|
|
9
|
+
|
|
10
|
+
const templatePath = join(dirname(fileURLToPath(import.meta.url)), 'default-headers.txt');
|
|
11
|
+
|
|
12
|
+
export function defaultSecurityHeaders(): string {
|
|
13
|
+
return readFileSync(templatePath, 'utf8');
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function writeBuildHeaders(buildDir: string): 'wrote' | 'kept' {
|
|
17
|
+
const dest = join(buildDir, '_headers');
|
|
18
|
+
if (existsSync(dest)) return 'kept';
|
|
19
|
+
writeFileSync(dest, defaultSecurityHeaders());
|
|
20
|
+
return 'wrote';
|
|
21
|
+
}
|
|
@@ -1,21 +1,36 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
2
|
+
* Post-`vite build` steps for a FilePress site:
|
|
3
|
+
* 1. Write default `build/_headers` unless the site already provided one
|
|
4
|
+
* 2. Copy `paths` mounts (from `.filepress/path-mounts.json`)
|
|
4
5
|
*
|
|
5
6
|
* Usage: node scripts/copy-path-mounts.mjs <siteRoot>
|
|
6
7
|
*/
|
|
7
|
-
import { cpSync, existsSync, mkdirSync, readFileSync, statSync } from 'node:fs';
|
|
8
|
-
import { join, resolve } from 'node:path';
|
|
8
|
+
import { cpSync, existsSync, mkdirSync, readFileSync, statSync, writeFileSync } from 'node:fs';
|
|
9
|
+
import { dirname, join, resolve } from 'node:path';
|
|
10
|
+
import { fileURLToPath } from 'node:url';
|
|
9
11
|
|
|
10
12
|
const siteRoot = resolve(process.argv[2] ?? '');
|
|
11
13
|
const buildDir = join(siteRoot, 'build');
|
|
12
14
|
const cachePath = join(siteRoot, '.filepress', 'path-mounts.json');
|
|
15
|
+
const headersTemplate = join(
|
|
16
|
+
dirname(fileURLToPath(import.meta.url)),
|
|
17
|
+
'../packages/core/src/lib/default-headers.txt'
|
|
18
|
+
);
|
|
13
19
|
|
|
14
|
-
if (!existsSync(
|
|
20
|
+
if (!existsSync(buildDir)) {
|
|
21
|
+
console.warn(`filepress: post-build skipped — build dir missing (${buildDir})`);
|
|
15
22
|
process.exit(0);
|
|
16
23
|
}
|
|
17
|
-
|
|
18
|
-
|
|
24
|
+
|
|
25
|
+
const headersDest = join(buildDir, '_headers');
|
|
26
|
+
if (existsSync(headersDest)) {
|
|
27
|
+
console.log('filepress: kept site _headers');
|
|
28
|
+
} else if (existsSync(headersTemplate)) {
|
|
29
|
+
writeFileSync(headersDest, readFileSync(headersTemplate, 'utf8'));
|
|
30
|
+
console.log('filepress: wrote default _headers');
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (!existsSync(cachePath)) {
|
|
19
34
|
process.exit(0);
|
|
20
35
|
}
|
|
21
36
|
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Idempotent LocalBerth claim for FilePress (and sibling) dev ports.
|
|
4
|
+
* Usage: node scripts/ensure-lease.mjs <name> <port>
|
|
5
|
+
* Missing CLI → one line, exit 0. Existing lease → keep it (do not rewrite).
|
|
6
|
+
*/
|
|
7
|
+
import { spawnSync } from 'node:child_process';
|
|
8
|
+
|
|
9
|
+
const name = process.argv[2];
|
|
10
|
+
const port = process.argv[3];
|
|
11
|
+
if (!name || !port) {
|
|
12
|
+
console.error('usage: node scripts/ensure-lease.mjs <name> <port>');
|
|
13
|
+
process.exit(1);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const opt = { encoding: 'utf8', timeout: 8000, windowsHide: true, shell: process.platform === 'win32' };
|
|
17
|
+
const got = spawnSync('localberth', ['get', name], { ...opt, stdio: ['ignore', 'pipe', 'ignore'] });
|
|
18
|
+
if (got.status === 0 && String(got.stdout || '').trim()) {
|
|
19
|
+
process.exit(0);
|
|
20
|
+
}
|
|
21
|
+
const claim = spawnSync('localberth', ['claim', name, '--port', port], { ...opt, stdio: 'inherit' });
|
|
22
|
+
if (claim.error || claim.status !== 0) {
|
|
23
|
+
console.warn(`localberth: skip claim ${name} (install the CLI to pin this site to ${port})`);
|
|
24
|
+
}
|