diff --git a/app/src/app.html b/app/src/app.html
index a89d42f..5f95b7d 100644
--- a/app/src/app.html
+++ b/app/src/app.html
@@ -10,6 +10,13 @@
+
diff --git a/app/src/routes/[...slug]/+page.svelte b/app/src/routes/[...slug]/+page.svelte
index fdd6bec..adcbb26 100644
--- a/app/src/routes/[...slug]/+page.svelte
+++ b/app/src/routes/[...slug]/+page.svelte
@@ -112,7 +112,7 @@
{/each}
-
+ {@html ``}
{/if}
diff --git a/app/svelte.config.js b/app/svelte.config.js
index ac0fb60..73c3a3b 100644
--- a/app/svelte.config.js
+++ b/app/svelte.config.js
@@ -18,6 +18,29 @@ const config = {
}),
alias: {
$lib: 'src/lib'
+ },
+ prerender: {
+ // Der Crawler folgt zur Build-Zeit href/src-attributen im HTML. Zwei
+ // faelle, in denen 404er kein echter fehler sind:
+ //
+ // 1. canonical/hreflang enthalten den `__SITE_URL__`-platzhalter, der
+ // erst beim deploy per sed durch die echte SITE_URL ersetzt wird.
+ // Pfade wie `//__SITE_URL__/` sind also pseudo-pfade.
+ // 2. Bild-references mit relativen pfaden (z.B. `h01-json-import.png`)
+ // in alten posts, die nicht zu Blossom-URLs migriert wurden — die
+ // sind im post-body als
und vom crawler verfolgte
+ // pseudo-routes. Die SPA selbst rendert die
-tags zwar, aber
+ // eine 404-route gibt es dafuer nicht.
+ handleHttpError: ({ path, message }) => {
+ if (path.includes('__SITE_URL__')) return;
+ if (/\.(png|jpe?g|gif|webp|svg|avif)\/?$/i.test(path)) return;
+ throw new Error(message);
+ },
+ // Markdown-headings bekommen ohne slugify-plugin keine id-attribute.
+ // Anchor-links in alten posts (z.B. [link](#ACF-JSON-Export)) sind
+ // damit zur build-zeit unauffindbar. Kein render-fehler — die SPA
+ // scrollt im browser entweder zum element oder garnicht.
+ handleMissingId: 'ignore'
}
}
};
diff --git a/snapshot/deno.lock b/snapshot/deno.lock
new file mode 100644
index 0000000..385c36a
--- /dev/null
+++ b/snapshot/deno.lock
@@ -0,0 +1,172 @@
+{
+ "version": "5",
+ "specifiers": {
+ "jsr:@std/assert@^1.0.6": "1.0.19",
+ "jsr:@std/cli@^1.0.6": "1.0.28",
+ "jsr:@std/fs@^1.0.4": "1.0.23",
+ "jsr:@std/internal@^1.0.12": "1.0.12",
+ "jsr:@std/path@^1.0.6": "1.1.4",
+ "jsr:@std/path@^1.1.4": "1.1.4",
+ "npm:applesauce-relay@2": "2.3.0",
+ "npm:nostr-tools@^2.10.4": "2.23.3",
+ "npm:rxjs@^7.8.1": "7.8.2"
+ },
+ "jsr": {
+ "@std/assert@1.0.19": {
+ "integrity": "eaada96ee120cb980bc47e040f82814d786fe8162ecc53c91d8df60b8755991e",
+ "dependencies": [
+ "jsr:@std/internal"
+ ]
+ },
+ "@std/cli@1.0.28": {
+ "integrity": "74ef9b976db59ca6b23a5283469c9072be6276853807a83ec6c7ce412135c70a",
+ "dependencies": [
+ "jsr:@std/internal"
+ ]
+ },
+ "@std/fs@1.0.23": {
+ "integrity": "3ecbae4ce4fee03b180fa710caff36bb5adb66631c46a6460aaad49515565a37",
+ "dependencies": [
+ "jsr:@std/internal",
+ "jsr:@std/path@^1.1.4"
+ ]
+ },
+ "@std/internal@1.0.12": {
+ "integrity": "972a634fd5bc34b242024402972cd5143eac68d8dffaca5eaa4dba30ce17b027"
+ },
+ "@std/path@1.1.4": {
+ "integrity": "1d2d43f39efb1b42f0b1882a25486647cb851481862dc7313390b2bb044314b5",
+ "dependencies": [
+ "jsr:@std/internal"
+ ]
+ }
+ },
+ "npm": {
+ "@noble/ciphers@2.1.1": {
+ "integrity": "sha512-bysYuiVfhxNJuldNXlFEitTVdNnYUc+XNJZd7Qm2a5j1vZHgY+fazadNFWFaMK/2vye0JVlxV3gHmC0WDfAOQw=="
+ },
+ "@noble/curves@2.0.1": {
+ "integrity": "sha512-vs1Az2OOTBiP4q0pwjW5aF0xp9n4MxVrmkFBxc6EKZc6ddYx5gaZiAsZoq0uRRXWbi3AT/sBqn05eRPtn1JCPw==",
+ "dependencies": [
+ "@noble/hashes@2.0.1"
+ ]
+ },
+ "@noble/hashes@1.8.0": {
+ "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A=="
+ },
+ "@noble/hashes@2.0.1": {
+ "integrity": "sha512-XlOlEbQcE9fmuXxrVTXCTlG2nlRXa9Rj3rr5Ue/+tX+nmkgbX720YHh0VR3hBF9xDvwnb8D2shVGOwNx+ulArw=="
+ },
+ "@scure/base@1.1.1": {
+ "integrity": "sha512-ZxOhsSyxYwLJj3pLZCefNitxsj093tb2vq90mp2txoYeBqbcjDjqFhyM8eUjq/uFm6zJ+mUuqxlS2FkuSY1MTA=="
+ },
+ "@scure/base@1.2.6": {
+ "integrity": "sha512-g/nm5FgUa//MCj1gV09zTJTaM6KBAHqLN907YVQqf7zC49+DcO4B1so4ZX07Ef10Twr6nuqYEH9GEggFXA4Fmg=="
+ },
+ "@scure/base@2.0.0": {
+ "integrity": "sha512-3E1kpuZginKkek01ovG8krQ0Z44E3DHPjc5S2rjJw9lZn3KSQOs8S7wqikF/AH7iRanHypj85uGyxk0XAyC37w=="
+ },
+ "@scure/bip32@2.0.1": {
+ "integrity": "sha512-4Md1NI5BzoVP+bhyJaY3K6yMesEFzNS1sE/cP+9nuvE7p/b0kx9XbpDHHFl8dHtufcbdHRUUQdRqLIPHN/s7yA==",
+ "dependencies": [
+ "@noble/curves",
+ "@noble/hashes@2.0.1",
+ "@scure/base@2.0.0"
+ ]
+ },
+ "@scure/bip39@2.0.1": {
+ "integrity": "sha512-PsxdFj/d2AcJcZDX1FXN3dDgitDDTmwf78rKZq1a6c1P1Nan1X/Sxc7667zU3U+AN60g7SxxP0YCVw2H/hBycg==",
+ "dependencies": [
+ "@noble/hashes@2.0.1",
+ "@scure/base@2.0.0"
+ ]
+ },
+ "applesauce-core@2.3.0": {
+ "integrity": "sha512-rMVrwGMgHxXAHZfrq3ibtMjljAxeEfT95nl5VYLl5mSMmOHXnwjbiPTccJ2UDd6GP+INdHfkPgeB8AOUf5DFog==",
+ "dependencies": [
+ "@noble/hashes@1.8.0",
+ "@scure/base@1.2.6",
+ "debug",
+ "fast-deep-equal",
+ "hash-sum",
+ "light-bolt11-decoder",
+ "nanoid",
+ "nostr-tools",
+ "rxjs"
+ ]
+ },
+ "applesauce-relay@2.3.0": {
+ "integrity": "sha512-tOijiN1yVyORS5jT5mXe8MTzqc1IVq/AdJXOzTe3uQgeDYhJzQ9lNYgqejDBXW1ahUThsRZgX2RybkOHVjBuHA==",
+ "dependencies": [
+ "@noble/hashes@1.8.0",
+ "applesauce-core",
+ "nanoid",
+ "nostr-tools",
+ "rxjs"
+ ]
+ },
+ "debug@4.4.3": {
+ "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
+ "dependencies": [
+ "ms"
+ ]
+ },
+ "fast-deep-equal@3.1.3": {
+ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="
+ },
+ "hash-sum@2.0.0": {
+ "integrity": "sha512-WdZTbAByD+pHfl/g9QSsBIIwy8IT+EsPiKDs0KNX+zSHhdDLFKdZu0BQHljvO+0QI/BasbMSUa8wYNCZTvhslg=="
+ },
+ "light-bolt11-decoder@3.2.0": {
+ "integrity": "sha512-3QEofgiBOP4Ehs9BI+RkZdXZNtSys0nsJ6fyGeSiAGCBsMwHGUDS/JQlY/sTnWs91A2Nh0S9XXfA8Sy9g6QpuQ==",
+ "dependencies": [
+ "@scure/base@1.1.1"
+ ]
+ },
+ "ms@2.1.3": {
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
+ },
+ "nanoid@5.1.7": {
+ "integrity": "sha512-ua3NDgISf6jdwezAheMOk4mbE1LXjm1DfMUDMuJf4AqxLFK3ccGpgWizwa5YV7Yz9EpXwEaWoRXSb/BnV0t5dQ==",
+ "bin": true
+ },
+ "nostr-tools@2.23.3": {
+ "integrity": "sha512-AALyt9k8xPdF4UV2mlLJ2mgCn4kpTB0DZ8t2r6wjdUh6anfx2cTVBsHUlo9U0EY/cKC5wcNyiMAmRJV5OVEalA==",
+ "dependencies": [
+ "@noble/ciphers",
+ "@noble/curves",
+ "@noble/hashes@2.0.1",
+ "@scure/base@2.0.0",
+ "@scure/bip32",
+ "@scure/bip39",
+ "nostr-wasm"
+ ]
+ },
+ "nostr-wasm@0.1.0": {
+ "integrity": "sha512-78BTryCLcLYv96ONU8Ws3Q1JzjlAt+43pWQhIl86xZmWeegYCNLPml7yQ+gG3vR6V5h4XGj+TxO+SS5dsThQIA=="
+ },
+ "rxjs@7.8.2": {
+ "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==",
+ "dependencies": [
+ "tslib"
+ ]
+ },
+ "tslib@2.8.1": {
+ "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="
+ }
+ },
+ "workspace": {
+ "dependencies": [
+ "jsr:@std/assert@^1.0.6",
+ "jsr:@std/cli@^1.0.6",
+ "jsr:@std/encoding@^1.0.5",
+ "jsr:@std/fs@^1.0.4",
+ "jsr:@std/path@^1.0.6",
+ "jsr:@std/testing@^1.0.3",
+ "jsr:@std/yaml@^1.0.5",
+ "npm:applesauce-relay@2",
+ "npm:nostr-tools@^2.10.4",
+ "npm:rxjs@^7.8.1"
+ ]
+ }
+}