edgeone middleware环境变量正确读取解析
This commit is contained in:
@@ -1,5 +1,226 @@
|
||||
#!/usr/bin/env node
|
||||
import { spawn } from 'node:child_process';
|
||||
import { copyFileSync, existsSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
|
||||
import { join } from 'node:path';
|
||||
|
||||
function loadLocalEnvFile() {
|
||||
const envPath = join(process.cwd(), '.env');
|
||||
if (!existsSync(envPath)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const content = readFileSync(envPath, 'utf8');
|
||||
for (const rawLine of content.split(/\r?\n/)) {
|
||||
const line = rawLine.trim();
|
||||
if (!line || line.startsWith('#')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const match = line.match(/^(?:export\s+)?([A-Za-z_][A-Za-z0-9_]*)=(.*)$/);
|
||||
if (!match || process.env[match[1]] !== undefined) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let value = match[2].trim();
|
||||
const quote = value[0];
|
||||
if ((quote === '"' || quote === "'") && value.endsWith(quote)) {
|
||||
value = value.slice(1, -1);
|
||||
}
|
||||
if (quote === '"') {
|
||||
value = value.replace(/\\n/g, '\n').replace(/\\"/g, '"').replace(/\\\\/g, '\\');
|
||||
}
|
||||
|
||||
process.env[match[1]] = value;
|
||||
}
|
||||
}
|
||||
|
||||
loadLocalEnvFile();
|
||||
|
||||
const runtimeEnvKeys = [
|
||||
'USERNAME',
|
||||
'PASSWORD',
|
||||
'NEXT_PUBLIC_STORAGE_TYPE',
|
||||
'UPSTASH_URL',
|
||||
'UPSTASH_TOKEN',
|
||||
'TMDB_API_KEY',
|
||||
'TMDB_IMAGE_DOMAIN',
|
||||
'NEXT_PUBLIC_SITE_NAME',
|
||||
'ANNOUNCEMENT',
|
||||
'ENABLE_REGISTER',
|
||||
'NEXT_PUBLIC_SEARCH_MAX_PAGE',
|
||||
'NEXT_PUBLIC_DOUBAN_PROXY_TYPE',
|
||||
'NEXT_PUBLIC_DOUBAN_PROXY',
|
||||
'NEXT_PUBLIC_DOUBAN_IMAGE_PROXY_TYPE',
|
||||
'NEXT_PUBLIC_DOUBAN_IMAGE_PROXY',
|
||||
'NEXT_PUBLIC_ENABLE_OFFLINE_DOWNLOAD',
|
||||
'NEXT_PUBLIC_IMAGE_PROXY',
|
||||
'NEXT_PUBLIC_IMAGE_PROXY_PREFIX',
|
||||
'NEXT_PUBLIC_DISABLE_YELLOW_FILTER',
|
||||
'DISABLE_USER_FOLDER',
|
||||
'NEXT_PUBLIC_STORAGE_PREFIX',
|
||||
'NEXT_PUBLIC_ENABLE_STREAM_PROXY',
|
||||
'NEXT_PUBLIC_STREAM_PROXY_URL',
|
||||
'NEXT_PUBLIC_ENABLE_TURNSTILE',
|
||||
'TURNSTILE_SECRET_KEY',
|
||||
'NEXT_PUBLIC_TURNSTILE_SITE_KEY',
|
||||
'NEXT_PUBLIC_THEME',
|
||||
'NEXT_PUBLIC_THEME_COLOR',
|
||||
'NEXT_PUBLIC_APP_URL',
|
||||
'ENABLE_TVBOX_SUBSCRIBE',
|
||||
'TVBOX_SUBSCRIBE_PATH',
|
||||
'TVBOX_SUBSCRIBE_TOKEN',
|
||||
'WATCH_ROOM_ENABLED',
|
||||
'WATCH_ROOM_WS_URL',
|
||||
'WATCH_ROOM_SERVER_URL',
|
||||
'WEBSOCKET_SECRET',
|
||||
'WEB_PUSH_EMAIL',
|
||||
'WEB_PUSH_PRIVATE_KEY',
|
||||
'WEB_PUSH_PUBLIC_KEY',
|
||||
'WEB_PUSH_BASEURL',
|
||||
'NEXT_PUBLIC_BASE_PATH',
|
||||
];
|
||||
|
||||
const edgeOneMiddlewareSkipPaths = [
|
||||
'/login',
|
||||
'/register',
|
||||
'/oidc-register',
|
||||
'/qr-login',
|
||||
'/warning',
|
||||
'/tv/login',
|
||||
'/api/login',
|
||||
'/api/register',
|
||||
'/api/logout',
|
||||
'/api/auth/oidc',
|
||||
'/api/auth/qr',
|
||||
'/api/auth/refresh',
|
||||
'/api/server-config',
|
||||
'/api/tvbox/subscribe',
|
||||
];
|
||||
|
||||
function getRuntimeEnvLiteral() {
|
||||
const env = {};
|
||||
for (const key of runtimeEnvKeys) {
|
||||
if (process.env[key] !== undefined) {
|
||||
env[key] = process.env[key];
|
||||
}
|
||||
}
|
||||
return JSON.stringify(env);
|
||||
}
|
||||
|
||||
function replaceEnvLiterals(code, envLiteral) {
|
||||
let output = '';
|
||||
let cursor = 0;
|
||||
let replaced = 0;
|
||||
const needle = 'env: {';
|
||||
|
||||
while (true) {
|
||||
const start = code.indexOf(needle, cursor);
|
||||
if (start === -1) {
|
||||
output += code.slice(cursor);
|
||||
break;
|
||||
}
|
||||
|
||||
let i = start + 'env: '.length;
|
||||
let depth = 0;
|
||||
let inString = false;
|
||||
let escaped = false;
|
||||
|
||||
for (; i < code.length; i += 1) {
|
||||
const char = code[i];
|
||||
|
||||
if (inString) {
|
||||
if (escaped) {
|
||||
escaped = false;
|
||||
} else if (char === '\\') {
|
||||
escaped = true;
|
||||
} else if (char === '"') {
|
||||
inString = false;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (char === '"') {
|
||||
inString = true;
|
||||
} else if (char === '{') {
|
||||
depth += 1;
|
||||
} else if (char === '}') {
|
||||
depth -= 1;
|
||||
if (depth === 0) {
|
||||
i += 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (depth !== 0) {
|
||||
console.warn('[edgeone-build] Unable to replace an env literal: malformed object');
|
||||
output += code.slice(cursor);
|
||||
break;
|
||||
}
|
||||
|
||||
output += code.slice(cursor, start) + `env: ${envLiteral}`;
|
||||
cursor = i;
|
||||
replaced += 1;
|
||||
}
|
||||
|
||||
if (replaced > 0) {
|
||||
console.log(`[edgeone-build] Replaced ${replaced} generated env literal(s) with filtered runtime env`);
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
function patchEdgeFunctionEnvInjection() {
|
||||
const edgeFunctionPath = join(process.cwd(), '.edgeone', 'edge-functions', 'index.js');
|
||||
let code;
|
||||
try {
|
||||
code = readFileSync(edgeFunctionPath, 'utf8');
|
||||
} catch {
|
||||
return;
|
||||
}
|
||||
|
||||
const marker = '/* edgeone-process-env-injected */';
|
||||
const envLiteral = getRuntimeEnvLiteral();
|
||||
|
||||
code = replaceEnvLiterals(code, envLiteral);
|
||||
|
||||
const target = 'let request = context.request;';
|
||||
if (!code.includes(marker) && !code.includes(target)) {
|
||||
console.warn('[edgeone-build] Unable to patch edge function env injection: target not found');
|
||||
} else if (!code.includes(marker)) {
|
||||
code = code.replace(
|
||||
target,
|
||||
`${target}\n ${marker}\n if (typeof globalThis !== 'undefined' && globalThis.process?.env && context?.env) {\n Object.assign(globalThis.process.env, context.env);\n }`
|
||||
);
|
||||
}
|
||||
|
||||
const middlewareSignature = 'async function executeMiddleware({request}) {';
|
||||
const middlewareMarker = '/* edgeone-middleware-env-injected */';
|
||||
if (!code.includes(middlewareMarker) && !code.includes(middlewareSignature)) {
|
||||
console.warn('[edgeone-build] Unable to patch middleware env injection: target not found');
|
||||
} else if (!code.includes(middlewareMarker)) {
|
||||
code = code.replace(
|
||||
middlewareSignature,
|
||||
`async function executeMiddleware({request, env}) {\n ${middlewareMarker}\n if (typeof globalThis !== 'undefined' && globalThis.process?.env && env) {\n Object.assign(globalThis.process.env, env);\n }`
|
||||
);
|
||||
}
|
||||
|
||||
const matcherFallbackMarker = '/* edgeone-middleware-matcher-fallback */';
|
||||
const matcherFallbackTarget = ` if (!matchesPath(pathname, config.matcher)) {
|
||||
return null;
|
||||
}`;
|
||||
if (!code.includes(matcherFallbackMarker) && !code.includes(matcherFallbackTarget)) {
|
||||
console.warn('[edgeone-build] Unable to patch middleware matcher fallback: target not found');
|
||||
} else if (!code.includes(matcherFallbackMarker)) {
|
||||
code = code.replace(
|
||||
matcherFallbackTarget,
|
||||
`${matcherFallbackTarget}\n\n ${matcherFallbackMarker}\n const edgeOneMiddlewareSkipPaths = ${JSON.stringify(edgeOneMiddlewareSkipPaths)};\n if (edgeOneMiddlewareSkipPaths.some((path) => pathname.startsWith(path))) {\n return null;\n }`
|
||||
);
|
||||
}
|
||||
|
||||
writeFileSync(edgeFunctionPath, code);
|
||||
console.log('[edgeone-build] Patched edge function process.env injection');
|
||||
}
|
||||
|
||||
const isInsideEdgeOneBuilder = process.env.NEXT_PRIVATE_STANDALONE === 'true';
|
||||
|
||||
@@ -18,6 +239,21 @@ const child = spawn(command, {
|
||||
});
|
||||
|
||||
child.on('exit', (code, signal) => {
|
||||
if (!signal && code === 0) {
|
||||
for (const file of ['edgeone.json', 'package.json']) {
|
||||
copyFileSync(join(process.cwd(), file), join(process.cwd(), '.edgeone', file));
|
||||
}
|
||||
|
||||
patchEdgeFunctionEnvInjection();
|
||||
|
||||
for (const envPath of [
|
||||
join(process.cwd(), '.edgeone', '.env'),
|
||||
join(process.cwd(), '.edgeone', 'cloud-functions', 'ssr-node', '.env'),
|
||||
]) {
|
||||
rmSync(envPath, { force: true });
|
||||
}
|
||||
}
|
||||
|
||||
if (signal) {
|
||||
process.kill(process.pid, signal);
|
||||
return;
|
||||
|
||||
Reference in New Issue
Block a user