ruby_everywhere 0.7.0 → 0.9.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.
Files changed (73) hide show
  1. checksums.yaml +4 -4
  2. data/exe/every +2 -13
  3. data/exe/rbe +2 -13
  4. data/lib/everywhere/boot.rb +9 -2
  5. data/lib/everywhere/builders/android.rb +55 -42
  6. data/lib/everywhere/builders/base.rb +53 -0
  7. data/lib/everywhere/builders/desktop.rb +7 -23
  8. data/lib/everywhere/builders/ios.rb +49 -52
  9. data/lib/everywhere/builders/native_sources.rb +38 -0
  10. data/lib/everywhere/child_processes.rb +4 -4
  11. data/lib/everywhere/child_supervision.rb +172 -0
  12. data/lib/everywhere/clock.rb +12 -0
  13. data/lib/everywhere/commands/build.rb +20 -9
  14. data/lib/everywhere/commands/dev.rb +59 -284
  15. data/lib/everywhere/commands/doctor.rb +6 -6
  16. data/lib/everywhere/commands/install.rb +1 -0
  17. data/lib/everywhere/commands/platform/auth_status.rb +1 -0
  18. data/lib/everywhere/commands/platform/build.rb +5 -6
  19. data/lib/everywhere/commands/platform/login.rb +4 -4
  20. data/lib/everywhere/commands/platform/logout.rb +1 -0
  21. data/lib/everywhere/commands/platform/runner.rb +62 -7
  22. data/lib/everywhere/commands/preview.rb +24 -97
  23. data/lib/everywhere/commands/publish.rb +2 -0
  24. data/lib/everywhere/commands/release.rb +14 -11
  25. data/lib/everywhere/commands/shell_dir.rb +2 -0
  26. data/lib/everywhere/commands/updates_keygen.rb +25 -1
  27. data/lib/everywhere/config/app.rb +126 -0
  28. data/lib/everywhere/config/auth.rb +108 -0
  29. data/lib/everywhere/config/data.rb +50 -0
  30. data/lib/everywhere/config/deep_linking.rb +107 -0
  31. data/lib/everywhere/config/desktop_ui.rb +153 -0
  32. data/lib/everywhere/config/mobile.rb +223 -0
  33. data/lib/everywhere/config/native_desktop.rb +168 -0
  34. data/lib/everywhere/config/native_mobile.rb +337 -0
  35. data/lib/everywhere/config/shell.rb +57 -0
  36. data/lib/everywhere/config/updates.rb +63 -0
  37. data/lib/everywhere/config.rb +30 -1423
  38. data/lib/everywhere/desktop_dev_app.rb +138 -0
  39. data/lib/everywhere/dock/state.rb +3 -1
  40. data/lib/everywhere/entrypoint.rb +24 -0
  41. data/lib/everywhere/error.rb +8 -0
  42. data/lib/everywhere/framework.rb +2 -2
  43. data/lib/everywhere/host.rb +11 -0
  44. data/lib/everywhere/ignore.rb +11 -5
  45. data/lib/everywhere/line_pump.rb +3 -1
  46. data/lib/everywhere/minisign.rb +1 -0
  47. data/lib/everywhere/native_platform.rb +44 -0
  48. data/lib/everywhere/paths.rb +23 -7
  49. data/lib/everywhere/platform/client.rb +19 -1
  50. data/lib/everywhere/platform/snapshot.rb +6 -4
  51. data/lib/everywhere/plist.rb +17 -0
  52. data/lib/everywhere/png.rb +1 -0
  53. data/lib/everywhere/raw_tty.rb +51 -0
  54. data/lib/everywhere/s3.rb +1 -0
  55. data/lib/everywhere/shell_pages.rb +109 -0
  56. data/lib/everywhere/tab_filter.rb +36 -0
  57. data/lib/everywhere/task_pool.rb +3 -4
  58. data/lib/everywhere/ui.rb +6 -1
  59. data/lib/everywhere/version.rb +6 -4
  60. data/lib/everywhere.rb +1 -2
  61. data/support/mobile/android/app/src/main/java/com/rubyeverywhere/shell/EverywhereApplication.kt +65 -4
  62. data/support/mobile/android/app/src/main/java/com/rubyeverywhere/shell/EverywhereConfig.kt +21 -0
  63. data/support/mobile/android/app/src/main/java/com/rubyeverywhere/shell/MainActivity.kt +75 -17
  64. data/support/mobile/android/app/src/main/java/com/rubyeverywhere/shell/MissingExtensionFragment.kt +105 -0
  65. data/support/mobile/android/app/src/main/java/com/rubyeverywhere/shell/WebFragment.kt +31 -4
  66. data/support/mobile/android/app/src/main/java/com/rubyeverywhere/shell/bridge/WebControlChannel.kt +6 -10
  67. data/support/mobile/android/app/src/main/res/layout/everywhere_error.xml +60 -0
  68. data/support/mobile/android/app/src/main/res/values/strings.xml +19 -0
  69. data/support/mobile/ios/App/ErrorViewController.swift +21 -3
  70. data/support/mobile/ios/App/SceneDelegate.swift +12 -1
  71. data/support/mobile/ios/App.xcodeproj/project.pbxproj +0 -2
  72. data/support/release/macos/notarize.sh +3 -0
  73. metadata +26 -1
