Files
AgrarmonitorConnector/dist/AgrarmonitorConnector.js
T
bjoernpoettkerandClaude Opus 5 b844b772b8 Detect expired session only via login page markup
The session check treated any response containing "Anmeldung" or
"Einloggen" as an expired session. Regular content pages (e.g. the FAQ)
mention these words in body text, which triggered a needless re-login and
returned the login page instead of the requested content.

Detection now relies on the status code and isLoginPageText() alone.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-07 17:36:05 +02:00

736 lines
30 KiB
JavaScript

"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.AgrarmonitorConnector = void 0;
const axios_1 = __importDefault(require("axios"));
const axios_cookiejar_support_1 = require("axios-cookiejar-support");
const jsdom_1 = require("jsdom");
const tough_cookie_1 = require("tough-cookie");
class AgrarmonitorConnector {
options;
http;
static s3DateienBaseUrl = 'https://s3-eu-central-1.amazonaws.com/dateien.agrarmonitor.de/07';
baseUrl;
apiBaseUrl;
timeoutMs;
autoLogin;
autoRetry;
loginStrategy;
logger;
cookieJar;
apiHttp;
loginInProgress = null;
constructor(options) {
this.options = options;
this.baseUrl = options.baseUrl ?? 'https://admin7.agrarmonitor.de';
this.apiBaseUrl = this.normalizeApiBaseUrl(options.apiBaseUrl ?? 'https://api.agrarmonitor.de/v1');
this.timeoutMs = options.timeoutMs ?? 15000;
this.autoLogin = options.autoLogin ?? true;
this.autoRetry = options.autoRetry ?? true;
this.loginStrategy = options.loginStrategy ?? 'redirect';
this.logger = options.logger;
}
async init() {
this.cookieJar = await this.options.cookieStore.load();
this.http = this.createHttpClient();
this.apiHttp = this.createApiHttpClient();
if (this.autoLogin) {
const valid = await this.isSessionValid();
if (!valid) {
await this.login();
}
}
return this;
}
async login() {
if (this.loginInProgress) {
return this.loginInProgress;
}
this.loginInProgress = this.performLogin().finally(() => {
this.loginInProgress = null;
});
return this.loginInProgress;
}
async clearSession() {
this.cookieJar = new tough_cookie_1.CookieJar();
await this.options.cookieStore.clear();
this.http = this.createHttpClient();
this.apiHttp = this.createApiHttpClient();
}
async saveSession() {
await this.options.cookieStore.save(this.cookieJar);
}
async getCookieCount(url = this.baseUrl) {
return this.cookieJar.getCookiesSync(url).length;
}
async checkFreigeschaltet() {
const response = await this.http.get('/', {
maxRedirects: 0,
validateStatus: status => status >= 200 && status < 400,
});
await this.saveSession();
const redirectLocation = this.getHeader(response, 'location');
const redirected = response.status >= 300 && response.status < 400 && this.isFreischaltungUrl(redirectLocation);
return {
freigeschaltet: !redirected,
status: response.status,
redirected,
redirectLocation,
timestamp: new Date().toISOString(),
cookies: await this.getCookieCount(),
};
}
async checkRegistriert() {
const response = await this.http.get('/', {
maxRedirects: 5,
validateStatus: status => status >= 200 && status < 500,
});
await this.saveSession();
const pageContent = typeof response.data === 'string' ? response.data : '';
const hasRegistrationText = pageContent.includes('Neues Gerät registrieren');
return {
registriert: !hasRegistrationText,
status: response.status,
hasRegistrationText,
timestamp: new Date().toISOString(),
cookies: await this.getCookieCount(),
};
}
async registerDevice(registration) {
const agrarmonitorId = registration.agrarmonitorId.trim();
const pcName = registration.pcName.trim();
if (!agrarmonitorId || !pcName) {
throw new Error('AgrarmonitorID und PC-Name sind erforderlich');
}
const freischaltungResponse = await this.http.get('/freischaltung/');
const responseContent = typeof freischaltungResponse.data === 'string' ? freischaltungResponse.data : '';
const nonce = this.extractNonce(responseContent, '#nonce, input[name="nonce"]');
const registerResponse = await this.http.post('/freischaltung/api/register.php', {
firma: agrarmonitorId,
name: pcName,
nonce,
}, {
headers: {
'Content-Type': 'application/json',
},
validateStatus: status => status >= 200 && status < 500,
});
await this.saveSession();
const success = registerResponse.status >= 200 && registerResponse.status < 300;
return {
success,
status: registerResponse.status,
message: success ? 'Registrierung erfolgreich' : 'Registrierung fehlgeschlagen',
data: {
agrarmonitorId,
pcName,
nonce: this.maskNonce(nonce),
},
timestamp: new Date().toISOString(),
cookies: await this.getCookieCount(),
};
}
async fetchCustomers(options = {}) {
const response = await this.apiRequest('/kunden', {
params: {
per_page: options.perPage ?? 99999,
},
apiToken: options.apiToken,
});
const responseData = response.data;
if (!responseData || !Array.isArray(responseData.data)) {
throw new Error('Ungueltige Agrarmonitor API-Antwort');
}
return responseData.data;
}
async getKunden2(options = {}) {
const customers = await this.fetchAllCustomers(options);
return customers.map(customer => this.mapKunde2(customer));
}
async eingangsrechnungenLivesearch(suchstring) {
const response = await this.http.get('/module/dateien/livesearch.php', {
params: this.createDateienLivesearchParams(suchstring),
});
await this.saveSession();
const document = this.parseHtmlDocument(response.data);
const rows = Array.from(document.querySelectorAll('table#dateien tbody tr'));
const results = [];
for (const row of rows) {
const cells = Array.from(row.querySelectorAll('td'));
const typText = cells[3]?.textContent?.trim() ?? '';
if (!typText.startsWith('Eingangsrechnungen')) {
continue;
}
const dokumentId = this.parseNumber(row.getAttribute('data-file_id'));
const dataFile = row.getAttribute('data-file') ?? '';
const dokumentName = cells[2]?.querySelector('b > a')?.textContent?.trim() ?? '';
const dateiName = cells[2]?.querySelector('span')?.textContent?.trim() ?? '';
const belegLink = cells[3]?.querySelector('a');
const belegTextParts = (belegLink?.textContent ?? '').split(',').map(part => part.trim()).filter(Boolean);
const belegNummer = belegTextParts[0] ?? '';
const belegDatum = this.parseGermanShortDateFromText(belegTextParts.at(-1) ?? '');
const eingangId = this.parseNumber(this.lastPathSegment(belegLink?.getAttribute('href') ?? ''));
const { interneBelegNummer, kundenId, betriebId, dokumentTyp } = await this.getEingangsrechnungEditMeta(eingangId);
const { eingangsDatum, buchungsDatum } = await this.getEingangsrechnungDetailMeta(eingangId);
results.push({
dokumentId,
vorschauUrl: `${AgrarmonitorConnector.s3DateienBaseUrl}/v_${this.fileBasename(dataFile)}.png`,
dokumentUrl: `${AgrarmonitorConnector.s3DateienBaseUrl}/${dataFile}`,
dokumentName,
dateiName,
belegNummer,
interneBelegNummer,
belegDatum,
buchungsDatum,
eingangsDatum,
eingangId,
kundenId,
betriebId,
dokumentTyp,
});
}
return results;
}
async eingangsrechnungVorhanden(suchstring) {
const response = await this.http.get('/module/dateien/livesearch.php', {
params: this.createDateienLivesearchParams(suchstring),
});
await this.saveSession();
return this.hasTableRows(response.data, 'table#dateien tbody tr');
}
async eingangsrechnungImDateieingangVorhanden(suchstring) {
const response = await this.http.get('/module/dateien/eingang/livesearch.php', {
params: {
suchstring,
seite: 1,
},
});
await this.saveSession();
return this.hasTableRows(response.data, 'table#dateien_eingang tbody tr');
}
async getRechnungsdaten(rechnungId) {
const response = await this.http.get('/module/eingangsrechnungen/api/eingangsrechnungen.php', {
params: {
id: 'edit',
rechnungId,
},
});
await this.saveSession();
const document = this.parseHtmlDocument(response.data);
return {
lieferschein: this.inputValue(document, 'lieferscheinnummer'),
rechnung: this.inputValue(document, 'rechnungsnummer'),
datum: this.requireDate(this.parseGermanShortDate(this.inputValue(document, 'rechnungsdatum')), 'rechnungsdatum'),
kundenId: this.selectedNumberValue(document, 'rgempf'),
adresstext: this.inputValue(document, 'addressName'),
};
}
async setRechnungsdaten(rechnungId, daten) {
const response = await this.http.post(`/module/eingangsrechnungen/api/eingangsrechnungen.php?id=update&rechnungId=${encodeURIComponent(rechnungId)}`, new URLSearchParams({
lieferscheinnummer: daten.lieferschein,
rechnungsnummer: daten.rechnung,
rechnungsdatum: this.formatGermanShortDate(daten.datum),
rgempf: String(daten.kundenId),
adresstext: daten.adresstext,
}), this.formPostConfig(`/eingangsrechnungen/detail/${rechnungId}`));
await this.saveSession();
return response.status >= 200 && response.status < 300;
}
async setLieferscheinNummer(rechnungId, nummer) {
const rechnungsdaten = await this.getRechnungsdaten(rechnungId);
const success = await this.setRechnungsdaten(rechnungId, {
...rechnungsdaten,
lieferschein: nummer,
});
if (!success) {
throw new Error('Lieferscheinnummer konnte nicht gespeichert werden');
}
}
async setEingangsdatum(rechnungId, datum) {
const response = await this.http.post('/module/eingangsrechnungen/api/updateReceived.php', new URLSearchParams({
datum: this.formatGermanShortDate(datum),
receiptID: String(rechnungId),
}), this.formPostConfig(`/eingangsrechnungen/detail/${rechnungId}`));
await this.saveSession();
return response.status >= 200 && response.status < 300;
}
async getCustomerById(id) {
const response = await this.apiRequest(`/kunden/${id}`);
this.logDebug('Agrarmonitor customer API raw response', response.data);
if (this.isWrappedApiCustomer(response.data)) {
return response.data.data;
}
if (this.isApiCustomer(response.data)) {
return response.data;
}
throw new Error('Ungueltige Agrarmonitor Kunden-API-Antwort');
}
async getMaschinenKategorien() {
const response = await this.http.get('/maschinen/kategorien');
await this.saveSession();
const document = this.parseHtmlDocument(response.data);
const rows = Array.from(document.querySelectorAll('table#kategorien tbody tr'));
return rows.map(row => {
const cells = Array.from(row.querySelectorAll('td'));
return {
id: this.parseNumber(row.id),
name: cells[0]?.textContent?.trim() ?? '',
zugmaschine: this.parseJaNein(cells[2]?.textContent ?? ''),
mobilSichtbar: Boolean(cells[4]?.querySelector('input[type="checkbox"]')?.checked),
};
});
}
async getMaschinen(gruppenId, suchstring = '') {
const response = await this.http.get('/module/maschinen/livesearch.php', {
params: {
suchstring,
maschinen_aktiv: 1,
maschinengruppe: gruppenId,
seite: 1,
},
});
await this.saveSession();
const document = this.parseHtmlDocument(response.data);
const rows = Array.from(document.querySelectorAll('table.maschinen_table tbody tr'));
return rows.map(row => {
const cells = Array.from(row.querySelectorAll('td'));
return {
id: this.parseNumber(row.getAttribute('data-id') ?? row.id),
nummer: cells[0]?.textContent?.trim() ?? '',
name: cells[1]?.textContent?.trim() ?? '',
kennzeichen: cells[2]?.textContent?.trim() ?? '',
aktiv: Boolean(cells[4]?.querySelector('.fa-check, .text-green')),
};
});
}
async getFirmen() {
const response = await this.http.get('/einstellungen');
await this.saveSession();
const document = this.parseHtmlDocument(response.data);
const rows = Array.from(document.querySelectorAll('table#firmen_table tbody tr'));
return rows.map(row => {
const cells = Array.from(row.querySelectorAll('td'));
return {
id: this.parseNumber(row.getAttribute('data-firma_id') ?? row.id),
bezeichnung: cells[0]?.textContent?.trim() ?? '',
};
});
}
async getArtikelEinheiten() {
const response = await this.http.get('/artikel/einheiten');
await this.saveSession();
const document = this.parseHtmlDocument(response.data);
const rows = Array.from(document.querySelectorAll('table#einheiten tbody tr'));
return rows.map(row => {
const cells = Array.from(row.querySelectorAll('td'));
return {
id: this.parseNumber(row.getAttribute('data-id') ?? row.id),
bezeichnung: cells[0]?.textContent?.trim() ?? '',
kurz: cells[1]?.textContent?.trim() ?? '',
};
});
}
async getArtikelKategorien() {
const response = await this.http.get('/artikel/kategorien');
await this.saveSession();
const document = this.parseHtmlDocument(response.data);
const rows = Array.from(document.querySelectorAll('table#kategorien tbody tr'));
return rows.map(row => {
const cells = Array.from(row.querySelectorAll('td'));
return {
id: this.parseNumber(row.id),
name: cells[1]?.textContent?.trim() ?? '',
};
});
}
async getArtikel(artikelGruppe, suchstring = '') {
const response = await this.http.get('/module/artikel/livesearch.php', {
params: {
suchstring,
artikel_aktiv: 0,
warengruppe: artikelGruppe,
lagerplatz: 0,
bestand: 0,
itemsperpage: 100000,
seite: 1,
},
});
await this.saveSession();
const document = this.parseHtmlDocument(response.data);
const rows = Array.from(document.querySelectorAll('table#artikel_table tbody tr'));
return rows.map(row => {
const cells = Array.from(row.querySelectorAll('td'));
return {
id: this.parseNumber(row.getAttribute('data-id') ?? row.id),
nummer: cells[0]?.textContent?.trim() ?? '',
bezeichnung: cells[1]?.textContent?.trim() ?? '',
};
});
}
async getMitarbeiter(suchstring = '', mitarbeitergruppe = 0) {
const response = await this.http.get('/module/mitarbeiter/livesearch.php', {
params: {
suchstring,
mitarbeiter_aktiv: 1,
mitarbeitergruppe,
itemsperpage: 100000,
seite: 1,
},
});
await this.saveSession();
const document = this.parseHtmlDocument(response.data);
const rows = Array.from(document.querySelectorAll('table#mitarbeiter_table tbody tr, table.mitarbeiter_table tbody tr'));
return rows.map(row => {
const cells = Array.from(row.querySelectorAll('td'));
return {
id: this.parseNumber(row.getAttribute('data-id') ?? row.id),
nummer: cells[0]?.textContent?.trim() ?? '',
nachname: cells[2]?.textContent?.trim() ?? '',
vorname: cells[3]?.textContent?.trim() ?? '',
aktiv: Boolean(row.querySelector('td.toggle .fa-check, td.toggle .text-green')),
};
});
}
createHttpClient() {
const client = (0, axios_cookiejar_support_1.wrapper)(axios_1.default.create({
baseURL: this.baseUrl,
jar: this.cookieJar,
withCredentials: true,
timeout: this.timeoutMs,
headers: {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36',
},
maxRedirects: 5,
validateStatus: status => status >= 200 && status < 400,
}));
client.interceptors.response.use(async (response) => {
await this.options.cookieStore.save(this.cookieJar);
const config = response.config;
if (this.autoRetry && !config._agrarmonitorLoginRequest && this.isLoginRequiredResponse(response)) {
return this.retryAfterLogin(config);
}
return response;
}, async (error) => {
const response = error.response;
const config = error.config;
if (this.autoRetry && response && config && !config._agrarmonitorLoginRequest && this.isLoginRequiredResponse(response)) {
return this.retryAfterLogin(config);
}
throw error;
});
return client;
}
createApiHttpClient(apiToken = this.options.apiToken) {
return axios_1.default.create({
baseURL: this.apiBaseUrl,
timeout: this.timeoutMs,
headers: {
Accept: 'application/json',
...(apiToken ? { Authorization: `Bearer ${apiToken}` } : {}),
},
validateStatus: status => status >= 200 && status < 500,
});
}
async apiRequest(url, config = {}) {
const apiToken = config.apiToken ?? this.options.apiToken;
if (!apiToken) {
throw new Error('Agrarmonitor API-Token nicht konfiguriert');
}
const { apiToken: _apiToken, ...axiosConfig } = config;
const client = apiToken === this.options.apiToken ? this.apiHttp : this.createApiHttpClient(apiToken);
return client.get(url, axiosConfig);
}
async fetchAllCustomers(options) {
const customers = [];
let page = 1;
let lastPage = 1;
do {
const response = await this.apiRequest('/kunden', {
params: {
per_page: options.perPage ?? 99999,
page,
},
apiToken: options.apiToken,
});
if (!response.data || !Array.isArray(response.data.data)) {
throw new Error('Ungueltige Agrarmonitor API-Antwort');
}
customers.push(...response.data.data);
lastPage = this.parsePositiveNumber(response.data.meta?.last_page, page);
page++;
} while (page <= lastPage);
return customers;
}
mapKunde2(customer) {
return {
ID: this.parseNumber(customer.id),
ist_Kunde: this.toBoolean(customer.ist_kunde),
Kundennummer: this.toStringValue(customer.kundennummer),
ist_Lieferant: this.toBoolean(customer.ist_lieferant),
Lieferantennummer: this.toStringValue(customer.lieferantennummer),
Firma: this.toStringValue(customer.firma),
Anrede: this.toStringValue(customer.anrede),
Vorname: this.toStringValue(customer.vorname),
Nachname: this.toStringValue(customer.nachname),
Strasse: this.toStringValue(customer.strasse),
Plz: this.toStringValue(customer.plz),
Ort: this.toStringValue(customer.ort),
Land: this.toStringValue(customer.land_iso_3166),
ist_aktiv: this.toBoolean(customer.ist_aktiv),
};
}
async performLogin() {
if (!this.options.username || !this.options.password) {
throw new Error('Agrarmonitor-Credentials nicht konfiguriert');
}
this.logger?.info?.('Fuehre Agrarmonitor-Login durch');
if (this.loginStrategy === 'auto') {
this.logger?.warn?.('loginStrategy "auto" ist veraltet; verwende Redirect-Login');
}
await this.performRedirectLogin();
if (!(await this.isSessionValid({ skipAutoRetry: true }))) {
throw new Error('Agrarmonitor-Login durchgefuehrt, Session weiterhin ungueltig - Geraet freigeschaltet? Credentials korrekt?');
}
await this.options.cookieStore.save(this.cookieJar);
this.logger?.info?.('Agrarmonitor-Login erfolgreich');
}
async performRedirectLogin() {
const loginPageResponse = await this.http.get('/', this.loginRequestConfig());
const loginPageText = typeof loginPageResponse.data === 'string' ? loginPageResponse.data : '';
if (!this.isLoginPageText(loginPageText)) {
return;
}
const nonce = this.extractNonce(loginPageText, 'input[name="nonce"]');
const loginData = {
username: this.options.username,
passwort: this.options.password,
nonce,
ssoAction: "",
ssoReturn: "",
};
const loginPostConfig = {
headers: {
'Content-Type': 'application/json',
},
_agrarmonitorLoginRequest: true,
};
const response = await this.http.post('/login/api/login.php', loginData, loginPostConfig);
const responseText = typeof response.data === 'string' ? response.data : '';
if (this.isLoginPageText(responseText)) {
throw new Error('Agrarmonitor-Redirect-Login fehlgeschlagen');
}
}
async isSessionValid(options = {}) {
try {
const response = await this.http.get('/', options.skipAutoRetry ? this.loginRequestConfig() : undefined);
return !this.isLoginRequiredResponse(response);
}
catch {
return false;
}
}
loginRequestConfig() {
return {
_agrarmonitorLoginRequest: true,
};
}
isLoginRequiredResponse(response) {
const responseUrl = this.getResponseUrl(response);
const responseText = typeof response.data === 'string' ? response.data : '';
return (response.status === 401 ||
response.status === 403 ||
this.isLoginPageText(responseText));
}
async retryAfterLogin(config) {
if (config._agrarmonitorRetry) {
throw new Error('Agrarmonitor-Request nach erneutem Login weiterhin nicht autorisiert');
}
config._agrarmonitorRetry = true;
this.logger?.info?.('Agrarmonitor-Session abgelaufen, erneuter Login wird ausgefuehrt');
await this.login();
return this.http.request(config);
}
createDateienLivesearchParams(suchstring) {
return {
suchstring,
stammdatum_typ: -1,
mobil: -1,
sensibel: -1,
firma: 0,
itemsperpage: 100000,
seite: 1,
};
}
async getEingangsrechnungEditMeta(rechnungId) {
const response = await this.http.get('/module/eingangsrechnungen/api/eingangsrechnungen.php', {
params: {
id: 'edit',
rechnungId,
},
});
await this.saveSession();
const document = this.parseHtmlDocument(response.data);
return {
interneBelegNummer: this.inputValue(document, 'lieferscheinnummer'),
kundenId: this.selectedNumberValue(document, 'rgempf'),
betriebId: this.selectedNumberValue(document, 'firma_id'),
dokumentTyp: this.selectedNumberValue(document, 'typ'),
};
}
async getEingangsrechnungDetailMeta(rechnungId) {
const response = await this.http.get(`/eingangsrechnungen/detail/${rechnungId}`);
await this.saveSession();
const document = this.parseHtmlDocument(response.data);
const receivedStatus = document.querySelector('#receivedStatus');
const receivedText = receivedStatus?.textContent?.trim() ?? '';
const parentParts = (receivedStatus?.parentElement?.textContent ?? '').split('-');
const bookingText = parentParts.at(-1)?.trim() ?? '';
return {
eingangsDatum: !receivedText || receivedText === 'Nicht empfangen'
? null
: this.parseGermanShortDateFromText(receivedText.slice(13).trim()),
buchungsDatum: !bookingText || bookingText === 'Nicht gebucht'
? null
: this.parseGermanShortDateFromText(bookingText.slice(11).trim()),
};
}
formPostConfig(refererPath) {
return {
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
Referer: `${this.baseUrl}${refererPath}`,
Origin: this.baseUrl,
},
validateStatus: status => status >= 200 && status < 400,
};
}
parseHtmlDocument(data) {
return new jsdom_1.JSDOM(typeof data === 'string' ? data : String(data ?? '')).window.document;
}
hasTableRows(data, selector) {
return this.parseHtmlDocument(data).querySelectorAll(selector).length > 0;
}
inputValue(document, name) {
return document.querySelector(`input[name="${name}"]`)?.value.trim() ?? '';
}
selectedNumberValue(document, name) {
return this.parseNumber(document.querySelector(`select[name="${name}"] option:checked`)?.value);
}
parseNumber(value) {
const numberValue = Number(String(value ?? '').trim());
return Number.isFinite(numberValue) ? numberValue : 0;
}
parsePositiveNumber(value, fallback) {
const numberValue = this.parseNumber(value);
return numberValue > 0 ? numberValue : fallback;
}
toStringValue(value) {
return value === null || typeof value === 'undefined' ? '' : String(value);
}
toBoolean(value) {
if (typeof value === 'boolean') {
return value;
}
if (typeof value === 'number') {
return value === 1;
}
const normalized = String(value ?? '').trim().toLowerCase();
return normalized === '1' || normalized === 'true' || normalized === 'ja';
}
parseJaNein(value) {
return value.trim().toLowerCase() === 'ja';
}
parseGermanShortDate(value) {
const match = value.trim().match(/^(\d{2})\.(\d{2})\.(\d{2})$/);
if (!match) {
return null;
}
const [, day, month, year] = match;
const parsed = new Date(Number(`20${year}`), Number(month) - 1, Number(day));
if (parsed.getFullYear() !== Number(`20${year}`) ||
parsed.getMonth() !== Number(month) - 1 ||
parsed.getDate() !== Number(day)) {
return null;
}
return parsed;
}
requireDate(value, fieldName) {
if (!value) {
throw new Error(`Ungueltiges Datumsformat fuer ${fieldName}`);
}
return value;
}
formatGermanShortDate(date) {
const day = String(date.getDate()).padStart(2, '0');
const month = String(date.getMonth() + 1).padStart(2, '0');
const year = String(date.getFullYear()).slice(-2);
return `${day}.${month}.${year}`;
}
lastPathSegment(value) {
return value.split('?')[0]?.split('/').filter(Boolean).at(-1) ?? '';
}
fileBasename(fileName) {
const lastDotIndex = fileName.lastIndexOf('.');
return lastDotIndex === -1 ? fileName : fileName.slice(0, lastDotIndex);
}
normalizeApiBaseUrl(value) {
const withoutTrailingSlash = value.replace(/\/+$/, '');
return withoutTrailingSlash.endsWith('/v1') ? withoutTrailingSlash : `${withoutTrailingSlash}/v1`;
}
isWrappedApiCustomer(value) {
return (typeof value === 'object' &&
value !== null &&
'data' in value &&
this.isApiCustomer(value.data));
}
isApiCustomer(value) {
return (typeof value === 'object' &&
value !== null &&
'id' in value &&
(typeof value.id === 'string' || typeof value.id === 'number'));
}
parseGermanShortDateFromText(value) {
const match = value.match(/(\d{2}\.\d{2}\.\d{2})/);
return match ? this.parseGermanShortDate(match[1]) : null;
}
logDebug(message, meta) {
if (this.logger?.debug) {
this.logger.debug(message, meta);
return;
}
this.logger?.info?.(message, meta);
}
getResponseUrl(response) {
const request = response.request;
return request?.res?.responseUrl ?? '';
}
getHeader(response, header) {
const value = response.headers[header.toLowerCase()];
if (Array.isArray(value)) {
return value[0] ?? null;
}
return typeof value === 'string' ? value : null;
}
isFreischaltungUrl(value) {
return Boolean(value?.includes('freischaltung'));
}
isLoginPageText(responseText) {
return responseText.includes('Anmeldung - AGRARMONITOR');
}
extractNonce(html, selector) {
const dom = new jsdom_1.JSDOM(html);
const element = dom.window.document.querySelector(selector);
const nonce = element?.getAttribute('value') ?? element?.value ?? '';
if (!nonce) {
throw new Error('Nonce-Element nicht gefunden oder leer');
}
return nonce;
}
maskNonce(nonce) {
return nonce.length <= 10 ? nonce : `${nonce.slice(0, 10)}...`;
}
}
exports.AgrarmonitorConnector = AgrarmonitorConnector;
//# sourceMappingURL=AgrarmonitorConnector.js.map