mercury-agent 0.8.0 → 0.8.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mercury-agent",
3
- "version": "0.8.0",
3
+ "version": "0.8.1",
4
4
  "description": "Personal AI assistant for chat platforms (WhatsApp, Slack, Discord, Telegram)",
5
5
  "license": "MIT",
6
6
  "author": "Avishai Tsabari",
@@ -2,10 +2,23 @@
2
2
  * Check if a caller is a global admin (configured in mercury.yaml / env).
3
3
  * Global admins are identified by `config.admins` and `config.dmAutoSpaceAdminIds`.
4
4
  * Platform-specific ID prefixes, + signs, and @domain suffixes are normalized.
5
+ *
6
+ * WhatsApp callers arrive canonicalized to their phone JID, but older configs
7
+ * may still list the LID digits (or vice versa when no mapping was known at
8
+ * config time). When an alias lookup is provided, the caller's learned
9
+ * LID↔phone counterpart is matched against the configured ids too.
5
10
  */
11
+
12
+ /** Subset of Db used to resolve WhatsApp LID↔phone pairs. */
13
+ export interface WaAliasLookup {
14
+ getWaPnForLid(lid: string): string | null;
15
+ getWaLidForPn(pn: string): string | null;
16
+ }
17
+
6
18
  export function isGlobalAdmin(
7
19
  callerId: string,
8
20
  config: { admins?: string; dmAutoSpaceAdminIds?: string },
21
+ aliases?: WaAliasLookup,
9
22
  ): boolean {
10
23
  const globalAdmins = [
11
24
  ...(config.admins
@@ -28,9 +41,20 @@ export function isGlobalAdmin(
28
41
  .replace(/^[+]+/, "")
29
42
  .replace(/@.*$/, "");
30
43
 
31
- const callerNormalized = normalize(callerId);
44
+ const callerCandidates = new Set([normalize(callerId)]);
45
+
46
+ if (aliases) {
47
+ const jid = callerId.replace(/^[^:]+:/, "");
48
+ if (jid.endsWith("@s.whatsapp.net")) {
49
+ const lid = aliases.getWaLidForPn(jid);
50
+ if (lid) callerCandidates.add(normalize(lid));
51
+ } else if (jid.endsWith("@lid")) {
52
+ const pn = aliases.getWaPnForLid(jid);
53
+ if (pn) callerCandidates.add(normalize(pn));
54
+ }
55
+ }
32
56
 
33
57
  return globalAdmins.some(
34
- (id) => id === callerId || normalize(id) === callerNormalized,
58
+ (id) => id === callerId || callerCandidates.has(normalize(id)),
35
59
  );
36
60
  }
@@ -7,13 +7,13 @@ export const broadcast = new Hono<Env>();
7
7
 
8
8
  broadcast.post("/", async (c) => {
9
9
  const { callerId } = getAuth(c);
10
- const { config, runtime } = getApiCtx(c);
10
+ const { config, db, runtime } = getApiCtx(c);
11
11
 
12
12
  if (!config.dmAutoSpaceEnabled) {
13
13
  return c.json({ error: "dm_auto_space is not enabled" }, 503);
14
14
  }
15
15
 
16
- if (!isGlobalAdmin(callerId, config)) {
16
+ if (!isGlobalAdmin(callerId, config, db)) {
17
17
  logger.warn("Broadcast denied — caller is not a global admin", {
18
18
  callerId,
19
19
  });
@@ -11,7 +11,7 @@ character.get("/", (c) => {
11
11
  const { callerId } = getAuth(c);
12
12
  const { config, db } = getApiCtx(c);
13
13
 
14
- if (!isGlobalAdmin(callerId, config)) {
14
+ if (!isGlobalAdmin(callerId, config, db)) {
15
15
  logger.warn("Character get denied — caller is not a global admin", {
16
16
  callerId,
17
17
  });
@@ -28,7 +28,7 @@ character.put("/", async (c) => {
28
28
  const { callerId } = getAuth(c);
29
29
  const { config, db } = getApiCtx(c);
30
30
 
31
- if (!isGlobalAdmin(callerId, config)) {
31
+ if (!isGlobalAdmin(callerId, config, db)) {
32
32
  logger.warn("Character set denied — caller is not a global admin", {
33
33
  callerId,
34
34
  });
@@ -57,7 +57,7 @@ character.delete("/", (c) => {
57
57
  const { callerId } = getAuth(c);
58
58
  const { config, db } = getApiCtx(c);
59
59
 
60
- if (!isGlobalAdmin(callerId, config)) {
60
+ if (!isGlobalAdmin(callerId, config, db)) {
61
61
  logger.warn("Character clear denied — caller is not a global admin", {
62
62
  callerId,
63
63
  });
@@ -13,9 +13,9 @@ export const send = new Hono<Env>();
13
13
 
14
14
  send.post("/", async (c) => {
15
15
  const { callerId } = getAuth(c);
16
- const { config, runtime } = getApiCtx(c);
16
+ const { config, db, runtime } = getApiCtx(c);
17
17
 
18
- if (!isGlobalAdmin(callerId, config)) {
18
+ if (!isGlobalAdmin(callerId, config, db)) {
19
19
  logger.warn("Direct send denied — caller is not a global admin", {
20
20
  callerId,
21
21
  });