@@ -1,5 +1,8 @@
1
1
  package com.rubyeverywhere.shell
2
2
 
3
+ import android.view.View
4
+ import android.widget.TextView
5
+ import androidx.core.view.isVisible
3
6
  import dev.hotwire.core.turbo.errors.VisitError
4
7
  import dev.hotwire.navigation.destinations.HotwireDestinationDeepLink
5
8
  import dev.hotwire.navigation.fragments.HotwireWebFragment
@@ -8,10 +11,11 @@ import dev.hotwire.navigation.fragments.HotwireWebFragment
8
11
  * The default destination for every web visit.
9
12
  *
10
13
  * Deliberately thin — the framework's own fragment already does the work. Its
11
- * one job is telling [MainActivity] when there is content on screen, which is
12
- * how the splash comes down. Android has no `NavigatorDelegate.requestDidFinish`
13
- * the way iOS does; the visit callbacks on the fragment are where that
14
- * information surfaces.
14
+ * jobs are telling [MainActivity] when there is content on screen (how the
15
+ * splash comes down Android has no `NavigatorDelegate.requestDidFinish` the
16
+ * way iOS does; the visit callbacks on the fragment are where that information
17
+ * surfaces) and swapping the library's button-less error view for one the user
18
+ * can act on.
15
19
  */
16
20
  @HotwireDestinationDeepLink(uri = "hotwire://fragment/web")
17
21
  open class WebFragment : HotwireWebFragment() {
@@ -30,6 +34,29 @@ open class WebFragment : HotwireWebFragment() {
30
34
  settled()
31
35
  }
32
36
 
37
+ /**
38
+ * The library's error view is a message with no controls — its only retry
39
+ * is pull-to-refresh, invisible exactly when the user is staring at a dead
40
+ * page. Ours adds an explicit retry, and — inside a picked instance, where
41
+ * retrying can only knock on the same dead host — the way home: clear the
42
+ * instance and re-root onto the app's own start page, exactly what the
43
+ * page's own `Everywhere.instance.clear()` would do if it could load.
44
+ */
45
+ override fun createErrorView(error: VisitError): View {
46
+ val view = layoutInflater.inflate(R.layout.everywhere_error, null)
47
+ view.findViewById<TextView>(R.id.everywhere_error_description).text = error.description()
48
+ view.findViewById<View>(R.id.everywhere_error_retry).setOnClickListener {
49
+ refresh(displayProgress = true)
50
+ }
51
+ view.findViewById<View>(R.id.everywhere_error_leave).apply {
52
+ isVisible = EverywhereConfig.shared.instanceUrl != null
53
+ setOnClickListener {
54
+ EverywhereEvents.emit(EverywhereEvents.Event.ClearInstance(null))
55
+ }
56
+ }
57
+ return view
58
+ }
59
+
33
60
  private fun settled() {
34
61
  (activity as? MainActivity)?.onWebContentSettled()
35
62
  }
@@ -189,16 +189,12 @@ class WebControlChannel : WebViewCompat.WebMessageListener {
189
189
  }
190
190
 
191
191
  /**
192
- * The app's own origin, derived from the *effective* root — so a dev
193
- * build against 127.0.0.1 and a picked instance both work without a
194
- * second list to keep in sync.
192
+ * Every origin the shell's own pages come from stamped root, dev
193
+ * override, picked instance (EverywhereConfig.trustedRootOrigins).
194
+ * All of them, not just the effective root: while the shell is rooted
195
+ * on an instance, the picker's own pages are still served from the
196
+ * stamped origin, and they need the channel to switch or leave.
195
197
  */
196
- private fun originRules(): Set<String> {
197
- val uri = EverywhereConfig.shared.rootUrl.toUri()
198
- val scheme = uri.scheme ?: return emptySet()
199
- val host = uri.host ?: return emptySet()
200
- val port = if (uri.port > 0) ":${uri.port}" else ""
201
- return setOf("$scheme://$host$port")
202
- }
198
+ private fun originRules(): Set<String> = EverywhereConfig.shared.trustedRootOrigins
203
199
  }
