kwtsms 0.1.0

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.
@@ -0,0 +1,80 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "net/http"
4
+ require "uri"
5
+ require "json"
6
+ require "time"
7
+
8
+ module KwtSMS
9
+ BASE_URL = "https://www.kwtsms.com/API/"
10
+
11
+ # kwtSMS server runs at GMT+3 (Asia/Kuwait).
12
+ # unix-timestamp values in API responses are server time, not UTC.
13
+ SERVER_TIMEZONE = "Asia/Kuwait (GMT+3)"
14
+
15
+ # POST to a kwtSMS REST/JSON API endpoint.
16
+ #
17
+ # Always sets Content-Type and Accept: application/json.
18
+ # Strips password from log entry.
19
+ # Returns parsed JSON hash.
20
+ # Raises RuntimeError on network / HTTP / parse failure.
21
+ def self.api_request(endpoint, payload, log_file = "")
22
+ url = URI.parse("#{BASE_URL}#{endpoint}/")
23
+
24
+ safe_payload = payload.transform_keys(&:to_s).each_with_object({}) do |(k, v), h|
25
+ h[k] = k == "password" ? "***" : v
26
+ end
27
+
28
+ log_entry = {
29
+ "ts" => Time.now.utc.iso8601,
30
+ "endpoint" => endpoint,
31
+ "request" => safe_payload,
32
+ "response" => nil,
33
+ "ok" => false,
34
+ "error" => nil
35
+ }
36
+
37
+ begin
38
+ http = Net::HTTP.new(url.host, url.port)
39
+ http.use_ssl = true
40
+ http.open_timeout = 15
41
+ http.read_timeout = 15
42
+
43
+ request = Net::HTTP::Post.new(url.path)
44
+ request["Content-Type"] = "application/json"
45
+ request["Accept"] = "application/json"
46
+ request.body = JSON.generate(payload)
47
+
48
+ response = http.request(request)
49
+ body = response.body.to_s
50
+
51
+ begin
52
+ data = JSON.parse(body)
53
+ rescue JSON::ParserError => e
54
+ log_entry["error"] = "Invalid JSON response: #{e.message}"
55
+ write_log(log_file, log_entry)
56
+ raise RuntimeError, "Invalid JSON response: #{e.message}"
57
+ end
58
+
59
+ log_entry["response"] = data
60
+ log_entry["ok"] = data["result"] == "OK"
61
+ write_log(log_file, log_entry)
62
+
63
+ # For HTTP errors (4xx/5xx), kwtSMS returns JSON error details in the body.
64
+ # If we successfully parsed the JSON, return it like a normal response.
65
+ return data
66
+
67
+ rescue Net::OpenTimeout, Net::ReadTimeout => e
68
+ err = "Network error: connection timed out"
69
+ log_entry["error"] = err
70
+ write_log(log_file, log_entry)
71
+ raise RuntimeError, err
72
+
73
+ rescue SocketError, Errno::ECONNREFUSED, Errno::EHOSTUNREACH, IOError => e
74
+ err = "Network error: #{e.message}"
75
+ log_entry["error"] = err
76
+ write_log(log_file, log_entry)
77
+ raise RuntimeError, err
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module KwtSMS
4
+ VERSION = "0.1.0"
5
+ end
data/lib/kwtsms.rb ADDED
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ # kwtsms: Ruby client for the kwtSMS API (kwtsms.com)
4
+ #
5
+ # Quick start:
6
+ # require "kwtsms"
7
+ #
8
+ # sms = KwtSMS::Client.from_env # reads .env / env vars
9
+ # ok, balance, err = sms.verify
10
+ # result = sms.send_sms("96598765432", "Your OTP is: 123456")
11
+ # result = sms.send_sms("96598765432", "Hello", sender: "MY-APP")
12
+ # report = sms.validate(["96598765432", "+96512345678"])
13
+ # balance = sms.balance
14
+ # delivery = sms.status(result["msg-id"])
15
+ #
16
+ # Utility functions:
17
+ # KwtSMS.normalize_phone("+965 9876 5432")
18
+ # KwtSMS.validate_phone_input("user@email.com")
19
+ # KwtSMS.clean_message("Hello \u{1F600} world")
20
+
21
+ require "set"
22
+
23
+ require_relative "kwtsms/version"
24
+ require_relative "kwtsms/errors"
25
+ require_relative "kwtsms/phone"
26
+ require_relative "kwtsms/message"
27
+ require_relative "kwtsms/env_loader"
28
+ require_relative "kwtsms/logger"
29
+ require_relative "kwtsms/request"
30
+ require_relative "kwtsms/client"
metadata ADDED
@@ -0,0 +1,65 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: kwtsms
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - boxlink
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2026-03-06 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: Official Ruby client library for the kwtSMS SMS gateway. Send SMS, check
14
+ balance, validate phone numbers, check delivery status, and manage sender IDs. Zero
15
+ external dependencies.
16
+ email:
17
+ - info@boxlink.net
18
+ executables:
19
+ - kwtsms
20
+ extensions: []
21
+ extra_rdoc_files: []
22
+ files:
23
+ - CHANGELOG.md
24
+ - LICENSE
25
+ - README.md
26
+ - exe/kwtsms
27
+ - lib/kwtsms.rb
28
+ - lib/kwtsms/client.rb
29
+ - lib/kwtsms/env_loader.rb
30
+ - lib/kwtsms/errors.rb
31
+ - lib/kwtsms/logger.rb
32
+ - lib/kwtsms/message.rb
33
+ - lib/kwtsms/phone.rb
34
+ - lib/kwtsms/request.rb
35
+ - lib/kwtsms/version.rb
36
+ homepage: https://github.com/boxlinknet/kwtsms-ruby
37
+ licenses:
38
+ - MIT
39
+ metadata:
40
+ homepage_uri: https://github.com/boxlinknet/kwtsms-ruby
41
+ source_code_uri: https://github.com/boxlinknet/kwtsms-ruby
42
+ changelog_uri: https://github.com/boxlinknet/kwtsms-ruby/blob/main/CHANGELOG.md
43
+ bug_tracker_uri: https://github.com/boxlinknet/kwtsms-ruby/issues
44
+ documentation_uri: https://github.com/boxlinknet/kwtsms-ruby#readme
45
+ rubygems_mfa_required: 'true'
46
+ post_install_message:
47
+ rdoc_options: []
48
+ require_paths:
49
+ - lib
50
+ required_ruby_version: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: 2.7.0
55
+ required_rubygems_version: !ruby/object:Gem::Requirement
56
+ requirements:
57
+ - - ">="
58
+ - !ruby/object:Gem::Version
59
+ version: '0'
60
+ requirements: []
61
+ rubygems_version: 3.5.22
62
+ signing_key:
63
+ specification_version: 4
64
+ summary: Ruby client for the kwtSMS API (kwtsms.com)
65
+ test_files: []