mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-06 19:34:01 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
65bc522f49 | ||
|
|
ae66e9d299 | ||
|
|
d399dfc92d | ||
|
|
53a5f01a79 | ||
|
|
39d33b3f29 | ||
|
|
d8f1742783 | ||
|
|
9db0813daf | ||
|
|
6b7bca2913 |
No files matched your search
@@ -3,6 +3,38 @@
|
||||
This changelog records public product changes. For the authoritative description
|
||||
of current runtime behavior, see [`docs/CURRENT-STATE.md`](docs/CURRENT-STATE.md).
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [0.1.1] — 2026-09-01 — Installation and live-data fixes
|
||||
|
||||
### Changed
|
||||
|
||||
- Tightened the README opening around keyless setup, source freshness, modeled
|
||||
experiences, and the accessibility of the provider stack.
|
||||
|
||||
### Fixed
|
||||
|
||||
- Pinokio now recognizes its nested successful-install marker, so a completed
|
||||
one-click install exposes Start instead of returning to Install.
|
||||
- The keyless `dev-fresh.sh` startup summary now names Esri World Imagery with
|
||||
keyless terrain and identifies OpenStreetMap as the fallback.
|
||||
- All three VIIRS sources now reach the Active Fires layer. Merging a source's
|
||||
detections used argument spread, which exceeds the engine's argument limit on
|
||||
the two largest sources and dropped them entirely — leaving roughly a third of
|
||||
global detections while reporting each dropped source twice, once as
|
||||
successful with its real count and once as failed.
|
||||
- `./scripts/dev-fresh.sh` no longer crashes on stock macOS bash 3.2 when no
|
||||
provider keys are exported: expanding the empty external-keys provenance
|
||||
array under `set -u` was fatal there. Launches with exported keys are
|
||||
unchanged.
|
||||
|
||||
### Security
|
||||
|
||||
- GBFS proxy body-size cap now measures the response in bytes
|
||||
(`Buffer.byteLength`) instead of JavaScript string length, so the
|
||||
`GBFS_MAX_BODY_BYTES` limit holds for multi-byte payloads and cannot be
|
||||
overrun by non-ASCII upstream responses.
|
||||
|
||||
## [0.1.0] — 2026-08-31 — One-click install, keyless boot, Provider Settings
|
||||
|
||||
### Added
|
||||
|
||||
@@ -20,7 +20,7 @@ Photorealistic 3D globe. Live aircraft, ships, satellites, earthquakes, traffic,
|
||||
|
||||
🏆 **#1 on GitHub Trending this past week — thank you.** You asked for a one-click install; it's here.
|
||||
|
||||
⚡ **No keys, no signup, no config file.** One click through [Pinokio](https://pinokio.computer/) — or `npm install && npm run dev` — and the globe is live: real aircraft, real satellites, real cameras. Keys are power-ups you paste into the app later. **[→ Quick Start](#-quick-start)**
|
||||
⚡ **No keys, no signup, no config file.** One click through [Pinokio](https://pinokio.computer/) — or `npm install && npm run dev` — and the globe comes to life. Keys are power-ups you paste into the app later. **[→ Quick Start](#-quick-start)**
|
||||
|
||||
</div>
|
||||
|
||||
@@ -42,10 +42,13 @@ Most open-source intelligence is a pile of browser tabs. The signals are abundan
|
||||
|
||||
> Half the magic is that it looks like a forbidden cockpit. The other half is that every line of code is inspectable.
|
||||
|
||||
Most feeds are live; explicitly labeled traffic, camera-pose, and launch
|
||||
experiences may be simulated, estimated, or reconstructed.
|
||||
Most feeds are live or regularly refreshed. Traffic is simulated along real
|
||||
roads using aggregate location data. CCTV camera poses and rocket launch
|
||||
trajectories are coarse estimates.
|
||||
|
||||
And it's honest about money: the best free and nearly-free APIs give you the real experience out of the box — then it's yours to extend with bigger, more expensive data sources whenever you're ready.
|
||||
You'll be surprised how accessible this is. Free and nearly-free APIs deliver
|
||||
a surprisingly complete experience out of the box — then it's yours to extend
|
||||
with bigger data sources whenever you're ready.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -2253,6 +2253,10 @@ silently demoting every later lookup for the session.
|
||||
## Auth + Launch
|
||||
|
||||
- Recommended launcher: `./scripts/dev-fresh.sh` (also: `dev-secure.sh` for stricter bindings, `dev-cctv.sh` for CCTV source-pack tuning)
|
||||
- A successful Pinokio install writes the owner-only `pinokio/.installed`
|
||||
marker. The nested launcher menu resolves that marker from its own directory:
|
||||
an absent marker exposes Install, a present marker exposes Start, and a
|
||||
running server with a captured ready URL exposes Open God's Eye View.
|
||||
- Build gate: `npm run build`
|
||||
- Network access: local-only by default (`HOST=localhost` in dev-fresh.sh); LAN is an explicit opt-in via `HOST=0.0.0.0` (launcher prints a key-exposure warning + LAN URL; see SECURITY.md)
|
||||
- OpenSky default mode: OAuth (`OPENSKY_AUTH_MODE=oauth`; `anon` works without credentials)
|
||||
|
||||
Generated
+2
-2
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "gods-eye-view",
|
||||
"version": "0.1.0",
|
||||
"version": "0.1.1",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "gods-eye-view",
|
||||
"version": "0.1.0",
|
||||
"version": "0.1.1",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@mapbox/vector-tile": "^3.0.0",
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "gods-eye-view",
|
||||
"private": true,
|
||||
"version": "0.1.0",
|
||||
"version": "0.1.1",
|
||||
"description": "A real-time intelligence console for planet Earth — photorealistic 3D globe, live aircraft/ships/satellites/earthquakes/CCTV, and hands-free voice control. Runs in a browser.",
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
|
||||
+2
-2
@@ -2,8 +2,8 @@ module.exports = {
|
||||
version: '3.6',
|
||||
title: "God's Eye View",
|
||||
description: 'A live 3D intelligence console for planet Earth.',
|
||||
menu: async (_kernel, info) => {
|
||||
const installed = info.exists('.installed');
|
||||
menu: async (kernel, info) => {
|
||||
const installed = await kernel.exists(__dirname, '.installed');
|
||||
const installing = info.running('install.js');
|
||||
const starting = info.running('start.js');
|
||||
const updating = info.running('update.js');
|
||||
|
||||
@@ -38,7 +38,7 @@ KEY_SETUP_EXTERNAL_KEYS=()
|
||||
[[ -n "${OPENSKY_CLIENT_ID:-}" ]] && KEY_SETUP_EXTERNAL_KEYS+=(OPENSKY_CLIENT_ID)
|
||||
[[ -n "${OPENSKY_CLIENT_SECRET:-}" ]] && KEY_SETUP_EXTERNAL_KEYS+=(OPENSKY_CLIENT_SECRET)
|
||||
[[ -n "${LL2_API_TOKEN:-}" ]] && KEY_SETUP_EXTERNAL_KEYS+=(LL2_API_TOKEN)
|
||||
KEY_SETUP_EXTERNAL_KEYS_CSV="$(IFS=,; printf '%s' "${KEY_SETUP_EXTERNAL_KEYS[*]}")"
|
||||
KEY_SETUP_EXTERNAL_KEYS_CSV="$(IFS=,; printf '%s' "${KEY_SETUP_EXTERNAL_KEYS[*]:-}")"
|
||||
|
||||
if command -v npm >/dev/null 2>&1; then
|
||||
DEV_COMMAND=(npm run dev --)
|
||||
@@ -329,7 +329,7 @@ if [[ -n "${GOOGLE_MAPS_API_KEY}" ]]; then
|
||||
elif [[ -n "${CESIUM_ION_TOKEN}" ]]; then
|
||||
echo "Startup map: Google Photorealistic 3D Tiles (Cesium ion)"
|
||||
else
|
||||
echo "Startup map: OpenStreetMap with keyless terrain"
|
||||
echo "Startup map: Esri World Imagery with keyless terrain (OpenStreetMap fallback)"
|
||||
fi
|
||||
[[ -n "${CESIUM_ION_TOKEN}" ]] && echo "Cesium ion token: configured — Google 3D, Bing, and world-terrain stacks available" || echo "Cesium ion token: not set"
|
||||
[[ -n "${TOMTOM_API_KEY}" ]] && echo "TomTom key (live traffic flow): configured" || echo "TomTom key (live traffic flow): not set — simulated traffic"
|
||||
|
||||
@@ -79,3 +79,56 @@ test('dev-fresh passes names-only boot provenance before resolving file fallback
|
||||
assert.match(source, /put_env GEV_LAUNCHER "dev-fresh"/);
|
||||
assert.match(source, /put_env GEV_KEY_SETUP_EXTERNAL_KEYS "\$\{KEY_SETUP_EXTERNAL_KEYS_CSV\}"/);
|
||||
});
|
||||
|
||||
const bashTest = process.platform === 'win32' ? test.skip : test;
|
||||
|
||||
bashTest('dev-fresh reports the real keyless startup map and fallback', async () => {
|
||||
const script = await fs.readFile(new URL('../scripts/dev-fresh.sh', import.meta.url), 'utf8');
|
||||
const start = script.indexOf('if [[ -n "${GOOGLE_MAPS_API_KEY}" ]]; then\n echo "Startup map:');
|
||||
const end = script.indexOf('\nfi', start);
|
||||
assert.ok(start >= 0 && end > start, 'startup-map status block not found in dev-fresh.sh');
|
||||
const block = script.slice(start, end + 3);
|
||||
assert.doesNotMatch(block, /Startup map: OpenStreetMap with keyless terrain/);
|
||||
|
||||
const { execFile } = await import('node:child_process');
|
||||
const { promisify } = await import('node:util');
|
||||
const run = promisify(execFile);
|
||||
const keyless = await run('bash', ['-c', block], {
|
||||
env: {
|
||||
PATH: process.env.PATH,
|
||||
GOOGLE_MAPS_API_KEY: '',
|
||||
CESIUM_ION_TOKEN: '',
|
||||
},
|
||||
});
|
||||
assert.equal(
|
||||
keyless.stdout.trim(),
|
||||
'Startup map: Esri World Imagery with keyless terrain (OpenStreetMap fallback)',
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
// Stock macOS ships bash 3.2, where expanding an EMPTY array under `set -u`
|
||||
// is a fatal "unbound variable" — the `:-` guard on the provenance CSV is what
|
||||
// keeps the keyless `dev-fresh.sh` launch alive there. Newer bash never fails
|
||||
// this way, so the idiom itself is asserted textually and the block's behavior
|
||||
// is exercised for both the keyless and the populated case.
|
||||
bashTest('the external-keys provenance block survives set -u keyless and joins names when keys are exported', async () => {
|
||||
const script = await fs.readFile(new URL('../scripts/dev-fresh.sh', import.meta.url), 'utf8');
|
||||
const start = script.indexOf('KEY_SETUP_EXTERNAL_KEYS=()');
|
||||
const csvAt = script.indexOf('KEY_SETUP_EXTERNAL_KEYS_CSV=');
|
||||
const end = script.indexOf('\n', csvAt);
|
||||
assert.ok(start > 0 && csvAt > start && end > csvAt, 'provenance block not found in dev-fresh.sh');
|
||||
const block = script.slice(start, end);
|
||||
assert.match(block, /\$\{KEY_SETUP_EXTERNAL_KEYS\[\*\]:-\}/);
|
||||
|
||||
const { execFile } = await import('node:child_process');
|
||||
const { promisify } = await import('node:util');
|
||||
const run = promisify(execFile);
|
||||
const probe = `set -u\n${block}\nprintf '%s' "$KEY_SETUP_EXTERNAL_KEYS_CSV"`;
|
||||
const keyless = await run('bash', ['-c', probe], { env: { PATH: process.env.PATH } });
|
||||
assert.equal(keyless.stdout, '');
|
||||
const keyed = await run('bash', ['-c', probe], {
|
||||
env: { PATH: process.env.PATH, FIRMS_MAP_KEY: 'x', TOMTOM_API_KEY: 'y' },
|
||||
});
|
||||
assert.equal(keyed.stdout, 'FIRMS_MAP_KEY,TOMTOM_API_KEY');
|
||||
});
|
||||
@@ -1,6 +1,6 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import { realpathSync } from 'node:fs';
|
||||
import { mkdir, mkdtemp, rm, symlink, writeFile } from 'node:fs/promises';
|
||||
import { access, copyFile, mkdir, mkdtemp, rm, symlink, writeFile } from 'node:fs/promises';
|
||||
import { createRequire } from 'node:module';
|
||||
import os from 'node:os';
|
||||
import path from 'node:path';
|
||||
@@ -62,12 +62,9 @@ test('Pinokio start has one fail-closed launcher process', () => {
|
||||
test('Pinokio install records success explicitly instead of trusting node_modules', async () => {
|
||||
const install = require('../pinokio/install.js');
|
||||
const fs = await import('node:fs/promises');
|
||||
const menuSource = await fs.readFile(new URL('../pinokio/pinokio.js', import.meta.url), 'utf8');
|
||||
const installSource = await fs.readFile(new URL('../scripts/pinokio-install.mjs', import.meta.url), 'utf8');
|
||||
assert.equal(install.run.at(-1).params.message, 'node scripts/pinokio-install.mjs');
|
||||
assert.equal(install.run[0].when, "{{!kernel.exists(cwd, 'ENVIRONMENT')}}");
|
||||
assert.match(menuSource, /info\.exists\('\.installed'\)/);
|
||||
assert.doesNotMatch(menuSource, /exists\('\.\.\/node_modules'\)/);
|
||||
assert.match(installSource, /includeKeychain: false/);
|
||||
assert.match(installSource, /authoritativeEnvironment: true/);
|
||||
assert.match(installSource, /applyPinokioEnvironment\(\)/);
|
||||
@@ -80,6 +77,79 @@ test('Pinokio install records success explicitly instead of trusting node_module
|
||||
}
|
||||
});
|
||||
|
||||
test('Pinokio menu resolves the nested install marker and exposes each lifecycle state', async (t) => {
|
||||
const fixture = await mkdtemp(path.join(os.tmpdir(), 'gev-pinokio-menu-'));
|
||||
t.after(() => rm(fixture, { recursive: true, force: true }));
|
||||
const launcherDir = path.join(fixture, 'app', 'pinokio');
|
||||
const launcherPath = path.join(launcherDir, 'pinokio.js');
|
||||
const markerPath = path.join(launcherDir, '.installed');
|
||||
await mkdir(launcherDir, { recursive: true });
|
||||
await copyFile(new URL('../pinokio/pinokio.js', import.meta.url), launcherPath);
|
||||
|
||||
const existsCalls = [];
|
||||
const kernel = {
|
||||
exists: async (...chunks) => {
|
||||
existsCalls.push(chunks);
|
||||
try {
|
||||
await access(path.resolve(...chunks));
|
||||
return true;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
};
|
||||
const runtime = { running: null, url: null };
|
||||
const info = {
|
||||
exists: () => assert.fail('menu must resolve the marker through kernel.exists'),
|
||||
running: (href) => runtime.running === href,
|
||||
local: () => runtime.url ? { url: runtime.url } : {},
|
||||
};
|
||||
const { menu } = require(launcherPath);
|
||||
const render = async ({ installed, running = null, url = null }) => {
|
||||
if (installed) await writeFile(markerPath, 'ready\n');
|
||||
else await rm(markerPath, { force: true });
|
||||
runtime.running = running;
|
||||
runtime.url = url;
|
||||
const items = await menu(kernel, info);
|
||||
assert.equal(items.filter((item) => item.default).length, 1);
|
||||
return items.map(({ text, href, default: isDefault = false }) => ({ text, href, default: isDefault }));
|
||||
};
|
||||
|
||||
assert.deepEqual(await render({ installed: false }), [
|
||||
{ text: 'Install', href: 'install.js', default: true },
|
||||
]);
|
||||
assert.deepEqual(await render({ installed: true }), [
|
||||
{ text: 'Start', href: 'start.js', default: true },
|
||||
{ text: 'Update', href: 'update.js', default: false },
|
||||
{ text: 'Repair installation', href: 'reset.js', default: false },
|
||||
]);
|
||||
for (const [running, text] of [
|
||||
['install.js', 'Installing'],
|
||||
['update.js', 'Updating'],
|
||||
['reset.js', 'Resetting'],
|
||||
]) {
|
||||
assert.deepEqual(await render({ installed: true, running }), [
|
||||
{ text, href: running, default: true },
|
||||
]);
|
||||
}
|
||||
assert.deepEqual(await render({ installed: true, running: 'start.js' }), [
|
||||
{ text: 'Starting', href: 'start.js', default: true },
|
||||
]);
|
||||
assert.deepEqual(await render({
|
||||
installed: true,
|
||||
running: 'start.js',
|
||||
url: 'http://127.0.0.1:4173/',
|
||||
}), [
|
||||
{ text: "Open God's Eye View", href: 'http://127.0.0.1:4173/', default: true },
|
||||
{ text: 'Server', href: 'start.js', default: false },
|
||||
]);
|
||||
assert.ok(existsCalls.length >= 7);
|
||||
const resolvedLauncherDir = realpathSync(launcherDir);
|
||||
for (const chunks of existsCalls) {
|
||||
assert.deepEqual(chunks, [resolvedLauncherDir, '.installed']);
|
||||
}
|
||||
});
|
||||
|
||||
test('Pinokio install recognizes direct execution through a linked app directory', async (t) => {
|
||||
const fixture = await mkdtemp(path.join(os.tmpdir(), 'gev-pinokio-entry-'));
|
||||
t.after(() => rm(fixture, { recursive: true, force: true }));
|
||||
|
||||
+5
-2
@@ -2086,7 +2086,10 @@ function firmsProxy() {
|
||||
try {
|
||||
const records = filterTrailing24h(await fetchSource(key, source), now);
|
||||
sources.push({ source, count: records.length, ok: true });
|
||||
fires.push(...records);
|
||||
// NOT fires.push(...records): spread passes each record as an argument,
|
||||
// and a world/2 VIIRS pull exceeds V8's argument limit (~125k) at
|
||||
// ~131k records — RangeError, and the whole source is silently dropped.
|
||||
for (const record of records) fires.push(record);
|
||||
} catch (err) {
|
||||
console.warn(`[firms-proxy] ${source} fetch failed:`, err?.message || err);
|
||||
sources.push({ source, count: 0, ok: false });
|
||||
@@ -3370,7 +3373,7 @@ function gbfsProxy() {
|
||||
return;
|
||||
}
|
||||
const body = await upstream.text();
|
||||
if (body.length > GBFS_MAX_BODY_BYTES) {
|
||||
if (Buffer.byteLength(body, 'utf8') > GBFS_MAX_BODY_BYTES) {
|
||||
res.writeHead(502, { 'Content-Type': 'application/json', 'Cache-Control': 'no-store' });
|
||||
res.end(JSON.stringify({ error: 'GBFS upstream response too large' }));
|
||||
return;
|
||||
|
||||
Reference in new issue
Block a user