remove blog
This commit is contained in:
parent
6cb6ec6e42
commit
d045461d89
11
package.json
11
package.json
@ -3,14 +3,13 @@
|
|||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "pnpm build:posts && vite --port 3000",
|
"dev": "vite --port 3000",
|
||||||
"build": "pnpm build:posts && vite build && tsc",
|
"build": "vite build && tsc",
|
||||||
"preview": "vite preview",
|
"preview": "vite preview",
|
||||||
"test": "vitest run",
|
"test": "vitest run",
|
||||||
"format": "biome format",
|
"format": "biome format",
|
||||||
"lint": "biome lint",
|
"lint": "biome lint",
|
||||||
"check": "biome check",
|
"check": "biome check"
|
||||||
"build:posts": "node scripts/build-posts.js"
|
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@t3-oss/env-core": "^0.13.8",
|
"@t3-oss/env-core": "^0.13.8",
|
||||||
@ -19,13 +18,9 @@
|
|||||||
"@tanstack/react-router": "^1.132.0",
|
"@tanstack/react-router": "^1.132.0",
|
||||||
"@tanstack/react-router-devtools": "^1.132.0",
|
"@tanstack/react-router-devtools": "^1.132.0",
|
||||||
"@tanstack/router-plugin": "^1.132.0",
|
"@tanstack/router-plugin": "^1.132.0",
|
||||||
"buffer": "^6.0.3",
|
|
||||||
"gray-matter": "^4.0.3",
|
|
||||||
"lucide-react": "^0.545.0",
|
"lucide-react": "^0.545.0",
|
||||||
"react": "^19.2.0",
|
"react": "^19.2.0",
|
||||||
"react-dom": "^19.2.0",
|
"react-dom": "^19.2.0",
|
||||||
"remark": "^15.0.1",
|
|
||||||
"remark-html": "^16.0.1",
|
|
||||||
"tailwindcss": "^4.0.6",
|
"tailwindcss": "^4.0.6",
|
||||||
"zod": "^4.1.11"
|
"zod": "^4.1.11"
|
||||||
},
|
},
|
||||||
|
|||||||
628
pnpm-lock.yaml
generated
628
pnpm-lock.yaml
generated
@ -26,12 +26,6 @@ importers:
|
|||||||
'@tanstack/router-plugin':
|
'@tanstack/router-plugin':
|
||||||
specifier: ^1.132.0
|
specifier: ^1.132.0
|
||||||
version: 1.158.0(@tanstack/react-router@1.158.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(vite@7.3.1(@types/node@22.19.8)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0))
|
version: 1.158.0(@tanstack/react-router@1.158.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(vite@7.3.1(@types/node@22.19.8)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0))
|
||||||
buffer:
|
|
||||||
specifier: ^6.0.3
|
|
||||||
version: 6.0.3
|
|
||||||
gray-matter:
|
|
||||||
specifier: ^4.0.3
|
|
||||||
version: 4.0.3
|
|
||||||
lucide-react:
|
lucide-react:
|
||||||
specifier: ^0.545.0
|
specifier: ^0.545.0
|
||||||
version: 0.545.0(react@19.2.4)
|
version: 0.545.0(react@19.2.4)
|
||||||
@ -41,12 +35,6 @@ importers:
|
|||||||
react-dom:
|
react-dom:
|
||||||
specifier: ^19.2.0
|
specifier: ^19.2.0
|
||||||
version: 19.2.4(react@19.2.4)
|
version: 19.2.4(react@19.2.4)
|
||||||
remark:
|
|
||||||
specifier: ^15.0.1
|
|
||||||
version: 15.0.1
|
|
||||||
remark-html:
|
|
||||||
specifier: ^16.0.1
|
|
||||||
version: 16.0.1
|
|
||||||
tailwindcss:
|
tailwindcss:
|
||||||
specifier: ^4.0.6
|
specifier: ^4.0.6
|
||||||
version: 4.1.18
|
version: 4.1.18
|
||||||
@ -917,12 +905,6 @@ packages:
|
|||||||
'@types/estree@1.0.8':
|
'@types/estree@1.0.8':
|
||||||
resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==}
|
resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==}
|
||||||
|
|
||||||
'@types/hast@3.0.4':
|
|
||||||
resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==}
|
|
||||||
|
|
||||||
'@types/mdast@4.0.4':
|
|
||||||
resolution: {integrity: sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==}
|
|
||||||
|
|
||||||
'@types/ms@2.1.0':
|
'@types/ms@2.1.0':
|
||||||
resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==}
|
resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==}
|
||||||
|
|
||||||
@ -937,12 +919,6 @@ packages:
|
|||||||
'@types/react@19.2.10':
|
'@types/react@19.2.10':
|
||||||
resolution: {integrity: sha512-WPigyYuGhgZ/cTPRXB2EwUw+XvsRA3GqHlsP4qteqrnnjDrApbS7MxcGr/hke5iUoeB7E/gQtrs9I37zAJ0Vjw==}
|
resolution: {integrity: sha512-WPigyYuGhgZ/cTPRXB2EwUw+XvsRA3GqHlsP4qteqrnnjDrApbS7MxcGr/hke5iUoeB7E/gQtrs9I37zAJ0Vjw==}
|
||||||
|
|
||||||
'@types/unist@3.0.3':
|
|
||||||
resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==}
|
|
||||||
|
|
||||||
'@ungap/structured-clone@1.3.0':
|
|
||||||
resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==}
|
|
||||||
|
|
||||||
'@vitejs/plugin-react@5.1.3':
|
'@vitejs/plugin-react@5.1.3':
|
||||||
resolution: {integrity: sha512-NVUnA6gQCl8jfoYqKqQU5Clv0aPw14KkZYCsX6T9Lfu9slI0LOU10OTwFHS/WmptsMMpshNd/1tuWsHQ2Uk+cg==}
|
resolution: {integrity: sha512-NVUnA6gQCl8jfoYqKqQU5Clv0aPw14KkZYCsX6T9Lfu9slI0LOU10OTwFHS/WmptsMMpshNd/1tuWsHQ2Uk+cg==}
|
||||||
engines: {node: ^20.19.0 || >=22.12.0}
|
engines: {node: ^20.19.0 || >=22.12.0}
|
||||||
@ -1003,9 +979,6 @@ packages:
|
|||||||
resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==}
|
resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==}
|
||||||
engines: {node: '>= 8'}
|
engines: {node: '>= 8'}
|
||||||
|
|
||||||
argparse@1.0.10:
|
|
||||||
resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==}
|
|
||||||
|
|
||||||
aria-query@5.3.0:
|
aria-query@5.3.0:
|
||||||
resolution: {integrity: sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==}
|
resolution: {integrity: sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==}
|
||||||
|
|
||||||
@ -1020,12 +993,6 @@ packages:
|
|||||||
babel-dead-code-elimination@1.0.12:
|
babel-dead-code-elimination@1.0.12:
|
||||||
resolution: {integrity: sha512-GERT7L2TiYcYDtYk1IpD+ASAYXjKbLTDPhBtYj7X1NuRMDTMtAx9kyBenub1Ev41lo91OHCKdmP+egTDmfQ7Ig==}
|
resolution: {integrity: sha512-GERT7L2TiYcYDtYk1IpD+ASAYXjKbLTDPhBtYj7X1NuRMDTMtAx9kyBenub1Ev41lo91OHCKdmP+egTDmfQ7Ig==}
|
||||||
|
|
||||||
bail@2.0.2:
|
|
||||||
resolution: {integrity: sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==}
|
|
||||||
|
|
||||||
base64-js@1.5.1:
|
|
||||||
resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==}
|
|
||||||
|
|
||||||
baseline-browser-mapping@2.9.19:
|
baseline-browser-mapping@2.9.19:
|
||||||
resolution: {integrity: sha512-ipDqC8FrAl/76p2SSWKSI+H9tFwm7vYqXQrItCuiVPt26Km0jS+NzSsBWAaBusvSbQcfJG+JitdMm+wZAgTYqg==}
|
resolution: {integrity: sha512-ipDqC8FrAl/76p2SSWKSI+H9tFwm7vYqXQrItCuiVPt26Km0jS+NzSsBWAaBusvSbQcfJG+JitdMm+wZAgTYqg==}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
@ -1046,9 +1013,6 @@ packages:
|
|||||||
engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
|
engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
buffer@6.0.3:
|
|
||||||
resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==}
|
|
||||||
|
|
||||||
cac@6.7.14:
|
cac@6.7.14:
|
||||||
resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==}
|
resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
@ -1056,9 +1020,6 @@ packages:
|
|||||||
caniuse-lite@1.0.30001767:
|
caniuse-lite@1.0.30001767:
|
||||||
resolution: {integrity: sha512-34+zUAMhSH+r+9eKmYG+k2Rpt8XttfE4yXAjoZvkAPs15xcYQhyBYdalJ65BzivAvGRMViEjy6oKr/S91loekQ==}
|
resolution: {integrity: sha512-34+zUAMhSH+r+9eKmYG+k2Rpt8XttfE4yXAjoZvkAPs15xcYQhyBYdalJ65BzivAvGRMViEjy6oKr/S91loekQ==}
|
||||||
|
|
||||||
ccount@2.0.1:
|
|
||||||
resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==}
|
|
||||||
|
|
||||||
chai@5.3.3:
|
chai@5.3.3:
|
||||||
resolution: {integrity: sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==}
|
resolution: {integrity: sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
@ -1067,15 +1028,6 @@ packages:
|
|||||||
resolution: {integrity: sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==}
|
resolution: {integrity: sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==}
|
||||||
engines: {node: ^12.17.0 || ^14.13 || >=16.0.0}
|
engines: {node: ^12.17.0 || ^14.13 || >=16.0.0}
|
||||||
|
|
||||||
character-entities-html4@2.1.0:
|
|
||||||
resolution: {integrity: sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==}
|
|
||||||
|
|
||||||
character-entities-legacy@3.0.0:
|
|
||||||
resolution: {integrity: sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==}
|
|
||||||
|
|
||||||
character-entities@2.0.2:
|
|
||||||
resolution: {integrity: sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==}
|
|
||||||
|
|
||||||
check-error@2.1.3:
|
check-error@2.1.3:
|
||||||
resolution: {integrity: sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA==}
|
resolution: {integrity: sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA==}
|
||||||
engines: {node: '>= 16'}
|
engines: {node: '>= 16'}
|
||||||
@ -1088,9 +1040,6 @@ packages:
|
|||||||
resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==}
|
resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==}
|
||||||
engines: {node: '>=6'}
|
engines: {node: '>=6'}
|
||||||
|
|
||||||
comma-separated-tokens@2.0.3:
|
|
||||||
resolution: {integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==}
|
|
||||||
|
|
||||||
convert-source-map@2.0.0:
|
convert-source-map@2.0.0:
|
||||||
resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==}
|
resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==}
|
||||||
|
|
||||||
@ -1129,9 +1078,6 @@ packages:
|
|||||||
decimal.js@10.6.0:
|
decimal.js@10.6.0:
|
||||||
resolution: {integrity: sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==}
|
resolution: {integrity: sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==}
|
||||||
|
|
||||||
decode-named-character-reference@1.3.0:
|
|
||||||
resolution: {integrity: sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q==}
|
|
||||||
|
|
||||||
deep-eql@5.0.2:
|
deep-eql@5.0.2:
|
||||||
resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==}
|
resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==}
|
||||||
engines: {node: '>=6'}
|
engines: {node: '>=6'}
|
||||||
@ -1144,9 +1090,6 @@ packages:
|
|||||||
resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==}
|
resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
|
|
||||||
devlop@1.1.0:
|
|
||||||
resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==}
|
|
||||||
|
|
||||||
diff@8.0.3:
|
diff@8.0.3:
|
||||||
resolution: {integrity: sha512-qejHi7bcSD4hQAZE0tNAawRK1ZtafHDmMTMkrrIGgSLl7hTnQHmKCeB45xAcbfTqK2zowkM3j3bHt/4b/ARbYQ==}
|
resolution: {integrity: sha512-qejHi7bcSD4hQAZE0tNAawRK1ZtafHDmMTMkrrIGgSLl7hTnQHmKCeB45xAcbfTqK2zowkM3j3bHt/4b/ARbYQ==}
|
||||||
engines: {node: '>=0.3.1'}
|
engines: {node: '>=0.3.1'}
|
||||||
@ -1189,13 +1132,6 @@ packages:
|
|||||||
resolution: {integrity: sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==}
|
resolution: {integrity: sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==}
|
||||||
engines: {node: '>=12.0.0'}
|
engines: {node: '>=12.0.0'}
|
||||||
|
|
||||||
extend-shallow@2.0.1:
|
|
||||||
resolution: {integrity: sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==}
|
|
||||||
engines: {node: '>=0.10.0'}
|
|
||||||
|
|
||||||
extend@3.0.2:
|
|
||||||
resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==}
|
|
||||||
|
|
||||||
fdir@6.5.0:
|
fdir@6.5.0:
|
||||||
resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==}
|
resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==}
|
||||||
engines: {node: '>=12.0.0'}
|
engines: {node: '>=12.0.0'}
|
||||||
@ -1233,26 +1169,10 @@ packages:
|
|||||||
graceful-fs@4.2.11:
|
graceful-fs@4.2.11:
|
||||||
resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==}
|
resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==}
|
||||||
|
|
||||||
gray-matter@4.0.3:
|
|
||||||
resolution: {integrity: sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q==}
|
|
||||||
engines: {node: '>=6.0'}
|
|
||||||
|
|
||||||
hast-util-sanitize@5.0.2:
|
|
||||||
resolution: {integrity: sha512-3yTWghByc50aGS7JlGhk61SPenfE/p1oaFeNwkOOyrscaOkMGrcW9+Cy/QAIOBpZxP1yqDIzFMR0+Np0i0+usg==}
|
|
||||||
|
|
||||||
hast-util-to-html@9.0.5:
|
|
||||||
resolution: {integrity: sha512-OguPdidb+fbHQSU4Q4ZiLKnzWo8Wwsf5bZfbvu7//a9oTYoqD/fWpe96NuHkoS9h0ccGOTe0C4NGXdtS0iObOw==}
|
|
||||||
|
|
||||||
hast-util-whitespace@3.0.0:
|
|
||||||
resolution: {integrity: sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==}
|
|
||||||
|
|
||||||
html-encoding-sniffer@6.0.0:
|
html-encoding-sniffer@6.0.0:
|
||||||
resolution: {integrity: sha512-CV9TW3Y3f8/wT0BRFc1/KAVQ3TUHiXmaAb6VW9vtiMFf7SLoMd1PdAc4W3KFOFETBJUb90KatHqlsZMWV+R9Gg==}
|
resolution: {integrity: sha512-CV9TW3Y3f8/wT0BRFc1/KAVQ3TUHiXmaAb6VW9vtiMFf7SLoMd1PdAc4W3KFOFETBJUb90KatHqlsZMWV+R9Gg==}
|
||||||
engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0}
|
engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0}
|
||||||
|
|
||||||
html-void-elements@3.0.0:
|
|
||||||
resolution: {integrity: sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==}
|
|
||||||
|
|
||||||
http-proxy-agent@7.0.2:
|
http-proxy-agent@7.0.2:
|
||||||
resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==}
|
resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==}
|
||||||
engines: {node: '>= 14'}
|
engines: {node: '>= 14'}
|
||||||
@ -1261,17 +1181,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==}
|
resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==}
|
||||||
engines: {node: '>= 14'}
|
engines: {node: '>= 14'}
|
||||||
|
|
||||||
ieee754@1.2.1:
|
|
||||||
resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==}
|
|
||||||
|
|
||||||
is-binary-path@2.1.0:
|
is-binary-path@2.1.0:
|
||||||
resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==}
|
resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
|
|
||||||
is-extendable@0.1.1:
|
|
||||||
resolution: {integrity: sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==}
|
|
||||||
engines: {node: '>=0.10.0'}
|
|
||||||
|
|
||||||
is-extglob@2.1.1:
|
is-extglob@2.1.1:
|
||||||
resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==}
|
resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
@ -1284,10 +1197,6 @@ packages:
|
|||||||
resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==}
|
resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==}
|
||||||
engines: {node: '>=0.12.0'}
|
engines: {node: '>=0.12.0'}
|
||||||
|
|
||||||
is-plain-obj@4.1.0:
|
|
||||||
resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==}
|
|
||||||
engines: {node: '>=12'}
|
|
||||||
|
|
||||||
is-potential-custom-element-name@1.0.1:
|
is-potential-custom-element-name@1.0.1:
|
||||||
resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==}
|
resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==}
|
||||||
|
|
||||||
@ -1305,10 +1214,6 @@ packages:
|
|||||||
js-tokens@9.0.1:
|
js-tokens@9.0.1:
|
||||||
resolution: {integrity: sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==}
|
resolution: {integrity: sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==}
|
||||||
|
|
||||||
js-yaml@3.14.2:
|
|
||||||
resolution: {integrity: sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==}
|
|
||||||
hasBin: true
|
|
||||||
|
|
||||||
jsdom@27.4.0:
|
jsdom@27.4.0:
|
||||||
resolution: {integrity: sha512-mjzqwWRD9Y1J1KUi7W97Gja1bwOOM5Ug0EZ6UDK3xS7j7mndrkwozHtSblfomlzyB4NepioNt+B2sOSzczVgtQ==}
|
resolution: {integrity: sha512-mjzqwWRD9Y1J1KUi7W97Gja1bwOOM5Ug0EZ6UDK3xS7j7mndrkwozHtSblfomlzyB4NepioNt+B2sOSzczVgtQ==}
|
||||||
engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0}
|
engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0}
|
||||||
@ -1328,10 +1233,6 @@ packages:
|
|||||||
engines: {node: '>=6'}
|
engines: {node: '>=6'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
kind-of@6.0.3:
|
|
||||||
resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==}
|
|
||||||
engines: {node: '>=0.10.0'}
|
|
||||||
|
|
||||||
launch-editor@2.12.0:
|
launch-editor@2.12.0:
|
||||||
resolution: {integrity: sha512-giOHXoOtifjdHqUamwKq6c49GzBdLjvxrd2D+Q4V6uOHopJv7p9VJxikDsQ/CBXZbEITgUqSVHXLTG3VhPP1Dg==}
|
resolution: {integrity: sha512-giOHXoOtifjdHqUamwKq6c49GzBdLjvxrd2D+Q4V6uOHopJv7p9VJxikDsQ/CBXZbEITgUqSVHXLTG3VhPP1Dg==}
|
||||||
|
|
||||||
@ -1405,9 +1306,6 @@ packages:
|
|||||||
resolution: {integrity: sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ==}
|
resolution: {integrity: sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ==}
|
||||||
engines: {node: '>= 12.0.0'}
|
engines: {node: '>= 12.0.0'}
|
||||||
|
|
||||||
longest-streak@3.1.0:
|
|
||||||
resolution: {integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==}
|
|
||||||
|
|
||||||
loupe@3.2.1:
|
loupe@3.2.1:
|
||||||
resolution: {integrity: sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==}
|
resolution: {integrity: sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==}
|
||||||
|
|
||||||
@ -1430,87 +1328,9 @@ packages:
|
|||||||
magic-string@0.30.21:
|
magic-string@0.30.21:
|
||||||
resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==}
|
resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==}
|
||||||
|
|
||||||
mdast-util-from-markdown@2.0.2:
|
|
||||||
resolution: {integrity: sha512-uZhTV/8NBuw0WHkPTrCqDOl0zVe1BIng5ZtHoDk49ME1qqcjYmmLmOf0gELgcRMxN4w2iuIeVso5/6QymSrgmA==}
|
|
||||||
|
|
||||||
mdast-util-phrasing@4.1.0:
|
|
||||||
resolution: {integrity: sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==}
|
|
||||||
|
|
||||||
mdast-util-to-hast@13.2.1:
|
|
||||||
resolution: {integrity: sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA==}
|
|
||||||
|
|
||||||
mdast-util-to-markdown@2.1.2:
|
|
||||||
resolution: {integrity: sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA==}
|
|
||||||
|
|
||||||
mdast-util-to-string@4.0.0:
|
|
||||||
resolution: {integrity: sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==}
|
|
||||||
|
|
||||||
mdn-data@2.12.2:
|
mdn-data@2.12.2:
|
||||||
resolution: {integrity: sha512-IEn+pegP1aManZuckezWCO+XZQDplx1366JoVhTpMpBB1sPey/SbveZQUosKiKiGYjg1wH4pMlNgXbCiYgihQA==}
|
resolution: {integrity: sha512-IEn+pegP1aManZuckezWCO+XZQDplx1366JoVhTpMpBB1sPey/SbveZQUosKiKiGYjg1wH4pMlNgXbCiYgihQA==}
|
||||||
|
|
||||||
micromark-core-commonmark@2.0.3:
|
|
||||||
resolution: {integrity: sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==}
|
|
||||||
|
|
||||||
micromark-factory-destination@2.0.1:
|
|
||||||
resolution: {integrity: sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==}
|
|
||||||
|
|
||||||
micromark-factory-label@2.0.1:
|
|
||||||
resolution: {integrity: sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==}
|
|
||||||
|
|
||||||
micromark-factory-space@2.0.1:
|
|
||||||
resolution: {integrity: sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==}
|
|
||||||
|
|
||||||
micromark-factory-title@2.0.1:
|
|
||||||
resolution: {integrity: sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==}
|
|
||||||
|
|
||||||
micromark-factory-whitespace@2.0.1:
|
|
||||||
resolution: {integrity: sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==}
|
|
||||||
|
|
||||||
micromark-util-character@2.1.1:
|
|
||||||
resolution: {integrity: sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==}
|
|
||||||
|
|
||||||
micromark-util-chunked@2.0.1:
|
|
||||||
resolution: {integrity: sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==}
|
|
||||||
|
|
||||||
micromark-util-classify-character@2.0.1:
|
|
||||||
resolution: {integrity: sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==}
|
|
||||||
|
|
||||||
micromark-util-combine-extensions@2.0.1:
|
|
||||||
resolution: {integrity: sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==}
|
|
||||||
|
|
||||||
micromark-util-decode-numeric-character-reference@2.0.2:
|
|
||||||
resolution: {integrity: sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==}
|
|
||||||
|
|
||||||
micromark-util-decode-string@2.0.1:
|
|
||||||
resolution: {integrity: sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ==}
|
|
||||||
|
|
||||||
micromark-util-encode@2.0.1:
|
|
||||||
resolution: {integrity: sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==}
|
|
||||||
|
|
||||||
micromark-util-html-tag-name@2.0.1:
|
|
||||||
resolution: {integrity: sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==}
|
|
||||||
|
|
||||||
micromark-util-normalize-identifier@2.0.1:
|
|
||||||
resolution: {integrity: sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==}
|
|
||||||
|
|
||||||
micromark-util-resolve-all@2.0.1:
|
|
||||||
resolution: {integrity: sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==}
|
|
||||||
|
|
||||||
micromark-util-sanitize-uri@2.0.1:
|
|
||||||
resolution: {integrity: sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==}
|
|
||||||
|
|
||||||
micromark-util-subtokenize@2.1.0:
|
|
||||||
resolution: {integrity: sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==}
|
|
||||||
|
|
||||||
micromark-util-symbol@2.0.1:
|
|
||||||
resolution: {integrity: sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==}
|
|
||||||
|
|
||||||
micromark-util-types@2.0.2:
|
|
||||||
resolution: {integrity: sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==}
|
|
||||||
|
|
||||||
micromark@4.0.2:
|
|
||||||
resolution: {integrity: sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==}
|
|
||||||
|
|
||||||
ms@2.1.3:
|
ms@2.1.3:
|
||||||
resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
|
resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
|
||||||
|
|
||||||
@ -1564,9 +1384,6 @@ packages:
|
|||||||
resolution: {integrity: sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==}
|
resolution: {integrity: sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==}
|
||||||
engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0}
|
engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0}
|
||||||
|
|
||||||
property-information@7.1.0:
|
|
||||||
resolution: {integrity: sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==}
|
|
||||||
|
|
||||||
punycode@2.3.1:
|
punycode@2.3.1:
|
||||||
resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==}
|
resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==}
|
||||||
engines: {node: '>=6'}
|
engines: {node: '>=6'}
|
||||||
@ -1595,18 +1412,6 @@ packages:
|
|||||||
resolution: {integrity: sha512-YTUo+Flmw4ZXiWfQKGcwwc11KnoRAYgzAE2E7mXKCjSviTKShtxBsN6YUUBB2gtaBzKzeKunxhUwNHQuRryhWA==}
|
resolution: {integrity: sha512-YTUo+Flmw4ZXiWfQKGcwwc11KnoRAYgzAE2E7mXKCjSviTKShtxBsN6YUUBB2gtaBzKzeKunxhUwNHQuRryhWA==}
|
||||||
engines: {node: '>= 4'}
|
engines: {node: '>= 4'}
|
||||||
|
|
||||||
remark-html@16.0.1:
|
|
||||||
resolution: {integrity: sha512-B9JqA5i0qZe0Nsf49q3OXyGvyXuZFDzAP2iOFLEumymuYJITVpiH1IgsTEwTpdptDmZlMDMWeDmSawdaJIGCXQ==}
|
|
||||||
|
|
||||||
remark-parse@11.0.0:
|
|
||||||
resolution: {integrity: sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==}
|
|
||||||
|
|
||||||
remark-stringify@11.0.0:
|
|
||||||
resolution: {integrity: sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==}
|
|
||||||
|
|
||||||
remark@15.0.1:
|
|
||||||
resolution: {integrity: sha512-Eht5w30ruCXgFmxVUSlNWQ9iiimq07URKeFS3hNc8cUWy1llX4KDWfyEDZRycMc+znsN9Ux5/tJ/BFdgdOwA3A==}
|
|
||||||
|
|
||||||
require-from-string@2.0.2:
|
require-from-string@2.0.2:
|
||||||
resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==}
|
resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
@ -1626,10 +1431,6 @@ packages:
|
|||||||
scheduler@0.27.0:
|
scheduler@0.27.0:
|
||||||
resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==}
|
resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==}
|
||||||
|
|
||||||
section-matter@1.0.0:
|
|
||||||
resolution: {integrity: sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA==}
|
|
||||||
engines: {node: '>=4'}
|
|
||||||
|
|
||||||
semver@6.3.1:
|
semver@6.3.1:
|
||||||
resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==}
|
resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
@ -1666,25 +1467,12 @@ packages:
|
|||||||
resolution: {integrity: sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==}
|
resolution: {integrity: sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==}
|
||||||
engines: {node: '>= 12'}
|
engines: {node: '>= 12'}
|
||||||
|
|
||||||
space-separated-tokens@2.0.2:
|
|
||||||
resolution: {integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==}
|
|
||||||
|
|
||||||
sprintf-js@1.0.3:
|
|
||||||
resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==}
|
|
||||||
|
|
||||||
stackback@0.0.2:
|
stackback@0.0.2:
|
||||||
resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==}
|
resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==}
|
||||||
|
|
||||||
std-env@3.10.0:
|
std-env@3.10.0:
|
||||||
resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==}
|
resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==}
|
||||||
|
|
||||||
stringify-entities@4.0.4:
|
|
||||||
resolution: {integrity: sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==}
|
|
||||||
|
|
||||||
strip-bom-string@1.0.0:
|
|
||||||
resolution: {integrity: sha512-uCC2VHvQRYu+lMh4My/sFNmF2klFymLX1wHJeXnbEJERpV/ZsVuonzerjfrGpIGF7LBVa1O7i9kjiWvJiFck8g==}
|
|
||||||
engines: {node: '>=0.10.0'}
|
|
||||||
|
|
||||||
strip-literal@3.1.0:
|
strip-literal@3.1.0:
|
||||||
resolution: {integrity: sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg==}
|
resolution: {integrity: sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg==}
|
||||||
|
|
||||||
@ -1745,12 +1533,6 @@ packages:
|
|||||||
resolution: {integrity: sha512-bLVMLPtstlZ4iMQHpFHTR7GAGj2jxi8Dg0s2h2MafAE4uSWF98FC/3MomU51iQAMf8/qDUbKWf5GxuvvVcXEhw==}
|
resolution: {integrity: sha512-bLVMLPtstlZ4iMQHpFHTR7GAGj2jxi8Dg0s2h2MafAE4uSWF98FC/3MomU51iQAMf8/qDUbKWf5GxuvvVcXEhw==}
|
||||||
engines: {node: '>=20'}
|
engines: {node: '>=20'}
|
||||||
|
|
||||||
trim-lines@3.0.1:
|
|
||||||
resolution: {integrity: sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==}
|
|
||||||
|
|
||||||
trough@2.2.0:
|
|
||||||
resolution: {integrity: sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==}
|
|
||||||
|
|
||||||
tslib@2.8.1:
|
tslib@2.8.1:
|
||||||
resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==}
|
resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==}
|
||||||
|
|
||||||
@ -1767,24 +1549,6 @@ packages:
|
|||||||
undici-types@6.21.0:
|
undici-types@6.21.0:
|
||||||
resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==}
|
resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==}
|
||||||
|
|
||||||
unified@11.0.5:
|
|
||||||
resolution: {integrity: sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==}
|
|
||||||
|
|
||||||
unist-util-is@6.0.1:
|
|
||||||
resolution: {integrity: sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==}
|
|
||||||
|
|
||||||
unist-util-position@5.0.0:
|
|
||||||
resolution: {integrity: sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==}
|
|
||||||
|
|
||||||
unist-util-stringify-position@4.0.0:
|
|
||||||
resolution: {integrity: sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==}
|
|
||||||
|
|
||||||
unist-util-visit-parents@6.0.2:
|
|
||||||
resolution: {integrity: sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ==}
|
|
||||||
|
|
||||||
unist-util-visit@5.1.0:
|
|
||||||
resolution: {integrity: sha512-m+vIdyeCOpdr/QeQCu2EzxX/ohgS8KbnPDgFni4dQsfSCtpz8UqDyY5GjRru8PDKuYn7Fq19j1CQ+nJSsGKOzg==}
|
|
||||||
|
|
||||||
unplugin@2.3.11:
|
unplugin@2.3.11:
|
||||||
resolution: {integrity: sha512-5uKD0nqiYVzlmCRs01Fhs2BdkEgBS3SAVP6ndrBsuK42iC2+JHyxM05Rm9G8+5mkmRtzMZGY8Ct5+mliZxU/Ww==}
|
resolution: {integrity: sha512-5uKD0nqiYVzlmCRs01Fhs2BdkEgBS3SAVP6ndrBsuK42iC2+JHyxM05Rm9G8+5mkmRtzMZGY8Ct5+mliZxU/Ww==}
|
||||||
engines: {node: '>=18.12.0'}
|
engines: {node: '>=18.12.0'}
|
||||||
@ -1803,12 +1567,6 @@ packages:
|
|||||||
util-deprecate@1.0.2:
|
util-deprecate@1.0.2:
|
||||||
resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
|
resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
|
||||||
|
|
||||||
vfile-message@4.0.3:
|
|
||||||
resolution: {integrity: sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==}
|
|
||||||
|
|
||||||
vfile@6.0.3:
|
|
||||||
resolution: {integrity: sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==}
|
|
||||||
|
|
||||||
vite-node@3.2.4:
|
vite-node@3.2.4:
|
||||||
resolution: {integrity: sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg==}
|
resolution: {integrity: sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg==}
|
||||||
engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0}
|
engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0}
|
||||||
@ -1941,9 +1699,6 @@ packages:
|
|||||||
zod@4.3.6:
|
zod@4.3.6:
|
||||||
resolution: {integrity: sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==}
|
resolution: {integrity: sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==}
|
||||||
|
|
||||||
zwitch@2.0.4:
|
|
||||||
resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==}
|
|
||||||
|
|
||||||
snapshots:
|
snapshots:
|
||||||
|
|
||||||
'@acemir/cssom@0.9.31': {}
|
'@acemir/cssom@0.9.31': {}
|
||||||
@ -2663,20 +2418,14 @@ snapshots:
|
|||||||
'@types/debug@4.1.12':
|
'@types/debug@4.1.12':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/ms': 2.1.0
|
'@types/ms': 2.1.0
|
||||||
|
optional: true
|
||||||
|
|
||||||
'@types/deep-eql@4.0.2': {}
|
'@types/deep-eql@4.0.2': {}
|
||||||
|
|
||||||
'@types/estree@1.0.8': {}
|
'@types/estree@1.0.8': {}
|
||||||
|
|
||||||
'@types/hast@3.0.4':
|
'@types/ms@2.1.0':
|
||||||
dependencies:
|
optional: true
|
||||||
'@types/unist': 3.0.3
|
|
||||||
|
|
||||||
'@types/mdast@4.0.4':
|
|
||||||
dependencies:
|
|
||||||
'@types/unist': 3.0.3
|
|
||||||
|
|
||||||
'@types/ms@2.1.0': {}
|
|
||||||
|
|
||||||
'@types/node@22.19.8':
|
'@types/node@22.19.8':
|
||||||
dependencies:
|
dependencies:
|
||||||
@ -2690,10 +2439,6 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
csstype: 3.2.3
|
csstype: 3.2.3
|
||||||
|
|
||||||
'@types/unist@3.0.3': {}
|
|
||||||
|
|
||||||
'@ungap/structured-clone@1.3.0': {}
|
|
||||||
|
|
||||||
'@vitejs/plugin-react@5.1.3(vite@7.3.1(@types/node@22.19.8)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0))':
|
'@vitejs/plugin-react@5.1.3(vite@7.3.1(@types/node@22.19.8)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0))':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@babel/core': 7.29.0
|
'@babel/core': 7.29.0
|
||||||
@ -2763,10 +2508,6 @@ snapshots:
|
|||||||
normalize-path: 3.0.0
|
normalize-path: 3.0.0
|
||||||
picomatch: 2.3.1
|
picomatch: 2.3.1
|
||||||
|
|
||||||
argparse@1.0.10:
|
|
||||||
dependencies:
|
|
||||||
sprintf-js: 1.0.3
|
|
||||||
|
|
||||||
aria-query@5.3.0:
|
aria-query@5.3.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
dequal: 2.0.3
|
dequal: 2.0.3
|
||||||
@ -2786,10 +2527,6 @@ snapshots:
|
|||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
bail@2.0.2: {}
|
|
||||||
|
|
||||||
base64-js@1.5.1: {}
|
|
||||||
|
|
||||||
baseline-browser-mapping@2.9.19: {}
|
baseline-browser-mapping@2.9.19: {}
|
||||||
|
|
||||||
bidi-js@1.0.3:
|
bidi-js@1.0.3:
|
||||||
@ -2810,17 +2547,10 @@ snapshots:
|
|||||||
node-releases: 2.0.27
|
node-releases: 2.0.27
|
||||||
update-browserslist-db: 1.2.3(browserslist@4.28.1)
|
update-browserslist-db: 1.2.3(browserslist@4.28.1)
|
||||||
|
|
||||||
buffer@6.0.3:
|
|
||||||
dependencies:
|
|
||||||
base64-js: 1.5.1
|
|
||||||
ieee754: 1.2.1
|
|
||||||
|
|
||||||
cac@6.7.14: {}
|
cac@6.7.14: {}
|
||||||
|
|
||||||
caniuse-lite@1.0.30001767: {}
|
caniuse-lite@1.0.30001767: {}
|
||||||
|
|
||||||
ccount@2.0.1: {}
|
|
||||||
|
|
||||||
chai@5.3.3:
|
chai@5.3.3:
|
||||||
dependencies:
|
dependencies:
|
||||||
assertion-error: 2.0.1
|
assertion-error: 2.0.1
|
||||||
@ -2831,12 +2561,6 @@ snapshots:
|
|||||||
|
|
||||||
chalk@5.6.2: {}
|
chalk@5.6.2: {}
|
||||||
|
|
||||||
character-entities-html4@2.1.0: {}
|
|
||||||
|
|
||||||
character-entities-legacy@3.0.0: {}
|
|
||||||
|
|
||||||
character-entities@2.0.2: {}
|
|
||||||
|
|
||||||
check-error@2.1.3: {}
|
check-error@2.1.3: {}
|
||||||
|
|
||||||
chokidar@3.6.0:
|
chokidar@3.6.0:
|
||||||
@ -2853,8 +2577,6 @@ snapshots:
|
|||||||
|
|
||||||
clsx@2.1.1: {}
|
clsx@2.1.1: {}
|
||||||
|
|
||||||
comma-separated-tokens@2.0.3: {}
|
|
||||||
|
|
||||||
convert-source-map@2.0.0: {}
|
convert-source-map@2.0.0: {}
|
||||||
|
|
||||||
cookie-es@2.0.0: {}
|
cookie-es@2.0.0: {}
|
||||||
@ -2886,20 +2608,12 @@ snapshots:
|
|||||||
|
|
||||||
decimal.js@10.6.0: {}
|
decimal.js@10.6.0: {}
|
||||||
|
|
||||||
decode-named-character-reference@1.3.0:
|
|
||||||
dependencies:
|
|
||||||
character-entities: 2.0.2
|
|
||||||
|
|
||||||
deep-eql@5.0.2: {}
|
deep-eql@5.0.2: {}
|
||||||
|
|
||||||
dequal@2.0.3: {}
|
dequal@2.0.3: {}
|
||||||
|
|
||||||
detect-libc@2.1.2: {}
|
detect-libc@2.1.2: {}
|
||||||
|
|
||||||
devlop@1.1.0:
|
|
||||||
dependencies:
|
|
||||||
dequal: 2.0.3
|
|
||||||
|
|
||||||
diff@8.0.3: {}
|
diff@8.0.3: {}
|
||||||
|
|
||||||
dom-accessibility-api@0.5.16: {}
|
dom-accessibility-api@0.5.16: {}
|
||||||
@ -2954,12 +2668,6 @@ snapshots:
|
|||||||
|
|
||||||
expect-type@1.3.0: {}
|
expect-type@1.3.0: {}
|
||||||
|
|
||||||
extend-shallow@2.0.1:
|
|
||||||
dependencies:
|
|
||||||
is-extendable: 0.1.1
|
|
||||||
|
|
||||||
extend@3.0.2: {}
|
|
||||||
|
|
||||||
fdir@6.5.0(picomatch@4.0.3):
|
fdir@6.5.0(picomatch@4.0.3):
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
picomatch: 4.0.3
|
picomatch: 4.0.3
|
||||||
@ -2987,45 +2695,12 @@ snapshots:
|
|||||||
|
|
||||||
graceful-fs@4.2.11: {}
|
graceful-fs@4.2.11: {}
|
||||||
|
|
||||||
gray-matter@4.0.3:
|
|
||||||
dependencies:
|
|
||||||
js-yaml: 3.14.2
|
|
||||||
kind-of: 6.0.3
|
|
||||||
section-matter: 1.0.0
|
|
||||||
strip-bom-string: 1.0.0
|
|
||||||
|
|
||||||
hast-util-sanitize@5.0.2:
|
|
||||||
dependencies:
|
|
||||||
'@types/hast': 3.0.4
|
|
||||||
'@ungap/structured-clone': 1.3.0
|
|
||||||
unist-util-position: 5.0.0
|
|
||||||
|
|
||||||
hast-util-to-html@9.0.5:
|
|
||||||
dependencies:
|
|
||||||
'@types/hast': 3.0.4
|
|
||||||
'@types/unist': 3.0.3
|
|
||||||
ccount: 2.0.1
|
|
||||||
comma-separated-tokens: 2.0.3
|
|
||||||
hast-util-whitespace: 3.0.0
|
|
||||||
html-void-elements: 3.0.0
|
|
||||||
mdast-util-to-hast: 13.2.1
|
|
||||||
property-information: 7.1.0
|
|
||||||
space-separated-tokens: 2.0.2
|
|
||||||
stringify-entities: 4.0.4
|
|
||||||
zwitch: 2.0.4
|
|
||||||
|
|
||||||
hast-util-whitespace@3.0.0:
|
|
||||||
dependencies:
|
|
||||||
'@types/hast': 3.0.4
|
|
||||||
|
|
||||||
html-encoding-sniffer@6.0.0:
|
html-encoding-sniffer@6.0.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@exodus/bytes': 1.11.0
|
'@exodus/bytes': 1.11.0
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- '@noble/hashes'
|
- '@noble/hashes'
|
||||||
|
|
||||||
html-void-elements@3.0.0: {}
|
|
||||||
|
|
||||||
http-proxy-agent@7.0.2:
|
http-proxy-agent@7.0.2:
|
||||||
dependencies:
|
dependencies:
|
||||||
agent-base: 7.1.4
|
agent-base: 7.1.4
|
||||||
@ -3040,14 +2715,10 @@ snapshots:
|
|||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
ieee754@1.2.1: {}
|
|
||||||
|
|
||||||
is-binary-path@2.1.0:
|
is-binary-path@2.1.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
binary-extensions: 2.3.0
|
binary-extensions: 2.3.0
|
||||||
|
|
||||||
is-extendable@0.1.1: {}
|
|
||||||
|
|
||||||
is-extglob@2.1.1: {}
|
is-extglob@2.1.1: {}
|
||||||
|
|
||||||
is-glob@4.0.3:
|
is-glob@4.0.3:
|
||||||
@ -3056,8 +2727,6 @@ snapshots:
|
|||||||
|
|
||||||
is-number@7.0.0: {}
|
is-number@7.0.0: {}
|
||||||
|
|
||||||
is-plain-obj@4.1.0: {}
|
|
||||||
|
|
||||||
is-potential-custom-element-name@1.0.1: {}
|
is-potential-custom-element-name@1.0.1: {}
|
||||||
|
|
||||||
isbot@5.1.34: {}
|
isbot@5.1.34: {}
|
||||||
@ -3068,11 +2737,6 @@ snapshots:
|
|||||||
|
|
||||||
js-tokens@9.0.1: {}
|
js-tokens@9.0.1: {}
|
||||||
|
|
||||||
js-yaml@3.14.2:
|
|
||||||
dependencies:
|
|
||||||
argparse: 1.0.10
|
|
||||||
esprima: 4.0.1
|
|
||||||
|
|
||||||
jsdom@27.4.0:
|
jsdom@27.4.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@acemir/cssom': 0.9.31
|
'@acemir/cssom': 0.9.31
|
||||||
@ -3105,8 +2769,6 @@ snapshots:
|
|||||||
|
|
||||||
json5@2.2.3: {}
|
json5@2.2.3: {}
|
||||||
|
|
||||||
kind-of@6.0.3: {}
|
|
||||||
|
|
||||||
launch-editor@2.12.0:
|
launch-editor@2.12.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
picocolors: 1.1.1
|
picocolors: 1.1.1
|
||||||
@ -3161,8 +2823,6 @@ snapshots:
|
|||||||
lightningcss-win32-arm64-msvc: 1.30.2
|
lightningcss-win32-arm64-msvc: 1.30.2
|
||||||
lightningcss-win32-x64-msvc: 1.30.2
|
lightningcss-win32-x64-msvc: 1.30.2
|
||||||
|
|
||||||
longest-streak@3.1.0: {}
|
|
||||||
|
|
||||||
loupe@3.2.1: {}
|
loupe@3.2.1: {}
|
||||||
|
|
||||||
lru-cache@11.2.5: {}
|
lru-cache@11.2.5: {}
|
||||||
@ -3181,191 +2841,8 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
'@jridgewell/sourcemap-codec': 1.5.5
|
'@jridgewell/sourcemap-codec': 1.5.5
|
||||||
|
|
||||||
mdast-util-from-markdown@2.0.2:
|
|
||||||
dependencies:
|
|
||||||
'@types/mdast': 4.0.4
|
|
||||||
'@types/unist': 3.0.3
|
|
||||||
decode-named-character-reference: 1.3.0
|
|
||||||
devlop: 1.1.0
|
|
||||||
mdast-util-to-string: 4.0.0
|
|
||||||
micromark: 4.0.2
|
|
||||||
micromark-util-decode-numeric-character-reference: 2.0.2
|
|
||||||
micromark-util-decode-string: 2.0.1
|
|
||||||
micromark-util-normalize-identifier: 2.0.1
|
|
||||||
micromark-util-symbol: 2.0.1
|
|
||||||
micromark-util-types: 2.0.2
|
|
||||||
unist-util-stringify-position: 4.0.0
|
|
||||||
transitivePeerDependencies:
|
|
||||||
- supports-color
|
|
||||||
|
|
||||||
mdast-util-phrasing@4.1.0:
|
|
||||||
dependencies:
|
|
||||||
'@types/mdast': 4.0.4
|
|
||||||
unist-util-is: 6.0.1
|
|
||||||
|
|
||||||
mdast-util-to-hast@13.2.1:
|
|
||||||
dependencies:
|
|
||||||
'@types/hast': 3.0.4
|
|
||||||
'@types/mdast': 4.0.4
|
|
||||||
'@ungap/structured-clone': 1.3.0
|
|
||||||
devlop: 1.1.0
|
|
||||||
micromark-util-sanitize-uri: 2.0.1
|
|
||||||
trim-lines: 3.0.1
|
|
||||||
unist-util-position: 5.0.0
|
|
||||||
unist-util-visit: 5.1.0
|
|
||||||
vfile: 6.0.3
|
|
||||||
|
|
||||||
mdast-util-to-markdown@2.1.2:
|
|
||||||
dependencies:
|
|
||||||
'@types/mdast': 4.0.4
|
|
||||||
'@types/unist': 3.0.3
|
|
||||||
longest-streak: 3.1.0
|
|
||||||
mdast-util-phrasing: 4.1.0
|
|
||||||
mdast-util-to-string: 4.0.0
|
|
||||||
micromark-util-classify-character: 2.0.1
|
|
||||||
micromark-util-decode-string: 2.0.1
|
|
||||||
unist-util-visit: 5.1.0
|
|
||||||
zwitch: 2.0.4
|
|
||||||
|
|
||||||
mdast-util-to-string@4.0.0:
|
|
||||||
dependencies:
|
|
||||||
'@types/mdast': 4.0.4
|
|
||||||
|
|
||||||
mdn-data@2.12.2: {}
|
mdn-data@2.12.2: {}
|
||||||
|
|
||||||
micromark-core-commonmark@2.0.3:
|
|
||||||
dependencies:
|
|
||||||
decode-named-character-reference: 1.3.0
|
|
||||||
devlop: 1.1.0
|
|
||||||
micromark-factory-destination: 2.0.1
|
|
||||||
micromark-factory-label: 2.0.1
|
|
||||||
micromark-factory-space: 2.0.1
|
|
||||||
micromark-factory-title: 2.0.1
|
|
||||||
micromark-factory-whitespace: 2.0.1
|
|
||||||
micromark-util-character: 2.1.1
|
|
||||||
micromark-util-chunked: 2.0.1
|
|
||||||
micromark-util-classify-character: 2.0.1
|
|
||||||
micromark-util-html-tag-name: 2.0.1
|
|
||||||
micromark-util-normalize-identifier: 2.0.1
|
|
||||||
micromark-util-resolve-all: 2.0.1
|
|
||||||
micromark-util-subtokenize: 2.1.0
|
|
||||||
micromark-util-symbol: 2.0.1
|
|
||||||
micromark-util-types: 2.0.2
|
|
||||||
|
|
||||||
micromark-factory-destination@2.0.1:
|
|
||||||
dependencies:
|
|
||||||
micromark-util-character: 2.1.1
|
|
||||||
micromark-util-symbol: 2.0.1
|
|
||||||
micromark-util-types: 2.0.2
|
|
||||||
|
|
||||||
micromark-factory-label@2.0.1:
|
|
||||||
dependencies:
|
|
||||||
devlop: 1.1.0
|
|
||||||
micromark-util-character: 2.1.1
|
|
||||||
micromark-util-symbol: 2.0.1
|
|
||||||
micromark-util-types: 2.0.2
|
|
||||||
|
|
||||||
micromark-factory-space@2.0.1:
|
|
||||||
dependencies:
|
|
||||||
micromark-util-character: 2.1.1
|
|
||||||
micromark-util-types: 2.0.2
|
|
||||||
|
|
||||||
micromark-factory-title@2.0.1:
|
|
||||||
dependencies:
|
|
||||||
micromark-factory-space: 2.0.1
|
|
||||||
micromark-util-character: 2.1.1
|
|
||||||
micromark-util-symbol: 2.0.1
|
|
||||||
micromark-util-types: 2.0.2
|
|
||||||
|
|
||||||
micromark-factory-whitespace@2.0.1:
|
|
||||||
dependencies:
|
|
||||||
micromark-factory-space: 2.0.1
|
|
||||||
micromark-util-character: 2.1.1
|
|
||||||
micromark-util-symbol: 2.0.1
|
|
||||||
micromark-util-types: 2.0.2
|
|
||||||
|
|
||||||
micromark-util-character@2.1.1:
|
|
||||||
dependencies:
|
|
||||||
micromark-util-symbol: 2.0.1
|
|
||||||
micromark-util-types: 2.0.2
|
|
||||||
|
|
||||||
micromark-util-chunked@2.0.1:
|
|
||||||
dependencies:
|
|
||||||
micromark-util-symbol: 2.0.1
|
|
||||||
|
|
||||||
micromark-util-classify-character@2.0.1:
|
|
||||||
dependencies:
|
|
||||||
micromark-util-character: 2.1.1
|
|
||||||
micromark-util-symbol: 2.0.1
|
|
||||||
micromark-util-types: 2.0.2
|
|
||||||
|
|
||||||
micromark-util-combine-extensions@2.0.1:
|
|
||||||
dependencies:
|
|
||||||
micromark-util-chunked: 2.0.1
|
|
||||||
micromark-util-types: 2.0.2
|
|
||||||
|
|
||||||
micromark-util-decode-numeric-character-reference@2.0.2:
|
|
||||||
dependencies:
|
|
||||||
micromark-util-symbol: 2.0.1
|
|
||||||
|
|
||||||
micromark-util-decode-string@2.0.1:
|
|
||||||
dependencies:
|
|
||||||
decode-named-character-reference: 1.3.0
|
|
||||||
micromark-util-character: 2.1.1
|
|
||||||
micromark-util-decode-numeric-character-reference: 2.0.2
|
|
||||||
micromark-util-symbol: 2.0.1
|
|
||||||
|
|
||||||
micromark-util-encode@2.0.1: {}
|
|
||||||
|
|
||||||
micromark-util-html-tag-name@2.0.1: {}
|
|
||||||
|
|
||||||
micromark-util-normalize-identifier@2.0.1:
|
|
||||||
dependencies:
|
|
||||||
micromark-util-symbol: 2.0.1
|
|
||||||
|
|
||||||
micromark-util-resolve-all@2.0.1:
|
|
||||||
dependencies:
|
|
||||||
micromark-util-types: 2.0.2
|
|
||||||
|
|
||||||
micromark-util-sanitize-uri@2.0.1:
|
|
||||||
dependencies:
|
|
||||||
micromark-util-character: 2.1.1
|
|
||||||
micromark-util-encode: 2.0.1
|
|
||||||
micromark-util-symbol: 2.0.1
|
|
||||||
|
|
||||||
micromark-util-subtokenize@2.1.0:
|
|
||||||
dependencies:
|
|
||||||
devlop: 1.1.0
|
|
||||||
micromark-util-chunked: 2.0.1
|
|
||||||
micromark-util-symbol: 2.0.1
|
|
||||||
micromark-util-types: 2.0.2
|
|
||||||
|
|
||||||
micromark-util-symbol@2.0.1: {}
|
|
||||||
|
|
||||||
micromark-util-types@2.0.2: {}
|
|
||||||
|
|
||||||
micromark@4.0.2:
|
|
||||||
dependencies:
|
|
||||||
'@types/debug': 4.1.12
|
|
||||||
debug: 4.4.3
|
|
||||||
decode-named-character-reference: 1.3.0
|
|
||||||
devlop: 1.1.0
|
|
||||||
micromark-core-commonmark: 2.0.3
|
|
||||||
micromark-factory-space: 2.0.1
|
|
||||||
micromark-util-character: 2.1.1
|
|
||||||
micromark-util-chunked: 2.0.1
|
|
||||||
micromark-util-combine-extensions: 2.0.1
|
|
||||||
micromark-util-decode-numeric-character-reference: 2.0.2
|
|
||||||
micromark-util-encode: 2.0.1
|
|
||||||
micromark-util-normalize-identifier: 2.0.1
|
|
||||||
micromark-util-resolve-all: 2.0.1
|
|
||||||
micromark-util-sanitize-uri: 2.0.1
|
|
||||||
micromark-util-subtokenize: 2.1.0
|
|
||||||
micromark-util-symbol: 2.0.1
|
|
||||||
micromark-util-types: 2.0.2
|
|
||||||
transitivePeerDependencies:
|
|
||||||
- supports-color
|
|
||||||
|
|
||||||
ms@2.1.3: {}
|
ms@2.1.3: {}
|
||||||
|
|
||||||
nanoid@3.3.11: {}
|
nanoid@3.3.11: {}
|
||||||
@ -3407,8 +2884,6 @@ snapshots:
|
|||||||
ansi-styles: 5.2.0
|
ansi-styles: 5.2.0
|
||||||
react-is: 17.0.2
|
react-is: 17.0.2
|
||||||
|
|
||||||
property-information@7.1.0: {}
|
|
||||||
|
|
||||||
punycode@2.3.1: {}
|
punycode@2.3.1: {}
|
||||||
|
|
||||||
react-dom@19.2.4(react@19.2.4):
|
react-dom@19.2.4(react@19.2.4):
|
||||||
@ -3434,38 +2909,6 @@ snapshots:
|
|||||||
tiny-invariant: 1.3.3
|
tiny-invariant: 1.3.3
|
||||||
tslib: 2.8.1
|
tslib: 2.8.1
|
||||||
|
|
||||||
remark-html@16.0.1:
|
|
||||||
dependencies:
|
|
||||||
'@types/mdast': 4.0.4
|
|
||||||
hast-util-sanitize: 5.0.2
|
|
||||||
hast-util-to-html: 9.0.5
|
|
||||||
mdast-util-to-hast: 13.2.1
|
|
||||||
unified: 11.0.5
|
|
||||||
|
|
||||||
remark-parse@11.0.0:
|
|
||||||
dependencies:
|
|
||||||
'@types/mdast': 4.0.4
|
|
||||||
mdast-util-from-markdown: 2.0.2
|
|
||||||
micromark-util-types: 2.0.2
|
|
||||||
unified: 11.0.5
|
|
||||||
transitivePeerDependencies:
|
|
||||||
- supports-color
|
|
||||||
|
|
||||||
remark-stringify@11.0.0:
|
|
||||||
dependencies:
|
|
||||||
'@types/mdast': 4.0.4
|
|
||||||
mdast-util-to-markdown: 2.1.2
|
|
||||||
unified: 11.0.5
|
|
||||||
|
|
||||||
remark@15.0.1:
|
|
||||||
dependencies:
|
|
||||||
'@types/mdast': 4.0.4
|
|
||||||
remark-parse: 11.0.0
|
|
||||||
remark-stringify: 11.0.0
|
|
||||||
unified: 11.0.5
|
|
||||||
transitivePeerDependencies:
|
|
||||||
- supports-color
|
|
||||||
|
|
||||||
require-from-string@2.0.2: {}
|
require-from-string@2.0.2: {}
|
||||||
|
|
||||||
resolve-pkg-maps@1.0.0: {}
|
resolve-pkg-maps@1.0.0: {}
|
||||||
@ -3507,11 +2950,6 @@ snapshots:
|
|||||||
|
|
||||||
scheduler@0.27.0: {}
|
scheduler@0.27.0: {}
|
||||||
|
|
||||||
section-matter@1.0.0:
|
|
||||||
dependencies:
|
|
||||||
extend-shallow: 2.0.1
|
|
||||||
kind-of: 6.0.3
|
|
||||||
|
|
||||||
semver@6.3.1: {}
|
semver@6.3.1: {}
|
||||||
|
|
||||||
seroval-plugins@1.5.0(seroval@1.5.0):
|
seroval-plugins@1.5.0(seroval@1.5.0):
|
||||||
@ -3536,21 +2974,10 @@ snapshots:
|
|||||||
|
|
||||||
source-map@0.7.6: {}
|
source-map@0.7.6: {}
|
||||||
|
|
||||||
space-separated-tokens@2.0.2: {}
|
|
||||||
|
|
||||||
sprintf-js@1.0.3: {}
|
|
||||||
|
|
||||||
stackback@0.0.2: {}
|
stackback@0.0.2: {}
|
||||||
|
|
||||||
std-env@3.10.0: {}
|
std-env@3.10.0: {}
|
||||||
|
|
||||||
stringify-entities@4.0.4:
|
|
||||||
dependencies:
|
|
||||||
character-entities-html4: 2.1.0
|
|
||||||
character-entities-legacy: 3.0.0
|
|
||||||
|
|
||||||
strip-bom-string@1.0.0: {}
|
|
||||||
|
|
||||||
strip-literal@3.1.0:
|
strip-literal@3.1.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
js-tokens: 9.0.1
|
js-tokens: 9.0.1
|
||||||
@ -3598,10 +3025,6 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
punycode: 2.3.1
|
punycode: 2.3.1
|
||||||
|
|
||||||
trim-lines@3.0.1: {}
|
|
||||||
|
|
||||||
trough@2.2.0: {}
|
|
||||||
|
|
||||||
tslib@2.8.1: {}
|
tslib@2.8.1: {}
|
||||||
|
|
||||||
tsx@4.21.0:
|
tsx@4.21.0:
|
||||||
@ -3615,39 +3038,6 @@ snapshots:
|
|||||||
|
|
||||||
undici-types@6.21.0: {}
|
undici-types@6.21.0: {}
|
||||||
|
|
||||||
unified@11.0.5:
|
|
||||||
dependencies:
|
|
||||||
'@types/unist': 3.0.3
|
|
||||||
bail: 2.0.2
|
|
||||||
devlop: 1.1.0
|
|
||||||
extend: 3.0.2
|
|
||||||
is-plain-obj: 4.1.0
|
|
||||||
trough: 2.2.0
|
|
||||||
vfile: 6.0.3
|
|
||||||
|
|
||||||
unist-util-is@6.0.1:
|
|
||||||
dependencies:
|
|
||||||
'@types/unist': 3.0.3
|
|
||||||
|
|
||||||
unist-util-position@5.0.0:
|
|
||||||
dependencies:
|
|
||||||
'@types/unist': 3.0.3
|
|
||||||
|
|
||||||
unist-util-stringify-position@4.0.0:
|
|
||||||
dependencies:
|
|
||||||
'@types/unist': 3.0.3
|
|
||||||
|
|
||||||
unist-util-visit-parents@6.0.2:
|
|
||||||
dependencies:
|
|
||||||
'@types/unist': 3.0.3
|
|
||||||
unist-util-is: 6.0.1
|
|
||||||
|
|
||||||
unist-util-visit@5.1.0:
|
|
||||||
dependencies:
|
|
||||||
'@types/unist': 3.0.3
|
|
||||||
unist-util-is: 6.0.1
|
|
||||||
unist-util-visit-parents: 6.0.2
|
|
||||||
|
|
||||||
unplugin@2.3.11:
|
unplugin@2.3.11:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@jridgewell/remapping': 2.3.5
|
'@jridgewell/remapping': 2.3.5
|
||||||
@ -3667,16 +3057,6 @@ snapshots:
|
|||||||
|
|
||||||
util-deprecate@1.0.2: {}
|
util-deprecate@1.0.2: {}
|
||||||
|
|
||||||
vfile-message@4.0.3:
|
|
||||||
dependencies:
|
|
||||||
'@types/unist': 3.0.3
|
|
||||||
unist-util-stringify-position: 4.0.0
|
|
||||||
|
|
||||||
vfile@6.0.3:
|
|
||||||
dependencies:
|
|
||||||
'@types/unist': 3.0.3
|
|
||||||
vfile-message: 4.0.3
|
|
||||||
|
|
||||||
vite-node@3.2.4(@types/node@22.19.8)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0):
|
vite-node@3.2.4(@types/node@22.19.8)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0):
|
||||||
dependencies:
|
dependencies:
|
||||||
cac: 6.7.14
|
cac: 6.7.14
|
||||||
@ -3791,5 +3171,3 @@ snapshots:
|
|||||||
zod@3.25.76: {}
|
zod@3.25.76: {}
|
||||||
|
|
||||||
zod@4.3.6: {}
|
zod@4.3.6: {}
|
||||||
|
|
||||||
zwitch@2.0.4: {}
|
|
||||||
|
|||||||
@ -1,49 +0,0 @@
|
|||||||
// scripts/build-posts.js
|
|
||||||
import fs from "fs";
|
|
||||||
import path from "path";
|
|
||||||
import matter from "gray-matter";
|
|
||||||
import { remark } from "remark";
|
|
||||||
import html from "remark-html";
|
|
||||||
import { fileURLToPath } from "url";
|
|
||||||
|
|
||||||
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
||||||
const postsDirectory = path.join(__dirname, "../src/posts");
|
|
||||||
const outputFile = path.join(__dirname, "../src/generated/posts.json");
|
|
||||||
|
|
||||||
async function buildPosts() {
|
|
||||||
const filenames = fs.readdirSync(postsDirectory);
|
|
||||||
|
|
||||||
const posts = await Promise.all(
|
|
||||||
filenames
|
|
||||||
.filter((name) => name.endsWith(".md"))
|
|
||||||
.map(async (filename) => {
|
|
||||||
const filePath = path.join(postsDirectory, filename);
|
|
||||||
const fileContents = fs.readFileSync(filePath, "utf8");
|
|
||||||
const { data, content } = matter(fileContents);
|
|
||||||
|
|
||||||
const processedContent = await remark().use(html).process(content);
|
|
||||||
|
|
||||||
const slug = data.slug || filename.replace(".md", "");
|
|
||||||
|
|
||||||
return {
|
|
||||||
slug,
|
|
||||||
title: data.title,
|
|
||||||
date: data.date,
|
|
||||||
description: data.description,
|
|
||||||
contentHtml: processedContent.toString(),
|
|
||||||
};
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
|
|
||||||
// Ensure directory exists
|
|
||||||
const outputDir = path.dirname(outputFile);
|
|
||||||
if (!fs.existsSync(outputDir)) {
|
|
||||||
fs.mkdirSync(outputDir, { recursive: true });
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write to JSON file
|
|
||||||
fs.writeFileSync(outputFile, JSON.stringify(posts, null, 2));
|
|
||||||
console.log(`✅ Built ${posts.length} posts to ${outputFile}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
buildPosts().catch(console.error);
|
|
||||||
@ -1,19 +0,0 @@
|
|||||||
import postsData from "@/generated/posts.json";
|
|
||||||
import type { Post, PostMeta } from "@/types/posts";
|
|
||||||
|
|
||||||
const allPosts: Post[] = postsData as Post[];
|
|
||||||
|
|
||||||
export function getAllPosts(): PostMeta[] {
|
|
||||||
return allPosts
|
|
||||||
.map(({ slug, title, date, description }) => ({
|
|
||||||
slug,
|
|
||||||
title,
|
|
||||||
date,
|
|
||||||
description,
|
|
||||||
}))
|
|
||||||
.sort((a, b) => new Date(b.date).getTime() - new Date(a.date).getTime());
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getPostBySlug(slug: string): Post | null {
|
|
||||||
return allPosts.find((post) => post.slug === slug) || null;
|
|
||||||
}
|
|
||||||
@ -1,222 +0,0 @@
|
|||||||
---
|
|
||||||
title: "Advanced Authorization in NestJS"
|
|
||||||
date: "2025-04-05"
|
|
||||||
description: "Implementing advanced authorization in NestJS using roles, permissions, actions, and resources for fine-grained access control."
|
|
||||||
slug: "advanced-authorization-in-nestjs"
|
|
||||||
---
|
|
||||||
|
|
||||||
In the [previous post](/blog/nestjs-role-based-access-control), we implemented a simple yet powerful Role-Based Access Control (RBAC) system in NestJS using guards and decorators. While that setup works great for small to medium applications, real-world systems often require more control over what users can do and where they can do it.
|
|
||||||
|
|
||||||
That's where Policy-Based Access Control (PBAC) steps in. Think of PBAC as RBAC's smarter cousin—it gives you fine-grained control at the action and resource level. Today, we're combining both of them for a solid, flexible, and scalable auth system.
|
|
||||||
|
|
||||||
## Why Go Beyond Basic RBAC?
|
|
||||||
|
|
||||||
RBAC is simple and intuitive—you assign users to roles (e.g., `admin`, `user`, `manager`), and those roles grant access to routes or resources. However, problems arise when:
|
|
||||||
- You need to allow `admin` to edit settings, but only allow them to read user data.
|
|
||||||
- You want `manager` to view reports but not update anything.
|
|
||||||
- You need flexibility to define custom permissions without rewriting a lot of code.
|
|
||||||
|
|
||||||
By introducing permissions, we can map roles to actions (like `CREATE`, `READ`, `UPDATE`, `DELETE`) on specific resources (like `ADMIN_SETTINGS`, `COURSE`, `USER_PROFILE`). This allows for declarative, readable, and maintainable access control.
|
|
||||||
|
|
||||||
Instead of scattering checks across your code, you define them once, assign them to roles, and the rest of the app can rely on centralized logic for checking access. This reduces duplication, prevents errors, and gives your team confidence in how access is managed across the system.
|
|
||||||
|
|
||||||
## 1. Define the Authorization Data Model
|
|
||||||
|
|
||||||
We'll begin by creating a flexible schema in Prisma for this approach.
|
|
||||||
|
|
||||||
You can use whatever ORM, Query Builder or what you prefer. Just do SQL how you're most comfortable with.
|
|
||||||
|
|
||||||
```prisma
|
|
||||||
enum PermissionAction {
|
|
||||||
READ
|
|
||||||
CREATE
|
|
||||||
UPDATE
|
|
||||||
DELETE
|
|
||||||
}
|
|
||||||
|
|
||||||
enum PermissionResource {
|
|
||||||
ADMIN_SETTINGS
|
|
||||||
}
|
|
||||||
|
|
||||||
enum UserType {
|
|
||||||
ADMIN
|
|
||||||
TEACHER
|
|
||||||
STUDENT
|
|
||||||
}
|
|
||||||
|
|
||||||
model Role {
|
|
||||||
id String @id @default(uuid())
|
|
||||||
name String @unique
|
|
||||||
users User[]
|
|
||||||
permissions Permission[] @relation("RoleToPermission")
|
|
||||||
createdAt DateTime @default(now())
|
|
||||||
updatedAt DateTime @updatedAt
|
|
||||||
}
|
|
||||||
|
|
||||||
model Permission {
|
|
||||||
id String @id @default(uuid())
|
|
||||||
actions PermissionAction[]
|
|
||||||
resource PermissionResource
|
|
||||||
roleId String
|
|
||||||
role Role @relation(fields: [roleId], references: [id], name: "RoleToPermission")
|
|
||||||
createdAt DateTime @default(now())
|
|
||||||
updatedAt DateTime @updatedAt
|
|
||||||
}
|
|
||||||
|
|
||||||
model User {
|
|
||||||
id String @id @default(uuid())
|
|
||||||
name String
|
|
||||||
email String @unique
|
|
||||||
username String @unique
|
|
||||||
password String
|
|
||||||
roleId String?
|
|
||||||
role Role? @relation(fields: [roleId], references: [id])
|
|
||||||
createdAt DateTime @default(now())
|
|
||||||
updatedAt DateTime @updatedAt
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
This schema defines a relationship between users, roles, and the permissions assigned to those roles. The `Permission` model connects a role to specific `actions` it can perform on a given `resource`. You can easily extend this to include new resources or actions as your application grows.
|
|
||||||
|
|
||||||
A nice benefit of this setup is that you don't need to hardcode permissions in your codebase. You can manage them in the database and even build an admin panel later to assign and change them dynamically.
|
|
||||||
|
|
||||||
## 2. The Permissions Decorator
|
|
||||||
|
|
||||||
From the [previous post](/blog/nestjs-role-based-access-control) we saw how to use decorators. We will create a `@Permissions` decorator here to attach the necessary auth metadata to routes.
|
|
||||||
|
|
||||||
Decorators in NestJS are a powerful way to declare metadata that can later be accessed by guards. This keeps your controller methods clean and expressive.
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
import { SetMetadata } from '@nestjs/common';
|
|
||||||
import { PermissionAction, PermissionResource } from '@prisma/client';
|
|
||||||
|
|
||||||
export const PERMISSIONS_KEY = 'permissions';
|
|
||||||
|
|
||||||
export const Permissions = (permissions: {
|
|
||||||
resource: PermissionResource;
|
|
||||||
actions: PermissionAction[];
|
|
||||||
}[]) => SetMetadata(PERMISSIONS_KEY, permissions);
|
|
||||||
```
|
|
||||||
|
|
||||||
Now when defining a controller method, you can do something like:
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
@Permissions([
|
|
||||||
{ resource: PermissionResource.ADMIN_SETTINGS, actions: [PermissionAction.READ] },
|
|
||||||
])
|
|
||||||
@Get('settings')
|
|
||||||
getSettings() {
|
|
||||||
return this.settingsService.getSettings();
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
This keeps your route logic clean while still ensuring strict access control.
|
|
||||||
|
|
||||||
## 3. The Authorization Guard
|
|
||||||
|
|
||||||
Now let's build a guard that checks whether the current user has the required permission to access a route. This guard will extract the metadata from the `@Permissions()` decorator and compare it with the permissions granted to the user's role.
|
|
||||||
|
|
||||||
Guards in NestJS are classes that implement the `CanActivate` interface and determine whether a request should proceed or not. Here's how you might implement a robust authorization guard:
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
import {
|
|
||||||
CanActivate,
|
|
||||||
ExecutionContext,
|
|
||||||
ForbiddenException,
|
|
||||||
Injectable,
|
|
||||||
UnauthorizedException,
|
|
||||||
} from '@nestjs/common';
|
|
||||||
import { Reflector } from '@nestjs/core';
|
|
||||||
import { AuthService } from 'src/auth/auth.service';
|
|
||||||
import { PERMISSIONS_KEY } from 'src/auth/decorators/permissions.decorator';
|
|
||||||
import { RequestWithUser } from 'src/auth/types';
|
|
||||||
import { PermissionDto } from 'src/roles/dto/request.dto';
|
|
||||||
|
|
||||||
@Injectable()
|
|
||||||
export class AuthorizationGuard implements CanActivate {
|
|
||||||
constructor(
|
|
||||||
private readonly reflector: Reflector,
|
|
||||||
private readonly authService: AuthService,
|
|
||||||
) {}
|
|
||||||
|
|
||||||
async canActivate(context: ExecutionContext): Promise<boolean> {
|
|
||||||
const request = context.switchToHttp().getRequest<RequestWithUser>();
|
|
||||||
|
|
||||||
if (!request.user.sub) throw new UnauthorizedException();
|
|
||||||
|
|
||||||
const routePermissions: PermissionDto[] = this.reflector.getAllAndOverride(
|
|
||||||
PERMISSIONS_KEY,
|
|
||||||
[context.getHandler(), context.getClass()],
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!routePermissions) return true;
|
|
||||||
|
|
||||||
try {
|
|
||||||
const userPermissions = await this.authService.getUserPermissions(
|
|
||||||
request.user.sub,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!userPermissions) throw new ForbiddenException();
|
|
||||||
|
|
||||||
for (const routePermission of routePermissions) {
|
|
||||||
const userPermission = userPermissions.find(
|
|
||||||
(perm) => perm.resource === routePermission.resource,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!userPermission) throw new ForbiddenException();
|
|
||||||
|
|
||||||
const allActionsAvailable = routePermission.actions.every(
|
|
||||||
(requiredAction) => userPermission.actions.includes(requiredAction),
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!allActionsAvailable) throw new ForbiddenException();
|
|
||||||
}
|
|
||||||
} catch {
|
|
||||||
throw new ForbiddenException();
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
This guard ensures that the current user's role includes the appropriate permissions to perform the requested action. If not, it throws a `ForbiddenException` and blocks access.
|
|
||||||
|
|
||||||
## Applying It to Real Routes
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
@Controller('settings/admin')
|
|
||||||
export class AdminSettingsController {
|
|
||||||
constructor(private readonly adminSettingsService: AdminSettingsService) {}
|
|
||||||
|
|
||||||
@UseGuards(AuthenticationGuard, AuthorizationGuard)
|
|
||||||
@Permissions([
|
|
||||||
{
|
|
||||||
resource: PermissionResource.ADMIN_SETTINGS,
|
|
||||||
actions: [PermissionAction.READ],
|
|
||||||
},
|
|
||||||
])
|
|
||||||
@Get('general')
|
|
||||||
getGeneralSettings() {
|
|
||||||
return this.adminSettingsService.getGeneralSettings();
|
|
||||||
}
|
|
||||||
|
|
||||||
@UseGuards(AuthenticationGuard, AuthorizationGuard)
|
|
||||||
@Permissions([
|
|
||||||
{
|
|
||||||
resource: PermissionResource.ADMIN_SETTINGS,
|
|
||||||
actions: [PermissionAction.UPDATE],
|
|
||||||
},
|
|
||||||
])
|
|
||||||
@Put('general')
|
|
||||||
updateGeneralSettings(@Body() dto: UpdateGeneralSettingsDto) {
|
|
||||||
return this.adminSettingsService.updateGeneralSettings(dto);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
With this setup, even admins can't update settings unless they specifically have the `UPDATE` action on `ADMIN_SETTINGS`.
|
|
||||||
|
|
||||||
## Conclusion
|
|
||||||
|
|
||||||
A simple `@Roles()` check might be enough to get started, but complex applications need granular and maintainable authorization logic. Always make sure your auth scales with you. Don't go super advanced when you don't need it but also never compromise your app by going so basic.
|
|
||||||
@ -1,157 +0,0 @@
|
|||||||
---
|
|
||||||
title: "Handling Role-Based Access Control in NestJS"
|
|
||||||
date: "2025-04-01"
|
|
||||||
description: "Learn how to implement RBAC in NestJS using decorators, guards, and JWT authentication."
|
|
||||||
slug: "nestjs-role-based-access-control"
|
|
||||||
---
|
|
||||||
|
|
||||||
Role-Based Access Control (RBAC) is a common approach to managing permissions in applications, ensuring that only authorized users can access specific routes or perform certain actions. In this post, we'll explore how to implement RBAC in a NestJS application using guards and decorators.
|
|
||||||
|
|
||||||
## TL;DR
|
|
||||||
|
|
||||||
Even though using a fully managed auth provider like Clerk is easy and probably saves time, learning how to do authentication from scratch is important for your learning experience.
|
|
||||||
|
|
||||||
This is not a beginners guide to RBAC but rather an overview of the overall implementation.
|
|
||||||
|
|
||||||
## 1. Setting Up User Roles
|
|
||||||
|
|
||||||
First, define the roles available in your application using an enum:
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
export enum Role {
|
|
||||||
Admin = 'admin',
|
|
||||||
User = 'user',
|
|
||||||
Manager = 'manager',
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
This enum will help us enforce role-based access at different levels of the application.
|
|
||||||
|
|
||||||
## 2. Creating a Roles Decorator
|
|
||||||
|
|
||||||
NestJS allows us to attach metadata to routes using decorators. Let's create a custom `@Roles()` decorator:
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
import { SetMetadata } from '@nestjs/common';
|
|
||||||
import { Role } from '../enums/role.enum';
|
|
||||||
|
|
||||||
export const ROLES_KEY = 'roles';
|
|
||||||
export const Roles = (...roles: Role[]) => SetMetadata(ROLES_KEY, roles);
|
|
||||||
```
|
|
||||||
|
|
||||||
This decorator will allow us to specify roles for each route, which our guard will later check.
|
|
||||||
|
|
||||||
## 3. Implementing the Roles Guard
|
|
||||||
|
|
||||||
Now, let's create a `RolesGuard` that will check if a user has the required role before allowing access to a route.
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common';
|
|
||||||
import { Reflector } from '@nestjs/core';
|
|
||||||
import { ROLES_KEY } from '../decorators/roles.decorator';
|
|
||||||
import { Role } from '../enums/role.enum';
|
|
||||||
|
|
||||||
@Injectable()
|
|
||||||
export class RolesGuard implements CanActivate {
|
|
||||||
constructor(private reflector: Reflector) {}
|
|
||||||
|
|
||||||
canActivate(context: ExecutionContext): boolean {
|
|
||||||
const requiredRoles = this.reflector.getAllAndOverride<Role[]>(ROLES_KEY, [
|
|
||||||
context.getHandler(),
|
|
||||||
context.getClass(),
|
|
||||||
]);
|
|
||||||
|
|
||||||
if (!requiredRoles) {
|
|
||||||
return true; // If no roles are set, allow access
|
|
||||||
}
|
|
||||||
|
|
||||||
const { user } = context.switchToHttp().getRequest();
|
|
||||||
return user && user.roles?.some((role) => requiredRoles.includes(role));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
This guard extracts the roles from metadata and verifies if the current user has one of the required roles.
|
|
||||||
|
|
||||||
## 4. Applying RBAC to Routes
|
|
||||||
|
|
||||||
Now, let's secure routes using our `@Roles()` decorator and `RolesGuard`.
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
import { Controller, Get, UseGuards } from '@nestjs/common';
|
|
||||||
import { Roles } from '../decorators/roles.decorator';
|
|
||||||
import { RolesGuard } from '../guards/roles.guard';
|
|
||||||
import { Role } from '../enums/role.enum';
|
|
||||||
|
|
||||||
@Controller('users')
|
|
||||||
@UseGuards(RolesGuard)
|
|
||||||
export class UsersController {
|
|
||||||
@Get('admin')
|
|
||||||
@Roles(Role.Admin)
|
|
||||||
getAdminData() {
|
|
||||||
return 'This is only accessible to admins';
|
|
||||||
}
|
|
||||||
|
|
||||||
@Get('manager')
|
|
||||||
@Roles(Role.Manager, Role.Admin)
|
|
||||||
getManagerData() {
|
|
||||||
return 'This is accessible to managers and admins';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
With this setup:
|
|
||||||
- The `/users/admin` route is accessible only to Admin users.
|
|
||||||
- The `/users/manager` route is accessible to both Admin and Manager users.
|
|
||||||
|
|
||||||
## 5. Ensuring User Role in JWT Authentication
|
|
||||||
|
|
||||||
If you're using JWT authentication, ensure that user roles are included when signing the JWT:
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
const payload = { username: user.username, sub: user.id, roles: user.roles };
|
|
||||||
const token = this.jwtService.sign(payload);
|
|
||||||
```
|
|
||||||
|
|
||||||
When a user logs in, this ensures their roles are available for the `RolesGuard` to check.
|
|
||||||
|
|
||||||
In a real world application you want to setup a `JwtAuthGuard` to decode the `Bearer <TOKEN>` and get the roles then re-attach them to the request before the `RolesGuard` gets the request.
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
import { Controller, UseGuards } from '@nestjs/common';
|
|
||||||
import { JwtAuthGuard } from '../guards/jwt.guard';
|
|
||||||
import { RolesGuard } from '../guards/roles.guard';
|
|
||||||
|
|
||||||
@Controller('users')
|
|
||||||
@UseGuards(JwtAuthGuard, RolesGuard)
|
|
||||||
export class UsersController {}
|
|
||||||
```
|
|
||||||
|
|
||||||
## 6. Storing and Managing Roles in a Database
|
|
||||||
|
|
||||||
For a real-world application, user roles should be stored in a database. If you're using TypeORM, define your User entity like this:
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
import { Entity, Column, PrimaryGeneratedColumn } from 'typeorm';
|
|
||||||
import { Role } from '../enums/role.enum';
|
|
||||||
|
|
||||||
@Entity()
|
|
||||||
export class User {
|
|
||||||
@PrimaryGeneratedColumn()
|
|
||||||
id: number;
|
|
||||||
|
|
||||||
@Column()
|
|
||||||
username: string;
|
|
||||||
|
|
||||||
@Column({ type: 'enum', enum: Role, array: true, default: [Role.User] })
|
|
||||||
roles: Role[];
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Then, fetch the user and roles from the database inside your authentication logic.
|
|
||||||
|
|
||||||
Reading from the database is always an extra network trip and will add a couple of milliseconds to each request.
|
|
||||||
|
|
||||||
## Conclusion
|
|
||||||
|
|
||||||
By implementing RBAC in NestJS, we can ensure that only authorized users can access specific routes. This approach is flexible and scalable, allowing for fine-grained access control.
|
|
||||||
@ -14,8 +14,6 @@ import { Route as StackRouteImport } from './routes/stack'
|
|||||||
import { Route as ProjectsRouteImport } from './routes/projects'
|
import { Route as ProjectsRouteImport } from './routes/projects'
|
||||||
import { Route as ContactRouteImport } from './routes/contact'
|
import { Route as ContactRouteImport } from './routes/contact'
|
||||||
import { Route as IndexRouteImport } from './routes/index'
|
import { Route as IndexRouteImport } from './routes/index'
|
||||||
import { Route as BlogIndexRouteImport } from './routes/blog/index'
|
|
||||||
import { Route as BlogSlugRouteImport } from './routes/blog/$slug'
|
|
||||||
|
|
||||||
const WorkRoute = WorkRouteImport.update({
|
const WorkRoute = WorkRouteImport.update({
|
||||||
id: '/work',
|
id: '/work',
|
||||||
@ -42,16 +40,6 @@ const IndexRoute = IndexRouteImport.update({
|
|||||||
path: '/',
|
path: '/',
|
||||||
getParentRoute: () => rootRouteImport,
|
getParentRoute: () => rootRouteImport,
|
||||||
} as any)
|
} as any)
|
||||||
const BlogIndexRoute = BlogIndexRouteImport.update({
|
|
||||||
id: '/blog/',
|
|
||||||
path: '/blog/',
|
|
||||||
getParentRoute: () => rootRouteImport,
|
|
||||||
} as any)
|
|
||||||
const BlogSlugRoute = BlogSlugRouteImport.update({
|
|
||||||
id: '/blog/$slug',
|
|
||||||
path: '/blog/$slug',
|
|
||||||
getParentRoute: () => rootRouteImport,
|
|
||||||
} as any)
|
|
||||||
|
|
||||||
export interface FileRoutesByFullPath {
|
export interface FileRoutesByFullPath {
|
||||||
'/': typeof IndexRoute
|
'/': typeof IndexRoute
|
||||||
@ -59,8 +47,6 @@ export interface FileRoutesByFullPath {
|
|||||||
'/projects': typeof ProjectsRoute
|
'/projects': typeof ProjectsRoute
|
||||||
'/stack': typeof StackRoute
|
'/stack': typeof StackRoute
|
||||||
'/work': typeof WorkRoute
|
'/work': typeof WorkRoute
|
||||||
'/blog/$slug': typeof BlogSlugRoute
|
|
||||||
'/blog/': typeof BlogIndexRoute
|
|
||||||
}
|
}
|
||||||
export interface FileRoutesByTo {
|
export interface FileRoutesByTo {
|
||||||
'/': typeof IndexRoute
|
'/': typeof IndexRoute
|
||||||
@ -68,8 +54,6 @@ export interface FileRoutesByTo {
|
|||||||
'/projects': typeof ProjectsRoute
|
'/projects': typeof ProjectsRoute
|
||||||
'/stack': typeof StackRoute
|
'/stack': typeof StackRoute
|
||||||
'/work': typeof WorkRoute
|
'/work': typeof WorkRoute
|
||||||
'/blog/$slug': typeof BlogSlugRoute
|
|
||||||
'/blog': typeof BlogIndexRoute
|
|
||||||
}
|
}
|
||||||
export interface FileRoutesById {
|
export interface FileRoutesById {
|
||||||
__root__: typeof rootRouteImport
|
__root__: typeof rootRouteImport
|
||||||
@ -78,37 +62,13 @@ export interface FileRoutesById {
|
|||||||
'/projects': typeof ProjectsRoute
|
'/projects': typeof ProjectsRoute
|
||||||
'/stack': typeof StackRoute
|
'/stack': typeof StackRoute
|
||||||
'/work': typeof WorkRoute
|
'/work': typeof WorkRoute
|
||||||
'/blog/$slug': typeof BlogSlugRoute
|
|
||||||
'/blog/': typeof BlogIndexRoute
|
|
||||||
}
|
}
|
||||||
export interface FileRouteTypes {
|
export interface FileRouteTypes {
|
||||||
fileRoutesByFullPath: FileRoutesByFullPath
|
fileRoutesByFullPath: FileRoutesByFullPath
|
||||||
fullPaths:
|
fullPaths: '/' | '/contact' | '/projects' | '/stack' | '/work'
|
||||||
| '/'
|
|
||||||
| '/contact'
|
|
||||||
| '/projects'
|
|
||||||
| '/stack'
|
|
||||||
| '/work'
|
|
||||||
| '/blog/$slug'
|
|
||||||
| '/blog/'
|
|
||||||
fileRoutesByTo: FileRoutesByTo
|
fileRoutesByTo: FileRoutesByTo
|
||||||
to:
|
to: '/' | '/contact' | '/projects' | '/stack' | '/work'
|
||||||
| '/'
|
id: '__root__' | '/' | '/contact' | '/projects' | '/stack' | '/work'
|
||||||
| '/contact'
|
|
||||||
| '/projects'
|
|
||||||
| '/stack'
|
|
||||||
| '/work'
|
|
||||||
| '/blog/$slug'
|
|
||||||
| '/blog'
|
|
||||||
id:
|
|
||||||
| '__root__'
|
|
||||||
| '/'
|
|
||||||
| '/contact'
|
|
||||||
| '/projects'
|
|
||||||
| '/stack'
|
|
||||||
| '/work'
|
|
||||||
| '/blog/$slug'
|
|
||||||
| '/blog/'
|
|
||||||
fileRoutesById: FileRoutesById
|
fileRoutesById: FileRoutesById
|
||||||
}
|
}
|
||||||
export interface RootRouteChildren {
|
export interface RootRouteChildren {
|
||||||
@ -117,8 +77,6 @@ export interface RootRouteChildren {
|
|||||||
ProjectsRoute: typeof ProjectsRoute
|
ProjectsRoute: typeof ProjectsRoute
|
||||||
StackRoute: typeof StackRoute
|
StackRoute: typeof StackRoute
|
||||||
WorkRoute: typeof WorkRoute
|
WorkRoute: typeof WorkRoute
|
||||||
BlogSlugRoute: typeof BlogSlugRoute
|
|
||||||
BlogIndexRoute: typeof BlogIndexRoute
|
|
||||||
}
|
}
|
||||||
|
|
||||||
declare module '@tanstack/react-router' {
|
declare module '@tanstack/react-router' {
|
||||||
@ -158,20 +116,6 @@ declare module '@tanstack/react-router' {
|
|||||||
preLoaderRoute: typeof IndexRouteImport
|
preLoaderRoute: typeof IndexRouteImport
|
||||||
parentRoute: typeof rootRouteImport
|
parentRoute: typeof rootRouteImport
|
||||||
}
|
}
|
||||||
'/blog/': {
|
|
||||||
id: '/blog/'
|
|
||||||
path: '/blog'
|
|
||||||
fullPath: '/blog/'
|
|
||||||
preLoaderRoute: typeof BlogIndexRouteImport
|
|
||||||
parentRoute: typeof rootRouteImport
|
|
||||||
}
|
|
||||||
'/blog/$slug': {
|
|
||||||
id: '/blog/$slug'
|
|
||||||
path: '/blog/$slug'
|
|
||||||
fullPath: '/blog/$slug'
|
|
||||||
preLoaderRoute: typeof BlogSlugRouteImport
|
|
||||||
parentRoute: typeof rootRouteImport
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -181,8 +125,6 @@ const rootRouteChildren: RootRouteChildren = {
|
|||||||
ProjectsRoute: ProjectsRoute,
|
ProjectsRoute: ProjectsRoute,
|
||||||
StackRoute: StackRoute,
|
StackRoute: StackRoute,
|
||||||
WorkRoute: WorkRoute,
|
WorkRoute: WorkRoute,
|
||||||
BlogSlugRoute: BlogSlugRoute,
|
|
||||||
BlogIndexRoute: BlogIndexRoute,
|
|
||||||
}
|
}
|
||||||
export const routeTree = rootRouteImport
|
export const routeTree = rootRouteImport
|
||||||
._addFileChildren(rootRouteChildren)
|
._addFileChildren(rootRouteChildren)
|
||||||
|
|||||||
@ -1,43 +0,0 @@
|
|||||||
import { getPostBySlug } from "@/lib/posts";
|
|
||||||
import { createFileRoute, Link, notFound } from "@tanstack/react-router";
|
|
||||||
|
|
||||||
export const Route = createFileRoute("/blog/$slug")({
|
|
||||||
component: BlogPost,
|
|
||||||
loader: ({ params }) => {
|
|
||||||
const post = getPostBySlug(params.slug);
|
|
||||||
if (!post) throw notFound();
|
|
||||||
return { post };
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
function BlogPost() {
|
|
||||||
const { post } = Route.useLoaderData();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<Link to="/" className="text-sm">
|
|
||||||
← <span className="underline">home</span>
|
|
||||||
</Link>
|
|
||||||
|
|
||||||
<article className="mt-8">
|
|
||||||
<div className="space-y-2">
|
|
||||||
<h1 className="text-2xl font-semibold max-w-prose wrap-break-word">
|
|
||||||
{post.title}
|
|
||||||
</h1>
|
|
||||||
<p className="text-xs text-gray-600">{post.date}</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div
|
|
||||||
className="mt-8 prose prose-sm"
|
|
||||||
dangerouslySetInnerHTML={{ __html: post.contentHtml }}
|
|
||||||
/>
|
|
||||||
</article>
|
|
||||||
|
|
||||||
<div className="pt-5 mt-20 border-t border-gray-200">
|
|
||||||
<Link to="/blog" className="text-sm">
|
|
||||||
← <span className="underline">All Blogs</span>
|
|
||||||
</Link>
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@ -1,52 +0,0 @@
|
|||||||
import { getAllPosts } from "@/lib/posts";
|
|
||||||
import { createFileRoute, Link } from "@tanstack/react-router";
|
|
||||||
|
|
||||||
export const Route = createFileRoute("/blog/")({
|
|
||||||
component: Blog,
|
|
||||||
loader: () => {
|
|
||||||
const posts = getAllPosts();
|
|
||||||
return { posts };
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
function Blog() {
|
|
||||||
const { posts } = Route.useLoaderData();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<Link to="/" className="text-sm">
|
|
||||||
← <span className="underline">home</span>
|
|
||||||
</Link>
|
|
||||||
|
|
||||||
<div className="mt-8">
|
|
||||||
<h1 className="text-lg font-semibold">Blog</h1>
|
|
||||||
|
|
||||||
<div className="space-y-6 mt-5 ml-2 text-sm">
|
|
||||||
{posts.map((post) => (
|
|
||||||
<div key={post.slug}>
|
|
||||||
<Link
|
|
||||||
to="/blog/$slug"
|
|
||||||
params={{ slug: post.slug }}
|
|
||||||
className="block group"
|
|
||||||
>
|
|
||||||
<p className="font-semibold max-w-prose group-hover:underline">
|
|
||||||
{post.title}
|
|
||||||
</p>
|
|
||||||
<p className="text-gray-600 text-xs mt-1">{post.date}</p>
|
|
||||||
<p className="text-gray-700 max-w-prose mt-1">
|
|
||||||
{post.description}
|
|
||||||
</p>
|
|
||||||
</Link>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="pt-5 mt-20 border-t border-gray-200">
|
|
||||||
<p className="text-sm text-gray-600">
|
|
||||||
{posts.length} {posts.length === 1 ? "post" : "posts"}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@ -38,13 +38,6 @@ function Home() {
|
|||||||
</Link>
|
</Link>
|
||||||
: tools and tech I use
|
: tools and tech I use
|
||||||
</li>
|
</li>
|
||||||
<li>
|
|
||||||
→{" "}
|
|
||||||
<Link to="/blog" className="underline">
|
|
||||||
blog
|
|
||||||
</Link>
|
|
||||||
: longer writing
|
|
||||||
</li>
|
|
||||||
<li>
|
<li>
|
||||||
→{" "}
|
→{" "}
|
||||||
<Link to="/contact" className="underline">
|
<Link to="/contact" className="underline">
|
||||||
@ -58,12 +51,7 @@ function Home() {
|
|||||||
<div className="pt-5 mt-20 border-t border-gray-200">
|
<div className="pt-5 mt-20 border-t border-gray-200">
|
||||||
<p className="text-xs mb-2">Recent Changes</p>
|
<p className="text-xs mb-2">Recent Changes</p>
|
||||||
<ul className="space-y-1 text-sm">
|
<ul className="space-y-1 text-sm">
|
||||||
<li>
|
<li>2026-02-01 — Redesign portfolio</li>
|
||||||
2026-02-01 —{" "}
|
|
||||||
<Link to="." className="underline">
|
|
||||||
New post about X
|
|
||||||
</Link>
|
|
||||||
</li>
|
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
|
|||||||
@ -1,10 +0,0 @@
|
|||||||
export interface PostMeta {
|
|
||||||
slug: string;
|
|
||||||
title: string;
|
|
||||||
date: string;
|
|
||||||
description: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Post extends PostMeta {
|
|
||||||
contentHtml: string;
|
|
||||||
}
|
|
||||||
Loading…
Reference in New Issue
Block a user