43 Commits

Author SHA1 Message Date
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
22 changed files with 1412 additions and 208 deletions

View File

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

View File

@@ -0,0 +1,66 @@
name: Build and Publish Docker Image
on:
workflow_dispatch:
push:
branches: [master]
tags: ['v*']
pull_request:
branches: [master]
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: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744
- name: Set up QEMU
uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392
with:
platforms: amd64,arm64
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435
- name: Log in to the Container registry
uses: docker/login-action@184bdaa0721073962dff0199f1fb9940f07167d1
with:
registry: ${{ env.REGISTRY }}
username: ${{ secrets.REGISTRY_USERNAME }}
password: ${{ secrets.REGISTRY_PASSWORD }}
- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@c1e51972afc2121e065aed6d45c65596fe445f3f
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: docker/build-push-action@ca052bb54ab0790a636c9b5f226502c73d547a25
with:
context: .
file: ./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,36 @@
name: Publish NPM Package
on:
workflow_dispatch:
push:
tags:
- 'v*'
jobs:
publish:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '22'
- name: Install dependencies
run: npm ci --registry=https://registry.npmjs.org/
- name: Package
run: make package
- name: Configure npm for publishing
uses: actions/setup-node@v4
with:
node-version: '22'
registry-url: 'https://git.quad4.io/api/packages/quad4-software/npm/'
- name: Publish
run: npm publish
env:
NPM_TOKEN: ${{ secrets.NPM_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}

View File

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

View File

@@ -1,40 +1,94 @@
# Surveilled
[Website](https://surveilled.quad4.io)
<img src="https://git.quad4.io/Quad4-Software/Surveilled/raw/commit/70503fcb56994c4c1bb019dfbcc3b589ebd94039/showcase/surveilled.png" alt="showcase image" width="900">
A map of cameras in the world using OpenStreetMap data.
Check out the live website at [surveilled.quad4.io](https://surveilled.quad4.io)
A map of cameras in the world using OpenStreetMap overpass data.
## 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
## Self-hosting
### NPM
```sh
npm config set @quad4:registry=https://git.quad4.io/api/packages/Quad4-Software/npm/
npm install -g @quad4/surveilled
surveilled
```
Or
```sh
PORT=8080 HOST=0.0.0.0 surveilled
```
### Docker
```sh
docker run -p 3000:3000 git.quad4.io/quad4-software/surveilled:latest
```
### Podman
```sh
podman run -p 3000:3000 git.quad4.io/quad4-software/surveilled:latest
```
## Development
```sh
git clone https://git.quad4.io/Quad4-Software/Surveilled
cd Surveilled
```
### NPM
```sh
npm install
npm run dev
```
### Makefile
```sh
make dev
```
## Building
#### Check/Lint/Format
```sh
make build
make check
make lint
make format
```
## Preview
```sh
make preview
```
## Docker
## Building Docker Image
Uses Chainguard Images which are rootless and very minimal images.
```sh
docker build -t surveilled .
docker run -p 3000:3000 surveilled
docker run --rm -p 3000:3000 surveilled
```
## Contributing
Send email to [team@quad4.io](mailto:team@quad4.io) with your feedback or any issues you may have.
## LICENSE
[MIT](LICENSE)
[MIT](LICENSE)

8
bin/surveilled.js Executable file
View File

@@ -0,0 +1,8 @@
#!/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

@@ -22,9 +22,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',

293
package-lock.json generated
View File

@@ -1,42 +1,51 @@
{
"name": "surveilled",
"version": "1.0.0",
"name": "@quad4/surveilled",
"version": "1.3.1",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "surveilled",
"version": "1.0.0",
"name": "@quad4/surveilled",
"version": "1.3.1",
"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"
},
"bin": {
"surveilled": "bin/surveilled.js"
},
"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-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"
},
"engines": {
"node": ">=18.0.0"
}
},
"node_modules/@alloc/quick-lru": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz",
"integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=10"
@@ -2403,6 +2412,7 @@
"version": "2.1.5",
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
"integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
"dev": true,
"license": "MIT",
"dependencies": {
"@nodelib/fs.stat": "2.0.5",
@@ -2416,6 +2426,7 @@
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
"integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 8"
@@ -2425,6 +2436,7 @@
"version": "1.2.8",
"resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
"integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@nodelib/fs.scandir": "2.1.5",
@@ -2447,6 +2459,64 @@
"dev": true,
"license": "MIT"
},
"node_modules/@rollup/plugin-commonjs": {
"version": "28.0.9",
"resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-28.0.9.tgz",
"integrity": "sha512-PIR4/OHZ79romx0BVVll/PkwWpJ7e5lsqFa3gFfcrFPWwLXLV39JVUzQV9RKjWerE7B845Hqjj9VYlQeieZ2dA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@rollup/pluginutils": "^5.0.1",
"commondir": "^1.0.1",
"estree-walker": "^2.0.2",
"fdir": "^6.2.0",
"is-reference": "1.2.1",
"magic-string": "^0.30.3",
"picomatch": "^4.0.2"
},
"engines": {
"node": ">=16.0.0 || 14 >= 14.17"
},
"peerDependencies": {
"rollup": "^2.68.0||^3.0.0||^4.0.0"
},
"peerDependenciesMeta": {
"rollup": {
"optional": true
}
}
},
"node_modules/@rollup/plugin-commonjs/node_modules/is-reference": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.2.1.tgz",
"integrity": "sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@types/estree": "*"
}
},
"node_modules/@rollup/plugin-json": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/@rollup/plugin-json/-/plugin-json-6.1.0.tgz",
"integrity": "sha512-EGI2te5ENk1coGeADSIwZ7G2Q8CJS2sF120T7jLw4xFw9n7wIOXHo+kIYRAoVpJAN+kmqZSoO3Fp4JtoNF4ReA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@rollup/pluginutils": "^5.1.0"
},
"engines": {
"node": ">=14.0.0"
},
"peerDependencies": {
"rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0"
},
"peerDependenciesMeta": {
"rollup": {
"optional": true
}
}
},
"node_modules/@rollup/plugin-node-resolve": {
"version": "15.3.1",
"resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-15.3.1.tgz",
@@ -2875,6 +2945,47 @@
"@sveltejs/kit": "^2.0.0"
}
},
"node_modules/@sveltejs/adapter-node": {
"version": "5.4.0",
"resolved": "https://registry.npmjs.org/@sveltejs/adapter-node/-/adapter-node-5.4.0.tgz",
"integrity": "sha512-NMsrwGVPEn+J73zH83Uhss/hYYZN6zT3u31R3IHAn3MiKC3h8fjmIAhLfTSOeNHr5wPYfjjMg8E+1gyFgyrEcQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@rollup/plugin-commonjs": "^28.0.1",
"@rollup/plugin-json": "^6.1.0",
"@rollup/plugin-node-resolve": "^16.0.0",
"rollup": "^4.9.5"
},
"peerDependencies": {
"@sveltejs/kit": "^2.4.0"
}
},
"node_modules/@sveltejs/adapter-node/node_modules/@rollup/plugin-node-resolve": {
"version": "16.0.3",
"resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-16.0.3.tgz",
"integrity": "sha512-lUYM3UBGuM93CnMPG1YocWu7X802BrNF3jW2zny5gQyLQgRFJhV1Sq0Zi74+dh/6NBx1DxFC4b4GXg9wUCG5Qg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@rollup/pluginutils": "^5.0.1",
"@types/resolve": "1.20.2",
"deepmerge": "^4.2.2",
"is-module": "^1.0.0",
"resolve": "^1.22.1"
},
"engines": {
"node": ">=14.0.0"
},
"peerDependencies": {
"rollup": "^2.78.0||^3.0.0||^4.0.0"
},
"peerDependenciesMeta": {
"rollup": {
"optional": true
}
}
},
"node_modules/@sveltejs/kit": {
"version": "2.49.2",
"resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-2.49.2.tgz",
@@ -2914,6 +3025,59 @@
}
}
},
"node_modules/@sveltejs/package": {
"version": "2.5.7",
"resolved": "https://registry.npmjs.org/@sveltejs/package/-/package-2.5.7.tgz",
"integrity": "sha512-qqD9xa9H7TDiGFrF6rz7AirOR8k15qDK/9i4MIE8te4vWsv5GEogPks61rrZcLy+yWph+aI6pIj2MdoK3YI8AQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"chokidar": "^5.0.0",
"kleur": "^4.1.5",
"sade": "^1.8.1",
"semver": "^7.5.4",
"svelte2tsx": "~0.7.33"
},
"bin": {
"svelte-package": "svelte-package.js"
},
"engines": {
"node": "^16.14 || >=18"
},
"peerDependencies": {
"svelte": "^3.44.0 || ^4.0.0 || ^5.0.0-next.1"
}
},
"node_modules/@sveltejs/package/node_modules/chokidar": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-5.0.0.tgz",
"integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==",
"dev": true,
"license": "MIT",
"dependencies": {
"readdirp": "^5.0.0"
},
"engines": {
"node": ">= 20.19.0"
},
"funding": {
"url": "https://paulmillr.com/funding/"
}
},
"node_modules/@sveltejs/package/node_modules/readdirp": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.0.0.tgz",
"integrity": "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 20.19.0"
},
"funding": {
"type": "individual",
"url": "https://paulmillr.com/funding/"
}
},
"node_modules/@sveltejs/vite-plugin-svelte": {
"version": "6.2.1",
"resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-6.2.1.tgz",
@@ -3298,12 +3462,14 @@
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz",
"integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==",
"dev": true,
"license": "MIT"
},
"node_modules/anymatch": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
"integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
"dev": true,
"license": "ISC",
"dependencies": {
"normalize-path": "^3.0.0",
@@ -3317,6 +3483,7 @@
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=8.6"
@@ -3329,6 +3496,7 @@
"version": "5.0.2",
"resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz",
"integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==",
"dev": true,
"license": "MIT"
},
"node_modules/argparse": {
@@ -3417,6 +3585,7 @@
"version": "10.4.23",
"resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.23.tgz",
"integrity": "sha512-YYTXSFulfwytnjAPlw8QHncHJmlvFKtczb8InXaAx9Q0LbfDnfEYDE55omerIJKihhmU61Ft+cAOSzQVaBUmeA==",
"dev": true,
"funding": [
{
"type": "opencollective",
@@ -3537,6 +3706,7 @@
"version": "2.9.11",
"resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.11.tgz",
"integrity": "sha512-Sg0xJUNDU1sJNGdfGWhVHX0kkZ+HWcvmVymJbj6NSgZZmW/8S9Y2HQ5euytnIgakgxN6papOAWiwDo1ctFDcoQ==",
"dev": true,
"license": "Apache-2.0",
"bin": {
"baseline-browser-mapping": "dist/cli.js"
@@ -3546,6 +3716,7 @@
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz",
"integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=8"
@@ -3568,6 +3739,7 @@
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
"integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
"dev": true,
"license": "MIT",
"dependencies": {
"fill-range": "^7.1.1"
@@ -3580,6 +3752,7 @@
"version": "4.28.1",
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz",
"integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==",
"dev": true,
"funding": [
{
"type": "opencollective",
@@ -3680,6 +3853,7 @@
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz",
"integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 6"
@@ -3689,6 +3863,7 @@
"version": "1.0.30001761",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001761.tgz",
"integrity": "sha512-JF9ptu1vP2coz98+5051jZ4PwQgd2ni8A+gYSN7EA7dPKIMf0pDlSUxhdmVOaV3/fYK5uWBkgSXJaRLr4+3A6g==",
"dev": true,
"funding": [
{
"type": "opencollective",
@@ -3771,6 +3946,7 @@
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz",
"integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 6"
@@ -3786,6 +3962,13 @@
"node": ">=4.0.0"
}
},
"node_modules/commondir": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz",
"integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==",
"dev": true,
"license": "MIT"
},
"node_modules/concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
@@ -3853,6 +4036,7 @@
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
"integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==",
"dev": true,
"license": "MIT",
"bin": {
"cssesc": "bin/cssesc"
@@ -3933,6 +4117,13 @@
}
}
},
"node_modules/dedent-js": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/dedent-js/-/dedent-js-1.0.1.tgz",
"integrity": "sha512-OUepMozQULMLUmhxS95Vudo0jb0UchLimi3+pQ2plj61Fcy8axbP9hbiD4Sz6DPqn6XG3kfmziVfQ1rSys5AJQ==",
"dev": true,
"license": "MIT"
},
"node_modules/deep-is": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
@@ -3996,12 +4187,14 @@
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz",
"integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==",
"dev": true,
"license": "Apache-2.0"
},
"node_modules/dlv": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz",
"integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==",
"dev": true,
"license": "MIT"
},
"node_modules/dunder-proto": {
@@ -4052,6 +4245,7 @@
"version": "1.5.267",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.267.tgz",
"integrity": "sha512-0Drusm6MVRXSOJpGbaSVgcQsuB4hEkMpHXaVstcPmhu5LIedxs1xNK/nIxmQIU/RPC0+1/o0AVZfBTkTNJOdUw==",
"dev": true,
"license": "ISC"
},
"node_modules/emoji-regex": {
@@ -4243,6 +4437,7 @@
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
"integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=6"
@@ -4555,6 +4750,7 @@
"version": "3.3.3",
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz",
"integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@nodelib/fs.stat": "^2.0.2",
@@ -4571,6 +4767,7 @@
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
"integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
"dev": true,
"license": "ISC",
"dependencies": {
"is-glob": "^4.0.1"
@@ -4614,6 +4811,7 @@
"version": "1.20.1",
"resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz",
"integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==",
"dev": true,
"license": "ISC",
"dependencies": {
"reusify": "^1.0.4"
@@ -4623,6 +4821,7 @@
"version": "6.5.0",
"resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
"integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=12.0.0"
@@ -4676,6 +4875,7 @@
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
"integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
"dev": true,
"license": "MIT",
"dependencies": {
"to-regex-range": "^5.0.1"
@@ -4759,6 +4959,7 @@
"version": "5.3.4",
"resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-5.3.4.tgz",
"integrity": "sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==",
"dev": true,
"license": "MIT",
"engines": {
"node": "*"
@@ -4788,6 +4989,7 @@
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
"integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
"dev": true,
"hasInstallScript": true,
"license": "MIT",
"optional": true,
@@ -4802,6 +5004,7 @@
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
"integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
"dev": true,
"license": "MIT",
"funding": {
"url": "https://github.com/sponsors/ljharb"
@@ -4969,6 +5172,7 @@
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
"integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
"dev": true,
"license": "ISC",
"dependencies": {
"is-glob": "^4.0.3"
@@ -5128,6 +5332,7 @@
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
"integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"function-bind": "^1.1.2"
@@ -5253,6 +5458,7 @@
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
"integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
"dev": true,
"license": "MIT",
"dependencies": {
"binary-extensions": "^2.0.0"
@@ -5295,6 +5501,7 @@
"version": "2.16.1",
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz",
"integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==",
"dev": true,
"license": "MIT",
"dependencies": {
"hasown": "^2.0.2"
@@ -5345,6 +5552,7 @@
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
"integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=0.10.0"
@@ -5400,6 +5608,7 @@
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
"integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
"dev": true,
"license": "MIT",
"dependencies": {
"is-extglob": "^2.1.1"
@@ -5445,6 +5654,7 @@
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=0.12.0"
@@ -5706,6 +5916,7 @@
"version": "1.21.7",
"resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz",
"integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==",
"dev": true,
"license": "MIT",
"bin": {
"jiti": "bin/jiti.js"
@@ -5879,6 +6090,7 @@
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
"integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==",
"dev": true,
"license": "MIT"
},
"node_modules/locate-character": {
@@ -5973,6 +6185,7 @@
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
"integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 8"
@@ -5982,6 +6195,7 @@
"version": "4.0.8",
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
"integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
"dev": true,
"license": "MIT",
"dependencies": {
"braces": "^3.0.3",
@@ -5995,6 +6209,7 @@
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=8.6"
@@ -6060,6 +6275,7 @@
"version": "2.7.0",
"resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz",
"integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==",
"dev": true,
"license": "MIT",
"dependencies": {
"any-promise": "^1.0.0",
@@ -6071,6 +6287,7 @@
"version": "3.3.11",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz",
"integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==",
"dev": true,
"funding": [
{
"type": "github",
@@ -6096,12 +6313,14 @@
"version": "2.0.27",
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz",
"integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==",
"dev": true,
"license": "MIT"
},
"node_modules/normalize-path": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
"integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=0.10.0"
@@ -6111,6 +6330,7 @@
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
"integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=0.10.0"
@@ -6120,6 +6340,7 @@
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz",
"integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 6"
@@ -6310,6 +6531,7 @@
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
"dev": true,
"license": "MIT"
},
"node_modules/path-scurry": {
@@ -6355,12 +6577,14 @@
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
"integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
"dev": true,
"license": "ISC"
},
"node_modules/picomatch": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=12"
@@ -6373,6 +6597,7 @@
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
"integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=0.10.0"
@@ -6382,6 +6607,7 @@
"version": "4.0.7",
"resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz",
"integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 6"
@@ -6401,6 +6627,7 @@
"version": "8.5.6",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz",
"integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==",
"dev": true,
"funding": [
{
"type": "opencollective",
@@ -6429,6 +6656,7 @@
"version": "15.1.0",
"resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz",
"integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==",
"dev": true,
"license": "MIT",
"dependencies": {
"postcss-value-parser": "^4.0.0",
@@ -6446,6 +6674,7 @@
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.1.0.tgz",
"integrity": "sha512-oIAOTqgIo7q2EOwbhb8UalYePMvYoIeRY2YKntdpFQXNosSu3vLrniGgmH9OKs/qAkfoj5oB3le/7mINW1LCfw==",
"dev": true,
"funding": [
{
"type": "opencollective",
@@ -6511,6 +6740,7 @@
"version": "6.2.0",
"resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.2.0.tgz",
"integrity": "sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==",
"dev": true,
"funding": [
{
"type": "opencollective",
@@ -6536,6 +6766,7 @@
"version": "6.1.2",
"resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz",
"integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==",
"dev": true,
"license": "MIT",
"dependencies": {
"cssesc": "^3.0.0",
@@ -6617,6 +6848,7 @@
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz",
"integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==",
"dev": true,
"license": "MIT"
},
"node_modules/prelude-ls": {
@@ -6689,6 +6921,7 @@
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
"integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
"dev": true,
"funding": [
{
"type": "github",
@@ -6746,6 +6979,7 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz",
"integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==",
"dev": true,
"license": "MIT",
"dependencies": {
"pify": "^2.3.0"
@@ -6881,6 +7115,7 @@
"version": "1.22.11",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz",
"integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"is-core-module": "^2.16.1",
@@ -6920,6 +7155,7 @@
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz",
"integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==",
"dev": true,
"license": "MIT",
"engines": {
"iojs": ">=1.0.0",
@@ -6972,6 +7208,7 @@
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
"integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
"dev": true,
"funding": [
{
"type": "github",
@@ -7080,6 +7317,13 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/scule": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/scule/-/scule-1.3.0.tgz",
"integrity": "sha512-6FtHJEvt+pVMIB9IBY+IcCJ6Z5f1iQnytgyfKMhDKgmzYG+TeH/wx1y3l27rshSbLiSanrR9ffZDrEsmjlQF2g==",
"dev": true,
"license": "MIT"
},
"node_modules/semver": {
"version": "7.7.3",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz",
@@ -7311,6 +7555,7 @@
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
"integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
"dev": true,
"license": "BSD-3-Clause",
"engines": {
"node": ">=0.10.0"
@@ -7592,6 +7837,7 @@
"version": "3.35.1",
"resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.1.tgz",
"integrity": "sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jridgewell/gen-mapping": "^0.3.2",
@@ -7627,6 +7873,7 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
"integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 0.4"
@@ -7728,10 +7975,26 @@
"url": "https://opencollective.com/eslint"
}
},
"node_modules/svelte2tsx": {
"version": "0.7.46",
"resolved": "https://registry.npmjs.org/svelte2tsx/-/svelte2tsx-0.7.46.tgz",
"integrity": "sha512-S++Vw3w47a8rBuhbz4JK0fcGea8tOoX1boT53Aib8+oUO2EKeOG+geXprJVTDfBlvR+IJdf3jIpR2RGwT6paQA==",
"dev": true,
"license": "MIT",
"dependencies": {
"dedent-js": "^1.0.1",
"scule": "^1.3.0"
},
"peerDependencies": {
"svelte": "^3.55 || ^4.0.0-next.0 || ^4.0 || ^5.0.0-next.0",
"typescript": "^4.9.4 || ^5.0.0"
}
},
"node_modules/tailwindcss": {
"version": "3.4.19",
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.19.tgz",
"integrity": "sha512-3ofp+LL8E+pK/JuPLPggVAIaEuhvIz4qNcf3nA1Xn2o/7fb7s/TYpHhwGDv1ZU3PkBluUVaF8PyCHcm48cKLWQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@alloc/quick-lru": "^5.2.0",
@@ -7769,6 +8032,7 @@
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
"integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==",
"dev": true,
"license": "MIT",
"dependencies": {
"anymatch": "~3.1.2",
@@ -7793,6 +8057,7 @@
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
"integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
"dev": true,
"license": "ISC",
"dependencies": {
"is-glob": "^4.0.1"
@@ -7805,6 +8070,7 @@
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz",
"integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=14"
@@ -7817,6 +8083,7 @@
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=8.6"
@@ -7829,6 +8096,7 @@
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-6.0.1.tgz",
"integrity": "sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==",
"dev": true,
"funding": [
{
"type": "opencollective",
@@ -7871,6 +8139,7 @@
"version": "6.1.2",
"resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz",
"integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==",
"dev": true,
"license": "MIT",
"dependencies": {
"cssesc": "^3.0.0",
@@ -7884,6 +8153,7 @@
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
"integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
"dev": true,
"license": "MIT",
"dependencies": {
"picomatch": "^2.2.1"
@@ -7951,6 +8221,7 @@
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz",
"integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==",
"dev": true,
"license": "MIT",
"dependencies": {
"any-promise": "^1.0.0"
@@ -7960,6 +8231,7 @@
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz",
"integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==",
"dev": true,
"license": "MIT",
"dependencies": {
"thenify": ">= 3.1.0 < 4"
@@ -7972,6 +8244,7 @@
"version": "0.2.15",
"resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz",
"integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"fdir": "^6.5.0",
@@ -7988,6 +8261,7 @@
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"is-number": "^7.0.0"
@@ -8033,6 +8307,7 @@
"version": "0.1.13",
"resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz",
"integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==",
"dev": true,
"license": "Apache-2.0"
},
"node_modules/type-check": {
@@ -8254,6 +8529,7 @@
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz",
"integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==",
"dev": true,
"funding": [
{
"type": "opencollective",
@@ -8294,6 +8570,7 @@
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
"dev": true,
"license": "MIT"
},
"node_modules/vite": {

View File

@@ -1,41 +1,70 @@
{
"name": "surveilled",
"private": true,
"version": "1.0.0",
"name": "@quad4/surveilled",
"version": "1.3.1",
"type": "module",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
"bin": {
"surveilled": "./bin/surveilled.js"
},
"engines": {
"node": ">=18.0.0"
},
"publishConfig": {
"registry": "https://git.quad4.io/api/packages/quad4-software/npm/"
},
"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-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"
}
}

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

@@ -28,18 +28,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 +57,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({