@etainabl/nodejs-sdk 1.3.181 → 1.3.186

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/esm/index.js CHANGED
@@ -3270,7 +3270,7 @@ var require_lodash = __commonJS({
3270
3270
  result2.__values__ = wrapper.__values__;
3271
3271
  return result2;
3272
3272
  }
3273
- function chunk2(array, size2, guard) {
3273
+ function chunk3(array, size2, guard) {
3274
3274
  if (guard ? isIterateeCall(array, size2, guard) : size2 === undefined2) {
3275
3275
  size2 = 1;
3276
3276
  } else {
@@ -5142,7 +5142,7 @@ var require_lodash = __commonJS({
5142
5142
  lodash.bindKey = bindKey;
5143
5143
  lodash.castArray = castArray;
5144
5144
  lodash.chain = chain2;
5145
- lodash.chunk = chunk2;
5145
+ lodash.chunk = chunk3;
5146
5146
  lodash.compact = compact;
5147
5147
  lodash.concat = concat;
5148
5148
  lodash.cond = cond;
@@ -5870,19 +5870,6 @@ var api_default = (auth, instanceOptions = {}) => {
5870
5870
  removeAccount: factory.remove(etainablApi, "accounts"),
5871
5871
  getAccountSchema: factory.get(etainablApi, "accounts", "schema"),
5872
5872
  invalidateAccountCache: factory.customWithId(etainablApi, "put", "accounts", "invalidate-cache"),
5873
- // alert triggers
5874
- getAlertTrigger: factory.getWithId(etainablApi, "alert-triggers"),
5875
- listAlertTriggers: factory.list(etainablApi, "alert-triggers"),
5876
- updateAlertTrigger: factory.update(etainablApi, "alert-triggers"),
5877
- createAlertTrigger: factory.create(etainablApi, "alert-triggers"),
5878
- removeAlertTrigger: factory.remove(etainablApi, "alert-triggers"),
5879
- bulkUpdateAlertTriggers: factory.create(
5880
- etainablApi,
5881
- "alert-triggers",
5882
- "bulk-update"
5883
- ),
5884
- retryAlertTrigger: factory.customWithId(etainablApi, "post", "alert-triggers", "retry"),
5885
- cancelAlertTrigger: factory.customWithId(etainablApi, "post", "alert-triggers", "cancel"),
5886
5873
  // custom alert triggers
5887
5874
  getCustomAlertTrigger: factory.getWithId(etainablApi, "custom-alert-triggers"),
5888
5875
  listCustomAlertTriggers: factory.list(etainablApi, "custom-alert-triggers"),
@@ -6281,28 +6268,28 @@ var emailTemplate_default = (options) => {
6281
6268
  import mjml2html from "mjml";
6282
6269
  var severityConfig = {
6283
6270
  error: {
6284
- color: "#DC2626",
6285
- bgColor: "#FEE2E2",
6271
+ color: "#FFFFFF",
6272
+ bgColor: "#e04f1a",
6286
6273
  label: "ERROR"
6287
6274
  },
6288
6275
  success: {
6289
- color: "#EA580C",
6290
- bgColor: "#23ae2aff",
6276
+ color: "#FFFFFF",
6277
+ bgColor: "#82b54b",
6291
6278
  label: "SUCCESS"
6292
6279
  },
6293
6280
  warning: {
6294
- color: "#F59E0B",
6295
- bgColor: "#FEF3C7",
6281
+ color: "#FFFFFF",
6282
+ bgColor: "#ff9f43",
6296
6283
  label: "WARNING"
6297
6284
  },
6298
6285
  tip: {
6299
- color: "#3B82F6",
6300
- bgColor: "#DBEAFE",
6286
+ color: "#FFFFFF",
6287
+ bgColor: "#00bad1",
6301
6288
  label: "TIP"
6302
6289
  },
6303
6290
  info: {
6304
- color: "#5ECFB1",
6305
- bgColor: "#D1FAE5",
6291
+ color: "#FFFFFF",
6292
+ bgColor: "#5ECFB1",
6306
6293
  label: "INFO"
6307
6294
  }
6308
6295
  };
@@ -6310,13 +6297,17 @@ function generateNotificationEmail(options) {
6310
6297
  if (!process.env.ETAINABL_UI_URL) {
6311
6298
  throw new Error("ETAINABL_UI_URL environment variable is not set");
6312
6299
  }
6313
- const { title, message, severity = "info", category = "Notification", actions = [], metadata = {} } = options;
6300
+ const { title, message, severity = "info", category = "Notification", actions = [], metadata = {}, items = [] } = options;
6314
6301
  const config = severityConfig[severity];
6302
+ const isSingleItem = items.length === 1;
6303
+ const hasMultipleItems = items.length > 1;
6304
+ const mainTitle = isSingleItem && items[0]?.message ? items[0].message : message;
6305
+ const subtitle = isSingleItem ? message : title;
6315
6306
  const mjmlTemplate = `
6316
6307
  <mjml>
6317
6308
  <mj-head>
6318
- <mj-title>${message} - Etainabl</mj-title>
6319
- <mj-preview>${title}</mj-preview>
6309
+ <mj-title>${mainTitle}</mj-title>
6310
+ <mj-preview>${subtitle}</mj-preview>
6320
6311
 
6321
6312
  <mj-attributes>
6322
6313
  <mj-all font-family="-apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Helvetica', 'Arial', sans-serif" />
@@ -6327,9 +6318,9 @@ function generateNotificationEmail(options) {
6327
6318
  <mj-style inline="inline">
6328
6319
  .severity-badge {
6329
6320
  display: inline-block;
6330
- padding: 4px 12px;
6331
- border-radius: 12px;
6332
- font-size: 11px;
6321
+ padding: 2px 6px;
6322
+ border-radius: 6px;
6323
+ font-size: 9px;
6333
6324
  font-weight: 600;
6334
6325
  letter-spacing: 0.5px;
6335
6326
  background-color: ${config.bgColor};
@@ -6371,7 +6362,7 @@ function generateNotificationEmail(options) {
6371
6362
  </mj-section>
6372
6363
 
6373
6364
  <!-- Spacer -->
6374
- <mj-section background-color="#F3F4F6" padding="20px 0">
6365
+ <mj-section background-color="#F3F4F6" padding="6px 0">
6375
6366
  <mj-column>
6376
6367
  <mj-text></mj-text>
6377
6368
  </mj-column>
@@ -6394,23 +6385,60 @@ function generateNotificationEmail(options) {
6394
6385
  </mj-column>
6395
6386
  </mj-section>
6396
6387
 
6397
- <!-- Message (Main Title) -->
6388
+ <!-- Main Title -->
6398
6389
  <mj-section padding="0 32px 8px 32px">
6399
6390
  <mj-column>
6400
6391
  <mj-text font-size="24px" font-weight="600" color="#1F2937" line-height="1.3" padding="0">
6401
- ${message}
6392
+ ${mainTitle}
6402
6393
  </mj-text>
6403
6394
  </mj-column>
6404
6395
  </mj-section>
6405
6396
 
6406
- <!-- Title (Subtitle) -->
6397
+ <!-- Subtitle -->
6407
6398
  <mj-section padding="0 32px 24px 32px">
6408
6399
  <mj-column>
6409
6400
  <mj-text font-size="14px" color="#6B7280" padding="0">
6410
- ${title}
6401
+ ${subtitle}
6402
+ </mj-text>
6403
+ </mj-column>
6404
+ </mj-section>
6405
+
6406
+ ${hasMultipleItems ? (() => {
6407
+ const maxItems = 3;
6408
+ const displayItems = items.slice(0, maxItems);
6409
+ const remainingCount = items.length - maxItems;
6410
+ return `
6411
+ <!-- Items List -->
6412
+ <mj-section padding="0 32px 24px 32px">
6413
+ <mj-column>
6414
+ <mj-text padding="0">
6415
+ <table style="width: 100%; border-collapse: collapse;">
6416
+ ${displayItems.map(
6417
+ (item) => `
6418
+ <tr>
6419
+ <td style="padding: 0 0 8px 0;">
6420
+ <table style="width: 100%; border-collapse: collapse; background-color: #F9FAFB; border-radius: 6px; overflow: hidden;">
6421
+ <tr>
6422
+ <td style="width: 6px; background-color: #5ECFB1; border-radius: 10px;"></td>
6423
+ <td style="padding: 16px;">
6424
+ <span style="color: #1F2937; font-size: 14px; line-height: 1.5;">${item.message}</span>
6425
+ </td>
6426
+ </tr>
6427
+ </table>
6428
+ </td>
6429
+ </tr>`
6430
+ ).join("")}${remainingCount > 0 ? `
6431
+ <tr>
6432
+ <td style="padding: 8px 0 0 0;">
6433
+ <span style="color: #6B7280; font-size: 13px; font-style: italic;">and ${remainingCount} more item${remainingCount === 1 ? "" : "s"}...</span>
6434
+ </td>
6435
+ </tr>` : ""}
6436
+ </table>
6411
6437
  </mj-text>
6412
6438
  </mj-column>
6413
6439
  </mj-section>
6440
+ `;
6441
+ })() : ""}
6414
6442
 
6415
6443
  ${Object.keys(metadata).length > 0 ? `
6416
6444
  <!-- Metadata Section -->
@@ -6463,7 +6491,7 @@ function generateNotificationEmail(options) {
6463
6491
  <mj-section padding="0 32px 24px 32px">
6464
6492
  <mj-column>
6465
6493
  <mj-button
6466
- background-color="#1F2937"
6494
+ background-color="#65c198"
6467
6495
  color="#FFFFFF"
6468
6496
  border-radius="6px"
6469
6497
  font-weight="600"
@@ -6508,7 +6536,7 @@ function generateNotificationEmail(options) {
6508
6536
  <a href="${process.env.ETAINABL_UI_URL}/messages/notifications" style="color: #5ECFB1; text-decoration: none;">Manage notification preferences</a>
6509
6537
  </mj-text>
6510
6538
  <mj-text align="center" font-size="11px" color="#9CA3AF" padding-top="16px">
6511
- \xA9 ${(/* @__PURE__ */ new Date()).getFullYear()} Etainabl. All rights reserved.
6539
+ \xA9 ${(/* @__PURE__ */ new Date()).getFullYear()} Etainabl Ltd. All rights reserved.
6512
6540
  </mj-text>
6513
6541
  </mj-column>
6514
6542
  </mj-section>
@@ -6626,10 +6654,10 @@ var ChecksumStream = class extends Duplex {
6626
6654
  }
6627
6655
  _read(size) {
6628
6656
  }
6629
- _write(chunk2, encoding, callback) {
6657
+ _write(chunk3, encoding, callback) {
6630
6658
  try {
6631
- this.checksum.update(chunk2);
6632
- this.push(chunk2);
6659
+ this.checksum.update(chunk3);
6660
+ this.push(chunk3);
6633
6661
  } catch (e4) {
6634
6662
  return callback(e4);
6635
6663
  }
@@ -6668,9 +6696,9 @@ var createChecksumStream = ({ expectedChecksum, checksum, source, checksumSource
6668
6696
  const transform = new TransformStream({
6669
6697
  start() {
6670
6698
  },
6671
- async transform(chunk2, controller) {
6672
- checksum.update(chunk2);
6673
- controller.enqueue(chunk2);
6699
+ async transform(chunk3, controller) {
6700
+ checksum.update(chunk3);
6701
+ controller.enqueue(chunk3);
6674
6702
  },
6675
6703
  async flush(controller) {
6676
6704
  const digest = await checksum.digest();
@@ -6743,7 +6771,7 @@ function createBufferedReadableStream(upstream, size, logger) {
6743
6771
  let mode = -1;
6744
6772
  const pull = async (controller) => {
6745
6773
  const { value, done } = await reader.read();
6746
- const chunk2 = value;
6774
+ const chunk3 = value;
6747
6775
  if (done) {
6748
6776
  if (mode !== -1) {
6749
6777
  const remainder = flush(buffers, mode);
@@ -6753,7 +6781,7 @@ function createBufferedReadableStream(upstream, size, logger) {
6753
6781
  }
6754
6782
  controller.close();
6755
6783
  } else {
6756
- const chunkMode = modeOf(chunk2, false);
6784
+ const chunkMode = modeOf(chunk3, false);
6757
6785
  if (mode !== chunkMode) {
6758
6786
  if (mode >= 0) {
6759
6787
  controller.enqueue(flush(buffers, mode));
@@ -6761,16 +6789,16 @@ function createBufferedReadableStream(upstream, size, logger) {
6761
6789
  mode = chunkMode;
6762
6790
  }
6763
6791
  if (mode === -1) {
6764
- controller.enqueue(chunk2);
6792
+ controller.enqueue(chunk3);
6765
6793
  return;
6766
6794
  }
6767
- const chunkSize = sizeOf(chunk2);
6795
+ const chunkSize = sizeOf(chunk3);
6768
6796
  bytesSeen += chunkSize;
6769
6797
  const bufferSize = sizeOf(buffers[mode]);
6770
6798
  if (chunkSize >= size && bufferSize === 0) {
6771
- controller.enqueue(chunk2);
6799
+ controller.enqueue(chunk3);
6772
6800
  } else {
6773
- const newSize = merge(buffers, mode, chunk2);
6801
+ const newSize = merge(buffers, mode, chunk3);
6774
6802
  if (!streamBufferingLoggedWarning && bytesSeen > size * 2) {
6775
6803
  streamBufferingLoggedWarning = true;
6776
6804
  logger?.warn(`@smithy/util-stream - stream chunk size ${chunkSize} is below threshold of ${size}, automatically buffering.`);
@@ -6787,14 +6815,14 @@ function createBufferedReadableStream(upstream, size, logger) {
6787
6815
  pull
6788
6816
  });
6789
6817
  }
6790
- function merge(buffers, mode, chunk2) {
6818
+ function merge(buffers, mode, chunk3) {
6791
6819
  switch (mode) {
6792
6820
  case 0:
6793
- buffers[0] += chunk2;
6821
+ buffers[0] += chunk3;
6794
6822
  return sizeOf(buffers[0]);
6795
6823
  case 1:
6796
6824
  case 2:
6797
- buffers[mode].push(chunk2);
6825
+ buffers[mode].push(chunk3);
6798
6826
  return sizeOf(buffers[mode]);
6799
6827
  }
6800
6828
  }
@@ -6810,17 +6838,17 @@ function flush(buffers, mode) {
6810
6838
  }
6811
6839
  throw new Error(`@smithy/util-stream - invalid index ${mode} given to flush()`);
6812
6840
  }
6813
- function sizeOf(chunk2) {
6814
- return chunk2?.byteLength ?? chunk2?.length ?? 0;
6841
+ function sizeOf(chunk3) {
6842
+ return chunk3?.byteLength ?? chunk3?.length ?? 0;
6815
6843
  }
6816
- function modeOf(chunk2, allowBuffer = true) {
6817
- if (allowBuffer && typeof Buffer !== "undefined" && chunk2 instanceof Buffer) {
6844
+ function modeOf(chunk3, allowBuffer = true) {
6845
+ if (allowBuffer && typeof Buffer !== "undefined" && chunk3 instanceof Buffer) {
6818
6846
  return 2;
6819
6847
  }
6820
- if (chunk2 instanceof Uint8Array) {
6848
+ if (chunk3 instanceof Uint8Array) {
6821
6849
  return 1;
6822
6850
  }
6823
- if (typeof chunk2 === "string") {
6851
+ if (typeof chunk3 === "string") {
6824
6852
  return 0;
6825
6853
  }
6826
6854
  return -1;
@@ -6841,8 +6869,8 @@ function createBufferedReadable(upstream, size, logger) {
6841
6869
  new ByteArrayCollector((size2) => Buffer.from(new Uint8Array(size2)))
6842
6870
  ];
6843
6871
  let mode = -1;
6844
- upstream.on("data", (chunk2) => {
6845
- const chunkMode = modeOf(chunk2, true);
6872
+ upstream.on("data", (chunk3) => {
6873
+ const chunkMode = modeOf(chunk3, true);
6846
6874
  if (mode !== chunkMode) {
6847
6875
  if (mode >= 0) {
6848
6876
  downstream.push(flush(buffers, mode));
@@ -6850,16 +6878,16 @@ function createBufferedReadable(upstream, size, logger) {
6850
6878
  mode = chunkMode;
6851
6879
  }
6852
6880
  if (mode === -1) {
6853
- downstream.push(chunk2);
6881
+ downstream.push(chunk3);
6854
6882
  return;
6855
6883
  }
6856
- const chunkSize = sizeOf(chunk2);
6884
+ const chunkSize = sizeOf(chunk3);
6857
6885
  bytesSeen += chunkSize;
6858
6886
  const bufferSize = sizeOf(buffers[mode]);
6859
6887
  if (chunkSize >= size && bufferSize === 0) {
6860
- downstream.push(chunk2);
6888
+ downstream.push(chunk3);
6861
6889
  } else {
6862
- const newSize = merge(buffers, mode, chunk2);
6890
+ const newSize = merge(buffers, mode, chunk3);
6863
6891
  if (!streamBufferingLoggedWarning && bytesSeen > size * 2) {
6864
6892
  streamBufferingLoggedWarning = true;
6865
6893
  logger?.warn(`@smithy/util-stream - stream chunk size ${chunkSize} is below threshold of ${size}, automatically buffering.`);
@@ -6934,14 +6962,14 @@ async function headStream(stream, bytes) {
6934
6962
  reader.releaseLock();
6935
6963
  const collected = new Uint8Array(Math.min(bytes, byteLengthCounter));
6936
6964
  let offset = 0;
6937
- for (const chunk2 of chunks) {
6938
- if (chunk2.byteLength > collected.byteLength - offset) {
6939
- collected.set(chunk2.subarray(0, collected.byteLength - offset), offset);
6965
+ for (const chunk3 of chunks) {
6966
+ if (chunk3.byteLength > collected.byteLength - offset) {
6967
+ collected.set(chunk3.subarray(0, collected.byteLength - offset), offset);
6940
6968
  break;
6941
6969
  } else {
6942
- collected.set(chunk2, offset);
6970
+ collected.set(chunk3, offset);
6943
6971
  }
6944
- offset += chunk2.length;
6972
+ offset += chunk3.length;
6945
6973
  }
6946
6974
  return collected;
6947
6975
  }
@@ -6970,9 +6998,9 @@ var Collector = class extends Writable {
6970
6998
  buffers = [];
6971
6999
  limit = Infinity;
6972
7000
  bytesBuffered = 0;
6973
- _write(chunk2, encoding, callback) {
6974
- this.buffers.push(chunk2);
6975
- this.bytesBuffered += chunk2.byteLength ?? 0;
7001
+ _write(chunk3, encoding, callback) {
7002
+ this.buffers.push(chunk3);
7003
+ this.bytesBuffered += chunk3.byteLength ?? 0;
6976
7004
  if (this.bytesBuffered >= this.limit) {
6977
7005
  const excess = this.bytesBuffered - this.limit;
6978
7006
  const tailBuffer = this.buffers[this.buffers.length - 1];
@@ -8570,9 +8598,7 @@ async function sendNotificationMessageBatch({
8570
8598
  const results = await Bluebird.mapSeries(chunks, async (batch) => {
8571
8599
  const entries = batch.map((msg, index) => ({
8572
8600
  Id: `msg-${index}`,
8573
- MessageBody: JSON.stringify(
8574
- createNotificationMessage(msg.eventName, msg.context, msg.input)
8575
- )
8601
+ MessageBody: JSON.stringify(createNotificationMessage(msg.eventName, msg.context, msg.input))
8576
8602
  }));
8577
8603
  const command = new SendMessageBatchCommand({
8578
8604
  QueueUrl: queueUrl,
@@ -8874,7 +8900,11 @@ __export(utils_exports, {
8874
8900
  automationSources: () => automationSources,
8875
8901
  getMeterPointNumberBottomLine: () => getMeterPointNumberBottomLine,
8876
8902
  isTransientError: () => isTransientError,
8903
+ paginatedFetch: () => paginatedFetch,
8904
+ resolveNotificationPreferences: () => resolveNotificationPreferences,
8905
+ sendToSqsBatched: () => sendToSqsBatched,
8877
8906
  units: () => units,
8907
+ updateBatchJobStatus: () => updateBatchJobStatus,
8878
8908
  utilityTypes: () => utilityTypes,
8879
8909
  wasteCategories: () => wasteCategories
8880
8910
  });
@@ -9181,6 +9211,64 @@ var getMeterPointNumberBottomLine = (meterPointNumber) => {
9181
9211
  return "";
9182
9212
  };
9183
9213
 
9214
+ // src/utils/job.ts
9215
+ async function updateBatchJobStatus({
9216
+ etnApi,
9217
+ automationRun,
9218
+ accountKey,
9219
+ status,
9220
+ errorMessage
9221
+ }) {
9222
+ if (!automationRun) return;
9223
+ if (automationRun.category !== "account") return;
9224
+ const jobKey = automationRun.jobId;
9225
+ const resolvedAccountKey = accountKey ?? automationRun.accountResults?.[0]?.id?.toString();
9226
+ if (!jobKey || !resolvedAccountKey) return;
9227
+ let jobEntry;
9228
+ try {
9229
+ jobEntry = await etnApi.getJob(jobKey);
9230
+ } catch (error) {
9231
+ console.error("Failed to fetch job for status update", {
9232
+ jobKey,
9233
+ accountKey: resolvedAccountKey,
9234
+ error
9235
+ });
9236
+ return;
9237
+ }
9238
+ if (!jobEntry || jobEntry.status === "completed" || jobEntry.status === "failed") return;
9239
+ const metadata = jobEntry.metadata ?? {};
9240
+ const completedAccountKeys = new Set(metadata.completedAccountKeys ?? []);
9241
+ const failedAccountKeys = new Set(metadata.failedAccountKeys ?? []);
9242
+ const { accountCount } = metadata;
9243
+ const now = (/* @__PURE__ */ new Date()).toISOString();
9244
+ if (status === "failed") {
9245
+ failedAccountKeys.add(resolvedAccountKey);
9246
+ } else {
9247
+ completedAccountKeys.add(resolvedAccountKey);
9248
+ }
9249
+ const updatePayload = {
9250
+ metadata: {
9251
+ ...metadata,
9252
+ completedAccountKeys: Array.from(completedAccountKeys),
9253
+ failedAccountKeys: Array.from(failedAccountKeys),
9254
+ completedCount: completedAccountKeys.size,
9255
+ failedCount: failedAccountKeys.size
9256
+ }
9257
+ };
9258
+ const totalProcessed = completedAccountKeys.size + failedAccountKeys.size;
9259
+ const hasFailures = failedAccountKeys.size > 0;
9260
+ if (status === "failed") {
9261
+ updatePayload.metadata = { ...updatePayload.metadata, result: "failed" };
9262
+ updatePayload.error = errorMessage || "Automation run failed";
9263
+ }
9264
+ if (accountCount && totalProcessed >= accountCount) {
9265
+ updatePayload.status = "completed";
9266
+ updatePayload.completedAt = now;
9267
+ updatePayload.metadata = { ...updatePayload.metadata, result: hasFailures ? "failed" : "success" };
9268
+ }
9269
+ await etnApi.updateJob(jobEntry._id, updatePayload);
9270
+ }
9271
+
9184
9272
  // node_modules/@aws-sdk/middleware-expect-continue/dist-es/index.js
9185
9273
  function addExpectContinueMiddleware(options) {
9186
9274
  return (next) => async (args) => {
@@ -12472,9 +12560,9 @@ var HeaderMarshaller = class {
12472
12560
  }
12473
12561
  const out = new Uint8Array(chunks.reduce((carry, bytes) => carry + bytes.byteLength, 0));
12474
12562
  let position = 0;
12475
- for (const chunk2 of chunks) {
12476
- out.set(chunk2, position);
12477
- position += chunk2.byteLength;
12563
+ for (const chunk3 of chunks) {
12564
+ out.set(chunk3, position);
12565
+ position += chunk3.byteLength;
12478
12566
  }
12479
12567
  return out;
12480
12568
  }
@@ -12794,8 +12882,8 @@ var SmithyMessageEncoderStream = class {
12794
12882
  return this.asyncIterator();
12795
12883
  }
12796
12884
  async *asyncIterator() {
12797
- for await (const chunk2 of this.options.inputStream) {
12798
- const payloadBuf = this.options.serializer(chunk2);
12885
+ for await (const chunk3 of this.options.inputStream) {
12886
+ const payloadBuf = this.options.serializer(chunk3);
12799
12887
  yield payloadBuf;
12800
12888
  }
12801
12889
  }
@@ -12979,9 +13067,9 @@ var HashCalculator = class extends Writable2 {
12979
13067
  super(options);
12980
13068
  this.hash = hash;
12981
13069
  }
12982
- _write(chunk2, encoding, callback) {
13070
+ _write(chunk3, encoding, callback) {
12983
13071
  try {
12984
- this.hash.update(toUint8Array(chunk2));
13072
+ this.hash.update(toUint8Array(chunk3));
12985
13073
  } catch (err) {
12986
13074
  return callback(err);
12987
13075
  }
@@ -13576,6 +13664,128 @@ function isTransientError(error) {
13576
13664
  return false;
13577
13665
  }
13578
13666
 
13667
+ // src/utils/pagination.ts
13668
+ var paginatedFetch = async (fetchPage, options = {}) => {
13669
+ const { pageSize = 100 } = options;
13670
+ const fetchAllPages = async (skip, accumulated) => {
13671
+ const response = await fetchPage({ $limit: pageSize, $skip: skip });
13672
+ accumulated.push(...response.data);
13673
+ return response.data.length < pageSize ? accumulated : fetchAllPages(skip + pageSize, accumulated);
13674
+ };
13675
+ return fetchAllPages(0, []);
13676
+ };
13677
+
13678
+ // src/utils/sqs.ts
13679
+ var import_lodash2 = __toESM(require_lodash(), 1);
13680
+ import Bluebird2 from "bluebird";
13681
+ var sendToSqsBatched = async (messages, options) => {
13682
+ const { queueUrl, concurrency = 5, batchSize = 10 } = options;
13683
+ const sqsClient = options.sqsClient ?? new SQSClient({ region: "eu-west-1" });
13684
+ if (messages.length === 0) {
13685
+ return { successful: 0, failed: 0 };
13686
+ }
13687
+ const batches = (0, import_lodash2.chunk)(messages, batchSize);
13688
+ let successful = 0;
13689
+ let failed = 0;
13690
+ await Bluebird2.map(
13691
+ batches,
13692
+ async (batch, batchIndex) => {
13693
+ const entries = batch.map((message, index) => ({
13694
+ Id: message.id ?? `msg_${batchIndex}_${index}`,
13695
+ MessageBody: JSON.stringify(message.body),
13696
+ ...message.attributes && { MessageAttributes: message.attributes }
13697
+ }));
13698
+ const response = await sqsClient.send(
13699
+ new SendMessageBatchCommand({
13700
+ QueueUrl: queueUrl,
13701
+ Entries: entries
13702
+ })
13703
+ );
13704
+ successful += response.Successful?.length ?? 0;
13705
+ if (response.Failed && response.Failed.length > 0) {
13706
+ failed += response.Failed.length;
13707
+ throw new Error(`Failed to send ${response.Failed.length} SQS messages in batch ${batchIndex}`);
13708
+ }
13709
+ },
13710
+ { concurrency }
13711
+ );
13712
+ return { successful, failed };
13713
+ };
13714
+
13715
+ // src/types/notification.ts
13716
+ var NotificationCategoryList = [
13717
+ "automation",
13718
+ "report",
13719
+ "team",
13720
+ "dataQuality",
13721
+ "discussion",
13722
+ "scraper"
13723
+ ];
13724
+ var NotificationDefaultChannels = {
13725
+ inApp: true,
13726
+ email: false,
13727
+ sms: false
13728
+ };
13729
+
13730
+ // src/utils/notification.ts
13731
+ function extractTemplates(source) {
13732
+ if (!source) return {};
13733
+ const templates = source.templates !== void 0 ? source.templates : source;
13734
+ if (templates && typeof templates === "object" && !Array.isArray(templates)) {
13735
+ return { ...templates };
13736
+ }
13737
+ return {};
13738
+ }
13739
+ function resolveNotificationPreferences(userPreferences, systemTemplates) {
13740
+ const prefs = userPreferences || {};
13741
+ const userCategories = prefs.categories || {};
13742
+ const userChannels = prefs.channels || {};
13743
+ const globalChannels = {
13744
+ inApp: userChannels.inApp !== void 0 ? userChannels.inApp : NotificationDefaultChannels.inApp,
13745
+ sms: userChannels.sms !== void 0 ? userChannels.sms : NotificationDefaultChannels.sms,
13746
+ email: userChannels.email !== void 0 ? userChannels.email : NotificationDefaultChannels.email
13747
+ };
13748
+ const convertTemplateToStringId = (template) => ({
13749
+ ...template,
13750
+ _id: template._id.toString()
13751
+ });
13752
+ const templatesByCategory = systemTemplates.reduce(
13753
+ (acc, template) => {
13754
+ const cat = template.category || "uncategorised";
13755
+ if (!acc[cat]) acc[cat] = [];
13756
+ acc[cat].push(convertTemplateToStringId(template));
13757
+ return acc;
13758
+ },
13759
+ {}
13760
+ );
13761
+ const categories = NotificationCategoryList.reduce(
13762
+ (acc, category) => {
13763
+ const userCategory = userCategories[category] || {};
13764
+ const userCategoryChannels = userCategory.channels || {};
13765
+ const userTemplates = extractTemplates(userCategory);
13766
+ const templateList = templatesByCategory[category] || [];
13767
+ acc[category] = {
13768
+ channels: {
13769
+ inApp: userCategoryChannels.inApp !== void 0 ? userCategoryChannels.inApp : NotificationDefaultChannels.inApp,
13770
+ sms: userCategoryChannels.sms !== void 0 ? userCategoryChannels.sms : NotificationDefaultChannels.sms,
13771
+ email: userCategoryChannels.email !== void 0 ? userCategoryChannels.email : NotificationDefaultChannels.email
13772
+ },
13773
+ templates: templateList.map((template) => ({
13774
+ _id: template._id,
13775
+ name: template.name,
13776
+ description: template.description,
13777
+ category: template.category,
13778
+ severity: template.severity,
13779
+ enabled: userTemplates[template._id] !== void 0 ? userTemplates[template._id] : template.enabledByDefault ?? true
13780
+ }))
13781
+ };
13782
+ return acc;
13783
+ },
13784
+ {}
13785
+ );
13786
+ return { channels: globalChannels, categories };
13787
+ }
13788
+
13579
13789
  // src/openai/index.ts
13580
13790
  var openai_exports = {};
13581
13791
  __export(openai_exports, {
@@ -15678,7 +15888,16 @@ var errorCodeMap = {
15678
15888
  unique: true
15679
15889
  }
15680
15890
  };
15681
- var dataFetchersIds = ["bacnet", "solis", "solarman", "gridfetch", "smartflow", "smartvatten", "beringar", "4dmonitoring"];
15891
+ var dataFetchersIds = [
15892
+ "bacnet",
15893
+ "solis",
15894
+ "solarman",
15895
+ "gridfetch",
15896
+ "smartflow",
15897
+ "smartvatten",
15898
+ "beringar",
15899
+ "4dmonitoring"
15900
+ ];
15682
15901
  function sendEmail(lambdaSource, context, error, destinations) {
15683
15902
  const sesClient = new SESClient({ region: "eu-west-1" });
15684
15903
  const template = emailTemplate_default({
@@ -15807,6 +16026,13 @@ async function handleError({ context, etnApi, automationRun, error, lambdaSource
15807
16026
  if (automationRun.category === "account" && accountId) {
15808
16027
  await etnApi.updateAccountStatusForAutomation(automation._id, accountId, { status: "error", error: error.message });
15809
16028
  }
16029
+ await updateBatchJobStatus({
16030
+ etnApi,
16031
+ automationRun,
16032
+ accountKey: accountId,
16033
+ status: "failed",
16034
+ errorMessage: error.message
16035
+ });
15810
16036
  }
15811
16037
  async function deleteMessage(queueUrl, receiptHandle, sqsClient) {
15812
16038
  if (!queueUrl || !receiptHandle) {
@@ -15829,43 +16055,19 @@ var scrapers_exports = {};
15829
16055
  // src/types/index.ts
15830
16056
  import { ObjectId } from "mongodb";
15831
16057
 
15832
- // src/types/notification.ts
15833
- var NotificationCategoryList = [
15834
- "automation",
15835
- "report",
15836
- "team",
15837
- "dataQuality",
15838
- "discussion",
15839
- "scraper"
15840
- ];
15841
- var NotificationDefaultChannels = {
15842
- inApp: true,
15843
- email: false,
15844
- sms: false
15845
- };
15846
-
15847
16058
  // src/types/notificationTemplate.ts
15848
- var NotificationTemplateCategories = [
15849
- "automation",
15850
- "report",
15851
- "team",
15852
- "dataQuality",
15853
- "discussion",
15854
- "scraper"
15855
- ];
15856
16059
  var EventNamesByCategory = {
15857
- automation: ["automationFailed", "runCompleted", "hasnotRun", "fileNotExpected"],
16060
+ automation: ["automationFailed", "automationCompleted", "automationOverdue", "automationExtractorOverdue"],
15858
16061
  report: ["reportSuccess", "reportFailed"],
15859
16062
  team: ["newUserSignIn"],
15860
- dataQuality: ["thresholdBreached", "approachingThreshold", "readingOverdue", "readingDueSoon", "contractRenewalUpcoming", "contractRenewalOverdue"],
15861
- discussion: ["commentAdded", "mentionInComment"],
15862
- scraper: ["scraperLoginError", "scraperHasnotRun", "scraperRunCompleted"]
16063
+ dataQuality: ["invoiceOverdue", "contractOverdue", "contractDueSoon", "readingOverdue", "readingDueSoon"],
16064
+ discussion: ["newDiscussionReply", "userAssignedToDiscussion", "discussionMessageDue"],
16065
+ scraper: ["scraperLoginError", "scraperHasNotRun", "scraperRunCompleted"]
15863
16066
  };
15864
16067
  export {
15865
16068
  EventNamesByCategory,
15866
16069
  NotificationCategoryList,
15867
16070
  NotificationDefaultChannels,
15868
- NotificationTemplateCategories,
15869
16071
  ObjectId,
15870
16072
  api_default as api,
15871
16073
  consumption_exports as consumption,