Update ReUI skill documentation to reflect the addition of 3 new components, increasing the total from 17 to 20. Adjust descriptions and examples accordingly, including updates to the data-grid API to align with TanStack Table v9. Ensure all references to components and their usage are consistent across the documentation.
Build and Push CFDM Docker Image / build-and-push (push) Successful in 2m2s
Build and Push CFDM Docker Image / create-release (push) Skipped
Build and Push CFDM Docker Image / update-wiki (push) Successful in 7s

This commit is contained in:
Denozordec committed 2026-08-07 09:46:30 +07:00
1 parent 721332e767
commit 3fb8480f8a
27 files changed
+444 -108

No files matched your search

+18 -2
View File
@@ -6717,6 +6717,12 @@ declare function updateDnsFields(db: Db, id: number, recordType: string, name: s
declare function setDnsSyncStatus(db: Db, id: number, syncStatus: string, cfRecordId: string | null, lastError: string | null): void;
declare function deleteDnsRecord(db: Db, id: number): void;
declare function listDnsByDomain(db: Db, domainId: number): DnsRecord[];
/**
* Origin A/AAAA из локальной таблицы dns_records для FQDN.
* content в CFDM — origin IP даже при proxied=true (в отличие от публичного DNS).
* Следует по CNAME-записям в той же БД.
*/
declare function listOriginIpsForFqdn(db: Db, fqdn: string, depth?: number): string[];
declare function findDnsByCfId(db: Db, domainId: number, cfRecordId: string): DnsRecord | null;
declare function markDnsPendingDelete(db: Db, id: number): void;
declare function listServices(db: Db): Service[];
@@ -6806,6 +6812,11 @@ type HealthAggregate = {
};
/** Worst status across ip_health_status rows for each ref_id in a scope. */
declare function aggregateIpHealthByRefs(db: Db, scope: HealthCheckScope, refIds: number[]): Map<number, HealthAggregate>;
/**
* Group-scope badge health: only IPs that are currently published/probed
* (A-record binding IPs of enabled services). Ignores stale pool-only rows.
*/
declare function aggregateGroupScopeHealthByIds(db: Db, groupIds: number[]): Map<number, HealthAggregate>;
/** Worst binding-scope health rolled up per service_id. */
declare function aggregateIpHealthByServiceIds(db: Db, serviceIds: number[]): Map<number, HealthAggregate>;
declare function mergeHealthAggregates(parts: Array<HealthAggregate | undefined | null>): HealthAggregate;
@@ -6813,7 +6824,10 @@ declare function getIpHealthStatusRow(db: Db, scope: HealthCheckScope, refId: nu
declare function upsertIpHealthStatus(db: Db, scope: HealthCheckScope, refId: number, ip: string, status: string, latencyMs: number | null, consecutiveFailures: number, lastError: string | null): void;
declare function deleteIpHealthStatusForRef(db: Db, scope: HealthCheckScope, refId: number): void;
declare function deleteIpHealthStatusForIp(db: Db, scope: HealthCheckScope, refId: number, ip: string): void;
/** Drop health rows whose IP is no longer a live probe target for that scope/ref. */
/** Drop health rows whose IP is no longer a live probe target for that scope/ref.
* Also clears refs that have stored rows but zero active targets (e.g. all
* services disabled) — otherwise stale `down` keeps poisoning the group badge.
*/
declare function pruneStaleIpHealthStatus(db: Db, activeTargets: Array<{
scope: HealthCheckScope;
ref_id: number;
@@ -6891,6 +6905,7 @@ type repos_HealthAggregate = HealthAggregate;
type repos_ServiceGroupLbPatch = ServiceGroupLbPatch;
type repos_UpdateSubdomainPatch = UpdateSubdomainPatch;
declare const repos_addDomainTags: typeof addDomainTags;
declare const repos_aggregateGroupScopeHealthByIds: typeof aggregateGroupScopeHealthByIds;
declare const repos_aggregateIpHealthByRefs: typeof aggregateIpHealthByRefs;
declare const repos_aggregateIpHealthByServiceIds: typeof aggregateIpHealthByServiceIds;
declare const repos_bindingsToRemove: typeof bindingsToRemove;
@@ -6959,6 +6974,7 @@ declare const repos_listGroups: typeof listGroups;
declare const repos_listHealthCheckTargets: typeof listHealthCheckTargets;
declare const repos_listIpHealthStatus: typeof listIpHealthStatus;
declare const repos_listNotificationLog: typeof listNotificationLog;
declare const repos_listOriginIpsForFqdn: typeof listOriginIpsForFqdn;
declare const repos_listRecordsForBinding: typeof listRecordsForBinding;
declare const repos_listServiceGroups: typeof listServiceGroups;
declare const repos_listServiceIps: typeof listServiceIps;
@@ -6997,7 +7013,7 @@ declare const repos_upsertCertificateCheck: typeof upsertCertificateCheck;
declare const repos_upsertIpHealthStatus: typeof upsertIpHealthStatus;
declare const repos_upsertSubdomain: typeof upsertSubdomain;
declare namespace repos {
export { type repos_BindingIpMeta as BindingIpMeta, type repos_BindingLbPatch as BindingLbPatch, type repos_DnsListFilter as DnsListFilter, type repos_DomainMonitorRow as DomainMonitorRow, type repos_HealthAggregate as HealthAggregate, type repos_ServiceGroupLbPatch as ServiceGroupLbPatch, type repos_UpdateSubdomainPatch as UpdateSubdomainPatch, repos_addDomainTags as addDomainTags, repos_aggregateIpHealthByRefs as aggregateIpHealthByRefs, repos_aggregateIpHealthByServiceIds as aggregateIpHealthByServiceIds, repos_bindingsToRemove as bindingsToRemove, repos_countCertificatesByStatus as countCertificatesByStatus, repos_createDomain as createDomain, repos_createDomainMonitor as createDomainMonitor, repos_createGroup as createGroup, repos_createService as createService, repos_createServiceGroup as createServiceGroup, repos_createSubdomain as createSubdomain, repos_createSyncJob as createSyncJob, repos_deleteBinding as deleteBinding, repos_deleteBindingsExcept as deleteBindingsExcept, repos_deleteCertificatesNotIn as deleteCertificatesNotIn, repos_deleteDnsRecord as deleteDnsRecord, repos_deleteDomain as deleteDomain, repos_deleteDomainMonitor as deleteDomainMonitor, repos_deleteGroup as deleteGroup, repos_deleteIpHealthStatusForIp as deleteIpHealthStatusForIp, repos_deleteIpHealthStatusForRef as deleteIpHealthStatusForRef, repos_deleteService as deleteService, repos_deleteServiceGroup as deleteServiceGroup, repos_deleteSubdomain as deleteSubdomain, repos_findBinding as findBinding, repos_findDnsByCfId as findDnsByCfId, repos_findDomainByZoneName as findDomainByZoneName, repos_findSubdomainByDomainAndName as findSubdomainByDomainAndName, repos_finishSyncJob as finishSyncJob, repos_getBinding as getBinding, repos_getBindingView as getBindingView, repos_getCertificate as getCertificate, repos_getDnsRecord as getDnsRecord, repos_getDomain as getDomain, repos_getDomainMonitor as getDomainMonitor, repos_getGroup as getGroup, repos_getGroupWithStats as getGroupWithStats, repos_getIpHealthStatusRow as getIpHealthStatusRow, repos_getService as getService, repos_getServiceGroup as getServiceGroup, repos_getSubdomain as getSubdomain, repos_getSyncJob as getSyncJob, repos_insertBinding as insertBinding, repos_insertDnsRecord as insertDnsRecord, repos_insertNotificationLog as insertNotificationLog, repos_linkBindingRecord as linkBindingRecord, repos_linkGroupDnsRecord as linkGroupDnsRecord, repos_listAllBindings as listAllBindings, repos_listAllDomains as listAllDomains, repos_listAllSubdomains as listAllSubdomains, repos_listBindingIps as listBindingIps, repos_listBindingIpsWithMeta as listBindingIpsWithMeta, repos_listBindingsByDomain as listBindingsByDomain, repos_listBindingsByService as listBindingsByService, repos_listCertificates as listCertificates, repos_listDnsByDomain as listDnsByDomain, repos_listDnsRecords as listDnsRecords, repos_listDomainMonitorResults as listDomainMonitorResults, repos_listDomainMonitorResultsForDomain as listDomainMonitorResultsForDomain, repos_listDomainMonitors as listDomainMonitors, repos_listDomainTags as listDomainTags, repos_listDomains as listDomains, repos_listDomainsEnriched as listDomainsEnriched, repos_listEnabledDomainMonitors as listEnabledDomainMonitors, repos_listGroupDnsRecords as listGroupDnsRecords, repos_listGroups as listGroups, repos_listHealthCheckTargets as listHealthCheckTargets, repos_listIpHealthStatus as listIpHealthStatus, repos_listNotificationLog as listNotificationLog, repos_listRecordsForBinding as listRecordsForBinding, repos_listServiceGroups as listServiceGroups, repos_listServiceIps as listServiceIps, repos_listServices as listServices, repos_listServicesByGroup as listServicesByGroup, repos_listSubdomainsByDomain as listSubdomainsByDomain, repos_listUngroupedServices as listUngroupedServices, repos_markDnsPendingDelete as markDnsPendingDelete, repos_mergeHealthAggregates as mergeHealthAggregates, repos_pruneStaleIpHealthStatus as pruneStaleIpHealthStatus, repos_reorderServices as reorderServices, repos_replaceBindingIps as replaceBindingIps, repos_replaceBindingIpsWithMeta as replaceBindingIpsWithMeta, repos_replaceServiceIps as replaceServiceIps, repos_setBindingCnameTarget as setBindingCnameTarget, repos_setBindingDnsRecordId as setBindingDnsRecordId, repos_setDnsSyncStatus as setDnsSyncStatus, repos_setDomainLastSynced as setDomainLastSynced, repos_setDomainTags as setDomainTags, repos_setServiceEnabled as setServiceEnabled, repos_setServiceGroup as setServiceGroup, repos_setServiceGroupEnabled as setServiceGroupEnabled, repos_setServiceLb as setServiceLb, repos_unlinkBindingRecord as unlinkBindingRecord, repos_unlinkGroupDnsRecord as unlinkGroupDnsRecord, repos_updateBindingFields as updateBindingFields, repos_updateBindingLbConfig as updateBindingLbConfig, repos_updateDnsFields as updateDnsFields, repos_updateDomain as updateDomain, repos_updateDomainMonitorResult as updateDomainMonitorResult, repos_updateGroup as updateGroup, repos_updateServiLine truncated
export { type repos_BindingIpMeta as BindingIpMeta, type repos_BindingLbPatch as BindingLbPatch, type repos_DnsListFilter as DnsListFilter, type repos_DomainMonitorRow as DomainMonitorRow, type repos_HealthAggregate as HealthAggregate, type repos_ServiceGroupLbPatch as ServiceGroupLbPatch, type repos_UpdateSubdomainPatch as UpdateSubdomainPatch, repos_addDomainTags as addDomainTags, repos_aggregateGroupScopeHealthByIds as aggregateGroupScopeHealthByIds, repos_aggregateIpHealthByRefs as aggregateIpHealthByRefs, repos_aggregateIpHealthByServiceIds as aggregateIpHealthByServiceIds, repos_bindingsToRemove as bindingsToRemove, repos_countCertificatesByStatus as countCertificatesByStatus, repos_createDomain as createDomain, repos_createDomainMonitor as createDomainMonitor, repos_createGroup as createGroup, repos_createService as createService, repos_createServiceGroup as createServiceGroup, repos_createSubdomain as createSubdomain, repos_createSyncJob as createSyncJob, repos_deleteBinding as deleteBinding, repos_deleteBindingsExcept as deleteBindingsExcept, repos_deleteCertificatesNotIn as deleteCertificatesNotIn, repos_deleteDnsRecord as deleteDnsRecord, repos_deleteDomain as deleteDomain, repos_deleteDomainMonitor as deleteDomainMonitor, repos_deleteGroup as deleteGroup, repos_deleteIpHealthStatusForIp as deleteIpHealthStatusForIp, repos_deleteIpHealthStatusForRef as deleteIpHealthStatusForRef, repos_deleteService as deleteService, repos_deleteServiceGroup as deleteServiceGroup, repos_deleteSubdomain as deleteSubdomain, repos_findBinding as findBinding, repos_findDnsByCfId as findDnsByCfId, repos_findDomainByZoneName as findDomainByZoneName, repos_findSubdomainByDomainAndName as findSubdomainByDomainAndName, repos_finishSyncJob as finishSyncJob, repos_getBinding as getBinding, repos_getBindingView as getBindingView, repos_getCertificate as getCertificate, repos_getDnsRecord as getDnsRecord, repos_getDomain as getDomain, repos_getDomainMonitor as getDomainMonitor, repos_getGroup as getGroup, repos_getGroupWithStats as getGroupWithStats, repos_getIpHealthStatusRow as getIpHealthStatusRow, repos_getService as getService, repos_getServiceGroup as getServiceGroup, repos_getSubdomain as getSubdomain, repos_getSyncJob as getSyncJob, repos_insertBinding as insertBinding, repos_insertDnsRecord as insertDnsRecord, repos_insertNotificationLog as insertNotificationLog, repos_linkBindingRecord as linkBindingRecord, repos_linkGroupDnsRecord as linkGroupDnsRecord, repos_listAllBindings as listAllBindings, repos_listAllDomains as listAllDomains, repos_listAllSubdomains as listAllSubdomains, repos_listBindingIps as listBindingIps, repos_listBindingIpsWithMeta as listBindingIpsWithMeta, repos_listBindingsByDomain as listBindingsByDomain, repos_listBindingsByService as listBindingsByService, repos_listCertificates as listCertificates, repos_listDnsByDomain as listDnsByDomain, repos_listDnsRecords as listDnsRecords, repos_listDomainMonitorResults as listDomainMonitorResults, repos_listDomainMonitorResultsForDomain as listDomainMonitorResultsForDomain, repos_listDomainMonitors as listDomainMonitors, repos_listDomainTags as listDomainTags, repos_listDomains as listDomains, repos_listDomainsEnriched as listDomainsEnriched, repos_listEnabledDomainMonitors as listEnabledDomainMonitors, repos_listGroupDnsRecords as listGroupDnsRecords, repos_listGroups as listGroups, repos_listHealthCheckTargets as listHealthCheckTargets, repos_listIpHealthStatus as listIpHealthStatus, repos_listNotificationLog as listNotificationLog, repos_listOriginIpsForFqdn as listOriginIpsForFqdn, repos_listRecordsForBinding as listRecordsForBinding, repos_listServiceGroups as listServiceGroups, repos_listServiceIps as listServiceIps, repos_listServices as listServices, repos_listServicesByGroup as listServicesByGroup, repos_listSubdomainsByDomain as listSubdomainsByDomain, repos_listUngroupedServices as listUngroupedServices, repos_markDnsPendingDelete as markDnsPendingDelete, repos_mergeHealthAggregates as mergeHealthAggregates, repos_pruneStaleIpHealthStatus as pruneStaleIpHealthStatus, repos_reorderServices as reorderServices, repos_replaceBindingIps as replaceBindingIps, repos_replaceBindingIpsWithMeta as replaceBindingIpsWithMeta, repos_replaceServiceIps as replaceServiceIps, repos_setBindingCnameTarget as setBindingCnameTarget, repos_setBindingDnsRecordId as setBindingDnsRecordId, repos_setDnsSyncStatus as setDnsSyncStatus, repos_setDomainLastSynced as setDomainLastSynced, repos_setDomainTags as setDomainTags, repos_setServiceEnabled as setServiceEnabled, repos_setServiceGroup as setServiceGroup, repos_setServiceGroupEnabled as setServiceGroupEnabled, repos_setServiceLb as setServiceLb, repos_unlinkBindingRecord as unlinkBindingRecord, repos_unlinkGroupDnsRecord as unlinkGroupDnsRecord, repos_updateBindingFields as updateBindingFields, repos_updateBindingLbConfig as updateBindingLbConfig, repos_updateDnsFields as updateDnsFields, repos_updateDomain as updLine truncated
}
export { type AppSettingsDto, type AppSettingsPatch, type AppendAuditInput, ConflictError, type Db, type DnsListFilter, NotFoundError, type Sqlite, type UpdateSubdomainPatch, appSettings, appendAudit, auditLog, certificates, createDb, createMemoryDb, dnsRecords, domainMonitorResults, domainMonitors, domainTags, domains, getAppSettings, getAppSettingsSecrets, groups, healthCheck, ipHealthStatus, listAudit, notificationLog, repos, resolveDatabasePath, runMigrations, schema, serviceBindingIps, serviceBindingRecords, serviceBindings, serviceGroupDnsRecords, serviceGroups, serviceIps, services, subdomains, syncJobs, touchVpsTrackerSync, updateAppSettings };
+88 -14
View File
@@ -491,6 +491,7 @@ function touchVpsTrackerSync(db) {
var repos_exports = {};
__export(repos_exports, {
addDomainTags: () => addDomainTags,
aggregateGroupScopeHealthByIds: () => aggregateGroupScopeHealthByIds,
aggregateIpHealthByRefs: () => aggregateIpHealthByRefs,
aggregateIpHealthByServiceIds: () => aggregateIpHealthByServiceIds,
bindingsToRemove: () => bindingsToRemove,
@@ -559,6 +560,7 @@ __export(repos_exports, {
listHealthCheckTargets: () => listHealthCheckTargets,
listIpHealthStatus: () => listIpHealthStatus,
listNotificationLog: () => listNotificationLog,
listOriginIpsForFqdn: () => listOriginIpsForFqdn,
listRecordsForBinding: () => listRecordsForBinding,
listServiceGroups: () => listServiceGroups,
listServiceIps: () => listServiceIps,
@@ -597,7 +599,7 @@ __export(repos_exports, {
upsertIpHealthStatus: () => upsertIpHealthStatus,
upsertSubdomain: () => upsertSubdomain
});
import { dnsRecordNamesMatch } from "@cfdm/shared";
import { dnsRecordNamesMatch, isIpLiteral } from "@cfdm/shared";
import { and as and2, asc, count, eq as eq3, isNull, like, notInArray, or as or2, sql as sql2 } from "drizzle-orm";
function listGroups(db) {
return db.select().from(groups).orderBy(asc(groups.name)).all();
@@ -870,6 +872,33 @@ function deleteDnsRecord(db, id) {
function listDnsByDomain(db, domainId) {
return db.select().from(dnsRecords).where(eq3(dnsRecords.domain_id, domainId)).all().map(mapDnsRecord);
}
function listOriginIpsForFqdn(db, fqdn, depth = 0) {
if (depth > 8) return [];
const normalized = fqdn.trim().toLowerCase().replace(/\.+$/, "");
if (!normalized) return [];
const aIps = [];
let cnameNext = null;
for (const domain of listAllDomains(db)) {
const zone = domain.zone_name.trim().toLowerCase().replace(/\.+$/, "");
if (!zone) continue;
if (normalized !== zone && !normalized.endsWith(`.${zone}`)) continue;
const hostLabel = normalized === zone ? "@" : normalized.slice(0, -(zone.length + 1));
for (const record of listDnsByDomain(db, domain.id)) {
const type = record.record_type.toUpperCase();
if (!dnsRecordNamesMatch(record.name, hostLabel, zone)) continue;
if (type === "A" || type === "AAAA") {
const ip = record.content.trim();
if (ip) aIps.push(ip);
} else if (type === "CNAME" && !cnameNext) {
const target = record.content.trim().replace(/\.+$/, "");
if (target) cnameNext = target.includes(".") ? target : `${target}.${zone}`;
}
}
}
if (aIps.length > 0) return [...new Set(aIps)];
if (cnameNext) return listOriginIpsForFqdn(db, cnameNext, depth + 1);
return [];
}
function findDnsByCfId(db, domainId, cfRecordId) {
const row = db.select().from(dnsRecords).where(
and2(
@@ -1169,17 +1198,22 @@ function enrichServiceBindingView(db, row) {
const configured = listBindingIpsWithMeta(db, row.id);
const configuredIps = configured.map((c) => c.ip);
const linkedRecords = listRecordsForBinding(db, row.id);
const linkedIps = linkedRecords.filter((record) => record.record_type.toUpperCase() === "A").map((record) => record.content);
const linkedIps = linkedRecords.filter((record) => {
const type = record.record_type.toUpperCase();
return (type === "A" || type === "AAAA") && isIpLiteral(record.content);
}).map((record) => record.content);
const target_ips = [
.../* @__PURE__ */ new Set([
...configuredIps,
...configuredIps.filter(isIpLiteral),
...linkedIps,
...row.target_ip ? [row.target_ip] : []
...row.target_ip && isIpLiteral(row.target_ip) ? [row.target_ip] : []
])
].sort();
if (target_ips.length === 0) {
for (const record of listDnsByDomain(db, row.domain_id)) {
if (record.record_type.toUpperCase() !== "A") continue;
const type = record.record_type.toUpperCase();
if (type !== "A" && type !== "AAAA") continue;
if (!isIpLiteral(record.content)) continue;
if (!dnsRecordMatchesHostname(record.name, row.hostname, row.zone_name)) {
continue;
}
@@ -1436,6 +1470,37 @@ function aggregateIpHealthByRefs(db, scope, refIds) {
}
return result;
}
function aggregateGroupScopeHealthByIds(db, groupIds) {
const result = /* @__PURE__ */ new Map();
if (groupIds.length === 0) return result;
const idList = sql2.join(
groupIds.map((id) => sql2`${id}`),
sql2`, `
);
const rows = db.all(sql2`
SELECT ihs.ref_id AS ref_id,
${WORST_HEALTH_SQL} AS health_status,
MAX(ihs.latency_ms) AS health_latency_ms
FROM ip_health_status ihs
WHERE ihs.scope = 'group'
AND ihs.ref_id IN (${idList})
AND EXISTS (
SELECT 1
FROM service_binding_ips sbi
JOIN service_bindings sb ON sb.id = sbi.binding_id
JOIN services s ON s.id = sb.service_id
WHERE s.service_group_id = ihs.ref_id
AND s.enabled = 1
AND sbi.ip = ihs.ip
AND (sb.cname_target IS NULL OR sb.cname_target = '')
)
GROUP BY ihs.ref_id
`);
for (const row of rows) {
result.set(row.ref_id, parseHealthAggregateRow(row));
}
return result;
}
function aggregateIpHealthByServiceIds(db, serviceIds) {
const result = /* @__PURE__ */ new Map();
if (serviceIds.length === 0) return result;
@@ -1538,12 +1603,18 @@ function pruneStaleIpHealthStatus(db, activeTargets) {
}
ips.add(t.ip);
}
const storedRefs = db.all(sql2`
SELECT DISTINCT scope, ref_id FROM ip_health_status
`);
let deleted = 0;
for (const [key, ips] of byRef) {
const sep = key.indexOf(":");
const scope = key.slice(0, sep);
const refId = Number(key.slice(sep + 1));
if (!Number.isFinite(refId)) continue;
for (const { scope, ref_id: refId } of storedRefs) {
const key = `${scope}:${refId}`;
const ips = byRef.get(key);
if (!ips || ips.size === 0) {
deleteIpHealthStatusForRef(db, scope, refId);
deleted += 1;
continue;
}
for (const row of listIpHealthStatus(db, scope, refId)) {
if (!ips.has(row.ip)) {
deleteIpHealthStatusForIp(db, scope, refId, row.ip);
@@ -1570,7 +1641,7 @@ function listHealthCheckTargets(db) {
WHERE sb.health_check_enabled = 1
`);
const groupTargets = db.all(sql2`
SELECT 'group' AS scope, sg.id AS ref_id, sip.ip,
SELECT DISTINCT 'group' AS scope, sg.id AS ref_id, sbi.ip,
sg.domain AS hostname,
sg.health_check_type AS type,
sg.health_check_port AS port,
@@ -1578,13 +1649,16 @@ function listHealthCheckTargets(db) {
sg.health_check_expected_status AS expected_status,
sg.health_check_timeout_ms AS timeout_ms,
sg.health_check_verify_tls AS verify_tls
FROM services s
JOIN service_ips sip ON sip.service_id = s.id
FROM service_binding_ips sbi
JOIN service_bindings sb ON sb.id = sbi.binding_id
JOIN services s ON s.id = sb.service_id
JOIN service_groups sg ON sg.id = s.service_group_id
WHERE sg.health_check_enabled = 1
AND sg.domain IS NOT NULL
AND sg.domain <> ''
AND s.enabled = 1
AND (sg.enabled = 1)
AND sg.enabled = 1
AND (sb.cname_target IS NULL OR sb.cname_target = '')
`);
const groupInheritedBindingTargets = db.all(sql2`
SELECT 'binding' AS scope, sb.id AS ref_id, sbi.ip,