@yoooclaw/phone-notifications 1.11.5 → 1.11.7
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 +439 -63
- package/dist/index.cjs.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -251,6 +251,18 @@ function writeDotEnv(key, value) {
|
|
|
251
251
|
}
|
|
252
252
|
(0, import_node_fs7.writeFileSync)(path2, lines.join("\n"), "utf-8");
|
|
253
253
|
}
|
|
254
|
+
function buildEnvUrls(host) {
|
|
255
|
+
const https = `https://${host}`;
|
|
256
|
+
const wss = `wss://${host}`;
|
|
257
|
+
return {
|
|
258
|
+
lightApiUrl: `${https}/api/message/tob/sendMessage`,
|
|
259
|
+
relayTunnelUrl: `${wss}/message/messages/ws/plugin`,
|
|
260
|
+
appNameMapUrl: `${https}/api/application-config/app-package/config-all`,
|
|
261
|
+
modelProxyLongRecordingSubmitTaskUrl: `${https}/api/model-proxy/long-recording/submit-task`,
|
|
262
|
+
modelProxyLongRecordingQueryTaskResultBaseUrl: `${https}/api/model-proxy/long-recording/query-task-result`,
|
|
263
|
+
accountFileDeleteUrl: `${https}/api/account/file/delete`
|
|
264
|
+
};
|
|
265
|
+
}
|
|
254
266
|
function readDotEnv() {
|
|
255
267
|
const path2 = resolveStateFile(".env");
|
|
256
268
|
if (!(0, import_node_fs7.existsSync)(path2)) return {};
|
|
@@ -290,7 +302,7 @@ function getEnvUrls(env) {
|
|
|
290
302
|
function getAvailableEnvs() {
|
|
291
303
|
return Object.keys(ENV_CONFIG);
|
|
292
304
|
}
|
|
293
|
-
var import_node_fs7, import_node_path6, ENV_CONFIG, VALID_ENVS;
|
|
305
|
+
var import_node_fs7, import_node_path6, ENV_HOSTS, ENV_CONFIG, VALID_ENVS;
|
|
294
306
|
var init_env = __esm({
|
|
295
307
|
"src/env.ts"() {
|
|
296
308
|
"use strict";
|
|
@@ -298,31 +310,15 @@ var init_env = __esm({
|
|
|
298
310
|
import_node_path6 = require("path");
|
|
299
311
|
init_credentials();
|
|
300
312
|
init_host();
|
|
313
|
+
ENV_HOSTS = {
|
|
314
|
+
development: "openclaw-service-dev.yoooclaw.com",
|
|
315
|
+
test: "openclaw-service-test.yoooclaw.com",
|
|
316
|
+
production: "openclaw-service.yoooclaw.com"
|
|
317
|
+
};
|
|
301
318
|
ENV_CONFIG = {
|
|
302
|
-
development:
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
appNameMapUrl: "https://openclaw-service-dev.yoooclaw.com/api/application-config/app-package/config-all",
|
|
306
|
-
modelProxyLongRecordingSubmitTaskUrl: "https://openclaw-service-dev.yoooclaw.com/api/model-proxy/long-recording/submit-task",
|
|
307
|
-
modelProxyLongRecordingQueryTaskResultBaseUrl: "https://openclaw-service-dev.yoooclaw.com/api/model-proxy/long-recording/query-task-result",
|
|
308
|
-
accountFileDeleteUrl: "https://openclaw-service-dev.yoooclaw.com/api/account/file/delete"
|
|
309
|
-
},
|
|
310
|
-
test: {
|
|
311
|
-
lightApiUrl: "https://openclaw-service-test.yoooclaw.com/api/message/tob/sendMessage",
|
|
312
|
-
relayTunnelUrl: "wss://openclaw-service-test.yoooclaw.com/message/messages/ws/plugin",
|
|
313
|
-
appNameMapUrl: "https://openclaw-service-test.yoooclaw.com/api/application-config/app-package/config-all",
|
|
314
|
-
modelProxyLongRecordingSubmitTaskUrl: "https://openclaw-service-test.yoooclaw.com/api/model-proxy/long-recording/submit-task",
|
|
315
|
-
modelProxyLongRecordingQueryTaskResultBaseUrl: "https://openclaw-service-test.yoooclaw.com/api/model-proxy/long-recording/query-task-result",
|
|
316
|
-
accountFileDeleteUrl: "https://openclaw-service-test.yoooclaw.com/api/account/file/delete"
|
|
317
|
-
},
|
|
318
|
-
production: {
|
|
319
|
-
lightApiUrl: "https://openclaw-service.yoooclaw.com/api/message/tob/sendMessage",
|
|
320
|
-
relayTunnelUrl: "wss://openclaw-service.yoooclaw.com/message/messages/ws/plugin",
|
|
321
|
-
appNameMapUrl: "https://openclaw-service.yoooclaw.com/api/application-config/app-package/config-all",
|
|
322
|
-
modelProxyLongRecordingSubmitTaskUrl: "https://openclaw-service.yoooclaw.com/api/model-proxy/long-recording/submit-task",
|
|
323
|
-
modelProxyLongRecordingQueryTaskResultBaseUrl: "https://openclaw-service.yoooclaw.com/api/model-proxy/long-recording/query-task-result",
|
|
324
|
-
accountFileDeleteUrl: "https://openclaw-service.yoooclaw.com/api/account/file/delete"
|
|
325
|
-
}
|
|
319
|
+
development: buildEnvUrls(ENV_HOSTS.development),
|
|
320
|
+
test: buildEnvUrls(ENV_HOSTS.test),
|
|
321
|
+
production: buildEnvUrls(ENV_HOSTS.production)
|
|
326
322
|
};
|
|
327
323
|
VALID_ENVS = new Set(Object.keys(ENV_CONFIG));
|
|
328
324
|
}
|
|
@@ -5578,7 +5574,7 @@ function readBuildInjectedVersion() {
|
|
|
5578
5574
|
if (false) {
|
|
5579
5575
|
return void 0;
|
|
5580
5576
|
}
|
|
5581
|
-
const version = "1.11.
|
|
5577
|
+
const version = "1.11.7".trim();
|
|
5582
5578
|
return version || void 0;
|
|
5583
5579
|
}
|
|
5584
5580
|
function readPluginVersionFromPackageJson() {
|
|
@@ -5598,6 +5594,78 @@ var PLUGIN_VERSION = readBuildInjectedVersion() ?? readPluginVersionFromPackageJ
|
|
|
5598
5594
|
// src/logger.ts
|
|
5599
5595
|
var DEFAULT_LOG_RETENTION_DAYS = 30;
|
|
5600
5596
|
var DAY_MS = 24 * 60 * 60 * 1e3;
|
|
5597
|
+
var REDACTED = "[redacted]";
|
|
5598
|
+
var REDACTED_SECRET = "[redacted-secret]";
|
|
5599
|
+
var REDACTED_URL = "[redacted-url]";
|
|
5600
|
+
var SECRET_KEYS = [
|
|
5601
|
+
"apiKey",
|
|
5602
|
+
"api_key",
|
|
5603
|
+
"appKey",
|
|
5604
|
+
"authorization",
|
|
5605
|
+
"password",
|
|
5606
|
+
"secret",
|
|
5607
|
+
"token",
|
|
5608
|
+
"accessToken",
|
|
5609
|
+
"refreshToken",
|
|
5610
|
+
"gatewayToken",
|
|
5611
|
+
"gatewayPassword",
|
|
5612
|
+
"apnsToken",
|
|
5613
|
+
"deviceToken",
|
|
5614
|
+
"X-Api-Key-Id",
|
|
5615
|
+
"x-api-key-id",
|
|
5616
|
+
"x-openclaw-password"
|
|
5617
|
+
];
|
|
5618
|
+
var USER_TEXT_KEYS = [
|
|
5619
|
+
"accountId",
|
|
5620
|
+
"body",
|
|
5621
|
+
"content",
|
|
5622
|
+
"conversationName",
|
|
5623
|
+
"deviceId",
|
|
5624
|
+
"loginAccount",
|
|
5625
|
+
"metadata",
|
|
5626
|
+
"name",
|
|
5627
|
+
"raw",
|
|
5628
|
+
"rawResponse",
|
|
5629
|
+
"reason",
|
|
5630
|
+
"recordResult",
|
|
5631
|
+
"recordingName",
|
|
5632
|
+
"resBody",
|
|
5633
|
+
"response",
|
|
5634
|
+
"senderName",
|
|
5635
|
+
"sourceText",
|
|
5636
|
+
"sourceTextList",
|
|
5637
|
+
"summary",
|
|
5638
|
+
"summaryResult",
|
|
5639
|
+
"summaryText",
|
|
5640
|
+
"text",
|
|
5641
|
+
"title",
|
|
5642
|
+
"transcript",
|
|
5643
|
+
"transcriptData",
|
|
5644
|
+
"userId"
|
|
5645
|
+
];
|
|
5646
|
+
var USER_URL_KEYS = [
|
|
5647
|
+
"audio",
|
|
5648
|
+
"audioOssUrl",
|
|
5649
|
+
"fileUrl",
|
|
5650
|
+
"oss_audio_url",
|
|
5651
|
+
"oss_srt_url",
|
|
5652
|
+
"srt",
|
|
5653
|
+
"url"
|
|
5654
|
+
];
|
|
5655
|
+
var SENSITIVE_QUERY_KEYS = [
|
|
5656
|
+
"access_token",
|
|
5657
|
+
"api_key",
|
|
5658
|
+
"apikey",
|
|
5659
|
+
"authorization",
|
|
5660
|
+
"fileUrl",
|
|
5661
|
+
"password",
|
|
5662
|
+
"refresh_token",
|
|
5663
|
+
"secret",
|
|
5664
|
+
"signature",
|
|
5665
|
+
"token",
|
|
5666
|
+
"x-api-key-id",
|
|
5667
|
+
"x-oss-security-token"
|
|
5668
|
+
];
|
|
5601
5669
|
function isBetaPluginVersion(version = PLUGIN_VERSION) {
|
|
5602
5670
|
return /\bbeta\b/i.test(version);
|
|
5603
5671
|
}
|
|
@@ -5606,13 +5674,14 @@ function createVersionAwareLogger(upstream, options = {}) {
|
|
|
5606
5674
|
return upstream;
|
|
5607
5675
|
}
|
|
5608
5676
|
return {
|
|
5609
|
-
info() {
|
|
5677
|
+
info(msg) {
|
|
5678
|
+
upstream.info(redactLogMessage(msg));
|
|
5610
5679
|
},
|
|
5611
5680
|
warn(msg) {
|
|
5612
|
-
upstream.warn(msg);
|
|
5681
|
+
upstream.warn(redactLogMessage(msg));
|
|
5613
5682
|
},
|
|
5614
5683
|
error(msg) {
|
|
5615
|
-
upstream.error(msg);
|
|
5684
|
+
upstream.error(redactLogMessage(msg));
|
|
5616
5685
|
}
|
|
5617
5686
|
};
|
|
5618
5687
|
}
|
|
@@ -5620,7 +5689,7 @@ var PluginFileLogger = class {
|
|
|
5620
5689
|
constructor(upstream, stateDir, options = {}) {
|
|
5621
5690
|
this.upstream = upstream;
|
|
5622
5691
|
this.logsDir = (0, import_node_path.join)(stateDir, "plugins", "phone-notifications", "logs");
|
|
5623
|
-
this.
|
|
5692
|
+
this.redactLogs = !isBetaPluginVersion(options.version ?? PLUGIN_VERSION);
|
|
5624
5693
|
this.retentionDays = Number.isFinite(options.retentionDays) && (options.retentionDays ?? 0) > 0 ? options.retentionDays : DEFAULT_LOG_RETENTION_DAYS;
|
|
5625
5694
|
(0, import_node_fs2.mkdirSync)(this.logsDir, { recursive: true });
|
|
5626
5695
|
const now = /* @__PURE__ */ new Date();
|
|
@@ -5628,24 +5697,27 @@ var PluginFileLogger = class {
|
|
|
5628
5697
|
this.lastPruneDateKey = formatDate(now);
|
|
5629
5698
|
}
|
|
5630
5699
|
logsDir;
|
|
5631
|
-
|
|
5700
|
+
redactLogs;
|
|
5632
5701
|
retentionDays;
|
|
5633
5702
|
lastPruneDateKey = null;
|
|
5634
5703
|
info(msg) {
|
|
5635
5704
|
this.prepareLogDate(/* @__PURE__ */ new Date());
|
|
5636
|
-
|
|
5637
|
-
|
|
5638
|
-
|
|
5639
|
-
this.upstream.info(msg);
|
|
5640
|
-
this.append("INFO", msg);
|
|
5705
|
+
const safeMsg = this.formatLogMessage(msg);
|
|
5706
|
+
this.upstream.info(safeMsg);
|
|
5707
|
+
this.append("INFO", safeMsg);
|
|
5641
5708
|
}
|
|
5642
5709
|
warn(msg) {
|
|
5643
|
-
this.
|
|
5644
|
-
this.
|
|
5710
|
+
const safeMsg = this.formatLogMessage(msg);
|
|
5711
|
+
this.upstream.warn(safeMsg);
|
|
5712
|
+
this.append("WARN", safeMsg);
|
|
5645
5713
|
}
|
|
5646
5714
|
error(msg) {
|
|
5647
|
-
this.
|
|
5648
|
-
this.
|
|
5715
|
+
const safeMsg = this.formatLogMessage(msg);
|
|
5716
|
+
this.upstream.error(safeMsg);
|
|
5717
|
+
this.append("ERROR", safeMsg);
|
|
5718
|
+
}
|
|
5719
|
+
formatLogMessage(msg) {
|
|
5720
|
+
return this.redactLogs ? redactLogMessage(msg) : msg;
|
|
5649
5721
|
}
|
|
5650
5722
|
append(level, msg) {
|
|
5651
5723
|
const now = /* @__PURE__ */ new Date();
|
|
@@ -5681,6 +5753,188 @@ var PluginFileLogger = class {
|
|
|
5681
5753
|
}
|
|
5682
5754
|
}
|
|
5683
5755
|
};
|
|
5756
|
+
function redactLogMessage(msg) {
|
|
5757
|
+
let redacted = String(msg);
|
|
5758
|
+
redacted = redactQuotedObjectFields(redacted, SECRET_KEYS, REDACTED_SECRET);
|
|
5759
|
+
redacted = redactQuotedObjectFields(redacted, USER_TEXT_KEYS, REDACTED);
|
|
5760
|
+
redacted = redactQuotedObjectFields(redacted, USER_URL_KEYS, REDACTED_URL);
|
|
5761
|
+
redacted = redactStructuredKeyValueFields(
|
|
5762
|
+
redacted,
|
|
5763
|
+
SECRET_KEYS,
|
|
5764
|
+
REDACTED_SECRET
|
|
5765
|
+
);
|
|
5766
|
+
redacted = redactStructuredKeyValueFields(redacted, USER_TEXT_KEYS, REDACTED);
|
|
5767
|
+
redacted = redactStructuredKeyValueFields(redacted, USER_URL_KEYS, REDACTED_URL);
|
|
5768
|
+
redacted = redactKeyValueFields(redacted, SECRET_KEYS, REDACTED_SECRET);
|
|
5769
|
+
redacted = redactKeyValueFields(redacted, USER_TEXT_KEYS, REDACTED);
|
|
5770
|
+
redacted = redactKeyValueFields(redacted, USER_URL_KEYS, REDACTED_URL);
|
|
5771
|
+
redacted = redactColonTextFields(redacted, SECRET_KEYS, REDACTED_SECRET);
|
|
5772
|
+
redacted = redactColonTextFields(redacted, USER_TEXT_KEYS, REDACTED);
|
|
5773
|
+
redacted = redactQueryParams(redacted, SENSITIVE_QUERY_KEYS);
|
|
5774
|
+
redacted = redactBearerTokens(redacted);
|
|
5775
|
+
redacted = redactLikelyUserUrls(redacted);
|
|
5776
|
+
redacted = redactEmails(redacted);
|
|
5777
|
+
redacted = redactPhoneNumbers(redacted);
|
|
5778
|
+
redacted = redactJwtTokens(redacted);
|
|
5779
|
+
redacted = redactLongHexTokens(redacted);
|
|
5780
|
+
return redacted;
|
|
5781
|
+
}
|
|
5782
|
+
function redactQuotedObjectFields(input, keys, placeholder) {
|
|
5783
|
+
const keyPattern = buildKeyPattern(keys);
|
|
5784
|
+
return input.replace(
|
|
5785
|
+
new RegExp(
|
|
5786
|
+
`(["'])(${keyPattern})\\1\\s*:\\s*(?:"(?:\\\\.|[^"\\\\])*"|'(?:\\\\.|[^'\\\\])*'|[^,}\\]]+)`,
|
|
5787
|
+
"gi"
|
|
5788
|
+
),
|
|
5789
|
+
(_match, quote, key) => `${quote}${key}${quote}: "${placeholder}"`
|
|
5790
|
+
);
|
|
5791
|
+
}
|
|
5792
|
+
function redactKeyValueFields(input, keys, placeholder) {
|
|
5793
|
+
const keyPattern = buildKeyPattern(keys);
|
|
5794
|
+
return input.replace(
|
|
5795
|
+
new RegExp(
|
|
5796
|
+
`(?<![?&])\\b(${keyPattern})\\s*=\\s*(?:Bearer\\s+[^,\\s)]+|"(?:\\\\.|[^"\\\\])*"|'(?:\\\\.|[^'\\\\])*'|[^,\\s)]+)`,
|
|
5797
|
+
"gi"
|
|
5798
|
+
),
|
|
5799
|
+
(_match, key) => `${key}=${placeholder}`
|
|
5800
|
+
);
|
|
5801
|
+
}
|
|
5802
|
+
function redactStructuredKeyValueFields(input, keys, placeholder) {
|
|
5803
|
+
const keyPattern = buildKeyPattern(keys);
|
|
5804
|
+
const regex = new RegExp(`\\b(${keyPattern})\\s*=\\s*([\\[{])`, "gi");
|
|
5805
|
+
let result = "";
|
|
5806
|
+
let lastIndex = 0;
|
|
5807
|
+
let match;
|
|
5808
|
+
while (match = regex.exec(input)) {
|
|
5809
|
+
const valueStart = regex.lastIndex - 1;
|
|
5810
|
+
const valueEnd = findStructuredValueEnd(input, valueStart);
|
|
5811
|
+
if (valueEnd === null) {
|
|
5812
|
+
continue;
|
|
5813
|
+
}
|
|
5814
|
+
result += input.slice(lastIndex, match.index);
|
|
5815
|
+
result += `${match[1]}=${placeholder}`;
|
|
5816
|
+
lastIndex = valueEnd;
|
|
5817
|
+
regex.lastIndex = valueEnd;
|
|
5818
|
+
}
|
|
5819
|
+
if (lastIndex === 0) {
|
|
5820
|
+
return input;
|
|
5821
|
+
}
|
|
5822
|
+
return result + input.slice(lastIndex);
|
|
5823
|
+
}
|
|
5824
|
+
function findStructuredValueEnd(input, start) {
|
|
5825
|
+
const open = input[start];
|
|
5826
|
+
const close = open === "{" ? "}" : "]";
|
|
5827
|
+
const stack = [close];
|
|
5828
|
+
let quote = null;
|
|
5829
|
+
let escaped = false;
|
|
5830
|
+
for (let i = start + 1; i < input.length; i++) {
|
|
5831
|
+
const ch = input[i];
|
|
5832
|
+
if (quote) {
|
|
5833
|
+
if (escaped) {
|
|
5834
|
+
escaped = false;
|
|
5835
|
+
} else if (ch === "\\") {
|
|
5836
|
+
escaped = true;
|
|
5837
|
+
} else if (ch === quote) {
|
|
5838
|
+
quote = null;
|
|
5839
|
+
}
|
|
5840
|
+
continue;
|
|
5841
|
+
}
|
|
5842
|
+
if (ch === '"' || ch === "'") {
|
|
5843
|
+
quote = ch;
|
|
5844
|
+
continue;
|
|
5845
|
+
}
|
|
5846
|
+
if (ch === "{" || ch === "[") {
|
|
5847
|
+
stack.push(ch === "{" ? "}" : "]");
|
|
5848
|
+
continue;
|
|
5849
|
+
}
|
|
5850
|
+
if (ch === stack[stack.length - 1]) {
|
|
5851
|
+
stack.pop();
|
|
5852
|
+
if (stack.length === 0) {
|
|
5853
|
+
return i + 1;
|
|
5854
|
+
}
|
|
5855
|
+
}
|
|
5856
|
+
}
|
|
5857
|
+
return null;
|
|
5858
|
+
}
|
|
5859
|
+
function redactColonTextFields(input, keys, placeholder) {
|
|
5860
|
+
const keyPattern = buildKeyPattern(keys);
|
|
5861
|
+
return input.replace(
|
|
5862
|
+
new RegExp(`\\b(${keyPattern})\\s*:\\s*([^,\\n]+)`, "gi"),
|
|
5863
|
+
(_match, key) => `${key}: ${placeholder}`
|
|
5864
|
+
);
|
|
5865
|
+
}
|
|
5866
|
+
function redactQueryParams(input, keys) {
|
|
5867
|
+
const keyPattern = buildKeyPattern(keys);
|
|
5868
|
+
return input.replace(
|
|
5869
|
+
new RegExp(`([?&](${keyPattern})=)([^&#\\s]+)`, "gi"),
|
|
5870
|
+
(_match, prefix) => `${prefix}${encodeURIComponent(REDACTED)}`
|
|
5871
|
+
);
|
|
5872
|
+
}
|
|
5873
|
+
function redactBearerTokens(input) {
|
|
5874
|
+
return input.replace(
|
|
5875
|
+
/\b(Bearer\s+)[A-Za-z0-9._~+/=-]+/gi,
|
|
5876
|
+
`$1${REDACTED_SECRET}`
|
|
5877
|
+
);
|
|
5878
|
+
}
|
|
5879
|
+
function redactJwtTokens(input) {
|
|
5880
|
+
return input.replace(
|
|
5881
|
+
/\beyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\b/g,
|
|
5882
|
+
REDACTED_SECRET
|
|
5883
|
+
);
|
|
5884
|
+
}
|
|
5885
|
+
function redactLongHexTokens(input) {
|
|
5886
|
+
return input.replace(/\b[a-f0-9]{32,}\b/gi, REDACTED_SECRET);
|
|
5887
|
+
}
|
|
5888
|
+
function redactEmails(input) {
|
|
5889
|
+
return input.replace(
|
|
5890
|
+
/\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}\b/gi,
|
|
5891
|
+
"[redacted-email]"
|
|
5892
|
+
);
|
|
5893
|
+
}
|
|
5894
|
+
function redactPhoneNumbers(input) {
|
|
5895
|
+
return input.replace(
|
|
5896
|
+
/\b1[3-9]\d{9}\b/g,
|
|
5897
|
+
(phone) => `${phone.slice(0, 3)}****${phone.slice(-4)}`
|
|
5898
|
+
);
|
|
5899
|
+
}
|
|
5900
|
+
function redactLikelyUserUrls(input) {
|
|
5901
|
+
return input.replace(
|
|
5902
|
+
/https?:\/\/[^\s"',)]+/gi,
|
|
5903
|
+
(rawUrl) => redactUrl(rawUrl)
|
|
5904
|
+
);
|
|
5905
|
+
}
|
|
5906
|
+
function redactUrl(rawUrl) {
|
|
5907
|
+
try {
|
|
5908
|
+
const url = new URL(rawUrl);
|
|
5909
|
+
for (const key of Array.from(url.searchParams.keys())) {
|
|
5910
|
+
if (SENSITIVE_QUERY_KEYS.some(
|
|
5911
|
+
(sensitiveKey) => sensitiveKey.toLowerCase() === key.toLowerCase()
|
|
5912
|
+
)) {
|
|
5913
|
+
url.searchParams.set(key, REDACTED);
|
|
5914
|
+
}
|
|
5915
|
+
}
|
|
5916
|
+
if (shouldRedactUrlPath(url)) {
|
|
5917
|
+
return `${url.origin}/${REDACTED_URL}`;
|
|
5918
|
+
}
|
|
5919
|
+
return url.toString();
|
|
5920
|
+
} catch {
|
|
5921
|
+
return rawUrl;
|
|
5922
|
+
}
|
|
5923
|
+
}
|
|
5924
|
+
function shouldRedactUrlPath(url) {
|
|
5925
|
+
const host = url.hostname.toLowerCase();
|
|
5926
|
+
const path2 = decodeURIComponent(url.pathname).toLowerCase();
|
|
5927
|
+
if (/(^|\.)((oss|cos|s3|storage|cdn)[.-])/.test(host) || /(aliyuncs|myqcloud|amazonaws|oss|storage|cdn)/.test(host)) {
|
|
5928
|
+
return true;
|
|
5929
|
+
}
|
|
5930
|
+
return /\/(audio|avatar|feedback|log|logs|recording|recordings)\//.test(path2) || /\.(aac|flac|json|m4a|md|mp3|ogg|opus|srt|wav|zip)$/i.test(path2);
|
|
5931
|
+
}
|
|
5932
|
+
function buildKeyPattern(keys) {
|
|
5933
|
+
return keys.map(escapeRegExp).join("|");
|
|
5934
|
+
}
|
|
5935
|
+
function escapeRegExp(value) {
|
|
5936
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
5937
|
+
}
|
|
5684
5938
|
function formatDate(d) {
|
|
5685
5939
|
const y = d.getFullYear();
|
|
5686
5940
|
const m = String(d.getMonth() + 1).padStart(2, "0");
|
|
@@ -7215,10 +7469,21 @@ var InlineLightRuleEvaluator = class {
|
|
|
7215
7469
|
*/
|
|
7216
7470
|
async evaluate(notifications) {
|
|
7217
7471
|
if (notifications.length === 0) return true;
|
|
7472
|
+
this.reloadRegistry("before evaluation");
|
|
7218
7473
|
const rules = this.registry.getEnabled();
|
|
7219
|
-
if (rules.length === 0)
|
|
7474
|
+
if (rules.length === 0) {
|
|
7475
|
+
this.logger.info(
|
|
7476
|
+
`lightrules: no enabled rules (notifications=${notifications.length})`
|
|
7477
|
+
);
|
|
7478
|
+
return true;
|
|
7479
|
+
}
|
|
7220
7480
|
const matches = await this.invoker.matchNotifications(notifications, rules);
|
|
7221
|
-
if (matches === null)
|
|
7481
|
+
if (matches === null) {
|
|
7482
|
+
this.logger.warn(
|
|
7483
|
+
`lightrules: match failed (notifications=${notifications.length}, rules=${rules.length})`
|
|
7484
|
+
);
|
|
7485
|
+
return false;
|
|
7486
|
+
}
|
|
7222
7487
|
if (matches.length === 0) {
|
|
7223
7488
|
this.logger.info(
|
|
7224
7489
|
`lightrules: 0 matches (notifications=${notifications.length}, rules=${rules.length})`
|
|
@@ -7226,12 +7491,19 @@ var InlineLightRuleEvaluator = class {
|
|
|
7226
7491
|
return true;
|
|
7227
7492
|
}
|
|
7228
7493
|
const firedRules = /* @__PURE__ */ new Set();
|
|
7494
|
+
this.reloadRegistry("before triggering");
|
|
7229
7495
|
for (const match of matches) {
|
|
7230
7496
|
if (firedRules.has(match.ruleName)) continue;
|
|
7231
7497
|
const rule = this.registry.get(match.ruleName);
|
|
7232
7498
|
if (!rule) {
|
|
7233
7499
|
this.logger.warn(
|
|
7234
|
-
`lightrules: matched rule '${match.ruleName}' not found
|
|
7500
|
+
`lightrules: matched rule '${match.ruleName}' skipped - not found after reload`
|
|
7501
|
+
);
|
|
7502
|
+
continue;
|
|
7503
|
+
}
|
|
7504
|
+
if (!rule.enabled) {
|
|
7505
|
+
this.logger.info(
|
|
7506
|
+
`lightrules: matched rule '${match.ruleName}' skipped - disabled after reload`
|
|
7235
7507
|
);
|
|
7236
7508
|
continue;
|
|
7237
7509
|
}
|
|
@@ -7244,6 +7516,15 @@ var InlineLightRuleEvaluator = class {
|
|
|
7244
7516
|
);
|
|
7245
7517
|
return true;
|
|
7246
7518
|
}
|
|
7519
|
+
reloadRegistry(stage) {
|
|
7520
|
+
try {
|
|
7521
|
+
this.registry.reload();
|
|
7522
|
+
} catch (err2) {
|
|
7523
|
+
this.logger.warn(
|
|
7524
|
+
`lightrules: registry reload failed ${stage}: ${err2?.message ?? err2}`
|
|
7525
|
+
);
|
|
7526
|
+
}
|
|
7527
|
+
}
|
|
7247
7528
|
async triggerLight(rule, notification) {
|
|
7248
7529
|
let apiKey;
|
|
7249
7530
|
try {
|
|
@@ -7302,6 +7583,74 @@ function summarizeContent(content) {
|
|
|
7302
7583
|
return `${trimmed.slice(0, REASON_CONTENT_MAX)}\u2026`;
|
|
7303
7584
|
}
|
|
7304
7585
|
|
|
7586
|
+
// src/light-rules/evaluation-scheduler.ts
|
|
7587
|
+
var DEFAULT_LIGHT_RULE_EVALUATION_DEBOUNCE_MS = 1e3;
|
|
7588
|
+
var LightRuleEvaluationScheduler = class {
|
|
7589
|
+
evaluator;
|
|
7590
|
+
logger;
|
|
7591
|
+
debounceMs;
|
|
7592
|
+
pending = [];
|
|
7593
|
+
timer = null;
|
|
7594
|
+
running = false;
|
|
7595
|
+
flushRequestedWhileRunning = false;
|
|
7596
|
+
constructor(deps) {
|
|
7597
|
+
this.evaluator = deps.evaluator;
|
|
7598
|
+
this.logger = deps.logger;
|
|
7599
|
+
const debounceMs = deps.options?.debounceMs ?? DEFAULT_LIGHT_RULE_EVALUATION_DEBOUNCE_MS;
|
|
7600
|
+
this.debounceMs = Number.isFinite(debounceMs) && debounceMs >= 0 ? debounceMs : DEFAULT_LIGHT_RULE_EVALUATION_DEBOUNCE_MS;
|
|
7601
|
+
}
|
|
7602
|
+
enqueue(notifications) {
|
|
7603
|
+
if (notifications.length === 0) return;
|
|
7604
|
+
this.pending.push(...notifications);
|
|
7605
|
+
this.scheduleFlush();
|
|
7606
|
+
}
|
|
7607
|
+
scheduleFlush() {
|
|
7608
|
+
if (this.timer !== null) return;
|
|
7609
|
+
this.timer = setTimeout(() => {
|
|
7610
|
+
this.timer = null;
|
|
7611
|
+
void this.drain().catch((err2) => {
|
|
7612
|
+
this.logger.warn(
|
|
7613
|
+
`lightrules: scheduled evaluation failed: ${err2?.message ?? err2}`
|
|
7614
|
+
);
|
|
7615
|
+
});
|
|
7616
|
+
}, this.debounceMs);
|
|
7617
|
+
const maybeNodeTimer = this.timer;
|
|
7618
|
+
maybeNodeTimer.unref?.();
|
|
7619
|
+
}
|
|
7620
|
+
async drain() {
|
|
7621
|
+
if (this.running) {
|
|
7622
|
+
this.flushRequestedWhileRunning = true;
|
|
7623
|
+
return;
|
|
7624
|
+
}
|
|
7625
|
+
const batch = this.pending.splice(0);
|
|
7626
|
+
if (batch.length === 0) return;
|
|
7627
|
+
this.running = true;
|
|
7628
|
+
try {
|
|
7629
|
+
await this.evaluator.evaluate(batch);
|
|
7630
|
+
} catch (err2) {
|
|
7631
|
+
this.logger.warn(
|
|
7632
|
+
`lightrules: evaluation failed (notifications=${batch.length}): ${err2?.message ?? err2}`
|
|
7633
|
+
);
|
|
7634
|
+
} finally {
|
|
7635
|
+
this.running = false;
|
|
7636
|
+
if (this.pending.length > 0) {
|
|
7637
|
+
if (this.flushRequestedWhileRunning) {
|
|
7638
|
+
this.flushRequestedWhileRunning = false;
|
|
7639
|
+
void this.drain().catch((err2) => {
|
|
7640
|
+
this.logger.warn(
|
|
7641
|
+
`lightrules: queued evaluation failed: ${err2?.message ?? err2}`
|
|
7642
|
+
);
|
|
7643
|
+
});
|
|
7644
|
+
} else {
|
|
7645
|
+
this.scheduleFlush();
|
|
7646
|
+
}
|
|
7647
|
+
} else {
|
|
7648
|
+
this.flushRequestedWhileRunning = false;
|
|
7649
|
+
}
|
|
7650
|
+
}
|
|
7651
|
+
}
|
|
7652
|
+
};
|
|
7653
|
+
|
|
7305
7654
|
// src/light-rules/pi-invoker.ts
|
|
7306
7655
|
var import_agent_runtime = require("openclaw/plugin-sdk/agent-runtime");
|
|
7307
7656
|
var DEFAULT_PROVIDER = "anthropic";
|
|
@@ -7325,7 +7674,16 @@ var PiAiInvoker = class {
|
|
|
7325
7674
|
*/
|
|
7326
7675
|
async matchNotifications(notifications, rules) {
|
|
7327
7676
|
if (notifications.length === 0 || rules.length === 0) return [];
|
|
7328
|
-
|
|
7677
|
+
let label;
|
|
7678
|
+
let prepared;
|
|
7679
|
+
try {
|
|
7680
|
+
({ label, prepared } = await this.prepareCompletionModel());
|
|
7681
|
+
} catch (err2) {
|
|
7682
|
+
this.logger.warn(
|
|
7683
|
+
`PiAiInvoker: prepare failed: ${err2?.message ?? String(err2)}`
|
|
7684
|
+
);
|
|
7685
|
+
return null;
|
|
7686
|
+
}
|
|
7329
7687
|
if ("error" in prepared) {
|
|
7330
7688
|
this.logger.warn(
|
|
7331
7689
|
`PiAiInvoker: prepare ${label} failed: ${prepared.error}`
|
|
@@ -11203,6 +11561,12 @@ var RecordingStorage = class {
|
|
|
11203
11561
|
if (typeof entry.lastError === "string" && entry.lastError.trim()) {
|
|
11204
11562
|
compacted.lastError = entry.lastError.trim();
|
|
11205
11563
|
}
|
|
11564
|
+
if (compacted.status === "transcribing") {
|
|
11565
|
+
compacted.status = "transcribe_failed";
|
|
11566
|
+
compacted.lastError = compacted.lastError ?? "\u8F6C\u5199\u4EFB\u52A1\u5DF2\u4E2D\u65AD\uFF0C\u8BF7\u91CD\u65B0\u53D1\u8D77\u8F6C\u5199";
|
|
11567
|
+
compacted.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
11568
|
+
needsRewrite = true;
|
|
11569
|
+
}
|
|
11206
11570
|
return compacted;
|
|
11207
11571
|
});
|
|
11208
11572
|
const hadLargeFields = raw.recordings.some(
|
|
@@ -11545,20 +11909,27 @@ async function triggerTranscription(recordingId, storage, asrConfig, logger, opt
|
|
|
11545
11909
|
storage.setLastError(recordingId, void 0);
|
|
11546
11910
|
emitRecordingStatus(recordingId, storage, logger, options.notifyStatus);
|
|
11547
11911
|
const audioFilePath = storage.getAudioFilePath(recordingId);
|
|
11548
|
-
|
|
11549
|
-
|
|
11550
|
-
|
|
11551
|
-
|
|
11552
|
-
|
|
11553
|
-
|
|
11554
|
-
|
|
11555
|
-
|
|
11556
|
-
|
|
11557
|
-
|
|
11558
|
-
|
|
11559
|
-
|
|
11560
|
-
|
|
11561
|
-
|
|
11912
|
+
let result;
|
|
11913
|
+
try {
|
|
11914
|
+
result = await runTranscriptionWorkflow({
|
|
11915
|
+
audioFilePath,
|
|
11916
|
+
audioOssUrl: entry.metadata.oss_audio_url,
|
|
11917
|
+
config: asrConfig,
|
|
11918
|
+
markers: entry.metadata.markers ?? [],
|
|
11919
|
+
recordingName: entry.metadata.name,
|
|
11920
|
+
durationSec: entry.metadata.duration_sec,
|
|
11921
|
+
createdAt: entry.metadata.created_at,
|
|
11922
|
+
transcriptDataDir: storage.getTranscriptDataDir(),
|
|
11923
|
+
transcriptsDir: storage.getTranscriptsDir(),
|
|
11924
|
+
summariesDir: storage.getSummariesDir(),
|
|
11925
|
+
recordingId,
|
|
11926
|
+
logger
|
|
11927
|
+
});
|
|
11928
|
+
} catch (err2) {
|
|
11929
|
+
const error = `\u8F6C\u5199\u4EFB\u52A1\u5F02\u5E38: ${err2?.message ?? err2}`;
|
|
11930
|
+
logger.error(`[asr-trigger] ${error}: ${recordingId}`);
|
|
11931
|
+
result = { ok: false, error };
|
|
11932
|
+
}
|
|
11562
11933
|
if (result.ok && result.transcriptFilename) {
|
|
11563
11934
|
if (result.transcriptDataFilename) {
|
|
11564
11935
|
storage.setTranscriptDataFile(recordingId, result.transcriptDataFilename);
|
|
@@ -11593,17 +11964,18 @@ async function triggerTranscription(recordingId, storage, asrConfig, logger, opt
|
|
|
11593
11964
|
});
|
|
11594
11965
|
}
|
|
11595
11966
|
} else {
|
|
11967
|
+
const error = result.error ?? "ASR \u8F6C\u5199\u5931\u8D25";
|
|
11596
11968
|
storage.updateStatus(recordingId, "transcribe_failed");
|
|
11597
|
-
storage.setLastError(recordingId,
|
|
11969
|
+
storage.setLastError(recordingId, error);
|
|
11598
11970
|
emitRecordingStatus(
|
|
11599
11971
|
recordingId,
|
|
11600
11972
|
storage,
|
|
11601
11973
|
logger,
|
|
11602
11974
|
options.notifyStatus,
|
|
11603
|
-
|
|
11975
|
+
error
|
|
11604
11976
|
);
|
|
11605
11977
|
logger.error(
|
|
11606
|
-
`[asr-trigger] \u8F6C\u5199\u5931\u8D25: ${recordingId}, error=${
|
|
11978
|
+
`[asr-trigger] \u8F6C\u5199\u5931\u8D25: ${recordingId}, error=${error}`
|
|
11607
11979
|
);
|
|
11608
11980
|
}
|
|
11609
11981
|
}
|
|
@@ -14077,6 +14449,10 @@ var index_default = {
|
|
|
14077
14449
|
registry: lightRuleRegistry,
|
|
14078
14450
|
invoker: lightRuleInvoker
|
|
14079
14451
|
});
|
|
14452
|
+
const lightRuleEvaluationScheduler = new LightRuleEvaluationScheduler({
|
|
14453
|
+
evaluator: inlineLightRuleEvaluator,
|
|
14454
|
+
logger
|
|
14455
|
+
});
|
|
14080
14456
|
registerStorageLifecycle({
|
|
14081
14457
|
api,
|
|
14082
14458
|
config,
|
|
@@ -14105,8 +14481,8 @@ var index_default = {
|
|
|
14105
14481
|
filterNotifications,
|
|
14106
14482
|
registerGatewayMethod: registerGatewayMethodWithBroadcastCapture,
|
|
14107
14483
|
tunnelService,
|
|
14108
|
-
onAfterIngest
|
|
14109
|
-
|
|
14484
|
+
onAfterIngest(inserted) {
|
|
14485
|
+
lightRuleEvaluationScheduler.enqueue(inserted);
|
|
14110
14486
|
}
|
|
14111
14487
|
});
|
|
14112
14488
|
registerLightControlTool(api, logger);
|