arnacon-webrtc-service 0.1.74 → 0.1.76

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.
@@ -77,7 +77,17 @@
77
77
  "rpc": "https://sapphire.oasis.io",
78
78
  "chainId": 23294,
79
79
  "businessNumberDbAddress": "",
80
- "callerIdPoolAddress": "0x903796dc34Bb9A5eD76A41bBA6C40CfebD1f4269"
80
+ "callerIdPoolAddress": "0x903796dc34Bb9A5eD76A41bBA6C40CfebD1f4269",
81
+ "businessNumberDb": {
82
+ "rpc": "https://sapphire.oasis.io",
83
+ "chainId": 23294,
84
+ "address": "0xFc80534F731E3849Bc06970B0e8645d72A34f493"
85
+ },
86
+ "callerIdPool": {
87
+ "rpc": "https://sapphire.oasis.io",
88
+ "chainId": 23294,
89
+ "address": "0x903796dc34Bb9A5eD76A41bBA6C40CfebD1f4269"
90
+ }
81
91
  },
82
92
  "messageProcessorUrl": "https://europe-west3-asterisk-tts-test.cloudfunctions.net/client_msg_processor",
83
93
  "polygon": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "arnacon-webrtc-service",
3
- "version": "0.1.74",
3
+ "version": "0.1.76",
4
4
  "description": "Arnacon WebRTC core runtime and service modules",
5
5
  "main": "./webRTCservice/core.js",
6
6
  "type": "commonjs",
