69 Commits

Author SHA1 Message Date
Renovate Bot
e65a88a1c8 Update https://git.quad4.io/actions/setup-node action to v6
All checks were successful
OSV-Scanner PR Scan / scan-pr (pull_request) Successful in 9s
2025-12-31 00:03:42 +00:00
1e694fcbf0 Update README.md
All checks were successful
OSV-Scanner Scheduled Scan / scan-scheduled (push) Successful in 10s
CI / check (push) Successful in 9m26s
CI / build (push) Successful in 9m36s
2025-12-29 20:13:27 -06:00
077dbf95c2 Add container image scanning and SBOM generation tasks to Taskfile 2025-12-29 20:13:19 -06:00
fc7892170e Add SBOM workflow
All checks were successful
OSV-Scanner Scheduled Scan / scan-scheduled (push) Successful in 4s
CI / check (push) Successful in 27s
CI / build (push) Successful in 9m32s
2025-12-29 17:46:56 -06:00
22b49c9548 Update README.md
All checks were successful
OSV-Scanner Scheduled Scan / scan-scheduled (push) Successful in 10s
CI / check (push) Successful in 9m24s
CI / build (push) Successful in 9m35s
2025-12-29 17:37:53 -06:00
754eb33e10 Add tasks to bump version in Taskfile for minor and major updates 2025-12-29 17:37:51 -06:00
82ee5ad723 Add Podman support to Taskfile for building and running containers
All checks were successful
OSV-Scanner Scheduled Scan / scan-scheduled (push) Successful in 5s
CI / check (push) Successful in 24s
CI / build (push) Successful in 36s
2025-12-29 17:34:59 -06:00
8f4cb3e320 Update Dockerfile to optimize build process by removing unnecessary node_modules and ensuring production dependencies are installed correctly. 2025-12-29 17:34:55 -06:00
f4a3be855a Update package version to 1.4.0 in package.json
All checks were successful
OSV-Scanner Scheduled Scan / scan-scheduled (push) Successful in 6s
CI / check (push) Successful in 23s
CI / build (push) Successful in 35s
2025-12-29 17:07:12 -06:00
912e115b18 Add CHANGELOG.md 2025-12-29 17:07:12 -06:00
92e919f165 Update README.md 2025-12-29 17:07:12 -06:00
c93a304c74 Add flake.lock 2025-12-29 17:07:12 -06:00
178e5ebbc3 Add flake.nix 2025-12-29 17:07:12 -06:00
5f23d9ccfe Enable eslint security rule for object injection detection in map.ts 2025-12-29 17:07:12 -06:00
dace6bdce3 Enable eslint security rule for object injection detection in +page.svelte 2025-12-29 17:07:12 -06:00
35a4486fd3 Clean up surveilled.js by removing unnecessary blank lines 2025-12-29 17:07:11 -06:00
d49797807c Add Taskfile 2025-12-29 17:07:11 -06:00
97ded97249 Remove makefile, bash scripts 2025-12-29 17:07:11 -06:00
45ba6b14dd Add eslint-plugin-security for enhanced security checks and configure global process variable for bin scripts 2025-12-29 17:07:11 -06:00
175bbc710b Move dockerfile 2025-12-29 17:07:11 -06:00
b911350ddb Remove package-lock.json, add pnpm-lock.yaml for dependency management, update package.json to include license, author, and package manager details, and add eslint-plugin-security as a new dependency. 2025-12-29 17:07:11 -06:00
cbb007662d Update CI, Docker, and NPM publish workflows to use direct action links, switch to PNPM caching, and replace npm commands with task commands for improved consistency and efficiency. 2025-12-29 17:07:11 -06:00
20c1b654a4 Change license from MIT to BSD 3-Clause, update README to reflect PNPM usage, and modify Svelte page to indicate new license type. 2025-12-29 17:07:10 -06:00
ivan
8de528cab0 Merge pull request 'Configure Renovate' (#4) from renovate/configure into master
All checks were successful
OSV-Scanner Scheduled Scan / scan-scheduled (push) Successful in 23s
CI / check (push) Successful in 32s
CI / build (push) Successful in 46s
Reviewed-on: #4
2025-12-27 20:32:29 +00:00
Renovate Bot
610c3ed707 Add renovate.json
All checks were successful
OSV-Scanner PR Scan / scan-pr (pull_request) Successful in 19s
2025-12-27 20:30:40 +00:00
33530f6e51 Update Docker workflow
All checks were successful
CI / check (push) Successful in 24s
OSV-Scanner Scheduled Scan / scan-scheduled (push) Successful in 19s
CI / build (push) Successful in 42s
2025-12-25 15:18:44 -06:00
2ed10bc86d Update README to use a direct link for the showcase image
Some checks failed
OSV-Scanner Scheduled Scan / scan-scheduled (push) Successful in 27s
CI / check (push) Successful in 33s
CI / build (push) Successful in 55s
Publish NPM Package / publish (push) Successful in 52s
Build and Publish Docker Image / build (push) Has been cancelled
2025-12-25 15:12:54 -06:00
c222981f69 Update package version to 1.3.1 in package.json and package-lock.json 2025-12-25 15:11:32 -06:00
606cbc0770 Update package-lock.json to reflect version bump to 1.3.0, add missing dependencies, and specify Node.js engine requirements. 2025-12-25 15:11:09 -06:00
81ce2fbbe6 Set default HOST and PORT environment variables in surveilled.js 2025-12-25 15:09:08 -06:00
3ba66ff179 Update README 2025-12-25 15:09:03 -06:00
f386459449 Update package.json by adding main and types fields, specifying Node.js engine version, updating file patterns, and introducing a start script for local development 2025-12-25 15:08:51 -06:00
70503fcb56 Update package version to 1.3.0, add bin entry for surveilled.js, and enhance package.json with additional build and file configurations
Some checks failed
CI / check (push) Failing after 25s
CI / build (push) Has been skipped
OSV-Scanner Scheduled Scan / scan-scheduled (push) Successful in 25s
Publish NPM Package / publish (push) Successful in 37s
Build and Publish Docker Image / build (push) Successful in 12m26s
2025-12-25 14:48:07 -06:00
42bcfc2dfc Update Svelte configuration to use adapter-node and add surveilled.js script for Node.js execution 2025-12-25 14:48:00 -06:00
b9bb7ec8b5 Update npm-publish workflow to use NPM_TOKEN for authentication 2025-12-25 14:45:41 -06:00
f92c8fced7 Update package version to 1.2.2 in package.json and package-lock.json
Some checks failed
CI / check (push) Successful in 52s
OSV-Scanner Scheduled Scan / scan-scheduled (push) Successful in 17s
Publish NPM Package / publish (push) Failing after 49s
CI / build (push) Successful in 48s
Build and Publish Docker Image / build (push) Successful in 14m35s
2025-12-25 14:26:32 -06:00
f80919c45f Update npm-publish workflow to use updated Gitea token variable for authentication 2025-12-25 14:26:20 -06:00
ad4fa4f93a Update npm-publish workflow to configure registry for publishing and ensure dependencies are installed from npmjs.org
Some checks failed
CI / check (push) Successful in 1m7s
OSV-Scanner Scheduled Scan / scan-scheduled (push) Successful in 35s
CI / build (push) Successful in 1m11s
Publish NPM Package / publish (push) Failing after 1m38s
Build and Publish Docker Image / build (push) Has been cancelled
2025-12-25 14:15:37 -06:00
66a1933cfb Improve app version retrieval in vite.config.ts to declare process.env for improved type safety and clarity.
Some checks failed
OSV-Scanner Scheduled Scan / scan-scheduled (push) Successful in 30s
Build and Publish Docker Image / build (push) Has been cancelled
CI / check (push) Successful in 52s
CI / build (push) Successful in 1m13s
2025-12-25 14:14:28 -06:00
620e63b7ba Fix
Some checks failed
CI / check (push) Failing after 27s
OSV-Scanner Scheduled Scan / scan-scheduled (push) Successful in 23s
CI / build (push) Has been skipped
Build and Publish Docker Image / build (push) Has been cancelled
Publish NPM Package / publish (push) Failing after 26s
2025-12-25 14:12:27 -06:00
9918638cb8 Refactor Camera interface in map.ts to export as a type for improved type management and clarity. 2025-12-25 14:11:32 -06:00
165f06e06b Update app version retrieval in vite.config.ts to use import.meta.env for improved compatibility with Vite's environment variables 2025-12-25 14:11:26 -06:00
405a254824 Add eslint directive to suppress unused variable warning for setStatusMessage function in +page.svelte 2025-12-25 14:11:19 -06:00
0bb79ff612 Add app version definition in vite.config.ts for improved version management 2025-12-25 14:09:40 -06:00
55a90bd146 Refactor APP_VERSION definition in version.ts to support multiple sources 2025-12-25 14:09:28 -06:00
7dcfb1ff7c format workflow 2025-12-25 14:01:35 -06:00
6b35ab80a2 Update module exports in index.ts to include API, constants, map, settings, and version files for improved accessibility and organization. 2025-12-25 14:00:30 -06:00
d9d97db0f9 Refactor package configuration to use scoped name and enhance export settings
- Updated package name to '@quad4/surveilled' for better namespace management.
- Added publish configuration for custom NPM registry.
- Defined exports for module entry points and included necessary files for packaging.
- Updated dependencies in package-lock.json to include new packages and versions.
2025-12-25 14:00:12 -06:00
6796d85a6a Update Makefile to include new package and publish targets, and modify clean command to remove 'dist' and 'package' directories. 2025-12-25 13:59:56 -06:00
6f1428b8e8 Configure NPM registry and authentication token in .npmrc for package management 2025-12-25 13:59:51 -06:00
1b38193ca3 Update .dockerignore and .gitignore to include 'dist/' directory for package management 2025-12-25 13:59:44 -06:00
f258254adf Add NPM publish workflow for automated package deployment 2025-12-25 13:59:39 -06:00
61c47c2d60 Update version to 1.2.0 in package.json and package-lock.json 2025-12-25 13:53:10 -06:00
5b31ef951d Update README
All checks were successful
OSV-Scanner Scheduled Scan / scan-scheduled (push) Successful in 24s
CI / check (push) Successful in 28s
CI / build (push) Successful in 45s
Build and Publish Docker Image / build (push) Successful in 10m17s
2025-12-25 13:43:16 -06:00
3c574b58f6 Enhance camera map interface with new settings and improved functionality
- Added settings management for Overpass API, custom tile URLs, and Nominatim search endpoints, allowing users to customize their experience.
- Implemented responsive design adjustments for mobile views, including a modal for location search.
- Improved camera selection and measurement features with enhanced visual feedback and distance labeling.
- Updated footer behavior to persist user preferences and improve usability.
2025-12-25 13:36:09 -06:00
07d5c540b6 Add settings management for Overpass API, custom tiles, Nominatim, basemap, and footer preferences
- Implemented Svelte stores to manage user preferences for Overpass API endpoints, custom tile URLs, Nominatim search endpoints, basemap selection, and footer visibility.
- Integrated localStorage for persistent settings across sessions, enhancing user experience and customization options.
2025-12-25 13:36:01 -06:00
b826ee8f4f Refactor API endpoint handling to prioritize user-defined settings
- Introduced dynamic endpoint selection for Overpass API based on user preferences.
- Updated Nominatim API URL construction to utilize a configurable base URL from settings.
- Enhanced the fetchOverpassWithFallback function to improve reliability by using preferred endpoints.
2025-12-25 13:35:55 -06:00
2df526c606 Update Overpass API endpoints in constants.ts to include additional servers for improved reliability 2025-12-25 13:35:48 -06:00
26f91f1aee Add responsive styling for zoom control in mobile view 2025-12-25 13:35:42 -06:00
85febfacc1 Update ESLint configuration to add readonly definitions for HTMLButtonElement and localStorage 2025-12-25 13:35:34 -06:00
0eab72db49 Add Docker support to Makefile 2025-12-25 13:34:20 -06:00
dffd3ff838 Format yaml 2025-12-25 13:34:08 -06:00
f5407e56e1 Add Docker workflow for building and publishing images
Some checks failed
OSV-Scanner Scheduled Scan / scan-scheduled (push) Successful in 23s
CI / check (push) Successful in 39s
Build and Publish Docker Image / build (push) Failing after 58s
CI / build (push) Successful in 46s
2025-12-25 13:16:25 -06:00
ivan
8adc0aa85d Update README.md
All checks were successful
OSV-Scanner Scheduled Scan / scan-scheduled (push) Successful in 22s
CI / check (push) Successful in 24s
CI / build (push) Successful in 39s
2025-12-25 04:50:40 +00:00
ivan
2e7780e711 Upload files to "showcase"
All checks were successful
OSV-Scanner Scheduled Scan / scan-scheduled (push) Successful in 21s
CI / check (push) Successful in 24s
CI / build (push) Successful in 39s
2025-12-25 04:47:24 +00:00
c0dd901def Add validation functions for API responses and map parameters
All checks were successful
OSV-Scanner Scheduled Scan / scan-scheduled (push) Successful in 19s
CI / check (push) Successful in 22s
CI / build (push) Successful in 39s
- Introduced validation functions for Overpass and Nominatim API responses to ensure correct data structure.
- Added latitude, longitude, and bounds validation functions in the Svelte component to enhance input handling.
- Updated the map state restoration logic to utilize these validation checks, improving robustness and error handling.
2025-12-24 21:20:07 -06:00
2d7efb03fb Update version to 1.1.0 in package.json and package-lock.json
All checks were successful
OSV-Scanner Scheduled Scan / scan-scheduled (push) Successful in 18s
CI / check (push) Successful in 22s
CI / build (push) Successful in 39s
2025-12-24 21:13:20 -06:00
191ed6b0e1 Improve box selection functionality in map component
- Improved box selection mode logic by ensuring proper state checks and event handling.
- Added conditions to prevent actions when the selection mode is not active or when necessary elements are missing.
- Updated the UI to include a tooltip for better user guidance during box selection.
- Refactored code for clarity and maintainability, ensuring a smoother user experience.
2025-12-24 21:13:08 -06:00
57187e7ed4 Add tooltip for box selection feature in map component
All checks were successful
OSV-Scanner Scheduled Scan / scan-scheduled (push) Successful in 19s
CI / check (push) Successful in 22s
CI / build (push) Successful in 40s
- Introduced a tooltip that guides users to draw a box for camera searches, displayed conditionally based on local storage state.
- Implemented tooltip positioning logic and dismiss functionality.
- Updated the Svelte component to enhance user interaction and experience.
2025-12-24 21:09:29 -06:00
36 changed files with 9343 additions and 9350 deletions

View File

@@ -21,3 +21,7 @@ Thumbs.db
# Vite
vite.config.js.timestamp-*
vite.config.ts.timestamp-*
# Package
dist/

View File

@@ -11,29 +11,41 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
uses: https://git.quad4.io/actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- name: Setup Node.js
uses: actions/setup-node@v4
uses: https://git.quad4.io/actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6
with:
node-version: 22
cache: npm
cache: pnpm
- name: Setup Task
uses: https://git.quad4.io/actions/setup-task@0ab1b2a65bc55236a3bc64cde78f80e20e8885c2 # v1
with:
version: '3.46.3'
- name: Setup environment
run: task setup
- name: Install dependencies
run: npm ci
run: task install:ci
- name: Svelte check (fail on warnings)
run: bash scripts/check.sh
run: task check
build:
runs-on: ubuntu-latest
needs: check
steps:
- name: Checkout
uses: actions/checkout@v4
uses: https://git.quad4.io/actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- name: Setup Node.js
uses: actions/setup-node@v4
uses: https://git.quad4.io/actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6
with:
node-version: 22
cache: npm
cache: pnpm
- name: Setup Task
uses: https://git.quad4.io/actions/setup-task@0ab1b2a65bc55236a3bc64cde78f80e20e8885c2 # v1
with:
version: '3.46.3'
- name: Setup environment
run: task setup
- name: Install dependencies
run: npm ci
run: task install:ci
- name: Build
run: bash scripts/build.sh
run: task build

View File

@@ -0,0 +1,64 @@
name: Build and Publish Docker Image
on:
workflow_dispatch:
push:
tags:
- 'v*'
env:
REGISTRY: git.quad4.io
IMAGE_NAME: quad4-software/surveilled
jobs:
build:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
outputs:
image_digest: ${{ steps.build.outputs.digest }}
image_tags: ${{ steps.meta.outputs.tags }}
steps:
- name: Checkout repository
uses: https://git.quad4.io/actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
- name: Set up QEMU
uses: https://git.quad4.io/actions/setup-qemu-action@c7c53464625b32c7a7e944ae62b3e17d2b600130 # v3.7.0
with:
platforms: amd64,arm64
- name: Set up Docker Buildx
uses: https://git.quad4.io/actions/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0
- name: Log in to the Container registry
uses: https://git.quad4.io/actions/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0
with:
registry: ${{ env.REGISTRY }}
username: ${{ secrets.REGISTRY_USERNAME }}
password: ${{ secrets.REGISTRY_PASSWORD }}
- name: Extract metadata (tags, labels) for Docker
id: meta
uses: https://git.quad4.io/actions/metadata-action@c299e40c65443455700f0fdfc63efafe5b349051 # v5.10.0
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=raw,value=latest,enable={{is_default_branch}}
type=ref,event=branch,prefix=,suffix=,enable={{is_default_branch}}
type=ref,event=pr
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=sha,format=short
- name: Build and push Docker image
id: build
uses: https://git.quad4.io/actions/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0
with:
context: .
file: ./docker/Dockerfile
platforms: linux/amd64,linux/arm64
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}

