Files
lzstealth 854da073d4
Publish container image / publish (push) Failing after 26s
Initial Sheet Relay application
2026-09-17 18:54:22 +01:00

100 lines
3.3 KiB
JavaScript

import { mkdir, readFile, writeFile } from 'node:fs/promises';
import { randomBytes } from 'node:crypto';
import path from 'node:path';
const dataDirectory = path.join(process.cwd(), 'data');
const configPath = path.join(dataDirectory, 'config.json');
const defaultConfig = () => ({
adminToken: randomBytes(24).toString('base64url'),
settings: {
corsOrigins: [],
trustedProxyHops: 0
},
credentials: [],
documents: [],
publications: []
});
function migrateConfig(config) {
if (config.credentials) {
return {
...config,
settings: {
...config.settings,
corsOrigins: config.settings?.corsOrigins || [],
trustedProxyHops: Number(config.settings?.trustedProxyHops) || 0
}
};
}
const legacyCredential = config.google?.apiKey || config.google?.serviceAccountJson ? {
id: crypto.randomUUID(),
name: 'Imported Google connection',
mode: config.google.mode,
apiKey: config.google.apiKey,
serviceAccountJson: config.google.serviceAccountJson,
requestsPerMinute: config.google.requestsPerMinute || 45
} : null;
const documents = (config.publications || []).map((publication) => ({
id: crypto.randomUUID(),
name: publication.name,
spreadsheetId: publication.spreadsheetId,
credentialId: legacyCredential?.id || '',
sheets: publication.sheets || []
}));
return {
adminToken: config.adminToken,
settings: { corsOrigins: [], trustedProxyHops: 0 },
credentials: legacyCredential ? [legacyCredential] : [],
documents,
publications: (config.publications || []).map((publication, index) => ({
id: publication.id,
name: publication.name,
documentId: documents[index].id,
sheets: publication.sheets || [],
apiToken: publication.apiToken,
cacheSeconds: config.google?.cacheSeconds || 30
}))
};
}
export async function loadConfig() {
try {
const config = migrateConfig(JSON.parse(await readFile(configPath, 'utf8')));
await saveConfig(config);
return config;
} catch (error) {
if (error.code !== 'ENOENT') throw error;
const config = defaultConfig();
await saveConfig(config);
console.log(`Created admin token: ${config.adminToken}`);
return config;
}
}
export async function saveConfig(config) {
await mkdir(dataDirectory, { recursive: true });
await writeFile(configPath, `${JSON.stringify(config, null, 2)}\n`, { mode: 0o600 });
}
export function publicConfig(config) {
return {
settings: config.settings,
credentials: config.credentials.map(({ apiKey, serviceAccountJson, ...credential }) => ({
...credential,
configured: credential.mode === 'apiKey' ? Boolean(apiKey) : Boolean(serviceAccountJson)
})),
documents: config.documents,
publications: config.publications.map(({ apiToken, ...publication }) => ({
...publication,
dataFormat: publication.dataFormat || 'rows',
range: publication.range || '',
omitBlankRows: Boolean(publication.omitBlankRows),
maxRows: Math.max(1, Math.min(100_000, Number(publication.maxRows) || 10_000)),
consumerRequestsPerMinute: Math.max(1, Number(publication.consumerRequestsPerMinute) || 120),
scheduledRefresh: Boolean(publication.scheduledRefresh),
enabled: publication.enabled !== false,
tokenConfigured: Boolean(apiToken)
}))
};
}