Versie 0.2.0
This commit is contained in:
commit
e77d8fd373
495 files changed
+81026
No files matched your search
@@ -0,0 +1,88 @@
|
||||
// Generated, do not edit. sha256:09721f6e6374d0297156a1b8af0d4578d0bbb9c98d4ea7c96458dafbb2d56dcc
|
||||
import { createHmac } from 'node:crypto';
|
||||
|
||||
const HANDLE_TEKENS = 6;
|
||||
|
||||
const BECH32 = 'qpzry9x8gf2tvdw0s3jn54khce6mua7l';
|
||||
const BASE58 = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz';
|
||||
const HEX = '0123456789abcdef';
|
||||
|
||||
const SOORTEN = Object.freeze({
|
||||
address: Object.freeze({ prefix: 'bc1q', lengte: 42, alfabet: BECH32, onmogelijk: 'o' }),
|
||||
xpub: Object.freeze({ prefix: 'xpub', lengte: 111, alfabet: BASE58, onmogelijk: '0' }),
|
||||
txid: Object.freeze({ prefix: '', lengte: 64, alfabet: HEX, onmogelijk: 'z' }),
|
||||
});
|
||||
|
||||
export const ALIAS_SOORTEN = Object.freeze(Object.keys(SOORTEN));
|
||||
|
||||
function vul(alfabet, lengte, zaad) {
|
||||
let s = '';
|
||||
for (let i = 0; i < lengte; i++) {
|
||||
const paar = parseInt(zaad.slice((i * 2) % zaad.length, (i * 2) % zaad.length + 2) || '0', 16);
|
||||
s += alfabet[(paar + i) % alfabet.length];
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
export function schijnwaarde(soort, zaad) {
|
||||
const s = SOORTEN[soort];
|
||||
if (!s) throw new Error(`unknown alias kind: ${soort}`);
|
||||
const romp = vul(s.alfabet, s.lengte - s.prefix.length, String(zaad));
|
||||
const met = `${romp.slice(0, 2)}${s.onmogelijk}${romp.slice(3)}`;
|
||||
return `${s.prefix}${met}`;
|
||||
}
|
||||
|
||||
export function isSchijnwaarde(tekst) {
|
||||
if (typeof tekst !== 'string') return false;
|
||||
for (const [, s] of Object.entries(SOORTEN)) {
|
||||
if (s.prefix && !tekst.startsWith(s.prefix)) continue;
|
||||
if (tekst.length !== s.lengte) continue;
|
||||
const data = tekst.slice(s.prefix.length);
|
||||
if (data.includes(s.onmogelijk)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
export function createAliasRegistry({ secret } = {}) {
|
||||
if (typeof secret !== 'string' || secret.length < 32) {
|
||||
throw new Error('An alias registry without a secret is not allowed.');
|
||||
}
|
||||
const heen = new Map();
|
||||
const terug = new Map();
|
||||
|
||||
const afgeleid = (soort, waarde) =>
|
||||
createHmac('sha256', secret).update(`${soort}\0${waarde}`).digest('hex');
|
||||
|
||||
function onthoud(sleutel, uit, soort, waarde) {
|
||||
const bestaand = terug.get(uit);
|
||||
if (bestaand && bestaand.waarde !== waarde) {
|
||||
throw new Error(`Handle collision on '${uit}': two different values yield the same handle.`);
|
||||
}
|
||||
heen.set(sleutel, uit);
|
||||
terug.set(uit, { soort, waarde });
|
||||
return uit;
|
||||
}
|
||||
|
||||
return {
|
||||
alias(soort, waarde) {
|
||||
const sleutel = `${soort} ${waarde}`;
|
||||
if (heen.has(sleutel)) return heen.get(sleutel);
|
||||
return onthoud(sleutel, schijnwaarde(soort, afgeleid(soort, waarde)), soort, waarde);
|
||||
},
|
||||
|
||||
handle(soort, waarde) {
|
||||
const sleutel = `${soort} ${waarde}`;
|
||||
if (heen.has(sleutel)) return heen.get(sleutel);
|
||||
return onthoud(sleutel, `${soort}:${afgeleid(soort, waarde).slice(0, HANDLE_TEKENS)}`, soort, waarde);
|
||||
},
|
||||
|
||||
resolve(uit) {
|
||||
const r = terug.get(uit);
|
||||
return r ? r.waarde : null;
|
||||
},
|
||||
|
||||
uitgegeven() {
|
||||
return [...terug.entries()].map(([uit, r]) => ({ uit, soort: r.soort }));
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
// Generated, do not edit. sha256:74e4ed13a040cfe4e2dc4c23217c88607a06c14c8cc97aceaf7026b8d073ba91
|
||||
import { CONFIG } from '../../shared/config.js';
|
||||
|
||||
const LADDERS = CONFIG.AI.BUCKET_LADDERS;
|
||||
|
||||
function bodemVan(ladderNaam) {
|
||||
const min = CONFIG.AI.BUCKET_MIN_VALUES[ladderNaam] || 0;
|
||||
if (!min) return 0;
|
||||
const ladder = LADDERS[ladderNaam];
|
||||
let smalst = Infinity;
|
||||
for (let i = 0; i < ladder.length; i++) {
|
||||
const onder = ladder[i];
|
||||
const boven = i + 1 < ladder.length ? ladder[i + 1] : 10;
|
||||
smalst = Math.min(smalst, (boven - onder) / onder);
|
||||
}
|
||||
return min / smalst;
|
||||
}
|
||||
|
||||
export function bucket(waarde, ladderNaam = 'COARSE') {
|
||||
const ladder = LADDERS[ladderNaam];
|
||||
if (!ladder) throw new Error(`unknown ladder: ${ladderNaam}`);
|
||||
if (typeof waarde !== 'number' || !Number.isFinite(waarde)) return null;
|
||||
|
||||
if (waarde === 0) return { from: 0, to: 0, exact: true };
|
||||
|
||||
const negatief = waarde < 0;
|
||||
const abs = Math.abs(waarde);
|
||||
|
||||
const bodem = Number.isInteger(waarde) ? bodemVan(ladderNaam) : 0;
|
||||
if (bodem && abs < bodem) {
|
||||
return negatief
|
||||
? { from: -bodem, to: 0, exact: false, floor: true }
|
||||
: { from: 0, to: bodem, exact: false, floor: true };
|
||||
}
|
||||
|
||||
const orde = Math.floor(Math.log10(abs));
|
||||
const schaal = 10 ** orde;
|
||||
const genormaliseerd = Math.min(Math.max(abs / schaal, 1), 9.999999999);
|
||||
|
||||
let onder = ladder[0];
|
||||
let boven = 10;
|
||||
for (let i = 0; i < ladder.length; i++) {
|
||||
if (genormaliseerd >= ladder[i]) {
|
||||
onder = ladder[i];
|
||||
boven = i + 1 < ladder.length ? ladder[i + 1] : 10;
|
||||
}
|
||||
}
|
||||
|
||||
const van = onder * schaal;
|
||||
const tot = boven * schaal;
|
||||
return negatief ? { from: -tot, to: -van, exact: false } : { from: van, to: tot, exact: false };
|
||||
}
|
||||
|
||||
export function bucketLabel(waarde, ladderNaam = 'COARSE') {
|
||||
const b = bucket(waarde, ladderNaam);
|
||||
if (!b) return null;
|
||||
if (b.exact) return String(b.from);
|
||||
if (b.floor) return b.to === 0 ? `meer dan ${getal(b.from)}` : `minder dan ${getal(b.to)}`;
|
||||
return `${getal(b.from)} tot ${getal(b.to)}`;
|
||||
}
|
||||
|
||||
function getal(n) {
|
||||
return Number.isInteger(n) ? String(n) : String(Math.round(n * 100) / 100);
|
||||
}
|
||||
|
||||
export function shareBucket(pct) {
|
||||
const grenzen = CONFIG.AI.SHARE_BUCKETS;
|
||||
if (typeof pct !== 'number' || !Number.isFinite(pct) || pct < 0) return null;
|
||||
if (pct === 0) return { from: 0, to: 0, below: false };
|
||||
if (pct < grenzen[0]) return { from: 0, to: grenzen[0], below: true };
|
||||
|
||||
let onder = grenzen[0];
|
||||
let boven = grenzen[grenzen.length - 1];
|
||||
for (let i = 0; i < grenzen.length; i++) {
|
||||
if (pct >= grenzen[i]) {
|
||||
onder = grenzen[i];
|
||||
boven = i + 1 < grenzen.length ? grenzen[i + 1] : grenzen[i];
|
||||
}
|
||||
}
|
||||
if (onder === boven) return { from: 100, to: 100, below: false };
|
||||
return { from: onder, to: boven, below: false };
|
||||
}
|
||||
|
||||
export function shareLabel(pct) {
|
||||
const b = shareBucket(pct);
|
||||
if (!b) return null;
|
||||
if (b.from === b.to) return `${b.from}%`;
|
||||
if (b.below) return `minder dan ${b.to}%`;
|
||||
return `${b.from} tot ${b.to}%`;
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
// Generated, do not edit. sha256:ec282b725055d62dd35348c8698b9fb220cb23c5aa15fc53463e42d07d187d42
|
||||
import { getPref } from '../data/preferences.js';
|
||||
import { ENUMS } from '../../shared/config.js';
|
||||
import { hasFeature } from '../license.mjs';
|
||||
|
||||
export const AI_DISABLED = 'ai_disabled';
|
||||
|
||||
export const AI_WRITE_DENIED = 'ai_write_denied';
|
||||
|
||||
export const AI_CONTROL_DENIED = 'ai_control_denied';
|
||||
|
||||
export const AI_UNLICENSED = 'ai_unlicensed';
|
||||
|
||||
export const AI_UNLICENSED_TEXT =
|
||||
'De AI-koppeling hoort bij de betaalde versie van AssetApp. De gratis versie laat de administratie '
|
||||
+ 'niet lezen of wijzigen via een AI-koppeling. Er is niets gelezen en niets gewijzigd; deze poging '
|
||||
+ 'staat wel in het activiteitenlogboek.';
|
||||
|
||||
export const AI_INACTIVE = 'ai_inactive';
|
||||
|
||||
export const AI_REFUSALS = Object.freeze([AI_UNLICENSED, AI_INACTIVE, AI_DISABLED, AI_WRITE_DENIED, AI_CONTROL_DENIED]);
|
||||
|
||||
export const AI_INACTIVE_TEXT =
|
||||
'De AI-koppeling van AssetApp staat uit. Er wordt niets gelezen, niets gewijzigd en niets getoond, '
|
||||
+ 'ook geen verbindingstest. De eigenaar van de app zet hem weer aan met de schuif "Actief" onder '
|
||||
+ 'Systeem, tabblad AI-activiteit. Deze poging staat wel in het activiteitenlogboek.';
|
||||
|
||||
export const AI_DISABLED_TEXT =
|
||||
'De AI-koppeling van AssetApp mag de administratie niet lezen. De koppeling zelf staat wel aan; '
|
||||
+ 'lezen is een aparte schuif die de eigenaar van de app zelf aanzet onder Systeem, tabblad '
|
||||
+ 'AI-activiteit. Er is niets gelezen en niets gewijzigd; deze poging staat wel in het '
|
||||
+ 'activiteitenlogboek.';
|
||||
|
||||
export function isAiEnabled() {
|
||||
try { return getPref('ai', 'allow_read') !== 0; }
|
||||
catch { return false; }
|
||||
}
|
||||
|
||||
export function isAiActive() {
|
||||
try { return getPref('ai', 'enabled') !== 0; }
|
||||
catch { return false; }
|
||||
}
|
||||
|
||||
export function assertAiEnabled() {
|
||||
if (isAiEnabled()) return;
|
||||
const e = new Error(AI_DISABLED_TEXT);
|
||||
e.code = AI_DISABLED;
|
||||
throw e;
|
||||
}
|
||||
|
||||
export const AI_WRITE_DENIED_TEXT =
|
||||
'De AI-koppeling van AssetApp mag niets wijzigen. Lezen kan wel; schrijven is een aparte instelling '
|
||||
+ 'die de eigenaar van de app zelf aanzet onder Systeem, tabblad AI-activiteit. Er is niets '
|
||||
+ 'gewijzigd; deze poging staat wel in het activiteitenlogboek.';
|
||||
|
||||
export function isAiWriteAllowed() {
|
||||
try { return getPref('ai', 'allow_write') === 1; }
|
||||
catch { return false; }
|
||||
}
|
||||
|
||||
export const AI_CONTROL_DENIED_TEXT =
|
||||
'De AI-koppeling van AssetApp mag de app niet besturen. Lezen kan wel; navigeren is een aparte '
|
||||
+ 'instelling die de eigenaar van de app zelf aanzet onder Systeem, tabblad AI-activiteit. Er is '
|
||||
+ 'niets gewijzigd; deze poging staat wel in het activiteitenlogboek.';
|
||||
|
||||
export function isAiControlAllowed() {
|
||||
try { return getPref('ai', 'allow_control') === 1; }
|
||||
catch { return false; }
|
||||
}
|
||||
|
||||
export function isAiRawAllowed() {
|
||||
try { return getPref('ai', 'allow_raw') === 1; }
|
||||
catch { return false; }
|
||||
}
|
||||
|
||||
function weigering(scope) {
|
||||
if (!hasFeature('ai')) return { code: AI_UNLICENSED, text: AI_UNLICENSED_TEXT };
|
||||
if (!isAiActive()) return { code: AI_INACTIVE, text: AI_INACTIVE_TEXT };
|
||||
if (scope === 'none') return null;
|
||||
if (scope === 'read') {
|
||||
return isAiEnabled() ? null : { code: AI_DISABLED, text: AI_DISABLED_TEXT };
|
||||
}
|
||||
if (scope === 'write') {
|
||||
return isAiWriteAllowed() ? null : { code: AI_WRITE_DENIED, text: AI_WRITE_DENIED_TEXT };
|
||||
}
|
||||
if (scope === 'control') {
|
||||
return isAiControlAllowed() ? null : { code: AI_CONTROL_DENIED, text: AI_CONTROL_DENIED_TEXT };
|
||||
}
|
||||
return {
|
||||
code: AI_DISABLED,
|
||||
text: `Onbekende scope '${scope}'; toegestaan is ${ENUMS.AI_SCOPE.join(', ')}.`,
|
||||
};
|
||||
}
|
||||
|
||||
export function assertScope(scope) {
|
||||
const w = weigering(scope);
|
||||
if (!w) return;
|
||||
const e = new Error(w.text);
|
||||
e.code = w.code;
|
||||
throw e;
|
||||
}
|
||||
|
||||
export function mayScope(scope) {
|
||||
return weigering(scope) === null;
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
// Generated, do not edit. sha256:ffc38e35f09c2a28784811c7505bad194c65e207ac58b284c202aff9a6c08ec2
|
||||
import { randomBytes } from 'node:crypto';
|
||||
|
||||
import { readSecretsStore, writeSecretsStore, secretsFile } from '../keys.mjs';
|
||||
|
||||
const SLEUTEL = 'ai_handle_secret';
|
||||
|
||||
const cache = new Map();
|
||||
|
||||
export async function handleSecret() {
|
||||
const pad = secretsFile();
|
||||
if (cache.has(pad)) return cache.get(pad);
|
||||
const store = await readSecretsStore();
|
||||
const bestaand = store[SLEUTEL];
|
||||
if (typeof bestaand === 'string' && bestaand.length >= 32) {
|
||||
cache.set(pad, bestaand);
|
||||
return bestaand;
|
||||
}
|
||||
const nieuw = randomBytes(32).toString('hex');
|
||||
await writeSecretsStore({ ...store, [SLEUTEL]: nieuw });
|
||||
cache.set(pad, nieuw);
|
||||
return nieuw;
|
||||
}
|
||||
|
||||
export function _resetHandleSecret() { cache.clear(); }
|
||||
@@ -0,0 +1,31 @@
|
||||
// Generated, do not edit. sha256:ec3bd3327478b77670de174a8843f03ad4b292ec52893e4b4f0f49c508b72a5f
|
||||
import { CONFIG } from '../../shared/config.js';
|
||||
|
||||
export function omittedNote(omitted, max) {
|
||||
return ` ... en nog ${omitted} niet getoond (grens: ${max} per lijst).`;
|
||||
}
|
||||
|
||||
export function limitRows(rows, max = CONFIG.AI.LIMITS.MAX_ROWS_PER_LIST) {
|
||||
const alle = Array.isArray(rows) ? rows : [];
|
||||
if (alle.length <= max) return { rows: alle, omitted: 0, capped: false };
|
||||
return { rows: alle.slice(0, max), omitted: alle.length - max, capped: true };
|
||||
}
|
||||
|
||||
export function limitedList(rows, render, max = CONFIG.AI.LIMITS.MAX_ROWS_PER_LIST) {
|
||||
const { rows: zichtbaar, omitted, capped } = limitRows(rows, max);
|
||||
const regels = zichtbaar.map(render);
|
||||
if (capped) regels.push(omittedNote(omitted, max));
|
||||
return { lines: regels, omitted, capped };
|
||||
}
|
||||
|
||||
export function limitText(text, max = CONFIG.AI.LIMITS.MAX_TEXT_CHARS) {
|
||||
const heel = String(text ?? '');
|
||||
if (heel.length <= max) return { text: heel, omitted: 0, capped: false };
|
||||
const markering = `\n[Afgekapt: dit antwoord was te lang en is ingekort op ${max} tekens.]`;
|
||||
const ruimte = Math.max(0, max - markering.length);
|
||||
return {
|
||||
text: heel.slice(0, ruimte) + markering.slice(0, max),
|
||||
omitted: heel.length - ruimte,
|
||||
capped: true,
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,231 @@
|
||||
// Generated, do not edit. sha256:49025914ad8e6294f0b8c9d075be9b80de842094dd53941a1aaa93bc73409a0d
|
||||
import { CONFIG } from '../../shared/config.js';
|
||||
|
||||
const RANG = new Map(CONFIG.AI.FIELD_CLASSES.map((k, i) => [k, i]));
|
||||
|
||||
export const FIELD_POLICY = Object.freeze({
|
||||
rawData: 'drop',
|
||||
settings: 'drop',
|
||||
value: 'drop',
|
||||
arguments: 'drop',
|
||||
text: 'drop',
|
||||
payload: 'drop',
|
||||
messageParts: 'drop',
|
||||
keyHeader: 'drop',
|
||||
signatureHeader: 'drop',
|
||||
timestampHeader: 'drop',
|
||||
windowHeader: 'drop',
|
||||
authenticationHeaderName: 'drop',
|
||||
authenticationParameterName: 'drop',
|
||||
|
||||
address: 'chain',
|
||||
externalAddress: 'chain',
|
||||
automaticLabel: 'chain',
|
||||
txid: 'chain',
|
||||
transactionHash: 'chain',
|
||||
blockHeight: 'chain',
|
||||
blockTime: 'chain',
|
||||
chainIndex: 'chain',
|
||||
derivationIndex: 'chain',
|
||||
scriptType: 'chain',
|
||||
|
||||
id: 'handle',
|
||||
assetId: 'handle',
|
||||
accountId: 'handle',
|
||||
fromAccountId: 'handle',
|
||||
toAccountId: 'handle',
|
||||
productId: 'handle',
|
||||
providerId: 'handle',
|
||||
connectionId: 'handle',
|
||||
sourceId: 'handle',
|
||||
labelId: 'handle',
|
||||
eventId: 'handle',
|
||||
scheduleId: 'handle',
|
||||
profileId: 'handle',
|
||||
walletTransactionId: 'handle',
|
||||
resolvedEventId: 'handle',
|
||||
createdEventId: 'handle',
|
||||
createdAccountId: 'handle',
|
||||
createdValuationId: 'handle',
|
||||
callId: 'handle',
|
||||
claimedBy: 'handle',
|
||||
principalAssetId: 'handle',
|
||||
payoutAssetId: 'handle',
|
||||
name: 'handle',
|
||||
searchName: 'handle',
|
||||
description: 'handle',
|
||||
note: 'handle',
|
||||
memo: 'handle',
|
||||
body: 'handle',
|
||||
fingerprint: 'handle',
|
||||
summary: 'handle',
|
||||
origin: 'handle',
|
||||
filename: 'handle',
|
||||
importReference: 'handle',
|
||||
externalId: 'handle',
|
||||
instanceKey: 'handle',
|
||||
sessionId: 'handle',
|
||||
client: 'handle',
|
||||
detail: 'handle',
|
||||
fieldsShared: 'handle',
|
||||
url: 'handle',
|
||||
baseUrl: 'handle',
|
||||
scope: 'plain',
|
||||
|
||||
amount: 'quantity',
|
||||
balance: 'quantity',
|
||||
balanceSats: 'quantity',
|
||||
balanceFound: 'quantity',
|
||||
valueSats: 'quantity',
|
||||
feeSats: 'quantity',
|
||||
unitFee: 'quantity',
|
||||
principalAmount: 'quantity',
|
||||
fineGrams: 'quantity',
|
||||
productCount: 'quantity',
|
||||
|
||||
fiatFee: 'quantityFiat',
|
||||
fiatValue: 'quantityFiat',
|
||||
|
||||
fiatPrice: 'rate',
|
||||
fiatRate: 'rate',
|
||||
annualRate: 'rate',
|
||||
|
||||
key: 'plain',
|
||||
portfolio: 'plain',
|
||||
symbol: 'plain',
|
||||
unit: 'plain',
|
||||
subunit: 'plain',
|
||||
displayUnit: 'plain',
|
||||
decimals: 'plain',
|
||||
kind: 'plain',
|
||||
taxCategory: 'plain',
|
||||
taxScope: 'plain',
|
||||
wealthScope: 'plain',
|
||||
balanceCapture: 'plain',
|
||||
state: 'plain',
|
||||
form: 'plain',
|
||||
type: 'plain',
|
||||
accountKind: 'plain',
|
||||
eventType: 'plain',
|
||||
source: 'plain',
|
||||
priceOrigin: 'plain',
|
||||
sourceName: 'plain',
|
||||
status: 'plain',
|
||||
lastStatus: 'plain',
|
||||
direction: 'plain',
|
||||
suggestedType: 'plain',
|
||||
method: 'plain',
|
||||
capability: 'plain',
|
||||
resolution: 'plain',
|
||||
transform: 'plain',
|
||||
internalField: 'plain',
|
||||
jsonPath: 'plain',
|
||||
pathTemplate: 'plain',
|
||||
queryTemplate: 'plain',
|
||||
quoteCurrency: 'plain',
|
||||
baseCurrency: 'plain',
|
||||
currency: 'plain',
|
||||
quoteUnit: 'plain',
|
||||
minIntervalSeconds: 'plain',
|
||||
callsPerMonth: 'plain',
|
||||
hashAlgorithm: 'plain',
|
||||
encoding: 'plain',
|
||||
authenticationKind: 'plain',
|
||||
authenticationRequired: 'plain',
|
||||
rateKind: 'plain',
|
||||
creditCadence: 'plain',
|
||||
creditWeekday: 'plain',
|
||||
creditDayOfMonth: 'plain',
|
||||
compounding: 'plain',
|
||||
outcome: 'plain',
|
||||
tool: 'plain',
|
||||
isActive: 'plain',
|
||||
isSeed: 'plain',
|
||||
isSystem: 'plain',
|
||||
isCatchAll: 'plain',
|
||||
isOwnCustody: 'plain',
|
||||
scanEnabled: 'plain',
|
||||
rank: 'plain',
|
||||
sortOrder: 'plain',
|
||||
version: 'plain',
|
||||
serverVersion: 'plain',
|
||||
count: 'plain',
|
||||
highWater: 'plain',
|
||||
rowCount: 'plain',
|
||||
okCount: 'plain',
|
||||
failCount: 'plain',
|
||||
addressesFound: 'plain',
|
||||
proposalsCreated: 'plain',
|
||||
transactionCount: 'plain',
|
||||
charactersOut: 'plain',
|
||||
sumLatencyMs: 'plain',
|
||||
maxLatencyMs: 'plain',
|
||||
layer: 'plain',
|
||||
target: 'plain',
|
||||
providerKey: 'plain',
|
||||
subject: 'plain',
|
||||
httpStatus: 'plain',
|
||||
errorKey: 'plain',
|
||||
latencyMs: 'plain',
|
||||
requestId: 'plain',
|
||||
windowMs: 'plain',
|
||||
gridX: 'plain',
|
||||
gridY: 'plain',
|
||||
spanWidth: 'plain',
|
||||
spanHeight: 'plain',
|
||||
bucketMinute: 'plain',
|
||||
tableName: 'plain',
|
||||
operation: 'plain',
|
||||
rowId: 'handle',
|
||||
originId: 'handle',
|
||||
changes: 'drop',
|
||||
occurredAt: 'plain',
|
||||
claimedAt: 'plain',
|
||||
expiresAt: 'plain',
|
||||
resolvedAt: 'plain',
|
||||
createdAt: 'plain',
|
||||
updatedAt: 'plain',
|
||||
closedAt: 'plain',
|
||||
detectedAt: 'plain',
|
||||
dismissedAt: 'plain',
|
||||
gapAcceptedAt: 'plain',
|
||||
importedAt: 'plain',
|
||||
observedAt: 'plain',
|
||||
scannedAt: 'plain',
|
||||
lastScannedAt: 'plain',
|
||||
lastCheckedAt: 'plain',
|
||||
rateAt: 'plain',
|
||||
valuedOn: 'plain',
|
||||
fromDay: 'plain',
|
||||
untilDay: 'plain',
|
||||
day: 'plain',
|
||||
startsOn: 'plain',
|
||||
endsOn: 'plain',
|
||||
periodStart: 'plain',
|
||||
periodEnd: 'plain',
|
||||
});
|
||||
|
||||
export const TABLE_POLICY = Object.freeze({
|
||||
Preference: Object.freeze({ value: 'plain' }),
|
||||
});
|
||||
|
||||
export function fieldClass(field, table = null) {
|
||||
if (table == null && typeof field === 'string') {
|
||||
const punt = field.indexOf('.');
|
||||
if (punt > 0) return fieldClass(field.slice(punt + 1), field.slice(0, punt));
|
||||
}
|
||||
|
||||
const basis = Object.hasOwn(FIELD_POLICY, field) ? FIELD_POLICY[field] : null;
|
||||
|
||||
if (basis === null || table == null) return basis;
|
||||
if (!Object.hasOwn(TABLE_POLICY, table)) return basis;
|
||||
|
||||
const perTabel = TABLE_POLICY[table];
|
||||
return Object.hasOwn(perTabel, field) ? perTabel[field] : basis;
|
||||
}
|
||||
|
||||
export function strictestClass(a, b) {
|
||||
if (a == null) return b;
|
||||
if (b == null) return a;
|
||||
return (RANG.get(a) ?? -1) >= (RANG.get(b) ?? -1) ? a : b;
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
// Generated, do not edit. sha256:5d115259dddad7958f7f0a20af1477db47898da5fb7fe4a5f958f0a3bc9b0df0
|
||||
import { isAiRawAllowed } from './gate.js';
|
||||
import { getPref } from '../data/preferences.js';
|
||||
|
||||
function bucketing(key) {
|
||||
try { return getPref('ai', key) !== 0; }
|
||||
catch { return true; }
|
||||
}
|
||||
|
||||
export function precisionSettings() {
|
||||
if (isAiRawAllowed()) {
|
||||
return Object.freeze({
|
||||
rawValues: true,
|
||||
bucketShares: false,
|
||||
bucketTotals: false,
|
||||
bucketAmounts: false,
|
||||
bucketQuantities: false,
|
||||
});
|
||||
}
|
||||
return Object.freeze({
|
||||
rawValues: false,
|
||||
bucketShares: bucketing('bucket_shares'),
|
||||
bucketTotals: bucketing('bucket_totals'),
|
||||
bucketAmounts: bucketing('bucket_amounts'),
|
||||
bucketQuantities: bucketing('bucket_quantities'),
|
||||
});
|
||||
}
|
||||
|
||||
export function shareDisclosure(precision) {
|
||||
const p = precision ?? {};
|
||||
if (p.rawValues) return 'exact';
|
||||
if (!p.bucketAmounts) return 'exact';
|
||||
if (p.bucketShares) return 'bucketed';
|
||||
if (p.bucketTotals) return 'exact';
|
||||
return 'omit';
|
||||
}
|
||||
|
||||
export function precisionKey(precision) {
|
||||
const p = precision ?? {};
|
||||
return Object.keys(p).sort().map(k => `${k}=${String(p[k])}`).join(',') || 'leeg';
|
||||
}
|
||||
@@ -0,0 +1,139 @@
|
||||
// Generated, do not edit. sha256:45a1e1f166c06347eecc16618109c15256ed61caf29cc462a558b68275a28363
|
||||
import { fieldClass } from './policy.js';
|
||||
import { createAliasRegistry, isSchijnwaarde } from './aliases.js';
|
||||
import { bucketLabel } from './buckets.js';
|
||||
|
||||
const SCHIJN_SOORT = Object.freeze({
|
||||
address: 'address',
|
||||
externalAddress: 'address',
|
||||
automaticLabel: 'address',
|
||||
txid: 'txid',
|
||||
transactionHash: 'txid',
|
||||
});
|
||||
|
||||
const HANDLE_SOORT = Object.freeze({
|
||||
assetId: 'asset',
|
||||
accountId: 'account',
|
||||
fromAccountId: 'account',
|
||||
toAccountId: 'account',
|
||||
productId: 'product',
|
||||
providerId: 'provider',
|
||||
connectionId: 'connection',
|
||||
sourceId: 'walletSource',
|
||||
labelId: 'label',
|
||||
eventId: 'event',
|
||||
scheduleId: 'schedule',
|
||||
profileId: 'profile',
|
||||
walletTransactionId: 'walletTransaction',
|
||||
resolvedEventId: 'event',
|
||||
createdEventId: 'event',
|
||||
createdAccountId: 'account',
|
||||
createdValuationId: 'valuation',
|
||||
principalAssetId: 'asset',
|
||||
payoutAssetId: 'asset',
|
||||
});
|
||||
|
||||
export function createTranslator({ secret, precision } = {}) {
|
||||
const stand = Object.freeze({ rawValues: false, ...(precision ?? {}) });
|
||||
const raw = stand.rawValues === true;
|
||||
const registry = createAliasRegistry({ secret });
|
||||
const gedeeld = new Set();
|
||||
|
||||
const uitgaand = new Map();
|
||||
|
||||
function onthoudUit(uit, echt) {
|
||||
uitgaand.set(uit, echt);
|
||||
return uit;
|
||||
}
|
||||
|
||||
function veld(naam, waarde, entiteit, tabel, rol) {
|
||||
const klasse = fieldClass(naam, tabel);
|
||||
|
||||
const logNaam = (tabel != null && klasse !== fieldClass(naam)) ? `${tabel}.${naam}` : naam;
|
||||
|
||||
if (klasse === null || klasse === 'drop') return undefined;
|
||||
|
||||
if (waarde === null || waarde === undefined) {
|
||||
gedeeld.add(logNaam);
|
||||
return null;
|
||||
}
|
||||
|
||||
switch (klasse) {
|
||||
case 'plain':
|
||||
case 'rate':
|
||||
gedeeld.add(logNaam);
|
||||
return waarde;
|
||||
|
||||
case 'quantity':
|
||||
case 'quantityFiat': {
|
||||
if (raw) { gedeeld.add(logNaam); return waarde; }
|
||||
const emmeren = klasse === 'quantity'
|
||||
? stand.bucketQuantities !== false
|
||||
: (rol === 'total' ? stand.bucketTotals !== false : stand.bucketAmounts !== false);
|
||||
if (!emmeren) { gedeeld.add(logNaam); return waarde; }
|
||||
const label = bucketLabel(Number(waarde), klasse === 'quantityFiat' ? 'FINE' : 'COARSE');
|
||||
if (label === null) return undefined;
|
||||
gedeeld.add(logNaam);
|
||||
return label;
|
||||
}
|
||||
|
||||
case 'chain': {
|
||||
const soort = SCHIJN_SOORT[naam];
|
||||
if (!soort) return undefined;
|
||||
gedeeld.add(logNaam);
|
||||
if (raw) return waarde;
|
||||
return onthoudUit(registry.alias(soort, String(waarde)), String(waarde));
|
||||
}
|
||||
|
||||
case 'handle': {
|
||||
if (raw) { gedeeld.add(logNaam); return waarde; }
|
||||
const soort = naam === 'id' ? (entiteit || 'record') : (HANDLE_SOORT[naam] || 'text');
|
||||
gedeeld.add(logNaam);
|
||||
return onthoudUit(registry.handle(soort, String(waarde)), String(waarde));
|
||||
}
|
||||
|
||||
default:
|
||||
throw new Error(`no handling for class '${klasse}' (field '${naam}')`);
|
||||
}
|
||||
}
|
||||
|
||||
function toAi(waarde, opties = {}) {
|
||||
const entiteit = opties.entity || null;
|
||||
const tabel = opties.table || null;
|
||||
const rol = opties.role || 'row';
|
||||
if (Array.isArray(waarde)) return waarde.map(v => toAi(v, opties));
|
||||
if (waarde === null || typeof waarde !== 'object') return waarde;
|
||||
|
||||
const uit = {};
|
||||
for (const [naam, v] of Object.entries(waarde)) {
|
||||
const vertaald = (v !== null && typeof v === 'object')
|
||||
? (fieldClass(naam, tabel) === null ? undefined : toAi(v, {}))
|
||||
: veld(naam, v, entiteit, tabel, rol);
|
||||
if (vertaald !== undefined) uit[naam] = vertaald;
|
||||
}
|
||||
return uit;
|
||||
}
|
||||
|
||||
function fromAi(tekst) {
|
||||
if (typeof tekst !== 'string') return { text: tekst, unresolved: [] };
|
||||
let uit = tekst;
|
||||
|
||||
const sleutels = [...uitgaand.keys()].sort((a, b) => b.length - a.length);
|
||||
for (const s of sleutels) uit = uit.split(s).join(uitgaand.get(s));
|
||||
|
||||
const unresolved = [];
|
||||
for (const m of uit.matchAll(/\b(?:bc1q[0-9a-z]{38}|xpub[0-9A-Za-z]{107}|[0-9a-z]{64})\b/g)) {
|
||||
if (isSchijnwaarde(m[0])) unresolved.push(m[0]);
|
||||
}
|
||||
return { text: uit, unresolved };
|
||||
}
|
||||
|
||||
return {
|
||||
toAi,
|
||||
fromAi,
|
||||
beginCall() { gedeeld.clear(); },
|
||||
fieldsShared: () => [...gedeeld].sort(),
|
||||
resolve: uit => registry.resolve(uit),
|
||||
precision: stand,
|
||||
};
|
||||
}
|
||||
Reference in new issue
Block a user