gemstack-dev 0.2.1 → 0.2.3

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: 232c6e46cd3a64ee5e389bbfad4fed124547e86e1a79d7edba7ff7512983dd54
4
- data.tar.gz: 7233f446b4440574a6cac4b44356cec680b1f1cd34e9743c7076d74e0f50165f
3
+ metadata.gz: 4367307a1f2096e2672373427947112d9415a4e1b6563e5bf378ec8b730f7399
4
+ data.tar.gz: 83db91725ba722e334d68056f3063633e4c56ee43af1e89f90e3ebb8fbe77c6e
5
5
  SHA512:
6
- metadata.gz: 255943a7f5f16acfa8f5a438ea46d30e58a4c0d72725142404ee999a8f5b8710c2f5f79ec70cf277b772a8d479c441c033305e06def6cf82df93a46dc62c87af
7
- data.tar.gz: 56cd408b00b494071b98c4cfdd54f0073da358ca6bb056efbda5572c6d513c0926d64686004aee5177da36eb2ead2c454651a97224e08dac1737e5ddf25bb093
6
+ metadata.gz: 3ea6107e79bc7c419c5302a37f0d67e9f7a83d29153fb81c75343ca7e37f512b33f39f4c3b4631bbe7e75e651606f0bfc02a38bdd08e5a90cc3c39c51c6a5225
7
+ data.tar.gz: 435533d5e3f323d4a6cb85e3dba4c7de7cf9e534f8ff383157279ce65ca8b7e6525f7d9524363f982f347d3866215efec0264f517dfeb26b0140a86bf0e3e3e1
data/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.2.3
4
+
5
+ See the [GemStack changelog](https://github.com/gemstack-rb/gemstack/blob/main/CHANGELOG.md).
6
+
7
+ ## 0.2.2
8
+
9
+ See the [GemStack changelog](https://github.com/gemstack-rb/gemstack/blob/main/CHANGELOG.md).
10
+
3
11
  ## 0.2.1
4
12
 
5
13
  See the [GemStack changelog](https://github.com/gemstack-rb/gemstack/blob/main/CHANGELOG.md).
data/LICENSE.txt CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2026 Shoaib Malik
3
+ Copyright (c) 2026 Adware Technologies (https://www.adwaretech.com)
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
data/README.md CHANGED
@@ -3,7 +3,7 @@
3
3
  GemStack development server: single-origin gateway and process supervisor.
4
4
 
5
5
  Part of [GemStack](https://github.com/gemstack-rb/gemstack), a modular Ruby API framework for Next.js
6
- applications. All GemStack gems are developed together in that repository and released with the same
6
+ applications by [Adware Technologies](https://www.adwaretech.com). All GemStack gems are developed together in that repository and released with the same
7
7
  version.
8
8
 
9
9
  ## Installation
@@ -21,4 +21,4 @@ Source, issues and pull requests: [gemstack-rb/gemstack](https://github.com/gems
21
21
 
22
22
  ## License
23
23
 
24
- MIT — see [LICENSE.txt](LICENSE.txt).
24
+ Open source under the MIT License — © [Adware Technologies](https://www.adwaretech.com). See [LICENSE.txt](LICENSE.txt).
@@ -22,7 +22,10 @@ module GemStack
22
22
  end
23
23
 
24
24
  def run
25
- prepare_frontend if frontend?
25
+ if frontend?
26
+ check_node!
27
+ prepare_frontend
28
+ end
26
29
  start
27
30
  install_signal_handlers
28
31
  loop_until_stopped
@@ -108,6 +111,18 @@ module GemStack
108
111
  [frontend_dir.join("node_modules/.bin/next").to_s, "dev", "--hostname", LOOPBACK, "--port", port.to_s]
109
112
  end
110
113
 
114
+ # Next.js exits at once on an old Node.js with a line that's easy to miss
115
+ # among the other output; say it up front, with the command that fixes it.
116
+ def check_node!(node = Toolchain.node)
117
+ return if node && Toolchain.node_ok?(node[:version])
118
+
119
+ wanted = [@root.join(".node-version"), @root.join(".nvmrc")].find(&:file?)&.read&.strip
120
+ wanted = Toolchain::LTS_NODE if wanted.nil? || wanted.empty?
121
+ found = node ? "Node.js #{node[:version]} (#{node[:path]})" : "no `node` on the PATH"
122
+ raise Error, "Next.js needs Node.js #{Toolchain::MIN_NODE.join(".")} or newer; found #{found}.\n " \
123
+ "→ #{Toolchain.node_hint(wanted, Toolchain.node_manager(node&.fetch(:path)))}"
124
+ end
125
+
111
126
  # Installs frontend dependencies on first run so `gemstack new && gemstack dev`
112
127
  # works even with --skip-install.
113
128
  def prepare_frontend
@@ -0,0 +1,86 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "open3"
4
+ require "rbconfig"
5
+
6
+ module GemStack
7
+ module Dev
8
+ # The Ruby and Node.js a developer runs, and how to change them — for
9
+ # whichever version manager installed them (rbenv, rvm, asdf, mise,
10
+ # chruby, nvm, fnm, nodenv, Volta, Homebrew…). GemStack pins versions in
11
+ # files every manager reads (.ruby-version, .node-version, .nvmrc,
12
+ # .tool-versions) and never assumes one manager (DECISIONS D-066).
13
+ module Toolchain
14
+ MIN_RUBY = "3.3"
15
+ MIN_NODE = [20, 9].freeze # Next.js 16
16
+ LTS_NODE = "22"
17
+
18
+ # [pattern in the executable's path, manager name]; the first match wins.
19
+ RUBY_MANAGERS = [
20
+ [%r{/\.rbenv/}, :rbenv], [%r{/\.rvm/|/rvm/rubies/}, :rvm], [%r{/\.asdf/|/asdf/installs/}, :asdf],
21
+ [%r{/mise/installs/|/\.local/share/mise/}, :mise], [%r{/\.rubies/|/opt/rubies/}, :chruby],
22
+ [%r{/(?:opt/)?homebrew/|/usr/local/Cellar/}, :homebrew]
23
+ ].freeze
24
+ NODE_MANAGERS = [
25
+ [%r{/\.nvm/}, :nvm], [%r{/fnm/|/\.fnm/|fnm_multishells}, :fnm], [%r{/\.nodenv/}, :nodenv],
26
+ [%r{/\.asdf/|/asdf/installs/}, :asdf], [%r{/mise/installs/|/\.local/share/mise/}, :mise],
27
+ [%r{/\.volta/}, :volta], [%r{/(?:opt/)?homebrew/|/usr/local/Cellar/}, :homebrew]
28
+ ].freeze
29
+
30
+ module_function
31
+
32
+ def ruby_manager(path = RbConfig.ruby) = detect(RUBY_MANAGERS, path)
33
+ def node_manager(path) = path && detect(NODE_MANAGERS, path)
34
+
35
+ def detect(managers, path)
36
+ managers.find { |pattern, _| path.to_s.match?(pattern) }&.last
37
+ end
38
+
39
+ # How to install and select a Ruby, with the manager in use.
40
+ def ruby_hint(version, manager = ruby_manager)
41
+ {
42
+ rbenv: "rbenv install #{version} && rbenv local #{version}",
43
+ rvm: "rvm install #{version} && rvm use #{version}",
44
+ asdf: "asdf install ruby #{version} && asdf set ruby #{version}",
45
+ mise: "mise use ruby@#{version}",
46
+ chruby: "ruby-install ruby #{version}, then: chruby #{version}",
47
+ homebrew: "brew upgrade ruby (or install #{version} with rbenv, rvm, asdf or mise)"
48
+ }.fetch(manager, "install Ruby #{version} (e.g. with rbenv, rvm, asdf or mise) and make it the active Ruby")
49
+ end
50
+
51
+ # How to install and select a Node.js, with the manager in use.
52
+ def node_hint(version, manager)
53
+ {
54
+ nvm: "nvm install #{version} && nvm use #{version}",
55
+ fnm: "fnm install #{version} && fnm use #{version}",
56
+ nodenv: "nodenv install #{version} && nodenv local #{version}",
57
+ asdf: "asdf install nodejs #{version} && asdf set nodejs #{version}",
58
+ mise: "mise use node@#{version}",
59
+ volta: "volta install node@#{version}",
60
+ homebrew: "brew install node@#{version} (or use nvm, fnm, asdf or mise)"
61
+ }.fetch(manager, "install Node.js #{version} (e.g. with nvm, fnm, asdf or mise) and make it the active node")
62
+ end
63
+
64
+ # { version: "22.11.0", path: "/…/bin/node" } or nil when there's no node.
65
+ def node(run = ->(*cmd) { Open3.capture2e(*cmd) })
66
+ out, status = run.call("node", "-p", "process.version + ' ' + process.execPath")
67
+ return nil unless status.success?
68
+
69
+ version, path = out.strip.split(" ", 2)
70
+ { version: version.delete_prefix("v"), path: path }
71
+ rescue SystemCallError
72
+ nil
73
+ end
74
+
75
+ def node_ok?(version) = (version.to_s.split(".").map(&:to_i) <=> MIN_NODE) >= 0
76
+ def ruby_ok?(version = RUBY_VERSION) = Gem::Version.new(version) >= Gem::Version.new(MIN_RUBY)
77
+
78
+ # The Node.js version new apps pin: the one running `gemstack new` when
79
+ # it's new enough, else the current LTS line.
80
+ def pinned_node_version(run = ->(*cmd) { Open3.capture2e(*cmd) })
81
+ found = node(run)
82
+ found && node_ok?(found[:version]) ? found[:version] : LTS_NODE
83
+ end
84
+ end
85
+ end
86
+ end
data/lib/gemstack/dev.rb CHANGED
@@ -13,6 +13,7 @@ module GemStack
13
13
  autoload :Ports, "gemstack/dev/ports"
14
14
  autoload :Supervisor, "gemstack/dev/supervisor"
15
15
  autoload :Terminal, "gemstack/dev/terminal"
16
+ autoload :Toolchain, "gemstack/dev/toolchain"
16
17
 
17
18
  class Config < Settings
18
19
  # The single public port.
metadata CHANGED
@@ -1,9 +1,10 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gemstack-dev
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.2.3
5
5
  platform: ruby
6
6
  authors:
7
+ - Adware Technologies
7
8
  - Shoaib Malik
8
9
  bindir: bin
9
10
  cert_chain: []
@@ -15,14 +16,14 @@ dependencies:
15
16
  requirements:
16
17
  - - '='
17
18
  - !ruby/object:Gem::Version
18
- version: 0.2.1
19
+ version: 0.2.3
19
20
  type: :runtime
20
21
  prerelease: false
21
22
  version_requirements: !ruby/object:Gem::Requirement
22
23
  requirements:
23
24
  - - '='
24
25
  - !ruby/object:Gem::Version
25
- version: 0.2.1
26
+ version: 0.2.3
26
27
  email:
27
28
  - gemstack26@gmail.com
28
29
  executables: []
@@ -39,6 +40,7 @@ files:
39
40
  - lib/gemstack/dev/ports.rb
40
41
  - lib/gemstack/dev/supervisor.rb
41
42
  - lib/gemstack/dev/terminal.rb
43
+ - lib/gemstack/dev/toolchain.rb
42
44
  homepage: https://github.com/gemstack-rb/gemstack
43
45
  licenses:
44
46
  - MIT
@@ -55,7 +57,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
55
57
  requirements:
56
58
  - - ">="
57
59
  - !ruby/object:Gem::Version
58
- version: '4.0'
60
+ version: '3.3'
59
61
  required_rubygems_version: !ruby/object:Gem::Requirement
60
62
  requirements:
61
63
  - - ">="