@@ -16,6 +16,8 @@ function createBlockchainApi({
16
16
  const SAPPHIRE_TESTNET_RPC = config.sapphireTestnet.rpc;
17
17
  const NFT_CALLER_ID_POOL_ADDRESS = config.sapphireTestnet.NFTCallerIdPool;
18
18
  const ROFL_LOGIC_CONFIG = config.roflLogic || {};
19
+ const ROFL_BUSINESS_NUMBER_DB_CONFIG = ROFL_LOGIC_CONFIG.businessNumberDb || {};
20
+ const ROFL_CALLER_ID_POOL_CONFIG = ROFL_LOGIC_CONFIG.callerIdPool || {};
19
21
  const ROFL_LOGIC_RPC =
20
22
  process.env.ROFL_LOGIC_RPC_URL ||
21
23
  ROFL_LOGIC_CONFIG.rpc ||
@@ -23,12 +25,36 @@ function createBlockchainApi({
23
25
  SAPPHIRE_RPC;
24
26
  const ROFL_LOGIC_CHAIN_ID =
25
27
  Number(process.env.ROFL_LOGIC_CHAIN_ID || ROFL_LOGIC_CONFIG.chainId || 0) || undefined;
28
+ const ROFL_BUSINESS_NUMBER_DB_RPC =
29
+ process.env.ROFL_LOGIC_BUSINESS_NUMBER_DB_RPC_URL ||
30
+ ROFL_BUSINESS_NUMBER_DB_CONFIG.rpc ||
31
+ ROFL_LOGIC_RPC;
32
+ const ROFL_BUSINESS_NUMBER_DB_CHAIN_ID =
33
+ Number(
34
+ process.env.ROFL_LOGIC_BUSINESS_NUMBER_DB_CHAIN_ID ||
35
+ ROFL_BUSINESS_NUMBER_DB_CONFIG.chainId ||
36
+ ROFL_LOGIC_CHAIN_ID ||
37
+ 0,
38
+ ) || undefined;
26
39
  const ROFL_BUSINESS_NUMBER_DB_ADDRESS =
27
40
  process.env.ROFL_LOGIC_BUSINESS_NUMBER_DB_ADDRESS ||
41
+ ROFL_BUSINESS_NUMBER_DB_CONFIG.address ||
28
42
  ROFL_LOGIC_CONFIG.businessNumberDbAddress ||
29
43
  "";
44
+ const ROFL_CALLER_ID_POOL_RPC =
45
+ process.env.ROFL_LOGIC_CALLER_ID_POOL_RPC_URL ||
46
+ ROFL_CALLER_ID_POOL_CONFIG.rpc ||
47
+ ROFL_LOGIC_RPC;
48
+ const ROFL_CALLER_ID_POOL_CHAIN_ID =
49
+ Number(
50
+ process.env.ROFL_LOGIC_CALLER_ID_POOL_CHAIN_ID ||
51
+ ROFL_CALLER_ID_POOL_CONFIG.chainId ||
52
+ ROFL_LOGIC_CHAIN_ID ||
53
+ 0,
54
+ ) || undefined;
30
55
  const ROFL_CALLER_ID_POOL_ADDRESS =
31
56
  process.env.ROFL_LOGIC_CALLER_ID_POOL_ADDRESS ||
57
+ ROFL_CALLER_ID_POOL_CONFIG.address ||
32
58
  ROFL_LOGIC_CONFIG.callerIdPoolAddress ||
33
59
  NFT_CALLER_ID_POOL_ADDRESS;
34
60
  const ROFL_PKEY = process.env.ROFL_LOGIC_PKEY || process.env.PKEY || "";
@@ -68,6 +94,8 @@ function createBlockchainApi({
68
94
  let sapphireProvider = null;
69
95
  let sapphireTestnetProvider = null;
70
96
  let roflLogicProvider = null;
97
+ let businessNumberDbProvider = null;
98
+ let callerIdPoolProvider = null;
71
99
  let businessNumberDbContract = null;
72
100
  let callerIdPoolRoflContract = null;
73
101
  let roflPoolOwnerAddress = null;
@@ -101,6 +129,34 @@ function createBlockchainApi({
101
129
  return roflLogicProvider;
102
130
  }
103
131
 
132
+ function getBusinessNumberDbProvider() {
133
+ if (!businessNumberDbProvider) {
134
+ if (ROFL_BUSINESS_NUMBER_DB_CHAIN_ID) {
135
+ businessNumberDbProvider = new ethers.providers.JsonRpcProvider(
136
+ ROFL_BUSINESS_NUMBER_DB_RPC,
137
+ ROFL_BUSINESS_NUMBER_DB_CHAIN_ID,
138
+ );
139
+ } else {
140
+ businessNumberDbProvider = new ethers.providers.JsonRpcProvider(ROFL_BUSINESS_NUMBER_DB_RPC);
141
+ }
142
+ }
143
+ return businessNumberDbProvider;
144
+ }
145
+
146
+ function getCallerIdPoolProvider() {
147
+ if (!callerIdPoolProvider) {
148
+ if (ROFL_CALLER_ID_POOL_CHAIN_ID) {
149
+ callerIdPoolProvider = new ethers.providers.JsonRpcProvider(
150
+ ROFL_CALLER_ID_POOL_RPC,
151
+ ROFL_CALLER_ID_POOL_CHAIN_ID,
152
+ );
153
+ } else {
154
+ callerIdPoolProvider = new ethers.providers.JsonRpcProvider(ROFL_CALLER_ID_POOL_RPC);
155
+ }
156
+ }
157
+ return callerIdPoolProvider;
158
+ }
159
+
104
160
  function normalizeContractAddress(value) {
105
161
  const normalized = String(value || "").trim();
106
162
  if (!normalized || normalized === "0x0000000000000000000000000000000000000000") return "";
@@ -129,7 +185,7 @@ function createBlockchainApi({
129
185
  if (!businessNumberDbContract) {
130
186
  const address = normalizeContractAddress(ROFL_BUSINESS_NUMBER_DB_ADDRESS);
131
187
  if (!address) return null;
132
- businessNumberDbContract = new ethers.Contract(address, BUSINESS_NUMBER_DB_ABI, getRoflLogicProvider());
188
+ businessNumberDbContract = new ethers.Contract(address, BUSINESS_NUMBER_DB_ABI, getBusinessNumberDbProvider());
133
189
  }
134
190
  return businessNumberDbContract;
135
191
  }
@@ -138,7 +194,7 @@ function createBlockchainApi({
138
194
  if (!callerIdPoolRoflContract) {
139
195
  const address = normalizeContractAddress(ROFL_CALLER_ID_POOL_ADDRESS);
140
196
  if (!address) return null;
141
- callerIdPoolRoflContract = new ethers.Contract(address, CALLER_ID_POOL_ROFL_ABI, getRoflLogicProvider());
197
+ callerIdPoolRoflContract = new ethers.Contract(address, CALLER_ID_POOL_ROFL_ABI, getCallerIdPoolProvider());
142
198
  }
143
199
  return callerIdPoolRoflContract;
144
200
  }
@@ -398,7 +454,9 @@ function createBlockchainApi({
398
454
  if (!businessName) return null;
399
455
  try {
400
456
  const phoneNumber = await contract.getPhoneNumber(businessName);
401
- return phoneNumber && phoneNumber !== "" ? phoneNumber : null;
457
+ const result = phoneNumber && phoneNumber !== "" ? phoneNumber : null;
458
+ logger.log(`[ROFL_LOCAL] business lookup ${businessName} -> ${result || "no-match"}`);
459
+ return result;
402
460
  } catch (err) {
403
461
  logger.error(`[ROFL_LOCAL] find-business-number failed for ${businessName}: ${err.message}`);
404
462
  return null;
@@ -452,7 +510,11 @@ function createBlockchainApi({
452
510
  return {
453
511
  rpc: ROFL_LOGIC_RPC || null,
454
512
  chainId: ROFL_LOGIC_CHAIN_ID || null,
513
+ businessNumberDbRpc: ROFL_BUSINESS_NUMBER_DB_RPC || null,
514
+ businessNumberDbChainId: ROFL_BUSINESS_NUMBER_DB_CHAIN_ID || null,
455
515
  businessNumberDbAddress: normalizeContractAddress(ROFL_BUSINESS_NUMBER_DB_ADDRESS) || null,
516
+ callerIdPoolRpc: ROFL_CALLER_ID_POOL_RPC || null,
517
+ callerIdPoolChainId: ROFL_CALLER_ID_POOL_CHAIN_ID || null,
456
518
  callerIdPoolAddress: normalizeContractAddress(ROFL_CALLER_ID_POOL_ADDRESS) || null,
457
519
  roflAddress: getRoflAddress() || null,
458
520
  };
@@ -61,11 +61,19 @@ function createCallRouter({
61
61
  }
62
62
  }
63
63
 
64
- async function roflCascadingBusinessLookup(identifier) {
65
- const lookups = [identifier];
64
+ function buildBusinessLookupKeys(identifier) {
65
+ const normalized = String(identifier || "").trim().toLowerCase().replace("@", "_");
66
+ if (!normalized) return [];
67
+ const lookups = [normalized];
66
68
 
67
- if (identifier.includes("_")) {
68
- const domain = identifier.split("_", 2)[1];
69
+ if (normalized.includes("_")) {
70
+ const [local, domain] = normalized.split("_", 2);
71
+ const localParts = String(local || "").split(".").filter(Boolean);
72
+ for (let i = 1; i < localParts.length; i++) {
73
+ const localSuffix = localParts.slice(i).join(".");
74
+ const key = `${localSuffix}_${domain}`;
75
+ if (localSuffix && domain && !lookups.includes(key)) lookups.push(key);
76
+ }
69
77
  if (!lookups.includes(domain)) lookups.push(domain);
70
78
  let parts = domain;
71
79
  while (parts.includes(".")) {
@@ -73,13 +81,20 @@ function createCallRouter({
73
81
  if (!lookups.includes(parts)) lookups.push(parts);
74
82
  }
75
83
  } else {
76
- let parts = identifier;
84
+ let parts = normalized;
77
85
  while (parts.includes(".")) {
78
86
  parts = parts.substring(0, parts.lastIndexOf("."));
79
87
  if (!lookups.includes(parts)) lookups.push(parts);
80
88
  }
81
89
  }
82
90
 
91
+ return lookups;
92
+ }
93
+
94
+ async function roflCascadingBusinessLookup(identifier) {
95
+ const lookups = buildBusinessLookupKeys(identifier);
96
+ if (lookups.length === 0) return null;
97
+
83
98
  logger.log(`[Route] Cascading business lookup: [${lookups.join(", ")}]`);
84
99
 
85
100
  for (const callee of lookups) {
@@ -46,8 +46,7 @@ async function resolveDestination(ctx) {
46
46
  if (addr && addr !== helpers.zeroAddress) {
47
47
  return { route: "webrtc", wallet: addr, ensName: emailEns };
48
48
  }
49
- const domainPart = String(parsedTo.value || "").split("@")[1] || parsedTo.value;
50
- const businessNumber = await helpers.lookupBusinessNumber(domainPart);
49
+ const businessNumber = await helpers.lookupBusinessNumberCascade(parsedTo.value);
51
50
  if (businessNumber) return { route: "sbc", number: businessNumber };
52
51
  return { route: "reject", reason: "No ENS owner and no business mapping" };
53
52
  }
@@ -55,8 +54,15 @@ async function resolveDestination(ctx) {
55
54
  if (parsedTo.type === "raw" || parsedTo.type === "unknown") {
56
55
  const normalized = helpers.normalizePhone(parsedTo.value);
57
56
  if (looksLikeBusinessDomain(normalized)) {
58
- const businessNumber = await helpers.lookupBusinessNumber(normalized);
57
+ const businessNumber = await helpers.lookupBusinessNumberCascade(normalized);
58
+ helpers.logRouteDecision?.({
59
+ serviceId: "email",
60
+ route: "business-domain-cascade",
61
+ target: normalized,
62
+ result: businessNumber || null,
63
+ });
59
64
  if (businessNumber) return { route: "sbc", number: businessNumber };
65
+ return { route: "reject", reason: `No business mapping for ${normalized}` };
60
66
  }
61
67
  const webrtcHit = await helpers.tryInternalWebrtcLookup(normalized, helpers.getAllServiceDomains());
62
68
  if (webrtcHit) return webrtcHit;
@@ -42,8 +42,15 @@ async function resolveDestination(ctx) {
42
42
  if (parsedTo.type === "raw" || parsedTo.type === "unknown") {
43
43
  const normalized = helpers.normalizePhone(parsedTo.value);
44
44
  if (looksLikeBusinessDomain(normalized)) {
45
- const businessNumber = await helpers.lookupBusinessNumber(normalized);
45
+ const businessNumber = await helpers.lookupBusinessNumberCascade(normalized);
46
+ helpers.logRouteDecision?.({
47
+ serviceId: "phonemyemail",
48
+ route: "business-domain-cascade",
49
+ target: normalized,
50
+ result: businessNumber || null,
51
+ });
46
52
  if (businessNumber) return { route: "sbc", number: businessNumber };
53
+ return { route: "reject", reason: `No business mapping for ${normalized}` };
47
54
  }
48
55
  const webrtcHit = await helpers.tryInternalWebrtcLookup(normalized, helpers.getAllServiceDomains());
49
56
  if (webrtcHit) return webrtcHit;
@@ -331,8 +331,14 @@ const roflLogicInfo = blockchainApi.getRoflLogicInfo();
331
331
  console.log(
332
332
  `[ROFL] mode=${USE_LOCAL_ROFL_LOGIC ? "local_rofl_logic" : "remote_http"} ` +
333
333
  `baseUrl=${ROFL_BASE_URL || "n/a"} rpc=${roflLogicInfo.rpc || "n/a"} ` +
334
- `chainId=${roflLogicInfo.chainId || "n/a"} businessDb=${roflLogicInfo.businessNumberDbAddress || "n/a"} ` +
335
- `callerIdPool=${roflLogicInfo.callerIdPoolAddress || "n/a"} roflAddress=${roflLogicInfo.roflAddress || "n/a"}`,
334
+ `chainId=${roflLogicInfo.chainId || "n/a"} ` +
335
+ `businessDb=${roflLogicInfo.businessNumberDbAddress || "n/a"} ` +
336
+ `businessDbRpc=${roflLogicInfo.businessNumberDbRpc || "n/a"} ` +
337
+ `businessDbChainId=${roflLogicInfo.businessNumberDbChainId || "n/a"} ` +
338
+ `callerIdPool=${roflLogicInfo.callerIdPoolAddress || "n/a"} ` +
339
+ `callerIdPoolRpc=${roflLogicInfo.callerIdPoolRpc || "n/a"} ` +
340
+ `callerIdPoolChainId=${roflLogicInfo.callerIdPoolChainId || "n/a"} ` +
341
+ `roflAddress=${roflLogicInfo.roflAddress || "n/a"}`,
336
342
  );
337
343
  const notificationApi = createNotificationApi({
338
344
  blockchainApi,
@@ -535,6 +541,7 @@ function getServiceHelpers(serviceRuntime) {
535
541
  lookupEnsTextRecord: (...args) => blockchainApi.resolveEnsTextRecord(...args),
536
542
  lookupNftOwnedNumber: (...args) => blockchainApi.nftGetOwnedNumber(...args),
537
543
  lookupBusinessNumber: (...args) => callRouterApi.roflFindBusinessNumber(...args),
544
+ lookupBusinessNumberCascade: (...args) => callRouterApi.roflCascadingBusinessLookup(...args),
538
545
  assignPoolFromNumber: (...args) => callRouterApi.roflAssignFromNumber(...args),
539
546
  getProviderForDomain: (domain) => {
540
547
  if (!domain) return null;