Module: Everywhere
- Defined in:
- lib/everywhere.rb,
lib/everywhere/s3.rb,
lib/everywhere/ui.rb,
lib/everywhere/cli.rb,
lib/everywhere/png.rb,
lib/everywhere/boot.rb,
lib/everywhere/icon.rb,
lib/everywhere/paths.rb,
lib/everywhere/config.rb,
lib/everywhere/engine.rb,
lib/everywhere/ignore.rb,
lib/everywhere/raster.rb,
lib/everywhere/blake2b.rb,
lib/everywhere/receipt.rb,
lib/everywhere/version.rb,
lib/everywhere/database.rb,
lib/everywhere/emulator.rb,
lib/everywhere/minisign.rb,
lib/everywhere/omniauth.rb,
lib/everywhere/shellout.rb,
lib/everywhere/framework.rb,
lib/everywhere/simulator.rb,
lib/everywhere/auth_token.rb,
lib/everywhere/log_filter.rb,
lib/everywhere/android_sdk.rb,
lib/everywhere/auth_handoff.rb,
lib/everywhere/builders/ios.rb,
lib/everywhere/commands/dev.rb,
lib/everywhere/asset_catalog.rb,
lib/everywhere/commands/icon.rb,
lib/everywhere/commands/logs.rb,
lib/everywhere/native_helper.rb,
lib/everywhere/commands/build.rb,
lib/everywhere/commands/clean.rb,
lib/everywhere/commands/doctor.rb,
lib/everywhere/platform/client.rb,
lib/everywhere/update_manifest.rb,
lib/everywhere/builders/android.rb,
lib/everywhere/commands/install.rb,
lib/everywhere/commands/publish.rb,
lib/everywhere/commands/release.rb,
lib/everywhere/android_resources.rb,
lib/everywhere/platform/snapshot.rb,
lib/everywhere/commands/shell_dir.rb,
lib/everywhere/platform/credentials.rb,
lib/everywhere/mobile_config_endpoint.rb,
lib/everywhere/commands/platform/build.rb,
lib/everywhere/commands/platform/login.rb,
lib/everywhere/commands/updates_keygen.rb,
lib/everywhere/commands/platform/logout.rb,
lib/everywhere/commands/platform/runner.rb,
lib/everywhere/mobile_configs_controller.rb,
lib/everywhere/commands/platform/auth_status.rb
Defined Under Namespace
Modules: AndroidResources, AndroidSdk, AssetCatalog, AuthToken, Blake2b, Builders, CLI, Commands, Database, Emulator, Icon, Minisign, NativeHelper, OmniAuth, PNG, Paths, Platform, Shellout, Simulator, UI, UpdateManifest Classes: AuthHandoff, Boot, Config, Configuration, Engine, Error, Framework, Ignore, LogFilter, MobileConfigEndpoint, MobileConfigsController, Raster, Receipt, S3
Constant Summary collapse
- VERSION =
"0.4.0"- BRIDGE_VERSION =
Version of the @rubyeverywhere/bridge JS this gem ships. bridge/ in the gem IS the npm package (served to Rails apps by Everywhere::Engine, vendored to public/ for Sinatra/Hanami), so its package.json is the single source of truth. The build receipt records it; it versions independently of the CLI.
File.read( File.("../../bridge/package.json", __dir__) )[/"version":\s*"([^"]+)"/, 1]
Class Attribute Summary collapse
-
.tabs_filter ⇒ Object
writeonly
Test/reset hook.
Class Method Summary collapse
- .boot!(root:) ⇒ Object
- .config ⇒ Object
- .configure {|config| ... } ⇒ Object
-
.filter_tabs(&block) ⇒ Object
Register a per-request filter for the mobile tab bar.
-
.mobile_auth_html(to) ⇒ Object
The page served at /everywhere/auth/native.
-
.mobile_reset_html(to) ⇒ Object
The tiny page served at /everywhere/reset.
-
.native_platform_of(user_agent) ⇒ Object
:ios, :android or nil, from a User-Agent string.
-
.reset_config! ⇒ Object
Test/reset seam.
-
.resolve_tabs(tabs, request) ⇒ Object
Apply the registered filter (identity when none is set).
Class Attribute Details
.tabs_filter=(value) ⇒ Object (writeonly)
Test/reset hook.
108 109 110 |
# File 'lib/everywhere/config.rb', line 108 def tabs_filter=(value) @tabs_filter = value end |
Class Method Details
.boot!(root:) ⇒ Object
161 162 163 |
# File 'lib/everywhere/boot.rb', line 161 def self.boot!(root:) Boot.call(root: root) end |
.config ⇒ Object
40 41 42 |
# File 'lib/everywhere.rb', line 40 def config @config ||= Configuration.new end |
.configure {|config| ... } ⇒ Object
44 45 46 |
# File 'lib/everywhere.rb', line 44 def configure yield config end |
.filter_tabs(&block) ⇒ Object
Register a per-request filter for the mobile tab bar. The block receives
the resolved tab list ([{ "title" =>, "path" =>, "icon" => }, …]) and
the current request, and returns the subset to show — return [] to hide
the tab bar entirely (the shell falls back to single-screen navigation).
It runs inside the mobile config endpoint, which shares the app's session and cookies, so it can branch on auth or any request state:
# config/initializers/everywhere.rb
Everywhere.filter_tabs do |tabs, request|
request.session[:user_id] ? tabs : []
end
Live like the rest of the config: the shell re-reads it on launch and on every foreground, so a sign-in shows the tabs on next foreground — no rebuild, no app-store release.
23 24 25 |
# File 'lib/everywhere/config.rb', line 23 def filter_tabs(&block) @tabs_filter = block end |
.mobile_auth_html(to) ⇒ Object
The page served at /everywhere/auth/native. The shell normally diverts a
provider path natively, before the request is ever made; this covers the
visits it can't see — a data-turbo="false" link, or the POST OmniAuth 2
requires — by asking the shell, from the page, to open the auth session.
In a browser it just continues to the provider.
74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 |
# File 'lib/everywhere/config.rb', line 74 def mobile_auth_html(to) require "json" target = to.to_s target = "/" unless target.start_with?("/") && !target.start_with?("//") # script_safe, as in mobile_reset_html: `to` is request input. encoded = JSON.generate(target, script_safe: true) <<~HTML <!DOCTYPE html><html><head><meta charset="utf-8"><title>Signing in…</title> <meta name="viewport" content="width=device-width,initial-scale=1"></head> <body><p>Opening secure sign-in…</p><script> (function(){var to=#{encoded};var msg={action:"authFlow",to:to}; var ios=window.webkit&&window.webkit.messageHandlers&&window.webkit.messageHandlers.everywhereControl; var android=window.everywhereControl; if(ios){ios.postMessage(msg);} else if(android&&android.postMessage){android.postMessage(JSON.stringify(msg));} else{window.location.replace(to);}})(); </script></body></html> HTML end |
.mobile_reset_html(to) ⇒ Object
The tiny page served at /everywhere/reset. Auth flows redirect the native
app here so it resets cleanly (fresh web views, re-fetched tabs) before
continuing — the standard Hotwire Native "reset the app" pattern. It talks
to the shell's control channel directly (no bridge/importmap dependency);
in a plain browser it just forwards to the target. to is constrained to
a same-origin path.
Both shells are addressed inline, and differently, for the same reason the bridge normalizes them: WKWebView's message handler takes an object, while Android's WebMessageListener channel takes a string. Reaching for the bridge here instead would trade that one line for an importmap dependency on a page whose whole job is to work before anything loads.
47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
# File 'lib/everywhere/config.rb', line 47 def mobile_reset_html(to) require "json" target = to.to_s target = "/" unless target.start_with?("/") && !target.start_with?("//") # script_safe, not to_json: this lands inside <script>, and outside Rails # nothing escapes "</script>" in a plain JSON string. encoded = JSON.generate(target, script_safe: true) <<~HTML <!DOCTYPE html><html><head><meta charset="utf-8"><title>One moment…</title> <meta name="viewport" content="width=device-width,initial-scale=1"></head> <body><script> (function(){var to=#{encoded};var msg={action:"reset",to:to}; var ios=window.webkit&&window.webkit.messageHandlers&&window.webkit.messageHandlers.everywhereControl; var android=window.everywhereControl; if(ios){ios.postMessage(msg);} else if(android&&android.postMessage){android.postMessage(JSON.stringify(msg));} else{window.location.replace(to);}})(); </script></body></html> HTML end |
.native_platform_of(user_agent) ⇒ Object
:ios, :android or nil, from a User-Agent string. The shells prepend
"RubyEverywhere/
99 100 101 102 103 104 105 |
# File 'lib/everywhere/config.rb', line 99 def native_platform_of(user_agent) ua = user_agent.to_s return :ios if ua.include?("Hotwire Native iOS") return :android if ua.include?("Hotwire Native Android") nil end |
.reset_config! ⇒ Object
Test/reset seam.
49 50 51 |
# File 'lib/everywhere.rb', line 49 def reset_config! @config = Configuration.new end |
.resolve_tabs(tabs, request) ⇒ Object
Apply the registered filter (identity when none is set). Always returns an Array so a stray nil/scalar from a block can't break serialization.
29 30 31 32 33 |
# File 'lib/everywhere/config.rb', line 29 def resolve_tabs(tabs, request) return tabs unless @tabs_filter Array(@tabs_filter.call(tabs, request)) end |