Versie 0.2.0

This commit is contained in:
Atreides Assets committed 2026-10-29 11:57:29 +01:00
commit e77d8fd373
495 files changed
+81026

No files matched your search

+200
View File
@@ -0,0 +1,200 @@
// Generated, do not edit. sha256:eca3b25957829a0a34656d92265e558efc50996dc58250a690f2dba7d2ab107a
import { AppError, errorPayload } from '../shared/app-error.js';
import { dataModules } from './registers.mjs';
import * as accountsMerge from './data/accounts-merge.js';
import * as accounts from './data/accounts.js';
import * as aiAudit from './data/ai-audit.js';
import * as aiProposals from './data/ai-proposals.js';
import * as apiMetrics from './data/api-metrics.js';
import * as assetNotes from './data/asset-notes.js';
import * as assets from './data/assets.js';
import * as bus from './data/bus.js';
import * as commands from './data/commands.js';
import * as connections from './data/connections.js';
import * as counts from './data/counts.js';
import * as dashboard from './data/dashboard.js';
import * as events from './data/events.js';
import * as hygiene from './data/hygiene.js';
import * as integrationLog from './data/integration-log.js';
import * as interestCredits from './data/interest-credits.js';
import * as interestSchedules from './data/interest-schedules.js';
import * as labels from './data/labels.js';
import * as licenseBuyer from './data/license-buyer.js';
import * as licenseInstall from './data/license-install.js';
import * as licenseStatus from './data/license-status.js';
import * as support from './data/support.js';
import * as market from './data/market.js';
import * as metals from './data/metals.js';
import * as notifications from './data/notifications.js';
import * as onboarding from './data/onboarding.js';
import * as positions from './data/positions.js';
import * as preferences from './data/preferences.js';
import * as priceHistory from './data/price-history.js';
import * as priceSource from './data/price-source.js';
import * as proposals from './data/proposals.js';
import * as providers from './data/providers.js';
import * as reservations from './data/reservations.js';
import * as scanLogs from './data/scan-logs.js';
import * as structure from './data/structure.js';
import * as tableViewer from './data/table-viewer.js';
import * as txLinks from './data/tx-links.js';
import * as valuations from './data/valuations.js';
import * as walletAddresses from './data/wallet-addresses.js';
import * as walletSources from './data/wallet-sources.js';
import * as walletTxs from './data/wallet-txs.js';
import { flushChanges } from './data/bus.js';
const MODULES = Object.freeze({
'accounts': accounts,
'accounts-merge': accountsMerge,
'ai-audit': aiAudit,
'ai-proposals': aiProposals,
'api-metrics': apiMetrics,
'asset-notes': assetNotes,
'assets': assets,
'bus': bus,
'commands': commands,
'connections': connections,
'counts': counts,
'dashboard': dashboard,
'events': events,
'hygiene': hygiene,
'integration-log': integrationLog,
'interest-credits': interestCredits,
'interest-schedules': interestSchedules,
'labels': labels,
'license-buyer': licenseBuyer,
'license-install': licenseInstall,
'license-status': licenseStatus,
'market': market,
'metals': metals,
'notifications': notifications,
'onboarding': onboarding,
'positions': positions,
'preferences': preferences,
'price-history': priceHistory,
'price-source': priceSource,
'proposals': proposals,
'providers': providers,
'reservations': reservations,
'scan-logs': scanLogs,
'structure': structure,
'support': support,
'table-viewer': tableViewer,
'tx-links': txLinks,
'valuations': valuations,
'wallet-addresses': walletAddresses,
'wallet-sources': walletSources,
'wallet-txs': walletTxs,
});
const INTERN = Object.freeze({
'bus': ['flushChanges', 'pruneChanges'],
'integration-log': ['recordIntegrationCall', 'countServiceCall'],
'interest-schedules': ['realizedForSchedule'],
'preferences': ['forgetPrefRow', 'tableViewCfg'],
'providers': ['emitProvidersChanged'],
'tx-links': ['linkProposalTxSoft'],
'wallet-sources': ['purgeWalletSourceSecret', 'assertSourceMatchesAccount'],
});
function modules() {
const extra = dataModules.list();
const dubbel = extra.find(m => Object.hasOwn(MODULES, m.id));
if (dubbel) throw new Error(`data module '${dubbel.id}' is registered and also a core module`);
return {
all: { ...MODULES, ...Object.fromEntries(extra.map(m => [m.id, m.module])) },
intern: { ...INTERN, ...Object.fromEntries(extra.filter(m => m.intern).map(m => [m.id, m.intern])) },
};
}
function oppervlakVan(module, internals = []) {
const intern = new Set(internals);
return Object.freeze(Object.entries(module)
.filter(([naam, waarde]) => typeof waarde === 'function' && !intern.has(naam))
.map(([naam]) => naam)
.sort());
}
let cache = { count: -1, surface: null, all: null };
function current() {
const count = dataModules.list().length;
if (cache.count !== count) {
const { all, intern } = modules();
const surface = Object.freeze(Object.fromEntries(
Object.keys(all).sort().map(mod => [mod, oppervlakVan(all[mod], intern[mod])])));
cache = { count, surface, all };
}
return cache;
}
export const surface = () => current().surface;
export function isAllowed(mod, fn) {
const s = surface();
return Object.hasOwn(s, mod) && s[mod].includes(fn);
}
export function codeer(waarde) {
if (waarde instanceof Map) return { __t: 'Map', v: [...waarde].map(([k, v]) => [k, codeer(v)]) };
if (waarde instanceof Set) return { __t: 'Set', v: [...waarde].map(codeer) };
if (Array.isArray(waarde)) return waarde.map(codeer);
if (waarde && typeof waarde === 'object' && Object.getPrototypeOf(waarde) === Object.prototype) {
return Object.fromEntries(Object.entries(waarde).map(([k, v]) => [k, codeer(v)]));
}
return waarde;
}
function sendJson(res, status, obj) {
res.writeHead(status, { 'Content-Type': 'application/json; charset=utf-8', 'X-Content-Type-Options': 'nosniff' });
res.end(JSON.stringify(obj));
}
const MAX_BODY = 5 * 1024 * 1024;
function readJsonBody(req) {
return new Promise((resolve, reject) => {
let len = 0; const chunks = [];
req.on('data', c => {
len += c.length;
if (len > MAX_BODY) { req.destroy(); reject(new AppError('common.requestTooLarge', null, 'Request too large.')); }
else chunks.push(c);
});
req.on('end', () => {
const raw = Buffer.concat(chunks).toString('utf-8');
if (!raw) return resolve({});
try { resolve(JSON.parse(raw)); } catch { reject(new Error('Invalid JSON.')); }
});
req.on('error', reject);
});
}
export async function handleDataApi(req, res, url) {
const pad = url.split('?')[0];
if (!pad.startsWith('/api/data/')) return false;
if (req.method !== 'POST') { sendJson(res, 405, { error: 'Alleen POST.' }); return true; }
const delen = pad.slice('/api/data/'.length).split('/');
if (delen.length !== 2) { sendJson(res, 404, { error: 'Unknown endpoint.' }); return true; }
const [mod, fn] = delen;
if (!isAllowed(mod, fn)) {
sendJson(res, 404, { error: `Unknown data-layer function '${mod}/${fn}'.` });
return true;
}
let args;
try {
const body = await readJsonBody(req);
args = Array.isArray(body.args) ? body.args : [];
} catch (e) { sendJson(res, 400, errorPayload(e)); return true; }
try {
flushChanges();
const result = await current().all[mod][fn](...args);
sendJson(res, 200, { result: codeer(result === undefined ? null : result), changes: flushChanges() });
} catch (e) {
sendJson(res, 400, errorPayload(e));
}
return true;
}