204
200
  }
@@ -0,0 +1,60 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <!--
3
+ FROZEN. The failed-visit screen WebFragment.createErrorView inflates in
4
+ place of the library's hotwire_error.xml, which has no controls at all —
5
+ its only retry is pull-to-refresh, invisible exactly when the user is
6
+ staring at a dead page. Same typography as the library's version, plus an
7
+ explicit retry button and an escape hatch for picked instances (shown by
8
+ WebFragment only when an instance override is active).
9
+ -->
10
+ <FrameLayout
11
+ xmlns:android="http://schemas.android.com/apk/res/android"
12
+ android:layout_width="match_parent"
13
+ android:layout_height="match_parent"
14
+ android:background="?android:colorBackground">
15
+
16
+ <LinearLayout
17
+ android:layout_width="match_parent"
18
+ android:layout_height="wrap_content"
19
+ android:layout_gravity="center"
20
+ android:orientation="vertical"
21
+ android:gravity="center_horizontal"
22
+ android:paddingStart="24dp"
23
+ android:paddingEnd="24dp">
24
+
25
+ <com.google.android.material.textview.MaterialTextView
26
+ style="@style/TextAppearance.MaterialComponents.Headline6"
27
+ android:id="@+id/everywhere_error_title"
28
+ android:layout_width="match_parent"
29
+ android:layout_height="wrap_content"
30
+ android:gravity="center_horizontal"
31
+ android:text="@string/everywhere_error_title" />
32
+
33
+ <com.google.android.material.textview.MaterialTextView
34
+ style="@style/TextAppearance.MaterialComponents.Caption"
35
+ android:id="@+id/everywhere_error_description"
36
+ android:layout_width="match_parent"
37
+ android:layout_height="wrap_content"
38
+ android:layout_marginTop="8dp"
39
+ android:gravity="center_horizontal"
40
+ android:textSize="14sp" />
41
+
42
+ <com.google.android.material.button.MaterialButton
43
+ android:id="@+id/everywhere_error_retry"
44
+ android:layout_width="wrap_content"
45
+ android:layout_height="wrap_content"
46
+ android:layout_marginTop="24dp"
47
+ android:text="@string/everywhere_error_retry" />
48
+
49
+ <com.google.android.material.button.MaterialButton
50
+ style="@style/Widget.MaterialComponents.Button.TextButton"
51
+ android:id="@+id/everywhere_error_leave"
52
+ android:layout_width="wrap_content"
53
+ android:layout_height="wrap_content"
54
+ android:layout_marginTop="8dp"
55
+ android:text="@string/everywhere_error_leave"
56
+ android:visibility="gone" />
57
+
58
+ </LinearLayout>
59
+
60
+ </FrameLayout>
@@ -15,4 +15,23 @@
15
15
  names its own overflow tab on iOS.
