kagi-api 0.0.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.
Files changed (39) hide show
  1. checksums.yaml +7 -0
  2. checksums.yaml.gz.sig +0 -0
  3. data/LICENSE.adoc +134 -0
  4. data/README.adoc +247 -0
  5. data/kagi-api.gemspec +37 -0
  6. data/lib/kagi/api/client.rb +33 -0
  7. data/lib/kagi/api/configuration/content.rb +12 -0
  8. data/lib/kagi/api/configuration/loader.rb +22 -0
  9. data/lib/kagi/api/container.rb +37 -0
  10. data/lib/kagi/api/contracts/error.rb +18 -0
  11. data/lib/kagi/api/contracts/fast.rb +18 -0
  12. data/lib/kagi/api/contracts/meta.rb +15 -0
  13. data/lib/kagi/api/contracts/reference.rb +14 -0
  14. data/lib/kagi/api/contracts/search.rb +27 -0
  15. data/lib/kagi/api/contracts/summary.rb +17 -0
  16. data/lib/kagi/api/dependencies.rb +9 -0
  17. data/lib/kagi/api/endpoints/container.rb +23 -0
  18. data/lib/kagi/api/endpoints/dependencies.rb +11 -0
  19. data/lib/kagi/api/endpoints/enrich/news.rb +55 -0
  20. data/lib/kagi/api/endpoints/enrich/web.rb +55 -0
  21. data/lib/kagi/api/endpoints/fast.rb +53 -0
  22. data/lib/kagi/api/endpoints/search.rb +53 -0
  23. data/lib/kagi/api/endpoints/summarize.rb +53 -0
  24. data/lib/kagi/api/models/content/error.rb +22 -0
  25. data/lib/kagi/api/models/content/fast.rb +16 -0
  26. data/lib/kagi/api/models/content/meta.rb +20 -0
  27. data/lib/kagi/api/models/content/reference.rb +12 -0
  28. data/lib/kagi/api/models/content/search.rb +35 -0
  29. data/lib/kagi/api/models/content/summary.rb +12 -0
  30. data/lib/kagi/api/models/content/thumbnail.rb +16 -0
  31. data/lib/kagi/api/models/error.rb +19 -0
  32. data/lib/kagi/api/models/fast.rb +19 -0
  33. data/lib/kagi/api/models/search.rb +19 -0
  34. data/lib/kagi/api/models/summary.rb +19 -0
  35. data/lib/kagi/api/requester.rb +31 -0
  36. data/lib/kagi/api.rb +24 -0
  37. data.tar.gz.sig +0 -0
  38. metadata +220 -0
  39. metadata.gz.sig +0 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: d75c5cc76c25528a0d8b03cdbd37b498c0e3a99f6a349b16fcca2deaf7d997d7
