shadwire 0.2.0 → 0.2.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1cdc0f4830063d6e21c79acbe20a20d3b81862ff346a3af2fff6888af18ba8c2
4
- data.tar.gz: a455411bae400e6e0a99f4ad693988add8b95945abf15081321631f5922e3124
3
+ metadata.gz: c857670a096593c58b47a25ad03b9c1613dd4386f54a7cc4f4ae84100960c7ff
4
+ data.tar.gz: 06b367750966cbcbaf8a26eabb229fdb80211a7379980b12ae71b7251d8cb7f2
5
5
  SHA512:
6
- metadata.gz: 4ae1610e1fc2382eba1787a94ba27be6efaed66ed8535bbd72a64a09b82aa79df01271ad9186330e9fbefebe3487f84f447f662472bab4292de552d43e950b76
7
- data.tar.gz: a10682b3ba15a5e955b0952967b5af2695d040b5f71d08f4dad3d9f9c70bb8f43b146a783081fe1e843646011a66ef8edf35821eab39ccb3a28ca270fb2fa01d
6
+ metadata.gz: 617cdd3e2b46c0cf2dd757e77eafe0a797144be2f18b7b85a96c40a94641d4dbfc575b4c905e058487f2ffd2d0dbb0c9f46a0a5f2737a1ee764db488305850b9
7
+ data.tar.gz: 62919522fee319ecc4706dc2e6b9ea4ab5b70b56d3bd5a7a41c005e2ae34a4004c3fd7cc44a0cee95b3f76f4108e5694e444e8157d34fa02ca99d4343fca9828
data/README.md CHANGED
@@ -78,7 +78,7 @@ files install (aliases), the Tailwind entrypoint, and what is installed:
78
78
 
79
79
  ```json
80
80
  {
81
- "registry": "https://edumoraes.github.io/shadwire/r",
81
+ "registry": "https://shadwire.edumoraes.dev.br/r",
82
82
  "tailwind": { "css": "app/assets/tailwind/application.css" },
83
83
  "aliases": {
84
84
  "components": "app/components",
@@ -104,7 +104,7 @@ For any command, the registry base URL is resolved in this order:
104
104
 
105
105
  1. the `--registry` flag, if given;
106
106
  2. the `registry` field in the app's `shadwire.json`;
107
- 3. the built-in default, `https://edumoraes.github.io/shadwire/r`.
107
+ 3. the built-in default, `https://shadwire.edumoraes.dev.br/r`.
108
108
 
109
109
  Both `https://` and local `file://` bases are supported. Point `--registry` at a
110
110
  `file://` path to install from a registry built locally with `bin/build_registry`
@@ -82,7 +82,12 @@ module Shadwire
82
82
  return if snippets.empty?
83
83
 
84
84
  @ui.say("Usage:")
85
- snippets.each { |snippet| @ui.say(snippet.lines.map { |line| " #{line}" }.join.chomp) }
85
+ # Blank line between snippets: items that document several recipes
86
+ # (date-picker) would otherwise print as one wall of ERB.
87
+ snippets.each_with_index do |snippet, index|
88
+ @ui.say("") unless index.zero?
89
+ @ui.say(snippet.lines.map { |line| " #{line}" }.join.chomp)
90
+ end
86
91
  end
87
92
 
88
93
  def section(label, values)
@@ -9,7 +9,7 @@ module Shadwire
9
9
  # On-disk JSON shape (mirrors shadcn's components.json conventions):
10
10
  #
11
11
  # {
12
- # "registry": "https://edumoraes.github.io/shadwire/r",
12
+ # "registry": "https://shadwire.edumoraes.dev.br/r",
13
13
  # "tailwind": { "css": "app/assets/tailwind/application.css" },
14
14
  # "aliases": {
15
15
  # "components": "app/components",
@@ -26,7 +26,7 @@ module Shadwire
26
26
  CONFIG_FILE = "shadwire.json"
27
27
 