View File

@@ -0,0 +1,45 @@
name: Publish NPM Package
on:
workflow_dispatch:
push:
tags:
- 'v*'
jobs:
publish:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: https://git.quad4.io/actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- name: Setup Node.js
uses: https://git.quad4.io/actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6
with:
node-version: '22'
cache: pnpm
- name: Setup Task
uses: https://git.quad4.io/actions/setup-task@0ab1b2a65bc55236a3bc64cde78f80e20e8885c2 # v1
with:
version: '3.46.3'
- name: Setup environment
run: task setup
- name: Install dependencies
run: task install:ci
- name: Package
run: task package
- name: Configure npm for publishing
uses: https://git.quad4.io/actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6
with:
node-version: '22'
registry-url: 'https://git.quad4.io/api/packages/quad4-software/npm/'
- name: Publish
run: task publish
env:
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}

View File

@@ -14,7 +14,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
uses: https://git.quad4.io/actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- name: OSV scan
run: bash scripts/osv_scan.sh

View File

@@ -14,7 +14,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
uses: https://git.quad4.io/actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- name: OSV scan
run: bash scripts/osv_scan.sh

58
.gitea/workflows/sbom.yml Normal file
View File

@@ -0,0 +1,58 @@
name: Generate SBOM
on:
push:
tags:
- 'v*'
workflow_dispatch:
jobs:
generate-sbom:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: https://git.quad4.io/actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
fetch-depth: 0
ref: ${{ github.ref }}
- name: Setup Node.js
uses: https://git.quad4.io/actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0
with:
node-version: 22
cache: pnpm
- name: Setup Task
uses: https://git.quad4.io/actions/setup-task@0ab1b2a65bc55236a3bc64cde78f80e20e8885c2 # v1
with:
version: '3.46.3'
- name: Setup environment
run: task setup
- name: Install dependencies
run: task install:ci
- name: Download Trivy
run: |
curl -L -o /tmp/trivy.deb https://git.quad4.io/Quad4-Extra/assets/raw/commit/90fdcea1bb71d91df2de6ff2e3897f278413f300/bin/trivy_0.68.2_Linux-64bit.deb
sudo dpkg -i /tmp/trivy.deb || sudo apt-get install -f -y
- name: Generate SBOM
run: |
mkdir -p sbom
trivy fs --format spdx-json --include-dev-deps --output sbom/sbom.spdx.json .
trivy fs --format cyclonedx --include-dev-deps --output sbom/sbom.cyclonedx.json .
- name: Commit and Push Changes
run: |
git config --global user.name "Gitea Action"
git config --global user.email "actions@noreply.quad4.io"
git remote set-url origin https://${{ secrets.GITEA_TOKEN }}@git.quad4.io/${{ github.repository }}.git
git fetch origin master
git checkout master
git add sbom/
git diff --quiet && git diff --staged --quiet || (git commit -m "Auto-update SBOM [skip ci]" && git push origin master)
env:
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}