16
16
  -->
17
17
  <string name="everywhere_more_tab">More</string>
18
+ <!--
19
+ The failed-visit screen (WebFragment.createErrorView). "Back to start"
20
+ shows only inside a picked instance, where retrying the same dead host
21
+ is the only other move — it clears the instance and re-roots.
22
+ -->
23
+ <string name="everywhere_error_title">Error loading page</string>
24
+ <string name="everywhere_error_retry">Try again</string>
25
+ <string name="everywhere_error_leave">Back to start</string>
26
+ <!--
27
+ MissingExtensionFragment — the fallback destination when a previewed
28
+ app's rule names a native screen compiled into ITS build, not this
29
+ shell. Copy mirrors iOS's MissingExtensionScreen.
30
+ -->
31
+ <string name="everywhere_missing_screen_nav_title">Preview</string>
32
+ <string name="everywhere_missing_screen_title">This screen is native</string>
33
+ <string name="everywhere_missing_screen_body">In the full build, “%1$s” is a native screen compiled into the app. Jump can\'t run another app\'s native code — everything else in this preview works.</string>
34
+ <!-- Older previewed apps serve no fallback_uri; their native-screen visits
35
+ are refused with this toast instead of a spinner that never ends. -->
36
+ <string name="everywhere_missing_screen_toast">“%1$s” is a native screen in the full build — Jump can\'t run another app\'s native code.</string>
18
37
  </resources>
@@ -1,14 +1,19 @@
1
1
  import UIKit
2
2
 
3
3
  /// A full-screen error page with a retry button, presented when a visit fails
4
- /// (e.g. the server is unreachable).
4
+ /// (e.g. the server is unreachable). When the failure happened inside a picked
5
+ /// instance — where retrying can only knock on the same dead host — a second
6
+ /// button offers the way home (SceneDelegate passes `leaveHandler` exactly
7
+ /// then, and it clears the instance and re-roots).
5
8
  final class ErrorViewController: UIViewController {
6
9
  private let error: Error
7
10
  private let retryHandler: (() -> Void)?
11
+ private let leaveHandler: (() -> Void)?
8
12
 
9
- init(error: Error, retryHandler: (() -> Void)?) {
13
+ init(error: Error, retryHandler: (() -> Void)?, leaveHandler: (() -> Void)? = nil) {
10
14
  self.error = error
11
15
  self.retryHandler = retryHandler
16
+ self.leaveHandler = leaveHandler
12
17
  super.init(nibName: nil, bundle: nil)
13
18
  }
14
19
 
@@ -41,7 +46,15 @@ final class ErrorViewController: UIViewController {
41
46
  })
42
47
  retryButton.isHidden = retryHandler == nil
43
48
 
44
- let stackView = UIStackView(arrangedSubviews: [imageView, messageLabel, retryButton])
49
+ var leaveConfiguration = UIButton.Configuration.plain()
50
+ leaveConfiguration.title = "Back to start"
51
+ leaveConfiguration.buttonSize = .large
52
+ let leaveButton = UIButton(configuration: leaveConfiguration, primaryAction: UIAction { [weak self] _ in
53
+ self?.leave()
54
+ })
55
+ leaveButton.isHidden = leaveHandler == nil
56
+
57
+ let stackView = UIStackView(arrangedSubviews: [imageView, messageLabel, retryButton, leaveButton])
45
58
  stackView.axis = .vertical
46
59
  stackView.alignment = .center
47
60
  stackView.spacing = 16
@@ -61,4 +74,9 @@ final class ErrorViewController: UIViewController {
61
74
  retryHandler?()
62
75
  dismiss(animated: true)
63
76
  }
77
+
78
+ private func leave() {
79
+ dismiss(animated: true)
80
+ leaveHandler?()
81
+ }
64
82
  }
@@ -599,7 +599,18 @@ extension SceneDelegate: NavigatorDelegate {
599
599
  }
600
600
 
