homura-runtime 0.2.24 → 0.2.26

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: 0e4fc42870cef61572354025f9091524f2b65d91f93910cb3470acd4038472e7
4
- data.tar.gz: b8fafbfe977f2bfa1cbaf42f16f0b2849a3f9f3b0f12525eb2f9809497fa38e2
3
+ metadata.gz: 961609130fd819224d263b877755bd615b98c27ec2677bb3842aaeeed13a131b
4
+ data.tar.gz: 4412446fe4defcfb5e65cbafc19f53c2bbdb7461a5e835a2a7fa7a09bf6da38e
5
5
  SHA512:
6
- metadata.gz: 3aabb8d2b5678419c57247f834bba6ae02d4de928b154529acf026011cb23c8b08cab01fd95a59b98c74e749b64e86a3f6f4749b6305ab143af54bf5cbc16852
7
- data.tar.gz: 8b71e4b7a2a297aa463b5d68734ca8dc6d88adab156d4bbc9b33e20f7caa58b1fd188c9a4a208fcce83c3df9a57aa2eaf5d18673f4d36cd4d962932dd59a0b97
6
+ metadata.gz: 36b7a90afec547e760a751bf2dcfe1a3ef5a9718d64f31d00d740f9715291a5ce869c9845d3fe7d8b5aa6f99f9787254d77d4197a20fc0095106dcc6bc6959a1
7
+ data.tar.gz: fa08804d6bfcc39032f75889de9066105c46ceccecb7c91a9b2126bffe8db05af8ccf3dfaf02d6da9795cae82dbc987a55a61e86cf676a1aff8a06a3de342ef8
data/CHANGELOG.md CHANGED
@@ -1,5 +1,33 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.2.26 (2026-04-29)
4
+
5
+ - `Rack::Handler::CloudflareWorkers#call`: when `@app` is nil, fall
6
+ back to `Sinatra::CloudflareWorkers.ensure_rack_app!` to discover
7
+ the Sinatra app lazily on the first fetch. This is what lets
8
+ classic-style apps omit the trailing `run Sinatra::Application`
9
+ line (paired with `sinatra-homura >= 0.2.23`).
10
+ - New `Rack::Handler::CloudflareWorkers.ensure_dispatcher_installed!`:
11
+ eagerly registers the JS-side dispatcher (`globalThis.__HOMURA_RACK_DISPATCH__`)
12
+ at script-load time, so a fetch arriving before `run` was called
13
+ still routes into our `call` method (where the lazy app discovery
14
+ above kicks in). On Workers `at_exit` is unreliable because the
15
+ isolate doesn't exit between requests; this eager install is the
16
+ reliable hook.
17
+
18
+ ## 0.2.25 (2026-04-29)
19
+
20
+ - `BuildSupport`: factor `opal_gem_paths` out of the path:-only
21
+ `path_gemfile_entries`. The new method also picks up
22
+ RubyGems-installed gems that opt in via
23
+ `spec.metadata['homura.auto_await'] = 'true'`. Without this, a
24
+ RubyGems-installed pure-Ruby gem (e.g. `sinatra-inertia >= 0.1.1`)
25
+ was missing from both the Opal load path and the auto-await pass,
26
+ so `require 'sinatra/inertia'` failed during `homura build`.
27
+ - `homura-build` iterates `opal_gem_paths` instead of the old
28
+ path:-only list, so any opted-in gem (path: or RubyGems) gets the
29
+ same auto-await rewrite.
30
+
3
31
  ## 0.2.24 (2026-04-29)
4
32
 
5
33
  - `BuildSupport.standalone_load_paths`: auto-discover `path:`-resolved
data/exe/homura-build CHANGED
@@ -275,13 +275,14 @@ else
275
275
  warn 'homura build: no app/ directory or top-level app.rb — skipping auto-await'
276
276
  end
277
277
 
278
- # Also run auto-await over any `path:`-resolved gems declared in the
279
- # consumer's Gemfile (e.g. `sinatra-inertia`). The transformed copies
280
- # are written to `build/auto_await/gem_<basename>/<original-relative>`,
281
- # and `standalone_load_paths` puts those directories ahead of the
282
- # untransformed gem `lib/` so `require 'sinatra/inertia'` resolves to
283
- # the rewritten file.
284
- CloudflareWorkers::BuildSupport.path_gemfile_entries(root).each do |gem_path|
278
+ # Also run auto-await over every gem we ship to Opal:
279
+ # `path:`-resolved gems in the consumer Gemfile *and* RubyGems-
280
+ # installed gems that opt in via
281
+ # `spec.metadata['homura.auto_await'] = 'true'`. Both go to
282
+ # `build/auto_await/gem_<basename>/<sub>` and
283
+ # `standalone_load_paths` puts those rewritten copies ahead of the
284
+ # gem's untransformed `lib/`.
285
+ CloudflareWorkers::BuildSupport.opal_gem_paths(root).each do |gem_path|
285
286
  %w[lib].each do |sub|
286
287
  src = gem_path.join(sub)
287
288
  next unless src.directory?
@@ -86,18 +86,19 @@ module CloudflareWorkers
86
86
  end
87
87
  end
88
88
 
89
- # Pick up any other `path:`-resolved gems declared in the consumer's
90
- # Gemfile (e.g. `sinatra-inertia`). This keeps the build pipeline
91
- # extensible: users can drop a pure-Ruby gem under `gems/foo`, list
92
- # it as `gem 'foo', path: '../../gems/foo'`, and Opal will find its
93
- # `lib/` automatically — no homura-runtime change required.
89
+ # Pick up any other gems that should ship in the Workers bundle:
94
90
  #
