getfilepress 0.1.5 → 0.1.7
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/package.json +106 -101
- package/packages/app/package.json +31 -31
- package/packages/app/src/lib/prerender-empty-ok.ts +15 -0
- package/packages/app/vite.config.ts +5 -4
- package/packages/core/src/lib/headers.ts +113 -0
- package/packages/core/src/lib/server.ts +2 -1
- package/scripts/create-site.mjs +1 -1
- package/scripts/filepress.mjs +12 -4
- package/packages/app/README.md +0 -19
- package/packages/core/README.md +0 -29
package/package.json
CHANGED
|
@@ -1,101 +1,106 @@
|
|
|
1
|
-
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "getfilepress",
|
|
3
|
+
"version": "0.1.7",
|
|
4
|
+
"private": false,
|
|
5
|
+
"type": "module",
|
|
6
|
+
"description": "FilePress — file-based Markdown blog engine. Link this package from a content-only site (config + posts), then run `filepress build`.",
|
|
7
|
+
"license": "MIT",
|
|
8
|
+
"homepage": "https://getfilepress.com",
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "git+https://github.com/Catalyst-Forge-LLC/filepress.git"
|
|
12
|
+
},
|
|
13
|
+
"bugs": {
|
|
14
|
+
"url": "https://github.com/Catalyst-Forge-LLC/filepress/issues"
|
|
15
|
+
},
|
|
16
|
+
"bin": {
|
|
17
|
+
"filepress": "./scripts/filepress.mjs",
|
|
18
|
+
"getfilepress": "./scripts/filepress.mjs"
|
|
19
|
+
},
|
|
20
|
+
"exports": {
|
|
21
|
+
".": {
|
|
22
|
+
"types": "./packages/core/src/lib/index.ts",
|
|
23
|
+
"svelte": "./packages/core/src/lib/index.ts",
|
|
24
|
+
"default": "./packages/core/src/lib/index.ts"
|
|
25
|
+
},
|
|
26
|
+
"./server": {
|
|
27
|
+
"types": "./packages/core/src/lib/server.ts",
|
|
28
|
+
"default": "./packages/core/src/lib/server.ts"
|
|
29
|
+
},
|
|
30
|
+
"./theme": {
|
|
31
|
+
"default": "./packages/core/src/lib/theme.ts"
|
|
32
|
+
},
|
|
33
|
+
"./package.json": "./package.json"
|
|
34
|
+
},
|
|
35
|
+
"files": [
|
|
36
|
+
"scripts/filepress.mjs",
|
|
37
|
+
"scripts/copy-path-mounts.mjs",
|
|
38
|
+
"scripts/create-site.mjs",
|
|
39
|
+
"scripts/ensure-lease.mjs",
|
|
40
|
+
"scripts/postinstall.mjs",
|
|
41
|
+
"scripts/link-embedded-packages.mjs",
|
|
42
|
+
"packages/core",
|
|
43
|
+
"packages/app",
|
|
44
|
+
"packages/import",
|
|
45
|
+
"pnpm-workspace.yaml",
|
|
46
|
+
"README.md",
|
|
47
|
+
"LICENSE"
|
|
48
|
+
],
|
|
49
|
+
"scripts": {
|
|
50
|
+
"postinstall": "node scripts/postinstall.mjs",
|
|
51
|
+
"filepress": "node scripts/filepress.mjs",
|
|
52
|
+
"test": "pnpm --filter @filepress/core test && pnpm --filter @filepress/import test && pnpm --filter @filepress/app test && tsx --test scripts/sync-sibling-sites.test.ts",
|
|
53
|
+
"check": "pnpm filepress check --site demo",
|
|
54
|
+
"build": "pnpm filepress build --site demo",
|
|
55
|
+
"build:demo": "pnpm filepress build --site demo",
|
|
56
|
+
"build:www": "pnpm filepress build --site getfilepress",
|
|
57
|
+
"ship": "pnpm build:www && wrangler pages deploy sites/getfilepress/build --project-name getfilepress",
|
|
58
|
+
"deploy:www": "pnpm ship",
|
|
59
|
+
"dev": "node scripts/ensure-lease.mjs demo 5179 && pnpm filepress dev --site demo --host 0.0.0.0",
|
|
60
|
+
"dev:demo": "node scripts/ensure-lease.mjs demo 5179 && pnpm filepress dev --site demo --host 0.0.0.0",
|
|
61
|
+
"dev:www": "node scripts/ensure-lease.mjs getfilepress 5180 && pnpm filepress dev --site getfilepress --host 0.0.0.0",
|
|
62
|
+
"create-site": "node scripts/create-site.mjs",
|
|
63
|
+
"sync-siblings": "tsx scripts/sync-sibling-sites.ts",
|
|
64
|
+
"import": "node scripts/filepress.mjs import",
|
|
65
|
+
"prepublishOnly": "node scripts/publish-gate.mjs",
|
|
66
|
+
"prepack": "node scripts/prepack.mjs",
|
|
67
|
+
"postpack": "node scripts/postpack.mjs",
|
|
68
|
+
"pack:smoke": "node scripts/pack-smoke.mjs"
|
|
69
|
+
},
|
|
70
|
+
"dependencies": {
|
|
71
|
+
"@fontsource-variable/inter": "^5.2.8",
|
|
72
|
+
"@fontsource-variable/newsreader": "^5.2.10",
|
|
73
|
+
"@sveltejs/adapter-static": "^3.0.10",
|
|
74
|
+
"@sveltejs/kit": "^2.63.0",
|
|
75
|
+
"@sveltejs/vite-plugin-svelte": "^7.1.2",
|
|
76
|
+
"@types/turndown": "^5.0.5",
|
|
77
|
+
"fast-xml-parser": "^5.2.5",
|
|
78
|
+
"gray-matter": "^4.0.3",
|
|
79
|
+
"highlight.js": "^11.11.1",
|
|
80
|
+
"linkedom": "^0.18.12",
|
|
81
|
+
"ollanet": "^0.4.0",
|
|
82
|
+
"rehype-autolink-headings": "^7.1.0",
|
|
83
|
+
"rehype-highlight": "^7.0.2",
|
|
84
|
+
"rehype-raw": "^7.0.0",
|
|
85
|
+
"rehype-slug": "^6.0.0",
|
|
86
|
+
"rehype-stringify": "^10.0.1",
|
|
87
|
+
"remark-gfm": "^4.0.1",
|
|
88
|
+
"remark-parse": "^11.0.0",
|
|
89
|
+
"remark-rehype": "^11.1.2",
|
|
90
|
+
"sirv-cli": "^3.0.1",
|
|
91
|
+
"svelte": "^5.56.1",
|
|
92
|
+
"svelte-check": "^4.6.0",
|
|
93
|
+
"tsx": "^4.20.5",
|
|
94
|
+
"turndown": "^7.2.1",
|
|
95
|
+
"typescript": "^6.0.3",
|
|
96
|
+
"unified": "^11.0.5",
|
|
97
|
+
"vite": "^8.0.16"
|
|
98
|
+
},
|
|
99
|
+
"engines": {
|
|
100
|
+
"node": ">=20"
|
|
101
|
+
},
|
|
102
|
+
"packageManager": "pnpm@10.30.1",
|
|
103
|
+
"devDependencies": {
|
|
104
|
+
"wrangler": "^4.120.1"
|
|
105
|
+
}
|
|
106
|
+
}
|
|
@@ -1,31 +1,31 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@filepress/app",
|
|
3
|
-
"private": true,
|
|
4
|
-
"version": "0.1.3",
|
|
5
|
-
"type": "module",
|
|
6
|
-
"description": "The single SvelteKit app for filepress. Sites under sites/* supply config + posts + static; this package owns all routes.",
|
|
7
|
-
"scripts": {
|
|
8
|
-
"dev": "vite dev",
|
|
9
|
-
"build": "vite build",
|
|
10
|
-
"preview": "vite preview",
|
|
11
|
-
"prepare": "svelte-kit sync || echo ''",
|
|
12
|
-
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
|
|
13
|
-
"test": "vitest run --config vitest.config.ts"
|
|
14
|
-
},
|
|
15
|
-
"dependencies": {
|
|
16
|
-
"@filepress/core": "workspace:*",
|
|
17
|
-
"@filepress/import": "workspace:*"
|
|
18
|
-
},
|
|
19
|
-
"devDependencies": {
|
|
20
|
-
"@sveltejs/adapter-static": "^3.0.10",
|
|
21
|
-
"@sveltejs/kit": "^2.63.0",
|
|
22
|
-
"@sveltejs/vite-plugin-svelte": "^7.1.2",
|
|
23
|
-
"@types/node": "^26.1.0",
|
|
24
|
-
"sirv-cli": "^3.0.1",
|
|
25
|
-
"svelte": "^5.56.1",
|
|
26
|
-
"svelte-check": "^4.6.0",
|
|
27
|
-
"typescript": "^6.0.3",
|
|
28
|
-
"vite": "^8.0.16",
|
|
29
|
-
"vitest": "^4.1.9"
|
|
30
|
-
}
|
|
31
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@filepress/app",
|
|
3
|
+
"private": true,
|
|
4
|
+
"version": "0.1.3",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"description": "The single SvelteKit app for filepress. Sites under sites/* supply config + posts + static; this package owns all routes.",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"dev": "vite dev --host",
|
|
9
|
+
"build": "vite build",
|
|
10
|
+
"preview": "vite preview",
|
|
11
|
+
"prepare": "svelte-kit sync || echo ''",
|
|
12
|
+
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
|
|
13
|
+
"test": "vitest run --config vitest.config.ts"
|
|
14
|
+
},
|
|
15
|
+
"dependencies": {
|
|
16
|
+
"@filepress/core": "workspace:*",
|
|
17
|
+
"@filepress/import": "workspace:*"
|
|
18
|
+
},
|
|
19
|
+
"devDependencies": {
|
|
20
|
+
"@sveltejs/adapter-static": "^3.0.10",
|
|
21
|
+
"@sveltejs/kit": "^2.63.0",
|
|
22
|
+
"@sveltejs/vite-plugin-svelte": "^7.1.2",
|
|
23
|
+
"@types/node": "^26.1.0",
|
|
24
|
+
"sirv-cli": "^3.0.1",
|
|
25
|
+
"svelte": "^5.56.1",
|
|
26
|
+
"svelte-check": "^4.6.0",
|
|
27
|
+
"typescript": "^6.0.3",
|
|
28
|
+
"vite": "^8.0.16",
|
|
29
|
+
"vitest": "^4.1.9"
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dynamic routes that may have zero `entries()` and still be a valid site:
|
|
3
|
+
* no extra index pages, no tags, no Markdown pages, or no posts (pages-only).
|
|
4
|
+
*/
|
|
5
|
+
export const prerenderEmptyOk = [
|
|
6
|
+
'/page/[n]',
|
|
7
|
+
'/tags/[tag]',
|
|
8
|
+
'/[slug]',
|
|
9
|
+
'/posts/[slug]'
|
|
10
|
+
] as const;
|
|
11
|
+
|
|
12
|
+
export function unexpectedUnseenPrerenderRoutes(routes: string[]): string[] {
|
|
13
|
+
const ok = new Set<string>(prerenderEmptyOk);
|
|
14
|
+
return routes.filter((route) => !ok.has(route));
|
|
15
|
+
}
|
|
@@ -12,6 +12,7 @@ import { geniePlugin } from './vite-plugin-genie.ts';
|
|
|
12
12
|
import { pathMountsPlugin } from './vite-plugin-path-mounts.ts';
|
|
13
13
|
import { filepressLeaseName, localberthGet } from './localberth-port.ts';
|
|
14
14
|
import type { PathMount } from '../core/src/lib/paths-shared.ts';
|
|
15
|
+
import { unexpectedUnseenPrerenderRoutes } from './src/lib/prerender-empty-ok.ts';
|
|
15
16
|
|
|
16
17
|
const appRoot = dirname(fileURLToPath(import.meta.url));
|
|
17
18
|
const defaultSiteRoot = resolve(appRoot, '../../sites/demo');
|
|
@@ -101,12 +102,13 @@ export default defineConfig(async () => {
|
|
|
101
102
|
`${JSON.stringify(pathMounts, null, '\t')}\n`
|
|
102
103
|
);
|
|
103
104
|
|
|
105
|
+
const host = process.env.HOST?.trim() || '127.0.0.1';
|
|
104
106
|
return {
|
|
105
107
|
server: fixedPort
|
|
106
|
-
? { port: fixedPort, strictPort: true }
|
|
108
|
+
? { host, port: fixedPort, strictPort: true }
|
|
107
109
|
: undefined,
|
|
108
110
|
preview: fixedPort
|
|
109
|
-
? { port: fixedPort, strictPort: true }
|
|
111
|
+
? { host, port: fixedPort, strictPort: true }
|
|
110
112
|
: undefined,
|
|
111
113
|
resolve: {
|
|
112
114
|
alias: [
|
|
@@ -160,8 +162,7 @@ export default defineConfig(async () => {
|
|
|
160
162
|
throw new Error(message);
|
|
161
163
|
},
|
|
162
164
|
handleUnseenRoutes: ({ routes }) => {
|
|
163
|
-
const
|
|
164
|
-
const unexpected = routes.filter((r) => !emptyOk.has(r));
|
|
165
|
+
const unexpected = unexpectedUnseenPrerenderRoutes(routes);
|
|
165
166
|
if (unexpected.length > 0) {
|
|
166
167
|
throw new Error(
|
|
167
168
|
`Routes marked prerenderable but not prerendered: ${unexpected.join(', ')}`
|
|
@@ -19,3 +19,116 @@ export function writeBuildHeaders(buildDir: string): 'wrote' | 'kept' {
|
|
|
19
19
|
writeFileSync(dest, defaultSecurityHeaders());
|
|
20
20
|
return 'wrote';
|
|
21
21
|
}
|
|
22
|
+
|
|
23
|
+
export type MergeSecurityHeadersResult = {
|
|
24
|
+
text: string;
|
|
25
|
+
changed: boolean;
|
|
26
|
+
added: string[];
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
type HeaderBlock = { path: string; lines: string[] };
|
|
30
|
+
|
|
31
|
+
/** Header name from a `_headers` line (`Name: value` or `! Name`). */
|
|
32
|
+
export function headerNameFromLine(line: string): string | null {
|
|
33
|
+
const t = line.trim();
|
|
34
|
+
if (!t || t.startsWith('#')) return null;
|
|
35
|
+
if (t.startsWith('! ')) return t.slice(2).trim().toLowerCase();
|
|
36
|
+
const colon = t.indexOf(':');
|
|
37
|
+
if (colon === -1) return null;
|
|
38
|
+
return t.slice(0, colon).trim().toLowerCase();
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function isPathLine(line: string): boolean {
|
|
42
|
+
if (line.startsWith(' ') || line.startsWith('\t')) return false;
|
|
43
|
+
const t = line.trim();
|
|
44
|
+
return t.startsWith('/') || t.startsWith('http://') || t.startsWith('https://');
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function parseHeadersFile(text: string): { preamble: string[]; blocks: HeaderBlock[] } {
|
|
48
|
+
const lines = text.replace(/\r\n/g, '\n').replace(/\r/g, '\n').split('\n');
|
|
49
|
+
const preamble: string[] = [];
|
|
50
|
+
const blocks: HeaderBlock[] = [];
|
|
51
|
+
let current: HeaderBlock | null = null;
|
|
52
|
+
let beforeFirst = true;
|
|
53
|
+
|
|
54
|
+
for (const line of lines) {
|
|
55
|
+
if (isPathLine(line)) {
|
|
56
|
+
current = { path: line.trim(), lines: [] };
|
|
57
|
+
blocks.push(current);
|
|
58
|
+
beforeFirst = false;
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
if (beforeFirst) preamble.push(line);
|
|
62
|
+
else if (current) current.lines.push(line);
|
|
63
|
+
}
|
|
64
|
+
return { preamble, blocks };
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function serializeHeadersFile(preamble: string[], blocks: HeaderBlock[]): string {
|
|
68
|
+
const out: string[] = [...preamble];
|
|
69
|
+
for (const block of blocks) {
|
|
70
|
+
out.push(block.path);
|
|
71
|
+
out.push(...block.lines);
|
|
72
|
+
}
|
|
73
|
+
let text = out.join('\n');
|
|
74
|
+
if (!text.endsWith('\n')) text += '\n';
|
|
75
|
+
return text;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function starHeaderLines(defaults: string): string[] {
|
|
79
|
+
const { blocks } = parseHeadersFile(defaults);
|
|
80
|
+
const star = blocks.find((b) => b.path === '/*');
|
|
81
|
+
if (!star) {
|
|
82
|
+
throw new Error('default _headers template has no /* block');
|
|
83
|
+
}
|
|
84
|
+
return star.lines.filter((line) => headerNameFromLine(line));
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function blockIndent(lines: string[]): string {
|
|
88
|
+
for (const line of lines) {
|
|
89
|
+
if (headerNameFromLine(line)) {
|
|
90
|
+
const match = /^(?<indent>[ \t]+)/.exec(line);
|
|
91
|
+
if (match?.groups?.indent) return match.groups.indent;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return ' ';
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Fold FilePress default `/*` security rules into a site-owned `_headers`
|
|
99
|
+
* without dropping other path blocks. Existing values for the same header
|
|
100
|
+
* name win (including an explicit `Access-Control-Allow-Origin`).
|
|
101
|
+
*/
|
|
102
|
+
export function mergeSecurityHeaders(
|
|
103
|
+
existing: string,
|
|
104
|
+
defaults: string = defaultSecurityHeaders()
|
|
105
|
+
): MergeSecurityHeadersResult {
|
|
106
|
+
const wanted = starHeaderLines(defaults);
|
|
107
|
+
const parsed = parseHeadersFile(existing);
|
|
108
|
+
const added: string[] = [];
|
|
109
|
+
let star = parsed.blocks.find((b) => b.path === '/*');
|
|
110
|
+
if (!star) {
|
|
111
|
+
star = { path: '/*', lines: [''] };
|
|
112
|
+
parsed.blocks.push(star);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const present = new Set(
|
|
116
|
+
star.lines.map((line) => headerNameFromLine(line)).filter((n): n is string => Boolean(n))
|
|
117
|
+
);
|
|
118
|
+
const indent = blockIndent(star.lines);
|
|
119
|
+
|
|
120
|
+
let insertAt = star.lines.length;
|
|
121
|
+
while (insertAt > 0 && star.lines[insertAt - 1].trim() === '') insertAt--;
|
|
122
|
+
|
|
123
|
+
for (const line of wanted) {
|
|
124
|
+
const name = headerNameFromLine(line);
|
|
125
|
+
if (!name || present.has(name)) continue;
|
|
126
|
+
star.lines.splice(insertAt, 0, `${indent}${line.trim()}`);
|
|
127
|
+
insertAt++;
|
|
128
|
+
present.add(name);
|
|
129
|
+
added.push(name);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const text = serializeHeadersFile(parsed.preamble, parsed.blocks);
|
|
133
|
+
return { text, changed: added.length > 0, added };
|
|
134
|
+
}
|
|
@@ -22,7 +22,8 @@ export {
|
|
|
22
22
|
|
|
23
23
|
export { absoluteUrl, ogImageUrl } from './config';
|
|
24
24
|
export type { SiteConfig, PathMount } from './config';
|
|
25
|
-
export { defaultSecurityHeaders, writeBuildHeaders } from './headers';
|
|
25
|
+
export { defaultSecurityHeaders, writeBuildHeaders, mergeSecurityHeaders } from './headers';
|
|
26
|
+
export type { MergeSecurityHeadersResult } from './headers';
|
|
26
27
|
export {
|
|
27
28
|
normalizePathMounts,
|
|
28
29
|
pathMountReservedSlugs,
|
package/scripts/create-site.mjs
CHANGED
package/scripts/filepress.mjs
CHANGED
|
@@ -59,7 +59,12 @@ function parseArgs(argv) {
|
|
|
59
59
|
} else if (a.startsWith('--port=')) {
|
|
60
60
|
args.port = a.slice('--port='.length);
|
|
61
61
|
} else if (a === '--host') {
|
|
62
|
-
|
|
62
|
+
const next = argv[i + 1];
|
|
63
|
+
if (next && !next.startsWith('-')) {
|
|
64
|
+
args.host = argv[++i];
|
|
65
|
+
} else {
|
|
66
|
+
args.host = '0.0.0.0';
|
|
67
|
+
}
|
|
63
68
|
} else if (a.startsWith('--host=')) {
|
|
64
69
|
args.host = a.slice('--host='.length);
|
|
65
70
|
} else if (a === '--') {
|
|
@@ -183,7 +188,7 @@ function runSiteCommand(argv) {
|
|
|
183
188
|
` filepress <${[...COMMANDS].join('|')}> # cwd is the site\n` +
|
|
184
189
|
` filepress <${[...COMMANDS].join('|')}> --root <path>\n` +
|
|
185
190
|
` filepress preview [--port 27777] # serves <site>/build (default 27777)\n` +
|
|
186
|
-
` filepress dev --port <n>
|
|
191
|
+
` filepress dev --port <n> [--host] # vite dev; optional fixed port / LAN\n` +
|
|
187
192
|
` filepress import --source <url> [--inspire <url>] …\n` +
|
|
188
193
|
`monorepo sites: ${listSites().join(', ') || '(none)'}`
|
|
189
194
|
);
|
|
@@ -218,6 +223,9 @@ function runSiteCommand(argv) {
|
|
|
218
223
|
...process.env,
|
|
219
224
|
FILEPRESS_SITE_ROOT: siteRoot
|
|
220
225
|
};
|
|
226
|
+
if (args.host !== null) {
|
|
227
|
+
env.HOST = args.host === 'true' ? '0.0.0.0' : args.host;
|
|
228
|
+
}
|
|
221
229
|
|
|
222
230
|
// Preview must serve the site's own build/ — not packages/app/.svelte-kit
|
|
223
231
|
// (shared across sites; another agent's last build can leak onto vite preview).
|
|
@@ -240,7 +248,7 @@ function runSiteCommand(argv) {
|
|
|
240
248
|
'--port',
|
|
241
249
|
String(port),
|
|
242
250
|
'--host',
|
|
243
|
-
args.host && args.host !== 'true' ? args.host : '127.0.0.1'
|
|
251
|
+
args.host && args.host !== 'true' ? args.host : args.host === 'true' ? '0.0.0.0' : '127.0.0.1'
|
|
244
252
|
],
|
|
245
253
|
{ cwd: appDir, env }
|
|
246
254
|
);
|
|
@@ -279,7 +287,7 @@ function runSiteCommand(argv) {
|
|
|
279
287
|
|
|
280
288
|
// dev | build → vite
|
|
281
289
|
const viteArgs = [command];
|
|
282
|
-
if (args.host !== null) viteArgs.push('--host', args.host === 'true' ? '
|
|
290
|
+
if (args.host !== null) viteArgs.push('--host', args.host === 'true' ? '0.0.0.0' : args.host);
|
|
283
291
|
viteArgs.push(...args.extra);
|
|
284
292
|
runNodeBin('vite', 'vite', viteArgs, {
|
|
285
293
|
cwd: appDir,
|
package/packages/app/README.md
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
# @filepress/app
|
|
2
|
-
|
|
3
|
-
The only SvelteKit application in the filepress monorepo. All routes, layouts, and
|
|
4
|
-
Kit wiring live here. Content sites under [`../../sites`](../../sites) provide:
|
|
5
|
-
|
|
6
|
-
- `filepress.config.ts` — identity
|
|
7
|
-
- `posts/` — Markdown
|
|
8
|
-
- `static/` — favicon, images (optional)
|
|
9
|
-
|
|
10
|
-
## Run against a site
|
|
11
|
-
|
|
12
|
-
From the repo root (do not run vite directly without `FILEPRESS_SITE_ROOT`):
|
|
13
|
-
|
|
14
|
-
```bash
|
|
15
|
-
pnpm filepress dev --site demo
|
|
16
|
-
pnpm filepress build --site demo
|
|
17
|
-
```
|
|
18
|
-
|
|
19
|
-
Build output is written to `sites/<name>/build/`.
|
package/packages/core/README.md
DELETED
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
# @filepress/core
|
|
2
|
-
|
|
3
|
-
The reusable filepress engine. Sites under [`../../sites`](../../sites) depend on
|
|
4
|
-
it (via `workspace:*` in this monorepo) and provide their own SvelteKit routes,
|
|
5
|
-
content, and `filepress.config.ts`.
|
|
6
|
-
|
|
7
|
-
## Entry points
|
|
8
|
-
|
|
9
|
-
- `@filepress/core` — client-safe: `PostCard`, `PostIndex`, `Newsletter`,
|
|
10
|
-
`SiteHeader`, `SiteFooter`, `defineFilepressConfig`, `absoluteUrl`,
|
|
11
|
-
`formatDate`, and shared types.
|
|
12
|
-
- `@filepress/core/server` — server-only (filesystem access): `createContent`,
|
|
13
|
-
`renderMarkdown`, `buildRssXml` / `buildSitemapXml` / `buildRobotsTxt`, and the
|
|
14
|
-
content-parsing primitives. Import only from `+page.server.ts`, `+server.ts`,
|
|
15
|
-
or `*.server.ts` modules.
|
|
16
|
-
- `@filepress/core/theme` — self-hosted fonts + the Essay theme CSS. Import once
|
|
17
|
-
from a site's root layout.
|
|
18
|
-
|
|
19
|
-
## Why routes live in the site
|
|
20
|
-
|
|
21
|
-
SvelteKit's router is per-project, so each site owns its `src/routes/`. Those
|
|
22
|
-
route files stay thin: they call `createContent(...)` + core builders and render
|
|
23
|
-
core components. `scripts/create-site.mjs` scaffolds them.
|
|
24
|
-
|
|
25
|
-
## Testing
|
|
26
|
-
|
|
27
|
-
`pnpm --filter @filepress/core test` runs the unit tests over the pure parsing
|
|
28
|
-
and figure-transform logic. Type-checking of the whole library happens through
|
|
29
|
-
each site's `svelte-check`.
|