28
28
  DEFAULTS = {
29
- "registry" => "https://edumoraes.github.io/shadwire/r",
29
+ "registry" => "https://shadwire.edumoraes.dev.br/r",
30
30
  "tailwind" => { "css" => "app/assets/tailwind/application.css" },
31
31
  "aliases" => {
32
32
  "components" => "app/components",
@@ -1,11 +1,42 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "json"
4
+ require "uri"
4
5
 
5
6
  module Shadwire
6
7
  # Fetches the published registry over file:// or http(s)://.
7
8
  # Both #index and #item are memoized within the instance.
8
9
  class RegistryClient
10
+ # Registries move: GitHub Pages answers 301 for every path once a custom
11
+ # domain is configured. Follow a few hops, then assume a misconfiguration
12
+ # rather than chasing a chain forever.
13
+ MAX_REDIRECTS = 5
14
+
15
+ # Resolves a redirect's Location against the URL it came from, rejecting
16
+ # redirects we must not follow. A registry serves source code that gets
17
+ # written into the user's app, so a redirect may upgrade to HTTPS but never
18
+ # drop it (GitHub Pages answers `Location: http://…` for a custom domain
19
+ # until "Enforce HTTPS" is on).
20
+ def self.redirect_target(from_uri, location)
21
+ if location.to_s.strip.empty?
22
+ raise RegistryError, "Registry redirect from #{from_uri} has no Location header"
23
+ end
24
+
25
+ begin
26
+ target = from_uri + location.strip
27
+ rescue URI::Error => e
28
+ raise RegistryError,
29
+ "Registry redirect from #{from_uri} has an unusable Location (#{location}): #{e.message}"
30
+ end
31
+
32
+ if from_uri.scheme == "https" && target.scheme != "https"
33
+ raise RegistryError,
34
+ "Registry redirect from #{from_uri} drops HTTPS (to #{target}); refusing to follow it"
35
+ end
36
+
37
+ target
38
+ end
39
+
9
40
  def initialize(base_url)
10
41
  # Normalise: drop any trailing slash so URL building is consistent.
11
42
  @base_url = base_url.chomp("/")
@@ -46,16 +77,33 @@ module Shadwire
46
77
 
47
78
  def fetch_http(url, name: nil)
48
79
  require "net/http"
49
- require "uri"
50
80
 
51
81
  uri = URI.parse(url)
52
- response = Net::HTTP.get_response(uri)
82
+ seen = []
83
+ response = nil
84
+
85
+ (MAX_REDIRECTS + 1).times do
86
+ if seen.include?(uri.to_s)
87
+ raise RegistryError, "Registry redirect from #{url} loops back to #{uri}"
88
+ end
89
+ seen << uri.to_s
90
+
91
+ response = Net::HTTP.get_response(uri)
92
+ break unless response.is_a?(Net::HTTPRedirection)
93
+
94
+ uri = self.class.redirect_target(uri, response["location"])
95
+ end
96
+
97
+ if response.is_a?(Net::HTTPRedirection)
98
+ raise RegistryError,
99
+ "Registry at #{url} redirected more than #{MAX_REDIRECTS} times (last: #{uri})"
100
+ end
53
101
 
54
102
  unless response.is_a?(Net::HTTPSuccess)
55
- raise RegistryError, missing_message(name, url, code: response.code)
103
+ raise RegistryError, missing_message(name, uri, code: response.code)
56
104
  end
57
105
 
58
- parse(response.body, url)
106
+ parse(response.body, uri)
59
107
  rescue SocketError, SystemCallError, Net::OpenTimeout, Net::ReadTimeout, OpenSSL::SSL::SSLError => e
60
108
  # An offline machine, a DNS failure or a TLS problem is an ordinary
61
109
  # condition here, not something to surface as a Ruby backtrace.
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Shadwire
4
- VERSION = "0.2.0"
4
+ VERSION = "0.2.1"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: shadwire
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Eduardo de Moraes