og_pilot_ruby 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 +7 -0
- data/LICENSE +21 -0
- data/README.md +94 -0
- data/lib/generators/og_pilot_ruby/install/USAGE +8 -0
- data/lib/generators/og_pilot_ruby/install/install_generator.rb +18 -0
- data/lib/generators/og_pilot_ruby/install/templates/initializer.rb +11 -0
- data/lib/og_pilot_ruby/client.rb +100 -0
- data/lib/og_pilot_ruby/configuration.rb +18 -0
- data/lib/og_pilot_ruby/errors.rb +7 -0
- data/lib/og_pilot_ruby/jwt_encoder.rb +13 -0
- data/lib/og_pilot_ruby/rails_helper.rb +9 -0
- data/lib/og_pilot_ruby/railtie.rb +14 -0
- data/lib/og_pilot_ruby/version.rb +5 -0
- data/lib/og_pilot_ruby.rb +37 -0
- metadata +102 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 54a99ba0e0f98aac023dc3e51ab7bb61602a4fb67e25867c1dd8401d7ddda8ed
|
|
4
|
+
data.tar.gz: ff0a2d846acd2ab806df0722e69faadaef51199aa299213c07776eeb444b4db7
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: edb9ac50dd687e1420b2adf4cb9e6ab4207ebd2772e57adfae8727d4e1e945f838f7ba2c7f848b4450e368d86c0bdd31134e8d9da2f0977b24b37a904d571626
|
|
7
|
+
data.tar.gz: '09bad37e9324e6ef35c618feb139c2f88c8f9b877631257db008b6a8c60adf0c22de29e19f9afe20701622743905143ef56ff3f38b028f57b8390ceb84b0ad70'
|
data/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Sunergos IT LLC
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# OG Pilot Ruby
|
|
2
|
+
|
|
3
|
+
A small Ruby client for generating OG Pilot Open Graph images via signed JWTs.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
Add to your Gemfile:
|
|
8
|
+
|
|
9
|
+
```ruby
|
|
10
|
+
gem "og_pilot_ruby"
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Then install:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
bundle install
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Configuration
|
|
20
|
+
|
|
21
|
+
The default initializer reads from `OG_PILOT_API_KEY` and `OG_PILOT_DOMAIN` automatically.
|
|
22
|
+
Override as needed:
|
|
23
|
+
|
|
24
|
+
```ruby
|
|
25
|
+
OgPilotRuby.configure do |config|
|
|
26
|
+
config.api_key = ENV.fetch("OG_PILOT_API_KEY")
|
|
27
|
+
config.domain = ENV.fetch("OG_PILOT_DOMAIN")
|
|
28
|
+
end
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
For Rails, drop the snippet above into `config/initializers/og_pilot_ruby.rb`.
|
|
32
|
+
You can also generate it with:
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
bin/rails og_pilot_ruby:install
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Usage
|
|
39
|
+
|
|
40
|
+
Generate an image URL (follows the redirect returned by OG Pilot). In Rails, you can skip the `require`:
|
|
41
|
+
|
|
42
|
+
```ruby
|
|
43
|
+
require "og_pilot_ruby"
|
|
44
|
+
|
|
45
|
+
image_url = OgPilotRuby.create_image(
|
|
46
|
+
template: "blog_post",
|
|
47
|
+
title: "How to Build Amazing OG Images",
|
|
48
|
+
description: "A complete guide to social media previews",
|
|
49
|
+
bg_color: "#1a1a1a",
|
|
50
|
+
text_color: "#ffffff",
|
|
51
|
+
author_name: "Jane Smith",
|
|
52
|
+
publish_date: "2024-01-15",
|
|
53
|
+
iat: Time.now.to_i
|
|
54
|
+
)
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
If you omit `iat`, OG Pilot will cache the image indefinitely. Provide an `iat` to
|
|
58
|
+
refresh the cache daily.
|
|
59
|
+
|
|
60
|
+
Fetch JSON metadata instead:
|
|
61
|
+
|
|
62
|
+
```ruby
|
|
63
|
+
payload = {
|
|
64
|
+
template: "page",
|
|
65
|
+
title: "Hello OG Pilot"
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
data = OgPilotRuby.create_image(**payload, json: true)
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Development
|
|
72
|
+
|
|
73
|
+
Run tests with:
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
bundle exec rake test
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### Releases
|
|
80
|
+
|
|
81
|
+
This repo uses `gem-release` to bump versions and tag releases:
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
bundle exec gem bump --version patch
|
|
85
|
+
bundle exec gem bump --version minor
|
|
86
|
+
bundle exec gem bump --version major
|
|
87
|
+
bundle exec gem bump --version 1.2.3
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Then publish:
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
bundle exec rake release
|
|
94
|
+
```
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "rails/generators"
|
|
4
|
+
|
|
5
|
+
module OgPilotRuby
|
|
6
|
+
module Generators
|
|
7
|
+
class InstallGenerator < Rails::Generators::Base
|
|
8
|
+
source_root File.expand_path("templates", __dir__)
|
|
9
|
+
|
|
10
|
+
desc "Creates an OG Pilot initializer\n" \
|
|
11
|
+
"Usage: rails g og_pilot_ruby:install"
|
|
12
|
+
|
|
13
|
+
def copy_initializer
|
|
14
|
+
template "initializer.rb", "config/initializers/og_pilot_ruby.rb"
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
OgPilotRuby.configure do |config|
|
|
4
|
+
# Defaults read from ENV:
|
|
5
|
+
# config.api_key = ENV.fetch("OG_PILOT_API_KEY", nil)
|
|
6
|
+
# config.domain = ENV.fetch("OG_PILOT_DOMAIN", nil)
|
|
7
|
+
|
|
8
|
+
# Optional overrides:
|
|
9
|
+
# config.open_timeout = 5
|
|
10
|
+
# config.read_timeout = 10
|
|
11
|
+
end
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "json"
|
|
4
|
+
require "net/http"
|
|
5
|
+
require "uri"
|
|
6
|
+
|
|
7
|
+
require_relative "errors"
|
|
8
|
+
require_relative "jwt_encoder"
|
|
9
|
+
|
|
10
|
+
module OgPilotRuby
|
|
11
|
+
class Client
|
|
12
|
+
ENDPOINT_PATH = "/api/v1/images"
|
|
13
|
+
|
|
14
|
+
def initialize(config)
|
|
15
|
+
@config = config
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def create_image(params = {}, json: false, iat: nil, headers: {})
|
|
19
|
+
uri = build_uri(params, iat:)
|
|
20
|
+
response = request(uri, json:, headers:)
|
|
21
|
+
|
|
22
|
+
if json
|
|
23
|
+
JSON.parse(response.body)
|
|
24
|
+
else
|
|
25
|
+
response["Location"] || uri.to_s
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
private
|
|
30
|
+
|
|
31
|
+
attr_reader :config
|
|
32
|
+
|
|
33
|
+
def request(uri, json:, headers:)
|
|
34
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
|
35
|
+
http.use_ssl = uri.scheme == "https"
|
|
36
|
+
http.open_timeout = config.open_timeout if config.open_timeout
|
|
37
|
+
http.read_timeout = config.read_timeout if config.read_timeout
|
|
38
|
+
|
|
39
|
+
request = Net::HTTP::Get.new(uri)
|
|
40
|
+
request["Accept"] = "application/json" if json
|
|
41
|
+
headers.each { |key, value| request[key] = value }
|
|
42
|
+
|
|
43
|
+
response = http.request(request)
|
|
44
|
+
return response unless response.is_a?(Net::HTTPClientError) || response.is_a?(Net::HTTPServerError)
|
|
45
|
+
|
|
46
|
+
raise OgPilotRuby::RequestError, "OG Pilot request failed with status #{response.code}: #{response.body}"
|
|
47
|
+
rescue OpenSSL::SSL::SSLError => e
|
|
48
|
+
raise OgPilotRuby::RequestError, "OG Pilot request failed with SSL error: #{e.message}"
|
|
49
|
+
rescue Net::OpenTimeout => e
|
|
50
|
+
raise OgPilotRuby::RequestError, "OG Pilot request timed out: #{e.message}"
|
|
51
|
+
rescue Net::ReadTimeout => e
|
|
52
|
+
raise OgPilotRuby::RequestError, "OG Pilot request timed out: #{e.message}"
|
|
53
|
+
rescue Net::HTTPBadRequest => e
|
|
54
|
+
raise OgPilotRuby::RequestError, "OG Pilot request failed with bad request: #{e.message}"
|
|
55
|
+
rescue Net::HTTPUnauthorized => e
|
|
56
|
+
raise OgPilotRuby::RequestError, "OG Pilot request failed with unauthorized: #{e.message}"
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def build_uri(params, iat:)
|
|
60
|
+
payload = build_payload(params, iat:)
|
|
61
|
+
token = OgPilotRuby::JwtEncoder.encode(payload, api_key!)
|
|
62
|
+
uri = URI.join(config.base_url, ENDPOINT_PATH)
|
|
63
|
+
uri.query = URI.encode_www_form(token: token)
|
|
64
|
+
uri
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def build_payload(params, iat:)
|
|
68
|
+
symbolized = params.transform_keys(&:to_sym)
|
|
69
|
+
|
|
70
|
+
symbolized[:iat] = iat.to_i if iat
|
|
71
|
+
symbolized[:iss] ||= domain!
|
|
72
|
+
symbolized[:sub] ||= api_key_prefix
|
|
73
|
+
|
|
74
|
+
validate_payload!(symbolized)
|
|
75
|
+
symbolized
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def validate_payload!(payload)
|
|
79
|
+
raise OgPilotRuby::ConfigurationError, "OG Pilot domain is missing" if payload[:iss].nil? || payload[:iss].empty?
|
|
80
|
+
raise OgPilotRuby::ConfigurationError, "OG Pilot API key prefix is missing" if payload[:sub].nil? || payload[:sub].empty?
|
|
81
|
+
raise ArgumentError, "OG Pilot title is required" if payload[:title].nil? || payload[:title].empty?
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def api_key!
|
|
85
|
+
return config.api_key if config.api_key
|
|
86
|
+
|
|
87
|
+
raise OgPilotRuby::ConfigurationError, "OG Pilot API key is missing"
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def domain!
|
|
91
|
+
return config.domain if config.domain
|
|
92
|
+
|
|
93
|
+
raise OgPilotRuby::ConfigurationError, "OG Pilot domain is missing"
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def api_key_prefix
|
|
97
|
+
api_key!.slice(0, 8)
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module OgPilotRuby
|
|
4
|
+
class Configuration
|
|
5
|
+
DEFAULT_BASE_URL = "https://ogpilot.com"
|
|
6
|
+
private_constant :DEFAULT_BASE_URL
|
|
7
|
+
|
|
8
|
+
attr_accessor :api_key, :domain, :base_url, :open_timeout, :read_timeout
|
|
9
|
+
|
|
10
|
+
def initialize
|
|
11
|
+
@api_key = ENV.fetch("OG_PILOT_API_KEY", nil)
|
|
12
|
+
@domain = ENV.fetch("OG_PILOT_DOMAIN", nil)
|
|
13
|
+
@base_url = DEFAULT_BASE_URL
|
|
14
|
+
@open_timeout = 5
|
|
15
|
+
@read_timeout = 10
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
if defined?(Rails::Railtie)
|
|
4
|
+
module OgPilotRuby
|
|
5
|
+
# Rails integration for OG Pilot Ruby
|
|
6
|
+
class Railtie < Rails::Railtie
|
|
7
|
+
initializer 'og_pilot_ruby.inflections' do
|
|
8
|
+
ActiveSupport::Inflector.inflections(:en) do |inflect|
|
|
9
|
+
inflect.acronym 'OgPilotRuby'
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "zeitwerk"
|
|
4
|
+
|
|
5
|
+
loader = Zeitwerk::Loader.for_gem
|
|
6
|
+
loader.ignore("#{__dir__}/generators")
|
|
7
|
+
loader.ignore("#{__dir__}/og_pilot_ruby/railtie.rb")
|
|
8
|
+
loader.setup
|
|
9
|
+
|
|
10
|
+
module OgPilotRuby
|
|
11
|
+
class << self
|
|
12
|
+
def config
|
|
13
|
+
@config ||= Configuration.new
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def configure
|
|
17
|
+
yield config
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def reset_config!
|
|
21
|
+
@config = Configuration.new
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def client
|
|
25
|
+
Client.new(config)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def create_image(params = {}, json: false, iat: nil, headers: {}, **keyword_params)
|
|
29
|
+
params ||= {}
|
|
30
|
+
client.create_image(params.merge(keyword_params), json:, iat:, headers:)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
if defined?(Rails::Railtie)
|
|
36
|
+
require "og_pilot_ruby/railtie"
|
|
37
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: og_pilot_ruby
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Sunergos IT LLC
|
|
8
|
+
- Raul Popadineti
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: jwt
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - "~>"
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '3.1'
|
|
20
|
+
type: :runtime
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - "~>"
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: '3.1'
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: zeitwerk
|
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - "~>"
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: '2'
|
|
34
|
+
type: :runtime
|
|
35
|
+
prerelease: false
|
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
+
requirements:
|
|
38
|
+
- - "~>"
|
|
39
|
+
- !ruby/object:Gem::Version
|
|
40
|
+
version: '2'
|
|
41
|
+
- !ruby/object:Gem::Dependency
|
|
42
|
+
name: gem-release
|
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
|
44
|
+
requirements:
|
|
45
|
+
- - "~>"
|
|
46
|
+
- !ruby/object:Gem::Version
|
|
47
|
+
version: '2.2'
|
|
48
|
+
type: :development
|
|
49
|
+
prerelease: false
|
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
51
|
+
requirements:
|
|
52
|
+
- - "~>"
|
|
53
|
+
- !ruby/object:Gem::Version
|
|
54
|
+
version: '2.2'
|
|
55
|
+
description: Generate OG Pilot image URLs or JSON metadata using signed JWTs.
|
|
56
|
+
email:
|
|
57
|
+
- office@sunergos.ro
|
|
58
|
+
- raul@sunergos.ro
|
|
59
|
+
executables: []
|
|
60
|
+
extensions: []
|
|
61
|
+
extra_rdoc_files: []
|
|
62
|
+
files:
|
|
63
|
+
- LICENSE
|
|
64
|
+
- README.md
|
|
65
|
+
- lib/generators/og_pilot_ruby/install/USAGE
|
|
66
|
+
- lib/generators/og_pilot_ruby/install/install_generator.rb
|
|
67
|
+
- lib/generators/og_pilot_ruby/install/templates/initializer.rb
|
|
68
|
+
- lib/og_pilot_ruby.rb
|
|
69
|
+
- lib/og_pilot_ruby/client.rb
|
|
70
|
+
- lib/og_pilot_ruby/configuration.rb
|
|
71
|
+
- lib/og_pilot_ruby/errors.rb
|
|
72
|
+
- lib/og_pilot_ruby/jwt_encoder.rb
|
|
73
|
+
- lib/og_pilot_ruby/rails_helper.rb
|
|
74
|
+
- lib/og_pilot_ruby/railtie.rb
|
|
75
|
+
- lib/og_pilot_ruby/version.rb
|
|
76
|
+
homepage: https://ogpilot.com
|
|
77
|
+
licenses:
|
|
78
|
+
- MIT
|
|
79
|
+
metadata:
|
|
80
|
+
homepage_uri: https://ogpilot.com
|
|
81
|
+
source_code_uri: https://github.com/sunergos-ro/og_pilot_ruby
|
|
82
|
+
changelog_uri: https://github.com/sunergos-ro/og_pilot_ruby/commits/main
|
|
83
|
+
documentation_uri: https://ogpilot.com/docs
|
|
84
|
+
bug_tracker_uri: https://github.com/sunergos-ro/og_pilot_ruby/issues
|
|
85
|
+
rdoc_options: []
|
|
86
|
+
require_paths:
|
|
87
|
+
- lib
|
|
88
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
89
|
+
requirements:
|
|
90
|
+
- - ">="
|
|
91
|
+
- !ruby/object:Gem::Version
|
|
92
|
+
version: 3.2.0
|
|
93
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
94
|
+
requirements:
|
|
95
|
+
- - ">="
|
|
96
|
+
- !ruby/object:Gem::Version
|
|
97
|
+
version: '0'
|
|
98
|
+
requirements: []
|
|
99
|
+
rubygems_version: 3.6.7
|
|
100
|
+
specification_version: 4
|
|
101
|
+
summary: Ruby client for the OG Pilot Open Graph image generator.
|
|
102
|
+
test_files: []
|