95
- # We prefer the auto-await-transformed copy under
96
- # `build/auto_await/gem_<basename>/lib` if present (homura-build
97
- # writes one for every path: gem before invoking Opal), so that
98
- # async chains inside the gem get `__await__` inserted just like
99
- # consumer app code.
100
- path_gemfile_entries(root).each do |gem_path|
91
+ # * `path:`-resolved gems in the consumer's Gemfile (monorepo
92
+ # dev mode), and
93
+ # * RubyGems-installed gems that opt in via
94
+ # `spec.metadata['homura.auto_await'] = 'true'`.
95
+ #
96
+ # Both go through the same auto-await pass during `homura-build`,
97
+ # and we prefer the rewritten copy under
98
+ # `build/auto_await/gem_<basename>/lib` if present so async chains
99
+ # inside gem code get `__await__` inserted just like consumer
100
+ # app code.
101
+ opal_gem_paths(root, loaded_specs: loaded_specs).each do |gem_path|
101
102
  basename = gem_path.basename.to_s
102
103
  rewritten_lib = root.join('build', 'auto_await', "gem_#{basename}", 'lib')
103
104
  load_paths << rewritten_lib.to_s if rewritten_lib.directory?
@@ -133,6 +134,31 @@ module CloudflareWorkers
133
134
  vend if vend.directory?
134
135
  end
135
136
 
137
+ # Returns the union of `path_gemfile_entries(project_root)` and any
138
+ # bundled gems that opt in to the Opal pipeline via
139
+ # `spec.metadata['homura.auto_await']`. This is the single source
140
+ # of truth for both `standalone_load_paths` and the auto-await pass
141
+ # that `homura-build` runs. Returns `Pathname` objects pointing at
142
+ # each gem's root directory.
143
+ def opal_gem_paths(project_root, loaded_specs: Gem.loaded_specs)
144
+ wired = [RUNTIME_GEM_NAME, SINATRA_GEM_NAME, SEQUEL_D1_GEM_NAME]
145
+ out = []
146
+ out.concat(path_gemfile_entries(project_root))
147
+
148
+ loaded_specs.each_value do |spec|
149
+ next if wired.include?(spec.name)
150
+ meta = spec.metadata
151
+ next unless meta.is_a?(Hash)
152
+ flag = meta['homura.auto_await']
153
+ next unless flag == 'true' || flag == true
154
+ next if spec.full_gem_path.nil?
155
+ gem_path = Pathname(spec.full_gem_path)
156
+ out << gem_path if gem_path.directory?
157
+ end
158
+
159
+ out.uniq
160
+ end
161
+
136
162
  # Returns absolute Pathnames for every `path:`-declared gem in the
137
163
  # project's Gemfile that should ship in the Workers bundle.
138
164
  #
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module CloudflareWorkers
4
- VERSION = '0.2.24'
4
+ VERSION = '0.2.26'
5
5
  end
@@ -134,6 +134,34 @@ module Rack
134
134
  @app
135
135
  end
136
136
 
137
+ def self.app=(app)
138
+ @app = app
139
+ end
140
+
141
+ # Eagerly install the JS-side dispatcher so a fetch arriving
142
+ # before `run` was called (e.g. classic-style apps that omit the
143
+ # trailing `run Sinatra::Application`) still gets routed into our
144
+ # `call` method, which can then discover the user's Sinatra app
145
+ # lazily via `Sinatra::CloudflareWorkers.ensure_rack_app!`. This
146
+ # is what makes the canonical sinatrarb.com snippet work
147
+ # verbatim on Workers — `at_exit` is unreliable here because the
148
+ # isolate never actually exits between fetches.
149
+ def self.ensure_dispatcher_installed!
150
+ return true if @dispatcher_installed
151
+ handler = self
152
+ `
153
+ globalThis.__HOMURA_RACK_DISPATCH__ = async function(req, env, ctx, body_text) {
154
+ return await #{handler}.$call(req, env, ctx, body_text == null ? "" : body_text);
155
+ };
156
+ (function () {
157
+ var g = globalThis;
158
+ g.__OPAL_WORKERS__ = g.__OPAL_WORKERS__ || {};
159
+ g.__OPAL_WORKERS__.rack = g.__HOMURA_RACK_DISPATCH__;
160
+ })();
161
+ `
162
+ @dispatcher_installed = true
163
+ end
164
+
137
165
  # Entry point invoked from the Module Worker (src/worker.mjs) for
138
166
  # every fetch event. `js_req` is a Cloudflare Workers Request,
139
167
  # `js_env` is the bindings object (D1, KV, R2, secrets...),
@@ -141,7 +169,13 @@ module Rack
141
169
  # request body (the worker.mjs front awaits req.text() before
142
170
  # handing control to Ruby because Opal runs synchronously).
143
171
  def self.call(js_req, js_env, js_ctx, body_text = '')
144
- raise '`run app` was never called from user code' if @app.nil?
172
+ if @app.nil?
173
+ if defined?(::Sinatra::CloudflareWorkers) &&
174
+ ::Sinatra::CloudflareWorkers.respond_to?(:ensure_rack_app!)
175
+ ::Sinatra::CloudflareWorkers.ensure_rack_app!
176
+ end
177
+ raise '`run app` was never called from user code, and no Sinatra app was discoverable (define `class App < Sinatra::Base` or use top-level classic Sinatra routes)' if @app.nil?
178
+ end
145
179
 
146
180
  env = build_rack_env(js_req, js_env, js_ctx, body_text)
147
181
  result = @app.call(env)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: homura-runtime
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.24
4
+ version: 0.2.26
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kazuhiro Homma