601
601
  private func presentError(_ error: HotwireNativeError, retryHandler: RetryBlock?) {
602
- let errorViewController = ErrorViewController(error: error, retryHandler: retryHandler)
602
+ // Inside a picked instance whose server has gone away, Retry can only
603
+ // knock on the same dead host — offer the way home too: clear the
604
+ // instance and re-root, exactly what the leave tab does when it can load.
605
+ var leaveHandler: (() -> Void)?
606
+ if config.remoteInstances == true, EverywhereConfig.instanceURL != nil {
607
+ leaveHandler = { [weak self] in
608
+ guard let self else { return }
609
+ EverywhereConfig.setInstanceURL(nil)
610
+ self.resetApp(to: self.config.startURL)
611
+ }
612
+ }
613
+ let errorViewController = ErrorViewController(error: error, retryHandler: retryHandler, leaveHandler: leaveHandler)
603
614
  errorViewController.modalPresentationStyle = .fullScreen
604
615
  activeNavigator.activeNavigationController.present(errorViewController, animated: true)
605
616
  }
@@ -361,7 +361,6 @@
361
361
  buildSettings = {
362
362
  ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
363
363
  ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
364
- CODE_SIGN_STYLE = Automatic;
365
364
  GENERATE_INFOPLIST_FILE = YES;
366
365
  INFOPLIST_FILE = App/Info.plist;
367
366
  INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
@@ -386,7 +385,6 @@
386
385
  buildSettings = {
387
386
  ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
388
387
  ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
389
- CODE_SIGN_STYLE = Automatic;
390
388
  GENERATE_INFOPLIST_FILE = YES;
391
389
  INFOPLIST_FILE = App/Info.plist;
392
390
  INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
@@ -94,6 +94,9 @@ if [ -n "${NOTARY_KEY:-}" ]; then
94
94
  elif [ -n "${NOTARY_PROFILE:-}" ]; then
95
95
  xcrun notarytool submit "$ZIP" --keychain-profile "$NOTARY_PROFILE" --wait
96
96
  else
97
+ # Last resort. --password puts the app-specific password on the command line,
98
+ # where any process on the machine can read it out of `ps` — prefer NOTARY_KEY
99
+ # (API key, above) or NOTARY_PROFILE, neither of which passes a secret in argv.
97
100
  # Accept APPLE_APP_SPECIFIC_PASSWORD as an alias for APPLE_PASSWORD.
98
101
  APPLE_PASSWORD="${APPLE_PASSWORD:-${APPLE_APP_SPECIFIC_PASSWORD:-}}"
99
102
  : "${APPLE_ID:?set APPLE_ID or NOTARY_PROFILE}"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby_everywhere
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.0
4
+ version: 0.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrea Fomera
@@ -114,10 +114,14 @@ files:
114
114
  - lib/everywhere/blake2b.rb
115
115
  - lib/everywhere/boot.rb
116
116
  - lib/everywhere/builders/android.rb
117
+ - lib/everywhere/builders/base.rb
117
118
  - lib/everywhere/builders/desktop.rb
118
119
  - lib/everywhere/builders/ios.rb
120
+ - lib/everywhere/builders/native_sources.rb
119
121
  - lib/everywhere/child_processes.rb
122
+ - lib/everywhere/child_supervision.rb
120
123
  - lib/everywhere/cli.rb
124
+ - lib/everywhere/clock.rb
121
125
  - lib/everywhere/commands/build.rb
122
126
  - lib/everywhere/commands/clean.rb
123
127
  - lib/everywhere/commands/dev.rb
@@ -136,17 +140,31 @@ files:
136
140
  - lib/everywhere/commands/shell_dir.rb
137
141
  - lib/everywhere/commands/updates_keygen.rb
138
142
  - lib/everywhere/config.rb
143
+ - lib/everywhere/config/app.rb
144
+ - lib/everywhere/config/auth.rb
145
+ - lib/everywhere/config/data.rb
146
+ - lib/everywhere/config/deep_linking.rb
147
+ - lib/everywhere/config/desktop_ui.rb
148
+ - lib/everywhere/config/mobile.rb
149
+ - lib/everywhere/config/native_desktop.rb
150
+ - lib/everywhere/config/native_mobile.rb
151
+ - lib/everywhere/config/shell.rb
152
+ - lib/everywhere/config/updates.rb
139
153
  - lib/everywhere/console.rb
140
154
  - lib/everywhere/database.rb
141
155
  - lib/everywhere/desktop_assets.rb
156
+ - lib/everywhere/desktop_dev_app.rb
142
157
  - lib/everywhere/dock.rb
143
158
  - lib/everywhere/dock/footer.rb
144
159
  - lib/everywhere/dock/screen.rb
145
160
  - lib/everywhere/dock/state.rb
146
161
  - lib/everywhere/emulator.rb
147
162
  - lib/everywhere/engine.rb
163
+ - lib/everywhere/entrypoint.rb
164
+ - lib/everywhere/error.rb
148
165
  - lib/everywhere/fatal.rb
149
166
  - lib/everywhere/framework.rb
167
+ - lib/everywhere/host.rb
150
168
  - lib/everywhere/icon.rb
151
169
  - lib/everywhere/ignore.rb
152
170
  - lib/everywhere/jump.rb
@@ -156,18 +174,23 @@ files:
156
174
  - lib/everywhere/mobile_config_endpoint.rb
157
175
  - lib/everywhere/mobile_configs_controller.rb
158
176
  - lib/everywhere/native_helper.rb
177
+ - lib/everywhere/native_platform.rb
159
178
  - lib/everywhere/omniauth.rb
160
179
  - lib/everywhere/paths.rb
161
180
  - lib/everywhere/platform/client.rb
162
181
  - lib/everywhere/platform/credentials.rb
163
182
  - lib/everywhere/platform/snapshot.rb
183
+ - lib/everywhere/plist.rb
164
184
  - lib/everywhere/png.rb
165
185
  - lib/everywhere/raster.rb
186
+ - lib/everywhere/raw_tty.rb
166
187
  - lib/everywhere/receipt.rb
167
188
  - lib/everywhere/relay.rb
168
189
  - lib/everywhere/s3.rb
190
+ - lib/everywhere/shell_pages.rb
169
191
  - lib/everywhere/shellout.rb
170
192
  - lib/everywhere/simulator.rb
193
+ - lib/everywhere/tab_filter.rb
171
194
  - lib/everywhere/task_pool.rb
172
195
  - lib/everywhere/ui.rb
173
196
  - lib/everywhere/update_manifest.rb
@@ -217,6 +240,7 @@ files:
217
240
  - support/mobile/android/app/src/main/java/com/rubyeverywhere/shell/IconFont.kt
218
241
  - support/mobile/android/app/src/main/java/com/rubyeverywhere/shell/MainActivity.kt
219
242
  - support/mobile/android/app/src/main/java/com/rubyeverywhere/shell/MainTabs.kt
243
+ - support/mobile/android/app/src/main/java/com/rubyeverywhere/shell/MissingExtensionFragment.kt
220
244
  - support/mobile/android/app/src/main/java/com/rubyeverywhere/shell/WebBottomSheetFragment.kt
221
245
  - support/mobile/android/app/src/main/java/com/rubyeverywhere/shell/WebFragment.kt
222
246
  - support/mobile/android/app/src/main/java/com/rubyeverywhere/shell/bridge/BiometricsComponent.kt
@@ -234,6 +258,7 @@ files:
234
258
  - support/mobile/android/app/src/main/res/layout/activity_main.xml
235
259
  - support/mobile/android/app/src/main/res/layout/bridge_menu_sheet.xml
236
260
  - support/mobile/android/app/src/main/res/layout/bridge_menu_sheet_item.xml
261
+ - support/mobile/android/app/src/main/res/layout/everywhere_error.xml
237
262
  - support/mobile/android/app/src/main/res/layout/tab_more_sheet.xml
238
263
  - support/mobile/android/app/src/main/res/layout/tab_more_sheet_item.xml
239
264
  - support/mobile/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml