@apocaliss92/nodelink-js 0.4.29 → 0.4.31

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.d.cts CHANGED
@@ -6310,9 +6310,19 @@ declare class ReolinkBaichuanApi {
6310
6310
  subscribeEmailPushEvents(params: {
6311
6311
  cameraId: string;
6312
6312
  channel?: number;
6313
+ /**
6314
+ * Optional handler invoked with the *full* `EmailPushEvent`
6315
+ * after the simple-event dispatch. Useful for consumers that
6316
+ * need fields beyond what `onSimpleEvent` carries — most
6317
+ * notably `event.attachment` (the JPEG snapshot from the
6318
+ * trigger frame) which a downstream plugin can republish to
6319
+ * MQTT or cache as the camera's last picture.
6320
+ */
6321
+ onEvent?: (event: EmailPushEvent) => void;
6313
6322
  } | {
6314
6323
  match: (event: EmailPushEvent) => boolean;
6315
6324
  channel?: number;
6325
+ onEvent?: (event: EmailPushEvent) => void;
6316
6326
  }): () => void;
6317
6327
  /**
6318
6328
  * Subscribe to minimal high-level events.
package/dist/index.d.ts CHANGED
@@ -7295,9 +7295,19 @@ export declare class ReolinkBaichuanApi {
7295
7295
  subscribeEmailPushEvents(params: {
7296
7296
  cameraId: string;
7297
7297
  channel?: number;
7298
+ /**
7299
+ * Optional handler invoked with the *full* `EmailPushEvent`
7300
+ * after the simple-event dispatch. Useful for consumers that
7301
+ * need fields beyond what `onSimpleEvent` carries — most
7302
+ * notably `event.attachment` (the JPEG snapshot from the
7303
+ * trigger frame) which a downstream plugin can republish to
7304
+ * MQTT or cache as the camera's last picture.
7305
+ */
7306
+ onEvent?: (event: EmailPushEvent) => void;
7298
7307
  } | {
7299
7308
  match: (event: EmailPushEvent) => boolean;
7300
7309
  channel?: number;
7310
+ onEvent?: (event: EmailPushEvent) => void;
7301
7311
  }): () => void;
