@attraccess/plugin-wago 0.1.0-nightly.954.1 → 0.1.0-nightly.955.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js
CHANGED
|
@@ -52997,10 +52997,10 @@ function canonicalEnvelope(data, category) {
|
|
|
52997
52997
|
}
|
|
52998
52998
|
function validEnvelope(data, now) {
|
|
52999
52999
|
const time = sourceTime(data.timestamp);
|
|
53000
|
-
return time !== null && time <= now && typeof data.streamId === "string" &&
|
|
53000
|
+
return time !== null && time <= now && typeof data.streamId === "string" && data.streamId.trim().length > 0 && data.streamId.length <= 128 && Number.isSafeInteger(data.sequence) && data.sequence >= 1;
|
|
53001
53001
|
}
|
|
53002
53002
|
function admitEnvelope(state, data, category, now) {
|
|
53003
|
-
const stream = data.streamId
|
|
53003
|
+
const stream = data.streamId;
|
|
53004
53004
|
const timestamp = sourceTime(data.timestamp);
|
|
53005
53005
|
const sequence = data.sequence;
|
|
53006
53006
|
if (state.retiredStreams.includes(stream) || state.trackingExhausted) return "rejected";
|
|
@@ -53166,7 +53166,7 @@ var WagoDiagnosticsStore = class {
|
|
|
53166
53166
|
const canonical = canonicalEnvelope(data, kind);
|
|
53167
53167
|
if (canonical && !validEnvelope(data, this.now())) return false;
|
|
53168
53168
|
const isObject = (value) => !!value && typeof value === "object" && !Array.isArray(value);
|
|
53169
|
-
if (canonical && kind === "state" && data.readiness !== void 0 && (!isObject(data.readiness) ||
|
|
53169
|
+
if (canonical && kind === "state" && data.readiness !== void 0 && (!isObject(data.readiness) || typeof data.readiness.hardwareAvailable !== "boolean"))
|
|
53170
53170
|
return false;
|
|
53171
53171
|
if (canonical && kind === "state" && !(data.contentHash === null || typeof data.contentHash === "string" && /^[0-9a-f]{64}$/i.test(data.contentHash)))
|
|
53172
53172
|
return false;
|
|
@@ -59411,7 +59411,7 @@ function diagnosticReferences(nodes, channelIds, revision, capabilities) {
|
|
|
59411
59411
|
resourceId: node.resourceId,
|
|
59412
59412
|
channelId,
|
|
59413
59413
|
control,
|
|
59414
|
-
href: `/resources/${node.resourceId}/flows`,
|
|
59414
|
+
href: `/resources/${node.resourceId}/flows?node=${encodeURIComponent(node.id)}`,
|
|
59415
59415
|
invalid: !channelIds.includes(channelId) || control && (node.data.expectedConfigurationRevision !== revision || capabilities && (!own(capabilities, channelId)?.includes("output") || node.data.action === "pulse" && !own(capabilities, channelId)?.includes("pulse"))),
|
|
59416
59416
|
conflict: control && nodes.some(
|
|
59417
59417
|
(other) => other.type === "plugin.wago.command" && other.resourceId !== node.resourceId && other.data.channelId === channelId
|
|
@@ -59424,6 +59424,90 @@ var WagoDiagnosticsService = class {
|
|
|
59424
59424
|
__publicField(this, "context", context);
|
|
59425
59425
|
__publicField(this, "wago", wago);
|
|
59426
59426
|
}
|
|
59427
|
+
async getResource(resourceId) {
|
|
59428
|
+
const nodes = await this.context.dataSource.getRepository(import_plugins_backend_sdk15.ResourceFlowNode).createQueryBuilder("node").where("node.resourceId = :resourceId", { resourceId }).andWhere("node.type LIKE :type", { type: "plugin.wago.%" }).orderBy("node.id", "ASC").take(1001).getMany();
|
|
59429
|
+
const controllerIds = /* @__PURE__ */ new Set();
|
|
59430
|
+
let invalidControllerReferences = 0;
|
|
59431
|
+
for (const node of nodes.slice(0, 1e3)) {
|
|
59432
|
+
const id = node.data.controllerId;
|
|
59433
|
+
if (typeof id !== "number" || !Number.isSafeInteger(id) || id <= 0) {
|
|
59434
|
+
invalidControllerReferences++;
|
|
59435
|
+
} else {
|
|
59436
|
+
controllerIds.add(id);
|
|
59437
|
+
}
|
|
59438
|
+
}
|
|
59439
|
+
const selectedControllerIds = [...controllerIds].slice(0, 20);
|
|
59440
|
+
if (!selectedControllerIds.length)
|
|
59441
|
+
return { resourceId, controllers: [], invalidControllerReferences, truncated: nodes.length > 1e3 };
|
|
59442
|
+
const localNodes = nodes.slice(0, 1e3);
|
|
59443
|
+
const localChannelIds = [
|
|
59444
|
+
...new Set(
|
|
59445
|
+
localNodes.map((node) => node.data.channelId).filter((channelId) => typeof channelId === "string")
|
|
59446
|
+
)
|
|
59447
|
+
];
|
|
59448
|
+
const controllerIdsForQuery = selectedControllerIds.map(String);
|
|
59449
|
+
const [controllers, appliedRevisions, conflictNodes] = await Promise.all([
|
|
59450
|
+
this.context.getRepository(WagoController).createQueryBuilder("controller").select(["controller.id", "controller.name", "controller.hardwareId"]).where("controller.id IN (:...controllerIds)", { controllerIds: selectedControllerIds }).getMany(),
|
|
59451
|
+
this.context.getRepository(WagoConfigurationRevision).createQueryBuilder("revision").select(["revision.controllerId", "revision.revision", "revision.snapshot"]).distinctOn(["revision.controllerId"]).where("revision.controllerId IN (:...controllerIds)", { controllerIds: selectedControllerIds }).andWhere("revision.state = :state", { state: "applied" }).orderBy("revision.controllerId", "ASC").addOrderBy("revision.revision", "DESC").getMany(),
|
|
59452
|
+
localChannelIds.length ? this.context.dataSource.getRepository(import_plugins_backend_sdk15.ResourceFlowNode).createQueryBuilder("node").where("node.data ->> 'controllerId' IN (:...controllerIds)", { controllerIds: controllerIdsForQuery }).andWhere("node.data ->> 'channelId' IN (:...channelIds)", { channelIds: localChannelIds }).andWhere("node.type = :type", { type: "plugin.wago.command" }).take(1001).getMany() : Promise.resolve([])
|
|
59453
|
+
]);
|
|
59454
|
+
const controllersById = new Map(controllers.map((controller) => [controller.id, controller]));
|
|
59455
|
+
const appliedByControllerId = new Map(appliedRevisions.map((revision) => [revision.controllerId, revision]));
|
|
59456
|
+
const referencesTruncated = conflictNodes.length > 1e3;
|
|
59457
|
+
const conflictNodesByControllerId = /* @__PURE__ */ new Map();
|
|
59458
|
+
for (const node of conflictNodes.slice(0, 1e3)) {
|
|
59459
|
+
const controllerId = node.data.controllerId;
|
|
59460
|
+
if (typeof controllerId !== "number") continue;
|
|
59461
|
+
const matchingNodes = conflictNodesByControllerId.get(controllerId) ?? [];
|
|
59462
|
+
matchingNodes.push(node);
|
|
59463
|
+
conflictNodesByControllerId.set(controllerId, matchingNodes);
|
|
59464
|
+
}
|
|
59465
|
+
const controllersResult = selectedControllerIds.map((controllerId) => {
|
|
59466
|
+
const controller = controllersById.get(controllerId);
|
|
59467
|
+
if (!controller)
|
|
59468
|
+
return {
|
|
59469
|
+
controllerId,
|
|
59470
|
+
name: `Controller ${controllerId}`,
|
|
59471
|
+
unavailable: true,
|
|
59472
|
+
references: [],
|
|
59473
|
+
referencesTruncated: false
|
|
59474
|
+
};
|
|
59475
|
+
try {
|
|
59476
|
+
const applied = appliedByControllerId.get(controllerId);
|
|
59477
|
+
const appliedSnapshot = applied ? JSON.parse(applied.snapshot) : null;
|
|
59478
|
+
const controllerNodes = localNodes.filter((node) => node.data.controllerId === controllerId);
|
|
59479
|
+
const references = diagnosticReferences(
|
|
59480
|
+
[...controllerNodes, ...conflictNodesByControllerId.get(controllerId) ?? []],
|
|
59481
|
+
appliedSnapshot?.logicalChannels.map((channel) => channel.id) ?? [],
|
|
59482
|
+
applied?.revision ?? null,
|
|
59483
|
+
Object.fromEntries(
|
|
59484
|
+
appliedSnapshot?.logicalChannels.map((channel) => [channel.id, channel.capabilities]) ?? []
|
|
59485
|
+
)
|
|
59486
|
+
).filter((reference) => reference.resourceId === resourceId);
|
|
59487
|
+
return {
|
|
59488
|
+
controllerId,
|
|
59489
|
+
name: controller.name ?? controller.hardwareId,
|
|
59490
|
+
unavailable: false,
|
|
59491
|
+
references,
|
|
59492
|
+
referencesTruncated
|
|
59493
|
+
};
|
|
59494
|
+
} catch {
|
|
59495
|
+
return {
|
|
59496
|
+
controllerId,
|
|
59497
|
+
name: controller.name ?? controller.hardwareId,
|
|
59498
|
+
unavailable: true,
|
|
59499
|
+
references: [],
|
|
59500
|
+
referencesTruncated: false
|
|
59501
|
+
};
|
|
59502
|
+
}
|
|
59503
|
+
});
|
|
59504
|
+
return {
|
|
59505
|
+
resourceId,
|
|
59506
|
+
controllers: controllersResult,
|
|
59507
|
+
invalidControllerReferences,
|
|
59508
|
+
truncated: nodes.length > 1e3 || controllerIds.size > 20
|
|
59509
|
+
};
|
|
59510
|
+
}
|
|
59427
59511
|
async get(controllerId) {
|
|
59428
59512
|
const controller = await this.context.getRepository(WagoController).findOneBy({ id: controllerId });
|
|
59429
59513
|
if (!controller) throw new import_common11.NotFoundException("WAGO controller not found");
|
|
@@ -59464,7 +59548,7 @@ var WagoDiagnosticsService = class {
|
|
|
59464
59548
|
stateConnected: runtime.connected ?? null,
|
|
59465
59549
|
stateHardwareAvailable: runtime.hardwareAvailable ?? null,
|
|
59466
59550
|
stateSourceAt: runtime.stateSourceAt ?? null,
|
|
59467
|
-
sequenceExplanation: runtime.activeStream ? "Gaps are scoped to boot
|
|
59551
|
+
sequenceExplanation: runtime.activeStream ? "Gaps are scoped to boot stream ID and message category; duplicates and retired streams are ignored." : "Legacy payloads have no source envelope; sequence gaps and source freshness are unavailable.",
|
|
59468
59552
|
configuration: {
|
|
59469
59553
|
draftUpdatedAt: draft?.updatedAt ?? null,
|
|
59470
59554
|
draftChanged: !!draft && (!latest || configurationHash(JSON.parse(draft.snapshot)) !== latest.contentHash || configurationHash(metadataFromProvenance(draft.presetProvenance)) !== configurationHash(metadataFromProvenance(latest.presetProvenance))),
|
|
@@ -59513,9 +59597,9 @@ var WagoDiagnosticsService = class {
|
|
|
59513
59597
|
limitations: [
|
|
59514
59598
|
"Hardware readiness remains unknown. Legacy samples have no source time and are never current.",
|
|
59515
59599
|
"Diagnostics retain at most 256 channels, 50 recent events and 15 minutes in this process.",
|
|
59516
|
-
"
|
|
59600
|
+
"Flow links select the affected node. Diagnostics warnings do not block resource usage; required flow nodes determine gating.",
|
|
59517
59601
|
"The MQTT SDK exposes neither retained-message flags nor broker connection events. Source age is bounded to 90 seconds; immediate broker-disconnect detection is unavailable.",
|
|
59518
|
-
"Stream tracking keeps at most 16 retired boot
|
|
59602
|
+
"Stream tracking keeps at most 16 retired boot stream IDs per controller and six category counters, and fails closed when exhausted. Replayed source times never become receipt times."
|
|
59519
59603
|
]
|
|
59520
59604
|
};
|
|
59521
59605
|
}
|
|
@@ -59531,10 +59615,17 @@ var WagoDiagnosticsController = class {
|
|
|
59531
59615
|
constructor(diagnostics) {
|
|
59532
59616
|
__publicField(this, "diagnostics", diagnostics);
|
|
59533
59617
|
}
|
|
59618
|
+
getResource(id) {
|
|
59619
|
+
return this.diagnostics.getResource(id);
|
|
59620
|
+
}
|
|
59534
59621
|
get(id) {
|
|
59535
59622
|
return this.diagnostics.get(id);
|
|
59536
59623
|
}
|
|
59537
59624
|
};
|
|
59625
|
+
__decorateClass([
|
|
59626
|
+
(0, import_common12.Get)("resources/:id/diagnostics"),
|
|
59627
|
+
__decorateParam(0, (0, import_common12.Param)("id", import_common12.ParseIntPipe))
|
|
59628
|
+
], WagoDiagnosticsController.prototype, "getResource", 1);
|
|
59538
59629
|
__decorateClass([
|
|
59539
59630
|
(0, import_common12.Get)("controllers/:id/diagnostics"),
|
|
59540
59631
|
__decorateParam(0, (0, import_common12.Param)("id", import_common12.ParseIntPipe))
|