4
+ data.tar.gz: 8916021276b36793878675e07a17d87c0133c5205a618ccb5df44a787dbc365e
5
+ SHA512:
6
+ metadata.gz: a109a93bda6740d5ff4294c940954717a4d1b7cc143d6ecf4838ab6787b58cce7356e3851344f4fea0d6a247bdaaf492e7b4df0689e81308bb9122daf3ed5164
7
+ data.tar.gz: a986438e6e5ebc0ccefcca9d6c507c43e635d10e896fa9cf7e214114c9b74e50b4cc9ee972f56449141e42e872b9dab7bbdc5c28d7717d96e935b892bc13bdf2
checksums.yaml.gz.sig ADDED
Binary file
data/LICENSE.adoc ADDED
@@ -0,0 +1,134 @@
1
+ = Hippocratic License
2
+
3
+ Version: 2.1.0.
4
+
5
+ Purpose. The purpose of this License is for the Licensor named above to
6
+ permit the Licensee (as defined below) broad permission, if consistent
7
+ with Human Rights Laws and Human Rights Principles (as each is defined
8
+ below), to use and work with the Software (as defined below) within the
9
+ full scope of Licensor’s copyright and patent rights, if any, in the
10
+ Software, while ensuring attribution and protecting the Licensor from
11
+ liability.
12
+
13
+ Permission and Conditions. The Licensor grants permission by this
14
+ license ("License"), free of charge, to the extent of Licensor’s
15
+ rights under applicable copyright and patent law, to any person or
16
+ entity (the "Licensee") obtaining a copy of this software and
17
+ associated documentation files (the "Software"), to do everything with
18
+ the Software that would otherwise infringe (i) the Licensor’s copyright
19
+ in the Software or (ii) any patent claims to the Software that the
20
+ Licensor can license or becomes able to license, subject to all of the
21
+ following terms and conditions:
22
+
23
+ * Acceptance. This License is automatically offered to every person and
24
+ entity subject to its terms and conditions. Licensee accepts this
25
+ License and agrees to its terms and conditions by taking any action with
26
+ the Software that, absent this License, would infringe any intellectual
27
+ property right held by Licensor.
28
+ * Notice. Licensee must ensure that everyone who gets a copy of any part
29
+ of this Software from Licensee, with or without changes, also receives
30
+ the License and the above copyright notice (and if included by the
31
+ Licensor, patent, trademark and attribution notice). Licensee must cause
32
+ any modified versions of the Software to carry prominent notices stating
33
+ that Licensee changed the Software. For clarity, although Licensee is
34
+ free to create modifications of the Software and distribute only the
35
+ modified portion created by Licensee with additional or different terms,
36
+ the portion of the Software not modified must be distributed pursuant to
37
+ this License. If anyone notifies Licensee in writing that Licensee has
38
+ not complied with this Notice section, Licensee can keep this License by
39
+ taking all practical steps to comply within 30 days after the notice. If
40
+ Licensee does not do so, Licensee’s License (and all rights licensed
41
+ hereunder) shall end immediately.
42
+ * Compliance with Human Rights Principles and Human Rights Laws.
43
+ [arabic]
44
+ . Human Rights Principles.
45
+ [loweralpha]
46
+ .. Licensee is advised to consult the articles of the United Nations
47
+ Universal Declaration of Human Rights and the United Nations Global
48
+ Compact that define recognized principles of international human rights
49
+ (the "Human Rights Principles"). Licensee shall use the Software in a
50
+ manner consistent with Human Rights Principles.
51
+ .. Unless the Licensor and Licensee agree otherwise, any dispute,
52
+ controversy, or claim arising out of or relating to (i) Section 1(a)
53
+ regarding Human Rights Principles, including the breach of Section 1(a),
54
+ termination of this License for breach of the Human Rights Principles,
55
+ or invalidity of Section 1(a) or (ii) a determination of whether any Law
56
+ is consistent or in conflict with Human Rights Principles pursuant to
57
+ Section 2, below, shall be settled by arbitration in accordance with the
58
+ Hague Rules on Business and Human Rights Arbitration (the "Rules");
59
+ provided, however, that Licensee may elect not to participate in such
60
+ arbitration, in which event this License (and all rights licensed
61
+ hereunder) shall end immediately. The number of arbitrators shall be one
62
+ unless the Rules require otherwise.
63
+ +
64
+ Unless both the Licensor and Licensee agree to the contrary: (1) All
65
+ documents and information concerning the arbitration shall be public and
66
+ may be disclosed by any party; (2) The repository referred to under
67
+ Article 43 of the Rules shall make available to the public in a timely
68
+ manner all documents concerning the arbitration which are communicated
69
+ to it, including all submissions of the parties, all evidence admitted
70
+ into the record of the proceedings, all transcripts or other recordings
71
+ of hearings and all orders, decisions and awards of the arbitral
72
+ tribunal, subject only to the arbitral tribunal’s powers to take such
73
+ measures as may be necessary to safeguard the integrity of the arbitral
74
+ process pursuant to Articles 18, 33, 41 and 42 of the Rules; and (3)
75
+ Article 26(6) of the Rules shall not apply.
76
+ . Human Rights Laws. The Software shall not be used by any person or
77
+ entity for any systems, activities, or other uses that violate any Human
78
+ Rights Laws. "Human Rights Laws" means any applicable laws,
79
+ regulations, or rules (collectively, "Laws") that protect human,
80
+ civil, labor, privacy, political, environmental, security, economic, due
81
+ process, or similar rights; provided, however, that such Laws are
82
+ consistent and not in conflict with Human Rights Principles (a dispute
83
+ over the consistency or a conflict between Laws and Human Rights
84
+ Principles shall be determined by arbitration as stated above). Where
85
+ the Human Rights Laws of more than one jurisdiction are applicable or in
86
+ conflict with respect to the use of the Software, the Human Rights Laws
87
+ that are most protective of the individuals or groups harmed shall
88
+ apply.
89
+ . Indemnity. Licensee shall hold harmless and indemnify Licensor (and
90
+ any other contributor) against all losses, damages, liabilities,
91
+ deficiencies, claims, actions, judgments, settlements, interest, awards,
92
+ penalties, fines, costs, or expenses of whatever kind, including
93
+ Licensor’s reasonable attorneys’ fees, arising out of or relating to
94
+ Licensee’s use of the Software in violation of Human Rights Laws or
95
+ Human Rights Principles.
96
+ * Failure to Comply. Any failure of Licensee to act according to the
97
+ terms and conditions of this License is both a breach of the License and
98
+ an infringement of the intellectual property rights of the Licensor
99
+ (subject to exceptions under Laws, e.g., fair use). In the event of a
100
+ breach or infringement, the terms and conditions of this License may be
101
+ enforced by Licensor under the Laws of any jurisdiction to which
102
+ Licensee is subject. Licensee also agrees that the Licensor may enforce
103
+ the terms and conditions of this License against Licensee through
104
+ specific performance (or similar remedy under Laws) to the extent
105
+ permitted by Laws. For clarity, except in the event of a breach of this
106
+ License, infringement, or as otherwise stated in this License, Licensor
107
+ may not terminate this License with Licensee.
108
+ * Enforceability and Interpretation. If any term or provision of this
109
+ License is determined to be invalid, illegal, or unenforceable by a
110
+ court of competent jurisdiction, then such invalidity, illegality, or
111
+ unenforceability shall not affect any other term or provision of this
112
+ License or invalidate or render unenforceable such term or provision in
113
+ any other jurisdiction; provided, however, subject to a court
114
+ modification pursuant to the immediately following sentence, if any term
115
+ or provision of this License pertaining to Human Rights Laws or Human
116
+ Rights Principles is deemed invalid, illegal, or unenforceable against
117
+ Licensee by a court of competent jurisdiction, all rights in the
118
+ Software granted to Licensee shall be deemed null and void as between
119
+ Licensor and Licensee. Upon a determination that any term or provision
120
+ is invalid, illegal, or unenforceable, to the extent permitted by Laws,
121
+ the court may modify this License to affect the original purpose that
122
+ the Software be used in compliance with Human Rights Principles and
123
+ Human Rights Laws as closely as possible. The language in this License
124
+ shall be interpreted as to its fair meaning and not strictly for or
125
+ against any party.
126
+ * Disclaimer. TO THE FULL EXTENT ALLOWED BY LAW, THIS SOFTWARE COMES
127
+ "AS IS," WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED, AND LICENSOR AND
128
+ ANY OTHER CONTRIBUTOR SHALL NOT BE LIABLE TO ANYONE FOR ANY DAMAGES OR
129
+ OTHER LIABILITY ARISING FROM, OUT OF, OR IN CONNECTION WITH THE SOFTWARE
130
+ OR THIS LICENSE, UNDER ANY KIND OF LEGAL CLAIM.
131
+
132
+ This Hippocratic License is an link:https://ethicalsource.dev[Ethical Source license] and is offered
133
+ for use by licensors and licensees at their own risk, on an "AS IS" basis, and with no warranties
134
+ express or implied, to the maximum extent permitted by Laws.
data/README.adoc ADDED
@@ -0,0 +1,247 @@
1
+ :toc: macro
2
+ :toclevels: 5
3
+ :figure-caption!:
4
+
5
+ :data_link: link:https://alchemists.io/articles/ruby_data[Data]
6
+ :dry_monads_link: link:https://dry-rb.org/gems/dry-monads[Dry Monads]
7
+ :kagi_link: link:https://kagi.com[Kagi]
8
+
9
+ = Kagi API
10
+
11
+ A monadic API client for {kagi_link} privacy focused information. This allows you to access the full Kagi API using a fault tolerant pipeline to yield whole value objects (i.e. {data_link}) for immediate interaction within your own applications.
12
+
13
+ toc::[]
14
+
15
+ == Features
16
+
17
+ * Provides a {kagi_link} API client.
18
+ * Provides full access to the Kagi APIs.
19
+ * Provides a fault tolerant pipeline for API requests and responses.
20
+
21
+ == Requirements
22
+
23
+ . link:https://www.ruby-lang.org[Ruby].
24
+ . A {kagi_link} account with an API key.
25
+
26
+ == Setup
27
+
28
+ To install _with_ security, run:
29
+
30
+ [source,bash]
31
+ ----
32
+ # 💡 Skip this line if you already have the public certificate installed.
33
+ gem cert --add <(curl --compressed --location https://alchemists.io/gems.pem)
34
+ gem install kagi-api --trust-policy HighSecurity
35
+ ----
36
+
37
+ To install _without_ security, run:
38
+
39
+ [source,bash]
40
+ ----
41
+ gem install kagi-api
42
+ ----
43
+
44
+ You can also add the gem directly to your project:
45
+
46
+ [source,bash]
47
+ ----
48
+ bundle add kagi-api
49
+ ----
50
+
51
+ Once the gem is installed, you only need to require it:
52
+
53
+ [source,ruby]
54
+ ----
55
+ require "kagi/api"
56
+ ----
57
+
58
+ == Usage
59
+
60
+ This client provides access to multiple endpoints. Each endpoint will answer either answer a `Success` or `Failure` (as provided by {dry_monads_link}) based on result of the API call. This allows you pattern match in your own code when using each endpoint. Example:
61
+
62
+ [source,ruby]
63
+ ----
64
+ client = Kagi::API::Client.new
65
+
66
+ case client.fast query: "Ruby"
67
+ in Success(payload) then puts payload
68
+ in Failure(response) then puts response
69
+ else puts "Unknown HTTP response."
70
+ end
71
+ ----
72
+
73
+ See xref:_endpoints[Endpoints] for further details.
74
+
75
+ === Configuration
76
+
77
+ You can configure the client using a block and adjusting the `content_type`, `token`, and/or `uri` settings as desired. For example, you'd only need to supply your Kagi API token (as found via your link:https://kagi.com/settings?p=api[account settings]) to start using the client:
78
+
79
+ [source,ruby]
80
+ ----
81
+ client = Kagi::API::Client.new do |settings| settings.token = "secret" }
82
+ client.fast query: "Ruby"
83
+ ----
84
+
85
+ If you don't configure the client, then the following defaults will be used:
86
+
87
+ [source,ruby]
88
+ ----
89
+ client = Kagi::API::Client.new do |settings|
90
+ settings.content_type = "application/json"
91
+ settings.token = nil
92
+ settings.uri = "https://kagi.com/api/v0"
93
+ end
94
+ ----
95
+
96
+ === Environment
97
+
98
+ You can configure the client via the following environment variables. This is handy when you don't want to use block syntax or want fallbacks when no configuration is provided.
99
+
100
+ * `KAGI_API_CONTENT_TYPE`: Defines the HTTP `Content-Type` header. You shouldn't need to change this. Default: `"application/json"`.
101
+ * `KAGI_API_TOKEN`: Defines your personal key for API access. Default: `nil`.
102
+ * `KAGI_API_URI`: Defines the API URI. Default: `"https://kagi.com/api/v0"`.
103
+
104
+ === Endpoints
105
+
106
+ All endpoints are accessible via the client instance. Each will answer a `Success` or `Failure` result you can pattern match against. Even better, within each result, you'll get a {data_link} object you can immediately interact with. See below to learn more about each endpoint.
107
+
108
+ ==== Enrich News
109
+
110
+ Message `#enrich_news` to make API requests. Example:
111
+
112
+ [source,ruby]
113
+ ----
114
+ client = Kagi::API.new
115
+
116
+ client.enrich_news q: "Ruby programming language"
117
+
118
+ # Success(#<data Kagi::API::Models::Search meta=#<data Kagi::API::Models::Content::Meta id="<redacted>", node="us-west2", duration=577, balance=2.259763>, data=[#<data Kagi::API::Models::Content::Search type=0, rank=nil, title="The Ruby Programming Language (Ruby)", url="https://github.com/ruby/ruby", snippet="For a complete list of ways to install Ruby...", published_at=2025-05-04 09:17:12 UTC, thumbnail=nil>]>)
119
+
120
+ client.enrich_news
121
+
122
+ # Failure(#<data Kagi::API::Models::Error meta=#<data Kagi::API::Models::Content::Meta id="<redacted>", node="us-west2", duration=87, balance=2.366512>, error=[#<data Kagi::API::Models::Content::Error code=1, message="Missing q parameter", reference=nil>]>)
123
+ ----
124
+
125
+ See link:https://help.kagi.com/kagi/api/enrich.html[Kagi API Documentation] for further details.
126
+
127
+ ==== Enrich Web
128
+
129
+ Message `#enrich_web` to make API requests. Example:
130
+
131
+ [source,ruby]
132
+ ----
133
+ client = Kagi::API.new
134
+
135
+ client.enrich_web q: "Ruby programming language"
136
+
137
+ # Success(#<data Kagi::API::Models::Search meta=#<data Kagi::API::Models::Content::Meta id="<redacted>", node="us-west2", duration=451, balance=2.257763>, data=[#<data Kagi::API::Models::Content::Search type=0, rank=nil, title="Ruby Programming Language", url="https://www.ruby-lang.org/en/", snippet="There is a vulnerability about Command Injection in RDoc which is bundled in Ruby. There is an XML round-trip vulnerability in REXML gem bundled with Ruby. And there is also an unintentional file creation vulnerability in tempfile library bundled with Ruby on Windows, because it uses tmpdir internally.", published_at=nil, thumbnail=nil>]>)
138
+
139
+ client.enrich_web
140
+
141
+ # Failure(#<data Kagi::API::Models::Error meta=#<data Kagi::API::Models::Content::Meta id="<redacted>", node="us-west2", duration=27, balance=2.362512>, error=[#<data Kagi::API::Models::Content::Error code=1, message="Missing q parameter", reference=nil>]>)
142
+ ----
143
+
144
+ See link:https://help.kagi.com/kagi/api/enrich.html[Kagi API Documentation] for further details.
145
+
146
+ ==== Fast
147
+
148
+ Message `#fast` to make API requests. Example:
149
+
150
+ [source,ruby]
151
+ ----
152
+ client = Kagi::API.new
153
+
154
+ client.fast query: "Ruby"
155
+
156
+ # Success(#<data Kagi::API::Models::Fast meta=#<data Kagi::API::Models::Content::Meta id="<redacted>", node="us-west2", duration=2915, balance=2.362512>, data=#<data Kagi::API::Models::Content::Fast output="Ruby is a dynamic, open-source programming language that focuses on simplicity and productivity. It has an elegant syntax that is natural to read and easy to write. Ruby supports multiple programming paradigms, including functional, object-oriented, and imperative. It is also known for its flexible nature, allowing developers to easily modify its parts. ", tokens=1172, references=[]>>)
157
+
158
+ client.fast
159
+
160
+ # Failure(#<data Kagi::API::Models::Error meta=#<data Kagi::API::Models::Content::Meta id="<redacted>", node="us-west2", duration=26, balance=2.347512>, error=[#<data Kagi::API::Models::Content::Error code=1, message="Parameter \"query\" is required and must not be empty", reference=nil>]>)
161
+ ----
162
+
163
+ See link:https://help.kagi.com/kagi/api/fastgpt.html[Kagi API Documentation] for further details.
164
+
165
+ ==== Search
166
+
167
+ Message `#search` to make API requests. Example:
168
+
169
+ [source,ruby]
170
+ ----
171
+ client = Kagi::API.new
172
+
173
+ client.search q: "Ruby"
174
+
175
+ # Success(#<data Kagi::API::Models::Search meta=#<data Kagi::API::Models::Content::Meta id="<redacted>", node="us-west2", duration=1225, balance=2.322512>, data=[#<data Kagi::API::Models::Content::Search type=0, rank=nil, title="Ruby Programming Language", url="https://www.ruby-lang.org/en/", snippet="A dynamic, open source programming language with a focus on simplicity and productivity. It has an elegant syntax that is natural to read and easy to write.", published_at=nil, thumbnail=nil>]>)
176
+
177
+ client.search
178
+
179
+ # Failure(#<data Kagi::API::Models::Error meta=#<data Kagi::API::Models::Content::Meta id="<redacted>", node="us-west2", duration=27, balance=2.322512>, error=[#<data Kagi::API::Models::Content::Error code=1, message="Missing q parameter", reference=nil>]>)
180
+ ----
181
+
182
+ See link:https://help.kagi.com/kagi/api/search.html[Kagi API Documentation] for further details.
183
+
184
+ ==== Summarize
185
+
186
+ Message `#summarize` to make API requests. Example:
187
+
188
+ [source,ruby]
189
+ ----
190
+ client = Kagi::API.new
191
+
192
+ client.summarize url: "https://www.ruby-lang.org/en", summary_type: "summary"
193
+
194
+ # Success(#<data Kagi::API::Models::Summary meta=#<data Kagi::API::Models::Content::Meta id="<redacted>", node="us-west2", duration=3828, balance=2.261763>, data=#<data Kagi::API::Models::Content::Summary output="The Ruby Programming Language is a dynamic, open-source language designed for simplicity and productivity, featuring an elegant syntax that is easy to read and write. It is well-known for its straightforward \"Hello World!\" program, which requires minimal syntax. The Ruby community actively shares updates, including recent releases such as Ruby 3.5.0-preview1, Ruby 3.4.3, and Ruby 3.3.8, along with security advisories highlighting vulnerabilities like CVE-2025-43857 related to the net-imap gem. \n\nUsers can easily get started with Ruby through resources like \"Try Ruby!\" and \"Ruby in Twenty Minutes.\" The website offers extensive documentation, libraries, and success stories, encouraging participation in a vibrant community through mailing lists, user groups, and issue tracking. Ruby's commitment to user engagement is evident through various community platforms where developers can collaborate and share knowledge. The site also provides multilingual support, making Ruby accessible to a global audience.", tokens=2025>>)
195
+
196
+ client.summarize
197
+
198
+ # Failure(#<data Kagi::API::Models::Error meta=#<data Kagi::API::Models::Content::Meta id="<redacted>", node="us-west2", duration=114, balance=2.322512>, error=[#<data Kagi::API::Models::Content::Error code=200, message="We are sorry, this input is not supported. (Invalid Input)", reference=nil>]>)
199
+ ----
200
+
201
+ See link:https://help.kagi.com/kagi/api/summarizer.html[Kagi API Documentation] for further details.
202
+
203
+ == Development
204
+
205
+ To contribute, run:
206
+
207
+ [source,bash]
208
+ ----
209
+ git clone https://github.com/bkuhlmann/kagi-api
210
+ cd kagi-api
211
+ bin/setup
212
+ ----
213
+
214
+ You can also use the IRB console for direct access to all objects:
215
+
216
+ [source,bash]
217
+ ----
218
+ bin/console
219
+ ----
220
+
221
+ == Tests
222
+
223
+ To test, run:
224
+
225
+ [source,bash]
226
+ ----
227
+ bin/rake
228
+ ----
229
+
230
+ == link:https://alchemists.io/policies/license[License]
231
+
232
+ == link:https://alchemists.io/policies/security[Security]
233
+
234
+ == link:https://alchemists.io/policies/code_of_conduct[Code of Conduct]
235
+
236
+ == link:https://alchemists.io/policies/contributions[Contributions]
237
+
238
+ == link:https://alchemists.io/policies/developer_certificate_of_origin[Developer Certificate of Origin]
239
+
240
+ == link:https://alchemists.io/projects/kagi-api/versions[Versions]
241
+
242
+ == link:https://alchemists.io/community[Community]
243
+
244
+ == Credits
245
+
246
+ * Built with link:https://alchemists.io/projects/gemsmith[Gemsmith].
247
+ * Engineered by link:https://alchemists.io/team/brooke_kuhlmann[Brooke Kuhlmann].
data/kagi-api.gemspec ADDED
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ Gem::Specification.new do |spec|
4
+ spec.name = "kagi-api"
5
+ spec.version = "0.0.0"
6
+ spec.authors = ["Brooke Kuhlmann"]
7
+ spec.email = ["brooke@alchemists.io"]
8
+ spec.homepage = "https://alchemists.io/projects/kagi-api"
9
+ spec.summary = "A Kagi API client for privacy focused information."
10
+ spec.license = "Hippocratic-2.1"
11
+
12
+ spec.metadata = {
13
+ "bug_tracker_uri" => "https://github.com/bkuhlmann/kagi-api/issues",
14
+ "changelog_uri" => "https://alchemists.io/projects/kagi-api/versions",
15
+ "homepage_uri" => "https://alchemists.io/projects/kagi-api",
16
+ "funding_uri" => "https://github.com/sponsors/bkuhlmann",
17
+ "label" => "Kagi API",
18
+ "rubygems_mfa_required" => "true",
19
+ "source_code_uri" => "https://github.com/bkuhlmann/kagi-api"
20
+ }
21
+
22
+ spec.signing_key = Gem.default_key_path
23
+ spec.cert_chain = [Gem.default_cert_path]
24
+
25
+ spec.required_ruby_version = "~> 3.4"
26
+ spec.add_dependency "cogger", "~> 1.2"
27
+ spec.add_dependency "containable", "~> 1.2"
28
+ spec.add_dependency "dry-monads", "~> 1.8"
29
+ spec.add_dependency "http", "~> 5.2"
30
+ spec.add_dependency "infusible", "~> 4.3"
31
+ spec.add_dependency "initable", "~> 0.4"
32
+ spec.add_dependency "pipeable", "~> 1.3"
33
+ spec.add_dependency "zeitwerk", "~> 2.7"
34
+
35
+ spec.extra_rdoc_files = Dir["README*", "LICENSE*"]
36
+ spec.files = Dir["*.gemspec", "lib/**/*"]
37
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kagi
4
+ module API
5
+ # Provides the primary client for making API requests.
6
+ class Client
7
+ include Dependencies[:settings]
8
+
9
+ include Endpoints::Dependencies[
10
+ endpoint_enrich_news: "enrich.news",
11
+ endpoint_enrich_web: "enrich.web",
12
+ endpoint_fast: :fast,
13
+ endpoint_search: :search,
14
+ endpoint_summarize: :summarize
15
+ ]
16
+
17
+ def initialize(**)
18
+ super
19
+ yield settings if block_given?
20
+ end
21
+
22
+ def enrich_news(**) = endpoint_enrich_news.call(**)
23
+
24
+ def enrich_web(**) = endpoint_enrich_web.call(**)
25
+
26
+ def fast(**) = endpoint_fast.call(**)
27
+
28
+ def search(**) = endpoint_search.call(**)
29
+
30
+ def summarize(**) = endpoint_summarize.call(**)
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kagi
4
+ module API
5
+ module Configuration
6
+ # Defines customizable API configuration content.
7
+ Content = Struct.new :content_type, :token, :uri do
8
+ def headers = {"Content-Type" => content_type}.compact
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "initable"
4
+
5
+ module Kagi
6
+ module API
7
+ module Configuration
8
+ # Loads configuration based on environment or falls back to defaults.
9
+ class Loader
10
+ include Initable[model: Content, environment: ENV]
11
+
12
+ def call
13
+ model[
14
+ content_type: environment.fetch("KAGI_API_CONTENT_TYPE", "application/json"),
15
+ token: environment["KAGI_API_TOKEN"],
16
+ uri: environment.fetch("KAGI_API_URI", "https://kagi.com/api/v0")
17
+ ]
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "cogger"
4
+ require "containable"
5
+ require "http"
6
+
7
+ module Kagi
8
+ module API
9
+ # Registers application dependencies.
10
+ module Container
11
+ extend Containable
12
+
13
+ register(:settings) { Configuration::Loader.new.call }
14
+ register(:requester) { Requester.new }
15
+ register(:logger) { Cogger.new id: "kagi-api", formatter: :json }
16
+
17
+ register :http do
18
+ HTTP.default_options = HTTP::Options.new features: {logging: {logger: self[:logger]}}
19
+ HTTP
20
+ end
21
+
22
+ namespace :contracts do
23
+ register :error, Contracts::Error
24
+ register :fast, Contracts::Fast
25
+ register :search, Contracts::Search
26
+ register :summary, Contracts::Summary
27
+ end
28
+
29
+ namespace :models do
30
+ register :error, Models::Error
31
+ register :fast, Models::Fast
32
+ register :search, Models::Search
33
+ register :summary, Models::Summary
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kagi
4
+ module API
5
+ module Contracts
6
+ # Validates error data.
7
+ Error = Dry::Schema.JSON do
8
+ required(:meta).hash Meta
9
+
10
+ required(:error).array(:hash) do
11
+ required(:code).filled :integer
12
+ required(:msg).filled :string
13
+ required(:ref).maybe :string
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kagi
4
+ module API
5
+ module Contracts
6
+ # Validates Fast GPT data.
7
+ Fast = Dry::Schema.JSON do
8
+ required(:meta).hash Meta
9
+
10
+ required(:data).hash do
11
+ required(:output).filled :string
12
+ required(:tokens).filled :integer
13
+ required(:references).array(Reference)
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kagi
4
+ module API
5
+ module Contracts
6
+ # Validates meta data.
7
+ Meta = Dry::Schema.JSON do
8
+ required(:id).filled :string
9
+ required(:node).filled :string
10
+ required(:ms).filled :integer
11
+ optional(:api_balance) { filled? > int? | float? }
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kagi
4
+ module API
5
+ module Contracts
6
+ # Validates reference data.
7
+ Reference = Dry::Schema.JSON do
8
+ required(:title).filled :string
9
+ required(:snippet).filled :string
10
+ required(:url).filled :string
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kagi
4
+ module API
5
+ module Contracts
6
+ # Validates search data.
7
+ Search = Dry::Schema.JSON do
8
+ required(:meta).hash Meta
9
+
10
+ required(:data).array(:hash) do
11
+ required(:t).filled :integer
12
+ optional(:rank).filled :integer
13
+ optional(:url).filled :string
14
+ optional(:title).filled :string
15
+ optional(:snippet).maybe :string
16
+ optional(:published).filled :time
17
+
18
+ optional(:thumbnail).hash do
19
+ required(:url).filled :string
20
+ optional(:width).filled :integer
21
+ optional(:height).filled :integer
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kagi
4
+ module API
5
+ module Contracts
6
+ # Validates summary data.
7
+ Summary = Dry::Schema.JSON do
8
+ required(:meta).hash Meta
9
+
10
+ required(:data).hash do
11
+ required(:output).filled :string
12
+ required(:tokens).filled :integer
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "infusible"
4
+
5
+ module Kagi
6
+ module API
7
+ Dependencies = Infusible[Container]
8
+ end
9
+ end