From 327ade48f36c09ef6c189196b3b85445ce25afc1 Mon Sep 17 00:00:00 2001 From: danji90 Date: Thu, 21 Aug 2025 14:39:45 +0200 Subject: [PATCH 1/9] chore: force commit --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 6c10f32a..6e95b583 100644 --- a/.gitignore +++ b/.gitignore @@ -65,6 +65,7 @@ lib/data/spatial/forest_types_ne lib/data/spatial/forest_types_sg lib/data/spatial/forest_types_sh lib/data/spatial/forest_types_so +lib/data/spatial/forest_types_sz lib/data/spatial/forest_types_tg lib/data/spatial/forest_types_vd lib/data/spatial/forest_types_zh From 486b827e268c7624f976449f531afab4dc2d3ca8 Mon Sep 17 00:00:00 2001 From: danji90 Date: Thu, 21 Aug 2025 16:28:33 +0200 Subject: [PATCH 2/9] chore: set up next server for tile hosting --- lib/data/spatial/3-tile.sh | 2 +- lib/data/spatial/tiles/.gitignore | 1 - lib/data/spatial/tiles/vercel.json | 49 --- lib/data/spatial/tree-app-tiles/.gitignore | 6 + .../spatial/tree-app-tiles/next.config.js | 17 + lib/data/spatial/tree-app-tiles/package.json | 21 ++ .../tree-app-tiles/pages/api/[...path].ts | 32 ++ .../spatial/tree-app-tiles/pnpm-lock.yaml | 325 ++++++++++++++++++ lib/data/spatial/tree-app-tiles/tsconfig.json | 30 ++ lib/package.json | 4 +- 10 files changed, 434 insertions(+), 53 deletions(-) delete mode 100644 lib/data/spatial/tiles/.gitignore delete mode 100755 lib/data/spatial/tiles/vercel.json create mode 100644 lib/data/spatial/tree-app-tiles/.gitignore create mode 100644 lib/data/spatial/tree-app-tiles/next.config.js create mode 100644 lib/data/spatial/tree-app-tiles/package.json create mode 100644 lib/data/spatial/tree-app-tiles/pages/api/[...path].ts create mode 100644 lib/data/spatial/tree-app-tiles/pnpm-lock.yaml create mode 100644 lib/data/spatial/tree-app-tiles/tsconfig.json diff --git a/lib/data/spatial/3-tile.sh b/lib/data/spatial/3-tile.sh index f7f083af..44d0b0fe 100755 --- a/lib/data/spatial/3-tile.sh +++ b/lib/data/spatial/3-tile.sh @@ -13,7 +13,7 @@ _tile "forest_types" _tile "silver_fir_areas" echo "Joining tiles ..." -cd /data/spatial/tiles +cd /data/spatial/tree-app-tiles/tiles tile-join --force --maximum-zoom=12 --no-tile-size-limit -e "tree" altitudinal_zones_1995.mbtiles altitudinal_zones_2085_dry.mbtiles altitudinal_zones_2085_less_dry.mbtiles cantonal_boundaries.mbtiles forest_ecoregions.mbtiles forest_types.mbtiles silver_fir_areas.mbtiles rm altitudinal_zones_1995.mbtiles altitudinal_zones_2085_dry.mbtiles altitudinal_zones_2085_less_dry.mbtiles cantonal_boundaries.mbtiles forest_ecoregions.mbtiles forest_types.mbtiles silver_fir_areas.mbtiles find tree -name '*.pbf' > tiles.txt \ No newline at end of file diff --git a/lib/data/spatial/tiles/.gitignore b/lib/data/spatial/tiles/.gitignore deleted file mode 100644 index e985853e..00000000 --- a/lib/data/spatial/tiles/.gitignore +++ /dev/null @@ -1 +0,0 @@ -.vercel diff --git a/lib/data/spatial/tiles/vercel.json b/lib/data/spatial/tiles/vercel.json deleted file mode 100755 index ee17b6d2..00000000 --- a/lib/data/spatial/tiles/vercel.json +++ /dev/null @@ -1,49 +0,0 @@ -{ - "headers": [ - { - "source": "/(.*).json", - "headers": [ - { - "key": "Access-Control-Allow-Origin", - "value": "*" - } - ] - }, - { - "source": "/(.*).pbf", - "headers": [ - { - "key": "Access-Control-Allow-Origin", - "value": "*" - } - ] - }, - { - "source": "/(.*).pdf", - "headers": [ - { - "key": "Content-Disposition", - "value": "inline" - } - ] - }, - { - "source": "/(.*).txt", - "headers": [ - { - "key": "Access-Control-Allow-Origin", - "value": "*" - } - ] - }, - { - "source": "/tree/(.*).pbf", - "headers": [ - { - "key": "Content-Encoding", - "value": "gzip" - } - ] - } - ] -} diff --git a/lib/data/spatial/tree-app-tiles/.gitignore b/lib/data/spatial/tree-app-tiles/.gitignore new file mode 100644 index 00000000..b10c6384 --- /dev/null +++ b/lib/data/spatial/tree-app-tiles/.gitignore @@ -0,0 +1,6 @@ +.vercel +node_modules +public/tiles.txt +tiles/fonts +tiles/tree +.next \ No newline at end of file diff --git a/lib/data/spatial/tree-app-tiles/next.config.js b/lib/data/spatial/tree-app-tiles/next.config.js new file mode 100644 index 00000000..a13727fa --- /dev/null +++ b/lib/data/spatial/tree-app-tiles/next.config.js @@ -0,0 +1,17 @@ +/** @type {import('next').NextConfig} */ +const nextConfig = { + async rewrites() { + return [ + { + source: '/tree/:path*', + destination: '/api/tree/:path*', + }, + { + source: '/fonts/:path*', + destination: '/api/fonts/:path*', + }, + ]; + }, +}; + +export default nextConfig; \ No newline at end of file diff --git a/lib/data/spatial/tree-app-tiles/package.json b/lib/data/spatial/tree-app-tiles/package.json new file mode 100644 index 00000000..9547b011 --- /dev/null +++ b/lib/data/spatial/tree-app-tiles/package.json @@ -0,0 +1,21 @@ +{ + "name": "tileserver", + "version": "1.0.0", + "private": true, + "type": "module", + "scripts": { + "dev": "next dev", + "build": "next build", + "start": "next start" + }, + "dependencies": { + "next": "14.2.0", + "react": "18.2.0", + "react-dom": "18.2.0" + }, + "devDependencies": { + "@types/node": "^24.3.0", + "@types/react": "^19.1.10", + "typescript": "^5.9.2" + } +} \ No newline at end of file diff --git a/lib/data/spatial/tree-app-tiles/pages/api/[...path].ts b/lib/data/spatial/tree-app-tiles/pages/api/[...path].ts new file mode 100644 index 00000000..49f12538 --- /dev/null +++ b/lib/data/spatial/tree-app-tiles/pages/api/[...path].ts @@ -0,0 +1,32 @@ +// pages/api/[...path].ts +import type { NextApiRequest, NextApiResponse } from "next"; +import fs from "fs"; +import path from "path"; + +export default function handler(req: NextApiRequest, res: NextApiResponse) { + try { + const requestedPath = (req.query.path as string[]).join("/"); + const filePath = path.join(process.cwd(), "tiles", requestedPath); + + if (!fs.existsSync(filePath)) { + res.status(404).end("Tile not found"); + return; + } + + res.setHeader("Content-Type", "application/vnd.mapbox-vector-tile"); + res.setHeader("Cache-Control", "public, max-age=31536000, immutable"); + res.setHeader("Access-Control-Allow-Origin", "*"); + res.setHeader("Access-Control-Allow-Headers", "*"); + + if (requestedPath.startsWith("tree/")) { + res.setHeader("Content-Type", "application/vnd.mapbox-vector-tile"); + res.setHeader("Content-Encoding", "gzip"); + } + + const readStream = fs.createReadStream(filePath); + readStream.pipe(res); + } catch (err) { + console.error(err); + res.status(500).end("Internal Server Error"); + } +} \ No newline at end of file diff --git a/lib/data/spatial/tree-app-tiles/pnpm-lock.yaml b/lib/data/spatial/tree-app-tiles/pnpm-lock.yaml new file mode 100644 index 00000000..88220d87 --- /dev/null +++ b/lib/data/spatial/tree-app-tiles/pnpm-lock.yaml @@ -0,0 +1,325 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + dependencies: + next: + specifier: 14.2.0 + version: 14.2.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + react: + specifier: 18.2.0 + version: 18.2.0 + react-dom: + specifier: 18.2.0 + version: 18.2.0(react@18.2.0) + devDependencies: + '@types/node': + specifier: ^24.3.0 + version: 24.3.0 + '@types/react': + specifier: ^19.1.10 + version: 19.1.10 + typescript: + specifier: ^5.9.2 + version: 5.9.2 + +packages: + + '@next/env@14.2.0': + resolution: {integrity: sha512-4+70ELtSbRtYUuyRpAJmKC8NHBW2x1HMje9KO2Xd7IkoyucmV9SjgO+qeWMC0JWkRQXgydv1O7yKOK8nu/rITQ==} + + '@next/swc-darwin-arm64@14.2.0': + resolution: {integrity: sha512-kHktLlw0AceuDnkVljJ/4lTJagLzDiO3klR1Fzl2APDFZ8r+aTxNaNcPmpp0xLMkgRwwk6sggYeqq0Rz9K4zzA==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [darwin] + + '@next/swc-darwin-x64@14.2.0': + resolution: {integrity: sha512-HFSDu7lb1U3RDxXNeKH3NGRR5KyTPBSUTuIOr9jXoAso7i76gNYvnTjbuzGVWt2X5izpH908gmOYWtI7un+JrA==} + engines: {node: '>= 10'} + cpu: [x64] + os: [darwin] + + '@next/swc-linux-arm64-gnu@14.2.0': + resolution: {integrity: sha512-iQsoWziO5ZMxDWZ4ZTCAc7hbJ1C9UDj/gATSqTaMjW2bJFwAsvf9UM79AKnljBl73uPZ+V0kH4rvnHTco4Ps2w==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + + '@next/swc-linux-arm64-musl@14.2.0': + resolution: {integrity: sha512-0JOk2uzLUt8fJK5LpsKKZa74zAch7bJjjgJzR9aOMs231AlE4gPYzsSm430ckZitjPGKeH5bgDZjqwqJQKIS2w==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + + '@next/swc-linux-x64-gnu@14.2.0': + resolution: {integrity: sha512-uYHkuTzX0NM6biKNp7hdKTf+BF0iMV254SxO0B8PgrQkxUBKGmk5ysHKB+FYBfdf9xei/t8OIKlXJs9ckD943A==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + + '@next/swc-linux-x64-musl@14.2.0': + resolution: {integrity: sha512-paN89nLs2dTBDtfXWty1/NVPit+q6ldwdktixYSVwiiAz647QDCd+EIYqoiS+/rPG3oXs/A7rWcJK9HVqfnMVg==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + + '@next/swc-win32-arm64-msvc@14.2.0': + resolution: {integrity: sha512-j1oiidZisnymYjawFqEfeGNcE22ZQ7lGUaa4pGOCVWrWeIDkPSj8zYgS9TzMNlg17Q3wSWCQC/F5uJAhSh7qcA==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [win32] + + '@next/swc-win32-ia32-msvc@14.2.0': + resolution: {integrity: sha512-6ff6F4xb+QGD1jhx/dOT9Ot7PQ/GAYekV9ykwEh2EFS/cLTyU4Y3cXkX5cNtNIhpctS5NvyjW9gIksRNErYE0A==} + engines: {node: '>= 10'} + cpu: [ia32] + os: [win32] + + '@next/swc-win32-x64-msvc@14.2.0': + resolution: {integrity: sha512-09DbG5vXAxz0eTFSf1uebWD36GF3D5toynRkgo2AlSrxwGZkWtJ1RhmrczRYQ17eD5bdo4FZ0ibiffdq5kc4vg==} + engines: {node: '>= 10'} + cpu: [x64] + os: [win32] + + '@swc/counter@0.1.3': + resolution: {integrity: sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==} + + '@swc/helpers@0.5.5': + resolution: {integrity: sha512-KGYxvIOXcceOAbEk4bi/dVLEK9z8sZ0uBB3Il5b1rhfClSpcX0yfRO0KmTkqR2cnQDymwLB+25ZyMzICg/cm/A==} + + '@types/node@24.3.0': + resolution: {integrity: sha512-aPTXCrfwnDLj4VvXrm+UUCQjNEvJgNA8s5F1cvwQU+3KNltTOkBm1j30uNLyqqPNe7gE3KFzImYoZEfLhp4Yow==} + + '@types/react@19.1.10': + resolution: {integrity: sha512-EhBeSYX0Y6ye8pNebpKrwFJq7BoQ8J5SO6NlvNwwHjSj6adXJViPQrKlsyPw7hLBLvckEMO1yxeGdR82YBBlDg==} + + busboy@1.6.0: + resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==} + engines: {node: '>=10.16.0'} + + caniuse-lite@1.0.30001736: + resolution: {integrity: sha512-ImpN5gLEY8gWeqfLUyEF4b7mYWcYoR2Si1VhnrbM4JizRFmfGaAQ12PhNykq6nvI4XvKLrsp8Xde74D5phJOSw==} + + client-only@0.0.1: + resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==} + + csstype@3.1.3: + resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} + + graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + + js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + + loose-envify@1.4.0: + resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} + hasBin: true + + nanoid@3.3.11: + resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + next@14.2.0: + resolution: {integrity: sha512-2T41HqJdKPqheR27ll7MFZ3gtTYvGew7cUc0PwPSyK9Ao5vvwpf9bYfP4V5YBGLckHF2kEGvrLte5BqLSv0s8g==} + engines: {node: '>=18.17.0'} + hasBin: true + peerDependencies: + '@opentelemetry/api': ^1.1.0 + '@playwright/test': ^1.41.2 + react: ^18.2.0 + react-dom: ^18.2.0 + sass: ^1.3.0 + peerDependenciesMeta: + '@opentelemetry/api': + optional: true + '@playwright/test': + optional: true + sass: + optional: true + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + postcss@8.4.31: + resolution: {integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==} + engines: {node: ^10 || ^12 || >=14} + + react-dom@18.2.0: + resolution: {integrity: sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==} + peerDependencies: + react: ^18.2.0 + + react@18.2.0: + resolution: {integrity: sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==} + engines: {node: '>=0.10.0'} + + scheduler@0.23.2: + resolution: {integrity: sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==} + + source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + engines: {node: '>=0.10.0'} + + streamsearch@1.1.0: + resolution: {integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==} + engines: {node: '>=10.0.0'} + + styled-jsx@5.1.1: + resolution: {integrity: sha512-pW7uC1l4mBZ8ugbiZrcIsiIvVx1UmTfw7UkC3Um2tmfUq9Bhk8IiyEIPl6F8agHgjzku6j0xQEZbfA5uSgSaCw==} + engines: {node: '>= 12.0.0'} + peerDependencies: + '@babel/core': '*' + babel-plugin-macros: '*' + react: '>= 16.8.0 || 17.x.x || ^18.0.0-0' + peerDependenciesMeta: + '@babel/core': + optional: true + babel-plugin-macros: + optional: true + + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + + typescript@5.9.2: + resolution: {integrity: sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==} + engines: {node: '>=14.17'} + hasBin: true + + undici-types@7.10.0: + resolution: {integrity: sha512-t5Fy/nfn+14LuOc2KNYg75vZqClpAiqscVvMygNnlsHBFpSXdJaYtXMcdNLpl/Qvc3P2cB3s6lOV51nqsFq4ag==} + +snapshots: + + '@next/env@14.2.0': {} + + '@next/swc-darwin-arm64@14.2.0': + optional: true + + '@next/swc-darwin-x64@14.2.0': + optional: true + + '@next/swc-linux-arm64-gnu@14.2.0': + optional: true + + '@next/swc-linux-arm64-musl@14.2.0': + optional: true + + '@next/swc-linux-x64-gnu@14.2.0': + optional: true + + '@next/swc-linux-x64-musl@14.2.0': + optional: true + + '@next/swc-win32-arm64-msvc@14.2.0': + optional: true + + '@next/swc-win32-ia32-msvc@14.2.0': + optional: true + + '@next/swc-win32-x64-msvc@14.2.0': + optional: true + + '@swc/counter@0.1.3': {} + + '@swc/helpers@0.5.5': + dependencies: + '@swc/counter': 0.1.3 + tslib: 2.8.1 + + '@types/node@24.3.0': + dependencies: + undici-types: 7.10.0 + + '@types/react@19.1.10': + dependencies: + csstype: 3.1.3 + + busboy@1.6.0: + dependencies: + streamsearch: 1.1.0 + + caniuse-lite@1.0.30001736: {} + + client-only@0.0.1: {} + + csstype@3.1.3: {} + + graceful-fs@4.2.11: {} + + js-tokens@4.0.0: {} + + loose-envify@1.4.0: + dependencies: + js-tokens: 4.0.0 + + nanoid@3.3.11: {} + + next@14.2.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0): + dependencies: + '@next/env': 14.2.0 + '@swc/helpers': 0.5.5 + busboy: 1.6.0 + caniuse-lite: 1.0.30001736 + graceful-fs: 4.2.11 + postcss: 8.4.31 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + styled-jsx: 5.1.1(react@18.2.0) + optionalDependencies: + '@next/swc-darwin-arm64': 14.2.0 + '@next/swc-darwin-x64': 14.2.0 + '@next/swc-linux-arm64-gnu': 14.2.0 + '@next/swc-linux-arm64-musl': 14.2.0 + '@next/swc-linux-x64-gnu': 14.2.0 + '@next/swc-linux-x64-musl': 14.2.0 + '@next/swc-win32-arm64-msvc': 14.2.0 + '@next/swc-win32-ia32-msvc': 14.2.0 + '@next/swc-win32-x64-msvc': 14.2.0 + transitivePeerDependencies: + - '@babel/core' + - babel-plugin-macros + + picocolors@1.1.1: {} + + postcss@8.4.31: + dependencies: + nanoid: 3.3.11 + picocolors: 1.1.1 + source-map-js: 1.2.1 + + react-dom@18.2.0(react@18.2.0): + dependencies: + loose-envify: 1.4.0 + react: 18.2.0 + scheduler: 0.23.2 + + react@18.2.0: + dependencies: + loose-envify: 1.4.0 + + scheduler@0.23.2: + dependencies: + loose-envify: 1.4.0 + + source-map-js@1.2.1: {} + + streamsearch@1.1.0: {} + + styled-jsx@5.1.1(react@18.2.0): + dependencies: + client-only: 0.0.1 + react: 18.2.0 + + tslib@2.8.1: {} + + typescript@5.9.2: {} + + undici-types@7.10.0: {} diff --git a/lib/data/spatial/tree-app-tiles/tsconfig.json b/lib/data/spatial/tree-app-tiles/tsconfig.json new file mode 100644 index 00000000..361182a1 --- /dev/null +++ b/lib/data/spatial/tree-app-tiles/tsconfig.json @@ -0,0 +1,30 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "ESNext", + "moduleResolution": "node", + "strict": true, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "isolatedModules": true, + "jsx": "preserve", + "lib": [ + "dom", + "dom.iterable", + "esnext" + ], + "allowJs": true, + "noEmit": true, + "incremental": true + }, + "include": [ + "next-env.d.ts", + "**/*.ts", + "**/*.tsx" + ], + "exclude": [ + "node_modules" + ] +} diff --git a/lib/package.json b/lib/package.json index 5270fd37..668804e5 100644 --- a/lib/package.json +++ b/lib/package.json @@ -18,8 +18,8 @@ "data:spatial:export": "cd data && docker-compose exec db sh -c '/data/spatial/2-export.sh'", "data:spatial:tile": "cd data && docker-compose exec tippecanoe sh -c '/data/spatial/3-tile.sh'", "data:spatial:fonts": "./data/spatial/4-fonts.sh", - "data:spatial:deploy": "vercel deploy --cwd ./data/spatial/tiles", - "data:spatial:deploy:local": "vercel dev --cwd ./data/spatial/tiles", + "data:spatial:deploy": "cd data/spatial/tree-app-tiles && pnpm install && pnpm build && vercel deploy --cwd .", + "data:spatial:deploy:local": "vercel dev --cwd ./data/spatial/tree-app-tiles", "data:export:csv": "node --experimental-json-modules export/src/export_csv.mjs", "doc:build": "documentation build src/** --format html --output doc --config documentation.yml", "doc:serve": "documentation serve --config documentation.yml --watch src/**", From 8476a4fd8649c39cc58244ed8399a1096928dbf3 Mon Sep 17 00:00:00 2001 From: danji90 Date: Thu, 21 Aug 2025 16:29:33 +0200 Subject: [PATCH 3/9] chore: fix font output path --- lib/data/spatial/4-fonts.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/data/spatial/4-fonts.sh b/lib/data/spatial/4-fonts.sh index 20021931..d4216f12 100755 --- a/lib/data/spatial/4-fonts.sh +++ b/lib/data/spatial/4-fonts.sh @@ -1,4 +1,4 @@ yarn run generate-mapbox-gl-fonts mkdir -p data/spatial/tiles/fonts -cp -r _output/Roboto\ Regular data/spatial/tiles/fonts/Roboto\ Regular +cp -r _output/Roboto\ Regular data/spatial/tree-app-tiles/tiles/fonts/Roboto\ Regular rm -r _output \ No newline at end of file From 157fd7c1f64957e49b88d427c59b2420ae7ea431 Mon Sep 17 00:00:00 2001 From: danji90 Date: Mon, 25 Aug 2025 09:53:39 +0200 Subject: [PATCH 4/9] chore: convert to hono server --- lib/data/spatial/tree-app-tiles/.gitignore | 5 +- .../spatial/tree-app-tiles/api/[...path].ts | 37 ++ .../spatial/tree-app-tiles/next.config.js | 17 - lib/data/spatial/tree-app-tiles/package.json | 19 +- .../tree-app-tiles/pages/api/[...path].ts | 32 -- .../spatial/tree-app-tiles/pnpm-lock.yaml | 469 +++++++++--------- lib/data/spatial/tree-app-tiles/server.ts | 48 ++ lib/data/spatial/tree-app-tiles/tsconfig.json | 30 +- 8 files changed, 347 insertions(+), 310 deletions(-) create mode 100644 lib/data/spatial/tree-app-tiles/api/[...path].ts delete mode 100644 lib/data/spatial/tree-app-tiles/next.config.js delete mode 100644 lib/data/spatial/tree-app-tiles/pages/api/[...path].ts create mode 100644 lib/data/spatial/tree-app-tiles/server.ts diff --git a/lib/data/spatial/tree-app-tiles/.gitignore b/lib/data/spatial/tree-app-tiles/.gitignore index b10c6384..74875ae2 100644 --- a/lib/data/spatial/tree-app-tiles/.gitignore +++ b/lib/data/spatial/tree-app-tiles/.gitignore @@ -1,6 +1,3 @@ .vercel node_modules -public/tiles.txt -tiles/fonts -tiles/tree -.next \ No newline at end of file +tiles/* \ No newline at end of file diff --git a/lib/data/spatial/tree-app-tiles/api/[...path].ts b/lib/data/spatial/tree-app-tiles/api/[...path].ts new file mode 100644 index 00000000..ca11668f --- /dev/null +++ b/lib/data/spatial/tree-app-tiles/api/[...path].ts @@ -0,0 +1,37 @@ +import { Hono } from 'hono' +import fs from 'fs' +import path from 'path' + +const app = new Hono() + +app.get('/:folder/:z/:x/:y', (c) => { + const folder = c.req.param('folder') + const z = c.req.param('z') + const x = c.req.param('x') + const y = c.req.param('y') + const filePath = path.join(process.cwd(), 'tiles', folder, z, x, `${y}`) + + if (!fs.existsSync(filePath)) { + return c.text('Tile not found', 404) + } + + if (folder === 'tree') { + c.header('Content-Type', 'application/x-protobuf') + c.header('Content-Encoding', 'gzip') + } else if (folder === 'fonts') { + c.header('Content-Type', 'application/x-protobuf') + } + + c.header('Cache-Control', 'public, max-age=31536000, immutable') + c.header('Access-Control-Allow-Origin', '*') + + return new Response(new Uint8Array(fs.readFileSync(filePath)), { + headers: { + "Content-Type": "application/x-protobuf", + "Cache-Control": "public, max-age=31536000, immutable", + "Access-Control-Allow-Origin": "*", + }, + }); +}) + +export default app \ No newline at end of file diff --git a/lib/data/spatial/tree-app-tiles/next.config.js b/lib/data/spatial/tree-app-tiles/next.config.js deleted file mode 100644 index a13727fa..00000000 --- a/lib/data/spatial/tree-app-tiles/next.config.js +++ /dev/null @@ -1,17 +0,0 @@ -/** @type {import('next').NextConfig} */ -const nextConfig = { - async rewrites() { - return [ - { - source: '/tree/:path*', - destination: '/api/tree/:path*', - }, - { - source: '/fonts/:path*', - destination: '/api/fonts/:path*', - }, - ]; - }, -}; - -export default nextConfig; \ No newline at end of file diff --git a/lib/data/spatial/tree-app-tiles/package.json b/lib/data/spatial/tree-app-tiles/package.json index 9547b011..bdff84c4 100644 --- a/lib/data/spatial/tree-app-tiles/package.json +++ b/lib/data/spatial/tree-app-tiles/package.json @@ -1,21 +1,18 @@ { - "name": "tileserver", + "name": "hono-tile-server", "version": "1.0.0", - "private": true, "type": "module", "scripts": { - "dev": "next dev", - "build": "next build", - "start": "next start" + "dev": "tsx watch server.ts", + "start": "node dist/server.js", + "build": "tsc" }, "dependencies": { - "next": "14.2.0", - "react": "18.2.0", - "react-dom": "18.2.0" + "@hono/node-server": "^1.11.0", + "hono": "^4.6.0" }, "devDependencies": { - "@types/node": "^24.3.0", - "@types/react": "^19.1.10", - "typescript": "^5.9.2" + "tsx": "^4.15.0", + "typescript": "^5.6.3" } } \ No newline at end of file diff --git a/lib/data/spatial/tree-app-tiles/pages/api/[...path].ts b/lib/data/spatial/tree-app-tiles/pages/api/[...path].ts deleted file mode 100644 index 49f12538..00000000 --- a/lib/data/spatial/tree-app-tiles/pages/api/[...path].ts +++ /dev/null @@ -1,32 +0,0 @@ -// pages/api/[...path].ts -import type { NextApiRequest, NextApiResponse } from "next"; -import fs from "fs"; -import path from "path"; - -export default function handler(req: NextApiRequest, res: NextApiResponse) { - try { - const requestedPath = (req.query.path as string[]).join("/"); - const filePath = path.join(process.cwd(), "tiles", requestedPath); - - if (!fs.existsSync(filePath)) { - res.status(404).end("Tile not found"); - return; - } - - res.setHeader("Content-Type", "application/vnd.mapbox-vector-tile"); - res.setHeader("Cache-Control", "public, max-age=31536000, immutable"); - res.setHeader("Access-Control-Allow-Origin", "*"); - res.setHeader("Access-Control-Allow-Headers", "*"); - - if (requestedPath.startsWith("tree/")) { - res.setHeader("Content-Type", "application/vnd.mapbox-vector-tile"); - res.setHeader("Content-Encoding", "gzip"); - } - - const readStream = fs.createReadStream(filePath); - readStream.pipe(res); - } catch (err) { - console.error(err); - res.status(500).end("Internal Server Error"); - } -} \ No newline at end of file diff --git a/lib/data/spatial/tree-app-tiles/pnpm-lock.yaml b/lib/data/spatial/tree-app-tiles/pnpm-lock.yaml index 88220d87..c7760937 100644 --- a/lib/data/spatial/tree-app-tiles/pnpm-lock.yaml +++ b/lib/data/spatial/tree-app-tiles/pnpm-lock.yaml @@ -8,318 +8,343 @@ importers: .: dependencies: - next: - specifier: 14.2.0 - version: 14.2.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - react: - specifier: 18.2.0 - version: 18.2.0 - react-dom: - specifier: 18.2.0 - version: 18.2.0(react@18.2.0) + '@hono/node-server': + specifier: ^1.5.0 + version: 1.19.0(hono@4.9.4) + hono: + specifier: ^4.6.6 + version: 4.9.4 devDependencies: - '@types/node': - specifier: ^24.3.0 - version: 24.3.0 - '@types/react': - specifier: ^19.1.10 - version: 19.1.10 + tsx: + specifier: ^4.7.0 + version: 4.20.5 typescript: - specifier: ^5.9.2 + specifier: ^5.6.3 version: 5.9.2 packages: - '@next/env@14.2.0': - resolution: {integrity: sha512-4+70ELtSbRtYUuyRpAJmKC8NHBW2x1HMje9KO2Xd7IkoyucmV9SjgO+qeWMC0JWkRQXgydv1O7yKOK8nu/rITQ==} + '@esbuild/aix-ppc64@0.25.9': + resolution: {integrity: sha512-OaGtL73Jck6pBKjNIe24BnFE6agGl+6KxDtTfHhy1HmhthfKouEcOhqpSL64K4/0WCtbKFLOdzD/44cJ4k9opA==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] - '@next/swc-darwin-arm64@14.2.0': - resolution: {integrity: sha512-kHktLlw0AceuDnkVljJ/4lTJagLzDiO3klR1Fzl2APDFZ8r+aTxNaNcPmpp0xLMkgRwwk6sggYeqq0Rz9K4zzA==} - engines: {node: '>= 10'} + '@esbuild/android-arm64@0.25.9': + resolution: {integrity: sha512-IDrddSmpSv51ftWslJMvl3Q2ZT98fUSL2/rlUXuVqRXHCs5EUF1/f+jbjF5+NG9UffUDMCiTyh8iec7u8RlTLg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm@0.25.9': + resolution: {integrity: sha512-5WNI1DaMtxQ7t7B6xa572XMXpHAaI/9Hnhk8lcxF4zVN4xstUgTlvuGDorBguKEnZO70qwEcLpfifMLoxiPqHQ==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + + '@esbuild/android-x64@0.25.9': + resolution: {integrity: sha512-I853iMZ1hWZdNllhVZKm34f4wErd4lMyeV7BLzEExGEIZYsOzqDWDf+y082izYUE8gtJnYHdeDpN/6tUdwvfiw==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + + '@esbuild/darwin-arm64@0.25.9': + resolution: {integrity: sha512-XIpIDMAjOELi/9PB30vEbVMs3GV1v2zkkPnuyRRURbhqjyzIINwj+nbQATh4H9GxUgH1kFsEyQMxwiLFKUS6Rg==} + engines: {node: '>=18'} cpu: [arm64] os: [darwin] - '@next/swc-darwin-x64@14.2.0': - resolution: {integrity: sha512-HFSDu7lb1U3RDxXNeKH3NGRR5KyTPBSUTuIOr9jXoAso7i76gNYvnTjbuzGVWt2X5izpH908gmOYWtI7un+JrA==} - engines: {node: '>= 10'} + '@esbuild/darwin-x64@0.25.9': + resolution: {integrity: sha512-jhHfBzjYTA1IQu8VyrjCX4ApJDnH+ez+IYVEoJHeqJm9VhG9Dh2BYaJritkYK3vMaXrf7Ogr/0MQ8/MeIefsPQ==} + engines: {node: '>=18'} cpu: [x64] os: [darwin] - '@next/swc-linux-arm64-gnu@14.2.0': - resolution: {integrity: sha512-iQsoWziO5ZMxDWZ4ZTCAc7hbJ1C9UDj/gATSqTaMjW2bJFwAsvf9UM79AKnljBl73uPZ+V0kH4rvnHTco4Ps2w==} - engines: {node: '>= 10'} + '@esbuild/freebsd-arm64@0.25.9': + resolution: {integrity: sha512-z93DmbnY6fX9+KdD4Ue/H6sYs+bhFQJNCPZsi4XWJoYblUqT06MQUdBCpcSfuiN72AbqeBFu5LVQTjfXDE2A6Q==} + engines: {node: '>=18'} cpu: [arm64] - os: [linux] + os: [freebsd] + + '@esbuild/freebsd-x64@0.25.9': + resolution: {integrity: sha512-mrKX6H/vOyo5v71YfXWJxLVxgy1kyt1MQaD8wZJgJfG4gq4DpQGpgTB74e5yBeQdyMTbgxp0YtNj7NuHN0PoZg==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] - '@next/swc-linux-arm64-musl@14.2.0': - resolution: {integrity: sha512-0JOk2uzLUt8fJK5LpsKKZa74zAch7bJjjgJzR9aOMs231AlE4gPYzsSm430ckZitjPGKeH5bgDZjqwqJQKIS2w==} - engines: {node: '>= 10'} + '@esbuild/linux-arm64@0.25.9': + resolution: {integrity: sha512-BlB7bIcLT3G26urh5Dmse7fiLmLXnRlopw4s8DalgZ8ef79Jj4aUcYbk90g8iCa2467HX8SAIidbL7gsqXHdRw==} + engines: {node: '>=18'} cpu: [arm64] os: [linux] - '@next/swc-linux-x64-gnu@14.2.0': - resolution: {integrity: sha512-uYHkuTzX0NM6biKNp7hdKTf+BF0iMV254SxO0B8PgrQkxUBKGmk5ysHKB+FYBfdf9xei/t8OIKlXJs9ckD943A==} - engines: {node: '>= 10'} - cpu: [x64] + '@esbuild/linux-arm@0.25.9': + resolution: {integrity: sha512-HBU2Xv78SMgaydBmdor38lg8YDnFKSARg1Q6AT0/y2ezUAKiZvc211RDFHlEZRFNRVhcMamiToo7bDx3VEOYQw==} + engines: {node: '>=18'} + cpu: [arm] os: [linux] - '@next/swc-linux-x64-musl@14.2.0': - resolution: {integrity: sha512-paN89nLs2dTBDtfXWty1/NVPit+q6ldwdktixYSVwiiAz647QDCd+EIYqoiS+/rPG3oXs/A7rWcJK9HVqfnMVg==} - engines: {node: '>= 10'} - cpu: [x64] + '@esbuild/linux-ia32@0.25.9': + resolution: {integrity: sha512-e7S3MOJPZGp2QW6AK6+Ly81rC7oOSerQ+P8L0ta4FhVi+/j/v2yZzx5CqqDaWjtPFfYz21Vi1S0auHrap3Ma3A==} + engines: {node: '>=18'} + cpu: [ia32] os: [linux] - '@next/swc-win32-arm64-msvc@14.2.0': - resolution: {integrity: sha512-j1oiidZisnymYjawFqEfeGNcE22ZQ7lGUaa4pGOCVWrWeIDkPSj8zYgS9TzMNlg17Q3wSWCQC/F5uJAhSh7qcA==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [win32] + '@esbuild/linux-loong64@0.25.9': + resolution: {integrity: sha512-Sbe10Bnn0oUAB2AalYztvGcK+o6YFFA/9829PhOCUS9vkJElXGdphz0A3DbMdP8gmKkqPmPcMJmJOrI3VYB1JQ==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] - '@next/swc-win32-ia32-msvc@14.2.0': - resolution: {integrity: sha512-6ff6F4xb+QGD1jhx/dOT9Ot7PQ/GAYekV9ykwEh2EFS/cLTyU4Y3cXkX5cNtNIhpctS5NvyjW9gIksRNErYE0A==} - engines: {node: '>= 10'} - cpu: [ia32] - os: [win32] + '@esbuild/linux-mips64el@0.25.9': + resolution: {integrity: sha512-YcM5br0mVyZw2jcQeLIkhWtKPeVfAerES5PvOzaDxVtIyZ2NUBZKNLjC5z3/fUlDgT6w89VsxP2qzNipOaaDyA==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] - '@next/swc-win32-x64-msvc@14.2.0': - resolution: {integrity: sha512-09DbG5vXAxz0eTFSf1uebWD36GF3D5toynRkgo2AlSrxwGZkWtJ1RhmrczRYQ17eD5bdo4FZ0ibiffdq5kc4vg==} - engines: {node: '>= 10'} - cpu: [x64] - os: [win32] + '@esbuild/linux-ppc64@0.25.9': + resolution: {integrity: sha512-++0HQvasdo20JytyDpFvQtNrEsAgNG2CY1CLMwGXfFTKGBGQT3bOeLSYE2l1fYdvML5KUuwn9Z8L1EWe2tzs1w==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] - '@swc/counter@0.1.3': - resolution: {integrity: sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==} + '@esbuild/linux-riscv64@0.25.9': + resolution: {integrity: sha512-uNIBa279Y3fkjV+2cUjx36xkx7eSjb8IvnL01eXUKXez/CBHNRw5ekCGMPM0BcmqBxBcdgUWuUXmVWwm4CH9kg==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] - '@swc/helpers@0.5.5': - resolution: {integrity: sha512-KGYxvIOXcceOAbEk4bi/dVLEK9z8sZ0uBB3Il5b1rhfClSpcX0yfRO0KmTkqR2cnQDymwLB+25ZyMzICg/cm/A==} + '@esbuild/linux-s390x@0.25.9': + resolution: {integrity: sha512-Mfiphvp3MjC/lctb+7D287Xw1DGzqJPb/J2aHHcHxflUo+8tmN/6d4k6I2yFR7BVo5/g7x2Monq4+Yew0EHRIA==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] - '@types/node@24.3.0': - resolution: {integrity: sha512-aPTXCrfwnDLj4VvXrm+UUCQjNEvJgNA8s5F1cvwQU+3KNltTOkBm1j30uNLyqqPNe7gE3KFzImYoZEfLhp4Yow==} + '@esbuild/linux-x64@0.25.9': + resolution: {integrity: sha512-iSwByxzRe48YVkmpbgoxVzn76BXjlYFXC7NvLYq+b+kDjyyk30J0JY47DIn8z1MO3K0oSl9fZoRmZPQI4Hklzg==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] - '@types/react@19.1.10': - resolution: {integrity: sha512-EhBeSYX0Y6ye8pNebpKrwFJq7BoQ8J5SO6NlvNwwHjSj6adXJViPQrKlsyPw7hLBLvckEMO1yxeGdR82YBBlDg==} + '@esbuild/netbsd-arm64@0.25.9': + resolution: {integrity: sha512-9jNJl6FqaUG+COdQMjSCGW4QiMHH88xWbvZ+kRVblZsWrkXlABuGdFJ1E9L7HK+T0Yqd4akKNa/lO0+jDxQD4Q==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] - busboy@1.6.0: - resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==} - engines: {node: '>=10.16.0'} + '@esbuild/netbsd-x64@0.25.9': + resolution: {integrity: sha512-RLLdkflmqRG8KanPGOU7Rpg829ZHu8nFy5Pqdi9U01VYtG9Y0zOG6Vr2z4/S+/3zIyOxiK6cCeYNWOFR9QP87g==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] - caniuse-lite@1.0.30001736: - resolution: {integrity: sha512-ImpN5gLEY8gWeqfLUyEF4b7mYWcYoR2Si1VhnrbM4JizRFmfGaAQ12PhNykq6nvI4XvKLrsp8Xde74D5phJOSw==} + '@esbuild/openbsd-arm64@0.25.9': + resolution: {integrity: sha512-YaFBlPGeDasft5IIM+CQAhJAqS3St3nJzDEgsgFixcfZeyGPCd6eJBWzke5piZuZ7CtL656eOSYKk4Ls2C0FRQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] - client-only@0.0.1: - resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==} + '@esbuild/openbsd-x64@0.25.9': + resolution: {integrity: sha512-1MkgTCuvMGWuqVtAvkpkXFmtL8XhWy+j4jaSO2wxfJtilVCi0ZE37b8uOdMItIHz4I6z1bWWtEX4CJwcKYLcuA==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] - csstype@3.1.3: - resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} + '@esbuild/openharmony-arm64@0.25.9': + resolution: {integrity: sha512-4Xd0xNiMVXKh6Fa7HEJQbrpP3m3DDn43jKxMjxLLRjWnRsfxjORYJlXPO4JNcXtOyfajXorRKY9NkOpTHptErg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] - graceful-fs@4.2.11: - resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + '@esbuild/sunos-x64@0.25.9': + resolution: {integrity: sha512-WjH4s6hzo00nNezhp3wFIAfmGZ8U7KtrJNlFMRKxiI9mxEK1scOMAaa9i4crUtu+tBr+0IN6JCuAcSBJZfnphw==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] - js-tokens@4.0.0: - resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + '@esbuild/win32-arm64@0.25.9': + resolution: {integrity: sha512-mGFrVJHmZiRqmP8xFOc6b84/7xa5y5YvR1x8djzXpJBSv/UsNK6aqec+6JDjConTgvvQefdGhFDAs2DLAds6gQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] - loose-envify@1.4.0: - resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} - hasBin: true + '@esbuild/win32-ia32@0.25.9': + resolution: {integrity: sha512-b33gLVU2k11nVx1OhX3C8QQP6UHQK4ZtN56oFWvVXvz2VkDoe6fbG8TOgHFxEvqeqohmRnIHe5A1+HADk4OQww==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] - nanoid@3.3.11: - resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} - engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} - hasBin: true + '@esbuild/win32-x64@0.25.9': + resolution: {integrity: sha512-PPOl1mi6lpLNQxnGoyAfschAodRFYXJ+9fs6WHXz7CSWKbOqiMZsubC+BQsVKuul+3vKLuwTHsS2c2y9EoKwxQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] - next@14.2.0: - resolution: {integrity: sha512-2T41HqJdKPqheR27ll7MFZ3gtTYvGew7cUc0PwPSyK9Ao5vvwpf9bYfP4V5YBGLckHF2kEGvrLte5BqLSv0s8g==} - engines: {node: '>=18.17.0'} - hasBin: true - peerDependencies: - '@opentelemetry/api': ^1.1.0 - '@playwright/test': ^1.41.2 - react: ^18.2.0 - react-dom: ^18.2.0 - sass: ^1.3.0 - peerDependenciesMeta: - '@opentelemetry/api': - optional: true - '@playwright/test': - optional: true - sass: - optional: true - - picocolors@1.1.1: - resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} - - postcss@8.4.31: - resolution: {integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==} - engines: {node: ^10 || ^12 || >=14} - - react-dom@18.2.0: - resolution: {integrity: sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==} + '@hono/node-server@1.19.0': + resolution: {integrity: sha512-1k8/8OHf5VIymJEcJyVksFpT+AQ5euY0VA5hUkCnlKpD4mr8FSbvXaHblxeTTEr90OaqWzAkQaqD80qHZQKxBA==} + engines: {node: '>=18.14.1'} peerDependencies: - react: ^18.2.0 + hono: ^4 - react@18.2.0: - resolution: {integrity: sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==} - engines: {node: '>=0.10.0'} + esbuild@0.25.9: + resolution: {integrity: sha512-CRbODhYyQx3qp7ZEwzxOk4JBqmD/seJrzPa/cGjY1VtIn5E09Oi9/dB4JwctnfZ8Q8iT7rioVv5k/FNT/uf54g==} + engines: {node: '>=18'} + hasBin: true - scheduler@0.23.2: - resolution: {integrity: sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==} + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] - source-map-js@1.2.1: - resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} - engines: {node: '>=0.10.0'} + get-tsconfig@4.10.1: + resolution: {integrity: sha512-auHyJ4AgMz7vgS8Hp3N6HXSmlMdUyhSUrfBF16w153rxtLIEOE+HGqaBppczZvnHLqQJfiHotCYpNhl0lUROFQ==} - streamsearch@1.1.0: - resolution: {integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==} - engines: {node: '>=10.0.0'} + hono@4.9.4: + resolution: {integrity: sha512-61hl6MF6ojTl/8QSRu5ran6GXt+6zsngIUN95KzF5v5UjiX/xnrLR358BNRawwIRO49JwUqJqQe3Rb2v559R8Q==} + engines: {node: '>=16.9.0'} - styled-jsx@5.1.1: - resolution: {integrity: sha512-pW7uC1l4mBZ8ugbiZrcIsiIvVx1UmTfw7UkC3Um2tmfUq9Bhk8IiyEIPl6F8agHgjzku6j0xQEZbfA5uSgSaCw==} - engines: {node: '>= 12.0.0'} - peerDependencies: - '@babel/core': '*' - babel-plugin-macros: '*' - react: '>= 16.8.0 || 17.x.x || ^18.0.0-0' - peerDependenciesMeta: - '@babel/core': - optional: true - babel-plugin-macros: - optional: true - - tslib@2.8.1: - resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + resolve-pkg-maps@1.0.0: + resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} + + tsx@4.20.5: + resolution: {integrity: sha512-+wKjMNU9w/EaQayHXb7WA7ZaHY6hN8WgfvHNQ3t1PnU91/7O8TcTnIhCDYTZwnt8JsO9IBqZ30Ln1r7pPF52Aw==} + engines: {node: '>=18.0.0'} + hasBin: true typescript@5.9.2: resolution: {integrity: sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==} engines: {node: '>=14.17'} hasBin: true - undici-types@7.10.0: - resolution: {integrity: sha512-t5Fy/nfn+14LuOc2KNYg75vZqClpAiqscVvMygNnlsHBFpSXdJaYtXMcdNLpl/Qvc3P2cB3s6lOV51nqsFq4ag==} - snapshots: - '@next/env@14.2.0': {} + '@esbuild/aix-ppc64@0.25.9': + optional: true - '@next/swc-darwin-arm64@14.2.0': + '@esbuild/android-arm64@0.25.9': optional: true - '@next/swc-darwin-x64@14.2.0': + '@esbuild/android-arm@0.25.9': optional: true - '@next/swc-linux-arm64-gnu@14.2.0': + '@esbuild/android-x64@0.25.9': optional: true - '@next/swc-linux-arm64-musl@14.2.0': + '@esbuild/darwin-arm64@0.25.9': optional: true - '@next/swc-linux-x64-gnu@14.2.0': + '@esbuild/darwin-x64@0.25.9': optional: true - '@next/swc-linux-x64-musl@14.2.0': + '@esbuild/freebsd-arm64@0.25.9': optional: true - '@next/swc-win32-arm64-msvc@14.2.0': + '@esbuild/freebsd-x64@0.25.9': optional: true - '@next/swc-win32-ia32-msvc@14.2.0': + '@esbuild/linux-arm64@0.25.9': optional: true - '@next/swc-win32-x64-msvc@14.2.0': + '@esbuild/linux-arm@0.25.9': optional: true - '@swc/counter@0.1.3': {} + '@esbuild/linux-ia32@0.25.9': + optional: true - '@swc/helpers@0.5.5': - dependencies: - '@swc/counter': 0.1.3 - tslib: 2.8.1 + '@esbuild/linux-loong64@0.25.9': + optional: true - '@types/node@24.3.0': - dependencies: - undici-types: 7.10.0 + '@esbuild/linux-mips64el@0.25.9': + optional: true - '@types/react@19.1.10': - dependencies: - csstype: 3.1.3 + '@esbuild/linux-ppc64@0.25.9': + optional: true - busboy@1.6.0: - dependencies: - streamsearch: 1.1.0 + '@esbuild/linux-riscv64@0.25.9': + optional: true + + '@esbuild/linux-s390x@0.25.9': + optional: true + + '@esbuild/linux-x64@0.25.9': + optional: true - caniuse-lite@1.0.30001736: {} + '@esbuild/netbsd-arm64@0.25.9': + optional: true - client-only@0.0.1: {} + '@esbuild/netbsd-x64@0.25.9': + optional: true - csstype@3.1.3: {} + '@esbuild/openbsd-arm64@0.25.9': + optional: true - graceful-fs@4.2.11: {} + '@esbuild/openbsd-x64@0.25.9': + optional: true - js-tokens@4.0.0: {} + '@esbuild/openharmony-arm64@0.25.9': + optional: true - loose-envify@1.4.0: - dependencies: - js-tokens: 4.0.0 + '@esbuild/sunos-x64@0.25.9': + optional: true - nanoid@3.3.11: {} + '@esbuild/win32-arm64@0.25.9': + optional: true - next@14.2.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0): - dependencies: - '@next/env': 14.2.0 - '@swc/helpers': 0.5.5 - busboy: 1.6.0 - caniuse-lite: 1.0.30001736 - graceful-fs: 4.2.11 - postcss: 8.4.31 - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) - styled-jsx: 5.1.1(react@18.2.0) - optionalDependencies: - '@next/swc-darwin-arm64': 14.2.0 - '@next/swc-darwin-x64': 14.2.0 - '@next/swc-linux-arm64-gnu': 14.2.0 - '@next/swc-linux-arm64-musl': 14.2.0 - '@next/swc-linux-x64-gnu': 14.2.0 - '@next/swc-linux-x64-musl': 14.2.0 - '@next/swc-win32-arm64-msvc': 14.2.0 - '@next/swc-win32-ia32-msvc': 14.2.0 - '@next/swc-win32-x64-msvc': 14.2.0 - transitivePeerDependencies: - - '@babel/core' - - babel-plugin-macros - - picocolors@1.1.1: {} - - postcss@8.4.31: - dependencies: - nanoid: 3.3.11 - picocolors: 1.1.1 - source-map-js: 1.2.1 + '@esbuild/win32-ia32@0.25.9': + optional: true - react-dom@18.2.0(react@18.2.0): - dependencies: - loose-envify: 1.4.0 - react: 18.2.0 - scheduler: 0.23.2 + '@esbuild/win32-x64@0.25.9': + optional: true - react@18.2.0: + '@hono/node-server@1.19.0(hono@4.9.4)': dependencies: - loose-envify: 1.4.0 + hono: 4.9.4 + + esbuild@0.25.9: + optionalDependencies: + '@esbuild/aix-ppc64': 0.25.9 + '@esbuild/android-arm': 0.25.9 + '@esbuild/android-arm64': 0.25.9 + '@esbuild/android-x64': 0.25.9 + '@esbuild/darwin-arm64': 0.25.9 + '@esbuild/darwin-x64': 0.25.9 + '@esbuild/freebsd-arm64': 0.25.9 + '@esbuild/freebsd-x64': 0.25.9 + '@esbuild/linux-arm': 0.25.9 + '@esbuild/linux-arm64': 0.25.9 + '@esbuild/linux-ia32': 0.25.9 + '@esbuild/linux-loong64': 0.25.9 + '@esbuild/linux-mips64el': 0.25.9 + '@esbuild/linux-ppc64': 0.25.9 + '@esbuild/linux-riscv64': 0.25.9 + '@esbuild/linux-s390x': 0.25.9 + '@esbuild/linux-x64': 0.25.9 + '@esbuild/netbsd-arm64': 0.25.9 + '@esbuild/netbsd-x64': 0.25.9 + '@esbuild/openbsd-arm64': 0.25.9 + '@esbuild/openbsd-x64': 0.25.9 + '@esbuild/openharmony-arm64': 0.25.9 + '@esbuild/sunos-x64': 0.25.9 + '@esbuild/win32-arm64': 0.25.9 + '@esbuild/win32-ia32': 0.25.9 + '@esbuild/win32-x64': 0.25.9 + + fsevents@2.3.3: + optional: true - scheduler@0.23.2: + get-tsconfig@4.10.1: dependencies: - loose-envify: 1.4.0 + resolve-pkg-maps: 1.0.0 - source-map-js@1.2.1: {} + hono@4.9.4: {} - streamsearch@1.1.0: {} + resolve-pkg-maps@1.0.0: {} - styled-jsx@5.1.1(react@18.2.0): + tsx@4.20.5: dependencies: - client-only: 0.0.1 - react: 18.2.0 - - tslib@2.8.1: {} + esbuild: 0.25.9 + get-tsconfig: 4.10.1 + optionalDependencies: + fsevents: 2.3.3 typescript@5.9.2: {} - - undici-types@7.10.0: {} diff --git a/lib/data/spatial/tree-app-tiles/server.ts b/lib/data/spatial/tree-app-tiles/server.ts new file mode 100644 index 00000000..a54afe4c --- /dev/null +++ b/lib/data/spatial/tree-app-tiles/server.ts @@ -0,0 +1,48 @@ +import { Hono } from 'hono' +import { serve } from '@hono/node-server' +import { readFile } from 'fs/promises' +import path from 'path' + +const app = new Hono() +const baseDir = path.join(process.cwd(), 'tiles') + +// Serve tiles.txt at root +app.get('/tiles.txt', async (c) => { + try { + const filePath = path.join(baseDir, 'tiles.txt') + const content = await readFile(filePath, 'utf-8') + c.header('Content-Type', 'text/plain') + c.header('Cache-Control', 'public, max-age=3600') + return c.text(content) + } catch (err) { + console.error('tiles.txt not found', err) + return c.text('File not found', 404) + } +}) + +// Serve vector tiles +app.get('/:folder/:z/:x/:y.pbf', async (c) => { + try { + const { folder, z, x } = c.req.param() + const y = c.req.param()['y.pbf'].replace('.pbf', '') + const tilePath = path.join(baseDir, folder, z, x, `${y}.pbf`) + const isTreeTile = folder === 'tree' + + const tileBuffer = await readFile(tilePath) + + c.header('Content-Type', 'application/x-protobuf') + c.header('Cache-Control', 'public, max-age=31536000, immutable') + c.header('Access-Control-Allow-Origin', '*') + c.header('Content-Encoding', isTreeTile ? 'gzip' : 'identity') + + return c.body(new Uint8Array(tileBuffer)) + } catch (err) { + return c.text('Tile not found', 404) + } +}) + +// Start server +serve({ + fetch: app.fetch, + port: 3000, +}) diff --git a/lib/data/spatial/tree-app-tiles/tsconfig.json b/lib/data/spatial/tree-app-tiles/tsconfig.json index 361182a1..fb327255 100644 --- a/lib/data/spatial/tree-app-tiles/tsconfig.json +++ b/lib/data/spatial/tree-app-tiles/tsconfig.json @@ -2,29 +2,11 @@ "compilerOptions": { "target": "ES2022", "module": "ESNext", - "moduleResolution": "node", - "strict": true, + "moduleResolution": "Node", "esModuleInterop": true, - "forceConsistentCasingInFileNames": true, - "skipLibCheck": true, - "resolveJsonModule": true, - "isolatedModules": true, - "jsx": "preserve", - "lib": [ - "dom", - "dom.iterable", - "esnext" - ], - "allowJs": true, - "noEmit": true, - "incremental": true + "outDir": "dist", + "strict": true, + "skipLibCheck": true }, - "include": [ - "next-env.d.ts", - "**/*.ts", - "**/*.tsx" - ], - "exclude": [ - "node_modules" - ] -} + "include": ["server.ts"] +} \ No newline at end of file From 108d11d163f1a484dedffe62a9cc94f4bfc999ef Mon Sep 17 00:00:00 2001 From: danji90 Date: Mon, 25 Aug 2025 10:12:15 +0200 Subject: [PATCH 5/9] chore: remove fs/promises dep --- lib/data/spatial/tree-app-tiles/.gitignore | 3 ++- lib/data/spatial/tree-app-tiles/pnpm-lock.yaml | 6 +++--- lib/data/spatial/tree-app-tiles/server.ts | 6 +++--- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/lib/data/spatial/tree-app-tiles/.gitignore b/lib/data/spatial/tree-app-tiles/.gitignore index 74875ae2..08df6912 100644 --- a/lib/data/spatial/tree-app-tiles/.gitignore +++ b/lib/data/spatial/tree-app-tiles/.gitignore @@ -1,3 +1,4 @@ .vercel node_modules -tiles/* \ No newline at end of file +tiles/* +dist \ No newline at end of file diff --git a/lib/data/spatial/tree-app-tiles/pnpm-lock.yaml b/lib/data/spatial/tree-app-tiles/pnpm-lock.yaml index c7760937..95dd8cce 100644 --- a/lib/data/spatial/tree-app-tiles/pnpm-lock.yaml +++ b/lib/data/spatial/tree-app-tiles/pnpm-lock.yaml @@ -9,14 +9,14 @@ importers: .: dependencies: '@hono/node-server': - specifier: ^1.5.0 + specifier: ^1.11.0 version: 1.19.0(hono@4.9.4) hono: - specifier: ^4.6.6 + specifier: ^4.6.0 version: 4.9.4 devDependencies: tsx: - specifier: ^4.7.0 + specifier: ^4.15.0 version: 4.20.5 typescript: specifier: ^5.6.3 diff --git a/lib/data/spatial/tree-app-tiles/server.ts b/lib/data/spatial/tree-app-tiles/server.ts index a54afe4c..8aaae4e9 100644 --- a/lib/data/spatial/tree-app-tiles/server.ts +++ b/lib/data/spatial/tree-app-tiles/server.ts @@ -1,6 +1,6 @@ import { Hono } from 'hono' import { serve } from '@hono/node-server' -import { readFile } from 'fs/promises' +import fs from 'fs' import path from 'path' const app = new Hono() @@ -10,7 +10,7 @@ const baseDir = path.join(process.cwd(), 'tiles') app.get('/tiles.txt', async (c) => { try { const filePath = path.join(baseDir, 'tiles.txt') - const content = await readFile(filePath, 'utf-8') + const content = await fs.promises.readFile(filePath, 'utf-8') c.header('Content-Type', 'text/plain') c.header('Cache-Control', 'public, max-age=3600') return c.text(content) @@ -28,7 +28,7 @@ app.get('/:folder/:z/:x/:y.pbf', async (c) => { const tilePath = path.join(baseDir, folder, z, x, `${y}.pbf`) const isTreeTile = folder === 'tree' - const tileBuffer = await readFile(tilePath) + const tileBuffer = await fs.promises.readFile(tilePath) c.header('Content-Type', 'application/x-protobuf') c.header('Cache-Control', 'public, max-age=31536000, immutable') From 3d959a66ae9845040eb7824576d9e1b195162490 Mon Sep 17 00:00:00 2001 From: danji90 Date: Mon, 25 Aug 2025 10:14:45 +0200 Subject: [PATCH 6/9] chore: add types/node --- lib/data/spatial/tree-app-tiles/package.json | 1 + lib/data/spatial/tree-app-tiles/pnpm-lock.yaml | 15 +++++++++++++++ lib/data/spatial/tree-app-tiles/tsconfig.json | 7 +++++-- 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/lib/data/spatial/tree-app-tiles/package.json b/lib/data/spatial/tree-app-tiles/package.json index bdff84c4..1ac6384c 100644 --- a/lib/data/spatial/tree-app-tiles/package.json +++ b/lib/data/spatial/tree-app-tiles/package.json @@ -12,6 +12,7 @@ "hono": "^4.6.0" }, "devDependencies": { + "@types/node": "^24.3.0", "tsx": "^4.15.0", "typescript": "^5.6.3" } diff --git a/lib/data/spatial/tree-app-tiles/pnpm-lock.yaml b/lib/data/spatial/tree-app-tiles/pnpm-lock.yaml index 95dd8cce..b89d878c 100644 --- a/lib/data/spatial/tree-app-tiles/pnpm-lock.yaml +++ b/lib/data/spatial/tree-app-tiles/pnpm-lock.yaml @@ -15,6 +15,9 @@ importers: specifier: ^4.6.0 version: 4.9.4 devDependencies: + '@types/node': + specifier: ^24.3.0 + version: 24.3.0 tsx: specifier: ^4.15.0 version: 4.20.5 @@ -186,6 +189,9 @@ packages: peerDependencies: hono: ^4 + '@types/node@24.3.0': + resolution: {integrity: sha512-aPTXCrfwnDLj4VvXrm+UUCQjNEvJgNA8s5F1cvwQU+3KNltTOkBm1j30uNLyqqPNe7gE3KFzImYoZEfLhp4Yow==} + esbuild@0.25.9: resolution: {integrity: sha512-CRbODhYyQx3qp7ZEwzxOk4JBqmD/seJrzPa/cGjY1VtIn5E09Oi9/dB4JwctnfZ8Q8iT7rioVv5k/FNT/uf54g==} engines: {node: '>=18'} @@ -216,6 +222,9 @@ packages: engines: {node: '>=14.17'} hasBin: true + undici-types@7.10.0: + resolution: {integrity: sha512-t5Fy/nfn+14LuOc2KNYg75vZqClpAiqscVvMygNnlsHBFpSXdJaYtXMcdNLpl/Qvc3P2cB3s6lOV51nqsFq4ag==} + snapshots: '@esbuild/aix-ppc64@0.25.9': @@ -300,6 +309,10 @@ snapshots: dependencies: hono: 4.9.4 + '@types/node@24.3.0': + dependencies: + undici-types: 7.10.0 + esbuild@0.25.9: optionalDependencies: '@esbuild/aix-ppc64': 0.25.9 @@ -348,3 +361,5 @@ snapshots: fsevents: 2.3.3 typescript@5.9.2: {} + + undici-types@7.10.0: {} diff --git a/lib/data/spatial/tree-app-tiles/tsconfig.json b/lib/data/spatial/tree-app-tiles/tsconfig.json index fb327255..b3a742da 100644 --- a/lib/data/spatial/tree-app-tiles/tsconfig.json +++ b/lib/data/spatial/tree-app-tiles/tsconfig.json @@ -3,10 +3,13 @@ "target": "ES2022", "module": "ESNext", "moduleResolution": "Node", - "esModuleInterop": true, "outDir": "dist", + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, "strict": true, - "skipLibCheck": true + "skipLibCheck": true, + "types": ["node"], + "lib": ["ES2022", "DOM"] }, "include": ["server.ts"] } \ No newline at end of file From 45da7b2c1312360e7f93bcdda1d9991e636256b8 Mon Sep 17 00:00:00 2001 From: danji90 Date: Mon, 25 Aug 2025 10:53:55 +0200 Subject: [PATCH 7/9] chore: fix font requests --- lib/data/spatial/tree-app-tiles/server.ts | 50 ++++++++++++++++++----- 1 file changed, 39 insertions(+), 11 deletions(-) diff --git a/lib/data/spatial/tree-app-tiles/server.ts b/lib/data/spatial/tree-app-tiles/server.ts index 8aaae4e9..f279cbe6 100644 --- a/lib/data/spatial/tree-app-tiles/server.ts +++ b/lib/data/spatial/tree-app-tiles/server.ts @@ -1,15 +1,15 @@ import { Hono } from 'hono' -import { serve } from '@hono/node-server' import fs from 'fs' import path from 'path' +import { serve } from '@hono/node-server' const app = new Hono() const baseDir = path.join(process.cwd(), 'tiles') // Serve tiles.txt at root app.get('/tiles.txt', async (c) => { + const filePath = path.join(baseDir, 'tiles.txt') try { - const filePath = path.join(baseDir, 'tiles.txt') const content = await fs.promises.readFile(filePath, 'utf-8') c.header('Content-Type', 'text/plain') c.header('Cache-Control', 'public, max-age=3600') @@ -20,29 +20,57 @@ app.get('/tiles.txt', async (c) => { } }) -// Serve vector tiles -app.get('/:folder/:z/:x/:y.pbf', async (c) => { +// Serve tree tiles (gzipped) +app.get('/tree/:z/:x/:y', async (c) => { try { - const { folder, z, x } = c.req.param() - const y = c.req.param()['y.pbf'].replace('.pbf', '') - const tilePath = path.join(baseDir, folder, z, x, `${y}.pbf`) - const isTreeTile = folder === 'tree' + const folder = 'tree' + const z = decodeURIComponent(c.req.param('z')) + const x = decodeURIComponent(c.req.param('x')) + const y = decodeURIComponent(c.req.param('y')) + + const filePath = path.join(baseDir, folder, z, x, y) - const tileBuffer = await fs.promises.readFile(tilePath) + await fs.promises.access(filePath) + const tileBuffer = await fs.promises.readFile(filePath) c.header('Content-Type', 'application/x-protobuf') + c.header('Content-Encoding', 'gzip') c.header('Cache-Control', 'public, max-age=31536000, immutable') c.header('Access-Control-Allow-Origin', '*') - c.header('Content-Encoding', isTreeTile ? 'gzip' : 'identity') return c.body(new Uint8Array(tileBuffer)) } catch (err) { + console.error('Tree tile not found:', err) return c.text('Tile not found', 404) } }) -// Start server +// Serve fonts tiles (raw, supports spaces and nested folders) +app.get('/fonts/*', async (c) => { + try { + // Remove '/fonts/' from path and decode + const relativePath = decodeURIComponent(c.req.path.replace(/^\/fonts\//, '')) + const filePath = path.join(baseDir, 'fonts', relativePath) + + await fs.promises.access(filePath) + const tileBuffer = await fs.promises.readFile(filePath) + + c.header('Content-Type', 'application/x-protobuf') + c.header('Content-Encoding', 'identity') + c.header('Cache-Control', 'public, max-age=31536000, immutable') + c.header('Access-Control-Allow-Origin', '*') + + return c.body(new Uint8Array(tileBuffer)) + } catch (err) { + console.error('Font tile not found:', err) + return c.text('Tile not found', 404) + } +}) + +// Start local server serve({ fetch: app.fetch, port: 3000, }) + +console.log('Server running at http://localhost:3000') From 427e8726d7b74d765012af196bf589166e385c13 Mon Sep 17 00:00:00 2001 From: danji90 Date: Mon, 25 Aug 2025 11:17:21 +0200 Subject: [PATCH 8/9] chore: remove api folder --- .../spatial/tree-app-tiles/api/[...path].ts | 37 ------------------- 1 file changed, 37 deletions(-) delete mode 100644 lib/data/spatial/tree-app-tiles/api/[...path].ts diff --git a/lib/data/spatial/tree-app-tiles/api/[...path].ts b/lib/data/spatial/tree-app-tiles/api/[...path].ts deleted file mode 100644 index ca11668f..00000000 --- a/lib/data/spatial/tree-app-tiles/api/[...path].ts +++ /dev/null @@ -1,37 +0,0 @@ -import { Hono } from 'hono' -import fs from 'fs' -import path from 'path' - -const app = new Hono() - -app.get('/:folder/:z/:x/:y', (c) => { - const folder = c.req.param('folder') - const z = c.req.param('z') - const x = c.req.param('x') - const y = c.req.param('y') - const filePath = path.join(process.cwd(), 'tiles', folder, z, x, `${y}`) - - if (!fs.existsSync(filePath)) { - return c.text('Tile not found', 404) - } - - if (folder === 'tree') { - c.header('Content-Type', 'application/x-protobuf') - c.header('Content-Encoding', 'gzip') - } else if (folder === 'fonts') { - c.header('Content-Type', 'application/x-protobuf') - } - - c.header('Cache-Control', 'public, max-age=31536000, immutable') - c.header('Access-Control-Allow-Origin', '*') - - return new Response(new Uint8Array(fs.readFileSync(filePath)), { - headers: { - "Content-Type": "application/x-protobuf", - "Cache-Control": "public, max-age=31536000, immutable", - "Access-Control-Allow-Origin": "*", - }, - }); -}) - -export default app \ No newline at end of file From b791021a159edf6ccc1a62a0024d4c6a0fd855e8 Mon Sep 17 00:00:00 2001 From: danji90 Date: Tue, 26 Aug 2025 08:35:38 +0200 Subject: [PATCH 9/9] chore: add cross-origin header for tiles.txt --- lib/data/spatial/tree-app-tiles/server.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/data/spatial/tree-app-tiles/server.ts b/lib/data/spatial/tree-app-tiles/server.ts index f279cbe6..b9c5fe67 100644 --- a/lib/data/spatial/tree-app-tiles/server.ts +++ b/lib/data/spatial/tree-app-tiles/server.ts @@ -13,6 +13,7 @@ app.get('/tiles.txt', async (c) => { const content = await fs.promises.readFile(filePath, 'utf-8') c.header('Content-Type', 'text/plain') c.header('Cache-Control', 'public, max-age=3600') + c.header('Access-Control-Allow-Origin', '*') return c.text(content) } catch (err) { console.error('tiles.txt not found', err)