whatsapp_notifier 0.9.1 → 0.9.3
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.
- checksums.yaml +4 -4
- data/lib/whatsapp_notifier/client.rb +4 -0
- data/lib/whatsapp_notifier/providers/web_automation.rb +10 -0
- data/lib/whatsapp_notifier/services/web_automation/bun.lock +77 -71
- data/lib/whatsapp_notifier/services/web_automation/history.test.ts +93 -1
- data/lib/whatsapp_notifier/services/web_automation/history.ts +61 -5
- data/lib/whatsapp_notifier/services/web_automation/inbound.test.ts +90 -0
- data/lib/whatsapp_notifier/services/web_automation/inbound.ts +150 -39
- data/lib/whatsapp_notifier/services/web_automation/index.ts +18 -1
- data/lib/whatsapp_notifier/services/web_automation/package.json +1 -1
- data/lib/whatsapp_notifier/version.rb +1 -1
- data/lib/whatsapp_notifier/web_adapter.rb +27 -1
- data/lib/whatsapp_notifier.rb +4 -0
- data/spec/client_spec.rb +5 -2
- data/spec/providers/web_automation_spec.rb +5 -1
- data/spec/web_adapter_spec.rb +31 -0
- data/spec/whatsapp_notifier_spec.rb +2 -0
- metadata +1 -1
|
@@ -34,7 +34,12 @@ module WhatsAppNotifier
|
|
|
34
34
|
media_size: %w[mediaSize media_size],
|
|
35
35
|
sender_name: %w[senderName sender_name],
|
|
36
36
|
to: %w[to],
|
|
37
|
-
from_me: %w[fromMe from_me]
|
|
37
|
+
from_me: %w[fromMe from_me],
|
|
38
|
+
# 0.9.3: the `<digits>@lid` privacy id the counterparty above was
|
|
39
|
+
# RESOLVED FROM, present only for a privacy-keyed chat. The phone in
|
|
40
|
+
# from/to is always a real phone — this says where it came from, so a
|
|
41
|
+
# host can audit a thread's origin. Never a value to thread on.
|
|
42
|
+
sender_lid: %w[senderLid sender_lid]
|
|
38
43
|
}.freeze
|
|
39
44
|
|
|
40
45
|
def self.default_base_url
|
|
@@ -183,6 +188,27 @@ module WhatsAppNotifier
|
|
|
183
188
|
Array(response["messages"]).map { |m| map_inbound_message(m) }
|
|
184
189
|
end
|
|
185
190
|
|
|
191
|
+
# Resolves ONE WhatsApp privacy id (`@lid`) to the phone number behind it,
|
|
192
|
+
# returning the bare digits or nil when nothing is recoverable.
|
|
193
|
+
#
|
|
194
|
+
# Hosts need this to repair conversations they keyed on an unresolved
|
|
195
|
+
# privacy id — rows written when the service still fabricated a "phone"
|
|
196
|
+
# out of the LID's own digits (fixed in 0.9.3). Live capture resolves on
|
|
197
|
+
# its own; this is the backward-looking half.
|
|
198
|
+
#
|
|
199
|
+
# nil is a real answer ("no phone behind this id"), not an error: the
|
|
200
|
+
# service replies 200 with pn: null, and only a transport/gate failure
|
|
201
|
+
# raises.
|
|
202
|
+
def resolve_lid(lid:, metadata: {})
|
|
203
|
+
user_id = user_id_from(metadata)
|
|
204
|
+
digits = lid.to_s.split("@").first.to_s.gsub(/\D/, "")
|
|
205
|
+
return nil if digits.empty?
|
|
206
|
+
|
|
207
|
+
response = request(:get, "/contacts/lid/#{user_id}?lid=#{digits}")
|
|
208
|
+
resolved = response["pn"].to_s.split("@").first.to_s.gsub(/\D/, "")
|
|
209
|
+
resolved.empty? ? nil : resolved
|
|
210
|
+
end
|
|
211
|
+
|
|
186
212
|
# Logs the user out of WhatsApp and clears their saved session on the service.
|
|
187
213
|
def logout(metadata: {})
|
|
188
214
|
user_id = user_id_from(metadata)
|
data/lib/whatsapp_notifier.rb
CHANGED
|
@@ -97,6 +97,10 @@ module WhatsAppNotifier
|
|
|
97
97
|
client.fetch_history(chat_id: chat_id, limit: limit, provider: provider, metadata: metadata)
|
|
98
98
|
end
|
|
99
99
|
|
|
100
|
+
def resolve_lid(lid:, provider: nil, metadata: {})
|
|
101
|
+
client.resolve_lid(lid: lid, provider: provider, metadata: metadata)
|
|
102
|
+
end
|
|
103
|
+
|
|
100
104
|
def logout(provider: nil, metadata: {})
|
|
101
105
|
client.logout(provider: provider, metadata: metadata)
|
|
102
106
|
end
|
data/spec/client_spec.rb
CHANGED
|
@@ -91,7 +91,7 @@ RSpec.describe WhatsAppNotifier::Client do
|
|
|
91
91
|
end
|
|
92
92
|
end
|
|
93
93
|
|
|
94
|
-
it "delegates list_chats and
|
|
94
|
+
it "delegates list_chats, fetch_history and resolve_lid to the provider" do
|
|
95
95
|
Dir.mktmpdir do |dir|
|
|
96
96
|
config.provider = :web_automation
|
|
97
97
|
config.web_automation_enabled = true
|
|
@@ -101,7 +101,8 @@ RSpec.describe WhatsAppNotifier::Client do
|
|
|
101
101
|
fetch_qr_code: "qr",
|
|
102
102
|
connection_status: { state: "AUTHENTICATED", authenticated: true },
|
|
103
103
|
list_chats: [{ id: "919@c.us", name: "Asha", last_message_at: 9 }],
|
|
104
|
-
fetch_history: [{ from: "919@c.us", body: "old", message_id: "h1" }]
|
|
104
|
+
fetch_history: [{ from: "919@c.us", body: "old", message_id: "h1" }],
|
|
105
|
+
resolve_lid: "919882536803"
|
|
105
106
|
)
|
|
106
107
|
config.web_adapter = adapter
|
|
107
108
|
client = described_class.new(configuration: config)
|
|
@@ -110,6 +111,8 @@ RSpec.describe WhatsAppNotifier::Client do
|
|
|
110
111
|
.to eq([{ id: "919@c.us", name: "Asha", last_message_at: 9 }])
|
|
111
112
|
expect(client.fetch_history(chat_id: "919@c.us", provider: :web_automation, metadata: { user_id: 1 }))
|
|
112
113
|
.to eq([{ from: "919@c.us", body: "old", message_id: "h1" }])
|
|
114
|
+
expect(client.resolve_lid(lid: "125417440686124@lid", provider: :web_automation, metadata: { user_id: 1 }))
|
|
115
|
+
.to eq("919882536803")
|
|
113
116
|
# The default page size survives the delegation chain untouched.
|
|
114
117
|
expect(adapter).to have_received(:fetch_history).with(chat_id: "919@c.us", limit: 50, metadata: { user_id: 1 })
|
|
115
118
|
end
|
|
@@ -249,11 +249,13 @@ RSpec.describe WhatsAppNotifier::Providers::WebAutomation do
|
|
|
249
249
|
adapter = double(
|
|
250
250
|
fetch_qr_code: "qr", connection_status: {},
|
|
251
251
|
list_chats: [{ id: "919@c.us", name: "Asha", last_message_at: 9 }],
|
|
252
|
-
fetch_history: [{ from: "919@c.us", body: "old", message_id: "h1" }]
|
|
252
|
+
fetch_history: [{ from: "919@c.us", body: "old", message_id: "h1" }],
|
|
253
|
+
resolve_lid: "919882536803"
|
|
253
254
|
)
|
|
254
255
|
config = build_config(path: File.join(dir, "session.json"), adapter: adapter)
|
|
255
256
|
provider = described_class.new(configuration: config)
|
|
256
257
|
|
|
258
|
+
expect(provider.resolve_lid(lid: "125417440686124@lid", metadata: { user_id: 1 })).to eq("919882536803")
|
|
257
259
|
expect(provider.list_chats(metadata: { user_id: 1 })).to eq([{ id: "919@c.us", name: "Asha", last_message_at: 9 }])
|
|
258
260
|
expect(provider.fetch_history(chat_id: "919@c.us", limit: 20, metadata: { user_id: 1 }))
|
|
259
261
|
.to eq([{ from: "919@c.us", body: "old", message_id: "h1" }])
|
|
@@ -282,6 +284,7 @@ RSpec.describe WhatsAppNotifier::Providers::WebAutomation do
|
|
|
282
284
|
|
|
283
285
|
expect { provider.list_chats }.to raise_error(WhatsAppNotifier::ConfigurationError, /disabled/)
|
|
284
286
|
expect { provider.fetch_history(chat_id: "919@c.us") }.to raise_error(WhatsAppNotifier::ConfigurationError, /disabled/)
|
|
287
|
+
expect { provider.resolve_lid(lid: "1@lid") }.to raise_error(WhatsAppNotifier::ConfigurationError, /disabled/)
|
|
285
288
|
end
|
|
286
289
|
end
|
|
287
290
|
|
|
@@ -293,6 +296,7 @@ RSpec.describe WhatsAppNotifier::Providers::WebAutomation do
|
|
|
293
296
|
|
|
294
297
|
expect { provider.list_chats }.to raise_error(WhatsAppNotifier::ConfigurationError, /chat listing/)
|
|
295
298
|
expect { provider.fetch_history(chat_id: "919@c.us") }.to raise_error(WhatsAppNotifier::ConfigurationError, /history replay/)
|
|
299
|
+
expect { provider.resolve_lid(lid: "1@lid") }.to raise_error(WhatsAppNotifier::ConfigurationError, /@lid resolution/)
|
|
296
300
|
end
|
|
297
301
|
end
|
|
298
302
|
|
data/spec/web_adapter_spec.rb
CHANGED
|
@@ -454,6 +454,37 @@ RSpec.describe WhatsAppNotifier::WebAdapter do
|
|
|
454
454
|
.to raise_error(/service request failed \(401\): User not authenticated/)
|
|
455
455
|
end
|
|
456
456
|
|
|
457
|
+
# Privacy-id resolution (0.9.3): the half a host needs to repair threads it
|
|
458
|
+
# already keyed on an unresolved @lid.
|
|
459
|
+
it "resolves a privacy id to bare phone digits" do
|
|
460
|
+
allow(ENV).to receive(:[]).and_call_original
|
|
461
|
+
allow(ENV).to receive(:[]).with("WHATSAPP_WEBHOOK_TOKEN").and_return("sekrit")
|
|
462
|
+
response = http_success(body: { "success" => true, "lid" => "125417440686124@lid", "pn" => "919882536803@c.us" })
|
|
463
|
+
captured = nil
|
|
464
|
+
http = double("http")
|
|
465
|
+
allow(http).to receive(:request) { |req| captured = req; response }
|
|
466
|
+
allow(Net::HTTP).to receive(:start) { |*_args, **_kwargs, &blk| blk.call(http) }
|
|
467
|
+
|
|
468
|
+
expect(adapter.resolve_lid(lid: "125417440686124@lid", metadata: { user_id: "u-1" }))
|
|
469
|
+
.to eq("919882536803")
|
|
470
|
+
expect(captured).to be_a(Net::HTTP::Get)
|
|
471
|
+
expect(captured.path).to eq("/contacts/lid/u-1?lid=125417440686124")
|
|
472
|
+
expect(captured["X-WA-Token"]).to eq("sekrit")
|
|
473
|
+
end
|
|
474
|
+
|
|
475
|
+
it "returns nil when the privacy id has no phone behind it" do
|
|
476
|
+
allow(Net::HTTP).to receive(:start)
|
|
477
|
+
.and_return(http_success(body: { "success" => true, "lid" => "1@lid", "pn" => nil }))
|
|
478
|
+
|
|
479
|
+
expect(adapter.resolve_lid(lid: "125417440686124", metadata: {})).to be_nil
|
|
480
|
+
end
|
|
481
|
+
|
|
482
|
+
it "does not call the service for a lid with no digits" do
|
|
483
|
+
expect(Net::HTTP).not_to receive(:start)
|
|
484
|
+
|
|
485
|
+
expect(adapter.resolve_lid(lid: "@lid", metadata: {})).to be_nil
|
|
486
|
+
end
|
|
487
|
+
|
|
457
488
|
it "fetches history with the token, posting the chat id and clamped limit" do
|
|
458
489
|
allow(ENV).to receive(:[]).and_call_original
|
|
459
490
|
allow(ENV).to receive(:[]).with("WHATSAPP_WEBHOOK_TOKEN").and_return("sekrit")
|
|
@@ -99,6 +99,7 @@ RSpec.describe WhatsAppNotifier do
|
|
|
99
99
|
allow(fake_client).to receive(:refetch_media).and_return(mime: "image/jpeg", filename: nil, size: 5, status: "available")
|
|
100
100
|
allow(fake_client).to receive(:list_chats).and_return([{ id: "919@c.us", name: "Asha", last_message_at: 9 }])
|
|
101
101
|
allow(fake_client).to receive(:fetch_history).and_return([{ from: "919@c.us", body: "old", message_id: "h1" }])
|
|
102
|
+
allow(fake_client).to receive(:resolve_lid).and_return("919882536803")
|
|
102
103
|
allow(fake_client).to receive(:logout).and_return(success: true)
|
|
103
104
|
described_class.instance_variable_set(:@client, fake_client)
|
|
104
105
|
|
|
@@ -111,6 +112,7 @@ RSpec.describe WhatsAppNotifier do
|
|
|
111
112
|
expect(described_class.refetch_media(message_id: "m1", chat_id: "919@c.us", provider: :web_automation, metadata: { user_id: 1 })).to include(status: "available")
|
|
112
113
|
expect(described_class.list_chats(provider: :web_automation, metadata: { user_id: 1 })).to eq([{ id: "919@c.us", name: "Asha", last_message_at: 9 }])
|
|
113
114
|
expect(described_class.fetch_history(chat_id: "919@c.us", limit: 20, provider: :web_automation, metadata: { user_id: 1 })).to eq([{ from: "919@c.us", body: "old", message_id: "h1" }])
|
|
115
|
+
expect(described_class.resolve_lid(lid: "125417440686124@lid", provider: :web_automation, metadata: { user_id: 1 })).to eq("919882536803")
|
|
114
116
|
expect(described_class.logout(provider: :web_automation, metadata: { user_id: 1 })).to eq(success: true)
|
|
115
117
|
expect(fake_client).to have_received(:fetch_media).with(message_id: "m1", provider: :web_automation, metadata: { user_id: 1 })
|
|
116
118
|
expect(fake_client).to have_received(:delete_media).with(message_id: "m1", provider: :web_automation, metadata: { user_id: 1 })
|