3
.gitignore vendored
View File

@@ -21,3 +21,6 @@ Thumbs.db
# Vite
vite.config.js.timestamp-*
vite.config.ts.timestamp-*
# Package
dist/

3
.npmrc
View File

@@ -1 +1,2 @@
engine-strict=true
@quad4:registry=https://git.quad4.io/api/packages/quad4-software/npm/
//git.quad4.io/api/packages/quad4-software/npm/:_authToken=${NPM_TOKEN}

37
CHANGELOG.md Normal file
View File

@@ -0,0 +1,37 @@
# Changelog
## 1.4.0 - 2025-12-29
### Major Codebase Changes
- Migrated from `npm` to `pnpm` (v10.25.0)
- Migrated from `Makefile` to `Taskfile` for all development tasks
- Updated license from `MIT` to `BSD-3-Clause`
- Added `license` and `author` fields to `package.json`
- Moved Dockerfile to `docker/` folder
- Added Nix flake for development environment
### Features
- Added Task section to README with available tasks
- Improved README structure
### Security
- Added `eslint-plugin-security` for security linting
- Updated Docker containers to use specific pnpm version (10.25.0)
### CI/CD Updates
- Updated workflows to use `task` commands
- Added `setup-task` action to workflows
- Updated workflows to use full action URLs with commit hashes
- Updated Docker workflow to reference `docker/Dockerfile`
- All workflows use pnpm with `--frozen-lockfile`
### Development
- Added `setup` task for enabling corepack
- Added `install:ci` task for CI dependency installation
- Updated Taskfile to reference `docker/Dockerfile` for Docker builds
- Added flake.nix with Task, Node.js 20, and pnpm

