@openfn/language-varo 1.0.2 → 1.1.0

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.cjs CHANGED
@@ -21,6 +21,8 @@ var src_exports = {};
21
21
  __export(src_exports, {
22
22
  alterState: () => import_language_common2.alterState,
23
23
  combine: () => import_language_common2.combine,
24
+ convertItemsToReports: () => convertItemsToReports,
25
+ convertReportsToMessageContents: () => convertReportsToMessageContents,
24
26
  convertToEms: () => convertToEms,
25
27
  cursor: () => import_language_common2.cursor,
26
28
  dataPath: () => import_language_common2.dataPath,
@@ -43,6 +45,8 @@ var Adaptor_exports = {};
43
45
  __export(Adaptor_exports, {
44
46
  alterState: () => import_language_common2.alterState,
45
47
  combine: () => import_language_common2.combine,
48
+ convertItemsToReports: () => convertItemsToReports,
49
+ convertReportsToMessageContents: () => convertReportsToMessageContents,
46
50
  convertToEms: () => convertToEms,
47
51
  cursor: () => import_language_common2.cursor,
48
52
  dataPath: () => import_language_common2.dataPath,
@@ -63,21 +67,258 @@ var import_util = require("@openfn/language-common/util");
63
67
  // src/Utils.js
64
68
  function parseMetadata(message) {
65
69
  var _a;
66
- if (!((_a = message.metadata) == null ? void 0 : _a.content)) {
70
+ const content = (_a = message.metadata) == null ? void 0 : _a.content;
71
+ if (!content) {
67
72
  console.error("No metadata supplied.");
68
73
  return null;
69
74
  }
70
75
  try {
71
- return JSON.parse(message.metadata.content);
76
+ return JSON.parse(content);
72
77
  } catch (error) {
73
78
  console.error("Invalid metadata JSON.", error);
74
79
  return null;
75
80
  }
76
81
  }
82
+ function removeNullProps(obj) {
83
+ for (const key in obj) {
84
+ if (obj[key] == null) {
85
+ delete obj[key];
86
+ }
87
+ }
88
+ return obj;
89
+ }
90
+ function deepEqual(a, b) {
91
+ if (a === b)
92
+ return true;
93
+ if (typeof a !== "object" || typeof b !== "object" || a === null || b === null)
94
+ return false;
95
+ const aKeys = Object.keys(a);
96
+ const bKeys = Object.keys(b);
97
+ if (aKeys.length !== bKeys.length)
98
+ return false;
99
+ for (const key of aKeys) {
100
+ if (!bKeys.includes(key) || !deepEqual(a[key], b[key]))
101
+ return false;
102
+ }
103
+ return true;
104
+ }
105
+ function formatDeviceInfo(data) {
106
+ function formatType(label, mfr, mod, ser) {
107
+ let output2 = "";
108
+ if (mfr || mod || ser) {
109
+ output2 += `${label}
110
+ `;
111
+ if (mfr) {
112
+ output2 += ` Manufacturer: ${mfr}
113
+ `;
114
+ }
115
+ if (mod) {
116
+ output2 += ` Model: ${mod}
117
+ `;
118
+ }
119
+ if (ser) {
120
+ output2 += ` Serial Number: ${ser}
121
+ `;
122
+ }
123
+ output2 += "\n";
124
+ }
125
+ return output2;
126
+ }
127
+ let output = "";
128
+ output += formatType("Appliance", data.AMFR, data.AMOD, data.ASER);
129
+ output += formatType("Logger", data.LMFR, data.LMOD, data.LSER);
130
+ output += formatType("EMD", data.EMFR, data.EMOD, data.ESER);
131
+ return output || "No valid data found";
132
+ }
133
+
134
+ // src/StreamingUtils.js
135
+ function parseRtmdCollectionToReports(collection) {
136
+ if (!Array.isArray(collection) || collection.length === 0) {
137
+ console.error("No records to process for report.");
138
+ return null;
139
+ }
140
+ return groupDifferencesAndMergeRecords(collection, "ESER", "ABST");
141
+ }
142
+ function parseFlatRecordsToReports(collection, reqReport, reqRecord) {
143
+ if (!Array.isArray(collection) || collection.length === 0) {
144
+ console.error("No records to process for report.");
145
+ return null;
146
+ }
147
+ const reports = [];
148
+ const groups = groupByProperty(collection, "LSER");
149
+ for (const key in groups) {
150
+ const records = groups[key];
151
+ const reportRecord = records[0];
152
+ const report = mapProperties(reportRecord, records, reqReport, reqRecord);
153
+ promoteDeviceProperties(report, "E");
154
+ reports.push(report);
155
+ }
156
+ return reports;
157
+ }
158
+ function groupDifferencesAndMergeRecords(collection, reportsGroupKey, recordsGroupKey) {
159
+ const groups = groupByProperty(collection, reportsGroupKey);
160
+ const reports = [];
161
+ for (const key in groups) {
162
+ const rawReports = groups[key];
163
+ const report = { ...rawReports[0] };
164
+ removeNullProps(report);
165
+ const allRecords = rawReports.flatMap((r) => r.records || []);
166
+ const mergedRecords = mergeRecords(allRecords, recordsGroupKey);
167
+ const allProps = getAllProps(rawReports, [reportsGroupKey, "records"]);
168
+ const differingProps = getDifferingProps(rawReports, allProps);
169
+ const differences = buildDifferences(rawReports, report, differingProps);
170
+ report["records"] = mergedRecords;
171
+ report["zDifferences"] = differences;
172
+ promoteDeviceProperties(report, "L");
173
+ reports.push(report);
174
+ }
175
+ return reports;
176
+ }
177
+ function groupByProperty(collection, property) {
178
+ return collection.reduce((acc, item) => {
179
+ const key = item[property];
180
+ if (!acc[key]) {
181
+ acc[key] = [];
182
+ }
183
+ acc[key].push(item);
184
+ return acc;
185
+ }, {});
186
+ }
187
+ function mergeRecords(records, groupKey) {
188
+ const grouped = groupByProperty(records, groupKey);
189
+ const merged = [];
190
+ for (const key in grouped) {
191
+ const group = grouped[key];
192
+ const mergedRecord = {};
193
+ let tvcAlrm = null;
194
+ let tambAlrm = null;
195
+ for (const record of group) {
196
+ Object.assign(mergedRecord, record);
197
+ const alrm = record["ALRM"];
198
+ if (alrm != null) {
199
+ if ("TVC" in record)
200
+ tvcAlrm = alrm;
201
+ if ("TAMB" in record)
202
+ tambAlrm = alrm;
203
+ }
204
+ }
205
+ if (tambAlrm != null) {
206
+ mergedRecord["zTambAlrm"] = tambAlrm;
207
+ mergedRecord["ALRM"] = tambAlrm;
208
+ }
209
+ if (tvcAlrm != null) {
210
+ mergedRecord["zTvcAlrm"] = tvcAlrm;
211
+ mergedRecord["ALRM"] = tvcAlrm;
212
+ }
213
+ removeNullProps(mergedRecord);
214
+ merged.push(mergedRecord);
215
+ }
216
+ return merged;
217
+ }
218
+ function getAllProps(collection, excludedProps = []) {
219
+ const props = /* @__PURE__ */ new Set();
220
+ for (const item of collection) {
221
+ for (const prop in item) {
222
+ if (excludedProps.includes(prop))
223
+ continue;
224
+ if (item[prop] === null)
225
+ continue;
226
+ props.add(prop);
227
+ }
228
+ }
229
+ return Array.from(props);
230
+ }
231
+ function getDifferingProps(records, props) {
232
+ const differing = [];
233
+ for (const prop of props) {
234
+ const firstValue = records[0][prop];
235
+ const isDifferent = records.some((r) => !deepEqual(r[prop], firstValue));
236
+ if (isDifferent) {
237
+ differing.push(prop);
238
+ }
239
+ }
240
+ return differing;
241
+ }
242
+ function buildDifferences(records, base, differingProps) {
243
+ const uniqueSet = /* @__PURE__ */ new Set();
244
+ return records.map((record) => {
245
+ const diff = {};
246
+ for (const prop of differingProps) {
247
+ if (!deepEqual(record[prop], base[prop])) {
248
+ diff[prop] = record[prop];
249
+ }
250
+ }
251
+ const sortedDiff = Object.keys(diff).sort().reduce((acc, key2) => {
252
+ acc[key2] = diff[key2];
253
+ return acc;
254
+ }, {});
255
+ const key = JSON.stringify(sortedDiff);
256
+ if (Object.keys(diff).length > 0 && !uniqueSet.has(key)) {
257
+ uniqueSet.add(key);
258
+ return sortedDiff;
259
+ }
260
+ return null;
261
+ }).filter(Boolean);
262
+ }
263
+ var defs = {
264
+ report: "ACAT,ADOP,AID,AMFR,AMID,AMOD,APQS,ASER,CDAT,CDAT2,CID,CNAM,CNAM2,CSER,CSER2,CSOF,CSOF2,DLST,DNAM,EDOP,EID,EMFR,EMOD,EMSV,EPQS,ESER,FID,FNAM,LACC,LAT,LDOP,LID,LMFR,LMOD,LNG,LPQS,LSER,LSV,RNAM,SIGN".split(","),
265
+ record: "ABST,ACCD,ACSV,ALRM,BEMD,BLOG,CMPR,CMPR2,CMPS,CMPS2,CSOF,CSOF2,DCCD,DCSV,DORF,DORV,DRCF,DRCV,EERR,FANS,HAMB,HCOM,HOLD,IDRF,IDRV,LERR,MSW,SVA,TAMB,TCON,TCON2,TFRZ,TPCB,TPCB2,TVC".split(",")
266
+ };
267
+ function mapProperties(report, records, reqReport, reqRecord) {
268
+ function resolveReqKeys(option, defaults) {
269
+ if (option === true)
270
+ return defaults;
271
+ if (typeof option === "string" && option.trim()) {
272
+ return option.split(",").map((k) => k.trim());
273
+ }
274
+ return [];
275
+ }
276
+ function extract(source, keys, reqKeys) {
277
+ const result = {};
278
+ for (const key of keys) {
279
+ if (key in source && source[key] !== null) {
280
+ result[key] = source[key];
281
+ } else if (reqKeys.includes(key)) {
282
+ result[key] = null;
283
+ }
284
+ }
285
+ return result;
286
+ }
287
+ if (!report)
288
+ return null;
289
+ const reqReportKeys = resolveReqKeys(reqReport, defs.report);
290
+ const reqRecordKeys = resolveReqKeys(reqRecord, defs.record);
291
+ const reportKeys = [.../* @__PURE__ */ new Set([...defs.report, ...reqReportKeys])];
292
+ const recordKeys = [.../* @__PURE__ */ new Set([...defs.record, ...reqRecordKeys])];
293
+ const reportResult = extract(report, reportKeys, reqReportKeys);
294
+ const recordResults = (records == null ? void 0 : records.map((record) => extract(record, recordKeys, reqRecordKeys)).filter((record) => Object.keys(record).length > 0)) ?? [];
295
+ return {
296
+ ...reportResult,
297
+ records: recordResults
298
+ };
299
+ }
300
+ function promoteDeviceProperties(source, destination) {
301
+ const keyPairs = [
302
+ ["LID", "EID"],
303
+ ["LMFR", "EMFR"],
304
+ ["LMOD", "EMOD"],
305
+ ["LSER", "ESER"],
306
+ ["LDOP", "EDOP"],
307
+ ["LSV", "EMSV"],
308
+ ["LPQS", "EPQS"]
309
+ ];
310
+ for (const [lKey, eKey] of keyPairs) {
311
+ const [fromKey, toKey] = destination === "E" ? [lKey, eKey] : [eKey, lKey];
312
+ if (source[toKey] != null)
313
+ continue;
314
+ if (source[fromKey] != null)
315
+ source[toKey] = source[fromKey];
316
+ }
317
+ }
77
318
 
78
319
  // src/VaroEmsUtils.js
79
- function parseVaroEmsToEms(metadata, data, dataPath2) {
80
- const result = {
320
+ function parseVaroEmsToReport(metadata, data, dataPath2) {
321
+ const report = {
81
322
  CID: null,
82
323
  LAT: metadata.location.used.latitude,
83
324
  LNG: metadata.location.used.longitude,
@@ -120,9 +361,9 @@ function parseVaroEmsToEms(metadata, data, dataPath2) {
120
361
  TAMB: item.TAMB,
121
362
  TVC: item.TVC
122
363
  };
123
- result.records.push(record);
364
+ report.records.push(record);
124
365
  }
125
- return result;
366
+ return report;
126
367
  }
127
368
  function parseRelativeDateFromUsbPluggedInfo(path) {
128
369
  const regex = /_CURRENT_DATA_(?<duration>\w+?)_(?<date>\w+?)\.json$/;
@@ -184,42 +425,44 @@ function parseIsoToAbbreviatedIso(iso) {
184
425
  }
185
426
 
186
427
  // src/FridgeTagUtils.js
187
- function parseFridgeTagToEms(metadata, nodes) {
188
- const result = {
189
- records: [],
190
- reports: []
191
- };
192
- applyMetadataToResult();
193
- applyNodesToResult();
194
- function applyMetadataToResult() {
428
+ function parseFridgeTagToReport(metadata, nodes) {
429
+ const report = {};
430
+ const records = [];
431
+ const zReports = [];
432
+ applyMetadataToReport();
433
+ applyNodesToReport();
434
+ report.records = records;
435
+ report.zReports = zReports;
436
+ return report;
437
+ function applyMetadataToReport() {
195
438
  var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
196
- applyPropertyToResult("AMFR", (_a = metadata == null ? void 0 : metadata.refrigerator) == null ? void 0 : _a.manufacturer);
197
- applyPropertyToResult("AMOD", (_b = metadata == null ? void 0 : metadata.refrigerator) == null ? void 0 : _b.model);
198
- applyPropertyToResult("LMFR", (_c = metadata == null ? void 0 : metadata.refrigerator) == null ? void 0 : _c.deviceManufacturer);
199
- applyPropertyToResult("CID", (_d = metadata == null ? void 0 : metadata.facility) == null ? void 0 : _d.country);
200
- applyPropertyToResult("LAT", (_f = (_e = metadata == null ? void 0 : metadata.location) == null ? void 0 : _e.used) == null ? void 0 : _f.latitude);
201
- applyPropertyToResult("LNG", (_h = (_g = metadata == null ? void 0 : metadata.location) == null ? void 0 : _g.used) == null ? void 0 : _h.longitude);
202
- applyPropertyToResult("LACC", (_j = (_i = metadata == null ? void 0 : metadata.location) == null ? void 0 : _i.used) == null ? void 0 : _j.accuracy);
439
+ applyPropertyToReport("AMFR", (_a = metadata == null ? void 0 : metadata.refrigerator) == null ? void 0 : _a.manufacturer);
440
+ applyPropertyToReport("AMOD", (_b = metadata == null ? void 0 : metadata.refrigerator) == null ? void 0 : _b.model);
441
+ applyPropertyToReport("LMFR", (_c = metadata == null ? void 0 : metadata.refrigerator) == null ? void 0 : _c.deviceManufacturer);
442
+ applyPropertyToReport("CID", (_d = metadata == null ? void 0 : metadata.facility) == null ? void 0 : _d.country);
443
+ applyPropertyToReport("LAT", (_f = (_e = metadata == null ? void 0 : metadata.location) == null ? void 0 : _e.used) == null ? void 0 : _f.latitude);
444
+ applyPropertyToReport("LNG", (_h = (_g = metadata == null ? void 0 : metadata.location) == null ? void 0 : _g.used) == null ? void 0 : _h.longitude);
445
+ applyPropertyToReport("LACC", (_j = (_i = metadata == null ? void 0 : metadata.location) == null ? void 0 : _i.used) == null ? void 0 : _j.accuracy);
203
446
  }
204
- function applyNodesToResult() {
447
+ function applyNodesToReport() {
205
448
  var _a, _b, _c;
206
- applyPropertyToResult("LMOD", nodes["Device"]);
207
- applyPropertyToResult("LSER", (_a = nodes["Conf"]) == null ? void 0 : _a["Serial"]);
208
- applyPropertyToResult("LSV", nodes["Fw Vers"]);
449
+ applyPropertyToReport("LMOD", nodes["Device"]);
450
+ applyPropertyToReport("LSER", (_a = nodes["Conf"]) == null ? void 0 : _a["Serial"]);
451
+ applyPropertyToReport("LSV", nodes["Fw Vers"]);
209
452
  let productionDate = (_b = nodes["Conf"]) == null ? void 0 : _b["Test TS"];
210
453
  productionDate = productionDate ? new Date(productionDate) : null;
211
- applyPropertyToResult("LDOP", productionDate);
454
+ applyPropertyToReport("LDOP", productionDate);
212
455
  let dayIndex = 1;
213
456
  let dayNode;
214
457
  while ((dayNode = (_c = nodes["Hist"]) == null ? void 0 : _c[dayIndex++]) !== void 0) {
215
458
  applyDayToRecords(dayNode);
216
- applyDayToReports(dayNode);
459
+ applyDayToZReports(dayNode);
217
460
  }
218
461
  }
219
- function applyPropertyToResult(property, text) {
462
+ function applyPropertyToReport(property, text) {
220
463
  if (!text)
221
464
  return;
222
- result[property] = text;
465
+ report[property] = text;
223
466
  }
224
467
  function applyDayToRecords(dayNode) {
225
468
  applyNodeToRecords(dayNode, "TS Min T", "Min T", "0", "FRZE");
@@ -234,11 +477,11 @@ function parseFridgeTagToEms(metadata, nodes) {
234
477
  (_a = dayNode2["Alarm"]) == null ? void 0 : _a[alarmField],
235
478
  alarmDescription
236
479
  );
237
- result.records.push({
480
+ records.push({
238
481
  ABST: dateTime,
239
482
  TVC: temp,
240
483
  ALRM: alarm,
241
- description: date + " " + tempField
484
+ zdescription: date + " " + tempField
242
485
  });
243
486
  function parseAlarm(alarmNode, description) {
244
487
  if (alarmNode["t Acc"] === "0")
@@ -247,17 +490,17 @@ function parseFridgeTagToEms(metadata, nodes) {
247
490
  }
248
491
  }
249
492
  }
250
- function applyDayToReports(dayNode) {
251
- const report = {
493
+ function applyDayToZReports(dayNode) {
494
+ const report2 = {
252
495
  date: new Date(dayNode["Date"]),
253
496
  duration: "1D",
254
497
  alarms: [],
255
498
  aggregates: []
256
499
  };
257
- applyAlarmsToReport(dayNode);
258
- applyAggregatesToReport(dayNode);
259
- result.reports.push(report);
260
- function applyAlarmsToReport(dayNode2) {
500
+ applyAlarmsToZReport(dayNode);
501
+ applyAggregatesToZReport(dayNode);
502
+ zReports.push(report2);
503
+ function applyAlarmsToZReport(dayNode2) {
261
504
  var _a, _b;
262
505
  const date = dayNode2["Date"];
263
506
  applyAlarmToAlarms((_a = dayNode2["Alarm"]) == null ? void 0 : _a["0"], "FRZE");
@@ -280,13 +523,13 @@ function parseFridgeTagToEms(metadata, nodes) {
280
523
  if (count) {
281
524
  alarm.count = count;
282
525
  }
283
- report.alarms.push(alarm);
526
+ report2.alarms.push(alarm);
284
527
  }
285
528
  }
286
- function applyAggregatesToReport(dayNode2) {
529
+ function applyAggregatesToZReport(dayNode2) {
287
530
  applyTvcToAggregates(dayNode2);
288
531
  function applyTvcToAggregates(dayNode3) {
289
- report.aggregates.push({
532
+ report2.aggregates.push({
290
533
  id: "TVC",
291
534
  min: parseFloat(dayNode3["Min T"]),
292
535
  max: parseFloat(dayNode3["Max T"]),
@@ -295,7 +538,6 @@ function parseFridgeTagToEms(metadata, nodes) {
295
538
  }
296
539
  }
297
540
  }
298
- return result;
299
541
  }
300
542
  function parseFridgeTag(text) {
301
543
  const result = {};
@@ -339,7 +581,7 @@ function convertToEms(messageContents) {
339
581
  return async (state) => {
340
582
  var _a, _b;
341
583
  const [resolvedMessageContents] = (0, import_util.expandReferences)(state, messageContents);
342
- const results = [];
584
+ const reports = [];
343
585
  console.log("Incoming message contents", resolvedMessageContents.length);
344
586
  for (const content of resolvedMessageContents) {
345
587
  if ((_a = content.fridgeTag) == null ? void 0 : _a.content) {
@@ -347,8 +589,8 @@ function convertToEms(messageContents) {
347
589
  if (!metadata)
348
590
  continue;
349
591
  const fridgeTagNodes = parseFridgeTag(content.fridgeTag.content);
350
- const result = parseFridgeTagToEms(metadata, fridgeTagNodes);
351
- results.push(result);
592
+ const result = parseFridgeTagToReport(metadata, fridgeTagNodes);
593
+ reports.push(result);
352
594
  continue;
353
595
  }
354
596
  if ((_b = content.data) == null ? void 0 : _b.content) {
@@ -357,16 +599,60 @@ function convertToEms(messageContents) {
357
599
  continue;
358
600
  const data = JSON.parse(content.data.content);
359
601
  const dataPath2 = content.data.filename;
360
- const result = parseVaroEmsToEms(metadata, data, dataPath2);
361
- results.push(result);
602
+ const result = parseVaroEmsToReport(metadata, data, dataPath2);
603
+ reports.push(result);
362
604
  continue;
363
605
  }
364
606
  console.error(
365
607
  `Insufficient content found for MessageID: ${content.messageId}`
366
608
  );
367
609
  }
368
- console.log("Converted message contents", results.length);
369
- return { ...(0, import_language_common.composeNextState)(state, results) };
610
+ console.log("Converted message contents", reports.length);
611
+ return { ...(0, import_language_common.composeNextState)(state, reports) };
612
+ };
613
+ }
614
+ function convertItemsToReports(items, reportType = "unknown") {
615
+ return async (state) => {
616
+ const [resolvedRecords, resolvedReportType] = (0, import_util.expandReferences)(
617
+ state,
618
+ items,
619
+ reportType
620
+ );
621
+ const reportParsers = {
622
+ ems: parseFlatRecordsToReports,
623
+ rtmd: parseRtmdCollectionToReports
624
+ };
625
+ const parser = reportParsers[resolvedReportType];
626
+ if (!parser) {
627
+ throw new Error(`Report type not supported: ${resolvedReportType}`);
628
+ }
629
+ const reports = parser(resolvedRecords);
630
+ return { ...(0, import_language_common.composeNextState)(state, reports) };
631
+ };
632
+ }
633
+ function convertReportsToMessageContents(reports, reportType = "unknown") {
634
+ return async (state) => {
635
+ const [resolvedReports, resolvedReportType] = (0, import_util.expandReferences)(
636
+ state,
637
+ reports,
638
+ reportType
639
+ );
640
+ const messageContents = [];
641
+ for (const report of resolvedReports) {
642
+ report["zReportType"] = resolvedReportType;
643
+ report["zGeneratedTimestamp"] = new Date().toISOString();
644
+ const serialNumber = report["ESER"] || report["LSER"] || report["ASER"];
645
+ const messageContent = {
646
+ subject: `OpenFn | ${resolvedReportType.toUpperCase()} | ${serialNumber}`,
647
+ body: formatDeviceInfo(report),
648
+ data: {
649
+ filename: "data.json",
650
+ content: JSON.stringify(report, null, 4)
651
+ }
652
+ };
653
+ messageContents.push(messageContent);
654
+ }
655
+ return { ...(0, import_language_common.composeNextState)(state, messageContents) };
370
656
  };
371
657
  }
372
658
 
@@ -376,6 +662,8 @@ var src_default = Adaptor_exports;
376
662
  0 && (module.exports = {
377
663
  alterState,
378
664
  combine,
665
+ convertItemsToReports,
666
+ convertReportsToMessageContents,
379
667
  convertToEms,
380
668
  cursor,
381
669
  dataPath,