gods-eye-view/scripts/pinokio-environment.mjs

141 lines
4.7 KiB
JavaScript

import { existsSync, readFileSync, writeFileSync } from 'node:fs';
import path from 'node:path';
import { parseEnv } from 'node:util';
import { fileURLToPath } from 'node:url';
const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
const DEFAULT_ENVIRONMENT_FILE = path.join(ROOT, 'pinokio', 'ENVIRONMENT');
export const PINOKIO_CONFIG_FIELDS = Object.freeze([
'GOOGLE_MAPS_API_KEY',
'CESIUM_ION_TOKEN',
'OPENAI_API_KEY',
'AISSTREAM_API_KEY',
'FIRMS_MAP_KEY',
'TOMTOM_API_KEY',
'OPENSKY_CLIENT_ID',
'OPENSKY_CLIENT_SECRET',
'LL2_API_TOKEN',
'GEV_RATELIMIT_OPENAI_PER_MIN',
'GEV_RATELIMIT_GOOGLE_PER_MIN',
'PINOKIO_SHARE_CLOUDFLARE',
'PINOKIO_SHARE_LOCAL',
'PINOKIO_SHARE_VAR',
]);
const PINOKIO_DEFAULTS = Object.freeze({
GEV_RATELIMIT_OPENAI_PER_MIN: '30',
GEV_RATELIMIT_GOOGLE_PER_MIN: '120',
PINOKIO_SHARE_CLOUDFLARE: 'false',
PINOKIO_SHARE_LOCAL: 'false',
PINOKIO_SHARE_VAR: '__gev_sharing_disabled__',
});
const PINOKIO_SHARE_SENTINEL = '__gev_sharing_disabled__';
const PINOKIO_SHARING_FIELDS = Object.freeze([
'PINOKIO_SHARE_CLOUDFLARE',
'PINOKIO_SHARE_LOCAL',
'PINOKIO_SHARE_VAR',
]);
function appendEnvironmentLine(source, line) {
const prefix = source.length > 0 && !source.endsWith('\n') ? '\n' : '';
return `${source}${prefix}${line}\n`;
}
function detectEnvironmentEncoding(buffer) {
if (buffer.length >= 2 && buffer[0] === 0xff && buffer[1] === 0xfe) return 'utf-16le';
if (buffer.length >= 2 && buffer[0] === 0xfe && buffer[1] === 0xff) return 'utf-16be';
let evenNulls = 0;
let oddNulls = 0;
const sampleLength = Math.min(buffer.length, 512);
for (let index = 0; index < sampleLength; index += 1) {
if (buffer[index] !== 0) continue;
if (index % 2 === 0) evenNulls += 1;
else oddNulls += 1;
}
const minimumNulls = Math.max(2, Math.floor(sampleLength / 16));
if (oddNulls >= minimumNulls && oddNulls > evenNulls * 2) return 'utf-16le';
if (evenNulls >= minimumNulls && evenNulls > oddNulls * 2) return 'utf-16be';
return 'utf-8';
}
export function readEnvironmentSource(filepath) {
if (!existsSync(filepath)) return '';
const buffer = readFileSync(filepath);
try {
return new TextDecoder(detectEnvironmentEncoding(buffer), { fatal: true }).decode(buffer);
} catch {
throw new Error('Pinokio ENVIRONMENT could not be decoded as UTF-8 or UTF-16.');
}
}
/** Persist only the non-secret controls Pinokio itself re-reads at local.set. */
export function ensurePinokioSharingBoundary(filepath = DEFAULT_ENVIRONMENT_FILE) {
const original = existsSync(filepath) ? readFileSync(filepath) : null;
let source = readEnvironmentSource(filepath);
try {
if (source) parseEnv(source);
} catch {
throw new Error('Pinokio ENVIRONMENT could not be parsed.');
}
// Pinokio re-reads this file after the child preflight. Remove every legacy,
// blank, or duplicate control before appending one canonical safe block so
// that its later global/app merge cannot diverge from the checked state.
const sharingLine = new RegExp(
`^[\\t ]*(?:${PINOKIO_SHARING_FIELDS.join('|')})[\\t ]*=.*(?:\\r?\\n|$)`,
'gm',
);
source = source.replace(sharingLine, '');
source = appendEnvironmentLine(source, [
'PINOKIO_SHARE_CLOUDFLARE=false',
'PINOKIO_SHARE_LOCAL=false',
`PINOKIO_SHARE_VAR=${PINOKIO_SHARE_SENTINEL}`,
].join('\n'));
let configured;
try {
configured = parseEnv(source);
} catch {
throw new Error('Pinokio ENVIRONMENT could not be parsed.');
}
const encoded = Buffer.from(source, 'utf8');
if (!original || !original.equals(encoded)) {
writeFileSync(filepath, source, { mode: 0o600 });
}
return configured;
}
/** Read the app-scoped Pinokio configuration without exposing its values. */
export function readPinokioEnvironment(filepath = DEFAULT_ENVIRONMENT_FILE) {
if (!existsSync(filepath)) return {};
try {
return parseEnv(readEnvironmentSource(filepath));
} catch {
throw new Error('Pinokio ENVIRONMENT could not be parsed.');
}
}
/**
* Make the app-scoped Pinokio file authoritative over Pinokio-global values.
* Pinokio removes blank entries before merging environments, so each child
* must restore the raw app value before diagnosis or Vite configuration.
*/
export function applyPinokioEnvironment({
environment = process.env,
filepath = DEFAULT_ENVIRONMENT_FILE,
} = {}) {
const configured = ensurePinokioSharingBoundary(filepath);
for (const field of PINOKIO_CONFIG_FIELDS) {
environment[field] = String(configured[field] ?? PINOKIO_DEFAULTS[field] ?? '');
}
// Sharing is unsupported on Pinokio 8.0.40. Never let a global passcode
// enter the child even if the host's global Pinokio environment defines it.
environment.PINOKIO_SHARE_PASSCODE = '';
return configured;
}