stactics 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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 10a190f7f56568230486fd936c573f32110f9cbe7eed13c8e7263cad64b06165
4
+ data.tar.gz: 17910e95c4eb977cae2978d6e67ed47850455fdb0cfb1955ae1fa9f893abd0d0
5
+ SHA512:
6
+ metadata.gz: 0dcb4e90d26597d7552de8b20573c3019c0e5af7c4ecd7c5cc4e11dfdefe365ed8329ade5a65da43cf5d05c078e2457fdd38ff7324103e74a54c9808840f82c5
7
+ data.tar.gz: 39a6570935436fd733d2377470abc9c46ede156ee52f92d1dfe6561ffd1a22ee2f22098c50f1a0b6ae8095683b4f987bc04f7fdf3e2d4e609aa3587a87ebca29
data/README.md ADDED
@@ -0,0 +1,17 @@
1
+ # Stactics Ruby SDK
2
+
3
+ Ruby client for the Stactics ingest API.
4
+
5
+ ```ruby
6
+ client = Stactics::Client.new(api_key: ENV.fetch("STACTICS_SECRET_KEY"))
7
+
8
+ client.track(
9
+ "signup",
10
+ user_id: "user_123",
11
+ email: "founder@example.com",
12
+ environment: "production",
13
+ metadata: { plan: "free" }
14
+ )
15
+ ```
16
+
17
+ Use a `sk_...` key for server-side Ruby apps.
@@ -0,0 +1,103 @@
1
+ require "json"
2
+ require "net/http"
3
+ require "uri"
4
+
5
+ module Stactics
6
+ class APIError < StandardError
7
+ attr_reader :status, :body
8
+
9
+ def initialize(status:, body:)
10
+ @status = status
11
+ @body = body
12
+ super(body.fetch("error", "Stactics API request failed"))
13
+ end
14
+ end
15
+
16
+ Result = Struct.new(:accepted?, :accepted_count, :body, keyword_init: true)
17
+
18
+ class Client
19
+ def initialize(api_key:, host: DEFAULT_HOST, timeout: 5, transport: nil)
20
+ raise ArgumentError, "api_key is required" if api_key.to_s.strip.empty?
21
+
22
+ @api_key = api_key
23
+ @host = host.to_s.delete_suffix("/")
24
+ @timeout = timeout
25
+ @transport = transport || method(:perform_request)
26
+ end
27
+
28
+ def track(event_type, attributes = {})
29
+ payload = stringify_keys(attributes).merge("event_type" => event_type.to_s)
30
+ request("/v1/events", payload)
31
+ end
32
+
33
+ def batch(events)
34
+ payload = { "events" => events.map { |event| stringify_keys(event) } }
35
+ request("/v1/events/batch", payload)
36
+ end
37
+
38
+ private
39
+
40
+ def request(path, payload)
41
+ response = @transport.call(
42
+ path: path,
43
+ payload: payload,
44
+ headers: headers,
45
+ timeout: @timeout
46
+ )
47
+ body = parse_json(response.body)
48
+ status = response.code.to_i
49
+ raise APIError.new(status: status, body: body) unless status.between?(200, 299)
50
+
51
+ Result.new(
52
+ accepted?: body.fetch("accepted", false),
53
+ accepted_count: body.fetch("accepted_count", 0),
54
+ body: body
55
+ )
56
+ end
57
+
58
+ def perform_request(path:, payload:, headers:, timeout:)
59
+ uri = URI("#{@host}#{path}")
60
+ request = Net::HTTP::Post.new(uri, headers)
61
+ request.body = JSON.generate(payload)
62
+
63
+ Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == "https", read_timeout: timeout, open_timeout: timeout) do |http|
64
+ http.request(request)
65
+ end
66
+ end
67
+
68
+ def headers
69
+ {
70
+ "Authorization" => "Bearer #{@api_key}",
71
+ "Content-Type" => "application/json",
72
+ "User-Agent" => "stactics-ruby/#{VERSION}"
73
+ }
74
+ end
75
+
76
+ def parse_json(raw_body)
77
+ JSON.parse(raw_body.to_s)
78
+ rescue JSON::ParserError
79
+ {}
80
+ end
81
+
82
+ def stringify_keys(value)
83
+ case value
84
+ when Hash
85
+ value.each_with_object({}) do |(key, nested_value), memo|
86
+ memo[camel_or_symbol_to_snake(key)] = stringify_keys(nested_value)
87
+ end
88
+ when Array
89
+ value.map { |item| stringify_keys(item) }
90
+ else
91
+ value
92
+ end
93
+ end
94
+
95
+ def camel_or_symbol_to_snake(key)
96
+ key.to_s
97
+ .gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
98
+ .gsub(/([a-z\d])([A-Z])/, '\1_\2')
99
+ .tr("-", "_")
100
+ .downcase
101
+ end
102
+ end
103
+ end
@@ -0,0 +1,3 @@
1
+ module Stactics
2
+ VERSION = "0.1.0"
3
+ end
data/lib/stactics.rb ADDED
@@ -0,0 +1,6 @@
1
+ require_relative "stactics/client"
2
+ require_relative "stactics/version"
3
+
4
+ module Stactics
5
+ DEFAULT_HOST = "https://api.stactics.io"
6
+ end
metadata ADDED
@@ -0,0 +1,47 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: stactics
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Nexu Industries
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2026-05-17 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: Track analytics events from Ruby and Rails apps with Stactics.
14
+ email:
15
+ - support@stactics.app
16
+ executables: []
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - README.md
21
+ - lib/stactics.rb
22
+ - lib/stactics/client.rb
23
+ - lib/stactics/version.rb
24
+ homepage: https://github.com/nexuindustries/stactics-sdks
25
+ licenses:
26
+ - MIT
27
+ metadata: {}
28
+ post_install_message:
29
+ rdoc_options: []
30
+ require_paths:
31
+ - lib
32
+ required_ruby_version: !ruby/object:Gem::Requirement
33
+ requirements:
34
+ - - ">="
35
+ - !ruby/object:Gem::Version
36
+ version: '3.1'
37
+ required_rubygems_version: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ version: '0'
42
+ requirements: []
43
+ rubygems_version: 3.3.26
44
+ signing_key:
45
+ specification_version: 4
46
+ summary: Ruby SDK for the Stactics ingest API
47
+ test_files: []