7302
7312
  /**
7303
7313
  * Subscribe to minimal high-level events.
package/dist/index.js CHANGED
@@ -65,7 +65,7 @@ import {
65
65
  setEmailPushCameraResolver,
66
66
  setGlobalLogger,
67
67
  xmlIndicatesFloodlight
68
- } from "./chunk-NQ7D5TLR.js";
68
+ } from "./chunk-XVFCEFM6.js";
69
69
  import {
70
70
  ReolinkCgiApi,
71
71
  ReolinkHttpClient,
@@ -8284,6 +8284,7 @@ function base64DecodeToBytes(b64) {
8284
8284
  }
8285
8285
 
8286
8286
  // src/emailPush/server.ts
8287
+ import { format as utilFormat } from "util";
8287
8288
  import { SMTPServer } from "smtp-server";
8288
8289
  import { simpleParser } from "mailparser";
8289
8290
 
@@ -8339,8 +8340,10 @@ function createEmailPushServer(params) {
8339
8340
  let server;
8340
8341
  let status = buildInitialStatus(config);
8341
8342
  function parseRecipient(rcpt) {
8342
- const [local, domain] = rcpt.toLowerCase().split("@");
8343
- if (!local || !domain) return void 0;
8343
+ const at = rcpt.lastIndexOf("@");
8344
+ if (at <= 0 || at === rcpt.length - 1) return void 0;
8345
+ const local = rcpt.slice(0, at);
8346
+ const domain = rcpt.slice(at + 1).toLowerCase();
8344
8347
  return { local, domain };
8345
8348
  }
8346
8349
  function resolveCameraIdFromRecipient(rcpt) {
@@ -8393,10 +8396,19 @@ function createEmailPushServer(params) {
8393
8396
  disabledCommands: config.requireAuth ? [] : ["AUTH"],
8394
8397
  allowInsecureAuth: !config.tls,
8395
8398
  size: config.maxMessageBytes,
8399
+ // smtp-server invokes its internal logger as
8400
+ // logger.info(metadata, formatString, ...args)
8401
+ // where `metadata` is an opaque session/connection object and
8402
+ // `formatString` may contain printf-style placeholders.
8403
+ // Naive `.map(String).join(" ")` would surface `[object Object]`
8404
+ // and leave `%s` unresolved (which is what the user was seeing).
8405
+ // Here we strip the metadata (keeping a compact `tnx`/`cid` tag
8406
+ // when present), then apply `util.format` so placeholders are
8407
+ // expanded by Node exactly like the smtp-server defaults do.
8396
8408
  logger: {
8397
- info: (...args) => log.debug(`[smtp] ${args.map((a) => String(a)).join(" ")}`),
8398
- debug: (...args) => log.debug(`[smtp] ${args.map((a) => String(a)).join(" ")}`),
8399
- error: (...args) => log.warn(`[smtp] ${args.map((a) => String(a)).join(" ")}`)
8409
+ info: (...args) => log.info(formatSmtpLogArgs(args)),
8410
+ debug: (...args) => log.debug(formatSmtpLogArgs(args)),
8411
+ error: (...args) => log.warn(formatSmtpLogArgs(args))
8400
8412
  },
8401
8413
  ...tlsOptions ? { secure: false, ...tlsOptions } : {},
8402
8414
  onConnect(session, callback) {
@@ -8445,24 +8457,37 @@ function createEmailPushServer(params) {
8445
8457
  );
8446
8458
  return callback(new Error("Invalid username or password"));
8447
8459
  },
8448
- onRcptTo(address, _session, callback) {
8460
+ onRcptTo(address, session, callback) {
8449
8461
  const cameraId = resolveCameraIdFromRecipient(address.address);
8450
8462
  if (!cameraId) {
8451
8463
  status.messagesRejected++;
8464
+ log.warn(
8465
+ `SMTP RCPT TO rejected ${address.address} \u2014 unknown recipient (sessionId=${session.id})`
8466
+ );
8452
8467
  return callback(
8453
8468
  new Error(
8454
8469
  `Unknown recipient ${address.address} (not registered)`
8455
8470
  )
8456
8471
  );
8457
8472
  }
8473
+ log.info(
8474
+ `SMTP RCPT TO ${address.address} \u2192 camera=${cameraId} (sessionId=${session.id})`
8475
+ );
8458
8476
  callback();
8459
8477
  },
8460
8478
  onData(stream, session, callback) {
8479
+ const startedAt = Date.now();
8480
+ log.debug(
8481
+ `SMTP DATA start (sessionId=${session.id} from=${session.envelope.mailFrom ? session.envelope.mailFrom.address : "?"})`
8482
+ );
8461
8483
  const chunks = [];
8462
8484
  stream.on("data", (chunk) => chunks.push(chunk));
8463
8485
  stream.on("end", () => {
8464
8486
  const recipients = session.envelope.rcptTo?.map((r) => r.address) ?? [];
8465
8487
  const buffer = Buffer.concat(chunks);
8488
+ log.info(
8489
+ `SMTP DATA received ${buffer.length}B in ${Date.now() - startedAt}ms for ${recipients.length} recipient(s) (sessionId=${session.id})`
8490
+ );
8466
8491
  const matched = recipients.map((r) => ({
8467
8492
  recipient: r,
8468
8493
  cameraId: resolveCameraIdFromRecipient(r)
@@ -8471,6 +8496,9 @@ function createEmailPushServer(params) {
8471
8496
  );
8472
8497
  if (matched.length === 0) {
8473
8498
  status.messagesRejected++;
8499
+ log.warn(
8500
+ `SMTP DATA dropped \u2014 no recognised recipients in [${recipients.join(", ")}] (sessionId=${session.id})`
8501
+ );
8474
8502
  return callback(new Error("No recognised recipients"));
8475
8503
  }
8476
8504
  Promise.all(
@@ -8479,13 +8507,15 @@ function createEmailPushServer(params) {
8479
8507
  )
8480
8508
  ).then(() => callback()).catch((err) => {
8481
8509
  const msg = err instanceof Error ? err.message : String(err);
8482
- log.error(`Email push pipeline error: ${msg}`);
8510
+ log.error(
8511
+ `Email push pipeline error (sessionId=${session.id}): ${msg}`
8512
+ );
8483
8513
  status.lastErrorMessage = msg;
8484
8514
  callback(new Error(msg));
8485
8515
  });
8486
8516
  });
8487
8517
  stream.on("error", (err) => {
8488
- log.warn(`SMTP stream error: ${err.message}`);
8518
+ log.warn(`SMTP stream error (sessionId=${session.id}): ${err.message}`);
8489
8519
  callback(err);
8490
8520
  });
8491
8521
  }
@@ -8533,6 +8563,25 @@ function createEmailPushServer(params) {
8533
8563
  }
8534
8564
  };
8535
8565
  }
8566
+ function formatSmtpLogArgs(args) {
8567
+ if (args.length === 0) return "[smtp]";
8568
+ const [first, ...rest] = args;
8569
+ let tag = "";
8570
+ let formatArgs = args;
8571
+ if (first && typeof first === "object" && !Array.isArray(first)) {
8572
+ const meta = first;
8573
+ const tnx = typeof meta.tnx === "string" ? meta.tnx : void 0;
8574
+ const cid = typeof meta.cid === "string" ? meta.cid : void 0;
8575
+ const sid = typeof meta.sid === "string" ? meta.sid : void 0;
8576
+ const bits = [];
8577
+ if (tnx) bits.push(tnx);
8578
+ if (cid) bits.push(`cid=${cid}`);
8579
+ if (sid) bits.push(`sid=${sid}`);
8580
+ if (bits.length > 0) tag = ` [${bits.join(" ")}]`;
8581
+ formatArgs = rest;
8582
+ }
8583
+ return `[smtp]${tag} ${utilFormat(...formatArgs)}`;
8584
+ }
8536
8585
  function buildInitialStatus(config) {
8537
8586
  return {
8538
8587
  enabled: true,