39
LICENSE
View File

@@ -1,22 +1,29 @@
MIT License
BSD 3-Clause License
Copyright (c) 2025 Quad4.io
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@@ -1,32 +0,0 @@
.PHONY: help install dev build preview check lint format clean
help:
@echo 'Usage: make [target]'
@echo ''
@echo 'Available targets:'
@awk 'BEGIN {FS = ":.*?## "} /^[a-zA-Z_-]+:.*?## / {printf " %-15s %s\n", $$1, $$2}' $(MAKEFILE_LIST)
install:
npm install
dev:
npm run dev
build:
npm run build
preview:
npm run preview
check:
npm run check
lint:
npm run lint
format:
npm run format
clean:
rm -rf .svelte-kit build node_modules/.vite

131
README.md
View File

@@ -1,40 +1,141 @@
# Surveilled
[Website](https://surveilled.quad4.io)
A map of cameras in the world using OpenStreetMap overpass data.
A map of cameras in the world using OpenStreetMap data.
<img src="https://git.quad4.io/Quad4-Software/Surveilled/raw/commit/70503fcb56994c4c1bb019dfbcc3b589ebd94039/showcase/surveilled.png" alt="showcase image" width="900">
Check out the live website at [surveilled.quad4.io](https://surveilled.quad4.io)
## Disclaimer
Data is fetched from OSM Overpass and may not be accurate or up to date as this data is community-sourced.
## Features
- Draw a box to get cameras for that area
- Measure distance between two points/cameras
- Export or copy GeoJSON of cameras in an area
- Customize Nominatim, Overpass, and Tile endpoints
- No reliance on external CDNs or Google fonts
- PWA installable
- Mobile-friendly
## Quick Start
### Using Docker
```sh
docker run -p 3000:3000 git.quad4.io/quad4-software/surveilled:latest
```
Then open your browser at `http://localhost:3000`
### Using Podman
```sh
podman run -p 3000:3000 git.quad4.io/quad4-software/surveilled:latest
```
Then open your browser at `http://localhost:3000`
### Using PNPM
```sh
pnpm config set @quad4:registry=https://git.quad4.io/api/packages/Quad4-Software/npm/
pnpm install -g @quad4/surveilled
surveilled
```
Or with custom port and host:
```sh
PORT=8080 HOST=0.0.0.0 surveilled
```
## Development
```sh
make dev
```
### Prerequisites
## Building
- Node.js `>=18.0.0`
- pnpm `>=10.25.0`
### Setup
```sh
make build
git clone https://git.quad4.io/Quad4-Software/Surveilled
cd Surveilled
pnpm install
```
## Preview
### Task
```sh
make preview
The project uses [Task](https://taskfile.dev/) for all development tasks.
```
| Task | Description |
|---------------|---------------------------------------|
| default | Show available tasks |
| dev | Run development server |
| build | Build the application |
| package | Package the application |
| publish | Publish to npm registry |
| preview | Preview production build |
| check | Run type checking |
| lint | Run linter |
| format | Format code |
| clean | Clean build artifacts |
| docker-build | Build Docker image |
| docker-run | Run Docker container |
| docker | Build and run Docker container |
| podman-build | Build Podman image |
| podman-run | Run Podman container |
| podman | Build and run Podman container |
| scan | Scan container image with trivy |
| sbom | Generate SBOM with trivy |
| version:minor | Bump version minor |
| version:major | Bump version major |
| setup | Setup development environment |
| install | Install dependencies |
| install:ci | Install dependencies for CI |
example: task dev
you might nee to set alias alias task=`go-task`
```
## Docker
## Building Container Image
Uses Chainguard Images which are rootless and very minimal images.
### Using Docker
```sh
docker build -t surveilled .
docker run -p 3000:3000 surveilled
task docker-build
task docker-run
```
## LICENSE
Or use the combined task:
[MIT](LICENSE)
```sh
task docker
```
### Using Podman
```sh
task podman-build
task podman-run
```
Or use the combined task:
```sh
task podman
```
## Contributing
Send email to [team@quad4.io](mailto:team@quad4.io) with your feedback or any issues you may have.
## License
[BSD 3-Clause](LICENSE)

118
Taskfile.yml Normal file
View File

@@ -0,0 +1,118 @@
version: '3'
tasks:
default:
desc: Show available tasks
cmds:
- task --list
dev:
desc: Run development server
cmds:
- pnpm install
- pnpm run dev
build:
desc: Build the application
cmds:
- pnpm run build
package:
desc: Package the application
cmds:
- pnpm run package
publish:
desc: Publish to npm registry
cmds:
- pnpm publish --no-git-checks
preview:
desc: Preview production build
cmds:
- pnpm run preview
check:
desc: Run type checking
cmds:
- pnpm run check
lint:
desc: Run linter
cmds:
- pnpm run lint
format:
desc: Format code
cmds:
- pnpm run format
clean:
desc: Clean build artifacts
cmds:
- rm -rf .svelte-kit build node_modules/.vite dist package
docker-build:
desc: Build Docker image
cmds:
- docker build -f docker/Dockerfile -t surveilled .
docker-run:
desc: Run Docker container
cmds:
- docker run --rm -p 3000:3000 surveilled
docker:
desc: Build and run Docker container
deps: [docker-build, docker-run]
podman-build:
desc: Build Podman image
cmds:
- podman build -f docker/Dockerfile -t surveilled .
podman-run:
desc: Run Podman container
cmds:
- podman run --rm -p 3000:3000 surveilled
podman:
desc: Build and run Podman container
deps: [podman-build, podman-run]
scan:
desc: Scan container image with trivy
cmds:
- trivy image --scanners vuln surveilled
sbom:
desc: Generate SBOM with trivy
cmds:
- mkdir -p sbom
- trivy fs --format spdx-json --include-dev-deps --output sbom/sbom.spdx.json .
- trivy fs --format cyclonedx --include-dev-deps --output sbom/sbom.cyclonedx.json .
setup:
desc: Setup development environment
cmds:
- corepack enable
install:
desc: Install dependencies
cmds:
- pnpm install
install:ci:
desc: Install dependencies for CI (frozen lockfile)
cmds:
- pnpm install --frozen-lockfile
version:minor:
desc: Bump version minor
cmds:
- pnpm version minor
version:major:
desc: Bump version major
cmds:
- pnpm version major

6
bin/surveilled.js Executable file
View File

@@ -0,0 +1,6 @@
#!/usr/bin/env node
process.env.HOST = process.env.HOST || '127.0.0.1';
process.env.PORT = process.env.PORT || '3000';
import '../build/index.js';

View File

@@ -2,23 +2,29 @@ FROM cgr.dev/chainguard/node:latest-dev AS builder
WORKDIR /app
COPY --chown=node:node package.json package-lock.json ./
RUN npm ci
USER root
RUN corepack enable && corepack prepare pnpm@10.25.0 --activate
USER node
RUN npm install --save-dev @sveltejs/adapter-node@latest
COPY --chown=node:node package.json pnpm-lock.yaml ./
RUN pnpm install --frozen-lockfile
RUN pnpm add -D @sveltejs/adapter-node@latest
COPY --chown=node:node . .
COPY --chown=node:node svelte.config.docker.js svelte.config.js
RUN npm run build
RUN pnpm run build
RUN rm -rf node_modules && \
pnpm install --prod --frozen-lockfile && \
pnpm store prune
FROM cgr.dev/chainguard/node:latest AS runtime
WORKDIR /app
COPY --from=builder --chown=node:node /app/package.json /app/package-lock.json ./
RUN npm install --omit=dev && \
npm cache clean --force
COPY --from=builder --chown=node:node /app/node_modules ./node_modules
COPY --from=builder --chown=node:node /app/build ./build
COPY --from=builder --chown=node:node /app/package.json ./

View File

@@ -3,6 +3,7 @@ import tsPlugin from '@typescript-eslint/eslint-plugin';
import tsParser from '@typescript-eslint/parser';
import sveltePlugin from 'eslint-plugin-svelte';
import svelteParser from 'svelte-eslint-parser';
import securityPlugin from 'eslint-plugin-security';
export default [
js.configs.recommended,
@@ -22,9 +23,11 @@ export default [
HTMLElement: 'readonly',
HTMLImageElement: 'readonly',
HTMLInputElement: 'readonly',
HTMLButtonElement: 'readonly',
navigator: 'readonly',
window: 'readonly',
document: 'readonly',
localStorage: 'readonly',
Blob: 'readonly',
Event: 'readonly',
MouseEvent: 'readonly',
@@ -41,9 +44,11 @@ export default [
plugins: {
'@typescript-eslint': tsPlugin,
svelte: sveltePlugin,
security: securityPlugin,
},
rules: {
...tsPlugin.configs.recommended.rules,
...securityPlugin.configs.recommended.rules,
},
},
{
@@ -61,6 +66,14 @@ export default [
...sveltePlugin.configs.recommended.rules,
},
},
{
files: ['bin/**/*.js'],
languageOptions: {
globals: {
process: 'readonly',
},
},
},
{
ignores: ['node_modules/**', '.svelte-kit/**', 'build/**', 'dist/**', 'archive/**'],
},

61
flake.lock generated Normal file
View File

@@ -0,0 +1,61 @@
{
"nodes": {
"flake-utils": {
"inputs": {
"systems": "systems"
},
"locked": {
"lastModified": 1731533236,
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1766902085,
"narHash": "sha256-coBu0ONtFzlwwVBzmjacUQwj3G+lybcZ1oeNSQkgC0M=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "c0b0e0fddf73fd517c3471e546c0df87a42d53f4",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"flake-utils": "flake-utils",
"nixpkgs": "nixpkgs"
}
},
"systems": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
}
},
"root": "root",
"version": 7
}

57
flake.nix Normal file
View File

@@ -0,0 +1,57 @@
{
description = "Surveilled development environment";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
flake-utils.url = "github:numtide/flake-utils";
};
outputs = { self, nixpkgs, flake-utils }:
flake-utils.lib.eachDefaultSystem (system:
let
pkgs = import nixpkgs {
inherit system;
};
task = pkgs.buildGoModule rec {
pname = "task";
version = "3.46.3";
src = pkgs.fetchFromGitHub {
owner = "go-task";
repo = "task";
rev = "v${version}";
hash = "sha256-1bS8ZZAcemgRG7PTeGTFfd49T9u6U6CxxrbotwCM15A=";
};
vendorHash = "sha256-Tm0tqureCRwcP5KKDTa9TO1yZ3Px3ulf9/jKQDDTjDw=";
subPackages = [ "cmd/task" ];
doCheck = false;
meta = with pkgs.lib; {
description = "A task runner / simpler Make alternative written in Go";
homepage = "https://taskfile.dev/";
license = licenses.mit;
maintainers = with maintainers; [ ];
};
};
in
{
devShells.default = pkgs.mkShell {
buildInputs = with pkgs; [
task
nodejs_20
nodePackages.pnpm
];
shellHook = ''
echo "Surveilled Development Environment"
echo "Task version: $(task --version 2>/dev/null || echo 'installed')"
echo "Node version: $(node --version)"
echo "pnpm version: $(pnpm --version)"
'';
};
});
}

9070
package-lock.json generated
View File

File diff suppressed because it is too large Load Diff

View File

@@ -1,41 +1,79 @@
{
"name": "surveilled",
"private": true,
"version": "1.0.0",
"name": "@quad4/surveilled",
"version": "1.4.0",
"license": "BSD-3-Clause",
"author": "Quad4",
"type": "module",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
"bin": {
"surveilled": "./bin/surveilled.js"
},
"engines": {
"node": ">=18.0.0"
},
"packageManager": "pnpm@10.25.0",
"publishConfig": {
"registry": "https://git.quad4.io/api/packages/quad4-software/npm/"
},
"pnpm": {
"overrides": {
"cookie": "1.1.1"
}
},
"exports": {
".": {
"types": "./dist/index.d.ts",
"svelte": "./dist/index.js",
"default": "./dist/index.js"
}
},
"files": [
"dist/**/*",
"build/**/*",
"bin/**/*",
"package/**/*",
"README.md",
"LICENSE"
],
"scripts": {
"dev": "VITE_APP_VERSION=$(node -p \"require('./package.json').version\") vite dev",
"build": "VITE_APP_VERSION=$(node -p \"require('./package.json').version\") vite build",
"preview": "VITE_APP_VERSION=$(node -p \"require('./package.json').version\") vite preview",
"prepare": "svelte-kit sync || echo ''",
"start": "HOST=127.0.0.1 PORT=3000 node build",
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
"format": "prettier --write .",
"lint": "eslint ."
"lint": "eslint .",
"package": "svelte-kit sync && svelte-package && vite build"
},
"devDependencies": {
"@eslint/js": "^9.39.2",
"@sveltejs/adapter-auto": "^7.0.0",
"@sveltejs/adapter-node": "^5.4.0",
"@sveltejs/kit": "^2.49.1",
"@sveltejs/package": "^2.3.9",
"@sveltejs/vite-plugin-svelte": "^6.2.1",
"@typescript-eslint/eslint-plugin": "^8.50.1",
"@typescript-eslint/parser": "^8.50.1",
"autoprefixer": "^10.4.23",
"eslint": "^9.39.2",
"eslint-plugin-security": "^3.0.1",
"eslint-plugin-svelte": "^3.13.1",
"postcss": "^8.5.6",
"prettier": "^3.7.4",
"prettier-plugin-svelte": "^3.4.1",
"svelte": "^5.45.6",
"svelte-check": "^4.3.4",
"svelte-eslint-parser": "^1.4.1",
"tailwindcss": "^3.4.19",
"typescript": "^5.9.3",
"vite": "^7.2.6",
"vite-plugin-pwa": "^1.2.0"
},
"dependencies": {
"autoprefixer": "^10.4.23",
"lucide-svelte": "^0.562.0",
"ol": "^10.7.0",
"postcss": "^8.5.6",
"tailwindcss": "^3.4.19"
"ol": "^10.7.0"
}
}

7762
pnpm-lock.yaml generated Normal file
View File

File diff suppressed because it is too large Load Diff

3
renovate.json Normal file
View File

@@ -0,0 +1,3 @@
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json"
}

View File

@@ -1,6 +0,0 @@
#!/usr/bin/env bash
set -euo pipefail
echo "Building app..."
VITE_APP_VERSION=$(node -p "require('./package.json').version") npm run build

View File

@@ -1,9 +0,0 @@
#!/usr/bin/env bash
set -euo pipefail
echo "Running Svelte sync..."
npx svelte-kit sync
echo "Running svelte-check (fail on errors)..."
npx svelte-check --tsconfig ./tsconfig.json

BIN
showcase/surveilled.png Normal file
View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 837 KiB

View File

@@ -80,6 +80,12 @@
background-color: #262626 !important;
}
@media (max-width: 640px) {
.ol-zoom {
display: none !important;
}
}
.ol-attribution.ol-unselectable.ol-control {
background-color: rgba(23, 23, 23, 0.9) !important;
color: #fafafa !important;

View File

@@ -1,9 +1,11 @@
import { get } from 'svelte/store';
import {
OVERPASS_ENDPOINTS,
OVERPASS_TIMEOUT,
OVERPASS_MAX_BOUNDS_SPAN,
ERROR_MESSAGES,
} from './constants';
import { overpassEndpoint, nominatimEndpoint } from './settings';
export interface Camera {
lon: number;
@@ -27,9 +29,19 @@ export interface OverpassResponse {
elements: OverpassElement[];
}
function isValidOverpassResponse(data: unknown): data is OverpassResponse {
if (!data || typeof data !== 'object') return false;
if (!('elements' in data)) return false;
if (!Array.isArray(data.elements)) return false;
return true;
}
export async function fetchOverpassWithFallback(query: string): Promise<OverpassResponse> {
let lastErr: Error | null = null;
for (const endpoint of OVERPASS_ENDPOINTS) {
const preferred = get(overpassEndpoint);
const endpoints = [preferred, ...OVERPASS_ENDPOINTS.filter((e) => e !== preferred)];
for (const endpoint of endpoints) {
try {
const url = `${endpoint}?data=${encodeURIComponent(query)}`;
const response = await fetch(url);
@@ -39,7 +51,11 @@ export async function fetchOverpassWithFallback(query: string): Promise<Overpass
if (response.status === 429) continue;
else continue;
}
return JSON.parse(text);
const parsed = JSON.parse(text);
if (!isValidOverpassResponse(parsed)) {
throw new Error('Invalid Overpass response structure');
}
return parsed;
} catch (err) {
lastErr = err as Error;
continue;
@@ -132,13 +148,30 @@ export interface NominatimResult {
export type NominatimResponse = NominatimResult[];
function isValidNominatimResponse(data: unknown): data is NominatimResponse {
if (!Array.isArray(data)) return false;
return data.every((item) => {
return (
item &&
typeof item === 'object' &&
typeof item.place_id === 'number' &&
typeof item.display_name === 'string' &&
typeof item.lat === 'string' &&
typeof item.lon === 'string'
);
});
}
export async function searchNominatim(query: string): Promise<NominatimResult[]> {
if (!query.trim()) {
return [];
}
const url = new URL('https://nominatim.openstreetmap.org/search');
url.searchParams.set('q', query);
const sanitizedQuery = query.trim().slice(0, 200);
const baseUrl = get(nominatimEndpoint);
const url = new URL(baseUrl);
url.searchParams.set('q', sanitizedQuery);
url.searchParams.set('format', 'json');
url.searchParams.set('limit', '10');
url.searchParams.set('addressdetails', '0');
@@ -156,7 +189,10 @@ export async function searchNominatim(query: string): Promise<NominatimResult[]>
throw new Error(`Nominatim error ${response.status}`);
}
const data: NominatimResponse = await response.json();
const data: unknown = await response.json();
if (!isValidNominatimResponse(data)) {
throw new Error('Invalid Nominatim response structure');
}
return data;
} catch (err) {
console.error('Nominatim search failed:', err);

View File

@@ -1,7 +1,9 @@
// Overpass API Configuration
export const OVERPASS_ENDPOINTS = [
'https://overpass-api.de/api/interpreter',
'https://lz4.overpass-api.de/api/interpreter',
'https://overpass.kumi.systems/api/interpreter',
'https://overpass.openstreetmap.fr/api/interpreter',
] as const;
export const OVERPASS_TIMEOUT = 25; // seconds

View File

@@ -1 +1,5 @@
// place files you want to import through the `$lib` alias in this folder.
export * from './api';
export * from './constants';
export * from './map';
export * from './settings';
export * from './version';

View File

@@ -1,3 +1,4 @@
/* eslint-disable security/detect-object-injection */
import Map from 'ol/Map.js';
import View from 'ol/View.js';
import { fromLonLat, toLonLat, transformExtent } from 'ol/proj.js';
@@ -28,18 +29,27 @@ import {
FOV_MIN_ZOOM,
LAYER_RENDER_BUFFER,
} from './constants';
import type { Camera } from './api';
export interface Camera {
lon: number;
lat: number;
type: string;
direction: string | null;
operator?: string;
description?: string;
}
export type { Camera };
const canUseCacheApi = typeof caches !== 'undefined';
function isValidTileUrl(url: string): boolean {
if (!url || typeof url !== 'string') return false;
if (url.startsWith('javascript:')) return false;
if (url.startsWith('data:')) {
if (!url.startsWith('data:image/')) return false;
return true;
}
try {
const parsed = new URL(url);
return parsed.protocol === 'http:' || parsed.protocol === 'https:';
} catch {
return false;
}
}
async function cachedTileLoad(imageTile: Tile, src: string) {
if (!(imageTile instanceof ImageTile)) {
return;
@@ -48,6 +58,10 @@ async function cachedTileLoad(imageTile: Tile, src: string) {
if (!(image instanceof HTMLImageElement)) {
return;
}
if (!isValidTileUrl(src)) {
console.error('Invalid tile URL:', src);
return;
}
if (!canUseCacheApi) {
image.src = src;
return;

129
src/lib/settings.ts Normal file
View File

@@ -0,0 +1,129 @@
import { writable } from 'svelte/store';
import { OVERPASS_ENDPOINTS } from './constants';
const STORAGE_KEY = 'surveilled-overpass-endpoint';
const TILE_STORAGE_KEY = 'surveilled-custom-tile-url';
const NOMINATIM_STORAGE_KEY = 'surveilled-nominatim-endpoint';
const BASEMAP_STORAGE_KEY = 'surveilled-basemap';
const FOOTER_COLLAPSED_KEY = 'surveilled-footer-collapsed';
function createOverpassSettings() {
// Default to the first endpoint in the constants
const defaultEndpoint: string = OVERPASS_ENDPOINTS[0];
// Initial value from localStorage if available
let initialEndpoint: string = defaultEndpoint;
if (typeof window !== 'undefined') {
const stored = localStorage.getItem(STORAGE_KEY);
if (stored) {
initialEndpoint = stored;
}
}
const { subscribe, set } = writable<string>(initialEndpoint);
return {
subscribe,
set: (value: string) => {
if (typeof window !== 'undefined') {
localStorage.setItem(STORAGE_KEY, value);
}
set(value);
},
reset: () => {
if (typeof window !== 'undefined') {
localStorage.removeItem(STORAGE_KEY);
}
set(defaultEndpoint);
},
};
}
export const overpassEndpoint = createOverpassSettings();
function createTileSettings() {
let initialUrl = '';
if (typeof window !== 'undefined') {
initialUrl = localStorage.getItem(TILE_STORAGE_KEY) || '';
}
const { subscribe, set } = writable<string>(initialUrl);
return {
subscribe,
set: (value: string) => {
if (typeof window !== 'undefined') {
if (value) localStorage.setItem(TILE_STORAGE_KEY, value);
else localStorage.removeItem(TILE_STORAGE_KEY);
}
set(value);
},
};
}
export const customTileUrl = createTileSettings();
function createNominatimSettings() {
let initialEndpoint = 'https://nominatim.openstreetmap.org/search';
if (typeof window !== 'undefined') {
const stored = localStorage.getItem(NOMINATIM_STORAGE_KEY);
if (stored) initialEndpoint = stored;
}
const { subscribe, set } = writable<string>(initialEndpoint);
return {
subscribe,
set: (value: string) => {
if (typeof window !== 'undefined') {
localStorage.setItem(NOMINATIM_STORAGE_KEY, value);
}
set(value);
},
};
}
export const nominatimEndpoint = createNominatimSettings();
function createBasemapSettings() {
let initialBasemap = 'dark';
if (typeof window !== 'undefined') {
const stored = localStorage.getItem(BASEMAP_STORAGE_KEY);
if (stored) initialBasemap = stored;
}
const { subscribe, set } = writable<string>(initialBasemap);
return {
subscribe,
set: (value: string) => {
if (typeof window !== 'undefined') {
localStorage.setItem(BASEMAP_STORAGE_KEY, value);
}
set(value);
},
};
}
export const basemapPreference = createBasemapSettings();
function createFooterSettings() {
let initialCollapsed = false;
if (typeof window !== 'undefined') {
initialCollapsed = localStorage.getItem(FOOTER_COLLAPSED_KEY) === 'true';
}
const { subscribe, set } = writable<boolean>(initialCollapsed);
return {
subscribe,
set: (value: boolean) => {
if (typeof window !== 'undefined') {
localStorage.setItem(FOOTER_COLLAPSED_KEY, String(value));
}
set(value);
},
};
}
export const footerCollapsedPref = createFooterSettings();

View File

@@ -1 +1,20 @@
export const APP_VERSION = import.meta.env.VITE_APP_VERSION || 'dev';
declare const __APP_VERSION__: string | undefined;
type ProcessLike = {
env?: Record<string, string | undefined>;
};
const definedVersion =
typeof __APP_VERSION__ !== 'undefined' && __APP_VERSION__ ? __APP_VERSION__ : undefined;
const processEnv =
typeof globalThis === 'object' && globalThis !== null
? ((globalThis as unknown as { process?: ProcessLike }).process?.env ?? undefined)
: undefined;
const envVersion =
typeof processEnv?.npm_package_version === 'string' && processEnv.npm_package_version
? processEnv.npm_package_version
: undefined;
export const APP_VERSION = definedVersion ?? envVersion ?? 'dev';

View File

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,4 @@
import adapter from '@sveltejs/adapter-auto';
import adapter from '@sveltejs/adapter-node';
import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';
/** @type {import('@sveltejs/kit').Config} */
@@ -8,9 +8,7 @@ const config = {
preprocess: vitePreprocess(),
kit: {
// adapter-auto only supports some environments, see https://svelte.dev/docs/kit/adapter-auto for a list.
// If your environment is not supported, or you settled on a specific environment, switch out the adapter.
// See https://svelte.dev/docs/kit/adapters for more information about adapters.
// adapter-node creates a Node.js server
adapter: adapter(),
},
};

View File

@@ -1,8 +1,18 @@
import { sveltekit } from '@sveltejs/kit/vite';
import { defineConfig } from 'vite';
import { VitePWA } from 'vite-plugin-pwa';
import pkg from './package.json' with { type: 'json' };
declare const process: {
env: Record<string, string | undefined>;
};
const appVersion = process.env.VITE_APP_VERSION ?? pkg.version ?? 'dev';
export default defineConfig({
define: {
__APP_VERSION__: JSON.stringify(appVersion),
},
plugins: [
sveltekit(),
VitePWA({