diff --git a/x/examples/outline-pwa/.gitignore b/x/examples/outline-pwa/.gitignore
new file mode 100644
index 00000000..1818ee61
--- /dev/null
+++ b/x/examples/outline-pwa/.gitignore
@@ -0,0 +1,7 @@
+.idea/
+node_modules/
+.vscode/
+*.map
+.DS_Store
+.sourcemaps
+dist/
diff --git a/x/examples/outline-pwa/LICENSE b/x/examples/outline-pwa/LICENSE
new file mode 100644
index 00000000..261eeb9e
--- /dev/null
+++ b/x/examples/outline-pwa/LICENSE
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/x/examples/outline-pwa/README.md b/x/examples/outline-pwa/README.md
new file mode 100644
index 00000000..765099d5
--- /dev/null
+++ b/x/examples/outline-pwa/README.md
@@ -0,0 +1,19 @@
+# Outline PWA Wrapper
+
+Demonstration of how to wrap any URL with CapacitorJS in a way that all content is loaded over Outline SDK's Mobileproxy. Turn your website into a censorship-resistant app!
+
+TODO: step-by-step walkthrough of the app-building process
+
+## Setup
+
+```sh
+npm ci
+npx cap sync
+```
+### iOS
+
+Open the `ios/App/App.xcworkspace` folder in XCode and run the project!
+
+### Android
+
+Open the `android` folder in Android Studio and run the project!
\ No newline at end of file
diff --git a/x/examples/outline-pwa/android/.gitignore b/x/examples/outline-pwa/android/.gitignore
new file mode 100644
index 00000000..48354a3d
--- /dev/null
+++ b/x/examples/outline-pwa/android/.gitignore
@@ -0,0 +1,101 @@
+# Using Android gitignore template: https://github.com/github/gitignore/blob/HEAD/Android.gitignore
+
+# Built application files
+*.apk
+*.aar
+*.ap_
+*.aab
+
+# Files for the ART/Dalvik VM
+*.dex
+
+# Java class files
+*.class
+
+# Generated files
+bin/
+gen/
+out/
+# Uncomment the following line in case you need and you don't have the release build type files in your app
+# release/
+
+# Gradle files
+.gradle/
+build/
+
+# Local configuration file (sdk path, etc)
+local.properties
+
+# Proguard folder generated by Eclipse
+proguard/
+
+# Log Files
+*.log
+
+# Android Studio Navigation editor temp files
+.navigation/
+
+# Android Studio captures folder
+captures/
+
+# IntelliJ
+*.iml
+.idea/workspace.xml
+.idea/tasks.xml
+.idea/gradle.xml
+.idea/assetWizardSettings.xml
+.idea/dictionaries
+.idea/libraries
+# Android Studio 3 in .gitignore file.
+.idea/caches
+.idea/modules.xml
+# Comment next line if keeping position of elements in Navigation Editor is relevant for you
+.idea/navEditor.xml
+
+# Keystore files
+# Uncomment the following lines if you do not want to check your keystore files in.
+#*.jks
+#*.keystore
+
+# External native build folder generated in Android Studio 2.2 and later
+.externalNativeBuild
+.cxx/
+
+# Google Services (e.g. APIs or Firebase)
+# google-services.json
+
+# Freeline
+freeline.py
+freeline/
+freeline_project_description.json
+
+# fastlane
+fastlane/report.xml
+fastlane/Preview.html
+fastlane/screenshots
+fastlane/test_output
+fastlane/readme.md
+
+# Version control
+vcs.xml
+
+# lint
+lint/intermediates/
+lint/generated/
+lint/outputs/
+lint/tmp/
+# lint/reports/
+
+# Android Profiling
+*.hprof
+
+# Cordova plugins for Capacitor
+capacitor-cordova-android-plugins
+
+# Copied web assets
+app/src/main/assets/public
+
+# Generated Config files
+app/src/main/assets/capacitor.config.json
+app/src/main/assets/capacitor.plugins.json
+app/src/main/res/xml/config.xml
diff --git a/x/examples/outline-pwa/android/app/.gitignore b/x/examples/outline-pwa/android/app/.gitignore
new file mode 100644
index 00000000..043df802
--- /dev/null
+++ b/x/examples/outline-pwa/android/app/.gitignore
@@ -0,0 +1,2 @@
+/build/*
+!/build/.npmkeep
diff --git a/x/examples/outline-pwa/android/app/build.gradle b/x/examples/outline-pwa/android/app/build.gradle
new file mode 100644
index 00000000..1cbcb011
--- /dev/null
+++ b/x/examples/outline-pwa/android/app/build.gradle
@@ -0,0 +1,57 @@
+apply plugin: 'com.android.application'
+
+android {
+ namespace "org.getoutline.pwa"
+ compileSdk rootProject.ext.compileSdkVersion
+ defaultConfig {
+ applicationId "org.getoutline.pwa"
+ minSdkVersion rootProject.ext.minSdkVersion
+ targetSdkVersion rootProject.ext.targetSdkVersion
+ versionCode 1
+ versionName "1.0"
+ testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+ aaptOptions {
+ // Files and dirs to omit from the packaged assets dir, modified to accommodate modern web apps.
+ // Default: https://android.googlesource.com/platform/frameworks/base/+/282e181b58cf72b6ca770dc7ca5f91f135444502/tools/aapt/AaptAssets.cpp#61
+ ignoreAssetsPattern '!.svn:!.git:!.ds_store:!*.scc:.*:!CVS:!thumbs.db:!picasa.ini:!*~'
+ }
+ }
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
+ }
+ }
+}
+
+repositories {
+ flatDir{
+ dirs '../capacitor-cordova-android-plugins/src/main/libs', 'libs'
+ }
+}
+
+dependencies {
+ implementation fileTree(include: ['*.jar'], dir: 'libs')
+ implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion"
+ implementation "androidx.coordinatorlayout:coordinatorlayout:$androidxCoordinatorLayoutVersion"
+ implementation "androidx.core:core-splashscreen:$coreSplashScreenVersion"
+ implementation "androidx.webkit:webkit:1.12.1"
+ implementation project(':capacitor-android')
+ testImplementation "junit:junit:$junitVersion"
+ androidTestImplementation "androidx.test.ext:junit:$androidxJunitVersion"
+ androidTestImplementation "androidx.test.espresso:espresso-core:$androidxEspressoCoreVersion"
+ implementation project(':capacitor-cordova-android-plugins')
+ implementation files('../../generated/mobileproxy.aar')
+}
+
+apply from: 'capacitor.build.gradle'
+apply plugin: 'org.jetbrains.kotlin.android'
+
+try {
+ def servicesJSON = file('google-services.json')
+ if (servicesJSON.text) {
+ apply plugin: 'com.google.gms.google-services'
+ }
+} catch(Exception e) {
+ logger.info("google-services.json not found, google-services plugin not applied. Push Notifications won't work")
+}
diff --git a/x/examples/outline-pwa/android/app/capacitor.build.gradle b/x/examples/outline-pwa/android/app/capacitor.build.gradle
new file mode 100644
index 00000000..0c464a28
--- /dev/null
+++ b/x/examples/outline-pwa/android/app/capacitor.build.gradle
@@ -0,0 +1,21 @@
+// DO NOT EDIT THIS FILE! IT IS GENERATED EACH TIME "capacitor update" IS RUN
+
+android {
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_17
+ targetCompatibility JavaVersion.VERSION_17
+ }
+}
+
+apply from: "../capacitor-cordova-android-plugins/cordova.variables.gradle"
+dependencies {
+ implementation project(':capacitor-camera')
+ implementation project(':capacitor-splash-screen')
+ implementation 'androidx.core:core-ktx:+'
+
+}
+
+
+if (hasProperty('postBuildExtras')) {
+ postBuildExtras()
+}
diff --git a/x/examples/outline-pwa/android/app/proguard-rules.pro b/x/examples/outline-pwa/android/app/proguard-rules.pro
new file mode 100644
index 00000000..f1b42451
--- /dev/null
+++ b/x/examples/outline-pwa/android/app/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
diff --git a/x/examples/outline-pwa/android/app/src/androidTest/java/com/getcapacitor/myapp/ExampleInstrumentedTest.java b/x/examples/outline-pwa/android/app/src/androidTest/java/com/getcapacitor/myapp/ExampleInstrumentedTest.java
new file mode 100644
index 00000000..f2c2217e
--- /dev/null
+++ b/x/examples/outline-pwa/android/app/src/androidTest/java/com/getcapacitor/myapp/ExampleInstrumentedTest.java
@@ -0,0 +1,26 @@
+package com.getcapacitor.myapp;
+
+import static org.junit.Assert.*;
+
+import android.content.Context;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.platform.app.InstrumentationRegistry;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Instrumented test, which will execute on an Android device.
+ *
+ * @see Testing documentation
+ */
+@RunWith(AndroidJUnit4.class)
+public class ExampleInstrumentedTest {
+
+ @Test
+ public void useAppContext() throws Exception {
+ // Context of the app under test.
+ Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
+
+ assertEquals("com.getcapacitor.app", appContext.getPackageName());
+ }
+}
diff --git a/x/examples/outline-pwa/android/app/src/main/AndroidManifest.xml b/x/examples/outline-pwa/android/app/src/main/AndroidManifest.xml
new file mode 100644
index 00000000..4d7ca380
--- /dev/null
+++ b/x/examples/outline-pwa/android/app/src/main/AndroidManifest.xml
@@ -0,0 +1,41 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/x/examples/outline-pwa/android/app/src/main/java/org/getoutline/pwa/MainActivity.kt b/x/examples/outline-pwa/android/app/src/main/java/org/getoutline/pwa/MainActivity.kt
new file mode 100644
index 00000000..f796a67f
--- /dev/null
+++ b/x/examples/outline-pwa/android/app/src/main/java/org/getoutline/pwa/MainActivity.kt
@@ -0,0 +1,53 @@
+package org.getoutline.pwa
+
+import android.os.Bundle
+import com.getcapacitor.BridgeActivity
+
+import mobileproxy.*
+
+import androidx.webkit.ProxyConfig
+import androidx.webkit.ProxyController
+import androidx.webkit.WebViewFeature
+
+// TODO: resize webview so the web content is not occluded by the device UI
+class MainActivity : BridgeActivity() {
+ private var proxy: Proxy? = null;
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+
+ if (WebViewFeature.isFeatureSupported(WebViewFeature.PROXY_OVERRIDE)) {
+ this.proxy = Mobileproxy.runProxy(
+ "127.0.0.1:0",
+ Mobileproxy.newSmartStreamDialer(
+ Mobileproxy.newListFromLines("www.radiozamaneh.com"),
+ "{\"dns\":[{\"https\":{\"name\":\"9.9.9.9\"}}],\"tls\":[\"\",\"split:1\",\"split:2\",\"tlsfrag:1\"]}",
+ Mobileproxy.newStderrLogWriter()
+ )
+ )
+
+ // NOTE: this affects all requests in the application
+ ProxyController.getInstance()
+ .setProxyOverride(
+ ProxyConfig.Builder()
+ .addProxyRule(this.proxy!!.address())
+ .build(),
+ {
+ runOnUiThread {
+ // Capacitor does not expose a way to defer the loading of the webview,
+ // so we simply refresh the page
+ this.bridge.webView.reload()
+ }
+ },
+ {}
+ )
+ }
+ }
+
+ override fun onDestroy() {
+ this.proxy?.stop(3000)
+ this.proxy = null
+
+ super.onDestroy()
+ }
+}
\ No newline at end of file
diff --git a/x/examples/outline-pwa/android/app/src/main/res/drawable-land-hdpi/splash.png b/x/examples/outline-pwa/android/app/src/main/res/drawable-land-hdpi/splash.png
new file mode 100644
index 00000000..e31573b4
Binary files /dev/null and b/x/examples/outline-pwa/android/app/src/main/res/drawable-land-hdpi/splash.png differ
diff --git a/x/examples/outline-pwa/android/app/src/main/res/drawable-land-mdpi/splash.png b/x/examples/outline-pwa/android/app/src/main/res/drawable-land-mdpi/splash.png
new file mode 100644
index 00000000..f7a64923
Binary files /dev/null and b/x/examples/outline-pwa/android/app/src/main/res/drawable-land-mdpi/splash.png differ
diff --git a/x/examples/outline-pwa/android/app/src/main/res/drawable-land-xhdpi/splash.png b/x/examples/outline-pwa/android/app/src/main/res/drawable-land-xhdpi/splash.png
new file mode 100644
index 00000000..80772550
Binary files /dev/null and b/x/examples/outline-pwa/android/app/src/main/res/drawable-land-xhdpi/splash.png differ
diff --git a/x/examples/outline-pwa/android/app/src/main/res/drawable-land-xxhdpi/splash.png b/x/examples/outline-pwa/android/app/src/main/res/drawable-land-xxhdpi/splash.png
new file mode 100644
index 00000000..14c6c8fe
Binary files /dev/null and b/x/examples/outline-pwa/android/app/src/main/res/drawable-land-xxhdpi/splash.png differ
diff --git a/x/examples/outline-pwa/android/app/src/main/res/drawable-land-xxxhdpi/splash.png b/x/examples/outline-pwa/android/app/src/main/res/drawable-land-xxxhdpi/splash.png
new file mode 100644
index 00000000..244ca250
Binary files /dev/null and b/x/examples/outline-pwa/android/app/src/main/res/drawable-land-xxxhdpi/splash.png differ
diff --git a/x/examples/outline-pwa/android/app/src/main/res/drawable-port-hdpi/splash.png b/x/examples/outline-pwa/android/app/src/main/res/drawable-port-hdpi/splash.png
new file mode 100644
index 00000000..74faaa58
Binary files /dev/null and b/x/examples/outline-pwa/android/app/src/main/res/drawable-port-hdpi/splash.png differ
diff --git a/x/examples/outline-pwa/android/app/src/main/res/drawable-port-mdpi/splash.png b/x/examples/outline-pwa/android/app/src/main/res/drawable-port-mdpi/splash.png
new file mode 100644
index 00000000..e944f4ad
Binary files /dev/null and b/x/examples/outline-pwa/android/app/src/main/res/drawable-port-mdpi/splash.png differ
diff --git a/x/examples/outline-pwa/android/app/src/main/res/drawable-port-xhdpi/splash.png b/x/examples/outline-pwa/android/app/src/main/res/drawable-port-xhdpi/splash.png
new file mode 100644
index 00000000..564a82ff
Binary files /dev/null and b/x/examples/outline-pwa/android/app/src/main/res/drawable-port-xhdpi/splash.png differ
diff --git a/x/examples/outline-pwa/android/app/src/main/res/drawable-port-xxhdpi/splash.png b/x/examples/outline-pwa/android/app/src/main/res/drawable-port-xxhdpi/splash.png
new file mode 100644
index 00000000..bfabe687
Binary files /dev/null and b/x/examples/outline-pwa/android/app/src/main/res/drawable-port-xxhdpi/splash.png differ
diff --git a/x/examples/outline-pwa/android/app/src/main/res/drawable-port-xxxhdpi/splash.png b/x/examples/outline-pwa/android/app/src/main/res/drawable-port-xxxhdpi/splash.png
new file mode 100644
index 00000000..69290712
Binary files /dev/null and b/x/examples/outline-pwa/android/app/src/main/res/drawable-port-xxxhdpi/splash.png differ
diff --git a/x/examples/outline-pwa/android/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/x/examples/outline-pwa/android/app/src/main/res/drawable-v24/ic_launcher_foreground.xml
new file mode 100644
index 00000000..c7bd21db
--- /dev/null
+++ b/x/examples/outline-pwa/android/app/src/main/res/drawable-v24/ic_launcher_foreground.xml
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/x/examples/outline-pwa/android/app/src/main/res/drawable/ic_launcher_background.xml b/x/examples/outline-pwa/android/app/src/main/res/drawable/ic_launcher_background.xml
new file mode 100644
index 00000000..d5fccc53
--- /dev/null
+++ b/x/examples/outline-pwa/android/app/src/main/res/drawable/ic_launcher_background.xml
@@ -0,0 +1,170 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/x/examples/outline-pwa/android/app/src/main/res/drawable/splash.png b/x/examples/outline-pwa/android/app/src/main/res/drawable/splash.png
new file mode 100644
index 00000000..f7a64923
Binary files /dev/null and b/x/examples/outline-pwa/android/app/src/main/res/drawable/splash.png differ
diff --git a/x/examples/outline-pwa/android/app/src/main/res/layout/activity_main.xml b/x/examples/outline-pwa/android/app/src/main/res/layout/activity_main.xml
new file mode 100644
index 00000000..b5ad1387
--- /dev/null
+++ b/x/examples/outline-pwa/android/app/src/main/res/layout/activity_main.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
diff --git a/x/examples/outline-pwa/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/x/examples/outline-pwa/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
new file mode 100644
index 00000000..036d09bc
--- /dev/null
+++ b/x/examples/outline-pwa/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/x/examples/outline-pwa/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/x/examples/outline-pwa/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
new file mode 100644
index 00000000..036d09bc
--- /dev/null
+++ b/x/examples/outline-pwa/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/x/examples/outline-pwa/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/x/examples/outline-pwa/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 00000000..c023e505
Binary files /dev/null and b/x/examples/outline-pwa/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ
diff --git a/x/examples/outline-pwa/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png b/x/examples/outline-pwa/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png
new file mode 100644
index 00000000..2127973b
Binary files /dev/null and b/x/examples/outline-pwa/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png differ
diff --git a/x/examples/outline-pwa/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/x/examples/outline-pwa/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
new file mode 100644
index 00000000..b441f37d
Binary files /dev/null and b/x/examples/outline-pwa/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png differ
diff --git a/x/examples/outline-pwa/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/x/examples/outline-pwa/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 00000000..72905b85
Binary files /dev/null and b/x/examples/outline-pwa/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ
diff --git a/x/examples/outline-pwa/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png b/x/examples/outline-pwa/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png
new file mode 100644
index 00000000..8ed0605c
Binary files /dev/null and b/x/examples/outline-pwa/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png differ
diff --git a/x/examples/outline-pwa/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/x/examples/outline-pwa/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
new file mode 100644
index 00000000..9502e47a
Binary files /dev/null and b/x/examples/outline-pwa/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png differ
diff --git a/x/examples/outline-pwa/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/x/examples/outline-pwa/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 00000000..4d1e0771
Binary files /dev/null and b/x/examples/outline-pwa/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ
diff --git a/x/examples/outline-pwa/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png b/x/examples/outline-pwa/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png
new file mode 100644
index 00000000..df0f1588
Binary files /dev/null and b/x/examples/outline-pwa/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png differ
diff --git a/x/examples/outline-pwa/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/x/examples/outline-pwa/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
new file mode 100644
index 00000000..853db043
Binary files /dev/null and b/x/examples/outline-pwa/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png differ
diff --git a/x/examples/outline-pwa/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/x/examples/outline-pwa/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 00000000..6cdf97c1
Binary files /dev/null and b/x/examples/outline-pwa/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/x/examples/outline-pwa/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png b/x/examples/outline-pwa/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png
new file mode 100644
index 00000000..2960cbb6
Binary files /dev/null and b/x/examples/outline-pwa/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png differ
diff --git a/x/examples/outline-pwa/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/x/examples/outline-pwa/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
new file mode 100644
index 00000000..8e3093a8
Binary files /dev/null and b/x/examples/outline-pwa/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png differ
diff --git a/x/examples/outline-pwa/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/x/examples/outline-pwa/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 00000000..46de6e25
Binary files /dev/null and b/x/examples/outline-pwa/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/x/examples/outline-pwa/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png b/x/examples/outline-pwa/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png
new file mode 100644
index 00000000..d2ea9abe
Binary files /dev/null and b/x/examples/outline-pwa/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png differ
diff --git a/x/examples/outline-pwa/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/x/examples/outline-pwa/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
new file mode 100644
index 00000000..a40d73e9
Binary files /dev/null and b/x/examples/outline-pwa/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png differ
diff --git a/x/examples/outline-pwa/android/app/src/main/res/values/ic_launcher_background.xml b/x/examples/outline-pwa/android/app/src/main/res/values/ic_launcher_background.xml
new file mode 100644
index 00000000..c5d5899f
--- /dev/null
+++ b/x/examples/outline-pwa/android/app/src/main/res/values/ic_launcher_background.xml
@@ -0,0 +1,4 @@
+
+
+ #FFFFFF
+
\ No newline at end of file
diff --git a/x/examples/outline-pwa/android/app/src/main/res/values/strings.xml b/x/examples/outline-pwa/android/app/src/main/res/values/strings.xml
new file mode 100644
index 00000000..e2d4e201
--- /dev/null
+++ b/x/examples/outline-pwa/android/app/src/main/res/values/strings.xml
@@ -0,0 +1,7 @@
+
+
+ outline-pwa-demo
+ outline-pwa-demo
+ org.getoutline.pwa
+ org.getoutline.pwa
+
diff --git a/x/examples/outline-pwa/android/app/src/main/res/values/styles.xml b/x/examples/outline-pwa/android/app/src/main/res/values/styles.xml
new file mode 100644
index 00000000..be874e54
--- /dev/null
+++ b/x/examples/outline-pwa/android/app/src/main/res/values/styles.xml
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/x/examples/outline-pwa/android/app/src/main/res/xml/file_paths.xml b/x/examples/outline-pwa/android/app/src/main/res/xml/file_paths.xml
new file mode 100644
index 00000000..bd0c4d80
--- /dev/null
+++ b/x/examples/outline-pwa/android/app/src/main/res/xml/file_paths.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/x/examples/outline-pwa/android/app/src/test/java/com/getcapacitor/myapp/ExampleUnitTest.java b/x/examples/outline-pwa/android/app/src/test/java/com/getcapacitor/myapp/ExampleUnitTest.java
new file mode 100644
index 00000000..02973278
--- /dev/null
+++ b/x/examples/outline-pwa/android/app/src/test/java/com/getcapacitor/myapp/ExampleUnitTest.java
@@ -0,0 +1,18 @@
+package com.getcapacitor.myapp;
+
+import static org.junit.Assert.*;
+
+import org.junit.Test;
+
+/**
+ * Example local unit test, which will execute on the development machine (host).
+ *
+ * @see Testing documentation
+ */
+public class ExampleUnitTest {
+
+ @Test
+ public void addition_isCorrect() throws Exception {
+ assertEquals(4, 2 + 2);
+ }
+}
diff --git a/x/examples/outline-pwa/android/build.gradle b/x/examples/outline-pwa/android/build.gradle
new file mode 100644
index 00000000..1ce9fbcb
--- /dev/null
+++ b/x/examples/outline-pwa/android/build.gradle
@@ -0,0 +1,33 @@
+// Top-level build file where you can add configuration options common to all sub-projects/modules.
+
+buildscript {
+
+ ext {
+ kotlin_version = '1.9.22'
+ }
+ repositories {
+ google()
+ mavenCentral()
+ }
+ dependencies {
+ classpath 'com.android.tools.build:gradle:8.2.1'
+ classpath 'com.google.gms:google-services:4.4.0'
+ classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
+
+ // NOTE: Do not place your application dependencies here; they belong
+ // in the individual module build.gradle files
+ }
+}
+
+apply from: "variables.gradle"
+
+allprojects {
+ repositories {
+ google()
+ mavenCentral()
+ }
+}
+
+task clean(type: Delete) {
+ delete rootProject.buildDir
+}
diff --git a/x/examples/outline-pwa/android/capacitor.settings.gradle b/x/examples/outline-pwa/android/capacitor.settings.gradle
new file mode 100644
index 00000000..ee1ef758
--- /dev/null
+++ b/x/examples/outline-pwa/android/capacitor.settings.gradle
@@ -0,0 +1,9 @@
+// DO NOT EDIT THIS FILE! IT IS GENERATED EACH TIME "capacitor update" IS RUN
+include ':capacitor-android'
+project(':capacitor-android').projectDir = new File('../node_modules/@capacitor/android/capacitor')
+
+include ':capacitor-camera'
+project(':capacitor-camera').projectDir = new File('../node_modules/@capacitor/camera/android')
+
+include ':capacitor-splash-screen'
+project(':capacitor-splash-screen').projectDir = new File('../node_modules/@capacitor/splash-screen/android')
diff --git a/x/examples/outline-pwa/android/gradle.properties b/x/examples/outline-pwa/android/gradle.properties
new file mode 100644
index 00000000..2e87c52f
--- /dev/null
+++ b/x/examples/outline-pwa/android/gradle.properties
@@ -0,0 +1,22 @@
+# Project-wide Gradle settings.
+
+# IDE (e.g. Android Studio) users:
+# Gradle settings configured through the IDE *will override*
+# any settings specified in this file.
+
+# For more details on how to configure your build environment visit
+# http://www.gradle.org/docs/current/userguide/build_environment.html
+
+# Specifies the JVM arguments used for the daemon process.
+# The setting is particularly useful for tweaking memory settings.
+org.gradle.jvmargs=-Xmx1536m
+
+# When configured, Gradle will run in incubating parallel mode.
+# This option should only be used with decoupled projects. More details, visit
+# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
+# org.gradle.parallel=true
+
+# AndroidX package structure to make it clearer which packages are bundled with the
+# Android operating system, and which are packaged with your app's APK
+# https://developer.android.com/topic/libraries/support-library/androidx-rn
+android.useAndroidX=true
diff --git a/x/examples/outline-pwa/android/gradle/wrapper/gradle-wrapper.jar b/x/examples/outline-pwa/android/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 00000000..033e24c4
Binary files /dev/null and b/x/examples/outline-pwa/android/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/x/examples/outline-pwa/android/gradle/wrapper/gradle-wrapper.properties b/x/examples/outline-pwa/android/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 00000000..c747538f
--- /dev/null
+++ b/x/examples/outline-pwa/android/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,7 @@
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.2.1-all.zip
+networkTimeout=10000
+validateDistributionUrl=true
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
diff --git a/x/examples/outline-pwa/android/gradlew b/x/examples/outline-pwa/android/gradlew
new file mode 100755
index 00000000..fcb6fca1
--- /dev/null
+++ b/x/examples/outline-pwa/android/gradlew
@@ -0,0 +1,248 @@
+#!/bin/sh
+
+#
+# Copyright © 2015-2021 the original authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+##############################################################################
+#
+# Gradle start up script for POSIX generated by Gradle.
+#
+# Important for running:
+#
+# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
+# noncompliant, but you have some other compliant shell such as ksh or
+# bash, then to run this script, type that shell name before the whole
+# command line, like:
+#
+# ksh Gradle
+#
+# Busybox and similar reduced shells will NOT work, because this script
+# requires all of these POSIX shell features:
+# * functions;
+# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
+# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
+# * compound commands having a testable exit status, especially «case»;
+# * various built-in commands including «command», «set», and «ulimit».
+#
+# Important for patching:
+#
+# (2) This script targets any POSIX shell, so it avoids extensions provided
+# by Bash, Ksh, etc; in particular arrays are avoided.
+#
+# The "traditional" practice of packing multiple parameters into a
+# space-separated string is a well documented source of bugs and security
+# problems, so this is (mostly) avoided, by progressively accumulating
+# options in "$@", and eventually passing that to Java.
+#
+# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
+# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
+# see the in-line comments for details.
+#
+# There are tweaks for specific operating systems such as AIX, CygWin,
+# Darwin, MinGW, and NonStop.
+#
+# (3) This script is generated from the Groovy template
+# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# within the Gradle project.
+#
+# You can find Gradle at https://github.com/gradle/gradle/.
+#
+##############################################################################
+
+# Attempt to set APP_HOME
+
+# Resolve links: $0 may be a link
+app_path=$0
+
+# Need this for daisy-chained symlinks.
+while
+ APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
+ [ -h "$app_path" ]
+do
+ ls=$( ls -ld "$app_path" )
+ link=${ls#*' -> '}
+ case $link in #(
+ /*) app_path=$link ;; #(
+ *) app_path=$APP_HOME$link ;;
+ esac
+done
+
+# This is normally unused
+# shellcheck disable=SC2034
+APP_BASE_NAME=${0##*/}
+APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD=maximum
+
+warn () {
+ echo "$*"
+} >&2
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+} >&2
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "$( uname )" in #(
+ CYGWIN* ) cygwin=true ;; #(
+ Darwin* ) darwin=true ;; #(
+ MSYS* | MINGW* ) msys=true ;; #(
+ NONSTOP* ) nonstop=true ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD=$JAVA_HOME/jre/sh/java
+ else
+ JAVACMD=$JAVA_HOME/bin/java
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD=java
+ if ! command -v java >/dev/null 2>&1
+ then
+ die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+fi
+
+# Increase the maximum file descriptors if we can.
+if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
+ case $MAX_FD in #(
+ max*)
+ # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
+ # shellcheck disable=SC3045
+ MAX_FD=$( ulimit -H -n ) ||
+ warn "Could not query maximum file descriptor limit"
+ esac
+ case $MAX_FD in #(
+ '' | soft) :;; #(
+ *)
+ # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
+ # shellcheck disable=SC3045
+ ulimit -n "$MAX_FD" ||
+ warn "Could not set maximum file descriptor limit to $MAX_FD"
+ esac
+fi
+
+# Collect all arguments for the java command, stacking in reverse order:
+# * args from the command line
+# * the main class name
+# * -classpath
+# * -D...appname settings
+# * --module-path (only if needed)
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
+
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if "$cygwin" || "$msys" ; then
+ APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
+ CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
+
+ JAVACMD=$( cygpath --unix "$JAVACMD" )
+
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ for arg do
+ if
+ case $arg in #(
+ -*) false ;; # don't mess with options #(
+ /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
+ [ -e "$t" ] ;; #(
+ *) false ;;
+ esac
+ then
+ arg=$( cygpath --path --ignore --mixed "$arg" )
+ fi
+ # Roll the args list around exactly as many times as the number of
+ # args, so each arg winds up back in the position where it started, but
+ # possibly modified.
+ #
+ # NB: a `for` loop captures its iteration list before it begins, so
+ # changing the positional parameters here affects neither the number of
+ # iterations, nor the values presented in `arg`.
+ shift # remove old arg
+ set -- "$@" "$arg" # push replacement arg
+ done
+fi
+
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
+# Collect all arguments for the java command;
+# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
+# shell script including quotes and variable substitutions, so put them in
+# double quotes to make sure that they get re-expanded; and
+# * put everything else in single quotes, so that it's not re-expanded.
+
+set -- \
+ "-Dorg.gradle.appname=$APP_BASE_NAME" \
+ -classpath "$CLASSPATH" \
+ org.gradle.wrapper.GradleWrapperMain \
+ "$@"
+
+# Stop when "xargs" is not available.
+if ! command -v xargs >/dev/null 2>&1
+then
+ die "xargs is not available"
+fi
+
+# Use "xargs" to parse quoted args.
+#
+# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
+#
+# In Bash we could simply go:
+#
+# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
+# set -- "${ARGS[@]}" "$@"
+#
+# but POSIX shell has neither arrays nor command substitution, so instead we
+# post-process each arg (as a line of input to sed) to backslash-escape any
+# character that might be a shell metacharacter, then use eval to reverse
+# that process (while maintaining the separation between arguments), and wrap
+# the whole thing up as a single "set" statement.
+#
+# This will of course break if any of these variables contains a newline or
+# an unmatched quote.
+#
+
+eval "set -- $(
+ printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
+ xargs -n1 |
+ sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
+ tr '\n' ' '
+ )" '"$@"'
+
+exec "$JAVACMD" "$@"
diff --git a/x/examples/outline-pwa/android/gradlew.bat b/x/examples/outline-pwa/android/gradlew.bat
new file mode 100644
index 00000000..6689b85b
--- /dev/null
+++ b/x/examples/outline-pwa/android/gradlew.bat
@@ -0,0 +1,92 @@
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem https://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+
+@if "%DEBUG%"=="" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%"=="" set DIRNAME=.
+@rem This is normally unused
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Resolve any "." and ".." in APP_HOME to make it shorter.
+for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if %ERRORLEVEL% equ 0 goto execute
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto execute
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+
+:end
+@rem End local scope for the variables with windows NT shell
+if %ERRORLEVEL% equ 0 goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+set EXIT_CODE=%ERRORLEVEL%
+if %EXIT_CODE% equ 0 set EXIT_CODE=1
+if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
+exit /b %EXIT_CODE%
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/x/examples/outline-pwa/android/settings.gradle b/x/examples/outline-pwa/android/settings.gradle
new file mode 100644
index 00000000..3b4431d7
--- /dev/null
+++ b/x/examples/outline-pwa/android/settings.gradle
@@ -0,0 +1,5 @@
+include ':app'
+include ':capacitor-cordova-android-plugins'
+project(':capacitor-cordova-android-plugins').projectDir = new File('./capacitor-cordova-android-plugins/')
+
+apply from: 'capacitor.settings.gradle'
\ No newline at end of file
diff --git a/x/examples/outline-pwa/android/variables.gradle b/x/examples/outline-pwa/android/variables.gradle
new file mode 100644
index 00000000..b9e2db79
--- /dev/null
+++ b/x/examples/outline-pwa/android/variables.gradle
@@ -0,0 +1,16 @@
+ext {
+ minSdkVersion = 26
+ compileSdkVersion = 35
+ targetSdkVersion = 35
+ androidxActivityVersion = '1.8.0'
+ androidxAppCompatVersion = '1.6.1'
+ androidxCoordinatorLayoutVersion = '1.2.0'
+ androidxCoreVersion = '1.12.0'
+ androidxFragmentVersion = '1.6.2'
+ coreSplashScreenVersion = '1.0.1'
+ androidxWebkitVersion = '1.9.0'
+ junitVersion = '4.13.2'
+ androidxJunitVersion = '1.1.5'
+ androidxEspressoCoreVersion = '3.5.1'
+ cordovaAndroidVersion = '10.1.1'
+}
\ No newline at end of file
diff --git a/x/examples/outline-pwa/capacitor.config.json b/x/examples/outline-pwa/capacitor.config.json
new file mode 100644
index 00000000..5259269f
--- /dev/null
+++ b/x/examples/outline-pwa/capacitor.config.json
@@ -0,0 +1,16 @@
+{
+ "appId": "org.getoutline.pwa",
+ "appName": "outline-pwa-demo",
+ "bundledWebRuntime": false,
+ "plugins": {
+ "SplashScreen": {
+ "launchShowDuration": 0
+ }
+ },
+ "server": {
+ "url": "https://www.radiozamaneh.com/"
+ },
+ "ios": {
+ "limitsNavigationsToAppBoundDomains": true
+ }
+}
diff --git a/x/examples/outline-pwa/generated/mobileproxy.aar b/x/examples/outline-pwa/generated/mobileproxy.aar
new file mode 100644
index 00000000..44d5d6df
Binary files /dev/null and b/x/examples/outline-pwa/generated/mobileproxy.aar differ
diff --git a/x/examples/outline-pwa/generated/mobileproxy.xcframework/Info.plist b/x/examples/outline-pwa/generated/mobileproxy.xcframework/Info.plist
new file mode 100644
index 00000000..62d0845e
--- /dev/null
+++ b/x/examples/outline-pwa/generated/mobileproxy.xcframework/Info.plist
@@ -0,0 +1,44 @@
+
+
+
+
+ AvailableLibraries
+
+
+ BinaryPath
+ Mobileproxy.framework/Mobileproxy
+ LibraryIdentifier
+ ios-arm64_x86_64-simulator
+ LibraryPath
+ Mobileproxy.framework
+ SupportedArchitectures
+
+ arm64
+ x86_64
+
+ SupportedPlatform
+ ios
+ SupportedPlatformVariant
+ simulator
+
+
+ BinaryPath
+ Mobileproxy.framework/Mobileproxy
+ LibraryIdentifier
+ ios-arm64
+ LibraryPath
+ Mobileproxy.framework
+ SupportedArchitectures
+
+ arm64
+
+ SupportedPlatform
+ ios
+
+
+ CFBundlePackageType
+ XFWK
+ XCFrameworkFormatVersion
+ 1.0
+
+
diff --git a/x/examples/outline-pwa/generated/mobileproxy.xcframework/ios-arm64/Mobileproxy.framework/Headers/Mobileproxy.h b/x/examples/outline-pwa/generated/mobileproxy.xcframework/ios-arm64/Mobileproxy.framework/Headers/Mobileproxy.h
new file mode 100644
index 00000000..159d63a6
--- /dev/null
+++ b/x/examples/outline-pwa/generated/mobileproxy.xcframework/ios-arm64/Mobileproxy.framework/Headers/Mobileproxy.h
@@ -0,0 +1,13 @@
+
+// Objective-C API for talking to the following Go packages
+//
+// github.com/Jigsaw-Code/outline-sdk/x/mobileproxy
+//
+// File is generated by gomobile bind. Do not edit.
+#ifndef __Mobileproxy_FRAMEWORK_H__
+#define __Mobileproxy_FRAMEWORK_H__
+
+#include "Mobileproxy.objc.h"
+#include "Universe.objc.h"
+
+#endif
diff --git a/x/examples/outline-pwa/generated/mobileproxy.xcframework/ios-arm64/Mobileproxy.framework/Headers/Mobileproxy.objc.h b/x/examples/outline-pwa/generated/mobileproxy.xcframework/ios-arm64/Mobileproxy.framework/Headers/Mobileproxy.objc.h
new file mode 100644
index 00000000..b166ffe7
--- /dev/null
+++ b/x/examples/outline-pwa/generated/mobileproxy.xcframework/ios-arm64/Mobileproxy.framework/Headers/Mobileproxy.objc.h
@@ -0,0 +1,148 @@
+// Objective-C API for talking to github.com/Jigsaw-Code/outline-sdk/x/mobileproxy Go package.
+// gobind -lang=objc github.com/Jigsaw-Code/outline-sdk/x/mobileproxy
+//
+// File is generated by gobind. Do not edit.
+
+#ifndef __Mobileproxy_H__
+#define __Mobileproxy_H__
+
+@import Foundation;
+#include "ref.h"
+#include "Universe.objc.h"
+
+
+@class MobileproxyProxy;
+@class MobileproxyStreamDialer;
+@class MobileproxyStringList;
+@protocol MobileproxyLogWriter;
+@class MobileproxyLogWriter;
+
+@protocol MobileproxyLogWriter
+- (BOOL)writeString:(NSString* _Nullable)s n:(long* _Nullable)n error:(NSError* _Nullable* _Nullable)error;
+@end
+
+/**
+ * Proxy enables you to get the actual address bound by the server and stop the service when no longer needed.
+ */
+@interface MobileproxyProxy : NSObject {
+}
+@property(strong, readonly) _Nonnull id _ref;
+
+- (nonnull instancetype)initWithRef:(_Nonnull id)ref;
+- (nonnull instancetype)init;
+/**
+ * AddURLProxy sets up a URL-based proxy handler that activates when an incoming HTTP request matches
+the specified path prefix. The pattern must represent a path segment, which is checked against
+the path of the incoming request.
+
+This function is particularly useful for libraries or components that accept URLs but do not support proxy
+configuration directly. By leveraging AddURLProxy, such components can route requests through a proxy by
+constructing URLs in the format "http://${HOST}:${PORT}/${PATH}/${URL}", where "${URL}" is the target resource.
+For instance, using "http://localhost:8080/proxy/https://example.com" routes the request for "https://example.com"
+through a proxy at "http://localhost:8080/proxy".
+
+The path should start with a forward slash ('/') for clarity, but one will be added if missing.
+
+The function associates the given 'dialer' with the specified 'path', allowing different dialers to be used for
+different path-based proxies within the same application in the future. currently we only support one URL proxy.
+ */
+- (void)addURLProxy:(NSString* _Nullable)path dialer:(MobileproxyStreamDialer* _Nullable)dialer;
+/**
+ * Address returns the IP and port the server is bound to.
+ */
+- (NSString* _Nonnull)address;
+/**
+ * Host returns the IP the server is bound to.
+ */
+- (NSString* _Nonnull)host;
+/**
+ * Port returns the port the server is bound to.
+ */
+- (long)port;
+/**
+ * Stop gracefully stops the proxy service, waiting for at most timeout seconds before forcefully closing it.
+The function takes a timeoutSeconds number instead of a [time.Duration] so it's compatible with Go Mobile.
+ */
+- (void)stop:(long)timeoutSeconds;
+@end
+
+/**
+ * StreamDialer encapsulates the logic to create stream connections (like TCP).
+ */
+@interface MobileproxyStreamDialer : NSObject {
+}
+@property(strong, readonly) _Nonnull id _ref;
+
+- (nonnull instancetype)initWithRef:(_Nonnull id)ref;
+/**
+ * NewStreamDialerFromConfig creates a [StreamDialer] based on the given config.
+The config format is specified in https://pkg.go.dev/github.com/Jigsaw-Code/outline-sdk/x/config#hdr-Config_Format.
+ */
+- (nullable instancetype)initFromConfig:(NSString* _Nullable)transportConfig;
+// skipped field StreamDialer.StreamDialer with unsupported type: github.com/Jigsaw-Code/outline-sdk/transport.StreamDialer
+
+// skipped method StreamDialer.DialStream with unsupported parameter or return types
+
+@end
+
+/**
+ * StringList allows us to pass a list of strings to the Go Mobile functions, since Go Mobile doesn't
+support slices as parameters.
+ */
+@interface MobileproxyStringList : NSObject {
+}
+@property(strong, readonly) _Nonnull id _ref;
+
+- (nonnull instancetype)initWithRef:(_Nonnull id)ref;
+- (nonnull instancetype)init;
+/**
+ * Append adds the string value to the end of the list.
+ */
+- (void)append:(NSString* _Nullable)value;
+@end
+
+/**
+ * NewListFromLines creates a StringList by splitting the input string on new lines.
+ */
+FOUNDATION_EXPORT MobileproxyStringList* _Nullable MobileproxyNewListFromLines(NSString* _Nullable lines);
+
+/**
+ * NewSmartStreamDialer automatically selects a DNS and TLS strategy to use, and returns a [StreamDialer]
+that will use the selected strategy.
+It uses testDomains to find a strategy that works when accessing those domains.
+The strategies to search are given in the searchConfig. An example can be found in
+https://github.com/Jigsaw-Code/outline-sdk/x/examples/smart-proxy/config.json
+ */
+FOUNDATION_EXPORT MobileproxyStreamDialer* _Nullable MobileproxyNewSmartStreamDialer(MobileproxyStringList* _Nullable testDomains, NSString* _Nullable searchConfig, id _Nullable logWriter, NSError* _Nullable* _Nullable error);
+
+/**
+ * NewStderrLogWriter creates a [LogWriter] that writes to the standard error output.
+ */
+FOUNDATION_EXPORT id _Nullable MobileproxyNewStderrLogWriter(void);
+
+/**
+ * NewStreamDialerFromConfig creates a [StreamDialer] based on the given config.
+The config format is specified in https://pkg.go.dev/github.com/Jigsaw-Code/outline-sdk/x/config#hdr-Config_Format.
+ */
+FOUNDATION_EXPORT MobileproxyStreamDialer* _Nullable MobileproxyNewStreamDialerFromConfig(NSString* _Nullable transportConfig, NSError* _Nullable* _Nullable error);
+
+/**
+ * RunProxy runs a local web proxy that listens on localAddress, and handles proxy requests by
+establishing connections to requested destination using the [StreamDialer].
+ */
+FOUNDATION_EXPORT MobileproxyProxy* _Nullable MobileproxyRunProxy(NSString* _Nullable localAddress, MobileproxyStreamDialer* _Nullable dialer, NSError* _Nullable* _Nullable error);
+
+@class MobileproxyLogWriter;
+
+/**
+ * LogWriter is used as a sink for logging.
+ */
+@interface MobileproxyLogWriter : NSObject {
+}
+@property(strong, readonly) _Nonnull id _ref;
+
+- (nonnull instancetype)initWithRef:(_Nonnull id)ref;
+- (BOOL)writeString:(NSString* _Nullable)s n:(long* _Nullable)n error:(NSError* _Nullable* _Nullable)error;
+@end
+
+#endif
diff --git a/x/examples/outline-pwa/generated/mobileproxy.xcframework/ios-arm64/Mobileproxy.framework/Headers/Universe.objc.h b/x/examples/outline-pwa/generated/mobileproxy.xcframework/ios-arm64/Mobileproxy.framework/Headers/Universe.objc.h
new file mode 100644
index 00000000..019e7502
--- /dev/null
+++ b/x/examples/outline-pwa/generated/mobileproxy.xcframework/ios-arm64/Mobileproxy.framework/Headers/Universe.objc.h
@@ -0,0 +1,29 @@
+// Objective-C API for talking to Go package.
+// gobind -lang=objc
+//
+// File is generated by gobind. Do not edit.
+
+#ifndef __Universe_H__
+#define __Universe_H__
+
+@import Foundation;
+#include "ref.h"
+
+@protocol Universeerror;
+@class Universeerror;
+
+@protocol Universeerror
+- (NSString* _Nonnull)error;
+@end
+
+@class Universeerror;
+
+@interface Universeerror : NSError {
+}
+@property(strong, readonly) _Nonnull id _ref;
+
+- (nonnull instancetype)initWithRef:(_Nonnull id)ref;
+- (NSString* _Nonnull)error;
+@end
+
+#endif
diff --git a/x/examples/outline-pwa/generated/mobileproxy.xcframework/ios-arm64/Mobileproxy.framework/Headers/ref.h b/x/examples/outline-pwa/generated/mobileproxy.xcframework/ios-arm64/Mobileproxy.framework/Headers/ref.h
new file mode 100644
index 00000000..b8036a4d
--- /dev/null
+++ b/x/examples/outline-pwa/generated/mobileproxy.xcframework/ios-arm64/Mobileproxy.framework/Headers/ref.h
@@ -0,0 +1,35 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#ifndef __GO_REF_HDR__
+#define __GO_REF_HDR__
+
+#include
+
+// GoSeqRef is an object tagged with an integer for passing back and
+// forth across the language boundary. A GoSeqRef may represent either
+// an instance of a Go object, or an Objective-C object passed to Go.
+// The explicit allocation of a GoSeqRef is used to pin a Go object
+// when it is passed to Objective-C. The Go seq package maintains a
+// reference to the Go object in a map keyed by the refnum along with
+// a reference count. When the reference count reaches zero, the Go
+// seq package will clear the corresponding entry in the map.
+@interface GoSeqRef : NSObject {
+}
+@property(readonly) int32_t refnum;
+@property(strong) id obj; // NULL when representing a Go object.
+
+// new GoSeqRef object to proxy a Go object. The refnum must be
+// provided from Go side.
+- (instancetype)initWithRefnum:(int32_t)refnum obj:(id)obj;
+
+- (int32_t)incNum;
+
+@end
+
+@protocol goSeqRefInterface
+-(GoSeqRef*) _ref;
+@end
+
+#endif
diff --git a/x/examples/outline-pwa/generated/mobileproxy.xcframework/ios-arm64/Mobileproxy.framework/Info.plist b/x/examples/outline-pwa/generated/mobileproxy.xcframework/ios-arm64/Mobileproxy.framework/Info.plist
new file mode 100644
index 00000000..0f143214
--- /dev/null
+++ b/x/examples/outline-pwa/generated/mobileproxy.xcframework/ios-arm64/Mobileproxy.framework/Info.plist
@@ -0,0 +1,18 @@
+
+
+
+
+ CFBundleExecutable
+ Mobileproxy
+ CFBundleIdentifier
+ Mobileproxy
+ MinimumOSVersion
+ 100.0
+ CFBundleShortVersionString
+ 0.0.1728590684
+ CFBundleVersion
+ 0.0.1728590684
+ CFBundlePackageType
+ FMWK
+
+
diff --git a/x/examples/outline-pwa/generated/mobileproxy.xcframework/ios-arm64/Mobileproxy.framework/Mobileproxy b/x/examples/outline-pwa/generated/mobileproxy.xcframework/ios-arm64/Mobileproxy.framework/Mobileproxy
new file mode 100644
index 00000000..9a63f2cf
Binary files /dev/null and b/x/examples/outline-pwa/generated/mobileproxy.xcframework/ios-arm64/Mobileproxy.framework/Mobileproxy differ
diff --git a/x/examples/outline-pwa/generated/mobileproxy.xcframework/ios-arm64/Mobileproxy.framework/Modules/module.modulemap b/x/examples/outline-pwa/generated/mobileproxy.xcframework/ios-arm64/Mobileproxy.framework/Modules/module.modulemap
new file mode 100644
index 00000000..93a1988a
--- /dev/null
+++ b/x/examples/outline-pwa/generated/mobileproxy.xcframework/ios-arm64/Mobileproxy.framework/Modules/module.modulemap
@@ -0,0 +1,8 @@
+framework module "Mobileproxy" {
+ header "ref.h"
+ header "Mobileproxy.objc.h"
+ header "Universe.objc.h"
+ header "Mobileproxy.h"
+
+ export *
+}
\ No newline at end of file
diff --git a/x/examples/outline-pwa/generated/mobileproxy.xcframework/ios-arm64_x86_64-simulator/Mobileproxy.framework/Headers/Mobileproxy.h b/x/examples/outline-pwa/generated/mobileproxy.xcframework/ios-arm64_x86_64-simulator/Mobileproxy.framework/Headers/Mobileproxy.h
new file mode 100644
index 00000000..159d63a6
--- /dev/null
+++ b/x/examples/outline-pwa/generated/mobileproxy.xcframework/ios-arm64_x86_64-simulator/Mobileproxy.framework/Headers/Mobileproxy.h
@@ -0,0 +1,13 @@
+
+// Objective-C API for talking to the following Go packages
+//
+// github.com/Jigsaw-Code/outline-sdk/x/mobileproxy
+//
+// File is generated by gomobile bind. Do not edit.
+#ifndef __Mobileproxy_FRAMEWORK_H__
+#define __Mobileproxy_FRAMEWORK_H__
+
+#include "Mobileproxy.objc.h"
+#include "Universe.objc.h"
+
+#endif
diff --git a/x/examples/outline-pwa/generated/mobileproxy.xcframework/ios-arm64_x86_64-simulator/Mobileproxy.framework/Headers/Mobileproxy.objc.h b/x/examples/outline-pwa/generated/mobileproxy.xcframework/ios-arm64_x86_64-simulator/Mobileproxy.framework/Headers/Mobileproxy.objc.h
new file mode 100644
index 00000000..b166ffe7
--- /dev/null
+++ b/x/examples/outline-pwa/generated/mobileproxy.xcframework/ios-arm64_x86_64-simulator/Mobileproxy.framework/Headers/Mobileproxy.objc.h
@@ -0,0 +1,148 @@
+// Objective-C API for talking to github.com/Jigsaw-Code/outline-sdk/x/mobileproxy Go package.
+// gobind -lang=objc github.com/Jigsaw-Code/outline-sdk/x/mobileproxy
+//
+// File is generated by gobind. Do not edit.
+
+#ifndef __Mobileproxy_H__
+#define __Mobileproxy_H__
+
+@import Foundation;
+#include "ref.h"
+#include "Universe.objc.h"
+
+
+@class MobileproxyProxy;
+@class MobileproxyStreamDialer;
+@class MobileproxyStringList;
+@protocol MobileproxyLogWriter;
+@class MobileproxyLogWriter;
+
+@protocol MobileproxyLogWriter
+- (BOOL)writeString:(NSString* _Nullable)s n:(long* _Nullable)n error:(NSError* _Nullable* _Nullable)error;
+@end
+
+/**
+ * Proxy enables you to get the actual address bound by the server and stop the service when no longer needed.
+ */
+@interface MobileproxyProxy : NSObject {
+}
+@property(strong, readonly) _Nonnull id _ref;
+
+- (nonnull instancetype)initWithRef:(_Nonnull id)ref;
+- (nonnull instancetype)init;
+/**
+ * AddURLProxy sets up a URL-based proxy handler that activates when an incoming HTTP request matches
+the specified path prefix. The pattern must represent a path segment, which is checked against
+the path of the incoming request.
+
+This function is particularly useful for libraries or components that accept URLs but do not support proxy
+configuration directly. By leveraging AddURLProxy, such components can route requests through a proxy by
+constructing URLs in the format "http://${HOST}:${PORT}/${PATH}/${URL}", where "${URL}" is the target resource.
+For instance, using "http://localhost:8080/proxy/https://example.com" routes the request for "https://example.com"
+through a proxy at "http://localhost:8080/proxy".
+
+The path should start with a forward slash ('/') for clarity, but one will be added if missing.
+
+The function associates the given 'dialer' with the specified 'path', allowing different dialers to be used for
+different path-based proxies within the same application in the future. currently we only support one URL proxy.
+ */
+- (void)addURLProxy:(NSString* _Nullable)path dialer:(MobileproxyStreamDialer* _Nullable)dialer;
+/**
+ * Address returns the IP and port the server is bound to.
+ */
+- (NSString* _Nonnull)address;
+/**
+ * Host returns the IP the server is bound to.
+ */
+- (NSString* _Nonnull)host;
+/**
+ * Port returns the port the server is bound to.
+ */
+- (long)port;
+/**
+ * Stop gracefully stops the proxy service, waiting for at most timeout seconds before forcefully closing it.
+The function takes a timeoutSeconds number instead of a [time.Duration] so it's compatible with Go Mobile.
+ */
+- (void)stop:(long)timeoutSeconds;
+@end
+
+/**
+ * StreamDialer encapsulates the logic to create stream connections (like TCP).
+ */
+@interface MobileproxyStreamDialer : NSObject {
+}
+@property(strong, readonly) _Nonnull id _ref;
+
+- (nonnull instancetype)initWithRef:(_Nonnull id)ref;
+/**
+ * NewStreamDialerFromConfig creates a [StreamDialer] based on the given config.
+The config format is specified in https://pkg.go.dev/github.com/Jigsaw-Code/outline-sdk/x/config#hdr-Config_Format.
+ */
+- (nullable instancetype)initFromConfig:(NSString* _Nullable)transportConfig;
+// skipped field StreamDialer.StreamDialer with unsupported type: github.com/Jigsaw-Code/outline-sdk/transport.StreamDialer
+
+// skipped method StreamDialer.DialStream with unsupported parameter or return types
+
+@end
+
+/**
+ * StringList allows us to pass a list of strings to the Go Mobile functions, since Go Mobile doesn't
+support slices as parameters.
+ */
+@interface MobileproxyStringList : NSObject {
+}
+@property(strong, readonly) _Nonnull id _ref;
+
+- (nonnull instancetype)initWithRef:(_Nonnull id)ref;
+- (nonnull instancetype)init;
+/**
+ * Append adds the string value to the end of the list.
+ */
+- (void)append:(NSString* _Nullable)value;
+@end
+
+/**
+ * NewListFromLines creates a StringList by splitting the input string on new lines.
+ */
+FOUNDATION_EXPORT MobileproxyStringList* _Nullable MobileproxyNewListFromLines(NSString* _Nullable lines);
+
+/**
+ * NewSmartStreamDialer automatically selects a DNS and TLS strategy to use, and returns a [StreamDialer]
+that will use the selected strategy.
+It uses testDomains to find a strategy that works when accessing those domains.
+The strategies to search are given in the searchConfig. An example can be found in
+https://github.com/Jigsaw-Code/outline-sdk/x/examples/smart-proxy/config.json
+ */
+FOUNDATION_EXPORT MobileproxyStreamDialer* _Nullable MobileproxyNewSmartStreamDialer(MobileproxyStringList* _Nullable testDomains, NSString* _Nullable searchConfig, id _Nullable logWriter, NSError* _Nullable* _Nullable error);
+
+/**
+ * NewStderrLogWriter creates a [LogWriter] that writes to the standard error output.
+ */
+FOUNDATION_EXPORT id _Nullable MobileproxyNewStderrLogWriter(void);
+
+/**
+ * NewStreamDialerFromConfig creates a [StreamDialer] based on the given config.
+The config format is specified in https://pkg.go.dev/github.com/Jigsaw-Code/outline-sdk/x/config#hdr-Config_Format.
+ */
+FOUNDATION_EXPORT MobileproxyStreamDialer* _Nullable MobileproxyNewStreamDialerFromConfig(NSString* _Nullable transportConfig, NSError* _Nullable* _Nullable error);
+
+/**
+ * RunProxy runs a local web proxy that listens on localAddress, and handles proxy requests by
+establishing connections to requested destination using the [StreamDialer].
+ */
+FOUNDATION_EXPORT MobileproxyProxy* _Nullable MobileproxyRunProxy(NSString* _Nullable localAddress, MobileproxyStreamDialer* _Nullable dialer, NSError* _Nullable* _Nullable error);
+
+@class MobileproxyLogWriter;
+
+/**
+ * LogWriter is used as a sink for logging.
+ */
+@interface MobileproxyLogWriter : NSObject {
+}
+@property(strong, readonly) _Nonnull id _ref;
+
+- (nonnull instancetype)initWithRef:(_Nonnull id)ref;
+- (BOOL)writeString:(NSString* _Nullable)s n:(long* _Nullable)n error:(NSError* _Nullable* _Nullable)error;
+@end
+
+#endif
diff --git a/x/examples/outline-pwa/generated/mobileproxy.xcframework/ios-arm64_x86_64-simulator/Mobileproxy.framework/Headers/Universe.objc.h b/x/examples/outline-pwa/generated/mobileproxy.xcframework/ios-arm64_x86_64-simulator/Mobileproxy.framework/Headers/Universe.objc.h
new file mode 100644
index 00000000..019e7502
--- /dev/null
+++ b/x/examples/outline-pwa/generated/mobileproxy.xcframework/ios-arm64_x86_64-simulator/Mobileproxy.framework/Headers/Universe.objc.h
@@ -0,0 +1,29 @@
+// Objective-C API for talking to Go package.
+// gobind -lang=objc
+//
+// File is generated by gobind. Do not edit.
+
+#ifndef __Universe_H__
+#define __Universe_H__
+
+@import Foundation;
+#include "ref.h"
+
+@protocol Universeerror;
+@class Universeerror;
+
+@protocol Universeerror
+- (NSString* _Nonnull)error;
+@end
+
+@class Universeerror;
+
+@interface Universeerror : NSError {
+}
+@property(strong, readonly) _Nonnull id _ref;
+
+- (nonnull instancetype)initWithRef:(_Nonnull id)ref;
+- (NSString* _Nonnull)error;
+@end
+
+#endif
diff --git a/x/examples/outline-pwa/generated/mobileproxy.xcframework/ios-arm64_x86_64-simulator/Mobileproxy.framework/Headers/ref.h b/x/examples/outline-pwa/generated/mobileproxy.xcframework/ios-arm64_x86_64-simulator/Mobileproxy.framework/Headers/ref.h
new file mode 100644
index 00000000..b8036a4d
--- /dev/null
+++ b/x/examples/outline-pwa/generated/mobileproxy.xcframework/ios-arm64_x86_64-simulator/Mobileproxy.framework/Headers/ref.h
@@ -0,0 +1,35 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#ifndef __GO_REF_HDR__
+#define __GO_REF_HDR__
+
+#include
+
+// GoSeqRef is an object tagged with an integer for passing back and
+// forth across the language boundary. A GoSeqRef may represent either
+// an instance of a Go object, or an Objective-C object passed to Go.
+// The explicit allocation of a GoSeqRef is used to pin a Go object
+// when it is passed to Objective-C. The Go seq package maintains a
+// reference to the Go object in a map keyed by the refnum along with
+// a reference count. When the reference count reaches zero, the Go
+// seq package will clear the corresponding entry in the map.
+@interface GoSeqRef : NSObject {
+}
+@property(readonly) int32_t refnum;
+@property(strong) id obj; // NULL when representing a Go object.
+
+// new GoSeqRef object to proxy a Go object. The refnum must be
+// provided from Go side.
+- (instancetype)initWithRefnum:(int32_t)refnum obj:(id)obj;
+
+- (int32_t)incNum;
+
+@end
+
+@protocol goSeqRefInterface
+-(GoSeqRef*) _ref;
+@end
+
+#endif
diff --git a/x/examples/outline-pwa/generated/mobileproxy.xcframework/ios-arm64_x86_64-simulator/Mobileproxy.framework/Info.plist b/x/examples/outline-pwa/generated/mobileproxy.xcframework/ios-arm64_x86_64-simulator/Mobileproxy.framework/Info.plist
new file mode 100644
index 00000000..0f143214
--- /dev/null
+++ b/x/examples/outline-pwa/generated/mobileproxy.xcframework/ios-arm64_x86_64-simulator/Mobileproxy.framework/Info.plist
@@ -0,0 +1,18 @@
+
+
+
+
+ CFBundleExecutable
+ Mobileproxy
+ CFBundleIdentifier
+ Mobileproxy
+ MinimumOSVersion
+ 100.0
+ CFBundleShortVersionString
+ 0.0.1728590684
+ CFBundleVersion
+ 0.0.1728590684
+ CFBundlePackageType
+ FMWK
+
+
diff --git a/x/examples/outline-pwa/generated/mobileproxy.xcframework/ios-arm64_x86_64-simulator/Mobileproxy.framework/Mobileproxy b/x/examples/outline-pwa/generated/mobileproxy.xcframework/ios-arm64_x86_64-simulator/Mobileproxy.framework/Mobileproxy
new file mode 100644
index 00000000..b382e5fe
Binary files /dev/null and b/x/examples/outline-pwa/generated/mobileproxy.xcframework/ios-arm64_x86_64-simulator/Mobileproxy.framework/Mobileproxy differ
diff --git a/x/examples/outline-pwa/generated/mobileproxy.xcframework/ios-arm64_x86_64-simulator/Mobileproxy.framework/Modules/module.modulemap b/x/examples/outline-pwa/generated/mobileproxy.xcframework/ios-arm64_x86_64-simulator/Mobileproxy.framework/Modules/module.modulemap
new file mode 100644
index 00000000..93a1988a
--- /dev/null
+++ b/x/examples/outline-pwa/generated/mobileproxy.xcframework/ios-arm64_x86_64-simulator/Mobileproxy.framework/Modules/module.modulemap
@@ -0,0 +1,8 @@
+framework module "Mobileproxy" {
+ header "ref.h"
+ header "Mobileproxy.objc.h"
+ header "Universe.objc.h"
+ header "Mobileproxy.h"
+
+ export *
+}
\ No newline at end of file
diff --git a/x/examples/outline-pwa/ios/.gitignore b/x/examples/outline-pwa/ios/.gitignore
new file mode 100644
index 00000000..f4702997
--- /dev/null
+++ b/x/examples/outline-pwa/ios/.gitignore
@@ -0,0 +1,13 @@
+App/build
+App/Pods
+App/output
+App/App/public
+DerivedData
+xcuserdata
+
+# Cordova plugins for Capacitor
+capacitor-cordova-ios-plugins
+
+# Generated Config files
+App/App/capacitor.config.json
+App/App/config.xml
diff --git a/x/examples/outline-pwa/ios/App/App.xcodeproj/project.pbxproj b/x/examples/outline-pwa/ios/App/App.xcodeproj/project.pbxproj
new file mode 100644
index 00000000..980ef65a
--- /dev/null
+++ b/x/examples/outline-pwa/ios/App/App.xcodeproj/project.pbxproj
@@ -0,0 +1,425 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 54;
+ objects = {
+
+/* Begin PBXBuildFile section */
+ 2FAD9763203C412B000D30F8 /* config.xml in Resources */ = {isa = PBXBuildFile; fileRef = 2FAD9762203C412B000D30F8 /* config.xml */; };
+ 50379B232058CBB4000EE86E /* capacitor.config.json in Resources */ = {isa = PBXBuildFile; fileRef = 50379B222058CBB4000EE86E /* capacitor.config.json */; };
+ 504EC3081FED79650016851F /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 504EC3071FED79650016851F /* AppDelegate.swift */; };
+ 504EC30D1FED79650016851F /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 504EC30B1FED79650016851F /* Main.storyboard */; };
+ 504EC30F1FED79650016851F /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 504EC30E1FED79650016851F /* Assets.xcassets */; };
+ 504EC3121FED79650016851F /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 504EC3101FED79650016851F /* LaunchScreen.storyboard */; };
+ 50B271D11FEDC1A000F3C39B /* public in Resources */ = {isa = PBXBuildFile; fileRef = 50B271D01FEDC1A000F3C39B /* public */; };
+ 65E7FC372CB71E37004207E3 /* OutlineBridgeViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65E7FC362CB71E37004207E3 /* OutlineBridgeViewController.swift */; };
+ 65E7FC3B2CB86B11004207E3 /* mobileproxy.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 65E7FC3A2CB86B11004207E3 /* mobileproxy.xcframework */; };
+ A084ECDBA7D38E1E42DFC39D /* Pods_App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AF277DCFFFF123FFC6DF26C7 /* Pods_App.framework */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXFileReference section */
+ 2FAD9762203C412B000D30F8 /* config.xml */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = config.xml; sourceTree = ""; };
+ 50379B222058CBB4000EE86E /* capacitor.config.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = capacitor.config.json; sourceTree = ""; };
+ 504EC3041FED79650016851F /* App.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = App.app; sourceTree = BUILT_PRODUCTS_DIR; };
+ 504EC3071FED79650016851F /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
+ 504EC30C1FED79650016851F /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
+ 504EC30E1FED79650016851F /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
+ 504EC3111FED79650016851F /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
+ 504EC3131FED79650016851F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
+ 50B271D01FEDC1A000F3C39B /* public */ = {isa = PBXFileReference; lastKnownFileType = folder; path = public; sourceTree = ""; };
+ 65E7FC362CB71E37004207E3 /* OutlineBridgeViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OutlineBridgeViewController.swift; sourceTree = ""; };
+ 65E7FC3A2CB86B11004207E3 /* mobileproxy.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = mobileproxy.xcframework; path = ../../generated/mobileproxy.xcframework; sourceTree = ""; };
+ AF277DCFFFF123FFC6DF26C7 /* Pods_App.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_App.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+ AF51FD2D460BCFE21FA515B2 /* Pods-App.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App.release.xcconfig"; path = "Pods/Target Support Files/Pods-App/Pods-App.release.xcconfig"; sourceTree = ""; };
+ FC68EB0AF532CFC21C3344DD /* Pods-App.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App.debug.xcconfig"; path = "Pods/Target Support Files/Pods-App/Pods-App.debug.xcconfig"; sourceTree = ""; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ 504EC3011FED79650016851F /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 65E7FC3B2CB86B11004207E3 /* mobileproxy.xcframework in Frameworks */,
+ A084ECDBA7D38E1E42DFC39D /* Pods_App.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ 27E2DDA53C4D2A4D1A88CE4A /* Frameworks */ = {
+ isa = PBXGroup;
+ children = (
+ 65E7FC3A2CB86B11004207E3 /* mobileproxy.xcframework */,
+ AF277DCFFFF123FFC6DF26C7 /* Pods_App.framework */,
+ );
+ name = Frameworks;
+ sourceTree = "";
+ };
+ 504EC2FB1FED79650016851F = {
+ isa = PBXGroup;
+ children = (
+ 504EC3061FED79650016851F /* App */,
+ 504EC3051FED79650016851F /* Products */,
+ 7F8756D8B27F46E3366F6CEA /* Pods */,
+ 27E2DDA53C4D2A4D1A88CE4A /* Frameworks */,
+ );
+ sourceTree = "";
+ };
+ 504EC3051FED79650016851F /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ 504EC3041FED79650016851F /* App.app */,
+ );
+ name = Products;
+ sourceTree = "";
+ };
+ 504EC3061FED79650016851F /* App */ = {
+ isa = PBXGroup;
+ children = (
+ 50379B222058CBB4000EE86E /* capacitor.config.json */,
+ 504EC3071FED79650016851F /* AppDelegate.swift */,
+ 504EC30B1FED79650016851F /* Main.storyboard */,
+ 504EC30E1FED79650016851F /* Assets.xcassets */,
+ 504EC3101FED79650016851F /* LaunchScreen.storyboard */,
+ 504EC3131FED79650016851F /* Info.plist */,
+ 2FAD9762203C412B000D30F8 /* config.xml */,
+ 50B271D01FEDC1A000F3C39B /* public */,
+ 65E7FC362CB71E37004207E3 /* OutlineBridgeViewController.swift */,
+ );
+ path = App;
+ sourceTree = "";
+ };
+ 7F8756D8B27F46E3366F6CEA /* Pods */ = {
+ isa = PBXGroup;
+ children = (
+ FC68EB0AF532CFC21C3344DD /* Pods-App.debug.xcconfig */,
+ AF51FD2D460BCFE21FA515B2 /* Pods-App.release.xcconfig */,
+ );
+ name = Pods;
+ sourceTree = "";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+ 504EC3031FED79650016851F /* App */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 504EC3161FED79650016851F /* Build configuration list for PBXNativeTarget "App" */;
+ buildPhases = (
+ 6634F4EFEBD30273BCE97C65 /* [CP] Check Pods Manifest.lock */,
+ 504EC3001FED79650016851F /* Sources */,
+ 504EC3011FED79650016851F /* Frameworks */,
+ 504EC3021FED79650016851F /* Resources */,
+ 9592DBEFFC6D2A0C8D5DEB22 /* [CP] Embed Pods Frameworks */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = App;
+ productName = App;
+ productReference = 504EC3041FED79650016851F /* App.app */;
+ productType = "com.apple.product-type.application";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ 504EC2FC1FED79650016851F /* Project object */ = {
+ isa = PBXProject;
+ attributes = {
+ LastSwiftUpdateCheck = 0920;
+ LastUpgradeCheck = 0920;
+ TargetAttributes = {
+ 504EC3031FED79650016851F = {
+ CreatedOnToolsVersion = 9.2;
+ LastSwiftMigration = 1100;
+ ProvisioningStyle = Automatic;
+ };
+ };
+ };
+ buildConfigurationList = 504EC2FF1FED79650016851F /* Build configuration list for PBXProject "App" */;
+ compatibilityVersion = "Xcode 8.0";
+ developmentRegion = en;
+ hasScannedForEncodings = 0;
+ knownRegions = (
+ en,
+ Base,
+ );
+ mainGroup = 504EC2FB1FED79650016851F;
+ packageReferences = (
+ );
+ productRefGroup = 504EC3051FED79650016851F /* Products */;
+ projectDirPath = "";
+ projectRoot = "";
+ targets = (
+ 504EC3031FED79650016851F /* App */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXResourcesBuildPhase section */
+ 504EC3021FED79650016851F /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 504EC3121FED79650016851F /* LaunchScreen.storyboard in Resources */,
+ 50B271D11FEDC1A000F3C39B /* public in Resources */,
+ 504EC30F1FED79650016851F /* Assets.xcassets in Resources */,
+ 50379B232058CBB4000EE86E /* capacitor.config.json in Resources */,
+ 504EC30D1FED79650016851F /* Main.storyboard in Resources */,
+ 2FAD9763203C412B000D30F8 /* config.xml in Resources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXShellScriptBuildPhase section */
+ 6634F4EFEBD30273BCE97C65 /* [CP] Check Pods Manifest.lock */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
+ "${PODS_ROOT}/Manifest.lock",
+ );
+ name = "[CP] Check Pods Manifest.lock";
+ outputPaths = (
+ "$(DERIVED_FILE_DIR)/Pods-App-checkManifestLockResult.txt",
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
+ showEnvVarsInLog = 0;
+ };
+ 9592DBEFFC6D2A0C8D5DEB22 /* [CP] Embed Pods Frameworks */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ );
+ name = "[CP] Embed Pods Frameworks";
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-App/Pods-App-frameworks.sh\"\n";
+ showEnvVarsInLog = 0;
+ };
+/* End PBXShellScriptBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+ 504EC3001FED79650016851F /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 65E7FC372CB71E37004207E3 /* OutlineBridgeViewController.swift in Sources */,
+ 504EC3081FED79650016851F /* AppDelegate.swift in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXVariantGroup section */
+ 504EC30B1FED79650016851F /* Main.storyboard */ = {
+ isa = PBXVariantGroup;
+ children = (
+ 504EC30C1FED79650016851F /* Base */,
+ );
+ name = Main.storyboard;
+ sourceTree = "";
+ };
+ 504EC3101FED79650016851F /* LaunchScreen.storyboard */ = {
+ isa = PBXVariantGroup;
+ children = (
+ 504EC3111FED79650016851F /* Base */,
+ );
+ name = LaunchScreen.storyboard;
+ sourceTree = "";
+ };
+/* End PBXVariantGroup section */
+
+/* Begin XCBuildConfiguration section */
+ 504EC3141FED79650016851F /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_ANALYZER_NONNULL = YES;
+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_COMMA = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
+ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ CODE_SIGN_IDENTITY = "iPhone Developer";
+ COPY_PHASE_STRIP = NO;
+ DEBUG_INFORMATION_FORMAT = dwarf;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ ENABLE_TESTABILITY = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu11;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "DEBUG=1",
+ "$(inherited)",
+ );
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ IPHONEOS_DEPLOYMENT_TARGET = 13.0;
+ MTL_ENABLE_DEBUG_INFO = YES;
+ ONLY_ACTIVE_ARCH = YES;
+ SDKROOT = iphoneos;
+ SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
+ SWIFT_OPTIMIZATION_LEVEL = "-Onone";
+ };
+ name = Debug;
+ };
+ 504EC3151FED79650016851F /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_ANALYZER_NONNULL = YES;
+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_COMMA = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
+ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ CODE_SIGN_IDENTITY = "iPhone Developer";
+ COPY_PHASE_STRIP = NO;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ ENABLE_NS_ASSERTIONS = NO;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu11;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ IPHONEOS_DEPLOYMENT_TARGET = 13.0;
+ MTL_ENABLE_DEBUG_INFO = NO;
+ SDKROOT = iphoneos;
+ SWIFT_COMPILATION_MODE = wholemodule;
+ SWIFT_OPTIMIZATION_LEVEL = "-O";
+ VALIDATE_PRODUCT = YES;
+ };
+ name = Release;
+ };
+ 504EC3171FED79650016851F /* Debug */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = FC68EB0AF532CFC21C3344DD /* Pods-App.debug.xcconfig */;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ CODE_SIGN_STYLE = Automatic;
+ CURRENT_PROJECT_VERSION = 1;
+ DEVELOPMENT_TEAM = QT8Z3Q9V3A;
+ INFOPLIST_FILE = App/Info.plist;
+ IPHONEOS_DEPLOYMENT_TARGET = 13.0;
+ LD_RUNPATH_SEARCH_PATHS = (
+ "$(inherited)",
+ "@executable_path/Frameworks",
+ );
+ MARKETING_VERSION = 1.0;
+ OTHER_SWIFT_FLAGS = "$(inherited) \"-D\" \"COCOAPODS\" \"-DDEBUG\"";
+ PRODUCT_BUNDLE_IDENTIFIER = org.getoutline.pwa.ios;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
+ SWIFT_VERSION = 5.0;
+ TARGETED_DEVICE_FAMILY = "1,2";
+ };
+ name = Debug;
+ };
+ 504EC3181FED79650016851F /* Release */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = AF51FD2D460BCFE21FA515B2 /* Pods-App.release.xcconfig */;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ CODE_SIGN_STYLE = Automatic;
+ CURRENT_PROJECT_VERSION = 1;
+ DEVELOPMENT_TEAM = QT8Z3Q9V3A;
+ INFOPLIST_FILE = App/Info.plist;
+ IPHONEOS_DEPLOYMENT_TARGET = 13.0;
+ LD_RUNPATH_SEARCH_PATHS = (
+ "$(inherited)",
+ "@executable_path/Frameworks",
+ );
+ MARKETING_VERSION = 1.0;
+ PRODUCT_BUNDLE_IDENTIFIER = org.getoutline.pwa.ios;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SWIFT_ACTIVE_COMPILATION_CONDITIONS = "";
+ SWIFT_VERSION = 5.0;
+ TARGETED_DEVICE_FAMILY = "1,2";
+ };
+ name = Release;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ 504EC2FF1FED79650016851F /* Build configuration list for PBXProject "App" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 504EC3141FED79650016851F /* Debug */,
+ 504EC3151FED79650016851F /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 504EC3161FED79650016851F /* Build configuration list for PBXNativeTarget "App" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 504EC3171FED79650016851F /* Debug */,
+ 504EC3181FED79650016851F /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = 504EC2FC1FED79650016851F /* Project object */;
+}
diff --git a/x/examples/outline-pwa/ios/App/App.xcworkspace/contents.xcworkspacedata b/x/examples/outline-pwa/ios/App/App.xcworkspace/contents.xcworkspacedata
new file mode 100644
index 00000000..b301e824
--- /dev/null
+++ b/x/examples/outline-pwa/ios/App/App.xcworkspace/contents.xcworkspacedata
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
diff --git a/x/examples/outline-pwa/ios/App/App.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/x/examples/outline-pwa/ios/App/App.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
new file mode 100644
index 00000000..18d98100
--- /dev/null
+++ b/x/examples/outline-pwa/ios/App/App.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
@@ -0,0 +1,8 @@
+
+
+
+
+ IDEDidComputeMac32BitWarning
+
+
+
diff --git a/x/examples/outline-pwa/ios/App/App/AppDelegate.swift b/x/examples/outline-pwa/ios/App/App/AppDelegate.swift
new file mode 100644
index 00000000..8db8ab64
--- /dev/null
+++ b/x/examples/outline-pwa/ios/App/App/AppDelegate.swift
@@ -0,0 +1,55 @@
+import UIKit
+import Capacitor
+import Mobileproxy
+
+@UIApplicationMain
+class AppDelegate: UIResponder, UIApplicationDelegate {
+
+ var window: UIWindow?
+
+ private var proxy: MobileproxyProxy? = nil
+
+ func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
+
+ self.window?.rootViewController = OutlineBridgeViewController()
+
+ return true
+ }
+
+ func applicationDidBecomeActive(_ application: UIApplication) {
+ var dialerError: NSError?
+ if let dialer = MobileproxyNewSmartStreamDialer(
+ MobileproxyNewListFromLines("www.radiozamaneh.com"),
+ "{\"dns\":[{\"https\":{\"name\":\"9.9.9.9\"}}],\"tls\":[\"\",\"split:1\",\"split:2\",\"tlsfrag:1\"]}",
+ MobileproxyNewStderrLogWriter(),
+ &dialerError
+ ) {
+ var proxyError: NSError?
+ self.proxy = MobileproxyRunProxy(
+ "127.0.0.1:8080",
+ dialer,
+ &proxyError
+ )
+ }
+ }
+
+ func applicationWillResignActive(_ application: UIApplication) {
+ if let proxy = self.proxy {
+ proxy.stop(3000)
+ self.proxy = nil
+ }
+ }
+
+ func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey: Any] = [:]) -> Bool {
+ // Called when the app was launched with a url. Feel free to add additional processing here,
+ // but if you want the App API to support tracking app url opens, make sure to keep this call
+ return ApplicationDelegateProxy.shared.application(app, open: url, options: options)
+ }
+
+ func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
+ // Called when the app was launched with an activity, including Universal Links.
+ // Feel free to add additional processing here, but if you want the App API to support
+ // tracking app url opens, make sure to keep this call
+ return ApplicationDelegateProxy.shared.application(application, continue: userActivity, restorationHandler: restorationHandler)
+ }
+}
diff --git a/x/examples/outline-pwa/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-512@2x.png b/x/examples/outline-pwa/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-512@2x.png
new file mode 100644
index 00000000..adf6ba01
Binary files /dev/null and b/x/examples/outline-pwa/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-512@2x.png differ
diff --git a/x/examples/outline-pwa/ios/App/App/Assets.xcassets/AppIcon.appiconset/Contents.json b/x/examples/outline-pwa/ios/App/App/Assets.xcassets/AppIcon.appiconset/Contents.json
new file mode 100644
index 00000000..9b7d382d
--- /dev/null
+++ b/x/examples/outline-pwa/ios/App/App/Assets.xcassets/AppIcon.appiconset/Contents.json
@@ -0,0 +1,14 @@
+{
+ "images" : [
+ {
+ "filename" : "AppIcon-512@2x.png",
+ "idiom" : "universal",
+ "platform" : "ios",
+ "size" : "1024x1024"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/x/examples/outline-pwa/ios/App/App/Assets.xcassets/Contents.json b/x/examples/outline-pwa/ios/App/App/Assets.xcassets/Contents.json
new file mode 100644
index 00000000..da4a164c
--- /dev/null
+++ b/x/examples/outline-pwa/ios/App/App/Assets.xcassets/Contents.json
@@ -0,0 +1,6 @@
+{
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/x/examples/outline-pwa/ios/App/App/Assets.xcassets/Splash.imageset/Contents.json b/x/examples/outline-pwa/ios/App/App/Assets.xcassets/Splash.imageset/Contents.json
new file mode 100644
index 00000000..d7d96a67
--- /dev/null
+++ b/x/examples/outline-pwa/ios/App/App/Assets.xcassets/Splash.imageset/Contents.json
@@ -0,0 +1,23 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "filename" : "splash-2732x2732-2.png",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "universal",
+ "filename" : "splash-2732x2732-1.png",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "universal",
+ "filename" : "splash-2732x2732.png",
+ "scale" : "3x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/x/examples/outline-pwa/ios/App/App/Assets.xcassets/Splash.imageset/splash-2732x2732-1.png b/x/examples/outline-pwa/ios/App/App/Assets.xcassets/Splash.imageset/splash-2732x2732-1.png
new file mode 100644
index 00000000..33ea6c97
Binary files /dev/null and b/x/examples/outline-pwa/ios/App/App/Assets.xcassets/Splash.imageset/splash-2732x2732-1.png differ
diff --git a/x/examples/outline-pwa/ios/App/App/Assets.xcassets/Splash.imageset/splash-2732x2732-2.png b/x/examples/outline-pwa/ios/App/App/Assets.xcassets/Splash.imageset/splash-2732x2732-2.png
new file mode 100644
index 00000000..33ea6c97
Binary files /dev/null and b/x/examples/outline-pwa/ios/App/App/Assets.xcassets/Splash.imageset/splash-2732x2732-2.png differ
diff --git a/x/examples/outline-pwa/ios/App/App/Assets.xcassets/Splash.imageset/splash-2732x2732.png b/x/examples/outline-pwa/ios/App/App/Assets.xcassets/Splash.imageset/splash-2732x2732.png
new file mode 100644
index 00000000..33ea6c97
Binary files /dev/null and b/x/examples/outline-pwa/ios/App/App/Assets.xcassets/Splash.imageset/splash-2732x2732.png differ
diff --git a/x/examples/outline-pwa/ios/App/App/Base.lproj/LaunchScreen.storyboard b/x/examples/outline-pwa/ios/App/App/Base.lproj/LaunchScreen.storyboard
new file mode 100644
index 00000000..e7ae5d78
--- /dev/null
+++ b/x/examples/outline-pwa/ios/App/App/Base.lproj/LaunchScreen.storyboard
@@ -0,0 +1,32 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/x/examples/outline-pwa/ios/App/App/Base.lproj/Main.storyboard b/x/examples/outline-pwa/ios/App/App/Base.lproj/Main.storyboard
new file mode 100644
index 00000000..b44df7be
--- /dev/null
+++ b/x/examples/outline-pwa/ios/App/App/Base.lproj/Main.storyboard
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/x/examples/outline-pwa/ios/App/App/Info.plist b/x/examples/outline-pwa/ios/App/App/Info.plist
new file mode 100644
index 00000000..da0711a1
--- /dev/null
+++ b/x/examples/outline-pwa/ios/App/App/Info.plist
@@ -0,0 +1,53 @@
+
+
+
+
+ CFBundleDevelopmentRegion
+ en
+ CFBundleDisplayName
+ outline-ios-pwa-demo
+ CFBundleExecutable
+ $(EXECUTABLE_NAME)
+ CFBundleIdentifier
+ $(PRODUCT_BUNDLE_IDENTIFIER)
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundleName
+ $(PRODUCT_NAME)
+ CFBundlePackageType
+ APPL
+ CFBundleShortVersionString
+ $(MARKETING_VERSION)
+ CFBundleVersion
+ $(CURRENT_PROJECT_VERSION)
+ LSRequiresIPhoneOS
+
+ UILaunchStoryboardName
+ LaunchScreen
+ UIMainStoryboardFile
+ Main
+ UIRequiredDeviceCapabilities
+
+ armv7
+
+ UISupportedInterfaceOrientations
+
+ UIInterfaceOrientationPortrait
+ UIInterfaceOrientationLandscapeLeft
+ UIInterfaceOrientationLandscapeRight
+
+ UISupportedInterfaceOrientations~ipad
+
+ UIInterfaceOrientationPortrait
+ UIInterfaceOrientationPortraitUpsideDown
+ UIInterfaceOrientationLandscapeLeft
+ UIInterfaceOrientationLandscapeRight
+
+ UIViewControllerBasedStatusBarAppearance
+
+ WKAppBoundDomains
+
+ www.radiozamaneh.com
+
+
+
diff --git a/x/examples/outline-pwa/ios/App/App/OutlineBridgeViewController.swift b/x/examples/outline-pwa/ios/App/App/OutlineBridgeViewController.swift
new file mode 100644
index 00000000..5f1c137b
--- /dev/null
+++ b/x/examples/outline-pwa/ios/App/App/OutlineBridgeViewController.swift
@@ -0,0 +1,47 @@
+//
+// OutlineBridgeViewController.swift
+// App
+//
+// Created by Daniel LaCosse on 10/9/24.
+//
+
+import UIKit
+import Capacitor
+
+class OutlineBridgeViewController: CAPBridgeViewController {
+ private let proxyHost: String = "127.0.0.1"
+ private let proxyPort: String = "8080"
+
+ override func webView(with frame: CGRect, configuration: WKWebViewConfiguration) -> WKWebView {
+ if #available(iOS 17.0, *) {
+ let endpoint = NWEndpoint.hostPort(
+ host: NWEndpoint.Host(self.proxyHost),
+ port: NWEndpoint.Port(self.proxyPort)!
+ )
+ let proxyConfig = ProxyConfiguration.init(httpCONNECTProxy: endpoint)
+
+ let websiteDataStore = WKWebsiteDataStore.default()
+ websiteDataStore.proxyConfigurations = [proxyConfig]
+
+ configuration.websiteDataStore = websiteDataStore
+ } else {
+ // TODO: use scheme handler
+ }
+
+ return super.webView(with: frame, configuration: configuration)
+ }
+
+ override open func viewWillLayoutSubviews() {
+ super.viewWillLayoutSubviews()
+
+ guard let webView = self.webView else { return }
+
+ if let safeAreaInsets = self.view.window?.safeAreaInsets {
+ webView.frame.origin = CGPoint(x: safeAreaInsets.left, y: safeAreaInsets.top)
+ webView.frame.size = CGSize(
+ width: UIScreen.main.bounds.width - safeAreaInsets.left - safeAreaInsets.right,
+ height: UIScreen.main.bounds.height - safeAreaInsets.top - safeAreaInsets.bottom
+ )
+ }
+ }
+}
diff --git a/x/examples/outline-pwa/ios/App/Podfile b/x/examples/outline-pwa/ios/App/Podfile
new file mode 100644
index 00000000..b091296b
--- /dev/null
+++ b/x/examples/outline-pwa/ios/App/Podfile
@@ -0,0 +1,25 @@
+require_relative '../../node_modules/@capacitor/ios/scripts/pods_helpers'
+
+platform :ios, '13.0'
+use_frameworks!
+
+# workaround to avoid Xcode caching of Pods that requires
+# Product -> Clean Build Folder after new Cordova plugins installed
+# Requires CocoaPods 1.6 or newer
+install! 'cocoapods', :disable_input_output_paths => true
+
+def capacitor_pods
+ pod 'Capacitor', :path => '../../node_modules/@capacitor/ios'
+ pod 'CapacitorCordova', :path => '../../node_modules/@capacitor/ios'
+ pod 'CapacitorCamera', :path => '../../node_modules/@capacitor/camera'
+ pod 'CapacitorSplashScreen', :path => '../../node_modules/@capacitor/splash-screen'
+end
+
+target 'App' do
+ capacitor_pods
+ # Add your Pods here
+end
+
+post_install do |installer|
+ assertDeploymentTarget(installer)
+end
diff --git a/x/examples/outline-pwa/ios/App/Podfile.lock b/x/examples/outline-pwa/ios/App/Podfile.lock
new file mode 100644
index 00000000..c4a9e865
--- /dev/null
+++ b/x/examples/outline-pwa/ios/App/Podfile.lock
@@ -0,0 +1,34 @@
+PODS:
+ - Capacitor (6.1.2):
+ - CapacitorCordova
+ - CapacitorCamera (6.0.2):
+ - Capacitor
+ - CapacitorCordova (6.1.2)
+ - CapacitorSplashScreen (6.0.2):
+ - Capacitor
+
+DEPENDENCIES:
+ - "Capacitor (from `../../node_modules/@capacitor/ios`)"
+ - "CapacitorCamera (from `../../node_modules/@capacitor/camera`)"
+ - "CapacitorCordova (from `../../node_modules/@capacitor/ios`)"
+ - "CapacitorSplashScreen (from `../../node_modules/@capacitor/splash-screen`)"
+
+EXTERNAL SOURCES:
+ Capacitor:
+ :path: "../../node_modules/@capacitor/ios"
+ CapacitorCamera:
+ :path: "../../node_modules/@capacitor/camera"
+ CapacitorCordova:
+ :path: "../../node_modules/@capacitor/ios"
+ CapacitorSplashScreen:
+ :path: "../../node_modules/@capacitor/splash-screen"
+
+SPEC CHECKSUMS:
+ Capacitor: 679f9673fdf30597493a6362a5d5bf233d46abc2
+ CapacitorCamera: ed022171dbf3853e68eec877b4d78995378af6b7
+ CapacitorCordova: f48c89f96c319101cd2f0ce8a2b7449b5fb8b3dd
+ CapacitorSplashScreen: 250df9ef8014fac5c7c1fd231f0f8b1d8f0b5624
+
+PODFILE CHECKSUM: c23ed3fd935a944047d8284cab144b362bbd00cb
+
+COCOAPODS: 1.15.2
diff --git a/x/examples/outline-pwa/package-lock.json b/x/examples/outline-pwa/package-lock.json
new file mode 100644
index 00000000..b7a96de3
--- /dev/null
+++ b/x/examples/outline-pwa/package-lock.json
@@ -0,0 +1,1197 @@
+{
+ "name": "outline-pwa-demo",
+ "version": "1.0.0",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "outline-pwa-demo",
+ "version": "1.0.0",
+ "license": "ISC",
+ "dependencies": {
+ "@capacitor/android": "^6.1.2",
+ "@capacitor/camera": "latest",
+ "@capacitor/core": "latest",
+ "@capacitor/ios": "^6.1.2",
+ "@capacitor/splash-screen": "latest"
+ },
+ "devDependencies": {
+ "@capacitor/cli": "latest"
+ }
+ },
+ "node_modules/@capacitor/android": {
+ "version": "6.1.2",
+ "resolved": "https://registry.npmjs.org/@capacitor/android/-/android-6.1.2.tgz",
+ "integrity": "sha512-Yh0gQDY1bgRrL25J6ecIlvvs2kF8iNSwIPXjyw6Yz9mnwYxBazF5KZbjpKtGPnJgicJhFkYGsqOkEtxrve0EoQ==",
+ "peerDependencies": {
+ "@capacitor/core": "^6.1.0"
+ }
+ },
+ "node_modules/@capacitor/camera": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/@capacitor/camera/-/camera-6.0.2.tgz",
+ "integrity": "sha512-bC2xxCcNTyfKYuLNLbGIyLlK9fok2MDhF4v8s01jusYAxoBI7LaKWQMQoGBA1MY/Ec6x/2pjIr+7k89Kmdr74g==",
+ "peerDependencies": {
+ "@capacitor/core": "^6.0.0"
+ }
+ },
+ "node_modules/@capacitor/cli": {
+ "version": "6.1.2",
+ "resolved": "https://registry.npmjs.org/@capacitor/cli/-/cli-6.1.2.tgz",
+ "integrity": "sha512-HKCNGE0RP8U7aiEF2vg5wTivJROS8BVfu8a3yYJb1mRQvzv+czpmtHNsTWS/WukvwoxUjyjRmsNQSAACHfMTmQ==",
+ "dev": true,
+ "dependencies": {
+ "@ionic/cli-framework-output": "^2.2.5",
+ "@ionic/utils-fs": "^3.1.6",
+ "@ionic/utils-process": "^2.1.11",
+ "@ionic/utils-subprocess": "2.1.11",
+ "@ionic/utils-terminal": "^2.3.3",
+ "commander": "^9.3.0",
+ "debug": "^4.3.4",
+ "env-paths": "^2.2.0",
+ "kleur": "^4.1.4",
+ "native-run": "^2.0.0",
+ "open": "^8.4.0",
+ "plist": "^3.0.5",
+ "prompts": "^2.4.2",
+ "rimraf": "^4.4.1",
+ "semver": "^7.3.7",
+ "tar": "^6.1.11",
+ "tslib": "^2.4.0",
+ "xml2js": "^0.5.0"
+ },
+ "bin": {
+ "cap": "bin/capacitor",
+ "capacitor": "bin/capacitor"
+ },
+ "engines": {
+ "node": ">=18.0.0"
+ }
+ },
+ "node_modules/@capacitor/core": {
+ "version": "6.1.2",
+ "resolved": "https://registry.npmjs.org/@capacitor/core/-/core-6.1.2.tgz",
+ "integrity": "sha512-xFy1/4qLFLp5WCIzIhtwUuVNNoz36+V7/BzHmLqgVJcvotc4MMjswW/TshnPQaLLujEOaLkA4h8ZJ0uoK3ImGg==",
+ "dependencies": {
+ "tslib": "^2.1.0"
+ }
+ },
+ "node_modules/@capacitor/ios": {
+ "version": "6.1.2",
+ "resolved": "https://registry.npmjs.org/@capacitor/ios/-/ios-6.1.2.tgz",
+ "integrity": "sha512-HaeW68KisBd/7TmavzPDlL2bpoDK5AjR2ZYrqU4TlGwM88GtQfvduBCAlSCj20X0w/4+rWMkseD9dAAkacjiyQ==",
+ "peerDependencies": {
+ "@capacitor/core": "^6.1.0"
+ }
+ },
+ "node_modules/@capacitor/splash-screen": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/@capacitor/splash-screen/-/splash-screen-6.0.2.tgz",
+ "integrity": "sha512-WC0KYZ+ev15up03xs4fTnoTKwBVUSxXsKKQr/8XAncvi/nAG8qrpanW8OlavSC5zF5e1IZZDLsI2GSv0SkZ7VQ==",
+ "peerDependencies": {
+ "@capacitor/core": "^6.0.0"
+ }
+ },
+ "node_modules/@ionic/cli-framework-output": {
+ "version": "2.2.8",
+ "resolved": "https://registry.npmjs.org/@ionic/cli-framework-output/-/cli-framework-output-2.2.8.tgz",
+ "integrity": "sha512-TshtaFQsovB4NWRBydbNFawql6yul7d5bMiW1WYYf17hd99V6xdDdk3vtF51bw6sLkxON3bDQpWsnUc9/hVo3g==",
+ "dev": true,
+ "dependencies": {
+ "@ionic/utils-terminal": "2.3.5",
+ "debug": "^4.0.0",
+ "tslib": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=16.0.0"
+ }
+ },
+ "node_modules/@ionic/utils-array": {
+ "version": "2.1.5",
+ "resolved": "https://registry.npmjs.org/@ionic/utils-array/-/utils-array-2.1.5.tgz",
+ "integrity": "sha512-HD72a71IQVBmQckDwmA8RxNVMTbxnaLbgFOl+dO5tbvW9CkkSFCv41h6fUuNsSEVgngfkn0i98HDuZC8mk+lTA==",
+ "dev": true,
+ "dependencies": {
+ "debug": "^4.0.0",
+ "tslib": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=10.3.0"
+ }
+ },
+ "node_modules/@ionic/utils-fs": {
+ "version": "3.1.7",
+ "resolved": "https://registry.npmjs.org/@ionic/utils-fs/-/utils-fs-3.1.7.tgz",
+ "integrity": "sha512-2EknRvMVfhnyhL1VhFkSLa5gOcycK91VnjfrTB0kbqkTFCOXyXgVLI5whzq7SLrgD9t1aqos3lMMQyVzaQ5gVA==",
+ "dev": true,
+ "dependencies": {
+ "@types/fs-extra": "^8.0.0",
+ "debug": "^4.0.0",
+ "fs-extra": "^9.0.0",
+ "tslib": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=16.0.0"
+ }
+ },
+ "node_modules/@ionic/utils-object": {
+ "version": "2.1.6",
+ "resolved": "https://registry.npmjs.org/@ionic/utils-object/-/utils-object-2.1.6.tgz",
+ "integrity": "sha512-vCl7sl6JjBHFw99CuAqHljYJpcE88YaH2ZW4ELiC/Zwxl5tiwn4kbdP/gxi2OT3MQb1vOtgAmSNRtusvgxI8ww==",
+ "dev": true,
+ "dependencies": {
+ "debug": "^4.0.0",
+ "tslib": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=16.0.0"
+ }
+ },
+ "node_modules/@ionic/utils-process": {
+ "version": "2.1.12",
+ "resolved": "https://registry.npmjs.org/@ionic/utils-process/-/utils-process-2.1.12.tgz",
+ "integrity": "sha512-Jqkgyq7zBs/v/J3YvKtQQiIcxfJyplPgECMWgdO0E1fKrrH8EF0QGHNJ9mJCn6PYe2UtHNS8JJf5G21e09DfYg==",
+ "dev": true,
+ "dependencies": {
+ "@ionic/utils-object": "2.1.6",
+ "@ionic/utils-terminal": "2.3.5",
+ "debug": "^4.0.0",
+ "signal-exit": "^3.0.3",
+ "tree-kill": "^1.2.2",
+ "tslib": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=16.0.0"
+ }
+ },
+ "node_modules/@ionic/utils-stream": {
+ "version": "3.1.5",
+ "resolved": "https://registry.npmjs.org/@ionic/utils-stream/-/utils-stream-3.1.5.tgz",
+ "integrity": "sha512-hkm46uHvEC05X/8PHgdJi4l4zv9VQDELZTM+Kz69odtO9zZYfnt8DkfXHJqJ+PxmtiE5mk/ehJWLnn/XAczTUw==",
+ "dev": true,
+ "dependencies": {
+ "debug": "^4.0.0",
+ "tslib": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=10.3.0"
+ }
+ },
+ "node_modules/@ionic/utils-subprocess": {
+ "version": "2.1.11",
+ "resolved": "https://registry.npmjs.org/@ionic/utils-subprocess/-/utils-subprocess-2.1.11.tgz",
+ "integrity": "sha512-6zCDixNmZCbMCy5np8klSxOZF85kuDyzZSTTQKQP90ZtYNCcPYmuFSzaqDwApJT4r5L3MY3JrqK1gLkc6xiUPw==",
+ "dev": true,
+ "dependencies": {
+ "@ionic/utils-array": "2.1.5",
+ "@ionic/utils-fs": "3.1.6",
+ "@ionic/utils-process": "2.1.10",
+ "@ionic/utils-stream": "3.1.5",
+ "@ionic/utils-terminal": "2.3.3",
+ "cross-spawn": "^7.0.3",
+ "debug": "^4.0.0",
+ "tslib": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=10.3.0"
+ }
+ },
+ "node_modules/@ionic/utils-subprocess/node_modules/@ionic/utils-fs": {
+ "version": "3.1.6",
+ "resolved": "https://registry.npmjs.org/@ionic/utils-fs/-/utils-fs-3.1.6.tgz",
+ "integrity": "sha512-eikrNkK89CfGPmexjTfSWl4EYqsPSBh0Ka7by4F0PLc1hJZYtJxUZV3X4r5ecA8ikjicUmcbU7zJmAjmqutG/w==",
+ "dev": true,
+ "dependencies": {
+ "@types/fs-extra": "^8.0.0",
+ "debug": "^4.0.0",
+ "fs-extra": "^9.0.0",
+ "tslib": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=10.3.0"
+ }
+ },
+ "node_modules/@ionic/utils-subprocess/node_modules/@ionic/utils-object": {
+ "version": "2.1.5",
+ "resolved": "https://registry.npmjs.org/@ionic/utils-object/-/utils-object-2.1.5.tgz",
+ "integrity": "sha512-XnYNSwfewUqxq+yjER1hxTKggftpNjFLJH0s37jcrNDwbzmbpFTQTVAp4ikNK4rd9DOebX/jbeZb8jfD86IYxw==",
+ "dev": true,
+ "dependencies": {
+ "debug": "^4.0.0",
+ "tslib": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=10.3.0"
+ }
+ },
+ "node_modules/@ionic/utils-subprocess/node_modules/@ionic/utils-process": {
+ "version": "2.1.10",
+ "resolved": "https://registry.npmjs.org/@ionic/utils-process/-/utils-process-2.1.10.tgz",
+ "integrity": "sha512-mZ7JEowcuGQK+SKsJXi0liYTcXd2bNMR3nE0CyTROpMECUpJeAvvaBaPGZf5ERQUPeWBVuwqAqjUmIdxhz5bxw==",
+ "dev": true,
+ "dependencies": {
+ "@ionic/utils-object": "2.1.5",
+ "@ionic/utils-terminal": "2.3.3",
+ "debug": "^4.0.0",
+ "signal-exit": "^3.0.3",
+ "tree-kill": "^1.2.2",
+ "tslib": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=10.3.0"
+ }
+ },
+ "node_modules/@ionic/utils-subprocess/node_modules/@ionic/utils-terminal": {
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/@ionic/utils-terminal/-/utils-terminal-2.3.3.tgz",
+ "integrity": "sha512-RnuSfNZ5fLEyX3R5mtcMY97cGD1A0NVBbarsSQ6yMMfRJ5YHU7hHVyUfvZeClbqkBC/pAqI/rYJuXKCT9YeMCQ==",
+ "dev": true,
+ "dependencies": {
+ "@types/slice-ansi": "^4.0.0",
+ "debug": "^4.0.0",
+ "signal-exit": "^3.0.3",
+ "slice-ansi": "^4.0.0",
+ "string-width": "^4.1.0",
+ "strip-ansi": "^6.0.0",
+ "tslib": "^2.0.1",
+ "untildify": "^4.0.0",
+ "wrap-ansi": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=10.3.0"
+ }
+ },
+ "node_modules/@ionic/utils-terminal": {
+ "version": "2.3.5",
+ "resolved": "https://registry.npmjs.org/@ionic/utils-terminal/-/utils-terminal-2.3.5.tgz",
+ "integrity": "sha512-3cKScz9Jx2/Pr9ijj1OzGlBDfcmx7OMVBt4+P1uRR0SSW4cm1/y3Mo4OY3lfkuaYifMNBW8Wz6lQHbs1bihr7A==",
+ "dev": true,
+ "dependencies": {
+ "@types/slice-ansi": "^4.0.0",
+ "debug": "^4.0.0",
+ "signal-exit": "^3.0.3",
+ "slice-ansi": "^4.0.0",
+ "string-width": "^4.1.0",
+ "strip-ansi": "^6.0.0",
+ "tslib": "^2.0.1",
+ "untildify": "^4.0.0",
+ "wrap-ansi": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=16.0.0"
+ }
+ },
+ "node_modules/@types/fs-extra": {
+ "version": "8.1.5",
+ "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-8.1.5.tgz",
+ "integrity": "sha512-0dzKcwO+S8s2kuF5Z9oUWatQJj5Uq/iqphEtE3GQJVRRYm/tD1LglU2UnXi2A8jLq5umkGouOXOR9y0n613ZwQ==",
+ "dev": true,
+ "dependencies": {
+ "@types/node": "*"
+ }
+ },
+ "node_modules/@types/node": {
+ "version": "22.7.5",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-22.7.5.tgz",
+ "integrity": "sha512-jML7s2NAzMWc//QSJ1a3prpk78cOPchGvXJsC3C6R6PSMoooztvRVQEz89gmBTBY1SPMaqo5teB4uNHPdetShQ==",
+ "dev": true,
+ "dependencies": {
+ "undici-types": "~6.19.2"
+ }
+ },
+ "node_modules/@types/slice-ansi": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/@types/slice-ansi/-/slice-ansi-4.0.0.tgz",
+ "integrity": "sha512-+OpjSaq85gvlZAYINyzKpLeiFkSC4EsC6IIiT6v6TLSU5k5U83fHGj9Lel8oKEXM0HqgrMVCjXPDPVICtxF7EQ==",
+ "dev": true
+ },
+ "node_modules/@xmldom/xmldom": {
+ "version": "0.8.10",
+ "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.10.tgz",
+ "integrity": "sha512-2WALfTl4xo2SkGCYRt6rDTFfk9R1czmBvUQy12gK2KuRKIpWEhcbbzy8EZXtz/jkRqHX8bFEc6FC1HjX4TUWYw==",
+ "dev": true,
+ "engines": {
+ "node": ">=10.0.0"
+ }
+ },
+ "node_modules/ansi-regex": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+ "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
+ "dependencies": {
+ "color-convert": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/astral-regex": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz",
+ "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/at-least-node": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz",
+ "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==",
+ "dev": true,
+ "engines": {
+ "node": ">= 4.0.0"
+ }
+ },
+ "node_modules/balanced-match": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
+ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
+ "dev": true
+ },
+ "node_modules/base64-js": {
+ "version": "1.5.1",
+ "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
+ "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ]
+ },
+ "node_modules/big-integer": {
+ "version": "1.6.52",
+ "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.52.tgz",
+ "integrity": "sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.6"
+ }
+ },
+ "node_modules/bplist-parser": {
+ "version": "0.3.2",
+ "resolved": "https://registry.npmjs.org/bplist-parser/-/bplist-parser-0.3.2.tgz",
+ "integrity": "sha512-apC2+fspHGI3mMKj+dGevkGo/tCqVB8jMb6i+OX+E29p0Iposz07fABkRIfVUPNd5A5VbuOz1bZbnmkKLYF+wQ==",
+ "dev": true,
+ "dependencies": {
+ "big-integer": "1.6.x"
+ },
+ "engines": {
+ "node": ">= 5.10.0"
+ }
+ },
+ "node_modules/brace-expansion": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
+ "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
+ "dev": true,
+ "dependencies": {
+ "balanced-match": "^1.0.0"
+ }
+ },
+ "node_modules/buffer-crc32": {
+ "version": "0.2.13",
+ "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz",
+ "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==",
+ "dev": true,
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/chownr": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz",
+ "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "dependencies": {
+ "color-name": "~1.1.4"
+ },
+ "engines": {
+ "node": ">=7.0.0"
+ }
+ },
+ "node_modules/color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true
+ },
+ "node_modules/commander": {
+ "version": "9.5.0",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz",
+ "integrity": "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==",
+ "dev": true,
+ "engines": {
+ "node": "^12.20.0 || >=14"
+ }
+ },
+ "node_modules/cross-spawn": {
+ "version": "7.0.3",
+ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
+ "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
+ "dev": true,
+ "dependencies": {
+ "path-key": "^3.1.0",
+ "shebang-command": "^2.0.0",
+ "which": "^2.0.1"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/debug": {
+ "version": "4.3.7",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
+ "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
+ "dev": true,
+ "dependencies": {
+ "ms": "^2.1.3"
+ },
+ "engines": {
+ "node": ">=6.0"
+ },
+ "peerDependenciesMeta": {
+ "supports-color": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/define-lazy-prop": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz",
+ "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/elementtree": {
+ "version": "0.1.7",
+ "resolved": "https://registry.npmjs.org/elementtree/-/elementtree-0.1.7.tgz",
+ "integrity": "sha512-wkgGT6kugeQk/P6VZ/f4T+4HB41BVgNBq5CDIZVbQ02nvTVqAiVTbskxxu3eA/X96lMlfYOwnLQpN2v5E1zDEg==",
+ "dev": true,
+ "dependencies": {
+ "sax": "1.1.4"
+ },
+ "engines": {
+ "node": ">= 0.4.0"
+ }
+ },
+ "node_modules/emoji-regex": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+ "dev": true
+ },
+ "node_modules/env-paths": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz",
+ "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/fd-slicer": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz",
+ "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==",
+ "dev": true,
+ "dependencies": {
+ "pend": "~1.2.0"
+ }
+ },
+ "node_modules/fs-extra": {
+ "version": "9.1.0",
+ "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz",
+ "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==",
+ "dev": true,
+ "dependencies": {
+ "at-least-node": "^1.0.0",
+ "graceful-fs": "^4.2.0",
+ "jsonfile": "^6.0.1",
+ "universalify": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/fs-minipass": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz",
+ "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==",
+ "dev": true,
+ "dependencies": {
+ "minipass": "^3.0.0"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/fs-minipass/node_modules/minipass": {
+ "version": "3.3.6",
+ "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz",
+ "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==",
+ "dev": true,
+ "dependencies": {
+ "yallist": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/fs.realpath": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+ "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
+ "dev": true
+ },
+ "node_modules/glob": {
+ "version": "9.3.5",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-9.3.5.tgz",
+ "integrity": "sha512-e1LleDykUz2Iu+MTYdkSsuWX8lvAjAcs0Xef0lNIu0S2wOAzuTxCJtcd9S3cijlwYF18EsU3rzb8jPVobxDh9Q==",
+ "dev": true,
+ "dependencies": {
+ "fs.realpath": "^1.0.0",
+ "minimatch": "^8.0.2",
+ "minipass": "^4.2.4",
+ "path-scurry": "^1.6.1"
+ },
+ "engines": {
+ "node": ">=16 || 14 >=14.17"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/graceful-fs": {
+ "version": "4.2.11",
+ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
+ "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
+ "dev": true
+ },
+ "node_modules/inherits": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
+ "dev": true
+ },
+ "node_modules/ini": {
+ "version": "4.1.3",
+ "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.3.tgz",
+ "integrity": "sha512-X7rqawQBvfdjS10YU1y1YVreA3SsLrW9dX2CewP2EbBJM4ypVNLDkO5y04gejPwKIY9lR+7r9gn3rFPt/kmWFg==",
+ "dev": true,
+ "engines": {
+ "node": "^14.17.0 || ^16.13.0 || >=18.0.0"
+ }
+ },
+ "node_modules/is-docker": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz",
+ "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==",
+ "dev": true,
+ "bin": {
+ "is-docker": "cli.js"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/is-fullwidth-code-point": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
+ "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/is-wsl": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz",
+ "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==",
+ "dev": true,
+ "dependencies": {
+ "is-docker": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/isexe": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
+ "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
+ "dev": true
+ },
+ "node_modules/jsonfile": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz",
+ "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==",
+ "dev": true,
+ "dependencies": {
+ "universalify": "^2.0.0"
+ },
+ "optionalDependencies": {
+ "graceful-fs": "^4.1.6"
+ }
+ },
+ "node_modules/kleur": {
+ "version": "4.1.5",
+ "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz",
+ "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/lru-cache": {
+ "version": "10.4.3",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz",
+ "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==",
+ "dev": true
+ },
+ "node_modules/minimatch": {
+ "version": "8.0.4",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-8.0.4.tgz",
+ "integrity": "sha512-W0Wvr9HyFXZRGIDgCicunpQ299OKXs9RgZfaukz4qAW/pJhcpUfupc9c+OObPOFueNy8VSrZgEmDtk6Kh4WzDA==",
+ "dev": true,
+ "dependencies": {
+ "brace-expansion": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=16 || 14 >=14.17"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/minipass": {
+ "version": "4.2.8",
+ "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.2.8.tgz",
+ "integrity": "sha512-fNzuVyifolSLFL4NzpF+wEF4qrgqaaKX0haXPQEdQ7NKAN+WecoKMHV09YcuL/DHxrUsYQOK3MiuDf7Ip2OXfQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/minizlib": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz",
+ "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==",
+ "dev": true,
+ "dependencies": {
+ "minipass": "^3.0.0",
+ "yallist": "^4.0.0"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/minizlib/node_modules/minipass": {
+ "version": "3.3.6",
+ "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz",
+ "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==",
+ "dev": true,
+ "dependencies": {
+ "yallist": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/mkdirp": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
+ "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==",
+ "dev": true,
+ "bin": {
+ "mkdirp": "bin/cmd.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/ms": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
+ "dev": true
+ },
+ "node_modules/native-run": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/native-run/-/native-run-2.0.1.tgz",
+ "integrity": "sha512-XfG1FBZLM50J10xH9361whJRC9SHZ0Bub4iNRhhI61C8Jv0e1ud19muex6sNKB51ibQNUJNuYn25MuYET/rE6w==",
+ "dev": true,
+ "dependencies": {
+ "@ionic/utils-fs": "^3.1.7",
+ "@ionic/utils-terminal": "^2.3.4",
+ "bplist-parser": "^0.3.2",
+ "debug": "^4.3.4",
+ "elementtree": "^0.1.7",
+ "ini": "^4.1.1",
+ "plist": "^3.1.0",
+ "split2": "^4.2.0",
+ "through2": "^4.0.2",
+ "tslib": "^2.6.2",
+ "yauzl": "^2.10.0"
+ },
+ "bin": {
+ "native-run": "bin/native-run"
+ },
+ "engines": {
+ "node": ">=16.0.0"
+ }
+ },
+ "node_modules/open": {
+ "version": "8.4.2",
+ "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz",
+ "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==",
+ "dev": true,
+ "dependencies": {
+ "define-lazy-prop": "^2.0.0",
+ "is-docker": "^2.1.1",
+ "is-wsl": "^2.2.0"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/path-key": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
+ "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/path-scurry": {
+ "version": "1.11.1",
+ "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz",
+ "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==",
+ "dev": true,
+ "dependencies": {
+ "lru-cache": "^10.2.0",
+ "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0"
+ },
+ "engines": {
+ "node": ">=16 || 14 >=14.18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/path-scurry/node_modules/minipass": {
+ "version": "7.1.2",
+ "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz",
+ "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==",
+ "dev": true,
+ "engines": {
+ "node": ">=16 || 14 >=14.17"
+ }
+ },
+ "node_modules/pend": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz",
+ "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==",
+ "dev": true
+ },
+ "node_modules/plist": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/plist/-/plist-3.1.0.tgz",
+ "integrity": "sha512-uysumyrvkUX0rX/dEVqt8gC3sTBzd4zoWfLeS29nb53imdaXVvLINYXTI2GNqzaMuvacNx4uJQ8+b3zXR0pkgQ==",
+ "dev": true,
+ "dependencies": {
+ "@xmldom/xmldom": "^0.8.8",
+ "base64-js": "^1.5.1",
+ "xmlbuilder": "^15.1.1"
+ },
+ "engines": {
+ "node": ">=10.4.0"
+ }
+ },
+ "node_modules/prompts": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz",
+ "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==",
+ "dev": true,
+ "dependencies": {
+ "kleur": "^3.0.3",
+ "sisteransi": "^1.0.5"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/prompts/node_modules/kleur": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz",
+ "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/readable-stream": {
+ "version": "3.6.2",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
+ "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
+ "dev": true,
+ "dependencies": {
+ "inherits": "^2.0.3",
+ "string_decoder": "^1.1.1",
+ "util-deprecate": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/rimraf": {
+ "version": "4.4.1",
+ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-4.4.1.tgz",
+ "integrity": "sha512-Gk8NlF062+T9CqNGn6h4tls3k6T1+/nXdOcSZVikNVtlRdYpA7wRJJMoXmuvOnLW844rPjdQ7JgXCYM6PPC/og==",
+ "dev": true,
+ "dependencies": {
+ "glob": "^9.2.0"
+ },
+ "bin": {
+ "rimraf": "dist/cjs/src/bin.js"
+ },
+ "engines": {
+ "node": ">=14"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/safe-buffer": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
+ "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ]
+ },
+ "node_modules/sax": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/sax/-/sax-1.1.4.tgz",
+ "integrity": "sha512-5f3k2PbGGp+YtKJjOItpg3P99IMD84E4HOvcfleTb5joCHNXYLsR9yWFPOYGgaeMPDubQILTCMdsFb2OMeOjtg==",
+ "dev": true
+ },
+ "node_modules/semver": {
+ "version": "7.6.3",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz",
+ "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==",
+ "dev": true,
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/shebang-command": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
+ "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
+ "dev": true,
+ "dependencies": {
+ "shebang-regex": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/shebang-regex": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
+ "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/signal-exit": {
+ "version": "3.0.7",
+ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
+ "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==",
+ "dev": true
+ },
+ "node_modules/sisteransi": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz",
+ "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==",
+ "dev": true
+ },
+ "node_modules/slice-ansi": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz",
+ "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^4.0.0",
+ "astral-regex": "^2.0.0",
+ "is-fullwidth-code-point": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/slice-ansi?sponsor=1"
+ }
+ },
+ "node_modules/split2": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz",
+ "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==",
+ "dev": true,
+ "engines": {
+ "node": ">= 10.x"
+ }
+ },
+ "node_modules/string_decoder": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
+ "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
+ "dev": true,
+ "dependencies": {
+ "safe-buffer": "~5.2.0"
+ }
+ },
+ "node_modules/string-width": {
+ "version": "4.2.3",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+ "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+ "dev": true,
+ "dependencies": {
+ "emoji-regex": "^8.0.0",
+ "is-fullwidth-code-point": "^3.0.0",
+ "strip-ansi": "^6.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/strip-ansi": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+ "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+ "dev": true,
+ "dependencies": {
+ "ansi-regex": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/tar": {
+ "version": "6.2.1",
+ "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz",
+ "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==",
+ "dev": true,
+ "dependencies": {
+ "chownr": "^2.0.0",
+ "fs-minipass": "^2.0.0",
+ "minipass": "^5.0.0",
+ "minizlib": "^2.1.1",
+ "mkdirp": "^1.0.3",
+ "yallist": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/tar/node_modules/minipass": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz",
+ "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/through2": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/through2/-/through2-4.0.2.tgz",
+ "integrity": "sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==",
+ "dev": true,
+ "dependencies": {
+ "readable-stream": "3"
+ }
+ },
+ "node_modules/tree-kill": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz",
+ "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==",
+ "dev": true,
+ "bin": {
+ "tree-kill": "cli.js"
+ }
+ },
+ "node_modules/tslib": {
+ "version": "2.7.0",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.7.0.tgz",
+ "integrity": "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA=="
+ },
+ "node_modules/undici-types": {
+ "version": "6.19.8",
+ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz",
+ "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==",
+ "dev": true
+ },
+ "node_modules/universalify": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz",
+ "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==",
+ "dev": true,
+ "engines": {
+ "node": ">= 10.0.0"
+ }
+ },
+ "node_modules/untildify": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz",
+ "integrity": "sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/util-deprecate": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
+ "dev": true
+ },
+ "node_modules/which": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
+ "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
+ "dev": true,
+ "dependencies": {
+ "isexe": "^2.0.0"
+ },
+ "bin": {
+ "node-which": "bin/node-which"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/wrap-ansi": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
+ "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^4.0.0",
+ "string-width": "^4.1.0",
+ "strip-ansi": "^6.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
+ }
+ },
+ "node_modules/xml2js": {
+ "version": "0.5.0",
+ "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.5.0.tgz",
+ "integrity": "sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA==",
+ "dev": true,
+ "dependencies": {
+ "sax": ">=0.6.0",
+ "xmlbuilder": "~11.0.0"
+ },
+ "engines": {
+ "node": ">=4.0.0"
+ }
+ },
+ "node_modules/xml2js/node_modules/xmlbuilder": {
+ "version": "11.0.1",
+ "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz",
+ "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==",
+ "dev": true,
+ "engines": {
+ "node": ">=4.0"
+ }
+ },
+ "node_modules/xmlbuilder": {
+ "version": "15.1.1",
+ "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-15.1.1.tgz",
+ "integrity": "sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==",
+ "dev": true,
+ "engines": {
+ "node": ">=8.0"
+ }
+ },
+ "node_modules/yallist": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
+ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
+ "dev": true
+ },
+ "node_modules/yauzl": {
+ "version": "2.10.0",
+ "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz",
+ "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==",
+ "dev": true,
+ "dependencies": {
+ "buffer-crc32": "~0.2.3",
+ "fd-slicer": "~1.1.0"
+ }
+ }
+ }
+}
diff --git a/x/examples/outline-pwa/package.json b/x/examples/outline-pwa/package.json
new file mode 100644
index 00000000..3a573af7
--- /dev/null
+++ b/x/examples/outline-pwa/package.json
@@ -0,0 +1,22 @@
+{
+ "name": "outline-pwa-demo",
+ "version": "1.0.0",
+ "description": "An Amazing Capacitor App",
+ "main": "index.js",
+ "keywords": [
+ "capacitor",
+ "mobile"
+ ],
+ "dependencies": {
+ "@capacitor/android": "^6.1.2",
+ "@capacitor/camera": "latest",
+ "@capacitor/core": "latest",
+ "@capacitor/ios": "^6.1.2",
+ "@capacitor/splash-screen": "latest"
+ },
+ "devDependencies": {
+ "@capacitor/cli": "latest"
+ },
+ "author": "",
+ "license": "ISC"
+}