Compare commits

..
8 Commits
Author SHA1 Message Date
Bilawal Sidhu 65bc522f49 Merge pull request #153 from bilawalsidhu/release/v0.1.1
release: v0.1.1 — installation and live-data fixes
2026-09-01 14:41:55 -05:00
Bilawal Sidhu ae66e9d299 chore(release): prepare v0.1.1
Promote the current reliability fixes into a dated patch release and align the package metadata.
2026-09-01 14:38:52 -05:00
Bilawal Sidhu d399dfc92d docs: tighten README opening
Simplify the keyless Quick Start pitch and clarify which data is live, regularly refreshed, simulated, or estimated.
2026-09-01 14:38:52 -05:00
Bilawal Sidhu 53a5f01a79 Merge pull request #152 from bilawalsidhu/fix/pinokio-install-marker
fix: recognize completed Pinokio setup
2026-09-01 11:21:54 -05:00
Manjunath 39d33b3f29 fix: repair fresh integration setup detection 2026-09-01 11:17:42 -05:00
Bilawal Sidhu d8f1742783 fix(dev-fresh): keyless launch no longer crashes on stock macOS bash 3.2 (#144)
Expanding the empty KEY_SETUP_EXTERNAL_KEYS array under set -u is a fatal
'unbound variable' on bash 3.2, which macOS ships as /bin/bash — so a keyless
./scripts/dev-fresh.sh died at the provenance-marker line before doing
anything. The ${arr[*]:-} guard keeps 3.2 alive and leaves populated launches
byte-identical (same idiom the script already uses for DEV_UNSET).

Verified with /bin/bash 3.2.57: the extracted block runs clean under set -u
with no keys (empty CSV) and with keys (ordered comma-joined names); the full
launcher boots keyless to a live server, and exported keys still classify as
externally managed in Provider Settings. A behavioral guard now runs the real
block from the script both ways in the dev-fresh test surface, plus a textual
assertion pinning the 3.2-safe idiom.
2026-08-31 19:00:33 -05:00
9db0813daf fix: measure GBFS response cap in bytes, not string length (#45)
* fix: measure GBFS response cap in bytes, not string length

The 5 MB cap compared GBFS_MAX_BODY_BYTES against body.length, which is the
string's UTF-16 code-unit count rather than its byte size. Those match for
ASCII but diverge for multi-byte payloads, so a large non-ASCII response
could slip past the cap. Switched to Buffer.byteLength.

Closes #32

* docs(changelog): move the GBFS byte-cap entry into the current Unreleased section

---------

Co-authored-by: Bilawal Sidhu <[email protected]>
Co-authored-by: Bilawal Sidhu <[email protected]>
2026-08-31 18:55:17 -05:00
6b7bca2913 fix(firms): drop argument spread in fires.push — RangeError silently dropped 2 of 3 VIIRS sources (#93)
* fix(firms): drop spread in fires.push — RangeError silently killed 2 of 3 VIIRS sources

fires.push(...records) passes every record as a function argument. A
world/2 VIIRS pull returns ~131k records for NOAA20 and SNPP, over V8's
~125k argument limit, so both threw RangeError: Maximum call stack size
exceeded. The throw landed after sources.push({ok:true}), so each failed
source was listed twice — once ok:true with its real count, once ok:false
— while its records were dropped entirely. Only NOAA21 (114k, under the
limit) survived, making the layer look healthy at a third of the data.

Global fire count goes 113,996 -> 377,169.

* docs(changelog): record the FIRMS multi-source merge fix

* docs(changelog): move the FIRMS fix into a new Unreleased section above 0.1.0

---------

Co-authored-by: Bilawal Sidhu <[email protected]>
Co-authored-by: Bilawal Sidhu <[email protected]>
2026-08-31 18:50:49 -05:00
10 changed files with 182 additions and 17 deletions

No files matched your search

+32
View File
@@ -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
+7 -4
View File
@@ -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.
---
+4
View File
@@ -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)
+2 -2
View File
@@ -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
View File
@@ -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
View File
@@ -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');
+2 -2
View File
@@ -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"
+53
View File
@@ -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');
});
+74 -4
View File
@@ -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
View File
@@ -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;