From 350547fcfdef9b3180a34a4bcdb94c7924b53b98 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Thu, 12 Feb 2026 01:33:48 +0000 Subject: [PATCH 1/7] docs: archive changelog for v0.7.12 [skip ci] --- .changelog/{v0.7.x.md => v0.7.12.md} | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename .changelog/{v0.7.x.md => v0.7.12.md} (95%) diff --git a/.changelog/v0.7.x.md b/.changelog/v0.7.12.md similarity index 95% rename from .changelog/v0.7.x.md rename to .changelog/v0.7.12.md index 6461c9d8..55ee07bb 100644 --- a/.changelog/v0.7.x.md +++ b/.changelog/v0.7.12.md @@ -1,4 +1,4 @@ -# Release v0.7.x - Migration Map, AI Discovery Improvements +# Release v0.7.12 - Migration Map, AI Discovery Improvements Released: Unreleased @@ -23,7 +23,7 @@ This release improves the AI Discovery feature with dismiss functionality, debug - GET `/api/ai-discovery/debug/runs/:runId` - detailed run info including prompt preview and output - Error details capture (last 10 lines of stderr/stdout) stored on failed runs -### Migration Map Visualization (v0.7.x) +### Migration Map Visualization (v0.7.12) - New 6th tree view mode: "Migration Map" plots ancestors on an interactive world map - Leaflet.js map with OpenStreetMap/CartoDB dark tiles - Lineage-colored markers (paternal=blue, maternal=red) with generation depth variation From c71d5acea706e2f97c912ff4b6d538251b25c42e Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Thu, 12 Feb 2026 01:34:00 +0000 Subject: [PATCH 2/7] build: prep v0.8.0 for next release [skip ci] --- client/package.json | 2 +- package-lock.json | 10 +++++----- package.json | 2 +- server/package.json | 2 +- shared/package.json | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/client/package.json b/client/package.json index 6eb95e0f..0a7d3ee5 100644 --- a/client/package.json +++ b/client/package.json @@ -1,6 +1,6 @@ { "name": "@fsf/client", - "version": "0.7.12", + "version": "0.8.0", "type": "module", "scripts": { "dev": "vite --port 6373", diff --git a/package-lock.json b/package-lock.json index e95fc62a..e42cef63 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "sparsetree", - "version": "0.7.12", + "version": "0.8.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "sparsetree", - "version": "0.7.12", + "version": "0.8.0", "license": "ISC", "workspaces": [ "shared", @@ -59,7 +59,7 @@ }, "client": { "name": "@fsf/client", - "version": "0.7.12", + "version": "0.8.0", "dependencies": { "@fsf/shared": "*", "d3": "^7.9.0", @@ -8404,7 +8404,7 @@ }, "server": { "name": "@fsf/server", - "version": "0.7.12", + "version": "0.8.0", "dependencies": { "@fsf/shared": "*", "better-sqlite3": "^12.6.2", @@ -8427,7 +8427,7 @@ }, "shared": { "name": "@fsf/shared", - "version": "0.7.12", + "version": "0.8.0", "devDependencies": { "typescript": "^5.7.2" } diff --git a/package.json b/package.json index f3e7da16..d3d7f04b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "sparsetree", - "version": "0.7.12", + "version": "0.8.0", "private": true, "description": "", "main": "index.js", diff --git a/server/package.json b/server/package.json index 618321e2..804e3a8e 100644 --- a/server/package.json +++ b/server/package.json @@ -1,6 +1,6 @@ { "name": "@fsf/server", - "version": "0.7.12", + "version": "0.8.0", "type": "module", "main": "dist/index.js", "scripts": { diff --git a/shared/package.json b/shared/package.json index fbf4ba71..8ff437f5 100644 --- a/shared/package.json +++ b/shared/package.json @@ -1,6 +1,6 @@ { "name": "@fsf/shared", - "version": "0.7.12", + "version": "0.8.0", "type": "module", "main": "types/index.js", "types": "types/index.d.ts", From 3189e81a2d3795e5a77dc0c4db94afcf9b7fd859 Mon Sep 17 00:00:00 2001 From: Adam Eivy Date: Fri, 20 Feb 2026 23:57:02 -0800 Subject: [PATCH 3/7] fix: security hardening, DRY cleanup, bug fixes, and CI version bump removal Remediate 95 code review findings across 7 phases: - Add 12 shared server utils and 2 client hooks to eliminate duplication - Harden security: path traversal, FTS injection, CORS, URL validation, body whitelisting - Fix bugs: infinite loops, memory leaks, stale closures, missing cleanup, type errors - Wrap async routes with error handler, wire up request timeout middleware - Remove CI auto-increment of version numbers (now handled in dev commits) - Add PWA support (favicon, manifest, apple-touch-icon) --- .changelog/v0.8.x.md | 48 ++ .github/workflows/ci.yml | 40 +- .github/workflows/release.yml | 18 +- .gitignore | 5 +- client/index.html | 9 +- client/package.json | 2 +- client/public/apple-touch-icon.png | Bin 0 -> 12677 bytes client/public/favicon.ico | Bin 0 -> 4286 bytes client/public/favicon.svg | 55 ++ client/public/icon-192.png | Bin 0 -> 12033 bytes client/public/icon-512.png | Bin 0 -> 36515 bytes client/public/manifest.json | 27 + .../components/favorites/SparseTreePage.tsx | 5 + client/src/components/indexer/IndexerPage.tsx | 123 ++-- .../components/integrity/IntegrityPage.tsx | 46 +- client/src/components/person/PersonDetail.tsx | 146 ++-- client/src/components/search/SearchPage.tsx | 26 +- client/src/hooks/useBrowserConnection.ts | 68 ++ client/src/hooks/useSSE.ts | 42 ++ client/src/hooks/useSocket.ts | 26 +- client/src/pages/BrowserSettingsPage.tsx | 66 +- client/src/pages/GedcomPage.tsx | 3 - client/src/pages/GenealogyProviders.tsx | 66 +- client/src/pages/ReportsPage.tsx | 47 +- client/src/services/api.ts | 2 +- package-lock.json | 43 +- package.json | 2 +- scripts/calc-generations.ts | 3 +- scripts/create-sample-data.ts | 18 +- scripts/find.ts | 17 +- scripts/index.ts | 18 +- scripts/migrate-augment-ids.ts | 8 +- scripts/migrate-photos-to-blobs.ts | 8 +- scripts/migrate-to-sqlite.ts | 640 ++++++++---------- scripts/migrate.ts | 3 +- scripts/print.ts | 15 +- scripts/purge.ts | 39 +- scripts/rebuild.ts | 22 +- scripts/utils/logPerson.ts | 16 +- server/package.json | 2 +- .../src/db/migrations/002_expanded_facts.ts | 14 +- server/src/db/sqlite.service.ts | 7 +- server/src/index.ts | 8 +- server/src/lib/familysearch/fetcher.ts | 4 +- server/src/lib/sqlite-writer.ts | 35 +- server/src/middleware/errorHandler.ts | 2 +- server/src/routes/ancestry-hints.routes.ts | 6 +- server/src/routes/ancestry-update.routes.ts | 6 +- server/src/routes/augmentation.routes.ts | 151 ++--- server/src/routes/browser.routes.ts | 51 +- server/src/routes/favorites.routes.ts | 9 +- .../src/routes/genealogy-provider.routes.ts | 9 +- server/src/routes/integrity.routes.ts | 6 +- server/src/routes/map.routes.ts | 18 +- server/src/routes/person.routes.ts | 153 +---- server/src/routes/provider.routes.ts | 21 +- server/src/routes/sync.routes.ts | 13 +- server/src/services/ai-discovery.service.ts | 14 +- server/src/services/ancestry-hints.service.ts | 74 +- server/src/services/ancestry-tree.service.ts | 17 +- .../src/services/ancestry-update.service.ts | 70 +- .../src/services/ancestry-upload.service.ts | 5 +- server/src/services/augmentation.service.ts | 213 ++---- server/src/services/blob.service.ts | 3 +- server/src/services/browser.service.ts | 5 +- server/src/services/bulk-discovery.service.ts | 64 +- server/src/services/credentials.service.ts | 5 +- server/src/services/database.service.ts | 77 +-- .../services/familysearch-redirect.service.ts | 4 +- .../services/familysearch-refresh.service.ts | 7 +- .../services/familysearch-upload.service.ts | 5 +- server/src/services/favorites.service.ts | 28 +- server/src/services/gedcom.service.ts | 6 +- .../services/genealogy-provider.service.ts | 5 +- server/src/services/id-mapping.service.ts | 16 +- server/src/services/integrity.service.ts | 9 +- .../multi-platform-comparison.service.ts | 109 +-- server/src/services/path.service.ts | 50 +- server/src/services/person.service.ts | 1 + server/src/services/provider.service.ts | 5 +- server/src/services/scraper.service.ts | 55 +- server/src/services/search.service.ts | 22 +- server/src/services/sparse-tree.service.ts | 52 +- server/src/services/sync.service.ts | 3 +- server/src/utils/applyOverrides.ts | 70 ++ server/src/utils/asyncHandler.ts | 13 + server/src/utils/batchFetchPersons.ts | 43 ++ server/src/utils/browserConnect.ts | 33 + server/src/utils/downloadImage.ts | 57 ++ server/src/utils/lifespan.ts | 10 + server/src/utils/operationTracker.ts | 52 ++ server/src/utils/parseYear.ts | 33 + server/src/utils/paths.ts | 35 + server/src/utils/resolveCanonical.ts | 22 + server/src/utils/sseHelpers.ts | 18 + server/src/utils/validation.ts | 54 ++ shared/package.json | 2 +- shared/src/index.ts | 2 +- 98 files changed, 1689 insertions(+), 1916 deletions(-) create mode 100644 .changelog/v0.8.x.md create mode 100644 client/public/apple-touch-icon.png create mode 100644 client/public/favicon.ico create mode 100644 client/public/favicon.svg create mode 100644 client/public/icon-192.png create mode 100644 client/public/icon-512.png create mode 100644 client/public/manifest.json create mode 100644 client/src/hooks/useBrowserConnection.ts create mode 100644 client/src/hooks/useSSE.ts create mode 100644 server/src/utils/applyOverrides.ts create mode 100644 server/src/utils/asyncHandler.ts create mode 100644 server/src/utils/batchFetchPersons.ts create mode 100644 server/src/utils/browserConnect.ts create mode 100644 server/src/utils/downloadImage.ts create mode 100644 server/src/utils/lifespan.ts create mode 100644 server/src/utils/operationTracker.ts create mode 100644 server/src/utils/parseYear.ts create mode 100644 server/src/utils/paths.ts create mode 100644 server/src/utils/resolveCanonical.ts create mode 100644 server/src/utils/sseHelpers.ts create mode 100644 server/src/utils/validation.ts diff --git a/.changelog/v0.8.x.md b/.changelog/v0.8.x.md new file mode 100644 index 00000000..3972aea7 --- /dev/null +++ b/.changelog/v0.8.x.md @@ -0,0 +1,48 @@ +# v0.8.x + +## Added +- 12 shared server utilities (`paths`, `downloadImage`, `parseYear`, `lifespan`, `validation`, `asyncHandler`, `sseHelpers`, `operationTracker`, `resolveCanonical`, `browserConnect`, `applyOverrides`, `batchFetchPersons`) +- `useBrowserConnection` and `useSSE` client hooks for deduplication +- Path traversal defense-in-depth across all file-serving endpoints +- FTS5 query sanitization for search +- CORS origin restriction via `CORS_ORIGIN` env var +- Request body whitelisting on provider/browser routes +- URL validation replacing string `includes()` checks +- `--dry-run` flag for purge script +- AbortController cleanup on PersonDetail navigation +- PWA support: favicon, manifest, apple-touch-icon, theme-color + +## Changed +- CI no longer auto-increments version on push to dev +- Release workflow no longer bumps version after release (changelog archiving preserved) +- CI permissions downgraded from `contents: write` to `contents: read` +- `process.exit(1)` in fetcher replaced with typed error +- ID mapping cache changed from FIFO to LRU eviction +- AI discovery runs bounded with MAX_STORED_RUNS limit +- Path finding guarded against infinite loops +- Error handler now logs stack traces +- `requestTimeout` middleware wired up +- `Person.parents` type corrected to `(string | null)[]` +- Scripts standardized on `import.meta.dirname` and shared types + +## Fixed +- `person_computed` view multi-row bug in vital event joins +- `typeof gen !== '?'` bug in logPerson +- Stale closures in IntegrityPage loader functions +- D3 zoom cleanup missing in SparseTreePage +- `useSocket` spread in deps array causing re-renders +- `useSocketConnection` returning stale snapshot instead of reactive state +- Dead state (`setScrapedData`, `setImportFile`) removed +- Safe JSON.parse on localStorage in PersonDetail +- Purge script whole-token matching (prevents partial ID matches) +- Migration script wrapped in transaction + +## Removed +- 20+ duplicate `DATA_DIR` declarations across services +- 3 duplicate `downloadImage` implementations +- 7 duplicate SSE header setup blocks +- 15 duplicate ULID validation blocks in person routes +- 3 duplicate browser connection blocks +- 3 duplicate operation tracker implementations +- 6 duplicate photo-serve route handlers +- Duplicate `BrowserStatus` interface in IndexerPage diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b3b5f3f8..30f757e3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,7 +12,7 @@ concurrency: cancel-in-progress: true permissions: - contents: write + contents: read jobs: build: @@ -151,41 +151,3 @@ jobs: name: scraper-test-results path: test-results/ retention-days: 7 - - bump-version: - name: Bump Version - runs-on: ubuntu-latest - needs: [unit-tests, integration-tests, scraper-tests] - # Only on push to dev, not PRs, and only if all tests passed - if: | - github.event_name == 'push' && - github.ref == 'refs/heads/dev' && - !contains(github.event.head_commit.message, '[skip ci]') - - steps: - - uses: actions/checkout@v4 - with: - token: ${{ secrets.GITHUB_TOKEN }} - - - name: Configure git - run: | - git config user.name "github-actions[bot]" - git config user.email "github-actions[bot]@users.noreply.github.com" - - - name: Bump patch version - run: | - CURRENT_VERSION=$(node -p "require('./package.json').version") - MAJOR=$(echo $CURRENT_VERSION | cut -d. -f1) - MINOR=$(echo $CURRENT_VERSION | cut -d. -f2) - PATCH=$(echo $CURRENT_VERSION | cut -d. -f3) - NEW_PATCH=$((PATCH + 1)) - NEW_VERSION="$MAJOR.$MINOR.$NEW_PATCH" - - npm version $NEW_VERSION --no-git-tag-version - cd shared && npm version $NEW_VERSION --no-git-tag-version && cd .. - cd client && npm version $NEW_VERSION --no-git-tag-version && cd .. - cd server && npm version $NEW_VERSION --no-git-tag-version && cd .. - - git add package.json package-lock.json shared/package.json client/package.json server/package.json - git commit -m "build: bump version to $NEW_VERSION [skip ci]" - git push diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 10086932..d575d011 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -100,19 +100,14 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - name: Prep dev branch for next release + - name: Archive changelog on dev branch if: steps.tag-check.outputs.exists == 'false' run: | - # Get current version (the one we just released) CURRENT_VERSION=${{ steps.package-version.outputs.version }} MAJOR=$(echo $CURRENT_VERSION | cut -d. -f1) MINOR=$(echo $CURRENT_VERSION | cut -d. -f2) MAJOR_MINOR="$MAJOR.$MINOR" - # Increment minor, reset patch to 0 - NEW_MINOR=$((MINOR + 1)) - NEW_VERSION="$MAJOR.$NEW_MINOR.0" - # Checkout dev branch git fetch origin dev git checkout dev @@ -143,14 +138,3 @@ jobs: git push origin main git checkout dev fi - - # Update package.json files for next version - npm version $NEW_VERSION --no-git-tag-version - cd shared && npm version $NEW_VERSION --no-git-tag-version && cd .. - cd client && npm version $NEW_VERSION --no-git-tag-version && cd .. - cd server && npm version $NEW_VERSION --no-git-tag-version && cd .. - - # Commit and push version bump - git add package.json package-lock.json shared/package.json client/package.json server/package.json - git commit -m "build: prep v$NEW_VERSION for next release [skip ci]" - git push origin dev diff --git a/.gitignore b/.gitignore index f2ab2667..917284b4 100644 --- a/.gitignore +++ b/.gitignore @@ -25,4 +25,7 @@ client/public/playwright-report/ # Screenshots (may contain personal family data) images/ -.playwright-mcp \ No newline at end of file +.playwright-mcp + +# Terminal themes +.ghostty-theme \ No newline at end of file diff --git a/client/index.html b/client/index.html index 1e0db263..d2ed38be 100644 --- a/client/index.html +++ b/client/index.html @@ -2,9 +2,16 @@ - SparseTree + + + + + + + +