diff --git a/node_modules/.bin/esbuild b/node_modules/.bin/esbuild new file mode 120000 index 0000000..c83ac07 --- /dev/null +++ b/node_modules/.bin/esbuild @@ -0,0 +1 @@ +../esbuild/bin/esbuild \ No newline at end of file diff --git a/node_modules/.bin/nanoid b/node_modules/.bin/nanoid new file mode 120000 index 0000000..e2be547 --- /dev/null +++ b/node_modules/.bin/nanoid @@ -0,0 +1 @@ +../nanoid/bin/nanoid.cjs \ No newline at end of file diff --git a/node_modules/.bin/rollup b/node_modules/.bin/rollup new file mode 120000 index 0000000..5939621 --- /dev/null +++ b/node_modules/.bin/rollup @@ -0,0 +1 @@ +../rollup/dist/bin/rollup \ No newline at end of file diff --git a/node_modules/@capacitor/android/LICENSE b/node_modules/@capacitor/android/LICENSE new file mode 100644 index 0000000..c3e903b --- /dev/null +++ b/node_modules/@capacitor/android/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2017-present Drifty Co. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/node_modules/@capacitor/android/capacitor/build.gradle b/node_modules/@capacitor/android/capacitor/build.gradle new file mode 100644 index 0000000..6ece3ed --- /dev/null +++ b/node_modules/@capacitor/android/capacitor/build.gradle @@ -0,0 +1,94 @@ +ext { + androidxActivityVersion = project.hasProperty('androidxActivityVersion') ? rootProject.ext.androidxActivityVersion : '1.11.0' + androidxAppCompatVersion = project.hasProperty('androidxAppCompatVersion') ? rootProject.ext.androidxAppCompatVersion : '1.7.1' + androidxCoordinatorLayoutVersion = project.hasProperty('androidxCoordinatorLayoutVersion') ? rootProject.ext.androidxCoordinatorLayoutVersion : '1.3.0' + androidxCoreVersion = project.hasProperty('androidxCoreVersion') ? rootProject.ext.androidxCoreVersion : '1.17.0' + androidxFragmentVersion = project.hasProperty('androidxFragmentVersion') ? rootProject.ext.androidxFragmentVersion : '1.8.9' + androidxWebkitVersion = project.hasProperty('androidxWebkitVersion') ? rootProject.ext.androidxWebkitVersion : '1.14.0' + junitVersion = project.hasProperty('junitVersion') ? rootProject.ext.junitVersion : '4.13.2' + androidxJunitVersion = project.hasProperty('androidxJunitVersion') ? rootProject.ext.androidxJunitVersion : '1.3.0' + androidxEspressoCoreVersion = project.hasProperty('androidxEspressoCoreVersion') ? rootProject.ext.androidxEspressoCoreVersion : '3.7.0' + cordovaAndroidVersion = project.hasProperty('cordovaAndroidVersion') ? rootProject.ext.cordovaAndroidVersion : '14.0.1' +} + + +buildscript { + repositories { + google() + mavenCentral() + maven { + url = "https://plugins.gradle.org/m2/" + } + } + dependencies { + classpath 'com.android.tools.build:gradle:8.13.0' + + if (System.getenv("CAP_PUBLISH") == "true") { + classpath 'io.github.gradle-nexus:publish-plugin:1.3.0' + } + } +} + +tasks.withType(Javadoc).all { enabled = false } + +apply plugin: 'com.android.library' + +if (System.getenv("CAP_PUBLISH") == "true") { + apply plugin: 'io.github.gradle-nexus.publish-plugin' + apply from: file('../scripts/publish-root.gradle') + apply from: file('../scripts/publish-module.gradle') +} + +android { + namespace = "com.getcapacitor.android" + compileSdk = project.hasProperty('compileSdkVersion') ? rootProject.ext.compileSdkVersion : 36 + defaultConfig { + minSdkVersion project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : 24 + targetSdkVersion project.hasProperty('targetSdkVersion') ? rootProject.ext.targetSdkVersion : 36 + versionCode 1 + versionName "1.0" + consumerProguardFiles 'proguard-rules.pro' + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } + lintOptions { + baseline file("lint-baseline.xml") + abortOnError = true + warningsAsErrors = true + lintConfig = file('lint.xml') + } + compileOptions { + sourceCompatibility JavaVersion.VERSION_21 + targetCompatibility JavaVersion.VERSION_21 + } + publishing { + singleVariant("release") + } +} + +repositories { + google() + mavenCentral() +} + +dependencies { + implementation fileTree(dir: 'libs', include: ['*.jar']) + implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion" + implementation "androidx.core:core:$androidxCoreVersion" + implementation "androidx.activity:activity:$androidxActivityVersion" + implementation "androidx.fragment:fragment:$androidxFragmentVersion" + implementation "androidx.coordinatorlayout:coordinatorlayout:$androidxCoordinatorLayoutVersion" + implementation "androidx.webkit:webkit:$androidxWebkitVersion" + testImplementation "junit:junit:$junitVersion" + androidTestImplementation "androidx.test.ext:junit:$androidxJunitVersion" + androidTestImplementation "androidx.test.espresso:espresso-core:$androidxEspressoCoreVersion" + implementation "org.apache.cordova:framework:$cordovaAndroidVersion" + testImplementation 'org.json:json:20250517' + testImplementation 'org.mockito:mockito-core:5.20.0' +} + diff --git a/node_modules/@capacitor/android/capacitor/lint-baseline.xml b/node_modules/@capacitor/android/capacitor/lint-baseline.xml new file mode 100644 index 0000000..c1ed9cc --- /dev/null +++ b/node_modules/@capacitor/android/capacitor/lint-baseline.xml @@ -0,0 +1,136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/node_modules/@capacitor/android/capacitor/lint.xml b/node_modules/@capacitor/android/capacitor/lint.xml new file mode 100644 index 0000000..b00604b --- /dev/null +++ b/node_modules/@capacitor/android/capacitor/lint.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/node_modules/@capacitor/android/capacitor/proguard-rules.pro b/node_modules/@capacitor/android/capacitor/proguard-rules.pro new file mode 100644 index 0000000..96db065 --- /dev/null +++ b/node_modules/@capacitor/android/capacitor/proguard-rules.pro @@ -0,0 +1,28 @@ +# 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 + +# Rules for Capacitor v3 plugins and annotations + -keep @com.getcapacitor.annotation.CapacitorPlugin public class * { + @com.getcapacitor.annotation.PermissionCallback ; + @com.getcapacitor.annotation.ActivityCallback ; + @com.getcapacitor.annotation.Permission ; + @com.getcapacitor.PluginMethod public ; + } + + -keep public class * extends com.getcapacitor.Plugin { *; } + +# Rules for Capacitor v2 plugins and annotations +# These are deprecated but can still be used with Capacitor for now +-keep @com.getcapacitor.NativePlugin public class * { + @com.getcapacitor.PluginMethod public ; +} + +# Rules for Cordova plugins +-keep public class * extends org.apache.cordova.* { + public ; + public ; +} \ No newline at end of file diff --git a/node_modules/@capacitor/android/capacitor/src/main/AndroidManifest.xml b/node_modules/@capacitor/android/capacitor/src/main/AndroidManifest.xml new file mode 100644 index 0000000..74b7379 --- /dev/null +++ b/node_modules/@capacitor/android/capacitor/src/main/AndroidManifest.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/node_modules/@capacitor/android/capacitor/src/main/assets/native-bridge.js b/node_modules/@capacitor/android/capacitor/src/main/assets/native-bridge.js new file mode 100644 index 0000000..f5e7cc4 --- /dev/null +++ b/node_modules/@capacitor/android/capacitor/src/main/assets/native-bridge.js @@ -0,0 +1,1039 @@ + +/*! Capacitor: https://capacitorjs.com/ - MIT License */ +/* Generated File. Do not edit. */ + +var nativeBridge = (function (exports) { + 'use strict'; + + var ExceptionCode; + (function (ExceptionCode) { + /** + * API is not implemented. + * + * This usually means the API can't be used because it is not implemented for + * the current platform. + */ + ExceptionCode["Unimplemented"] = "UNIMPLEMENTED"; + /** + * API is not available. + * + * This means the API can't be used right now because: + * - it is currently missing a prerequisite, such as network connectivity + * - it requires a particular platform or browser version + */ + ExceptionCode["Unavailable"] = "UNAVAILABLE"; + })(ExceptionCode || (ExceptionCode = {})); + class CapacitorException extends Error { + constructor(message, code, data) { + super(message); + this.message = message; + this.code = code; + this.data = data; + } + } + + // For removing exports for iOS/Android, keep let for reassignment + // eslint-disable-next-line + let dummy = {}; + const readFileAsBase64 = (file) => new Promise((resolve, reject) => { + const reader = new FileReader(); + reader.onloadend = () => { + const data = reader.result; + resolve(btoa(data)); + }; + reader.onerror = reject; + reader.readAsBinaryString(file); + }); + const convertFormData = async (formData) => { + const newFormData = []; + for (const pair of formData.entries()) { + const [key, value] = pair; + if (value instanceof File) { + const base64File = await readFileAsBase64(value); + newFormData.push({ + key, + value: base64File, + type: 'base64File', + contentType: value.type, + fileName: value.name, + }); + } + else { + newFormData.push({ key, value, type: 'string' }); + } + } + return newFormData; + }; + const convertBody = async (body, contentType) => { + if (body instanceof ReadableStream || body instanceof Uint8Array) { + let encodedData; + if (body instanceof ReadableStream) { + const reader = body.getReader(); + const chunks = []; + while (true) { + const { done, value } = await reader.read(); + if (done) + break; + chunks.push(value); + } + const concatenated = new Uint8Array(chunks.reduce((acc, chunk) => acc + chunk.length, 0)); + let position = 0; + for (const chunk of chunks) { + concatenated.set(chunk, position); + position += chunk.length; + } + encodedData = concatenated; + } + else { + encodedData = body; + } + let data = new TextDecoder().decode(encodedData); + let type; + if (contentType === 'application/json') { + try { + data = JSON.parse(data); + } + catch (ignored) { + // ignore + } + type = 'json'; + } + else if (contentType === 'multipart/form-data') { + type = 'formData'; + } + else if (contentType === null || contentType === void 0 ? void 0 : contentType.startsWith('image')) { + type = 'image'; + } + else if (contentType === 'application/octet-stream') { + type = 'binary'; + } + else { + type = 'text'; + } + return { + data, + type, + headers: { 'Content-Type': contentType || 'application/octet-stream' }, + }; + } + else if (body instanceof URLSearchParams) { + return { + data: body.toString(), + type: 'text', + }; + } + else if (body instanceof FormData) { + return { + data: await convertFormData(body), + type: 'formData', + }; + } + else if (body instanceof File) { + const fileData = await readFileAsBase64(body); + return { + data: fileData, + type: 'file', + headers: { 'Content-Type': body.type }, + }; + } + return { data: body, type: 'json' }; + }; + const CAPACITOR_HTTP_INTERCEPTOR = '/_capacitor_http_interceptor_'; + const CAPACITOR_HTTP_INTERCEPTOR_URL_PARAM = 'u'; + // TODO: export as Cap function + const isRelativeOrProxyUrl = (url) => !url || !(url.startsWith('http:') || url.startsWith('https:')) || url.indexOf(CAPACITOR_HTTP_INTERCEPTOR) > -1; + // TODO: export as Cap function + const createProxyUrl = (url, win) => { + var _a, _b; + if (isRelativeOrProxyUrl(url)) + return url; + const bridgeUrl = new URL((_b = (_a = win.Capacitor) === null || _a === void 0 ? void 0 : _a.getServerUrl()) !== null && _b !== void 0 ? _b : ''); + bridgeUrl.pathname = CAPACITOR_HTTP_INTERCEPTOR; + bridgeUrl.searchParams.append(CAPACITOR_HTTP_INTERCEPTOR_URL_PARAM, url); + return bridgeUrl.toString(); + }; + const initBridge = (w) => { + const getPlatformId = (win) => { + var _a, _b; + if (win === null || win === void 0 ? void 0 : win.androidBridge) { + return 'android'; + } + else if ((_b = (_a = win === null || win === void 0 ? void 0 : win.webkit) === null || _a === void 0 ? void 0 : _a.messageHandlers) === null || _b === void 0 ? void 0 : _b.bridge) { + return 'ios'; + } + else { + return 'web'; + } + }; + const convertFileSrcServerUrl = (webviewServerUrl, filePath) => { + if (typeof filePath === 'string') { + if (filePath.startsWith('/')) { + return webviewServerUrl + '/_capacitor_file_' + filePath; + } + else if (filePath.startsWith('file://')) { + return webviewServerUrl + filePath.replace('file://', '/_capacitor_file_'); + } + else if (filePath.startsWith('content://')) { + return webviewServerUrl + filePath.replace('content:/', '/_capacitor_content_'); + } + } + return filePath; + }; + const initEvents = (win, cap) => { + cap.addListener = (pluginName, eventName, callback) => { + const callbackId = cap.nativeCallback(pluginName, 'addListener', { + eventName: eventName, + }, callback); + return { + remove: async () => { + var _a; + (_a = win === null || win === void 0 ? void 0 : win.console) === null || _a === void 0 ? void 0 : _a.debug('Removing listener', pluginName, eventName); + cap.removeListener(pluginName, callbackId, eventName, callback); + }, + }; + }; + cap.removeListener = (pluginName, callbackId, eventName, callback) => { + cap.nativeCallback(pluginName, 'removeListener', { + callbackId: callbackId, + eventName: eventName, + }, callback); + }; + cap.createEvent = (eventName, eventData) => { + const doc = win.document; + if (doc) { + const ev = doc.createEvent('Events'); + ev.initEvent(eventName, false, false); + if (eventData && typeof eventData === 'object') { + for (const i in eventData) { + // eslint-disable-next-line no-prototype-builtins + if (eventData.hasOwnProperty(i)) { + ev[i] = eventData[i]; + } + } + } + return ev; + } + return null; + }; + cap.triggerEvent = (eventName, target, eventData) => { + const doc = win.document; + const cordova = win.cordova; + eventData = eventData || {}; + const ev = cap.createEvent(eventName, eventData); + if (ev) { + if (target === 'document') { + if (cordova === null || cordova === void 0 ? void 0 : cordova.fireDocumentEvent) { + cordova.fireDocumentEvent(eventName, eventData); + return true; + } + else if (doc === null || doc === void 0 ? void 0 : doc.dispatchEvent) { + return doc.dispatchEvent(ev); + } + } + else if (target === 'window' && win.dispatchEvent) { + return win.dispatchEvent(ev); + } + else if (doc === null || doc === void 0 ? void 0 : doc.querySelector) { + const targetEl = doc.querySelector(target); + if (targetEl) { + return targetEl.dispatchEvent(ev); + } + } + } + return false; + }; + win.Capacitor = cap; + }; + const initLegacyHandlers = (win, cap) => { + // define cordova if it's not there already + win.cordova = win.cordova || {}; + const doc = win.document; + const nav = win.navigator; + if (nav) { + nav.app = nav.app || {}; + nav.app.exitApp = () => { + var _a; + if (!((_a = cap.Plugins) === null || _a === void 0 ? void 0 : _a.App)) { + win.console.warn('App plugin not installed'); + } + else { + cap.nativeCallback('App', 'exitApp', {}); + } + }; + } + if (doc) { + const docAddEventListener = doc.addEventListener; + doc.addEventListener = (...args) => { + var _a; + const eventName = args[0]; + const handler = args[1]; + if (eventName === 'deviceready' && handler) { + Promise.resolve().then(handler); + } + else if (eventName === 'backbutton' && cap.Plugins.App) { + // Add a dummy listener so Capacitor doesn't do the default + // back button action + if (!((_a = cap.Plugins) === null || _a === void 0 ? void 0 : _a.App)) { + win.console.warn('App plugin not installed'); + } + else { + cap.Plugins.App.addListener('backButton', () => { + // ignore + }); + } + } + return docAddEventListener.apply(doc, args); + }; + } + win.Capacitor = cap; + }; + const initVendor = (win, cap) => { + const Ionic = (win.Ionic = win.Ionic || {}); + const IonicWebView = (Ionic.WebView = Ionic.WebView || {}); + const Plugins = cap.Plugins; + IonicWebView.getServerBasePath = (callback) => { + var _a; + (_a = Plugins === null || Plugins === void 0 ? void 0 : Plugins.WebView) === null || _a === void 0 ? void 0 : _a.getServerBasePath().then((result) => { + callback(result.path); + }); + }; + IonicWebView.setServerAssetPath = (path) => { + var _a; + (_a = Plugins === null || Plugins === void 0 ? void 0 : Plugins.WebView) === null || _a === void 0 ? void 0 : _a.setServerAssetPath({ path }); + }; + IonicWebView.setServerBasePath = (path) => { + var _a; + (_a = Plugins === null || Plugins === void 0 ? void 0 : Plugins.WebView) === null || _a === void 0 ? void 0 : _a.setServerBasePath({ path }); + }; + IonicWebView.persistServerBasePath = () => { + var _a; + (_a = Plugins === null || Plugins === void 0 ? void 0 : Plugins.WebView) === null || _a === void 0 ? void 0 : _a.persistServerBasePath(); + }; + IonicWebView.convertFileSrc = (url) => cap.convertFileSrc(url); + win.Capacitor = cap; + win.Ionic.WebView = IonicWebView; + }; + const initLogger = (win, cap) => { + const BRIDGED_CONSOLE_METHODS = ['debug', 'error', 'info', 'log', 'trace', 'warn']; + const createLogFromNative = (c) => (result) => { + if (isFullConsole(c)) { + const success = result.success === true; + const tagStyles = success + ? 'font-style: italic; font-weight: lighter; color: gray' + : 'font-style: italic; font-weight: lighter; color: red'; + c.groupCollapsed('%cresult %c' + result.pluginId + '.' + result.methodName + ' (#' + result.callbackId + ')', tagStyles, 'font-style: italic; font-weight: bold; color: #444'); + if (result.success === false) { + c.error(result.error); + } + else { + c.dir(JSON.stringify(result.data)); + } + c.groupEnd(); + } + else { + if (result.success === false) { + c.error('LOG FROM NATIVE', result.error); + } + else { + c.log('LOG FROM NATIVE', result.data); + } + } + }; + const createLogToNative = (c) => (call) => { + if (isFullConsole(c)) { + c.groupCollapsed('%cnative %c' + call.pluginId + '.' + call.methodName + ' (#' + call.callbackId + ')', 'font-weight: lighter; color: gray', 'font-weight: bold; color: #000'); + c.dir(call); + c.groupEnd(); + } + else { + c.log('LOG TO NATIVE: ', call); + } + }; + const isFullConsole = (c) => { + if (!c) { + return false; + } + return typeof c.groupCollapsed === 'function' || typeof c.groupEnd === 'function' || typeof c.dir === 'function'; + }; + const serializeConsoleMessage = (msg) => { + try { + if (typeof msg === 'object') { + msg = JSON.stringify(msg); + } + return String(msg); + } + catch (e) { + return ''; + } + }; + const platform = getPlatformId(win); + if (platform == 'android' && typeof win.CapacitorSystemBarsAndroidInterface !== 'undefined') { + // add DOM ready listener for System Bars + document.addEventListener('DOMContentLoaded', function () { + win.CapacitorSystemBarsAndroidInterface.onDOMReady(); + }); + } + if (platform == 'android' || platform == 'ios') { + // patch document.cookie on Android/iOS + win.CapacitorCookiesDescriptor = + Object.getOwnPropertyDescriptor(Document.prototype, 'cookie') || + Object.getOwnPropertyDescriptor(HTMLDocument.prototype, 'cookie'); + let doPatchCookies = false; + // check if capacitor cookies is disabled before patching + if (platform === 'ios') { + // Use prompt to synchronously get capacitor cookies config. + // https://stackoverflow.com/questions/29249132/wkwebview-complex-communication-between-javascript-native-code/49474323#49474323 + const payload = { + type: 'CapacitorCookies.isEnabled', + }; + const isCookiesEnabled = prompt(JSON.stringify(payload)); + if (isCookiesEnabled === 'true') { + doPatchCookies = true; + } + } + else if (typeof win.CapacitorCookiesAndroidInterface !== 'undefined') { + const isCookiesEnabled = win.CapacitorCookiesAndroidInterface.isEnabled(); + if (isCookiesEnabled === true) { + doPatchCookies = true; + } + } + if (doPatchCookies) { + Object.defineProperty(document, 'cookie', { + get: function () { + var _a, _b, _c; + if (platform === 'ios') { + // Use prompt to synchronously get cookies. + // https://stackoverflow.com/questions/29249132/wkwebview-complex-communication-between-javascript-native-code/49474323#49474323 + const payload = { + type: 'CapacitorCookies.get', + }; + const res = prompt(JSON.stringify(payload)); + return res; + } + else if (typeof win.CapacitorCookiesAndroidInterface !== 'undefined') { + // return original document.cookie since Android does not support filtering of `httpOnly` cookies + return (_c = (_b = (_a = win.CapacitorCookiesDescriptor) === null || _a === void 0 ? void 0 : _a.get) === null || _b === void 0 ? void 0 : _b.call(document)) !== null && _c !== void 0 ? _c : ''; + } + }, + set: function (val) { + const cookiePairs = val.split(';'); + const domainSection = val.toLowerCase().split('domain=')[1]; + const domain = cookiePairs.length > 1 && domainSection != null && domainSection.length > 0 + ? domainSection.split(';')[0].trim() + : ''; + if (platform === 'ios') { + // Use prompt to synchronously set cookies. + // https://stackoverflow.com/questions/29249132/wkwebview-complex-communication-between-javascript-native-code/49474323#49474323 + const payload = { + type: 'CapacitorCookies.set', + action: val, + domain, + }; + prompt(JSON.stringify(payload)); + } + else if (typeof win.CapacitorCookiesAndroidInterface !== 'undefined') { + win.CapacitorCookiesAndroidInterface.setCookie(domain, val); + } + }, + }); + } + // patch fetch / XHR on Android/iOS + // store original fetch & XHR functions + win.CapacitorWebFetch = window.fetch; + win.CapacitorWebXMLHttpRequest = { + abort: window.XMLHttpRequest.prototype.abort, + constructor: window.XMLHttpRequest.prototype.constructor, + fullObject: window.XMLHttpRequest, + getAllResponseHeaders: window.XMLHttpRequest.prototype.getAllResponseHeaders, + getResponseHeader: window.XMLHttpRequest.prototype.getResponseHeader, + open: window.XMLHttpRequest.prototype.open, + prototype: window.XMLHttpRequest.prototype, + send: window.XMLHttpRequest.prototype.send, + setRequestHeader: window.XMLHttpRequest.prototype.setRequestHeader, + }; + let doPatchHttp = false; + // check if capacitor http is disabled before patching + if (platform === 'ios') { + // Use prompt to synchronously get capacitor http config. + // https://stackoverflow.com/questions/29249132/wkwebview-complex-communication-between-javascript-native-code/49474323#49474323 + const payload = { + type: 'CapacitorHttp', + }; + const isHttpEnabled = prompt(JSON.stringify(payload)); + if (isHttpEnabled === 'true') { + doPatchHttp = true; + } + } + else if (typeof win.CapacitorHttpAndroidInterface !== 'undefined') { + const isHttpEnabled = win.CapacitorHttpAndroidInterface.isEnabled(); + if (isHttpEnabled === true) { + doPatchHttp = true; + } + } + if (doPatchHttp) { + // fetch patch + window.fetch = async (resource, options) => { + const headers = new Headers(options === null || options === void 0 ? void 0 : options.headers); + const contentType = headers.get('Content-Type') || headers.get('content-type'); + if ((options === null || options === void 0 ? void 0 : options.body) instanceof FormData && + (contentType === null || contentType === void 0 ? void 0 : contentType.includes('multipart/form-data')) && + !contentType.includes('boundary')) { + headers.delete('Content-Type'); + headers.delete('content-type'); + options.headers = headers; + } + const request = new Request(resource, options); + if (request.url.startsWith(`${cap.getServerUrl()}/`)) { + return win.CapacitorWebFetch(resource, options); + } + const { method } = request; + if (method.toLocaleUpperCase() === 'GET' || + method.toLocaleUpperCase() === 'HEAD' || + method.toLocaleUpperCase() === 'OPTIONS' || + method.toLocaleUpperCase() === 'TRACE') { + // a workaround for following android webview issue: + // https://issues.chromium.org/issues/40450316 + // Sets the user-agent header to a custom value so that its not stripped + // on its way to the native layer + if (platform === 'android' && (options === null || options === void 0 ? void 0 : options.headers)) { + const userAgent = headers.get('User-Agent') || headers.get('user-agent'); + if (userAgent !== null) { + headers.set('x-cap-user-agent', userAgent); + options.headers = headers; + } + } + if (typeof resource === 'string') { + return await win.CapacitorWebFetch(createProxyUrl(resource, win), options); + } + else if (resource instanceof URL) { + const modifiedURL = new URL(createProxyUrl(resource.toString(), win)); + return await win.CapacitorWebFetch(modifiedURL, options); + } + else if (resource instanceof Request) { + const modifiedRequest = new Request(createProxyUrl(resource.url, win), resource); + return await win.CapacitorWebFetch(modifiedRequest, options); + } + } + const tag = `CapacitorHttp fetch ${Date.now()} ${resource}`; + console.time(tag); + try { + const { body } = request; + const optionHeaders = Object.fromEntries(request.headers.entries()); + const { data: requestData, type, headers: requestHeaders, } = await convertBody((options === null || options === void 0 ? void 0 : options.body) || body || undefined, optionHeaders['Content-Type'] || optionHeaders['content-type']); + const nativeHeaders = Object.assign(Object.assign({}, requestHeaders), optionHeaders); + if (platform === 'android') { + if (headers.has('User-Agent')) { + nativeHeaders['User-Agent'] = headers.get('User-Agent'); + } + if (headers.has('user-agent')) { + nativeHeaders['user-agent'] = headers.get('user-agent'); + } + } + const nativeResponse = await cap.nativePromise('CapacitorHttp', 'request', { + url: request.url, + method: method, + data: requestData, + dataType: type, + headers: nativeHeaders, + }); + const contentType = nativeResponse.headers['Content-Type'] || nativeResponse.headers['content-type']; + let data = (contentType === null || contentType === void 0 ? void 0 : contentType.startsWith('application/json')) + ? JSON.stringify(nativeResponse.data) + : nativeResponse.data; + // use null data for 204 No Content HTTP response + if (nativeResponse.status === 204) { + data = null; + } + // intercept & parse response before returning + const response = new Response(data, { + headers: nativeResponse.headers, + status: nativeResponse.status, + }); + /* + * copy url to response, `cordova-plugin-ionic` uses this url from the response + * we need `Object.defineProperty` because url is an inherited getter on the Response + * see: https://stackoverflow.com/a/57382543 + * */ + Object.defineProperty(response, 'url', { + value: nativeResponse.url, + }); + console.timeEnd(tag); + return response; + } + catch (error) { + console.timeEnd(tag); + return Promise.reject(error); + } + }; + window.XMLHttpRequest = function () { + const xhr = new win.CapacitorWebXMLHttpRequest.constructor(); + Object.defineProperties(xhr, { + _headers: { + value: {}, + writable: true, + }, + _method: { + value: xhr.method, + writable: true, + }, + }); + const prototype = win.CapacitorWebXMLHttpRequest.prototype; + const isProgressEventAvailable = () => typeof ProgressEvent !== 'undefined' && ProgressEvent.prototype instanceof Event; + // XHR patch abort + prototype.abort = function () { + if (isRelativeOrProxyUrl(this._url)) { + return win.CapacitorWebXMLHttpRequest.abort.call(this); + } + this.readyState = 0; + setTimeout(() => { + this.dispatchEvent(new Event('abort')); + this.dispatchEvent(new Event('loadend')); + }); + }; + // XHR patch open + prototype.open = function (method, url) { + this._method = method.toLocaleUpperCase(); + this._url = url; + if (!this._method || + this._method === 'GET' || + this._method === 'HEAD' || + this._method === 'OPTIONS' || + this._method === 'TRACE') { + if (isRelativeOrProxyUrl(url)) { + return win.CapacitorWebXMLHttpRequest.open.call(this, method, url); + } + this._url = createProxyUrl(this._url, win); + return win.CapacitorWebXMLHttpRequest.open.call(this, method, this._url); + } + Object.defineProperties(this, { + readyState: { + get: function () { + var _a; + return (_a = this._readyState) !== null && _a !== void 0 ? _a : 0; + }, + set: function (val) { + this._readyState = val; + setTimeout(() => { + this.dispatchEvent(new Event('readystatechange')); + }); + }, + }, + }); + setTimeout(() => { + this.dispatchEvent(new Event('loadstart')); + }); + this.readyState = 1; + }; + // XHR patch set request header + prototype.setRequestHeader = function (header, value) { + // a workaround for the following android web view issue: + // https://issues.chromium.org/issues/40450316 + // Sets the user-agent header to a custom value so that its not stripped + // on its way to the native layer + if (platform === 'android' && (header === 'User-Agent' || header === 'user-agent')) { + header = 'x-cap-user-agent'; + } + if (isRelativeOrProxyUrl(this._url)) { + return win.CapacitorWebXMLHttpRequest.setRequestHeader.call(this, header, value); + } + this._headers[header] = value; + }; + // XHR patch send + prototype.send = function (body) { + if (isRelativeOrProxyUrl(this._url)) { + return win.CapacitorWebXMLHttpRequest.send.call(this, body); + } + const tag = `CapacitorHttp XMLHttpRequest ${Date.now()} ${this._url}`; + console.time(tag); + try { + this.readyState = 2; + Object.defineProperties(this, { + response: { + value: '', + writable: true, + }, + responseText: { + value: '', + writable: true, + }, + responseURL: { + value: '', + writable: true, + }, + status: { + value: 0, + writable: true, + }, + }); + convertBody(body).then(({ data, type, headers }) => { + let otherHeaders = this._headers != null && Object.keys(this._headers).length > 0 ? this._headers : undefined; + if (body instanceof FormData) { + if (!this._headers['Content-Type'] && !this._headers['content-type']) { + otherHeaders = Object.assign(Object.assign({}, otherHeaders), { 'Content-Type': `multipart/form-data; boundary=----WebKitFormBoundary${Math.random().toString(36).substring(2, 15)}` }); + } + } + // intercept request & pass to the bridge + cap + .nativePromise('CapacitorHttp', 'request', { + url: this._url, + method: this._method, + data: data !== null ? data : undefined, + headers: Object.assign(Object.assign({}, headers), otherHeaders), + dataType: type, + }) + .then((nativeResponse) => { + var _a; + // intercept & parse response before returning + if (this.readyState == 2) { + //TODO: Add progress event emission on native side + if (isProgressEventAvailable()) { + this.dispatchEvent(new ProgressEvent('progress', { + lengthComputable: true, + loaded: nativeResponse.data.length, + total: nativeResponse.data.length, + })); + } + this._headers = nativeResponse.headers; + this.status = nativeResponse.status; + if (this.responseType === '' || this.responseType === 'text') { + this.response = + typeof nativeResponse.data !== 'string' + ? JSON.stringify(nativeResponse.data) + : nativeResponse.data; + } + else { + this.response = nativeResponse.data; + } + this.responseText = ((_a = (nativeResponse.headers['Content-Type'] || nativeResponse.headers['content-type'])) === null || _a === void 0 ? void 0 : _a.startsWith('application/json')) + ? JSON.stringify(nativeResponse.data) + : nativeResponse.data; + this.responseURL = nativeResponse.url; + this.readyState = 4; + setTimeout(() => { + this.dispatchEvent(new Event('load')); + this.dispatchEvent(new Event('loadend')); + }); + } + console.timeEnd(tag); + }) + .catch((error) => { + this.status = error.status; + this._headers = error.headers; + this.response = error.data; + this.responseText = JSON.stringify(error.data); + this.responseURL = error.url; + this.readyState = 4; + if (isProgressEventAvailable()) { + this.dispatchEvent(new ProgressEvent('progress', { + lengthComputable: false, + loaded: 0, + total: 0, + })); + } + setTimeout(() => { + this.dispatchEvent(new Event('error')); + this.dispatchEvent(new Event('loadend')); + }); + console.timeEnd(tag); + }); + }); + } + catch (error) { + this.status = 500; + this._headers = {}; + this.response = error; + this.responseText = error.toString(); + this.responseURL = this._url; + this.readyState = 4; + if (isProgressEventAvailable()) { + this.dispatchEvent(new ProgressEvent('progress', { + lengthComputable: false, + loaded: 0, + total: 0, + })); + } + setTimeout(() => { + this.dispatchEvent(new Event('error')); + this.dispatchEvent(new Event('loadend')); + }); + console.timeEnd(tag); + } + }; + // XHR patch getAllResponseHeaders + prototype.getAllResponseHeaders = function () { + if (isRelativeOrProxyUrl(this._url)) { + return win.CapacitorWebXMLHttpRequest.getAllResponseHeaders.call(this); + } + let returnString = ''; + for (const key in this._headers) { + if (key != 'Set-Cookie') { + returnString += key + ': ' + this._headers[key] + '\r\n'; + } + } + return returnString; + }; + // XHR patch getResponseHeader + prototype.getResponseHeader = function (name) { + if (isRelativeOrProxyUrl(this._url)) { + return win.CapacitorWebXMLHttpRequest.getResponseHeader.call(this, name); + } + return this._headers[name]; + }; + Object.setPrototypeOf(xhr, prototype); + return xhr; + }; + Object.assign(window.XMLHttpRequest, win.CapacitorWebXMLHttpRequest.fullObject); + } + } + // patch window.console on iOS and store original console fns + const isIos = getPlatformId(win) === 'ios'; + if (win.console && isIos) { + Object.defineProperties(win.console, BRIDGED_CONSOLE_METHODS.reduce((props, method) => { + const consoleMethod = win.console[method].bind(win.console); + props[method] = { + value: (...args) => { + const msgs = [...args]; + cap.toNative('Console', 'log', { + level: method, + message: msgs.map(serializeConsoleMessage).join(' '), + }); + return consoleMethod(...args); + }, + }; + return props; + }, {})); + } + cap.logJs = (msg, level) => { + switch (level) { + case 'error': + win.console.error(msg); + break; + case 'warn': + win.console.warn(msg); + break; + case 'info': + win.console.info(msg); + break; + default: + win.console.log(msg); + } + }; + cap.logToNative = createLogToNative(win.console); + cap.logFromNative = createLogFromNative(win.console); + cap.handleError = (err) => win.console.error(err); + win.Capacitor = cap; + }; + function initNativeBridge(win) { + const cap = win.Capacitor || {}; + // keep a collection of callbacks for native response data + const callbacks = new Map(); + const webviewServerUrl = typeof win.WEBVIEW_SERVER_URL === 'string' ? win.WEBVIEW_SERVER_URL : ''; + cap.getServerUrl = () => webviewServerUrl; + cap.convertFileSrc = (filePath) => convertFileSrcServerUrl(webviewServerUrl, filePath); + // Counter of callback ids, randomized to avoid + // any issues during reloads if a call comes back with + // an existing callback id from an old session + let callbackIdCount = Math.floor(Math.random() * 134217728); + let postToNative = null; + const isNativePlatform = () => true; + const getPlatform = () => getPlatformId(win); + cap.getPlatform = getPlatform; + cap.isPluginAvailable = (name) => Object.prototype.hasOwnProperty.call(cap.Plugins, name); + cap.isNativePlatform = isNativePlatform; + // create the postToNative() fn if needed + if (getPlatformId(win) === 'android') { + // android platform + postToNative = (data) => { + var _a; + try { + win.androidBridge.postMessage(JSON.stringify(data)); + } + catch (e) { + (_a = win === null || win === void 0 ? void 0 : win.console) === null || _a === void 0 ? void 0 : _a.error(e); + } + }; + } + else if (getPlatformId(win) === 'ios') { + // ios platform + postToNative = (data) => { + var _a; + try { + data.type = data.type ? data.type : 'message'; + win.webkit.messageHandlers.bridge.postMessage(data); + } + catch (e) { + (_a = win === null || win === void 0 ? void 0 : win.console) === null || _a === void 0 ? void 0 : _a.error(e); + } + }; + } + cap.handleWindowError = (msg, url, lineNo, columnNo, err) => { + const str = msg.toLowerCase(); + if (str.indexOf('script error') > -1) ; + else { + const errObj = { + type: 'js.error', + error: { + message: msg, + url: url, + line: lineNo, + col: columnNo, + errorObject: JSON.stringify(err), + }, + }; + if (err !== null) { + cap.handleError(err); + } + postToNative(errObj); + } + return false; + }; + if (cap.DEBUG) { + window.onerror = cap.handleWindowError; + } + initLogger(win, cap); + /** + * Send a plugin method call to the native layer + */ + cap.toNative = (pluginName, methodName, options, storedCallback) => { + var _a, _b; + try { + if (typeof postToNative === 'function') { + let callbackId = '-1'; + if (storedCallback && + (typeof storedCallback.callback === 'function' || typeof storedCallback.resolve === 'function')) { + // store the call for later lookup + callbackId = String(++callbackIdCount); + callbacks.set(callbackId, storedCallback); + } + const callData = { + callbackId: callbackId, + pluginId: pluginName, + methodName: methodName, + options: options || {}, + }; + if (cap.isLoggingEnabled && pluginName !== 'Console') { + cap.logToNative(callData); + } + // post the call data to native + postToNative(callData); + return callbackId; + } + else { + (_a = win === null || win === void 0 ? void 0 : win.console) === null || _a === void 0 ? void 0 : _a.warn(`implementation unavailable for: ${pluginName}`); + } + } + catch (e) { + (_b = win === null || win === void 0 ? void 0 : win.console) === null || _b === void 0 ? void 0 : _b.error(e); + } + return null; + }; + if (win === null || win === void 0 ? void 0 : win.androidBridge) { + win.androidBridge.onmessage = function (event) { + returnResult(JSON.parse(event.data)); + }; + } + /** + * Process a response from the native layer. + */ + cap.fromNative = (result) => { + returnResult(result); + }; + const returnResult = (result) => { + var _a, _b; + if (cap.isLoggingEnabled && result.pluginId !== 'Console') { + cap.logFromNative(result); + } + // get the stored call, if it exists + try { + const storedCall = callbacks.get(result.callbackId); + if (storedCall) { + // looks like we've got a stored call + if (result.error) { + // ensure stacktraces by copying error properties to an Error + result.error = Object.keys(result.error).reduce((err, key) => { + // use any type to avoid importing util and compiling most of .ts files + err[key] = result.error[key]; + return err; + }, new cap.Exception('')); + } + if (typeof storedCall.callback === 'function') { + // callback + if (result.success) { + storedCall.callback(result.data); + } + else { + storedCall.callback(null, result.error); + } + } + else if (typeof storedCall.resolve === 'function') { + // promise + if (result.success) { + storedCall.resolve(result.data); + } + else { + storedCall.reject(result.error); + } + // no need to keep this stored callback + // around for a one time resolve promise + callbacks.delete(result.callbackId); + } + } + else if (!result.success && result.error) { + // no stored callback, but if there was an error let's log it + (_a = win === null || win === void 0 ? void 0 : win.console) === null || _a === void 0 ? void 0 : _a.warn(result.error); + } + if (result.save === false) { + callbacks.delete(result.callbackId); + } + } + catch (e) { + (_b = win === null || win === void 0 ? void 0 : win.console) === null || _b === void 0 ? void 0 : _b.error(e); + } + // always delete to prevent memory leaks + // overkill but we're not sure what apps will do with this data + delete result.data; + delete result.error; + }; + cap.nativeCallback = (pluginName, methodName, options, callback) => { + if (typeof options === 'function') { + console.warn(`Using a callback as the 'options' parameter of 'nativeCallback()' is deprecated.`); + callback = options; + options = null; + } + return cap.toNative(pluginName, methodName, options, { callback }); + }; + cap.nativePromise = (pluginName, methodName, options) => { + return new Promise((resolve, reject) => { + cap.toNative(pluginName, methodName, options, { + resolve: resolve, + reject: reject, + }); + }); + }; + // eslint-disable-next-line @typescript-eslint/no-unused-vars + cap.withPlugin = (_pluginId, _fn) => dummy; + cap.Exception = CapacitorException; + initEvents(win, cap); + initLegacyHandlers(win, cap); + initVendor(win, cap); + win.Capacitor = cap; + } + initNativeBridge(w); + }; + initBridge(typeof globalThis !== 'undefined' + ? globalThis + : typeof self !== 'undefined' + ? self + : typeof window !== 'undefined' + ? window + : typeof global !== 'undefined' + ? global + : {}); + + dummy = initBridge; + + Object.defineProperty(exports, '__esModule', { value: true }); + + return exports; + +})({}); diff --git a/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/AndroidProtocolHandler.java b/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/AndroidProtocolHandler.java new file mode 100755 index 0000000..df893c7 --- /dev/null +++ b/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/AndroidProtocolHandler.java @@ -0,0 +1,94 @@ +// Copyright 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package com.getcapacitor; + +import android.content.Context; +import android.content.res.AssetManager; +import android.net.Uri; +import android.util.TypedValue; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.List; + +public class AndroidProtocolHandler { + + private Context context; + + public AndroidProtocolHandler(Context context) { + this.context = context; + } + + public InputStream openAsset(String path) throws IOException { + return context.getAssets().open(path, AssetManager.ACCESS_STREAMING); + } + + public InputStream openResource(Uri uri) { + assert uri.getPath() != null; + // The path must be of the form ".../asset_type/asset_name.ext". + List pathSegments = uri.getPathSegments(); + String assetType = pathSegments.get(pathSegments.size() - 2); + String assetName = pathSegments.get(pathSegments.size() - 1); + + // Drop the file extension. + assetName = assetName.split("\\.")[0]; + try { + // Use the application context for resolving the resource package name so that we do + // not use the browser's own resources. Note that if 'context' here belongs to the + // test suite, it does not have a separate application context. In that case we use + // the original context object directly. + if (context.getApplicationContext() != null) { + context = context.getApplicationContext(); + } + int fieldId = getFieldId(context, assetType, assetName); + int valueType = getValueType(context, fieldId); + if (valueType == TypedValue.TYPE_STRING) { + return context.getResources().openRawResource(fieldId); + } else { + Logger.error("Asset not of type string: " + uri); + } + } catch (ClassNotFoundException | IllegalAccessException | NoSuchFieldException e) { + Logger.error("Unable to open resource URL: " + uri, e); + } + return null; + } + + private static int getFieldId(Context context, String assetType, String assetName) + throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException { + Class d = context.getClassLoader().loadClass(context.getPackageName() + ".R$" + assetType); + java.lang.reflect.Field field = d.getField(assetName); + return field.getInt(null); + } + + public InputStream openFile(String filePath) throws IOException { + String realPath = filePath.replace(Bridge.CAPACITOR_FILE_START, ""); + File localFile = new File(realPath); + return new FileInputStream(localFile); + } + + public InputStream openContentUrl(Uri uri) throws IOException { + Integer port = uri.getPort(); + String baseUrl = uri.getScheme() + "://" + uri.getHost(); + if (port != -1) { + baseUrl += ":" + port; + } + String realPath = uri.toString().replace(baseUrl + Bridge.CAPACITOR_CONTENT_START, "content:/"); + + InputStream stream = null; + try { + stream = context.getContentResolver().openInputStream(Uri.parse(realPath)); + } catch (SecurityException e) { + Logger.error("Unable to open content URL: " + uri, e); + } + return stream; + } + + private static int getValueType(Context context, int fieldId) { + TypedValue value = new TypedValue(); + context.getResources().getValue(fieldId, value, true); + return value.type; + } +} diff --git a/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/App.java b/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/App.java new file mode 100644 index 0000000..f46b633 --- /dev/null +++ b/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/App.java @@ -0,0 +1,61 @@ +package com.getcapacitor; + +import androidx.annotation.Nullable; + +public class App { + + /** + * Interface for callbacks when app status changes. + */ + public interface AppStatusChangeListener { + void onAppStatusChanged(Boolean isActive); + } + + /** + * Interface for callbacks when app is restored with pending plugin call. + */ + public interface AppRestoredListener { + void onAppRestored(PluginResult result); + } + + @Nullable + private AppStatusChangeListener statusChangeListener; + + @Nullable + private AppRestoredListener appRestoredListener; + + private boolean isActive = false; + + public boolean isActive() { + return isActive; + } + + /** + * Set the object to receive callbacks. + * @param listener + */ + public void setStatusChangeListener(@Nullable AppStatusChangeListener listener) { + this.statusChangeListener = listener; + } + + /** + * Set the object to receive callbacks. + * @param listener + */ + public void setAppRestoredListener(@Nullable AppRestoredListener listener) { + this.appRestoredListener = listener; + } + + protected void fireRestoredResult(PluginResult result) { + if (appRestoredListener != null) { + appRestoredListener.onAppRestored(result); + } + } + + public void fireStatusChange(boolean isActive) { + this.isActive = isActive; + if (statusChangeListener != null) { + statusChangeListener.onAppStatusChanged(isActive); + } + } +} diff --git a/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/AppUUID.java b/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/AppUUID.java new file mode 100644 index 0000000..3c1b1db --- /dev/null +++ b/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/AppUUID.java @@ -0,0 +1,65 @@ +package com.getcapacitor; + +import android.content.Context; +import android.content.SharedPreferences; +import androidx.appcompat.app.AppCompatActivity; +import java.nio.charset.StandardCharsets; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.Objects; +import java.util.UUID; + +public final class AppUUID { + + private static final String KEY = "CapacitorAppUUID"; + + public static String getAppUUID(AppCompatActivity activity) throws Exception { + assertAppUUID(activity); + return readUUID(activity); + } + + public static void regenerateAppUUID(AppCompatActivity activity) throws Exception { + try { + String uuid = generateUUID(); + writeUUID(activity, uuid); + } catch (NoSuchAlgorithmException ex) { + throw new Exception("Capacitor App UUID could not be generated."); + } + } + + private static void assertAppUUID(AppCompatActivity activity) throws Exception { + String uuid = readUUID(activity); + if (uuid.equals("")) { + regenerateAppUUID(activity); + } + } + + private static String generateUUID() throws NoSuchAlgorithmException { + MessageDigest salt = MessageDigest.getInstance("SHA-256"); + salt.update(UUID.randomUUID().toString().getBytes(StandardCharsets.UTF_8)); + return bytesToHex(salt.digest()); + } + + private static String readUUID(AppCompatActivity activity) { + SharedPreferences sharedPref = activity.getPreferences(Context.MODE_PRIVATE); + return sharedPref.getString(KEY, ""); + } + + private static void writeUUID(AppCompatActivity activity, String uuid) { + SharedPreferences sharedPref = activity.getPreferences(Context.MODE_PRIVATE); + SharedPreferences.Editor editor = sharedPref.edit(); + editor.putString(KEY, uuid); + editor.apply(); + } + + private static String bytesToHex(byte[] bytes) { + byte[] HEX_ARRAY = "0123456789ABCDEF".getBytes(StandardCharsets.US_ASCII); + byte[] hexChars = new byte[bytes.length * 2]; + for (int j = 0; j < bytes.length; j++) { + int v = bytes[j] & 0xFF; + hexChars[j * 2] = HEX_ARRAY[v >>> 4]; + hexChars[j * 2 + 1] = HEX_ARRAY[v & 0x0F]; + } + return new String(hexChars, StandardCharsets.UTF_8); + } +} diff --git a/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/Bridge.java b/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/Bridge.java new file mode 100644 index 0000000..d4995fb --- /dev/null +++ b/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/Bridge.java @@ -0,0 +1,1627 @@ +package com.getcapacitor; + +import android.annotation.SuppressLint; +import android.app.Activity; +import android.content.ActivityNotFoundException; +import android.content.Context; +import android.content.Intent; +import android.content.SharedPreferences; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.content.res.Configuration; +import android.net.Uri; +import android.os.Build; +import android.os.Bundle; +import android.os.Handler; +import android.os.HandlerThread; +import android.webkit.ServiceWorkerClient; +import android.webkit.ServiceWorkerController; +import android.webkit.ValueCallback; +import android.webkit.WebResourceRequest; +import android.webkit.WebResourceResponse; +import android.webkit.WebSettings; +import android.webkit.WebView; +import androidx.activity.result.ActivityResultCallback; +import androidx.activity.result.ActivityResultLauncher; +import androidx.activity.result.contract.ActivityResultContract; +import androidx.annotation.NonNull; +import androidx.appcompat.app.AppCompatActivity; +import androidx.core.app.ActivityCompat; +import androidx.core.content.pm.PackageInfoCompat; +import androidx.fragment.app.Fragment; +import androidx.webkit.WebViewCompat; +import androidx.webkit.WebViewFeature; +import com.getcapacitor.android.R; +import com.getcapacitor.annotation.CapacitorPlugin; +import com.getcapacitor.annotation.Permission; +import com.getcapacitor.cordova.MockCordovaInterfaceImpl; +import com.getcapacitor.cordova.MockCordovaWebViewImpl; +import com.getcapacitor.util.HostMask; +import com.getcapacitor.util.InternalUtils; +import com.getcapacitor.util.PermissionHelper; +import com.getcapacitor.util.WebColor; +import java.io.File; +import java.net.SocketTimeoutException; +import java.net.URL; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import org.apache.cordova.ConfigXmlParser; +import org.apache.cordova.CordovaPreferences; +import org.apache.cordova.CordovaWebView; +import org.apache.cordova.PluginEntry; +import org.apache.cordova.PluginManager; +import org.json.JSONException; + +/** + * The Bridge class is the main engine of Capacitor. It manages + * loading and communicating with all Plugins, + * proxying Native events to Plugins, executing Plugin methods, + * communicating with the WebView, and a whole lot more. + * + * Generally, you'll not use Bridge directly, instead, extend from BridgeActivity + * to get a WebView instance and proxy native events automatically. + * + * If you want to use this Bridge in an existing Android app, please + * see the source for BridgeActivity for the methods you'll need to + * pass through to Bridge: + * + * BridgeActivity.java + */ +public class Bridge { + + private static final String PERMISSION_PREFS_NAME = "PluginPermStates"; + private static final String BUNDLE_LAST_PLUGIN_ID_KEY = "capacitorLastActivityPluginId"; + private static final String BUNDLE_LAST_PLUGIN_CALL_METHOD_NAME_KEY = "capacitorLastActivityPluginMethod"; + private static final String BUNDLE_PLUGIN_CALL_OPTIONS_SAVED_KEY = "capacitorLastPluginCallOptions"; + private static final String BUNDLE_PLUGIN_CALL_BUNDLE_KEY = "capacitorLastPluginCallBundle"; + private static final String LAST_BINARY_VERSION_CODE = "lastBinaryVersionCode"; + private static final String LAST_BINARY_VERSION_NAME = "lastBinaryVersionName"; + private static final String MINIMUM_ANDROID_WEBVIEW_ERROR = "System WebView is not supported"; + + // The name of the directory we use to look for index.html and the rest of our web assets + public static final String DEFAULT_WEB_ASSET_DIR = "public"; + public static final String CAPACITOR_HTTP_SCHEME = "http"; + public static final String CAPACITOR_HTTPS_SCHEME = "https"; + public static final String CAPACITOR_FILE_START = "/_capacitor_file_"; + public static final String CAPACITOR_CONTENT_START = "/_capacitor_content_"; + public static final String CAPACITOR_HTTP_INTERCEPTOR_START = "/_capacitor_http_interceptor_"; + + /** @deprecated CAPACITOR_HTTPS_INTERCEPTOR_START is no longer required. All proxied requests are handled via CAPACITOR_HTTP_INTERCEPTOR_START instead */ + @Deprecated + public static final String CAPACITOR_HTTPS_INTERCEPTOR_START = "/_capacitor_https_interceptor_"; + + public static final String CAPACITOR_HTTP_INTERCEPTOR_URL_PARAM = "u"; + + public static final int DEFAULT_ANDROID_WEBVIEW_VERSION = 60; + public static final int MINIMUM_ANDROID_WEBVIEW_VERSION = 55; + public static final int DEFAULT_HUAWEI_WEBVIEW_VERSION = 10; + public static final int MINIMUM_HUAWEI_WEBVIEW_VERSION = 10; + + // Loaded Capacitor config + private CapConfig config; + + // A reference to the main activity for the app + private final AppCompatActivity context; + // A reference to the containing Fragment if used + private final Fragment fragment; + private WebViewLocalServer localServer; + private String localUrl; + private String appUrl; + private String appUrlConfig; + private HostMask appAllowNavigationMask; + private Set allowedOriginRules = new HashSet(); + private ArrayList authorities = new ArrayList<>(); + private ArrayList miscJSFileInjections = new ArrayList(); + private Boolean canInjectJS = true; + // A reference to the main WebView for the app + private final WebView webView; + public final MockCordovaInterfaceImpl cordovaInterface; + private CordovaWebView cordovaWebView; + private CordovaPreferences preferences; + private BridgeWebViewClient webViewClient; + private App app; + + // Our MessageHandler for sending and receiving data to the WebView + private final MessageHandler msgHandler; + + // The ThreadHandler for executing plugin calls + private final HandlerThread handlerThread = new HandlerThread("CapacitorPlugins"); + + // Our Handler for posting plugin calls. Created from the ThreadHandler + private Handler taskHandler = null; + + private final List> initialPlugins; + + private final List pluginInstances; + + // A map of Plugin Id's to PluginHandle's + private Map plugins = new HashMap<>(); + + // Stored plugin calls that we're keeping around to call again someday + private Map savedCalls = new HashMap<>(); + + // The call IDs of saved plugin calls with associated plugin id for handling permissions + private Map> savedPermissionCallIds = new HashMap<>(); + + // Store a plugin that started a new activity, in case we need to resume + // the app and return that data back + private PluginCall pluginCallForLastActivity; + + // Any URI that was passed to the app on start + private Uri intentUri; + + // A list of listeners that trigger when webView events occur + private List webViewListeners = new ArrayList<>(); + + // An interface to manipulate route resolving + private RouteProcessor routeProcessor; + + // A pre-determined path to load the bridge + private ServerPath serverPath; + + /** + * Create the Bridge with a reference to the main {@link Activity} for the + * app, and a reference to the {@link WebView} our app will use. + * @param context + * @param webView + * @deprecated Use {@link Bridge.Builder} to create Bridge instances + */ + @Deprecated + public Bridge( + AppCompatActivity context, + WebView webView, + List> initialPlugins, + MockCordovaInterfaceImpl cordovaInterface, + PluginManager pluginManager, + CordovaPreferences preferences, + CapConfig config + ) { + this(context, null, null, webView, initialPlugins, new ArrayList<>(), cordovaInterface, pluginManager, preferences, config); + } + + private Bridge( + AppCompatActivity context, + ServerPath serverPath, + Fragment fragment, + WebView webView, + List> initialPlugins, + List pluginInstances, + MockCordovaInterfaceImpl cordovaInterface, + PluginManager pluginManager, + CordovaPreferences preferences, + CapConfig config + ) { + this.app = new App(); + this.serverPath = serverPath; + this.context = context; + this.fragment = fragment; + this.webView = webView; + this.webViewClient = new BridgeWebViewClient(this); + this.initialPlugins = initialPlugins; + this.pluginInstances = pluginInstances; + this.cordovaInterface = cordovaInterface; + this.preferences = preferences; + + // Start our plugin execution threads and handlers + handlerThread.start(); + taskHandler = new Handler(handlerThread.getLooper()); + + this.config = config != null ? config : CapConfig.loadDefault(getActivity()); + Logger.init(this.config); + + // Initialize web view and message handler for it + this.initWebView(); + this.setAllowedOriginRules(); + this.msgHandler = new MessageHandler(this, webView, pluginManager); + + // Grab any intent info that our app was launched with + Intent intent = context.getIntent(); + this.intentUri = intent.getData(); + // Register our core plugins + this.registerAllPlugins(); + + this.loadWebView(); + } + + private void setAllowedOriginRules() { + String[] appAllowNavigationConfig = this.config.getAllowNavigation(); + String authority = this.getHost(); + String scheme = this.getScheme(); + allowedOriginRules.add(scheme + "://" + authority); + if (this.getServerUrl() != null) { + allowedOriginRules.add(this.getServerUrl()); + } + if (appAllowNavigationConfig != null) { + for (String allowNavigation : appAllowNavigationConfig) { + if (!allowNavigation.startsWith("http")) { + allowedOriginRules.add("https://" + allowNavigation); + } else { + allowedOriginRules.add(allowNavigation); + } + } + authorities.addAll(Arrays.asList(appAllowNavigationConfig)); + } + this.appAllowNavigationMask = HostMask.Parser.parse(appAllowNavigationConfig); + } + + public App getApp() { + return app; + } + + private void loadWebView() { + final boolean html5mode = this.config.isHTML5Mode(); + + // Start the local web server + JSInjector injector = getJSInjector(); + if (WebViewFeature.isFeatureSupported(WebViewFeature.DOCUMENT_START_SCRIPT)) { + String allowedOrigin = Uri.parse(appUrl).buildUpon().path(null).fragment(null).clearQuery().build().toString(); + try { + WebViewCompat.addDocumentStartJavaScript(webView, injector.getScriptString(), Collections.singleton(allowedOrigin)); + injector = null; + } catch (IllegalArgumentException ex) { + Logger.warn("Invalid url, using fallback"); + } + } + localServer = new WebViewLocalServer(context, this, injector, authorities, html5mode); + localServer.hostAssets(DEFAULT_WEB_ASSET_DIR); + + Logger.debug("Loading app at " + appUrl); + + webView.setWebChromeClient(new BridgeWebChromeClient(this)); + webView.setWebViewClient(this.webViewClient); + + if (config.isResolveServiceWorkerRequests()) { + ServiceWorkerController swController = ServiceWorkerController.getInstance(); + swController.setServiceWorkerClient( + new ServiceWorkerClient() { + @Override + public WebResourceResponse shouldInterceptRequest(WebResourceRequest request) { + return getLocalServer().shouldInterceptRequest(request); + } + } + ); + } + + if (!isDeployDisabled() && !isNewBinary()) { + SharedPreferences prefs = getContext().getSharedPreferences( + com.getcapacitor.plugin.WebView.WEBVIEW_PREFS_NAME, + Activity.MODE_PRIVATE + ); + String path = prefs.getString(com.getcapacitor.plugin.WebView.CAP_SERVER_PATH, null); + if (path != null && !path.isEmpty() && new File(path).exists()) { + setServerBasePath(path); + } + } + if (!this.isMinimumWebViewInstalled()) { + String errorUrl = this.getErrorUrl(); + if (errorUrl != null) { + webView.loadUrl(errorUrl); + return; + } else { + Logger.error(MINIMUM_ANDROID_WEBVIEW_ERROR); + } + } + + // If serverPath configured, start server based on provided path + if (serverPath != null) { + if (serverPath.getType() == ServerPath.PathType.ASSET_PATH) { + setServerAssetPath(serverPath.getPath()); + } else { + setServerBasePath(serverPath.getPath()); + } + } else { + // Get to work + webView.loadUrl(appUrl); + } + } + + @SuppressLint("WebViewApiAvailability") + public boolean isMinimumWebViewInstalled() { + PackageManager pm = getContext().getPackageManager(); + + // Check getCurrentWebViewPackage() directly if above Android 8 + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + PackageInfo info = WebView.getCurrentWebViewPackage(); + Pattern pattern = Pattern.compile("(\\d+)"); + Matcher matcher = pattern.matcher(info.versionName); + if (matcher.find()) { + String majorVersionStr = matcher.group(0); + int majorVersion = Integer.parseInt(majorVersionStr); + if (info.packageName.equals("com.huawei.webview")) { + return majorVersion >= config.getMinHuaweiWebViewVersion(); + } + return majorVersion >= config.getMinWebViewVersion(); + } else { + return false; + } + } + + // Otherwise manually check WebView versions + try { + PackageInfo info = InternalUtils.getPackageInfo(pm, "com.android.chrome"); + String majorVersionStr = info.versionName.split("\\.")[0]; + int majorVersion = Integer.parseInt(majorVersionStr); + return majorVersion >= config.getMinWebViewVersion(); + } catch (Exception ex) { + Logger.warn("Unable to get package info for 'com.google.android.webview'" + ex.toString()); + } + + try { + PackageInfo info = InternalUtils.getPackageInfo(pm, "com.android.webview"); + String majorVersionStr = info.versionName.split("\\.")[0]; + int majorVersion = Integer.parseInt(majorVersionStr); + return majorVersion >= config.getMinWebViewVersion(); + } catch (Exception ex) { + Logger.warn("Unable to get package info for 'com.android.webview'" + ex.toString()); + } + + final int amazonFireMajorWebViewVersion = extractWebViewMajorVersion(pm, "com.amazon.webview.chromium"); + if (amazonFireMajorWebViewVersion >= config.getMinWebViewVersion()) { + return true; + } + + // Could not detect any webview, return false + return false; + } + + private int extractWebViewMajorVersion(final PackageManager pm, final String webViewPackageName) { + try { + final PackageInfo info = InternalUtils.getPackageInfo(pm, webViewPackageName); + final String majorVersionStr = info.versionName.split("\\.")[0]; + final int majorVersion = Integer.parseInt(majorVersionStr); + return majorVersion; + } catch (Exception ex) { + Logger.warn(String.format("Unable to get package info for '%s' with err '%s'", webViewPackageName, ex)); + } + return 0; + } + + public boolean launchIntent(Uri url) { + /* + * Give plugins the chance to handle the url + */ + for (Map.Entry entry : plugins.entrySet()) { + Plugin plugin = entry.getValue().getInstance(); + if (plugin != null) { + Boolean shouldOverrideLoad = plugin.shouldOverrideLoad(url); + if (shouldOverrideLoad != null) { + return shouldOverrideLoad; + } + } + } + + if (url.getScheme().equals("data") || url.getScheme().equals("blob")) { + return false; + } + + Uri appUri = Uri.parse(appUrl); + if ( + !(appUri.getHost().equals(url.getHost()) && url.getScheme().equals(appUri.getScheme())) && + !appAllowNavigationMask.matches(url.getHost()) + ) { + try { + Intent openIntent = new Intent(Intent.ACTION_VIEW, url); + getContext().startActivity(openIntent); + } catch (ActivityNotFoundException e) { + // TODO - trigger an event + } + return true; + } + return false; + } + + private boolean isNewBinary() { + String versionCode = ""; + String versionName = ""; + SharedPreferences prefs = getContext().getSharedPreferences( + com.getcapacitor.plugin.WebView.WEBVIEW_PREFS_NAME, + Activity.MODE_PRIVATE + ); + String lastVersionCode = prefs.getString(LAST_BINARY_VERSION_CODE, null); + String lastVersionName = prefs.getString(LAST_BINARY_VERSION_NAME, null); + + try { + PackageManager pm = getContext().getPackageManager(); + PackageInfo pInfo = InternalUtils.getPackageInfo(pm, getContext().getPackageName()); + versionCode = Integer.toString((int) PackageInfoCompat.getLongVersionCode(pInfo)); + versionName = pInfo.versionName != null ? pInfo.versionName : ""; + } catch (Exception ex) { + Logger.error("Unable to get package info", ex); + } + + if (!versionCode.equals(lastVersionCode) || !versionName.equals(lastVersionName)) { + SharedPreferences.Editor editor = prefs.edit(); + editor.putString(LAST_BINARY_VERSION_CODE, versionCode); + editor.putString(LAST_BINARY_VERSION_NAME, versionName); + editor.putString(com.getcapacitor.plugin.WebView.CAP_SERVER_PATH, ""); + editor.apply(); + return true; + } + return false; + } + + public boolean isDeployDisabled() { + return preferences.getBoolean("DisableDeploy", false); + } + + public boolean shouldKeepRunning() { + return preferences.getBoolean("KeepRunning", true); + } + + public void handleAppUrlLoadError(Exception ex) { + if (ex instanceof SocketTimeoutException) { + Logger.error( + "Unable to load app. Ensure the server is running at " + + appUrl + + ", or modify the " + + "appUrl setting in capacitor.config.json (make sure to npx cap copy after to commit changes).", + ex + ); + } + } + + public boolean isDevMode() { + return (getActivity().getApplicationInfo().flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0; + } + + protected void setCordovaWebView(CordovaWebView cordovaWebView) { + this.cordovaWebView = cordovaWebView; + } + + /** + * Get the Context for the App + * @return + */ + public Context getContext() { + return this.context; + } + + /** + * Get the activity for the app + * @return + */ + public AppCompatActivity getActivity() { + return this.context; + } + + /** + * Get the fragment for the app, if applicable. This will likely be null unless Capacitor + * is being used embedded in a Native Android app. + * + * @return The fragment containing the Capacitor WebView. + */ + public Fragment getFragment() { + return this.fragment; + } + + /** + * Get the core WebView under Capacitor's control + * @return + */ + public WebView getWebView() { + return this.webView; + } + + /** + * Get the URI that was used to launch the app (if any) + * @return + */ + public Uri getIntentUri() { + return intentUri; + } + + /** + * Get scheme that is used to serve content + * @return + */ + public String getScheme() { + return this.config.getAndroidScheme(); + } + + /** + * Get host name that is used to serve content + * @return + */ + public String getHost() { + return this.config.getHostname(); + } + + /** + * Get the server url that is used to serve content + * @return + */ + public String getServerUrl() { + return this.config.getServerUrl(); + } + + public String getErrorUrl() { + String errorPath = this.config.getErrorPath(); + + if (errorPath != null && !errorPath.trim().isEmpty()) { + String authority = this.getHost(); + String scheme = this.getScheme(); + + String localUrl = scheme + "://" + authority; + + return localUrl + "/" + errorPath; + } + + return null; + } + + public String getAppUrl() { + return appUrl; + } + + public CapConfig getConfig() { + return this.config; + } + + public void reset() { + savedCalls = new HashMap<>(); + for (PluginHandle handle : this.plugins.values()) { + handle.getInstance().removeAllListeners(); + } + } + + /** + * Initialize the WebView, setting required flags + */ + @SuppressLint("SetJavaScriptEnabled") + private void initWebView() { + WebSettings settings = webView.getSettings(); + settings.setJavaScriptEnabled(true); + settings.setDomStorageEnabled(true); + settings.setGeolocationEnabled(true); + settings.setMediaPlaybackRequiresUserGesture(false); + settings.setJavaScriptCanOpenWindowsAutomatically(true); + if (this.config.isMixedContentAllowed()) { + settings.setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW); + } + + String appendUserAgent = this.config.getAppendedUserAgentString(); + if (appendUserAgent != null) { + String defaultUserAgent = settings.getUserAgentString(); + settings.setUserAgentString(defaultUserAgent + " " + appendUserAgent); + } + String overrideUserAgent = this.config.getOverriddenUserAgentString(); + if (overrideUserAgent != null) { + settings.setUserAgentString(overrideUserAgent); + } + + String backgroundColor = this.config.getBackgroundColor(); + try { + if (backgroundColor != null) { + webView.setBackgroundColor(WebColor.parseColor(backgroundColor)); + } + } catch (IllegalArgumentException ex) { + Logger.debug("WebView background color not applied"); + } + + settings.setDisplayZoomControls(false); + settings.setBuiltInZoomControls(this.config.isZoomableWebView()); + + if (config.isInitialFocus()) { + webView.requestFocusFromTouch(); + } + + WebView.setWebContentsDebuggingEnabled(this.config.isWebContentsDebuggingEnabled()); + + appUrlConfig = this.getServerUrl(); + String authority = this.getHost(); + authorities.add(authority); + String scheme = this.getScheme(); + + localUrl = scheme + "://" + authority; + + if (appUrlConfig != null) { + try { + URL appUrlObject = new URL(appUrlConfig); + authorities.add(appUrlObject.getAuthority()); + localUrl = appUrlObject.getProtocol() + "://" + appUrlObject.getAuthority(); + } catch (Exception ex) { + Logger.error("Provided server url is invalid: " + ex.getMessage()); + return; + } + appUrl = appUrlConfig; + } else { + appUrl = localUrl; + // custom URL schemes requires path ending with / + if (!scheme.equals(Bridge.CAPACITOR_HTTP_SCHEME) && !scheme.equals(CAPACITOR_HTTPS_SCHEME)) { + appUrl += "/"; + } + } + + String appUrlPath = this.config.getStartPath(); + if (appUrlPath != null && !appUrlPath.trim().isEmpty()) { + appUrl += appUrlPath; + } + } + + /** + * Register our core Plugin APIs + */ + private void registerAllPlugins() { + this.registerPlugin(com.getcapacitor.plugin.CapacitorCookies.class); + this.registerPlugin(com.getcapacitor.plugin.WebView.class); + this.registerPlugin(com.getcapacitor.plugin.CapacitorHttp.class); + this.registerPlugin(com.getcapacitor.plugin.SystemBars.class); + + for (Class pluginClass : this.initialPlugins) { + this.registerPlugin(pluginClass); + } + + for (Plugin plugin : pluginInstances) { + registerPluginInstance(plugin); + } + } + + /** + * Register additional plugins + * @param pluginClasses the plugins to register + */ + public void registerPlugins(Class[] pluginClasses) { + for (Class plugin : pluginClasses) { + this.registerPlugin(plugin); + } + } + + public void registerPluginInstances(Plugin[] pluginInstances) { + for (Plugin plugin : pluginInstances) { + this.registerPluginInstance(plugin); + } + } + + @SuppressWarnings("deprecation") + private String getLegacyPluginName(Class pluginClass) { + NativePlugin legacyPluginAnnotation = pluginClass.getAnnotation(NativePlugin.class); + if (legacyPluginAnnotation == null) { + Logger.error("Plugin doesn't have the @CapacitorPlugin annotation. Please add it"); + return null; + } + + return legacyPluginAnnotation.name(); + } + + /** + * Register a plugin class + * @param pluginClass a class inheriting from Plugin + */ + public void registerPlugin(Class pluginClass) { + String pluginId = pluginId(pluginClass); + if (pluginId == null) return; + + try { + this.plugins.put(pluginId, new PluginHandle(this, pluginClass)); + } catch (InvalidPluginException ex) { + logInvalidPluginException(pluginClass); + } catch (PluginLoadException ex) { + logPluginLoadException(pluginClass, ex); + } + } + + public void registerPluginInstance(Plugin plugin) { + Class clazz = plugin.getClass(); + String pluginId = pluginId(clazz); + if (pluginId == null) return; + + try { + this.plugins.put(pluginId, new PluginHandle(this, plugin)); + } catch (InvalidPluginException ex) { + logInvalidPluginException(clazz); + } + } + + private String pluginId(Class clazz) { + String pluginName = pluginName(clazz); + String pluginId = clazz.getSimpleName(); + if (pluginName == null) return null; + + if (!pluginName.equals("")) { + pluginId = pluginName; + } + Logger.debug("Registering plugin instance: " + pluginId); + return pluginId; + } + + private String pluginName(Class clazz) { + String pluginName; + CapacitorPlugin pluginAnnotation = clazz.getAnnotation(CapacitorPlugin.class); + if (pluginAnnotation == null) { + pluginName = this.getLegacyPluginName(clazz); + } else { + pluginName = pluginAnnotation.name(); + } + + return pluginName; + } + + private void logInvalidPluginException(Class clazz) { + Logger.error( + "NativePlugin " + + clazz.getName() + + " is invalid. Ensure the @CapacitorPlugin annotation exists on the plugin class and" + + " the class extends Plugin" + ); + } + + private void logPluginLoadException(Class clazz, Exception ex) { + Logger.error("NativePlugin " + clazz.getName() + " failed to load", ex); + } + + public PluginHandle getPlugin(String pluginId) { + return this.plugins.get(pluginId); + } + + /** + * Find the plugin handle that responds to the given request code. This will + * fire after certain Android OS intent results/permission checks/etc. + * @param requestCode + * @return + */ + @Deprecated + @SuppressWarnings("deprecation") + public PluginHandle getPluginWithRequestCode(int requestCode) { + for (PluginHandle handle : this.plugins.values()) { + int[] requestCodes; + + CapacitorPlugin pluginAnnotation = handle.getPluginAnnotation(); + if (pluginAnnotation == null) { + // Check for legacy plugin annotation, @NativePlugin + NativePlugin legacyPluginAnnotation = handle.getLegacyPluginAnnotation(); + if (legacyPluginAnnotation == null) { + continue; + } + + if (legacyPluginAnnotation.permissionRequestCode() == requestCode) { + return handle; + } + + requestCodes = legacyPluginAnnotation.requestCodes(); + + for (int rc : requestCodes) { + if (rc == requestCode) { + return handle; + } + } + } else { + requestCodes = pluginAnnotation.requestCodes(); + + for (int rc : requestCodes) { + if (rc == requestCode) { + return handle; + } + } + } + } + return null; + } + + /** + * Call a method on a plugin. + * @param pluginId the plugin id to use to lookup the plugin handle + * @param methodName the name of the method to call + * @param call the call object to pass to the method + */ + public void callPluginMethod(String pluginId, final String methodName, final PluginCall call) { + try { + final PluginHandle plugin = this.getPlugin(pluginId); + + if (plugin == null) { + Logger.error("unable to find plugin : " + pluginId); + call.errorCallback("unable to find plugin : " + pluginId); + return; + } + + if (Logger.shouldLog()) { + Logger.verbose( + "callback: " + + call.getCallbackId() + + ", pluginId: " + + plugin.getId() + + ", methodName: " + + methodName + + ", methodData: " + + call.getData().toString() + ); + } + + Runnable currentThreadTask = () -> { + try { + plugin.invoke(methodName, call); + + if (call.isKeptAlive()) { + saveCall(call); + } + } catch (PluginLoadException | InvalidPluginMethodException ex) { + Logger.error("Unable to execute plugin method", ex); + } catch (Exception ex) { + Logger.error("Serious error executing plugin", ex); + throw new RuntimeException(ex); + } + }; + + taskHandler.post(currentThreadTask); + } catch (Exception ex) { + Logger.error(Logger.tags("callPluginMethod"), "error : " + ex, null); + call.errorCallback(ex.toString()); + } + } + + /** + * Evaluate JavaScript in the web view. This method + * executes on the main thread automatically. + * @param js the JS to execute + * @param callback an optional ValueCallback that will synchronously receive a value + * after calling the JS + */ + public void eval(final String js, final ValueCallback callback) { + Handler mainHandler = new Handler(context.getMainLooper()); + mainHandler.post(() -> webView.evaluateJavascript(js, callback)); + } + + public void logToJs(final String message, final String level) { + eval("window.Capacitor.logJs(\"" + message + "\", \"" + level + "\")", null); + } + + public void logToJs(final String message) { + logToJs(message, "log"); + } + + public void triggerJSEvent(final String eventName, final String target) { + eval("window.Capacitor.triggerEvent(\"" + eventName + "\", \"" + target + "\")", (s) -> {}); + } + + public void triggerJSEvent(final String eventName, final String target, final String data) { + eval("window.Capacitor.triggerEvent(\"" + eventName + "\", \"" + target + "\", " + data + ")", (s) -> {}); + } + + public void triggerWindowJSEvent(final String eventName) { + this.triggerJSEvent(eventName, "window"); + } + + public void triggerWindowJSEvent(final String eventName, final String data) { + this.triggerJSEvent(eventName, "window", data); + } + + public void triggerDocumentJSEvent(final String eventName) { + this.triggerJSEvent(eventName, "document"); + } + + public void triggerDocumentJSEvent(final String eventName, final String data) { + this.triggerJSEvent(eventName, "document", data); + } + + public void execute(Runnable runnable) { + taskHandler.post(runnable); + } + + public void executeOnMainThread(Runnable runnable) { + Handler mainHandler = new Handler(context.getMainLooper()); + + mainHandler.post(runnable); + } + + /** + * Retain a call between plugin invocations + * @param call + */ + public void saveCall(PluginCall call) { + this.savedCalls.put(call.getCallbackId(), call); + } + + /** + * Get a retained plugin call + * @param callbackId the callbackId to use to lookup the call with + * @return the stored call + */ + public PluginCall getSavedCall(String callbackId) { + if (callbackId == null) { + return null; + } + + return this.savedCalls.get(callbackId); + } + + PluginCall getPluginCallForLastActivity() { + PluginCall pluginCallForLastActivity = this.pluginCallForLastActivity; + this.pluginCallForLastActivity = null; + return pluginCallForLastActivity; + } + + void setPluginCallForLastActivity(PluginCall pluginCallForLastActivity) { + this.pluginCallForLastActivity = pluginCallForLastActivity; + } + + /** + * Release a retained call + * @param call a call to release + */ + public void releaseCall(PluginCall call) { + releaseCall(call.getCallbackId()); + } + + /** + * Release a retained call by its ID + * @param callbackId an ID of a callback to release + */ + public void releaseCall(String callbackId) { + this.savedCalls.remove(callbackId); + } + + /** + * Removes the earliest saved call prior to a permissions request for a given plugin and + * returns it. + * + * @return The saved plugin call + */ + protected PluginCall getPermissionCall(String pluginId) { + LinkedList permissionCallIds = this.savedPermissionCallIds.get(pluginId); + String savedCallId = null; + if (permissionCallIds != null) { + savedCallId = permissionCallIds.poll(); + } + + return getSavedCall(savedCallId); + } + + /** + * Save a call to be retrieved after requesting permissions. Calls are saved in order. + * + * @param call The plugin call to save. + */ + protected void savePermissionCall(PluginCall call) { + if (call != null) { + if (!savedPermissionCallIds.containsKey(call.getPluginId())) { + savedPermissionCallIds.put(call.getPluginId(), new LinkedList<>()); + } + + savedPermissionCallIds.get(call.getPluginId()).add(call.getCallbackId()); + saveCall(call); + } + } + + /** + * Register an Activity Result Launcher to the containing Fragment or Activity. + * + * @param contract A contract specifying that an activity can be called with an input of + * type I and produce an output of type O. + * @param callback The callback run on Activity Result. + * @return A registered Activity Result Launcher. + */ + public ActivityResultLauncher registerForActivityResult( + @NonNull final ActivityResultContract contract, + @NonNull final ActivityResultCallback callback + ) { + if (fragment != null) { + return fragment.registerForActivityResult(contract, callback); + } else { + return context.registerForActivityResult(contract, callback); + } + } + + /** + * Build the JSInjector that will be used to inject JS into files served to the app, + * to ensure that Capacitor's JS and the JS for all the plugins is loaded each time. + */ + private JSInjector getJSInjector() { + try { + String globalJS = JSExport.getGlobalJS(context, config.isLoggingEnabled(), isDevMode()); + String bridgeJS = JSExport.getBridgeJS(context); + String pluginJS = JSExport.getPluginJS(plugins.values()); + String cordovaJS = JSExport.getCordovaJS(context); + String cordovaPluginsJS = JSExport.getCordovaPluginJS(context); + String cordovaPluginsFileJS = JSExport.getCordovaPluginsFileJS(context); + String localUrlJS = "window.WEBVIEW_SERVER_URL = '" + localUrl + "';"; + String miscJS = JSExport.getMiscFileJS(miscJSFileInjections, context); + + miscJSFileInjections = new ArrayList<>(); + canInjectJS = false; + + return new JSInjector(globalJS, bridgeJS, pluginJS, cordovaJS, cordovaPluginsJS, cordovaPluginsFileJS, localUrlJS, miscJS); + } catch (Exception ex) { + Logger.error("Unable to export Capacitor JS. App will not function!", ex); + } + return null; + } + + /** + * Inject JavaScript from an external file before the WebView loads. + * @param path relative to public folder + */ + public void injectScriptBeforeLoad(String path) { + if (canInjectJS) { + miscJSFileInjections.add(path); + } + } + + /** + * Restore any saved bundle state data + * @param savedInstanceState + */ + public void restoreInstanceState(Bundle savedInstanceState) { + String lastPluginId = savedInstanceState.getString(BUNDLE_LAST_PLUGIN_ID_KEY); + String lastPluginCallMethod = savedInstanceState.getString(BUNDLE_LAST_PLUGIN_CALL_METHOD_NAME_KEY); + String lastOptionsJson = savedInstanceState.getString(BUNDLE_PLUGIN_CALL_OPTIONS_SAVED_KEY); + + if (lastPluginId != null) { + // If we have JSON blob saved, create a new plugin call with the original options + if (lastOptionsJson != null) { + try { + JSObject options = new JSObject(lastOptionsJson); + + pluginCallForLastActivity = new PluginCall( + msgHandler, + lastPluginId, + PluginCall.CALLBACK_ID_DANGLING, + lastPluginCallMethod, + options + ); + } catch (JSONException ex) { + Logger.error("Unable to restore plugin call, unable to parse persisted JSON object", ex); + } + } + + // Let the plugin restore any state it needs + Bundle bundleData = savedInstanceState.getBundle(BUNDLE_PLUGIN_CALL_BUNDLE_KEY); + PluginHandle lastPlugin = getPlugin(lastPluginId); + if (bundleData != null && lastPlugin != null) { + lastPlugin.getInstance().restoreState(bundleData); + } else { + Logger.error("Unable to restore last plugin call"); + } + } + } + + public void saveInstanceState(Bundle outState) { + Logger.debug("Saving instance state!"); + + // If there was a last PluginCall for a started activity, we need to + // persist it so we can load it again in case our app gets terminated + if (pluginCallForLastActivity != null) { + PluginCall call = pluginCallForLastActivity; + PluginHandle handle = getPlugin(call.getPluginId()); + + if (handle != null) { + Bundle bundle = handle.getInstance().saveInstanceState(); + if (bundle != null) { + outState.putString(BUNDLE_LAST_PLUGIN_ID_KEY, call.getPluginId()); + outState.putString(BUNDLE_LAST_PLUGIN_CALL_METHOD_NAME_KEY, call.getMethodName()); + outState.putString(BUNDLE_PLUGIN_CALL_OPTIONS_SAVED_KEY, call.getData().toString()); + outState.putBundle(BUNDLE_PLUGIN_CALL_BUNDLE_KEY, bundle); + } else { + Logger.error("Couldn't save last " + call.getPluginId() + "'s Plugin " + call.getMethodName() + " call"); + } + } + } + } + + @Deprecated + @SuppressWarnings("deprecation") + public void startActivityForPluginWithResult(PluginCall call, Intent intent, int requestCode) { + Logger.debug("Starting activity for result"); + + pluginCallForLastActivity = call; + + getActivity().startActivityForResult(intent, requestCode); + } + + /** + * Check for legacy Capacitor or Cordova plugins that may have registered to handle a permission + * request, and handle them if so. If not handled, false is returned. + * + * @param requestCode the code that was requested + * @param permissions the permissions requested + * @param grantResults the set of granted/denied permissions + * @return true if permission code was handled by a plugin explicitly, false if not + */ + @SuppressWarnings("deprecation") + boolean onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { + PluginHandle plugin = getPluginWithRequestCode(requestCode); + + if (plugin == null) { + boolean permissionHandled = false; + Logger.debug("Unable to find a Capacitor plugin to handle permission requestCode, trying Cordova plugins " + requestCode); + try { + permissionHandled = cordovaInterface.handlePermissionResult(requestCode, permissions, grantResults); + } catch (JSONException e) { + Logger.debug("Error on Cordova plugin permissions request " + e.getMessage()); + } + return permissionHandled; + } + + // Call deprecated method if using deprecated NativePlugin annotation + if (plugin.getPluginAnnotation() == null) { + plugin.getInstance().handleRequestPermissionsResult(requestCode, permissions, grantResults); + return true; + } + + return false; + } + + /** + * Saves permission states and rejects if permissions were not correctly defined in + * the AndroidManifest.xml file. + * + * @param plugin + * @param savedCall + * @param permissions + * @return true if permissions were saved and defined correctly, false if not + */ + protected boolean validatePermissions(Plugin plugin, PluginCall savedCall, Map permissions) { + SharedPreferences prefs = getContext().getSharedPreferences(PERMISSION_PREFS_NAME, Activity.MODE_PRIVATE); + + for (Map.Entry permission : permissions.entrySet()) { + String permString = permission.getKey(); + boolean isGranted = permission.getValue(); + + if (isGranted) { + // Permission granted. If previously denied, remove cached state + String state = prefs.getString(permString, null); + + if (state != null) { + SharedPreferences.Editor editor = prefs.edit(); + editor.remove(permString); + editor.apply(); + } + } else { + SharedPreferences.Editor editor = prefs.edit(); + + if (ActivityCompat.shouldShowRequestPermissionRationale(getActivity(), permString)) { + // Permission denied, can prompt again with rationale + editor.putString(permString, PermissionState.PROMPT_WITH_RATIONALE.toString()); + } else { + // Permission denied permanently, store this state for future reference + editor.putString(permString, PermissionState.DENIED.toString()); + } + + editor.apply(); + } + } + + String[] permStrings = permissions.keySet().toArray(new String[0]); + + if (!PermissionHelper.hasDefinedPermissions(getContext(), permStrings)) { + StringBuilder builder = new StringBuilder(); + builder.append("Missing the following permissions in AndroidManifest.xml:\n"); + String[] missing = PermissionHelper.getUndefinedPermissions(getContext(), permStrings); + for (String perm : missing) { + builder.append(perm + "\n"); + } + savedCall.reject(builder.toString()); + return false; + } + + return true; + } + + /** + * Helper to check all permissions and see the current states of each permission. + * + * @since 3.0.0 + * @return A mapping of permission aliases to the associated granted status. + */ + protected Map getPermissionStates(Plugin plugin) { + Map permissionsResults = new HashMap<>(); + CapacitorPlugin annotation = plugin.getPluginHandle().getPluginAnnotation(); + for (Permission perm : annotation.permissions()) { + // If a permission is defined with no permission constants, return GRANTED for it. + // Otherwise, get its true state. + if (perm.strings().length == 0 || (perm.strings().length == 1 && perm.strings()[0].isEmpty())) { + String key = perm.alias(); + if (!key.isEmpty()) { + PermissionState existingResult = permissionsResults.get(key); + + // auto set permission state to GRANTED if the alias is empty. + if (existingResult == null) { + permissionsResults.put(key, PermissionState.GRANTED); + } + } + } else { + for (String permString : perm.strings()) { + String key = perm.alias().isEmpty() ? permString : perm.alias(); + PermissionState permissionStatus; + if (ActivityCompat.checkSelfPermission(this.getContext(), permString) == PackageManager.PERMISSION_GRANTED) { + permissionStatus = PermissionState.GRANTED; + } else { + permissionStatus = PermissionState.PROMPT; + + // Check if there is a cached permission state for the "Never ask again" state + SharedPreferences prefs = getContext().getSharedPreferences(PERMISSION_PREFS_NAME, Activity.MODE_PRIVATE); + String state = prefs.getString(permString, null); + + if (state != null) { + permissionStatus = PermissionState.byState(state); + } + } + + PermissionState existingResult = permissionsResults.get(key); + + // multiple permissions with the same alias must all be true, otherwise all false. + if (existingResult == null || existingResult == PermissionState.GRANTED) { + permissionsResults.put(key, permissionStatus); + } + } + } + } + + return permissionsResults; + } + + /** + * Handle an activity result and pass it to a plugin that has indicated it wants to + * handle the result. + * @param requestCode + * @param resultCode + * @param data + */ + @SuppressWarnings("deprecation") + boolean onActivityResult(int requestCode, int resultCode, Intent data) { + PluginHandle plugin = getPluginWithRequestCode(requestCode); + + if (plugin == null || plugin.getInstance() == null) { + Logger.debug("Unable to find a Capacitor plugin to handle requestCode, trying Cordova plugins " + requestCode); + return cordovaInterface.onActivityResult(requestCode, resultCode, data); + } + + // deprecated, to be removed + PluginCall lastCall = plugin.getInstance().getSavedCall(); + + // If we don't have a saved last call (because our app was killed and restarted, for example), + // Then we should see if we have any saved plugin call information and generate a new, + // "dangling" plugin call (a plugin call that doesn't have a corresponding web callback) + // and then send that to the plugin + if (lastCall == null && pluginCallForLastActivity != null) { + plugin.getInstance().saveCall(pluginCallForLastActivity); + } + + plugin.getInstance().handleOnActivityResult(requestCode, resultCode, data); + + // Clear the plugin call we may have re-hydrated on app launch + pluginCallForLastActivity = null; + + return true; + } + + /** + * Handle an onNewIntent lifecycle event and notify the plugins + * @param intent + */ + public void onNewIntent(Intent intent) { + for (PluginHandle plugin : plugins.values()) { + plugin.getInstance().handleOnNewIntent(intent); + } + + if (cordovaWebView != null) { + cordovaWebView.onNewIntent(intent); + } + } + + /** + * Handle an onConfigurationChanged event and notify the plugins + * @param newConfig + */ + public void onConfigurationChanged(Configuration newConfig) { + for (PluginHandle plugin : plugins.values()) { + plugin.getInstance().handleOnConfigurationChanged(newConfig); + } + } + + /** + * Handle onRestart lifecycle event and notify the plugins + */ + public void onRestart() { + for (PluginHandle plugin : plugins.values()) { + plugin.getInstance().handleOnRestart(); + } + } + + /** + * Handle onStart lifecycle event and notify the plugins + */ + public void onStart() { + for (PluginHandle plugin : plugins.values()) { + plugin.getInstance().handleOnStart(); + } + + if (cordovaWebView != null) { + cordovaWebView.handleStart(); + } + } + + /** + * Handle onResume lifecycle event and notify the plugins + */ + public void onResume() { + for (PluginHandle plugin : plugins.values()) { + plugin.getInstance().handleOnResume(); + } + + if (cordovaWebView != null) { + cordovaWebView.handleResume(this.shouldKeepRunning()); + } + } + + /** + * Handle onPause lifecycle event and notify the plugins + */ + public void onPause() { + for (PluginHandle plugin : plugins.values()) { + plugin.getInstance().handleOnPause(); + } + + if (cordovaWebView != null) { + boolean keepRunning = this.shouldKeepRunning() || cordovaInterface.getActivityResultCallback() != null; + cordovaWebView.handlePause(keepRunning); + } + } + + /** + * Handle onStop lifecycle event and notify the plugins + */ + public void onStop() { + for (PluginHandle plugin : plugins.values()) { + plugin.getInstance().handleOnStop(); + } + + if (cordovaWebView != null) { + cordovaWebView.handleStop(); + } + } + + /** + * Handle onDestroy lifecycle event and notify the plugins + */ + public void onDestroy() { + for (PluginHandle plugin : plugins.values()) { + plugin.getInstance().handleOnDestroy(); + } + + handlerThread.quitSafely(); + + if (cordovaWebView != null) { + cordovaWebView.handleDestroy(); + } + } + + /** + * Handle onDetachedFromWindow lifecycle event + */ + public void onDetachedFromWindow() { + webView.removeAllViews(); + webView.destroy(); + } + + public String getServerBasePath() { + return this.localServer.getBasePath(); + } + + /** + * Tell the local server to load files from the given + * file path instead of the assets path. + * @param path + */ + public void setServerBasePath(String path) { + localServer.hostFiles(path); + webView.post(() -> webView.loadUrl(appUrl)); + } + + /** + * Tell the local server to load files from the given + * asset path. + * @param path + */ + public void setServerAssetPath(String path) { + localServer.hostAssets(path); + webView.post(() -> webView.loadUrl(appUrl)); + } + + /** + * Reload the WebView + */ + public void reload() { + webView.post(() -> webView.loadUrl(appUrl)); + } + + public String getLocalUrl() { + return localUrl; + } + + public WebViewLocalServer getLocalServer() { + return localServer; + } + + public HostMask getAppAllowNavigationMask() { + return appAllowNavigationMask; + } + + public Set getAllowedOriginRules() { + return allowedOriginRules; + } + + public BridgeWebViewClient getWebViewClient() { + return this.webViewClient; + } + + public void setWebViewClient(BridgeWebViewClient client) { + this.webViewClient = client; + webView.setWebViewClient(client); + } + + List getWebViewListeners() { + return webViewListeners; + } + + void setWebViewListeners(List webViewListeners) { + this.webViewListeners = webViewListeners; + } + + RouteProcessor getRouteProcessor() { + return routeProcessor; + } + + void setRouteProcessor(RouteProcessor routeProcessor) { + this.routeProcessor = routeProcessor; + } + + ServerPath getServerPath() { + return serverPath; + } + + /** + * Add a listener that the WebViewClient can trigger on certain events. + * @param webViewListener A {@link WebViewListener} to add. + */ + public void addWebViewListener(WebViewListener webViewListener) { + webViewListeners.add(webViewListener); + } + + /** + * Remove a listener that the WebViewClient triggers on certain events. + * @param webViewListener A {@link WebViewListener} to remove. + */ + public void removeWebViewListener(WebViewListener webViewListener) { + webViewListeners.remove(webViewListener); + } + + public static class Builder { + + private Bundle instanceState = null; + private CapConfig config = null; + private List> plugins = new ArrayList<>(); + private List pluginInstances = new ArrayList<>(); + private AppCompatActivity activity; + private Fragment fragment; + private RouteProcessor routeProcessor; + private final List webViewListeners = new ArrayList<>(); + private ServerPath serverPath; + + public Builder(AppCompatActivity activity) { + this.activity = activity; + } + + public Builder(Fragment fragment) { + this.activity = (AppCompatActivity) fragment.getActivity(); + this.fragment = fragment; + } + + public Builder setInstanceState(Bundle instanceState) { + this.instanceState = instanceState; + return this; + } + + public Builder setConfig(CapConfig config) { + this.config = config; + return this; + } + + public Builder setPlugins(List> plugins) { + this.plugins = plugins; + return this; + } + + public Builder addPlugin(Class plugin) { + this.plugins.add(plugin); + return this; + } + + public Builder addPlugins(List> plugins) { + for (Class cls : plugins) { + this.addPlugin(cls); + } + + return this; + } + + public Builder addPluginInstance(Plugin plugin) { + this.pluginInstances.add(plugin); + return this; + } + + public Builder addPluginInstances(List plugins) { + this.pluginInstances.addAll(plugins); + return this; + } + + public Builder addWebViewListener(WebViewListener webViewListener) { + webViewListeners.add(webViewListener); + return this; + } + + public Builder addWebViewListeners(List webViewListeners) { + for (WebViewListener listener : webViewListeners) { + this.addWebViewListener(listener); + } + + return this; + } + + public Builder setRouteProcessor(RouteProcessor routeProcessor) { + this.routeProcessor = routeProcessor; + return this; + } + + public Builder setServerPath(ServerPath serverPath) { + this.serverPath = serverPath; + return this; + } + + public Bridge create() { + // Cordova initialization + ConfigXmlParser parser = new ConfigXmlParser(); + parser.parse(activity.getApplicationContext()); + CordovaPreferences preferences = parser.getPreferences(); + preferences.setPreferencesBundle(activity.getIntent().getExtras()); + List pluginEntries = parser.getPluginEntries(); + + MockCordovaInterfaceImpl cordovaInterface = new MockCordovaInterfaceImpl(activity); + if (instanceState != null) { + cordovaInterface.restoreInstanceState(instanceState); + } + + WebView webView = this.fragment != null ? fragment.getView().findViewById(R.id.webview) : activity.findViewById(R.id.webview); + MockCordovaWebViewImpl mockWebView = new MockCordovaWebViewImpl(activity.getApplicationContext()); + mockWebView.init(cordovaInterface, pluginEntries, preferences, webView); + PluginManager pluginManager = mockWebView.getPluginManager(); + cordovaInterface.onCordovaInit(pluginManager); + + // Bridge initialization + Bridge bridge = new Bridge( + activity, + serverPath, + fragment, + webView, + plugins, + pluginInstances, + cordovaInterface, + pluginManager, + preferences, + config + ); + + if (webView instanceof CapacitorWebView capacitorWebView) { + capacitorWebView.setBridge(bridge); + } + + bridge.setCordovaWebView(mockWebView); + bridge.setWebViewListeners(webViewListeners); + bridge.setRouteProcessor(routeProcessor); + + if (instanceState != null) { + bridge.restoreInstanceState(instanceState); + } + + return bridge; + } + } +} diff --git a/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/BridgeActivity.java b/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/BridgeActivity.java new file mode 100644 index 0000000..bfd532c --- /dev/null +++ b/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/BridgeActivity.java @@ -0,0 +1,218 @@ +package com.getcapacitor; + +import android.content.Intent; +import android.content.res.Configuration; +import android.os.Bundle; +import androidx.appcompat.app.AppCompatActivity; +import com.getcapacitor.android.R; +import java.util.ArrayList; +import java.util.List; + +public class BridgeActivity extends AppCompatActivity { + + protected Bridge bridge; + protected boolean keepRunning = true; + protected CapConfig config; + + protected int activityDepth = 0; + protected List> initialPlugins = new ArrayList<>(); + protected final Bridge.Builder bridgeBuilder = new Bridge.Builder(this); + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + bridgeBuilder.setInstanceState(savedInstanceState); + getApplication().setTheme(R.style.AppTheme_NoActionBar); + setTheme(R.style.AppTheme_NoActionBar); + try { + setContentView(R.layout.capacitor_bridge_layout_main); + } catch (Exception ex) { + setContentView(R.layout.no_webview); + return; + } + + PluginManager loader = new PluginManager(getAssets()); + + try { + bridgeBuilder.addPlugins(loader.loadPluginClasses()); + } catch (PluginLoadException ex) { + Logger.error("Error loading plugins.", ex); + } + + this.load(); + } + + protected void load() { + Logger.debug("Starting BridgeActivity"); + + bridge = bridgeBuilder.addPlugins(initialPlugins).setConfig(config).create(); + + this.keepRunning = bridge.shouldKeepRunning(); + this.onNewIntent(getIntent()); + } + + public void registerPlugin(Class plugin) { + bridgeBuilder.addPlugin(plugin); + } + + public void registerPlugins(List> plugins) { + bridgeBuilder.addPlugins(plugins); + } + + public Bridge getBridge() { + return this.bridge; + } + + @Override + public void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + if (bridge != null) { + bridge.saveInstanceState(outState); + } + } + + @Override + public void onStart() { + super.onStart(); + activityDepth++; + if (this.bridge != null) { + this.bridge.onStart(); + Logger.debug("App started"); + } + } + + @Override + public void onRestart() { + super.onRestart(); + if (this.bridge != null) { + this.bridge.onRestart(); + Logger.debug("App restarted"); + } + } + + @Override + public void onResume() { + super.onResume(); + if (bridge != null) { + bridge.getApp().fireStatusChange(true); + this.bridge.onResume(); + Logger.debug("App resumed"); + } + } + + @Override + public void onPause() { + super.onPause(); + if (bridge != null) { + this.bridge.onPause(); + Logger.debug("App paused"); + } + } + + @Override + public void onStop() { + super.onStop(); + if (bridge != null) { + activityDepth = Math.max(0, activityDepth - 1); + if (activityDepth == 0) { + bridge.getApp().fireStatusChange(false); + } + + this.bridge.onStop(); + Logger.debug("App stopped"); + } + } + + @Override + public void onDestroy() { + super.onDestroy(); + if (this.bridge != null) { + this.bridge.onDestroy(); + Logger.debug("App destroyed"); + } + } + + @Override + public void onDetachedFromWindow() { + super.onDetachedFromWindow(); + if (this.bridge != null) { + this.bridge.onDetachedFromWindow(); + } + } + + /** + * Handles permission request results. + * + * Capacitor is backwards compatible such that plugins using legacy permission request codes + * may coexist with plugins using the AndroidX Activity v1.2 permission callback flow introduced + * in Capacitor 3.0. + * + * In this method, plugins are checked first for ownership of the legacy permission request code. + * If the {@link Bridge#onRequestPermissionsResult(int, String[], int[])} method indicates it has + * handled the permission, then the permission callback will be considered complete. Otherwise, + * the permission will be handled using the AndroidX Activity flow. + * + * @param requestCode the request code associated with the permission request + * @param permissions the Android permission strings requested + * @param grantResults the status result of the permission request + */ + @Override + public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { + if (this.bridge == null) { + return; + } + + if (!bridge.onRequestPermissionsResult(requestCode, permissions, grantResults)) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults); + } + } + + /** + * Handles activity results. + * + * Capacitor is backwards compatible such that plugins using legacy activity result codes + * may coexist with plugins using the AndroidX Activity v1.2 activity callback flow introduced + * in Capacitor 3.0. + * + * In this method, plugins are checked first for ownership of the legacy request code. If the + * {@link Bridge#onActivityResult(int, int, Intent)} method indicates it has handled the activity + * result, then the callback will be considered complete. Otherwise, the result will be handled + * using the AndroidX Activiy flow. + * + * @param requestCode the request code associated with the activity result + * @param resultCode the result code + * @param data any data included with the activity result + */ + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + if (this.bridge == null) { + return; + } + + if (!bridge.onActivityResult(requestCode, resultCode, data)) { + super.onActivityResult(requestCode, resultCode, data); + } + } + + @Override + protected void onNewIntent(Intent intent) { + super.onNewIntent(intent); + + if (this.bridge == null || intent == null) { + return; + } + + this.bridge.onNewIntent(intent); + } + + @Override + public void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + + if (this.bridge == null) { + return; + } + + this.bridge.onConfigurationChanged(newConfig); + } +} diff --git a/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/BridgeWebChromeClient.java b/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/BridgeWebChromeClient.java new file mode 100644 index 0000000..6ca1c8a --- /dev/null +++ b/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/BridgeWebChromeClient.java @@ -0,0 +1,467 @@ +package com.getcapacitor; + +import android.Manifest; +import android.annotation.SuppressLint; +import android.app.Activity; +import android.app.AlertDialog; +import android.content.ActivityNotFoundException; +import android.content.Intent; +import android.net.Uri; +import android.os.Build; +import android.os.Environment; +import android.provider.MediaStore; +import android.view.View; +import android.webkit.ConsoleMessage; +import android.webkit.GeolocationPermissions; +import android.webkit.JsPromptResult; +import android.webkit.JsResult; +import android.webkit.MimeTypeMap; +import android.webkit.PermissionRequest; +import android.webkit.ValueCallback; +import android.webkit.WebChromeClient; +import android.webkit.WebView; +import android.widget.EditText; +import androidx.activity.result.ActivityResult; +import androidx.activity.result.ActivityResultCallback; +import androidx.activity.result.ActivityResultLauncher; +import androidx.activity.result.contract.ActivityResultContracts; +import androidx.core.content.FileProvider; +import com.getcapacitor.util.PermissionHelper; +import java.io.File; +import java.io.IOException; +import java.text.SimpleDateFormat; +import java.util.*; + +/** + * Custom WebChromeClient handler, required for showing dialogs, confirms, etc. in our + * WebView instance. + */ +public class BridgeWebChromeClient extends WebChromeClient { + + private interface PermissionListener { + void onPermissionSelect(Boolean isGranted); + } + + private interface ActivityResultListener { + void onActivityResult(ActivityResult result); + } + + private ActivityResultLauncher permissionLauncher; + private ActivityResultLauncher activityLauncher; + private PermissionListener permissionListener; + private ActivityResultListener activityListener; + + private Bridge bridge; + + public BridgeWebChromeClient(Bridge bridge) { + this.bridge = bridge; + + ActivityResultCallback> permissionCallback = (Map isGranted) -> { + if (permissionListener != null) { + boolean granted = true; + for (Map.Entry permission : isGranted.entrySet()) { + if (!permission.getValue()) granted = false; + } + permissionListener.onPermissionSelect(granted); + } + }; + + permissionLauncher = bridge.registerForActivityResult(new ActivityResultContracts.RequestMultiplePermissions(), permissionCallback); + activityLauncher = bridge.registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), (result) -> { + if (activityListener != null) { + activityListener.onActivityResult(result); + } + }); + } + + /** + * Render web content in `view`. + * + * Both this method and {@link #onHideCustomView()} are required for + * rendering web content in full screen. + * + * @see onShowCustomView() docs + */ + @Override + public void onShowCustomView(View view, CustomViewCallback callback) { + callback.onCustomViewHidden(); + super.onShowCustomView(view, callback); + } + + /** + * Render web content in the original Web View again. + * + * Do not remove this method--@see #onShowCustomView(View, CustomViewCallback). + */ + @Override + public void onHideCustomView() { + super.onHideCustomView(); + } + + @Override + public void onPermissionRequest(final PermissionRequest request) { + List permissionList = new ArrayList<>(); + if (Arrays.asList(request.getResources()).contains("android.webkit.resource.VIDEO_CAPTURE")) { + permissionList.add(Manifest.permission.CAMERA); + } + if (Arrays.asList(request.getResources()).contains("android.webkit.resource.AUDIO_CAPTURE")) { + permissionList.add(Manifest.permission.MODIFY_AUDIO_SETTINGS); + permissionList.add(Manifest.permission.RECORD_AUDIO); + } + if (!permissionList.isEmpty()) { + String[] permissions = permissionList.toArray(new String[0]); + permissionListener = (isGranted) -> { + if (isGranted) { + request.grant(request.getResources()); + } else { + request.deny(); + } + }; + permissionLauncher.launch(permissions); + } else { + request.grant(request.getResources()); + } + } + + /** + * Show the browser alert modal + * @param view + * @param url + * @param message + * @param result + * @return + */ + @Override + public boolean onJsAlert(WebView view, String url, String message, final JsResult result) { + if (bridge.getActivity().isFinishing()) { + return true; + } + + AlertDialog.Builder builder = new AlertDialog.Builder(view.getContext()); + builder + .setMessage(message) + .setPositiveButton("OK", (dialog, buttonIndex) -> { + dialog.dismiss(); + result.confirm(); + }) + .setOnCancelListener((dialog) -> { + dialog.dismiss(); + result.cancel(); + }); + + AlertDialog dialog = builder.create(); + + dialog.show(); + + return true; + } + + /** + * Show the browser confirm modal + * @param view + * @param url + * @param message + * @param result + * @return + */ + @Override + public boolean onJsConfirm(WebView view, String url, String message, final JsResult result) { + if (bridge.getActivity().isFinishing()) { + return true; + } + + final AlertDialog.Builder builder = new AlertDialog.Builder(view.getContext()); + + builder + .setMessage(message) + .setPositiveButton("OK", (dialog, buttonIndex) -> { + dialog.dismiss(); + result.confirm(); + }) + .setNegativeButton("Cancel", (dialog, buttonIndex) -> { + dialog.dismiss(); + result.cancel(); + }) + .setOnCancelListener((dialog) -> { + dialog.dismiss(); + result.cancel(); + }); + + AlertDialog dialog = builder.create(); + + dialog.show(); + + return true; + } + + /** + * Show the browser prompt modal + * @param view + * @param url + * @param message + * @param defaultValue + * @param result + * @return + */ + @Override + public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, final JsPromptResult result) { + if (bridge.getActivity().isFinishing()) { + return true; + } + + final AlertDialog.Builder builder = new AlertDialog.Builder(view.getContext()); + final EditText input = new EditText(view.getContext()); + + builder + .setMessage(message) + .setView(input) + .setPositiveButton("OK", (dialog, buttonIndex) -> { + dialog.dismiss(); + + String inputText1 = input.getText().toString().trim(); + result.confirm(inputText1); + }) + .setNegativeButton("Cancel", (dialog, buttonIndex) -> { + dialog.dismiss(); + result.cancel(); + }) + .setOnCancelListener((dialog) -> { + dialog.dismiss(); + result.cancel(); + }); + + AlertDialog dialog = builder.create(); + + dialog.show(); + + return true; + } + + /** + * Handle the browser geolocation permission prompt + * @param origin + * @param callback + */ + @Override + public void onGeolocationPermissionsShowPrompt(String origin, GeolocationPermissions.Callback callback) { + super.onGeolocationPermissionsShowPrompt(origin, callback); + Logger.debug("onGeolocationPermissionsShowPrompt: DOING IT HERE FOR ORIGIN: " + origin); + final String[] geoPermissions = { Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION }; + + if (!PermissionHelper.hasPermissions(bridge.getContext(), geoPermissions)) { + permissionListener = (isGranted) -> { + if (isGranted) { + callback.invoke(origin, true, false); + } else { + final String[] coarsePermission = { Manifest.permission.ACCESS_COARSE_LOCATION }; + if ( + Build.VERSION.SDK_INT >= Build.VERSION_CODES.S && + PermissionHelper.hasPermissions(bridge.getContext(), coarsePermission) + ) { + callback.invoke(origin, true, false); + } else { + callback.invoke(origin, false, false); + } + } + }; + permissionLauncher.launch(geoPermissions); + } else { + // permission is already granted + callback.invoke(origin, true, false); + Logger.debug("onGeolocationPermissionsShowPrompt: has required permission"); + } + } + + @Override + public boolean onShowFileChooser( + WebView webView, + final ValueCallback filePathCallback, + final FileChooserParams fileChooserParams + ) { + List acceptTypes = Arrays.asList(fileChooserParams.getAcceptTypes()); + boolean captureEnabled = fileChooserParams.isCaptureEnabled(); + boolean capturePhoto = captureEnabled && acceptTypes.contains("image/*"); + final boolean captureVideo = captureEnabled && acceptTypes.contains("video/*"); + if ((capturePhoto || captureVideo)) { + if (isMediaCaptureSupported()) { + showMediaCaptureOrFilePicker(filePathCallback, fileChooserParams, captureVideo); + } else { + permissionListener = (isGranted) -> { + if (isGranted) { + showMediaCaptureOrFilePicker(filePathCallback, fileChooserParams, captureVideo); + } else { + Logger.warn(Logger.tags("FileChooser"), "Camera permission not granted"); + filePathCallback.onReceiveValue(null); + } + }; + final String[] camPermission = { Manifest.permission.CAMERA }; + permissionLauncher.launch(camPermission); + } + } else { + showFilePicker(filePathCallback, fileChooserParams); + } + + return true; + } + + private boolean isMediaCaptureSupported() { + String[] permissions = { Manifest.permission.CAMERA }; + return ( + PermissionHelper.hasPermissions(bridge.getContext(), permissions) || + !PermissionHelper.hasDefinedPermission(bridge.getContext(), Manifest.permission.CAMERA) + ); + } + + private void showMediaCaptureOrFilePicker(ValueCallback filePathCallback, FileChooserParams fileChooserParams, boolean isVideo) { + boolean shown; + if (isVideo) { + shown = showVideoCapturePicker(filePathCallback); + } else { + shown = showImageCapturePicker(filePathCallback); + } + if (!shown) { + Logger.warn(Logger.tags("FileChooser"), "Media capture intent could not be launched. Falling back to default file picker."); + showFilePicker(filePathCallback, fileChooserParams); + } + } + + @SuppressLint("QueryPermissionsNeeded") + private boolean showImageCapturePicker(final ValueCallback filePathCallback) { + Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); + if (takePictureIntent.resolveActivity(bridge.getActivity().getPackageManager()) == null) { + return false; + } + + final Uri imageFileUri; + try { + imageFileUri = createImageFileUri(); + } catch (Exception ex) { + Logger.error("Unable to create temporary media capture file: " + ex.getMessage()); + return false; + } + takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, imageFileUri); + activityListener = (activityResult) -> { + Uri[] result = null; + if (activityResult.getResultCode() == Activity.RESULT_OK) { + result = new Uri[] { imageFileUri }; + } + filePathCallback.onReceiveValue(result); + }; + activityLauncher.launch(takePictureIntent); + + return true; + } + + @SuppressLint("QueryPermissionsNeeded") + private boolean showVideoCapturePicker(final ValueCallback filePathCallback) { + Intent takeVideoIntent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE); + if (takeVideoIntent.resolveActivity(bridge.getActivity().getPackageManager()) == null) { + return false; + } + + activityListener = (activityResult) -> { + Uri[] result = null; + if (activityResult.getResultCode() == Activity.RESULT_OK) { + result = new Uri[] { activityResult.getData().getData() }; + } + filePathCallback.onReceiveValue(result); + }; + activityLauncher.launch(takeVideoIntent); + + return true; + } + + private void showFilePicker(final ValueCallback filePathCallback, FileChooserParams fileChooserParams) { + Intent intent = fileChooserParams.createIntent(); + if (fileChooserParams.getMode() == FileChooserParams.MODE_OPEN_MULTIPLE) { + intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true); + } + if (fileChooserParams.getAcceptTypes().length > 1 || intent.getType().startsWith(".")) { + String[] validTypes = getValidTypes(fileChooserParams.getAcceptTypes()); + intent.putExtra(Intent.EXTRA_MIME_TYPES, validTypes); + if (intent.getType().startsWith(".")) { + intent.setType(validTypes[0]); + } + } + try { + activityListener = (activityResult) -> { + Uri[] result; + Intent resultIntent = activityResult.getData(); + if (activityResult.getResultCode() == Activity.RESULT_OK && resultIntent.getClipData() != null) { + final int numFiles = resultIntent.getClipData().getItemCount(); + result = new Uri[numFiles]; + for (int i = 0; i < numFiles; i++) { + result[i] = resultIntent.getClipData().getItemAt(i).getUri(); + } + } else { + result = WebChromeClient.FileChooserParams.parseResult(activityResult.getResultCode(), resultIntent); + } + filePathCallback.onReceiveValue(result); + }; + activityLauncher.launch(intent); + } catch (ActivityNotFoundException e) { + filePathCallback.onReceiveValue(null); + } + } + + private String[] getValidTypes(String[] currentTypes) { + List validTypes = new ArrayList<>(); + MimeTypeMap mtm = MimeTypeMap.getSingleton(); + for (String mime : currentTypes) { + if (mime.startsWith(".")) { + String extension = mime.substring(1); + String extensionMime = mtm.getMimeTypeFromExtension(extension); + if (extensionMime != null && !validTypes.contains(extensionMime)) { + validTypes.add(extensionMime); + } + } else if (!validTypes.contains(mime)) { + validTypes.add(mime); + } + } + Object[] validObj = validTypes.toArray(); + return Arrays.copyOf(validObj, validObj.length, String[].class); + } + + @Override + public boolean onConsoleMessage(ConsoleMessage consoleMessage) { + String tag = Logger.tags("Console"); + if (consoleMessage.message() != null && isValidMsg(consoleMessage.message())) { + String msg = String.format( + "File: %s - Line %d - Msg: %s", + consoleMessage.sourceId(), + consoleMessage.lineNumber(), + consoleMessage.message() + ); + String level = consoleMessage.messageLevel().name(); + if ("ERROR".equalsIgnoreCase(level)) { + Logger.error(tag, msg, null); + } else if ("WARNING".equalsIgnoreCase(level)) { + Logger.warn(tag, msg); + } else if ("TIP".equalsIgnoreCase(level)) { + Logger.debug(tag, msg); + } else { + Logger.info(tag, msg); + } + } + return true; + } + + public boolean isValidMsg(String msg) { + return !(msg.contains("%cresult %c") || (msg.contains("%cnative %c")) || msg.equalsIgnoreCase("console.groupEnd")); + } + + private Uri createImageFileUri() throws IOException { + Activity activity = bridge.getActivity(); + File photoFile = createImageFile(activity); + return FileProvider.getUriForFile(activity, bridge.getContext().getPackageName() + ".fileprovider", photoFile); + } + + private File createImageFile(Activity activity) throws IOException { + // Create an image file name + String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date()); + String imageFileName = "JPEG_" + timeStamp + "_"; + File storageDir = activity.getExternalFilesDir(Environment.DIRECTORY_PICTURES); + + return File.createTempFile(imageFileName, ".jpg", storageDir); + } +} diff --git a/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/BridgeWebViewClient.java b/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/BridgeWebViewClient.java new file mode 100644 index 0000000..f9df97b --- /dev/null +++ b/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/BridgeWebViewClient.java @@ -0,0 +1,117 @@ +package com.getcapacitor; + +import android.graphics.Bitmap; +import android.net.Uri; +import android.webkit.RenderProcessGoneDetail; +import android.webkit.WebResourceError; +import android.webkit.WebResourceRequest; +import android.webkit.WebResourceResponse; +import android.webkit.WebView; +import android.webkit.WebViewClient; +import java.util.List; + +public class BridgeWebViewClient extends WebViewClient { + + private Bridge bridge; + + public BridgeWebViewClient(Bridge bridge) { + this.bridge = bridge; + } + + @Override + public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) { + return bridge.getLocalServer().shouldInterceptRequest(request); + } + + @Override + public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) { + Uri url = request.getUrl(); + return bridge.launchIntent(url); + } + + @Override + public void onPageFinished(WebView view, String url) { + super.onPageFinished(view, url); + List webViewListeners = bridge.getWebViewListeners(); + + if (webViewListeners != null && view.getProgress() == 100) { + for (WebViewListener listener : bridge.getWebViewListeners()) { + listener.onPageLoaded(view); + } + } + } + + @Override + public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) { + super.onReceivedError(view, request, error); + + List webViewListeners = bridge.getWebViewListeners(); + if (webViewListeners != null) { + for (WebViewListener listener : bridge.getWebViewListeners()) { + listener.onReceivedError(view); + } + } + + String errorPath = bridge.getErrorUrl(); + if (errorPath != null && request.isForMainFrame()) { + view.loadUrl(errorPath); + } + } + + @Override + public void onPageStarted(WebView view, String url, Bitmap favicon) { + super.onPageStarted(view, url, favicon); + bridge.reset(); + List webViewListeners = bridge.getWebViewListeners(); + + if (webViewListeners != null) { + for (WebViewListener listener : bridge.getWebViewListeners()) { + listener.onPageStarted(view); + } + } + } + + @Override + public void onReceivedHttpError(WebView view, WebResourceRequest request, WebResourceResponse errorResponse) { + super.onReceivedHttpError(view, request, errorResponse); + + List webViewListeners = bridge.getWebViewListeners(); + if (webViewListeners != null) { + for (WebViewListener listener : bridge.getWebViewListeners()) { + listener.onReceivedHttpError(view); + } + } + + String errorPath = bridge.getErrorUrl(); + if (errorPath != null && request.isForMainFrame()) { + view.loadUrl(errorPath); + } + } + + @Override + public boolean onRenderProcessGone(WebView view, RenderProcessGoneDetail detail) { + super.onRenderProcessGone(view, detail); + boolean result = false; + + List webViewListeners = bridge.getWebViewListeners(); + if (webViewListeners != null) { + for (WebViewListener listener : bridge.getWebViewListeners()) { + result = listener.onRenderProcessGone(view, detail) || result; + } + } + + return result; + } + + @Override + public void onPageCommitVisible(WebView view, String url) { + super.onPageCommitVisible(view, url); + + List webViewListeners = bridge.getWebViewListeners(); + if (webViewListeners != null) { + for (WebViewListener listener : bridge.getWebViewListeners()) { + listener.onPageCommitVisible(view, url); + } + } + } +} diff --git a/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/CapConfig.java b/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/CapConfig.java new file mode 100644 index 0000000..b20799b --- /dev/null +++ b/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/CapConfig.java @@ -0,0 +1,709 @@ +package com.getcapacitor; + +import static com.getcapacitor.Bridge.CAPACITOR_HTTPS_SCHEME; +import static com.getcapacitor.Bridge.DEFAULT_ANDROID_WEBVIEW_VERSION; +import static com.getcapacitor.Bridge.DEFAULT_HUAWEI_WEBVIEW_VERSION; +import static com.getcapacitor.Bridge.MINIMUM_ANDROID_WEBVIEW_VERSION; +import static com.getcapacitor.Bridge.MINIMUM_HUAWEI_WEBVIEW_VERSION; +import static com.getcapacitor.FileUtils.readFileFromAssets; + +import android.content.Context; +import android.content.pm.ApplicationInfo; +import android.content.res.AssetManager; +import androidx.annotation.Nullable; +import com.getcapacitor.util.JSONUtils; +import java.io.File; +import java.io.IOException; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import org.json.JSONException; +import org.json.JSONObject; + +/** + * Represents the configuration options for Capacitor + */ +public class CapConfig { + + private static final String LOG_BEHAVIOR_NONE = "none"; + private static final String LOG_BEHAVIOR_DEBUG = "debug"; + private static final String LOG_BEHAVIOR_PRODUCTION = "production"; + + // Server Config + private boolean html5mode = true; + private String serverUrl; + private String hostname = "localhost"; + private String androidScheme = CAPACITOR_HTTPS_SCHEME; + private String[] allowNavigation; + + // Android Config + private String overriddenUserAgentString; + private String appendedUserAgentString; + private String backgroundColor; + private boolean allowMixedContent = false; + private boolean captureInput = false; + private boolean webContentsDebuggingEnabled = false; + private boolean loggingEnabled = true; + private boolean initialFocus = true; + private boolean useLegacyBridge = false; + private int minWebViewVersion = DEFAULT_ANDROID_WEBVIEW_VERSION; + private int minHuaweiWebViewVersion = DEFAULT_HUAWEI_WEBVIEW_VERSION; + private String errorPath; + private boolean zoomableWebView = false; + private boolean resolveServiceWorkerRequests = true; + + // Embedded + private String startPath; + + // Plugins + private Map pluginsConfiguration = null; + + // Config Object JSON (legacy) + private JSONObject configJSON = new JSONObject(); + + /** + * Constructs an empty config file. + */ + private CapConfig() {} + + /** + * Get an instance of the Config file object. + * @deprecated use {@link #loadDefault(Context)} to load an instance of the Config object + * from the capacitor.config.json file, or use the {@link CapConfig.Builder} to construct + * a CapConfig for embedded use. + * + * @param assetManager The AssetManager used to load the config file + * @param config JSON describing a configuration to use + */ + @Deprecated + public CapConfig(AssetManager assetManager, JSONObject config) { + if (config != null) { + this.configJSON = config; + } else { + // Load the capacitor.config.json + loadConfigFromAssets(assetManager, null); + } + + deserializeConfig(null); + } + + /** + * Constructs a Capacitor Configuration from config.json file. + * + * @param context The context. + * @return A loaded config file, if successful. + */ + public static CapConfig loadDefault(Context context) { + CapConfig config = new CapConfig(); + + if (context == null) { + Logger.error("Capacitor Config could not be created from file. Context must not be null."); + return config; + } + + config.loadConfigFromAssets(context.getAssets(), null); + config.deserializeConfig(context); + return config; + } + + /** + * Constructs a Capacitor Configuration from config.json file within the app assets. + * + * @param context The context. + * @param path A path relative to the root assets directory. + * @return A loaded config file, if successful. + */ + public static CapConfig loadFromAssets(Context context, String path) { + CapConfig config = new CapConfig(); + + if (context == null) { + Logger.error("Capacitor Config could not be created from file. Context must not be null."); + return config; + } + + config.loadConfigFromAssets(context.getAssets(), path); + config.deserializeConfig(context); + return config; + } + + /** + * Constructs a Capacitor Configuration from config.json file within the app file-space. + * + * @param context The context. + * @param path A path relative to the root of the app file-space. + * @return A loaded config file, if successful. + */ + public static CapConfig loadFromFile(Context context, String path) { + CapConfig config = new CapConfig(); + + if (context == null) { + Logger.error("Capacitor Config could not be created from file. Context must not be null."); + return config; + } + + config.loadConfigFromFile(path); + config.deserializeConfig(context); + return config; + } + + /** + * Constructs a Capacitor Configuration using ConfigBuilder. + * + * @param builder A config builder initialized with values + */ + private CapConfig(Builder builder) { + // Server Config + this.html5mode = builder.html5mode; + this.serverUrl = builder.serverUrl; + this.hostname = builder.hostname; + + if (this.validateScheme(builder.androidScheme)) { + this.androidScheme = builder.androidScheme; + } + + this.allowNavigation = builder.allowNavigation; + + // Android Config + this.overriddenUserAgentString = builder.overriddenUserAgentString; + this.appendedUserAgentString = builder.appendedUserAgentString; + this.backgroundColor = builder.backgroundColor; + this.allowMixedContent = builder.allowMixedContent; + this.captureInput = builder.captureInput; + this.webContentsDebuggingEnabled = builder.webContentsDebuggingEnabled; + this.loggingEnabled = builder.loggingEnabled; + this.initialFocus = builder.initialFocus; + this.useLegacyBridge = builder.useLegacyBridge; + this.minWebViewVersion = builder.minWebViewVersion; + this.minHuaweiWebViewVersion = builder.minHuaweiWebViewVersion; + this.errorPath = builder.errorPath; + this.zoomableWebView = builder.zoomableWebView; + this.resolveServiceWorkerRequests = builder.resolveServiceWorkerRequests; + + // Embedded + this.startPath = builder.startPath; + + // Plugins Config + this.pluginsConfiguration = builder.pluginsConfiguration; + } + + /** + * Loads a Capacitor Configuration JSON file into a Capacitor Configuration object. + * An optional path string can be provided to look for the config in a subdirectory path. + */ + private void loadConfigFromAssets(AssetManager assetManager, String path) { + if (path == null) { + path = ""; + } else { + // Add slash at the end to form a proper file path if going deeper in assets dir + if (path.charAt(path.length() - 1) != '/') { + path = path + "/"; + } + } + + try { + String jsonString = readFileFromAssets(assetManager, path + "capacitor.config.json"); + configJSON = new JSONObject(jsonString); + } catch (IOException ex) { + Logger.error("Unable to load capacitor.config.json. Run npx cap copy first", ex); + } catch (JSONException ex) { + Logger.error("Unable to parse capacitor.config.json. Make sure it's valid json", ex); + } + } + + /** + * Loads a Capacitor Configuration JSON file into a Capacitor Configuration object. + * An optional path string can be provided to look for the config in a subdirectory path. + */ + private void loadConfigFromFile(String path) { + if (path == null) { + path = ""; + } else { + // Add slash at the end to form a proper file path if going deeper in assets dir + if (path.charAt(path.length() - 1) != '/') { + path = path + "/"; + } + } + + try { + File configFile = new File(path + "capacitor.config.json"); + String jsonString = FileUtils.readFileFromDisk(configFile); + configJSON = new JSONObject(jsonString); + } catch (JSONException ex) { + Logger.error("Unable to parse capacitor.config.json. Make sure it's valid json", ex); + } catch (IOException ex) { + Logger.error("Unable to load capacitor.config.json.", ex); + } + } + + /** + * Deserializes the config from JSON into a Capacitor Configuration object. + */ + private void deserializeConfig(@Nullable Context context) { + boolean isDebug = context != null && (context.getApplicationInfo().flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0; + + // Server + html5mode = JSONUtils.getBoolean(configJSON, "server.html5mode", html5mode); + serverUrl = JSONUtils.getString(configJSON, "server.url", null); + hostname = JSONUtils.getString(configJSON, "server.hostname", hostname); + errorPath = JSONUtils.getString(configJSON, "server.errorPath", null); + startPath = JSONUtils.getString(configJSON, "server.appStartPath", null); + + String configSchema = JSONUtils.getString(configJSON, "server.androidScheme", androidScheme); + if (this.validateScheme(configSchema)) { + androidScheme = configSchema; + } + + allowNavigation = JSONUtils.getArray(configJSON, "server.allowNavigation", null); + + // Android + overriddenUserAgentString = JSONUtils.getString( + configJSON, + "android.overrideUserAgent", + JSONUtils.getString(configJSON, "overrideUserAgent", null) + ); + appendedUserAgentString = JSONUtils.getString( + configJSON, + "android.appendUserAgent", + JSONUtils.getString(configJSON, "appendUserAgent", null) + ); + backgroundColor = JSONUtils.getString( + configJSON, + "android.backgroundColor", + JSONUtils.getString(configJSON, "backgroundColor", null) + ); + allowMixedContent = JSONUtils.getBoolean( + configJSON, + "android.allowMixedContent", + JSONUtils.getBoolean(configJSON, "allowMixedContent", allowMixedContent) + ); + minWebViewVersion = JSONUtils.getInt(configJSON, "android.minWebViewVersion", DEFAULT_ANDROID_WEBVIEW_VERSION); + minHuaweiWebViewVersion = JSONUtils.getInt(configJSON, "android.minHuaweiWebViewVersion", DEFAULT_HUAWEI_WEBVIEW_VERSION); + captureInput = JSONUtils.getBoolean(configJSON, "android.captureInput", captureInput); + useLegacyBridge = JSONUtils.getBoolean(configJSON, "android.useLegacyBridge", useLegacyBridge); + webContentsDebuggingEnabled = JSONUtils.getBoolean(configJSON, "android.webContentsDebuggingEnabled", isDebug); + zoomableWebView = JSONUtils.getBoolean(configJSON, "android.zoomEnabled", JSONUtils.getBoolean(configJSON, "zoomEnabled", false)); + resolveServiceWorkerRequests = JSONUtils.getBoolean(configJSON, "android.resolveServiceWorkerRequests", true); + + String logBehavior = JSONUtils.getString( + configJSON, + "android.loggingBehavior", + JSONUtils.getString(configJSON, "loggingBehavior", LOG_BEHAVIOR_DEBUG) + ); + switch (logBehavior.toLowerCase(Locale.ROOT)) { + case LOG_BEHAVIOR_PRODUCTION: + loggingEnabled = true; + break; + case LOG_BEHAVIOR_NONE: + loggingEnabled = false; + break; + default: // LOG_BEHAVIOR_DEBUG + loggingEnabled = isDebug; + } + + initialFocus = JSONUtils.getBoolean( + configJSON, + "android.initialFocus", + JSONUtils.getBoolean(configJSON, "initialFocus", initialFocus) + ); + + // Plugins + pluginsConfiguration = deserializePluginsConfig(JSONUtils.getObject(configJSON, "plugins")); + } + + private boolean validateScheme(String scheme) { + List invalidSchemes = Arrays.asList("file", "ftp", "ftps", "ws", "wss", "about", "blob", "data"); + if (invalidSchemes.contains(scheme)) { + Logger.warn(scheme + " is not an allowed scheme. Defaulting to https."); + return false; + } + + // Non-http(s) schemes are not allowed to modify the URL path as of Android Webview 117 + if (!scheme.equals("http") && !scheme.equals("https")) { + Logger.warn( + "Using a non-standard scheme: " + scheme + " for Android. This is known to cause issues as of Android Webview 117." + ); + } + + return true; + } + + public boolean isHTML5Mode() { + return html5mode; + } + + public String getServerUrl() { + return serverUrl; + } + + public String getErrorPath() { + return errorPath; + } + + public String getHostname() { + return hostname; + } + + public String getStartPath() { + return startPath; + } + + public String getAndroidScheme() { + return androidScheme; + } + + public String[] getAllowNavigation() { + return allowNavigation; + } + + public String getOverriddenUserAgentString() { + return overriddenUserAgentString; + } + + public String getAppendedUserAgentString() { + return appendedUserAgentString; + } + + public String getBackgroundColor() { + return backgroundColor; + } + + public boolean isMixedContentAllowed() { + return allowMixedContent; + } + + public boolean isInputCaptured() { + return captureInput; + } + + public boolean isResolveServiceWorkerRequests() { + return resolveServiceWorkerRequests; + } + + public boolean isWebContentsDebuggingEnabled() { + return webContentsDebuggingEnabled; + } + + public boolean isZoomableWebView() { + return zoomableWebView; + } + + public boolean isLoggingEnabled() { + return loggingEnabled; + } + + public boolean isInitialFocus() { + return initialFocus; + } + + public boolean isUsingLegacyBridge() { + return useLegacyBridge; + } + + public int getMinWebViewVersion() { + if (minWebViewVersion < MINIMUM_ANDROID_WEBVIEW_VERSION) { + Logger.warn("Specified minimum webview version is too low, defaulting to " + MINIMUM_ANDROID_WEBVIEW_VERSION); + return MINIMUM_ANDROID_WEBVIEW_VERSION; + } + + return minWebViewVersion; + } + + public int getMinHuaweiWebViewVersion() { + if (minHuaweiWebViewVersion < MINIMUM_HUAWEI_WEBVIEW_VERSION) { + Logger.warn("Specified minimum Huawei webview version is too low, defaulting to " + MINIMUM_HUAWEI_WEBVIEW_VERSION); + return MINIMUM_HUAWEI_WEBVIEW_VERSION; + } + + return minHuaweiWebViewVersion; + } + + public PluginConfig getPluginConfiguration(String pluginId) { + PluginConfig pluginConfig = pluginsConfiguration.get(pluginId); + if (pluginConfig == null) { + pluginConfig = new PluginConfig(new JSONObject()); + } + + return pluginConfig; + } + + /** + * Get a JSON object value from the Capacitor config. + * @deprecated use {@link PluginConfig#getObject(String)} to access plugin config values. + * For main Capacitor config values, use the appropriate getter. + * + * @param key A key to fetch from the config + * @return The value from the config, if exists. Null if not + */ + @Deprecated + public JSONObject getObject(String key) { + try { + return configJSON.getJSONObject(key); + } catch (Exception ex) {} + return null; + } + + /** + * Get a string value from the Capacitor config. + * @deprecated use {@link PluginConfig#getString(String, String)} to access plugin config + * values. For main Capacitor config values, use the appropriate getter. + * + * @param key A key to fetch from the config + * @return The value from the config, if exists. Null if not + */ + @Deprecated + public String getString(String key) { + return JSONUtils.getString(configJSON, key, null); + } + + /** + * Get a string value from the Capacitor config. + * @deprecated use {@link PluginConfig#getString(String, String)} to access plugin config + * values. For main Capacitor config values, use the appropriate getter. + * + * @param key A key to fetch from the config + * @param defaultValue A default value to return if the key does not exist in the config + * @return The value from the config, if key exists. Default value returned if not + */ + @Deprecated + public String getString(String key, String defaultValue) { + return JSONUtils.getString(configJSON, key, defaultValue); + } + + /** + * Get a boolean value from the Capacitor config. + * @deprecated use {@link PluginConfig#getBoolean(String, boolean)} to access plugin config + * values. For main Capacitor config values, use the appropriate getter. + * + * @param key A key to fetch from the config + * @param defaultValue A default value to return if the key does not exist in the config + * @return The value from the config, if key exists. Default value returned if not + */ + @Deprecated + public boolean getBoolean(String key, boolean defaultValue) { + return JSONUtils.getBoolean(configJSON, key, defaultValue); + } + + /** + * Get an integer value from the Capacitor config. + * @deprecated use {@link PluginConfig#getInt(String, int)} to access the plugin config + * values. For main Capacitor config values, use the appropriate getter. + * + * @param key A key to fetch from the config + * @param defaultValue A default value to return if the key does not exist in the config + * @return The value from the config, if key exists. Default value returned if not + */ + @Deprecated + public int getInt(String key, int defaultValue) { + return JSONUtils.getInt(configJSON, key, defaultValue); + } + + /** + * Get a string array value from the Capacitor config. + * @deprecated use {@link PluginConfig#getArray(String)} to access the plugin config + * values. For main Capacitor config values, use the appropriate getter. + * + * @param key A key to fetch from the config + * @return The value from the config, if exists. Null if not + */ + @Deprecated + public String[] getArray(String key) { + return JSONUtils.getArray(configJSON, key, null); + } + + /** + * Get a string array value from the Capacitor config. + * @deprecated use {@link PluginConfig#getArray(String, String[])} to access the plugin + * config values. For main Capacitor config values, use the appropriate getter. + * + * @param key A key to fetch from the config + * @param defaultValue A default value to return if the key does not exist in the config + * @return The value from the config, if key exists. Default value returned if not + */ + @Deprecated + public String[] getArray(String key, String[] defaultValue) { + return JSONUtils.getArray(configJSON, key, defaultValue); + } + + private static Map deserializePluginsConfig(JSONObject pluginsConfig) { + Map pluginsMap = new HashMap<>(); + + // return an empty map if there is no pluginsConfig json + if (pluginsConfig == null) { + return pluginsMap; + } + + Iterator pluginIds = pluginsConfig.keys(); + + while (pluginIds.hasNext()) { + String pluginId = pluginIds.next(); + JSONObject value = null; + + try { + value = pluginsConfig.getJSONObject(pluginId); + PluginConfig pluginConfig = new PluginConfig(value); + pluginsMap.put(pluginId, pluginConfig); + } catch (JSONException e) { + e.printStackTrace(); + } + } + + return pluginsMap; + } + + /** + * Builds a Capacitor Configuration in code + */ + public static class Builder { + + private Context context; + + // Server Config Values + private boolean html5mode = true; + private String serverUrl; + private String errorPath; + private String hostname = "localhost"; + private String androidScheme = CAPACITOR_HTTPS_SCHEME; + private String[] allowNavigation; + + // Android Config Values + private String overriddenUserAgentString; + private String appendedUserAgentString; + private String backgroundColor; + private boolean allowMixedContent = false; + private boolean captureInput = false; + private Boolean webContentsDebuggingEnabled = null; + private boolean loggingEnabled = true; + private boolean initialFocus = false; + private boolean useLegacyBridge = false; + private int minWebViewVersion = DEFAULT_ANDROID_WEBVIEW_VERSION; + private int minHuaweiWebViewVersion = DEFAULT_HUAWEI_WEBVIEW_VERSION; + private boolean zoomableWebView = false; + private boolean resolveServiceWorkerRequests = true; + + // Embedded + private String startPath = null; + + // Plugins Config Object + private Map pluginsConfiguration = new HashMap<>(); + + /** + * Constructs a new CapConfig Builder. + * + * @param context The context + */ + public Builder(Context context) { + this.context = context; + } + + /** + * Builds a Capacitor Config from the builder. + * + * @return A new Capacitor Config + */ + public CapConfig create() { + if (webContentsDebuggingEnabled == null) { + webContentsDebuggingEnabled = (context.getApplicationInfo().flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0; + } + + return new CapConfig(this); + } + + public Builder setPluginsConfiguration(JSONObject pluginsConfiguration) { + this.pluginsConfiguration = deserializePluginsConfig(pluginsConfiguration); + return this; + } + + public Builder setHTML5mode(boolean html5mode) { + this.html5mode = html5mode; + return this; + } + + public Builder setServerUrl(String serverUrl) { + this.serverUrl = serverUrl; + return this; + } + + public Builder setErrorPath(String errorPath) { + this.errorPath = errorPath; + return this; + } + + public Builder setHostname(String hostname) { + this.hostname = hostname; + return this; + } + + public Builder setStartPath(String path) { + this.startPath = path; + return this; + } + + public Builder setAndroidScheme(String androidScheme) { + this.androidScheme = androidScheme; + return this; + } + + public Builder setAllowNavigation(String[] allowNavigation) { + this.allowNavigation = allowNavigation; + return this; + } + + public Builder setOverriddenUserAgentString(String overriddenUserAgentString) { + this.overriddenUserAgentString = overriddenUserAgentString; + return this; + } + + public Builder setAppendedUserAgentString(String appendedUserAgentString) { + this.appendedUserAgentString = appendedUserAgentString; + return this; + } + + public Builder setBackgroundColor(String backgroundColor) { + this.backgroundColor = backgroundColor; + return this; + } + + public Builder setAllowMixedContent(boolean allowMixedContent) { + this.allowMixedContent = allowMixedContent; + return this; + } + + public Builder setCaptureInput(boolean captureInput) { + this.captureInput = captureInput; + return this; + } + + public Builder setUseLegacyBridge(boolean useLegacyBridge) { + this.useLegacyBridge = useLegacyBridge; + return this; + } + + public Builder setResolveServiceWorkerRequests(boolean resolveServiceWorkerRequests) { + this.resolveServiceWorkerRequests = resolveServiceWorkerRequests; + return this; + } + + public Builder setWebContentsDebuggingEnabled(boolean webContentsDebuggingEnabled) { + this.webContentsDebuggingEnabled = webContentsDebuggingEnabled; + return this; + } + + public Builder setZoomableWebView(boolean zoomableWebView) { + this.zoomableWebView = zoomableWebView; + return this; + } + + public Builder setLoggingEnabled(boolean enabled) { + this.loggingEnabled = enabled; + return this; + } + + public Builder setInitialFocus(boolean focus) { + this.initialFocus = focus; + return this; + } + } +} diff --git a/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/CapacitorWebView.java b/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/CapacitorWebView.java new file mode 100644 index 0000000..22f6f97 --- /dev/null +++ b/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/CapacitorWebView.java @@ -0,0 +1,57 @@ +package com.getcapacitor; + +import android.content.Context; +import android.os.Build; +import android.util.AttributeSet; +import android.util.TypedValue; +import android.view.KeyEvent; +import android.view.inputmethod.BaseInputConnection; +import android.view.inputmethod.EditorInfo; +import android.view.inputmethod.InputConnection; +import android.webkit.WebView; +import androidx.core.graphics.Insets; +import androidx.core.view.ViewCompat; +import androidx.core.view.WindowInsetsCompat; + +public class CapacitorWebView extends WebView { + + private BaseInputConnection capInputConnection; + private Bridge bridge; + + public CapacitorWebView(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public void setBridge(Bridge bridge) { + this.bridge = bridge; + } + + @Override + public InputConnection onCreateInputConnection(EditorInfo outAttrs) { + CapConfig config; + if (bridge != null) { + config = bridge.getConfig(); + } else { + config = CapConfig.loadDefault(getContext()); + } + + boolean captureInput = config.isInputCaptured(); + if (captureInput) { + if (capInputConnection == null) { + capInputConnection = new BaseInputConnection(this, false); + } + return capInputConnection; + } + return super.onCreateInputConnection(outAttrs); + } + + @Override + @SuppressWarnings("deprecation") + public boolean dispatchKeyEvent(KeyEvent event) { + if (event.getAction() == KeyEvent.ACTION_MULTIPLE) { + evaluateJavascript("document.activeElement.value = document.activeElement.value + '" + event.getCharacters() + "';", null); + return false; + } + return super.dispatchKeyEvent(event); + } +} diff --git a/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/FileUtils.java b/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/FileUtils.java new file mode 100644 index 0000000..ce09e7c --- /dev/null +++ b/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/FileUtils.java @@ -0,0 +1,303 @@ +/** + * Portions adopted from react-native-image-crop-picker + * + * MIT License + + * Copyright (c) 2017 Ivan Pusic + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.getcapacitor; + +import android.content.ContentUris; +import android.content.Context; +import android.content.res.AssetManager; +import android.database.Cursor; +import android.net.Uri; +import android.os.Environment; +import android.provider.DocumentsContract; +import android.provider.MediaStore; +import android.provider.OpenableColumns; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileOutputStream; +import java.io.FileReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; + +/** + * Common File utilities, such as resolve content URIs and + * creating portable web paths from low-level files + */ +public class FileUtils { + + private static String CapacitorFileScheme = Bridge.CAPACITOR_FILE_START; + + public enum Type { + IMAGE("image"); + + private String type; + + Type(String type) { + this.type = type; + } + } + + public static String getPortablePath(Context c, String host, Uri u) { + String path = getFileUrlForUri(c, u); + if (path.startsWith("file://")) { + path = path.replace("file://", ""); + } + return host + Bridge.CAPACITOR_FILE_START + path; + } + + public static String getFileUrlForUri(final Context context, final Uri uri) { + // DocumentProvider + if (DocumentsContract.isDocumentUri(context, uri)) { + // ExternalStorageProvider + if (isExternalStorageDocument(uri)) { + final String docId = DocumentsContract.getDocumentId(uri); + final String[] split = docId.split(":"); + final String type = split[0]; + + if ("primary".equalsIgnoreCase(type)) { + return legacyPrimaryPath(split[1]); + } else { + final int splitIndex = docId.indexOf(':', 1); + final String tag = docId.substring(0, splitIndex); + final String path = docId.substring(splitIndex + 1); + + String nonPrimaryVolume = getPathToNonPrimaryVolume(context, tag); + if (nonPrimaryVolume != null) { + String result = nonPrimaryVolume + "/" + path; + File file = new File(result); + if (file.exists() && file.canRead()) { + return result; + } + return null; + } + } + } + // DownloadsProvider + else if (isDownloadsDocument(uri)) { + final String id = DocumentsContract.getDocumentId(uri); + final Uri contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"), Long.valueOf(id)); + + return getDataColumn(context, contentUri, null, null); + } + // MediaProvider + else if (isMediaDocument(uri)) { + final String docId = DocumentsContract.getDocumentId(uri); + final String[] split = docId.split(":"); + final String type = split[0]; + + Uri contentUri = null; + if ("image".equals(type)) { + contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI; + } else if ("video".equals(type)) { + contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI; + } else if ("audio".equals(type)) { + contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI; + } + + final String selection = "_id=?"; + final String[] selectionArgs = new String[] { split[1] }; + + return getDataColumn(context, contentUri, selection, selectionArgs); + } + } + // MediaStore (and general) + else if ("content".equalsIgnoreCase(uri.getScheme())) { + // Return the remote address + if (isGooglePhotosUri(uri)) return uri.getLastPathSegment(); + return getDataColumn(context, uri, null, null); + } + // File + else if ("file".equalsIgnoreCase(uri.getScheme())) { + return uri.getPath(); + } + + return null; + } + + @SuppressWarnings("deprecation") + private static String legacyPrimaryPath(String pathPart) { + return Environment.getExternalStorageDirectory() + "/" + pathPart; + } + + /** + * Read a plaintext file from the assets directory. + * + * @param assetManager Used to open the file. + * @param fileName The path of the file to read. + * @return The contents of the file path. + * @throws IOException Thrown if any issues reading the provided file path. + */ + static String readFileFromAssets(AssetManager assetManager, String fileName) throws IOException { + try (BufferedReader reader = new BufferedReader(new InputStreamReader(assetManager.open(fileName)))) { + StringBuilder buffer = new StringBuilder(); + String line; + while ((line = reader.readLine()) != null) { + buffer.append(line).append("\n"); + } + + return buffer.toString(); + } + } + + /** + * Read a plaintext file from within the app disk space. + * + * @param file The file to read. + * @return The contents of the file path. + * @throws IOException Thrown if any issues reading the provided file path. + */ + static String readFileFromDisk(File file) throws IOException { + try (BufferedReader reader = new BufferedReader(new FileReader(file))) { + StringBuilder buffer = new StringBuilder(); + String line; + while ((line = reader.readLine()) != null) { + buffer.append(line).append("\n"); + } + + return buffer.toString(); + } + } + + /** + * Get the value of the data column for this Uri. This is useful for + * MediaStore Uris, and other file-based ContentProviders. + * + * @param context The context. + * @param uri The Uri to query. + * @param selection (Optional) Filter used in the query. + * @param selectionArgs (Optional) Selection arguments used in the query. + * @return The value of the _data column, which is typically a file path. + */ + private static String getDataColumn(Context context, Uri uri, String selection, String[] selectionArgs) { + String path = null; + Cursor cursor = null; + final String column = "_data"; + final String[] projection = { column }; + + try { + cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, null); + if (cursor != null && cursor.moveToFirst()) { + final int index = cursor.getColumnIndexOrThrow(column); + path = cursor.getString(index); + } + } catch (IllegalArgumentException ex) { + return getCopyFilePath(uri, context); + } finally { + if (cursor != null) cursor.close(); + } + if (path == null) { + return getCopyFilePath(uri, context); + } + return path; + } + + private static String getCopyFilePath(Uri uri, Context context) { + Cursor cursor = context.getContentResolver().query(uri, null, null, null, null); + int nameIndex = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME); + cursor.moveToFirst(); + String name = (cursor.getString(nameIndex)); + String fileName = sanitizeFilename(name); + File file = new File(context.getFilesDir(), fileName); + try { + InputStream inputStream = context.getContentResolver().openInputStream(uri); + FileOutputStream outputStream = new FileOutputStream(file); + int read = 0; + int maxBufferSize = 1024 * 1024; + int bufferSize = Math.min(inputStream.available(), maxBufferSize); + final byte[] buffers = new byte[bufferSize]; + while ((read = inputStream.read(buffers)) != -1) { + outputStream.write(buffers, 0, read); + } + inputStream.close(); + outputStream.close(); + } catch (Exception e) { + return null; + } finally { + if (cursor != null) cursor.close(); + } + return file.getPath(); + } + + /** + * @param uri The Uri to check. + * @return Whether the Uri authority is ExternalStorageProvider. + */ + private static boolean isExternalStorageDocument(Uri uri) { + return "com.android.externalstorage.documents".equals(uri.getAuthority()); + } + + /** + * @param uri The Uri to check. + * @return Whether the Uri authority is DownloadsProvider. + */ + private static boolean isDownloadsDocument(Uri uri) { + return "com.android.providers.downloads.documents".equals(uri.getAuthority()); + } + + /** + * @param uri The Uri to check. + * @return Whether the Uri authority is MediaProvider. + */ + private static boolean isMediaDocument(Uri uri) { + return "com.android.providers.media.documents".equals(uri.getAuthority()); + } + + /** + * @param uri The Uri to check. + * @return Whether the Uri authority is Google Photos. + */ + private static boolean isGooglePhotosUri(Uri uri) { + return "com.google.android.apps.photos.content".equals(uri.getAuthority()); + } + + private static String getPathToNonPrimaryVolume(Context context, String tag) { + File[] volumes = context.getExternalCacheDirs(); + if (volumes != null) { + for (File volume : volumes) { + if (volume != null) { + String path = volume.getAbsolutePath(); + if (path != null) { + int index = path.indexOf(tag); + if (index != -1) { + return path.substring(0, index) + tag; + } + } + } + } + } + return null; + } + + private static String sanitizeFilename(String displayName) { + String[] badCharacters = new String[] { "..", "/" }; + String[] segments = displayName.split("/"); + String fileName = segments[segments.length - 1]; + for (String suspString : badCharacters) { + fileName = fileName.replace(suspString, "_"); + } + return fileName; + } +} diff --git a/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/InvalidPluginException.java b/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/InvalidPluginException.java new file mode 100644 index 0000000..1757e32 --- /dev/null +++ b/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/InvalidPluginException.java @@ -0,0 +1,8 @@ +package com.getcapacitor; + +class InvalidPluginException extends Exception { + + public InvalidPluginException(String s) { + super(s); + } +} diff --git a/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/InvalidPluginMethodException.java b/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/InvalidPluginMethodException.java new file mode 100644 index 0000000..94be491 --- /dev/null +++ b/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/InvalidPluginMethodException.java @@ -0,0 +1,16 @@ +package com.getcapacitor; + +class InvalidPluginMethodException extends Exception { + + public InvalidPluginMethodException(String s) { + super(s); + } + + public InvalidPluginMethodException(Throwable t) { + super(t); + } + + public InvalidPluginMethodException(String s, Throwable t) { + super(s, t); + } +} diff --git a/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/JSArray.java b/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/JSArray.java new file mode 100644 index 0000000..06b7f4d --- /dev/null +++ b/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/JSArray.java @@ -0,0 +1,51 @@ +package com.getcapacitor; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import org.json.JSONArray; +import org.json.JSONException; + +public class JSArray extends JSONArray { + + public JSArray() { + super(); + } + + public JSArray(String json) throws JSONException { + super(json); + } + + public JSArray(Collection copyFrom) { + super(copyFrom); + } + + public JSArray(Object array) throws JSONException { + super(array); + } + + @SuppressWarnings("unchecked") + public List toList() throws JSONException { + List items = new ArrayList<>(); + Object o = null; + for (int i = 0; i < this.length(); i++) { + o = this.get(i); + try { + items.add((E) this.get(i)); + } catch (Exception ex) { + throw new JSONException("Not all items are instances of the given type"); + } + } + return items; + } + + /** + * Create a new JSArray without throwing a error + */ + public static JSArray from(Object array) { + try { + return new JSArray(array); + } catch (JSONException ex) {} + return null; + } +} diff --git a/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/JSExport.java b/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/JSExport.java new file mode 100644 index 0000000..2083c2c --- /dev/null +++ b/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/JSExport.java @@ -0,0 +1,208 @@ +package com.getcapacitor; + +import static com.getcapacitor.FileUtils.readFileFromAssets; + +import android.content.Context; +import android.text.TextUtils; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +public class JSExport { + + private static String CATCHALL_OPTIONS_PARAM = "_options"; + private static String CALLBACK_PARAM = "_callback"; + + public static String getGlobalJS(Context context, boolean loggingEnabled, boolean isDebug) { + return "window.Capacitor = { DEBUG: " + isDebug + ", isLoggingEnabled: " + loggingEnabled + ", Plugins: {} };"; + } + + public static String getMiscFileJS(ArrayList paths, Context context) { + List lines = new ArrayList<>(); + + for (String path : paths) { + try { + String fileContent = readFileFromAssets(context.getAssets(), "public/" + path); + lines.add(fileContent); + } catch (IOException ex) { + Logger.error("Unable to read public/" + path); + } + } + + return TextUtils.join("\n", lines); + } + + public static String getCordovaJS(Context context) { + String fileContent = ""; + try { + fileContent = readFileFromAssets(context.getAssets(), "public/cordova.js"); + } catch (IOException ex) { + Logger.error("Unable to read public/cordova.js file, Cordova plugins will not work"); + } + return fileContent; + } + + public static String getCordovaPluginsFileJS(Context context) { + String fileContent = ""; + try { + fileContent = readFileFromAssets(context.getAssets(), "public/cordova_plugins.js"); + } catch (IOException ex) { + Logger.error("Unable to read public/cordova_plugins.js file, Cordova plugins will not work"); + } + return fileContent; + } + + public static String getPluginJS(Collection plugins) { + List lines = new ArrayList<>(); + JSONArray pluginArray = new JSONArray(); + + lines.add("// Begin: Capacitor Plugin JS"); + for (PluginHandle plugin : plugins) { + lines.add( + "(function(w) {\n" + + "var a = (w.Capacitor = w.Capacitor || {});\n" + + "var p = (a.Plugins = a.Plugins || {});\n" + + "var t = (p['" + + plugin.getId() + + "'] = {});\n" + + "t.addListener = function(eventName, callback) {\n" + + " return w.Capacitor.addListener('" + + plugin.getId() + + "', eventName, callback);\n" + + "}" + ); + Collection methods = plugin.getMethods(); + for (PluginMethodHandle method : methods) { + if (method.getName().equals("addListener") || method.getName().equals("removeListener")) { + // Don't export add/remove listener, we do that automatically above as they are "special snowflakes" + continue; + } + lines.add(generateMethodJS(plugin, method)); + } + + lines.add("})(window);\n"); + pluginArray.put(createPluginHeader(plugin)); + } + + return TextUtils.join("\n", lines) + "\nwindow.Capacitor.PluginHeaders = " + pluginArray.toString() + ";"; + } + + public static String getCordovaPluginJS(Context context) { + return getFilesContent(context, "public/plugins"); + } + + public static String getFilesContent(Context context, String path) { + StringBuilder builder = new StringBuilder(); + try { + String[] content = context.getAssets().list(path); + if (content.length > 0) { + for (String file : content) { + if (!file.endsWith(".map")) { + builder.append(getFilesContent(context, path + "/" + file)); + } + } + } else { + return readFileFromAssets(context.getAssets(), path); + } + } catch (IOException ex) { + Logger.warn("Unable to read file at path " + path); + } + return builder.toString(); + } + + private static JSONObject createPluginHeader(PluginHandle plugin) { + JSONObject pluginObj = new JSONObject(); + Collection methods = plugin.getMethods(); + try { + String id = plugin.getId(); + JSONArray methodArray = new JSONArray(); + pluginObj.put("name", id); + + for (PluginMethodHandle method : methods) { + methodArray.put(createPluginMethodHeader(method)); + } + + pluginObj.put("methods", methodArray); + } catch (JSONException e) { + // ignore + } + return pluginObj; + } + + private static JSONObject createPluginMethodHeader(PluginMethodHandle method) { + JSONObject methodObj = new JSONObject(); + + try { + methodObj.put("name", method.getName()); + if (!method.getReturnType().equals(PluginMethod.RETURN_NONE)) { + methodObj.put("rtype", method.getReturnType()); + } + } catch (JSONException e) { + // ignore + } + + return methodObj; + } + + public static String getBridgeJS(Context context) throws JSExportException { + return getFilesContent(context, "native-bridge.js"); + } + + private static String generateMethodJS(PluginHandle plugin, PluginMethodHandle method) { + List lines = new ArrayList<>(); + + List args = new ArrayList<>(); + // Add the catch all param that will take a full javascript object to pass to the plugin + args.add(CATCHALL_OPTIONS_PARAM); + + String returnType = method.getReturnType(); + if (returnType.equals(PluginMethod.RETURN_CALLBACK)) { + args.add(CALLBACK_PARAM); + } + + // Create the method function declaration + lines.add("t['" + method.getName() + "'] = function(" + TextUtils.join(", ", args) + ") {"); + + switch (returnType) { + case PluginMethod.RETURN_NONE: + lines.add( + "return w.Capacitor.nativeCallback('" + + plugin.getId() + + "', '" + + method.getName() + + "', " + + CATCHALL_OPTIONS_PARAM + + ")" + ); + break; + case PluginMethod.RETURN_PROMISE: + lines.add( + "return w.Capacitor.nativePromise('" + plugin.getId() + "', '" + method.getName() + "', " + CATCHALL_OPTIONS_PARAM + ")" + ); + break; + case PluginMethod.RETURN_CALLBACK: + lines.add( + "return w.Capacitor.nativeCallback('" + + plugin.getId() + + "', '" + + method.getName() + + "', " + + CATCHALL_OPTIONS_PARAM + + ", " + + CALLBACK_PARAM + + ")" + ); + break; + default: + // TODO: Do something here? + } + + lines.add("}"); + + return TextUtils.join("\n", lines); + } +} diff --git a/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/JSExportException.java b/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/JSExportException.java new file mode 100644 index 0000000..14b6043 --- /dev/null +++ b/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/JSExportException.java @@ -0,0 +1,16 @@ +package com.getcapacitor; + +public class JSExportException extends Exception { + + public JSExportException(String s) { + super(s); + } + + public JSExportException(Throwable t) { + super(t); + } + + public JSExportException(String s, Throwable t) { + super(s, t); + } +} diff --git a/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/JSInjector.java b/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/JSInjector.java new file mode 100644 index 0000000..1ee6aa1 --- /dev/null +++ b/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/JSInjector.java @@ -0,0 +1,127 @@ +package com.getcapacitor; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.nio.charset.StandardCharsets; + +/** + * JSInject is responsible for returning Capacitor's core + * runtime JS and any plugin JS back into HTML page responses + * to the client. + */ +class JSInjector { + + private String globalJS; + private String bridgeJS; + private String pluginJS; + private String cordovaJS; + private String cordovaPluginsJS; + private String cordovaPluginsFileJS; + private String localUrlJS; + private String miscJS; + + public JSInjector( + String globalJS, + String bridgeJS, + String pluginJS, + String cordovaJS, + String cordovaPluginsJS, + String cordovaPluginsFileJS, + String localUrlJS + ) { + this(globalJS, bridgeJS, pluginJS, cordovaJS, cordovaPluginsJS, cordovaPluginsFileJS, localUrlJS, null); + } + + public JSInjector( + String globalJS, + String bridgeJS, + String pluginJS, + String cordovaJS, + String cordovaPluginsJS, + String cordovaPluginsFileJS, + String localUrlJS, + String miscJS + ) { + this.globalJS = globalJS; + this.bridgeJS = bridgeJS; + this.pluginJS = pluginJS; + this.cordovaJS = cordovaJS; + this.cordovaPluginsJS = cordovaPluginsJS; + this.cordovaPluginsFileJS = cordovaPluginsFileJS; + this.localUrlJS = localUrlJS; + this.miscJS = miscJS; + } + + /** + * Generates injectable JS content. + * This may be used in other forms of injecting that aren't using an InputStream. + * @return + */ + public String getScriptString() { + String scriptString = + globalJS + + "\n\n" + + localUrlJS + + "\n\n" + + bridgeJS + + "\n\n" + + pluginJS + + "\n\n" + + cordovaJS + + "\n\n" + + cordovaPluginsFileJS + + "\n\n" + + cordovaPluginsJS; + + if (miscJS != null) { + scriptString += "\n\n" + miscJS; + } + + return scriptString; + } + + /** + * Given an InputStream from the web server, prepend it with + * our JS stream + * @param responseStream + * @return + */ + public InputStream getInjectedStream(InputStream responseStream) { + String js = ""; + String html = this.readAssetStream(responseStream); + + // Insert the js string at the position after or before using StringBuilder + StringBuilder modifiedHtml = new StringBuilder(html); + if (html.contains("")) { + modifiedHtml.insert(html.indexOf("") + "".length(), "\n" + js + "\n"); + html = modifiedHtml.toString(); + } else if (html.contains("")) { + modifiedHtml.insert(html.indexOf(""), "\n" + js + "\n"); + html = modifiedHtml.toString(); + } else { + Logger.error("Unable to inject Capacitor, Plugins won't work"); + } + return new ByteArrayInputStream(html.getBytes(StandardCharsets.UTF_8)); + } + + private String readAssetStream(InputStream stream) { + try { + final int bufferSize = 1024; + final char[] buffer = new char[bufferSize]; + final StringBuilder out = new StringBuilder(); + Reader in = new InputStreamReader(stream, StandardCharsets.UTF_8); + for (;;) { + int rsz = in.read(buffer, 0, buffer.length); + if (rsz < 0) break; + out.append(buffer, 0, rsz); + } + return out.toString(); + } catch (Exception e) { + Logger.error("Unable to process HTML asset file. This is a fatal error", e); + } + + return ""; + } +} diff --git a/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/JSObject.java b/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/JSObject.java new file mode 100644 index 0000000..0e98707 --- /dev/null +++ b/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/JSObject.java @@ -0,0 +1,164 @@ +package com.getcapacitor; + +import androidx.annotation.Nullable; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import org.json.JSONException; +import org.json.JSONObject; + +/** + * A wrapper around JSONObject that isn't afraid to do simple + * JSON put operations without having to throw an exception + * for every little thing jeez + */ +public class JSObject extends JSONObject { + + public JSObject() { + super(); + } + + public JSObject(String json) throws JSONException { + super(json); + } + + public JSObject(JSONObject obj, String[] names) throws JSONException { + super(obj, names); + } + + /** + * Convert a pathetic JSONObject into a JSObject + * @param obj + */ + public static JSObject fromJSONObject(JSONObject obj) throws JSONException { + Iterator keysIter = obj.keys(); + List keys = new ArrayList<>(); + while (keysIter.hasNext()) { + keys.add(keysIter.next()); + } + + return new JSObject(obj, keys.toArray(new String[keys.size()])); + } + + @Override + @Nullable + public String getString(String key) { + return getString(key, null); + } + + @Nullable + public String getString(String key, @Nullable String defaultValue) { + try { + String value = super.getString(key); + if (!super.isNull(key)) { + return value; + } + } catch (JSONException ex) {} + return defaultValue; + } + + @Nullable + public Integer getInteger(String key) { + return getInteger(key, null); + } + + @Nullable + public Integer getInteger(String key, @Nullable Integer defaultValue) { + try { + return super.getInt(key); + } catch (JSONException e) {} + return defaultValue; + } + + @Nullable + public Boolean getBoolean(String key, @Nullable Boolean defaultValue) { + try { + return super.getBoolean(key); + } catch (JSONException e) {} + return defaultValue; + } + + /** + * Fetch boolean from jsonObject + */ + @Nullable + public Boolean getBool(String key) { + return getBoolean(key, null); + } + + @Nullable + public JSObject getJSObject(String name) { + try { + return getJSObject(name, null); + } catch (JSONException e) {} + return null; + } + + @Nullable + public JSObject getJSObject(String name, @Nullable JSObject defaultValue) throws JSONException { + try { + Object obj = get(name); + if (obj instanceof JSONObject) { + Iterator keysIter = ((JSONObject) obj).keys(); + List keys = new ArrayList<>(); + while (keysIter.hasNext()) { + keys.add(keysIter.next()); + } + + return new JSObject((JSONObject) obj, keys.toArray(new String[keys.size()])); + } + } catch (JSONException ex) {} + return defaultValue; + } + + @Override + public JSObject put(String key, boolean value) { + try { + super.put(key, value); + } catch (JSONException ex) {} + return this; + } + + @Override + public JSObject put(String key, int value) { + try { + super.put(key, value); + } catch (JSONException ex) {} + return this; + } + + @Override + public JSObject put(String key, long value) { + try { + super.put(key, value); + } catch (JSONException ex) {} + return this; + } + + @Override + public JSObject put(String key, double value) { + try { + super.put(key, value); + } catch (JSONException ex) {} + return this; + } + + @Override + public JSObject put(String key, Object value) { + try { + super.put(key, value); + } catch (JSONException ex) {} + return this; + } + + public JSObject put(String key, String value) { + try { + super.put(key, value); + } catch (JSONException ex) {} + return this; + } + + public JSObject putSafe(String key, Object value) throws JSONException { + return (JSObject) super.put(key, value); + } +} diff --git a/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/JSValue.java b/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/JSValue.java new file mode 100644 index 0000000..d97ba91 --- /dev/null +++ b/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/JSValue.java @@ -0,0 +1,65 @@ +package com.getcapacitor; + +import org.json.JSONException; + +/** + * Represents a single user-data value of any type on the capacitor PluginCall object. + */ +public class JSValue { + + private final Object value; + + /** + * @param call The capacitor plugin call, used for accessing the value safely. + * @param name The name of the property to access. + */ + public JSValue(PluginCall call, String name) { + this.value = this.toValue(call, name); + } + + /** + * Returns the coerced but uncasted underlying value. + */ + public Object getValue() { + return this.value; + } + + @Override + public String toString() { + return this.getValue().toString(); + } + + /** + * Returns the underlying value as a JSObject, or throwing if it cannot. + * + * @throws JSONException If the underlying value is not a JSObject. + */ + public JSObject toJSObject() throws JSONException { + if (this.value instanceof JSObject) return (JSObject) this.value; + throw new JSONException("JSValue could not be coerced to JSObject."); + } + + /** + * Returns the underlying value as a JSArray, or throwing if it cannot. + * + * @throws JSONException If the underlying value is not a JSArray. + */ + public JSArray toJSArray() throws JSONException { + if (this.value instanceof JSArray) return (JSArray) this.value; + throw new JSONException("JSValue could not be coerced to JSArray."); + } + + /** + * Returns the underlying value this object represents, coercing it into a capacitor-friendly object if supported. + */ + private Object toValue(PluginCall call, String name) { + Object value = null; + value = call.getArray(name, null); + if (value != null) return value; + value = call.getObject(name, null); + if (value != null) return value; + value = call.getString(name, null); + if (value != null) return value; + return call.getData().opt(name); + } +} diff --git a/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/Logger.java b/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/Logger.java new file mode 100644 index 0000000..9d24fed --- /dev/null +++ b/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/Logger.java @@ -0,0 +1,103 @@ +package com.getcapacitor; + +import android.text.TextUtils; +import android.util.Log; + +public class Logger { + + public static final String LOG_TAG_CORE = "Capacitor"; + public static CapConfig config; + + private static Logger instance; + + private static Logger getInstance() { + if (instance == null) { + instance = new Logger(); + } + return instance; + } + + public static void init(CapConfig config) { + Logger.getInstance().loadConfig(config); + } + + private void loadConfig(CapConfig config) { + Logger.config = config; + } + + public static String tags(String... subtags) { + if (subtags != null && subtags.length > 0) { + return LOG_TAG_CORE + "/" + TextUtils.join("/", subtags); + } + + return LOG_TAG_CORE; + } + + public static void verbose(String message) { + verbose(LOG_TAG_CORE, message); + } + + public static void verbose(String tag, String message) { + if (!shouldLog()) { + return; + } + + Log.v(tag, message); + } + + public static void debug(String message) { + debug(LOG_TAG_CORE, message); + } + + public static void debug(String tag, String message) { + if (!shouldLog()) { + return; + } + + Log.d(tag, message); + } + + public static void info(String message) { + info(LOG_TAG_CORE, message); + } + + public static void info(String tag, String message) { + if (!shouldLog()) { + return; + } + + Log.i(tag, message); + } + + public static void warn(String message) { + warn(LOG_TAG_CORE, message); + } + + public static void warn(String tag, String message) { + if (!shouldLog()) { + return; + } + + Log.w(tag, message); + } + + public static void error(String message) { + error(LOG_TAG_CORE, message, null); + } + + public static void error(String message, Throwable e) { + error(LOG_TAG_CORE, message, e); + } + + public static void error(String tag, String message, Throwable e) { + if (!shouldLog()) { + return; + } + + Log.e(tag, message, e); + } + + public static boolean shouldLog() { + return config == null || config.isLoggingEnabled(); + } +} diff --git a/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/MessageHandler.java b/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/MessageHandler.java new file mode 100644 index 0000000..dc91c9b --- /dev/null +++ b/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/MessageHandler.java @@ -0,0 +1,157 @@ +package com.getcapacitor; + +import android.webkit.JavascriptInterface; +import android.webkit.WebView; +import androidx.webkit.JavaScriptReplyProxy; +import androidx.webkit.WebViewCompat; +import androidx.webkit.WebViewFeature; +import org.apache.cordova.PluginManager; + +/** + * MessageHandler handles messages from the WebView, dispatching them + * to plugins. + */ +public class MessageHandler { + + private Bridge bridge; + private WebView webView; + private PluginManager cordovaPluginManager; + private JavaScriptReplyProxy javaScriptReplyProxy; + + public MessageHandler(Bridge bridge, WebView webView, PluginManager cordovaPluginManager) { + this.bridge = bridge; + this.webView = webView; + this.cordovaPluginManager = cordovaPluginManager; + + if (WebViewFeature.isFeatureSupported(WebViewFeature.WEB_MESSAGE_LISTENER) && !bridge.getConfig().isUsingLegacyBridge()) { + WebViewCompat.WebMessageListener capListener = (view, message, sourceOrigin, isMainFrame, replyProxy) -> { + if (isMainFrame) { + postMessage(message.getData()); + javaScriptReplyProxy = replyProxy; + } else { + Logger.warn("Plugin execution is allowed in Main Frame only"); + } + }; + try { + WebViewCompat.addWebMessageListener(webView, "androidBridge", bridge.getAllowedOriginRules(), capListener); + } catch (Exception ex) { + webView.addJavascriptInterface(this, "androidBridge"); + } + } else { + webView.addJavascriptInterface(this, "androidBridge"); + } + } + + /** + * The main message handler that will be called from JavaScript + * to send a message to the native bridge. + * @param jsonStr + */ + @JavascriptInterface + @SuppressWarnings("unused") + public void postMessage(String jsonStr) { + try { + JSObject postData = new JSObject(jsonStr); + + String type = postData.getString("type"); + + boolean typeIsNotNull = type != null; + boolean isCordovaPlugin = typeIsNotNull && type.equals("cordova"); + boolean isJavaScriptError = typeIsNotNull && type.equals("js.error"); + + String callbackId = postData.getString("callbackId"); + + if (isCordovaPlugin) { + String service = postData.getString("service"); + String action = postData.getString("action"); + String actionArgs = postData.getString("actionArgs"); + + Logger.verbose( + Logger.tags("Plugin"), + "To native (Cordova plugin): callbackId: " + + callbackId + + ", service: " + + service + + ", action: " + + action + + ", actionArgs: " + + actionArgs + ); + + this.callCordovaPluginMethod(callbackId, service, action, actionArgs); + } else if (isJavaScriptError) { + Logger.error("JavaScript Error: " + jsonStr); + } else { + String pluginId = postData.getString("pluginId"); + String methodName = postData.getString("methodName"); + JSObject methodData = postData.getJSObject("options", new JSObject()); + + Logger.verbose( + Logger.tags("Plugin"), + "To native (Capacitor plugin): callbackId: " + callbackId + ", pluginId: " + pluginId + ", methodName: " + methodName + ); + + this.callPluginMethod(callbackId, pluginId, methodName, methodData); + } + } catch (Exception ex) { + Logger.error("Post message error:", ex); + } + } + + public void sendResponseMessage(PluginCall call, PluginResult successResult, PluginResult errorResult) { + try { + PluginResult data = new PluginResult(); + data.put("save", call.isKeptAlive()); + data.put("callbackId", call.getCallbackId()); + data.put("pluginId", call.getPluginId()); + data.put("methodName", call.getMethodName()); + + boolean pluginResultInError = errorResult != null; + if (pluginResultInError) { + data.put("success", false); + data.put("error", errorResult); + Logger.debug("Sending plugin error: " + data.toString()); + } else { + data.put("success", true); + if (successResult != null) { + data.put("data", successResult); + } + } + + boolean isValidCallbackId = !call.getCallbackId().equals(PluginCall.CALLBACK_ID_DANGLING); + if (isValidCallbackId) { + if (bridge.getConfig().isUsingLegacyBridge()) { + legacySendResponseMessage(data); + } else if (WebViewFeature.isFeatureSupported(WebViewFeature.WEB_MESSAGE_LISTENER) && javaScriptReplyProxy != null) { + javaScriptReplyProxy.postMessage(data.toString()); + } else { + legacySendResponseMessage(data); + } + } else { + bridge.getApp().fireRestoredResult(data); + } + } catch (Exception ex) { + Logger.error("sendResponseMessage: error: " + ex); + } + if (!call.isKeptAlive()) { + call.release(bridge); + } + } + + private void legacySendResponseMessage(PluginResult data) { + final String runScript = "window.Capacitor.fromNative(" + data.toString() + ")"; + final WebView webView = this.webView; + webView.post(() -> webView.evaluateJavascript(runScript, null)); + } + + private void callPluginMethod(String callbackId, String pluginId, String methodName, JSObject methodData) { + PluginCall call = new PluginCall(this, pluginId, callbackId, methodName, methodData); + bridge.callPluginMethod(pluginId, methodName, call); + } + + private void callCordovaPluginMethod(String callbackId, String service, String action, String actionArgs) { + bridge.execute(() -> { + cordovaPluginManager.exec(service, action, callbackId, actionArgs); + }); + } +} diff --git a/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/NativePlugin.java b/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/NativePlugin.java new file mode 100644 index 0000000..c430762 --- /dev/null +++ b/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/NativePlugin.java @@ -0,0 +1,37 @@ +package com.getcapacitor; + +import com.getcapacitor.annotation.CapacitorPlugin; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * Base annotation for all Plugins + * @deprecated + *

Use {@link CapacitorPlugin} instead + */ +@Retention(RetentionPolicy.RUNTIME) +@Deprecated +public @interface NativePlugin { + /** + * Request codes this plugin uses and responds to, in order to tie + * Android events back the plugin to handle + */ + int[] requestCodes() default {}; + + /** + * Permissions this plugin needs, in order to make permission requests + * easy if the plugin only needs basic permission prompting + */ + String[] permissions() default {}; + + /** + * The request code to use when automatically requesting permissions + */ + int permissionRequestCode() default 9000; + + /** + * A custom name for the plugin, otherwise uses the + * simple class name. + */ + String name() default ""; +} diff --git a/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/PermissionState.java b/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/PermissionState.java new file mode 100644 index 0000000..382cff7 --- /dev/null +++ b/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/PermissionState.java @@ -0,0 +1,31 @@ +package com.getcapacitor; + +import java.util.Locale; + +/** + * Represents the state of a permission + * + * @since 3.0.0 + */ +public enum PermissionState { + GRANTED("granted"), + DENIED("denied"), + PROMPT("prompt"), + PROMPT_WITH_RATIONALE("prompt-with-rationale"); + + private String state; + + PermissionState(String state) { + this.state = state; + } + + @Override + public String toString() { + return state; + } + + public static PermissionState byState(String state) { + state = state.toUpperCase(Locale.ROOT).replace('-', '_'); + return valueOf(state); + } +} diff --git a/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/Plugin.java b/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/Plugin.java new file mode 100644 index 0000000..19c8b8b --- /dev/null +++ b/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/Plugin.java @@ -0,0 +1,1050 @@ +package com.getcapacitor; + +import android.app.Activity; +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.content.res.Configuration; +import android.net.Uri; +import android.os.Bundle; +import androidx.activity.result.ActivityResult; +import androidx.activity.result.ActivityResultLauncher; +import androidx.activity.result.contract.ActivityResultContracts; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; +import androidx.core.app.ActivityCompat; +import com.getcapacitor.annotation.ActivityCallback; +import com.getcapacitor.annotation.CapacitorPlugin; +import com.getcapacitor.annotation.Permission; +import com.getcapacitor.annotation.PermissionCallback; +import com.getcapacitor.util.PermissionHelper; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.CopyOnWriteArrayList; +import org.json.JSONException; + +/** + * Plugin is the base class for all plugins, containing a number of + * convenient features for interacting with the {@link Bridge}, managing + * plugin permissions, tracking lifecycle events, and more. + * + * You should inherit from this class when creating new plugins, along with + * adding the {@link CapacitorPlugin} annotation to add additional required + * metadata about the Plugin + */ +public class Plugin { + + // The key we will use inside of a persisted Bundle for the JSON blob + // for a plugin call options. + private static final String BUNDLE_PERSISTED_OPTIONS_JSON_KEY = "_json"; + + // Reference to the Bridge + protected Bridge bridge; + + // Reference to the PluginHandle wrapper for this Plugin + protected PluginHandle handle; + + /** + * A way for plugins to quickly save a call that they will need to reference + * between activity/permissions starts/requests + * + * @deprecated store calls on the bridge using the methods + * {@link com.getcapacitor.Bridge#saveCall(PluginCall)}, + * {@link com.getcapacitor.Bridge#getSavedCall(String)} and + * {@link com.getcapacitor.Bridge#releaseCall(PluginCall)} + */ + @Deprecated + protected PluginCall savedLastCall; + + // Stored event listeners + private final Map> eventListeners; + + /** + * Launchers used by the plugin to handle activity results + */ + private final Map> activityLaunchers = new HashMap<>(); + + /** + * Launchers used by the plugin to handle permission results + */ + private final Map> permissionLaunchers = new HashMap<>(); + + private String lastPluginCallId; + + // Stored results of an event if an event was fired and + // no listeners were attached yet. Only stores the last value. + private final Map> retainedEventArguments; + + public Plugin() { + eventListeners = new HashMap<>(); + retainedEventArguments = new HashMap<>(); + } + + /** + * Called when the plugin has been connected to the bridge + * and is ready to start initializing. + */ + public void load() {} + + /** + * Registers activity result launchers defined on plugins, used for permission requests and + * activities started for result. + */ + void initializeActivityLaunchers() { + List pluginClassMethods = new ArrayList<>(); + for ( + Class pluginCursor = getClass(); + !pluginCursor.getName().equals(Object.class.getName()); + pluginCursor = pluginCursor.getSuperclass() + ) { + pluginClassMethods.addAll(Arrays.asList(pluginCursor.getDeclaredMethods())); + } + + for (final Method method : pluginClassMethods) { + if (method.isAnnotationPresent(ActivityCallback.class)) { + // register callbacks annotated with ActivityCallback for activity results + ActivityResultLauncher launcher = bridge.registerForActivityResult( + new ActivityResultContracts.StartActivityForResult(), + (result) -> triggerActivityCallback(method, result) + ); + + activityLaunchers.put(method.getName(), launcher); + } else if (method.isAnnotationPresent(PermissionCallback.class)) { + // register callbacks annotated with PermissionCallback for permission results + ActivityResultLauncher launcher = bridge.registerForActivityResult( + new ActivityResultContracts.RequestMultiplePermissions(), + (permissions) -> triggerPermissionCallback(method, permissions) + ); + + permissionLaunchers.put(method.getName(), launcher); + } + } + } + + private void triggerPermissionCallback(Method method, Map permissionResultMap) { + PluginCall savedCall = bridge.getPermissionCall(handle.getId()); + + // validate permissions and invoke the permission result callback + if (bridge.validatePermissions(this, savedCall, permissionResultMap)) { + try { + method.setAccessible(true); + method.invoke(this, savedCall); + } catch (IllegalAccessException | InvocationTargetException e) { + e.printStackTrace(); + } + } + } + + private void triggerActivityCallback(Method method, ActivityResult result) { + PluginCall savedCall = bridge.getSavedCall(lastPluginCallId); + if (savedCall == null) { + savedCall = bridge.getPluginCallForLastActivity(); + } + // invoke the activity result callback + try { + method.setAccessible(true); + method.invoke(this, savedCall, result); + } catch (IllegalAccessException | InvocationTargetException e) { + e.printStackTrace(); + } + } + + /** + * Start activity for result with the provided Intent and resolve with the provided callback method name. + *

+ * If there is no registered activity callback for the method name passed in, the call will + * be rejected. Make sure a valid activity result callback method is registered using the + * {@link ActivityCallback} annotation. + * + * @param call the plugin call + * @param intent the intent used to start an activity + * @param callbackName the name of the callback to run when the launched activity is finished + * @since 3.0.0 + */ + public void startActivityForResult(PluginCall call, Intent intent, String callbackName) { + ActivityResultLauncher activityResultLauncher = getActivityLauncherOrReject(call, callbackName); + if (activityResultLauncher == null) { + // return when null since call was rejected in getLauncherOrReject + return; + } + bridge.setPluginCallForLastActivity(call); + lastPluginCallId = call.getCallbackId(); + bridge.saveCall(call); + activityResultLauncher.launch(intent); + } + + private void permissionActivityResult(PluginCall call, String[] permissionStrings, String callbackName) { + ActivityResultLauncher permissionResultLauncher = getPermissionLauncherOrReject(call, callbackName); + if (permissionResultLauncher == null) { + // return when null since call was rejected in getLauncherOrReject + return; + } + + bridge.savePermissionCall(call); + permissionResultLauncher.launch(permissionStrings); + } + + /** + * Get the main {@link Context} for the current Activity (your app) + * @return the Context for the current activity + */ + public Context getContext() { + return this.bridge.getContext(); + } + + /** + * Get the main {@link Activity} for the app + * @return the Activity for the current app + */ + public AppCompatActivity getActivity() { + return this.bridge.getActivity(); + } + + /** + * Set the Bridge instance for this plugin + * @param bridge + */ + public void setBridge(Bridge bridge) { + this.bridge = bridge; + } + + /** + * Get the Bridge instance for this plugin + */ + public Bridge getBridge() { + return this.bridge; + } + + /** + * Set the wrapper {@link PluginHandle} instance for this plugin that + * contains additional metadata about the Plugin instance (such + * as indexed methods for reflection, and {@link CapacitorPlugin} annotation data). + * @param pluginHandle + */ + public void setPluginHandle(PluginHandle pluginHandle) { + this.handle = pluginHandle; + } + + /** + * Return the wrapper {@link PluginHandle} for this plugin. + * + * This wrapper contains additional metadata about the plugin instance, + * such as indexed methods for reflection, and {@link CapacitorPlugin} annotation data). + * @return + */ + public PluginHandle getPluginHandle() { + return this.handle; + } + + /** + * Get the root App ID + * @return + */ + public String getAppId() { + return getContext().getPackageName(); + } + + /** + * Called to save a {@link PluginCall} in order to reference it + * later, such as in an activity or permissions result handler + * @deprecated use {@link Bridge#saveCall(PluginCall)} + * + * @param lastCall + */ + @Deprecated + public void saveCall(PluginCall lastCall) { + this.savedLastCall = lastCall; + } + + /** + * Set the last saved call to null to free memory + * @deprecated use {@link PluginCall#release(Bridge)} + */ + @Deprecated + public void freeSavedCall() { + this.savedLastCall.release(bridge); + this.savedLastCall = null; + } + + /** + * Get the last saved call, if any + * @deprecated use {@link Bridge#getSavedCall(String)} + * + * @return + */ + @Deprecated + public PluginCall getSavedCall() { + return this.savedLastCall; + } + + /** + * Get the config options for this plugin. + * + * @return a config object representing the plugin config options, or an empty config + * if none exists + */ + public PluginConfig getConfig() { + return bridge.getConfig().getPluginConfiguration(handle.getId()); + } + + /** + * Get the value for a key on the config for this plugin. + * @deprecated use {@link #getConfig()} and access config values using the methods available + * depending on the type. + * + * @param key the key for the config value + * @return some object containing the value from the config + */ + @Deprecated + public Object getConfigValue(String key) { + try { + PluginConfig pluginConfig = getConfig(); + return pluginConfig.getConfigJSON().get(key); + } catch (JSONException ex) { + return null; + } + } + + /** + * Check whether any of the given permissions has been defined in the AndroidManifest.xml + * @deprecated use {@link #isPermissionDeclared(String)} + * + * @param permissions + * @return + */ + @Deprecated + public boolean hasDefinedPermissions(String[] permissions) { + for (String permission : permissions) { + if (!PermissionHelper.hasDefinedPermission(getContext(), permission)) { + return false; + } + } + return true; + } + + /** + * Check if all annotated permissions have been defined in the AndroidManifest.xml + * @deprecated use {@link #isPermissionDeclared(String)} + * + * @return true if permissions are all defined in the Manifest + */ + @Deprecated + public boolean hasDefinedRequiredPermissions() { + CapacitorPlugin annotation = handle.getPluginAnnotation(); + if (annotation == null) { + // Check for legacy plugin annotation, @NativePlugin + NativePlugin legacyAnnotation = handle.getLegacyPluginAnnotation(); + return hasDefinedPermissions(legacyAnnotation.permissions()); + } else { + for (Permission perm : annotation.permissions()) { + for (String permString : perm.strings()) { + if (!PermissionHelper.hasDefinedPermission(getContext(), permString)) { + return false; + } + } + } + } + + return true; + } + + /** + * Checks if the given permission alias is correctly declared in AndroidManifest.xml + * @param alias a permission alias defined on the plugin + * @return true only if all permissions associated with the given alias are declared in the manifest + */ + public boolean isPermissionDeclared(String alias) { + CapacitorPlugin annotation = handle.getPluginAnnotation(); + if (annotation != null) { + for (Permission perm : annotation.permissions()) { + if (alias.equalsIgnoreCase(perm.alias())) { + boolean result = true; + for (String permString : perm.strings()) { + result = result && PermissionHelper.hasDefinedPermission(getContext(), permString); + } + + return result; + } + } + } + + Logger.error(String.format("isPermissionDeclared: No alias defined for %s " + "or missing @CapacitorPlugin annotation.", alias)); + return false; + } + + /** + * Check whether the given permission has been granted by the user + * @deprecated use {@link #getPermissionState(String)} and {@link #getPermissionStates()} to get + * the states of permissions defined on the Plugin in conjunction with the @CapacitorPlugin + * annotation. Use the Android API {@link ActivityCompat#checkSelfPermission(Context, String)} + * methods to check permissions with Android permission strings + * + * @param permission + * @return + */ + @Deprecated + public boolean hasPermission(String permission) { + return ActivityCompat.checkSelfPermission(this.getContext(), permission) == PackageManager.PERMISSION_GRANTED; + } + + /** + * If the plugin annotation specified a set of permissions, this method checks if each is + * granted + * @deprecated use {@link #getPermissionState(String)} or {@link #getPermissionStates()} to + * check whether permissions are granted or not + * + * @return + */ + @Deprecated + public boolean hasRequiredPermissions() { + CapacitorPlugin annotation = handle.getPluginAnnotation(); + if (annotation == null) { + // Check for legacy plugin annotation, @NativePlugin + NativePlugin legacyAnnotation = handle.getLegacyPluginAnnotation(); + for (String perm : legacyAnnotation.permissions()) { + if (ActivityCompat.checkSelfPermission(this.getContext(), perm) != PackageManager.PERMISSION_GRANTED) { + return false; + } + } + + return true; + } + + for (Permission perm : annotation.permissions()) { + for (String permString : perm.strings()) { + if (ActivityCompat.checkSelfPermission(this.getContext(), permString) != PackageManager.PERMISSION_GRANTED) { + return false; + } + } + } + + return true; + } + + /** + * Request all of the specified permissions in the CapacitorPlugin annotation (if any) + * + * If there is no registered permission callback for the PluginCall passed in, the call will + * be rejected. Make sure a valid permission callback method is registered using the + * {@link PermissionCallback} annotation. + * + * @since 3.0.0 + * @param call the plugin call + * @param callbackName the name of the callback to run when the permission request is complete + */ + protected void requestAllPermissions(@NonNull PluginCall call, @NonNull String callbackName) { + CapacitorPlugin annotation = handle.getPluginAnnotation(); + if (annotation != null) { + HashSet perms = new HashSet<>(); + for (Permission perm : annotation.permissions()) { + perms.addAll(Arrays.asList(perm.strings())); + } + + permissionActivityResult(call, perms.toArray(new String[0]), callbackName); + } + } + + /** + * Request permissions using an alias defined on the plugin. + * + * If there is no registered permission callback for the PluginCall passed in, the call will + * be rejected. Make sure a valid permission callback method is registered using the + * {@link PermissionCallback} annotation. + * + * @param alias an alias defined on the plugin + * @param call the plugin call involved in originating the request + * @param callbackName the name of the callback to run when the permission request is complete + */ + protected void requestPermissionForAlias(@NonNull String alias, @NonNull PluginCall call, @NonNull String callbackName) { + requestPermissionForAliases(new String[] { alias }, call, callbackName); + } + + /** + * Request permissions using aliases defined on the plugin. + * + * If there is no registered permission callback for the PluginCall passed in, the call will + * be rejected. Make sure a valid permission callback method is registered using the + * {@link PermissionCallback} annotation. + * + * @param aliases a set of aliases defined on the plugin + * @param call the plugin call involved in originating the request + * @param callbackName the name of the callback to run when the permission request is complete + */ + protected void requestPermissionForAliases(@NonNull String[] aliases, @NonNull PluginCall call, @NonNull String callbackName) { + if (aliases.length == 0) { + Logger.error("No permission alias was provided"); + return; + } + + String[] permissions = getPermissionStringsForAliases(aliases); + + if (permissions.length > 0) { + permissionActivityResult(call, permissions, callbackName); + } + } + + /** + * Gets the Android permission strings defined on the {@link CapacitorPlugin} annotation with + * the provided aliases. + * + * @param aliases aliases for permissions defined on the plugin + * @return Android permission strings associated with the provided aliases, if exists + */ + private String[] getPermissionStringsForAliases(@NonNull String[] aliases) { + CapacitorPlugin annotation = handle.getPluginAnnotation(); + HashSet perms = new HashSet<>(); + for (Permission perm : annotation.permissions()) { + if (Arrays.asList(aliases).contains(perm.alias())) { + perms.addAll(Arrays.asList(perm.strings())); + } + } + + return perms.toArray(new String[0]); + } + + /** + * Gets the activity launcher associated with the calling methodName, or rejects the call if + * no registered launcher exists + * + * @param call the plugin call + * @param methodName the name of the activity callback method + * @return a launcher, or null if none found + */ + private @Nullable ActivityResultLauncher getActivityLauncherOrReject(PluginCall call, String methodName) { + ActivityResultLauncher activityLauncher = activityLaunchers.get(methodName); + + // if there is no registered launcher, reject the call with an error and return null + if (activityLauncher == null) { + String registerError = + "There is no ActivityCallback method registered for the name: %s. " + + "Please define a callback method annotated with @ActivityCallback " + + "that receives arguments: (PluginCall, ActivityResult)"; + registerError = String.format(Locale.US, registerError, methodName); + Logger.error(registerError); + call.reject(registerError); + return null; + } + + return activityLauncher; + } + + /** + * Gets the permission launcher associated with the calling methodName, or rejects the call if + * no registered launcher exists + * + * @param call the plugin call + * @param methodName the name of the permission callback method + * @return a launcher, or null if none found + */ + private @Nullable ActivityResultLauncher getPermissionLauncherOrReject(PluginCall call, String methodName) { + ActivityResultLauncher permissionLauncher = permissionLaunchers.get(methodName); + + // if there is no registered launcher, reject the call with an error and return null + if (permissionLauncher == null) { + String registerError = + "There is no PermissionCallback method registered for the name: %s. " + + "Please define a callback method annotated with @PermissionCallback " + + "that receives arguments: (PluginCall)"; + registerError = String.format(Locale.US, registerError, methodName); + Logger.error(registerError); + call.reject(registerError); + return null; + } + + return permissionLauncher; + } + + /** + * Request all of the specified permissions in the CapacitorPlugin annotation (if any) + * + * @deprecated use {@link #requestAllPermissions(PluginCall, String)} in conjunction with @CapacitorPlugin + */ + @Deprecated + public void pluginRequestAllPermissions() { + NativePlugin legacyAnnotation = handle.getLegacyPluginAnnotation(); + ActivityCompat.requestPermissions(getActivity(), legacyAnnotation.permissions(), legacyAnnotation.permissionRequestCode()); + } + + /** + * Helper for requesting a specific permission + * + * @param permission the permission to request + * @param requestCode the requestCode to use to associate the result with the plugin + * @deprecated use {@link #requestPermissionForAlias(String, PluginCall, String)} in conjunction with @CapacitorPlugin + */ + @Deprecated + public void pluginRequestPermission(String permission, int requestCode) { + ActivityCompat.requestPermissions(getActivity(), new String[] { permission }, requestCode); + } + + /** + * Helper for requesting specific permissions + * @deprecated use {@link #requestPermissionForAliases(String[], PluginCall, String)} in conjunction + * with @CapacitorPlugin + * + * @param permissions the set of permissions to request + * @param requestCode the requestCode to use to associate the result with the plugin + */ + @Deprecated + public void pluginRequestPermissions(String[] permissions, int requestCode) { + ActivityCompat.requestPermissions(getActivity(), permissions, requestCode); + } + + /** + * Get the permission state for the provided permission alias. + * + * @param alias the permission alias to get + * @return the state of the provided permission alias or null + */ + public PermissionState getPermissionState(String alias) { + return getPermissionStates().get(alias); + } + + /** + * Helper to check all permissions defined on a plugin and see the state of each. + * + * @since 3.0.0 + * @return A mapping of permission aliases to the associated granted status. + */ + public Map getPermissionStates() { + return bridge.getPermissionStates(this); + } + + /** + * Add a listener for the given event + * @param eventName + * @param call + */ + private void addEventListener(String eventName, PluginCall call) { + List listeners = eventListeners.get(eventName); + if (listeners == null || listeners.isEmpty()) { + listeners = new ArrayList<>(); + eventListeners.put(eventName, listeners); + + // Must add the call before sending retained arguments + listeners.add(call); + + sendRetainedArgumentsForEvent(eventName); + } else { + listeners.add(call); + } + } + + /** + * Remove a listener from the given event + * @param eventName + * @param call + */ + private void removeEventListener(String eventName, PluginCall call) { + List listeners = eventListeners.get(eventName); + if (listeners == null) { + return; + } + + listeners.remove(call); + } + + /** + * Notify all listeners that an event occurred + * @param eventName + * @param data + */ + protected void notifyListeners(String eventName, JSObject data, boolean retainUntilConsumed) { + Logger.verbose(getLogTag(), "Notifying listeners for event " + eventName); + List listeners = eventListeners.get(eventName); + if (listeners == null || listeners.isEmpty()) { + Logger.debug(getLogTag(), "No listeners found for event " + eventName); + if (retainUntilConsumed) { + List argList = retainedEventArguments.get(eventName); + + if (argList == null) { + argList = new ArrayList(); + } + + argList.add(data); + retainedEventArguments.put(eventName, argList); + } + return; + } + + CopyOnWriteArrayList listenersCopy = new CopyOnWriteArrayList(listeners); + for (PluginCall call : listenersCopy) { + call.resolve(data); + } + } + + /** + * Notify all listeners that an event occurred + * This calls {@link Plugin#notifyListeners(String, JSObject, boolean)} + * with retainUntilConsumed set to false + * @param eventName + * @param data + */ + protected void notifyListeners(String eventName, JSObject data) { + notifyListeners(eventName, data, false); + } + + /** + * Check if there are any listeners for the given event + */ + protected boolean hasListeners(String eventName) { + List listeners = eventListeners.get(eventName); + if (listeners == null) { + return false; + } + return !listeners.isEmpty(); + } + + /** + * Send retained arguments (if any) for this event. This + * is called only when the first listener for an event is added + * @param eventName + */ + private void sendRetainedArgumentsForEvent(String eventName) { + // copy retained args and null source to prevent potential race conditions + List retainedArgs = retainedEventArguments.get(eventName); + if (retainedArgs == null) { + return; + } + + retainedEventArguments.remove(eventName); + + for (JSObject retained : retainedArgs) { + notifyListeners(eventName, retained); + } + } + + /** + * Exported plugin call for adding a listener to this plugin + * @param call + */ + @SuppressWarnings("unused") + @PluginMethod(returnType = PluginMethod.RETURN_NONE) + public void addListener(PluginCall call) { + String eventName = call.getString("eventName"); + call.setKeepAlive(true); + addEventListener(eventName, call); + } + + /** + * Exported plugin call to remove a listener from this plugin + * @param call + */ + @SuppressWarnings("unused") + @PluginMethod(returnType = PluginMethod.RETURN_NONE) + public void removeListener(PluginCall call) { + String eventName = call.getString("eventName"); + String callbackId = call.getString("callbackId"); + PluginCall savedCall = bridge.getSavedCall(callbackId); + if (savedCall != null) { + removeEventListener(eventName, savedCall); + bridge.releaseCall(savedCall); + } + } + + /** + * Exported plugin call to remove all listeners from this plugin + * @param call + */ + @SuppressWarnings("unused") + @PluginMethod(returnType = PluginMethod.RETURN_PROMISE) + public void removeAllListeners(PluginCall call) { + eventListeners.clear(); + call.resolve(); + } + + public void removeAllListeners() { + eventListeners.clear(); + } + + /** + * Exported plugin call for checking the granted status for each permission + * declared on the plugin. This plugin call responds with a mapping of permissions to + * the associated granted status. + * + * @since 3.0.0 + */ + @PluginMethod + @PermissionCallback + public void checkPermissions(PluginCall pluginCall) { + Map permissionsResult = getPermissionStates(); + + if (permissionsResult.size() == 0) { + // if no permissions are defined on the plugin, resolve undefined + pluginCall.resolve(); + } else { + JSObject permissionsResultJSON = new JSObject(); + for (Map.Entry entry : permissionsResult.entrySet()) { + permissionsResultJSON.put(entry.getKey(), entry.getValue()); + } + + pluginCall.resolve(permissionsResultJSON); + } + } + + /** + * Exported plugin call to request all permissions for this plugin. + * To manually request permissions within a plugin use: + * {@link #requestAllPermissions(PluginCall, String)}, or + * {@link #requestPermissionForAlias(String, PluginCall, String)}, or + * {@link #requestPermissionForAliases(String[], PluginCall, String)} + * + * @param call the plugin call + */ + @PluginMethod + public void requestPermissions(PluginCall call) { + CapacitorPlugin annotation = handle.getPluginAnnotation(); + if (annotation == null) { + handleLegacyPermission(call); + } else { + // handle permission requests for plugins defined with @CapacitorPlugin (since 3.0.0) + String[] permAliases = null; + Set autoGrantPerms = new HashSet<>(); + + // If call was made with a list of specific permission aliases to request, save them + // to be requested + JSArray providedPerms = call.getArray("permissions"); + List providedPermsList = null; + + if (providedPerms != null) { + try { + providedPermsList = providedPerms.toList(); + } catch (JSONException ignore) { + // do nothing + } + } + + // If call was made without any custom permissions, request all from plugin annotation + Set aliasSet = new HashSet<>(); + if (providedPermsList == null || providedPermsList.isEmpty()) { + for (Permission perm : annotation.permissions()) { + // If a permission is defined with no permission strings, separate it for auto-granting. + // Otherwise, the alias is added to the list to be requested. + if (perm.strings().length == 0 || (perm.strings().length == 1 && perm.strings()[0].isEmpty())) { + if (!perm.alias().isEmpty()) { + autoGrantPerms.add(perm.alias()); + } + } else { + aliasSet.add(perm.alias()); + } + } + + permAliases = aliasSet.toArray(new String[0]); + } else { + for (Permission perm : annotation.permissions()) { + if (providedPermsList.contains(perm.alias())) { + aliasSet.add(perm.alias()); + } + } + + if (aliasSet.isEmpty()) { + call.reject("No valid permission alias was requested of this plugin."); + } else { + permAliases = aliasSet.toArray(new String[0]); + } + } + + if (permAliases != null && permAliases.length > 0) { + // request permissions using provided aliases or all defined on the plugin + requestPermissionForAliases(permAliases, call, "checkPermissions"); + } else if (!autoGrantPerms.isEmpty()) { + // if the plugin only has auto-grant permissions, return all as GRANTED + JSObject permissionsResults = new JSObject(); + + for (String perm : autoGrantPerms) { + permissionsResults.put(perm, PermissionState.GRANTED.toString()); + } + + call.resolve(permissionsResults); + } else { + // no permissions are defined on the plugin, resolve undefined + call.resolve(); + } + } + } + + @SuppressWarnings("deprecation") + private void handleLegacyPermission(PluginCall call) { + // handle permission requests for plugins defined with @NativePlugin (prior to 3.0.0) + NativePlugin legacyAnnotation = this.handle.getLegacyPluginAnnotation(); + String[] perms = legacyAnnotation.permissions(); + if (perms.length > 0) { + saveCall(call); + pluginRequestPermissions(perms, legacyAnnotation.permissionRequestCode()); + } else { + call.resolve(); + } + } + + /** + * Handle request permissions result. A plugin using the deprecated {@link NativePlugin} + * should override this to handle the result, or this method will handle the result + * for our convenient requestPermissions call. + * @deprecated in favor of using callbacks in conjunction with {@link CapacitorPlugin} + * + * @param requestCode + * @param permissions + * @param grantResults + */ + @Deprecated + protected void handleRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { + if (!hasDefinedPermissions(permissions)) { + StringBuilder builder = new StringBuilder(); + builder.append("Missing the following permissions in AndroidManifest.xml:\n"); + String[] missing = PermissionHelper.getUndefinedPermissions(getContext(), permissions); + for (String perm : missing) { + builder.append(perm + "\n"); + } + savedLastCall.reject(builder.toString()); + savedLastCall = null; + } + } + + /** + * Called before the app is destroyed to give a plugin the chance to + * save the last call options for a saved plugin. By default, this + * method saves the full JSON blob of the options call. Since Bundle sizes + * may be limited, plugins that expect to be called with large data + * objects (such as a file), should override this method and selectively + * store option values in a {@link Bundle} to avoid exceeding limits. + * @return a new {@link Bundle} with fields set from the options of the last saved {@link PluginCall} + */ + protected Bundle saveInstanceState() { + PluginCall savedCall = bridge.getSavedCall(lastPluginCallId); + + if (savedCall == null) { + return null; + } + + Bundle ret = new Bundle(); + JSObject callData = savedCall.getData(); + + if (callData != null) { + ret.putString(BUNDLE_PERSISTED_OPTIONS_JSON_KEY, callData.toString()); + } + + return ret; + } + + /** + * Called when the app is opened with a previously un-handled + * activity response. If the plugin that started the activity + * stored data in {@link Plugin#saveInstanceState()} then this + * method will be called to allow the plugin to restore from that. + * @param state + */ + protected void restoreState(Bundle state) {} + + /** + * Handle activity result, should be overridden by each plugin + * + * @deprecated provide a callback method using the {@link ActivityCallback} annotation and use + * the {@link #startActivityForResult(PluginCall, Intent, String)} method + * + * @param requestCode + * @param resultCode + * @param data + */ + @Deprecated + protected void handleOnActivityResult(int requestCode, int resultCode, Intent data) {} + + /** + * Handle onNewIntent + * @param intent + */ + protected void handleOnNewIntent(Intent intent) {} + + /** + * Handle onConfigurationChanged + * @param newConfig + */ + protected void handleOnConfigurationChanged(Configuration newConfig) {} + + /** + * Handle onStart + */ + protected void handleOnStart() {} + + /** + * Handle onRestart + */ + protected void handleOnRestart() {} + + /** + * Handle onResume + */ + protected void handleOnResume() {} + + /** + * Handle onPause + */ + protected void handleOnPause() {} + + /** + * Handle onStop + */ + protected void handleOnStop() {} + + /** + * Handle onDestroy + */ + protected void handleOnDestroy() {} + + /** + * Give the plugins a chance to take control when a URL is about to be loaded in the WebView. + * Returning true causes the WebView to abort loading the URL. + * Returning false causes the WebView to continue loading the URL. + * Returning null will defer to the default Capacitor policy + */ + @SuppressWarnings("unused") + public Boolean shouldOverrideLoad(Uri url) { + return null; + } + + /** + * Start a new Activity. + * + * Note: This method must be used by all plugins instead of calling + * {@link Activity#startActivityForResult} as it associates the plugin with + * any resulting data from the new Activity even if this app + * is destroyed by the OS (to free up memory, for example). + * @param intent + * @param resultCode + */ + @Deprecated + protected void startActivityForResult(PluginCall call, Intent intent, int resultCode) { + bridge.startActivityForPluginWithResult(call, intent, resultCode); + } + + /** + * Execute the given runnable on the Bridge's task handler + * @param runnable + */ + public void execute(Runnable runnable) { + bridge.execute(runnable); + } + + /** + * Shortcut for getting the plugin log tag + * @param subTags + */ + protected String getLogTag(String... subTags) { + return Logger.tags(subTags); + } + + /** + * Gets a plugin log tag with the child's class name as subTag. + */ + protected String getLogTag() { + return Logger.tags(this.getClass().getSimpleName()); + } +} diff --git a/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/PluginCall.java b/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/PluginCall.java new file mode 100644 index 0000000..7308f07 --- /dev/null +++ b/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/PluginCall.java @@ -0,0 +1,394 @@ +package com.getcapacitor; + +import androidx.annotation.Nullable; +import java.util.ArrayList; +import java.util.List; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +/** + * Wraps a call from the web layer to native + */ +public class PluginCall { + + /** + * A special callback id that indicates there is no matching callback + * on the client to associate any PluginCall results back to. This is used + * in the case of an app resuming with saved instance data, for example. + */ + public static final String CALLBACK_ID_DANGLING = "-1"; + + private final MessageHandler msgHandler; + private final String pluginId; + private final String callbackId; + private final String methodName; + private final JSObject data; + + private boolean keepAlive = false; + + /** + * Indicates that this PluginCall was released, and should no longer be used + */ + @Deprecated + private boolean isReleased = false; + + public PluginCall(MessageHandler msgHandler, String pluginId, String callbackId, String methodName, JSObject data) { + this.msgHandler = msgHandler; + this.pluginId = pluginId; + this.callbackId = callbackId; + this.methodName = methodName; + this.data = data; + } + + public void successCallback(PluginResult successResult) { + if (CALLBACK_ID_DANGLING.equals(this.callbackId)) { + // don't send back response if the callbackId was "-1" + return; + } + + this.msgHandler.sendResponseMessage(this, successResult, null); + } + + public void resolve(JSObject data) { + PluginResult result = new PluginResult(data); + this.msgHandler.sendResponseMessage(this, result, null); + } + + public void resolve() { + this.msgHandler.sendResponseMessage(this, null, null); + } + + public void errorCallback(String msg) { + PluginResult errorResult = new PluginResult(); + + try { + errorResult.put("message", msg); + } catch (Exception jsonEx) { + Logger.error(Logger.tags("Plugin"), jsonEx.toString(), null); + } + + this.msgHandler.sendResponseMessage(this, null, errorResult); + } + + public void reject(String msg, String code, Exception ex, JSObject data) { + PluginResult errorResult = new PluginResult(); + + if (ex != null) { + Logger.error(Logger.tags("Plugin"), msg, ex); + } + + try { + errorResult.put("message", msg); + errorResult.put("code", code); + if (null != data) { + errorResult.put("data", data); + } + } catch (Exception jsonEx) { + Logger.error(Logger.tags("Plugin"), jsonEx.getMessage(), jsonEx); + } + + this.msgHandler.sendResponseMessage(this, null, errorResult); + } + + public void reject(String msg, Exception ex, JSObject data) { + reject(msg, null, ex, data); + } + + public void reject(String msg, String code, JSObject data) { + reject(msg, code, null, data); + } + + public void reject(String msg, String code, Exception ex) { + reject(msg, code, ex, null); + } + + public void reject(String msg, JSObject data) { + reject(msg, null, null, data); + } + + public void reject(String msg, Exception ex) { + reject(msg, null, ex, null); + } + + public void reject(String msg, String code) { + reject(msg, code, null, null); + } + + public void reject(String msg) { + reject(msg, null, null, null); + } + + public void unimplemented() { + unimplemented("not implemented"); + } + + public void unimplemented(String msg) { + reject(msg, "UNIMPLEMENTED", null, null); + } + + public void unavailable() { + unavailable("not available"); + } + + public void unavailable(String msg) { + reject(msg, "UNAVAILABLE", null, null); + } + + public String getPluginId() { + return this.pluginId; + } + + public String getCallbackId() { + return this.callbackId; + } + + public String getMethodName() { + return this.methodName; + } + + public JSObject getData() { + return this.data; + } + + @Nullable + public String getString(String name) { + return this.getString(name, null); + } + + @Nullable + public String getString(String name, @Nullable String defaultValue) { + Object value = this.data.opt(name); + if (value == null) { + return defaultValue; + } + + if (value instanceof String) { + return (String) value; + } + return defaultValue; + } + + @Nullable + public Integer getInt(String name) { + return this.getInt(name, null); + } + + @Nullable + public Integer getInt(String name, @Nullable Integer defaultValue) { + Object value = this.data.opt(name); + if (value == null) { + return defaultValue; + } + + if (value instanceof Integer) { + return (Integer) value; + } + return defaultValue; + } + + @Nullable + public Long getLong(String name) { + return this.getLong(name, null); + } + + @Nullable + public Long getLong(String name, @Nullable Long defaultValue) { + Object value = this.data.opt(name); + if (value == null) { + return defaultValue; + } + + if (value instanceof Long) { + return (Long) value; + } + return defaultValue; + } + + @Nullable + public Float getFloat(String name) { + return this.getFloat(name, null); + } + + @Nullable + public Float getFloat(String name, @Nullable Float defaultValue) { + Object value = this.data.opt(name); + if (value == null) { + return defaultValue; + } + + if (value instanceof Float) { + return (Float) value; + } + if (value instanceof Double) { + return ((Double) value).floatValue(); + } + if (value instanceof Integer) { + return ((Integer) value).floatValue(); + } + return defaultValue; + } + + @Nullable + public Double getDouble(String name) { + return this.getDouble(name, null); + } + + @Nullable + public Double getDouble(String name, @Nullable Double defaultValue) { + Object value = this.data.opt(name); + if (value == null) { + return defaultValue; + } + + if (value instanceof Double) { + return (Double) value; + } + if (value instanceof Float) { + return ((Float) value).doubleValue(); + } + if (value instanceof Integer) { + return ((Integer) value).doubleValue(); + } + return defaultValue; + } + + @Nullable + public Boolean getBoolean(String name) { + return this.getBoolean(name, null); + } + + @Nullable + public Boolean getBoolean(String name, @Nullable Boolean defaultValue) { + Object value = this.data.opt(name); + if (value == null) { + return defaultValue; + } + + if (value instanceof Boolean) { + return (Boolean) value; + } + return defaultValue; + } + + public JSObject getObject(String name) { + return this.getObject(name, null); + } + + @Nullable + public JSObject getObject(String name, JSObject defaultValue) { + Object value = this.data.opt(name); + if (value == null) { + return defaultValue; + } + + if (value instanceof JSONObject) { + try { + return JSObject.fromJSONObject((JSONObject) value); + } catch (JSONException ex) { + return defaultValue; + } + } + return defaultValue; + } + + public JSArray getArray(String name) { + return this.getArray(name, null); + } + + /** + * Get a JSONArray and turn it into a JSArray + * @param name + * @param defaultValue + * @return + */ + @Nullable + public JSArray getArray(String name, JSArray defaultValue) { + Object value = this.data.opt(name); + if (value == null) { + return defaultValue; + } + + if (value instanceof JSONArray) { + try { + JSONArray valueArray = (JSONArray) value; + List items = new ArrayList<>(); + for (int i = 0; i < valueArray.length(); i++) { + items.add(valueArray.get(i)); + } + return new JSArray(items.toArray()); + } catch (JSONException ex) { + return defaultValue; + } + } + return defaultValue; + } + + /** + * @param name of the option to check + * @return boolean indicating if the plugin call has an option for the provided name. + * @deprecated Presence of a key should not be considered significant. + * Use typed accessors to check the value instead. + */ + @Deprecated + public boolean hasOption(String name) { + return this.data.has(name); + } + + /** + * Indicate that the Bridge should cache this call in order to call + * it again later. For example, the addListener system uses this to + * continuously call the call's callback (😆). + * @deprecated use {@link #setKeepAlive(Boolean)} instead + */ + @Deprecated + public void save() { + setKeepAlive(true); + } + + /** + * Indicate that the Bridge should cache this call in order to call + * it again later. For example, the addListener system uses this to + * continuously call the call's callback. + * + * @param keepAlive whether to keep the callback saved + */ + public void setKeepAlive(Boolean keepAlive) { + this.keepAlive = keepAlive; + } + + public void release(Bridge bridge) { + this.keepAlive = false; + bridge.releaseCall(this); + this.isReleased = true; + } + + /** + * @deprecated use {@link #isKeptAlive()} + * @return true if the plugin call is kept alive + */ + @Deprecated + public boolean isSaved() { + return isKeptAlive(); + } + + /** + * Gets the keepAlive value of the plugin call + * @return true if the plugin call is kept alive + */ + public boolean isKeptAlive() { + return keepAlive; + } + + @Deprecated + public boolean isReleased() { + return isReleased; + } + + class PluginCallDataTypeException extends Exception { + + PluginCallDataTypeException(String m) { + super(m); + } + } +} diff --git a/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/PluginConfig.java b/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/PluginConfig.java new file mode 100644 index 0000000..0f00fc5 --- /dev/null +++ b/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/PluginConfig.java @@ -0,0 +1,116 @@ +package com.getcapacitor; + +import com.getcapacitor.util.JSONUtils; +import org.json.JSONObject; + +/** + * Represents the configuration options for plugins used by Capacitor + */ +public class PluginConfig { + + /** + * The object containing plugin config values. + */ + private final JSONObject config; + + /** + * Constructs a PluginsConfig with the provided JSONObject value. + * + * @param config A plugin configuration expressed as a JSON Object + */ + PluginConfig(JSONObject config) { + this.config = config; + } + + /** + * Get a string value for a plugin in the Capacitor config. + * + * @param configKey The key of the value to retrieve + * @return The value from the config, if exists. Null if not + */ + public String getString(String configKey) { + return getString(configKey, null); + } + + /** + * Get a string value for a plugin in the Capacitor config. + * + * @param configKey The key of the value to retrieve + * @param defaultValue A default value to return if the key does not exist in the config + * @return The value from the config, if key exists. Default value returned if not + */ + public String getString(String configKey, String defaultValue) { + return JSONUtils.getString(config, configKey, defaultValue); + } + + /** + * Get a boolean value for a plugin in the Capacitor config. + * + * @param configKey The key of the value to retrieve + * @param defaultValue A default value to return if the key does not exist in the config + * @return The value from the config, if key exists. Default value returned if not + */ + public boolean getBoolean(String configKey, boolean defaultValue) { + return JSONUtils.getBoolean(config, configKey, defaultValue); + } + + /** + * Get an integer value for a plugin in the Capacitor config. + * + * @param configKey The key of the value to retrieve + * @param defaultValue A default value to return if the key does not exist in the config + * @return The value from the config, if key exists. Default value returned if not + */ + public int getInt(String configKey, int defaultValue) { + return JSONUtils.getInt(config, configKey, defaultValue); + } + + /** + * Get a string array value for a plugin in the Capacitor config. + * + * @param configKey The key of the value to retrieve + * @return The value from the config, if exists. Null if not + */ + public String[] getArray(String configKey) { + return getArray(configKey, null); + } + + /** + * Get a string array value for a plugin in the Capacitor config. + * + * @param configKey The key of the value to retrieve + * @param defaultValue A default value to return if the key does not exist in the config + * @return The value from the config, if key exists. Default value returned if not + */ + public String[] getArray(String configKey, String[] defaultValue) { + return JSONUtils.getArray(config, configKey, defaultValue); + } + + /** + * Get a JSON object value for a plugin in the Capacitor config. + * + * @param configKey The key of the value to retrieve + * @return The value from the config, if exists. Null if not + */ + public JSONObject getObject(String configKey) { + return JSONUtils.getObject(config, configKey); + } + + /** + * Check if the PluginConfig is empty. + * + * @return true if the plugin config has no entries + */ + public boolean isEmpty() { + return config.length() == 0; + } + + /** + * Gets the JSON Object containing the config of the the provided plugin ID. + * + * @return The config for that plugin + */ + public JSONObject getConfigJSON() { + return config; + } +} diff --git a/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/PluginHandle.java b/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/PluginHandle.java new file mode 100644 index 0000000..bfdd922 --- /dev/null +++ b/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/PluginHandle.java @@ -0,0 +1,160 @@ +package com.getcapacitor; + +import com.getcapacitor.annotation.CapacitorPlugin; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; + +/** + * PluginHandle is an instance of a plugin that has been registered + * and indexed. Think of it as a Plugin instance with extra metadata goodies + */ +public class PluginHandle { + + private final Bridge bridge; + private final Class pluginClass; + + private final Map pluginMethods = new HashMap<>(); + + private final String pluginId; + + @SuppressWarnings("deprecation") + private NativePlugin legacyPluginAnnotation; + + private CapacitorPlugin pluginAnnotation; + + private Plugin instance; + + @SuppressWarnings("deprecation") + private PluginHandle(Class clazz, Bridge bridge) throws InvalidPluginException { + this.bridge = bridge; + this.pluginClass = clazz; + + CapacitorPlugin pluginAnnotation = pluginClass.getAnnotation(CapacitorPlugin.class); + if (pluginAnnotation == null) { + // Check for legacy plugin annotation, @NativePlugin + NativePlugin legacyPluginAnnotation = pluginClass.getAnnotation(NativePlugin.class); + if (legacyPluginAnnotation == null) { + throw new InvalidPluginException("No @CapacitorPlugin annotation found for plugin " + pluginClass.getName()); + } + + if (!legacyPluginAnnotation.name().equals("")) { + this.pluginId = legacyPluginAnnotation.name(); + } else { + this.pluginId = pluginClass.getSimpleName(); + } + + this.legacyPluginAnnotation = legacyPluginAnnotation; + } else { + if (!pluginAnnotation.name().equals("")) { + this.pluginId = pluginAnnotation.name(); + } else { + this.pluginId = pluginClass.getSimpleName(); + } + + this.pluginAnnotation = pluginAnnotation; + } + + this.indexMethods(clazz); + } + + public PluginHandle(Bridge bridge, Class pluginClass) throws InvalidPluginException, PluginLoadException { + this(pluginClass, bridge); + this.load(); + } + + public PluginHandle(Bridge bridge, Plugin plugin) throws InvalidPluginException { + this(plugin.getClass(), bridge); + this.loadInstance(plugin); + } + + public Class getPluginClass() { + return pluginClass; + } + + public String getId() { + return this.pluginId; + } + + @SuppressWarnings("deprecation") + public NativePlugin getLegacyPluginAnnotation() { + return this.legacyPluginAnnotation; + } + + public CapacitorPlugin getPluginAnnotation() { + return this.pluginAnnotation; + } + + public Plugin getInstance() { + return this.instance; + } + + public Collection getMethods() { + return this.pluginMethods.values(); + } + + public Plugin load() throws PluginLoadException { + if (this.instance != null) { + return this.instance; + } + + try { + this.instance = this.pluginClass.getDeclaredConstructor().newInstance(); + return this.loadInstance(instance); + } catch (Exception ex) { + throw new PluginLoadException("Unable to load plugin instance. Ensure plugin is publicly accessible"); + } + } + + public Plugin loadInstance(Plugin plugin) { + this.instance = plugin; + this.instance.setPluginHandle(this); + this.instance.setBridge(this.bridge); + this.instance.load(); + this.instance.initializeActivityLaunchers(); + return this.instance; + } + + /** + * Call a method on a plugin. + * @param methodName the name of the method to call + * @param call the constructed PluginCall with parameters from the caller + * @throws InvalidPluginMethodException if no method was found on that plugin + */ + public void invoke(String methodName, PluginCall call) + throws PluginLoadException, InvalidPluginMethodException, InvocationTargetException, IllegalAccessException { + if (this.instance == null) { + // Can throw PluginLoadException + this.load(); + } + + PluginMethodHandle methodMeta = pluginMethods.get(methodName); + if (methodMeta == null) { + throw new InvalidPluginMethodException("No method " + methodName + " found for plugin " + pluginClass.getName()); + } + + methodMeta.getMethod().invoke(this.instance, call); + } + + /** + * Index all the known callable methods for a plugin for faster + * invocation later + */ + private void indexMethods(Class plugin) { + //Method[] methods = pluginClass.getDeclaredMethods(); + Method[] methods = pluginClass.getMethods(); + + for (Method methodReflect : methods) { + PluginMethod method = methodReflect.getAnnotation(PluginMethod.class); + + if (method == null) { + continue; + } + + PluginMethodHandle methodMeta = new PluginMethodHandle(methodReflect, method); + pluginMethods.put(methodReflect.getName(), methodMeta); + } + } +} diff --git a/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/PluginInvocationException.java b/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/PluginInvocationException.java new file mode 100644 index 0000000..ae6b0eb --- /dev/null +++ b/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/PluginInvocationException.java @@ -0,0 +1,16 @@ +package com.getcapacitor; + +class PluginInvocationException extends Exception { + + public PluginInvocationException(String s) { + super(s); + } + + public PluginInvocationException(Throwable t) { + super(t); + } + + public PluginInvocationException(String s, Throwable t) { + super(s, t); + } +} diff --git a/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/PluginLoadException.java b/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/PluginLoadException.java new file mode 100644 index 0000000..8d81a38 --- /dev/null +++ b/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/PluginLoadException.java @@ -0,0 +1,19 @@ +package com.getcapacitor; + +/** + * Thrown when a plugin fails to instantiate + */ +public class PluginLoadException extends Exception { + + public PluginLoadException(String s) { + super(s); + } + + public PluginLoadException(Throwable t) { + super(t); + } + + public PluginLoadException(String s, Throwable t) { + super(s, t); + } +} diff --git a/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/PluginManager.java b/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/PluginManager.java new file mode 100644 index 0000000..540bc91 --- /dev/null +++ b/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/PluginManager.java @@ -0,0 +1,56 @@ +package com.getcapacitor; + +import android.content.res.AssetManager; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.ArrayList; +import java.util.List; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +public class PluginManager { + + private final AssetManager assetManager; + + public PluginManager(AssetManager assetManager) { + this.assetManager = assetManager; + } + + public List> loadPluginClasses() throws PluginLoadException { + JSONArray pluginsJSON = parsePluginsJSON(); + ArrayList> pluginList = new ArrayList<>(); + + try { + for (int i = 0, size = pluginsJSON.length(); i < size; i++) { + JSONObject pluginJSON = pluginsJSON.getJSONObject(i); + String classPath = pluginJSON.getString("classpath"); + Class c = Class.forName(classPath); + pluginList.add(c.asSubclass(Plugin.class)); + } + } catch (JSONException e) { + throw new PluginLoadException("Could not parse capacitor.plugins.json as JSON"); + } catch (ClassNotFoundException e) { + throw new PluginLoadException("Could not find class by class path: " + e.getMessage()); + } + + return pluginList; + } + + private JSONArray parsePluginsJSON() throws PluginLoadException { + try (BufferedReader reader = new BufferedReader(new InputStreamReader(assetManager.open("capacitor.plugins.json")))) { + StringBuilder builder = new StringBuilder(); + String line; + while ((line = reader.readLine()) != null) { + builder.append(line); + } + String jsonString = builder.toString(); + return new JSONArray(jsonString); + } catch (IOException e) { + throw new PluginLoadException("Could not load capacitor.plugins.json"); + } catch (JSONException e) { + throw new PluginLoadException("Could not parse capacitor.plugins.json as JSON"); + } + } +} diff --git a/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/PluginMethod.java b/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/PluginMethod.java new file mode 100644 index 0000000..8566304 --- /dev/null +++ b/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/PluginMethod.java @@ -0,0 +1,15 @@ +package com.getcapacitor; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +@Retention(RetentionPolicy.RUNTIME) +public @interface PluginMethod { + String RETURN_PROMISE = "promise"; + + String RETURN_CALLBACK = "callback"; + + String RETURN_NONE = "none"; + + String returnType() default RETURN_PROMISE; +} diff --git a/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/PluginMethodHandle.java b/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/PluginMethodHandle.java new file mode 100644 index 0000000..a728c1f --- /dev/null +++ b/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/PluginMethodHandle.java @@ -0,0 +1,33 @@ +package com.getcapacitor; + +import java.lang.reflect.Method; + +public class PluginMethodHandle { + + // The reflect method reference + private final Method method; + // The name of the method + private final String name; + // The return type of the method (see PluginMethod for constants) + private final String returnType; + + public PluginMethodHandle(Method method, PluginMethod methodDecorator) { + this.method = method; + + this.name = method.getName(); + + this.returnType = methodDecorator.returnType(); + } + + public String getReturnType() { + return returnType; + } + + public String getName() { + return name; + } + + public Method getMethod() { + return method; + } +} diff --git a/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/PluginResult.java b/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/PluginResult.java new file mode 100644 index 0000000..cdc169e --- /dev/null +++ b/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/PluginResult.java @@ -0,0 +1,84 @@ +package com.getcapacitor; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.TimeZone; + +/** + * Wraps a result for web from calling a native plugin. + */ +public class PluginResult { + + private final JSObject json; + + public PluginResult() { + this(new JSObject()); + } + + public PluginResult(JSObject json) { + this.json = json; + } + + public PluginResult put(String name, boolean value) { + return this.jsonPut(name, value); + } + + public PluginResult put(String name, double value) { + return this.jsonPut(name, value); + } + + public PluginResult put(String name, int value) { + return this.jsonPut(name, value); + } + + public PluginResult put(String name, long value) { + return this.jsonPut(name, value); + } + + /** + * Format a date as an ISO string + */ + public PluginResult put(String name, Date value) { + TimeZone tz = TimeZone.getTimeZone("UTC"); + DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm'Z'"); + df.setTimeZone(tz); + return this.jsonPut(name, df.format(value)); + } + + public PluginResult put(String name, Object value) { + return this.jsonPut(name, value); + } + + public PluginResult put(String name, PluginResult value) { + return this.jsonPut(name, value.json); + } + + PluginResult jsonPut(String name, Object value) { + try { + this.json.put(name, value); + } catch (Exception ex) { + Logger.error(Logger.tags("Plugin"), "", ex); + } + return this; + } + + public String toString() { + return this.json.toString(); + } + + /** + * Return plugin metadata and information about the result, if it succeeded the data, or error information if it didn't. + * This is used for appRestoredResult, as it's technically a raw data response from a plugin. + * @return the raw data response from the plugin. + */ + public JSObject getWrappedResult() { + JSObject ret = new JSObject(); + ret.put("pluginId", this.json.getString("pluginId")); + ret.put("methodName", this.json.getString("methodName")); + ret.put("success", this.json.getBoolean("success", false)); + ret.put("data", this.json.getJSObject("data")); + ret.put("error", this.json.getJSObject("error")); + return ret; + } +} diff --git a/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/ProcessedRoute.java b/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/ProcessedRoute.java new file mode 100644 index 0000000..eb3d7b0 --- /dev/null +++ b/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/ProcessedRoute.java @@ -0,0 +1,37 @@ +package com.getcapacitor; + +/** + * An data class used in conjunction with RouteProcessor. + * + * @see com.getcapacitor.RouteProcessor + */ +public class ProcessedRoute { + + private String path; + private boolean isAsset; + private boolean ignoreAssetPath; + + public String getPath() { + return path; + } + + public void setPath(String path) { + this.path = path; + } + + public boolean isAsset() { + return isAsset; + } + + public void setAsset(boolean asset) { + isAsset = asset; + } + + public boolean isIgnoreAssetPath() { + return ignoreAssetPath; + } + + public void setIgnoreAssetPath(boolean ignoreAssetPath) { + this.ignoreAssetPath = ignoreAssetPath; + } +} diff --git a/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/RouteProcessor.java b/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/RouteProcessor.java new file mode 100644 index 0000000..670c8bc --- /dev/null +++ b/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/RouteProcessor.java @@ -0,0 +1,8 @@ +package com.getcapacitor; + +/** + * An interface used in the processing of routes + */ +public interface RouteProcessor { + ProcessedRoute process(String basePath, String path); +} diff --git a/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/ServerPath.java b/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/ServerPath.java new file mode 100644 index 0000000..5b34b46 --- /dev/null +++ b/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/ServerPath.java @@ -0,0 +1,25 @@ +package com.getcapacitor; + +public class ServerPath { + + public enum PathType { + BASE_PATH, + ASSET_PATH + } + + private final PathType type; + private final String path; + + public ServerPath(PathType type, String path) { + this.type = type; + this.path = path; + } + + public PathType getType() { + return type; + } + + public String getPath() { + return path; + } +} diff --git a/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/UriMatcher.java b/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/UriMatcher.java new file mode 100755 index 0000000..3a77a05 --- /dev/null +++ b/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/UriMatcher.java @@ -0,0 +1,184 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * 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. + */ +//package com.google.webviewlocalserver.third_party.android; +package com.getcapacitor; + +import android.net.Uri; +import com.getcapacitor.util.HostMask; +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Pattern; + +public class UriMatcher { + + /** + * Creates the root node of the URI tree. + * + * @param code the code to match for the root URI + */ + public UriMatcher(Object code) { + mCode = code; + mWhich = -1; + mChildren = new ArrayList<>(); + mText = null; + } + + private UriMatcher() { + mCode = null; + mWhich = -1; + mChildren = new ArrayList<>(); + mText = null; + } + + /** + * Add a URI to match, and the code to return when this URI is + * matched. URI nodes may be exact match string, the token "*" + * that matches any text, or the token "#" that matches only + * numbers. + *

+ * Starting from API level {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}, + * this method will accept a leading slash in the path. + * + * @param authority the authority to match + * @param path the path to match. * may be used as a wild card for + * any text, and # may be used as a wild card for numbers. + * @param code the code that is returned when a URI is matched + * against the given components. Must be positive. + */ + public void addURI(String scheme, String authority, String path, Object code) { + if (code == null) { + throw new IllegalArgumentException("Code can't be null"); + } + + String[] tokens = null; + if (path != null) { + String newPath = path; + // Strip leading slash if present. + if (!path.isEmpty() && path.charAt(0) == '/') { + newPath = path.substring(1); + } + tokens = PATH_SPLIT_PATTERN.split(newPath); + } + + int numTokens = tokens != null ? tokens.length : 0; + UriMatcher node = this; + for (int i = -2; i < numTokens; i++) { + String token; + if (i == -2) token = scheme; + else if (i == -1) token = authority; + else token = tokens[i]; + ArrayList children = node.mChildren; + int numChildren = children.size(); + UriMatcher child; + int j; + for (j = 0; j < numChildren; j++) { + child = children.get(j); + if (token.equals(child.mText)) { + node = child; + break; + } + } + if (j == numChildren) { + // Child not found, create it + child = new UriMatcher(); + if (i == -1 && token.contains("*")) { + child.mWhich = MASK; + } else if (token.equals("**")) { + child.mWhich = REST; + } else if (token.equals("*")) { + child.mWhich = TEXT; + } else { + child.mWhich = EXACT; + } + child.mText = token; + node.mChildren.add(child); + node = child; + } + } + node.mCode = code; + } + + static final Pattern PATH_SPLIT_PATTERN = Pattern.compile("/"); + + /** + * Try to match against the path in a url. + * + * @param uri The url whose path we will match against. + * @return The code for the matched node (added using addURI), + * or null if there is no matched node. + */ + public Object match(Uri uri) { + final List pathSegments = uri.getPathSegments(); + final int li = pathSegments.size(); + + UriMatcher node = this; + + if (li == 0 && uri.getAuthority() == null) { + return this.mCode; + } + + for (int i = -2; i < li; i++) { + String u; + if (i == -2) u = uri.getScheme(); + else if (i == -1) u = uri.getAuthority(); + else u = pathSegments.get(i); + ArrayList list = node.mChildren; + if (list == null) { + break; + } + node = null; + int lj = list.size(); + for (int j = 0; j < lj; j++) { + UriMatcher n = list.get(j); + which_switch: switch (n.mWhich) { + case MASK: + if (HostMask.Parser.parse(n.mText).matches(u)) { + node = n; + } + break; + case EXACT: + if (n.mText.equals(u)) { + node = n; + } + break; + case TEXT: + node = n; + break; + case REST: + return n.mCode; + } + if (node != null) { + break; + } + } + if (node == null) { + return null; + } + } + + return node.mCode; + } + + private static final int EXACT = 0; + private static final int TEXT = 1; + private static final int REST = 2; + private static final int MASK = 3; + + private Object mCode; + private int mWhich; + private String mText; + private ArrayList mChildren; +} diff --git a/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/WebViewListener.java b/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/WebViewListener.java new file mode 100644 index 0000000..6031344 --- /dev/null +++ b/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/WebViewListener.java @@ -0,0 +1,67 @@ +package com.getcapacitor; + +import android.webkit.RenderProcessGoneDetail; +import android.webkit.WebView; + +/** + * Provides callbacks associated with the {@link BridgeWebViewClient} + */ +public abstract class WebViewListener { + + /** + * Callback for page load event. + * + * @param webView The WebView that loaded + */ + public void onPageLoaded(WebView webView) { + // Override me to add behavior to the page loaded event + } + + /** + * Callback for onReceivedError event. + * + * @param webView The WebView that loaded + */ + public void onReceivedError(WebView webView) { + // Override me to add behavior to handle the onReceivedError event + } + + /** + * Callback for onReceivedHttpError event. + * + * @param webView The WebView that loaded + */ + public void onReceivedHttpError(WebView webView) { + // Override me to add behavior to handle the onReceivedHttpError event + } + + /** + * Callback for page start event. + * + * @param webView The WebView that loaded + */ + public void onPageStarted(WebView webView) { + // Override me to add behavior to the page started event + } + + /** + * Callback for render process gone event. Return true if the state is handled. + * + * @param webView The WebView that loaded + * @return returns false by default if the listener is not overridden and used + */ + public boolean onRenderProcessGone(WebView webView, RenderProcessGoneDetail detail) { + // Override me to add behavior to the web view render process gone event + return false; + } + + /** + * Callback for page start event. + * + * @param view The WebView for which the navigation occurred. + * @param url The URL corresponding to the page navigation that triggered this callback. + */ + public void onPageCommitVisible(WebView view, String url) { + // Override me to add behavior to handle the onPageCommitVisible event + } +} diff --git a/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/WebViewLocalServer.java b/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/WebViewLocalServer.java new file mode 100755 index 0000000..a39483d --- /dev/null +++ b/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/WebViewLocalServer.java @@ -0,0 +1,773 @@ +/* +Copyright 2015 Google Inc. All rights reserved. + +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. + */ +package com.getcapacitor; + +import static com.getcapacitor.plugin.util.HttpRequestHandler.isDomainExcludedFromSSL; + +import android.content.Context; +import android.net.Uri; +import android.util.Base64; +import android.webkit.CookieManager; +import android.webkit.WebResourceRequest; +import android.webkit.WebResourceResponse; +import com.getcapacitor.plugin.util.CapacitorHttpUrlConnection; +import com.getcapacitor.plugin.util.HttpRequestHandler; +import java.io.IOException; +import java.io.InputStream; +import java.net.HttpURLConnection; +import java.net.URL; +import java.net.URLConnection; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +/** + * Helper class meant to be used with the android.webkit.WebView class to enable hosting assets, + * resources and other data on 'virtual' https:// URL. + * Hosting assets and resources on https:// URLs is desirable as it is compatible with the + * Same-Origin policy. + *

+ * This class is intended to be used from within the + * {@link android.webkit.WebViewClient#shouldInterceptRequest(android.webkit.WebView, String)} and + * {@link android.webkit.WebViewClient#shouldInterceptRequest(android.webkit.WebView, + * android.webkit.WebResourceRequest)} + * methods. + */ +public class WebViewLocalServer { + + private static final String capacitorFileStart = Bridge.CAPACITOR_FILE_START; + private static final String capacitorContentStart = Bridge.CAPACITOR_CONTENT_START; + private String basePath; + + private final UriMatcher uriMatcher; + private final AndroidProtocolHandler protocolHandler; + private final ArrayList authorities; + private boolean isAsset; + // Whether to route all requests to paths without extensions back to `index.html` + private final boolean html5mode; + private final JSInjector jsInjector; + private final Bridge bridge; + + /** + * A handler that produces responses for paths on the virtual asset server. + *

+ * Methods of this handler will be invoked on a background thread and care must be taken to + * correctly synchronize access to any shared state. + *

+ * On Android KitKat and above these methods may be called on more than one thread. This thread + * may be different than the thread on which the shouldInterceptRequest method was invoke. + * This means that on Android KitKat and above it is possible to block in this method without + * blocking other resources from loading. The number of threads used to parallelize loading + * is an internal implementation detail of the WebView and may change between updates which + * means that the amount of time spend blocking in this method should be kept to an absolute + * minimum. + */ + public abstract static class PathHandler { + + protected String mimeType; + private String encoding; + private String charset; + private int statusCode; + private String reasonPhrase; + private Map responseHeaders; + + public PathHandler() { + this(null, null, 200, "OK", null); + } + + public PathHandler(String encoding, String charset, int statusCode, String reasonPhrase, Map responseHeaders) { + this.encoding = encoding; + this.charset = charset; + this.statusCode = statusCode; + this.reasonPhrase = reasonPhrase; + Map tempResponseHeaders; + if (responseHeaders == null) { + tempResponseHeaders = new HashMap<>(); + } else { + tempResponseHeaders = responseHeaders; + } + tempResponseHeaders.put("Cache-Control", "no-cache"); + this.responseHeaders = tempResponseHeaders; + } + + public InputStream handle(WebResourceRequest request) { + return handle(request.getUrl()); + } + + public abstract InputStream handle(Uri url); + + public String getEncoding() { + return encoding; + } + + public String getCharset() { + return charset; + } + + public int getStatusCode() { + return statusCode; + } + + public String getReasonPhrase() { + return reasonPhrase; + } + + /** + * @deprecated This method may return incorrect headers in concurrent range requests. + *

+ * Use {@link #buildDefaultResponseHeaders()} instead, which returns a copy of the map. + *

+ * This method will be removed in a future major version of Capacitor. + *

+ */ + @Deprecated(forRemoval = true) // adjust version as appropriate + public Map getResponseHeaders() { + return responseHeaders; + } + + public Map buildDefaultResponseHeaders() { + return new HashMap<>(responseHeaders); + } + } + + WebViewLocalServer(Context context, Bridge bridge, JSInjector jsInjector, ArrayList authorities, boolean html5mode) { + uriMatcher = new UriMatcher(null); + this.html5mode = html5mode; + this.protocolHandler = new AndroidProtocolHandler(context.getApplicationContext()); + this.authorities = authorities; + this.bridge = bridge; + this.jsInjector = jsInjector; + } + + private static Uri parseAndVerifyUrl(String url) { + if (url == null) { + return null; + } + Uri uri = Uri.parse(url); + if (uri == null) { + Logger.error("Malformed URL: " + url); + return null; + } + String path = uri.getPath(); + if (path == null || path.isEmpty()) { + Logger.error("URL does not have a path: " + url); + return null; + } + return uri; + } + + /** + * Attempt to retrieve the WebResourceResponse associated with the given request. + * This method should be invoked from within + * {@link android.webkit.WebViewClient#shouldInterceptRequest(android.webkit.WebView, + * android.webkit.WebResourceRequest)}. + * + * @param request the request to process. + * @return a response if the request URL had a matching handler, null if no handler was found. + */ + public WebResourceResponse shouldInterceptRequest(WebResourceRequest request) { + Uri loadingUrl = request.getUrl(); + + if (null != loadingUrl.getPath() && loadingUrl.getPath().startsWith(Bridge.CAPACITOR_HTTP_INTERCEPTOR_START)) { + Logger.debug("Handling CapacitorHttp request: " + loadingUrl); + try { + return handleCapacitorHttpRequest(request); + } catch (Exception e) { + Logger.error(e.getLocalizedMessage()); + return null; + } + } + + PathHandler handler; + synchronized (uriMatcher) { + handler = (PathHandler) uriMatcher.match(request.getUrl()); + } + if (handler == null) { + return null; + } + + if (isLocalFile(loadingUrl) || isMainUrl(loadingUrl) || !isAllowedUrl(loadingUrl) || isErrorUrl(loadingUrl)) { + Logger.debug("Handling local request: " + request.getUrl().toString()); + return handleLocalRequest(request, handler); + } else { + return handleProxyRequest(request, handler); + } + } + + private boolean isLocalFile(Uri uri) { + String path = uri.getPath(); + return path.startsWith(capacitorContentStart) || path.startsWith(capacitorFileStart); + } + + private boolean isErrorUrl(Uri uri) { + String url = uri.toString(); + return url.equals(bridge.getErrorUrl()); + } + + private boolean isMainUrl(Uri loadingUrl) { + return (bridge.getServerUrl() == null && loadingUrl.getHost().equalsIgnoreCase(bridge.getHost())); + } + + private boolean isAllowedUrl(Uri loadingUrl) { + return !(bridge.getServerUrl() == null && !bridge.getAppAllowNavigationMask().matches(loadingUrl.getHost())); + } + + private String getReasonPhraseFromResponseCode(int code) { + return switch (code) { + case 100 -> "Continue"; + case 101 -> "Switching Protocols"; + case 200 -> "OK"; + case 201 -> "Created"; + case 202 -> "Accepted"; + case 203 -> "Non-Authoritative Information"; + case 204 -> "No Content"; + case 205 -> "Reset Content"; + case 206 -> "Partial Content"; + case 300 -> "Multiple Choices"; + case 301 -> "Moved Permanently"; + case 302 -> "Found"; + case 303 -> "See Other"; + case 304 -> "Not Modified"; + case 400 -> "Bad Request"; + case 401 -> "Unauthorized"; + case 403 -> "Forbidden"; + case 404 -> "Not Found"; + case 405 -> "Method Not Allowed"; + case 406 -> "Not Acceptable"; + case 407 -> "Proxy Authentication Required"; + case 408 -> "Request Timeout"; + case 409 -> "Conflict"; + case 410 -> "Gone"; + case 500 -> "Internal Server Error"; + case 501 -> "Not Implemented"; + case 502 -> "Bad Gateway"; + case 503 -> "Service Unavailable"; + case 504 -> "Gateway Timeout"; + case 505 -> "HTTP Version Not Supported"; + default -> "Unknown"; + }; + } + + private WebResourceResponse handleCapacitorHttpRequest(WebResourceRequest request) throws IOException { + String urlString = request.getUrl().getQueryParameter(Bridge.CAPACITOR_HTTP_INTERCEPTOR_URL_PARAM); + URL url = new URL(urlString); + JSObject headers = new JSObject(); + + for (Map.Entry header : request.getRequestHeaders().entrySet()) { + headers.put(header.getKey(), header.getValue()); + } + + // a workaround for the following android web view issue: + // https://issues.chromium.org/issues/40450316 + // x-cap-user-agent contains the user agent set in JavaScript + String userAgentValue = headers.getString("x-cap-user-agent"); + if (userAgentValue != null) { + headers.put("User-Agent", userAgentValue); + } + headers.remove("x-cap-user-agent"); + + HttpRequestHandler.HttpURLConnectionBuilder connectionBuilder = new HttpRequestHandler.HttpURLConnectionBuilder() + .setUrl(url) + .setMethod(request.getMethod()) + .setHeaders(headers) + .openConnection(); + + CapacitorHttpUrlConnection connection = connectionBuilder.build(); + + if (!isDomainExcludedFromSSL(bridge, url)) { + connection.setSSLSocketFactory(bridge); + } + + connection.connect(); + + String mimeType = null; + String encoding = null; + Map responseHeaders = new LinkedHashMap<>(); + for (Map.Entry> entry : connection.getHeaderFields().entrySet()) { + StringBuilder builder = new StringBuilder(); + for (String value : entry.getValue()) { + builder.append(value); + builder.append(", "); + } + builder.setLength(builder.length() - 2); + + if ("Content-Type".equalsIgnoreCase(entry.getKey())) { + String[] contentTypeParts = builder.toString().split(";"); + mimeType = contentTypeParts[0].trim(); + if (contentTypeParts.length > 1) { + String[] encodingParts = contentTypeParts[1].split("="); + if (encodingParts.length > 1) { + encoding = encodingParts[1].trim(); + } + } + } else { + responseHeaders.put(entry.getKey(), builder.toString()); + } + } + + InputStream inputStream = connection.getErrorStream(); + if (inputStream == null) { + inputStream = connection.getInputStream(); + } + + if (null == mimeType) { + mimeType = getMimeType(request.getUrl().getPath(), inputStream); + } + + int responseCode = connection.getResponseCode(); + String reasonPhrase = getReasonPhraseFromResponseCode(responseCode); + + return new WebResourceResponse(mimeType, encoding, responseCode, reasonPhrase, responseHeaders, inputStream); + } + + private WebResourceResponse handleLocalRequest(WebResourceRequest request, PathHandler handler) { + String path = request.getUrl().getPath(); + + Map requestHeaders = request.getRequestHeaders(); + String rangeString = requestHeaders.get("Range") != null ? requestHeaders.get("Range") : requestHeaders.get("range"); + + if (rangeString != null) { + InputStream responseStream = new LollipopLazyInputStream(handler, request); + String mimeType = getMimeType(path, responseStream); + Map tempResponseHeaders = handler.buildDefaultResponseHeaders(); + int statusCode = 206; + try { + int totalRange = responseStream.available(); + String[] parts = rangeString.split("="); + String[] streamParts = parts[1].split("-"); + String fromRange = streamParts[0]; + int range = totalRange - 1; + if (streamParts.length > 1) { + range = Integer.parseInt(streamParts[1]); + } + tempResponseHeaders.put("Accept-Ranges", "bytes"); + tempResponseHeaders.put("Content-Range", "bytes " + fromRange + "-" + range + "/" + totalRange); + } catch (IOException e) { + statusCode = 404; + } + return new WebResourceResponse( + mimeType, + handler.getEncoding(), + statusCode, + handler.getReasonPhrase(), + tempResponseHeaders, + responseStream + ); + } + + if (isLocalFile(request.getUrl()) || isErrorUrl(request.getUrl())) { + InputStream responseStream = new LollipopLazyInputStream(handler, request); + String mimeType = getMimeType(request.getUrl().getPath(), responseStream); + int statusCode = getStatusCode(responseStream, handler.getStatusCode()); + return new WebResourceResponse( + mimeType, + handler.getEncoding(), + statusCode, + handler.getReasonPhrase(), + handler.buildDefaultResponseHeaders(), + responseStream + ); + } + + if (path.equals("/cordova.js")) { + return new WebResourceResponse( + "application/javascript", + handler.getEncoding(), + handler.getStatusCode(), + handler.getReasonPhrase(), + handler.buildDefaultResponseHeaders(), + null + ); + } + + if (path.equals("/") || (!request.getUrl().getLastPathSegment().contains(".") && html5mode)) { + InputStream responseStream; + try { + String startPath = this.basePath + "/index.html"; + if (bridge.getRouteProcessor() != null) { + ProcessedRoute processedRoute = bridge.getRouteProcessor().process(this.basePath, "/index.html"); + startPath = processedRoute.getPath(); + isAsset = processedRoute.isAsset(); + } + + if (isAsset) { + responseStream = protocolHandler.openAsset(startPath); + } else { + responseStream = protocolHandler.openFile(startPath); + } + } catch (IOException e) { + Logger.error("Unable to open index.html", e); + return null; + } + + if (jsInjector != null) { + responseStream = jsInjector.getInjectedStream(responseStream); + } + + int statusCode = getStatusCode(responseStream, handler.getStatusCode()); + return new WebResourceResponse( + "text/html", + handler.getEncoding(), + statusCode, + handler.getReasonPhrase(), + handler.buildDefaultResponseHeaders(), + responseStream + ); + } + + if ("/favicon.ico".equalsIgnoreCase(path)) { + try { + return new WebResourceResponse("image/png", null, null); + } catch (Exception e) { + Logger.error("favicon handling failed", e); + } + } + + int periodIndex = path.lastIndexOf("."); + if (periodIndex >= 0) { + String ext = path.substring(path.lastIndexOf(".")); + + InputStream responseStream = new LollipopLazyInputStream(handler, request); + + // TODO: Conjure up a bit more subtlety than this + if (ext.equals(".html") && jsInjector != null) { + responseStream = jsInjector.getInjectedStream(responseStream); + } + + String mimeType = getMimeType(path, responseStream); + int statusCode = getStatusCode(responseStream, handler.getStatusCode()); + return new WebResourceResponse( + mimeType, + handler.getEncoding(), + statusCode, + handler.getReasonPhrase(), + handler.buildDefaultResponseHeaders(), + responseStream + ); + } + + return null; + } + + /** + * Prepends an {@code InputStream} with the JavaScript required by Capacitor. + * This method only changes the original {@code InputStream} if {@code WebView} does not + * support the {@code DOCUMENT_START_SCRIPT} feature. + * @param original the original {@code InputStream} + * @return the modified {@code InputStream} + */ + public InputStream getJavaScriptInjectedStream(InputStream original) { + if (jsInjector != null) { + return jsInjector.getInjectedStream(original); + } + return original; + } + + /** + * Instead of reading files from the filesystem/assets, proxy through to the URL + * and let an external server handle it. + * @param request + * @param handler + * @return + */ + private WebResourceResponse handleProxyRequest(WebResourceRequest request, PathHandler handler) { + if (jsInjector != null) { + final String method = request.getMethod(); + if (method.equals("GET")) { + try { + String url = request.getUrl().toString(); + Map headers = request.getRequestHeaders(); + boolean isHtmlText = false; + for (Map.Entry header : headers.entrySet()) { + if (header.getKey().equalsIgnoreCase("Accept") && header.getValue().toLowerCase().contains("text/html")) { + isHtmlText = true; + break; + } + } + if (isHtmlText) { + HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection(); + for (Map.Entry header : headers.entrySet()) { + conn.setRequestProperty(header.getKey(), header.getValue()); + } + String getCookie = CookieManager.getInstance().getCookie(url); + if (getCookie != null) { + conn.setRequestProperty("Cookie", getCookie); + } + conn.setRequestMethod(method); + conn.setReadTimeout(30 * 1000); + conn.setConnectTimeout(30 * 1000); + if (request.getUrl().getUserInfo() != null) { + byte[] userInfoBytes = request.getUrl().getUserInfo().getBytes(StandardCharsets.UTF_8); + String base64 = Base64.encodeToString(userInfoBytes, Base64.NO_WRAP); + conn.setRequestProperty("Authorization", "Basic " + base64); + } + + List cookies = conn.getHeaderFields().get("Set-Cookie"); + if (cookies != null) { + for (String cookie : cookies) { + CookieManager.getInstance().setCookie(url, cookie); + } + } + InputStream responseStream = conn.getInputStream(); + responseStream = jsInjector.getInjectedStream(responseStream); + + return new WebResourceResponse( + "text/html", + handler.getEncoding(), + handler.getStatusCode(), + handler.getReasonPhrase(), + handler.buildDefaultResponseHeaders(), + responseStream + ); + } + } catch (Exception ex) { + bridge.handleAppUrlLoadError(ex); + } + } + } + return null; + } + + private String getMimeType(String path, InputStream stream) { + String mimeType = null; + try { + mimeType = URLConnection.guessContentTypeFromName(path); // Does not recognize *.js + if (mimeType != null && path.endsWith(".js") && mimeType.equals("image/x-icon")) { + Logger.debug("We shouldn't be here"); + } + if (mimeType == null) { + if (path.endsWith(".js") || path.endsWith(".mjs")) { + // Make sure JS files get the proper mimetype to support ES modules + mimeType = "application/javascript"; + } else if (path.endsWith(".wasm")) { + mimeType = "application/wasm"; + } else { + mimeType = URLConnection.guessContentTypeFromStream(stream); + } + } + } catch (Exception ex) { + Logger.error("Unable to get mime type" + path, ex); + } + return mimeType; + } + + private int getStatusCode(InputStream stream, int defaultCode) { + int finalStatusCode = defaultCode; + try { + if (stream.available() == -1) { + finalStatusCode = 404; + } + } catch (IOException e) { + finalStatusCode = 500; + } + return finalStatusCode; + } + + /** + * Registers a handler for the given uri. The handler will be invoked + * every time the shouldInterceptRequest method of the instance is called with + * a matching uri. + * + * @param uri the uri to use the handler for. The scheme and authority (domain) will be matched + * exactly. The path may contain a '*' element which will match a single element of + * a path (so a handler registered for /a/* will be invoked for /a/b and /a/c.html + * but not for /a/b/b) or the '**' element which will match any number of path + * elements. + * @param handler the handler to use for the uri. + */ + void register(Uri uri, PathHandler handler) { + synchronized (uriMatcher) { + uriMatcher.addURI(uri.getScheme(), uri.getAuthority(), uri.getPath(), handler); + } + } + + /** + * Hosts the application's assets on an https:// URL. Assets from the local path + * assetPath/... will be available under + * https://{uuid}.androidplatform.net/assets/.... + * + * @param assetPath the local path in the application's asset folder which will be made + * available by the server (for example "/www"). + * @return prefixes under which the assets are hosted. + */ + public void hostAssets(String assetPath) { + this.isAsset = true; + this.basePath = assetPath; + createHostingDetails(); + } + + /** + * Hosts the application's files on an https:// URL. Files from the basePath + * basePath/... will be available under + * https://{uuid}.androidplatform.net/.... + * + * @param basePath the local path in the application's data folder which will be made + * available by the server (for example "/www"). + * @return prefixes under which the assets are hosted. + */ + public void hostFiles(final String basePath) { + this.isAsset = false; + this.basePath = basePath; + createHostingDetails(); + } + + private void createHostingDetails() { + final String assetPath = this.basePath; + + if (assetPath.indexOf('*') != -1) { + throw new IllegalArgumentException("assetPath cannot contain the '*' character."); + } + + PathHandler handler = new PathHandler() { + @Override + public InputStream handle(Uri url) { + InputStream stream = null; + String path = url.getPath(); + + // Pass path to routeProcessor if present + RouteProcessor routeProcessor = bridge.getRouteProcessor(); + boolean ignoreAssetPath = false; + if (routeProcessor != null) { + ProcessedRoute processedRoute = bridge.getRouteProcessor().process("", path); + path = processedRoute.getPath(); + isAsset = processedRoute.isAsset(); + ignoreAssetPath = processedRoute.isIgnoreAssetPath(); + } + + try { + if (path.startsWith(capacitorContentStart)) { + stream = protocolHandler.openContentUrl(url); + } else if (path.startsWith(capacitorFileStart)) { + stream = protocolHandler.openFile(path); + } else if (!isAsset) { + if (routeProcessor == null) { + path = basePath + url.getPath(); + } + + stream = protocolHandler.openFile(path); + } else if (ignoreAssetPath) { + stream = protocolHandler.openAsset(path); + } else { + stream = protocolHandler.openAsset(assetPath + path); + } + } catch (IOException e) { + Logger.error("Unable to open asset URL: " + url); + return null; + } + + return stream; + } + }; + + for (String authority : authorities) { + registerUriForScheme(Bridge.CAPACITOR_HTTP_SCHEME, handler, authority); + registerUriForScheme(Bridge.CAPACITOR_HTTPS_SCHEME, handler, authority); + + String customScheme = this.bridge.getScheme(); + if (!customScheme.equals(Bridge.CAPACITOR_HTTP_SCHEME) && !customScheme.equals(Bridge.CAPACITOR_HTTPS_SCHEME)) { + registerUriForScheme(customScheme, handler, authority); + } + } + } + + private void registerUriForScheme(String scheme, PathHandler handler, String authority) { + Uri.Builder uriBuilder = new Uri.Builder(); + uriBuilder.scheme(scheme); + uriBuilder.authority(authority); + uriBuilder.path(""); + Uri uriPrefix = uriBuilder.build(); + + register(Uri.withAppendedPath(uriPrefix, "/"), handler); + register(Uri.withAppendedPath(uriPrefix, "**"), handler); + } + + /** + * The KitKat WebView reads the InputStream on a separate threadpool. We can use that to + * parallelize loading. + */ + private abstract static class LazyInputStream extends InputStream { + + protected final PathHandler handler; + private InputStream is = null; + + public LazyInputStream(PathHandler handler) { + this.handler = handler; + } + + private InputStream getInputStream() { + if (is == null) { + is = handle(); + } + return is; + } + + protected abstract InputStream handle(); + + @Override + public int available() throws IOException { + InputStream is = getInputStream(); + return (is != null) ? is.available() : -1; + } + + @Override + public int read() throws IOException { + InputStream is = getInputStream(); + return (is != null) ? is.read() : -1; + } + + @Override + public int read(byte[] b) throws IOException { + InputStream is = getInputStream(); + return (is != null) ? is.read(b) : -1; + } + + @Override + public int read(byte[] b, int off, int len) throws IOException { + InputStream is = getInputStream(); + return (is != null) ? is.read(b, off, len) : -1; + } + + @Override + public long skip(long n) throws IOException { + InputStream is = getInputStream(); + return (is != null) ? is.skip(n) : 0; + } + } + + // For L and above. + private static class LollipopLazyInputStream extends LazyInputStream { + + private WebResourceRequest request; + private InputStream is; + + public LollipopLazyInputStream(PathHandler handler, WebResourceRequest request) { + super(handler); + this.request = request; + } + + @Override + protected InputStream handle() { + return handler.handle(request); + } + } + + public String getBasePath() { + return this.basePath; + } +} diff --git a/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/annotation/ActivityCallback.java b/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/annotation/ActivityCallback.java new file mode 100644 index 0000000..b8112f1 --- /dev/null +++ b/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/annotation/ActivityCallback.java @@ -0,0 +1,10 @@ +package com.getcapacitor.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +public @interface ActivityCallback {} diff --git a/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/annotation/CapacitorPlugin.java b/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/annotation/CapacitorPlugin.java new file mode 100644 index 0000000..903378d --- /dev/null +++ b/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/annotation/CapacitorPlugin.java @@ -0,0 +1,35 @@ +package com.getcapacitor.annotation; + +import android.content.Intent; +import com.getcapacitor.PluginCall; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * Base annotation for all Plugins + */ +@Retention(RetentionPolicy.RUNTIME) +public @interface CapacitorPlugin { + /** + * A custom name for the plugin, otherwise uses the + * simple class name. + */ + String name() default ""; + + /** + * Request codes this plugin uses and responds to, in order to tie + * Android events back the plugin to handle. + * + * NOTE: This is a legacy option provided to support third party libraries + * not currently implementing the new AndroidX Activity Results API. Plugins + * without this limitation should use a registered callback with + * {@link com.getcapacitor.Plugin#startActivityForResult(PluginCall, Intent, String)} + */ + int[] requestCodes() default {}; + + /** + * Permissions this plugin needs, in order to make permission requests + * easy if the plugin only needs basic permission prompting + */ + Permission[] permissions() default {}; +} diff --git a/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/annotation/Permission.java b/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/annotation/Permission.java new file mode 100644 index 0000000..3511437 --- /dev/null +++ b/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/annotation/Permission.java @@ -0,0 +1,22 @@ +package com.getcapacitor.annotation; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * Permission annotation for use with @CapacitorPlugin + */ +@Retention(RetentionPolicy.RUNTIME) +public @interface Permission { + /** + * An array of Android permission strings. + * Eg: {Manifest.permission.ACCESS_COARSE_LOCATION} + * or {"android.permission.ACCESS_COARSE_LOCATION"} + */ + String[] strings() default {}; + + /** + * An optional name to use instead of the Android permission string. + */ + String alias() default ""; +} diff --git a/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/annotation/PermissionCallback.java b/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/annotation/PermissionCallback.java new file mode 100644 index 0000000..1b81ee0 --- /dev/null +++ b/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/annotation/PermissionCallback.java @@ -0,0 +1,10 @@ +package com.getcapacitor.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +public @interface PermissionCallback {} diff --git a/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/cordova/CapacitorCordovaCookieManager.java b/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/cordova/CapacitorCordovaCookieManager.java new file mode 100644 index 0000000..72ac4ee --- /dev/null +++ b/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/cordova/CapacitorCordovaCookieManager.java @@ -0,0 +1,42 @@ +package com.getcapacitor.cordova; + +import android.webkit.CookieManager; +import android.webkit.WebView; +import org.apache.cordova.ICordovaCookieManager; + +class CapacitorCordovaCookieManager implements ICordovaCookieManager { + + protected final WebView webView; + private final CookieManager cookieManager; + + public CapacitorCordovaCookieManager(WebView webview) { + webView = webview; + cookieManager = CookieManager.getInstance(); + cookieManager.setAcceptThirdPartyCookies(webView, true); + } + + @Override + public void setCookiesEnabled(boolean accept) { + cookieManager.setAcceptCookie(accept); + } + + @Override + public void setCookie(final String url, final String value) { + cookieManager.setCookie(url, value); + } + + @Override + public String getCookie(final String url) { + return cookieManager.getCookie(url); + } + + @Override + public void clearCookies() { + cookieManager.removeAllCookies(null); + } + + @Override + public void flush() { + cookieManager.flush(); + } +} diff --git a/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/cordova/MockCordovaInterfaceImpl.java b/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/cordova/MockCordovaInterfaceImpl.java new file mode 100644 index 0000000..7e8358d --- /dev/null +++ b/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/cordova/MockCordovaInterfaceImpl.java @@ -0,0 +1,39 @@ +package com.getcapacitor.cordova; + +import android.util.Pair; +import androidx.appcompat.app.AppCompatActivity; +import java.util.concurrent.Executors; +import org.apache.cordova.CordovaInterfaceImpl; +import org.apache.cordova.CordovaPlugin; +import org.json.JSONException; + +public class MockCordovaInterfaceImpl extends CordovaInterfaceImpl { + + public MockCordovaInterfaceImpl(AppCompatActivity activity) { + super(activity, Executors.newCachedThreadPool()); + } + + public CordovaPlugin getActivityResultCallback() { + return this.activityResultCallback; + } + + /** + * Checks Cordova permission callbacks to handle permissions defined by a Cordova plugin. + * Returns true if Cordova is handling the permission request with a registered code. + * + * @param requestCode + * @param permissions + * @param grantResults + * @return true if Cordova handled the permission request, false if not + */ + @SuppressWarnings("deprecation") + public boolean handlePermissionResult(int requestCode, String[] permissions, int[] grantResults) throws JSONException { + Pair callback = permissionResultCallbacks.getAndRemoveCallback(requestCode); + if (callback != null) { + callback.first.onRequestPermissionResult(callback.second, permissions, grantResults); + return true; + } + + return false; + } +} diff --git a/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/cordova/MockCordovaWebViewImpl.java b/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/cordova/MockCordovaWebViewImpl.java new file mode 100644 index 0000000..1115429 --- /dev/null +++ b/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/cordova/MockCordovaWebViewImpl.java @@ -0,0 +1,282 @@ +package com.getcapacitor.cordova; + +import android.content.Context; +import android.content.Intent; +import android.os.Handler; +import android.view.View; +import android.webkit.ValueCallback; +import android.webkit.WebChromeClient; +import android.webkit.WebView; +import java.util.List; +import java.util.Map; +import org.apache.cordova.CordovaInterface; +import org.apache.cordova.CordovaPreferences; +import org.apache.cordova.CordovaResourceApi; +import org.apache.cordova.CordovaWebView; +import org.apache.cordova.CordovaWebViewEngine; +import org.apache.cordova.ICordovaCookieManager; +import org.apache.cordova.NativeToJsMessageQueue; +import org.apache.cordova.PluginEntry; +import org.apache.cordova.PluginManager; +import org.apache.cordova.PluginResult; + +public class MockCordovaWebViewImpl implements CordovaWebView { + + private Context context; + private PluginManager pluginManager; + private CordovaPreferences preferences; + private CordovaResourceApi resourceApi; + private NativeToJsMessageQueue nativeToJsMessageQueue; + private CordovaInterface cordova; + private CapacitorCordovaCookieManager cookieManager; + private WebView webView; + private boolean hasPausedEver; + + public MockCordovaWebViewImpl(Context context) { + this.context = context; + } + + @Override + public void init(CordovaInterface cordova, List pluginEntries, CordovaPreferences preferences) { + this.cordova = cordova; + this.preferences = preferences; + this.pluginManager = new PluginManager(this, this.cordova, pluginEntries); + this.resourceApi = new CordovaResourceApi(this.context, this.pluginManager); + this.pluginManager.init(); + } + + public void init(CordovaInterface cordova, List pluginEntries, CordovaPreferences preferences, WebView webView) { + this.cordova = cordova; + this.webView = webView; + this.preferences = preferences; + this.pluginManager = new PluginManager(this, this.cordova, pluginEntries); + this.resourceApi = new CordovaResourceApi(this.context, this.pluginManager); + nativeToJsMessageQueue = new NativeToJsMessageQueue(); + nativeToJsMessageQueue.addBridgeMode(new CapacitorEvalBridgeMode(webView, this.cordova)); + nativeToJsMessageQueue.setBridgeMode(0); + this.cookieManager = new CapacitorCordovaCookieManager(webView); + this.pluginManager.init(); + } + + public static class CapacitorEvalBridgeMode extends NativeToJsMessageQueue.BridgeMode { + + private final WebView webView; + private final CordovaInterface cordova; + + public CapacitorEvalBridgeMode(WebView webView, CordovaInterface cordova) { + this.webView = webView; + this.cordova = cordova; + } + + @Override + public void onNativeToJsMessageAvailable(final NativeToJsMessageQueue queue) { + cordova + .getActivity() + .runOnUiThread(() -> { + String js = queue.popAndEncodeAsJs(); + if (js != null) { + webView.evaluateJavascript(js, null); + } + }); + } + } + + @Override + public boolean isInitialized() { + return cordova != null; + } + + @Override + public View getView() { + return this.webView; + } + + @Override + public void loadUrlIntoView(String url, boolean recreatePlugins) { + if (url.equals("about:blank") || url.startsWith("javascript:")) { + webView.loadUrl(url); + return; + } + } + + @Override + public void stopLoading() {} + + @Override + public boolean canGoBack() { + return false; + } + + @Override + public void clearCache() {} + + @Deprecated + @Override + public void clearCache(boolean b) {} + + @Override + public void clearHistory() {} + + @Override + public boolean backHistory() { + return false; + } + + @Override + public void handlePause(boolean keepRunning) { + if (!isInitialized()) { + return; + } + hasPausedEver = true; + pluginManager.onPause(keepRunning); + triggerDocumentEvent("pause"); + // If app doesn't want to run in background + if (!keepRunning) { + // Pause JavaScript timers. This affects all webviews within the app! + this.setPaused(true); + } + } + + @Override + public void onNewIntent(Intent intent) { + if (this.pluginManager != null) { + this.pluginManager.onNewIntent(intent); + } + } + + @Override + public void handleResume(boolean keepRunning) { + if (!isInitialized()) { + return; + } + this.setPaused(false); + this.pluginManager.onResume(keepRunning); + if (hasPausedEver) { + triggerDocumentEvent("resume"); + } + } + + @Override + public void handleStart() { + if (!isInitialized()) { + return; + } + pluginManager.onStart(); + } + + @Override + public void handleStop() { + if (!isInitialized()) { + return; + } + pluginManager.onStop(); + } + + @Override + public void handleDestroy() { + if (!isInitialized()) { + return; + } + this.pluginManager.onDestroy(); + } + + @Deprecated + @Override + public void sendJavascript(String statememt) { + nativeToJsMessageQueue.addJavaScript(statememt); + } + + public void eval(final String js, final ValueCallback callback) { + Handler mainHandler = new Handler(context.getMainLooper()); + mainHandler.post(() -> webView.evaluateJavascript(js, callback)); + } + + public void triggerDocumentEvent(final String eventName) { + eval("window.Capacitor.triggerEvent('" + eventName + "', 'document');", (s) -> {}); + } + + @Override + public void showWebPage(String url, boolean openExternal, boolean clearHistory, Map params) {} + + @Deprecated + @Override + public boolean isCustomViewShowing() { + return false; + } + + @Deprecated + @Override + public void showCustomView(View view, WebChromeClient.CustomViewCallback callback) {} + + @Deprecated + @Override + public void hideCustomView() {} + + @Override + public CordovaResourceApi getResourceApi() { + return this.resourceApi; + } + + @Override + public void setButtonPlumbedToJs(int keyCode, boolean override) {} + + @Override + public boolean isButtonPlumbedToJs(int keyCode) { + return false; + } + + @Override + public void sendPluginResult(PluginResult cr, String callbackId) { + nativeToJsMessageQueue.addPluginResult(cr, callbackId); + } + + @Override + public PluginManager getPluginManager() { + return this.pluginManager; + } + + @Override + public CordovaWebViewEngine getEngine() { + return null; + } + + @Override + public CordovaPreferences getPreferences() { + return this.preferences; + } + + @Override + public ICordovaCookieManager getCookieManager() { + return cookieManager; + } + + @Override + public String getUrl() { + return webView.getUrl(); + } + + @Override + public Context getContext() { + return this.webView.getContext(); + } + + @Override + public void loadUrl(String url) { + loadUrlIntoView(url, true); + } + + @Override + public Object postMessage(String id, Object data) { + return pluginManager.postMessage(id, data); + } + + public void setPaused(boolean value) { + if (value) { + webView.onPause(); + webView.pauseTimers(); + } else { + webView.onResume(); + webView.resumeTimers(); + } + } +} diff --git a/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/plugin/CapacitorCookieManager.java b/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/plugin/CapacitorCookieManager.java new file mode 100644 index 0000000..cf4ab63 --- /dev/null +++ b/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/plugin/CapacitorCookieManager.java @@ -0,0 +1,239 @@ +package com.getcapacitor.plugin; + +import com.getcapacitor.Bridge; +import com.getcapacitor.Logger; +import java.net.CookieManager; +import java.net.CookiePolicy; +import java.net.CookieStore; +import java.net.HttpCookie; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Objects; + +public class CapacitorCookieManager extends CookieManager { + + private final android.webkit.CookieManager webkitCookieManager; + + private final String localUrl; + + private final String serverUrl; + + private final String TAG = "CapacitorCookies"; + + /** + * Create a new cookie manager with the default cookie store and policy + */ + public CapacitorCookieManager(Bridge bridge) { + this(null, null, bridge); + } + + /** + * Create a new cookie manager with specified cookie store and cookie policy. + * @param store a {@code CookieStore} to be used by CookieManager. if {@code null}, cookie + * manager will use a default one, which is an in-memory CookieStore implementation. + * @param policy a {@code CookiePolicy} instance to be used by cookie manager as policy + * callback. if {@code null}, ACCEPT_ORIGINAL_SERVER will be used. + */ + public CapacitorCookieManager(CookieStore store, CookiePolicy policy, Bridge bridge) { + super(store, policy); + webkitCookieManager = android.webkit.CookieManager.getInstance(); + this.localUrl = bridge.getLocalUrl(); + this.serverUrl = bridge.getServerUrl(); + } + + public void removeSessionCookies() { + this.webkitCookieManager.removeSessionCookies(null); + } + + public String getSanitizedDomain(String url) throws URISyntaxException { + if (this.serverUrl != null && !this.serverUrl.isEmpty() && (url == null || url.isEmpty() || this.serverUrl.contains(url))) { + url = this.serverUrl; + } else if (this.localUrl != null && !this.localUrl.isEmpty() && (url == null || url.isEmpty() || this.localUrl.contains(url))) { + url = this.localUrl; + } else try { + URI uri = new URI(url); + String scheme = uri.getScheme(); + if (scheme == null || scheme.isEmpty()) { + url = "https://" + url; + } + } catch (URISyntaxException e) { + Logger.error(TAG, "Failed to get scheme from URL.", e); + } + + try { + new URI(url); + } catch (Exception error) { + Logger.error(TAG, "Failed to get sanitized URL.", error); + throw error; + } + return url; + } + + private String getDomainFromCookieString(String cookie) throws URISyntaxException { + String[] domain = cookie.toLowerCase(Locale.ROOT).split("domain="); + return getSanitizedDomain(domain.length <= 1 ? null : domain[1].split(";")[0].trim()); + } + + /** + * Gets the cookies for the given URL. + * @param url the URL for which the cookies are requested + * @return value the cookies as a string, using the format of the 'Cookie' HTTP request header + */ + public String getCookieString(String url) { + try { + url = getSanitizedDomain(url); + Logger.info(TAG, "Getting cookies at: '" + url + "'"); + return webkitCookieManager.getCookie(url); + } catch (Exception error) { + Logger.error(TAG, "Failed to get cookies at the given URL.", error); + } + + return null; + } + + /** + * Gets a cookie value for the given URL and key. + * @param url the URL for which the cookies are requested + * @param key the key of the cookie to search for + * @return the {@code HttpCookie} value of the cookie at the key, + * otherwise it will return a new empty {@code HttpCookie} + */ + public HttpCookie getCookie(String url, String key) { + HttpCookie[] cookies = getCookies(url); + for (HttpCookie cookie : cookies) { + if (cookie.getName().equals(key)) { + return cookie; + } + } + + return null; + } + + /** + * Gets an array of {@code HttpCookie} given a URL. + * @param url the URL for which the cookies are requested + * @return an {@code HttpCookie} array of non-expired cookies + */ + public HttpCookie[] getCookies(String url) { + try { + ArrayList cookieList = new ArrayList<>(); + String cookieString = getCookieString(url); + if (cookieString != null) { + String[] singleCookie = cookieString.split(";"); + for (String c : singleCookie) { + HttpCookie parsed = HttpCookie.parse(c).get(0); + parsed.setValue(parsed.getValue()); + cookieList.add(parsed); + } + } + HttpCookie[] cookies = new HttpCookie[cookieList.size()]; + return cookieList.toArray(cookies); + } catch (Exception ex) { + return new HttpCookie[0]; + } + } + + /** + * Sets a cookie for the given URL. Any existing cookie with the same host, path and name will + * be replaced with the new cookie. The cookie being set will be ignored if it is expired. + * @param url the URL for which the cookie is to be set + * @param value the cookie as a string, using the format of the 'Set-Cookie' HTTP response header + */ + public void setCookie(String url, String value) { + try { + url = getSanitizedDomain(url); + Logger.info(TAG, "Setting cookie '" + value + "' at: '" + url + "'"); + webkitCookieManager.setCookie(url, value); + flush(); + } catch (Exception error) { + Logger.error(TAG, "Failed to set cookie.", error); + } + } + + /** + * Sets a cookie for the given URL. Any existing cookie with the same host, path and name will + * be replaced with the new cookie. The cookie being set will be ignored if it is expired. + * @param url the URL for which the cookie is to be set + * @param key the {@code HttpCookie} name to use for lookup + * @param value the value of the {@code HttpCookie} given a key + */ + public void setCookie(String url, String key, String value) { + String cookieValue = key + "=" + value; + setCookie(url, cookieValue); + } + + public void setCookie(String url, String key, String value, String expires, String path) { + String cookieValue = key + "=" + value + "; expires=" + expires + "; path=" + path; + setCookie(url, cookieValue); + } + + /** + * Removes all cookies. This method is asynchronous. + */ + public void removeAllCookies() { + webkitCookieManager.removeAllCookies(null); + flush(); + } + + /** + * Ensures all cookies currently accessible through the getCookie API are written to persistent + * storage. This call will block the caller until it is done and may perform I/O. + */ + public void flush() { + webkitCookieManager.flush(); + } + + @Override + public void put(URI uri, Map> responseHeaders) { + // make sure our args are valid + if ((uri == null) || (responseHeaders == null)) return; + + // go over the headers + for (String headerKey : responseHeaders.keySet()) { + // ignore headers which aren't cookie related + if ((headerKey == null) || !(headerKey.equalsIgnoreCase("Set-Cookie2") || headerKey.equalsIgnoreCase("Set-Cookie"))) continue; + + // process each of the headers + for (String headerValue : Objects.requireNonNull(responseHeaders.get(headerKey))) { + try { + // Set at the requested server url + setCookie(uri.toString(), headerValue); + + // Set at the defined domain in the response or at default capacitor hosted url + setCookie(getDomainFromCookieString(headerValue), headerValue); + } catch (Exception ignored) {} + } + } + } + + @Override + public Map> get(URI uri, Map> requestHeaders) { + // make sure our args are valid + if ((uri == null) || (requestHeaders == null)) throw new IllegalArgumentException("Argument is null"); + + // save our url once + String url = uri.toString(); + + // prepare our response + Map> res = new HashMap<>(); + + // get the cookie + String cookie = getCookieString(url); + + // return it + if (cookie != null) res.put("Cookie", Collections.singletonList(cookie)); + return res; + } + + @Override + public CookieStore getCookieStore() { + // we don't want anyone to work with this cookie store directly + throw new UnsupportedOperationException(); + } +} diff --git a/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/plugin/CapacitorCookies.java b/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/plugin/CapacitorCookies.java new file mode 100644 index 0000000..6ba4605 --- /dev/null +++ b/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/plugin/CapacitorCookies.java @@ -0,0 +1,119 @@ +package com.getcapacitor.plugin; + +import android.webkit.JavascriptInterface; +import com.getcapacitor.JSObject; +import com.getcapacitor.Plugin; +import com.getcapacitor.PluginCall; +import com.getcapacitor.PluginConfig; +import com.getcapacitor.PluginMethod; +import com.getcapacitor.annotation.CapacitorPlugin; +import java.io.UnsupportedEncodingException; +import java.net.CookieHandler; +import java.net.HttpCookie; +import java.net.URLDecoder; +import java.nio.charset.StandardCharsets; + +@CapacitorPlugin +public class CapacitorCookies extends Plugin { + + CapacitorCookieManager cookieManager; + + @Override + public void load() { + this.bridge.getWebView().addJavascriptInterface(this, "CapacitorCookiesAndroidInterface"); + this.cookieManager = new CapacitorCookieManager(null, java.net.CookiePolicy.ACCEPT_ALL, this.bridge); + this.cookieManager.removeSessionCookies(); + CookieHandler.setDefault(this.cookieManager); + super.load(); + } + + @Override + protected void handleOnDestroy() { + super.handleOnDestroy(); + this.cookieManager.removeSessionCookies(); + } + + @JavascriptInterface + public boolean isEnabled() { + PluginConfig pluginConfig = getBridge().getConfig().getPluginConfiguration("CapacitorCookies"); + return pluginConfig.getBoolean("enabled", false); + } + + @JavascriptInterface + public void setCookie(String domain, String action) { + cookieManager.setCookie(domain, action); + } + + @PluginMethod + public void getCookies(PluginCall call) { + this.bridge.eval("document.cookie", (value) -> { + String cookies = value.substring(1, value.length() - 1); + String[] cookieArray = cookies.split(";"); + + JSObject cookieMap = new JSObject(); + + for (String cookie : cookieArray) { + if (cookie.length() > 0) { + String[] keyValue = cookie.split("=", 2); + + if (keyValue.length == 2) { + String key = keyValue[0].trim(); + String val = keyValue[1].trim(); + try { + key = URLDecoder.decode(keyValue[0].trim(), StandardCharsets.UTF_8.name()); + val = URLDecoder.decode(keyValue[1].trim(), StandardCharsets.UTF_8.name()); + } catch (UnsupportedEncodingException ignored) {} + + cookieMap.put(key, val); + } + } + } + + call.resolve(cookieMap); + }); + } + + @PluginMethod + public void setCookie(PluginCall call) { + String key = call.getString("key"); + if (null == key) { + call.reject("Must provide key"); + } + String value = call.getString("value"); + if (null == value) { + call.reject("Must provide value"); + } + String url = call.getString("url"); + String expires = call.getString("expires", ""); + String path = call.getString("path", "/"); + cookieManager.setCookie(url, key, value, expires, path); + call.resolve(); + } + + @PluginMethod + public void deleteCookie(PluginCall call) { + String key = call.getString("key"); + if (null == key) { + call.reject("Must provide key"); + } + String url = call.getString("url"); + cookieManager.setCookie(url, key + "=; Expires=Wed, 31 Dec 2000 23:59:59 GMT"); + call.resolve(); + } + + @PluginMethod + public void clearCookies(PluginCall call) { + String url = call.getString("url"); + HttpCookie[] cookies = cookieManager.getCookies(url); + for (HttpCookie cookie : cookies) { + cookieManager.setCookie(url, cookie.getName() + "=; Expires=Wed, 31 Dec 2000 23:59:59 GMT"); + } + call.resolve(); + } + + @PluginMethod + public void clearAllCookies(PluginCall call) { + cookieManager.removeAllCookies(); + call.resolve(); + } +} diff --git a/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/plugin/CapacitorHttp.java b/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/plugin/CapacitorHttp.java new file mode 100644 index 0000000..46bc174 --- /dev/null +++ b/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/plugin/CapacitorHttp.java @@ -0,0 +1,119 @@ +package com.getcapacitor.plugin; + +import android.Manifest; +import android.webkit.JavascriptInterface; +import com.getcapacitor.JSObject; +import com.getcapacitor.Plugin; +import com.getcapacitor.PluginCall; +import com.getcapacitor.PluginConfig; +import com.getcapacitor.PluginMethod; +import com.getcapacitor.annotation.CapacitorPlugin; +import com.getcapacitor.annotation.Permission; +import com.getcapacitor.plugin.util.CapacitorHttpUrlConnection; +import com.getcapacitor.plugin.util.HttpRequestHandler; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +@CapacitorPlugin( + permissions = { + @Permission(strings = { Manifest.permission.WRITE_EXTERNAL_STORAGE }, alias = "HttpWrite"), + @Permission(strings = { Manifest.permission.READ_EXTERNAL_STORAGE }, alias = "HttpRead") + } +) +public class CapacitorHttp extends Plugin { + + private final Map activeRequests = new ConcurrentHashMap<>(); + private final ExecutorService executor = Executors.newCachedThreadPool(); + + @Override + public void load() { + this.bridge.getWebView().addJavascriptInterface(this, "CapacitorHttpAndroidInterface"); + super.load(); + } + + @Override + protected void handleOnDestroy() { + super.handleOnDestroy(); + + for (Map.Entry entry : activeRequests.entrySet()) { + Runnable job = entry.getKey(); + PluginCall call = entry.getValue(); + + if (call.getData().has("activeCapacitorHttpUrlConnection")) { + try { + CapacitorHttpUrlConnection connection = (CapacitorHttpUrlConnection) call + .getData() + .get("activeCapacitorHttpUrlConnection"); + connection.disconnect(); + call.getData().remove("activeCapacitorHttpUrlConnection"); + } catch (Exception ignored) {} + } + + getBridge().releaseCall(call); + } + + activeRequests.clear(); + executor.shutdownNow(); + } + + private void http(final PluginCall call, final String httpMethod) { + Runnable asyncHttpCall = new Runnable() { + @Override + public void run() { + try { + JSObject response = HttpRequestHandler.request(call, httpMethod, getBridge()); + call.resolve(response); + } catch (Exception e) { + call.reject(e.getLocalizedMessage(), e.getClass().getSimpleName(), e); + } finally { + activeRequests.remove(this); + } + } + }; + + if (!executor.isShutdown()) { + activeRequests.put(asyncHttpCall, call); + executor.submit(asyncHttpCall); + } else { + call.reject("Failed to execute request - Http Plugin was shutdown"); + } + } + + @JavascriptInterface + public boolean isEnabled() { + PluginConfig pluginConfig = getBridge().getConfig().getPluginConfiguration("CapacitorHttp"); + return pluginConfig.getBoolean("enabled", false); + } + + @PluginMethod + public void request(final PluginCall call) { + this.http(call, null); + } + + @PluginMethod + public void get(final PluginCall call) { + this.http(call, "GET"); + } + + @PluginMethod + public void post(final PluginCall call) { + this.http(call, "POST"); + } + + @PluginMethod + public void put(final PluginCall call) { + this.http(call, "PUT"); + } + + @PluginMethod + public void patch(final PluginCall call) { + this.http(call, "PATCH"); + } + + @PluginMethod + public void delete(final PluginCall call) { + this.http(call, "DELETE"); + } +} diff --git a/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/plugin/SystemBars.java b/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/plugin/SystemBars.java new file mode 100644 index 0000000..b335b4b --- /dev/null +++ b/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/plugin/SystemBars.java @@ -0,0 +1,346 @@ +package com.getcapacitor.plugin; + +import android.content.Context; +import android.content.pm.PackageInfo; +import android.content.res.Configuration; +import android.content.res.Resources; +import android.os.Build; +import android.util.TypedValue; +import android.view.View; +import android.view.Window; +import android.webkit.JavascriptInterface; +import android.webkit.WebView; +import androidx.core.graphics.Insets; +import androidx.core.view.ViewCompat; +import androidx.core.view.WindowCompat; +import androidx.core.view.WindowInsetsCompat; +import androidx.core.view.WindowInsetsControllerCompat; +import androidx.webkit.WebViewCompat; +import com.getcapacitor.Plugin; +import com.getcapacitor.PluginCall; +import com.getcapacitor.PluginMethod; +import com.getcapacitor.WebViewListener; +import com.getcapacitor.annotation.CapacitorPlugin; +import java.util.Locale; + +@CapacitorPlugin +public class SystemBars extends Plugin { + + static final String STYLE_LIGHT = "LIGHT"; + static final String STYLE_DARK = "DARK"; + static final String STYLE_DEFAULT = "DEFAULT"; + static final String BAR_STATUS_BAR = "StatusBar"; + static final String BAR_GESTURE_BAR = "NavigationBar"; + + static final String INSETS_HANDLING_CSS = "css"; + static final String INSETS_HANDLING_DISABLE = "disable"; + + // https://issues.chromium.org/issues/40699457 + private static final int WEBVIEW_VERSION_WITH_SAFE_AREA_FIX = 140; + // https://issues.chromium.org/issues/457682720 + private static final int WEBVIEW_VERSION_WITH_SAFE_AREA_KEYBOARD_FIX = 144; + + static final String viewportMetaJSFunction = """ + function capacitorSystemBarsCheckMetaViewport() { + const meta = document.querySelectorAll("meta[name=viewport]"); + if (meta.length == 0) { + return false; + } + // get the last found meta viewport tag + const metaContent = meta[meta.length - 1].content; + return metaContent.includes("viewport-fit=cover"); + } + capacitorSystemBarsCheckMetaViewport(); + """; + + private boolean insetHandlingEnabled = true; + private boolean hasViewportCover = false; + + private String currentStatusBarStyle = STYLE_DEFAULT; + private String currentGestureBarStyle = STYLE_DEFAULT; + + @Override + public void load() { + getBridge().getWebView().addJavascriptInterface(this, "CapacitorSystemBarsAndroidInterface"); + super.load(); + + initSystemBars(); + } + + @Override + protected void handleOnStart() { + super.handleOnStart(); + + this.getBridge().addWebViewListener( + new WebViewListener() { + @Override + public void onPageCommitVisible(WebView view, String url) { + super.onPageCommitVisible(view, url); + getBridge().getWebView().requestApplyInsets(); + } + } + ); + } + + @Override + protected void handleOnConfigurationChanged(Configuration newConfig) { + super.handleOnConfigurationChanged(newConfig); + + setStyle(currentGestureBarStyle, BAR_GESTURE_BAR); + setStyle(currentStatusBarStyle, BAR_STATUS_BAR); + } + + private void initSystemBars() { + String style = getConfig().getString("style", STYLE_DEFAULT).toUpperCase(Locale.US); + boolean hidden = getConfig().getBoolean("hidden", false); + + String insetsHandling = getConfig().getString("insetsHandling", "css"); + if (insetsHandling.equals(INSETS_HANDLING_DISABLE)) { + insetHandlingEnabled = false; + } + + initWindowInsetsListener(); + initSafeAreaCSSVariables(); + + getBridge().executeOnMainThread(() -> { + setStyle(style, ""); + setHidden(hidden, ""); + }); + } + + @PluginMethod + public void setStyle(final PluginCall call) { + String bar = call.getString("bar", ""); + String style = call.getString("style", STYLE_DEFAULT); + + getBridge().executeOnMainThread(() -> { + setStyle(style, bar); + call.resolve(); + }); + } + + @PluginMethod + public void show(final PluginCall call) { + String bar = call.getString("bar", ""); + + getBridge().executeOnMainThread(() -> { + setHidden(false, bar); + call.resolve(); + }); + } + + @PluginMethod + public void hide(final PluginCall call) { + String bar = call.getString("bar", ""); + + getBridge().executeOnMainThread(() -> { + setHidden(true, bar); + call.resolve(); + }); + } + + @PluginMethod + public void setAnimation(final PluginCall call) { + call.resolve(); + } + + @JavascriptInterface + public void onDOMReady() { + getActivity().runOnUiThread(() -> { + this.bridge.getWebView().evaluateJavascript(viewportMetaJSFunction, (res) -> { + hasViewportCover = res.equals("true"); + + getBridge().getWebView().requestApplyInsets(); + }); + }); + } + + private Insets calcSafeAreaInsets(WindowInsetsCompat insets) { + Insets safeArea = insets.getInsets(WindowInsetsCompat.Type.systemBars() | WindowInsetsCompat.Type.displayCutout()); + if (insets.isVisible(WindowInsetsCompat.Type.ime())) { + return Insets.of(safeArea.left, safeArea.top, safeArea.right, 0); + } + return Insets.of(safeArea.left, safeArea.top, safeArea.right, safeArea.bottom); + } + + private void initSafeAreaCSSVariables() { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM && insetHandlingEnabled) { + View v = (View) this.getBridge().getWebView().getParent(); + WindowInsetsCompat insets = ViewCompat.getRootWindowInsets(v); + if (insets != null) { + Insets safeAreaInsets = calcSafeAreaInsets(insets); + injectSafeAreaCSS(safeAreaInsets.top, safeAreaInsets.right, safeAreaInsets.bottom, safeAreaInsets.left); + } + } + } + + private void initWindowInsetsListener() { + ViewCompat.setOnApplyWindowInsetsListener((View) getBridge().getWebView().getParent(), (v, insets) -> { + boolean shouldPassthroughInsets = getWebViewMajorVersion() >= WEBVIEW_VERSION_WITH_SAFE_AREA_FIX && hasViewportCover; + + Insets systemBarsInsets = insets.getInsets(WindowInsetsCompat.Type.systemBars() | WindowInsetsCompat.Type.displayCutout()); + Insets imeInsets = insets.getInsets(WindowInsetsCompat.Type.ime()); + boolean keyboardVisible = insets.isVisible(WindowInsetsCompat.Type.ime()); + + if (shouldPassthroughInsets) { + // We need to correct for a possible shown IME + v.setPadding(0, 0, 0, keyboardVisible ? imeInsets.bottom : 0); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM && hasViewportCover && insetHandlingEnabled) { + Insets safeAreaInsets = calcSafeAreaInsets(insets); + injectSafeAreaCSS(safeAreaInsets.top, safeAreaInsets.right, safeAreaInsets.bottom, safeAreaInsets.left); + } + + return new WindowInsetsCompat.Builder(insets) + .setInsets( + WindowInsetsCompat.Type.systemBars() | WindowInsetsCompat.Type.displayCutout(), + Insets.of( + systemBarsInsets.left, + systemBarsInsets.top, + systemBarsInsets.right, + getBottomInset(systemBarsInsets, keyboardVisible) + ) + ) + .build(); + } + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM) { + // We need to correct for a possible shown IME + v.setPadding( + systemBarsInsets.left, + systemBarsInsets.top, + systemBarsInsets.right, + keyboardVisible ? imeInsets.bottom : systemBarsInsets.bottom + ); + } + + // Returning `WindowInsetsCompat.CONSUMED` breaks recalculation of safe area insets + // So we have to explicitly set insets to `0` + // See: https://issues.chromium.org/issues/461332423 + WindowInsetsCompat newInsets = new WindowInsetsCompat.Builder(insets) + .setInsets(WindowInsetsCompat.Type.systemBars() | WindowInsetsCompat.Type.displayCutout(), Insets.of(0, 0, 0, 0)) + .build(); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM && hasViewportCover && insetHandlingEnabled) { + Insets safeAreaInsets = calcSafeAreaInsets(newInsets); + injectSafeAreaCSS(safeAreaInsets.top, safeAreaInsets.right, safeAreaInsets.bottom, safeAreaInsets.left); + } + + return newInsets; + }); + } + + private void injectSafeAreaCSS(int top, int right, int bottom, int left) { + // Convert pixels to density-independent pixels + float density = getActivity().getResources().getDisplayMetrics().density; + float topPx = top / density; + float rightPx = right / density; + float bottomPx = bottom / density; + float leftPx = left / density; + + // Execute JavaScript to inject the CSS + getBridge().executeOnMainThread(() -> { + if (bridge != null && bridge.getWebView() != null) { + String script = String.format( + Locale.US, + """ + try { + document.documentElement.style.setProperty("--safe-area-inset-top", "%dpx"); + document.documentElement.style.setProperty("--safe-area-inset-right", "%dpx"); + document.documentElement.style.setProperty("--safe-area-inset-bottom", "%dpx"); + document.documentElement.style.setProperty("--safe-area-inset-left", "%dpx"); + } catch(e) { console.error('Error injecting safe area CSS:', e); } + """, + (int) topPx, + (int) rightPx, + (int) bottomPx, + (int) leftPx + ); + + bridge.getWebView().evaluateJavascript(script, null); + } + }); + } + + private void setStyle(String style, String bar) { + if (style.equals(STYLE_DEFAULT)) { + style = getStyleForTheme(); + } + + Window window = getActivity().getWindow(); + WindowInsetsControllerCompat windowInsetsControllerCompat = WindowCompat.getInsetsController(window, window.getDecorView()); + if (bar.isEmpty() || bar.equals(BAR_STATUS_BAR)) { + currentStatusBarStyle = style; + windowInsetsControllerCompat.setAppearanceLightStatusBars(!style.equals(STYLE_DARK)); + } + + if (bar.isEmpty() || bar.equals(BAR_GESTURE_BAR)) { + currentGestureBarStyle = style; + windowInsetsControllerCompat.setAppearanceLightNavigationBars(!style.equals(STYLE_DARK)); + } + + getActivity().getWindow().getDecorView().setBackgroundColor(getThemeColor(getContext(), android.R.attr.windowBackground)); + } + + private void setHidden(boolean hide, String bar) { + Window window = getActivity().getWindow(); + WindowInsetsControllerCompat windowInsetsControllerCompat = WindowCompat.getInsetsController(window, window.getDecorView()); + + if (hide) { + if (bar.isEmpty() || bar.equals(BAR_STATUS_BAR)) { + windowInsetsControllerCompat.hide(WindowInsetsCompat.Type.statusBars()); + } + if (bar.isEmpty() || bar.equals(BAR_GESTURE_BAR)) { + windowInsetsControllerCompat.hide(WindowInsetsCompat.Type.navigationBars()); + } + return; + } + + if (bar.isEmpty() || bar.equals(BAR_STATUS_BAR)) { + windowInsetsControllerCompat.show(WindowInsetsCompat.Type.systemBars()); + } + if (bar.isEmpty() || bar.equals(BAR_GESTURE_BAR)) { + windowInsetsControllerCompat.show(WindowInsetsCompat.Type.navigationBars()); + } + } + + private String getStyleForTheme() { + int currentNightMode = getActivity().getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK; + if (currentNightMode != Configuration.UI_MODE_NIGHT_YES) { + return STYLE_LIGHT; + } + return STYLE_DARK; + } + + public int getThemeColor(Context context, int attrRes) { + TypedValue typedValue = new TypedValue(); + + Resources.Theme theme = context.getTheme(); + theme.resolveAttribute(attrRes, typedValue, true); + return typedValue.data; + } + + private Integer getWebViewMajorVersion() { + PackageInfo info = WebViewCompat.getCurrentWebViewPackage(getContext()); + if (info != null && info.versionName != null) { + String[] versionSegments = info.versionName.split("\\."); + return Integer.valueOf(versionSegments[0]); + } + + return 0; + } + + private int getBottomInset(Insets systemBarsInsets, boolean keyboardVisible) { + if (getWebViewMajorVersion() < WEBVIEW_VERSION_WITH_SAFE_AREA_KEYBOARD_FIX) { + // This is a workaround for webview versions that have a bug + // that causes the bottom inset to be incorrect if the IME is visible + // See: https://issues.chromium.org/issues/457682720 + + if (keyboardVisible) { + return 0; + } + } + + return systemBarsInsets.bottom; + } +} diff --git a/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/plugin/WebView.java b/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/plugin/WebView.java new file mode 100644 index 0000000..096d62a --- /dev/null +++ b/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/plugin/WebView.java @@ -0,0 +1,48 @@ +package com.getcapacitor.plugin; + +import android.app.Activity; +import android.content.SharedPreferences; +import com.getcapacitor.JSObject; +import com.getcapacitor.Plugin; +import com.getcapacitor.PluginCall; +import com.getcapacitor.PluginMethod; +import com.getcapacitor.annotation.CapacitorPlugin; + +@CapacitorPlugin +public class WebView extends Plugin { + + public static final String WEBVIEW_PREFS_NAME = "CapWebViewSettings"; + public static final String CAP_SERVER_PATH = "serverBasePath"; + + @PluginMethod + public void setServerAssetPath(PluginCall call) { + String path = call.getString("path"); + bridge.setServerAssetPath(path); + call.resolve(); + } + + @PluginMethod + public void setServerBasePath(PluginCall call) { + String path = call.getString("path"); + bridge.setServerBasePath(path); + call.resolve(); + } + + @PluginMethod + public void getServerBasePath(PluginCall call) { + String path = bridge.getServerBasePath(); + JSObject ret = new JSObject(); + ret.put("path", path); + call.resolve(ret); + } + + @PluginMethod + public void persistServerBasePath(PluginCall call) { + String path = bridge.getServerBasePath(); + SharedPreferences prefs = getContext().getSharedPreferences(WEBVIEW_PREFS_NAME, Activity.MODE_PRIVATE); + SharedPreferences.Editor editor = prefs.edit(); + editor.putString(CAP_SERVER_PATH, path); + editor.apply(); + call.resolve(); + } +} diff --git a/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/plugin/util/AssetUtil.java b/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/plugin/util/AssetUtil.java new file mode 100644 index 0000000..3a7043b --- /dev/null +++ b/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/plugin/util/AssetUtil.java @@ -0,0 +1,358 @@ +package com.getcapacitor.plugin.util; + +import android.content.ContentResolver; +import android.content.Context; +import android.content.res.AssetManager; +import android.content.res.Resources; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.net.Uri; +import android.os.StrictMode; +import androidx.core.content.FileProvider; +import com.getcapacitor.Logger; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.HttpURLConnection; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.UUID; + +/** + * Manager for assets. + */ +public final class AssetUtil { + + public static final int RESOURCE_ID_ZERO_VALUE = 0; + // Name of the storage folder + private static final String STORAGE_FOLDER = "/capacitorassets"; + + // Ref to the context passed through the constructor to access the + // resources and app directory. + private final Context context; + + /** + * Constructor + * + * @param context Application context. + */ + private AssetUtil(Context context) { + this.context = context; + } + + /** + * Static method to retrieve class instance. + * + * @param context Application context. + */ + public static AssetUtil getInstance(Context context) { + return new AssetUtil(context); + } + + /** + * The URI for a path. + * + * @param path The given path. + */ + public Uri parse(String path) { + if (path == null || path.isEmpty()) { + return Uri.EMPTY; + } else if (path.startsWith("res:")) { + return getUriForResourcePath(path); + } else if (path.startsWith("file:///")) { + return getUriFromPath(path); + } else if (path.startsWith("file://")) { + return getUriFromAsset(path); + } else if (path.startsWith("http")) { + return getUriFromRemote(path); + } else if (path.startsWith("content://")) { + return Uri.parse(path); + } + + return Uri.EMPTY; + } + + /** + * URI for a file. + * + * @param path Absolute path like file:///... + * + * @return URI pointing to the given path. + */ + private Uri getUriFromPath(String path) { + String absPath = path.replaceFirst("file://", "").replaceFirst("\\?.*$", ""); + File file = new File(absPath); + + if (!file.exists()) { + Logger.error("File not found: " + file.getAbsolutePath()); + return Uri.EMPTY; + } + + return getUriFromFile(file); + } + + /** + * URI for an asset. + * + * @param path Asset path like file://... + * + * @return URI pointing to the given path. + */ + private Uri getUriFromAsset(String path) { + String resPath = path.replaceFirst("file:/", "www").replaceFirst("\\?.*$", ""); + String fileName = resPath.substring(resPath.lastIndexOf('/') + 1); + File file = getTmpFile(fileName); + + if (file == null) return Uri.EMPTY; + + try { + AssetManager assets = context.getAssets(); + InputStream in = assets.open(resPath); + FileOutputStream out = new FileOutputStream(file); + copyFile(in, out); + } catch (Exception e) { + Logger.error("File not found: assets/" + resPath); + return Uri.EMPTY; + } + + return getUriFromFile(file); + } + + /** + * The URI for a resource. + * + * @param path The given relative path. + * + * @return URI pointing to the given path. + */ + private Uri getUriForResourcePath(String path) { + Resources res = context.getResources(); + String resPath = path.replaceFirst("res://", ""); + int resId = getResId(resPath); + + if (resId == 0) { + Logger.error("File not found: " + resPath); + return Uri.EMPTY; + } + + return new Uri.Builder() + .scheme(ContentResolver.SCHEME_ANDROID_RESOURCE) + .authority(res.getResourcePackageName(resId)) + .appendPath(res.getResourceTypeName(resId)) + .appendPath(res.getResourceEntryName(resId)) + .build(); + } + + /** + * Uri from remote located content. + * + * @param path Remote address. + * + * @return Uri of the downloaded file. + */ + private Uri getUriFromRemote(String path) { + File file = getTmpFile(); + + if (file == null) return Uri.EMPTY; + + try { + URL url = new URL(path); + HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + + StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build(); + + StrictMode.setThreadPolicy(policy); + + connection.setRequestProperty("Connection", "close"); + connection.setConnectTimeout(5000); + connection.connect(); + + InputStream in = connection.getInputStream(); + FileOutputStream out = new FileOutputStream(file); + + copyFile(in, out); + return getUriFromFile(file); + } catch (MalformedURLException e) { + Logger.error(Logger.tags("Asset"), "Incorrect URL", e); + } catch (FileNotFoundException e) { + Logger.error(Logger.tags("Asset"), "Failed to create new File from HTTP Content", e); + } catch (IOException e) { + Logger.error(Logger.tags("Asset"), "No Input can be created from http Stream", e); + } + + return Uri.EMPTY; + } + + /** + * Copy content from input stream into output stream. + * + * @param in The input stream. + * @param out The output stream. + */ + private void copyFile(InputStream in, FileOutputStream out) { + byte[] buffer = new byte[1024]; + int read; + + try { + while ((read = in.read(buffer)) != -1) { + out.write(buffer, 0, read); + } + out.flush(); + out.close(); + } catch (Exception e) { + Logger.error("Error copying", e); + } + } + + /** + * Resource ID for drawable. + * + * @param resPath Resource path as string. + * + * @return The resource ID or 0 if not found. + */ + public int getResId(String resPath) { + int resId = getResId(context.getResources(), resPath); + + if (resId == 0) { + resId = getResId(Resources.getSystem(), resPath); + } + + return resId; + } + + /** + * Get resource ID. + * + * @param res The resources where to look for. + * @param resPath The name of the resource. + * + * @return The resource ID or 0 if not found. + */ + private int getResId(Resources res, String resPath) { + String pkgName = getPkgName(res); + String resName = getBaseName(resPath); + int resId; + + resId = res.getIdentifier(resName, "mipmap", pkgName); + + if (resId == 0) { + resId = res.getIdentifier(resName, "drawable", pkgName); + } + + if (resId == 0) { + resId = res.getIdentifier(resName, "raw", pkgName); + } + + return resId; + } + + /** + * Convert URI to Bitmap. + * + * @param uri Internal image URI + */ + public Bitmap getIconFromUri(Uri uri) throws IOException { + InputStream input = context.getContentResolver().openInputStream(uri); + return BitmapFactory.decodeStream(input); + } + + /** + * Extract name of drawable resource from path. + * + * @param resPath Resource path as string. + */ + private String getBaseName(String resPath) { + String drawable = resPath; + + if (drawable.contains("/")) { + drawable = drawable.substring(drawable.lastIndexOf('/') + 1); + } + + if (resPath.contains(".")) { + drawable = drawable.substring(0, drawable.lastIndexOf('.')); + } + + return drawable; + } + + /** + * Returns a file located under the external cache dir of that app. + * + * @return File with a random UUID name. + */ + private File getTmpFile() { + return getTmpFile(UUID.randomUUID().toString()); + } + + /** + * Returns a file located under the external cache dir of that app. + * + * @param name The name of the file. + * + * @return File with the provided name. + */ + private File getTmpFile(String name) { + File dir = context.getExternalCacheDir(); + + if (dir == null) { + dir = context.getCacheDir(); + } + + if (dir == null) { + Logger.error(Logger.tags("Asset"), "Missing cache dir", null); + return null; + } + + String storage = dir.toString() + STORAGE_FOLDER; + + //noinspection ResultOfMethodCallIgnored + new File(storage).mkdir(); + + return new File(storage, name); + } + + /** + * Get content URI for the specified file. + * + * @param file The file to get the URI. + * + * @return content://... + */ + private Uri getUriFromFile(File file) { + try { + String authority = context.getPackageName() + ".provider"; + return FileProvider.getUriForFile(context, authority, file); + } catch (IllegalArgumentException e) { + Logger.error("File not supported by provider", e); + return Uri.EMPTY; + } + } + + /** + * Package name specified by the resource bundle. + */ + private String getPkgName(Resources res) { + return res == Resources.getSystem() ? "android" : context.getPackageName(); + } + + public static int getResourceID(Context context, String resourceName, String dir) { + return context.getResources().getIdentifier(resourceName, dir, context.getPackageName()); + } + + public static String getResourceBaseName(String resPath) { + if (resPath == null) return null; + + if (resPath.contains("/")) { + return resPath.substring(resPath.lastIndexOf('/') + 1); + } + + if (resPath.contains(".")) { + return resPath.substring(0, resPath.lastIndexOf('.')); + } + + return resPath; + } +} diff --git a/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/plugin/util/CapacitorHttpUrlConnection.java b/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/plugin/util/CapacitorHttpUrlConnection.java new file mode 100644 index 0000000..6180d64 --- /dev/null +++ b/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/plugin/util/CapacitorHttpUrlConnection.java @@ -0,0 +1,515 @@ +package com.getcapacitor.plugin.util; + +import android.os.Build; +import android.os.LocaleList; +import android.text.TextUtils; +import com.getcapacitor.Bridge; +import com.getcapacitor.JSArray; +import com.getcapacitor.JSObject; +import com.getcapacitor.JSValue; +import com.getcapacitor.PluginCall; +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.lang.reflect.Method; +import java.net.HttpURLConnection; +import java.net.ProtocolException; +import java.net.SocketTimeoutException; +import java.net.URL; +import java.net.URLEncoder; +import java.net.UnknownServiceException; +import java.nio.charset.StandardCharsets; +import java.util.Base64; +import java.util.Iterator; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.UUID; +import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.SSLSocketFactory; +import org.json.JSONException; +import org.json.JSONObject; + +public class CapacitorHttpUrlConnection implements ICapacitorHttpUrlConnection { + + private final HttpURLConnection connection; + + /** + * Make a new CapacitorHttpUrlConnection instance, which wraps around HttpUrlConnection + * and provides some helper functions for setting request headers and the request body + * @param conn the base HttpUrlConnection. You can pass the value from + * {@code (HttpUrlConnection) URL.openConnection()} + */ + public CapacitorHttpUrlConnection(HttpURLConnection conn) { + connection = conn; + this.setDefaultRequestProperties(); + } + + /** + * Returns the underlying HttpUrlConnection value + * @return the underlying HttpUrlConnection value + */ + public HttpURLConnection getHttpConnection() { + return connection; + } + + public void disconnect() { + connection.disconnect(); + } + + /** + * Set the value of the {@code allowUserInteraction} field of + * this {@code URLConnection}. + * + * @param isAllowedInteraction the new value. + * @throws IllegalStateException if already connected + */ + public void setAllowUserInteraction(boolean isAllowedInteraction) { + connection.setAllowUserInteraction(isAllowedInteraction); + } + + /** + * Set the method for the URL request, one of: + *
    + *
  • GET + *
  • POST + *
  • HEAD + *
  • OPTIONS + *
  • PUT + *
  • DELETE + *
  • TRACE + *
are legal, subject to protocol restrictions. The default + * method is GET. + * + * @param method the HTTP method + * @exception ProtocolException if the method cannot be reset or if + * the requested method isn't valid for HTTP. + * @exception SecurityException if a security manager is set and the + * method is "TRACE", but the "allowHttpTrace" + * NetPermission is not granted. + */ + public void setRequestMethod(String method) throws ProtocolException { + connection.setRequestMethod(method); + } + + /** + * Sets a specified timeout value, in milliseconds, to be used + * when opening a communications link to the resource referenced + * by this URLConnection. If the timeout expires before the + * connection can be established, a + * java.net.SocketTimeoutException is raised. A timeout of zero is + * interpreted as an infinite timeout. + * + *

Warning: If the hostname resolves to multiple IP + * addresses, Android's default implementation of {@link HttpURLConnection} + * will try each in + * RFC 3484 order. If + * connecting to each of these addresses fails, multiple timeouts will + * elapse before the connect attempt throws an exception. Host names + * that support both IPv6 and IPv4 always have at least 2 IP addresses. + * + * @param timeout an {@code int} that specifies the connect + * timeout value in milliseconds + * @throws IllegalArgumentException if the timeout parameter is negative + */ + public void setConnectTimeout(int timeout) { + if (timeout < 0) { + throw new IllegalArgumentException("timeout can not be negative"); + } + connection.setConnectTimeout(timeout); + } + + /** + * Sets the read timeout to a specified timeout, in + * milliseconds. A non-zero value specifies the timeout when + * reading from Input stream when a connection is established to a + * resource. If the timeout expires before there is data available + * for read, a java.net.SocketTimeoutException is raised. A + * timeout of zero is interpreted as an infinite timeout. + * + * @param timeout an {@code int} that specifies the timeout + * value to be used in milliseconds + * @throws IllegalArgumentException if the timeout parameter is negative + */ + public void setReadTimeout(int timeout) { + if (timeout < 0) { + throw new IllegalArgumentException("timeout can not be negative"); + } + connection.setReadTimeout(timeout); + } + + /** + * Sets whether automatic HTTP redirects should be disabled + * @param disableRedirects the flag to determine if redirects should be followed + */ + public void setDisableRedirects(boolean disableRedirects) { + connection.setInstanceFollowRedirects(!disableRedirects); + } + + /** + * Sets the request headers given a JSObject of key-value pairs + * @param headers the JSObject values to map to the HttpUrlConnection request headers + */ + public void setRequestHeaders(JSObject headers) { + Iterator keys = headers.keys(); + while (keys.hasNext()) { + String key = keys.next(); + String value = headers.getString(key); + connection.setRequestProperty(key, value); + } + } + + /** + * Sets the value of the {@code doOutput} field for this + * {@code URLConnection} to the specified value. + *

+ * A URL connection can be used for input and/or output. Set the DoOutput + * flag to true if you intend to use the URL connection for output, + * false if not. The default is false. + * + * @param shouldDoOutput the new value. + * @throws IllegalStateException if already connected + */ + public void setDoOutput(boolean shouldDoOutput) { + connection.setDoOutput(shouldDoOutput); + } + + /** + * + * @param call + * @throws JSONException + * @throws IOException + */ + public void setRequestBody(PluginCall call, JSValue body) throws JSONException, IOException { + setRequestBody(call, body, null); + } + + /** + * + * @param call + * @throws JSONException + * @throws IOException + */ + public void setRequestBody(PluginCall call, JSValue body, String bodyType) throws JSONException, IOException { + String contentType = connection.getRequestProperty("Content-Type"); + String dataString = ""; + + if (contentType == null || contentType.isEmpty()) return; + + if (contentType.contains("application/json")) { + JSArray jsArray = null; + if (body != null) { + dataString = body.toString(); + } else { + jsArray = call.getArray("data", null); + } + if (jsArray != null) { + dataString = jsArray.toString(); + } else if (body == null) { + dataString = call.getString("data"); + } + this.writeRequestBody(dataString != null ? dataString : ""); + } else if (bodyType != null && bodyType.equals("file")) { + try (DataOutputStream os = new DataOutputStream(connection.getOutputStream())) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + os.write(Base64.getDecoder().decode(body.toString())); + } + os.flush(); + } + } else if (contentType.contains("application/x-www-form-urlencoded")) { + try { + JSObject obj = body.toJSObject(); + this.writeObjectRequestBody(obj); + } catch (Exception e) { + // Body is not a valid JSON, treat it as an already formatted string + this.writeRequestBody(body.toString()); + } + } else if (bodyType != null && bodyType.equals("formData")) { + String boundary = extractBoundaryFromContentType(contentType); + if (boundary == null) { + // If no boundary is provided, generate a random one and set the Content-Type header accordingly + // or otherwise servers will not be able to parse the request body. Browsers do this automatically + // but here we need to do this manually in order to comply with browser api behavior. + boundary = UUID.randomUUID().toString(); + connection.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary); + } + + this.writeFormDataRequestBody(boundary, body.toJSArray()); + } else { + this.writeRequestBody(body.toString()); + } + } + + /** + * Writes the provided string to the HTTP connection managed by this instance. + * + * @param body The string value to write to the connection stream. + */ + private void writeRequestBody(String body) throws IOException { + try (DataOutputStream os = new DataOutputStream(connection.getOutputStream())) { + os.write(body.getBytes(StandardCharsets.UTF_8)); + os.flush(); + } + } + + private void writeObjectRequestBody(JSObject object) throws IOException, JSONException { + try (DataOutputStream os = new DataOutputStream(connection.getOutputStream())) { + Iterator keys = object.keys(); + while (keys.hasNext()) { + String key = keys.next(); + Object d = object.get(key); + os.writeBytes(URLEncoder.encode(key, "UTF-8")); + os.writeBytes("="); + os.writeBytes(URLEncoder.encode(d.toString(), "UTF-8")); + + if (keys.hasNext()) { + os.writeBytes("&"); + } + } + os.flush(); + } + } + + private void writeFormDataRequestBody(String boundary, JSArray entries) throws IOException, JSONException { + try (DataOutputStream os = new DataOutputStream(connection.getOutputStream())) { + String lineEnd = "\r\n"; + String twoHyphens = "--"; + + for (Object e : entries.toList()) { + if (e instanceof JSONObject) { + JSONObject entry = (JSONObject) e; + String type = entry.getString("type"); + String key = entry.getString("key"); + String value = entry.getString("value"); + if (type.equals("string")) { + os.writeBytes(twoHyphens + boundary + lineEnd); + os.writeBytes("Content-Disposition: form-data; name=\"" + key + "\"" + lineEnd + lineEnd); + os.write(value.getBytes(StandardCharsets.UTF_8)); + os.writeBytes(lineEnd); + } else if (type.equals("base64File")) { + String fileName = entry.getString("fileName"); + String fileContentType = entry.getString("contentType"); + + os.writeBytes(twoHyphens + boundary + lineEnd); + os.writeBytes("Content-Disposition: form-data; name=\"" + key + "\"; filename=\"" + fileName + "\"" + lineEnd); + os.writeBytes("Content-Type: " + fileContentType + lineEnd); + os.writeBytes("Content-Transfer-Encoding: binary" + lineEnd); + os.writeBytes(lineEnd); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + os.write(Base64.getDecoder().decode(value)); + } else { + os.write(android.util.Base64.decode(value, android.util.Base64.DEFAULT)); + } + + os.writeBytes(lineEnd); + } + } + } + + os.writeBytes(twoHyphens + boundary + twoHyphens + lineEnd); + os.flush(); + } + } + + /** + * Extracts the boundary value from the `Content-Type` header for multipart/form-data requests, if provided. + * + * The boundary value might be surrounded by double quotes (") which will be stripped away. + * + * @param contentType The `Content-Type` header string. + * @return The boundary value if found, otherwise `null`. + */ + public static String extractBoundaryFromContentType(String contentType) { + String boundaryPrefix = "boundary="; + int boundaryIndex = contentType.indexOf(boundaryPrefix); + if (boundaryIndex == -1) { + return null; + } + + // Extract the substring starting right after "boundary=" + String boundary = contentType.substring(boundaryIndex + boundaryPrefix.length()); + + // Find the end of the boundary value by looking for the next ";" + int endIndex = boundary.indexOf(";"); + if (endIndex != -1) { + boundary = boundary.substring(0, endIndex); + } + + // Remove surrounding double quotes if present + boundary = boundary.trim(); + if (boundary.startsWith("\"") && boundary.endsWith("\"")) { + boundary = boundary.substring(1, boundary.length() - 1); + } + + return boundary; + } + + /** + * Opens a communications link to the resource referenced by this + * URL, if such a connection has not already been established. + *

+ * If the {@code connect} method is called when the connection + * has already been opened (indicated by the {@code connected} + * field having the value {@code true}), the call is ignored. + *

+ * URLConnection objects go through two phases: first they are + * created, then they are connected. After being created, and + * before being connected, various options can be specified + * (e.g., doInput and UseCaches). After connecting, it is an + * error to try to set them. Operations that depend on being + * connected, like getContentLength, will implicitly perform the + * connection, if necessary. + * + * @throws SocketTimeoutException if the timeout expires before + * the connection can be established + * @exception IOException if an I/O error occurs while opening the + * connection. + */ + public void connect() throws IOException { + connection.connect(); + } + + /** + * Gets the status code from an HTTP response message. + * For example, in the case of the following status lines: + *

+     * HTTP/1.0 200 OK
+     * HTTP/1.0 401 Unauthorized
+     * 
+ * It will return 200 and 401 respectively. + * Returns -1 if no code can be discerned + * from the response (i.e., the response is not valid HTTP). + * @throws IOException if an error occurred connecting to the server. + * @return the HTTP Status-Code, or -1 + */ + public int getResponseCode() throws IOException { + return connection.getResponseCode(); + } + + /** + * Returns the value of this {@code URLConnection}'s {@code URL} + * field. + * + * @return the value of this {@code URLConnection}'s {@code URL} + * field. + */ + public URL getURL() { + return connection.getURL(); + } + + /** + * Returns the error stream if the connection failed + * but the server sent useful data nonetheless. The + * typical example is when an HTTP server responds + * with a 404, which will cause a FileNotFoundException + * to be thrown in connect, but the server sent an HTML + * help page with suggestions as to what to do. + * + *

This method will not cause a connection to be initiated. If + * the connection was not connected, or if the server did not have + * an error while connecting or if the server had an error but + * no error data was sent, this method will return null. This is + * the default. + * + * @return an error stream if any, null if there have been no + * errors, the connection is not connected or the server sent no + * useful data. + */ + @Override + public InputStream getErrorStream() { + return connection.getErrorStream(); + } + + /** + * Returns the value of the named header field. + *

+ * If called on a connection that sets the same header multiple times + * with possibly different values, only the last value is returned. + * + * + * @param name the name of a header field. + * @return the value of the named header field, or {@code null} + * if there is no such field in the header. + */ + @Override + public String getHeaderField(String name) { + return connection.getHeaderField(name); + } + + /** + * Returns an input stream that reads from this open connection. + * + * A SocketTimeoutException can be thrown when reading from the + * returned input stream if the read timeout expires before data + * is available for read. + * + * @return an input stream that reads from this open connection. + * @exception IOException if an I/O error occurs while + * creating the input stream. + * @exception UnknownServiceException if the protocol does not support + * input. + * @see #setReadTimeout(int) + */ + @Override + public InputStream getInputStream() throws IOException { + return connection.getInputStream(); + } + + /** + * Returns an unmodifiable Map of the header fields. + * The Map keys are Strings that represent the + * response-header field names. Each Map value is an + * unmodifiable List of Strings that represents + * the corresponding field values. + * + * @return a Map of header fields + */ + public Map> getHeaderFields() { + return connection.getHeaderFields(); + } + + /** + * Sets the default request properties on the newly created connection. + * This is called as early as possible to allow overrides by user-provided values. + */ + private void setDefaultRequestProperties() { + String acceptLanguage = buildDefaultAcceptLanguageProperty(); + if (!TextUtils.isEmpty(acceptLanguage)) { + connection.setRequestProperty("Accept-Language", acceptLanguage); + } + } + + /** + * Builds and returns a locale string describing the device's current locale preferences. + */ + private String buildDefaultAcceptLanguageProperty() { + Locale locale = LocaleList.getDefault().get(0); + String result = ""; + String lang = locale.getLanguage(); + String country = locale.getCountry(); + if (!TextUtils.isEmpty(lang)) { + if (!TextUtils.isEmpty(country)) { + result = String.format("%s-%s,%s;q=0.5", lang, country, lang); + } else { + result = String.format("%s;q=0.5", lang); + } + } + return result; + } + + public void setSSLSocketFactory(Bridge bridge) { + // Attach SSL Certificates if Enterprise Plugin is available + try { + Class sslPinningImpl = Class.forName("io.ionic.sslpinning.SSLPinning"); + Method method = sslPinningImpl.getDeclaredMethod("getSSLSocketFactory", Bridge.class); + SSLSocketFactory sslSocketFactory = (SSLSocketFactory) method.invoke( + sslPinningImpl.getDeclaredConstructor().newInstance(), + bridge + ); + if (sslSocketFactory != null) { + ((HttpsURLConnection) this.connection).setSSLSocketFactory(sslSocketFactory); + } + } catch (Exception ignored) {} + } +} diff --git a/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/plugin/util/HttpRequestHandler.java b/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/plugin/util/HttpRequestHandler.java new file mode 100644 index 0000000..b47d57c --- /dev/null +++ b/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/plugin/util/HttpRequestHandler.java @@ -0,0 +1,465 @@ +package com.getcapacitor.plugin.util; + +import android.text.TextUtils; +import android.util.Base64; +import com.getcapacitor.Bridge; +import com.getcapacitor.JSArray; +import com.getcapacitor.JSObject; +import com.getcapacitor.JSValue; +import com.getcapacitor.PluginCall; +import java.io.BufferedReader; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.UnsupportedEncodingException; +import java.lang.reflect.Method; +import java.net.HttpURLConnection; +import java.net.MalformedURLException; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.net.URLEncoder; +import java.util.Iterator; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +public class HttpRequestHandler { + + /** + * An enum specifying conventional HTTP Response Types + * See https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/responseType + */ + public enum ResponseType { + ARRAY_BUFFER("arraybuffer"), + BLOB("blob"), + DOCUMENT("document"), + JSON("json"), + TEXT("text"); + + private final String name; + + ResponseType(String name) { + this.name = name; + } + + static final ResponseType DEFAULT = TEXT; + + public static ResponseType parse(String value) { + for (ResponseType responseType : values()) { + if (responseType.name.equalsIgnoreCase(value)) { + return responseType; + } + } + return DEFAULT; + } + } + + /** + * Internal builder class for building a CapacitorHttpUrlConnection + */ + public static class HttpURLConnectionBuilder { + + public Integer connectTimeout; + public Integer readTimeout; + public Boolean disableRedirects; + public JSObject headers; + public String method; + public URL url; + + public CapacitorHttpUrlConnection connection; + + public HttpURLConnectionBuilder setConnectTimeout(Integer connectTimeout) { + this.connectTimeout = connectTimeout; + return this; + } + + public HttpURLConnectionBuilder setReadTimeout(Integer readTimeout) { + this.readTimeout = readTimeout; + return this; + } + + public HttpURLConnectionBuilder setDisableRedirects(Boolean disableRedirects) { + this.disableRedirects = disableRedirects; + return this; + } + + public HttpURLConnectionBuilder setHeaders(JSObject headers) { + this.headers = headers; + return this; + } + + public HttpURLConnectionBuilder setMethod(String method) { + this.method = method; + return this; + } + + public HttpURLConnectionBuilder setUrl(URL url) { + this.url = url; + return this; + } + + public HttpURLConnectionBuilder openConnection() throws IOException { + connection = new CapacitorHttpUrlConnection((HttpURLConnection) url.openConnection()); + + connection.setAllowUserInteraction(false); + connection.setRequestMethod(method); + + if (connectTimeout != null) connection.setConnectTimeout(connectTimeout); + if (readTimeout != null) connection.setReadTimeout(readTimeout); + if (disableRedirects != null) connection.setDisableRedirects(disableRedirects); + + connection.setRequestHeaders(headers); + return this; + } + + public HttpURLConnectionBuilder setUrlParams(JSObject params) throws MalformedURLException, URISyntaxException, JSONException { + return this.setUrlParams(params, true); + } + + public HttpURLConnectionBuilder setUrlParams(JSObject params, boolean shouldEncode) + throws URISyntaxException, MalformedURLException { + String initialQuery = url.getQuery(); + String initialQueryBuilderStr = initialQuery == null ? "" : initialQuery; + + Iterator keys = params.keys(); + + if (!keys.hasNext()) { + return this; + } + + StringBuilder urlQueryBuilder = new StringBuilder(initialQueryBuilderStr); + + // Build the new query string + while (keys.hasNext()) { + String key = keys.next(); + + // Attempt as JSONArray and fallback to string if it fails + try { + StringBuilder value = new StringBuilder(); + JSONArray arr = params.getJSONArray(key); + for (int x = 0; x < arr.length(); x++) { + this.addUrlParam(value, key, arr.getString(x), shouldEncode); + if (x != arr.length() - 1) { + value.append("&"); + } + } + if (urlQueryBuilder.length() > 0) { + urlQueryBuilder.append("&"); + } + urlQueryBuilder.append(value); + } catch (JSONException e) { + if (urlQueryBuilder.length() > 0) { + urlQueryBuilder.append("&"); + } + this.addUrlParam(urlQueryBuilder, key, params.getString(key), shouldEncode); + } + } + + String urlQuery = urlQueryBuilder.toString(); + + URI uri = url.toURI(); + String unEncodedUrlString = + uri.getScheme() + + "://" + + uri.getAuthority() + + uri.getPath() + + ((!urlQuery.equals("")) ? "?" + urlQuery : "") + + ((uri.getFragment() != null) ? uri.getFragment() : ""); + this.url = new URL(unEncodedUrlString); + + return this; + } + + private static void addUrlParam(StringBuilder sb, String key, String value, boolean shouldEncode) { + if (shouldEncode) { + try { + key = URLEncoder.encode(key, "UTF-8"); + value = URLEncoder.encode(value, "UTF-8"); + } catch (UnsupportedEncodingException ex) { + throw new RuntimeException(ex.getCause()); + } + } + sb.append(key).append("=").append(value); + } + + public CapacitorHttpUrlConnection build() { + return connection; + } + } + + /** + * Builds an HTTP Response given CapacitorHttpUrlConnection and ResponseType objects. + * Defaults to ResponseType.DEFAULT + * @param connection The CapacitorHttpUrlConnection to respond with + * @throws IOException Thrown if the InputStream is unable to be parsed correctly + * @throws JSONException Thrown if the JSON is unable to be parsed + */ + public static JSObject buildResponse(CapacitorHttpUrlConnection connection) throws IOException, JSONException { + return buildResponse(connection, ResponseType.DEFAULT); + } + + /** + * Builds an HTTP Response given CapacitorHttpUrlConnection and ResponseType objects + * @param connection The CapacitorHttpUrlConnection to respond with + * @param responseType The requested ResponseType + * @return A JSObject that contains the HTTPResponse to return to the browser + * @throws IOException Thrown if the InputStream is unable to be parsed correctly + * @throws JSONException Thrown if the JSON is unable to be parsed + */ + public static JSObject buildResponse(CapacitorHttpUrlConnection connection, ResponseType responseType) + throws IOException, JSONException { + int statusCode = connection.getResponseCode(); + + JSObject output = new JSObject(); + output.put("status", statusCode); + output.put("headers", buildResponseHeaders(connection)); + output.put("url", connection.getURL()); + output.put("data", readData(connection, responseType)); + + InputStream errorStream = connection.getErrorStream(); + if (errorStream != null) { + output.put("error", true); + } + + return output; + } + + /** + * Read the existing ICapacitorHttpUrlConnection data + * @param connection The ICapacitorHttpUrlConnection object to read in + * @param responseType The type of HTTP response to return to the API + * @return The parsed data from the connection + * @throws IOException Thrown if the InputStreams cannot be properly parsed + * @throws JSONException Thrown if the JSON is malformed when parsing as JSON + */ + public static Object readData(ICapacitorHttpUrlConnection connection, ResponseType responseType) throws IOException, JSONException { + InputStream errorStream = connection.getErrorStream(); + String contentType = connection.getHeaderField("Content-Type"); + + if (errorStream != null) { + if (isOneOf(contentType, MimeType.APPLICATION_JSON, MimeType.APPLICATION_VND_API_JSON)) { + return parseJSON(readStreamAsString(errorStream)); + } else { + return readStreamAsString(errorStream); + } + } else if (contentType != null && contentType.contains(MimeType.APPLICATION_JSON.getValue())) { + // backward compatibility + return parseJSON(readStreamAsString(connection.getInputStream())); + } else { + InputStream stream = connection.getInputStream(); + switch (responseType) { + case ARRAY_BUFFER: + case BLOB: + return readStreamAsBase64(stream); + case JSON: + return parseJSON(readStreamAsString(stream)); + case DOCUMENT: + case TEXT: + default: + return readStreamAsString(stream); + } + } + } + + /** + * Helper function for determining if the Content-Type is a typeof an existing Mime-Type + * @param contentType The Content-Type string to check for + * @param mimeTypes The Mime-Type values to check against + * @return + */ + public static boolean isOneOf(String contentType, MimeType... mimeTypes) { + if (contentType != null) { + for (MimeType mimeType : mimeTypes) { + if (contentType.contains(mimeType.getValue())) { + return true; + } + } + } + return false; + } + + /** + * Build the JSObject response headers based on the connection header map + * @param connection The CapacitorHttpUrlConnection connection + * @return A JSObject of the header values from the CapacitorHttpUrlConnection + */ + public static JSObject buildResponseHeaders(CapacitorHttpUrlConnection connection) { + JSObject output = new JSObject(); + + for (Map.Entry> entry : connection.getHeaderFields().entrySet()) { + String valuesString = TextUtils.join(", ", entry.getValue()); + output.put(entry.getKey(), valuesString); + } + + return output; + } + + /** + * Returns a JSObject or a JSArray based on a string-ified input + * @param input String-ified JSON that needs parsing + * @return A JSObject or JSArray + * @throws JSONException thrown if the JSON is malformed + */ + public static Object parseJSON(String input) throws JSONException { + JSONObject json = new JSONObject(); + try { + if ("null".equals(input.trim())) { + return JSONObject.NULL; + } else if ("true".equals(input.trim())) { + return true; + } else if ("false".equals(input.trim())) { + return false; + } else if (input.trim().length() <= 0) { + return ""; + } else if (input.trim().matches("^\".*\"$")) { + // a string enclosed in " " is a json value, return the string without the quotes + return input.trim().substring(1, input.trim().length() - 1); + } else if (input.trim().matches("^-?\\d+$")) { + return Integer.parseInt(input.trim()); + } else if (input.trim().matches("^-?\\d+(\\.\\d+)?$")) { + return Double.parseDouble(input.trim()); + } else { + try { + return new JSObject(input); + } catch (JSONException e) { + return new JSArray(input); + } + } + } catch (JSONException e) { + return input; + } + } + + /** + * Returns a string based on a base64 InputStream + * @param in The base64 InputStream to convert to a String + * @return String value of InputStream + * @throws IOException thrown if the InputStream is unable to be read as base64 + */ + public static String readStreamAsBase64(InputStream in) throws IOException { + try (ByteArrayOutputStream out = new ByteArrayOutputStream()) { + byte[] buffer = new byte[1024]; + int readBytes; + while ((readBytes = in.read(buffer)) != -1) { + out.write(buffer, 0, readBytes); + } + byte[] result = out.toByteArray(); + return Base64.encodeToString(result, 0, result.length, Base64.DEFAULT); + } + } + + /** + * Returns a string based on an InputStream + * @param in The InputStream to convert to a String + * @return String value of InputStream + * @throws IOException thrown if the InputStream is unable to be read + */ + public static String readStreamAsString(InputStream in) throws IOException { + try (BufferedReader reader = new BufferedReader(new InputStreamReader(in))) { + StringBuilder builder = new StringBuilder(); + String line = reader.readLine(); + while (line != null) { + builder.append(line); + line = reader.readLine(); + if (line != null) { + builder.append(System.getProperty("line.separator")); + } + } + return builder.toString(); + } + } + + /** + * Makes an Http Request based on the PluginCall parameters + * @param call The Capacitor PluginCall that contains the options need for an Http request + * @param httpMethod The HTTP method that overrides the PluginCall HTTP method + * @throws IOException throws an IO request when a connection can't be made + * @throws URISyntaxException thrown when the URI is malformed + * @throws JSONException thrown when the incoming JSON is malformed + */ + public static JSObject request(PluginCall call, String httpMethod, Bridge bridge) + throws IOException, URISyntaxException, JSONException { + String urlString = call.getString("url", ""); + JSObject headers = call.getObject("headers", new JSObject()); + JSObject params = call.getObject("params", new JSObject()); + Integer connectTimeout = call.getInt("connectTimeout"); + Integer readTimeout = call.getInt("readTimeout"); + Boolean disableRedirects = call.getBoolean("disableRedirects"); + Boolean shouldEncode = call.getBoolean("shouldEncodeUrlParams", true); + ResponseType responseType = ResponseType.parse(call.getString("responseType")); + String dataType = call.getString("dataType"); + + String method = httpMethod != null ? httpMethod.toUpperCase(Locale.ROOT) : call.getString("method", "GET").toUpperCase(Locale.ROOT); + + boolean isHttpMutate = method.equals("DELETE") || method.equals("PATCH") || method.equals("POST") || method.equals("PUT"); + + // a workaround for the following android web view issue: + // https://issues.chromium.org/issues/40450316 + // x-cap-user-agent contains the user agent set in JavaScript + String userAgentValue = headers.getString("x-cap-user-agent"); + if (userAgentValue != null) { + headers.put("User-Agent", userAgentValue); + } + headers.remove("x-cap-user-agent"); + + if (!headers.has("User-Agent") && !headers.has("user-agent")) { + headers.put("User-Agent", bridge.getConfig().getOverriddenUserAgentString()); + } + + URL url = new URL(urlString); + HttpURLConnectionBuilder connectionBuilder = new HttpURLConnectionBuilder() + .setUrl(url) + .setMethod(method) + .setHeaders(headers) + .setUrlParams(params, shouldEncode) + .setConnectTimeout(connectTimeout) + .setReadTimeout(readTimeout) + .setDisableRedirects(disableRedirects) + .openConnection(); + + CapacitorHttpUrlConnection connection = connectionBuilder.build(); + + if (null != bridge && !isDomainExcludedFromSSL(bridge, url)) { + connection.setSSLSocketFactory(bridge); + } + + // Set HTTP body on a non GET or HEAD request + if (isHttpMutate) { + JSValue data = new JSValue(call, "data"); + if (data.getValue() != null) { + connection.setDoOutput(true); + connection.setRequestBody(call, data, dataType); + } + } + + call.getData().put("activeCapacitorHttpUrlConnection", connection); + connection.connect(); + + JSObject response = buildResponse(connection, responseType); + + connection.disconnect(); + call.getData().remove("activeCapacitorHttpUrlConnection"); + + return response; + } + + public static Boolean isDomainExcludedFromSSL(Bridge bridge, URL url) { + try { + Class sslPinningImpl = Class.forName("io.ionic.sslpinning.SSLPinning"); + Method method = sslPinningImpl.getDeclaredMethod("isDomainExcluded", Bridge.class, URL.class); + return (Boolean) method.invoke(sslPinningImpl.getDeclaredConstructor().newInstance(), bridge, url); + } catch (Exception ignored) { + return false; + } + } + + @FunctionalInterface + public interface ProgressEmitter { + void emit(Integer bytes, Integer contentLength); + } +} diff --git a/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/plugin/util/ICapacitorHttpUrlConnection.java b/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/plugin/util/ICapacitorHttpUrlConnection.java new file mode 100644 index 0000000..4ed8881 --- /dev/null +++ b/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/plugin/util/ICapacitorHttpUrlConnection.java @@ -0,0 +1,15 @@ +package com.getcapacitor.plugin.util; + +import java.io.IOException; +import java.io.InputStream; + +/** + * This interface was extracted from {@link CapacitorHttpUrlConnection} to enable mocking that class. + */ +public interface ICapacitorHttpUrlConnection { + InputStream getErrorStream(); + + String getHeaderField(String name); + + InputStream getInputStream() throws IOException; +} diff --git a/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/plugin/util/MimeType.java b/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/plugin/util/MimeType.java new file mode 100644 index 0000000..cfc90f8 --- /dev/null +++ b/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/plugin/util/MimeType.java @@ -0,0 +1,17 @@ +package com.getcapacitor.plugin.util; + +enum MimeType { + APPLICATION_JSON("application/json"), + APPLICATION_VND_API_JSON("application/vnd.api+json"), // https://jsonapi.org + TEXT_HTML("text/html"); + + private final String value; + + MimeType(String value) { + this.value = value; + } + + String getValue() { + return value; + } +} diff --git a/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/util/HostMask.java b/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/util/HostMask.java new file mode 100644 index 0000000..486d0fd --- /dev/null +++ b/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/util/HostMask.java @@ -0,0 +1,123 @@ +package com.getcapacitor.util; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +public interface HostMask { + boolean matches(String host); + + class Parser { + + private static HostMask NOTHING = new Nothing(); + + public static HostMask parse(String[] masks) { + return masks == null ? NOTHING : HostMask.Any.parse(masks); + } + + public static HostMask parse(String mask) { + return mask == null ? NOTHING : HostMask.Simple.parse(mask); + } + } + + class Simple implements HostMask { + + private final List maskParts; + + private Simple(List maskParts) { + if (maskParts == null) { + throw new IllegalArgumentException("Mask parts can not be null"); + } + this.maskParts = maskParts; + } + + static Simple parse(String mask) { + List parts = Util.splitAndReverse(mask); + return new Simple(parts); + } + + @Override + public boolean matches(String host) { + if (host == null) { + return false; + } + List hostParts = Util.splitAndReverse(host); + int hostSize = hostParts.size(); + int maskSize = maskParts.size(); + if (maskSize > 1 && hostSize != maskSize) { + return false; + } + + int minSize = Math.min(hostSize, maskSize); + + for (int i = 0; i < minSize; i++) { + String maskPart = maskParts.get(i); + String hostPart = hostParts.get(i); + if (!Util.matches(maskPart, hostPart)) { + return false; + } + } + return true; + } + } + + class Any implements HostMask { + + private final List masks; + + Any(List masks) { + this.masks = masks; + } + + @Override + public boolean matches(String host) { + for (HostMask mask : masks) { + if (mask.matches(host)) { + return true; + } + } + return false; + } + + static Any parse(String... rawMasks) { + List masks = new ArrayList<>(); + for (String raw : rawMasks) { + masks.add(HostMask.Simple.parse(raw)); + } + return new Any(masks); + } + } + + class Nothing implements HostMask { + + @Override + public boolean matches(String host) { + return false; + } + } + + class Util { + + static boolean matches(String mask, String string) { + if (mask == null) { + return false; + } else if ("*".equals(mask)) { + return true; + } else if (string == null) { + return false; + } else { + return mask.toUpperCase().equals(string.toUpperCase()); + } + } + + static List splitAndReverse(String string) { + if (string == null) { + throw new IllegalArgumentException("Can not split null argument"); + } + List parts = Arrays.asList(string.split("\\.")); + Collections.reverse(parts); + return parts; + } + } +} diff --git a/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/util/InternalUtils.java b/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/util/InternalUtils.java new file mode 100644 index 0000000..b735415 --- /dev/null +++ b/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/util/InternalUtils.java @@ -0,0 +1,27 @@ +package com.getcapacitor.util; + +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.os.Build; + +public class InternalUtils { + + public static PackageInfo getPackageInfo(PackageManager pm, String packageName) throws PackageManager.NameNotFoundException { + return InternalUtils.getPackageInfo(pm, packageName, 0); + } + + public static PackageInfo getPackageInfo(PackageManager pm, String packageName, long flags) + throws PackageManager.NameNotFoundException { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + return pm.getPackageInfo(packageName, PackageManager.PackageInfoFlags.of(flags)); + } else { + return getPackageInfoLegacy(pm, packageName, (int) flags); + } + } + + @SuppressWarnings("deprecation") + private static PackageInfo getPackageInfoLegacy(PackageManager pm, String packageName, long flags) + throws PackageManager.NameNotFoundException { + return pm.getPackageInfo(packageName, (int) flags); + } +} diff --git a/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/util/JSONUtils.java b/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/util/JSONUtils.java new file mode 100644 index 0000000..1d2fc20 --- /dev/null +++ b/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/util/JSONUtils.java @@ -0,0 +1,166 @@ +package com.getcapacitor.util; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +/** + * Helper methods for parsing JSON objects. + */ +public class JSONUtils { + + /** + * Get a string value from the given JSON object. + * + * @param jsonObject A JSON object to search + * @param key A key to fetch from the JSON object + * @param defaultValue A default value to return if the key cannot be found + * @return The value at the given key in the JSON object, or the default value + */ + public static String getString(JSONObject jsonObject, String key, String defaultValue) { + String k = getDeepestKey(key); + try { + JSONObject o = getDeepestObject(jsonObject, key); + + String value = o.getString(k); + if (value == null) { + return defaultValue; + } + return value; + } catch (JSONException ignore) { + // value was not found + } + + return defaultValue; + } + + /** + * Get a boolean value from the given JSON object. + * + * @param jsonObject A JSON object to search + * @param key A key to fetch from the JSON object + * @param defaultValue A default value to return if the key cannot be found + * @return The value at the given key in the JSON object, or the default value + */ + public static boolean getBoolean(JSONObject jsonObject, String key, boolean defaultValue) { + String k = getDeepestKey(key); + try { + JSONObject o = getDeepestObject(jsonObject, key); + + return o.getBoolean(k); + } catch (JSONException ignore) { + // value was not found + } + + return defaultValue; + } + + /** + * Get an int value from the given JSON object. + * + * @param jsonObject A JSON object to search + * @param key A key to fetch from the JSON object + * @param defaultValue A default value to return if the key cannot be found + * @return The value at the given key in the JSON object, or the default value + */ + public static int getInt(JSONObject jsonObject, String key, int defaultValue) { + String k = getDeepestKey(key); + try { + JSONObject o = getDeepestObject(jsonObject, key); + return o.getInt(k); + } catch (JSONException ignore) { + // value was not found + } + + return defaultValue; + } + + /** + * Get a JSON object value from the given JSON object. + * + * @param jsonObject A JSON object to search + * @param key A key to fetch from the JSON object + * @return The value from the config, if exists. Null if not + */ + public static JSONObject getObject(JSONObject jsonObject, String key) { + String k = getDeepestKey(key); + try { + JSONObject o = getDeepestObject(jsonObject, key); + + return o.getJSONObject(k); + } catch (JSONException ignore) { + // value was not found + } + + return null; + } + + /** + * Get a string array value from the given JSON object. + * + * @param jsonObject A JSON object to search + * @param key A key to fetch from the JSON object + * @param defaultValue A default value to return if the key cannot be found + * @return The value at the given key in the JSON object, or the default value + */ + public static String[] getArray(JSONObject jsonObject, String key, String[] defaultValue) { + String k = getDeepestKey(key); + try { + JSONObject o = getDeepestObject(jsonObject, key); + + JSONArray a = o.getJSONArray(k); + if (a == null) { + return defaultValue; + } + + int l = a.length(); + String[] value = new String[l]; + + for (int i = 0; i < l; i++) { + value[i] = (String) a.get(i); + } + + return value; + } catch (JSONException ignore) { + // value was not found + } + + return defaultValue; + } + + /** + * Given a JSON key path, gets the deepest key. + * + * @param key The key path + * @return The deepest key + */ + private static String getDeepestKey(String key) { + String[] parts = key.split("\\."); + if (parts.length > 0) { + return parts[parts.length - 1]; + } + + return null; + } + + /** + * Given a JSON object and key path, gets the deepest object in the path. + * + * @param jsonObject A JSON object + * @param key The key path to follow + * @return The deepest object along the key path + * @throws JSONException Thrown if any JSON errors + */ + private static JSONObject getDeepestObject(JSONObject jsonObject, String key) throws JSONException { + String[] parts = key.split("\\."); + JSONObject o = jsonObject; + + // Search until the second to last part of the key + for (int i = 0; i < parts.length - 1; i++) { + String k = parts[i]; + o = o.getJSONObject(k); + } + + return o; + } +} diff --git a/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/util/PermissionHelper.java b/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/util/PermissionHelper.java new file mode 100644 index 0000000..e7b8332 --- /dev/null +++ b/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/util/PermissionHelper.java @@ -0,0 +1,114 @@ +package com.getcapacitor.util; + +import android.content.Context; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import androidx.core.app.ActivityCompat; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * A helper class for checking permissions. + * + * @since 3.0.0 + */ +public class PermissionHelper { + + /** + * Checks if a list of given permissions are all granted by the user + * + * @since 3.0.0 + * @param permissions Permissions to check. + * @return True if all permissions are granted, false if at least one is not. + */ + public static boolean hasPermissions(Context context, String[] permissions) { + for (String perm : permissions) { + if (ActivityCompat.checkSelfPermission(context, perm) != PackageManager.PERMISSION_GRANTED) { + return false; + } + } + return true; + } + + /** + * Check whether the given permission has been defined in the AndroidManifest.xml + * + * @since 3.0.0 + * @param permission A permission to check. + * @return True if the permission has been defined in the Manifest, false if not. + */ + public static boolean hasDefinedPermission(Context context, String permission) { + boolean hasPermission = false; + String[] requestedPermissions = PermissionHelper.getManifestPermissions(context); + if (requestedPermissions != null && requestedPermissions.length > 0) { + List requestedPermissionsList = Arrays.asList(requestedPermissions); + ArrayList requestedPermissionsArrayList = new ArrayList<>(requestedPermissionsList); + if (requestedPermissionsArrayList.contains(permission)) { + hasPermission = true; + } + } + return hasPermission; + } + + /** + * Check whether all of the given permissions have been defined in the AndroidManifest.xml + * @param context the app context + * @param permissions a list of permissions + * @return true only if all permissions are defined in the AndroidManifest.xml + */ + public static boolean hasDefinedPermissions(Context context, String[] permissions) { + for (String permission : permissions) { + if (!PermissionHelper.hasDefinedPermission(context, permission)) { + return false; + } + } + + return true; + } + + /** + * Get the permissions defined in AndroidManifest.xml + * + * @since 3.0.0 + * @return The permissions defined in AndroidManifest.xml + */ + public static String[] getManifestPermissions(Context context) { + String[] requestedPermissions = null; + try { + PackageManager pm = context.getPackageManager(); + PackageInfo packageInfo = InternalUtils.getPackageInfo(pm, context.getPackageName(), PackageManager.GET_PERMISSIONS); + + if (packageInfo != null) { + requestedPermissions = packageInfo.requestedPermissions; + } + } catch (Exception ex) {} + return requestedPermissions; + } + + /** + * Given a list of permissions, return a new list with the ones not present in AndroidManifest.xml + * + * @since 3.0.0 + * @param neededPermissions The permissions needed. + * @return The permissions not present in AndroidManifest.xml + */ + public static String[] getUndefinedPermissions(Context context, String[] neededPermissions) { + ArrayList undefinedPermissions = new ArrayList<>(); + String[] requestedPermissions = getManifestPermissions(context); + if (requestedPermissions != null && requestedPermissions.length > 0) { + List requestedPermissionsList = Arrays.asList(requestedPermissions); + ArrayList requestedPermissionsArrayList = new ArrayList<>(requestedPermissionsList); + for (String permission : neededPermissions) { + if (!requestedPermissionsArrayList.contains(permission)) { + undefinedPermissions.add(permission); + } + } + String[] undefinedPermissionArray = new String[undefinedPermissions.size()]; + undefinedPermissionArray = undefinedPermissions.toArray(undefinedPermissionArray); + + return undefinedPermissionArray; + } + return neededPermissions; + } +} diff --git a/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/util/WebColor.java b/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/util/WebColor.java new file mode 100644 index 0000000..e055021 --- /dev/null +++ b/node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/util/WebColor.java @@ -0,0 +1,28 @@ +package com.getcapacitor.util; + +import android.graphics.Color; + +public class WebColor { + + /** + * Parse the color string, and return the corresponding color-int. If the string cannot be parsed, throws an IllegalArgumentException exception. + * @param colorString The hexadecimal color string. The format is an RGB or RGBA hex string. + * @return The corresponding color as an int. + */ + public static int parseColor(String colorString) { + String formattedColor = colorString; + if (colorString.charAt(0) != '#') { + formattedColor = "#" + formattedColor; + } + + if (formattedColor.length() != 7 && formattedColor.length() != 9) { + throw new IllegalArgumentException("The encoded color space is invalid or unknown"); + } else if (formattedColor.length() == 7) { + return Color.parseColor(formattedColor); + } else { + // Convert to Android format #AARRGGBB from #RRGGBBAA + formattedColor = "#" + formattedColor.substring(7) + formattedColor.substring(1, 7); + return Color.parseColor(formattedColor); + } + } +} diff --git a/node_modules/@capacitor/android/capacitor/src/main/res/layout/capacitor_bridge_layout_main.xml b/node_modules/@capacitor/android/capacitor/src/main/res/layout/capacitor_bridge_layout_main.xml new file mode 100644 index 0000000..12f0b8f --- /dev/null +++ b/node_modules/@capacitor/android/capacitor/src/main/res/layout/capacitor_bridge_layout_main.xml @@ -0,0 +1,15 @@ + + + + + + diff --git a/node_modules/@capacitor/android/capacitor/src/main/res/layout/no_webview.xml b/node_modules/@capacitor/android/capacitor/src/main/res/layout/no_webview.xml new file mode 100644 index 0000000..7228cc2 --- /dev/null +++ b/node_modules/@capacitor/android/capacitor/src/main/res/layout/no_webview.xml @@ -0,0 +1,14 @@ + + + + + \ No newline at end of file diff --git a/node_modules/@capacitor/android/capacitor/src/main/res/values/colors.xml b/node_modules/@capacitor/android/capacitor/src/main/res/values/colors.xml new file mode 100644 index 0000000..347d608 --- /dev/null +++ b/node_modules/@capacitor/android/capacitor/src/main/res/values/colors.xml @@ -0,0 +1,6 @@ + + + #3F51B5 + #303F9F + #FF4081 + diff --git a/node_modules/@capacitor/android/capacitor/src/main/res/values/strings.xml b/node_modules/@capacitor/android/capacitor/src/main/res/values/strings.xml new file mode 100644 index 0000000..2db1111 --- /dev/null +++ b/node_modules/@capacitor/android/capacitor/src/main/res/values/strings.xml @@ -0,0 +1,3 @@ + + This app requires a WebView to work + diff --git a/node_modules/@capacitor/android/capacitor/src/main/res/values/styles.xml b/node_modules/@capacitor/android/capacitor/src/main/res/values/styles.xml new file mode 100644 index 0000000..d326892 --- /dev/null +++ b/node_modules/@capacitor/android/capacitor/src/main/res/values/styles.xml @@ -0,0 +1,6 @@ + + + diff --git a/node_modules/@capacitor/android/package.json b/node_modules/@capacitor/android/package.json new file mode 100644 index 0000000..8ae93f3 --- /dev/null +++ b/node_modules/@capacitor/android/package.json @@ -0,0 +1,31 @@ +{ + "name": "@capacitor/android", + "version": "8.3.4", + "description": "Capacitor: Cross-platform apps with JavaScript and the web", + "homepage": "https://capacitorjs.com", + "author": "Ionic Team (https://ionic.io)", + "license": "MIT", + "repository": { + "type": "git", + "url": "git+https://github.com/ionic-team/capacitor.git" + }, + "bugs": { + "url": "https://github.com/ionic-team/capacitor/issues" + }, + "files": [ + "capacitor/build.gradle", + "capacitor/lint-baseline.xml", + "capacitor/lint.xml", + "capacitor/proguard-rules.pro", + "capacitor/src/main/" + ], + "scripts": { + "verify": "./gradlew clean lint build test -b capacitor/build.gradle" + }, + "peerDependencies": { + "@capacitor/core": "^8.3.0" + }, + "publishConfig": { + "access": "public" + } +} diff --git a/node_modules/@capacitor/cli/LICENSE b/node_modules/@capacitor/cli/LICENSE new file mode 100644 index 0000000..c3e903b --- /dev/null +++ b/node_modules/@capacitor/cli/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2017-present Drifty Co. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/node_modules/@capacitor/cli/README.md b/node_modules/@capacitor/cli/README.md new file mode 100644 index 0000000..b9471c3 --- /dev/null +++ b/node_modules/@capacitor/cli/README.md @@ -0,0 +1,84 @@ +# Capacitor CLI + +The Capacitor command-line interface (CLI) is a tool for creating and managing Capacitor applications. While it can be installed globally, it's recommended to install it locally in your project and execute through `npm` scripts. + +## Installation + +### Project Installation (Recommended) + +Install the CLI locally in your project: + +```bash +npm install @capacitor/cli --save-dev +``` + +### Global Installation + +While not recommended for project use, you can install the CLI globally: + +```bash +npm install -g @capacitor/cli +``` + +## Using Capacitor CLI + +The CLI can be used through the `capacitor` or `cap` command. When installed locally, use it through your project's `npm` scripts or `npx`. + +Common commands: + +- `cap init`: Initialize a new Capacitor project +- `cap add`: Add a native platform (ios, android) +- `cap sync`: Sync your web code to your native projects + +For detailed information, consult the [Getting Started guide](https://capacitorjs.com/docs/getting-started). + +## Local Development + +If you're contributing to the Capacitor CLI or testing local changes: + +1. Clone and setup: + + ```bash + git clone https://github.com/ionic-team/capacitor.git + cd cli + npm install + ``` + +2. Build the CLI: + + ```bash + npm run build + ``` + +3. Create a local link: + + ```bash + npm link + ``` + +4. Development workflow: + - Run `npm run watch` to automatically rebuild on changes + - Use `capacitor` or `cap` commands to test your changes + - Run `npm test` to execute the test suite + +## Debugging + +### Using VS Code Launch Configurations + +The CLI includes VS Code launch configurations for debugging. To debug a CLI command: + +1. Open the project in VS Code +2. Right now we don't have debugging working in the ts files, so select one of the .js files inside of /dist/\*\*.js +3. Place a breakpoint +4. Press F5 or go to Run > Start Debugging +5. Select a launch config and run filling out the path you want to run the cli in, and the command that you want run. + +You can add more configurations by copying and modifying the existing ones in `.vscode/launch.json`. + +## Contributing + +Contributions are welcome! Please read our [Contributing Guide](https://github.com/ionic-team/capacitor/blob/main/CONTRIBUTING.md) for details. + +### License + +- [MIT](https://github.com/ionic-team/capacitor/blob/HEAD/LICENSE) diff --git a/node_modules/@capacitor/cli/assets/android-template.tar.gz b/node_modules/@capacitor/cli/assets/android-template.tar.gz new file mode 100644 index 0000000..7ff2869 Binary files /dev/null and b/node_modules/@capacitor/cli/assets/android-template.tar.gz differ diff --git a/node_modules/@capacitor/cli/assets/capacitor-cordova-android-plugins.tar.gz b/node_modules/@capacitor/cli/assets/capacitor-cordova-android-plugins.tar.gz new file mode 100644 index 0000000..e42df0a Binary files /dev/null and b/node_modules/@capacitor/cli/assets/capacitor-cordova-android-plugins.tar.gz differ diff --git a/node_modules/@capacitor/cli/assets/capacitor-cordova-ios-plugins.tar.gz b/node_modules/@capacitor/cli/assets/capacitor-cordova-ios-plugins.tar.gz new file mode 100644 index 0000000..04c9120 Binary files /dev/null and b/node_modules/@capacitor/cli/assets/capacitor-cordova-ios-plugins.tar.gz differ diff --git a/node_modules/@capacitor/cli/assets/ios-pods-template.tar.gz b/node_modules/@capacitor/cli/assets/ios-pods-template.tar.gz new file mode 100644 index 0000000..03fa089 Binary files /dev/null and b/node_modules/@capacitor/cli/assets/ios-pods-template.tar.gz differ diff --git a/node_modules/@capacitor/cli/assets/ios-spm-template.tar.gz b/node_modules/@capacitor/cli/assets/ios-spm-template.tar.gz new file mode 100644 index 0000000..e7519c8 Binary files /dev/null and b/node_modules/@capacitor/cli/assets/ios-spm-template.tar.gz differ diff --git a/node_modules/@capacitor/cli/bin/capacitor b/node_modules/@capacitor/cli/bin/capacitor new file mode 100755 index 0000000..415b237 --- /dev/null +++ b/node_modules/@capacitor/cli/bin/capacitor @@ -0,0 +1,18 @@ +#!/usr/bin/env node +'use strict'; + +var satisfies = require('semver/functions/satisfies'); +var packageJson = require('../package.json'); +var requiresNodeVersion = packageJson.engines.node; + +if (!satisfies(process.version, requiresNodeVersion, { includePrerelease: true})) { + process.stdout.write( + '\x1b[31m[fatal]\x1b[39m The Capacitor CLI requires NodeJS ' + requiresNodeVersion + '\n' + + ' Please install the latest LTS version.\n' + ); + + process.exit(1); +} + +var cli = require('../dist/index'); +cli.run(); diff --git a/node_modules/@capacitor/cli/dist/android/add.js b/node_modules/@capacitor/cli/dist/android/add.js new file mode 100644 index 0000000..395ca01 --- /dev/null +++ b/node_modules/@capacitor/cli/dist/android/add.js @@ -0,0 +1,52 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.createLocalProperties = exports.addAndroid = void 0; +const tslib_1 = require("tslib"); +const fs_extra_1 = require("fs-extra"); +const os_1 = require("os"); +const path_1 = require("path"); +const colors_1 = tslib_1.__importDefault(require("../colors")); +const common_1 = require("../common"); +const subprocess_1 = require("../util/subprocess"); +const template_1 = require("../util/template"); +async function addAndroid(config) { + await (0, common_1.runTask)(`Adding native android project in ${colors_1.default.strong(config.android.platformDir)}`, async () => { + return (0, template_1.extractTemplate)(config.cli.assets.android.platformTemplateArchiveAbs, config.android.platformDirAbs); + }); +} +exports.addAndroid = addAndroid; +async function createLocalProperties(platformDir) { + const defaultAndroidPath = (0, path_1.join)((0, os_1.homedir)(), 'Library/Android/sdk'); + if (await (0, fs_extra_1.pathExists)(defaultAndroidPath)) { + const localSettings = ` +## This file is automatically generated by Android Studio. +# Do not modify this file -- YOUR CHANGES WILL BE ERASED! +# +# This file should *NOT* be checked into Version Control Systems, +# as it contains information specific to your local configuration. +# +# Location of the SDK. This is only used by Gradle. +# For customization when using a Version Control System, please read the +# header note. +sdk.dir=${defaultAndroidPath} + `; + await (0, fs_extra_1.writeFile)((0, path_1.join)(platformDir, 'local.properties'), localSettings, { + encoding: 'utf-8', + }); + // Only sync if we were able to create the local properties above, otherwise + // this will fail + try { + await gradleSync(platformDir); + } + catch (e) { + console.error('Error running gradle sync', e); + console.error('Unable to infer default Android SDK settings. This is fine, just run npx cap open android and import and sync gradle manually'); + } + } +} +exports.createLocalProperties = createLocalProperties; +async function gradleSync(platformDir) { + await (0, subprocess_1.runCommand)(`./gradlew`, [], { + cwd: platformDir, + }); +} diff --git a/node_modules/@capacitor/cli/dist/android/build.js b/node_modules/@capacitor/cli/dist/android/build.js new file mode 100644 index 0000000..90752e9 --- /dev/null +++ b/node_modules/@capacitor/cli/dist/android/build.js @@ -0,0 +1,104 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.buildAndroid = void 0; +const tslib_1 = require("tslib"); +const path_1 = require("path"); +const colors_1 = tslib_1.__importDefault(require("../colors")); +const common_1 = require("../common"); +const log_1 = require("../log"); +const subprocess_1 = require("../util/subprocess"); +async function buildAndroid(config, buildOptions) { + var _a, _b; + const releaseType = (_a = buildOptions.androidreleasetype) !== null && _a !== void 0 ? _a : 'AAB'; + const releaseTypeIsAAB = releaseType === 'AAB'; + const flavor = (_b = buildOptions.flavor) !== null && _b !== void 0 ? _b : ''; + const arg = releaseTypeIsAAB ? `:app:bundle${flavor}Release` : `assemble${flavor}Release`; + const gradleArgs = [arg]; + try { + await (0, common_1.runTask)('Running Gradle build', async () => (0, subprocess_1.runCommand)('./gradlew', gradleArgs, { + cwd: config.android.platformDirAbs, + })); + } + catch (e) { + if (e.includes('EACCES')) { + throw `gradlew file does not have executable permissions. This can happen if the Android platform was added on a Windows machine. Please run ${colors_1.default.strong(`chmod +x ./${config.android.platformDir}/gradlew`)} and try again.`; + } + else { + throw e; + } + } + const releaseDir = releaseTypeIsAAB + ? flavor !== '' + ? `${flavor}Release` + : 'release' + : flavor !== '' + ? (0, path_1.join)(flavor, 'release') + : 'release'; + const releasePath = (0, path_1.join)(config.android.appDirAbs, 'build', 'outputs', releaseTypeIsAAB ? 'bundle' : 'apk', releaseDir); + const unsignedReleaseName = `app${flavor !== '' ? `-${flavor}` : ''}-release${releaseTypeIsAAB ? '' : '-unsigned'}.${releaseType.toLowerCase()}`; + const signedReleaseName = unsignedReleaseName.replace(`-release${releaseTypeIsAAB ? '' : '-unsigned'}.${releaseType.toLowerCase()}`, `-release-signed.${releaseType.toLowerCase()}`); + if (buildOptions.signingtype == 'jarsigner') { + await signWithJarSigner(config, buildOptions, releasePath, signedReleaseName, unsignedReleaseName); + } + else { + await signWithApkSigner(config, buildOptions, releasePath, signedReleaseName, unsignedReleaseName); + } + (0, log_1.logSuccess)(`Successfully generated ${signedReleaseName} at: ${releasePath}`); +} +exports.buildAndroid = buildAndroid; +async function signWithApkSigner(config, buildOptions, releasePath, signedReleaseName, unsignedReleaseName) { + if (!buildOptions.keystorepath || !buildOptions.keystorepass) { + throw 'Missing options. Please supply all options for android signing. (Keystore Path, Keystore Password)'; + } + const signingArgs = [ + 'sign', + '--ks', + buildOptions.keystorepath, + '--ks-pass', + `pass:${buildOptions.keystorepass}`, + '--in', + `${(0, path_1.join)(releasePath, unsignedReleaseName)}`, + '--out', + `${(0, path_1.join)(releasePath, signedReleaseName)}`, + ]; + if (buildOptions.keystorealias) { + signingArgs.push('--ks-key-alias', buildOptions.keystorealias); + } + if (buildOptions.keystorealiaspass) { + signingArgs.push('--key-pass', `pass:${buildOptions.keystorealiaspass}`); + } + await (0, common_1.runTask)('Signing Release', async () => { + await (0, subprocess_1.runCommand)('apksigner', signingArgs, { + cwd: config.android.platformDirAbs, + }); + }); +} +async function signWithJarSigner(config, buildOptions, releasePath, signedReleaseName, unsignedReleaseName) { + if (!buildOptions.keystorepath || + !buildOptions.keystorealias || + !buildOptions.keystorealiaspass || + !buildOptions.keystorepass) { + throw 'Missing options. Please supply all options for android signing. (Keystore Path, Keystore Password, Keystore Key Alias, Keystore Key Password)'; + } + const signingArgs = [ + '-sigalg', + 'SHA1withRSA', + '-digestalg', + 'SHA1', + '-keystore', + buildOptions.keystorepath, + '-keypass', + buildOptions.keystorealiaspass, + '-storepass', + buildOptions.keystorepass, + `-signedjar`, + `${(0, path_1.join)(releasePath, signedReleaseName)}`, + `${(0, path_1.join)(releasePath, unsignedReleaseName)}`, + buildOptions.keystorealias, + ]; + await (0, common_1.runTask)('Signing Release', async () => { + await (0, subprocess_1.runCommand)('jarsigner', signingArgs, { + cwd: config.android.platformDirAbs, + }); + }); +} diff --git a/node_modules/@capacitor/cli/dist/android/common.js b/node_modules/@capacitor/cli/dist/android/common.js new file mode 100644 index 0000000..bed59ac --- /dev/null +++ b/node_modules/@capacitor/cli/dist/android/common.js @@ -0,0 +1,94 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.editProjectSettingsAndroid = exports.resolvePlugin = exports.getAndroidPlugins = exports.checkAndroidPackage = void 0; +const fs_extra_1 = require("fs-extra"); +const path_1 = require("path"); +const common_1 = require("../common"); +const cordova_1 = require("../cordova"); +const plugin_1 = require("../plugin"); +const fs_1 = require("../util/fs"); +async function checkAndroidPackage(config) { + return (0, common_1.checkCapacitorPlatform)(config, 'android'); +} +exports.checkAndroidPackage = checkAndroidPackage; +async function getAndroidPlugins(allPlugins) { + const resolved = await Promise.all(allPlugins.map(async (plugin) => await resolvePlugin(plugin))); + return resolved.filter((plugin) => !!plugin); +} +exports.getAndroidPlugins = getAndroidPlugins; +async function resolvePlugin(plugin) { + var _a; + const platform = 'android'; + if ((_a = plugin.manifest) === null || _a === void 0 ? void 0 : _a.android) { + let pluginFilesPath = plugin.manifest.android.src ? plugin.manifest.android.src : platform; + const absolutePath = (0, path_1.join)(plugin.rootPath, pluginFilesPath, plugin.id); + // Android folder shouldn't have subfolders, but they used to, so search for them for compatibility reasons + if (await (0, fs_extra_1.pathExists)(absolutePath)) { + pluginFilesPath = (0, path_1.join)(platform, plugin.id); + } + plugin.android = { + type: 0 /* PluginType.Core */, + path: (0, fs_1.convertToUnixPath)(pluginFilesPath), + }; + } + else if (plugin.xml) { + plugin.android = { + type: 1 /* PluginType.Cordova */, + path: 'src/' + platform, + }; + if ((0, cordova_1.getIncompatibleCordovaPlugins)(platform).includes(plugin.id) || !(0, plugin_1.getPluginPlatform)(plugin, platform)) { + plugin.android.type = 2 /* PluginType.Incompatible */; + } + } + else { + return null; + } + return plugin; +} +exports.resolvePlugin = resolvePlugin; +/** + * Update an Android project with the desired app name and appId. + * This is a little trickier for Android because the appId becomes + * the package name. + */ +async function editProjectSettingsAndroid(config) { + const appId = config.app.appId; + const appName = config.app.appName + .replace(/&/g, '&') + .replace(/ checkGradlew(config), () => checkAppSrcDirs(config)]); + (0, log_1.logSuccess)('Android looking great! 👌'); + } + catch (e) { + if (!(0, errors_1.isFatal)(e)) { + (0, errors_1.fatal)((_a = e.stack) !== null && _a !== void 0 ? _a : e); + } + throw e; + } +} +exports.doctorAndroid = doctorAndroid; +async function checkAppSrcDirs(config) { + if (!(await (0, fs_extra_1.pathExists)(config.android.appDirAbs))) { + return `${colors_1.default.strong(config.android.appDir)} directory is missing in ${colors_1.default.strong(config.android.platformDir)}`; + } + if (!(await (0, fs_extra_1.pathExists)(config.android.srcMainDirAbs))) { + return `${colors_1.default.strong(config.android.srcMainDir)} directory is missing in ${colors_1.default.strong(config.android.platformDir)}`; + } + if (!(await (0, fs_extra_1.pathExists)(config.android.assetsDirAbs))) { + return `${colors_1.default.strong(config.android.assetsDir)} directory is missing in ${colors_1.default.strong(config.android.platformDir)}`; + } + if (!(await (0, fs_extra_1.pathExists)(config.android.webDirAbs))) { + return `${colors_1.default.strong(config.android.webDir)} directory is missing in ${colors_1.default.strong(config.android.platformDir)}`; + } + const appSrcMainAssetsWwwIndexHtmlDir = (0, path_1.join)(config.android.webDirAbs, 'index.html'); + if (!(await (0, fs_extra_1.pathExists)(appSrcMainAssetsWwwIndexHtmlDir))) { + return `${colors_1.default.strong('index.html')} file is missing in ${colors_1.default.strong(config.android.webDirAbs)}`; + } + return checkAndroidManifestFile(config); +} +async function checkAndroidManifestFile(config) { + const manifestFileName = 'AndroidManifest.xml'; + const manifestFilePath = (0, path_1.join)(config.android.srcMainDirAbs, manifestFileName); + if (!(await (0, fs_extra_1.pathExists)(manifestFilePath))) { + return `${colors_1.default.strong(manifestFileName)} is missing in ${colors_1.default.strong(config.android.srcMainDir)}`; + } + try { + const xmlData = await (0, xml_1.readXML)(manifestFilePath); + return checkAndroidManifestData(config, xmlData); + } + catch (e) { + return e; + } +} +async function checkAndroidManifestData(config, xmlData) { + const manifestNode = xmlData.manifest; + if (!manifestNode) { + return `Missing ${colors_1.default.input('')} XML node in ${colors_1.default.strong(config.android.srcMainDir)}`; + } + const applicationChildNodes = manifestNode.application; + if (!Array.isArray(manifestNode.application)) { + return `Missing ${colors_1.default.input('')} XML node as a child node of ${colors_1.default.input('')} in ${colors_1.default.strong(config.android.srcMainDir)}`; + } + let mainActivityClassPath = ''; + const mainApplicationNode = applicationChildNodes.find((applicationChildNode) => { + const activityChildNodes = applicationChildNode.activity; + if (!Array.isArray(activityChildNodes)) { + return false; + } + const mainActivityNode = activityChildNodes.find((activityChildNode) => { + const intentFilterChildNodes = activityChildNode['intent-filter']; + if (!Array.isArray(intentFilterChildNodes)) { + return false; + } + return intentFilterChildNodes.find((intentFilterChildNode) => { + const actionChildNodes = intentFilterChildNode.action; + if (!Array.isArray(actionChildNodes)) { + return false; + } + const mainActionChildNode = actionChildNodes.find((actionChildNode) => { + const androidName = actionChildNode.$['android:name']; + return androidName === 'android.intent.action.MAIN'; + }); + if (!mainActionChildNode) { + return false; + } + const categoryChildNodes = intentFilterChildNode.category; + if (!Array.isArray(categoryChildNodes)) { + return false; + } + return categoryChildNodes.find((categoryChildNode) => { + const androidName = categoryChildNode.$['android:name']; + return androidName === 'android.intent.category.LAUNCHER'; + }); + }); + }); + if (mainActivityNode) { + mainActivityClassPath = mainActivityNode.$['android:name']; + } + return mainActivityNode; + }); + if (!mainApplicationNode) { + return `Missing main ${colors_1.default.input('')} XML node in ${colors_1.default.strong(config.android.srcMainDir)}`; + } + if (!mainActivityClassPath) { + return `Missing ${colors_1.default.input('')} attribute for MainActivity class in ${colors_1.default.strong(config.android.srcMainDir)}`; + } + return checkPackage(config, mainActivityClassPath); +} +async function checkPackage(config, mainActivityClassPath) { + const appSrcMainJavaDir = (0, path_1.join)(config.android.srcMainDirAbs, 'java'); + if (!(await (0, fs_extra_1.pathExists)(appSrcMainJavaDir))) { + return `${colors_1.default.strong('java')} directory is missing in ${colors_1.default.strong(appSrcMainJavaDir)}`; + } + const mainActivityClassName = mainActivityClassPath.split('.').pop(); + const srcFiles = await (0, fs_1.readdirp)(appSrcMainJavaDir, { + filter: (entry) => !entry.stats.isDirectory() && + ['.java', '.kt'].includes((0, path_1.extname)(entry.path)) && + mainActivityClassName === (0, path_1.parse)(entry.path).name, + }); + if (srcFiles.length == 0) { + return `Main activity file (${mainActivityClassName}) is missing`; + } + return checkBuildGradle(config); +} +async function checkBuildGradle(config) { + const fileName = 'build.gradle'; + const filePath = (0, path_1.join)(config.android.appDirAbs, fileName); + if (!(await (0, fs_extra_1.pathExists)(filePath))) { + return `${colors_1.default.strong(fileName)} file is missing in ${colors_1.default.strong(config.android.appDir)}`; + } + let fileContent = await (0, fs_extra_1.readFile)(filePath, { encoding: 'utf-8' }); + fileContent = fileContent.replace(/'|"/g, '').replace(/\s+/g, ' '); + const searchFor = `applicationId`; + if (fileContent.indexOf(searchFor) === -1) { + return `${colors_1.default.strong('build.gradle')} file missing ${colors_1.default.input(`applicationId`)} config in ${filePath}`; + } + return null; +} +async function checkGradlew(config) { + const fileName = 'gradlew'; + const filePath = (0, path_1.join)(config.android.platformDirAbs, fileName); + if (!(await (0, fs_extra_1.pathExists)(filePath))) { + return `${colors_1.default.strong(fileName)} file is missing in ${colors_1.default.strong(config.android.platformDir)}`; + } + return null; +} +async function checkAndroidInstalled() { + /* + if (!await isInstalled('android')) { + return 'Android is not installed. For information: https://developer.android.com/studio/index.html'; + } + */ + return null; +} diff --git a/node_modules/@capacitor/cli/dist/android/open.js b/node_modules/@capacitor/cli/dist/android/open.js new file mode 100644 index 0000000..a5b8b78 --- /dev/null +++ b/node_modules/@capacitor/cli/dist/android/open.js @@ -0,0 +1,28 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.openAndroid = void 0; +const tslib_1 = require("tslib"); +const debug_1 = tslib_1.__importDefault(require("debug")); +const fs_extra_1 = require("fs-extra"); +const open_1 = tslib_1.__importDefault(require("open")); +const colors_1 = tslib_1.__importDefault(require("../colors")); +const log_1 = require("../log"); +const debug = (0, debug_1.default)('capacitor:android:open'); +async function openAndroid(config) { + const androidStudioPath = await config.android.studioPath; + const dir = config.android.platformDirAbs; + try { + if (!(await (0, fs_extra_1.pathExists)(androidStudioPath))) { + throw new Error(`Android Studio does not exist at: ${androidStudioPath}`); + } + await (0, open_1.default)(dir, { app: { name: androidStudioPath }, wait: false }); + log_1.logger.info(`Opening Android project at: ${colors_1.default.strong(config.android.platformDir)}.`); + } + catch (e) { + debug('Error opening Android Studio: %O', e); + log_1.logger.error('Unable to launch Android Studio. Is it installed?\n' + + `Attempted to open Android Studio at: ${colors_1.default.strong(androidStudioPath)}\n` + + `You can configure this with the ${colors_1.default.input('CAPACITOR_ANDROID_STUDIO_PATH')} environment variable.`); + } +} +exports.openAndroid = openAndroid; diff --git a/node_modules/@capacitor/cli/dist/android/run.js b/node_modules/@capacitor/cli/dist/android/run.js new file mode 100644 index 0000000..3f52728 --- /dev/null +++ b/node_modules/@capacitor/cli/dist/android/run.js @@ -0,0 +1,42 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.runAndroid = void 0; +const tslib_1 = require("tslib"); +const debug_1 = tslib_1.__importDefault(require("debug")); +const path_1 = require("path"); +const colors_1 = tslib_1.__importDefault(require("../colors")); +const common_1 = require("../common"); +const native_run_1 = require("../util/native-run"); +const subprocess_1 = require("../util/subprocess"); +const debug = (0, debug_1.default)('capacitor:android:run'); +async function runAndroid(config, { target: selectedTarget, targetName: selectedTargetName, targetNameSdkVersion: selectedTargetSdkVersion, flavor: selectedFlavor, forwardPorts: selectedPorts, }) { + var _a; + const target = await (0, common_1.promptForPlatformTarget)(await (0, native_run_1.getPlatformTargets)('android'), selectedTarget !== null && selectedTarget !== void 0 ? selectedTarget : selectedTargetName, selectedTargetSdkVersion, selectedTargetName !== undefined); + const runFlavor = selectedFlavor || ((_a = config.android) === null || _a === void 0 ? void 0 : _a.flavor) || ''; + const arg = `assemble${runFlavor}Debug`; + const gradleArgs = [arg]; + debug('Invoking ./gradlew with args: %O', gradleArgs); + try { + await (0, common_1.runTask)('Running Gradle build', async () => (0, subprocess_1.runCommand)('./gradlew', gradleArgs, { + cwd: config.android.platformDirAbs, + })); + } + catch (e) { + if (e.includes('EACCES')) { + throw `gradlew file does not have executable permissions. This can happen if the Android platform was added on a Windows machine. Please run ${colors_1.default.strong(`chmod +x ./${config.android.platformDir}/gradlew`)} and try again.`; + } + else { + throw e; + } + } + const pathToApk = `${config.android.platformDirAbs}/${config.android.appDir}/build/outputs/apk${runFlavor !== '' ? '/' + runFlavor : ''}/debug`; + const apkName = (0, common_1.parseApkNameFromFlavor)(runFlavor); + const apkPath = (0, path_1.resolve)(pathToApk, apkName); + const nativeRunArgs = ['android', '--app', apkPath, '--target', target.id]; + if (selectedPorts) { + nativeRunArgs.push('--forward', `${selectedPorts}`); + } + debug('Invoking native-run with args: %O', nativeRunArgs); + await (0, common_1.runTask)(`Deploying ${colors_1.default.strong(apkName)} to ${colors_1.default.input(target.id)}`, async () => (0, native_run_1.runNativeRun)(nativeRunArgs)); +} +exports.runAndroid = runAndroid; diff --git a/node_modules/@capacitor/cli/dist/android/update.js b/node_modules/@capacitor/cli/dist/android/update.js new file mode 100644 index 0000000..bc5699a --- /dev/null +++ b/node_modules/@capacitor/cli/dist/android/update.js @@ -0,0 +1,317 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.handleCordovaPluginsGradle = exports.installGradlePlugins = exports.updateAndroid = void 0; +const tslib_1 = require("tslib"); +const debug_1 = tslib_1.__importDefault(require("debug")); +const fs_extra_1 = require("fs-extra"); +const path_1 = require("path"); +const colors_1 = tslib_1.__importDefault(require("../colors")); +const common_1 = require("../common"); +const cordova_1 = require("../cordova"); +const errors_1 = require("../errors"); +const plugin_1 = require("../plugin"); +const copy_1 = require("../tasks/copy"); +const fs_1 = require("../util/fs"); +const node_1 = require("../util/node"); +const template_1 = require("../util/template"); +const common_2 = require("./common"); +const platform = 'android'; +const debug = (0, debug_1.default)('capacitor:android:update'); +async function updateAndroid(config) { + var _a; + const plugins = await getPluginsTask(config); + const capacitorPlugins = plugins.filter((p) => (0, plugin_1.getPluginType)(p, platform) === 0 /* PluginType.Core */); + (0, plugin_1.printPlugins)(capacitorPlugins, 'android'); + await writePluginsJson(config, capacitorPlugins); + await removePluginsNativeFiles(config); + const cordovaPlugins = plugins.filter((p) => (0, plugin_1.getPluginType)(p, platform) === 1 /* PluginType.Cordova */); + if (cordovaPlugins.length > 0) { + await copyPluginsNativeFiles(config, cordovaPlugins); + } + if (!(await (0, fs_extra_1.pathExists)(config.android.webDirAbs))) { + await (0, copy_1.copy)(config, platform); + } + await (0, cordova_1.handleCordovaPluginsJS)(cordovaPlugins, config, platform); + await (0, cordova_1.checkPluginDependencies)(plugins, platform, (_a = config.app.extConfig.cordova) === null || _a === void 0 ? void 0 : _a.failOnUninstalledPlugins); + await installGradlePlugins(config, capacitorPlugins, cordovaPlugins); + await handleCordovaPluginsGradle(config, cordovaPlugins); + await (0, cordova_1.writeCordovaAndroidManifest)(cordovaPlugins, config, platform); + const incompatibleCordovaPlugins = plugins.filter((p) => (0, plugin_1.getPluginType)(p, platform) === 2 /* PluginType.Incompatible */); + (0, plugin_1.printPlugins)(incompatibleCordovaPlugins, platform, 'incompatible'); + await (0, common_1.checkPlatformVersions)(config, platform); +} +exports.updateAndroid = updateAndroid; +function getGradlePackageName(id) { + return id.replace('@', '').replace('/', '-'); +} +async function writePluginsJson(config, plugins) { + const classes = await findAndroidPluginClasses(plugins); + const pluginsJsonPath = (0, path_1.resolve)(config.android.assetsDirAbs, 'capacitor.plugins.json'); + await (0, fs_extra_1.writeJSON)(pluginsJsonPath, classes, { spaces: '\t' }); +} +async function findAndroidPluginClasses(plugins) { + const entries = []; + for (const plugin of plugins) { + entries.push(...(await findAndroidPluginClassesInPlugin(plugin))); + } + return entries; +} +async function findAndroidPluginClassesInPlugin(plugin) { + if (!plugin.android || (0, plugin_1.getPluginType)(plugin, platform) !== 0 /* PluginType.Core */) { + return []; + } + const srcPath = (0, path_1.resolve)(plugin.rootPath, plugin.android.path, 'src/main'); + const srcFiles = await (0, fs_1.readdirp)(srcPath, { + filter: (entry) => !entry.stats.isDirectory() && ['.java', '.kt'].includes((0, path_1.extname)(entry.path)), + }); + const classRegex = /^@(?:CapacitorPlugin|NativePlugin)[\s\S]+?class ([\w]+)/gm; + const packageRegex = /^package ([\w.]+);?$/gm; + debug('Searching %O source files in %O by %O regex', srcFiles.length, srcPath, classRegex); + const entries = await Promise.all(srcFiles.map(async (srcFile) => { + const srcFileContents = await (0, fs_extra_1.readFile)(srcFile, { encoding: 'utf-8' }); + classRegex.lastIndex = 0; + const classMatch = classRegex.exec(srcFileContents); + if (classMatch) { + const className = classMatch[1]; + debug('Searching %O for package by %O regex', srcFile, packageRegex); + packageRegex.lastIndex = 0; + const packageMatch = packageRegex.exec(srcFileContents.substring(0, classMatch.index)); + if (!packageMatch) { + (0, errors_1.fatal)(`Package could not be parsed from Android plugin.\n` + `Location: ${colors_1.default.strong(srcFile)}`); + } + const packageName = packageMatch[1]; + const classpath = `${packageName}.${className}`; + debug('%O is a suitable plugin class', classpath); + return { + pkg: plugin.id, + classpath, + }; + } + })); + return entries.filter((entry) => !!entry); +} +async function installGradlePlugins(config, capacitorPlugins, cordovaPlugins) { + const capacitorAndroidPackagePath = (0, node_1.resolveNode)(config.app.rootDir, '@capacitor/android', 'package.json'); + if (!capacitorAndroidPackagePath) { + (0, errors_1.fatal)(`Unable to find ${colors_1.default.strong('node_modules/@capacitor/android')}.\n` + + `Are you sure ${colors_1.default.strong('@capacitor/android')} is installed?`); + } + const capacitorAndroidPath = (0, path_1.resolve)((0, path_1.dirname)(capacitorAndroidPackagePath), 'capacitor'); + const settingsPath = config.android.platformDirAbs; + const dependencyPath = config.android.appDirAbs; + const relativeCapcitorAndroidPath = (0, fs_1.convertToUnixPath)((0, path_1.relative)(settingsPath, capacitorAndroidPath)); + const settingsLines = `// DO NOT EDIT THIS FILE! IT IS GENERATED EACH TIME "capacitor update" IS RUN +include ':capacitor-android' +project(':capacitor-android').projectDir = new File('${relativeCapcitorAndroidPath}') +${capacitorPlugins + .map((p) => { + if (!p.android) { + return ''; + } + const relativePluginPath = (0, fs_1.convertToUnixPath)((0, path_1.relative)(settingsPath, p.rootPath)); + return ` +include ':${getGradlePackageName(p.id)}' +project(':${getGradlePackageName(p.id)}').projectDir = new File('${relativePluginPath}/${p.android.path}') +`; + }) + .join('')}`; + const applyArray = []; + const frameworksArray = []; + let prefsArray = []; + cordovaPlugins.map((p) => { + const relativePluginPath = (0, fs_1.convertToUnixPath)((0, path_1.relative)(dependencyPath, p.rootPath)); + const frameworks = (0, plugin_1.getPlatformElement)(p, platform, 'framework'); + frameworks.map((framework) => { + if (framework.$.custom && + framework.$.custom === 'true' && + framework.$.type && + framework.$.type === 'gradleReference') { + applyArray.push(`apply from: "${relativePluginPath}/${framework.$.src}"`); + } + else if (!framework.$.type && !framework.$.custom) { + if (framework.$.src.startsWith('platform(')) { + frameworksArray.push(` implementation ${framework.$.src}`); + } + else { + frameworksArray.push(` implementation "${framework.$.src}"`); + } + } + }); + prefsArray = prefsArray.concat((0, plugin_1.getAllElements)(p, platform, 'preference')); + }); + let frameworkString = frameworksArray.join('\n'); + frameworkString = await replaceFrameworkVariables(config, prefsArray, frameworkString); + const dependencyLines = `// DO NOT EDIT THIS FILE! IT IS GENERATED EACH TIME "capacitor update" IS RUN + +android { + compileOptions { + sourceCompatibility JavaVersion.VERSION_21 + targetCompatibility JavaVersion.VERSION_21 + } +} + +apply from: "../capacitor-cordova-android-plugins/cordova.variables.gradle" +dependencies { +${capacitorPlugins + .map((p) => { + return ` implementation project(':${getGradlePackageName(p.id)}')`; + }) + .join('\n')} +${frameworkString} +} +${applyArray.join('\n')} + +if (hasProperty('postBuildExtras')) { + postBuildExtras() +} +`; + await (0, fs_extra_1.writeFile)((0, path_1.join)(settingsPath, 'capacitor.settings.gradle'), settingsLines); + await (0, fs_extra_1.writeFile)((0, path_1.join)(dependencyPath, 'capacitor.build.gradle'), dependencyLines); +} +exports.installGradlePlugins = installGradlePlugins; +async function handleCordovaPluginsGradle(config, cordovaPlugins) { + var _a, _b, _c; + const pluginsGradlePath = (0, path_1.join)(config.android.cordovaPluginsDirAbs, 'build.gradle'); + const kotlinNeeded = await kotlinNeededCheck(config, cordovaPlugins); + const kotlinVersionString = (_c = (_b = (_a = config.app.extConfig.cordova) === null || _a === void 0 ? void 0 : _a.preferences) === null || _b === void 0 ? void 0 : _b.GradlePluginKotlinVersion) !== null && _c !== void 0 ? _c : '2.2.20'; + const frameworksArray = []; + let prefsArray = []; + const applyArray = []; + applyArray.push(`apply from: "cordova.variables.gradle"`); + cordovaPlugins.map((p) => { + const relativePluginPath = (0, fs_1.convertToUnixPath)((0, path_1.relative)(config.android.cordovaPluginsDirAbs, p.rootPath)); + const frameworks = (0, plugin_1.getPlatformElement)(p, platform, 'framework'); + frameworks.map((framework) => { + if (!framework.$.type && !framework.$.custom) { + frameworksArray.push(framework.$.src); + } + else if (framework.$.custom && + framework.$.custom === 'true' && + framework.$.type && + framework.$.type === 'gradleReference') { + applyArray.push(`apply from: "${relativePluginPath}/${framework.$.src}"`); + } + }); + prefsArray = prefsArray.concat((0, plugin_1.getAllElements)(p, platform, 'preference')); + }); + let frameworkString = frameworksArray + .map((f) => { + if (f.startsWith('platform(')) { + return ` implementation ${f}`; + } + else { + return ` implementation "${f}"`; + } + }) + .join('\n'); + frameworkString = await replaceFrameworkVariables(config, prefsArray, frameworkString); + if (kotlinNeeded) { + frameworkString += `\n implementation "androidx.core:core-ktx:$androidxCoreKTXVersion"`; + frameworkString += `\n implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"`; + } + const applyString = applyArray.join('\n'); + let buildGradle = await (0, fs_extra_1.readFile)(pluginsGradlePath, { encoding: 'utf-8' }); + buildGradle = buildGradle.replace(/(SUB-PROJECT DEPENDENCIES START)[\s\S]*(\/\/ SUB-PROJECT DEPENDENCIES END)/, '$1\n' + frameworkString.concat('\n') + ' $2'); + buildGradle = buildGradle.replace(/(PLUGIN GRADLE EXTENSIONS START)[\s\S]*(\/\/ PLUGIN GRADLE EXTENSIONS END)/, '$1\n' + applyString.concat('\n') + '$2'); + if (kotlinNeeded) { + buildGradle = buildGradle.replace(/(buildscript\s{\n(\t|\s{4})repositories\s{\n((\t{2}|\s{8}).+\n)+(\t|\s{4})}\n(\t|\s{4})dependencies\s{\n(\t{2}|\s{8}).+)\n((\t|\s{4})}\n}\n)/, `$1\n classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"\n$8`); + buildGradle = buildGradle.replace(/(ext\s{)/, `$1\n androidxCoreKTXVersion = project.hasProperty('androidxCoreKTXVersion') ? rootProject.ext.androidxCoreKTXVersion : '1.8.0'`); + buildGradle = buildGradle.replace(/(buildscript\s{)/, `$1\n ext.kotlin_version = project.hasProperty('kotlin_version') ? rootProject.ext.kotlin_version : '${kotlinVersionString}'`); + buildGradle = buildGradle.replace(/(apply\splugin:\s'com\.android\.library')/, `$1\napply plugin: 'kotlin-android'`); + buildGradle = buildGradle.replace(/(compileOptions\s{\n((\t{2}|\s{8}).+\n)+(\t|\s{4})})\n(})/, `$1\n sourceSets {\n main.java.srcDirs += 'src/main/kotlin'\n }\n$5`); + } + await (0, fs_extra_1.writeFile)(pluginsGradlePath, buildGradle); + const cordovaVariables = `// DO NOT EDIT THIS FILE! IT IS GENERATED EACH TIME "capacitor update" IS RUN +ext { + cdvMinSdkVersion = project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : ${config.android.minVersion} + // Plugin gradle extensions can append to this to have code run at the end. + cdvPluginPostBuildExtras = [] + cordovaConfig = [:] +}`; + await (0, fs_extra_1.writeFile)((0, path_1.join)(config.android.cordovaPluginsDirAbs, 'cordova.variables.gradle'), cordovaVariables); +} +exports.handleCordovaPluginsGradle = handleCordovaPluginsGradle; +async function kotlinNeededCheck(config, cordovaPlugins) { + var _a, _b; + if (((_b = (_a = config.app.extConfig.cordova) === null || _a === void 0 ? void 0 : _a.preferences) === null || _b === void 0 ? void 0 : _b.GradlePluginKotlinEnabled) !== 'true') { + for (const plugin of cordovaPlugins) { + const androidPlatform = (0, plugin_1.getPluginPlatform)(plugin, platform); + const sourceFiles = androidPlatform['source-file']; + if (sourceFiles) { + for (const srcFile of sourceFiles) { + if (/^.*\.kt$/.test(srcFile['$'].src)) { + return true; + } + } + } + } + return false; + } + else { + return true; + } +} +async function copyPluginsNativeFiles(config, cordovaPlugins) { + const pluginsPath = (0, path_1.join)(config.android.cordovaPluginsDirAbs, 'src', 'main'); + for (const p of cordovaPlugins) { + const androidPlatform = (0, plugin_1.getPluginPlatform)(p, platform); + if (androidPlatform) { + const sourceFiles = androidPlatform['source-file']; + if (sourceFiles) { + for (const sourceFile of sourceFiles) { + const fileName = sourceFile.$.src.split('/').pop(); + let baseFolder = 'java/'; + if (fileName.split('.').pop() === 'aidl') { + baseFolder = 'aidl/'; + } + const target = sourceFile.$['target-dir'].replace('app/src/main/', '').replace('src/', baseFolder); + await (0, fs_extra_1.copy)((0, plugin_1.getFilePath)(config, p, sourceFile.$.src), (0, path_1.join)(pluginsPath, target, fileName)); + } + } + const resourceFiles = androidPlatform['resource-file']; + if (resourceFiles) { + for (const resourceFile of resourceFiles) { + const target = resourceFile.$['target']; + if (resourceFile.$.src.split('.').pop() === 'aar') { + await (0, fs_extra_1.copy)((0, plugin_1.getFilePath)(config, p, resourceFile.$.src), (0, path_1.join)(pluginsPath, 'libs', target.split('/').pop())); + } + else if (target !== '.') { + await (0, fs_extra_1.copy)((0, plugin_1.getFilePath)(config, p, resourceFile.$.src), (0, path_1.join)(pluginsPath, target)); + } + } + } + const libFiles = (0, plugin_1.getPlatformElement)(p, platform, 'lib-file'); + for (const libFile of libFiles) { + await (0, fs_extra_1.copy)((0, plugin_1.getFilePath)(config, p, libFile.$.src), (0, path_1.join)(pluginsPath, 'libs', libFile.$.src.split('/').pop())); + } + } + } +} +async function removePluginsNativeFiles(config) { + await (0, fs_extra_1.remove)(config.android.cordovaPluginsDirAbs); + await (0, template_1.extractTemplate)(config.cli.assets.android.cordovaPluginsTemplateArchiveAbs, config.android.cordovaPluginsDirAbs); +} +async function getPluginsTask(config) { + return await (0, common_1.runTask)('Updating Android plugins', async () => { + const allPlugins = await (0, plugin_1.getPlugins)(config, 'android'); + const androidPlugins = await (0, common_2.getAndroidPlugins)(allPlugins); + return androidPlugins; + }); +} +async function getVariablesGradleFile(config) { + const variablesFile = (0, path_1.resolve)(config.android.platformDirAbs, 'variables.gradle'); + let variablesGradle = ''; + if (await (0, fs_extra_1.pathExists)(variablesFile)) { + variablesGradle = await (0, fs_extra_1.readFile)(variablesFile, { encoding: 'utf-8' }); + } + return variablesGradle; +} +async function replaceFrameworkVariables(config, prefsArray, frameworkString) { + const variablesGradle = await getVariablesGradleFile(config); + prefsArray.map((preference) => { + if (!variablesGradle.includes(preference.$.name)) { + frameworkString = frameworkString.replace(new RegExp(('$' + preference.$.name).replace('$', '\\$&'), 'g'), preference.$.default); + } + }); + return frameworkString; +} diff --git a/node_modules/@capacitor/cli/dist/colors.js b/node_modules/@capacitor/cli/dist/colors.js new file mode 100644 index 0000000..8fe2c66 --- /dev/null +++ b/node_modules/@capacitor/cli/dist/colors.js @@ -0,0 +1,26 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.ancillary = exports.failure = exports.success = exports.input = exports.weak = exports.strong = void 0; +const tslib_1 = require("tslib"); +const kleur_1 = tslib_1.__importDefault(require("kleur")); +exports.strong = kleur_1.default.bold; +exports.weak = kleur_1.default.dim; +exports.input = kleur_1.default.cyan; +exports.success = kleur_1.default.green; +exports.failure = kleur_1.default.red; +exports.ancillary = kleur_1.default.cyan; +const COLORS = { + strong: exports.strong, + weak: exports.weak, + input: exports.input, + success: exports.success, + failure: exports.failure, + ancillary: exports.ancillary, + log: { + DEBUG: kleur_1.default.magenta, + INFO: kleur_1.default.cyan, + WARN: kleur_1.default.yellow, + ERROR: kleur_1.default.red, + }, +}; +exports.default = COLORS; diff --git a/node_modules/@capacitor/cli/dist/common.js b/node_modules/@capacitor/cli/dist/common.js new file mode 100644 index 0000000..1597e5e --- /dev/null +++ b/node_modules/@capacitor/cli/dist/common.js @@ -0,0 +1,437 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.parseApkNameFromFlavor = exports.checkJDKMajorVersion = exports.resolvePlatform = exports.checkPlatformVersions = exports.getAddedPlatforms = exports.getPlatformTargetName = exports.promptForPlatformTarget = exports.promptForPlatform = exports.isValidEnterprisePlatform = exports.getKnownEnterprisePlatforms = exports.isValidCommunityPlatform = exports.getKnownCommunityPlatforms = exports.isValidPlatform = exports.getKnownPlatforms = exports.selectPlatforms = exports.getProjectPlatformDirectory = exports.getCLIVersion = exports.getCoreVersion = exports.getCapacitorPackageVersion = exports.requireCapacitorPackage = exports.getCapacitorPackage = exports.runTask = exports.runPlatformHook = exports.runHooks = exports.wait = exports.checkAppName = exports.checkAppId = exports.checkAppDir = exports.checkAppConfig = exports.checkCapacitorPlatform = exports.checkPackage = exports.checkWebDir = exports.check = void 0; +const tslib_1 = require("tslib"); +const utils_terminal_1 = require("@ionic/utils-terminal"); +const fs_extra_1 = require("fs-extra"); +const path_1 = require("path"); +const colors_1 = tslib_1.__importDefault(require("./colors")); +const errors_1 = require("./errors"); +const log_1 = require("./log"); +const plugin_1 = require("./plugin"); +const monorepotools_1 = require("./util/monorepotools"); +const node_1 = require("./util/node"); +const subprocess_1 = require("./util/subprocess"); +async function check(checks) { + const results = await Promise.all(checks.map((f) => f())); + const errors = results.filter((r) => r != null); + if (errors.length > 0) { + throw errors.join('\n'); + } +} +exports.check = check; +async function checkWebDir(config) { + var _a; + // We can skip checking the web dir if a server URL is set. + if ((_a = config.app.extConfig.server) === null || _a === void 0 ? void 0 : _a.url) { + return null; + } + const invalidFolders = ['', '.', '..', '../', './']; + if (invalidFolders.includes(config.app.webDir)) { + return `"${config.app.webDir}" is not a valid value for webDir`; + } + if (!(await (0, fs_extra_1.pathExists)(config.app.webDirAbs))) { + return (`Could not find the web assets directory: ${colors_1.default.strong((0, utils_terminal_1.prettyPath)(config.app.webDirAbs))}.\n` + + `Please create it and make sure it has an ${colors_1.default.strong('index.html')} file. You can change the path of this directory in ${colors_1.default.strong(config.app.extConfigName)} (${colors_1.default.input('webDir')} option). You may need to compile the web assets for your app (typically ${colors_1.default.input('npm run build')}). More info: ${colors_1.default.strong('https://capacitorjs.com/docs/basics/workflow#sync-your-project')}`); + } + if (!(await (0, fs_extra_1.pathExists)((0, path_1.join)(config.app.webDirAbs, 'index.html')))) { + return (`The web assets directory (${colors_1.default.strong((0, utils_terminal_1.prettyPath)(config.app.webDirAbs))}) must contain an ${colors_1.default.strong('index.html')} file.\n` + + `It will be the entry point for the web portion of the Capacitor app.`); + } + return null; +} +exports.checkWebDir = checkWebDir; +async function checkPackage() { + if (!(await (0, fs_extra_1.pathExists)('package.json'))) { + if (await (0, fs_extra_1.pathExists)('project.json')) { + return null; + } + else { + return (`The Capacitor CLI needs to run at the root of an npm package or in a valid NX monorepo.\n` + + `Make sure you have a package.json or project.json file in the directory where you run the Capacitor CLI.\n` + + `More info: ${colors_1.default.strong('https://docs.npmjs.com/cli/init')}`); + } + } + return null; +} +exports.checkPackage = checkPackage; +async function checkCapacitorPlatform(config, platform) { + const pkg = await getCapacitorPackage(config, platform); + if (!pkg) { + return (`Could not find the ${colors_1.default.input(platform)} platform.\n` + + `You must install it in your project first, e.g. w/ ${colors_1.default.input(`npm install @capacitor/${platform}`)}`); + } + return null; +} +exports.checkCapacitorPlatform = checkCapacitorPlatform; +async function checkAppConfig(config) { + if (!config.app.appId) { + return (`Missing ${colors_1.default.input('appId')} for new platform.\n` + + `Please add it in ${config.app.extConfigName} or run ${colors_1.default.input('npx cap init')}.`); + } + if (!config.app.appName) { + return (`Missing ${colors_1.default.input('appName')} for new platform.\n` + + `Please add it in ${config.app.extConfigName} or run ${colors_1.default.input('npx cap init')}.`); + } + const appIdError = await checkAppId(config, config.app.appId); + if (appIdError) { + return appIdError; + } + const appNameError = await checkAppName(config, config.app.appName); + if (appNameError) { + return appNameError; + } + return null; +} +exports.checkAppConfig = checkAppConfig; +async function checkAppDir(config, dir) { + if (!/^\S*$/.test(dir)) { + return `Your app directory should not contain spaces`; + } + return null; +} +exports.checkAppDir = checkAppDir; +async function checkAppId(config, id) { + if (!id) { + return `Invalid App ID. App ID is required and cannot be blank.`; + } + if (/^[a-zA-Z][\w]*(?:\.[a-zA-Z][\w]*)+$/.test(id.toLowerCase())) { + return null; + } + return ` + Invalid App ID "${id}". Your App ID must meet the following requirements to be valid on both iOS and Android: + - Must be in Java package form with no dashes (ex: com.example.app) + - It must have at least two segments (one or more dots). + - Each segment must start with a letter. + - All characters must be alphanumeric or an underscore [a-zA-Z][a-zA-Z0-9]+. + + If you would like to skip validation, run "cap init" with the "--skip-appid-validation" flag. + `; +} +exports.checkAppId = checkAppId; +async function checkAppName(config, name) { + // We allow pretty much anything right now, have fun + if (!(name === null || name === void 0 ? void 0 : name.length)) { + return `Must provide an app name. For example: 'Spacebook'`; + } + return null; +} +exports.checkAppName = checkAppName; +async function wait(time) { + return new Promise((resolve) => setTimeout(resolve, time)); +} +exports.wait = wait; +async function runHooks(config, platformName, dir, hook) { + await runPlatformHook(config, platformName, dir, hook); + const allPlugins = await (0, plugin_1.getPlugins)(config, platformName); + for (const p of allPlugins) { + await runPlatformHook(config, platformName, p.rootPath, hook); + } +} +exports.runHooks = runHooks; +async function runPlatformHook(config, platformName, platformDir, hook) { + var _a; + const { spawn } = await Promise.resolve().then(() => tslib_1.__importStar(require('child_process'))); + let pkg; + if ((0, monorepotools_1.isNXMonorepo)(platformDir)) { + pkg = await (0, fs_extra_1.readJSON)((0, path_1.join)((0, monorepotools_1.findNXMonorepoRoot)(platformDir), 'package.json')); + } + else { + pkg = await (0, fs_extra_1.readJSON)((0, path_1.join)(platformDir, 'package.json')); + } + const cmd = (_a = pkg.scripts) === null || _a === void 0 ? void 0 : _a[hook]; + if (!cmd) { + return; + } + return new Promise((resolve, reject) => { + const p = spawn(cmd, { + stdio: 'inherit', + shell: true, + cwd: platformDir, + env: { + INIT_CWD: platformDir, + CAPACITOR_ROOT_DIR: config.app.rootDir, + CAPACITOR_WEB_DIR: config.app.webDirAbs, + CAPACITOR_CONFIG: JSON.stringify(config.app.extConfig), + CAPACITOR_PLATFORM_NAME: platformName, + ...process.env, + }, + }); + p.on('close', (code) => { + if (code === 0) { + resolve(); + } + else { + reject(new Error(`${hook} hook on ${platformName} failed with error code: ${code} while running command: ${cmd}`)); + } + }); + p.on('error', (err) => { + reject(err); + }); + }); +} +exports.runPlatformHook = runPlatformHook; +async function runTask(title, fn) { + const chain = log_1.output.createTaskChain(); + chain.next(title); + try { + const value = await fn(); + chain.end(); + return value; + } + catch (e) { + chain.fail(); + throw e; + } +} +exports.runTask = runTask; +async function getCapacitorPackage(config, name) { + const packagePath = (0, node_1.resolveNode)(config.app.rootDir, `@capacitor/${name}`, 'package.json'); + if (!packagePath) { + return null; + } + return (0, fs_extra_1.readJSON)(packagePath); +} +exports.getCapacitorPackage = getCapacitorPackage; +async function requireCapacitorPackage(config, name) { + const pkg = await getCapacitorPackage(config, name); + if (!pkg) { + (0, errors_1.fatal)(`Unable to find node_modules/@capacitor/${name}.\n` + + `Are you sure ${colors_1.default.strong(`@capacitor/${name}`)} is installed?`); + } + return pkg; +} +exports.requireCapacitorPackage = requireCapacitorPackage; +async function getCapacitorPackageVersion(config, platform) { + return (await requireCapacitorPackage(config, platform)).version; +} +exports.getCapacitorPackageVersion = getCapacitorPackageVersion; +async function getCoreVersion(config) { + return getCapacitorPackageVersion(config, 'core'); +} +exports.getCoreVersion = getCoreVersion; +async function getCLIVersion(config) { + return getCapacitorPackageVersion(config, 'cli'); +} +exports.getCLIVersion = getCLIVersion; +function getPlatformDirectory(config, platform) { + switch (platform) { + case 'android': + return config.android.platformDirAbs; + case 'ios': + return config.ios.platformDirAbs; + case 'web': + return config.web.platformDirAbs; + } + return null; +} +async function getProjectPlatformDirectory(config, platform) { + const platformPath = getPlatformDirectory(config, platform); + if (platformPath && (await (0, fs_extra_1.pathExists)(platformPath))) { + return platformPath; + } + return null; +} +exports.getProjectPlatformDirectory = getProjectPlatformDirectory; +async function selectPlatforms(config, selectedPlatformName) { + if (selectedPlatformName) { + // already passed in a platform name + const platformName = selectedPlatformName.toLowerCase().trim(); + if (!(await isValidPlatform(platformName))) { + (0, errors_1.fatal)(`Invalid platform: ${colors_1.default.input(platformName)}`); + } + else if (!(await getProjectPlatformDirectory(config, platformName))) { + if (platformName === 'web') { + (0, errors_1.fatal)(`Could not find the web platform directory.\n` + `Make sure ${colors_1.default.strong(config.app.webDir)} exists.`); + } + (0, errors_1.fatal)(`${colors_1.default.strong(platformName)} platform has not been added yet.\n` + + `See the docs for adding the ${colors_1.default.strong(platformName)} platform: ${colors_1.default.strong(`https://capacitorjs.com/docs/${platformName}#adding-the-${platformName}-platform`)}`); + } + // return the platform in an string array + return [platformName]; + } + // wasn't given a platform name, so let's + // get the platforms that have already been created + return getAddedPlatforms(config); +} +exports.selectPlatforms = selectPlatforms; +async function getKnownPlatforms() { + return ['web', 'android', 'ios']; +} +exports.getKnownPlatforms = getKnownPlatforms; +async function isValidPlatform(platform) { + return (await getKnownPlatforms()).includes(platform); +} +exports.isValidPlatform = isValidPlatform; +async function getKnownCommunityPlatforms() { + return ['electron']; +} +exports.getKnownCommunityPlatforms = getKnownCommunityPlatforms; +async function isValidCommunityPlatform(platform) { + return (await getKnownCommunityPlatforms()).includes(platform); +} +exports.isValidCommunityPlatform = isValidCommunityPlatform; +async function getKnownEnterprisePlatforms() { + return ['windows']; +} +exports.getKnownEnterprisePlatforms = getKnownEnterprisePlatforms; +async function isValidEnterprisePlatform(platform) { + return (await getKnownEnterprisePlatforms()).includes(platform); +} +exports.isValidEnterprisePlatform = isValidEnterprisePlatform; +async function promptForPlatform(platforms, promptMessage, selectedPlatformName) { + const { prompt } = await Promise.resolve().then(() => tslib_1.__importStar(require('prompts'))); + if (!selectedPlatformName) { + const answers = await prompt([ + { + type: 'select', + name: 'mode', + message: promptMessage, + choices: platforms.map((p) => ({ title: p, value: p })), + }, + ], { onCancel: () => process.exit(1) }); + return answers.mode.toLowerCase().trim(); + } + const platformName = selectedPlatformName.toLowerCase().trim(); + if (!(await isValidPlatform(platformName))) { + const knownPlatforms = await getKnownPlatforms(); + (0, errors_1.fatal)(`Invalid platform: ${colors_1.default.input(platformName)}.\n` + `Valid platforms include: ${knownPlatforms.join(', ')}`); + } + return platformName; +} +exports.promptForPlatform = promptForPlatform; +async function promptForPlatformTarget(targets, selectedTarget, selectedTargetSdkVersion, selectByName) { + const { prompt } = await Promise.resolve().then(() => tslib_1.__importStar(require('prompts'))); + const validTargets = targets.filter((t) => t.id !== undefined); + if (!selectedTarget) { + if (validTargets.length === 1) { + return validTargets[0]; + } + else { + const answers = await prompt([ + { + type: 'select', + name: 'target', + message: 'Please choose a target device:', + choices: validTargets.map((t) => ({ + title: `${getPlatformTargetName(t)} (${t.id})`, + value: t, + })), + }, + ], { onCancel: () => process.exit(1) }); + return answers.target; + } + } + const targetID = selectedTarget.trim(); + const target = targets.find((t) => { + var _a; + if (selectByName === true) { + let name = (_a = t.name) !== null && _a !== void 0 ? _a : t.model; + if (name) { + // Apple device names may have "smart quotes" in the name, + // strip them and replace them with the "straight" versions + name = name.replace(/[\u2018\u2019]/g, "'").replace(/[\u201C\u201D]/g, '"'); + } + if (selectedTargetSdkVersion) { + return name === targetID && t.sdkVersion === selectedTargetSdkVersion; + } + return name === targetID; + } + return t.id === targetID; + }); + if (!target) { + if (selectByName) { + let invalidTargetName = targetID; + if (selectedTargetSdkVersion) { + invalidTargetName += ` [${selectedTargetSdkVersion}]`; + } + (0, errors_1.fatal)(`Invalid target name: ${colors_1.default.input(invalidTargetName)}.\n` + + `Valid targets are:\n ${targets.map((t) => { var _a; return `${(_a = t.name) !== null && _a !== void 0 ? _a : t.model} [${t.sdkVersion}]`; }).join('\n')}`); + } + (0, errors_1.fatal)(`Invalid target ID: ${colors_1.default.input(targetID)}.\n` + `Valid targets are:\n ${targets.map((t) => t.id).join('\n')}`); + } + return target; +} +exports.promptForPlatformTarget = promptForPlatformTarget; +function getPlatformTargetName(target) { + var _a, _b, _c; + return `${(_c = (_b = (_a = target.name) !== null && _a !== void 0 ? _a : target.model) !== null && _b !== void 0 ? _b : target.id) !== null && _c !== void 0 ? _c : '?'}${target.virtual ? ` (${target.platform === 'ios' ? 'simulator' : 'emulator'})` : ''}`; +} +exports.getPlatformTargetName = getPlatformTargetName; +async function getAddedPlatforms(config) { + const platforms = []; + if (await getProjectPlatformDirectory(config, config.android.name)) { + platforms.push(config.android.name); + } + if (await getProjectPlatformDirectory(config, config.ios.name)) { + platforms.push(config.ios.name); + } + platforms.push(config.web.name); + return platforms; +} +exports.getAddedPlatforms = getAddedPlatforms; +async function checkPlatformVersions(config, platform) { + const semver = await Promise.resolve().then(() => tslib_1.__importStar(require('semver'))); + const coreVersion = await getCoreVersion(config); + const platformVersion = await getCapacitorPackageVersion(config, platform); + if (semver.diff(coreVersion, platformVersion) === 'minor' || semver.diff(coreVersion, platformVersion) === 'major') { + log_1.logger.warn(`${colors_1.default.strong('@capacitor/core')}${colors_1.default.weak(`@${coreVersion}`)} version doesn't match ${colors_1.default.strong(`@capacitor/${platform}`)}${colors_1.default.weak(`@${platformVersion}`)} version.\n` + + `Consider updating to a matching version, e.g. w/ ${colors_1.default.input(`npm install @capacitor/core@${platformVersion}`)}`); + } +} +exports.checkPlatformVersions = checkPlatformVersions; +function resolvePlatform(config, platform) { + if (platform[0] !== '@') { + const core = (0, node_1.resolveNode)(config.app.rootDir, `@capacitor/${platform}`, 'package.json'); + if (core) { + return (0, path_1.dirname)(core); + } + const community = (0, node_1.resolveNode)(config.app.rootDir, `@capacitor-community/${platform}`, 'package.json'); + if (community) { + return (0, path_1.dirname)(community); + } + const enterprise = (0, node_1.resolveNode)(config.app.rootDir, `@ionic-enterprise/capacitor-${platform}`, 'package.json'); + if (enterprise) { + return (0, path_1.dirname)(enterprise); + } + } + // third-party + const thirdParty = (0, node_1.resolveNode)(config.app.rootDir, platform, 'package.json'); + if (thirdParty) { + return (0, path_1.dirname)(thirdParty); + } + return null; +} +exports.resolvePlatform = resolvePlatform; +async function checkJDKMajorVersion() { + try { + const string = await (0, subprocess_1.runCommand)('java', ['--version']); + const versionRegex = RegExp(/([0-9]+)\.?([0-9]*)\.?([0-9]*)/); + const versionMatch = versionRegex.exec(string); + if (versionMatch === null) { + return -1; + } + const firstVersionNumber = parseInt(versionMatch[1]); + const secondVersionNumber = parseInt(versionMatch[2]); + if (typeof firstVersionNumber === 'number' && firstVersionNumber != 1) { + return firstVersionNumber; + } + else if (typeof secondVersionNumber === 'number' && firstVersionNumber == 1 && secondVersionNumber < 9) { + return secondVersionNumber; + } + else { + return -1; + } + } + catch (e) { + return -1; + } +} +exports.checkJDKMajorVersion = checkJDKMajorVersion; +function parseApkNameFromFlavor(flavor) { + let convertedName = flavor.replace(/([A-Z])/g, '-$1').toLowerCase(); + if (convertedName.startsWith('-')) + convertedName = convertedName.replace('-', ''); + return `app-${convertedName ? `${convertedName}-` : ''}debug.apk`; +} +exports.parseApkNameFromFlavor = parseApkNameFromFlavor; diff --git a/node_modules/@capacitor/cli/dist/config.js b/node_modules/@capacitor/cli/dist/config.js new file mode 100644 index 0000000..2dc8bb0 --- /dev/null +++ b/node_modules/@capacitor/cli/dist/config.js @@ -0,0 +1,415 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.writeConfig = exports.loadConfig = exports.CONFIG_FILE_NAME_JSON = exports.CONFIG_FILE_NAME_JS = exports.CONFIG_FILE_NAME_TS = void 0; +const tslib_1 = require("tslib"); +const debug_1 = tslib_1.__importDefault(require("debug")); +const fs_extra_1 = require("fs-extra"); +const path_1 = require("path"); +const colors_1 = tslib_1.__importDefault(require("./colors")); +const common_1 = require("./common"); +const errors_1 = require("./errors"); +const log_1 = require("./log"); +const fn_1 = require("./util/fn"); +const js_1 = require("./util/js"); +const monorepotools_1 = require("./util/monorepotools"); +const node_1 = require("./util/node"); +const promise_1 = require("./util/promise"); +const subprocess_1 = require("./util/subprocess"); +const debug = (0, debug_1.default)('capacitor:config'); +exports.CONFIG_FILE_NAME_TS = 'capacitor.config.ts'; +exports.CONFIG_FILE_NAME_JS = 'capacitor.config.js'; +exports.CONFIG_FILE_NAME_JSON = 'capacitor.config.json'; +async function loadConfig() { + var _a, _b, _c, _d; + const appRootDir = process.cwd(); + const cliRootDir = (0, path_1.dirname)(__dirname); + const conf = await loadExtConfig(appRootDir); + const depsForNx = await (async () => { + var _a, _b; + if ((0, monorepotools_1.isNXMonorepo)(appRootDir)) { + const rootOfNXMonorepo = (0, monorepotools_1.findNXMonorepoRoot)(appRootDir); + const pkgJSONOfMonorepoRoot = await (0, fn_1.tryFn)(fs_extra_1.readJSON, (0, path_1.resolve)(rootOfNXMonorepo, 'package.json')); + const devDependencies = (_a = pkgJSONOfMonorepoRoot === null || pkgJSONOfMonorepoRoot === void 0 ? void 0 : pkgJSONOfMonorepoRoot.devDependencies) !== null && _a !== void 0 ? _a : {}; + const dependencies = (_b = pkgJSONOfMonorepoRoot === null || pkgJSONOfMonorepoRoot === void 0 ? void 0 : pkgJSONOfMonorepoRoot.dependencies) !== null && _b !== void 0 ? _b : {}; + return { + devDependencies, + dependencies, + }; + } + return {}; + })(); + const appId = (_a = conf.extConfig.appId) !== null && _a !== void 0 ? _a : ''; + const appName = (_b = conf.extConfig.appName) !== null && _b !== void 0 ? _b : ''; + const webDir = (_c = conf.extConfig.webDir) !== null && _c !== void 0 ? _c : 'www'; + const cli = await loadCLIConfig(cliRootDir); + const config = { + android: await loadAndroidConfig(appRootDir, conf.extConfig, cli), + ios: await loadIOSConfig(appRootDir, conf.extConfig), + web: await loadWebConfig(appRootDir, webDir), + cli, + app: { + rootDir: appRootDir, + appId, + appName, + webDir, + webDirAbs: (0, path_1.resolve)(appRootDir, webDir), + package: (_d = (await (0, fn_1.tryFn)(fs_extra_1.readJSON, (0, path_1.resolve)(appRootDir, 'package.json')))) !== null && _d !== void 0 ? _d : { + name: appName, + version: '1.0.0', + ...depsForNx, + }, + ...conf, + }, + }; + debug('config: %O', config); + return config; +} +exports.loadConfig = loadConfig; +async function writeConfig(extConfig, extConfigFilePath) { + switch ((0, path_1.extname)(extConfigFilePath)) { + case '.json': { + await (0, fs_extra_1.writeJSON)(extConfigFilePath, extConfig, { spaces: 2 }); + break; + } + case '.ts': { + await (0, fs_extra_1.writeFile)(extConfigFilePath, formatConfigTS(extConfig)); + break; + } + } +} +exports.writeConfig = writeConfig; +async function loadExtConfigTS(rootDir, extConfigName, extConfigFilePath) { + var _a; + try { + const tsPath = (0, node_1.resolveNode)(rootDir, 'typescript'); + if (!tsPath) { + (0, errors_1.fatal)('Could not find installation of TypeScript.\n' + + `To use ${colors_1.default.strong(extConfigName)} files, you must install TypeScript in your project, e.g. w/ ${colors_1.default.input('npm install -D typescript')}`); + } + const ts = require(tsPath); // eslint-disable-line @typescript-eslint/no-var-requires + const extConfigObject = (0, node_1.requireTS)(ts, extConfigFilePath); + const extConfig = extConfigObject.default ? await extConfigObject.default : extConfigObject; + return { + extConfigType: 'ts', + extConfigName, + extConfigFilePath: extConfigFilePath, + extConfig, + }; + } + catch (e) { + if (!(0, errors_1.isFatal)(e)) { + (0, errors_1.fatal)(`Parsing ${colors_1.default.strong(extConfigName)} failed.\n\n${(_a = e.stack) !== null && _a !== void 0 ? _a : e}`); + } + throw e; + } +} +async function loadExtConfigJS(rootDir, extConfigName, extConfigFilePath) { + var _a; + try { + return { + extConfigType: 'js', + extConfigName, + extConfigFilePath: extConfigFilePath, + extConfig: await require(extConfigFilePath), + }; + } + catch (e) { + (0, errors_1.fatal)(`Parsing ${colors_1.default.strong(extConfigName)} failed.\n\n${(_a = e.stack) !== null && _a !== void 0 ? _a : e}`); + } +} +async function loadExtConfig(rootDir) { + var _a; + const extConfigFilePathTS = (0, path_1.resolve)(rootDir, exports.CONFIG_FILE_NAME_TS); + if (await (0, fs_extra_1.pathExists)(extConfigFilePathTS)) { + return loadExtConfigTS(rootDir, exports.CONFIG_FILE_NAME_TS, extConfigFilePathTS); + } + const extConfigFilePathJS = (0, path_1.resolve)(rootDir, exports.CONFIG_FILE_NAME_JS); + if (await (0, fs_extra_1.pathExists)(extConfigFilePathJS)) { + return loadExtConfigJS(rootDir, exports.CONFIG_FILE_NAME_JS, extConfigFilePathJS); + } + const extConfigFilePath = (0, path_1.resolve)(rootDir, exports.CONFIG_FILE_NAME_JSON); + return { + extConfigType: 'json', + extConfigName: exports.CONFIG_FILE_NAME_JSON, + extConfigFilePath: extConfigFilePath, + extConfig: (_a = (await (0, fn_1.tryFn)(fs_extra_1.readJSON, extConfigFilePath))) !== null && _a !== void 0 ? _a : {}, + }; +} +async function loadCLIConfig(rootDir) { + const assetsDir = 'assets'; + const assetsDirAbs = (0, path_1.join)(rootDir, assetsDir); + const iosPlatformTemplateArchive = 'ios-spm-template.tar.gz'; + const iosCordovaPluginsTemplateArchive = 'capacitor-cordova-ios-plugins.tar.gz'; + const androidPlatformTemplateArchive = 'android-template.tar.gz'; + const androidCordovaPluginsTemplateArchive = 'capacitor-cordova-android-plugins.tar.gz'; + return { + rootDir, + assetsDir, + assetsDirAbs, + assets: { + ios: { + platformTemplateArchive: iosPlatformTemplateArchive, + platformTemplateArchiveAbs: (0, path_1.resolve)(assetsDirAbs, iosPlatformTemplateArchive), + cordovaPluginsTemplateArchive: iosCordovaPluginsTemplateArchive, + cordovaPluginsTemplateArchiveAbs: (0, path_1.resolve)(assetsDirAbs, iosCordovaPluginsTemplateArchive), + }, + android: { + platformTemplateArchive: androidPlatformTemplateArchive, + platformTemplateArchiveAbs: (0, path_1.resolve)(assetsDirAbs, androidPlatformTemplateArchive), + cordovaPluginsTemplateArchive: androidCordovaPluginsTemplateArchive, + cordovaPluginsTemplateArchiveAbs: (0, path_1.resolve)(assetsDirAbs, androidCordovaPluginsTemplateArchive), + }, + }, + package: await (0, fs_extra_1.readJSON)((0, path_1.resolve)(rootDir, 'package.json')), + os: determineOS(process.platform), + }; +} +async function loadAndroidConfig(rootDir, extConfig, cliConfig) { + var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s; + const name = 'android'; + const platformDir = (_b = (_a = extConfig.android) === null || _a === void 0 ? void 0 : _a.path) !== null && _b !== void 0 ? _b : 'android'; + const platformDirAbs = (0, path_1.resolve)(rootDir, platformDir); + const appDir = 'app'; + const srcDir = `${appDir}/src`; + const srcMainDir = `${srcDir}/main`; + const assetsDir = `${srcMainDir}/assets`; + const webDir = `${assetsDir}/public`; + const resDir = `${srcMainDir}/res`; + let apkPath = `${appDir}/build/outputs/apk/`; + const flavor = ((_c = extConfig.android) === null || _c === void 0 ? void 0 : _c.flavor) || ''; + if ((_d = extConfig.android) === null || _d === void 0 ? void 0 : _d.flavor) { + apkPath = `${apkPath}/${(_e = extConfig.android) === null || _e === void 0 ? void 0 : _e.flavor}`; + } + const apkName = (0, common_1.parseApkNameFromFlavor)(flavor); + const buildOutputDir = `${apkPath}/debug`; + const cordovaPluginsDir = 'capacitor-cordova-android-plugins'; + const studioPath = (0, promise_1.lazy)(() => determineAndroidStudioPath(cliConfig.os)); + const buildOptions = { + keystorePath: (_g = (_f = extConfig.android) === null || _f === void 0 ? void 0 : _f.buildOptions) === null || _g === void 0 ? void 0 : _g.keystorePath, + keystorePassword: (_j = (_h = extConfig.android) === null || _h === void 0 ? void 0 : _h.buildOptions) === null || _j === void 0 ? void 0 : _j.keystorePassword, + keystoreAlias: (_l = (_k = extConfig.android) === null || _k === void 0 ? void 0 : _k.buildOptions) === null || _l === void 0 ? void 0 : _l.keystoreAlias, + keystoreAliasPassword: (_o = (_m = extConfig.android) === null || _m === void 0 ? void 0 : _m.buildOptions) === null || _o === void 0 ? void 0 : _o.keystoreAliasPassword, + signingType: (_q = (_p = extConfig.android) === null || _p === void 0 ? void 0 : _p.buildOptions) === null || _q === void 0 ? void 0 : _q.signingType, + releaseType: (_s = (_r = extConfig.android) === null || _r === void 0 ? void 0 : _r.buildOptions) === null || _s === void 0 ? void 0 : _s.releaseType, + }; + return { + name, + minVersion: '24', + studioPath, + platformDir, + platformDirAbs, + cordovaPluginsDir, + cordovaPluginsDirAbs: (0, path_1.resolve)(platformDirAbs, cordovaPluginsDir), + appDir, + appDirAbs: (0, path_1.resolve)(platformDirAbs, appDir), + srcDir, + srcDirAbs: (0, path_1.resolve)(platformDirAbs, srcDir), + srcMainDir, + srcMainDirAbs: (0, path_1.resolve)(platformDirAbs, srcMainDir), + assetsDir, + assetsDirAbs: (0, path_1.resolve)(platformDirAbs, assetsDir), + webDir, + webDirAbs: (0, path_1.resolve)(platformDirAbs, webDir), + resDir, + resDirAbs: (0, path_1.resolve)(platformDirAbs, resDir), + apkName, + buildOutputDir, + buildOutputDirAbs: (0, path_1.resolve)(platformDirAbs, buildOutputDir), + flavor, + buildOptions, + }; +} +async function loadIOSConfig(rootDir, extConfig) { + var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m; + const name = 'ios'; + const platformDir = (_b = (_a = extConfig.ios) === null || _a === void 0 ? void 0 : _a.path) !== null && _b !== void 0 ? _b : 'ios'; + const platformDirAbs = (0, path_1.resolve)(rootDir, platformDir); + const scheme = (_d = (_c = extConfig.ios) === null || _c === void 0 ? void 0 : _c.scheme) !== null && _d !== void 0 ? _d : 'App'; + const nativeProjectDir = 'App'; + const nativeProjectDirAbs = (0, path_1.resolve)(platformDirAbs, nativeProjectDir); + const nativeTargetDir = `${nativeProjectDir}/App`; + const nativeTargetDirAbs = (0, path_1.resolve)(platformDirAbs, nativeTargetDir); + const nativeXcodeProjDir = `${nativeProjectDir}/App.xcodeproj`; + const nativeXcodeProjDirAbs = (0, path_1.resolve)(platformDirAbs, nativeXcodeProjDir); + const nativeXcodeWorkspaceDirAbs = (0, promise_1.lazy)(() => determineXcodeWorkspaceDirAbs(nativeProjectDirAbs)); + const podPath = (0, promise_1.lazy)(() => determineCocoapodPath()); + const packageManager = (0, promise_1.lazy)(() => determinePackageManager(rootDir, platformDirAbs, nativeProjectDirAbs)); + const webDirAbs = (0, promise_1.lazy)(() => determineIOSWebDirAbs(nativeProjectDirAbs, nativeTargetDirAbs, nativeXcodeProjDirAbs)); + const cordovaPluginsDir = 'capacitor-cordova-ios-plugins'; + const buildOptions = { + exportMethod: (_f = (_e = extConfig.ios) === null || _e === void 0 ? void 0 : _e.buildOptions) === null || _f === void 0 ? void 0 : _f.exportMethod, + xcodeSigningStyle: (_h = (_g = extConfig.ios) === null || _g === void 0 ? void 0 : _g.buildOptions) === null || _h === void 0 ? void 0 : _h.signingStyle, + signingCertificate: (_k = (_j = extConfig.ios) === null || _j === void 0 ? void 0 : _j.buildOptions) === null || _k === void 0 ? void 0 : _k.signingCertificate, + provisioningProfile: (_m = (_l = extConfig.ios) === null || _l === void 0 ? void 0 : _l.buildOptions) === null || _m === void 0 ? void 0 : _m.provisioningProfile, + }; + return { + name, + minVersion: '15.0', + platformDir, + platformDirAbs, + scheme, + cordovaPluginsDir, + cordovaPluginsDirAbs: (0, path_1.resolve)(platformDirAbs, cordovaPluginsDir), + nativeProjectDir, + nativeProjectDirAbs, + nativeTargetDir, + nativeTargetDirAbs, + nativeXcodeProjDir, + nativeXcodeProjDirAbs, + nativeXcodeWorkspaceDir: (0, promise_1.lazy)(async () => (0, path_1.relative)(platformDirAbs, await nativeXcodeWorkspaceDirAbs)), + nativeXcodeWorkspaceDirAbs, + webDir: (0, promise_1.lazy)(async () => (0, path_1.relative)(platformDirAbs, await webDirAbs)), + webDirAbs, + podPath, + packageManager, + buildOptions, + }; +} +async function loadWebConfig(rootDir, webDir) { + const platformDir = webDir; + const platformDirAbs = (0, path_1.resolve)(rootDir, platformDir); + return { + name: 'web', + platformDir, + platformDirAbs, + }; +} +function determineOS(os) { + switch (os) { + case 'darwin': + return "mac" /* OS.Mac */; + case 'win32': + return "windows" /* OS.Windows */; + case 'linux': + return "linux" /* OS.Linux */; + } + return "unknown" /* OS.Unknown */; +} +async function determineXcodeWorkspaceDirAbs(nativeProjectDirAbs) { + return (0, path_1.resolve)(nativeProjectDirAbs, 'App.xcworkspace'); +} +async function determineIOSWebDirAbs(nativeProjectDirAbs, nativeTargetDirAbs, nativeXcodeProjDirAbs) { + const re = /path\s=\spublic[\s\S]+?sourceTree\s=\s([^;]+)/; + const pbxprojPath = (0, path_1.resolve)(nativeXcodeProjDirAbs, 'project.pbxproj'); + try { + const pbxproj = await (0, fs_extra_1.readFile)(pbxprojPath, { encoding: 'utf8' }); + const m = pbxproj.match(re); + if (m && m[1] === 'SOURCE_ROOT') { + log_1.logger.warn(`Using the iOS project root for the ${colors_1.default.strong('public')} directory is deprecated.\n` + + `Please follow the Upgrade Guide to move ${colors_1.default.strong('public')} inside the iOS target directory: ${colors_1.default.strong('https://capacitorjs.com/docs/updating/3-0#move-public-into-the-ios-target-directory')}`); + return (0, path_1.resolve)(nativeProjectDirAbs, 'public'); + } + } + catch (e) { + // ignore + } + return (0, path_1.resolve)(nativeTargetDirAbs, 'public'); +} +async function determineAndroidStudioPath(os) { + if (process.env.CAPACITOR_ANDROID_STUDIO_PATH) { + return process.env.CAPACITOR_ANDROID_STUDIO_PATH; + } + switch (os) { + case "mac" /* OS.Mac */: + return '/Applications/Android Studio.app'; + case "windows" /* OS.Windows */: { + const { runCommand } = await Promise.resolve().then(() => tslib_1.__importStar(require('./util/subprocess'))); + let p = 'C:\\Program Files\\Android\\Android Studio\\bin\\studio64.exe'; + try { + if (!(await (0, fs_extra_1.pathExists)(p))) { + let commandResult = await runCommand('REG', [ + 'QUERY', + 'HKEY_LOCAL_MACHINE\\SOFTWARE\\Android Studio', + '/v', + 'Path', + ]); + commandResult = commandResult.replace(/(\r\n|\n|\r)/gm, ''); + const i = commandResult.indexOf('REG_SZ'); + if (i > 0) { + p = commandResult.substring(i + 6).trim() + '\\bin\\studio64.exe'; + } + } + } + catch (e) { + debug(`Error checking registry for Android Studio path: %O`, e); + break; + } + return p; + } + case "linux" /* OS.Linux */: { + const studioExecPath = '/usr/local/android-studio/bin/studio'; + const studioShPath = '/usr/local/android-studio/bin/studio.sh'; + try { + if (await (0, fs_extra_1.pathExists)(studioExecPath)) { + return studioExecPath; + } + } + catch (e) { + debug(`Error checking for studio executable: %O`, e); + } + return studioShPath; + } + } + return ''; +} +async function determineCocoapodPath() { + if (process.env.CAPACITOR_COCOAPODS_PATH) { + return process.env.CAPACITOR_COCOAPODS_PATH; + } + return 'pod'; +} +async function determinePackageManager(rootDir, platformDir, nativeProjectDirAbs) { + if ((0, fs_extra_1.existsSync)((0, path_1.resolve)(nativeProjectDirAbs, 'CapApp-SPM'))) { + return 'SPM'; + } + if (process.env.CAPACITOR_COCOAPODS_PATH) { + return 'Cocoapods'; + } + let gemfilePath = ''; + if (await (0, fs_extra_1.pathExists)((0, path_1.resolve)(rootDir, 'Gemfile'))) { + gemfilePath = (0, path_1.resolve)(rootDir, 'Gemfile'); + } + else if (await (0, fs_extra_1.pathExists)((0, path_1.resolve)(platformDir, 'Gemfile'))) { + gemfilePath = (0, path_1.resolve)(platformDir, 'Gemfile'); + } + else if (await (0, fs_extra_1.pathExists)((0, path_1.resolve)(nativeProjectDirAbs, 'Gemfile'))) { + gemfilePath = (0, path_1.resolve)(nativeProjectDirAbs, 'Gemfile'); + } + const appSpecificGemfileExists = gemfilePath != ''; + // Multi-app projects might share a single global 'Gemfile' at the Git repository root directory. + if (!appSpecificGemfileExists) { + try { + const output = await (0, subprocess_1.getCommandOutput)('git', ['rev-parse', '--show-toplevel'], { cwd: rootDir }); + if (output != null) { + gemfilePath = (0, path_1.resolve)(output, 'Gemfile'); + } + } + catch (e) { + // Nothing + } + } + try { + const gemfileText = (await (0, fs_extra_1.readFile)(gemfilePath)).toString(); + if (!gemfileText) { + return 'Cocoapods'; + } + const cocoapodsInGemfile = new RegExp(/gem\s+['"]cocoapods/).test(gemfileText); + if (cocoapodsInGemfile && (await (0, subprocess_1.isInstalled)('bundle'))) { + return 'bundler'; + } + else { + return 'Cocoapods'; + } + } + catch { + return 'Cocoapods'; + } +} +function formatConfigTS(extConfig) { + // TODO: tags + return `import type { CapacitorConfig } from '@capacitor/cli'; + +const config: CapacitorConfig = ${(0, js_1.formatJSObject)(extConfig)}; + +export default config;\n`; +} diff --git a/node_modules/@capacitor/cli/dist/cordova.js b/node_modules/@capacitor/cli/dist/cordova.js new file mode 100644 index 0000000..1f5f33f --- /dev/null +++ b/node_modules/@capacitor/cli/dist/cordova.js @@ -0,0 +1,801 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.writeCordovaAndroidManifest = exports.getCordovaPreferences = exports.needsStaticPod = exports.getIncompatibleCordovaPlugins = exports.checkPluginDependencies = exports.logCordovaManualSteps = exports.getCordovaPlugins = exports.handleCordovaPluginsJS = exports.autoGenerateConfig = exports.removePluginFiles = exports.createEmptyCordovaJS = exports.copyCordovaJS = exports.copyPluginsJS = exports.generateCordovaPluginsJSFile = void 0; +const tslib_1 = require("tslib"); +const fs_extra_1 = require("fs-extra"); +const path_1 = require("path"); +const plist_1 = tslib_1.__importDefault(require("plist")); +const prompts_1 = tslib_1.__importDefault(require("prompts")); +const common_1 = require("./android/common"); +const colors_1 = tslib_1.__importDefault(require("./colors")); +const errors_1 = require("./errors"); +const common_2 = require("./ios/common"); +const log_1 = require("./log"); +const plugin_1 = require("./plugin"); +const node_1 = require("./util/node"); +const term_1 = require("./util/term"); +const xml_1 = require("./util/xml"); +/** + * Build the root cordova_plugins.js file referencing each Plugin JS file. + */ +function generateCordovaPluginsJSFile(config, plugins, platform) { + const pluginModules = []; + const pluginExports = []; + plugins.map((p) => { + const pluginId = p.xml.$.id; + const jsModules = (0, plugin_1.getJSModules)(p, platform); + jsModules.map((jsModule) => { + const clobbers = []; + const merges = []; + let clobbersModule = ''; + let mergesModule = ''; + let runsModule = ''; + let clobberKey = ''; + let mergeKey = ''; + if (jsModule.clobbers) { + jsModule.clobbers.map((clobber) => { + clobbers.push(clobber.$.target); + clobberKey = clobber.$.target; + }); + clobbersModule = `, + "clobbers": [ + "${clobbers.join('",\n "')}" + ]`; + } + if (jsModule.merges) { + jsModule.merges.map((merge) => { + merges.push(merge.$.target); + mergeKey = merge.$.target; + }); + mergesModule = `, + "merges": [ + "${merges.join('",\n "')}" + ]`; + } + if (jsModule.runs) { + runsModule = ',\n "runs": true'; + } + const pluginModule = { + clobber: clobberKey, + merge: mergeKey, + // mimics Cordova's module name logic if the name attr is missing + pluginContent: `{ + "id": "${pluginId + '.' + (jsModule.$.name || jsModule.$.src.match(/([^/]+)\.js/)[1])}", + "file": "plugins/${pluginId}/${jsModule.$.src}", + "pluginId": "${pluginId}"${clobbersModule}${mergesModule}${runsModule} + }`, + }; + pluginModules.push(pluginModule); + }); + pluginExports.push(`"${pluginId}": "${p.xml.$.version}"`); + }); + return ` + cordova.define('cordova/plugin_list', function(require, exports, module) { + module.exports = [ + ${pluginModules + .sort((a, b) => a.clobber && b.clobber // Clobbers in alpha order + ? a.clobber.localeCompare(b.clobber) + : a.clobber || b.clobber // Clobbers before anything else + ? b.clobber.localeCompare(a.clobber) + : a.merge.localeCompare(b.merge)) + .map((e) => e.pluginContent) + .join(',\n ')} + ]; + module.exports.metadata = + // TOP OF METADATA + { + ${pluginExports.join(',\n ')} + }; + // BOTTOM OF METADATA + }); + `; +} +exports.generateCordovaPluginsJSFile = generateCordovaPluginsJSFile; +/** + * Build the plugins/* files for each Cordova plugin installed. + */ +async function copyPluginsJS(config, cordovaPlugins, platform) { + const webDir = await getWebDir(config, platform); + const pluginsDir = (0, path_1.join)(webDir, 'plugins'); + const cordovaPluginsJSFile = (0, path_1.join)(webDir, 'cordova_plugins.js'); + await removePluginFiles(config, platform); + await Promise.all(cordovaPlugins.map(async (p) => { + const pluginId = p.xml.$.id; + const pluginDir = (0, path_1.join)(pluginsDir, pluginId, 'www'); + await (0, fs_extra_1.ensureDir)(pluginDir); + const jsModules = (0, plugin_1.getJSModules)(p, platform); + await Promise.all(jsModules.map(async (jsModule) => { + const filePath = (0, path_1.join)(webDir, 'plugins', pluginId, jsModule.$.src); + await (0, fs_extra_1.copy)((0, path_1.join)(p.rootPath, jsModule.$.src), filePath); + let data = await (0, fs_extra_1.readFile)(filePath, { encoding: 'utf-8' }); + data = data.trim(); + // mimics Cordova's module name logic if the name attr is missing + const name = pluginId + '.' + (jsModule.$.name || (0, path_1.basename)(jsModule.$.src, (0, path_1.extname)(jsModule.$.src))); + data = `cordova.define("${name}", function(require, exports, module) { \n${data}\n});`; + data = data.replace(/)<[^<]*)*<\/script\s*>/gi, ''); + await (0, fs_extra_1.writeFile)(filePath, data, { encoding: 'utf-8' }); + })); + const assets = (0, plugin_1.getAssets)(p, platform); + await Promise.all(assets.map(async (asset) => { + const filePath = (0, path_1.join)(webDir, asset.$.target); + await (0, fs_extra_1.copy)((0, path_1.join)(p.rootPath, asset.$.src), filePath); + })); + })); + await (0, fs_extra_1.writeFile)(cordovaPluginsJSFile, generateCordovaPluginsJSFile(config, cordovaPlugins, platform)); +} +exports.copyPluginsJS = copyPluginsJS; +async function copyCordovaJS(config, platform) { + const cordovaPath = (0, node_1.resolveNode)(config.app.rootDir, '@capacitor/core', 'cordova.js'); + if (!cordovaPath) { + (0, errors_1.fatal)(`Unable to find ${colors_1.default.strong('node_modules/@capacitor/core/cordova.js')}.\n` + + `Are you sure ${colors_1.default.strong('@capacitor/core')} is installed?`); + } + return (0, fs_extra_1.copy)(cordovaPath, (0, path_1.join)(await getWebDir(config, platform), 'cordova.js')); +} +exports.copyCordovaJS = copyCordovaJS; +async function createEmptyCordovaJS(config, platform) { + const webDir = await getWebDir(config, platform); + await (0, fs_extra_1.writeFile)((0, path_1.join)(webDir, 'cordova.js'), ''); + await (0, fs_extra_1.writeFile)((0, path_1.join)(webDir, 'cordova_plugins.js'), ''); +} +exports.createEmptyCordovaJS = createEmptyCordovaJS; +async function removePluginFiles(config, platform) { + const webDir = await getWebDir(config, platform); + const pluginsDir = (0, path_1.join)(webDir, 'plugins'); + const cordovaPluginsJSFile = (0, path_1.join)(webDir, 'cordova_plugins.js'); + await (0, fs_extra_1.remove)(pluginsDir); + await (0, fs_extra_1.remove)(cordovaPluginsJSFile); +} +exports.removePluginFiles = removePluginFiles; +async function autoGenerateConfig(config, cordovaPlugins, platform) { + var _a, _b, _c, _d; + let xmlDir = (0, path_1.join)(config.android.resDirAbs, 'xml'); + const fileName = 'config.xml'; + if (platform === 'ios') { + xmlDir = config.ios.nativeTargetDirAbs; + } + await (0, fs_extra_1.ensureDir)(xmlDir); + const cordovaConfigXMLFile = (0, path_1.join)(xmlDir, fileName); + await (0, fs_extra_1.remove)(cordovaConfigXMLFile); + const pluginEntries = []; + cordovaPlugins.map((p) => { + const currentPlatform = (0, plugin_1.getPluginPlatform)(p, platform); + if (currentPlatform) { + const configFiles = currentPlatform['config-file']; + if (configFiles) { + const configXMLEntries = configFiles.filter(function (item) { + var _a; + return (_a = item.$) === null || _a === void 0 ? void 0 : _a.target.includes(fileName); + }); + configXMLEntries.map((entry) => { + if (entry.feature) { + const feature = { feature: entry.feature }; + pluginEntries.push(feature); + } + }); + } + } + }); + let accessOriginString = []; + if ((_b = (_a = config.app.extConfig) === null || _a === void 0 ? void 0 : _a.cordova) === null || _b === void 0 ? void 0 : _b.accessOrigins) { + accessOriginString = await Promise.all(config.app.extConfig.cordova.accessOrigins.map(async (host) => { + return ` + `; + })); + } + else { + accessOriginString.push(``); + } + const pluginEntriesString = await Promise.all(pluginEntries.map(async (item) => { + const xmlString = await (0, xml_1.writeXML)(item); + return xmlString; + })); + let pluginPreferencesString = []; + if ((_d = (_c = config.app.extConfig) === null || _c === void 0 ? void 0 : _c.cordova) === null || _d === void 0 ? void 0 : _d.preferences) { + pluginPreferencesString = await Promise.all(Object.entries(config.app.extConfig.cordova.preferences).map(async ([key, value]) => { + return ` + `; + })); + } + const content = ` + + ${accessOriginString.join('')} + ${pluginEntriesString.join('')} + ${pluginPreferencesString.join('')} +`; + await (0, fs_extra_1.writeFile)(cordovaConfigXMLFile, content); +} +exports.autoGenerateConfig = autoGenerateConfig; +async function getWebDir(config, platform) { + if (platform === 'ios') { + return config.ios.webDirAbs; + } + if (platform === 'android') { + return config.android.webDirAbs; + } + return ''; +} +async function handleCordovaPluginsJS(cordovaPlugins, config, platform) { + const webDir = await getWebDir(config, platform); + await (0, fs_extra_1.mkdirp)(webDir); + if (cordovaPlugins.length > 0) { + (0, plugin_1.printPlugins)(cordovaPlugins, platform, 'cordova'); + await copyCordovaJS(config, platform); + await copyPluginsJS(config, cordovaPlugins, platform); + } + else { + await removePluginFiles(config, platform); + await createEmptyCordovaJS(config, platform); + } + await autoGenerateConfig(config, cordovaPlugins, platform); +} +exports.handleCordovaPluginsJS = handleCordovaPluginsJS; +async function getCordovaPlugins(config, platform) { + const allPlugins = await (0, plugin_1.getPlugins)(config, platform); + let plugins = []; + if (platform === config.ios.name) { + plugins = await (0, common_2.getIOSPlugins)(allPlugins); + } + else if (platform === config.android.name) { + plugins = await (0, common_1.getAndroidPlugins)(allPlugins); + } + return plugins.filter((p) => (0, plugin_1.getPluginType)(p, platform) === 1 /* PluginType.Cordova */); +} +exports.getCordovaPlugins = getCordovaPlugins; +async function logCordovaManualSteps(cordovaPlugins, config, platform) { + cordovaPlugins.map((p) => { + const editConfig = (0, plugin_1.getPlatformElement)(p, platform, 'edit-config'); + const configFile = (0, plugin_1.getPlatformElement)(p, platform, 'config-file'); + editConfig.concat(configFile).map(async (configElement) => { + if (configElement.$ && !configElement.$.target.includes('config.xml')) { + if (platform === config.ios.name) { + if (configElement.$.target.includes('Info.plist')) { + logiOSPlist(configElement, config, p); + } + } + } + }); + }); +} +exports.logCordovaManualSteps = logCordovaManualSteps; +async function logiOSPlist(configElement, config, plugin) { + var _a, _b; + let plistPath = (0, path_1.resolve)(config.ios.nativeTargetDirAbs, 'Info.plist'); + if ((_a = config.app.extConfig.ios) === null || _a === void 0 ? void 0 : _a.scheme) { + plistPath = (0, path_1.resolve)(config.ios.nativeProjectDirAbs, `${(_b = config.app.extConfig.ios) === null || _b === void 0 ? void 0 : _b.scheme}-Info.plist`); + } + if (!(await (0, fs_extra_1.pathExists)(plistPath))) { + plistPath = (0, path_1.resolve)(config.ios.nativeTargetDirAbs, 'Base.lproj', 'Info.plist'); + } + if (await (0, fs_extra_1.pathExists)(plistPath)) { + const xmlMeta = await (0, xml_1.readXML)(plistPath); + const data = await (0, fs_extra_1.readFile)(plistPath, { encoding: 'utf-8' }); + const trimmedPlistData = data.replace(/(\t|\r|\n)/g, ''); + const plistData = plist_1.default.parse(data); + const dict = xmlMeta.plist.dict.pop(); + if (!dict.key.includes(configElement.$.parent)) { + let xml = buildConfigFileXml(configElement); + xml = `${configElement.$.parent}${getConfigFileTagContent(xml)}`; + log_1.logger.warn(`Configuration required for ${colors_1.default.strong(plugin.id)}.\n` + `Add the following to Info.plist:\n` + xml); + } + else if (configElement.array || configElement.dict) { + if (configElement.array && configElement.array.length > 0 && configElement.array[0].string) { + let xml = ''; + configElement.array[0].string.map((element) => { + const d = plistData[configElement.$.parent]; + if (Array.isArray(d) && !d.includes(element)) { + xml = xml.concat(`${element}\n`); + } + }); + if (xml.length > 0) { + log_1.logger.warn(`Configuration required for ${colors_1.default.strong(plugin.id)}.\n` + + `Add the following in the existing ${colors_1.default.strong(configElement.$.parent)} array of your Info.plist:\n` + + xml); + } + } + else { + let xml = buildConfigFileXml(configElement); + xml = `${configElement.$.parent}${getConfigFileTagContent(xml)}`; + xml = `${xml}`; + const parseXmlToSearchable = (childElementsObj, arrayToAddTo) => { + for (const childElement of childElementsObj) { + const childElementName = childElement['#name']; + const toAdd = { name: childElementName }; + if (childElementName === 'key' || childElementName === 'string') { + toAdd.value = childElement['_']; + } + else { + if (childElement['$']) { + toAdd.attrs = { ...childElement['$'] }; + } + if (childElement['$$']) { + toAdd.children = []; + parseXmlToSearchable(childElement['$$'], toAdd['children']); + } + } + arrayToAddTo.push(toAdd); + } + }; + const existingElements = (0, xml_1.parseXML)(trimmedPlistData, { + explicitChildren: true, + trim: true, + preserveChildrenOrder: true, + }); + const parsedExistingElements = []; + const rootKeyOfExistingElements = Object.keys(existingElements)[0]; + const rootOfExistingElementsToAdd = { name: rootKeyOfExistingElements, children: [] }; + if (existingElements[rootKeyOfExistingElements]['$']) { + rootOfExistingElementsToAdd.attrs = { + ...existingElements[rootKeyOfExistingElements]['$'], + }; + } + parseXmlToSearchable(existingElements[rootKeyOfExistingElements]['$$'], rootOfExistingElementsToAdd['children']); + parsedExistingElements.push(rootOfExistingElementsToAdd); + const requiredElements = (0, xml_1.parseXML)(xml, { + explicitChildren: true, + trim: true, + preserveChildrenOrder: true, + }); + const parsedRequiredElements = []; + const rootKeyOfRequiredElements = Object.keys(requiredElements)[0]; + const rootOfRequiredElementsToAdd = { name: rootKeyOfRequiredElements, children: [] }; + if (requiredElements[rootKeyOfRequiredElements]['$']) { + rootOfRequiredElementsToAdd.attrs = { + ...requiredElements[rootKeyOfRequiredElements]['$'], + }; + } + parseXmlToSearchable(requiredElements[rootKeyOfRequiredElements]['$$'], rootOfRequiredElementsToAdd['children']); + parsedRequiredElements.push(rootOfRequiredElementsToAdd); + const doesContainElements = (requiredElementsArray, existingElementsArray) => { + for (const requiredElement of requiredElementsArray) { + if (requiredElement.name === 'key' || requiredElement.name === 'string') { + let foundMatch = false; + for (const existingElement of existingElementsArray) { + if (existingElement.name === requiredElement.name && + (existingElement.value === requiredElement.value || + /^[$].{1,}$/.test(requiredElement.value.trim()))) { + foundMatch = true; + break; + } + } + if (!foundMatch) { + return false; + } + } + else { + let foundMatch = false; + for (const existingElement of existingElementsArray) { + if (existingElement.name === requiredElement.name) { + if ((requiredElement.children !== undefined) === (existingElement.children !== undefined)) { + if (doesContainElements(requiredElement.children, existingElement.children)) { + foundMatch = true; + break; + } + } + } + } + if (!foundMatch) { + return false; + } + } + } + return true; + }; + if (!doesContainElements(parsedRequiredElements, parsedExistingElements)) { + logPossibleMissingItem(configElement, plugin); + } + } + } + } + else { + logPossibleMissingItem(configElement, plugin); + } +} +function logPossibleMissingItem(configElement, plugin) { + let xml = buildConfigFileXml(configElement); + xml = getConfigFileTagContent(xml); + xml = removeOuterTags(xml); + log_1.logger.warn(`Configuration might be missing for ${colors_1.default.strong(plugin.id)}.\n` + + `Add the following to the existing ${colors_1.default.strong(configElement.$.parent)} entry of Info.plist:\n` + + xml); +} +function buildConfigFileXml(configElement) { + return (0, xml_1.buildXmlElement)(configElement, 'config-file'); +} +function getConfigFileTagContent(str) { + return str.replace(/|<\/config-file>/g, ''); +} +function removeOuterTags(str) { + const start = str.indexOf('>') + 1; + const end = str.lastIndexOf('<'); + return str.substring(start, end); +} +async function checkPluginDependencies(plugins, platform, failOnMissingDeps = false) { + const pluginDeps = new Map(); + const cordovaPlugins = plugins.filter((p) => (0, plugin_1.getPluginType)(p, platform) === 1 /* PluginType.Cordova */); + const incompatible = plugins.filter((p) => (0, plugin_1.getPluginType)(p, platform) === 2 /* PluginType.Incompatible */); + await Promise.all(cordovaPlugins.map(async (p) => { + let allDependencies = []; + allDependencies = allDependencies.concat((0, plugin_1.getPlatformElement)(p, platform, 'dependency')); + if (p.xml['dependency']) { + allDependencies = allDependencies.concat(p.xml['dependency']); + } + allDependencies = allDependencies.filter((dep) => !getIncompatibleCordovaPlugins(platform).includes(dep.$.id) && + incompatible.filter((p) => p.id === dep.$.id || p.xml.$.id === dep.$.id).length === 0); + if (allDependencies) { + await Promise.all(allDependencies.map(async (dep) => { + var _a; + let plugin = dep.$.id; + let version = dep.$.version; + if (plugin.includes('@') && plugin.indexOf('@') !== 0) { + [plugin, version] = plugin.split('@'); + } + if (cordovaPlugins.filter((p) => p.id === plugin || p.xml.$.id === plugin).length === 0) { + if ((_a = dep.$.url) === null || _a === void 0 ? void 0 : _a.startsWith('http')) { + plugin = dep.$.url; + version = dep.$.commit; + } + const deps = pluginDeps.get(p.id) || []; + deps.push(`${plugin}${version ? colors_1.default.weak(` (${version})`) : ''}`); + pluginDeps.set(p.id, deps); + } + })); + } + })); + if (pluginDeps.size > 0) { + let msg = `${colors_1.default.failure(colors_1.default.strong('Plugins are missing dependencies.'))}\n` + + `Cordova plugin dependencies must be installed in your project (e.g. w/ ${colors_1.default.input('npm install')}).\n`; + for (const [plugin, deps] of pluginDeps.entries()) { + msg += `\n ${colors_1.default.strong(plugin)} is missing dependencies:\n` + deps.map((d) => ` - ${d}`).join('\n'); + } + if (failOnMissingDeps) { + (0, errors_1.fatal)(`${msg}\n`); + } + log_1.logger.warn(`${msg}\n`); + } +} +exports.checkPluginDependencies = checkPluginDependencies; +function getIncompatibleCordovaPlugins(platform) { + const pluginList = [ + 'cordova-plugin-splashscreen', + 'cordova-plugin-ionic-webview', + 'cordova-plugin-crosswalk-webview', + 'cordova-plugin-wkwebview-engine', + 'cordova-plugin-console', + 'cordova-plugin-music-controls', + 'cordova-plugin-add-swift-support', + 'cordova-plugin-ionic-keyboard', + 'cordova-plugin-braintree', + '@ionic-enterprise/filesystem', + '@ionic-enterprise/keyboard', + '@ionic-enterprise/splashscreen', + 'cordova-support-google-services', + ]; + if (platform === 'ios') { + pluginList.push('cordova-plugin-statusbar', '@ionic-enterprise/statusbar', 'SalesforceMobileSDK-CordovaPlugin'); + } + if (platform === 'android') { + pluginList.push('cordova-plugin-compat'); + } + return pluginList; +} +exports.getIncompatibleCordovaPlugins = getIncompatibleCordovaPlugins; +function needsStaticPod(plugin) { + return useFrameworks(plugin); +} +exports.needsStaticPod = needsStaticPod; +function useFrameworks(plugin) { + const podspecs = (0, plugin_1.getPlatformElement)(plugin, 'ios', 'podspec'); + const frameworkPods = podspecs.filter((podspec) => podspec.pods.filter((pods) => pods.$ && pods.$['use-frameworks'] === 'true').length > 0); + return frameworkPods.length > 0; +} +async function getCordovaPreferences(config) { + var _a, _b, _c, _d, _e; + const configXml = (0, path_1.join)(config.app.rootDir, 'config.xml'); + let cordova = {}; + if (await (0, fs_extra_1.pathExists)(configXml)) { + cordova.preferences = {}; + const xmlMeta = await (0, xml_1.readXML)(configXml); + if (xmlMeta.widget.preference) { + xmlMeta.widget.preference.map((pref) => { + cordova.preferences[pref.$.name] = pref.$.value; + }); + } + } + if (cordova.preferences && Object.keys(cordova.preferences).length > 0) { + if ((0, term_1.isInteractive)()) { + const answers = await (0, log_1.logPrompt)(`${colors_1.default.strong(`Cordova preferences can be automatically ported to ${colors_1.default.strong(config.app.extConfigName)}.`)}\n` + + `Keep in mind: Not all values can be automatically migrated from ${colors_1.default.strong('config.xml')}. There may be more work to do.\n` + + `More info: ${colors_1.default.strong('https://capacitorjs.com/docs/cordova/migrating-from-cordova-to-capacitor')}`, { + type: 'confirm', + name: 'confirm', + message: `Migrate Cordova preferences from config.xml?`, + initial: true, + }); + if (answers.confirm) { + if ((_b = (_a = config.app.extConfig) === null || _a === void 0 ? void 0 : _a.cordova) === null || _b === void 0 ? void 0 : _b.preferences) { + const answers = await (0, prompts_1.default)([ + { + type: 'confirm', + name: 'confirm', + message: `${config.app.extConfigName} already contains Cordova preferences. Overwrite?`, + }, + ], { onCancel: () => process.exit(1) }); + if (!answers.confirm) { + cordova = (_c = config.app.extConfig) === null || _c === void 0 ? void 0 : _c.cordova; + } + } + } + else { + cordova = (_d = config.app.extConfig) === null || _d === void 0 ? void 0 : _d.cordova; + } + } + } + else { + cordova = (_e = config.app.extConfig) === null || _e === void 0 ? void 0 : _e.cordova; + } + return cordova; +} +exports.getCordovaPreferences = getCordovaPreferences; +async function writeCordovaAndroidManifest(cordovaPlugins, config, platform, cleartext) { + var _a; + const manifestPath = (0, path_1.join)(config.android.cordovaPluginsDirAbs, 'src', 'main', 'AndroidManifest.xml'); + const rootXMLEntries = []; + const applicationXMLEntries = []; + const applicationXMLAttributes = []; + let prefsArray = []; + cordovaPlugins.map(async (p) => { + const editConfig = (0, plugin_1.getPlatformElement)(p, platform, 'edit-config'); + const configFile = (0, plugin_1.getPlatformElement)(p, platform, 'config-file'); + prefsArray = prefsArray.concat((0, plugin_1.getAllElements)(p, platform, 'preference')); + editConfig.concat(configFile).map(async (configElement) => { + var _a, _b; + if (configElement.$ && + (((_a = configElement.$.target) === null || _a === void 0 ? void 0 : _a.includes('AndroidManifest.xml')) || + ((_b = configElement.$.file) === null || _b === void 0 ? void 0 : _b.includes('AndroidManifest.xml')))) { + const keys = Object.keys(configElement).filter((k) => k !== '$'); + keys.map((k) => { + configElement[k].map(async (e) => { + const xmlElement = (0, xml_1.buildXmlElement)(e, k); + const pathParts = getPathParts(configElement.$.parent || configElement.$.target); + if (pathParts.length > 1) { + if (pathParts.pop() === 'application') { + if (configElement.$.mode && configElement.$.mode === 'merge' && xmlElement.startsWith(' { + applicationXMLAttributes.push(`${ek}="${e.$[ek]}"`); + }); + } + else if (!applicationXMLEntries.includes(xmlElement) && + !contains(applicationXMLEntries, xmlElement, k)) { + applicationXMLEntries.push(xmlElement); + } + } + else { + const manifestPathOfCapApp = (0, path_1.join)(config.android.appDirAbs, 'src', 'main', 'AndroidManifest.xml'); + const manifestContentTrimmed = (await (0, fs_extra_1.readFile)(manifestPathOfCapApp)) + .toString() + .trim() + .replace(/\n|\t|\r/g, '') + .replace(/[\s]{1,}[\s]{1,}/g, '>') + .replace(/[\s]{2,}/g, ' '); + const requiredManifestContentTrimmed = xmlElement + .trim() + .replace(/\n|\t|\r/g, '') + .replace(/[\s]{1,}[\s]{1,}/g, '>') + .replace(/[\s]{2,}/g, ' '); + const pathPartList = getPathParts(configElement.$.parent || configElement.$.target); + const doesXmlManifestContainRequiredInfo = (requiredElements, existingElements, pathTarget) => { + const findElementsToSearchIn = (existingElements, pathTarget) => { + const parts = [...pathTarget]; + const elementsToSearchNextIn = []; + for (const existingElement of existingElements) { + if (existingElement.name === pathTarget[0]) { + if (existingElement.children) { + for (const el of existingElement.children) { + elementsToSearchNextIn.push(el); + } + } + else { + elementsToSearchNextIn.push(existingElement); + } + } + } + if (elementsToSearchNextIn.length === 0) { + return []; + } + else { + parts.splice(0, 1); + if (parts.length <= 0) { + return elementsToSearchNextIn; + } + else { + return findElementsToSearchIn(elementsToSearchNextIn, parts); + } + } + }; + const parseXmlToSearchable = (childElementsObj, arrayToAddTo) => { + for (const childElementKey of Object.keys(childElementsObj)) { + for (const occurannceOfElement of childElementsObj[childElementKey]) { + const toAdd = { name: childElementKey }; + if (occurannceOfElement['$']) { + toAdd.attrs = { ...occurannceOfElement['$'] }; + } + if (occurannceOfElement['$$']) { + toAdd.children = []; + parseXmlToSearchable(occurannceOfElement['$$'], toAdd['children']); + } + arrayToAddTo.push(toAdd); + } + } + }; + const doesElementMatch = (requiredElement, existingElement) => { + var _a; + if (requiredElement.name !== existingElement.name) { + return false; + } + if ((requiredElement.attrs !== undefined) !== (existingElement.attrs !== undefined)) { + return false; + } + else { + if (requiredElement.attrs !== undefined) { + const requiredELementAttrKeys = Object.keys(requiredElement.attrs); + for (const key of requiredELementAttrKeys) { + if (!/^[$].{1,}$/.test(requiredElement.attrs[key].trim())) { + if (requiredElement.attrs[key] !== existingElement.attrs[key]) { + return false; + } + } + } + } + } + if ((requiredElement.children !== undefined) !== (existingElement.children !== undefined) && + ((_a = requiredElement.children) === null || _a === void 0 ? void 0 : _a.length) !== 0) { + return false; + } + else { + if (requiredElement.children !== undefined) { + // each req element is in existing element + for (const requiredElementItem of requiredElement.children) { + let foundRequiredElement = false; + for (const existingElementItem of existingElement.children) { + const foundRequiredElementIn = doesElementMatch(requiredElementItem, existingElementItem); + if (foundRequiredElementIn) { + foundRequiredElement = true; + break; + } + } + if (!foundRequiredElement) { + return false; + } + } + } + else { + if (requiredElement.children === undefined && existingElement.children === undefined) { + return true; + } + else { + let foundRequiredElement = false; + for (const existingElementItem of existingElement.children) { + const foundRequiredElementIn = doesElementMatch(requiredElement, existingElementItem); + if (foundRequiredElementIn) { + foundRequiredElement = true; + break; + } + } + if (!foundRequiredElement) { + return false; + } + } + } + } + return true; + }; + const parsedExistingElements = []; + const rootKeyOfExistingElements = Object.keys(existingElements)[0]; + const rootOfExistingElementsToAdd = { name: rootKeyOfExistingElements, children: [] }; + if (existingElements[rootKeyOfExistingElements]['$']) { + rootOfExistingElementsToAdd.attrs = { + ...existingElements[rootKeyOfExistingElements]['$'], + }; + } + parseXmlToSearchable(existingElements[rootKeyOfExistingElements]['$$'], rootOfExistingElementsToAdd['children']); + parsedExistingElements.push(rootOfExistingElementsToAdd); + const parsedRequiredElements = []; + const rootKeyOfRequiredElements = Object.keys(requiredElements)[0]; + const rootOfRequiredElementsToAdd = { name: rootKeyOfRequiredElements, children: [] }; + if (requiredElements[rootKeyOfRequiredElements]['$']) { + rootOfRequiredElementsToAdd.attrs = { + ...requiredElements[rootKeyOfRequiredElements]['$'], + }; + } + if (requiredElements[rootKeyOfRequiredElements]['$$'] !== undefined) { + parseXmlToSearchable(requiredElements[rootKeyOfRequiredElements]['$$'], rootOfRequiredElementsToAdd['children']); + } + parsedRequiredElements.push(rootOfRequiredElementsToAdd); + const elementsToSearch = findElementsToSearchIn(parsedExistingElements, pathTarget); + for (const requiredElement of parsedRequiredElements) { + let foundMatch = false; + for (const existingElement of elementsToSearch) { + const doesContain = doesElementMatch(requiredElement, existingElement); + if (doesContain) { + foundMatch = true; + break; + } + } + if (!foundMatch) { + return false; + } + } + return true; + }; + if (!doesXmlManifestContainRequiredInfo((0, xml_1.parseXML)(requiredManifestContentTrimmed, { + explicitChildren: true, + trim: true, + }), (0, xml_1.parseXML)(manifestContentTrimmed, { + explicitChildren: true, + trim: true, + }), pathPartList)) { + log_1.logger.warn(`Android Configuration required for ${colors_1.default.strong(p.id)}.\n` + + `Add the following to AndroidManifest.xml:\n` + + xmlElement); + } + } + } + else { + if (!rootXMLEntries.includes(xmlElement) && !contains(rootXMLEntries, xmlElement, k)) { + rootXMLEntries.push(xmlElement); + } + } + }); + }); + } + }); + }); + const cleartextString = 'android:usesCleartextTraffic="true"'; + const cleartextValue = (cleartext || ((_a = config.app.extConfig.server) === null || _a === void 0 ? void 0 : _a.cleartext)) && !applicationXMLAttributes.includes(cleartextString) + ? cleartextString + : ''; + let content = ` + + +${applicationXMLEntries.join('\n')} + +${rootXMLEntries.join('\n')} +`; + content = content.replace(new RegExp('$PACKAGE_NAME'.replace('$', '\\$&'), 'g'), '${applicationId}'); + for (const preference of prefsArray) { + content = content.replace(new RegExp(('$' + preference.$.name).replace('$', '\\$&'), 'g'), preference.$.default); + } + if (await (0, fs_extra_1.pathExists)(manifestPath)) { + await (0, fs_extra_1.writeFile)(manifestPath, content); + } +} +exports.writeCordovaAndroidManifest = writeCordovaAndroidManifest; +function getPathParts(path) { + const rootPath = 'manifest'; + path = path.replace('/*', rootPath); + const parts = path.split('/').filter((part) => part !== ''); + if (parts.length > 1 || parts.includes(rootPath)) { + return parts; + } + return [rootPath, path]; +} +function contains(entries, obj, k) { + const element = (0, xml_1.parseXML)(obj); + for (const entry of entries) { + const current = (0, xml_1.parseXML)(entry); + if (element && + current && + current[k] && + element[k] && + current[k].$ && + element[k].$ && + element[k].$['android:name'] === current[k].$['android:name']) { + return true; + } + } + return false; +} diff --git a/node_modules/@capacitor/cli/dist/declarations.d.ts b/node_modules/@capacitor/cli/dist/declarations.d.ts new file mode 100644 index 0000000..62c0aee --- /dev/null +++ b/node_modules/@capacitor/cli/dist/declarations.d.ts @@ -0,0 +1,734 @@ +export interface CapacitorConfig { + /** + * The unique identifier of your packaged app. + * + * This is also known as the Bundle ID in iOS and the Application ID in + * Android. It must be in reverse domain name notation, generally + * representing a domain name that you or your company owns. + * + * @since 1.0.0 + */ + appId?: string; + /** + * The human-friendly name of your app. + * + * This should be what you'd see in the App Store, but can be changed after + * within each native platform after it is generated. + * + * @since 1.0.0 + */ + appName?: string; + /** + * The directory of your compiled web assets. + * + * This directory should contain the final `index.html` of your app. + * + * @since 1.0.0 + */ + webDir?: string; + /** + * The build configuration (as defined by the native app) under which Capacitor + * will send statements to the log system. This applies to log statements in + * native code as well as statements redirected from JavaScript (`console.debug`, + * `console.error`, etc.). Enabling logging will let statements render in the + * Xcode and Android Studio windows but can leak information on device if enabled + * in released builds. + * + * 'none' = logs are never produced + * 'debug' = logs are produced in debug builds but not production builds + * 'production' = logs are always produced + * + * @since 3.0.0 + * @default debug + */ + loggingBehavior?: 'none' | 'debug' | 'production'; + /** + * User agent of Capacitor Web View. + * + * @since 1.4.0 + */ + overrideUserAgent?: string; + /** + * String to append to the original user agent of Capacitor Web View. + * + * This is disregarded if `overrideUserAgent` is used. + * + * @since 1.4.0 + */ + appendUserAgent?: string; + /** + * Background color of the Capacitor Web View. + * + * @since 1.1.0 + */ + backgroundColor?: string; + /** + * Enable zooming within the Capacitor Web View. + * + * @default false + * @since 6.0.0 + */ + zoomEnabled?: boolean; + /** + * Whether to give the webview initial focus. + * + * @since 7.0.0 + * @default true + */ + initialFocus?: boolean; + android?: { + /** + * Specify a custom path to the native Android project. + * + * @since 3.0.0 + * @default android + */ + path?: string; + /** + * User agent of Capacitor Web View on Android. + * + * Overrides global `overrideUserAgent` option. + * + * @since 1.4.0 + */ + overrideUserAgent?: string; + /** + * String to append to the original user agent of Capacitor Web View for Android. + * + * Overrides global `appendUserAgent` option. + * + * This is disregarded if `overrideUserAgent` is used. + * + * @since 1.4.0 + */ + appendUserAgent?: string; + /** + * Background color of the Capacitor Web View for Android. + * + * Overrides global `backgroundColor` option. + * + * @since 1.1.0 + */ + backgroundColor?: string; + /** + * Enable zooming within the Capacitor Web View for Android. + * + * @default false + * @since 6.0.0 + */ + zoomEnabled?: boolean; + /** + * Enable mixed content in the Capacitor Web View for Android. + * + * [Mixed + * content](https://developer.mozilla.org/en-US/docs/Web/Security/Mixed_content) + * is disabled by default for security. During development, you may need to + * enable it to allow the Web View to load files from different schemes. + * + * **This is not intended for use in production.** + * + * @since 1.0.0 + * @default false + */ + allowMixedContent?: boolean; + /** + * This enables a simpler keyboard which may have some limitations. + * + * This will capture JS keys using an alternative + * [`InputConnection`](https://developer.android.com/reference/android/view/inputmethod/InputConnection). + * + * @since 1.0.0 + * @default false + */ + captureInput?: boolean; + /** + * Always enable debuggable web content. + * + * This is automatically enabled during development. + * + * @since 1.0.0 + * @default false + */ + webContentsDebuggingEnabled?: boolean; + /** + * The build configuration under which Capacitor will generate logs on Android. + * + * Overrides global `loggingBehavior` option. + * + * @since 3.0.0 + * @default debug + */ + loggingBehavior?: 'none' | 'debug' | 'production'; + /** + * Allowlist of plugins to include during `npx cap sync` for Android. + * + * Overrides global `includePlugins` option. + * + * @since 3.0.0 + */ + includePlugins?: string[]; + /** + * Android flavor to use. + * + * If the app has flavors declared in the `build.gradle` + * configure the flavor you want to run with `npx cap run` command. + * + * @since 3.1.0 + */ + flavor?: string; + /** + * Whether to give the webview initial focus. + * + * Overrides global `initialFocus` option. + * + * @since 3.5.1 + * @default true + */ + initialFocus?: boolean; + /** + * The minimum supported webview version on Android supported by your app. + * + * The minimum supported cannot be lower than version `55`, which is required for Capacitor. + * + * If the device uses a lower WebView version, an error message will be shown on Logcat. + * If `server.errorPath` is configured, the WebView will redirect to that file, so can be + * used to show a custom error. + * + * @since 4.0.0 + * @default 60 + */ + minWebViewVersion?: number; + /** + * The minimum supported Huawei webview version on Android supported by your app. + * + * The minimum supported cannot be lower than version `10`, which is required for Capacitor. + * + * If the device uses a lower WebView version, an error message will be shown on Logcat. + * If `server.errorPath` is configured, the WebView will redirect to that file, so can be + * used to show a custom error. + * + * @since 4.6.4 + * @default 10 + */ + minHuaweiWebViewVersion?: number; + buildOptions?: { + /** + * Path to your keystore + * + * @since 4.4.0 + */ + keystorePath?: string; + /** + * Password to your keystore + * + * @since 4.4.0 + */ + keystorePassword?: string; + /** + * Alias in the keystore to use + * + * @since 4.4.0 + */ + keystoreAlias?: string; + /** + * Password for the alias in the keystore to use + * + * @since 4.4.0 + */ + keystoreAliasPassword?: string; + /** + * Bundle type for your release build + * + * @since 4.4.0 + * @default "AAB" + */ + releaseType?: 'AAB' | 'APK'; + /** + * Program to sign your build with + * + * @since 5.1.0 + * @default "jarsigner" + */ + signingType?: 'apksigner' | 'jarsigner'; + }; + /** + * Use legacy [addJavascriptInterface](https://developer.android.com/reference/android/webkit/WebView#addJavascriptInterface(java.lang.Object,%20java.lang.String)) + * instead of the new and more secure [addWebMessageListener](https://developer.android.com/reference/androidx/webkit/WebViewCompat#addWebMessageListener(android.webkit.WebView,java.lang.String,java.util.Set%3Cjava.lang.String%3E,androidx.webkit.WebViewCompat.WebMessageListener)) + * + * @since 4.5.0 + * @default false + */ + useLegacyBridge?: boolean; + /** + * Make service worker requests go through Capacitor bridge. + * Set it to false to use your own handling. + * + * @since 7.0.0 + * @default true + */ + resolveServiceWorkerRequests?: boolean; + }; + ios?: { + /** + * Specify a custom path to the native iOS project. + * + * @since 3.0.0 + * @default ios + */ + path?: string; + /** + * iOS build scheme to use. + * + * Usually this matches your app's target in Xcode. You can use the + * following command to list schemes: + * + * ```shell + * xcodebuild -workspace ios/App/App.xcworkspace -list + * ``` + * + * @since 3.0.0 + * @default App + */ + scheme?: string; + /** + * User agent of Capacitor Web View on iOS. + * + * Overrides global `overrideUserAgent` option. + * + * @since 1.4.0 + */ + overrideUserAgent?: string; + /** + * String to append to the original user agent of Capacitor Web View for iOS. + * + * Overrides global `appendUserAgent` option. + * + * This is disregarded if `overrideUserAgent` is used. + * + * @since 1.4.0 + */ + appendUserAgent?: string; + /** + * Background color of the Capacitor Web View for iOS. + * + * Overrides global `backgroundColor` option. + * + * @since 1.1.0 + */ + backgroundColor?: string; + /** + * Enable zooming within the Capacitor Web View for iOS. + * + * @default false + * @since 6.0.0 + */ + zoomEnabled?: boolean; + /** + * Configure the scroll view's content inset adjustment behavior. + * + * This will set the + * [`contentInsetAdjustmentBehavior`](https://developer.apple.com/documentation/uikit/uiscrollview/2902261-contentinsetadjustmentbehavior) + * property on the Web View's + * [`UIScrollView`](https://developer.apple.com/documentation/uikit/uiscrollview). + * + * @since 2.0.0 + * @default never + */ + contentInset?: 'automatic' | 'scrollableAxes' | 'never' | 'always'; + /** + * Configure whether the scroll view is scrollable. + * + * This will set the + * [`isScrollEnabled`](https://developer.apple.com/documentation/uikit/uiscrollview/1619395-isscrollenabled) + * property on the Web View's + * [`UIScrollView`](https://developer.apple.com/documentation/uikit/uiscrollview). + * + * @since 1.0.0 + */ + scrollEnabled?: boolean; + /** + * Configure custom linker flags for compiling Cordova plugins. + * + * @since 1.0.0 + * @default [] + */ + cordovaLinkerFlags?: string[]; + /** + * Allow destination previews when pressing on links. + * + * This will set the + * [`allowsLinkPreview`](https://developer.apple.com/documentation/webkit/wkwebview/1415000-allowslinkpreview) + * property on the Web View, instead of using the default value. + * + * @since 2.0.0 + */ + allowsLinkPreview?: boolean; + /** + * The build configuration under which Capacitor will generate logs on iOS. + * + * Overrides global `loggingBehavior` option. + * + * @since 3.0.0 + * @default debug + */ + loggingBehavior?: 'none' | 'debug' | 'production'; + /** + * Allowlist of plugins to include during `npx cap sync` for iOS. + * + * Overrides global `includePlugins` option. + * + * @since 3.0.0 + */ + includePlugins?: string[]; + /** + * Sets WKWebView configuration for limitsNavigationsToAppBoundDomains. + * + * If the Info.plist file includes `WKAppBoundDomains` key, it's recommended to + * set this option to true, otherwise some features won't work. + * But as side effect, it blocks navigation outside the domains in the + * `WKAppBoundDomains` list. + * `localhost` (or the value configured as `server.hostname`) also needs to be + * added to the `WKAppBoundDomains` list. + * + * @since 3.1.0 + * @default false + */ + limitsNavigationsToAppBoundDomains?: boolean; + /** + * The content mode for the web view to use when it loads and renders web content. + * + * - 'recommended': The content mode that is appropriate for the current device. + * - 'desktop': The content mode that represents a desktop experience. + * - 'mobile': The content mode that represents a mobile experience. + * + * @since 4.0.0 + * @default recommended + */ + preferredContentMode?: 'recommended' | 'desktop' | 'mobile'; + /** + * Configure if Capacitor will handle local/push notifications. + * Set to false if you want to use your own UNUserNotificationCenter to handle notifications. + * + * @since 4.5.0 + * @default true + */ + handleApplicationNotifications?: boolean; + /** + * Using Xcode 14.3, on iOS 16.4 and greater, enable debuggable web content for release builds. + * + * If not set, it's `true` for development builds. + * + * @since 4.8.0 + * @default false + */ + webContentsDebuggingEnabled?: boolean; + /** + * Whether to give the webview initial focus. + * + * Overrides global `initialFocus` option. + * + * @since 7.0.0 + * @default true + */ + initialFocus?: boolean; + buildOptions?: { + /** + * The signing style to use when building the app for distribution. + * + * @since 7.1.0 + * @default 'automatic' + */ + signingStyle?: 'automatic' | 'manual'; + /** + * The method used by xcodebuild to export the archive + * + * @since 7.1.0 + * @default 'app-store-connect' + */ + exportMethod?: string; + /** + * A certificate name, SHA-1 hash, or automatic selector to use for signing for iOS builds. + * + * @since 7.1.0 + */ + signingCertificate?: string; + /** + * A provisioning profile name or UUID for iOS builds. + * + * @since 7.1.0 + */ + provisioningProfile?: string; + }; + }; + experimental?: { + /** + * Experimental iOS-specific configuration. + * + * These options may change or be removed in future versions. + * + * @since 8.2.0 + */ + ios?: { + /** + * Swift Package Manager (SPM) specific configuration. + * + * @since 8.2.0 + */ + spm?: { + /** + * Swift tools version to use in Package.swift header. + * + * Defines the minimum version of the Swift compiler version required to build your app. + * For more information check the [swift documentation](https://docs.swift.org/swiftpm/documentation/packagemanagerdocs/settingswifttoolsversion/) + * + * Warning: Capacitor does not officially support Swift 6 yet. + * Setting this property to 6.0 or higher may cause issues. + * If you need to set this property to 6.0 or higher, make sure to throughrouly test your iOS app. + * + * This setting may graduate to `ios.spm.swiftToolsVersion` in a future major release. + * + * @since 8.3.0 + * @default '5.9' + * @example '6.1' + */ + swiftToolsVersion?: string; + /** + * Define package traits for SPM plugin dependencies. + * + * This requires explicitly setting experimental.ios.spm.swiftToolsVersion + * to '6.1' or higher. + * + * The key is the plugin ID (e.g. `@capacitor-firebase/analytics`) + * and the value is an array of trait names. + * + * Packages can have default traits. If you use this property, and + * want to preserve the defaults, include ".defaults" in the array. + * + * This setting may graduate to `ios.spm.packageTraits` in a future major release. + * + * @since 8.3.0 + */ + packageTraits?: { + [pluginId: string]: string[]; + }; + }; + }; + }; + server?: { + /** + * Configure the local hostname of the device. + * + * It is recommended to keep this as `localhost` as it allows the use of + * Web APIs that would otherwise require a [secure + * context](https://developer.mozilla.org/en-US/docs/Web/Security/Secure_Contexts) + * such as + * [`navigator.geolocation`](https://developer.mozilla.org/en-US/docs/Web/API/Navigator/geolocation) + * and + * [`MediaDevices.getUserMedia`](https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia). + * + * @since 1.0.0 + * @default localhost + */ + hostname?: string; + /** + * Configure the local scheme on iOS. + * + * [Can't be set to schemes that the WKWebView already handles, such as http or https](https://developer.apple.com/documentation/webkit/wkwebviewconfiguration/2875766-seturlschemehandler) + * This can be useful when migrating from + * [`cordova-plugin-ionic-webview`](https://github.com/ionic-team/cordova-plugin-ionic-webview), + * where the default scheme on iOS is `ionic`. + * + * @since 1.2.0 + * @default capacitor + */ + iosScheme?: string; + /** + * Configure the local scheme on Android. + * + * Custom schemes on Android are unable to change the URL path as of Webview 117. Changing this value from anything other than `http` or `https` can result in your + * application unable to resolve routing. If you must change this for some reason, consider using a hash-based url strategy, but there are no guarentees that this + * will continue to work long term as allowing non-standard schemes to modify query parameters and url fragments is only allowed for compatibility reasons. + * https://ionic.io/blog/capacitor-android-customscheme-issue-with-chrome-117 + * + * @since 1.2.0 + * @default https + */ + androidScheme?: string; + /** + * Load an external URL in the Web View. + * + * This is intended for use with live-reload servers. + * + * **This is not intended for use in production.** + * + * @since 1.0.0 + */ + url?: string; + /** + * Allow cleartext traffic in the Web View. + * + * On Android, all cleartext traffic is disabled by default as of API 28. + * + * This is intended for use with live-reload servers where unencrypted HTTP + * traffic is often used. + * + * **This is not intended for use in production.** + * + * @since 1.5.0 + * @default false + */ + cleartext?: boolean; + /** + * Set additional URLs the Web View can navigate to. + * + * By default, all external URLs are opened in the external browser (not + * the Web View). + * + * **This is not intended for use in production.** + * + * @since 1.0.0 + * @default [] + */ + allowNavigation?: string[]; + /** + * Specify path to a local html page to display in case of errors. + * On Android the html file won't have access to Capacitor plugins. + * + * @since 4.0.0 + * @default null + */ + errorPath?: string; + /** + * Append a path to the app URL. + * + * Allows loading from other paths than the default `/index.html`. + * @since 7.3.0 + * @default null + */ + appStartPath?: string; + }; + cordova?: { + /** + * Populates tags in the config.xml with the origin set to + * the values entered here. + * If not provided, a single tag gets included. + * It only has effect on a few Cordova plugins that respect the whitelist. + * + * @since 3.3.0 + */ + accessOrigins?: string[]; + /** + * Configure Cordova preferences. + * + * @since 1.3.0 + */ + preferences?: { + [key: string]: string | undefined; + }; + /** + * Fail on cap update/sync if the CLI detects that a cordova plugin + * has uninstalled dependencies. + * + * @default false + * @since 7.4.0 + */ + failOnUninstalledPlugins?: boolean; + }; + /** + * Configure plugins. + * + * This is an object with configuration values specified by plugin class + * name. + * + * @since 1.0.0 + */ + plugins?: PluginsConfig; + /** + * Allowlist of plugins to include during `npx cap sync`. + * + * This should be an array of strings representing the npm package name of + * plugins to include when running `npx cap sync`. If unset, Capacitor will + * inspect `package.json` for a list of potential plugins. + * + * @since 3.0.0 + */ + includePlugins?: string[]; +} +export interface PluginsConfig { + /** + * Plugin configuration by class name. + * + * @since 1.0.0 + */ + [key: string]: { + [key: string]: any; + } | undefined; + /** + * Capacitor Cookies plugin configuration + * + * @since 4.3.0 + */ + CapacitorCookies?: { + /** + * Enable CapacitorCookies to override the global `document.cookie` on native. + * + * @default false + */ + enabled?: boolean; + }; + /** + * Capacitor Http plugin configuration + * + * @since 4.3.0 + */ + CapacitorHttp?: { + /** + * Enable CapacitorHttp to override the global `fetch` and `XMLHttpRequest` on native. + * + * @default false + */ + enabled?: boolean; + }; + /** + * System Bars plugin configuration + * + * @since 8.0.0 + */ + SystemBars?: { + /** + * Specifies how to handle problematic insets on Android. + * + * This option is only supported on Android. + * + * `css` = Injects CSS variables (`--safe-area-inset-*`) containing correct safe area inset values into the webview. + * + * `disable` = Disable CSS variables injection. + * + * @default "css" + */ + insetsHandling?: 'css' | 'disable'; + /** + * The style of the text and icons of the system bars. + * + * This option is only supported on Android. + * + * @default `DEFAULT` + */ + style?: string; + /** + * Hide the system bars on start. + * + * @default false + */ + hidden?: boolean; + /** + * The type of status bar animation used when showing or hiding. + * + * This option is only supported on iOS. + * + * @default 'FADE' + * + */ + animation?: 'FADE' | 'NONE'; + }; +} diff --git a/node_modules/@capacitor/cli/dist/declarations.js b/node_modules/@capacitor/cli/dist/declarations.js new file mode 100644 index 0000000..c8ad2e5 --- /dev/null +++ b/node_modules/@capacitor/cli/dist/declarations.js @@ -0,0 +1,2 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); diff --git a/node_modules/@capacitor/cli/dist/definitions.js b/node_modules/@capacitor/cli/dist/definitions.js new file mode 100644 index 0000000..d914875 --- /dev/null +++ b/node_modules/@capacitor/cli/dist/definitions.js @@ -0,0 +1,13 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.XcodeExportMethod = void 0; +var XcodeExportMethod; +(function (XcodeExportMethod) { + XcodeExportMethod["AppStoreConnect"] = "app-store-connect"; + XcodeExportMethod["ReleaseTesting"] = "release-testing"; + XcodeExportMethod["Enterprise"] = "enterprise"; + XcodeExportMethod["Debugging"] = "debugging"; + XcodeExportMethod["DeveloperID"] = "developer-id"; + XcodeExportMethod["MacApplication"] = "mac-application"; + XcodeExportMethod["Validation"] = "validation"; +})(XcodeExportMethod = exports.XcodeExportMethod || (exports.XcodeExportMethod = {})); diff --git a/node_modules/@capacitor/cli/dist/errors.js b/node_modules/@capacitor/cli/dist/errors.js new file mode 100644 index 0000000..061c9a9 --- /dev/null +++ b/node_modules/@capacitor/cli/dist/errors.js @@ -0,0 +1,27 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.isFatal = exports.fatal = exports.FatalException = exports.BaseException = void 0; +class BaseException extends Error { + constructor(message, code) { + super(message); + this.message = message; + this.code = code; + } +} +exports.BaseException = BaseException; +class FatalException extends BaseException { + constructor(message, exitCode = 1) { + super(message, 'FATAL'); + this.message = message; + this.exitCode = exitCode; + } +} +exports.FatalException = FatalException; +function fatal(message) { + throw new FatalException(message); +} +exports.fatal = fatal; +function isFatal(e) { + return e && e instanceof FatalException; +} +exports.isFatal = isFatal; diff --git a/node_modules/@capacitor/cli/dist/framework-configs.js b/node_modules/@capacitor/cli/dist/framework-configs.js new file mode 100644 index 0000000..257a760 --- /dev/null +++ b/node_modules/@capacitor/cli/dist/framework-configs.js @@ -0,0 +1,109 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.detectFramework = void 0; +const FRAMEWORK_CONFIGS = [ + { + name: 'Angular', + isMatch: (config) => hasDependency(config, '@angular/cli'), + webDir: 'dist', + priority: 3, + }, + { + name: 'Create React App', + isMatch: (config) => hasDependency(config, 'react-scripts'), + webDir: 'build', + priority: 3, + }, + { + name: 'Ember', + isMatch: (config) => hasDependency(config, 'ember-cli'), + webDir: 'dist', + priority: 3, + }, + { + name: 'Gatsby', + isMatch: (config) => hasDependency(config, 'gatsby'), + webDir: 'public', + priority: 2, + }, + { + name: 'Ionic Angular', + isMatch: (config) => hasDependency(config, '@ionic/angular'), + webDir: 'www', + priority: 1, + }, + { + name: 'Ionic React', + isMatch: (config) => hasDependency(config, '@ionic/react'), + webDir: 'build', + priority: 1, + }, + { + name: 'Ionic Vue', + isMatch: (config) => hasDependency(config, '@ionic/vue'), + webDir: 'public', + priority: 1, + }, + { + name: 'Next', + isMatch: (config) => hasDependency(config, 'next'), + webDir: 'public', + priority: 2, + }, + { + name: 'Preact', + isMatch: (config) => hasDependency(config, 'preact-cli'), + webDir: 'build', + priority: 3, + }, + { + name: 'Stencil', + isMatch: (config) => hasDependency(config, '@stencil/core'), + webDir: 'www', + priority: 3, + }, + { + name: 'Svelte', + isMatch: (config) => hasDependency(config, 'svelte') && hasDependency(config, 'sirv-cli'), + webDir: 'public', + priority: 3, + }, + { + name: 'Vite', + isMatch: (config) => hasDependency(config, 'vite'), + webDir: 'dist', + priority: 2, + }, + { + name: 'Vue', + isMatch: (config) => hasDependency(config, '@vue/cli-service'), + webDir: 'dist', + priority: 3, + }, +]; +function detectFramework(config) { + const frameworks = FRAMEWORK_CONFIGS.filter((f) => f.isMatch(config)).sort((a, b) => { + if (a.priority < b.priority) + return -1; + if (a.priority > b.priority) + return 1; + return 0; + }); + return frameworks[0]; +} +exports.detectFramework = detectFramework; +function hasDependency(config, depName) { + const deps = getDependencies(config); + return deps.includes(depName); +} +function getDependencies(config) { + var _a, _b, _c, _d; + const deps = []; + if ((_b = (_a = config === null || config === void 0 ? void 0 : config.app) === null || _a === void 0 ? void 0 : _a.package) === null || _b === void 0 ? void 0 : _b.dependencies) { + deps.push(...Object.keys(config.app.package.dependencies)); + } + if ((_d = (_c = config === null || config === void 0 ? void 0 : config.app) === null || _c === void 0 ? void 0 : _c.package) === null || _d === void 0 ? void 0 : _d.devDependencies) { + deps.push(...Object.keys(config.app.package.devDependencies)); + } + return deps; +} diff --git a/node_modules/@capacitor/cli/dist/index.js b/node_modules/@capacitor/cli/dist/index.js new file mode 100644 index 0000000..e37e2ab --- /dev/null +++ b/node_modules/@capacitor/cli/dist/index.js @@ -0,0 +1,265 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.runProgram = exports.run = void 0; +const tslib_1 = require("tslib"); +const commander_1 = require("commander"); +const path_1 = require("path"); +const colors_1 = tslib_1.__importDefault(require("./colors")); +const config_1 = require("./config"); +const errors_1 = require("./errors"); +const ipc_1 = require("./ipc"); +const log_1 = require("./log"); +const telemetry_1 = require("./telemetry"); +const cli_1 = require("./util/cli"); +const emoji_1 = require("./util/emoji"); +process.on('unhandledRejection', (error) => { + console.error(colors_1.default.failure('[fatal]'), error); +}); +process.on('message', ipc_1.receive); +async function run() { + try { + const config = await (0, config_1.loadConfig)(); + runProgram(config); + } + catch (e) { + process.exitCode = (0, errors_1.isFatal)(e) ? e.exitCode : 1; + log_1.logger.error(e.message ? e.message : String(e)); + } +} +exports.run = run; +async function getPackageManager(config, packageManager) { + if (packageManager === 'cocoapods') { + if ((await config.ios.packageManager) === 'bundler') { + return 'bundler'; + } + return 'Cocoapods'; + } + return 'SPM'; +} +function runProgram(config) { + commander_1.program.version(config.cli.package.version); + commander_1.program + .command('config', { hidden: true }) + .description(`print evaluated Capacitor config`) + .option('--json', 'Print in JSON format') + .action((0, cli_1.wrapAction)(async ({ json }) => { + const { configCommand } = await Promise.resolve().then(() => tslib_1.__importStar(require('./tasks/config'))); + await configCommand(config, json); + })); + commander_1.program + .command('create [directory] [name] [id]', { hidden: true }) + .description('Creates a new Capacitor project') + .action((0, cli_1.wrapAction)(async () => { + const { createCommand } = await Promise.resolve().then(() => tslib_1.__importStar(require('./tasks/create'))); + await createCommand(); + })); + commander_1.program + .command('init [appName] [appId]') + .description(`Initialize Capacitor configuration`) + .option('--web-dir ', 'Optional: Directory of your projects built web assets') + .option('--skip-appid-validation', 'Optional: Skip validating the app ID for iOS and Android compatibility') + .action((0, cli_1.wrapAction)((0, telemetry_1.telemetryAction)(config, async (appName, appId, { webDir, skipAppidValidation }) => { + const { initCommand } = await Promise.resolve().then(() => tslib_1.__importStar(require('./tasks/init'))); + await initCommand(config, appName, appId, webDir, skipAppidValidation); + }))); + commander_1.program + .command('serve', { hidden: true }) + .description('Serves a Capacitor Progressive Web App in the browser') + .action((0, cli_1.wrapAction)(async () => { + const { serveCommand } = await Promise.resolve().then(() => tslib_1.__importStar(require('./tasks/serve'))); + await serveCommand(); + })); + commander_1.program + .command('sync [platform]') + .description(`${colors_1.default.input('copy')} + ${colors_1.default.input('update')}`) + .option('--deployment', 'Optional: if provided, pod install will use --deployment option') + .option('--inline', 'Optional: if true, all source maps will be inlined for easier debugging on mobile devices', false) + .action((0, cli_1.wrapAction)((0, telemetry_1.telemetryAction)(config, async (platform, { deployment, inline }) => { + const { syncCommand } = await Promise.resolve().then(() => tslib_1.__importStar(require('./tasks/sync'))); + await syncCommand(config, platform, deployment, inline); + }))); + commander_1.program + .command('update [platform]') + .description(`updates the native plugins and dependencies based on ${colors_1.default.strong('package.json')}`) + .option('--deployment', 'Optional: if provided, pod install will use --deployment option') + .action((0, cli_1.wrapAction)((0, telemetry_1.telemetryAction)(config, async (platform, { deployment }) => { + const { updateCommand } = await Promise.resolve().then(() => tslib_1.__importStar(require('./tasks/update'))); + await updateCommand(config, platform, deployment); + }))); + commander_1.program + .command('copy [platform]') + .description('copies the web app build into the native app') + .option('--inline', 'Optional: if true, all source maps will be inlined for easier debugging on mobile devices', false) + .action((0, cli_1.wrapAction)((0, telemetry_1.telemetryAction)(config, async (platform, { inline }) => { + const { copyCommand } = await Promise.resolve().then(() => tslib_1.__importStar(require('./tasks/copy'))); + await copyCommand(config, platform, inline); + }))); + commander_1.program + .command('build ') + .description('builds the release version of the selected platform') + .option('--scheme ', 'iOS Scheme to build') + .option('--flavor ', 'Android Flavor to build') + .option('--keystorepath ', 'Path to the keystore') + .option('--keystorepass ', 'Password to the keystore') + .option('--keystorealias ', 'Key Alias in the keystore') + .option('--configuration ', 'Configuration name of the iOS Scheme') + .option('--keystorealiaspass ', 'Password for the Key Alias') + .addOption(new commander_1.Option('--androidreleasetype ', 'Android release type; APK or AAB').choices([ + 'AAB', + 'APK', + ])) + .addOption(new commander_1.Option('--signing-type ', 'Program used to sign apps (default: jarsigner)').choices([ + 'apksigner', + 'jarsigner', + ])) + .addOption(new commander_1.Option('--xcode-team-id ', 'The Developer team to use for building and exporting the archive')) + .addOption(new commander_1.Option('--xcode-export-method ', 'Describes how xcodebuild should export the archive (default: app-store-connect)').choices([ + 'app-store-connect', + 'release-testing', + 'enterprise', + 'debugging', + 'developer-id', + 'mac-application', + 'validation', + ])) + .addOption(new commander_1.Option('--xcode-signing-style ', 'The iOS signing style to use when building the app for distribution (default: automatic)').choices(['automatic', 'manual'])) + .addOption(new commander_1.Option('--xcode-signing-certificate ', 'A certificate name, SHA-1 hash, or automatic selector to use for signing for iOS builds')) + .addOption(new commander_1.Option('--xcode-provisioning-profile ', 'A provisioning profile name or UUID for iOS builds')) + .action((0, cli_1.wrapAction)((0, telemetry_1.telemetryAction)(config, async (platform, { scheme, flavor, keystorepath, keystorepass, keystorealias, keystorealiaspass, androidreleasetype, signingType, configuration, xcodeTeamId, xcodeExportMethod, xcodeSigningStyle, xcodeSigningCertificate, xcodeProvisioningProfile, }) => { + const { buildCommand } = await Promise.resolve().then(() => tslib_1.__importStar(require('./tasks/build'))); + await buildCommand(config, platform, { + scheme, + flavor, + keystorepath, + keystorepass, + keystorealias, + keystorealiaspass, + androidreleasetype, + signingtype: signingType, + configuration, + xcodeTeamId, + xcodeExportMethod, + xcodeSigningType: xcodeSigningStyle, + xcodeSigningCertificate, + xcodeProvisioningProfile, + }); + }))); + commander_1.program + .command(`run [platform]`) + .description(`runs ${colors_1.default.input('sync')}, then builds and deploys the native app`) + .option('--scheme ', 'set the scheme of the iOS project') + .option('--flavor ', 'set the flavor of the Android project (flavor dimensions not yet supported)') + .option('--list', 'list targets, then quit') + .addOption(new commander_1.Option('--json').hideHelp()) + .option('--target ', 'use a specific target') + .option('--target-name ', 'use a specific target by name') + .option('--target-name-sdk-version ', 'use a specific sdk version when using --target-name, ex: 26.0 (for iOS 26) or 35 (for Android API 35)') + .option('--no-sync', `do not run ${colors_1.default.input('sync')}`) + .option('--forwardPorts ', 'Automatically run "adb reverse" for better live-reloading support') + .option('-l, --live-reload', 'Set live-reload URL via CLI (uses defaults, overrides server.url config)') + .option('--host ', 'Configure host for live-reload URL (used with --live-reload)') + .option('--port ', 'Configure port for live-reload URL (used with --live-reload)') + .option('--configuration ', 'Configuration name of the iOS Scheme') + .option('--https', 'Use https:// instead of http:// for live-reload URL (used with --live-reload)') + .action((0, cli_1.wrapAction)((0, telemetry_1.telemetryAction)(config, async (platform, { scheme, flavor, list, json, target, targetName, targetNameSdkVersion, sync, forwardPorts, liveReload, host, port, configuration, https, }) => { + const { runCommand } = await Promise.resolve().then(() => tslib_1.__importStar(require('./tasks/run'))); + await runCommand(config, platform, { + scheme, + flavor, + list, + json, + target, + targetName, + targetNameSdkVersion, + sync, + forwardPorts, + liveReload, + host, + port, + configuration, + https, + }); + }))); + commander_1.program + .command('open [platform]') + .description('opens the native project workspace (Xcode for iOS)') + .action((0, cli_1.wrapAction)((0, telemetry_1.telemetryAction)(config, async (platform) => { + const { openCommand } = await Promise.resolve().then(() => tslib_1.__importStar(require('./tasks/open'))); + await openCommand(config, platform); + }))); + commander_1.program + .command('add [platform]') + .description('add a native platform project') + .option('--packagemanager ', 'The package manager to use for dependency installs (CocoaPods or SPM)') + .action((0, cli_1.wrapAction)((0, telemetry_1.telemetryAction)(config, async (platform, { packagemanager }) => { + const { addCommand } = await Promise.resolve().then(() => tslib_1.__importStar(require('./tasks/add'))); + const configWritable = config; + configWritable.ios.packageManager = getPackageManager(config, packagemanager === null || packagemanager === void 0 ? void 0 : packagemanager.toLowerCase()); + if ((packagemanager === null || packagemanager === void 0 ? void 0 : packagemanager.toLowerCase()) === 'CocoaPods'.toLowerCase()) { + configWritable.cli.assets.ios.platformTemplateArchive = 'ios-pods-template.tar.gz'; + configWritable.cli.assets.ios.platformTemplateArchiveAbs = (0, path_1.resolve)(configWritable.cli.assetsDirAbs, configWritable.cli.assets.ios.platformTemplateArchive); + } + await addCommand(configWritable, platform); + }))); + commander_1.program + .command('ls [platform]') + .description('list installed Cordova and Capacitor plugins') + .action((0, cli_1.wrapAction)((0, telemetry_1.telemetryAction)(config, async (platform) => { + const { listCommand } = await Promise.resolve().then(() => tslib_1.__importStar(require('./tasks/list'))); + await listCommand(config, platform); + }))); + commander_1.program + .command('doctor [platform]') + .description('checks the current setup for common errors') + .action((0, cli_1.wrapAction)((0, telemetry_1.telemetryAction)(config, async (platform) => { + const { doctorCommand } = await Promise.resolve().then(() => tslib_1.__importStar(require('./tasks/doctor'))); + await doctorCommand(config, platform); + }))); + commander_1.program + .command('telemetry [on|off]', { hidden: true }) + .description('enable or disable telemetry') + .action((0, cli_1.wrapAction)(async (onOrOff) => { + const { telemetryCommand } = await Promise.resolve().then(() => tslib_1.__importStar(require('./tasks/telemetry'))); + await telemetryCommand(onOrOff); + })); + commander_1.program + .command('📡', { hidden: true }) + .description('IPC receiver command') + .action(() => { + // no-op: IPC messages are received via `process.on('message')` + }); + commander_1.program + .command('plugin:generate', { hidden: true }) + .description('start a new Capacitor plugin') + .action((0, cli_1.wrapAction)(async () => { + const { newPluginCommand } = await Promise.resolve().then(() => tslib_1.__importStar(require('./tasks/new-plugin'))); + await newPluginCommand(); + })); + commander_1.program + .command('migrate') + .option('--noprompt', 'do not prompt for confirmation') + .option('--packagemanager ', 'The package manager to use for dependency installs (npm, pnpm, yarn)') + .description('Migrate your current Capacitor app to the latest major version of Capacitor.') + .action((0, cli_1.wrapAction)(async ({ noprompt, packagemanager }) => { + const { migrateCommand } = await Promise.resolve().then(() => tslib_1.__importStar(require('./tasks/migrate'))); + await migrateCommand(config, noprompt, packagemanager); + })); + commander_1.program + .command('spm-migration-assistant') + .description('Remove Cocoapods from project and switch to Swift Package Manager') + .action((0, cli_1.wrapAction)(async () => { + const { migrateToSPM } = await Promise.resolve().then(() => tslib_1.__importStar(require('./tasks/migrate-spm'))); + await migrateToSPM(config); + })); + commander_1.program.arguments('[command]').action((0, cli_1.wrapAction)(async (cmd) => { + if (typeof cmd === 'undefined') { + log_1.output.write(`\n ${(0, emoji_1.emoji)('⚡️', '--')} ${colors_1.default.strong('Capacitor - Cross-Platform apps with JavaScript and the Web')} ${(0, emoji_1.emoji)('⚡️', '--')}\n\n`); + commander_1.program.outputHelp(); + } + else { + (0, errors_1.fatal)(`Unknown command: ${colors_1.default.input(cmd)}`); + } + })); + commander_1.program.parse(process.argv); +} +exports.runProgram = runProgram; diff --git a/node_modules/@capacitor/cli/dist/ios/add.js b/node_modules/@capacitor/cli/dist/ios/add.js new file mode 100644 index 0000000..7472926 --- /dev/null +++ b/node_modules/@capacitor/cli/dist/ios/add.js @@ -0,0 +1,13 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.addIOS = void 0; +const tslib_1 = require("tslib"); +const colors_1 = tslib_1.__importDefault(require("../colors")); +const common_1 = require("../common"); +const template_1 = require("../util/template"); +async function addIOS(config) { + await (0, common_1.runTask)(`Adding native Xcode project in ${colors_1.default.strong(config.ios.platformDir)}`, () => { + return (0, template_1.extractTemplate)(config.cli.assets.ios.platformTemplateArchiveAbs, config.ios.platformDirAbs); + }); +} +exports.addIOS = addIOS; diff --git a/node_modules/@capacitor/cli/dist/ios/build.js b/node_modules/@capacitor/cli/dist/ios/build.js new file mode 100644 index 0000000..249518e --- /dev/null +++ b/node_modules/@capacitor/cli/dist/ios/build.js @@ -0,0 +1,94 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.buildiOS = void 0; +const fs_extra_1 = require("fs-extra"); +const path_1 = require("path"); +const rimraf_1 = require("rimraf"); +const common_1 = require("../common"); +const definitions_1 = require("../definitions"); +const log_1 = require("../log"); +const subprocess_1 = require("../util/subprocess"); +async function buildiOS(config, buildOptions) { + var _a, _b, _c, _d; + const theScheme = (_a = buildOptions.scheme) !== null && _a !== void 0 ? _a : 'App'; + let typeOfBuild; + let projectName; + if ((await config.ios.packageManager) !== 'SPM') { + typeOfBuild = '-workspace'; + projectName = (0, path_1.basename)(await config.ios.nativeXcodeWorkspaceDirAbs); + } + else { + typeOfBuild = '-project'; + projectName = (0, path_1.basename)(await config.ios.nativeXcodeProjDirAbs); + } + if (buildOptions.xcodeSigningType == 'manual' && + (!buildOptions.xcodeSigningCertificate || !buildOptions.xcodeProvisioningProfile)) { + throw 'Manually signed Xcode builds require a signing certificate and provisioning profile.'; + } + const buildArgs = [ + typeOfBuild, + projectName, + '-scheme', + `${theScheme}`, + '-destination', + `generic/platform=iOS`, + '-archivePath', + `${theScheme}.xcarchive`, + 'archive', + '-configuration', + buildOptions.configuration, + ]; + if (buildOptions.xcodeTeamId) { + buildArgs.push(`DEVELOPMENT_TEAM=${buildOptions.xcodeTeamId}`); + } + if (buildOptions.xcodeSigningType == 'manual') { + buildArgs.push(`PROVISIONING_PROFILE_SPECIFIER=${buildOptions.xcodeProvisioningProfile}`); + } + await (0, common_1.runTask)('Building xArchive', async () => (0, subprocess_1.runCommand)('xcodebuild', buildArgs, { + cwd: config.ios.nativeProjectDirAbs, + })); + const manualSigningContents = `provisioningProfiles + +${config.app.appId} +${(_b = buildOptions.xcodeProvisioningProfile) !== null && _b !== void 0 ? _b : ''} + +signingCertificate +${(_c = buildOptions.xcodeSigningCertificate) !== null && _c !== void 0 ? _c : ''}`; + const archivePlistContents = ` + + + +method +${(_d = buildOptions.xcodeExportMethod) !== null && _d !== void 0 ? _d : definitions_1.XcodeExportMethod.AppStoreConnect} +signingStyle +${buildOptions.xcodeSigningType} +${buildOptions.xcodeSigningType == 'manual' ? manualSigningContents : ''} + +`; + const archivePlistPath = (0, path_1.join)(`${config.ios.nativeProjectDirAbs}`, 'archive.plist'); + (0, fs_extra_1.writeFileSync)(archivePlistPath, archivePlistContents); + const archiveArgs = [ + 'archive', + '-archivePath', + `${theScheme}.xcarchive`, + '-exportArchive', + '-exportOptionsPlist', + 'archive.plist', + '-exportPath', + 'output', + '-configuration', + buildOptions.configuration, + ]; + if (buildOptions.xcodeSigningType == 'automatic') { + archiveArgs.push('-allowProvisioningUpdates'); + } + await (0, common_1.runTask)('Building IPA', async () => (0, subprocess_1.runCommand)('xcodebuild', archiveArgs, { + cwd: config.ios.nativeProjectDirAbs, + })); + await (0, common_1.runTask)('Cleaning up', async () => { + (0, fs_extra_1.unlinkSync)(archivePlistPath); + rimraf_1.rimraf.sync((0, path_1.join)(config.ios.nativeProjectDirAbs, `${theScheme}.xcarchive`)); + }); + (0, log_1.logSuccess)(`Successfully generated an IPA at: ${(0, path_1.join)(config.ios.nativeProjectDirAbs, 'output')}`); +} +exports.buildiOS = buildiOS; diff --git a/node_modules/@capacitor/cli/dist/ios/common.js b/node_modules/@capacitor/cli/dist/ios/common.js new file mode 100644 index 0000000..76051d9 --- /dev/null +++ b/node_modules/@capacitor/cli/dist/ios/common.js @@ -0,0 +1,125 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.getMajoriOSVersion = exports.editProjectSettingsIOS = exports.resolvePlugin = exports.getIOSPlugins = exports.checkCocoaPods = exports.checkBundler = exports.getCommonChecks = exports.checkIOSPackage = void 0; +const tslib_1 = require("tslib"); +const child_process_1 = require("child_process"); +const fs_extra_1 = require("fs-extra"); +const path_1 = require("path"); +const colors_1 = tslib_1.__importDefault(require("../colors")); +const common_1 = require("../common"); +const cordova_1 = require("../cordova"); +const log_1 = require("../log"); +const plugin_1 = require("../plugin"); +const spm_1 = require("../util/spm"); +const subprocess_1 = require("../util/subprocess"); +async function checkIOSPackage(config) { + return (0, common_1.checkCapacitorPlatform)(config, 'ios'); +} +exports.checkIOSPackage = checkIOSPackage; +function execBundler() { + try { + const bundleOutput = (0, child_process_1.execSync)('bundle &> /dev/null ; echo $?'); + return parseInt(bundleOutput.toString()); + } + catch (e) { + return -1; + } +} +async function getCommonChecks(config) { + var _a, _b, _c; + const checks = []; + if ((await config.ios.packageManager) === 'bundler') { + checks.push(() => checkBundler(config)); + } + else if ((await config.ios.packageManager) === 'Cocoapods') { + checks.push(() => checkCocoaPods(config)); + } + else if ((await config.ios.packageManager) === 'SPM') { + const swiftToolsVersion = (_c = (_b = (_a = config.app.extConfig.experimental) === null || _a === void 0 ? void 0 : _a.ios) === null || _b === void 0 ? void 0 : _b.spm) === null || _c === void 0 ? void 0 : _c.swiftToolsVersion; + if (swiftToolsVersion) { + checks.push(() => (0, spm_1.checkSwiftToolsVersion)(config, swiftToolsVersion)); + } + checks.push(() => (0, spm_1.checkPackageTraitsRequirements)(config)); + } + return checks; +} +exports.getCommonChecks = getCommonChecks; +async function checkBundler(config) { + if (config.cli.os === "mac" /* OS.Mac */) { + let bundlerResult = execBundler(); + if (bundlerResult === 1) { + // Bundler version is outdated + log_1.logger.info(`Using ${colors_1.default.strong('Gemfile')}: Bundler update needed...`); + await (0, subprocess_1.runCommand)('gem', ['install', 'bundler']); + bundlerResult = execBundler(); + } + if (bundlerResult === 0) { + // Bundler in use, all gems current + log_1.logger.info(`Using ${colors_1.default.strong('Gemfile')}: RubyGems bundle installed`); + } + } + return null; +} +exports.checkBundler = checkBundler; +async function checkCocoaPods(config) { + if (!(await (0, subprocess_1.isInstalled)(await config.ios.podPath)) && config.cli.os === "mac" /* OS.Mac */) { + return (`CocoaPods is not installed.\n` + + `See this install guide: ${colors_1.default.strong('https://capacitorjs.com/docs/getting-started/environment-setup#homebrew')}`); + } + return null; +} +exports.checkCocoaPods = checkCocoaPods; +async function getIOSPlugins(allPlugins) { + const resolved = await Promise.all(allPlugins.map(async (plugin) => await resolvePlugin(plugin))); + return resolved.filter((plugin) => !!plugin); +} +exports.getIOSPlugins = getIOSPlugins; +async function resolvePlugin(plugin) { + var _a, _b; + const platform = 'ios'; + if ((_a = plugin.manifest) === null || _a === void 0 ? void 0 : _a.ios) { + plugin.ios = { + name: plugin.name, + type: 0 /* PluginType.Core */, + path: (_b = plugin.manifest.ios.src) !== null && _b !== void 0 ? _b : platform, + }; + } + else if (plugin.xml) { + plugin.ios = { + name: plugin.name, + type: 1 /* PluginType.Cordova */, + path: 'src/' + platform, + }; + if ((0, cordova_1.getIncompatibleCordovaPlugins)(platform).includes(plugin.id) || !(0, plugin_1.getPluginPlatform)(plugin, platform)) { + plugin.ios.type = 2 /* PluginType.Incompatible */; + } + } + else { + return null; + } + return plugin; +} +exports.resolvePlugin = resolvePlugin; +/** + * Update the native project files with the desired app id and app name + */ +async function editProjectSettingsIOS(config) { + const appId = config.app.appId; + const appName = config.app.appName.replace(/&/g, '&').replace(//g, '>'); + const pbxPath = `${config.ios.nativeXcodeProjDirAbs}/project.pbxproj`; + const plistPath = (0, path_1.resolve)(config.ios.nativeTargetDirAbs, 'Info.plist'); + let plistContent = await (0, fs_extra_1.readFile)(plistPath, { encoding: 'utf-8' }); + plistContent = plistContent.replace(/CFBundleDisplayName<\/key>[\s\S]?\s+([^<]*)<\/string>/, `CFBundleDisplayName\n ${appName}`); + let pbxContent = await (0, fs_extra_1.readFile)(pbxPath, { encoding: 'utf-8' }); + pbxContent = pbxContent.replace(/PRODUCT_BUNDLE_IDENTIFIER = ([^;]+)/g, `PRODUCT_BUNDLE_IDENTIFIER = ${appId}`); + await (0, fs_extra_1.writeFile)(plistPath, plistContent, { encoding: 'utf-8' }); + await (0, fs_extra_1.writeFile)(pbxPath, pbxContent, { encoding: 'utf-8' }); +} +exports.editProjectSettingsIOS = editProjectSettingsIOS; +function getMajoriOSVersion(config) { + const pbx = (0, fs_extra_1.readFileSync)((0, path_1.join)(config.ios.nativeXcodeProjDirAbs, 'project.pbxproj'), 'utf-8'); + const searchString = 'IPHONEOS_DEPLOYMENT_TARGET = '; + const iosVersion = pbx.substring(pbx.indexOf(searchString) + searchString.length, pbx.indexOf(searchString) + searchString.length + 2); + return iosVersion; +} +exports.getMajoriOSVersion = getMajoriOSVersion; diff --git a/node_modules/@capacitor/cli/dist/ios/doctor.js b/node_modules/@capacitor/cli/dist/ios/doctor.js new file mode 100644 index 0000000..fb0861d --- /dev/null +++ b/node_modules/@capacitor/cli/dist/ios/doctor.js @@ -0,0 +1,45 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.doctorIOS = void 0; +const common_1 = require("../common"); +const errors_1 = require("../errors"); +const log_1 = require("../log"); +const subprocess_1 = require("../util/subprocess"); +const common_2 = require("./common"); +async function doctorIOS(config) { + var _a; + // DOCTOR ideas for iOS: + // plugin specific warnings + // check cocoapods installed + // check projects exist + // check content in www === ios/www + // check CLI versions + // check plugins versions + // check native project deps are up-to-date === npm install + // check if npm install was updated + // check online datebase of common errors + // check if www folder is empty (index.html does not exist) + try { + await (0, common_1.check)([() => (0, common_1.checkWebDir)(config), checkXcode, ...(await (0, common_2.getCommonChecks)(config))]); + (0, log_1.logSuccess)('iOS looking great! 👌'); + } + catch (e) { + (0, errors_1.fatal)((_a = e.stack) !== null && _a !== void 0 ? _a : e); + } +} +exports.doctorIOS = doctorIOS; +async function checkXcode() { + if (!(await (0, subprocess_1.isInstalled)('xcodebuild'))) { + return `Xcode is not installed`; + } + // const matches = output.match(/^Xcode (.*)/); + // if (matches && matches.length === 2) { + // const minVersion = '9.0.0'; + // const semver = await import('semver'); + // console.log(matches[1]); + // if (semver.gt(minVersion, matches[1])) { + // return `Xcode version is too old, ${minVersion} is required`; + // } + // } + return null; +} diff --git a/node_modules/@capacitor/cli/dist/ios/open.js b/node_modules/@capacitor/cli/dist/ios/open.js new file mode 100644 index 0000000..e83be3c --- /dev/null +++ b/node_modules/@capacitor/cli/dist/ios/open.js @@ -0,0 +1,16 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.openIOS = void 0; +const tslib_1 = require("tslib"); +const open_1 = tslib_1.__importDefault(require("open")); +const common_1 = require("../common"); +async function openIOS(config) { + if ((await config.ios.packageManager) == 'SPM') { + await (0, open_1.default)(config.ios.nativeXcodeProjDirAbs, { wait: false }); + } + else { + await (0, open_1.default)(await config.ios.nativeXcodeWorkspaceDirAbs, { wait: false }); + } + await (0, common_1.wait)(3000); +} +exports.openIOS = openIOS; diff --git a/node_modules/@capacitor/cli/dist/ios/run.js b/node_modules/@capacitor/cli/dist/ios/run.js new file mode 100644 index 0000000..1800c7e --- /dev/null +++ b/node_modules/@capacitor/cli/dist/ios/run.js @@ -0,0 +1,50 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.runIOS = void 0; +const tslib_1 = require("tslib"); +const debug_1 = tslib_1.__importDefault(require("debug")); +const path_1 = require("path"); +const colors_1 = tslib_1.__importDefault(require("../colors")); +const common_1 = require("../common"); +const native_run_1 = require("../util/native-run"); +const subprocess_1 = require("../util/subprocess"); +const debug = (0, debug_1.default)('capacitor:ios:run'); +async function runIOS(config, { target: selectedTarget, targetName: selectedTargetName, targetNameSdkVersion: selectedTargetSdkVersion, scheme: selectedScheme, configuration: selectedConfiguration, }) { + const target = await (0, common_1.promptForPlatformTarget)(await (0, native_run_1.getPlatformTargets)('ios'), selectedTarget !== null && selectedTarget !== void 0 ? selectedTarget : selectedTargetName, selectedTargetSdkVersion, selectedTargetName !== undefined); + const runScheme = selectedScheme || config.ios.scheme; + const configuration = selectedConfiguration || 'Debug'; + const derivedDataPath = (0, path_1.resolve)(config.ios.platformDirAbs, 'DerivedData', target.id); + const packageManager = await config.ios.packageManager; + let typeOfBuild; + let projectName; + if (packageManager !== 'SPM') { + typeOfBuild = '-workspace'; + projectName = (0, path_1.basename)(await config.ios.nativeXcodeWorkspaceDirAbs); + } + else { + typeOfBuild = '-project'; + projectName = (0, path_1.basename)(await config.ios.nativeXcodeProjDirAbs); + } + const xcodebuildArgs = [ + typeOfBuild, + projectName, + '-scheme', + runScheme, + '-configuration', + configuration, + '-destination', + `id=${target.id}`, + '-derivedDataPath', + derivedDataPath, + ]; + debug('Invoking xcodebuild with args: %O', xcodebuildArgs); + await (0, common_1.runTask)('Running xcodebuild', async () => (0, subprocess_1.runCommand)('xcrun', ['xcodebuild', ...xcodebuildArgs], { + cwd: config.ios.nativeProjectDirAbs, + })); + const appName = `${runScheme}.app`; + const appPath = (0, path_1.resolve)(derivedDataPath, 'Build/Products', target.virtual ? `${configuration}-iphonesimulator` : `${configuration}-iphoneos`, appName); + const nativeRunArgs = ['ios', '--app', appPath, '--target', target.id]; + debug('Invoking native-run with args: %O', nativeRunArgs); + await (0, common_1.runTask)(`Deploying ${colors_1.default.strong(appName)} to ${colors_1.default.input(target.id)}`, async () => (0, native_run_1.runNativeRun)(nativeRunArgs)); +} +exports.runIOS = runIOS; diff --git a/node_modules/@capacitor/cli/dist/ios/update.js b/node_modules/@capacitor/cli/dist/ios/update.js new file mode 100644 index 0000000..54456cd --- /dev/null +++ b/node_modules/@capacitor/cli/dist/ios/update.js @@ -0,0 +1,604 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.installCocoaPodsPlugins = exports.updateIOS = void 0; +const tslib_1 = require("tslib"); +const fs_extra_1 = require("fs-extra"); +const path_1 = require("path"); +const colors_1 = tslib_1.__importDefault(require("../colors")); +const common_1 = require("../common"); +const cordova_1 = require("../cordova"); +const errors_1 = require("../errors"); +const log_1 = require("../log"); +const plugin_1 = require("../plugin"); +const copy_1 = require("../tasks/copy"); +const migrate_1 = require("../tasks/migrate"); +const fs_1 = require("../util/fs"); +const iosplugin_1 = require("../util/iosplugin"); +const node_1 = require("../util/node"); +const spm_1 = require("../util/spm"); +const subprocess_1 = require("../util/subprocess"); +const template_1 = require("../util/template"); +const common_2 = require("./common"); +const platform = 'ios'; +async function updateIOS(config, deployment) { + const plugins = await getPluginsTask(config); + const capacitorPlugins = plugins.filter((p) => (0, plugin_1.getPluginType)(p, platform) === 0 /* PluginType.Core */); + await updatePluginFiles(config, plugins, deployment); + await (0, common_1.checkPlatformVersions)(config, platform); + (0, iosplugin_1.generateIOSPackageJSON)(config, plugins); + (0, plugin_1.printPlugins)(capacitorPlugins, 'ios'); +} +exports.updateIOS = updateIOS; +async function updatePluginFiles(config, plugins, deployment) { + var _a; + await removePluginsNativeFiles(config); + const cordovaPlugins = plugins.filter((p) => (0, plugin_1.getPluginType)(p, platform) === 1 /* PluginType.Cordova */); + if (cordovaPlugins.length > 0) { + await copyPluginsNativeFiles(config, cordovaPlugins); + } + if (!(await (0, fs_extra_1.pathExists)(await config.ios.webDirAbs))) { + await (0, copy_1.copy)(config, platform); + } + await (0, cordova_1.handleCordovaPluginsJS)(cordovaPlugins, config, platform); + await (0, cordova_1.checkPluginDependencies)(plugins, platform, (_a = config.app.extConfig.cordova) === null || _a === void 0 ? void 0 : _a.failOnUninstalledPlugins); + if ((await config.ios.packageManager) === 'SPM') { + await generateCordovaPackageFiles(cordovaPlugins, config); + const validSPMPackages = await (0, spm_1.checkPluginsForPackageSwift)(config, plugins); + await (0, spm_1.generatePackageFile)(config, validSPMPackages.concat(cordovaPlugins)); + } + else { + await generateCordovaPodspecs(cordovaPlugins, config); + await installCocoaPodsPlugins(config, plugins, deployment); + } + await (0, cordova_1.logCordovaManualSteps)(cordovaPlugins, config, platform); + const incompatibleCordovaPlugins = plugins.filter((p) => (0, plugin_1.getPluginType)(p, platform) === 2 /* PluginType.Incompatible */); + (0, plugin_1.printPlugins)(incompatibleCordovaPlugins, platform, 'incompatible'); +} +async function generateCordovaPackageFiles(cordovaPlugins, config) { + cordovaPlugins.map((plugin) => { + generateCordovaPackageFile(plugin, config); + }); +} +async function generateCordovaPackageFile(p, config) { + var _a; + const iosPlatformVersion = await (0, common_1.getCapacitorPackageVersion)(config, config.ios.name); + const platformTag = (0, plugin_1.getPluginPlatform)(p, platform); + if ((_a = platformTag.$) === null || _a === void 0 ? void 0 : _a.package) { + const packageSwiftPath = (0, path_1.join)(p.rootPath, 'Package.swift'); + let content = await (0, fs_extra_1.readFile)(packageSwiftPath, { encoding: 'utf-8' }); + content = content.replace(`apache`, `ionic-team`).replaceAll(`cordova-ios`, `capacitor-swift-pm`); + content = (0, migrate_1.setAllStringIn)(content, `url: "https://github.com/ionic-team/capacitor-swift-pm.git",`, `)`, ` from: "${iosPlatformVersion}"`); + await (0, fs_extra_1.writeFile)(packageSwiftPath, content); + } + else { + await writeGeneratedPackageSwift(p, config, iosPlatformVersion); + } +} +function buildBinaryTargetEntries(p, frameworks) { + const customXcframeworks = frameworks.filter((f) => f.$.custom === 'true' && f.$.src.endsWith('.xcframework')); + const customFrameworks = frameworks.filter((f) => f.$.custom === 'true' && f.$.src.endsWith('.framework')); + if (customFrameworks.length > 0) { + customFrameworks.forEach((f) => { + log_1.logger.warn(`${p.id}: custom .framework files are not supported as binaryTarget in SPM (${f.$.src}). Convert to .xcframework for SPM compatibility.`); + }); + } + const binaryTargetsText = customXcframeworks + .map((f) => { + const name = f.$.src.split('/').pop().replace('.xcframework', ''); + return `, + .binaryTarget( + name: "${name}", + path: "${f.$.src}" + )`; + }) + .join(''); + const binaryDepsText = customXcframeworks + .map((f) => { + const name = f.$.src.split('/').pop().replace('.xcframework', ''); + return `,\n .target(name: "${name}")`; + }) + .join(''); + return { binaryTargetsText, binaryDepsText }; +} +function buildResourcesText(resources) { + const resourceEntry = []; + for (const resource of resources) { + resourceEntry.push(`.copy("resources/${resource.$.src.split('/').pop()}")`); + } + return resources.length > 0 + ? `, + resources: [ + ${resourceEntry.join(',\n ')} + ]` + : ''; +} +async function buildDependencyTexts(p, config) { + let allDependencies = (0, plugin_1.getPlatformElement)(p, platform, 'dependency'); + if (p.xml['dependency']) { + allDependencies = allDependencies.concat(p.xml['dependency']); + } + let packageText = ''; + let productText = ''; + await Promise.all(allDependencies.map(async (dep) => { + let plugin = dep.$.id; + if (plugin.includes('@') && plugin.indexOf('@') !== 0) { + [plugin] = plugin.split('@'); + } + const depPlugin = await (0, plugin_1.resolvePlugin)(config, plugin); + if (depPlugin) { + const headerFiles = (0, plugin_1.getPlatformElement)(depPlugin, platform, 'header-file'); + const resources = (0, plugin_1.getPlatformElement)(depPlugin, platform, 'resource-file'); + const sourceFiles = (0, plugin_1.getPlatformElement)(depPlugin, platform, 'source-file'); + if (sourceFiles.length === 0 && headerFiles.length === 0 && resources.length === 0) { + return; + } + packageText += `,\n .package(name: "${depPlugin.name}", path: "../${depPlugin.name}")`; + productText += `,\n .product(name: "${depPlugin.name}", package: "${depPlugin.name}")`; + } + })); + return { packageText, productText }; +} +function buildCSettingsText(p, sourceFiles) { + var _a; + const pluginId = p.id; + const allFlags = new Set(); + for (const sourceFile of sourceFiles) { + const flags = (_a = sourceFile.$) === null || _a === void 0 ? void 0 : _a['compiler-flags']; + if (flags) { + flags + .split(/\s+/) + .map((f) => f.trim()) + .filter((f) => f.length > 0) + .forEach((f) => allFlags.add(f)); + } + } + if (allFlags.size === 0) { + return ''; + } + const entries = []; + const unsupportedFlags = []; + for (const flag of allFlags) { + if (flag.startsWith('-D')) { + const definition = flag.slice(2); + const eqIndex = definition.indexOf('='); + if (eqIndex !== -1) { + const name = definition.slice(0, eqIndex); + const value = definition.slice(eqIndex + 1); + entries.push(` .define("${name}", to: "${value}")`); + } + else { + entries.push(` .define("${definition}")`); + } + } + else { + unsupportedFlags.push(flag); + } + } + if (unsupportedFlags.length > 0) { + log_1.logger.warn(`${pluginId}: the following compiler flags are not supported in SPM and were ignored: ${unsupportedFlags.join(', ')}. ` + + `This might cause the plugin to fail to compile.`); + } + if (entries.length === 0) { + return ''; + } + return `, + cSettings: [ +${entries.join(',\n')} + ]`; +} +async function writeGeneratedPackageSwift(p, config, iosPlatformVersion) { + const iosVersion = (0, common_2.getMajoriOSVersion)(config); + const headerFiles = (0, plugin_1.getPlatformElement)(p, platform, 'header-file'); + const headersText = headerFiles.length > 0 + ? `, + publicHeadersPath: "."` + : ''; + const resources = (0, plugin_1.getPlatformElement)(p, platform, 'resource-file'); + const sourceFiles = (0, plugin_1.getPlatformElement)(p, platform, 'source-file'); + if (sourceFiles.length === 0 && headerFiles.length === 0 && resources.length === 0) { + return; + } + const frameworks = (0, plugin_1.getPlatformElement)(p, platform, 'framework'); + const { binaryTargetsText, binaryDepsText } = buildBinaryTargetEntries(p, frameworks); + const cSettingsText = buildCSettingsText(p, sourceFiles); + const systemFrameworks = frameworks.filter((f) => !f.$.custom && f.$.src.endsWith('.framework')); + const hasWeakFrameworks = systemFrameworks.some((f) => f.$.weak === 'true'); + const requiredSystemFrameworks = systemFrameworks.filter((f) => f.$.weak !== 'true'); + const resourcesText = buildResourcesText(resources); + const libraryTypeText = hasWeakFrameworks ? `\n type: .dynamic,` : ''; + const linkerSettingsText = requiredSystemFrameworks.length > 0 + ? `, + linkerSettings: [ +${requiredSystemFrameworks.map((f) => ` .linkedFramework("${f.$.src.replace('.framework', '')}")`).join(',\n')} + ]` + : ''; + const { packageText, productText } = await buildDependencyTexts(p, config); + const content = `// swift-tools-version: 5.9 + +import PackageDescription + +let package = Package( + name: "${p.name}", + platforms: [.iOS(.v${iosVersion})], + products: [ + .library( + name: "${p.name}",${libraryTypeText} + targets: ["${p.name}"] + ) + ], + dependencies: [ + .package(url: "https://github.com/ionic-team/capacitor-swift-pm.git", from: "${iosPlatformVersion}")${packageText} + ], + targets: [ + .target( + name: "${p.name}", + dependencies: [ + .product(name: "Cordova", package: "capacitor-swift-pm")${binaryDepsText}${productText} + ], + path: "."${resourcesText}${headersText}${cSettingsText}${linkerSettingsText} + )${binaryTargetsText} + ] +)`; + await (0, fs_extra_1.writeFile)((0, path_1.join)(config.ios.cordovaPluginsDirAbs, 'sources', p.name, 'Package.swift'), content); +} +async function installCocoaPodsPlugins(config, plugins, deployment) { + await (0, common_1.runTask)(`Updating iOS native dependencies with ${colors_1.default.input(`${await config.ios.podPath} install`)}`, () => { + return updatePodfile(config, plugins, deployment); + }); +} +exports.installCocoaPodsPlugins = installCocoaPodsPlugins; +async function updatePodfile(config, plugins, deployment) { + const dependenciesContent = await generatePodFile(config, plugins); + const relativeCapacitoriOSPath = await getRelativeCapacitoriOSPath(config); + const podfilePath = (0, path_1.join)(config.ios.nativeProjectDirAbs, 'Podfile'); + let podfileContent = await (0, fs_extra_1.readFile)(podfilePath, { encoding: 'utf-8' }); + podfileContent = podfileContent.replace(/(def capacitor_pods)[\s\S]+?(\nend)/, `$1${dependenciesContent}$2`); + podfileContent = podfileContent.replace(/(require_relative)[\s\S]+?(@capacitor\/ios\/scripts\/pods_helpers')/, `require_relative '${relativeCapacitoriOSPath}/scripts/pods_helpers'`); + await (0, fs_extra_1.writeFile)(podfilePath, podfileContent, { encoding: 'utf-8' }); + const podPath = await config.ios.podPath; + const useBundler = (await config.ios.packageManager) === 'bundler'; + if (useBundler) { + await (0, subprocess_1.runCommand)('bundle', ['exec', 'pod', 'install', ...(deployment ? ['--deployment'] : [])], { + cwd: config.ios.nativeProjectDirAbs, + }); + } + else if (await (0, subprocess_1.isInstalled)('pod')) { + await (0, subprocess_1.runCommand)(podPath, ['install', ...(deployment ? ['--deployment'] : [])], { + cwd: config.ios.nativeProjectDirAbs, + }); + } + else { + log_1.logger.warn('Skipping pod install because CocoaPods is not installed'); + } + const isXcodebuildAvailable = await (0, subprocess_1.isInstalled)('xcodebuild'); + if (isXcodebuildAvailable) { + await (0, subprocess_1.runCommand)('xcodebuild', ['-project', (0, path_1.basename)(`${config.ios.nativeXcodeProjDirAbs}`), 'clean'], { + cwd: config.ios.nativeProjectDirAbs, + }); + } + else { + log_1.logger.warn('Unable to find "xcodebuild". Skipping xcodebuild clean step...'); + } +} +async function getRelativeCapacitoriOSPath(config) { + const capacitoriOSPath = (0, node_1.resolveNode)(config.app.rootDir, '@capacitor/ios', 'package.json'); + if (!capacitoriOSPath) { + (0, errors_1.fatal)(`Unable to find ${colors_1.default.strong('node_modules/@capacitor/ios')}.\n` + + `Are you sure ${colors_1.default.strong('@capacitor/ios')} is installed?`); + } + return (0, fs_1.convertToUnixPath)((0, path_1.relative)(config.ios.nativeProjectDirAbs, await (0, fs_extra_1.realpath)((0, path_1.dirname)(capacitoriOSPath)))); +} +async function generatePodFile(config, plugins) { + const relativeCapacitoriOSPath = await getRelativeCapacitoriOSPath(config); + const capacitorPlugins = plugins.filter((p) => (0, plugin_1.getPluginType)(p, platform) === 0 /* PluginType.Core */); + const pods = await Promise.all(capacitorPlugins.map(async (p) => { + if (!p.ios) { + return ''; + } + return ` pod '${p.ios.name}', :path => '${(0, fs_1.convertToUnixPath)((0, path_1.relative)(config.ios.nativeProjectDirAbs, await (0, fs_extra_1.realpath)(p.rootPath)))}'\n`; + })); + const cordovaPlugins = plugins.filter((p) => (0, plugin_1.getPluginType)(p, platform) === 1 /* PluginType.Cordova */); + cordovaPlugins.map(async (p) => { + const podspecs = (0, plugin_1.getPlatformElement)(p, platform, 'podspec'); + podspecs.map((podspec) => { + podspec.pods.map((pPods) => { + pPods.pod.map((pod) => { + if (pod.$.git) { + let gitRef = ''; + if (pod.$.tag) { + gitRef = `, :tag => '${pod.$.tag}'`; + } + else if (pod.$.branch) { + gitRef = `, :branch => '${pod.$.branch}'`; + } + else if (pod.$.commit) { + gitRef = `, :commit => '${pod.$.commit}'`; + } + pods.push(` pod '${pod.$.name}', :git => '${pod.$.git}'${gitRef}\n`); + } + }); + }); + }); + }); + const staticPlugins = cordovaPlugins.filter((p) => (0, cordova_1.needsStaticPod)(p)); + const noStaticPlugins = cordovaPlugins.filter((el) => !staticPlugins.includes(el)); + if (noStaticPlugins.length > 0) { + pods.push(` pod 'CordovaPlugins', :path => '../capacitor-cordova-ios-plugins'\n`); + } + if (staticPlugins.length > 0) { + pods.push(` pod 'CordovaPluginsStatic', :path => '../capacitor-cordova-ios-plugins'\n`); + } + const resourcesPlugins = cordovaPlugins.filter(filterResources); + if (resourcesPlugins.length > 0) { + pods.push(` pod 'CordovaPluginsResources', :path => '../capacitor-cordova-ios-plugins'\n`); + } + return ` + pod 'Capacitor', :path => '${relativeCapacitoriOSPath}' + pod 'CapacitorCordova', :path => '${relativeCapacitoriOSPath}' +${pods.join('').trimRight()}`; +} +function getFrameworkName(framework) { + if (isFramework(framework)) { + if (framework.$.custom && framework.$.custom === 'true') { + return framework.$.src; + } + return framework.$.src.substr(0, framework.$.src.indexOf('.')); + } + return framework.$.src.substr(0, framework.$.src.indexOf('.')).replace('lib', ''); +} +function isFramework(framework) { + return framework.$.src.split('.').pop().includes('framework'); +} +async function generateCordovaPodspecs(cordovaPlugins, config) { + const staticPlugins = cordovaPlugins.filter((p) => (0, cordova_1.needsStaticPod)(p)); + const noStaticPlugins = cordovaPlugins.filter((el) => !staticPlugins.includes(el)); + generateCordovaPodspec(noStaticPlugins, config, false); + generateCordovaPodspec(staticPlugins, config, true); +} +async function generateCordovaPodspec(cordovaPlugins, config, isStatic) { + const weakFrameworks = []; + const linkedFrameworks = []; + const customFrameworks = []; + const systemLibraries = []; + const sourceFrameworks = []; + const frameworkDeps = []; + const compilerFlags = []; + let prefsArray = []; + let name = 'CordovaPlugins'; + let sourcesFolderName = 'sources'; + if (isStatic) { + name += 'Static'; + frameworkDeps.push('s.static_framework = true'); + sourcesFolderName += 'static'; + } + cordovaPlugins.map((plugin) => { + const frameworks = (0, plugin_1.getPlatformElement)(plugin, platform, 'framework'); + frameworks.map((framework) => { + if (!framework.$.type) { + const name = getFrameworkName(framework); + if (isFramework(framework)) { + if (framework.$.weak && framework.$.weak === 'true') { + if (!weakFrameworks.includes(name)) { + weakFrameworks.push(name); + } + } + else if (framework.$.custom && framework.$.custom === 'true') { + const frameworktPath = (0, path_1.join)(sourcesFolderName, plugin.name, name); + if (!customFrameworks.includes(frameworktPath)) { + customFrameworks.push(frameworktPath); + } + } + else { + if (!linkedFrameworks.includes(name)) { + linkedFrameworks.push(name); + } + } + } + else { + if (!systemLibraries.includes(name)) { + systemLibraries.push(name); + } + } + } + else if (framework.$.type && framework.$.type === 'podspec') { + let depString = `s.dependency '${framework.$.src}'`; + if (framework.$.spec && framework.$.spec !== '') { + depString += `, '${framework.$.spec}'`; + } + if (!frameworkDeps.includes(depString)) { + frameworkDeps.push(depString); + } + } + }); + prefsArray = prefsArray.concat((0, plugin_1.getAllElements)(plugin, platform, 'preference')); + const podspecs = (0, plugin_1.getPlatformElement)(plugin, platform, 'podspec'); + podspecs.map((podspec) => { + podspec.pods.map((pods) => { + pods.pod.map((pod) => { + let depString = `s.dependency '${pod.$.name}'`; + if (pod.$.spec && pod.$.spec !== '') { + depString += `, '${pod.$.spec}'`; + } + if (!frameworkDeps.includes(depString)) { + frameworkDeps.push(depString); + } + }); + }); + }); + const sourceFiles = (0, plugin_1.getPlatformElement)(plugin, platform, 'source-file'); + sourceFiles.map((sourceFile) => { + if (sourceFile.$.framework && sourceFile.$.framework === 'true') { + let fileName = sourceFile.$.src.split('/').pop(); + if (!fileName.startsWith('lib')) { + fileName = 'lib' + fileName; + } + const frameworktPath = (0, path_1.join)(sourcesFolderName, plugin.name, fileName); + if (!sourceFrameworks.includes(frameworktPath)) { + sourceFrameworks.push(frameworktPath); + } + } + else if (sourceFile.$['compiler-flags']) { + const cFlag = sourceFile.$['compiler-flags']; + if (!compilerFlags.includes(cFlag)) { + compilerFlags.push(cFlag); + } + } + }); + }); + const onlySystemLibraries = systemLibraries.filter((library) => removeNoSystem(library, sourceFrameworks)); + if (weakFrameworks.length > 0) { + frameworkDeps.push(`s.weak_frameworks = '${weakFrameworks.join(`', '`)}'`); + } + if (linkedFrameworks.length > 0) { + frameworkDeps.push(`s.frameworks = '${linkedFrameworks.join(`', '`)}'`); + } + if (onlySystemLibraries.length > 0) { + frameworkDeps.push(`s.libraries = '${onlySystemLibraries.join(`', '`)}'`); + } + if (customFrameworks.length > 0) { + frameworkDeps.push(`s.vendored_frameworks = '${customFrameworks.join(`', '`)}'`); + frameworkDeps.push(`s.exclude_files = 'sources/**/*.framework/Headers/*.h', 'sources/**/*.framework/PrivateHeaders/*.h'`); + } + if (sourceFrameworks.length > 0) { + frameworkDeps.push(`s.vendored_libraries = '${sourceFrameworks.join(`', '`)}'`); + } + if (compilerFlags.length > 0) { + frameworkDeps.push(`s.compiler_flags = '${compilerFlags.join(' ')}'`); + } + const arcPlugins = cordovaPlugins.filter(filterARCFiles); + if (arcPlugins.length > 0) { + frameworkDeps.push(`s.subspec 'noarc' do |sna| + sna.requires_arc = false + sna.source_files = 'noarc/**/*.{swift,h,m,c,cc,mm,cpp}' + end`); + } + let frameworksString = frameworkDeps.join('\n '); + frameworksString = await replaceFrameworkVariables(config, prefsArray, frameworksString); + const content = ` + Pod::Spec.new do |s| + s.name = '${name}' + s.version = '${config.cli.package.version}' + s.summary = 'Autogenerated spec' + s.license = 'Unknown' + s.homepage = 'https://example.com' + s.authors = { 'Capacitor Generator' => 'hi@example.com' } + s.source = { :git => 'https://github.com/ionic-team/does-not-exist.git', :tag => '${config.cli.package.version}' } + s.source_files = '${sourcesFolderName}/**/*.{swift,h,m,c,cc,mm,cpp}' + s.ios.deployment_target = '${config.ios.minVersion}' + s.xcconfig = {'GCC_PREPROCESSOR_DEFINITIONS' => '$(inherited) COCOAPODS=1 WK_WEB_VIEW_ONLY=1' } + s.dependency 'CapacitorCordova'${getLinkerFlags(config)} + s.swift_version = '5.1' + ${frameworksString} + end`; + await (0, fs_extra_1.writeFile)((0, path_1.join)(config.ios.cordovaPluginsDirAbs, `${name}.podspec`), content); +} +function getLinkerFlags(config) { + var _a; + if ((_a = config.app.extConfig.ios) === null || _a === void 0 ? void 0 : _a.cordovaLinkerFlags) { + return `\n s.pod_target_xcconfig = { 'OTHER_LDFLAGS' => '${config.app.extConfig.ios.cordovaLinkerFlags.join(' ')}' }`; + } + return ''; +} +async function copyPluginsNativeFiles(config, cordovaPlugins) { + var _a; + const isSPM = (await config.ios.packageManager) === 'SPM'; + for (const p of cordovaPlugins) { + const platformTag = (0, plugin_1.getPluginPlatform)(p, platform); + if (isSPM && ((_a = platformTag.$) === null || _a === void 0 ? void 0 : _a.package)) { + continue; + } + const sourceFiles = (0, plugin_1.getPlatformElement)(p, platform, 'source-file'); + const headerFiles = (0, plugin_1.getPlatformElement)(p, platform, 'header-file'); + const codeFiles = sourceFiles.concat(headerFiles); + const frameworks = (0, plugin_1.getPlatformElement)(p, platform, 'framework'); + let sourcesFolderName = 'sources'; + if (!isSPM && (0, cordova_1.needsStaticPod)(p)) { + sourcesFolderName += 'static'; + } + const sourcesFolder = (0, path_1.join)(config.ios.cordovaPluginsDirAbs, sourcesFolderName, p.name); + for (const codeFile of codeFiles) { + let fileName = codeFile.$.src.split('/').pop(); + const fileExt = codeFile.$.src.split('.').pop(); + if (fileExt === 'a' && !fileName.startsWith('lib')) { + fileName = 'lib' + fileName; + } + let destFolder = sourcesFolderName; + if (!isSPM && codeFile.$['compiler-flags'] && codeFile.$['compiler-flags'] === '-fno-objc-arc') { + destFolder = 'noarc'; + } + const filePath = (0, plugin_1.getFilePath)(config, p, codeFile.$.src); + const fileDest = (0, path_1.join)(config.ios.cordovaPluginsDirAbs, destFolder, p.name, fileName); + await (0, fs_extra_1.copy)(filePath, fileDest); + if (!codeFile.$.framework) { + let fileContent = await (0, fs_extra_1.readFile)(fileDest, { encoding: 'utf-8' }); + if (fileExt === 'swift') { + fileContent = 'import Cordova\n' + fileContent; + await (0, fs_extra_1.writeFile)(fileDest, fileContent, { encoding: 'utf-8' }); + } + else { + if (fileContent.includes('@import Firebase;')) { + fileContent = fileContent.replace('@import Firebase;', '#import '); + await (0, fs_extra_1.writeFile)(fileDest, fileContent, { encoding: 'utf-8' }); + } + if (fileContent.includes('[NSBundle bundleForClass:[self class]]') || + fileContent.includes('[NSBundle bundleForClass:[CDVCapture class]]')) { + const bundleName = isSPM ? 'SWIFTPM_MODULE_BUNDLE' : '[NSBundle mainBundle]'; + fileContent = fileContent.replace('[NSBundle bundleForClass:[self class]]', bundleName); + fileContent = fileContent.replace('[NSBundle bundleForClass:[CDVCapture class]]', bundleName); + await (0, fs_extra_1.writeFile)(fileDest, fileContent, { encoding: 'utf-8' }); + } + if (isSPM && fileContent.includes('[NSBundle mainBundle] URLForResource')) { + fileContent = fileContent.replace('[NSBundle mainBundle] URLForResource', 'SWIFTPM_MODULE_BUNDLE URLForResource'); + await (0, fs_extra_1.writeFile)(fileDest, fileContent, { encoding: 'utf-8' }); + } + if (fileContent.includes('[self.webView superview]') || fileContent.includes('self.webView.superview')) { + fileContent = fileContent.replace(/\[self.webView superview\]/g, 'self.viewController.view'); + fileContent = fileContent.replace(/self.webView.superview/g, 'self.viewController.view'); + await (0, fs_extra_1.writeFile)(fileDest, fileContent, { encoding: 'utf-8' }); + } + } + } + } + const resourceFiles = (0, plugin_1.getPlatformElement)(p, platform, 'resource-file'); + for (const resourceFile of resourceFiles) { + const fileName = resourceFile.$.src.split('/').pop(); + const rootResFolder = isSPM ? sourcesFolder : config.ios.cordovaPluginsDirAbs; + await (0, fs_extra_1.copy)((0, plugin_1.getFilePath)(config, p, resourceFile.$.src), (0, path_1.join)(rootResFolder, 'resources', fileName)); + } + for (const framework of frameworks) { + if (framework.$.custom && framework.$.custom === 'true') { + await (0, fs_extra_1.copy)((0, plugin_1.getFilePath)(config, p, framework.$.src), (0, path_1.join)(sourcesFolder, framework.$.src)); + } + } + } +} +async function removePluginsNativeFiles(config) { + await (0, fs_extra_1.remove)(config.ios.cordovaPluginsDirAbs); + await (0, template_1.extractTemplate)(config.cli.assets.ios.cordovaPluginsTemplateArchiveAbs, config.ios.cordovaPluginsDirAbs); +} +function filterResources(plugin) { + const resources = (0, plugin_1.getPlatformElement)(plugin, platform, 'resource-file'); + return resources.length > 0; +} +function filterARCFiles(plugin) { + const sources = (0, plugin_1.getPlatformElement)(plugin, platform, 'source-file'); + const sourcesARC = sources.filter((sourceFile) => sourceFile.$['compiler-flags'] && sourceFile.$['compiler-flags'] === '-fno-objc-arc'); + return sourcesARC.length > 0; +} +function removeNoSystem(library, sourceFrameworks) { + const libraries = sourceFrameworks.filter((framework) => framework.includes(library)); + return libraries.length === 0; +} +async function getPluginsTask(config) { + return await (0, common_1.runTask)('Updating iOS plugins', async () => { + const allPlugins = await (0, plugin_1.getPlugins)(config, 'ios'); + const iosPlugins = await (0, common_2.getIOSPlugins)(allPlugins); + return iosPlugins; + }); +} +async function replaceFrameworkVariables(config, prefsArray, frameworkString) { + prefsArray.map((preference) => { + frameworkString = frameworkString.replace(new RegExp(('$' + preference.$.name).replace('$', '\\$&'), 'g'), preference.$.default); + }); + return frameworkString; +} diff --git a/node_modules/@capacitor/cli/dist/ipc.js b/node_modules/@capacitor/cli/dist/ipc.js new file mode 100644 index 0000000..b7850f1 --- /dev/null +++ b/node_modules/@capacitor/cli/dist/ipc.js @@ -0,0 +1,61 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.receive = exports.send = void 0; +const tslib_1 = require("tslib"); +const utils_subprocess_1 = require("@ionic/utils-subprocess"); +const debug_1 = tslib_1.__importDefault(require("debug")); +const fs_extra_1 = require("fs-extra"); +const https_1 = require("https"); +const path_1 = require("path"); +const cli_1 = require("./util/cli"); +const debug = (0, debug_1.default)('capacitor:ipc'); +/** + * Send an IPC message to a forked process. + */ +async function send(msg) { + const dir = cli_1.ENV_PATHS.log; + await (0, fs_extra_1.mkdirp)(dir); + const logPath = (0, path_1.resolve)(dir, 'ipc.log'); + debug('Sending %O IPC message to forked process (logs: %O)', msg.type, logPath); + const fd = await (0, fs_extra_1.open)(logPath, 'a'); + const p = (0, utils_subprocess_1.fork)(process.argv[1], ['📡'], { stdio: ['ignore', fd, fd, 'ipc'] }); + p.send(msg); + p.disconnect(); + p.unref(); +} +exports.send = send; +/** + * Receive and handle an IPC message. + * + * Assume minimal context and keep external dependencies to a minimum. + */ +async function receive(msg) { + debug('Received %O IPC message', msg.type); + if (msg.type === 'telemetry') { + const now = new Date().toISOString(); + const { data } = msg; + // This request is only made if telemetry is on. + const req = (0, https_1.request)({ + hostname: 'metrics-capacitor.outsystems.com', + port: 443, + path: '/metrics', + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + }, (response) => { + debug('Sent %O metric to events service (status: %O)', data.name, response.statusCode); + if (response.statusCode !== 202) { + response.on('data', (chunk) => { + debug('Bad response from events service. Request body: %O', chunk.toString()); + }); + } + }); + const body = { + metrics: [data], + sent_at: now, + }; + req.end(JSON.stringify(body)); + } +} +exports.receive = receive; diff --git a/node_modules/@capacitor/cli/dist/log.js b/node_modules/@capacitor/cli/dist/log.js new file mode 100644 index 0000000..e8cfee2 --- /dev/null +++ b/node_modules/@capacitor/cli/dist/log.js @@ -0,0 +1,39 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.logSuccess = exports.logPrompt = exports.logger = exports.output = void 0; +const tslib_1 = require("tslib"); +const cli_framework_output_1 = require("@ionic/cli-framework-output"); +const colors_1 = tslib_1.__importDefault(require("./colors")); +const term_1 = require("./util/term"); +const options = { + colors: colors_1.default, + stream: process.argv.includes('--json') ? process.stderr : process.stdout, +}; +exports.output = (0, term_1.isInteractive)() ? new cli_framework_output_1.TTYOutputStrategy(options) : new cli_framework_output_1.StreamOutputStrategy(options); +exports.logger = (0, cli_framework_output_1.createDefaultLogger)({ + output: exports.output, + formatterOptions: { + titleize: false, + tags: new Map([ + [cli_framework_output_1.LOGGER_LEVELS.DEBUG, colors_1.default.log.DEBUG('[debug]')], + [cli_framework_output_1.LOGGER_LEVELS.INFO, colors_1.default.log.INFO('[info]')], + [cli_framework_output_1.LOGGER_LEVELS.WARN, colors_1.default.log.WARN('[warn]')], + [cli_framework_output_1.LOGGER_LEVELS.ERROR, colors_1.default.log.ERROR('[error]')], + ]), + }, +}); +async function logPrompt(msg, promptObject) { + const { wordWrap } = await Promise.resolve().then(() => tslib_1.__importStar(require('@ionic/cli-framework-output'))); + const { prompt } = await Promise.resolve().then(() => tslib_1.__importStar(require('prompts'))); + exports.logger.log({ + msg: `${colors_1.default.input('[?]')} ${wordWrap(msg, { indentation: 4 })}`, + logger: exports.logger, + format: false, + }); + return prompt(promptObject, { onCancel: () => process.exit(1) }); +} +exports.logPrompt = logPrompt; +function logSuccess(msg) { + exports.logger.msg(`${colors_1.default.success('[success]')} ${msg}`); +} +exports.logSuccess = logSuccess; diff --git a/node_modules/@capacitor/cli/dist/plugin.js b/node_modules/@capacitor/cli/dist/plugin.js new file mode 100644 index 0000000..3be0fa0 --- /dev/null +++ b/node_modules/@capacitor/cli/dist/plugin.js @@ -0,0 +1,182 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.getAllElements = exports.getFilePath = exports.getAssets = exports.getJSModules = exports.getPluginType = exports.getPlatformElement = exports.getPluginPlatform = exports.printPlugins = exports.fixName = exports.getDependencies = exports.resolvePlugin = exports.getPlugins = exports.getIncludedPluginPackages = void 0; +const tslib_1 = require("tslib"); +const fs_extra_1 = require("fs-extra"); +const path_1 = require("path"); +const colors_1 = tslib_1.__importDefault(require("./colors")); +const errors_1 = require("./errors"); +const log_1 = require("./log"); +const node_1 = require("./util/node"); +const xml_1 = require("./util/xml"); +function getIncludedPluginPackages(config, platform) { + var _a, _b, _c, _d; + const { extConfig } = config.app; + switch (platform) { + case 'android': + return (_b = (_a = extConfig.android) === null || _a === void 0 ? void 0 : _a.includePlugins) !== null && _b !== void 0 ? _b : extConfig.includePlugins; + case 'ios': + return (_d = (_c = extConfig.ios) === null || _c === void 0 ? void 0 : _c.includePlugins) !== null && _d !== void 0 ? _d : extConfig.includePlugins; + } +} +exports.getIncludedPluginPackages = getIncludedPluginPackages; +async function getPlugins(config, platform) { + var _a; + const possiblePlugins = (_a = getIncludedPluginPackages(config, platform)) !== null && _a !== void 0 ? _a : getDependencies(config); + const resolvedPlugins = await Promise.all(possiblePlugins.map(async (p) => resolvePlugin(config, p))); + return resolvedPlugins.filter((p) => !!p); +} +exports.getPlugins = getPlugins; +async function resolvePlugin(config, name) { + try { + const packagePath = (0, node_1.resolveNode)(config.app.rootDir, name, 'package.json'); + if (!packagePath) { + (0, errors_1.fatal)(`Unable to find ${colors_1.default.strong(`node_modules/${name}`)}.\n` + `Are you sure ${colors_1.default.strong(name)} is installed?`); + } + const rootPath = (0, path_1.dirname)(packagePath); + const meta = await (0, fs_extra_1.readJSON)(packagePath); + if (!meta) { + return null; + } + if (meta.capacitor) { + return { + id: name, + name: fixName(name), + version: meta.version, + rootPath, + repository: meta.repository, + manifest: meta.capacitor, + }; + } + const pluginXMLPath = (0, path_1.join)(rootPath, 'plugin.xml'); + const xmlMeta = await (0, xml_1.readXML)(pluginXMLPath); + return { + id: name, + name: fixName(name), + version: meta.version, + rootPath: rootPath, + repository: meta.repository, + xml: xmlMeta.plugin, + }; + } + catch (e) { + // ignore + } + return null; +} +exports.resolvePlugin = resolvePlugin; +function getDependencies(config) { + var _a, _b; + return [ + ...Object.keys((_a = config.app.package.dependencies) !== null && _a !== void 0 ? _a : {}), + ...Object.keys((_b = config.app.package.devDependencies) !== null && _b !== void 0 ? _b : {}), + ]; +} +exports.getDependencies = getDependencies; +function fixName(name) { + name = name + .replace(/\//g, '_') + .replace(/-/g, '_') + .replace(/@/g, '') + .replace(/_\w/g, (m) => m[1].toUpperCase()); + return name.charAt(0).toUpperCase() + name.slice(1); +} +exports.fixName = fixName; +function printPlugins(plugins, platform, type = 'capacitor') { + if (plugins.length === 0) { + return; + } + let msg; + const plural = plugins.length === 1 ? '' : 's'; + switch (type) { + case 'cordova': + msg = `Found ${plugins.length} Cordova plugin${plural} for ${colors_1.default.strong(platform)}:\n`; + break; + case 'incompatible': + msg = `Found ${plugins.length} incompatible Cordova plugin${plural} for ${colors_1.default.strong(platform)}, skipped install:\n`; + break; + case 'capacitor': + msg = `Found ${plugins.length} Capacitor plugin${plural} for ${colors_1.default.strong(platform)}:\n`; + break; + } + msg += plugins.map((p) => `${p.id}${colors_1.default.weak(`@${p.version}`)}`).join('\n'); + log_1.logger.info(msg); +} +exports.printPlugins = printPlugins; +function getPluginPlatform(p, platform) { + const platforms = p.xml.platform; + if (platforms) { + const platforms = p.xml.platform.filter(function (item) { + return item.$.name === platform; + }); + return platforms[0]; + } + return []; +} +exports.getPluginPlatform = getPluginPlatform; +function getPlatformElement(p, platform, elementName) { + const platformTag = getPluginPlatform(p, platform); + if (platformTag) { + const element = platformTag[elementName]; + if (element) { + return element; + } + } + return []; +} +exports.getPlatformElement = getPlatformElement; +function getPluginType(p, platform) { + var _a, _b, _c, _d; + switch (platform) { + case 'ios': + return (_b = (_a = p.ios) === null || _a === void 0 ? void 0 : _a.type) !== null && _b !== void 0 ? _b : 0 /* PluginType.Core */; + case 'android': + return (_d = (_c = p.android) === null || _c === void 0 ? void 0 : _c.type) !== null && _d !== void 0 ? _d : 0 /* PluginType.Core */; + } + return 0 /* PluginType.Core */; +} +exports.getPluginType = getPluginType; +/** + * Get each JavaScript Module for the given plugin + */ +function getJSModules(p, platform) { + return getAllElements(p, platform, 'js-module'); +} +exports.getJSModules = getJSModules; +/** + * Get each asset tag for the given plugin + */ +function getAssets(p, platform) { + return getAllElements(p, platform, 'asset'); +} +exports.getAssets = getAssets; +function getFilePath(config, plugin, path) { + if (path.startsWith('node_modules')) { + let pathSegments = path.split('/').slice(1); + if (pathSegments[0].startsWith('@')) { + pathSegments = [pathSegments[0] + '/' + pathSegments[1], ...pathSegments.slice(2)]; + } + const filePath = (0, node_1.resolveNode)(config.app.rootDir, ...pathSegments); + if (!filePath) { + throw new Error(`Can't resolve module ${pathSegments[0]}`); + } + return filePath; + } + return (0, path_1.join)(plugin.rootPath, path); +} +exports.getFilePath = getFilePath; +/** + * For a given plugin, return all the plugin.xml elements with elementName, checking root and specified platform + */ +function getAllElements(p, platform, elementName) { + let modules = []; + if (p.xml[elementName]) { + modules = modules.concat(p.xml[elementName]); + } + const platformModules = getPluginPlatform(p, platform); + if (platformModules === null || platformModules === void 0 ? void 0 : platformModules[elementName]) { + modules = modules.concat(platformModules[elementName]); + } + return modules; +} +exports.getAllElements = getAllElements; diff --git a/node_modules/@capacitor/cli/dist/sysconfig.js b/node_modules/@capacitor/cli/dist/sysconfig.js new file mode 100644 index 0000000..4862407 --- /dev/null +++ b/node_modules/@capacitor/cli/dist/sysconfig.js @@ -0,0 +1,35 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.writeConfig = exports.readConfig = void 0; +const tslib_1 = require("tslib"); +const debug_1 = tslib_1.__importDefault(require("debug")); +const fs_extra_1 = require("fs-extra"); +const path_1 = require("path"); +const cli_1 = require("./util/cli"); +const uuid_1 = require("./util/uuid"); +const debug = (0, debug_1.default)('capacitor:sysconfig'); +const SYSCONFIG_FILE = 'sysconfig.json'; +const SYSCONFIG_PATH = (0, path_1.resolve)(cli_1.ENV_PATHS.config, SYSCONFIG_FILE); +async function readConfig() { + debug('Reading from %O', SYSCONFIG_PATH); + try { + return await (0, fs_extra_1.readJSON)(SYSCONFIG_PATH); + } + catch (e) { + if (e.code !== 'ENOENT') { + throw e; + } + const sysconfig = { + machine: (0, uuid_1.uuidv4)(), + }; + await writeConfig(sysconfig); + return sysconfig; + } +} +exports.readConfig = readConfig; +async function writeConfig(sysconfig) { + debug('Writing to %O', SYSCONFIG_PATH); + await (0, fs_extra_1.mkdirp)((0, path_1.dirname)(SYSCONFIG_PATH)); + await (0, fs_extra_1.writeJSON)(SYSCONFIG_PATH, sysconfig, { spaces: '\t' }); +} +exports.writeConfig = writeConfig; diff --git a/node_modules/@capacitor/cli/dist/tasks/add.js b/node_modules/@capacitor/cli/dist/tasks/add.js new file mode 100644 index 0000000..43e3131 --- /dev/null +++ b/node_modules/@capacitor/cli/dist/tasks/add.js @@ -0,0 +1,115 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.addCommand = void 0; +const tslib_1 = require("tslib"); +const utils_terminal_1 = require("@ionic/utils-terminal"); +const fs_extra_1 = require("fs-extra"); +const add_1 = require("../android/add"); +const common_1 = require("../android/common"); +const colors_1 = tslib_1.__importDefault(require("../colors")); +const common_2 = require("../common"); +const errors_1 = require("../errors"); +const add_2 = require("../ios/add"); +const common_3 = require("../ios/common"); +const log_1 = require("../log"); +const sync_1 = require("./sync"); +async function addCommand(config, selectedPlatformName) { + var _a; + if (selectedPlatformName && !(await (0, common_2.isValidPlatform)(selectedPlatformName))) { + const platformDir = (0, common_2.resolvePlatform)(config, selectedPlatformName); + if (platformDir) { + await (0, common_2.runPlatformHook)(config, selectedPlatformName, platformDir, 'capacitor:add'); + } + else { + let msg = `Platform ${colors_1.default.input(selectedPlatformName)} not found.`; + if (await (0, common_2.isValidCommunityPlatform)(selectedPlatformName)) { + msg += `\nTry installing ${colors_1.default.strong(`@capacitor-community/${selectedPlatformName}`)} and adding the platform again.`; + } + if (await (0, common_2.isValidEnterprisePlatform)(selectedPlatformName)) { + msg += + `\nThis is an enterprise platform and @ionic-enterprise/capacitor-${selectedPlatformName} is not installed.\n` + + `To learn how to use this platform, visit https://ionic.io/docs/${selectedPlatformName}`; + } + log_1.logger.error(msg); + } + } + else { + const knownPlatforms = await (0, common_2.getKnownPlatforms)(); + const platformName = await (0, common_2.promptForPlatform)(knownPlatforms, `Please choose a platform to add:`, selectedPlatformName); + if (platformName === config.web.name) { + webWarning(); + return; + } + const existingPlatformDir = await (0, common_2.getProjectPlatformDirectory)(config, platformName); + if (existingPlatformDir) { + (0, errors_1.fatal)(`${colors_1.default.input(platformName)} platform already exists.\n` + + `To re-add this platform, first remove ${colors_1.default.strong((0, utils_terminal_1.prettyPath)(existingPlatformDir))}, then run this command again.\n` + + `${colors_1.default.strong('WARNING')}: Your native project will be completely removed.`); + } + try { + await (0, common_2.check)([() => (0, common_2.checkPackage)(), () => (0, common_2.checkAppConfig)(config), ...(await getAddChecks(config, platformName))]); + await doAdd(config, platformName); + await editPlatforms(config, platformName); + if (await (0, fs_extra_1.pathExists)(config.app.webDirAbs)) { + await (0, sync_1.sync)(config, platformName, false, false); + if (platformName === config.android.name) { + await (0, common_2.runTask)('Syncing Gradle', async () => { + return (0, add_1.createLocalProperties)(config.android.platformDirAbs); + }); + } + } + else { + log_1.logger.warn(`${colors_1.default.success(colors_1.default.strong('sync'))} could not run--missing ${colors_1.default.strong(config.app.webDir)} directory.`); + } + printNextSteps(platformName); + } + catch (e) { + if (!(0, errors_1.isFatal)(e)) { + (0, errors_1.fatal)((_a = e.stack) !== null && _a !== void 0 ? _a : e); + } + throw e; + } + } +} +exports.addCommand = addCommand; +function printNextSteps(platformName) { + (0, log_1.logSuccess)(`${colors_1.default.strong(platformName)} platform added!`); + log_1.output.write(`Follow the Developer Workflow guide to get building:\n${colors_1.default.strong(`https://capacitorjs.com/docs/basics/workflow`)}\n`); +} +async function getAddChecks(config, platformName) { + if (platformName === config.ios.name) { + return [() => (0, common_3.checkIOSPackage)(config), ...(await (0, common_3.getCommonChecks)(config))]; + } + else if (platformName === config.android.name) { + return [() => (0, common_1.checkAndroidPackage)(config)]; + } + else if (platformName === config.web.name) { + return []; + } + else { + throw `Platform ${platformName} is not valid.`; + } +} +async function doAdd(config, platformName) { + await (0, common_2.runTask)(colors_1.default.success(colors_1.default.strong('add')), async () => { + if (platformName === config.ios.name) { + await (0, add_2.addIOS)(config); + } + else if (platformName === config.android.name) { + await (0, add_1.addAndroid)(config); + } + }); +} +async function editPlatforms(config, platformName) { + if (platformName === config.ios.name) { + await (0, common_3.editProjectSettingsIOS)(config); + } + else if (platformName === config.android.name) { + await (0, common_1.editProjectSettingsAndroid)(config); + } +} +function webWarning() { + log_1.logger.error(`Not adding platform ${colors_1.default.strong('web')}.\n` + + `In Capacitor, the web platform is just your web app! For example, if you have a React or Angular project, the web platform is that project.\n` + + `To add Capacitor functionality to your web app, follow the Web Getting Started Guide: ${colors_1.default.strong('https://capacitorjs.com/docs/web')}`); +} diff --git a/node_modules/@capacitor/cli/dist/tasks/build.js b/node_modules/@capacitor/cli/dist/tasks/build.js new file mode 100644 index 0000000..71f2324 --- /dev/null +++ b/node_modules/@capacitor/cli/dist/tasks/build.js @@ -0,0 +1,63 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.build = exports.buildCommand = void 0; +const build_1 = require("../android/build"); +const common_1 = require("../common"); +const definitions_1 = require("../definitions"); +const errors_1 = require("../errors"); +const build_2 = require("../ios/build"); +async function buildCommand(config, selectedPlatformName, buildOptions) { + var _a; + const platforms = await (0, common_1.selectPlatforms)(config, selectedPlatformName); + let platformName; + if (platforms.length === 1) { + platformName = platforms[0]; + } + else { + platformName = await (0, common_1.promptForPlatform)(platforms.filter(createBuildablePlatformFilter(config)), `Please choose a platform to build for:`); + } + const buildCommandOptions = { + scheme: buildOptions.scheme || config.ios.scheme, + flavor: buildOptions.flavor || config.android.flavor, + keystorepath: buildOptions.keystorepath || config.android.buildOptions.keystorePath, + keystorepass: buildOptions.keystorepass || config.android.buildOptions.keystorePassword, + keystorealias: buildOptions.keystorealias || config.android.buildOptions.keystoreAlias, + keystorealiaspass: buildOptions.keystorealiaspass || config.android.buildOptions.keystoreAliasPassword, + androidreleasetype: buildOptions.androidreleasetype || config.android.buildOptions.releaseType || 'AAB', + signingtype: buildOptions.signingtype || config.android.buildOptions.signingType || 'jarsigner', + configuration: buildOptions.configuration || 'Release', + xcodeTeamId: buildOptions.xcodeTeamId || config.ios.buildOptions.teamId, + xcodeExportMethod: buildOptions.xcodeExportMethod || config.ios.buildOptions.exportMethod || definitions_1.XcodeExportMethod.AppStoreConnect, + xcodeSigningType: buildOptions.xcodeSigningType || config.ios.buildOptions.xcodeSigningStyle || 'automatic', + xcodeSigningCertificate: buildOptions.xcodeSigningCertificate || config.ios.buildOptions.signingCertificate, + xcodeProvisioningProfile: buildOptions.xcodeProvisioningProfile || config.ios.buildOptions.provisioningProfile, + }; + try { + await build(config, platformName, buildCommandOptions); + } + catch (e) { + if (!(0, errors_1.isFatal)(e)) { + (0, errors_1.fatal)((_a = e.stack) !== null && _a !== void 0 ? _a : e); + } + throw e; + } +} +exports.buildCommand = buildCommand; +async function build(config, platformName, buildOptions) { + if (platformName == config.ios.name) { + await (0, build_2.buildiOS)(config, buildOptions); + } + else if (platformName === config.android.name) { + await (0, build_1.buildAndroid)(config, buildOptions); + } + else if (platformName === config.web.name) { + throw `Platform "${platformName}" is not available in the build command.`; + } + else { + throw `Platform "${platformName}" is not valid.`; + } +} +exports.build = build; +function createBuildablePlatformFilter(config) { + return (platform) => platform === config.ios.name || platform === config.android.name; +} diff --git a/node_modules/@capacitor/cli/dist/tasks/config.js b/node_modules/@capacitor/cli/dist/tasks/config.js new file mode 100644 index 0000000..721463d --- /dev/null +++ b/node_modules/@capacitor/cli/dist/tasks/config.js @@ -0,0 +1,28 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.configCommand = void 0; +const tslib_1 = require("tslib"); +const util_1 = tslib_1.__importDefault(require("util")); +const log_1 = require("../log"); +async function configCommand(config, json) { + const evaluatedConfig = await deepAwait(config); + if (json) { + process.stdout.write(`${JSON.stringify(evaluatedConfig)}\n`); + } + else { + log_1.output.write(`${util_1.default.inspect(evaluatedConfig, { depth: Infinity, colors: true })}\n`); + } +} +exports.configCommand = configCommand; +async function deepAwait(obj) { + if (obj && !Array.isArray(obj) && typeof obj === 'object' && obj.constructor === Object) { + const o = {}; + for (const [k, v] of Object.entries(obj)) { + o[k] = await deepAwait(v); + } + return o; + } + else { + return await obj; + } +} diff --git a/node_modules/@capacitor/cli/dist/tasks/copy.js b/node_modules/@capacitor/cli/dist/tasks/copy.js new file mode 100644 index 0000000..46dfedb --- /dev/null +++ b/node_modules/@capacitor/cli/dist/tasks/copy.js @@ -0,0 +1,210 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.copy = exports.copyCommand = void 0; +const tslib_1 = require("tslib"); +const fs_extra_1 = require("fs-extra"); +const path_1 = require("path"); +const colors_1 = tslib_1.__importDefault(require("../colors")); +const common_1 = require("../common"); +const cordova_1 = require("../cordova"); +const errors_1 = require("../errors"); +const common_2 = require("../ios/common"); +const log_1 = require("../log"); +const plugin_1 = require("../plugin"); +const iosplugin_1 = require("../util/iosplugin"); +const promise_1 = require("../util/promise"); +const sourcemaps_1 = require("./sourcemaps"); +async function copyCommand(config, selectedPlatformName, inline = false) { + var _a; + if (selectedPlatformName && !(await (0, common_1.isValidPlatform)(selectedPlatformName))) { + const platformDir = (0, common_1.resolvePlatform)(config, selectedPlatformName); + if (platformDir) { + await (0, common_1.runPlatformHook)(config, selectedPlatformName, platformDir, 'capacitor:copy'); + } + else { + log_1.logger.error(`Platform ${colors_1.default.input(selectedPlatformName)} not found.`); + } + } + else { + const platforms = await (0, common_1.selectPlatforms)(config, selectedPlatformName); + try { + await (0, promise_1.allSerial)(platforms.map((platformName) => () => copy(config, platformName, inline))); + } + catch (e) { + if ((0, errors_1.isFatal)(e)) { + throw e; + } + log_1.logger.error((_a = e.stack) !== null && _a !== void 0 ? _a : e); + } + } +} +exports.copyCommand = copyCommand; +async function copy(config, platformName, inline = false) { + await (0, common_1.runTask)(colors_1.default.success(colors_1.default.strong(`copy ${platformName}`)), async () => { + var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v; + const result = await (0, common_1.checkWebDir)(config); + if (result) { + throw result; + } + await (0, common_1.runHooks)(config, platformName, config.app.rootDir, 'capacitor:copy:before'); + const allPlugins = await (0, plugin_1.getPlugins)(config, platformName); + let usesFederatedCapacitor = false; + if (allPlugins.filter((plugin) => plugin.id === '@ionic-enterprise/federated-capacitor').length > 0) { + usesFederatedCapacitor = true; + } + let usesLiveUpdates = false; + if (allPlugins.filter((plugin) => plugin.id === '@capacitor/live-updates').length > 0) { + usesLiveUpdates = true; + } + let usesSSLPinning = false; + if (allPlugins.filter((plugin) => plugin.id === '@ionic-enterprise/ssl-pinning' || plugin.id === '@capacitor/ssl-pinning').length > 0) { + usesSSLPinning = true; + } + if (platformName === config.ios.name) { + if (usesFederatedCapacitor) { + await copyFederatedWebDirs(config, await config.ios.webDirAbs); + if ((_c = (_b = (_a = config.app.extConfig) === null || _a === void 0 ? void 0 : _a.plugins) === null || _b === void 0 ? void 0 : _b.FederatedCapacitor) === null || _c === void 0 ? void 0 : _c.liveUpdatesKey) { + await copySecureLiveUpdatesKey(config.app.extConfig.plugins.FederatedCapacitor.liveUpdatesKey, config.app.rootDir, config.ios.nativeTargetDirAbs); + } + } + else { + await copyWebDir(config, await config.ios.webDirAbs, config.app.webDirAbs); + } + if (usesLiveUpdates && ((_f = (_e = (_d = config.app.extConfig) === null || _d === void 0 ? void 0 : _d.plugins) === null || _e === void 0 ? void 0 : _e.LiveUpdates) === null || _f === void 0 ? void 0 : _f.key)) { + await copySecureLiveUpdatesKey(config.app.extConfig.plugins.LiveUpdates.key, config.app.rootDir, config.ios.nativeTargetDirAbs); + } + if (usesSSLPinning && ((_j = (_h = (_g = config.app.extConfig) === null || _g === void 0 ? void 0 : _g.plugins) === null || _h === void 0 ? void 0 : _h.SSLPinning) === null || _j === void 0 ? void 0 : _j.certs)) { + await copySSLCert((_k = config.app.extConfig.plugins.SSLPinning) === null || _k === void 0 ? void 0 : _k.certs, config.app.rootDir, await config.ios.webDirAbs); + } + await copyCapacitorConfig(config, config.ios.nativeTargetDirAbs); + const cordovaPlugins = await (0, cordova_1.getCordovaPlugins)(config, platformName); + await (0, cordova_1.handleCordovaPluginsJS)(cordovaPlugins, config, platformName); + const iosPlugins = await (0, common_2.getIOSPlugins)(allPlugins); + await (0, iosplugin_1.generateIOSPackageJSON)(config, iosPlugins); + } + else if (platformName === config.android.name) { + if (usesFederatedCapacitor) { + await copyFederatedWebDirs(config, config.android.webDirAbs); + if ((_o = (_m = (_l = config.app.extConfig) === null || _l === void 0 ? void 0 : _l.plugins) === null || _m === void 0 ? void 0 : _m.FederatedCapacitor) === null || _o === void 0 ? void 0 : _o.liveUpdatesKey) { + await copySecureLiveUpdatesKey(config.app.extConfig.plugins.FederatedCapacitor.liveUpdatesKey, config.app.rootDir, config.android.assetsDirAbs); + } + } + else { + await copyWebDir(config, config.android.webDirAbs, config.app.webDirAbs); + } + if (usesLiveUpdates && ((_r = (_q = (_p = config.app.extConfig) === null || _p === void 0 ? void 0 : _p.plugins) === null || _q === void 0 ? void 0 : _q.LiveUpdates) === null || _r === void 0 ? void 0 : _r.key)) { + await copySecureLiveUpdatesKey(config.app.extConfig.plugins.LiveUpdates.key, config.app.rootDir, config.android.assetsDirAbs); + } + if (usesSSLPinning && ((_u = (_t = (_s = config.app.extConfig) === null || _s === void 0 ? void 0 : _s.plugins) === null || _t === void 0 ? void 0 : _t.SSLPinning) === null || _u === void 0 ? void 0 : _u.certs)) { + await copySSLCert((_v = config.app.extConfig.plugins.SSLPinning) === null || _v === void 0 ? void 0 : _v.certs, config.app.rootDir, config.android.assetsDirAbs); + } + await copyCapacitorConfig(config, config.android.assetsDirAbs); + const cordovaPlugins = await (0, cordova_1.getCordovaPlugins)(config, platformName); + await (0, cordova_1.handleCordovaPluginsJS)(cordovaPlugins, config, platformName); + await (0, cordova_1.writeCordovaAndroidManifest)(cordovaPlugins, config, platformName); + } + else if (platformName === config.web.name) { + if (usesFederatedCapacitor) { + log_1.logger.info('FederatedCapacitor Plugin installed, skipping web bundling...'); + } + } + else { + throw `Platform ${platformName} is not valid.`; + } + if (inline) { + await (0, sourcemaps_1.inlineSourceMaps)(config, platformName); + } + }); + await (0, common_1.runHooks)(config, platformName, config.app.rootDir, 'capacitor:copy:after'); +} +exports.copy = copy; +async function copyCapacitorConfig(config, nativeAbsDir) { + const nativeRelDir = (0, path_1.relative)(config.app.rootDir, nativeAbsDir); + const nativeConfigFile = 'capacitor.config.json'; + const nativeConfigFilePath = (0, path_1.join)(nativeAbsDir, nativeConfigFile); + await (0, common_1.runTask)(`Creating ${colors_1.default.strong(nativeConfigFile)} in ${nativeRelDir}`, async () => { + var _a, _b; + (_a = config.app.extConfig.android) === null || _a === void 0 ? true : delete _a.buildOptions; + (_b = config.app.extConfig.ios) === null || _b === void 0 ? true : delete _b.buildOptions; + await (0, fs_extra_1.writeJSON)(nativeConfigFilePath, config.app.extConfig, { + spaces: '\t', + }); + }); +} +async function copyWebDir(config, nativeAbsDir, webAbsDir) { + var _a; + const webRelDir = (0, path_1.basename)(webAbsDir); + const nativeRelDir = (0, path_1.relative)(config.app.rootDir, nativeAbsDir); + if (((_a = config.app.extConfig.server) === null || _a === void 0 ? void 0 : _a.url) && !(await (0, fs_extra_1.pathExists)(webAbsDir))) { + log_1.logger.warn(`Cannot copy web assets from ${colors_1.default.strong(webRelDir)} to ${nativeRelDir}\n` + + `Web asset directory specified by ${colors_1.default.input('webDir')} does not exist. This is not an error because ${colors_1.default.input('server.url')} is set in config.`); + return; + } + await (0, common_1.runTask)(`Copying web assets from ${colors_1.default.strong(webRelDir)} to ${nativeRelDir}`, async () => { + await (0, fs_extra_1.remove)(nativeAbsDir); + return (0, fs_extra_1.copy)(webAbsDir, nativeAbsDir); + }); +} +async function copyFederatedWebDirs(config, nativeAbsDir) { + var _a, _b; + log_1.logger.info('FederatedCapacitor Plugin Loaded - Copying Web Assets'); + if (!((_b = (_a = config.app.extConfig) === null || _a === void 0 ? void 0 : _a.plugins) === null || _b === void 0 ? void 0 : _b.FederatedCapacitor)) { + throw `FederatedCapacitor plugin is present but no valid config is defined.`; + } + const federatedConfig = config.app.extConfig.plugins.FederatedCapacitor; + if (federatedConfig) { + if (federatedConfig.shell.name === undefined) { + throw `FederatedCapacitor plugin is present but no valid Shell application is defined in the config.`; + } + if (!federatedConfig.apps.every(isFederatedApp)) { + throw `FederatedCapacitor plugin is present but there is a problem with the apps defined in the config.`; + } + const copyApps = () => { + return federatedConfig.apps.map((app) => { + const appDir = (0, path_1.resolve)(config.app.rootDir, app.webDir); + return copyWebDir(config, (0, path_1.resolve)(nativeAbsDir, app.name), appDir); + }); + }; + const copyShell = () => { + return copyWebDir(config, (0, path_1.resolve)(nativeAbsDir, federatedConfig.shell.name), config.app.webDirAbs); + }; + await Promise.all([...copyApps(), copyShell()]); + } +} +function isFederatedApp(config) { + return config.webDir !== undefined && config.name !== undefined; +} +async function copySecureLiveUpdatesKey(secureLiveUpdatesKeyFile, rootDir, nativeAbsDir) { + const keyAbsFromPath = (0, path_1.join)(rootDir, secureLiveUpdatesKeyFile); + const keyAbsToPath = (0, path_1.join)(nativeAbsDir, (0, path_1.basename)(keyAbsFromPath)); + const keyRelToDir = (0, path_1.relative)(rootDir, nativeAbsDir); + if (!(await (0, fs_extra_1.pathExists)(keyAbsFromPath))) { + log_1.logger.warn(`Cannot copy Secure Live Updates signature file from ${colors_1.default.strong(keyAbsFromPath)} to ${keyRelToDir}\n` + + `Signature file does not exist at specified key path.`); + return; + } + await (0, common_1.runTask)(`Copying Secure Live Updates key from ${colors_1.default.strong(secureLiveUpdatesKeyFile)} to ${keyRelToDir}`, async () => { + return (0, fs_extra_1.copy)(keyAbsFromPath, keyAbsToPath); + }); +} +async function copySSLCert(sslCertPaths, rootDir, targetDir) { + const validCertPaths = []; + for (const sslCertPath of sslCertPaths) { + const certAbsFromPath = (0, path_1.join)(rootDir, sslCertPath); + if (!(await (0, fs_extra_1.pathExists)(certAbsFromPath))) { + log_1.logger.warn(`Cannot copy SSL Certificate file from ${colors_1.default.strong(certAbsFromPath)}\n` + + `SSL Certificate does not exist at specified path.`); + return; + } + validCertPaths.push(certAbsFromPath); + } + const certsDirAbsToPath = (0, path_1.join)(targetDir, 'certs'); + const certsDirRelToDir = (0, path_1.relative)(rootDir, targetDir); + await (0, common_1.runTask)(`Copying SSL Certificates from to ${certsDirRelToDir}`, async () => { + const promises = []; + for (const certPath of validCertPaths) { + promises.push((0, fs_extra_1.copy)(certPath, (0, path_1.join)(certsDirAbsToPath, (0, path_1.basename)(certPath)))); + } + return Promise.all(promises); + }); +} diff --git a/node_modules/@capacitor/cli/dist/tasks/create.js b/node_modules/@capacitor/cli/dist/tasks/create.js new file mode 100644 index 0000000..76c28d3 --- /dev/null +++ b/node_modules/@capacitor/cli/dist/tasks/create.js @@ -0,0 +1,10 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.createCommand = void 0; +const tslib_1 = require("tslib"); +const colors_1 = tslib_1.__importDefault(require("../colors")); +const errors_1 = require("../errors"); +async function createCommand() { + (0, errors_1.fatal)(`The create command has been removed.\n` + `Use ${colors_1.default.input('npm init @capacitor/app')}`); +} +exports.createCommand = createCommand; diff --git a/node_modules/@capacitor/cli/dist/tasks/doctor.js b/node_modules/@capacitor/cli/dist/tasks/doctor.js new file mode 100644 index 0000000..7065343 --- /dev/null +++ b/node_modules/@capacitor/cli/dist/tasks/doctor.js @@ -0,0 +1,68 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.doctor = exports.doctorCore = exports.doctorCommand = void 0; +const tslib_1 = require("tslib"); +const fs_extra_1 = require("fs-extra"); +const doctor_1 = require("../android/doctor"); +const colors_1 = tslib_1.__importDefault(require("../colors")); +const common_1 = require("../common"); +const doctor_2 = require("../ios/doctor"); +const log_1 = require("../log"); +const emoji_1 = require("../util/emoji"); +const node_1 = require("../util/node"); +const subprocess_1 = require("../util/subprocess"); +async function doctorCommand(config, selectedPlatformName) { + log_1.output.write(`${(0, emoji_1.emoji)('💊', '')} ${colors_1.default.strong('Capacitor Doctor')} ${(0, emoji_1.emoji)('💊', '')} \n\n`); + await doctorCore(config); + const platforms = await (0, common_1.selectPlatforms)(config, selectedPlatformName); + await Promise.all(platforms.map((platformName) => { + return doctor(config, platformName); + })); +} +exports.doctorCommand = doctorCommand; +async function doctorCore(config) { + const [cliVersion, coreVersion, androidVersion, iosVersion] = await Promise.all([ + (0, subprocess_1.getCommandOutput)('npm', ['info', '@capacitor/cli', 'version']), + (0, subprocess_1.getCommandOutput)('npm', ['info', '@capacitor/core', 'version']), + (0, subprocess_1.getCommandOutput)('npm', ['info', '@capacitor/android', 'version']), + (0, subprocess_1.getCommandOutput)('npm', ['info', '@capacitor/ios', 'version']), + ]); + log_1.output.write(`${colors_1.default.strong('Latest Dependencies:')}\n\n` + + ` @capacitor/cli: ${colors_1.default.weak(cliVersion !== null && cliVersion !== void 0 ? cliVersion : 'unknown')}\n` + + ` @capacitor/core: ${colors_1.default.weak(coreVersion !== null && coreVersion !== void 0 ? coreVersion : 'unknown')}\n` + + ` @capacitor/android: ${colors_1.default.weak(androidVersion !== null && androidVersion !== void 0 ? androidVersion : 'unknown')}\n` + + ` @capacitor/ios: ${colors_1.default.weak(iosVersion !== null && iosVersion !== void 0 ? iosVersion : 'unknown')}\n\n` + + `${colors_1.default.strong('Installed Dependencies:')}\n\n`); + await printInstalledPackages(config); + log_1.output.write('\n'); +} +exports.doctorCore = doctorCore; +async function printInstalledPackages(config) { + const packageNames = ['@capacitor/cli', '@capacitor/core', '@capacitor/android', '@capacitor/ios']; + await Promise.all(packageNames.map(async (packageName) => { + const packagePath = (0, node_1.resolveNode)(config.app.rootDir, packageName, 'package.json'); + await printPackageVersion(packageName, packagePath); + })); +} +async function printPackageVersion(packageName, packagePath) { + let version; + if (packagePath) { + version = (await (0, fs_extra_1.readJSON)(packagePath)).version; + } + log_1.output.write(` ${packageName}: ${colors_1.default.weak(version || 'not installed')}\n`); +} +async function doctor(config, platformName) { + if (platformName === config.ios.name) { + await (0, doctor_2.doctorIOS)(config); + } + else if (platformName === config.android.name) { + await (0, doctor_1.doctorAndroid)(config); + } + else if (platformName === config.web.name) { + return Promise.resolve(); + } + else { + throw `Platform ${platformName} is not valid.`; + } +} +exports.doctor = doctor; diff --git a/node_modules/@capacitor/cli/dist/tasks/init.js b/node_modules/@capacitor/cli/dist/tasks/init.js new file mode 100644 index 0000000..159b88b --- /dev/null +++ b/node_modules/@capacitor/cli/dist/tasks/init.js @@ -0,0 +1,138 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.initCommand = void 0; +const tslib_1 = require("tslib"); +const open_1 = tslib_1.__importDefault(require("open")); +const path_1 = require("path"); +const colors_1 = tslib_1.__importDefault(require("../colors")); +const common_1 = require("../common"); +const config_1 = require("../config"); +const cordova_1 = require("../cordova"); +const errors_1 = require("../errors"); +const framework_configs_1 = require("../framework-configs"); +const log_1 = require("../log"); +const sysconfig_1 = require("../sysconfig"); +const node_1 = require("../util/node"); +const term_1 = require("../util/term"); +async function initCommand(config, name, id, webDirFromCLI, skipAppIDValidation) { + var _a, _b; + try { + if (!(0, term_1.checkInteractive)(name, id)) { + return; + } + if (config.app.extConfigType !== 'json') { + (0, errors_1.fatal)(`Cannot run ${colors_1.default.input('init')} for a project using a non-JSON configuration file.\n` + + `Delete ${colors_1.default.strong(config.app.extConfigName)} and try again.`); + } + const isNewConfig = Object.keys(config.app.extConfig).length === 0; + const tsInstalled = !!(0, node_1.resolveNode)(config.app.rootDir, 'typescript'); + const appName = await getName(config, name); + const appId = await getAppId(config, id); + const webDir = (0, term_1.isInteractive)() + ? await getWebDir(config, webDirFromCLI) + : ((_a = webDirFromCLI !== null && webDirFromCLI !== void 0 ? webDirFromCLI : config.app.extConfig.webDir) !== null && _a !== void 0 ? _a : 'www'); + if (skipAppIDValidation === true) { + await (0, common_1.check)([() => (0, common_1.checkAppName)(config, appName)]); + } + else { + await (0, common_1.check)([() => (0, common_1.checkAppName)(config, appName), () => (0, common_1.checkAppId)(config, appId)]); + } + const cordova = await (0, cordova_1.getCordovaPreferences)(config); + await runMergeConfig(config, { + appId, + appName, + webDir, + cordova, + }, isNewConfig && tsInstalled ? 'ts' : 'json'); + } + catch (e) { + if (!(0, errors_1.isFatal)(e)) { + log_1.output.write('Usage: npx cap init appName appId\n' + 'Example: npx cap init "My App" "com.example.myapp"\n\n'); + (0, errors_1.fatal)((_b = e.stack) !== null && _b !== void 0 ? _b : e); + } + throw e; + } +} +exports.initCommand = initCommand; +async function getName(config, name) { + var _a; + if (!name) { + const answers = await (0, log_1.logPrompt)(`${colors_1.default.strong(`What is the name of your app?`)}\n` + + `This should be a human-friendly app name, like what you'd see in the App Store.`, { + type: 'text', + name: 'name', + message: `Name`, + initial: config.app.appName ? config.app.appName : ((_a = config.app.package.name) !== null && _a !== void 0 ? _a : 'App'), + }); + return answers.name; + } + return name; +} +async function getAppId(config, id) { + if (!id) { + const answers = await (0, log_1.logPrompt)(`${colors_1.default.strong(`What should be the Package ID for your app?`)}\n` + + `Package IDs (aka Bundle ID in iOS and Application ID in Android) are unique identifiers for apps. They must be in reverse domain name notation, generally representing a domain name that you or your company owns.`, { + type: 'text', + name: 'id', + message: `Package ID`, + initial: config.app.appId ? config.app.appId : 'com.example.app', + }); + return answers.id; + } + return id; +} +async function getWebDir(config, webDir) { + if (!webDir) { + const framework = (0, framework_configs_1.detectFramework)(config); + if (framework === null || framework === void 0 ? void 0 : framework.webDir) { + return framework.webDir; + } + const answers = await (0, log_1.logPrompt)(`${colors_1.default.strong(`What is the web asset directory for your app?`)}\n` + + `This directory should contain the final ${colors_1.default.strong('index.html')} of your app.`, { + type: 'text', + name: 'webDir', + message: `Web asset directory`, + initial: config.app.webDir ? config.app.webDir : 'www', + }); + return answers.webDir; + } + return webDir; +} +async function runMergeConfig(config, extConfig, type) { + const configDirectory = (0, path_1.dirname)(config.app.extConfigFilePath); + const newConfigPath = (0, path_1.resolve)(configDirectory, type === 'ts' ? config_1.CONFIG_FILE_NAME_TS : config_1.CONFIG_FILE_NAME_JSON); + await (0, common_1.runTask)(`Creating ${colors_1.default.strong((0, path_1.basename)(newConfigPath))} in ${colors_1.default.input(config.app.rootDir)}`, async () => { + await mergeConfig(config, extConfig, newConfigPath); + }); + printNextSteps((0, path_1.basename)(newConfigPath)); + if ((0, term_1.isInteractive)()) { + let sysconfig = await (0, sysconfig_1.readConfig)(); + if (typeof sysconfig.signup === 'undefined') { + const signup = await promptToSignup(); + sysconfig = { ...sysconfig, signup }; + await (0, sysconfig_1.writeConfig)(sysconfig); + } + } +} +async function mergeConfig(config, extConfig, newConfigPath) { + const oldConfig = { ...config.app.extConfig }; + const newConfig = { ...oldConfig, ...extConfig }; + await (0, config_1.writeConfig)(newConfig, newConfigPath); +} +function printNextSteps(newConfigName) { + (0, log_1.logSuccess)(`${colors_1.default.strong(newConfigName)} created!`); + log_1.output.write(`\nNext steps: \n${colors_1.default.strong(`https://capacitorjs.com/docs/getting-started#where-to-go-next`)}\n`); +} +async function promptToSignup() { + const answers = await (0, log_1.logPrompt)(`Join the Ionic Community! 💙\n` + + `Connect with millions of developers on the Ionic Forum and get access to live events, news updates, and more.`, { + type: 'confirm', + name: 'create', + message: `Create free Ionic account?`, + initial: true, + }); + if (answers.create) { + (0, open_1.default)(`http://ionicframework.com/signup?source=capacitor`); + } + return answers.create; +} diff --git a/node_modules/@capacitor/cli/dist/tasks/list.js b/node_modules/@capacitor/cli/dist/tasks/list.js new file mode 100644 index 0000000..6ff8da1 --- /dev/null +++ b/node_modules/@capacitor/cli/dist/tasks/list.js @@ -0,0 +1,50 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.list = exports.listCommand = void 0; +const tslib_1 = require("tslib"); +const common_1 = require("../android/common"); +const colors_1 = tslib_1.__importDefault(require("../colors")); +const common_2 = require("../common"); +const errors_1 = require("../errors"); +const common_3 = require("../ios/common"); +const log_1 = require("../log"); +const plugin_1 = require("../plugin"); +const promise_1 = require("../util/promise"); +async function listCommand(config, selectedPlatformName) { + var _a; + const platforms = await (0, common_2.selectPlatforms)(config, selectedPlatformName); + try { + await (0, promise_1.allSerial)(platforms.map((platformName) => () => list(config, platformName))); + } + catch (e) { + if ((0, errors_1.isFatal)(e)) { + throw e; + } + log_1.logger.error((_a = e.stack) !== null && _a !== void 0 ? _a : e); + } +} +exports.listCommand = listCommand; +async function list(config, platform) { + const allPlugins = await (0, plugin_1.getPlugins)(config, platform); + let plugins = []; + if (platform === config.ios.name) { + plugins = await (0, common_3.getIOSPlugins)(allPlugins); + } + else if (platform === config.android.name) { + plugins = await (0, common_1.getAndroidPlugins)(allPlugins); + } + else if (platform === config.web.name) { + log_1.logger.info(`Listing plugins for ${colors_1.default.input(platform)} is not possible.`); + return; + } + else { + throw `Platform ${colors_1.default.input(platform)} is not valid.`; + } + const capacitorPlugins = plugins.filter((p) => (0, plugin_1.getPluginType)(p, platform) === 0 /* PluginType.Core */); + (0, plugin_1.printPlugins)(capacitorPlugins, platform); + const cordovaPlugins = plugins.filter((p) => (0, plugin_1.getPluginType)(p, platform) === 1 /* PluginType.Cordova */); + (0, plugin_1.printPlugins)(cordovaPlugins, platform, 'cordova'); + const incompatibleCordovaPlugins = plugins.filter((p) => (0, plugin_1.getPluginType)(p, platform) === 2 /* PluginType.Incompatible */); + (0, plugin_1.printPlugins)(incompatibleCordovaPlugins, platform, 'incompatible'); +} +exports.list = list; diff --git a/node_modules/@capacitor/cli/dist/tasks/migrate-spm.js b/node_modules/@capacitor/cli/dist/tasks/migrate-spm.js new file mode 100644 index 0000000..9ece859 --- /dev/null +++ b/node_modules/@capacitor/cli/dist/tasks/migrate-spm.js @@ -0,0 +1,24 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.migrateToSPM = void 0; +const common_1 = require("../common"); +const errors_1 = require("../errors"); +const common_2 = require("../ios/common"); +const log_1 = require("../log"); +const spm_1 = require("../util/spm"); +const update_1 = require("./update"); +async function migrateToSPM(config) { + if ((await config.ios.packageManager) == 'SPM') { + (0, errors_1.fatal)('Capacitor project is already using SPM, exiting.'); + } + await (0, common_1.check)(await (0, common_2.getCommonChecks)(config)); + await (0, spm_1.extractSPMPackageDirectory)(config); + await (0, spm_1.runCocoapodsDeintegrate)(config); + await (0, spm_1.removeCocoapodsFiles)(config); + await (0, spm_1.addInfoPlistDebugIfNeeded)(config); + const configWritable = config; + configWritable.ios.packageManager = Promise.resolve('SPM'); + await (0, update_1.update)(configWritable, 'ios', false); + log_1.logger.info('To complete migration follow the manual steps at https://capacitorjs.com/docs/ios/spm#using-our-migration-tool'); +} +exports.migrateToSPM = migrateToSPM; diff --git a/node_modules/@capacitor/cli/dist/tasks/migrate.js b/node_modules/@capacitor/cli/dist/tasks/migrate.js new file mode 100644 index 0000000..b8798aa --- /dev/null +++ b/node_modules/@capacitor/cli/dist/tasks/migrate.js @@ -0,0 +1,519 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.setAllStringIn = exports.migrateCommand = void 0; +const tslib_1 = require("tslib"); +const fs_extra_1 = require("fs-extra"); +const path_1 = require("path"); +const rimraf_1 = require("rimraf"); +const semver_1 = require("semver"); +const colors_1 = tslib_1.__importDefault(require("../colors")); +const common_1 = require("../common"); +const errors_1 = require("../errors"); +const common_2 = require("../ios/common"); +const log_1 = require("../log"); +const fs_1 = require("../util/fs"); +const subprocess_1 = require("../util/subprocess"); +const template_1 = require("../util/template"); +// eslint-disable-next-line prefer-const +let allDependencies = {}; +const libs = ['@capacitor/core', '@capacitor/cli', '@capacitor/ios', '@capacitor/android']; +const plugins = [ + '@capacitor/action-sheet', + '@capacitor/app', + '@capacitor/app-launcher', + '@capacitor/browser', + '@capacitor/camera', + '@capacitor/clipboard', + '@capacitor/device', + '@capacitor/dialog', + '@capacitor/filesystem', + '@capacitor/geolocation', + '@capacitor/google-maps', + '@capacitor/haptics', + '@capacitor/keyboard', + '@capacitor/local-notifications', + '@capacitor/motion', + '@capacitor/network', + '@capacitor/preferences', + '@capacitor/push-notifications', + '@capacitor/screen-orientation', + '@capacitor/screen-reader', + '@capacitor/share', + '@capacitor/splash-screen', + '@capacitor/status-bar', + '@capacitor/text-zoom', + '@capacitor/toast', +]; +const coreVersion = '^8.0.0'; +const pluginVersion = '^8.0.0'; +const gradleVersion = '8.14.3'; +const iOSVersion = '15'; +const kotlinVersion = '2.2.20'; +let installFailed = false; +async function migrateCommand(config, noprompt, packagemanager) { + if (config === null) { + (0, errors_1.fatal)('Config data missing'); + } + const capMajor = await checkCapacitorMajorVersion(config); + if (capMajor < 7) { + (0, errors_1.fatal)('Migrate can only be used on Capacitor 7, please use the CLI in Capacitor 7 to upgrade to 7 first'); + } + const jdkMajor = await (0, common_1.checkJDKMajorVersion)(); + if (jdkMajor < 21) { + log_1.logger.warn('Capacitor 8 requires JDK 21 or higher. Some steps may fail.'); + } + const variablesAndClasspaths = await getAndroidVariablesAndClasspaths(config); + if (!variablesAndClasspaths) { + (0, errors_1.fatal)('Variable and Classpath info could not be read.'); + } + allDependencies = { + ...config.app.package.dependencies, + ...config.app.package.devDependencies, + }; + const monorepoWarning = 'Please note this tool is not intended for use in a mono-repo environment, you should migrate manually instead. Refer to https://capacitorjs.com/docs/next/updating/8-0'; + log_1.logger.info(monorepoWarning); + const { migrateconfirm } = noprompt + ? { migrateconfirm: 'y' } + : await (0, log_1.logPrompt)(`Capacitor 8 sets a deployment target of iOS ${iOSVersion} and Android 16 (SDK 36). \n`, { + type: 'text', + name: 'migrateconfirm', + message: `Are you sure you want to migrate? (Y/n)`, + initial: 'y', + }); + if (typeof migrateconfirm === 'string' && migrateconfirm.toLowerCase() === 'y') { + try { + const { depInstallConfirm } = noprompt + ? { depInstallConfirm: 'y' } + : await (0, log_1.logPrompt)(`Would you like the migrator to run npm, yarn, pnpm, or bun install to install the latest versions of capacitor packages? (Those using other package managers should answer N)`, { + type: 'text', + name: 'depInstallConfirm', + message: `Run Dependency Install? (Y/n)`, + initial: 'y', + }); + const runNpmInstall = typeof depInstallConfirm === 'string' && depInstallConfirm.toLowerCase() === 'y'; + let installerType = 'npm'; + if (runNpmInstall) { + const { manager } = packagemanager + ? { manager: packagemanager } + : await (0, log_1.logPrompt)('What dependency manager do you use?', { + type: 'select', + name: 'manager', + message: `Dependency Management Tool`, + choices: [ + { title: 'NPM', value: 'npm' }, + { title: 'Yarn', value: 'yarn' }, + { title: 'PNPM', value: 'pnpm' }, + { title: 'Bun', value: 'bun' }, + ], + initial: 0, + }); + installerType = manager; + } + try { + await (0, common_1.runTask)(`Installing Latest Modules using ${installerType}.`, () => { + return installLatestLibs(installerType, runNpmInstall, config); + }); + } + catch (ex) { + log_1.logger.error(`${installerType} install failed. Try deleting node_modules folder and running ${colors_1.default.input(`${installerType} install --force`)} manually.`); + installFailed = true; + } + // Update iOS Projects + if (allDependencies['@capacitor/ios'] && (0, fs_extra_1.existsSync)(config.ios.platformDirAbs)) { + const currentiOSVersion = (0, common_2.getMajoriOSVersion)(config); + if (parseInt(currentiOSVersion) < parseInt(iOSVersion)) { + // ios template changes + await (0, common_1.runTask)(`Migrating deployment target to ${iOSVersion}.0.`, () => { + return updateFile(config, (0, path_1.join)(config.ios.nativeXcodeProjDirAbs, 'project.pbxproj'), 'IPHONEOS_DEPLOYMENT_TARGET = ', ';', `${iOSVersion}.0`); + }); + if ((await config.ios.packageManager) !== 'SPM') { + // Update Podfile + await (0, common_1.runTask)(`Migrating Podfile to ${iOSVersion}.0.`, () => { + return updateFile(config, (0, path_1.join)(config.ios.nativeProjectDirAbs, 'Podfile'), `platform :ios, '`, `'`, `${iOSVersion}.0`); + }); + } + } + else { + log_1.logger.warn('Skipped updating deployment target'); + } + } + if (!installFailed) { + await (0, common_1.runTask)(`Running cap sync.`, () => { + return (0, subprocess_1.runCommand)('npx', ['cap', 'sync']); + }); + } + else { + log_1.logger.warn('Skipped Running cap sync.'); + } + if (allDependencies['@capacitor/android'] && (0, fs_extra_1.existsSync)(config.android.platformDirAbs)) { + // AndroidManifest.xml add "density" + await (0, common_1.runTask)(`Migrating AndroidManifest.xml by adding density to Activity configChanges.`, () => { + return updateAndroidManifest((0, path_1.join)(config.android.srcMainDirAbs, 'AndroidManifest.xml')); + }); + const gradleWrapperVersion = getGradleWrapperVersion((0, path_1.join)(config.android.platformDirAbs, 'gradle', 'wrapper', 'gradle-wrapper.properties')); + if (!installFailed && (0, semver_1.gte)(gradleVersion, gradleWrapperVersion)) { + try { + await (0, common_1.runTask)(`Upgrading gradle wrapper`, () => { + return updateGradleWrapperFiles(config.android.platformDirAbs); + }); + // Run twice as first time it only updates the wrapper properties file + await (0, common_1.runTask)(`Upgrading gradle wrapper files`, () => { + return updateGradleWrapperFiles(config.android.platformDirAbs); + }); + } + catch (e) { + if (e.includes('EACCES')) { + log_1.logger.error(`gradlew file does not have executable permissions. This can happen if the Android platform was added on a Windows machine. Please run ${colors_1.default.input(`chmod +x ./${config.android.platformDir}/gradlew`)} and ${colors_1.default.input(`cd ${config.android.platformDir} && ./gradlew wrapper --distribution-type all --gradle-version ${gradleVersion} --warning-mode all`)} to update the files manually`); + } + else { + log_1.logger.error(`gradle wrapper files were not updated`); + } + } + } + else { + log_1.logger.warn('Skipped upgrading gradle wrapper files'); + } + await (0, common_1.runTask)(`Migrating root build.gradle file.`, () => { + return updateBuildGradle((0, path_1.join)(config.android.platformDirAbs, 'build.gradle'), variablesAndClasspaths); + }); + await (0, common_1.runTask)(`Migrating app build.gradle file.`, () => { + return updateAppBuildGradle((0, path_1.join)(config.android.appDirAbs, 'build.gradle')); + }); + // Variables gradle + await (0, common_1.runTask)(`Migrating variables.gradle file.`, () => { + return (async () => { + const variablesPath = (0, path_1.join)(config.android.platformDirAbs, 'variables.gradle'); + let txt = readFile(variablesPath); + if (!txt) { + return; + } + txt = txt.replace(/= {2}'/g, `= '`); + (0, fs_extra_1.writeFileSync)(variablesPath, txt, { encoding: 'utf-8' }); + for (const variable of Object.keys(variablesAndClasspaths.variables)) { + let replaceStart = `${variable} = '`; + let replaceEnd = `'\n`; + if (typeof variablesAndClasspaths.variables[variable] === 'number') { + replaceStart = `${variable} = `; + replaceEnd = `\n`; + } + if (txt.includes(replaceStart)) { + const first = txt.indexOf(replaceStart) + replaceStart.length; + const value = txt.substring(first, txt.indexOf(replaceEnd, first)); + if ((typeof variablesAndClasspaths.variables[variable] === 'number' && + value <= variablesAndClasspaths.variables[variable]) || + (typeof variablesAndClasspaths.variables[variable] === 'string' && + (0, semver_1.lt)(value, variablesAndClasspaths.variables[variable]))) { + await updateFile(config, variablesPath, replaceStart, replaceEnd, variablesAndClasspaths.variables[variable].toString(), true); + } + } + else { + let file = readFile(variablesPath); + if (file) { + file = file.replace('}', ` ${replaceStart}${variablesAndClasspaths.variables[variable].toString()}${replaceEnd}}`); + (0, fs_extra_1.writeFileSync)(variablesPath, file); + } + } + } + const pluginVariables = { + firebaseMessagingVersion: '25.0.1', + playServicesLocationVersion: '21.3.0', + androidxBrowserVersion: '1.9.0', + androidxMaterialVersion: '1.13.0', + androidxExifInterfaceVersion: '1.4.1', + androidxCoreKTXVersion: '1.17.0', + googleMapsPlayServicesVersion: '19.2.0', + googleMapsUtilsVersion: '3.19.1', + googleMapsKtxVersion: '5.2.1', + googleMapsUtilsKtxVersion: '5.2.1', + kotlinxCoroutinesVersion: '1.10.2', + coreSplashScreenVersion: '1.2.0', + }; + for (const variable of Object.keys(pluginVariables)) { + await updateFile(config, variablesPath, `${variable} = '`, `'`, pluginVariables[variable], true); + } + })(); + }); + rimraf_1.rimraf.sync((0, path_1.join)(config.android.appDirAbs, 'build')); + } + // Write all breaking changes + await (0, common_1.runTask)(`Writing breaking changes.`, () => { + return writeBreakingChanges(); + }); + if (!installFailed) { + (0, log_1.logSuccess)(`Migration to Capacitor ${coreVersion} is complete. Run and test your app!`); + } + else { + log_1.logger.warn(`Migration to Capacitor ${coreVersion} is incomplete. Check the log messages for more information.`); + } + } + catch (err) { + (0, errors_1.fatal)(`Failed to migrate: ${err}`); + } + } + else { + (0, errors_1.fatal)(`User canceled migration.`); + } +} +exports.migrateCommand = migrateCommand; +async function checkCapacitorMajorVersion(config) { + var _a; + const capacitorVersion = await (0, common_1.getCoreVersion)(config); + const versionArray = (_a = capacitorVersion.match(/([0-9]+)\.([0-9]+)\.([0-9]+)/)) !== null && _a !== void 0 ? _a : []; + const majorVersion = parseInt(versionArray[1]); + return majorVersion; +} +async function installLatestLibs(dependencyManager, runInstall, config) { + const pkgJsonPath = (0, path_1.join)(config.app.rootDir, 'package.json'); + const pkgJsonFile = readFile(pkgJsonPath); + if (!pkgJsonFile) { + return; + } + const pkgJson = JSON.parse(pkgJsonFile); + for (const devDepKey of Object.keys(pkgJson['devDependencies'] || {})) { + if (libs.includes(devDepKey)) { + pkgJson['devDependencies'][devDepKey] = coreVersion; + } + else if (plugins.includes(devDepKey)) { + pkgJson['devDependencies'][devDepKey] = pluginVersion; + } + } + for (const depKey of Object.keys(pkgJson['dependencies'] || {})) { + if (libs.includes(depKey)) { + pkgJson['dependencies'][depKey] = coreVersion; + } + else if (plugins.includes(depKey)) { + pkgJson['dependencies'][depKey] = pluginVersion; + } + } + (0, fs_extra_1.writeFileSync)(pkgJsonPath, JSON.stringify(pkgJson, null, 2), { + encoding: 'utf-8', + }); + if (runInstall) { + rimraf_1.rimraf.sync((0, path_1.join)(config.app.rootDir, 'node_modules/@capacitor/!(cli)')); + await (0, subprocess_1.runCommand)(dependencyManager, ['install']); + if (dependencyManager == 'yarn') { + await (0, subprocess_1.runCommand)(dependencyManager, ['upgrade']); + } + else { + await (0, subprocess_1.runCommand)(dependencyManager, ['update']); + } + } + else { + log_1.logger.info(`Please run an install command with your package manager of choice. (ex: yarn install)`); + } +} +async function writeBreakingChanges() { + const breaking = [ + '@capacitor/action-sheet', + '@capacitor/barcode-scanner', + '@capacitor/browser', + '@capacitor/camera', + '@capacitor/geolocation', + '@capacitor/google-maps', + '@capacitor/push-notifications', + '@capacitor/screen-orientation', + '@capacitor/splash-screen', + '@capacitor/status-bar', + ]; + const broken = []; + for (const lib of breaking) { + if (allDependencies[lib]) { + broken.push(lib); + } + } + if (broken.length > 0) { + log_1.logger.info(`IMPORTANT: Review https://capacitorjs.com/docs/next/updating/8-0#plugins for breaking changes in these plugins that you use: ${broken.join(', ')}.`); + } +} +async function getAndroidVariablesAndClasspaths(config) { + const tempAndroidTemplateFolder = (0, path_1.join)(config.cli.assetsDirAbs, 'tempAndroidTemplate'); + await (0, template_1.extractTemplate)(config.cli.assets.android.platformTemplateArchiveAbs, tempAndroidTemplateFolder); + const variablesGradleFile = readFile((0, path_1.join)(tempAndroidTemplateFolder, 'variables.gradle')); + const buildGradleFile = readFile((0, path_1.join)(tempAndroidTemplateFolder, 'build.gradle')); + if (!variablesGradleFile || !buildGradleFile) { + return; + } + (0, fs_1.deleteFolderRecursive)(tempAndroidTemplateFolder); + const firstIndxOfCATBGV = buildGradleFile.indexOf(`classpath 'com.android.tools.build:gradle:`) + 42; + const firstIndxOfCGGGS = buildGradleFile.indexOf(`com.google.gms:google-services:`) + 31; + const comAndroidToolsBuildGradleVersion = '' + buildGradleFile.substring(firstIndxOfCATBGV, buildGradleFile.indexOf("'", firstIndxOfCATBGV)); + const comGoogleGmsGoogleServices = '' + buildGradleFile.substring(firstIndxOfCGGGS, buildGradleFile.indexOf("'", firstIndxOfCGGGS)); + const variablesGradleAsJSON = JSON.parse(variablesGradleFile + .replace('ext ', '') + .replace(/=/g, ':') + .replace(/\n/g, ',') + .replace(/,([^:]+):/g, function (_k, p1) { + return `,"${p1}":`; + }) + .replace('{,', '{') + .replace(',}', '}') + .replace(/\s/g, '') + .replace(/'/g, '"')); + return { + variables: variablesGradleAsJSON, + 'com.android.tools.build:gradle': comAndroidToolsBuildGradleVersion, + 'com.google.gms:google-services': comGoogleGmsGoogleServices, + }; +} +function readFile(filename) { + try { + if (!(0, fs_extra_1.existsSync)(filename)) { + log_1.logger.error(`Unable to find ${filename}. Try updating it manually`); + return; + } + return (0, fs_extra_1.readFileSync)(filename, 'utf-8'); + } + catch (err) { + log_1.logger.error(`Unable to read ${filename}. Verify it is not already open. ${err}`); + } +} +function getGradleWrapperVersion(filename) { + var _a; + const txt = readFile(filename); + if (!txt) { + return '0.0.0'; + } + const version = txt.substring(txt.indexOf('gradle-') + 7, txt.indexOf('-all.zip')); + const semverVersion = (_a = (0, semver_1.coerce)(version)) === null || _a === void 0 ? void 0 : _a.version; + return semverVersion ? semverVersion : '0.0.0'; +} +async function updateGradleWrapperFiles(platformDir) { + await (0, subprocess_1.runCommand)(`./gradlew`, ['wrapper', '--distribution-type', 'all', '--gradle-version', gradleVersion, '--warning-mode', 'all'], { + cwd: platformDir, + }); +} +async function updateBuildGradle(filename, variablesAndClasspaths) { + const txt = readFile(filename); + if (!txt) { + return; + } + const neededDeps = { + 'com.android.tools.build:gradle': variablesAndClasspaths['com.android.tools.build:gradle'], + 'com.google.gms:google-services': variablesAndClasspaths['com.google.gms:google-services'], + }; + let replaced = txt; + for (const dep of Object.keys(neededDeps)) { + if (replaced.includes(`classpath '${dep}`)) { + const firstIndex = replaced.indexOf(dep) + dep.length + 1; + const existingVersion = '' + replaced.substring(firstIndex, replaced.indexOf("'", firstIndex)); + if ((0, semver_1.gte)(neededDeps[dep], existingVersion)) { + replaced = setAllStringIn(replaced, `classpath '${dep}:`, `'`, neededDeps[dep]); + log_1.logger.info(`Set ${dep} = ${neededDeps[dep]}.`); + } + } + } + const beforeKotlinVersionUpdate = replaced; + replaced = replaceVersion(replaced, /(ext\.kotlin_version\s*=\s*['"])([^'"]+)(['"])/, kotlinVersion); + replaced = replaceVersion(replaced, /(org\.jetbrains\.kotlin:kotlin[^:]*:)([\d.]+)(['"])/, kotlinVersion); + if (beforeKotlinVersionUpdate !== replaced) { + log_1.logger.info(`Set Kotlin version to ${kotlinVersion}`); + } + (0, fs_extra_1.writeFileSync)(filename, replaced, 'utf-8'); +} +function replaceVersion(text, regex, newVersion) { + return text.replace(regex, (match, prefix, currentVersion, suffix) => { + var _a; + const semVer = (_a = (0, semver_1.coerce)(currentVersion)) === null || _a === void 0 ? void 0 : _a.version; + if ((0, semver_1.gte)(newVersion, semVer ? semVer : '0.0.0')) { + return `${prefix || ''}${newVersion}${suffix || ''}`; + } + return match; + }); +} +async function updateAppBuildGradle(filename) { + const txt = readFile(filename); + if (!txt) { + return; + } + let replaced = txt; + const gradlePproperties = ['compileSdk', 'namespace', 'ignoreAssetsPattern']; + for (const prop of gradlePproperties) { + // Use updated Groovy DSL syntax with " = " assignment + const regex = new RegExp(`(^\\s*${prop})\\s+(?!=)(.+)$`, 'gm'); + replaced = replaced.replace(regex, (_match, key, value) => { + return `${key} = ${value.trim()}`; + }); + } + (0, fs_extra_1.writeFileSync)(filename, replaced, 'utf-8'); +} +async function updateFile(config, filename, textStart, textEnd, replacement, skipIfNotFound) { + if (config === null) { + return false; + } + const path = filename; + let txt = readFile(path); + if (!txt) { + return false; + } + if (txt.includes(textStart)) { + if (replacement) { + txt = setAllStringIn(txt, textStart, textEnd, replacement); + (0, fs_extra_1.writeFileSync)(path, txt, { encoding: 'utf-8' }); + } + else { + // Replacing in code so we need to count the number of brackets to find the end of the function in swift + const lines = txt.split('\n'); + let replaced = ''; + let keep = true; + let brackets = 0; + for (const line of lines) { + if (line.includes(textStart)) { + keep = false; + } + if (!keep) { + brackets += (line.match(/{/g) || []).length; + brackets -= (line.match(/}/g) || []).length; + if (brackets == 0) { + keep = true; + } + } + else { + replaced += line + '\n'; + } + } + (0, fs_extra_1.writeFileSync)(path, replaced, { encoding: 'utf-8' }); + } + return true; + } + else if (!skipIfNotFound) { + log_1.logger.error(`Unable to find "${textStart}" in ${filename}. Try updating it manually`); + } + return false; +} +function setAllStringIn(data, start, end, replacement) { + let position = 0; + let result = data; + let replaced = true; + while (replaced) { + const foundIdx = result.indexOf(start, position); + if (foundIdx == -1) { + replaced = false; + } + else { + const idx = foundIdx + start.length; + position = idx + replacement.length; + result = result.substring(0, idx) + replacement + result.substring(result.indexOf(end, idx)); + } + } + return result; +} +exports.setAllStringIn = setAllStringIn; +async function updateAndroidManifest(filename) { + const txt = readFile(filename); + if (!txt) { + return; + } + if (txt.includes('|density') || txt.includes('density|')) { + return; // Probably already updated + } + // Since navigation was an optional change in Capacitor 7, attempting to add density and/or navigation + const replaced = txt + .replace('android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|smallestScreenSize|screenLayout|uiMode|navigation"', 'android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|smallestScreenSize|screenLayout|uiMode|navigation|density"') + .replace('android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|smallestScreenSize|screenLayout|uiMode"', 'android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|smallestScreenSize|screenLayout|uiMode|navigation|density"'); + if (!replaced.includes('|density')) { + log_1.logger.error(`Unable to add 'density' to 'android:configChanges' in ${filename}. Try adding it manually`); + } + else { + (0, fs_extra_1.writeFileSync)(filename, replaced, 'utf-8'); + } +} diff --git a/node_modules/@capacitor/cli/dist/tasks/new-plugin.js b/node_modules/@capacitor/cli/dist/tasks/new-plugin.js new file mode 100644 index 0000000..884ebc7 --- /dev/null +++ b/node_modules/@capacitor/cli/dist/tasks/new-plugin.js @@ -0,0 +1,10 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.newPluginCommand = void 0; +const tslib_1 = require("tslib"); +const colors_1 = tslib_1.__importDefault(require("../colors")); +const errors_1 = require("../errors"); +async function newPluginCommand() { + (0, errors_1.fatal)(`The plugin:generate command has been removed.\n` + `Use ${colors_1.default.input('npm init @capacitor/plugin')}`); +} +exports.newPluginCommand = newPluginCommand; diff --git a/node_modules/@capacitor/cli/dist/tasks/open.js b/node_modules/@capacitor/cli/dist/tasks/open.js new file mode 100644 index 0000000..12bed17 --- /dev/null +++ b/node_modules/@capacitor/cli/dist/tasks/open.js @@ -0,0 +1,62 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.open = exports.openCommand = void 0; +const tslib_1 = require("tslib"); +const open_1 = require("../android/open"); +const colors_1 = tslib_1.__importDefault(require("../colors")); +const common_1 = require("../common"); +const errors_1 = require("../errors"); +const open_2 = require("../ios/open"); +const log_1 = require("../log"); +async function openCommand(config, selectedPlatformName) { + var _a; + if (selectedPlatformName && !(await (0, common_1.isValidPlatform)(selectedPlatformName))) { + const platformDir = (0, common_1.resolvePlatform)(config, selectedPlatformName); + if (platformDir) { + await (0, common_1.runPlatformHook)(config, selectedPlatformName, platformDir, 'capacitor:open'); + } + else { + log_1.logger.error(`Platform ${colors_1.default.input(selectedPlatformName)} not found.`); + } + } + else { + const platforms = await (0, common_1.selectPlatforms)(config, selectedPlatformName); + let platformName; + if (platforms.length === 1) { + platformName = platforms[0]; + } + else { + platformName = await (0, common_1.promptForPlatform)(platforms.filter(createOpenablePlatformFilter(config)), `Please choose a platform to open:`); + } + try { + await open(config, platformName); + } + catch (e) { + if (!(0, errors_1.isFatal)(e)) { + (0, errors_1.fatal)((_a = e.stack) !== null && _a !== void 0 ? _a : e); + } + throw e; + } + } +} +exports.openCommand = openCommand; +function createOpenablePlatformFilter(config) { + return (platform) => platform === config.ios.name || platform === config.android.name; +} +async function open(config, platformName) { + if (platformName === config.ios.name) { + await (0, common_1.runTask)('Opening the Xcode workspace...', () => { + return (0, open_2.openIOS)(config); + }); + } + else if (platformName === config.android.name) { + return (0, open_1.openAndroid)(config); + } + else if (platformName === config.web.name) { + return Promise.resolve(); + } + else { + throw `Platform ${platformName} is not valid.`; + } +} +exports.open = open; diff --git a/node_modules/@capacitor/cli/dist/tasks/run.js b/node_modules/@capacitor/cli/dist/tasks/run.js new file mode 100644 index 0000000..efccc1b --- /dev/null +++ b/node_modules/@capacitor/cli/dist/tasks/run.js @@ -0,0 +1,120 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.run = exports.runCommand = void 0; +const tslib_1 = require("tslib"); +const utils_terminal_1 = require("@ionic/utils-terminal"); +const run_1 = require("../android/run"); +const colors_1 = tslib_1.__importDefault(require("../colors")); +const common_1 = require("../common"); +const cordova_1 = require("../cordova"); +const errors_1 = require("../errors"); +const run_2 = require("../ios/run"); +const log_1 = require("../log"); +const livereload_1 = require("../util/livereload"); +const native_run_1 = require("../util/native-run"); +const sync_1 = require("./sync"); +async function runCommand(config, selectedPlatformName, options) { + var _a, _b, _c; + options.host = (_b = (_a = options.host) !== null && _a !== void 0 ? _a : livereload_1.CapLiveReloadHelper.getIpAddress()) !== null && _b !== void 0 ? _b : 'localhost'; + if (!options.https && !options.port) { + options.port = '3000'; + } + if (selectedPlatformName && !(await (0, common_1.isValidPlatform)(selectedPlatformName))) { + const platformDir = (0, common_1.resolvePlatform)(config, selectedPlatformName); + if (platformDir) { + await (0, common_1.runPlatformHook)(config, selectedPlatformName, platformDir, 'capacitor:run'); + } + else { + log_1.logger.error(`Platform ${colors_1.default.input(selectedPlatformName)} not found.`); + } + } + else { + const platforms = await (0, common_1.selectPlatforms)(config, selectedPlatformName); + let platformName; + if (platforms.length === 1) { + platformName = platforms[0]; + } + else { + platformName = await (0, common_1.promptForPlatform)(platforms.filter(createRunnablePlatformFilter(config)), `Please choose a platform to run:`); + } + if (options.list) { + const targets = await (0, native_run_1.getPlatformTargets)(platformName); + const outputTargets = targets.map((t) => { + var _a; + return ({ + name: (0, common_1.getPlatformTargetName)(t), + api: `${t.platform === 'ios' ? 'iOS' : 'API'} ${t.sdkVersion}`, + id: (_a = t.id) !== null && _a !== void 0 ? _a : '?', + }); + }); + if (options.json) { + process.stdout.write(`${JSON.stringify(outputTargets)}\n`); + } + else { + const rows = outputTargets.map((t) => [t.name, t.api, t.id]); + log_1.output.write(`${(0, utils_terminal_1.columnar)(rows, { + headers: ['Name', 'API', 'Target ID'], + vsep: ' ', + })}\n`); + } + return; + } + try { + if (options.sync) { + await (0, sync_1.sync)(config, platformName, false, true); + } + const cordovaPlugins = await (0, cordova_1.getCordovaPlugins)(config, platformName); + if (options.liveReload) { + await livereload_1.CapLiveReloadHelper.editCapConfigForLiveReload(config, platformName, options); + if (platformName === config.android.name) { + await await (0, cordova_1.writeCordovaAndroidManifest)(cordovaPlugins, config, platformName, true); + } + } + await run(config, platformName, options); + if (options.liveReload) { + new Promise((resolve) => process.on('SIGINT', resolve)) + .then(async () => { + await livereload_1.CapLiveReloadHelper.revertCapConfigForLiveReload(); + if (platformName === config.android.name) { + await (0, cordova_1.writeCordovaAndroidManifest)(cordovaPlugins, config, platformName, false); + } + }) + .then(() => process.exit()); + log_1.logger.info(`App running with live reload listing for: ${options.https ? 'https' : 'http'}://${options.host}${options.port ? `:${options.port}` : ''}. Press Ctrl+C to quit.`); + await sleepForever(); + } + } + catch (e) { + if (!(0, errors_1.isFatal)(e)) { + (0, errors_1.fatal)((_c = e.stack) !== null && _c !== void 0 ? _c : e); + } + throw e; + } + } +} +exports.runCommand = runCommand; +async function run(config, platformName, options) { + if (platformName == config.ios.name) { + await (0, run_2.runIOS)(config, options); + } + else if (platformName === config.android.name) { + await (0, run_1.runAndroid)(config, options); + } + else if (platformName === config.web.name) { + return; + } + else { + throw `Platform ${platformName} is not valid.`; + } +} +exports.run = run; +function createRunnablePlatformFilter(config) { + return (platform) => platform === config.ios.name || platform === config.android.name; +} +async function sleepForever() { + return new Promise(() => { + setInterval(() => { + /* do nothing */ + }, 1000); + }); +} diff --git a/node_modules/@capacitor/cli/dist/tasks/serve.js b/node_modules/@capacitor/cli/dist/tasks/serve.js new file mode 100644 index 0000000..bad369f --- /dev/null +++ b/node_modules/@capacitor/cli/dist/tasks/serve.js @@ -0,0 +1,11 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.serveCommand = void 0; +const tslib_1 = require("tslib"); +const colors_1 = tslib_1.__importDefault(require("../colors")); +const errors_1 = require("../errors"); +async function serveCommand() { + (0, errors_1.fatal)(`The serve command has been removed.\n` + + `Use a third-party tool for serving single page apps, such as ${colors_1.default.strong('serve')}: ${colors_1.default.strong('https://www.npmjs.com/package/serve')}`); +} +exports.serveCommand = serveCommand; diff --git a/node_modules/@capacitor/cli/dist/tasks/sourcemaps.js b/node_modules/@capacitor/cli/dist/tasks/sourcemaps.js new file mode 100644 index 0000000..f1b7fba --- /dev/null +++ b/node_modules/@capacitor/cli/dist/tasks/sourcemaps.js @@ -0,0 +1,39 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.inlineSourceMaps = void 0; +const fs_extra_1 = require("fs-extra"); +const path_1 = require("path"); +const log_1 = require("../log"); +function walkDirectory(dirPath) { + const files = (0, fs_extra_1.readdirSync)(dirPath); + files.forEach((file) => { + const targetFile = (0, path_1.join)(dirPath, file); + if ((0, fs_extra_1.existsSync)(targetFile) && (0, fs_extra_1.lstatSync)(targetFile).isDirectory()) { + walkDirectory(targetFile); + } + else { + const mapFile = (0, path_1.join)(dirPath, `${file}.map`); + if (((0, path_1.extname)(file) === '.js' || (0, path_1.extname)(file) === '.css') && (0, fs_extra_1.existsSync)(mapFile)) { + const bufMap = (0, fs_extra_1.readFileSync)(mapFile).toString('base64'); + const bufFile = (0, fs_extra_1.readFileSync)(targetFile, 'utf8'); + const result = bufFile.replace(`sourceMappingURL=${file}.map`, 'sourceMappingURL=data:application/json;charset=utf-8;base64,' + bufMap); + (0, fs_extra_1.writeFileSync)(targetFile, result); + (0, fs_extra_1.unlinkSync)(mapFile); + } + } + }); +} +async function inlineSourceMaps(config, platformName) { + let buildDir = ''; + if (platformName == config.ios.name) { + buildDir = await config.ios.webDirAbs; + } + if (platformName == config.android.name) { + buildDir = await config.android.webDirAbs; + } + if (buildDir) { + log_1.logger.info('Inlining sourcemaps'); + walkDirectory(buildDir); + } +} +exports.inlineSourceMaps = inlineSourceMaps; diff --git a/node_modules/@capacitor/cli/dist/tasks/sync.js b/node_modules/@capacitor/cli/dist/tasks/sync.js new file mode 100644 index 0000000..3d43cdd --- /dev/null +++ b/node_modules/@capacitor/cli/dist/tasks/sync.js @@ -0,0 +1,55 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.sync = exports.syncCommand = void 0; +const common_1 = require("../common"); +const errors_1 = require("../errors"); +const log_1 = require("../log"); +const promise_1 = require("../util/promise"); +const copy_1 = require("./copy"); +const update_1 = require("./update"); +/** + * Sync is a copy and an update in one. + */ +async function syncCommand(config, selectedPlatformName, deployment, inline = false) { + var _a, _b; + if (selectedPlatformName && !(await (0, common_1.isValidPlatform)(selectedPlatformName))) { + try { + await (0, copy_1.copyCommand)(config, selectedPlatformName, inline); + } + catch (e) { + log_1.logger.error((_a = e.stack) !== null && _a !== void 0 ? _a : e); + } + await (0, update_1.updateCommand)(config, selectedPlatformName, deployment); + } + else { + const then = +new Date(); + const platforms = await (0, common_1.selectPlatforms)(config, selectedPlatformName); + try { + await (0, common_1.check)([() => (0, common_1.checkPackage)(), () => (0, common_1.checkWebDir)(config), ...(await (0, update_1.addUpdateChecks)(config, platforms))]); + await (0, promise_1.allSerial)(platforms.map((platformName) => () => sync(config, platformName, deployment, inline))); + const now = +new Date(); + const diff = (now - then) / 1000; + log_1.logger.info(`Sync finished in ${diff}s`); + } + catch (e) { + if (!(0, errors_1.isFatal)(e)) { + (0, errors_1.fatal)((_b = e.stack) !== null && _b !== void 0 ? _b : e); + } + throw e; + } + } +} +exports.syncCommand = syncCommand; +async function sync(config, platformName, deployment, inline = false) { + var _a; + await (0, common_1.runHooks)(config, platformName, config.app.rootDir, 'capacitor:sync:before'); + try { + await (0, copy_1.copy)(config, platformName, inline); + } + catch (e) { + log_1.logger.error((_a = e.stack) !== null && _a !== void 0 ? _a : e); + } + await (0, update_1.update)(config, platformName, deployment); + await (0, common_1.runHooks)(config, platformName, config.app.rootDir, 'capacitor:sync:after'); +} +exports.sync = sync; diff --git a/node_modules/@capacitor/cli/dist/tasks/telemetry.js b/node_modules/@capacitor/cli/dist/tasks/telemetry.js new file mode 100644 index 0000000..aca5595 --- /dev/null +++ b/node_modules/@capacitor/cli/dist/tasks/telemetry.js @@ -0,0 +1,41 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.telemetryCommand = void 0; +const tslib_1 = require("tslib"); +const colors_1 = tslib_1.__importDefault(require("../colors")); +const errors_1 = require("../errors"); +const log_1 = require("../log"); +const sysconfig_1 = require("../sysconfig"); +const THANK_YOU = `\nThank you for helping to make Capacitor better! 💖` + + `\nInformation about the data we collect is available on our website: ${colors_1.default.strong('https://capacitorjs.com/docs/next/cli/telemetry')}\n`; +async function telemetryCommand(onOrOff) { + const sysconfig = await (0, sysconfig_1.readConfig)(); + const enabled = interpretEnabled(onOrOff); + if (typeof enabled === 'boolean') { + if (sysconfig.telemetry === enabled) { + log_1.logger.info(`Telemetry is already ${colors_1.default.strong(enabled ? 'on' : 'off')}`); + } + else { + await (0, sysconfig_1.writeConfig)({ ...sysconfig, telemetry: enabled }); + (0, log_1.logSuccess)(`You have ${colors_1.default.strong(`opted ${enabled ? 'in' : 'out'}`)} ${enabled ? 'for' : 'of'} telemetry on this machine.`); + if (enabled) { + log_1.output.write(THANK_YOU); + } + } + } + else { + log_1.logger.info(`Telemetry is ${colors_1.default.strong(sysconfig.telemetry ? 'on' : 'off')}`); + } +} +exports.telemetryCommand = telemetryCommand; +function interpretEnabled(onOrOff) { + switch (onOrOff) { + case 'on': + return true; + case 'off': + return false; + case undefined: + return undefined; + } + (0, errors_1.fatal)(`Argument must be ${colors_1.default.strong('on')} or ${colors_1.default.strong('off')} (or left unspecified)`); +} diff --git a/node_modules/@capacitor/cli/dist/tasks/update.js b/node_modules/@capacitor/cli/dist/tasks/update.js new file mode 100644 index 0000000..3aeb45b --- /dev/null +++ b/node_modules/@capacitor/cli/dist/tasks/update.js @@ -0,0 +1,99 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.update = exports.updateChecks = exports.addUpdateChecks = exports.updateCommand = void 0; +const tslib_1 = require("tslib"); +const update_1 = require("../android/update"); +const colors_1 = tslib_1.__importDefault(require("../colors")); +const common_1 = require("../common"); +const errors_1 = require("../errors"); +const common_2 = require("../ios/common"); +const update_2 = require("../ios/update"); +const log_1 = require("../log"); +const promise_1 = require("../util/promise"); +async function updateCommand(config, selectedPlatformName, deployment) { + var _a; + if (selectedPlatformName && !(await (0, common_1.isValidPlatform)(selectedPlatformName))) { + const platformDir = (0, common_1.resolvePlatform)(config, selectedPlatformName); + if (platformDir) { + await (0, common_1.runPlatformHook)(config, selectedPlatformName, platformDir, 'capacitor:update'); + } + else { + log_1.logger.error(`Platform ${colors_1.default.input(selectedPlatformName)} not found.`); + } + } + else { + const then = +new Date(); + const platforms = await (0, common_1.selectPlatforms)(config, selectedPlatformName); + try { + await (0, common_1.check)([() => (0, common_1.checkPackage)(), ...(await addUpdateChecks(config, platforms))]); + await (0, promise_1.allSerial)(platforms.map((platformName) => async () => await update(config, platformName, deployment))); + const now = +new Date(); + const diff = (now - then) / 1000; + log_1.logger.info(`Update finished in ${diff}s`); + } + catch (e) { + if (!(0, errors_1.isFatal)(e)) { + (0, errors_1.fatal)((_a = e.stack) !== null && _a !== void 0 ? _a : e); + } + throw e; + } + } +} +exports.updateCommand = updateCommand; +async function addUpdateChecks(config, platforms) { + let checks = []; + for (const platformName of platforms) { + if (platformName === config.ios.name) { + checks = await (0, common_2.getCommonChecks)(config); + } + else if (platformName === config.android.name) { + continue; + } + else if (platformName === config.web.name) { + continue; + } + else { + throw `Platform ${platformName} is not valid.`; + } + } + return checks; +} +exports.addUpdateChecks = addUpdateChecks; +/** + * @deprecated use addUpdateChecks + * @param config + * @param platforms + * @returns + */ +function updateChecks(config, platforms) { + const checks = []; + for (const platformName of platforms) { + if (platformName === config.ios.name) { + checks.push(() => (0, common_2.checkBundler)(config) || (0, common_2.checkCocoaPods)(config)); + } + else if (platformName === config.android.name) { + continue; + } + else if (platformName === config.web.name) { + continue; + } + else { + throw `Platform ${platformName} is not valid.`; + } + } + return checks; +} +exports.updateChecks = updateChecks; +async function update(config, platformName, deployment) { + await (0, common_1.runTask)(colors_1.default.success(colors_1.default.strong(`update ${platformName}`)), async () => { + await (0, common_1.runHooks)(config, platformName, config.app.rootDir, 'capacitor:update:before'); + if (platformName === config.ios.name) { + await (0, update_2.updateIOS)(config, deployment); + } + else if (platformName === config.android.name) { + await (0, update_1.updateAndroid)(config); + } + await (0, common_1.runHooks)(config, platformName, config.app.rootDir, 'capacitor:update:after'); + }); +} +exports.update = update; diff --git a/node_modules/@capacitor/cli/dist/telemetry.js b/node_modules/@capacitor/cli/dist/telemetry.js new file mode 100644 index 0000000..75ff2c2 --- /dev/null +++ b/node_modules/@capacitor/cli/dist/telemetry.js @@ -0,0 +1,119 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.sendMetric = exports.telemetryAction = void 0; +const tslib_1 = require("tslib"); +const commander_1 = require("commander"); +const debug_1 = tslib_1.__importDefault(require("debug")); +const colors_1 = tslib_1.__importDefault(require("./colors")); +const ipc_1 = require("./ipc"); +const log_1 = require("./log"); +const sysconfig_1 = require("./sysconfig"); +const subprocess_1 = require("./util/subprocess"); +const term_1 = require("./util/term"); +const debug = (0, debug_1.default)('capacitor:telemetry'); +const THANK_YOU = `\nThank you for helping improve Capacitor by sharing anonymous usage data! 💖` + + `\nInformation about the data we collect is available on our website: ${colors_1.default.strong('https://capacitorjs.com/docs/next/cli/telemetry')}` + + `\nYou can disable telemetry at any time by using the ${colors_1.default.input('npx cap telemetry off')} command.`; +function telemetryAction(config, action) { + return async (...actionArgs) => { + const start = new Date(); + // This is how commanderjs works--the command object is either the last + // element or second to last if there are additional options (via `.allowUnknownOption()`) + const lastArg = actionArgs[actionArgs.length - 1]; + const cmd = lastArg instanceof commander_1.Command ? lastArg : actionArgs[actionArgs.length - 2]; + const command = getFullCommandName(cmd); + let error; + try { + await action(...actionArgs); + } + catch (e) { + error = e; + } + const end = new Date(); + const duration = end.getTime() - start.getTime(); + const packages = Object.entries({ + ...config.app.package.devDependencies, + ...config.app.package.dependencies, + }); + // Only collect packages in the capacitor org: + // https://www.npmjs.com/org/capacitor + const capacitorPackages = packages.filter(([k]) => k.startsWith('@capacitor/')); + const versions = capacitorPackages.map(([k, v]) => [ + `${k.replace(/^@capacitor\//, '').replace(/-/g, '_')}_version`, + v, + ]); + const data = { + app_id: await getAppIdentifier(config), + command, + arguments: cmd.args.join(' '), + options: JSON.stringify(cmd.opts()), + duration, + error: error ? (error.message ? error.message : String(error)) : null, + node_version: process.version, + os: config.cli.os, + ...Object.fromEntries(versions), + }; + if ((0, term_1.isInteractive)()) { + let sysconfig = await (0, sysconfig_1.readConfig)(); + if (!error && typeof sysconfig.telemetry === 'undefined') { + // Telemetry is opt-out; turn telemetry on then inform the user how to opt-out. + sysconfig = { ...sysconfig, telemetry: true }; + await (0, sysconfig_1.writeConfig)(sysconfig); + log_1.output.write(THANK_YOU); + } + await sendMetric(sysconfig, 'capacitor_cli_command', data); + } + if (error) { + throw error; + } + }; +} +exports.telemetryAction = telemetryAction; +/** + * If telemetry is enabled, send a metric via IPC to a forked process for uploading. + */ +async function sendMetric(sysconfig, name, data) { + if (sysconfig.telemetry && (0, term_1.isInteractive)()) { + const message = { + name, + timestamp: new Date().toISOString(), + session_id: sysconfig.machine, + source: 'capacitor_cli', + value: data, + }; + await (0, ipc_1.send)({ type: 'telemetry', data: message }); + } + else { + debug('Telemetry is off (user choice, non-interactive terminal, or CI)--not sending metric'); + } +} +exports.sendMetric = sendMetric; +/** + * Get a unique anonymous identifier for this app. + */ +async function getAppIdentifier(config) { + const { createHash } = await Promise.resolve().then(() => tslib_1.__importStar(require('crypto'))); + // get the first commit hash, which should be universally unique + const output = await (0, subprocess_1.getCommandOutput)('git', ['rev-list', '--max-parents=0', 'HEAD'], { cwd: config.app.rootDir }); + const firstLine = output === null || output === void 0 ? void 0 : output.split('\n')[0]; + if (!firstLine) { + debug('Could not obtain unique app identifier'); + return null; + } + // use sha1 to create a one-way hash to anonymize + const id = createHash('sha1').update(firstLine).digest('hex'); + return id; +} +/** + * Walk through the command's parent tree and construct a space-separated name. + * + * Probably overkill because we don't have nested commands, but whatever. + */ +function getFullCommandName(cmd) { + const names = []; + while (cmd.parent !== null) { + names.push(cmd.name()); + cmd = cmd.parent; + } + return names.reverse().join(' '); +} diff --git a/node_modules/@capacitor/cli/dist/util/cli.js b/node_modules/@capacitor/cli/dist/util/cli.js new file mode 100644 index 0000000..bedab98 --- /dev/null +++ b/node_modules/@capacitor/cli/dist/util/cli.js @@ -0,0 +1,25 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.wrapAction = exports.ENV_PATHS = void 0; +const tslib_1 = require("tslib"); +const env_paths_1 = tslib_1.__importDefault(require("env-paths")); +const errors_1 = require("../errors"); +const log_1 = require("../log"); +exports.ENV_PATHS = (0, env_paths_1.default)('capacitor', { suffix: '' }); +function wrapAction(action) { + return async (...args) => { + try { + await action(...args); + } + catch (e) { + if ((0, errors_1.isFatal)(e)) { + process.exitCode = e.exitCode; + log_1.logger.error(e.message); + } + else { + throw e; + } + } + }; +} +exports.wrapAction = wrapAction; diff --git a/node_modules/@capacitor/cli/dist/util/emoji.js b/node_modules/@capacitor/cli/dist/util/emoji.js new file mode 100644 index 0000000..00a9dbc --- /dev/null +++ b/node_modules/@capacitor/cli/dist/util/emoji.js @@ -0,0 +1,13 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.emoji = void 0; +// Emoji falback, right now just uses fallback on windows, +// but could expand to be more sophisticated to allow emoji +// on Hyper term on windows, for example. +const emoji = (x, fallback) => { + if (process.platform === 'win32') { + return fallback; + } + return x; +}; +exports.emoji = emoji; diff --git a/node_modules/@capacitor/cli/dist/util/fn.js b/node_modules/@capacitor/cli/dist/util/fn.js new file mode 100644 index 0000000..9c99b90 --- /dev/null +++ b/node_modules/@capacitor/cli/dist/util/fn.js @@ -0,0 +1,13 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.tryFn = void 0; +const tryFn = async (fn, ...args) => { + try { + return await fn(...args); + } + catch { + // ignore + } + return null; +}; +exports.tryFn = tryFn; diff --git a/node_modules/@capacitor/cli/dist/util/fs.js b/node_modules/@capacitor/cli/dist/util/fs.js new file mode 100644 index 0000000..ac0709c --- /dev/null +++ b/node_modules/@capacitor/cli/dist/util/fs.js @@ -0,0 +1,43 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.readdirp = exports.deleteFolderRecursive = exports.convertToUnixPath = void 0; +const fs_1 = require("fs"); +const promises_1 = require("fs/promises"); +const fs_extra_1 = require("fs-extra"); +const path_1 = require("path"); +const convertToUnixPath = (path) => { + return path.replace(/\\/g, '/'); +}; +exports.convertToUnixPath = convertToUnixPath; +const deleteFolderRecursive = (directoryPath) => { + if ((0, fs_extra_1.existsSync)(directoryPath)) { + (0, fs_extra_1.readdirSync)(directoryPath).forEach((file) => { + const curPath = (0, path_1.join)(directoryPath, file); + if ((0, fs_extra_1.lstatSync)(curPath).isDirectory()) { + (0, exports.deleteFolderRecursive)(curPath); + } + else { + (0, fs_extra_1.unlinkSync)(curPath); + } + }); + (0, fs_extra_1.rmdirSync)(directoryPath); + } +}; +exports.deleteFolderRecursive = deleteFolderRecursive; +async function readdirp(dir, { filter }) { + const dirContent = await (0, promises_1.readdir)(dir, { recursive: true }); + const dirContentWalker = []; + const filteredContent = []; + dirContent.forEach((element) => { + const path = (0, path_1.join)(dir, element); + const stats = (0, fs_1.statSync)(path); + dirContentWalker.push({ path, stats }); + }); + dirContentWalker.forEach((element) => { + if (filter(element)) { + filteredContent.push(element.path); + } + }); + return filteredContent; +} +exports.readdirp = readdirp; diff --git a/node_modules/@capacitor/cli/dist/util/iosplugin.js b/node_modules/@capacitor/cli/dist/util/iosplugin.js new file mode 100644 index 0000000..449b3b8 --- /dev/null +++ b/node_modules/@capacitor/cli/dist/util/iosplugin.js @@ -0,0 +1,66 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.generateIOSPackageJSON = exports.writePluginJSON = exports.findPluginClasses = exports.getPluginFiles = void 0; +const fs_extra_1 = require("fs-extra"); +const path_1 = require("path"); +const cordova_1 = require("../cordova"); +const plugin_1 = require("../plugin"); +const fs_1 = require("./fs"); +async function getPluginFiles(plugins) { + var _a; + let filenameList = []; + const options = { + filter: (item) => { + if (item.stats.isFile() && (item.path.endsWith('.swift') || item.path.endsWith('.m'))) { + return true; + } + else { + return false; + } + }, + }; + for (const plugin of plugins) { + if (plugin.ios && (0, plugin_1.getPluginType)(plugin, 'ios') === 0 /* PluginType.Core */) { + const pluginPath = (0, path_1.resolve)(plugin.rootPath, (_a = plugin.ios) === null || _a === void 0 ? void 0 : _a.path); + const filenames = await (0, fs_1.readdirp)(pluginPath, options); + filenameList = filenameList.concat(filenames); + } + } + return filenameList; +} +exports.getPluginFiles = getPluginFiles; +async function findPluginClasses(files) { + const classList = []; + for (const file of files) { + const fileData = (0, fs_extra_1.readFileSync)(file, 'utf-8'); + const swiftPluginRegex = RegExp(/@objc\(([A-Za-z0-9_-]+)\)/); + const objcPluginRegex = RegExp(/CAP_PLUGIN\(([A-Za-z0-9_-]+)/); + const swiftMatches = swiftPluginRegex.exec(fileData); + if ((swiftMatches === null || swiftMatches === void 0 ? void 0 : swiftMatches[1]) && !classList.includes(swiftMatches[1])) { + classList.push(swiftMatches[1]); + } + const objcMatches = objcPluginRegex.exec(fileData); + if ((objcMatches === null || objcMatches === void 0 ? void 0 : objcMatches[1]) && !classList.includes(objcMatches[1])) { + classList.push(objcMatches[1]); + } + } + return classList; +} +exports.findPluginClasses = findPluginClasses; +async function writePluginJSON(config, classList) { + const capJSONFile = (0, path_1.resolve)(config.ios.nativeTargetDirAbs, 'capacitor.config.json'); + const capJSON = (0, fs_extra_1.readJSONSync)(capJSONFile); + capJSON['packageClassList'] = classList; + (0, fs_extra_1.writeJSONSync)(capJSONFile, capJSON, { spaces: '\t' }); +} +exports.writePluginJSON = writePluginJSON; +async function generateIOSPackageJSON(config, plugins) { + const fileList = await getPluginFiles(plugins); + const classList = await findPluginClasses(fileList); + const cordovaPlugins = await (0, cordova_1.getCordovaPlugins)(config, 'ios'); + if (cordovaPlugins.length > 0) { + classList.push('CDVPlugin'); + } + writePluginJSON(config, classList); +} +exports.generateIOSPackageJSON = generateIOSPackageJSON; diff --git a/node_modules/@capacitor/cli/dist/util/js.js b/node_modules/@capacitor/cli/dist/util/js.js new file mode 100644 index 0000000..ceabcda --- /dev/null +++ b/node_modules/@capacitor/cli/dist/util/js.js @@ -0,0 +1,21 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.formatJSObject = void 0; +const tslib_1 = require("tslib"); +const util_1 = tslib_1.__importDefault(require("util")); +function formatJSObject(o) { + try { + o = JSON.parse(JSON.stringify(o)); + } + catch (e) { + throw new Error(`Cannot parse object as JSON: ${e.stack ? e.stack : e}`); + } + return util_1.default.inspect(o, { + compact: false, + breakLength: Infinity, + depth: Infinity, + maxArrayLength: Infinity, + maxStringLength: Infinity, + }); +} +exports.formatJSObject = formatJSObject; diff --git a/node_modules/@capacitor/cli/dist/util/livereload.js b/node_modules/@capacitor/cli/dist/util/livereload.js new file mode 100644 index 0000000..86c6301 --- /dev/null +++ b/node_modules/@capacitor/cli/dist/util/livereload.js @@ -0,0 +1,149 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.CapLiveReloadHelper = void 0; +const fs_extra_1 = require("fs-extra"); +const os_1 = require("os"); +const path_1 = require("path"); +class CapLiveReload { + constructor() { + this.configJsonToRevertTo = { + json: null, + platformPath: null, + }; + // nothing to do + } + getIpAddress(name, family) { + var _a; + const interfaces = (_a = (0, os_1.networkInterfaces)()) !== null && _a !== void 0 ? _a : {}; + const _normalizeFamily = (family) => { + if (family === 4) { + return 'ipv4'; + } + if (family === 6) { + return 'ipv6'; + } + return family ? family.toLowerCase() : 'ipv4'; + }; + const isLoopback = (addr) => { + return (/^(::f{4}:)?127\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})/.test(addr) || + /^fe80::1$/.test(addr) || + /^::1$/.test(addr) || + /^::$/.test(addr)); + }; + const isPrivate = (addr) => { + return (/^(::f{4}:)?10\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})$/i.test(addr) || + /^(::f{4}:)?192\.168\.([0-9]{1,3})\.([0-9]{1,3})$/i.test(addr) || + /^(::f{4}:)?172\.(1[6-9]|2\d|30|31)\.([0-9]{1,3})\.([0-9]{1,3})$/i.test(addr) || + /^(::f{4}:)?127\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})$/i.test(addr) || + /^(::f{4}:)?169\.254\.([0-9]{1,3})\.([0-9]{1,3})$/i.test(addr) || + /^f[cd][0-9a-f]{2}:/i.test(addr) || + /^fe80:/i.test(addr) || + /^::1$/.test(addr) || + /^::$/.test(addr)); + }; + const isPublic = (addr) => { + return !isPrivate(addr); + }; + const loopback = (family) => { + // + // Default to `ipv4` + // + family = _normalizeFamily(family); + if (family !== 'ipv4' && family !== 'ipv6') { + throw new Error('family must be ipv4 or ipv6'); + } + return family === 'ipv4' ? '127.0.0.1' : 'fe80::1'; + }; + // + // Default to `ipv4` + // + family = _normalizeFamily(family); + // + // If a specific network interface has been named, + // return the address. + // + if (name && name !== 'private' && name !== 'public') { + const res = interfaces[name].filter((details) => { + const itemFamily = _normalizeFamily(details.family); + return itemFamily === family; + }); + if (res.length === 0) { + return undefined; + } + return res[0].address; + } + const all = Object.keys(interfaces) + .map((nic) => { + // + // Note: name will only be `public` or `private` + // when this is called. + // + const addresses = interfaces[nic].filter((details) => { + details.family = _normalizeFamily(details.family); + if (details.family !== family || isLoopback(details.address)) { + return false; + } + if (!name) { + return true; + } + return name === 'public' ? isPrivate(details.address) : isPublic(details.address); + }); + return addresses.length ? addresses[0].address : undefined; + }) + .filter(Boolean); + return !all.length ? loopback(family) : all[0]; + } + // TODO remove on next major as it's unused + async editExtConfigForLiveReload(config, platformName, options, rootConfigChange = false) { + const platformAbsPath = platformName == config.ios.name + ? config.ios.nativeTargetDirAbs + : platformName == config.android.name + ? config.android.assetsDirAbs + : null; + if (platformAbsPath == null) + throw new Error('Platform not found.'); + const capConfigPath = rootConfigChange + ? config.app.extConfigFilePath + : (0, path_1.join)(platformAbsPath, 'capacitor.config.json'); + const configJson = { ...config.app.extConfig }; + this.configJsonToRevertTo.json = JSON.stringify(configJson, null, 2); + this.configJsonToRevertTo.platformPath = capConfigPath; + const url = `http://${options.host}:${options.port}`; + configJson.server = { + url, + }; + return configJson; + } + // TODO remove rootConfigChange param on next major as it's unused + async editCapConfigForLiveReload(config, platformName, options, rootConfigChange = false) { + const platformAbsPath = platformName == config.ios.name + ? config.ios.nativeTargetDirAbs + : platformName == config.android.name + ? config.android.assetsDirAbs + : null; + if (platformAbsPath == null) + throw new Error('Platform not found.'); + const capConfigPath = rootConfigChange + ? config.app.extConfigFilePath + : (0, path_1.join)(platformAbsPath, 'capacitor.config.json'); + const configJson = (0, fs_extra_1.readJSONSync)(capConfigPath); + this.configJsonToRevertTo.json = JSON.stringify(configJson, null, 2); + this.configJsonToRevertTo.platformPath = capConfigPath; + const url = `${options.https ? 'https' : 'http'}://${options.host}${options.port ? `:${options.port}` : ''}`; + configJson.server = { + ...configJson.server, + url, + }; + (0, fs_extra_1.writeJSONSync)(capConfigPath, configJson, { spaces: '\t' }); + } + async revertCapConfigForLiveReload() { + if (this.configJsonToRevertTo.json == null || this.configJsonToRevertTo.platformPath == null) + return; + const capConfigPath = this.configJsonToRevertTo.platformPath; + const configJson = this.configJsonToRevertTo.json; + (0, fs_extra_1.writeJSONSync)(capConfigPath, JSON.parse(configJson), { spaces: '\t' }); + this.configJsonToRevertTo.json = null; + this.configJsonToRevertTo.platformPath = null; + } +} +exports.CapLiveReloadHelper = new CapLiveReload(); diff --git a/node_modules/@capacitor/cli/dist/util/monorepotools.js b/node_modules/@capacitor/cli/dist/util/monorepotools.js new file mode 100644 index 0000000..233a494 --- /dev/null +++ b/node_modules/@capacitor/cli/dist/util/monorepotools.js @@ -0,0 +1,109 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.isNXMonorepo = exports.isMonorepo = exports.findPackageRelativePathInMonorepo = exports.findPackagePath = exports.findNXMonorepoRoot = exports.findMonorepoRoot = void 0; +const node_fs_1 = require("node:fs"); +const node_path_1 = require("node:path"); +/** + * Finds the monorepo root from the given path. + * @param currentPath - The current path to start searching from. + * @returns The path to the monorepo root. + * @throws An error if the monorepo root is not found. + */ +function findMonorepoRoot(currentPath) { + const packageJsonPath = (0, node_path_1.join)(currentPath, 'package.json'); + const pnpmWorkspacePath = (0, node_path_1.join)(currentPath, 'pnpm-workspace.yaml'); + if ((0, node_fs_1.existsSync)(pnpmWorkspacePath) || + ((0, node_fs_1.existsSync)(packageJsonPath) && JSON.parse((0, node_fs_1.readFileSync)(packageJsonPath, 'utf-8')).workspaces)) { + return currentPath; + } + const parentPath = (0, node_path_1.dirname)(currentPath); + if (parentPath === currentPath) { + throw new Error('Monorepo root not found'); + } + return findMonorepoRoot(parentPath); +} +exports.findMonorepoRoot = findMonorepoRoot; +/** + * Finds the NX monorepo root from the given path. + * @param currentPath - The current path to start searching from. + * @returns The path to the monorepo root. + * @throws An error if the monorepo root is not found. + */ +function findNXMonorepoRoot(currentPath) { + const nxJsonPath = (0, node_path_1.join)(currentPath, 'nx.json'); + if ((0, node_fs_1.existsSync)(nxJsonPath)) { + return currentPath; + } + const parentPath = (0, node_path_1.dirname)(currentPath); + if (parentPath === currentPath) { + throw new Error('Monorepo root not found'); + } + return findNXMonorepoRoot(parentPath); +} +exports.findNXMonorepoRoot = findNXMonorepoRoot; +/** + * Finds the path to a package within the node_modules folder, + * searching up the directory hierarchy until the last possible directory is reached. + * @param packageName - The name of the package to find. + * @param currentPath - The current path to start searching from. + * @param lastPossibleDirectory - The last possible directory to search for the package. + * @returns The path to the package, or null if not found. + */ +function findPackagePath(packageName, currentPath, lastPossibleDirectory) { + const nodeModulesPath = (0, node_path_1.join)(currentPath, 'node_modules', packageName); + if ((0, node_fs_1.existsSync)(nodeModulesPath)) { + return nodeModulesPath; + } + if (currentPath === lastPossibleDirectory) { + return null; + } + const parentPath = (0, node_path_1.dirname)(currentPath); + return findPackagePath(packageName, parentPath, lastPossibleDirectory); +} +exports.findPackagePath = findPackagePath; +/** + * Finds the relative path to a package from the current directory, + * using the monorepo root as the last possible directory. + * @param packageName - The name of the package to find. + * @param currentPath - The current path to start searching from. + * @returns The relative path to the package, or null if not found. + */ +function findPackageRelativePathInMonorepo(packageName, currentPath) { + const monorepoRoot = findMonorepoRoot(currentPath); + const packagePath = findPackagePath(packageName, currentPath, monorepoRoot); + if (packagePath) { + return (0, node_path_1.relative)(currentPath, packagePath); + } + return null; +} +exports.findPackageRelativePathInMonorepo = findPackageRelativePathInMonorepo; +/** + * Detects if the current directory is part of a monorepo (npm, yarn, pnpm). + * @param currentPath - The current path to start searching from. + * @returns True if the current directory is part of a monorepo, false otherwise. + */ +function isMonorepo(currentPath) { + try { + findMonorepoRoot(currentPath); + return true; + } + catch (error) { + return false; + } +} +exports.isMonorepo = isMonorepo; +/** + * Detects if the current directory is part of a nx integrated monorepo. + * @param currentPath - The current path to start searching from. + * @returns True if the current directory is part of a monorepo, false otherwise. + */ +function isNXMonorepo(currentPath) { + try { + findNXMonorepoRoot(currentPath); + return true; + } + catch (error) { + return false; + } +} +exports.isNXMonorepo = isNXMonorepo; diff --git a/node_modules/@capacitor/cli/dist/util/native-run.js b/node_modules/@capacitor/cli/dist/util/native-run.js new file mode 100644 index 0000000..2b1101e --- /dev/null +++ b/node_modules/@capacitor/cli/dist/util/native-run.js @@ -0,0 +1,63 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.getPlatformTargets = exports.runNativeRun = void 0; +const tslib_1 = require("tslib"); +const path_1 = require("path"); +const colors_1 = tslib_1.__importDefault(require("../colors")); +const errors_1 = require("../errors"); +const log_1 = require("../log"); +const node_1 = require("./node"); +const subprocess_1 = require("./subprocess"); +async function runNativeRun(args, options = {}) { + const p = (0, node_1.resolveNode)(__dirname, (0, path_1.dirname)('native-run/package'), 'bin/native-run'); + if (!p) { + (0, errors_1.fatal)(`${colors_1.default.input('native-run')} not found.`); + } + if (process.versions.pnp) { + return await (0, subprocess_1.runCommand)('yarn', ['node', p, ...args], options); + } + else { + return await (0, subprocess_1.runCommand)(p, args, options); + } +} +exports.runNativeRun = runNativeRun; +async function getPlatformTargets(platformName) { + const errors = []; + try { + const output = await runNativeRun([platformName, '--list', '--json']); + const parsedOutput = JSON.parse(output); + if (parsedOutput.devices.length || parsedOutput.virtualDevices.length) { + return [ + ...parsedOutput.devices.map((t) => ({ ...t, virtual: false })), + ...parsedOutput.virtualDevices.map((t) => ({ + ...t, + virtual: true, + })), + ]; + } + else { + parsedOutput.errors.map((e) => { + errors.push(e); + }); + } + } + catch (e) { + const err = JSON.parse(e); + errors.push(err); + } + if (errors.length === 0) { + log_1.logger.info('No devices found.'); + return []; + } + const plural = errors.length > 1 ? 's' : ''; + const errMsg = `${colors_1.default.strong('native-run')} failed with error${plural}\n + ${errors + .map((e) => { + return `\t${colors_1.default.strong(e.code)}: ${e.error}`; + }) + .join('\n')} + \n\tMore details for this error${plural} may be available online: ${colors_1.default.strong('https://github.com/ionic-team/native-run/wiki/Android-Errors')} + `; + throw errMsg; +} +exports.getPlatformTargets = getPlatformTargets; diff --git a/node_modules/@capacitor/cli/dist/util/node.js b/node_modules/@capacitor/cli/dist/util/node.js new file mode 100644 index 0000000..7a0a3f8 --- /dev/null +++ b/node_modules/@capacitor/cli/dist/util/node.js @@ -0,0 +1,54 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.resolveNode = exports.requireTS = void 0; +const fs_1 = require("fs"); +const fs_extra_1 = require("fs-extra"); +const path_1 = require("path"); +/** + * @see https://github.com/ionic-team/stencil/blob/HEAD/src/compiler/sys/node-require.ts + */ +const requireTS = (ts, p) => { + const id = (0, path_1.resolve)(p); + delete require.cache[id]; + require.extensions['.ts'] = (module, fileName) => { + var _a; + let sourceText = (0, fs_extra_1.readFileSync)(fileName, 'utf8'); + if (fileName.endsWith('.ts')) { + const tsResults = ts.transpileModule(sourceText, { + fileName, + compilerOptions: { + module: ts.ModuleKind.CommonJS, + moduleResolution: ts.ModuleResolutionKind.NodeJs, + esModuleInterop: true, + strict: true, + target: ts.ScriptTarget.ES2017, + }, + reportDiagnostics: true, + }); + sourceText = tsResults.outputText; + } + else { + // quick hack to turn a modern es module + // into and old school commonjs module + sourceText = sourceText.replace(/export\s+\w+\s+(\w+)/gm, 'exports.$1'); + } + (_a = module._compile) === null || _a === void 0 ? void 0 : _a.call(module, sourceText, fileName); + }; + const m = require(id); // eslint-disable-line @typescript-eslint/no-var-requires + delete require.extensions['.ts']; + return m; +}; +exports.requireTS = requireTS; +function resolveNode(root, ...pathSegments) { + try { + return require.resolve(pathSegments.join('/'), { paths: [root] }); + } + catch (e) { + const path = [root, 'node_modules', ...pathSegments].join('/'); + if ((0, fs_1.existsSync)(path)) { + return path; + } + return null; + } +} +exports.resolveNode = resolveNode; diff --git a/node_modules/@capacitor/cli/dist/util/promise.js b/node_modules/@capacitor/cli/dist/util/promise.js new file mode 100644 index 0000000..b3bbfd8 --- /dev/null +++ b/node_modules/@capacitor/cli/dist/util/promise.js @@ -0,0 +1,35 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.lazy = exports.LazyPromise = exports.allSerial = void 0; +function allSerial(funcs) { + return funcs.reduce((promise, func) => promise.then((result) => func().then((x) => result.concat(x))), Promise.resolve([])); +} +exports.allSerial = allSerial; +class LazyPromise extends Promise { + constructor(executor) { + super(() => { + /* ignore */ + }); + this._executor = executor; + } + then(onfulfilled, onrejected) { + this._promise = this._promise || new Promise(this._executor); + return this._promise.then(onfulfilled, onrejected); + } + catch(onrejected) { + this._promise = this._promise || new Promise(this._executor); + return this._promise.catch(onrejected); + } +} +exports.LazyPromise = LazyPromise; +function lazy(fn) { + return new LazyPromise(async (resolve, reject) => { + try { + resolve(await fn()); + } + catch (e) { + reject(e); + } + }); +} +exports.lazy = lazy; diff --git a/node_modules/@capacitor/cli/dist/util/spm.js b/node_modules/@capacitor/cli/dist/util/spm.js new file mode 100644 index 0000000..d3f6de5 --- /dev/null +++ b/node_modules/@capacitor/cli/dist/util/spm.js @@ -0,0 +1,256 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.checkPackageTraitsRequirements = exports.checkSwiftToolsVersion = exports.addInfoPlistDebugIfNeeded = exports.runCocoapodsDeintegrate = exports.generatePackageText = exports.removeCocoapodsFiles = exports.extractSPMPackageDirectory = exports.checkPluginsForPackageSwift = exports.generatePackageFile = exports.findPackageSwiftFile = exports.checkPackageManager = void 0; +const fs_extra_1 = require("fs-extra"); +const os_1 = require("os"); +const path_1 = require("path"); +const plist_1 = require("plist"); +const tar_1 = require("tar"); +const common_1 = require("../common"); +const errors_1 = require("../errors"); +const common_2 = require("../ios/common"); +const log_1 = require("../log"); +const plugin_1 = require("../plugin"); +const subprocess_1 = require("../util/subprocess"); +/** + * @deprecated use config.ios.packageManager + * @param config + * @returns 'Cocoapods' | 'SPM' + */ +async function checkPackageManager(config) { + const iosDirectory = config.ios.nativeProjectDirAbs; + if ((0, fs_extra_1.existsSync)((0, path_1.resolve)(iosDirectory, 'CapApp-SPM'))) { + return 'SPM'; + } + return 'Cocoapods'; +} +exports.checkPackageManager = checkPackageManager; +async function findPackageSwiftFile(config) { + const packageDirectory = (0, path_1.resolve)(config.ios.nativeProjectDirAbs, 'CapApp-SPM'); + return (0, path_1.resolve)(packageDirectory, 'Package.swift'); +} +exports.findPackageSwiftFile = findPackageSwiftFile; +async function generatePackageFile(config, plugins) { + const packageSwiftFile = await findPackageSwiftFile(config); + try { + log_1.logger.info('Writing Package.swift'); + const textToWrite = await generatePackageText(config, plugins); + (0, fs_extra_1.writeFileSync)(packageSwiftFile, textToWrite); + } + catch (err) { + log_1.logger.error(`Unable to write to ${packageSwiftFile}. Verify it is not already open. \n Error: ${err}`); + } +} +exports.generatePackageFile = generatePackageFile; +async function checkPluginsForPackageSwift(config, plugins) { + const iOSCapacitorPlugins = plugins.filter((p) => (0, plugin_1.getPluginType)(p, 'ios') === 0 /* PluginType.Core */); + const packageSwiftPluginList = await pluginsWithPackageSwift(iOSCapacitorPlugins); + if (iOSCapacitorPlugins.length == packageSwiftPluginList.length) { + log_1.logger.debug(`Found ${iOSCapacitorPlugins.length} Capacitor iOS plugins, ${packageSwiftPluginList.length} have a Package.swift file`); + log_1.logger.info('All Capacitor plugins have a Package.swift file and will be included in Package.swift'); + } + else { + log_1.logger.warn('Some installed Capacitor plugins are not compatible with SPM'); + } + return packageSwiftPluginList; +} +exports.checkPluginsForPackageSwift = checkPluginsForPackageSwift; +async function extractSPMPackageDirectory(config) { + const spmDirectory = (0, path_1.join)(config.ios.nativeProjectDirAbs, 'CapApp-SPM'); + const spmTemplate = (0, path_1.join)(config.cli.assetsDirAbs, 'ios-spm-template.tar.gz'); + const debugConfig = (0, path_1.join)(config.ios.platformDirAbs, 'debug.xcconfig'); + log_1.logger.info('Extracting ' + spmTemplate + ' to ' + spmDirectory); + try { + const tempCapDir = await (0, fs_extra_1.mkdtemp)((0, path_1.join)((0, os_1.tmpdir)(), 'cap-')); + const tempCapSPM = (0, path_1.join)(tempCapDir, 'App', 'CapApp-SPM'); + const tempDebugXCConfig = (0, path_1.join)(tempCapDir, 'debug.xcconfig'); + await (0, tar_1.extract)({ file: spmTemplate, cwd: tempCapDir }); + await (0, fs_extra_1.move)(tempCapSPM, spmDirectory); + await (0, fs_extra_1.move)(tempDebugXCConfig, debugConfig); + } + catch (err) { + (0, errors_1.fatal)('Failed to create ' + spmDirectory + ' with error: ' + err); + } +} +exports.extractSPMPackageDirectory = extractSPMPackageDirectory; +async function removeCocoapodsFiles(config) { + const iosDirectory = config.ios.nativeProjectDirAbs; + const podFile = (0, path_1.resolve)(iosDirectory, 'Podfile'); + const podlockFile = (0, path_1.resolve)(iosDirectory, 'Podfile.lock'); + const xcworkspaceFile = (0, path_1.resolve)(iosDirectory, 'App.xcworkspace'); + await (0, fs_extra_1.remove)(podFile); + await (0, fs_extra_1.remove)(podlockFile); + await (0, fs_extra_1.remove)(xcworkspaceFile); +} +exports.removeCocoapodsFiles = removeCocoapodsFiles; +async function generatePackageText(config, plugins) { + var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o; + const iosPlatformVersion = await (0, common_1.getCapacitorPackageVersion)(config, config.ios.name); + const iosVersion = (0, common_2.getMajoriOSVersion)(config); + const packageTraits = (_d = (_c = (_b = (_a = config.app.extConfig.experimental) === null || _a === void 0 ? void 0 : _a.ios) === null || _b === void 0 ? void 0 : _b.spm) === null || _c === void 0 ? void 0 : _c.packageTraits) !== null && _d !== void 0 ? _d : {}; + const swiftToolsVersion = (_h = (_g = (_f = (_e = config.app.extConfig.experimental) === null || _e === void 0 ? void 0 : _e.ios) === null || _f === void 0 ? void 0 : _f.spm) === null || _g === void 0 ? void 0 : _g.swiftToolsVersion) !== null && _h !== void 0 ? _h : '5.9'; + let packageSwiftText = `// swift-tools-version: ${swiftToolsVersion} +import PackageDescription + +// DO NOT MODIFY THIS FILE - managed by Capacitor CLI commands +let package = Package( + name: "CapApp-SPM", + platforms: [.iOS(.v${iosVersion})], + products: [ + .library( + name: "CapApp-SPM", + targets: ["CapApp-SPM"]) + ], + dependencies: [ + .package(url: "https://github.com/ionic-team/capacitor-swift-pm.git", exact: "${iosPlatformVersion}")`; + for (const plugin of plugins) { + if ((0, plugin_1.getPluginType)(plugin, config.ios.name) === 1 /* PluginType.Cordova */) { + const platformTag = (0, plugin_1.getPluginPlatform)(plugin, config.ios.name); + if ((_j = platformTag.$) === null || _j === void 0 ? void 0 : _j.package) { + const relPath = (0, path_1.relative)(config.ios.nativeXcodeProjDirAbs, plugin.rootPath); + packageSwiftText += `,\n .package(name: "${plugin.id}", path: "${relPath}")`; + } + else { + const sourceFiles = (0, plugin_1.getPlatformElement)(plugin, config.ios.name, 'source-file'); + const headerFiles = (0, plugin_1.getPlatformElement)(plugin, config.ios.name, 'header-file'); + if (sourceFiles.length === 0 && headerFiles.length === 0) { + continue; + } + packageSwiftText += `,\n .package(name: "${plugin.name}", path: "../../capacitor-cordova-ios-plugins/sources/${plugin.name}")`; + } + } + else { + const relPath = (0, path_1.relative)(config.ios.nativeXcodeProjDirAbs, plugin.rootPath); + const traits = packageTraits[plugin.id]; + const traitsSuffix = (traits === null || traits === void 0 ? void 0 : traits.length) + ? `, traits: [${traits + .map((t) => { + // Any trait is written with quotes, with the exception of .defaults + return /^\.?defaults?$/i.test(t) ? '.defaults' : `"${t}"`; + }) + .join(', ')}]` + : ''; + packageSwiftText += `,\n .package(name: "${(_k = plugin.ios) === null || _k === void 0 ? void 0 : _k.name}", path: "${relPath}"${traitsSuffix})`; + } + } + packageSwiftText += ` + ], + targets: [ + .target( + name: "CapApp-SPM", + dependencies: [ + .product(name: "Capacitor", package: "capacitor-swift-pm"), + .product(name: "Cordova", package: "capacitor-swift-pm")`; + for (const plugin of plugins) { + let pluginText = `,\n .product(name: "${(_l = plugin.ios) === null || _l === void 0 ? void 0 : _l.name}", package: "${(_m = plugin.ios) === null || _m === void 0 ? void 0 : _m.name}")`; + if ((0, plugin_1.getPluginType)(plugin, config.ios.name) === 1 /* PluginType.Cordova */) { + const platformTag = (0, plugin_1.getPluginPlatform)(plugin, config.ios.name); + if ((_o = platformTag.$) === null || _o === void 0 ? void 0 : _o.package) { + pluginText = `,\n .product(name: "${plugin.id}", package: "${plugin.id}")`; + } + else { + const sourceFiles = (0, plugin_1.getPlatformElement)(plugin, config.ios.name, 'source-file'); + const headerFiles = (0, plugin_1.getPlatformElement)(plugin, config.ios.name, 'header-file'); + if (sourceFiles.length === 0 && headerFiles.length === 0) { + pluginText = ''; + } + } + } + packageSwiftText += pluginText; + } + packageSwiftText += ` + ] + ) + ] +) +`; + return packageSwiftText; +} +exports.generatePackageText = generatePackageText; +async function runCocoapodsDeintegrate(config) { + const podPath = await config.ios.podPath; + const projectFileName = config.ios.nativeXcodeProjDirAbs; + const useBundler = (await config.ios.packageManager) === 'bundler'; + log_1.logger.info('Running pod deintegrate on project ' + projectFileName); + if (useBundler) { + log_1.logger.info('Found bundler, using it to run CocoaPods.'); + await (0, subprocess_1.runCommand)('bundle', ['exec', 'pod', 'deintegrate', projectFileName], { + cwd: config.ios.nativeProjectDirAbs, + }); + } + else { + await (0, subprocess_1.runCommand)(podPath, ['deintegrate', projectFileName], { + cwd: config.ios.nativeProjectDirAbs, + }); + } +} +exports.runCocoapodsDeintegrate = runCocoapodsDeintegrate; +async function addInfoPlistDebugIfNeeded(config) { + const infoPlist = (0, path_1.resolve)(config.ios.nativeTargetDirAbs, 'Info.plist'); + log_1.logger.info('Checking ' + infoPlist + ' for CAPACITOR_DEBUG'); + if ((0, fs_extra_1.existsSync)(infoPlist)) { + const infoPlistContents = (0, fs_extra_1.readFileSync)(infoPlist, 'utf-8'); + const plistEntries = (0, plist_1.parse)(infoPlistContents); + if (plistEntries['CAPACITOR_DEBUG'] === undefined) { + log_1.logger.info('Writing CAPACITOR_DEBUG to ' + infoPlist); + plistEntries['CAPACITOR_DEBUG'] = '$(CAPACITOR_DEBUG)'; + const plistToWrite = (0, plist_1.build)(plistEntries); + (0, fs_extra_1.writeFileSync)(infoPlist, plistToWrite); + } + else { + log_1.logger.warn('Found CAPACITOR_DEBUG set to ' + plistEntries['CAPACITOR_DEBUG'] + ', skipping.'); + } + } + else { + log_1.logger.warn(infoPlist + ' not found.'); + } +} +exports.addInfoPlistDebugIfNeeded = addInfoPlistDebugIfNeeded; +async function checkSwiftToolsVersion(config, version) { + if (!version) { + return null; + } + const swiftToolsVersionRegex = /^[0-9]+\.[0-9]+(\.[0-9]+)?$/; + if (!swiftToolsVersionRegex.test(version)) { + return (`Invalid Swift tools version: "${version}".\n` + + `The Swift tools version must be in major.minor or major.minor.patch format (e.g., "5.9", "6.0", "5.9.2").`); + } + return null; +} +exports.checkSwiftToolsVersion = checkSwiftToolsVersion; +async function checkPackageTraitsRequirements(config) { + var _a, _b, _c, _d, _e, _f; + const packageTraits = (_c = (_b = (_a = config.app.extConfig.experimental) === null || _a === void 0 ? void 0 : _a.ios) === null || _b === void 0 ? void 0 : _b.spm) === null || _c === void 0 ? void 0 : _c.packageTraits; + const swiftToolsVersion = (_f = (_e = (_d = config.app.extConfig.experimental) === null || _d === void 0 ? void 0 : _d.ios) === null || _e === void 0 ? void 0 : _e.spm) === null || _f === void 0 ? void 0 : _f.swiftToolsVersion; + const hasPackageTraits = packageTraits && Object.keys(packageTraits).some((key) => { var _a; return ((_a = packageTraits[key]) === null || _a === void 0 ? void 0 : _a.length) > 0; }); + if (!hasPackageTraits) { + return null; + } + if (!swiftToolsVersion) { + return (`Package traits require an explicit Swift tools version of 6.1 or higher.\n` + + `Set experimental.ios.spm.swiftToolsVersion to '6.1' or higher in your Capacitor configuration.`); + } + const versionParts = swiftToolsVersion.split('.').map((part) => parseInt(part, 10)); + const major = versionParts[0] || 0; + const minor = versionParts[1] || 0; + if (major < 6 || (major === 6 && minor < 1)) { + return (`Package traits require Swift tools version 6.1 or higher, but "${swiftToolsVersion}" was specified.\n` + + `Update experimental.ios.spm.swiftToolsVersion to '6.1' or higher in your Capacitor configuration.`); + } + return null; +} +exports.checkPackageTraitsRequirements = checkPackageTraitsRequirements; +// Private Functions +async function pluginsWithPackageSwift(plugins) { + const pluginList = []; + for (const plugin of plugins) { + const packageSwiftFound = await (0, fs_extra_1.pathExists)((0, path_1.join)(plugin.rootPath, 'Package.swift')); + if (packageSwiftFound) { + pluginList.push(plugin); + } + else { + log_1.logger.warn(plugin.id + ' does not have a Package.swift'); + } + } + return pluginList; +} diff --git a/node_modules/@capacitor/cli/dist/util/subprocess.js b/node_modules/@capacitor/cli/dist/util/subprocess.js new file mode 100644 index 0000000..0bcefb5 --- /dev/null +++ b/node_modules/@capacitor/cli/dist/util/subprocess.js @@ -0,0 +1,37 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.isInstalled = exports.getCommandOutput = exports.runCommand = void 0; +const utils_subprocess_1 = require("@ionic/utils-subprocess"); +async function runCommand(command, args, options = {}) { + const p = new utils_subprocess_1.Subprocess(command, args, options); + try { + return await p.output(); + } + catch (e) { + if (e instanceof utils_subprocess_1.SubprocessError) { + // old behavior of just throwing the stdout/stderr strings + throw e.output ? e.output : e.cause ? `${e.message} ${e.cause.toString()}` : e.code ? e.code : 'Unknown error'; + } + throw e; + } +} +exports.runCommand = runCommand; +async function getCommandOutput(command, args, options = {}) { + try { + return (await runCommand(command, args, options)).trim(); + } + catch (e) { + return null; + } +} +exports.getCommandOutput = getCommandOutput; +async function isInstalled(command) { + try { + await (0, utils_subprocess_1.which)(command); + } + catch (e) { + return false; + } + return true; +} +exports.isInstalled = isInstalled; diff --git a/node_modules/@capacitor/cli/dist/util/template.js b/node_modules/@capacitor/cli/dist/util/template.js new file mode 100644 index 0000000..4313784 --- /dev/null +++ b/node_modules/@capacitor/cli/dist/util/template.js @@ -0,0 +1,10 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.extractTemplate = void 0; +const fs_extra_1 = require("fs-extra"); +const tar_1 = require("tar"); +async function extractTemplate(src, dir) { + await (0, fs_extra_1.mkdirp)(dir); + await (0, tar_1.extract)({ file: src, cwd: dir }); +} +exports.extractTemplate = extractTemplate; diff --git a/node_modules/@capacitor/cli/dist/util/term.js b/node_modules/@capacitor/cli/dist/util/term.js new file mode 100644 index 0000000..00615c7 --- /dev/null +++ b/node_modules/@capacitor/cli/dist/util/term.js @@ -0,0 +1,30 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.isInteractive = exports.checkInteractive = void 0; +const tslib_1 = require("tslib"); +const utils_terminal_1 = require("@ionic/utils-terminal"); +const colors_1 = tslib_1.__importDefault(require("../colors")); +const log_1 = require("../log"); +// Given input variables to a command, make sure all are provided if the terminal +// is not interactive (because we won't be able to prompt the user) +const checkInteractive = (...args) => { + if ((0, exports.isInteractive)()) { + return true; + } + // Fail if no args are provided, treat this as just a check of whether the term is + // interactive or not. + if (!args.length) { + return false; + } + // Make sure none of the provided args are empty, otherwise print the interactive + // warning and return false + if (args.filter((arg) => !arg).length) { + log_1.logger.error(`Non-interactive shell detected.\n` + + `Run the command with ${colors_1.default.input('--help')} to see a list of arguments that must be provided.`); + return false; + } + return true; +}; +exports.checkInteractive = checkInteractive; +const isInteractive = () => utils_terminal_1.TERMINAL_INFO.tty && !utils_terminal_1.TERMINAL_INFO.ci; +exports.isInteractive = isInteractive; diff --git a/node_modules/@capacitor/cli/dist/util/uuid.js b/node_modules/@capacitor/cli/dist/util/uuid.js new file mode 100644 index 0000000..07c0324 --- /dev/null +++ b/node_modules/@capacitor/cli/dist/util/uuid.js @@ -0,0 +1,11 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.uuidv4 = void 0; +function uuidv4() { + return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => { + const r = (Math.random() * 16) | 0; + const v = c == 'x' ? r : (r & 0x3) | 0x8; + return v.toString(16); + }); +} +exports.uuidv4 = uuidv4; diff --git a/node_modules/@capacitor/cli/dist/util/xml.js b/node_modules/@capacitor/cli/dist/util/xml.js new file mode 100644 index 0000000..7acedc8 --- /dev/null +++ b/node_modules/@capacitor/cli/dist/util/xml.js @@ -0,0 +1,55 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.buildXmlElement = exports.writeXML = exports.parseXML = exports.readXML = void 0; +const tslib_1 = require("tslib"); +const fs_extra_1 = require("fs-extra"); +const xml2js_1 = tslib_1.__importDefault(require("xml2js")); +async function readXML(path) { + var _a; + try { + const xmlStr = await (0, fs_extra_1.readFile)(path, { encoding: 'utf-8' }); + try { + return await xml2js_1.default.parseStringPromise(xmlStr); + } + catch (e) { + throw `Error parsing: ${path}, ${(_a = e.stack) !== null && _a !== void 0 ? _a : e}`; + } + } + catch (e) { + throw `Unable to read: ${path}`; + } +} +exports.readXML = readXML; +function parseXML(xmlStr, options) { + const parser = options !== undefined ? new xml2js_1.default.Parser({ ...options }) : new xml2js_1.default.Parser(); + let xmlObj; + parser.parseString(xmlStr, (err, result) => { + if (!err) { + xmlObj = result; + } + }); + return xmlObj; +} +exports.parseXML = parseXML; +async function writeXML(object) { + return new Promise((resolve) => { + const builder = new xml2js_1.default.Builder({ + headless: true, + explicitRoot: false, + rootName: 'deleteme', + }); + let xml = builder.buildObject(object); + xml = xml.replace('', '').replace('', ''); + resolve(xml); + }); +} +exports.writeXML = writeXML; +function buildXmlElement(configElement, rootName) { + const builder = new xml2js_1.default.Builder({ + headless: true, + explicitRoot: false, + rootName: rootName, + }); + return builder.buildObject(configElement); +} +exports.buildXmlElement = buildXmlElement; diff --git a/node_modules/@capacitor/cli/package.json b/node_modules/@capacitor/cli/package.json new file mode 100644 index 0000000..9df346b --- /dev/null +++ b/node_modules/@capacitor/cli/package.json @@ -0,0 +1,88 @@ +{ + "name": "@capacitor/cli", + "version": "8.3.4", + "description": "Capacitor: Cross-platform apps with JavaScript and the web", + "homepage": "https://capacitorjs.com", + "author": "Ionic Team (https://ionic.io)", + "license": "MIT", + "repository": { + "type": "git", + "url": "https://github.com/ionic-team/capacitor.git" + }, + "bugs": { + "url": "https://github.com/ionic-team/capacitor/issues" + }, + "files": [ + "assets/", + "bin/", + "dist/**/*.js", + "dist/declarations.d.ts" + ], + "keywords": [ + "ionic", + "ionic framework", + "capacitor", + "universal app", + "progressive web apps", + "cross platform" + ], + "engines": { + "node": ">=22.0.0" + }, + "main": "dist/index.js", + "types": "dist/declarations.d.ts", + "bin": { + "capacitor": "./bin/capacitor", + "cap": "./bin/capacitor" + }, + "scripts": { + "build": "npm run clean && npm run assets && tsc", + "clean": "rimraf ./dist", + "assets": "node ../scripts/pack-cli-assets.mjs", + "prepublishOnly": "npm run build", + "test": "jest -i", + "watch": "npm run assets && tsc -w" + }, + "dependencies": { + "@ionic/cli-framework-output": "^2.2.8", + "@ionic/utils-subprocess": "^3.0.1", + "@ionic/utils-terminal": "^2.3.5", + "commander": "^12.1.0", + "debug": "^4.4.0", + "env-paths": "^2.2.0", + "fs-extra": "^11.2.0", + "kleur": "^4.1.5", + "native-run": "^2.0.3", + "open": "^8.4.0", + "plist": "^3.1.0", + "prompts": "^2.4.2", + "rimraf": "^6.0.1", + "semver": "^7.6.3", + "tar": "^7.5.3", + "tslib": "^2.8.1", + "xml2js": "^0.6.2" + }, + "devDependencies": { + "@types/debug": "^4.1.12", + "@types/fs-extra": "^11.0.4", + "@types/jest": "^29.5.14", + "@types/plist": "^3.0.5", + "@types/prompts": "^2.4.9", + "@types/semver": "^7.5.8", + "@types/tmp": "^0.2.6", + "@types/xml2js": "0.4.5", + "jest": "^29.7.0", + "jest-environment-jsdom": "^29.7.0", + "jest-jasmine2": "^29.7.0", + "tmp": "^0.2.3", + "ts-jest": "^29.0.5", + "typescript": "~5.0.2" + }, + "jest": { + "preset": "ts-jest", + "testRunner": "jest-jasmine2" + }, + "publishConfig": { + "access": "public" + } +} diff --git a/node_modules/@capacitor/core/LICENSE b/node_modules/@capacitor/core/LICENSE new file mode 100644 index 0000000..c3e903b --- /dev/null +++ b/node_modules/@capacitor/core/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2017-present Drifty Co. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/node_modules/@capacitor/core/README.md b/node_modules/@capacitor/core/README.md new file mode 100644 index 0000000..e877ef3 --- /dev/null +++ b/node_modules/@capacitor/core/README.md @@ -0,0 +1,3 @@ +# Capacitor Core JS + +See the [Capacitor website](https://capacitorjs.com) for more information. diff --git a/node_modules/@capacitor/core/cookies.md b/node_modules/@capacitor/core/cookies.md new file mode 100644 index 0000000..a1d237e --- /dev/null +++ b/node_modules/@capacitor/core/cookies.md @@ -0,0 +1,250 @@ +# CapacitorCookies + +The Capacitor Cookies API provides native cookie support via patching `document.cookie` to use native libraries. It also provides methods for modifying cookies at a specific url. This plugin is bundled with `@capacitor/core`. + +## Configuration + +By default, the patching of `document.cookie` to use native libraries is disabled. +If you would like to enable this feature, modify the configuration below in the `capacitor.config` file. + +| Prop | Type | Description | Default | +| ------------- | -------------------- | ------------------------------------------------------------------------- | ------------------ | +| **`enabled`** | boolean | Enable the patching of `document.cookie` to use native libraries instead. | false | + +### Example Configuration + +In `capacitor.config.json`: + +```json +{ + "plugins": { + "CapacitorCookies": { + "enabled": true + } + } +} +``` + +In `capacitor.config.ts`: + +```ts +import { CapacitorConfig } from '@capacitor/cli'; + +const config: CapacitorConfig = { + plugins: { + CapacitorCookies: { + enabled: true, + }, + }, +}; + +export default config; +``` + +## Example + +```typescript +import { CapacitorCookies } from '@capacitor/core'; + +const getCookies = () => { + return document.cookie; +}; + +const setCookie = () => { + document.cookie = key + '=' + value; +}; + +const setCapacitorCookie = async () => { + await CapacitorCookies.setCookie({ + url: 'http://example.com', + key: 'language', + value: 'en', + }); +}; + +const deleteCookie = async () => { + await CapacitorCookies.deleteCookie({ + url: 'https://example.com', + key: 'language', + }); +}; + +const clearCookiesOnUrl = async () => { + await CapacitorCookies.clearCookies({ + url: 'https://example.com', + }); +}; + +const clearAllCookies = async () => { + await CapacitorCookies.clearAllCookies(); +}; +``` + +## Third Party Cookies on iOS + +As of iOS 14, you cannot use 3rd party cookies by default. Add the following lines to your Info.plist file to get better support for cookies on iOS. You can add up to 10 domains. + +```xml +WKAppBoundDomains + + www.mydomain.com + api.mydomain.com + www.myothercooldomain.com + +``` + +## API + + + +* [`getCookies(...)`](#getcookies) +* [`setCookie(...)`](#setcookie) +* [`deleteCookie(...)`](#deletecookie) +* [`clearCookies(...)`](#clearcookies) +* [`clearAllCookies()`](#clearallcookies) +* [Interfaces](#interfaces) +* [Type Aliases](#type-aliases) + + + + + + +### getCookies(...) + +```typescript +getCookies(options?: GetCookieOptions) => Promise +``` + +| Param | Type | +| ------------- | ------------------------------------------------------------- | +| **`options`** | GetCookieOptions | + +**Returns:** Promise<HttpCookieMap> + +-------------------- + + +### setCookie(...) + +```typescript +setCookie(options: SetCookieOptions) => Promise +``` + +Write a cookie to the device. + +| Param | Type | +| ------------- | ------------------------------------------------------------- | +| **`options`** | SetCookieOptions | + +-------------------- + + +### deleteCookie(...) + +```typescript +deleteCookie(options: DeleteCookieOptions) => Promise +``` + +Delete a cookie from the device. + +| Param | Type | +| ------------- | ------------------------------------------------------------------- | +| **`options`** | DeleteCookieOptions | + +-------------------- + + +### clearCookies(...) + +```typescript +clearCookies(options: ClearCookieOptions) => Promise +``` + +Clear cookies from the device at a given URL. + +| Param | Type | +| ------------- | ----------------------------------------------------------------- | +| **`options`** | ClearCookieOptions | + +-------------------- + + +### clearAllCookies() + +```typescript +clearAllCookies() => Promise +``` + +Clear all cookies on the device. + +-------------------- + + +### Interfaces + + +#### HttpCookieMap + + +#### HttpCookie + +| Prop | Type | Description | +| ----------- | ------------------- | ------------------------ | +| **`url`** | string | The URL of the cookie. | +| **`key`** | string | The key of the cookie. | +| **`value`** | string | The value of the cookie. | + + +#### HttpCookieExtras + +| Prop | Type | Description | +| ------------- | ------------------- | -------------------------------- | +| **`path`** | string | The path to write the cookie to. | +| **`expires`** | string | The date to expire the cookie. | + + +### Type Aliases + + +#### GetCookieOptions + +Omit<HttpCookie, 'key' | 'value'> + + +#### Omit + +Construct a type with the properties of T except for those in type K. + +Pick<T, Exclude<keyof T, K>> + + +#### Pick + +From T, pick a set of properties whose keys are in the union K + +{ [P in K]: T[P]; } + + +#### Exclude + +Exclude from T those types that are assignable to U + +T extends U ? never : T + + +#### SetCookieOptions + +HttpCookie & HttpCookieExtras + + +#### DeleteCookieOptions + +Omit<HttpCookie, 'value'> + + +#### ClearCookieOptions + +Omit<HttpCookie, 'key' | 'value'> + + \ No newline at end of file diff --git a/node_modules/@capacitor/core/cordova.js b/node_modules/@capacitor/core/cordova.js new file mode 100644 index 0000000..b0219ff --- /dev/null +++ b/node_modules/@capacitor/core/cordova.js @@ -0,0 +1,1559 @@ +// Platform: Capacitor +/* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you 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. +*/ +(function () { + var PLATFORM_VERSION_BUILD_LABEL = '1.0.0'; + // file: src/scripts/require.js + + /* jshint -W079 */ + /* jshint -W020 */ + + var require; + var define; + + (function () { + var modules = {}; + // Stack of moduleIds currently being built. + var requireStack = []; + // Map of module ID -> index into requireStack of modules currently being built. + var inProgressModules = {}; + var SEPARATOR = '.'; + + function build(module) { + var factory = module.factory; + var localRequire = function (id) { + var resultantId = id; + // Its a relative path, so lop off the last portion and add the id (minus "./") + if (id.charAt(0) === '.') { + resultantId = module.id.slice(0, module.id.lastIndexOf(SEPARATOR)) + SEPARATOR + id.slice(2); + } + return require(resultantId); + }; + module.exports = {}; + delete module.factory; + factory(localRequire, module.exports, module); + return module.exports; + } + + require = function (id) { + if (!modules[id]) { + throw 'module ' + id + ' not found'; + } else if (id in inProgressModules) { + var cycle = requireStack.slice(inProgressModules[id]).join('->') + '->' + id; + throw 'Cycle in require graph: ' + cycle; + } + if (modules[id].factory) { + try { + inProgressModules[id] = requireStack.length; + requireStack.push(id); + return build(modules[id]); + } finally { + delete inProgressModules[id]; + requireStack.pop(); + } + } + return modules[id].exports; + }; + + define = function (id, factory) { + if (modules[id]) { + throw 'module ' + id + ' already defined'; + } + + modules[id] = { + id: id, + factory: factory, + }; + }; + + define.remove = function (id) { + delete modules[id]; + }; + + define.moduleMap = modules; + })(); + + // Export for use in node + if (typeof module === 'object' && typeof require === 'function') { + module.exports.require = require; + module.exports.define = define; + } + + // file: src/cordova.js + define('cordova', function (require, exports, module) { + var channel = require('cordova/channel'); + var platform = require('cordova/platform'); + + /** + * Intercept calls to addEventListener + removeEventListener and handle deviceready, + * resume, and pause events. + */ + var m_document_addEventListener = document.addEventListener; + var m_document_removeEventListener = document.removeEventListener; + var m_window_addEventListener = window.addEventListener; + var m_window_removeEventListener = window.removeEventListener; + + /** + * Houses custom event handlers to intercept on document + window event listeners. + */ + var documentEventHandlers = {}; + var windowEventHandlers = {}; + + document.addEventListener = function (evt, handler, capture) { + var e = evt.toLowerCase(); + if (typeof documentEventHandlers[e] !== 'undefined') { + documentEventHandlers[e].subscribe(handler); + } else { + m_document_addEventListener.call(document, evt, handler, capture); + } + }; + + window.addEventListener = function (evt, handler, capture) { + var e = evt.toLowerCase(); + if (typeof windowEventHandlers[e] !== 'undefined') { + windowEventHandlers[e].subscribe(handler); + } else { + m_window_addEventListener.call(window, evt, handler, capture); + } + }; + + document.removeEventListener = function (evt, handler, capture) { + var e = evt.toLowerCase(); + // If unsubscribing from an event that is handled by a plugin + if (typeof documentEventHandlers[e] !== 'undefined') { + documentEventHandlers[e].unsubscribe(handler); + } else { + m_document_removeEventListener.call(document, evt, handler, capture); + } + }; + + window.removeEventListener = function (evt, handler, capture) { + var e = evt.toLowerCase(); + // If unsubscribing from an event that is handled by a plugin + if (typeof windowEventHandlers[e] !== 'undefined') { + windowEventHandlers[e].unsubscribe(handler); + } else { + m_window_removeEventListener.call(window, evt, handler, capture); + } + }; + + /* eslint-disable no-undef */ + var cordova = { + define: define, + require: require, + version: PLATFORM_VERSION_BUILD_LABEL, + platformVersion: PLATFORM_VERSION_BUILD_LABEL, + platformId: platform.id, + + /* eslint-enable no-undef */ + + /** + * Methods to add/remove your own addEventListener hijacking on document + window. + */ + addWindowEventHandler: function (event) { + return (windowEventHandlers[event] = channel.create(event)); + }, + addStickyDocumentEventHandler: function (event) { + return (documentEventHandlers[event] = channel.createSticky(event)); + }, + addDocumentEventHandler: function (event) { + return (documentEventHandlers[event] = channel.create(event)); + }, + removeWindowEventHandler: function (event) { + delete windowEventHandlers[event]; + }, + removeDocumentEventHandler: function (event) { + delete documentEventHandlers[event]; + }, + /** + * Retrieve original event handlers that were replaced by Cordova + * + * @return object + */ + getOriginalHandlers: function () { + return { + document: { + addEventListener: m_document_addEventListener, + removeEventListener: m_document_removeEventListener, + }, + window: { + addEventListener: m_window_addEventListener, + removeEventListener: m_window_removeEventListener, + }, + }; + }, + /** + * Method to fire event from native code + * bNoDetach is required for events which cause an exception which needs to be caught in native code + */ + fireDocumentEvent: function (type, data, bNoDetach) { + var evt = window.Capacitor.createEvent(type, data); + if (typeof documentEventHandlers[type] !== 'undefined') { + if (bNoDetach) { + documentEventHandlers[type].fire(evt); + } else { + setTimeout(function () { + // Fire deviceready on listeners that were registered before cordova.js was loaded. + if (type === 'deviceready') { + document.dispatchEvent(evt); + } + documentEventHandlers[type].fire(evt); + }, 0); + } + } else { + document.dispatchEvent(evt); + } + }, + fireWindowEvent: function (type, data) { + var evt = window.Capacitor.createEvent(type, data); + if (typeof windowEventHandlers[type] !== 'undefined') { + setTimeout(function () { + windowEventHandlers[type].fire(evt); + }, 0); + } else { + window.dispatchEvent(evt); + } + }, + + /** + * Plugin callback mechanism. + */ + // Randomize the starting callbackId to avoid collisions after refreshing or navigating. + // This way, it's very unlikely that any new callback would get the same callbackId as an old callback. + callbackId: Math.floor(Math.random() * 2000000000), + callbacks: {}, + callbackStatus: { + NO_RESULT: 0, + OK: 1, + CLASS_NOT_FOUND_EXCEPTION: 2, + ILLEGAL_ACCESS_EXCEPTION: 3, + INSTANTIATION_EXCEPTION: 4, + MALFORMED_URL_EXCEPTION: 5, + IO_EXCEPTION: 6, + INVALID_ACTION: 7, + JSON_EXCEPTION: 8, + ERROR: 9, + }, + + /** + * Called by native code when returning successful result from an action. + */ + callbackSuccess: function (callbackId, args) { + cordova.callbackFromNative(callbackId, true, args.status, [args.message], args.keepCallback); + }, + + /** + * Called by native code when returning error result from an action. + */ + callbackError: function (callbackId, args) { + // TODO: Deprecate callbackSuccess and callbackError in favour of callbackFromNative. + // Derive success from status. + cordova.callbackFromNative(callbackId, false, args.status, [args.message], args.keepCallback); + }, + + /** + * Called by native code when returning the result from an action. + */ + callbackFromNative: function (callbackId, isSuccess, status, args, keepCallback) { + try { + var callback = cordova.callbacks[callbackId]; + if (callback) { + if (isSuccess && status === cordova.callbackStatus.OK) { + callback.success && callback.success.apply(null, args); + } else if (!isSuccess) { + callback.fail && callback.fail.apply(null, args); + } + /* + else + Note, this case is intentionally not caught. + this can happen if isSuccess is true, but callbackStatus is NO_RESULT + which is used to remove a callback from the list without calling the callbacks + typically keepCallback is false in this case + */ + // Clear callback if not expecting any more results + if (!keepCallback) { + delete cordova.callbacks[callbackId]; + } + } + } catch (err) { + var msg = 'Error in ' + (isSuccess ? 'Success' : 'Error') + ' callbackId: ' + callbackId + ' : ' + err; + console && console.log && console.log(msg); + cordova.fireWindowEvent('cordovacallbackerror', { message: msg }); + throw err; + } + }, + addConstructor: function (func) { + channel.onCordovaReady.subscribe(function () { + try { + func(); + } catch (e) { + console.log('Failed to run constructor: ' + e); + } + }); + }, + }; + + module.exports = cordova; + }); + + // file: src/common/argscheck.js + define('cordova/argscheck', function (require, exports, module) { + var utils = require('cordova/utils'); + + var moduleExports = module.exports; + + var typeMap = { + A: 'Array', + D: 'Date', + N: 'Number', + S: 'String', + F: 'Function', + O: 'Object', + }; + + function extractParamName(callee, argIndex) { + return /.*?\((.*?)\)/.exec(callee)[1].split(', ')[argIndex]; + } + + function checkArgs(spec, functionName, args, opt_callee) { + if (!moduleExports.enableChecks) { + return; + } + var errMsg = null; + var typeName; + for (var i = 0; i < spec.length; ++i) { + var c = spec.charAt(i); + var cUpper = c.toUpperCase(); + var arg = args[i]; + // Asterix means allow anything. + if (c === '*') { + continue; + } + typeName = utils.typeName(arg); + if ((arg === null || arg === undefined) && c === cUpper) { + continue; + } + if (typeName !== typeMap[cUpper]) { + errMsg = 'Expected ' + typeMap[cUpper]; + break; + } + } + if (errMsg) { + errMsg += ', but got ' + typeName + '.'; + errMsg = + 'Wrong type for parameter "' + + extractParamName(opt_callee || args.callee, i) + + '" of ' + + functionName + + ': ' + + errMsg; + // Don't log when running unit tests. + if (typeof jasmine === 'undefined') { + console.error(errMsg); + } + throw TypeError(errMsg); + } + } + + function getValue(value, defaultValue) { + return value === undefined ? defaultValue : value; + } + + moduleExports.checkArgs = checkArgs; + moduleExports.getValue = getValue; + moduleExports.enableChecks = true; + }); + + // file: src/common/base64.js + define('cordova/base64', function (require, exports, module) { + var base64 = exports; + + base64.fromArrayBuffer = function (arrayBuffer) { + var array = new Uint8Array(arrayBuffer); + return uint8ToBase64(array); + }; + + base64.toArrayBuffer = function (str) { + var decodedStr = typeof atob !== 'undefined' ? atob(str) : Buffer.from(str, 'base64').toString('binary'); // eslint-disable-line no-undef + var arrayBuffer = new ArrayBuffer(decodedStr.length); + var array = new Uint8Array(arrayBuffer); + for (var i = 0, len = decodedStr.length; i < len; i++) { + array[i] = decodedStr.charCodeAt(i); + } + return arrayBuffer; + }; + + // ------------------------------------------------------------------------------ + + /* This code is based on the performance tests at http://jsperf.com/b64tests + * This 12-bit-at-a-time algorithm was the best performing version on all + * platforms tested. + */ + + var b64_6bit = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; + var b64_12bit; + + var b64_12bitTable = function () { + b64_12bit = []; + for (var i = 0; i < 64; i++) { + for (var j = 0; j < 64; j++) { + b64_12bit[i * 64 + j] = b64_6bit[i] + b64_6bit[j]; + } + } + b64_12bitTable = function () { + return b64_12bit; + }; + return b64_12bit; + }; + + function uint8ToBase64(rawData) { + var numBytes = rawData.byteLength; + var output = ''; + var segment; + var table = b64_12bitTable(); + for (var i = 0; i < numBytes - 2; i += 3) { + segment = (rawData[i] << 16) + (rawData[i + 1] << 8) + rawData[i + 2]; + output += table[segment >> 12]; + output += table[segment & 0xfff]; + } + if (numBytes - i === 2) { + segment = (rawData[i] << 16) + (rawData[i + 1] << 8); + output += table[segment >> 12]; + output += b64_6bit[(segment & 0xfff) >> 6]; + output += '='; + } else if (numBytes - i === 1) { + segment = rawData[i] << 16; + output += table[segment >> 12]; + output += '=='; + } + return output; + } + }); + + // file: src/common/builder.js + define('cordova/builder', function (require, exports, module) { + var utils = require('cordova/utils'); + + function each(objects, func, context) { + for (var prop in objects) { + if (objects.hasOwnProperty(prop)) { + func.apply(context, [objects[prop], prop]); + } + } + } + + function clobber(obj, key, value) { + exports.replaceHookForTesting(obj, key); + var needsProperty = false; + try { + obj[key] = value; + } catch (e) { + needsProperty = true; + } + // Getters can only be overridden by getters. + if (needsProperty || obj[key] !== value) { + utils.defineGetter(obj, key, function () { + return value; + }); + } + } + + function assignOrWrapInDeprecateGetter(obj, key, value, message) { + if (message) { + utils.defineGetter(obj, key, function () { + console.log(message); + delete obj[key]; + clobber(obj, key, value); + return value; + }); + } else { + clobber(obj, key, value); + } + } + + function include(parent, objects, clobber, merge) { + each(objects, function (obj, key) { + try { + var result = obj.path ? require(obj.path) : {}; + + if (clobber) { + // Clobber if it doesn't exist. + if (typeof parent[key] === 'undefined') { + assignOrWrapInDeprecateGetter(parent, key, result, obj.deprecated); + } else if (typeof obj.path !== 'undefined') { + // If merging, merge properties onto parent, otherwise, clobber. + if (merge) { + recursiveMerge(parent[key], result); + } else { + assignOrWrapInDeprecateGetter(parent, key, result, obj.deprecated); + } + } + result = parent[key]; + } else { + // Overwrite if not currently defined. + if (typeof parent[key] === 'undefined') { + assignOrWrapInDeprecateGetter(parent, key, result, obj.deprecated); + } else { + // Set result to what already exists, so we can build children into it if they exist. + result = parent[key]; + } + } + + if (obj.children) { + include(result, obj.children, clobber, merge); + } + } catch (e) { + utils.alert('Exception building Cordova JS globals: ' + e + ' for key "' + key + '"'); + } + }); + } + + /** + * Merge properties from one object onto another recursively. Properties from + * the src object will overwrite existing target property. + * + * @param target Object to merge properties into. + * @param src Object to merge properties from. + */ + function recursiveMerge(target, src) { + for (var prop in src) { + if (src.hasOwnProperty(prop)) { + if (target.prototype && target.prototype.constructor === target) { + // If the target object is a constructor override off prototype. + clobber(target.prototype, prop, src[prop]); + } else { + if (typeof src[prop] === 'object' && typeof target[prop] === 'object') { + recursiveMerge(target[prop], src[prop]); + } else { + clobber(target, prop, src[prop]); + } + } + } + } + } + + exports.buildIntoButDoNotClobber = function (objects, target) { + include(target, objects, false, false); + }; + exports.buildIntoAndClobber = function (objects, target) { + include(target, objects, true, false); + }; + exports.buildIntoAndMerge = function (objects, target) { + include(target, objects, true, true); + }; + exports.recursiveMerge = recursiveMerge; + exports.assignOrWrapInDeprecateGetter = assignOrWrapInDeprecateGetter; + exports.replaceHookForTesting = function () {}; + }); + + // file: src/common/channel.js + define('cordova/channel', function (require, exports, module) { + var utils = require('cordova/utils'); + var nextGuid = 1; + + /** + * Custom pub-sub "channel" that can have functions subscribed to it + * This object is used to define and control firing of events for + * cordova initialization, as well as for custom events thereafter. + * + * The order of events during page load and Cordova startup is as follows: + * + * onDOMContentLoaded* Internal event that is received when the web page is loaded and parsed. + * onNativeReady* Internal event that indicates the Cordova native side is ready. + * onCordovaReady* Internal event fired when all Cordova JavaScript objects have been created. + * onDeviceReady* User event fired to indicate that Cordova is ready + * onResume User event fired to indicate a start/resume lifecycle event + * onPause User event fired to indicate a pause lifecycle event + * + * The events marked with an * are sticky. Once they have fired, they will stay in the fired state. + * All listeners that subscribe after the event is fired will be executed right away. + * + * The only Cordova events that user code should register for are: + * deviceready Cordova native code is initialized and Cordova APIs can be called from JavaScript + * pause App has moved to background + * resume App has returned to foreground + * + * Listeners can be registered as: + * document.addEventListener("deviceready", myDeviceReadyListener, false); + * document.addEventListener("resume", myResumeListener, false); + * document.addEventListener("pause", myPauseListener, false); + * + * The DOM lifecycle events should be used for saving and restoring state + * window.onload + * window.onunload + * + */ + + /** + * Channel + * @constructor + * @param type String the channel name + */ + var Channel = function (type, sticky) { + this.type = type; + // Map of guid -> function. + this.handlers = {}; + // 0 = Non-sticky, 1 = Sticky non-fired, 2 = Sticky fired. + this.state = sticky ? 1 : 0; + // Used in sticky mode to remember args passed to fire(). + this.fireArgs = null; + // Used by onHasSubscribersChange to know if there are any listeners. + this.numHandlers = 0; + // Function that is called when the first listener is subscribed, or when + // the last listener is unsubscribed. + this.onHasSubscribersChange = null; + }; + var channel = { + /** + * Calls the provided function only after all of the channels specified + * have been fired. All channels must be sticky channels. + */ + join: function (h, c) { + var len = c.length; + var i = len; + var f = function () { + if (!--i) h(); + }; + for (var j = 0; j < len; j++) { + if (c[j].state === 0) { + throw Error('Can only use join with sticky channels.'); + } + c[j].subscribe(f); + } + if (!len) h(); + }, + /* eslint-disable no-return-assign */ + create: function (type) { + return (channel[type] = new Channel(type, false)); + }, + createSticky: function (type) { + return (channel[type] = new Channel(type, true)); + }, + /* eslint-enable no-return-assign */ + /** + * cordova Channels that must fire before "deviceready" is fired. + */ + deviceReadyChannelsArray: [], + deviceReadyChannelsMap: {}, + + /** + * Indicate that a feature needs to be initialized before it is ready to be used. + * This holds up Cordova's "deviceready" event until the feature has been initialized + * and Cordova.initComplete(feature) is called. + * + * @param feature {String} The unique feature name + */ + waitForInitialization: function (feature) { + if (feature) { + var c = channel[feature] || this.createSticky(feature); + this.deviceReadyChannelsMap[feature] = c; + this.deviceReadyChannelsArray.push(c); + } + }, + + /** + * Indicate that initialization code has completed and the feature is ready to be used. + * + * @param feature {String} The unique feature name + */ + initializationComplete: function (feature) { + var c = this.deviceReadyChannelsMap[feature]; + if (c) { + c.fire(); + } + }, + }; + + function checkSubscriptionArgument(argument) { + if (typeof argument !== 'function' && typeof argument.handleEvent !== 'function') { + throw new Error( + 'Must provide a function or an EventListener object ' + 'implementing the handleEvent interface.', + ); + } + } + + /** + * Subscribes the given function to the channel. Any time that + * Channel.fire is called so too will the function. + * Optionally specify an execution context for the function + * and a guid that can be used to stop subscribing to the channel. + * Returns the guid. + */ + Channel.prototype.subscribe = function (eventListenerOrFunction, eventListener) { + checkSubscriptionArgument(eventListenerOrFunction); + var handleEvent, guid; + + if (eventListenerOrFunction && typeof eventListenerOrFunction === 'object') { + // Received an EventListener object implementing the handleEvent interface + handleEvent = eventListenerOrFunction.handleEvent; + eventListener = eventListenerOrFunction; + } else { + // Received a function to handle event + handleEvent = eventListenerOrFunction; + } + + if (this.state === 2) { + handleEvent.apply(eventListener || this, this.fireArgs); + return; + } + + guid = eventListenerOrFunction.observer_guid; + if (typeof eventListener === 'object') { + handleEvent = utils.close(eventListener, handleEvent); + } + + if (!guid) { + // First time any channel has seen this subscriber + guid = '' + nextGuid++; + } + handleEvent.observer_guid = guid; + eventListenerOrFunction.observer_guid = guid; + + // Don't add the same handler more than once. + if (!this.handlers[guid]) { + this.handlers[guid] = handleEvent; + this.numHandlers++; + if (this.numHandlers === 1) { + this.onHasSubscribersChange && this.onHasSubscribersChange(); + } + } + }; + + /** + * Unsubscribes the function with the given guid from the channel. + */ + Channel.prototype.unsubscribe = function (eventListenerOrFunction) { + checkSubscriptionArgument(eventListenerOrFunction); + var handleEvent, guid, handler; + + if (eventListenerOrFunction && typeof eventListenerOrFunction === 'object') { + // Received an EventListener object implementing the handleEvent interface + handleEvent = eventListenerOrFunction.handleEvent; + } else { + // Received a function to handle event + handleEvent = eventListenerOrFunction; + } + + guid = handleEvent.observer_guid; + handler = this.handlers[guid]; + if (handler) { + delete this.handlers[guid]; + this.numHandlers--; + if (this.numHandlers === 0) { + this.onHasSubscribersChange && this.onHasSubscribersChange(); + } + } + }; + + /** + * Calls all functions subscribed to this channel. + */ + Channel.prototype.fire = function (e) { + var fail = false; // eslint-disable-line no-unused-vars + var fireArgs = Array.prototype.slice.call(arguments); + // Apply stickiness. + if (this.state === 1) { + this.state = 2; + this.fireArgs = fireArgs; + } + if (this.numHandlers) { + // Copy the values first so that it is safe to modify it from within + // callbacks. + var toCall = []; + for (var item in this.handlers) { + toCall.push(this.handlers[item]); + } + for (var i = 0; i < toCall.length; ++i) { + toCall[i].apply(this, fireArgs); + } + if (this.state === 2 && this.numHandlers) { + this.numHandlers = 0; + this.handlers = {}; + this.onHasSubscribersChange && this.onHasSubscribersChange(); + } + } + }; + + // defining them here so they are ready super fast! + // DOM event that is received when the web page is loaded and parsed. + channel.createSticky('onDOMContentLoaded'); + + // Event to indicate the Cordova native side is ready. + channel.createSticky('onNativeReady'); + + // Event to indicate that all Cordova JavaScript objects have been created + // and it's time to run plugin constructors. + channel.createSticky('onCordovaReady'); + + // Event to indicate that all automatically loaded JS plugins are loaded and ready. + // FIXME remove this + channel.createSticky('onPluginsReady'); + + // Event to indicate that Cordova is ready + channel.createSticky('onDeviceReady'); + + // Event to indicate a resume lifecycle event + channel.create('onResume'); + + // Event to indicate a pause lifecycle event + channel.create('onPause'); + + // Channels that must fire before "deviceready" is fired. + channel.waitForInitialization('onCordovaReady'); + channel.waitForInitialization('onDOMContentLoaded'); + + module.exports = channel; + }); + + define('cordova/exec', function (require, exports, module) { + /*global require, module, atob, document */ + + /** + * Creates a gap bridge iframe used to notify the native code about queued + * commands. + */ + var cordova = require('cordova'), + utils = require('cordova/utils'), + base64 = require('cordova/base64'), + execIframe, + commandQueue = [], // Contains pending JS->Native messages. + isInContextOfEvalJs = 0, + failSafeTimerId = 0; + + function massageArgsJsToNative(args) { + if (window.androidBridge) { + for (var i = 0; i < args.length; i++) { + if (utils.typeName(args[i]) == 'ArrayBuffer') { + args[i] = base64.fromArrayBuffer(args[i]); + } + } + return args; + } else { + if (!args || utils.typeName(args) !== 'Array') { + return args; + } + var ret = []; + args.forEach(function (arg, i) { + if (utils.typeName(arg) === 'ArrayBuffer') { + ret.push({ + CDVType: 'ArrayBuffer', + data: base64.fromArrayBuffer(arg), + }); + } else { + ret.push(arg); + } + }); + return ret; + } + } + + function massageMessageNativeToJs(message) { + if (message.CDVType === 'ArrayBuffer') { + var stringToArrayBuffer = function (str) { + var ret = new Uint8Array(str.length); + for (var i = 0; i < str.length; i++) { + ret[i] = str.charCodeAt(i); + } + return ret.buffer; + }; + var base64ToArrayBuffer = function (b64) { + return stringToArrayBuffer(atob(b64)); // eslint-disable-line no-undef + }; + message = base64ToArrayBuffer(message.data); + } + return message; + } + + function convertMessageToArgsNativeToJs(message) { + var args = []; + if (!message || !message.hasOwnProperty('CDVType')) { + args.push(message); + } else if (message.CDVType === 'MultiPart') { + message.messages.forEach(function (e) { + args.push(massageMessageNativeToJs(e)); + }); + } else { + args.push(massageMessageNativeToJs(message)); + } + return args; + } + + var capacitorExec = function () { + // detect change in bridge, if there is a change, we forward to new bridge + + var successCallback, failCallback, service, action, actionArgs; + var callbackId = null; + if (typeof arguments[0] !== 'string') { + // FORMAT ONE + successCallback = arguments[0]; + failCallback = arguments[1]; + service = arguments[2]; + action = arguments[3]; + actionArgs = arguments[4]; + + // Since we need to maintain backwards compatibility, we have to pass + // an invalid callbackId even if no callback was provided since plugins + // will be expecting it. The Cordova.exec() implementation allocates + // an invalid callbackId and passes it even if no callbacks were given. + callbackId = 'INVALID'; + } else { + throw new Error( + 'The old format of this exec call has been removed (deprecated since 2.1). Change to: ' + // eslint-disable-line + "cordova.exec(null, null, 'Service', 'action', [ arg1, arg2 ]);", + ); + } + + // If actionArgs is not provided, default to an empty array + actionArgs = actionArgs || []; + + // Register the callbacks and add the callbackId to the positional + // arguments if given. + if (successCallback || failCallback) { + callbackId = service + cordova.callbackId++; + cordova.callbacks[callbackId] = { + success: successCallback, + fail: failCallback, + }; + } + + // Properly encode ArrayBuffer action arguments + actionArgs = massageArgsJsToNative(actionArgs); + actionArgs = JSON.parse(JSON.stringify(actionArgs)); + var command = { + type: 'cordova', + callbackId: callbackId, + service: service, + action: action, + actionArgs: actionArgs, + }; + if (window.androidBridge) { + window.androidBridge.postMessage(JSON.stringify(command)); + } else if (window.webkit && window.webkit.messageHandlers && window.webkit.messageHandlers.bridge) { + window.webkit.messageHandlers.bridge.postMessage(command); + } + }; + + // CB-10530 + function proxyChanged() { + var cexec = cordovaExec(); + + return ( + execProxy !== cexec && capacitorExec !== cexec // proxy objects are different // proxy object is not the current capacitorExec + ); + } + + // CB-10106 + function handleBridgeChange() { + if (proxyChanged()) { + var commandString = commandQueue.shift(); + while (commandString) { + var command = JSON.parse(commandString); + var callbackId = command[0]; + var service = command[1]; + var action = command[2]; + var actionArgs = command[3]; + var callbacks = cordova.callbacks[callbackId] || {}; + + execProxy(callbacks.success, callbacks.fail, service, action, actionArgs); + + commandString = commandQueue.shift(); + } + return true; + } + + return false; + } + + function pokeNative() { + // CB-5488 - Don't attempt to create iframe before document.body is available. + if (!document.body) { + setTimeout(pokeNative); + return; + } + + // Check if they've removed it from the DOM, and put it back if so. + if (execIframe && execIframe.contentWindow) { + execIframe.contentWindow.location = 'gap://ready'; + } else { + execIframe = document.createElement('iframe'); + execIframe.style.display = 'none'; + execIframe.src = 'gap://ready'; + document.body.appendChild(execIframe); + } + // Use a timer to protect against iframe being unloaded during the poke (CB-7735). + // This makes the bridge ~ 7% slower, but works around the poke getting lost + // when the iframe is removed from the DOM. + // An onunload listener could be used in the case where the iframe has just been + // created, but since unload events fire only once, it doesn't work in the normal + // case of iframe reuse (where unload will have already fired due to the attempted + // navigation of the page). + failSafeTimerId = setTimeout(function () { + if (commandQueue.length) { + // CB-10106 - flush the queue on bridge change + if (!handleBridgeChange()) { + pokeNative(); + } + } + }, 50); // Making this > 0 improves performance (marginally) in the normal case (where it doesn't fire). + } + + capacitorExec.nativeFetchMessages = function () { + // Stop listing for window detatch once native side confirms poke. + if (failSafeTimerId) { + clearTimeout(failSafeTimerId); + failSafeTimerId = 0; + } + // Each entry in commandQueue is a JSON string already. + if (!commandQueue.length) { + return ''; + } + var json = '[' + commandQueue.join(',') + ']'; + commandQueue.length = 0; + return json; + }; + + capacitorExec.nativeCallback = function (callbackId, status, message, keepCallback, debug) { + var success = status === 0 || status === 1; + var args = convertMessageToArgsNativeToJs(message); + Promise.resolve().then(function () { + cordova.callbackFromNative(callbackId, success, status, args, keepCallback); // eslint-disable-line + }); + }; + + // for backwards compatibility + capacitorExec.nativeEvalAndFetch = function (func) { + try { + func(); + } catch (e) { + console.log(e); + } + }; + + // Proxy the exec for bridge changes. See CB-10106 + function cordovaExec() { + var cexec = require('cordova/exec'); + var cexec_valid = + typeof cexec.nativeFetchMessages === 'function' && + typeof cexec.nativeEvalAndFetch === 'function' && + typeof cexec.nativeCallback === 'function'; + return cexec_valid && execProxy !== cexec ? cexec : capacitorExec; + } + function execProxy() { + cordovaExec().apply(null, arguments); + } + + execProxy.nativeFetchMessages = function () { + return cordovaExec().nativeFetchMessages.apply(null, arguments); + }; + + execProxy.nativeEvalAndFetch = function () { + return cordovaExec().nativeEvalAndFetch.apply(null, arguments); + }; + + execProxy.nativeCallback = function () { + return cordovaExec().nativeCallback.apply(null, arguments); + }; + + module.exports = execProxy; + }); + + // file: src/common/exec/proxy.js + define('cordova/exec/proxy', function (require, exports, module) { + // internal map of proxy function + var CommandProxyMap = {}; + + module.exports = { + // example: cordova.commandProxy.add("Accelerometer",{getCurrentAcceleration: function(successCallback, errorCallback, options) {...},...); + add: function (id, proxyObj) { + console.log('adding proxy for ' + id); + CommandProxyMap[id] = proxyObj; + return proxyObj; + }, + + // cordova.commandProxy.remove("Accelerometer"); + remove: function (id) { + var proxy = CommandProxyMap[id]; + delete CommandProxyMap[id]; + CommandProxyMap[id] = null; + return proxy; + }, + + get: function (service, action) { + return CommandProxyMap[service] ? CommandProxyMap[service][action] : null; + }, + }; + }); + + // file: src/common/init.js + define('cordova/init', function (require, exports, module) { + var channel = require('cordova/channel'); + var cordova = require('cordova'); + var modulemapper = require('cordova/modulemapper'); + var platform = require('cordova/platform'); + var pluginloader = require('cordova/pluginloader'); + var utils = require('cordova/utils'); + + var platformInitChannelsArray = [channel.onNativeReady, channel.onPluginsReady]; + + function logUnfiredChannels(arr) { + for (var i = 0; i < arr.length; ++i) { + if (arr[i].state !== 2) { + console.log('Channel not fired: ' + arr[i].type); + } + } + } + + window.setTimeout(function () { + if (channel.onDeviceReady.state !== 2) { + console.log('deviceready has not fired after 5 seconds.'); + logUnfiredChannels(platformInitChannelsArray); + logUnfiredChannels(channel.deviceReadyChannelsArray); + } + }, 5000); + + // Replace navigator before any modules are required(), to ensure it happens as soon as possible. + // We replace it so that properties that can't be clobbered can instead be overridden. + function replaceNavigator(origNavigator) { + var CordovaNavigator = function () {}; + CordovaNavigator.prototype = origNavigator; + var newNavigator = new CordovaNavigator(); + // This work-around really only applies to new APIs that are newer than Function.bind. + // Without it, APIs such as getGamepads() break. + if (CordovaNavigator.bind) { + for (var key in origNavigator) { + if (typeof origNavigator[key] === 'function') { + newNavigator[key] = origNavigator[key].bind(origNavigator); + } else { + (function (k) { + utils.defineGetterSetter(newNavigator, key, function () { + return origNavigator[k]; + }); + })(key); + } + } + } + return newNavigator; + } + + if (window.navigator) { + window.navigator = replaceNavigator(window.navigator); + } + + // Register pause, resume and deviceready channels as events on document. + channel.onPause = cordova.addDocumentEventHandler('pause'); + channel.onResume = cordova.addDocumentEventHandler('resume'); + channel.onActivated = cordova.addDocumentEventHandler('activated'); + channel.onDeviceReady = cordova.addStickyDocumentEventHandler('deviceready'); + + // Listen for DOMContentLoaded and notify our channel subscribers. + if (document.readyState === 'complete' || document.readyState === 'interactive') { + channel.onDOMContentLoaded.fire(); + } else { + document.addEventListener( + 'DOMContentLoaded', + function () { + channel.onDOMContentLoaded.fire(); + }, + false, + ); + } + + // _nativeReady is global variable that the native side can set + // to signify that the native code is ready. It is a global since + // it may be called before any cordova JS is ready. + if (window._nativeReady) { + channel.onNativeReady.fire(); + } + + modulemapper.clobbers('cordova', 'cordova'); + modulemapper.clobbers('cordova/exec', 'cordova.exec'); + modulemapper.clobbers('cordova/exec', 'Cordova.exec'); + + // Call the platform-specific initialization. + platform.bootstrap && platform.bootstrap(); + + // Wrap in a setTimeout to support the use-case of having plugin JS appended to cordova.js. + // The delay allows the attached modules to be defined before the plugin loader looks for them. + setTimeout(function () { + pluginloader.load(function () { + channel.onPluginsReady.fire(); + }); + }, 0); + + /** + * Create all cordova objects once native side is ready. + */ + channel.join(function () { + modulemapper.mapModules(window); + + platform.initialize && platform.initialize(); + + // Fire event to notify that all objects are created + channel.onCordovaReady.fire(); + + // Fire onDeviceReady event once page has fully loaded, all + // constructors have run and cordova info has been received from native + // side. + channel.join(function () { + require('cordova').fireDocumentEvent('deviceready'); + }, channel.deviceReadyChannelsArray); + }, platformInitChannelsArray); + }); + + // file: src/common/modulemapper.js + define('cordova/modulemapper', function (require, exports, module) { + var builder = require('cordova/builder'); + var moduleMap = define.moduleMap; // eslint-disable-line no-undef + var symbolList; + var deprecationMap; + + exports.reset = function () { + symbolList = []; + deprecationMap = {}; + }; + + function addEntry(strategy, moduleName, symbolPath, opt_deprecationMessage) { + if (!(moduleName in moduleMap)) { + throw new Error('Module ' + moduleName + ' does not exist.'); + } + symbolList.push(strategy, moduleName, symbolPath); + if (opt_deprecationMessage) { + deprecationMap[symbolPath] = opt_deprecationMessage; + } + } + + // Note: Android 2.3 does have Function.bind(). + exports.clobbers = function (moduleName, symbolPath, opt_deprecationMessage) { + addEntry('c', moduleName, symbolPath, opt_deprecationMessage); + }; + + exports.merges = function (moduleName, symbolPath, opt_deprecationMessage) { + addEntry('m', moduleName, symbolPath, opt_deprecationMessage); + }; + + exports.defaults = function (moduleName, symbolPath, opt_deprecationMessage) { + addEntry('d', moduleName, symbolPath, opt_deprecationMessage); + }; + + exports.runs = function (moduleName) { + addEntry('r', moduleName, null); + }; + + function prepareNamespace(symbolPath, context) { + if (!symbolPath) { + return context; + } + var parts = symbolPath.split('.'); + var cur = context; + for (var i = 0, part; (part = parts[i]); ++i) { + // eslint-disable-line no-cond-assign + cur = cur[part] = cur[part] || {}; + } + return cur; + } + + exports.mapModules = function (context) { + var origSymbols = {}; + context.CDV_origSymbols = origSymbols; + for (var i = 0, len = symbolList.length; i < len; i += 3) { + var strategy = symbolList[i]; + var moduleName = symbolList[i + 1]; + var module = require(moduleName); + // + if (strategy === 'r') { + continue; + } + var symbolPath = symbolList[i + 2]; + var lastDot = symbolPath.lastIndexOf('.'); + var namespace = symbolPath.substr(0, lastDot); + var lastName = symbolPath.substr(lastDot + 1); + + var deprecationMsg = + symbolPath in deprecationMap + ? 'Access made to deprecated symbol: ' + symbolPath + '. ' + deprecationMsg + : null; + var parentObj = prepareNamespace(namespace, context); + var target = parentObj[lastName]; + + if (strategy === 'm' && target) { + builder.recursiveMerge(target, module); + } else if ((strategy === 'd' && !target) || strategy !== 'd') { + if (!(symbolPath in origSymbols)) { + origSymbols[symbolPath] = target; + } + builder.assignOrWrapInDeprecateGetter(parentObj, lastName, module, deprecationMsg); + } + } + }; + + exports.getOriginalSymbol = function (context, symbolPath) { + var origSymbols = context.CDV_origSymbols; + if (origSymbols && symbolPath in origSymbols) { + return origSymbols[symbolPath]; + } + var parts = symbolPath.split('.'); + var obj = context; + for (var i = 0; i < parts.length; ++i) { + obj = obj && obj[parts[i]]; + } + return obj; + }; + + exports.reset(); + }); + + define('cordova/platform', function (require, exports, module) { + module.exports = { + id: window.Capacitor.getPlatform(), + bootstrap: function () { + require('cordova/channel').onNativeReady.fire(); + }, + }; + }); + + // file: src/common/pluginloader.js + define('cordova/pluginloader', function (require, exports, module) { + var modulemapper = require('cordova/modulemapper'); + + function onScriptLoadingComplete(moduleList, finishPluginLoading) { + console.log('onscript loading complete'); + // Loop through all the plugins and then through their clobbers and merges. + for (var i = 0, module; (module = moduleList[i]); i++) { + // eslint-disable-line no-cond-assign + if (module.clobbers && module.clobbers.length) { + for (var j = 0; j < module.clobbers.length; j++) { + modulemapper.clobbers(module.id, module.clobbers[j]); + } + } + + if (module.merges && module.merges.length) { + for (var k = 0; k < module.merges.length; k++) { + modulemapper.merges(module.id, module.merges[k]); + } + } + + // Finally, if runs is truthy we want to simply require() the module. + if (module.runs) { + modulemapper.runs(module.id); + } + } + + finishPluginLoading(); + } + + // Tries to load all plugins' js-modules. + // This is an async process, but onDeviceReady is blocked on onPluginsReady. + // onPluginsReady is fired when there are no plugins to load, or they are all done. + exports.load = function (callback) { + var moduleList = require('cordova/plugin_list'); + onScriptLoadingComplete(moduleList, callback); + }; + }); + + // file: src/common/urlutil.js + define('cordova/urlutil', function (require, exports, module) { + /** + * For already absolute URLs, returns what is passed in. + * For relative URLs, converts them to absolute ones. + */ + exports.makeAbsolute = function makeAbsolute(url) { + var anchorEl = document.createElement('a'); + anchorEl.href = url; + return anchorEl.href; + }; + }); + + // file: src/common/utils.js + define('cordova/utils', function (require, exports, module) { + var utils = exports; + + /** + * Defines a property getter / setter for obj[key]. + */ + utils.defineGetterSetter = function (obj, key, getFunc, opt_setFunc) { + if (Object.defineProperty) { + var desc = { + get: getFunc, + configurable: true, + }; + if (opt_setFunc) { + desc.set = opt_setFunc; + } + Object.defineProperty(obj, key, desc); + } else { + obj.__defineGetter__(key, getFunc); + if (opt_setFunc) { + obj.__defineSetter__(key, opt_setFunc); + } + } + }; + + /** + * Defines a property getter for obj[key]. + */ + utils.defineGetter = utils.defineGetterSetter; + + utils.arrayIndexOf = function (a, item) { + if (a.indexOf) { + return a.indexOf(item); + } + var len = a.length; + for (var i = 0; i < len; ++i) { + if (a[i] === item) { + return i; + } + } + return -1; + }; + + /** + * Returns whether the item was found in the array. + */ + utils.arrayRemove = function (a, item) { + var index = utils.arrayIndexOf(a, item); + if (index !== -1) { + a.splice(index, 1); + } + return index !== -1; + }; + + utils.typeName = function (val) { + return Object.prototype.toString.call(val).slice(8, -1); + }; + + /** + * Returns an indication of whether the argument is an array or not + */ + utils.isArray = + Array.isArray || + function (a) { + return utils.typeName(a) === 'Array'; + }; + + /** + * Returns an indication of whether the argument is a Date or not + */ + utils.isDate = function (d) { + return d instanceof Date; + }; + + /** + * Does a deep clone of the object. + */ + utils.clone = function (obj) { + if (!obj || typeof obj === 'function' || utils.isDate(obj) || typeof obj !== 'object') { + return obj; + } + + var retVal, i; + + if (utils.isArray(obj)) { + retVal = []; + for (i = 0; i < obj.length; ++i) { + retVal.push(utils.clone(obj[i])); + } + return retVal; + } + + retVal = {}; + for (i in obj) { + // https://issues.apache.org/jira/browse/CB-11522 'unknown' type may be returned in + // custom protocol activation case on Windows Phone 8.1 causing "No such interface supported" exception + // on cloning. + if ((!(i in retVal) || retVal[i] !== obj[i]) && typeof obj[i] !== 'undefined' && typeof obj[i] !== 'unknown') { + // eslint-disable-line valid-typeof + retVal[i] = utils.clone(obj[i]); + } + } + return retVal; + }; + + /** + * Returns a wrapped version of the function + */ + utils.close = function (context, func, params) { + return function () { + var args = params || arguments; + return func.apply(context, args); + }; + }; + + // ------------------------------------------------------------------------------ + function UUIDcreatePart(length) { + var uuidpart = ''; + for (var i = 0; i < length; i++) { + var uuidchar = parseInt(Math.random() * 256, 10).toString(16); + if (uuidchar.length === 1) { + uuidchar = '0' + uuidchar; + } + uuidpart += uuidchar; + } + return uuidpart; + } + + /** + * Create a UUID + */ + utils.createUUID = function () { + return ( + UUIDcreatePart(4) + + '-' + + UUIDcreatePart(2) + + '-' + + UUIDcreatePart(2) + + '-' + + UUIDcreatePart(2) + + '-' + + UUIDcreatePart(6) + ); + }; + + /** + * Extends a child object from a parent object using classical inheritance + * pattern. + */ + utils.extend = (function () { + // proxy used to establish prototype chain + var F = function () {}; + // extend Child from Parent + return function (Child, Parent) { + F.prototype = Parent.prototype; + Child.prototype = new F(); + Child.__super__ = Parent.prototype; + Child.prototype.constructor = Child; + }; + })(); + + /** + * Alerts a message in any available way: alert or console.log. + */ + utils.alert = function (msg) { + if (window.alert) { + window.alert(msg); + } else if (console && console.log) { + console.log(msg); + } + }; + }); + + window.cordova = require('cordova'); + // file: src/scripts/bootstrap.js + + require('cordova/init'); +})(); diff --git a/node_modules/@capacitor/core/dist/capacitor.js b/node_modules/@capacitor/core/dist/capacitor.js new file mode 100644 index 0000000..64722c3 --- /dev/null +++ b/node_modules/@capacitor/core/dist/capacitor.js @@ -0,0 +1,3 @@ +/*! Capacitor: https://capacitorjs.com/ - MIT License */ +var capacitorExports=function(e){"use strict";var t;e.ExceptionCode=void 0,(t=e.ExceptionCode||(e.ExceptionCode={})).Unimplemented="UNIMPLEMENTED",t.Unavailable="UNAVAILABLE";class n extends Error{constructor(e,t,n){super(e),this.message=e,this.code=t,this.data=n}}const s=t=>{const s=t.CapacitorCustomPlatform||null,r=t.Capacitor||{},i=r.Plugins=r.Plugins||{},a=()=>null!==s?s.name:(e=>{var t,n;return(null==e?void 0:e.androidBridge)?"android":(null===(n=null===(t=null==e?void 0:e.webkit)||void 0===t?void 0:t.messageHandlers)||void 0===n?void 0:n.bridge)?"ios":"web"})(t),o=e=>{var t;return null===(t=r.PluginHeaders)||void 0===t?void 0:t.find(t=>t.name===e)},c=new Map;return r.convertFileSrc||(r.convertFileSrc=e=>e),r.getPlatform=a,r.handleError=e=>t.console.error(e),r.isNativePlatform=()=>"web"!==a(),r.isPluginAvailable=e=>{const t=c.get(e);return!!(null==t?void 0:t.platforms.has(a()))||!!o(e)},r.registerPlugin=(t,l={})=>{const d=c.get(t);if(d)return console.warn(`Capacitor plugin "${t}" already registered. Cannot register plugins twice.`),d.proxy;const u=a(),p=o(t);let m;const h=i=>{let a;const o=(...o)=>{const c=(async()=>(!m&&u in l?m=m="function"==typeof l[u]?await l[u]():l[u]:null!==s&&!m&&"web"in l&&(m=m="function"==typeof l.web?await l.web():l.web),m))().then(s=>{const c=((s,i)=>{var a,o;if(!p){if(s)return null===(o=s[i])||void 0===o?void 0:o.bind(s);throw new n(`"${t}" plugin is not implemented on ${u}`,e.ExceptionCode.Unimplemented)}{const e=null==p?void 0:p.methods.find(e=>i===e.name);if(e)return"promise"===e.rtype?e=>r.nativePromise(t,i.toString(),e):(e,n)=>r.nativeCallback(t,i.toString(),e,n);if(s)return null===(a=s[i])||void 0===a?void 0:a.bind(s)}})(s,i);if(c){const e=c(...o);return a=null==e?void 0:e.remove,e}throw new n(`"${t}.${i}()" is not implemented on ${u}`,e.ExceptionCode.Unimplemented)});return"addListener"===i&&(c.remove=async()=>a()),c};return o.toString=()=>`${i.toString()}() { [capacitor code] }`,Object.defineProperty(o,"name",{value:i,writable:!1,configurable:!1}),o},w=h("addListener"),g=h("removeListener"),v=(e,t)=>{const n=w({eventName:e},t),s=async()=>{const s=await n;g({eventName:e,callbackId:s},t)},r=new Promise(e=>n.then(()=>e({remove:s})));return r.remove=async()=>{console.warn("Using addListener() without 'await' is deprecated."),await s()},r},y=new Proxy({},{get(e,t){switch(t){case"$$typeof":return;case"toJSON":return()=>({});case"addListener":return p?v:w;case"removeListener":return g;default:return h(t)}}});return i[t]=y,c.set(t,{name:t,proxy:y,platforms:new Set([...Object.keys(l),...p?[u]:[]])}),y},r.Exception=n,r.DEBUG=!!r.DEBUG,r.isLoggingEnabled=!!r.isLoggingEnabled,r},r=(e=>e.Capacitor=s(e))("undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:"undefined"!=typeof window?window:"undefined"!=typeof global?global:{}),i=r.registerPlugin;class a{constructor(){this.listeners={},this.retainedEventArguments={},this.windowListeners={}}addListener(e,t){let n=!1;this.listeners[e]||(this.listeners[e]=[],n=!0),this.listeners[e].push(t);const s=this.windowListeners[e];s&&!s.registered&&this.addWindowListener(s),n&&this.sendRetainedArgumentsForEvent(e);return Promise.resolve({remove:async()=>this.removeListener(e,t)})}async removeAllListeners(){this.listeners={};for(const e in this.windowListeners)this.removeWindowListener(this.windowListeners[e]);this.windowListeners={}}notifyListeners(e,t,n){const s=this.listeners[e];if(s)s.forEach(e=>e(t));else if(n){let n=this.retainedEventArguments[e];n||(n=[]),n.push(t),this.retainedEventArguments[e]=n}}hasListeners(e){var t;return!!(null===(t=this.listeners[e])||void 0===t?void 0:t.length)}registerWindowListener(e,t){this.windowListeners[t]={registered:!1,windowEventName:e,pluginEventName:t,handler:e=>{this.notifyListeners(t,e)}}}unimplemented(t="not implemented"){return new r.Exception(t,e.ExceptionCode.Unimplemented)}unavailable(t="not available"){return new r.Exception(t,e.ExceptionCode.Unavailable)}async removeListener(e,t){const n=this.listeners[e];if(!n)return;const s=n.indexOf(t);this.listeners[e].splice(s,1),this.listeners[e].length||this.removeWindowListener(this.windowListeners[e])}addWindowListener(e){window.addEventListener(e.windowEventName,e.handler),e.registered=!0}removeWindowListener(e){e&&(window.removeEventListener(e.windowEventName,e.handler),e.registered=!1)}sendRetainedArgumentsForEvent(e){const t=this.retainedEventArguments[e];t&&(delete this.retainedEventArguments[e],t.forEach(t=>{this.notifyListeners(e,t)}))}}const o=i("WebView"),c=e=>encodeURIComponent(e).replace(/%(2[346B]|5E|60|7C)/g,decodeURIComponent).replace(/[()]/g,escape),l=e=>e.replace(/(%[\dA-F]{2})+/gi,decodeURIComponent);class d extends a{async getCookies(){const e=document.cookie,t={};return e.split(";").forEach(e=>{if(e.length<=0)return;let[n,s]=e.replace(/=/,"CAP_COOKIE").split("CAP_COOKIE");n=l(n).trim(),s=l(s).trim(),t[n]=s}),t}async setCookie(e){try{const t=c(e.key),n=c(e.value),s=e.expires?`; expires=${e.expires.replace("expires=","")}`:"",r=(e.path||"/").replace("path=",""),i=null!=e.url&&e.url.length>0?`domain=${e.url}`:"";document.cookie=`${t}=${n||""}${s}; path=${r}; ${i};`}catch(e){return Promise.reject(e)}}async deleteCookie(e){try{document.cookie=`${e.key}=; Max-Age=0`}catch(e){return Promise.reject(e)}}async clearCookies(){try{const e=document.cookie.split(";")||[];for(const t of e)document.cookie=t.replace(/^ +/,"").replace(/=.*/,`=;expires=${(new Date).toUTCString()};path=/`)}catch(e){return Promise.reject(e)}}async clearAllCookies(){try{await this.clearCookies()}catch(e){return Promise.reject(e)}}}const u=i("CapacitorCookies",{web:()=>new d}),p=(e,t={})=>{const n=Object.assign({method:e.method||"GET",headers:e.headers},t),s=((e={})=>{const t=Object.keys(e);return Object.keys(e).map(e=>e.toLocaleLowerCase()).reduce((n,s,r)=>(n[s]=e[t[r]],n),{})})(e.headers)["content-type"]||"";if("string"==typeof e.data)n.body=e.data;else if(s.includes("application/x-www-form-urlencoded")){const t=new URLSearchParams;for(const[n,s]of Object.entries(e.data||{}))t.set(n,s);n.body=t.toString()}else if(s.includes("multipart/form-data")||e.data instanceof FormData){const t=new FormData;if(e.data instanceof FormData)e.data.forEach((e,n)=>{t.append(n,e)});else for(const n of Object.keys(e.data))t.append(n,e.data[n]);n.body=t;const s=new Headers(n.headers);s.delete("content-type"),n.headers=s}else(s.includes("application/json")||"object"==typeof e.data)&&(n.body=JSON.stringify(e.data));return n};class m extends a{async request(e){const t=p(e,e.webFetchExtra),n=((e,t=!0)=>e?Object.entries(e).reduce((e,n)=>{const[s,r]=n;let i,a;return Array.isArray(r)?(a="",r.forEach(e=>{i=t?encodeURIComponent(e):e,a+=`${s}=${i}&`}),a.slice(0,-1)):(i=t?encodeURIComponent(r):r,a=`${s}=${i}`),`${e}&${a}`},"").substr(1):null)(e.params,e.shouldEncodeUrlParams),s=n?`${e.url}?${n}`:e.url,r=await fetch(s,t),i=r.headers.get("content-type")||"";let a,o,{responseType:c="text"}=r.ok?e:{};switch(i.includes("application/json")&&(c="json"),c){case"arraybuffer":case"blob":o=await r.blob(),a=await(async e=>new Promise((t,n)=>{const s=new FileReader;s.onload=()=>{const e=s.result;t(e.indexOf(",")>=0?e.split(",")[1]:e)},s.onerror=e=>n(e),s.readAsDataURL(e)}))(o);break;case"json":a=await r.json();break;default:a=await r.text()}const l={};return r.headers.forEach((e,t)=>{l[t]=e}),{data:a,headers:l,status:r.status,url:r.url}}async get(e){return this.request(Object.assign(Object.assign({},e),{method:"GET"}))}async post(e){return this.request(Object.assign(Object.assign({},e),{method:"POST"}))}async put(e){return this.request(Object.assign(Object.assign({},e),{method:"PUT"}))}async patch(e){return this.request(Object.assign(Object.assign({},e),{method:"PATCH"}))}async delete(e){return this.request(Object.assign(Object.assign({},e),{method:"DELETE"}))}}const h=i("CapacitorHttp",{web:()=>new m});var w,g;e.SystemBarsStyle=void 0,(w=e.SystemBarsStyle||(e.SystemBarsStyle={})).Dark="DARK",w.Light="LIGHT",w.Default="DEFAULT",e.SystemBarType=void 0,(g=e.SystemBarType||(e.SystemBarType={})).StatusBar="StatusBar",g.NavigationBar="NavigationBar";class v extends a{async setStyle(){this.unavailable("not available for web")}async setAnimation(){this.unavailable("not available for web")}async show(){this.unavailable("not available for web")}async hide(){this.unavailable("not available for web")}}const y=i("SystemBars",{web:()=>new v});return e.Capacitor=r,e.CapacitorCookies=u,e.CapacitorException=n,e.CapacitorHttp=h,e.SystemBars=y,e.WebPlugin=a,e.WebView=o,e.buildRequestInit=p,e.registerPlugin=i,Object.defineProperty(e,"__esModule",{value:!0}),e}({}); +//# sourceMappingURL=capacitor.js.map diff --git a/node_modules/@capacitor/core/dist/capacitor.js.map b/node_modules/@capacitor/core/dist/capacitor.js.map new file mode 100644 index 0000000..a498f66 --- /dev/null +++ b/node_modules/@capacitor/core/dist/capacitor.js.map @@ -0,0 +1 @@ +{"version":3,"file":"capacitor.js","sources":["../build/util.js","../build/runtime.js","../build/global.js","../build/web-plugin.js","../build/core-plugins.js"],"sourcesContent":["export var ExceptionCode;\n(function (ExceptionCode) {\n /**\n * API is not implemented.\n *\n * This usually means the API can't be used because it is not implemented for\n * the current platform.\n */\n ExceptionCode[\"Unimplemented\"] = \"UNIMPLEMENTED\";\n /**\n * API is not available.\n *\n * This means the API can't be used right now because:\n * - it is currently missing a prerequisite, such as network connectivity\n * - it requires a particular platform or browser version\n */\n ExceptionCode[\"Unavailable\"] = \"UNAVAILABLE\";\n})(ExceptionCode || (ExceptionCode = {}));\nexport class CapacitorException extends Error {\n constructor(message, code, data) {\n super(message);\n this.message = message;\n this.code = code;\n this.data = data;\n }\n}\nexport const getPlatformId = (win) => {\n var _a, _b;\n if (win === null || win === void 0 ? void 0 : win.androidBridge) {\n return 'android';\n }\n else if ((_b = (_a = win === null || win === void 0 ? void 0 : win.webkit) === null || _a === void 0 ? void 0 : _a.messageHandlers) === null || _b === void 0 ? void 0 : _b.bridge) {\n return 'ios';\n }\n else {\n return 'web';\n }\n};\n//# sourceMappingURL=util.js.map","import { CapacitorException, getPlatformId, ExceptionCode } from './util';\nexport const createCapacitor = (win) => {\n const capCustomPlatform = win.CapacitorCustomPlatform || null;\n const cap = win.Capacitor || {};\n const Plugins = (cap.Plugins = cap.Plugins || {});\n const getPlatform = () => {\n return capCustomPlatform !== null ? capCustomPlatform.name : getPlatformId(win);\n };\n const isNativePlatform = () => getPlatform() !== 'web';\n const isPluginAvailable = (pluginName) => {\n const plugin = registeredPlugins.get(pluginName);\n if (plugin === null || plugin === void 0 ? void 0 : plugin.platforms.has(getPlatform())) {\n // JS implementation available for the current platform.\n return true;\n }\n if (getPluginHeader(pluginName)) {\n // Native implementation available.\n return true;\n }\n return false;\n };\n const getPluginHeader = (pluginName) => { var _a; return (_a = cap.PluginHeaders) === null || _a === void 0 ? void 0 : _a.find((h) => h.name === pluginName); };\n const handleError = (err) => win.console.error(err);\n const registeredPlugins = new Map();\n const registerPlugin = (pluginName, jsImplementations = {}) => {\n const registeredPlugin = registeredPlugins.get(pluginName);\n if (registeredPlugin) {\n console.warn(`Capacitor plugin \"${pluginName}\" already registered. Cannot register plugins twice.`);\n return registeredPlugin.proxy;\n }\n const platform = getPlatform();\n const pluginHeader = getPluginHeader(pluginName);\n let jsImplementation;\n const loadPluginImplementation = async () => {\n if (!jsImplementation && platform in jsImplementations) {\n jsImplementation =\n typeof jsImplementations[platform] === 'function'\n ? (jsImplementation = await jsImplementations[platform]())\n : (jsImplementation = jsImplementations[platform]);\n }\n else if (capCustomPlatform !== null && !jsImplementation && 'web' in jsImplementations) {\n jsImplementation =\n typeof jsImplementations['web'] === 'function'\n ? (jsImplementation = await jsImplementations['web']())\n : (jsImplementation = jsImplementations['web']);\n }\n return jsImplementation;\n };\n const createPluginMethod = (impl, prop) => {\n var _a, _b;\n if (pluginHeader) {\n const methodHeader = pluginHeader === null || pluginHeader === void 0 ? void 0 : pluginHeader.methods.find((m) => prop === m.name);\n if (methodHeader) {\n if (methodHeader.rtype === 'promise') {\n return (options) => cap.nativePromise(pluginName, prop.toString(), options);\n }\n else {\n return (options, callback) => cap.nativeCallback(pluginName, prop.toString(), options, callback);\n }\n }\n else if (impl) {\n return (_a = impl[prop]) === null || _a === void 0 ? void 0 : _a.bind(impl);\n }\n }\n else if (impl) {\n return (_b = impl[prop]) === null || _b === void 0 ? void 0 : _b.bind(impl);\n }\n else {\n throw new CapacitorException(`\"${pluginName}\" plugin is not implemented on ${platform}`, ExceptionCode.Unimplemented);\n }\n };\n const createPluginMethodWrapper = (prop) => {\n let remove;\n const wrapper = (...args) => {\n const p = loadPluginImplementation().then((impl) => {\n const fn = createPluginMethod(impl, prop);\n if (fn) {\n const p = fn(...args);\n remove = p === null || p === void 0 ? void 0 : p.remove;\n return p;\n }\n else {\n throw new CapacitorException(`\"${pluginName}.${prop}()\" is not implemented on ${platform}`, ExceptionCode.Unimplemented);\n }\n });\n if (prop === 'addListener') {\n p.remove = async () => remove();\n }\n return p;\n };\n // Some flair ✨\n wrapper.toString = () => `${prop.toString()}() { [capacitor code] }`;\n Object.defineProperty(wrapper, 'name', {\n value: prop,\n writable: false,\n configurable: false,\n });\n return wrapper;\n };\n const addListener = createPluginMethodWrapper('addListener');\n const removeListener = createPluginMethodWrapper('removeListener');\n const addListenerNative = (eventName, callback) => {\n const call = addListener({ eventName }, callback);\n const remove = async () => {\n const callbackId = await call;\n removeListener({\n eventName,\n callbackId,\n }, callback);\n };\n const p = new Promise((resolve) => call.then(() => resolve({ remove })));\n p.remove = async () => {\n console.warn(`Using addListener() without 'await' is deprecated.`);\n await remove();\n };\n return p;\n };\n const proxy = new Proxy({}, {\n get(_, prop) {\n switch (prop) {\n // https://github.com/facebook/react/issues/20030\n case '$$typeof':\n return undefined;\n case 'toJSON':\n return () => ({});\n case 'addListener':\n return pluginHeader ? addListenerNative : addListener;\n case 'removeListener':\n return removeListener;\n default:\n return createPluginMethodWrapper(prop);\n }\n },\n });\n Plugins[pluginName] = proxy;\n registeredPlugins.set(pluginName, {\n name: pluginName,\n proxy,\n platforms: new Set([...Object.keys(jsImplementations), ...(pluginHeader ? [platform] : [])]),\n });\n return proxy;\n };\n // Add in convertFileSrc for web, it will already be available in native context\n if (!cap.convertFileSrc) {\n cap.convertFileSrc = (filePath) => filePath;\n }\n cap.getPlatform = getPlatform;\n cap.handleError = handleError;\n cap.isNativePlatform = isNativePlatform;\n cap.isPluginAvailable = isPluginAvailable;\n cap.registerPlugin = registerPlugin;\n cap.Exception = CapacitorException;\n cap.DEBUG = !!cap.DEBUG;\n cap.isLoggingEnabled = !!cap.isLoggingEnabled;\n return cap;\n};\nexport const initCapacitorGlobal = (win) => (win.Capacitor = createCapacitor(win));\n//# sourceMappingURL=runtime.js.map","import { initCapacitorGlobal } from './runtime';\nexport const Capacitor = /*#__PURE__*/ initCapacitorGlobal(typeof globalThis !== 'undefined'\n ? globalThis\n : typeof self !== 'undefined'\n ? self\n : typeof window !== 'undefined'\n ? window\n : typeof global !== 'undefined'\n ? global\n : {});\nexport const registerPlugin = Capacitor.registerPlugin;\n//# sourceMappingURL=global.js.map","import { Capacitor } from './global';\nimport { ExceptionCode } from './util';\n/**\n * Base class web plugins should extend.\n */\nexport class WebPlugin {\n constructor() {\n this.listeners = {};\n this.retainedEventArguments = {};\n this.windowListeners = {};\n }\n addListener(eventName, listenerFunc) {\n let firstListener = false;\n const listeners = this.listeners[eventName];\n if (!listeners) {\n this.listeners[eventName] = [];\n firstListener = true;\n }\n this.listeners[eventName].push(listenerFunc);\n // If we haven't added a window listener for this event and it requires one,\n // go ahead and add it\n const windowListener = this.windowListeners[eventName];\n if (windowListener && !windowListener.registered) {\n this.addWindowListener(windowListener);\n }\n if (firstListener) {\n this.sendRetainedArgumentsForEvent(eventName);\n }\n const remove = async () => this.removeListener(eventName, listenerFunc);\n const p = Promise.resolve({ remove });\n return p;\n }\n async removeAllListeners() {\n this.listeners = {};\n for (const listener in this.windowListeners) {\n this.removeWindowListener(this.windowListeners[listener]);\n }\n this.windowListeners = {};\n }\n notifyListeners(eventName, data, retainUntilConsumed) {\n const listeners = this.listeners[eventName];\n if (!listeners) {\n if (retainUntilConsumed) {\n let args = this.retainedEventArguments[eventName];\n if (!args) {\n args = [];\n }\n args.push(data);\n this.retainedEventArguments[eventName] = args;\n }\n return;\n }\n listeners.forEach((listener) => listener(data));\n }\n hasListeners(eventName) {\n var _a;\n return !!((_a = this.listeners[eventName]) === null || _a === void 0 ? void 0 : _a.length);\n }\n registerWindowListener(windowEventName, pluginEventName) {\n this.windowListeners[pluginEventName] = {\n registered: false,\n windowEventName,\n pluginEventName,\n handler: (event) => {\n this.notifyListeners(pluginEventName, event);\n },\n };\n }\n unimplemented(msg = 'not implemented') {\n return new Capacitor.Exception(msg, ExceptionCode.Unimplemented);\n }\n unavailable(msg = 'not available') {\n return new Capacitor.Exception(msg, ExceptionCode.Unavailable);\n }\n async removeListener(eventName, listenerFunc) {\n const listeners = this.listeners[eventName];\n if (!listeners) {\n return;\n }\n const index = listeners.indexOf(listenerFunc);\n this.listeners[eventName].splice(index, 1);\n // If there are no more listeners for this type of event,\n // remove the window listener\n if (!this.listeners[eventName].length) {\n this.removeWindowListener(this.windowListeners[eventName]);\n }\n }\n addWindowListener(handle) {\n window.addEventListener(handle.windowEventName, handle.handler);\n handle.registered = true;\n }\n removeWindowListener(handle) {\n if (!handle) {\n return;\n }\n window.removeEventListener(handle.windowEventName, handle.handler);\n handle.registered = false;\n }\n sendRetainedArgumentsForEvent(eventName) {\n const args = this.retainedEventArguments[eventName];\n if (!args) {\n return;\n }\n delete this.retainedEventArguments[eventName];\n args.forEach((arg) => {\n this.notifyListeners(eventName, arg);\n });\n }\n}\n//# sourceMappingURL=web-plugin.js.map","import { registerPlugin } from './global';\nimport { WebPlugin } from './web-plugin';\nexport const WebView = /*#__PURE__*/ registerPlugin('WebView');\n/******** END WEB VIEW PLUGIN ********/\n/******** COOKIES PLUGIN ********/\n/**\n * Safely web encode a string value (inspired by js-cookie)\n * @param str The string value to encode\n */\nconst encode = (str) => encodeURIComponent(str)\n .replace(/%(2[346B]|5E|60|7C)/g, decodeURIComponent)\n .replace(/[()]/g, escape);\n/**\n * Safely web decode a string value (inspired by js-cookie)\n * @param str The string value to decode\n */\nconst decode = (str) => str.replace(/(%[\\dA-F]{2})+/gi, decodeURIComponent);\nexport class CapacitorCookiesPluginWeb extends WebPlugin {\n async getCookies() {\n const cookies = document.cookie;\n const cookieMap = {};\n cookies.split(';').forEach((cookie) => {\n if (cookie.length <= 0)\n return;\n // Replace first \"=\" with CAP_COOKIE to prevent splitting on additional \"=\"\n let [key, value] = cookie.replace(/=/, 'CAP_COOKIE').split('CAP_COOKIE');\n key = decode(key).trim();\n value = decode(value).trim();\n cookieMap[key] = value;\n });\n return cookieMap;\n }\n async setCookie(options) {\n try {\n // Safely Encoded Key/Value\n const encodedKey = encode(options.key);\n const encodedValue = encode(options.value);\n // Clean & sanitize options\n const expires = options.expires ? `; expires=${options.expires.replace('expires=', '')}` : '';\n const path = (options.path || '/').replace('path=', ''); // Default is \"path=/\"\n const domain = options.url != null && options.url.length > 0 ? `domain=${options.url}` : '';\n document.cookie = `${encodedKey}=${encodedValue || ''}${expires}; path=${path}; ${domain};`;\n }\n catch (error) {\n return Promise.reject(error);\n }\n }\n async deleteCookie(options) {\n try {\n document.cookie = `${options.key}=; Max-Age=0`;\n }\n catch (error) {\n return Promise.reject(error);\n }\n }\n async clearCookies() {\n try {\n const cookies = document.cookie.split(';') || [];\n for (const cookie of cookies) {\n document.cookie = cookie.replace(/^ +/, '').replace(/=.*/, `=;expires=${new Date().toUTCString()};path=/`);\n }\n }\n catch (error) {\n return Promise.reject(error);\n }\n }\n async clearAllCookies() {\n try {\n await this.clearCookies();\n }\n catch (error) {\n return Promise.reject(error);\n }\n }\n}\nexport const CapacitorCookies = registerPlugin('CapacitorCookies', {\n web: () => new CapacitorCookiesPluginWeb(),\n});\n// UTILITY FUNCTIONS\n/**\n * Read in a Blob value and return it as a base64 string\n * @param blob The blob value to convert to a base64 string\n */\nexport const readBlobAsBase64 = async (blob) => new Promise((resolve, reject) => {\n const reader = new FileReader();\n reader.onload = () => {\n const base64String = reader.result;\n // remove prefix \"data:application/pdf;base64,\"\n resolve(base64String.indexOf(',') >= 0 ? base64String.split(',')[1] : base64String);\n };\n reader.onerror = (error) => reject(error);\n reader.readAsDataURL(blob);\n});\n/**\n * Normalize an HttpHeaders map by lowercasing all of the values\n * @param headers The HttpHeaders object to normalize\n */\nconst normalizeHttpHeaders = (headers = {}) => {\n const originalKeys = Object.keys(headers);\n const loweredKeys = Object.keys(headers).map((k) => k.toLocaleLowerCase());\n const normalized = loweredKeys.reduce((acc, key, index) => {\n acc[key] = headers[originalKeys[index]];\n return acc;\n }, {});\n return normalized;\n};\n/**\n * Builds a string of url parameters that\n * @param params A map of url parameters\n * @param shouldEncode true if you should encodeURIComponent() the values (true by default)\n */\nconst buildUrlParams = (params, shouldEncode = true) => {\n if (!params)\n return null;\n const output = Object.entries(params).reduce((accumulator, entry) => {\n const [key, value] = entry;\n let encodedValue;\n let item;\n if (Array.isArray(value)) {\n item = '';\n value.forEach((str) => {\n encodedValue = shouldEncode ? encodeURIComponent(str) : str;\n item += `${key}=${encodedValue}&`;\n });\n // last character will always be \"&\" so slice it off\n item.slice(0, -1);\n }\n else {\n encodedValue = shouldEncode ? encodeURIComponent(value) : value;\n item = `${key}=${encodedValue}`;\n }\n return `${accumulator}&${item}`;\n }, '');\n // Remove initial \"&\" from the reduce\n return output.substr(1);\n};\n/**\n * Build the RequestInit object based on the options passed into the initial request\n * @param options The Http plugin options\n * @param extra Any extra RequestInit values\n */\nexport const buildRequestInit = (options, extra = {}) => {\n const output = Object.assign({ method: options.method || 'GET', headers: options.headers }, extra);\n // Get the content-type\n const headers = normalizeHttpHeaders(options.headers);\n const type = headers['content-type'] || '';\n // If body is already a string, then pass it through as-is.\n if (typeof options.data === 'string') {\n output.body = options.data;\n }\n // Build request initializers based off of content-type\n else if (type.includes('application/x-www-form-urlencoded')) {\n const params = new URLSearchParams();\n for (const [key, value] of Object.entries(options.data || {})) {\n params.set(key, value);\n }\n output.body = params.toString();\n }\n else if (type.includes('multipart/form-data') || options.data instanceof FormData) {\n const form = new FormData();\n if (options.data instanceof FormData) {\n options.data.forEach((value, key) => {\n form.append(key, value);\n });\n }\n else {\n for (const key of Object.keys(options.data)) {\n form.append(key, options.data[key]);\n }\n }\n output.body = form;\n const headers = new Headers(output.headers);\n headers.delete('content-type'); // content-type will be set by `window.fetch` to includy boundary\n output.headers = headers;\n }\n else if (type.includes('application/json') || typeof options.data === 'object') {\n output.body = JSON.stringify(options.data);\n }\n return output;\n};\n// WEB IMPLEMENTATION\nexport class CapacitorHttpPluginWeb extends WebPlugin {\n /**\n * Perform an Http request given a set of options\n * @param options Options to build the HTTP request\n */\n async request(options) {\n const requestInit = buildRequestInit(options, options.webFetchExtra);\n const urlParams = buildUrlParams(options.params, options.shouldEncodeUrlParams);\n const url = urlParams ? `${options.url}?${urlParams}` : options.url;\n const response = await fetch(url, requestInit);\n const contentType = response.headers.get('content-type') || '';\n // Default to 'text' responseType so no parsing happens\n let { responseType = 'text' } = response.ok ? options : {};\n // If the response content-type is json, force the response to be json\n if (contentType.includes('application/json')) {\n responseType = 'json';\n }\n let data;\n let blob;\n switch (responseType) {\n case 'arraybuffer':\n case 'blob':\n blob = await response.blob();\n data = await readBlobAsBase64(blob);\n break;\n case 'json':\n data = await response.json();\n break;\n case 'document':\n case 'text':\n default:\n data = await response.text();\n }\n // Convert fetch headers to Capacitor HttpHeaders\n const headers = {};\n response.headers.forEach((value, key) => {\n headers[key] = value;\n });\n return {\n data,\n headers,\n status: response.status,\n url: response.url,\n };\n }\n /**\n * Perform an Http GET request given a set of options\n * @param options Options to build the HTTP request\n */\n async get(options) {\n return this.request(Object.assign(Object.assign({}, options), { method: 'GET' }));\n }\n /**\n * Perform an Http POST request given a set of options\n * @param options Options to build the HTTP request\n */\n async post(options) {\n return this.request(Object.assign(Object.assign({}, options), { method: 'POST' }));\n }\n /**\n * Perform an Http PUT request given a set of options\n * @param options Options to build the HTTP request\n */\n async put(options) {\n return this.request(Object.assign(Object.assign({}, options), { method: 'PUT' }));\n }\n /**\n * Perform an Http PATCH request given a set of options\n * @param options Options to build the HTTP request\n */\n async patch(options) {\n return this.request(Object.assign(Object.assign({}, options), { method: 'PATCH' }));\n }\n /**\n * Perform an Http DELETE request given a set of options\n * @param options Options to build the HTTP request\n */\n async delete(options) {\n return this.request(Object.assign(Object.assign({}, options), { method: 'DELETE' }));\n }\n}\nexport const CapacitorHttp = registerPlugin('CapacitorHttp', {\n web: () => new CapacitorHttpPluginWeb(),\n});\n/******** END HTTP PLUGIN ********/\n/******** SYSTEM BARS PLUGIN ********/\n/**\n * Available status bar styles.\n */\nexport var SystemBarsStyle;\n(function (SystemBarsStyle) {\n /**\n * Light system bar content on a dark background.\n *\n * @since 8.0.0\n */\n SystemBarsStyle[\"Dark\"] = \"DARK\";\n /**\n * For dark system bar content on a light background.\n *\n * @since 8.0.0\n */\n SystemBarsStyle[\"Light\"] = \"LIGHT\";\n /**\n * The style is based on the device appearance or the underlying content.\n * If the device is using Dark mode, the system bars content will be light.\n * If the device is using Light mode, the system bars content will be dark.\n *\n * @since 8.0.0\n */\n SystemBarsStyle[\"Default\"] = \"DEFAULT\";\n})(SystemBarsStyle || (SystemBarsStyle = {}));\n/**\n * Available system bar types.\n */\nexport var SystemBarType;\n(function (SystemBarType) {\n /**\n * The top status bar on both Android and iOS.\n *\n * @since 8.0.0\n */\n SystemBarType[\"StatusBar\"] = \"StatusBar\";\n /**\n * The navigation bar (or gesture bar on iOS) on both Android and iOS.\n *\n * @since 8.0.0\n */\n SystemBarType[\"NavigationBar\"] = \"NavigationBar\";\n})(SystemBarType || (SystemBarType = {}));\nexport class SystemBarsPluginWeb extends WebPlugin {\n async setStyle() {\n this.unavailable('not available for web');\n }\n async setAnimation() {\n this.unavailable('not available for web');\n }\n async show() {\n this.unavailable('not available for web');\n }\n async hide() {\n this.unavailable('not available for web');\n }\n}\nexport const SystemBars = registerPlugin('SystemBars', {\n web: () => new SystemBarsPluginWeb(),\n});\n/******** END SYSTEM BARS PLUGIN ********/\n//# sourceMappingURL=core-plugins.js.map"],"names":["ExceptionCode","exports","CapacitorException","Error","constructor","message","code","data","super","this","createCapacitor","win","capCustomPlatform","CapacitorCustomPlatform","cap","Capacitor","Plugins","getPlatform","name","_a","_b","androidBridge","webkit","messageHandlers","bridge","getPlatformId","getPluginHeader","pluginName","PluginHeaders","find","h","registeredPlugins","Map","convertFileSrc","filePath","handleError","err","console","error","isNativePlatform","isPluginAvailable","plugin","get","platforms","has","registerPlugin","jsImplementations","registeredPlugin","warn","proxy","platform","pluginHeader","jsImplementation","createPluginMethodWrapper","prop","remove","wrapper","args","p","async","loadPluginImplementation","then","impl","fn","bind","Unimplemented","methodHeader","methods","m","rtype","options","nativePromise","toString","callback","nativeCallback","createPluginMethod","Object","defineProperty","value","writable","configurable","addListener","removeListener","addListenerNative","eventName","call","callbackId","Promise","resolve","Proxy","_","set","Set","keys","Exception","DEBUG","isLoggingEnabled","initCapacitorGlobal","globalThis","self","window","global","WebPlugin","listeners","retainedEventArguments","windowListeners","listenerFunc","firstListener","push","windowListener","registered","addWindowListener","sendRetainedArgumentsForEvent","removeAllListeners","listener","removeWindowListener","notifyListeners","retainUntilConsumed","forEach","hasListeners","length","registerWindowListener","windowEventName","pluginEventName","handler","event","unimplemented","msg","unavailable","Unavailable","index","indexOf","splice","handle","addEventListener","removeEventListener","arg","WebView","encode","str","encodeURIComponent","replace","decodeURIComponent","escape","decode","CapacitorCookiesPluginWeb","getCookies","cookies","document","cookie","cookieMap","split","key","trim","setCookie","encodedKey","encodedValue","expires","path","domain","url","reject","deleteCookie","clearCookies","Date","toUTCString","clearAllCookies","CapacitorCookies","web","buildRequestInit","extra","output","assign","method","headers","type","originalKeys","map","k","toLocaleLowerCase","reduce","acc","normalizeHttpHeaders","body","includes","params","URLSearchParams","entries","FormData","form","append","Headers","delete","JSON","stringify","CapacitorHttpPluginWeb","request","requestInit","webFetchExtra","urlParams","shouldEncode","accumulator","entry","item","Array","isArray","slice","substr","buildUrlParams","shouldEncodeUrlParams","response","fetch","contentType","blob","responseType","ok","reader","FileReader","onload","base64String","result","onerror","readAsDataURL","readBlobAsBase64","json","text","status","post","put","patch","CapacitorHttp","SystemBarsStyle","SystemBarType","SystemBarsPluginWeb","setStyle","setAnimation","show","hide","SystemBars"],"mappings":"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"} \ No newline at end of file diff --git a/node_modules/@capacitor/core/dist/index.cjs.js b/node_modules/@capacitor/core/dist/index.cjs.js new file mode 100644 index 0000000..e48348e --- /dev/null +++ b/node_modules/@capacitor/core/dist/index.cjs.js @@ -0,0 +1,658 @@ +/*! Capacitor: https://capacitorjs.com/ - MIT License */ +'use strict'; + +Object.defineProperty(exports, '__esModule', { value: true }); + +exports.ExceptionCode = void 0; +(function (ExceptionCode) { + /** + * API is not implemented. + * + * This usually means the API can't be used because it is not implemented for + * the current platform. + */ + ExceptionCode["Unimplemented"] = "UNIMPLEMENTED"; + /** + * API is not available. + * + * This means the API can't be used right now because: + * - it is currently missing a prerequisite, such as network connectivity + * - it requires a particular platform or browser version + */ + ExceptionCode["Unavailable"] = "UNAVAILABLE"; +})(exports.ExceptionCode || (exports.ExceptionCode = {})); +class CapacitorException extends Error { + constructor(message, code, data) { + super(message); + this.message = message; + this.code = code; + this.data = data; + } +} +const getPlatformId = (win) => { + var _a, _b; + if (win === null || win === void 0 ? void 0 : win.androidBridge) { + return 'android'; + } + else if ((_b = (_a = win === null || win === void 0 ? void 0 : win.webkit) === null || _a === void 0 ? void 0 : _a.messageHandlers) === null || _b === void 0 ? void 0 : _b.bridge) { + return 'ios'; + } + else { + return 'web'; + } +}; + +const createCapacitor = (win) => { + const capCustomPlatform = win.CapacitorCustomPlatform || null; + const cap = win.Capacitor || {}; + const Plugins = (cap.Plugins = cap.Plugins || {}); + const getPlatform = () => { + return capCustomPlatform !== null ? capCustomPlatform.name : getPlatformId(win); + }; + const isNativePlatform = () => getPlatform() !== 'web'; + const isPluginAvailable = (pluginName) => { + const plugin = registeredPlugins.get(pluginName); + if (plugin === null || plugin === void 0 ? void 0 : plugin.platforms.has(getPlatform())) { + // JS implementation available for the current platform. + return true; + } + if (getPluginHeader(pluginName)) { + // Native implementation available. + return true; + } + return false; + }; + const getPluginHeader = (pluginName) => { var _a; return (_a = cap.PluginHeaders) === null || _a === void 0 ? void 0 : _a.find((h) => h.name === pluginName); }; + const handleError = (err) => win.console.error(err); + const registeredPlugins = new Map(); + const registerPlugin = (pluginName, jsImplementations = {}) => { + const registeredPlugin = registeredPlugins.get(pluginName); + if (registeredPlugin) { + console.warn(`Capacitor plugin "${pluginName}" already registered. Cannot register plugins twice.`); + return registeredPlugin.proxy; + } + const platform = getPlatform(); + const pluginHeader = getPluginHeader(pluginName); + let jsImplementation; + const loadPluginImplementation = async () => { + if (!jsImplementation && platform in jsImplementations) { + jsImplementation = + typeof jsImplementations[platform] === 'function' + ? (jsImplementation = await jsImplementations[platform]()) + : (jsImplementation = jsImplementations[platform]); + } + else if (capCustomPlatform !== null && !jsImplementation && 'web' in jsImplementations) { + jsImplementation = + typeof jsImplementations['web'] === 'function' + ? (jsImplementation = await jsImplementations['web']()) + : (jsImplementation = jsImplementations['web']); + } + return jsImplementation; + }; + const createPluginMethod = (impl, prop) => { + var _a, _b; + if (pluginHeader) { + const methodHeader = pluginHeader === null || pluginHeader === void 0 ? void 0 : pluginHeader.methods.find((m) => prop === m.name); + if (methodHeader) { + if (methodHeader.rtype === 'promise') { + return (options) => cap.nativePromise(pluginName, prop.toString(), options); + } + else { + return (options, callback) => cap.nativeCallback(pluginName, prop.toString(), options, callback); + } + } + else if (impl) { + return (_a = impl[prop]) === null || _a === void 0 ? void 0 : _a.bind(impl); + } + } + else if (impl) { + return (_b = impl[prop]) === null || _b === void 0 ? void 0 : _b.bind(impl); + } + else { + throw new CapacitorException(`"${pluginName}" plugin is not implemented on ${platform}`, exports.ExceptionCode.Unimplemented); + } + }; + const createPluginMethodWrapper = (prop) => { + let remove; + const wrapper = (...args) => { + const p = loadPluginImplementation().then((impl) => { + const fn = createPluginMethod(impl, prop); + if (fn) { + const p = fn(...args); + remove = p === null || p === void 0 ? void 0 : p.remove; + return p; + } + else { + throw new CapacitorException(`"${pluginName}.${prop}()" is not implemented on ${platform}`, exports.ExceptionCode.Unimplemented); + } + }); + if (prop === 'addListener') { + p.remove = async () => remove(); + } + return p; + }; + // Some flair ✨ + wrapper.toString = () => `${prop.toString()}() { [capacitor code] }`; + Object.defineProperty(wrapper, 'name', { + value: prop, + writable: false, + configurable: false, + }); + return wrapper; + }; + const addListener = createPluginMethodWrapper('addListener'); + const removeListener = createPluginMethodWrapper('removeListener'); + const addListenerNative = (eventName, callback) => { + const call = addListener({ eventName }, callback); + const remove = async () => { + const callbackId = await call; + removeListener({ + eventName, + callbackId, + }, callback); + }; + const p = new Promise((resolve) => call.then(() => resolve({ remove }))); + p.remove = async () => { + console.warn(`Using addListener() without 'await' is deprecated.`); + await remove(); + }; + return p; + }; + const proxy = new Proxy({}, { + get(_, prop) { + switch (prop) { + // https://github.com/facebook/react/issues/20030 + case '$$typeof': + return undefined; + case 'toJSON': + return () => ({}); + case 'addListener': + return pluginHeader ? addListenerNative : addListener; + case 'removeListener': + return removeListener; + default: + return createPluginMethodWrapper(prop); + } + }, + }); + Plugins[pluginName] = proxy; + registeredPlugins.set(pluginName, { + name: pluginName, + proxy, + platforms: new Set([...Object.keys(jsImplementations), ...(pluginHeader ? [platform] : [])]), + }); + return proxy; + }; + // Add in convertFileSrc for web, it will already be available in native context + if (!cap.convertFileSrc) { + cap.convertFileSrc = (filePath) => filePath; + } + cap.getPlatform = getPlatform; + cap.handleError = handleError; + cap.isNativePlatform = isNativePlatform; + cap.isPluginAvailable = isPluginAvailable; + cap.registerPlugin = registerPlugin; + cap.Exception = CapacitorException; + cap.DEBUG = !!cap.DEBUG; + cap.isLoggingEnabled = !!cap.isLoggingEnabled; + return cap; +}; +const initCapacitorGlobal = (win) => (win.Capacitor = createCapacitor(win)); + +const Capacitor = /*#__PURE__*/ initCapacitorGlobal(typeof globalThis !== 'undefined' + ? globalThis + : typeof self !== 'undefined' + ? self + : typeof window !== 'undefined' + ? window + : typeof global !== 'undefined' + ? global + : {}); +const registerPlugin = Capacitor.registerPlugin; + +/** + * Base class web plugins should extend. + */ +class WebPlugin { + constructor() { + this.listeners = {}; + this.retainedEventArguments = {}; + this.windowListeners = {}; + } + addListener(eventName, listenerFunc) { + let firstListener = false; + const listeners = this.listeners[eventName]; + if (!listeners) { + this.listeners[eventName] = []; + firstListener = true; + } + this.listeners[eventName].push(listenerFunc); + // If we haven't added a window listener for this event and it requires one, + // go ahead and add it + const windowListener = this.windowListeners[eventName]; + if (windowListener && !windowListener.registered) { + this.addWindowListener(windowListener); + } + if (firstListener) { + this.sendRetainedArgumentsForEvent(eventName); + } + const remove = async () => this.removeListener(eventName, listenerFunc); + const p = Promise.resolve({ remove }); + return p; + } + async removeAllListeners() { + this.listeners = {}; + for (const listener in this.windowListeners) { + this.removeWindowListener(this.windowListeners[listener]); + } + this.windowListeners = {}; + } + notifyListeners(eventName, data, retainUntilConsumed) { + const listeners = this.listeners[eventName]; + if (!listeners) { + if (retainUntilConsumed) { + let args = this.retainedEventArguments[eventName]; + if (!args) { + args = []; + } + args.push(data); + this.retainedEventArguments[eventName] = args; + } + return; + } + listeners.forEach((listener) => listener(data)); + } + hasListeners(eventName) { + var _a; + return !!((_a = this.listeners[eventName]) === null || _a === void 0 ? void 0 : _a.length); + } + registerWindowListener(windowEventName, pluginEventName) { + this.windowListeners[pluginEventName] = { + registered: false, + windowEventName, + pluginEventName, + handler: (event) => { + this.notifyListeners(pluginEventName, event); + }, + }; + } + unimplemented(msg = 'not implemented') { + return new Capacitor.Exception(msg, exports.ExceptionCode.Unimplemented); + } + unavailable(msg = 'not available') { + return new Capacitor.Exception(msg, exports.ExceptionCode.Unavailable); + } + async removeListener(eventName, listenerFunc) { + const listeners = this.listeners[eventName]; + if (!listeners) { + return; + } + const index = listeners.indexOf(listenerFunc); + this.listeners[eventName].splice(index, 1); + // If there are no more listeners for this type of event, + // remove the window listener + if (!this.listeners[eventName].length) { + this.removeWindowListener(this.windowListeners[eventName]); + } + } + addWindowListener(handle) { + window.addEventListener(handle.windowEventName, handle.handler); + handle.registered = true; + } + removeWindowListener(handle) { + if (!handle) { + return; + } + window.removeEventListener(handle.windowEventName, handle.handler); + handle.registered = false; + } + sendRetainedArgumentsForEvent(eventName) { + const args = this.retainedEventArguments[eventName]; + if (!args) { + return; + } + delete this.retainedEventArguments[eventName]; + args.forEach((arg) => { + this.notifyListeners(eventName, arg); + }); + } +} + +const WebView = /*#__PURE__*/ registerPlugin('WebView'); +/******** END WEB VIEW PLUGIN ********/ +/******** COOKIES PLUGIN ********/ +/** + * Safely web encode a string value (inspired by js-cookie) + * @param str The string value to encode + */ +const encode = (str) => encodeURIComponent(str) + .replace(/%(2[346B]|5E|60|7C)/g, decodeURIComponent) + .replace(/[()]/g, escape); +/** + * Safely web decode a string value (inspired by js-cookie) + * @param str The string value to decode + */ +const decode = (str) => str.replace(/(%[\dA-F]{2})+/gi, decodeURIComponent); +class CapacitorCookiesPluginWeb extends WebPlugin { + async getCookies() { + const cookies = document.cookie; + const cookieMap = {}; + cookies.split(';').forEach((cookie) => { + if (cookie.length <= 0) + return; + // Replace first "=" with CAP_COOKIE to prevent splitting on additional "=" + let [key, value] = cookie.replace(/=/, 'CAP_COOKIE').split('CAP_COOKIE'); + key = decode(key).trim(); + value = decode(value).trim(); + cookieMap[key] = value; + }); + return cookieMap; + } + async setCookie(options) { + try { + // Safely Encoded Key/Value + const encodedKey = encode(options.key); + const encodedValue = encode(options.value); + // Clean & sanitize options + const expires = options.expires ? `; expires=${options.expires.replace('expires=', '')}` : ''; + const path = (options.path || '/').replace('path=', ''); // Default is "path=/" + const domain = options.url != null && options.url.length > 0 ? `domain=${options.url}` : ''; + document.cookie = `${encodedKey}=${encodedValue || ''}${expires}; path=${path}; ${domain};`; + } + catch (error) { + return Promise.reject(error); + } + } + async deleteCookie(options) { + try { + document.cookie = `${options.key}=; Max-Age=0`; + } + catch (error) { + return Promise.reject(error); + } + } + async clearCookies() { + try { + const cookies = document.cookie.split(';') || []; + for (const cookie of cookies) { + document.cookie = cookie.replace(/^ +/, '').replace(/=.*/, `=;expires=${new Date().toUTCString()};path=/`); + } + } + catch (error) { + return Promise.reject(error); + } + } + async clearAllCookies() { + try { + await this.clearCookies(); + } + catch (error) { + return Promise.reject(error); + } + } +} +const CapacitorCookies = registerPlugin('CapacitorCookies', { + web: () => new CapacitorCookiesPluginWeb(), +}); +// UTILITY FUNCTIONS +/** + * Read in a Blob value and return it as a base64 string + * @param blob The blob value to convert to a base64 string + */ +const readBlobAsBase64 = async (blob) => new Promise((resolve, reject) => { + const reader = new FileReader(); + reader.onload = () => { + const base64String = reader.result; + // remove prefix "data:application/pdf;base64," + resolve(base64String.indexOf(',') >= 0 ? base64String.split(',')[1] : base64String); + }; + reader.onerror = (error) => reject(error); + reader.readAsDataURL(blob); +}); +/** + * Normalize an HttpHeaders map by lowercasing all of the values + * @param headers The HttpHeaders object to normalize + */ +const normalizeHttpHeaders = (headers = {}) => { + const originalKeys = Object.keys(headers); + const loweredKeys = Object.keys(headers).map((k) => k.toLocaleLowerCase()); + const normalized = loweredKeys.reduce((acc, key, index) => { + acc[key] = headers[originalKeys[index]]; + return acc; + }, {}); + return normalized; +}; +/** + * Builds a string of url parameters that + * @param params A map of url parameters + * @param shouldEncode true if you should encodeURIComponent() the values (true by default) + */ +const buildUrlParams = (params, shouldEncode = true) => { + if (!params) + return null; + const output = Object.entries(params).reduce((accumulator, entry) => { + const [key, value] = entry; + let encodedValue; + let item; + if (Array.isArray(value)) { + item = ''; + value.forEach((str) => { + encodedValue = shouldEncode ? encodeURIComponent(str) : str; + item += `${key}=${encodedValue}&`; + }); + // last character will always be "&" so slice it off + item.slice(0, -1); + } + else { + encodedValue = shouldEncode ? encodeURIComponent(value) : value; + item = `${key}=${encodedValue}`; + } + return `${accumulator}&${item}`; + }, ''); + // Remove initial "&" from the reduce + return output.substr(1); +}; +/** + * Build the RequestInit object based on the options passed into the initial request + * @param options The Http plugin options + * @param extra Any extra RequestInit values + */ +const buildRequestInit = (options, extra = {}) => { + const output = Object.assign({ method: options.method || 'GET', headers: options.headers }, extra); + // Get the content-type + const headers = normalizeHttpHeaders(options.headers); + const type = headers['content-type'] || ''; + // If body is already a string, then pass it through as-is. + if (typeof options.data === 'string') { + output.body = options.data; + } + // Build request initializers based off of content-type + else if (type.includes('application/x-www-form-urlencoded')) { + const params = new URLSearchParams(); + for (const [key, value] of Object.entries(options.data || {})) { + params.set(key, value); + } + output.body = params.toString(); + } + else if (type.includes('multipart/form-data') || options.data instanceof FormData) { + const form = new FormData(); + if (options.data instanceof FormData) { + options.data.forEach((value, key) => { + form.append(key, value); + }); + } + else { + for (const key of Object.keys(options.data)) { + form.append(key, options.data[key]); + } + } + output.body = form; + const headers = new Headers(output.headers); + headers.delete('content-type'); // content-type will be set by `window.fetch` to includy boundary + output.headers = headers; + } + else if (type.includes('application/json') || typeof options.data === 'object') { + output.body = JSON.stringify(options.data); + } + return output; +}; +// WEB IMPLEMENTATION +class CapacitorHttpPluginWeb extends WebPlugin { + /** + * Perform an Http request given a set of options + * @param options Options to build the HTTP request + */ + async request(options) { + const requestInit = buildRequestInit(options, options.webFetchExtra); + const urlParams = buildUrlParams(options.params, options.shouldEncodeUrlParams); + const url = urlParams ? `${options.url}?${urlParams}` : options.url; + const response = await fetch(url, requestInit); + const contentType = response.headers.get('content-type') || ''; + // Default to 'text' responseType so no parsing happens + let { responseType = 'text' } = response.ok ? options : {}; + // If the response content-type is json, force the response to be json + if (contentType.includes('application/json')) { + responseType = 'json'; + } + let data; + let blob; + switch (responseType) { + case 'arraybuffer': + case 'blob': + blob = await response.blob(); + data = await readBlobAsBase64(blob); + break; + case 'json': + data = await response.json(); + break; + case 'document': + case 'text': + default: + data = await response.text(); + } + // Convert fetch headers to Capacitor HttpHeaders + const headers = {}; + response.headers.forEach((value, key) => { + headers[key] = value; + }); + return { + data, + headers, + status: response.status, + url: response.url, + }; + } + /** + * Perform an Http GET request given a set of options + * @param options Options to build the HTTP request + */ + async get(options) { + return this.request(Object.assign(Object.assign({}, options), { method: 'GET' })); + } + /** + * Perform an Http POST request given a set of options + * @param options Options to build the HTTP request + */ + async post(options) { + return this.request(Object.assign(Object.assign({}, options), { method: 'POST' })); + } + /** + * Perform an Http PUT request given a set of options + * @param options Options to build the HTTP request + */ + async put(options) { + return this.request(Object.assign(Object.assign({}, options), { method: 'PUT' })); + } + /** + * Perform an Http PATCH request given a set of options + * @param options Options to build the HTTP request + */ + async patch(options) { + return this.request(Object.assign(Object.assign({}, options), { method: 'PATCH' })); + } + /** + * Perform an Http DELETE request given a set of options + * @param options Options to build the HTTP request + */ + async delete(options) { + return this.request(Object.assign(Object.assign({}, options), { method: 'DELETE' })); + } +} +const CapacitorHttp = registerPlugin('CapacitorHttp', { + web: () => new CapacitorHttpPluginWeb(), +}); +/******** END HTTP PLUGIN ********/ +/******** SYSTEM BARS PLUGIN ********/ +/** + * Available status bar styles. + */ +exports.SystemBarsStyle = void 0; +(function (SystemBarsStyle) { + /** + * Light system bar content on a dark background. + * + * @since 8.0.0 + */ + SystemBarsStyle["Dark"] = "DARK"; + /** + * For dark system bar content on a light background. + * + * @since 8.0.0 + */ + SystemBarsStyle["Light"] = "LIGHT"; + /** + * The style is based on the device appearance or the underlying content. + * If the device is using Dark mode, the system bars content will be light. + * If the device is using Light mode, the system bars content will be dark. + * + * @since 8.0.0 + */ + SystemBarsStyle["Default"] = "DEFAULT"; +})(exports.SystemBarsStyle || (exports.SystemBarsStyle = {})); +/** + * Available system bar types. + */ +exports.SystemBarType = void 0; +(function (SystemBarType) { + /** + * The top status bar on both Android and iOS. + * + * @since 8.0.0 + */ + SystemBarType["StatusBar"] = "StatusBar"; + /** + * The navigation bar (or gesture bar on iOS) on both Android and iOS. + * + * @since 8.0.0 + */ + SystemBarType["NavigationBar"] = "NavigationBar"; +})(exports.SystemBarType || (exports.SystemBarType = {})); +class SystemBarsPluginWeb extends WebPlugin { + async setStyle() { + this.unavailable('not available for web'); + } + async setAnimation() { + this.unavailable('not available for web'); + } + async show() { + this.unavailable('not available for web'); + } + async hide() { + this.unavailable('not available for web'); + } +} +const SystemBars = registerPlugin('SystemBars', { + web: () => new SystemBarsPluginWeb(), +}); +/******** END SYSTEM BARS PLUGIN ********/ + +exports.Capacitor = Capacitor; +exports.CapacitorCookies = CapacitorCookies; +exports.CapacitorException = CapacitorException; +exports.CapacitorHttp = CapacitorHttp; +exports.SystemBars = SystemBars; +exports.WebPlugin = WebPlugin; +exports.WebView = WebView; +exports.buildRequestInit = buildRequestInit; +exports.registerPlugin = registerPlugin; +//# sourceMappingURL=index.cjs.js.map diff --git a/node_modules/@capacitor/core/dist/index.cjs.js.map b/node_modules/@capacitor/core/dist/index.cjs.js.map new file mode 100644 index 0000000..92ca85b --- /dev/null +++ b/node_modules/@capacitor/core/dist/index.cjs.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.cjs.js","sources":["../build/util.js","../build/runtime.js","../build/global.js","../build/web-plugin.js","../build/core-plugins.js"],"sourcesContent":["export var ExceptionCode;\n(function (ExceptionCode) {\n /**\n * API is not implemented.\n *\n * This usually means the API can't be used because it is not implemented for\n * the current platform.\n */\n ExceptionCode[\"Unimplemented\"] = \"UNIMPLEMENTED\";\n /**\n * API is not available.\n *\n * This means the API can't be used right now because:\n * - it is currently missing a prerequisite, such as network connectivity\n * - it requires a particular platform or browser version\n */\n ExceptionCode[\"Unavailable\"] = \"UNAVAILABLE\";\n})(ExceptionCode || (ExceptionCode = {}));\nexport class CapacitorException extends Error {\n constructor(message, code, data) {\n super(message);\n this.message = message;\n this.code = code;\n this.data = data;\n }\n}\nexport const getPlatformId = (win) => {\n var _a, _b;\n if (win === null || win === void 0 ? void 0 : win.androidBridge) {\n return 'android';\n }\n else if ((_b = (_a = win === null || win === void 0 ? void 0 : win.webkit) === null || _a === void 0 ? void 0 : _a.messageHandlers) === null || _b === void 0 ? void 0 : _b.bridge) {\n return 'ios';\n }\n else {\n return 'web';\n }\n};\n//# sourceMappingURL=util.js.map","import { CapacitorException, getPlatformId, ExceptionCode } from './util';\nexport const createCapacitor = (win) => {\n const capCustomPlatform = win.CapacitorCustomPlatform || null;\n const cap = win.Capacitor || {};\n const Plugins = (cap.Plugins = cap.Plugins || {});\n const getPlatform = () => {\n return capCustomPlatform !== null ? capCustomPlatform.name : getPlatformId(win);\n };\n const isNativePlatform = () => getPlatform() !== 'web';\n const isPluginAvailable = (pluginName) => {\n const plugin = registeredPlugins.get(pluginName);\n if (plugin === null || plugin === void 0 ? void 0 : plugin.platforms.has(getPlatform())) {\n // JS implementation available for the current platform.\n return true;\n }\n if (getPluginHeader(pluginName)) {\n // Native implementation available.\n return true;\n }\n return false;\n };\n const getPluginHeader = (pluginName) => { var _a; return (_a = cap.PluginHeaders) === null || _a === void 0 ? void 0 : _a.find((h) => h.name === pluginName); };\n const handleError = (err) => win.console.error(err);\n const registeredPlugins = new Map();\n const registerPlugin = (pluginName, jsImplementations = {}) => {\n const registeredPlugin = registeredPlugins.get(pluginName);\n if (registeredPlugin) {\n console.warn(`Capacitor plugin \"${pluginName}\" already registered. Cannot register plugins twice.`);\n return registeredPlugin.proxy;\n }\n const platform = getPlatform();\n const pluginHeader = getPluginHeader(pluginName);\n let jsImplementation;\n const loadPluginImplementation = async () => {\n if (!jsImplementation && platform in jsImplementations) {\n jsImplementation =\n typeof jsImplementations[platform] === 'function'\n ? (jsImplementation = await jsImplementations[platform]())\n : (jsImplementation = jsImplementations[platform]);\n }\n else if (capCustomPlatform !== null && !jsImplementation && 'web' in jsImplementations) {\n jsImplementation =\n typeof jsImplementations['web'] === 'function'\n ? (jsImplementation = await jsImplementations['web']())\n : (jsImplementation = jsImplementations['web']);\n }\n return jsImplementation;\n };\n const createPluginMethod = (impl, prop) => {\n var _a, _b;\n if (pluginHeader) {\n const methodHeader = pluginHeader === null || pluginHeader === void 0 ? void 0 : pluginHeader.methods.find((m) => prop === m.name);\n if (methodHeader) {\n if (methodHeader.rtype === 'promise') {\n return (options) => cap.nativePromise(pluginName, prop.toString(), options);\n }\n else {\n return (options, callback) => cap.nativeCallback(pluginName, prop.toString(), options, callback);\n }\n }\n else if (impl) {\n return (_a = impl[prop]) === null || _a === void 0 ? void 0 : _a.bind(impl);\n }\n }\n else if (impl) {\n return (_b = impl[prop]) === null || _b === void 0 ? void 0 : _b.bind(impl);\n }\n else {\n throw new CapacitorException(`\"${pluginName}\" plugin is not implemented on ${platform}`, ExceptionCode.Unimplemented);\n }\n };\n const createPluginMethodWrapper = (prop) => {\n let remove;\n const wrapper = (...args) => {\n const p = loadPluginImplementation().then((impl) => {\n const fn = createPluginMethod(impl, prop);\n if (fn) {\n const p = fn(...args);\n remove = p === null || p === void 0 ? void 0 : p.remove;\n return p;\n }\n else {\n throw new CapacitorException(`\"${pluginName}.${prop}()\" is not implemented on ${platform}`, ExceptionCode.Unimplemented);\n }\n });\n if (prop === 'addListener') {\n p.remove = async () => remove();\n }\n return p;\n };\n // Some flair ✨\n wrapper.toString = () => `${prop.toString()}() { [capacitor code] }`;\n Object.defineProperty(wrapper, 'name', {\n value: prop,\n writable: false,\n configurable: false,\n });\n return wrapper;\n };\n const addListener = createPluginMethodWrapper('addListener');\n const removeListener = createPluginMethodWrapper('removeListener');\n const addListenerNative = (eventName, callback) => {\n const call = addListener({ eventName }, callback);\n const remove = async () => {\n const callbackId = await call;\n removeListener({\n eventName,\n callbackId,\n }, callback);\n };\n const p = new Promise((resolve) => call.then(() => resolve({ remove })));\n p.remove = async () => {\n console.warn(`Using addListener() without 'await' is deprecated.`);\n await remove();\n };\n return p;\n };\n const proxy = new Proxy({}, {\n get(_, prop) {\n switch (prop) {\n // https://github.com/facebook/react/issues/20030\n case '$$typeof':\n return undefined;\n case 'toJSON':\n return () => ({});\n case 'addListener':\n return pluginHeader ? addListenerNative : addListener;\n case 'removeListener':\n return removeListener;\n default:\n return createPluginMethodWrapper(prop);\n }\n },\n });\n Plugins[pluginName] = proxy;\n registeredPlugins.set(pluginName, {\n name: pluginName,\n proxy,\n platforms: new Set([...Object.keys(jsImplementations), ...(pluginHeader ? [platform] : [])]),\n });\n return proxy;\n };\n // Add in convertFileSrc for web, it will already be available in native context\n if (!cap.convertFileSrc) {\n cap.convertFileSrc = (filePath) => filePath;\n }\n cap.getPlatform = getPlatform;\n cap.handleError = handleError;\n cap.isNativePlatform = isNativePlatform;\n cap.isPluginAvailable = isPluginAvailable;\n cap.registerPlugin = registerPlugin;\n cap.Exception = CapacitorException;\n cap.DEBUG = !!cap.DEBUG;\n cap.isLoggingEnabled = !!cap.isLoggingEnabled;\n return cap;\n};\nexport const initCapacitorGlobal = (win) => (win.Capacitor = createCapacitor(win));\n//# sourceMappingURL=runtime.js.map","import { initCapacitorGlobal } from './runtime';\nexport const Capacitor = /*#__PURE__*/ initCapacitorGlobal(typeof globalThis !== 'undefined'\n ? globalThis\n : typeof self !== 'undefined'\n ? self\n : typeof window !== 'undefined'\n ? window\n : typeof global !== 'undefined'\n ? global\n : {});\nexport const registerPlugin = Capacitor.registerPlugin;\n//# sourceMappingURL=global.js.map","import { Capacitor } from './global';\nimport { ExceptionCode } from './util';\n/**\n * Base class web plugins should extend.\n */\nexport class WebPlugin {\n constructor() {\n this.listeners = {};\n this.retainedEventArguments = {};\n this.windowListeners = {};\n }\n addListener(eventName, listenerFunc) {\n let firstListener = false;\n const listeners = this.listeners[eventName];\n if (!listeners) {\n this.listeners[eventName] = [];\n firstListener = true;\n }\n this.listeners[eventName].push(listenerFunc);\n // If we haven't added a window listener for this event and it requires one,\n // go ahead and add it\n const windowListener = this.windowListeners[eventName];\n if (windowListener && !windowListener.registered) {\n this.addWindowListener(windowListener);\n }\n if (firstListener) {\n this.sendRetainedArgumentsForEvent(eventName);\n }\n const remove = async () => this.removeListener(eventName, listenerFunc);\n const p = Promise.resolve({ remove });\n return p;\n }\n async removeAllListeners() {\n this.listeners = {};\n for (const listener in this.windowListeners) {\n this.removeWindowListener(this.windowListeners[listener]);\n }\n this.windowListeners = {};\n }\n notifyListeners(eventName, data, retainUntilConsumed) {\n const listeners = this.listeners[eventName];\n if (!listeners) {\n if (retainUntilConsumed) {\n let args = this.retainedEventArguments[eventName];\n if (!args) {\n args = [];\n }\n args.push(data);\n this.retainedEventArguments[eventName] = args;\n }\n return;\n }\n listeners.forEach((listener) => listener(data));\n }\n hasListeners(eventName) {\n var _a;\n return !!((_a = this.listeners[eventName]) === null || _a === void 0 ? void 0 : _a.length);\n }\n registerWindowListener(windowEventName, pluginEventName) {\n this.windowListeners[pluginEventName] = {\n registered: false,\n windowEventName,\n pluginEventName,\n handler: (event) => {\n this.notifyListeners(pluginEventName, event);\n },\n };\n }\n unimplemented(msg = 'not implemented') {\n return new Capacitor.Exception(msg, ExceptionCode.Unimplemented);\n }\n unavailable(msg = 'not available') {\n return new Capacitor.Exception(msg, ExceptionCode.Unavailable);\n }\n async removeListener(eventName, listenerFunc) {\n const listeners = this.listeners[eventName];\n if (!listeners) {\n return;\n }\n const index = listeners.indexOf(listenerFunc);\n this.listeners[eventName].splice(index, 1);\n // If there are no more listeners for this type of event,\n // remove the window listener\n if (!this.listeners[eventName].length) {\n this.removeWindowListener(this.windowListeners[eventName]);\n }\n }\n addWindowListener(handle) {\n window.addEventListener(handle.windowEventName, handle.handler);\n handle.registered = true;\n }\n removeWindowListener(handle) {\n if (!handle) {\n return;\n }\n window.removeEventListener(handle.windowEventName, handle.handler);\n handle.registered = false;\n }\n sendRetainedArgumentsForEvent(eventName) {\n const args = this.retainedEventArguments[eventName];\n if (!args) {\n return;\n }\n delete this.retainedEventArguments[eventName];\n args.forEach((arg) => {\n this.notifyListeners(eventName, arg);\n });\n }\n}\n//# sourceMappingURL=web-plugin.js.map","import { registerPlugin } from './global';\nimport { WebPlugin } from './web-plugin';\nexport const WebView = /*#__PURE__*/ registerPlugin('WebView');\n/******** END WEB VIEW PLUGIN ********/\n/******** COOKIES PLUGIN ********/\n/**\n * Safely web encode a string value (inspired by js-cookie)\n * @param str The string value to encode\n */\nconst encode = (str) => encodeURIComponent(str)\n .replace(/%(2[346B]|5E|60|7C)/g, decodeURIComponent)\n .replace(/[()]/g, escape);\n/**\n * Safely web decode a string value (inspired by js-cookie)\n * @param str The string value to decode\n */\nconst decode = (str) => str.replace(/(%[\\dA-F]{2})+/gi, decodeURIComponent);\nexport class CapacitorCookiesPluginWeb extends WebPlugin {\n async getCookies() {\n const cookies = document.cookie;\n const cookieMap = {};\n cookies.split(';').forEach((cookie) => {\n if (cookie.length <= 0)\n return;\n // Replace first \"=\" with CAP_COOKIE to prevent splitting on additional \"=\"\n let [key, value] = cookie.replace(/=/, 'CAP_COOKIE').split('CAP_COOKIE');\n key = decode(key).trim();\n value = decode(value).trim();\n cookieMap[key] = value;\n });\n return cookieMap;\n }\n async setCookie(options) {\n try {\n // Safely Encoded Key/Value\n const encodedKey = encode(options.key);\n const encodedValue = encode(options.value);\n // Clean & sanitize options\n const expires = options.expires ? `; expires=${options.expires.replace('expires=', '')}` : '';\n const path = (options.path || '/').replace('path=', ''); // Default is \"path=/\"\n const domain = options.url != null && options.url.length > 0 ? `domain=${options.url}` : '';\n document.cookie = `${encodedKey}=${encodedValue || ''}${expires}; path=${path}; ${domain};`;\n }\n catch (error) {\n return Promise.reject(error);\n }\n }\n async deleteCookie(options) {\n try {\n document.cookie = `${options.key}=; Max-Age=0`;\n }\n catch (error) {\n return Promise.reject(error);\n }\n }\n async clearCookies() {\n try {\n const cookies = document.cookie.split(';') || [];\n for (const cookie of cookies) {\n document.cookie = cookie.replace(/^ +/, '').replace(/=.*/, `=;expires=${new Date().toUTCString()};path=/`);\n }\n }\n catch (error) {\n return Promise.reject(error);\n }\n }\n async clearAllCookies() {\n try {\n await this.clearCookies();\n }\n catch (error) {\n return Promise.reject(error);\n }\n }\n}\nexport const CapacitorCookies = registerPlugin('CapacitorCookies', {\n web: () => new CapacitorCookiesPluginWeb(),\n});\n// UTILITY FUNCTIONS\n/**\n * Read in a Blob value and return it as a base64 string\n * @param blob The blob value to convert to a base64 string\n */\nexport const readBlobAsBase64 = async (blob) => new Promise((resolve, reject) => {\n const reader = new FileReader();\n reader.onload = () => {\n const base64String = reader.result;\n // remove prefix \"data:application/pdf;base64,\"\n resolve(base64String.indexOf(',') >= 0 ? base64String.split(',')[1] : base64String);\n };\n reader.onerror = (error) => reject(error);\n reader.readAsDataURL(blob);\n});\n/**\n * Normalize an HttpHeaders map by lowercasing all of the values\n * @param headers The HttpHeaders object to normalize\n */\nconst normalizeHttpHeaders = (headers = {}) => {\n const originalKeys = Object.keys(headers);\n const loweredKeys = Object.keys(headers).map((k) => k.toLocaleLowerCase());\n const normalized = loweredKeys.reduce((acc, key, index) => {\n acc[key] = headers[originalKeys[index]];\n return acc;\n }, {});\n return normalized;\n};\n/**\n * Builds a string of url parameters that\n * @param params A map of url parameters\n * @param shouldEncode true if you should encodeURIComponent() the values (true by default)\n */\nconst buildUrlParams = (params, shouldEncode = true) => {\n if (!params)\n return null;\n const output = Object.entries(params).reduce((accumulator, entry) => {\n const [key, value] = entry;\n let encodedValue;\n let item;\n if (Array.isArray(value)) {\n item = '';\n value.forEach((str) => {\n encodedValue = shouldEncode ? encodeURIComponent(str) : str;\n item += `${key}=${encodedValue}&`;\n });\n // last character will always be \"&\" so slice it off\n item.slice(0, -1);\n }\n else {\n encodedValue = shouldEncode ? encodeURIComponent(value) : value;\n item = `${key}=${encodedValue}`;\n }\n return `${accumulator}&${item}`;\n }, '');\n // Remove initial \"&\" from the reduce\n return output.substr(1);\n};\n/**\n * Build the RequestInit object based on the options passed into the initial request\n * @param options The Http plugin options\n * @param extra Any extra RequestInit values\n */\nexport const buildRequestInit = (options, extra = {}) => {\n const output = Object.assign({ method: options.method || 'GET', headers: options.headers }, extra);\n // Get the content-type\n const headers = normalizeHttpHeaders(options.headers);\n const type = headers['content-type'] || '';\n // If body is already a string, then pass it through as-is.\n if (typeof options.data === 'string') {\n output.body = options.data;\n }\n // Build request initializers based off of content-type\n else if (type.includes('application/x-www-form-urlencoded')) {\n const params = new URLSearchParams();\n for (const [key, value] of Object.entries(options.data || {})) {\n params.set(key, value);\n }\n output.body = params.toString();\n }\n else if (type.includes('multipart/form-data') || options.data instanceof FormData) {\n const form = new FormData();\n if (options.data instanceof FormData) {\n options.data.forEach((value, key) => {\n form.append(key, value);\n });\n }\n else {\n for (const key of Object.keys(options.data)) {\n form.append(key, options.data[key]);\n }\n }\n output.body = form;\n const headers = new Headers(output.headers);\n headers.delete('content-type'); // content-type will be set by `window.fetch` to includy boundary\n output.headers = headers;\n }\n else if (type.includes('application/json') || typeof options.data === 'object') {\n output.body = JSON.stringify(options.data);\n }\n return output;\n};\n// WEB IMPLEMENTATION\nexport class CapacitorHttpPluginWeb extends WebPlugin {\n /**\n * Perform an Http request given a set of options\n * @param options Options to build the HTTP request\n */\n async request(options) {\n const requestInit = buildRequestInit(options, options.webFetchExtra);\n const urlParams = buildUrlParams(options.params, options.shouldEncodeUrlParams);\n const url = urlParams ? `${options.url}?${urlParams}` : options.url;\n const response = await fetch(url, requestInit);\n const contentType = response.headers.get('content-type') || '';\n // Default to 'text' responseType so no parsing happens\n let { responseType = 'text' } = response.ok ? options : {};\n // If the response content-type is json, force the response to be json\n if (contentType.includes('application/json')) {\n responseType = 'json';\n }\n let data;\n let blob;\n switch (responseType) {\n case 'arraybuffer':\n case 'blob':\n blob = await response.blob();\n data = await readBlobAsBase64(blob);\n break;\n case 'json':\n data = await response.json();\n break;\n case 'document':\n case 'text':\n default:\n data = await response.text();\n }\n // Convert fetch headers to Capacitor HttpHeaders\n const headers = {};\n response.headers.forEach((value, key) => {\n headers[key] = value;\n });\n return {\n data,\n headers,\n status: response.status,\n url: response.url,\n };\n }\n /**\n * Perform an Http GET request given a set of options\n * @param options Options to build the HTTP request\n */\n async get(options) {\n return this.request(Object.assign(Object.assign({}, options), { method: 'GET' }));\n }\n /**\n * Perform an Http POST request given a set of options\n * @param options Options to build the HTTP request\n */\n async post(options) {\n return this.request(Object.assign(Object.assign({}, options), { method: 'POST' }));\n }\n /**\n * Perform an Http PUT request given a set of options\n * @param options Options to build the HTTP request\n */\n async put(options) {\n return this.request(Object.assign(Object.assign({}, options), { method: 'PUT' }));\n }\n /**\n * Perform an Http PATCH request given a set of options\n * @param options Options to build the HTTP request\n */\n async patch(options) {\n return this.request(Object.assign(Object.assign({}, options), { method: 'PATCH' }));\n }\n /**\n * Perform an Http DELETE request given a set of options\n * @param options Options to build the HTTP request\n */\n async delete(options) {\n return this.request(Object.assign(Object.assign({}, options), { method: 'DELETE' }));\n }\n}\nexport const CapacitorHttp = registerPlugin('CapacitorHttp', {\n web: () => new CapacitorHttpPluginWeb(),\n});\n/******** END HTTP PLUGIN ********/\n/******** SYSTEM BARS PLUGIN ********/\n/**\n * Available status bar styles.\n */\nexport var SystemBarsStyle;\n(function (SystemBarsStyle) {\n /**\n * Light system bar content on a dark background.\n *\n * @since 8.0.0\n */\n SystemBarsStyle[\"Dark\"] = \"DARK\";\n /**\n * For dark system bar content on a light background.\n *\n * @since 8.0.0\n */\n SystemBarsStyle[\"Light\"] = \"LIGHT\";\n /**\n * The style is based on the device appearance or the underlying content.\n * If the device is using Dark mode, the system bars content will be light.\n * If the device is using Light mode, the system bars content will be dark.\n *\n * @since 8.0.0\n */\n SystemBarsStyle[\"Default\"] = \"DEFAULT\";\n})(SystemBarsStyle || (SystemBarsStyle = {}));\n/**\n * Available system bar types.\n */\nexport var SystemBarType;\n(function (SystemBarType) {\n /**\n * The top status bar on both Android and iOS.\n *\n * @since 8.0.0\n */\n SystemBarType[\"StatusBar\"] = \"StatusBar\";\n /**\n * The navigation bar (or gesture bar on iOS) on both Android and iOS.\n *\n * @since 8.0.0\n */\n SystemBarType[\"NavigationBar\"] = \"NavigationBar\";\n})(SystemBarType || (SystemBarType = {}));\nexport class SystemBarsPluginWeb extends WebPlugin {\n async setStyle() {\n this.unavailable('not available for web');\n }\n async setAnimation() {\n this.unavailable('not available for web');\n }\n async show() {\n this.unavailable('not available for web');\n }\n async hide() {\n this.unavailable('not available for web');\n }\n}\nexport const SystemBars = registerPlugin('SystemBars', {\n web: () => new SystemBarsPluginWeb(),\n});\n/******** END SYSTEM BARS PLUGIN ********/\n//# sourceMappingURL=core-plugins.js.map"],"names":["ExceptionCode","SystemBarsStyle","SystemBarType"],"mappings":";;;;;AAAWA,+BAAc;AACzB,CAAC,UAAU,aAAa,EAAE;AAC1B;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,aAAa,CAAC,eAAe,CAAC,GAAG,eAAe,CAAC;AACrD;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,aAAa,CAAC,aAAa,CAAC,GAAG,aAAa,CAAC;AACjD,CAAC,EAAEA,qBAAa,KAAKA,qBAAa,GAAG,EAAE,CAAC,CAAC,CAAC;AACnC,MAAM,kBAAkB,SAAS,KAAK,CAAC;AAC9C,IAAI,WAAW,CAAC,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE;AACrC,QAAQ,KAAK,CAAC,OAAO,CAAC,CAAC;AACvB,QAAQ,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;AAC/B,QAAQ,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;AACzB,QAAQ,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;AACzB,KAAK;AACL,CAAC;AACM,MAAM,aAAa,GAAG,CAAC,GAAG,KAAK;AACtC,IAAI,IAAI,EAAE,EAAE,EAAE,CAAC;AACf,IAAI,IAAI,GAAG,KAAK,IAAI,IAAI,GAAG,KAAK,KAAK,CAAC,GAAG,KAAK,CAAC,GAAG,GAAG,CAAC,aAAa,EAAE;AACrE,QAAQ,OAAO,SAAS,CAAC;AACzB,KAAK;AACL,SAAS,IAAI,CAAC,EAAE,GAAG,CAAC,EAAE,GAAG,GAAG,KAAK,IAAI,IAAI,GAAG,KAAK,KAAK,CAAC,GAAG,KAAK,CAAC,GAAG,GAAG,CAAC,MAAM,MAAM,IAAI,IAAI,EAAE,KAAK,KAAK,CAAC,GAAG,KAAK,CAAC,GAAG,EAAE,CAAC,eAAe,MAAM,IAAI,IAAI,EAAE,KAAK,KAAK,CAAC,GAAG,KAAK,CAAC,GAAG,EAAE,CAAC,MAAM,EAAE;AACxL,QAAQ,OAAO,KAAK,CAAC;AACrB,KAAK;AACL,SAAS;AACT,QAAQ,OAAO,KAAK,CAAC;AACrB,KAAK;AACL,CAAC;;ACpCM,MAAM,eAAe,GAAG,CAAC,GAAG,KAAK;AACxC,IAAI,MAAM,iBAAiB,GAAG,GAAG,CAAC,uBAAuB,IAAI,IAAI,CAAC;AAClE,IAAI,MAAM,GAAG,GAAG,GAAG,CAAC,SAAS,IAAI,EAAE,CAAC;AACpC,IAAI,MAAM,OAAO,IAAI,GAAG,CAAC,OAAO,GAAG,GAAG,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC;AACtD,IAAI,MAAM,WAAW,GAAG,MAAM;AAC9B,QAAQ,OAAO,iBAAiB,KAAK,IAAI,GAAG,iBAAiB,CAAC,IAAI,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC;AACxF,KAAK,CAAC;AACN,IAAI,MAAM,gBAAgB,GAAG,MAAM,WAAW,EAAE,KAAK,KAAK,CAAC;AAC3D,IAAI,MAAM,iBAAiB,GAAG,CAAC,UAAU,KAAK;AAC9C,QAAQ,MAAM,MAAM,GAAG,iBAAiB,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;AACzD,QAAQ,IAAI,MAAM,KAAK,IAAI,IAAI,MAAM,KAAK,KAAK,CAAC,GAAG,KAAK,CAAC,GAAG,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC,EAAE;AACjG;AACA,YAAY,OAAO,IAAI,CAAC;AACxB,SAAS;AACT,QAAQ,IAAI,eAAe,CAAC,UAAU,CAAC,EAAE;AACzC;AACA,YAAY,OAAO,IAAI,CAAC;AACxB,SAAS;AACT,QAAQ,OAAO,KAAK,CAAC;AACrB,KAAK,CAAC;AACN,IAAI,MAAM,eAAe,GAAG,CAAC,UAAU,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,EAAE,GAAG,GAAG,CAAC,aAAa,MAAM,IAAI,IAAI,EAAE,KAAK,KAAK,CAAC,GAAG,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,KAAK,UAAU,CAAC,CAAC,EAAE,CAAC;AACpK,IAAI,MAAM,WAAW,GAAG,CAAC,GAAG,KAAK,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;AACxD,IAAI,MAAM,iBAAiB,GAAG,IAAI,GAAG,EAAE,CAAC;AACxC,IAAI,MAAM,cAAc,GAAG,CAAC,UAAU,EAAE,iBAAiB,GAAG,EAAE,KAAK;AACnE,QAAQ,MAAM,gBAAgB,GAAG,iBAAiB,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;AACnE,QAAQ,IAAI,gBAAgB,EAAE;AAC9B,YAAY,OAAO,CAAC,IAAI,CAAC,CAAC,kBAAkB,EAAE,UAAU,CAAC,oDAAoD,CAAC,CAAC,CAAC;AAChH,YAAY,OAAO,gBAAgB,CAAC,KAAK,CAAC;AAC1C,SAAS;AACT,QAAQ,MAAM,QAAQ,GAAG,WAAW,EAAE,CAAC;AACvC,QAAQ,MAAM,YAAY,GAAG,eAAe,CAAC,UAAU,CAAC,CAAC;AACzD,QAAQ,IAAI,gBAAgB,CAAC;AAC7B,QAAQ,MAAM,wBAAwB,GAAG,YAAY;AACrD,YAAY,IAAI,CAAC,gBAAgB,IAAI,QAAQ,IAAI,iBAAiB,EAAE;AACpE,gBAAgB,gBAAgB;AAChC,oBAAoB,OAAO,iBAAiB,CAAC,QAAQ,CAAC,KAAK,UAAU;AACrE,2BAA2B,gBAAgB,GAAG,MAAM,iBAAiB,CAAC,QAAQ,CAAC,EAAE;AACjF,2BAA2B,gBAAgB,GAAG,iBAAiB,CAAC,QAAQ,CAAC,CAAC,CAAC;AAC3E,aAAa;AACb,iBAAiB,IAAI,iBAAiB,KAAK,IAAI,IAAI,CAAC,gBAAgB,IAAI,KAAK,IAAI,iBAAiB,EAAE;AACpG,gBAAgB,gBAAgB;AAChC,oBAAoB,OAAO,iBAAiB,CAAC,KAAK,CAAC,KAAK,UAAU;AAClE,2BAA2B,gBAAgB,GAAG,MAAM,iBAAiB,CAAC,KAAK,CAAC,EAAE;AAC9E,2BAA2B,gBAAgB,GAAG,iBAAiB,CAAC,KAAK,CAAC,CAAC,CAAC;AACxE,aAAa;AACb,YAAY,OAAO,gBAAgB,CAAC;AACpC,SAAS,CAAC;AACV,QAAQ,MAAM,kBAAkB,GAAG,CAAC,IAAI,EAAE,IAAI,KAAK;AACnD,YAAY,IAAI,EAAE,EAAE,EAAE,CAAC;AACvB,YAAY,IAAI,YAAY,EAAE;AAC9B,gBAAgB,MAAM,YAAY,GAAG,YAAY,KAAK,IAAI,IAAI,YAAY,KAAK,KAAK,CAAC,GAAG,KAAK,CAAC,GAAG,YAAY,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC;AACnJ,gBAAgB,IAAI,YAAY,EAAE;AAClC,oBAAoB,IAAI,YAAY,CAAC,KAAK,KAAK,SAAS,EAAE;AAC1D,wBAAwB,OAAO,CAAC,OAAO,KAAK,GAAG,CAAC,aAAa,CAAC,UAAU,EAAE,IAAI,CAAC,QAAQ,EAAE,EAAE,OAAO,CAAC,CAAC;AACpG,qBAAqB;AACrB,yBAAyB;AACzB,wBAAwB,OAAO,CAAC,OAAO,EAAE,QAAQ,KAAK,GAAG,CAAC,cAAc,CAAC,UAAU,EAAE,IAAI,CAAC,QAAQ,EAAE,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC;AACzH,qBAAqB;AACrB,iBAAiB;AACjB,qBAAqB,IAAI,IAAI,EAAE;AAC/B,oBAAoB,OAAO,CAAC,EAAE,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,IAAI,IAAI,EAAE,KAAK,KAAK,CAAC,GAAG,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAChG,iBAAiB;AACjB,aAAa;AACb,iBAAiB,IAAI,IAAI,EAAE;AAC3B,gBAAgB,OAAO,CAAC,EAAE,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,IAAI,IAAI,EAAE,KAAK,KAAK,CAAC,GAAG,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC5F,aAAa;AACb,iBAAiB;AACjB,gBAAgB,MAAM,IAAI,kBAAkB,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC,+BAA+B,EAAE,QAAQ,CAAC,CAAC,EAAEA,qBAAa,CAAC,aAAa,CAAC,CAAC;AACtI,aAAa;AACb,SAAS,CAAC;AACV,QAAQ,MAAM,yBAAyB,GAAG,CAAC,IAAI,KAAK;AACpD,YAAY,IAAI,MAAM,CAAC;AACvB,YAAY,MAAM,OAAO,GAAG,CAAC,GAAG,IAAI,KAAK;AACzC,gBAAgB,MAAM,CAAC,GAAG,wBAAwB,EAAE,CAAC,IAAI,CAAC,CAAC,IAAI,KAAK;AACpE,oBAAoB,MAAM,EAAE,GAAG,kBAAkB,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;AAC9D,oBAAoB,IAAI,EAAE,EAAE;AAC5B,wBAAwB,MAAM,CAAC,GAAG,EAAE,CAAC,GAAG,IAAI,CAAC,CAAC;AAC9C,wBAAwB,MAAM,GAAG,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,KAAK,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC;AAChF,wBAAwB,OAAO,CAAC,CAAC;AACjC,qBAAqB;AACrB,yBAAyB;AACzB,wBAAwB,MAAM,IAAI,kBAAkB,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,EAAE,IAAI,CAAC,0BAA0B,EAAE,QAAQ,CAAC,CAAC,EAAEA,qBAAa,CAAC,aAAa,CAAC,CAAC;AACjJ,qBAAqB;AACrB,iBAAiB,CAAC,CAAC;AACnB,gBAAgB,IAAI,IAAI,KAAK,aAAa,EAAE;AAC5C,oBAAoB,CAAC,CAAC,MAAM,GAAG,YAAY,MAAM,EAAE,CAAC;AACpD,iBAAiB;AACjB,gBAAgB,OAAO,CAAC,CAAC;AACzB,aAAa,CAAC;AACd;AACA,YAAY,OAAO,CAAC,QAAQ,GAAG,MAAM,CAAC,EAAE,IAAI,CAAC,QAAQ,EAAE,CAAC,uBAAuB,CAAC,CAAC;AACjF,YAAY,MAAM,CAAC,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE;AACnD,gBAAgB,KAAK,EAAE,IAAI;AAC3B,gBAAgB,QAAQ,EAAE,KAAK;AAC/B,gBAAgB,YAAY,EAAE,KAAK;AACnC,aAAa,CAAC,CAAC;AACf,YAAY,OAAO,OAAO,CAAC;AAC3B,SAAS,CAAC;AACV,QAAQ,MAAM,WAAW,GAAG,yBAAyB,CAAC,aAAa,CAAC,CAAC;AACrE,QAAQ,MAAM,cAAc,GAAG,yBAAyB,CAAC,gBAAgB,CAAC,CAAC;AAC3E,QAAQ,MAAM,iBAAiB,GAAG,CAAC,SAAS,EAAE,QAAQ,KAAK;AAC3D,YAAY,MAAM,IAAI,GAAG,WAAW,CAAC,EAAE,SAAS,EAAE,EAAE,QAAQ,CAAC,CAAC;AAC9D,YAAY,MAAM,MAAM,GAAG,YAAY;AACvC,gBAAgB,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC;AAC9C,gBAAgB,cAAc,CAAC;AAC/B,oBAAoB,SAAS;AAC7B,oBAAoB,UAAU;AAC9B,iBAAiB,EAAE,QAAQ,CAAC,CAAC;AAC7B,aAAa,CAAC;AACd,YAAY,MAAM,CAAC,GAAG,IAAI,OAAO,CAAC,CAAC,OAAO,KAAK,IAAI,CAAC,IAAI,CAAC,MAAM,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC;AACrF,YAAY,CAAC,CAAC,MAAM,GAAG,YAAY;AACnC,gBAAgB,OAAO,CAAC,IAAI,CAAC,CAAC,kDAAkD,CAAC,CAAC,CAAC;AACnF,gBAAgB,MAAM,MAAM,EAAE,CAAC;AAC/B,aAAa,CAAC;AACd,YAAY,OAAO,CAAC,CAAC;AACrB,SAAS,CAAC;AACV,QAAQ,MAAM,KAAK,GAAG,IAAI,KAAK,CAAC,EAAE,EAAE;AACpC,YAAY,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE;AACzB,gBAAgB,QAAQ,IAAI;AAC5B;AACA,oBAAoB,KAAK,UAAU;AACnC,wBAAwB,OAAO,SAAS,CAAC;AACzC,oBAAoB,KAAK,QAAQ;AACjC,wBAAwB,OAAO,OAAO,EAAE,CAAC,CAAC;AAC1C,oBAAoB,KAAK,aAAa;AACtC,wBAAwB,OAAO,YAAY,GAAG,iBAAiB,GAAG,WAAW,CAAC;AAC9E,oBAAoB,KAAK,gBAAgB;AACzC,wBAAwB,OAAO,cAAc,CAAC;AAC9C,oBAAoB;AACpB,wBAAwB,OAAO,yBAAyB,CAAC,IAAI,CAAC,CAAC;AAC/D,iBAAiB;AACjB,aAAa;AACb,SAAS,CAAC,CAAC;AACX,QAAQ,OAAO,CAAC,UAAU,CAAC,GAAG,KAAK,CAAC;AACpC,QAAQ,iBAAiB,CAAC,GAAG,CAAC,UAAU,EAAE;AAC1C,YAAY,IAAI,EAAE,UAAU;AAC5B,YAAY,KAAK;AACjB,YAAY,SAAS,EAAE,IAAI,GAAG,CAAC,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,iBAAiB,CAAC,EAAE,IAAI,YAAY,GAAG,CAAC,QAAQ,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;AACxG,SAAS,CAAC,CAAC;AACX,QAAQ,OAAO,KAAK,CAAC;AACrB,KAAK,CAAC;AACN;AACA,IAAI,IAAI,CAAC,GAAG,CAAC,cAAc,EAAE;AAC7B,QAAQ,GAAG,CAAC,cAAc,GAAG,CAAC,QAAQ,KAAK,QAAQ,CAAC;AACpD,KAAK;AACL,IAAI,GAAG,CAAC,WAAW,GAAG,WAAW,CAAC;AAClC,IAAI,GAAG,CAAC,WAAW,GAAG,WAAW,CAAC;AAClC,IAAI,GAAG,CAAC,gBAAgB,GAAG,gBAAgB,CAAC;AAC5C,IAAI,GAAG,CAAC,iBAAiB,GAAG,iBAAiB,CAAC;AAC9C,IAAI,GAAG,CAAC,cAAc,GAAG,cAAc,CAAC;AACxC,IAAI,GAAG,CAAC,SAAS,GAAG,kBAAkB,CAAC;AACvC,IAAI,GAAG,CAAC,KAAK,GAAG,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC;AAC5B,IAAI,GAAG,CAAC,gBAAgB,GAAG,CAAC,CAAC,GAAG,CAAC,gBAAgB,CAAC;AAClD,IAAI,OAAO,GAAG,CAAC;AACf,CAAC,CAAC;AACK,MAAM,mBAAmB,GAAG,CAAC,GAAG,MAAM,GAAG,CAAC,SAAS,GAAG,eAAe,CAAC,GAAG,CAAC,CAAC;;AC3JtE,MAAC,SAAS,iBAAiB,mBAAmB,CAAC,OAAO,UAAU,KAAK,WAAW;AAC5F,MAAM,UAAU;AAChB,MAAM,OAAO,IAAI,KAAK,WAAW;AACjC,UAAU,IAAI;AACd,UAAU,OAAO,MAAM,KAAK,WAAW;AACvC,cAAc,MAAM;AACpB,cAAc,OAAO,MAAM,KAAK,WAAW;AAC3C,kBAAkB,MAAM;AACxB,kBAAkB,EAAE,EAAE;AACV,MAAC,cAAc,GAAG,SAAS,CAAC;;ACRxC;AACA;AACA;AACO,MAAM,SAAS,CAAC;AACvB,IAAI,WAAW,GAAG;AAClB,QAAQ,IAAI,CAAC,SAAS,GAAG,EAAE,CAAC;AAC5B,QAAQ,IAAI,CAAC,sBAAsB,GAAG,EAAE,CAAC;AACzC,QAAQ,IAAI,CAAC,eAAe,GAAG,EAAE,CAAC;AAClC,KAAK;AACL,IAAI,WAAW,CAAC,SAAS,EAAE,YAAY,EAAE;AACzC,QAAQ,IAAI,aAAa,GAAG,KAAK,CAAC;AAClC,QAAQ,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;AACpD,QAAQ,IAAI,CAAC,SAAS,EAAE;AACxB,YAAY,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,GAAG,EAAE,CAAC;AAC3C,YAAY,aAAa,GAAG,IAAI,CAAC;AACjC,SAAS;AACT,QAAQ,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;AACrD;AACA;AACA,QAAQ,MAAM,cAAc,GAAG,IAAI,CAAC,eAAe,CAAC,SAAS,CAAC,CAAC;AAC/D,QAAQ,IAAI,cAAc,IAAI,CAAC,cAAc,CAAC,UAAU,EAAE;AAC1D,YAAY,IAAI,CAAC,iBAAiB,CAAC,cAAc,CAAC,CAAC;AACnD,SAAS;AACT,QAAQ,IAAI,aAAa,EAAE;AAC3B,YAAY,IAAI,CAAC,6BAA6B,CAAC,SAAS,CAAC,CAAC;AAC1D,SAAS;AACT,QAAQ,MAAM,MAAM,GAAG,YAAY,IAAI,CAAC,cAAc,CAAC,SAAS,EAAE,YAAY,CAAC,CAAC;AAChF,QAAQ,MAAM,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC;AAC9C,QAAQ,OAAO,CAAC,CAAC;AACjB,KAAK;AACL,IAAI,MAAM,kBAAkB,GAAG;AAC/B,QAAQ,IAAI,CAAC,SAAS,GAAG,EAAE,CAAC;AAC5B,QAAQ,KAAK,MAAM,QAAQ,IAAI,IAAI,CAAC,eAAe,EAAE;AACrD,YAAY,IAAI,CAAC,oBAAoB,CAAC,IAAI,CAAC,eAAe,CAAC,QAAQ,CAAC,CAAC,CAAC;AACtE,SAAS;AACT,QAAQ,IAAI,CAAC,eAAe,GAAG,EAAE,CAAC;AAClC,KAAK;AACL,IAAI,eAAe,CAAC,SAAS,EAAE,IAAI,EAAE,mBAAmB,EAAE;AAC1D,QAAQ,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;AACpD,QAAQ,IAAI,CAAC,SAAS,EAAE;AACxB,YAAY,IAAI,mBAAmB,EAAE;AACrC,gBAAgB,IAAI,IAAI,GAAG,IAAI,CAAC,sBAAsB,CAAC,SAAS,CAAC,CAAC;AAClE,gBAAgB,IAAI,CAAC,IAAI,EAAE;AAC3B,oBAAoB,IAAI,GAAG,EAAE,CAAC;AAC9B,iBAAiB;AACjB,gBAAgB,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAChC,gBAAgB,IAAI,CAAC,sBAAsB,CAAC,SAAS,CAAC,GAAG,IAAI,CAAC;AAC9D,aAAa;AACb,YAAY,OAAO;AACnB,SAAS;AACT,QAAQ,SAAS,CAAC,OAAO,CAAC,CAAC,QAAQ,KAAK,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC;AACxD,KAAK;AACL,IAAI,YAAY,CAAC,SAAS,EAAE;AAC5B,QAAQ,IAAI,EAAE,CAAC;AACf,QAAQ,OAAO,CAAC,EAAE,CAAC,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,MAAM,IAAI,IAAI,EAAE,KAAK,KAAK,CAAC,GAAG,KAAK,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,CAAC;AACnG,KAAK;AACL,IAAI,sBAAsB,CAAC,eAAe,EAAE,eAAe,EAAE;AAC7D,QAAQ,IAAI,CAAC,eAAe,CAAC,eAAe,CAAC,GAAG;AAChD,YAAY,UAAU,EAAE,KAAK;AAC7B,YAAY,eAAe;AAC3B,YAAY,eAAe;AAC3B,YAAY,OAAO,EAAE,CAAC,KAAK,KAAK;AAChC,gBAAgB,IAAI,CAAC,eAAe,CAAC,eAAe,EAAE,KAAK,CAAC,CAAC;AAC7D,aAAa;AACb,SAAS,CAAC;AACV,KAAK;AACL,IAAI,aAAa,CAAC,GAAG,GAAG,iBAAiB,EAAE;AAC3C,QAAQ,OAAO,IAAI,SAAS,CAAC,SAAS,CAAC,GAAG,EAAEA,qBAAa,CAAC,aAAa,CAAC,CAAC;AACzE,KAAK;AACL,IAAI,WAAW,CAAC,GAAG,GAAG,eAAe,EAAE;AACvC,QAAQ,OAAO,IAAI,SAAS,CAAC,SAAS,CAAC,GAAG,EAAEA,qBAAa,CAAC,WAAW,CAAC,CAAC;AACvE,KAAK;AACL,IAAI,MAAM,cAAc,CAAC,SAAS,EAAE,YAAY,EAAE;AAClD,QAAQ,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;AACpD,QAAQ,IAAI,CAAC,SAAS,EAAE;AACxB,YAAY,OAAO;AACnB,SAAS;AACT,QAAQ,MAAM,KAAK,GAAG,SAAS,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;AACtD,QAAQ,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;AACnD;AACA;AACA,QAAQ,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,MAAM,EAAE;AAC/C,YAAY,IAAI,CAAC,oBAAoB,CAAC,IAAI,CAAC,eAAe,CAAC,SAAS,CAAC,CAAC,CAAC;AACvE,SAAS;AACT,KAAK;AACL,IAAI,iBAAiB,CAAC,MAAM,EAAE;AAC9B,QAAQ,MAAM,CAAC,gBAAgB,CAAC,MAAM,CAAC,eAAe,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;AACxE,QAAQ,MAAM,CAAC,UAAU,GAAG,IAAI,CAAC;AACjC,KAAK;AACL,IAAI,oBAAoB,CAAC,MAAM,EAAE;AACjC,QAAQ,IAAI,CAAC,MAAM,EAAE;AACrB,YAAY,OAAO;AACnB,SAAS;AACT,QAAQ,MAAM,CAAC,mBAAmB,CAAC,MAAM,CAAC,eAAe,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;AAC3E,QAAQ,MAAM,CAAC,UAAU,GAAG,KAAK,CAAC;AAClC,KAAK;AACL,IAAI,6BAA6B,CAAC,SAAS,EAAE;AAC7C,QAAQ,MAAM,IAAI,GAAG,IAAI,CAAC,sBAAsB,CAAC,SAAS,CAAC,CAAC;AAC5D,QAAQ,IAAI,CAAC,IAAI,EAAE;AACnB,YAAY,OAAO;AACnB,SAAS;AACT,QAAQ,OAAO,IAAI,CAAC,sBAAsB,CAAC,SAAS,CAAC,CAAC;AACtD,QAAQ,IAAI,CAAC,OAAO,CAAC,CAAC,GAAG,KAAK;AAC9B,YAAY,IAAI,CAAC,eAAe,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC;AACjD,SAAS,CAAC,CAAC;AACX,KAAK;AACL;;AC1GY,MAAC,OAAO,iBAAiB,cAAc,CAAC,SAAS,EAAE;AAC/D;AACA;AACA;AACA;AACA;AACA;AACA,MAAM,MAAM,GAAG,CAAC,GAAG,KAAK,kBAAkB,CAAC,GAAG,CAAC;AAC/C,KAAK,OAAO,CAAC,sBAAsB,EAAE,kBAAkB,CAAC;AACxD,KAAK,OAAO,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;AAC9B;AACA;AACA;AACA;AACA,MAAM,MAAM,GAAG,CAAC,GAAG,KAAK,GAAG,CAAC,OAAO,CAAC,kBAAkB,EAAE,kBAAkB,CAAC,CAAC;AACrE,MAAM,yBAAyB,SAAS,SAAS,CAAC;AACzD,IAAI,MAAM,UAAU,GAAG;AACvB,QAAQ,MAAM,OAAO,GAAG,QAAQ,CAAC,MAAM,CAAC;AACxC,QAAQ,MAAM,SAAS,GAAG,EAAE,CAAC;AAC7B,QAAQ,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,KAAK;AAC/C,YAAY,IAAI,MAAM,CAAC,MAAM,IAAI,CAAC;AAClC,gBAAgB,OAAO;AACvB;AACA,YAAY,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,EAAE,YAAY,CAAC,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;AACrF,YAAY,GAAG,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;AACrC,YAAY,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC;AACzC,YAAY,SAAS,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;AACnC,SAAS,CAAC,CAAC;AACX,QAAQ,OAAO,SAAS,CAAC;AACzB,KAAK;AACL,IAAI,MAAM,SAAS,CAAC,OAAO,EAAE;AAC7B,QAAQ,IAAI;AACZ;AACA,YAAY,MAAM,UAAU,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;AACnD,YAAY,MAAM,YAAY,GAAG,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AACvD;AACA,YAAY,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,GAAG,CAAC,UAAU,EAAE,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC;AAC1G,YAAY,MAAM,IAAI,GAAG,CAAC,OAAO,CAAC,IAAI,IAAI,GAAG,EAAE,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;AACpE,YAAY,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,IAAI,IAAI,IAAI,OAAO,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,GAAG,CAAC,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC;AACxG,YAAY,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,UAAU,CAAC,CAAC,EAAE,YAAY,IAAI,EAAE,CAAC,EAAE,OAAO,CAAC,OAAO,EAAE,IAAI,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC;AACxG,SAAS;AACT,QAAQ,OAAO,KAAK,EAAE;AACtB,YAAY,OAAO,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AACzC,SAAS;AACT,KAAK;AACL,IAAI,MAAM,YAAY,CAAC,OAAO,EAAE;AAChC,QAAQ,IAAI;AACZ,YAAY,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;AAC3D,SAAS;AACT,QAAQ,OAAO,KAAK,EAAE;AACtB,YAAY,OAAO,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AACzC,SAAS;AACT,KAAK;AACL,IAAI,MAAM,YAAY,GAAG;AACzB,QAAQ,IAAI;AACZ,YAAY,MAAM,OAAO,GAAG,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;AAC7D,YAAY,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE;AAC1C,gBAAgB,QAAQ,CAAC,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC,UAAU,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;AAC3H,aAAa;AACb,SAAS;AACT,QAAQ,OAAO,KAAK,EAAE;AACtB,YAAY,OAAO,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AACzC,SAAS;AACT,KAAK;AACL,IAAI,MAAM,eAAe,GAAG;AAC5B,QAAQ,IAAI;AACZ,YAAY,MAAM,IAAI,CAAC,YAAY,EAAE,CAAC;AACtC,SAAS;AACT,QAAQ,OAAO,KAAK,EAAE;AACtB,YAAY,OAAO,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AACzC,SAAS;AACT,KAAK;AACL,CAAC;AACW,MAAC,gBAAgB,GAAG,cAAc,CAAC,kBAAkB,EAAE;AACnE,IAAI,GAAG,EAAE,MAAM,IAAI,yBAAyB,EAAE;AAC9C,CAAC,EAAE;AACH;AACA;AACA;AACA;AACA;AACO,MAAM,gBAAgB,GAAG,OAAO,IAAI,KAAK,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,KAAK;AACjF,IAAI,MAAM,MAAM,GAAG,IAAI,UAAU,EAAE,CAAC;AACpC,IAAI,MAAM,CAAC,MAAM,GAAG,MAAM;AAC1B,QAAQ,MAAM,YAAY,GAAG,MAAM,CAAC,MAAM,CAAC;AAC3C;AACA,QAAQ,OAAO,CAAC,YAAY,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,YAAY,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,YAAY,CAAC,CAAC;AAC5F,KAAK,CAAC;AACN,IAAI,MAAM,CAAC,OAAO,GAAG,CAAC,KAAK,KAAK,MAAM,CAAC,KAAK,CAAC,CAAC;AAC9C,IAAI,MAAM,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC;AAC/B,CAAC,CAAC,CAAC;AACH;AACA;AACA;AACA;AACA,MAAM,oBAAoB,GAAG,CAAC,OAAO,GAAG,EAAE,KAAK;AAC/C,IAAI,MAAM,YAAY,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;AAC9C,IAAI,MAAM,WAAW,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,iBAAiB,EAAE,CAAC,CAAC;AAC/E,IAAI,MAAM,UAAU,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,KAAK,KAAK;AAC/D,QAAQ,GAAG,CAAC,GAAG,CAAC,GAAG,OAAO,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC;AAChD,QAAQ,OAAO,GAAG,CAAC;AACnB,KAAK,EAAE,EAAE,CAAC,CAAC;AACX,IAAI,OAAO,UAAU,CAAC;AACtB,CAAC,CAAC;AACF;AACA;AACA;AACA;AACA;AACA,MAAM,cAAc,GAAG,CAAC,MAAM,EAAE,YAAY,GAAG,IAAI,KAAK;AACxD,IAAI,IAAI,CAAC,MAAM;AACf,QAAQ,OAAO,IAAI,CAAC;AACpB,IAAI,MAAM,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,WAAW,EAAE,KAAK,KAAK;AACzE,QAAQ,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,GAAG,KAAK,CAAC;AACnC,QAAQ,IAAI,YAAY,CAAC;AACzB,QAAQ,IAAI,IAAI,CAAC;AACjB,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE;AAClC,YAAY,IAAI,GAAG,EAAE,CAAC;AACtB,YAAY,KAAK,CAAC,OAAO,CAAC,CAAC,GAAG,KAAK;AACnC,gBAAgB,YAAY,GAAG,YAAY,GAAG,kBAAkB,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC;AAC5E,gBAAgB,IAAI,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC,EAAE,YAAY,CAAC,CAAC,CAAC,CAAC;AAClD,aAAa,CAAC,CAAC;AACf;AACA,YAAY,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AAC9B,SAAS;AACT,aAAa;AACb,YAAY,YAAY,GAAG,YAAY,GAAG,kBAAkB,CAAC,KAAK,CAAC,GAAG,KAAK,CAAC;AAC5E,YAAY,IAAI,GAAG,CAAC,EAAE,GAAG,CAAC,CAAC,EAAE,YAAY,CAAC,CAAC,CAAC;AAC5C,SAAS;AACT,QAAQ,OAAO,CAAC,EAAE,WAAW,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC;AACxC,KAAK,EAAE,EAAE,CAAC,CAAC;AACX;AACA,IAAI,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AAC5B,CAAC,CAAC;AACF;AACA;AACA;AACA;AACA;AACY,MAAC,gBAAgB,GAAG,CAAC,OAAO,EAAE,KAAK,GAAG,EAAE,KAAK;AACzD,IAAI,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,IAAI,KAAK,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,EAAE,KAAK,CAAC,CAAC;AACvG;AACA,IAAI,MAAM,OAAO,GAAG,oBAAoB,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;AAC1D,IAAI,MAAM,IAAI,GAAG,OAAO,CAAC,cAAc,CAAC,IAAI,EAAE,CAAC;AAC/C;AACA,IAAI,IAAI,OAAO,OAAO,CAAC,IAAI,KAAK,QAAQ,EAAE;AAC1C,QAAQ,MAAM,CAAC,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;AACnC,KAAK;AACL;AACA,SAAS,IAAI,IAAI,CAAC,QAAQ,CAAC,mCAAmC,CAAC,EAAE;AACjE,QAAQ,MAAM,MAAM,GAAG,IAAI,eAAe,EAAE,CAAC;AAC7C,QAAQ,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,IAAI,EAAE,CAAC,EAAE;AACvE,YAAY,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;AACnC,SAAS;AACT,QAAQ,MAAM,CAAC,IAAI,GAAG,MAAM,CAAC,QAAQ,EAAE,CAAC;AACxC,KAAK;AACL,SAAS,IAAI,IAAI,CAAC,QAAQ,CAAC,qBAAqB,CAAC,IAAI,OAAO,CAAC,IAAI,YAAY,QAAQ,EAAE;AACvF,QAAQ,MAAM,IAAI,GAAG,IAAI,QAAQ,EAAE,CAAC;AACpC,QAAQ,IAAI,OAAO,CAAC,IAAI,YAAY,QAAQ,EAAE;AAC9C,YAAY,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,GAAG,KAAK;AACjD,gBAAgB,IAAI,CAAC,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;AACxC,aAAa,CAAC,CAAC;AACf,SAAS;AACT,aAAa;AACb,YAAY,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE;AACzD,gBAAgB,IAAI,CAAC,MAAM,CAAC,GAAG,EAAE,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AACpD,aAAa;AACb,SAAS;AACT,QAAQ,MAAM,CAAC,IAAI,GAAG,IAAI,CAAC;AAC3B,QAAQ,MAAM,OAAO,GAAG,IAAI,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;AACpD,QAAQ,OAAO,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC;AACvC,QAAQ,MAAM,CAAC,OAAO,GAAG,OAAO,CAAC;AACjC,KAAK;AACL,SAAS,IAAI,IAAI,CAAC,QAAQ,CAAC,kBAAkB,CAAC,IAAI,OAAO,OAAO,CAAC,IAAI,KAAK,QAAQ,EAAE;AACpF,QAAQ,MAAM,CAAC,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;AACnD,KAAK;AACL,IAAI,OAAO,MAAM,CAAC;AAClB,EAAE;AACF;AACO,MAAM,sBAAsB,SAAS,SAAS,CAAC;AACtD;AACA;AACA;AACA;AACA,IAAI,MAAM,OAAO,CAAC,OAAO,EAAE;AAC3B,QAAQ,MAAM,WAAW,GAAG,gBAAgB,CAAC,OAAO,EAAE,OAAO,CAAC,aAAa,CAAC,CAAC;AAC7E,QAAQ,MAAM,SAAS,GAAG,cAAc,CAAC,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC,qBAAqB,CAAC,CAAC;AACxF,QAAQ,MAAM,GAAG,GAAG,SAAS,GAAG,CAAC,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC;AAC5E,QAAQ,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC;AACvD,QAAQ,MAAM,WAAW,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,IAAI,EAAE,CAAC;AACvE;AACA,QAAQ,IAAI,EAAE,YAAY,GAAG,MAAM,EAAE,GAAG,QAAQ,CAAC,EAAE,GAAG,OAAO,GAAG,EAAE,CAAC;AACnE;AACA,QAAQ,IAAI,WAAW,CAAC,QAAQ,CAAC,kBAAkB,CAAC,EAAE;AACtD,YAAY,YAAY,GAAG,MAAM,CAAC;AAClC,SAAS;AACT,QAAQ,IAAI,IAAI,CAAC;AACjB,QAAQ,IAAI,IAAI,CAAC;AACjB,QAAQ,QAAQ,YAAY;AAC5B,YAAY,KAAK,aAAa,CAAC;AAC/B,YAAY,KAAK,MAAM;AACvB,gBAAgB,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;AAC7C,gBAAgB,IAAI,GAAG,MAAM,gBAAgB,CAAC,IAAI,CAAC,CAAC;AACpD,gBAAgB,MAAM;AACtB,YAAY,KAAK,MAAM;AACvB,gBAAgB,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;AAC7C,gBAAgB,MAAM;AACtB,YAAY,KAAK,UAAU,CAAC;AAC5B,YAAY,KAAK,MAAM,CAAC;AACxB,YAAY;AACZ,gBAAgB,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;AAC7C,SAAS;AACT;AACA,QAAQ,MAAM,OAAO,GAAG,EAAE,CAAC;AAC3B,QAAQ,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,GAAG,KAAK;AACjD,YAAY,OAAO,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;AACjC,SAAS,CAAC,CAAC;AACX,QAAQ,OAAO;AACf,YAAY,IAAI;AAChB,YAAY,OAAO;AACnB,YAAY,MAAM,EAAE,QAAQ,CAAC,MAAM;AACnC,YAAY,GAAG,EAAE,QAAQ,CAAC,GAAG;AAC7B,SAAS,CAAC;AACV,KAAK;AACL;AACA;AACA;AACA;AACA,IAAI,MAAM,GAAG,CAAC,OAAO,EAAE;AACvB,QAAQ,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,EAAE,OAAO,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC;AAC1F,KAAK;AACL;AACA;AACA;AACA;AACA,IAAI,MAAM,IAAI,CAAC,OAAO,EAAE;AACxB,QAAQ,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,EAAE,OAAO,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC;AAC3F,KAAK;AACL;AACA;AACA;AACA;AACA,IAAI,MAAM,GAAG,CAAC,OAAO,EAAE;AACvB,QAAQ,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,EAAE,OAAO,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC;AAC1F,KAAK;AACL;AACA;AACA;AACA;AACA,IAAI,MAAM,KAAK,CAAC,OAAO,EAAE;AACzB,QAAQ,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,EAAE,OAAO,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC;AAC5F,KAAK;AACL;AACA;AACA;AACA;AACA,IAAI,MAAM,MAAM,CAAC,OAAO,EAAE;AAC1B,QAAQ,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,EAAE,OAAO,CAAC,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC;AAC7F,KAAK;AACL,CAAC;AACW,MAAC,aAAa,GAAG,cAAc,CAAC,eAAe,EAAE;AAC7D,IAAI,GAAG,EAAE,MAAM,IAAI,sBAAsB,EAAE;AAC3C,CAAC,EAAE;AACH;AACA;AACA;AACA;AACA;AACWC,iCAAgB;AAC3B,CAAC,UAAU,eAAe,EAAE;AAC5B;AACA;AACA;AACA;AACA;AACA,IAAI,eAAe,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC;AACrC;AACA;AACA;AACA;AACA;AACA,IAAI,eAAe,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC;AACvC;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,eAAe,CAAC,SAAS,CAAC,GAAG,SAAS,CAAC;AAC3C,CAAC,EAAEA,uBAAe,KAAKA,uBAAe,GAAG,EAAE,CAAC,CAAC,CAAC;AAC9C;AACA;AACA;AACWC,+BAAc;AACzB,CAAC,UAAU,aAAa,EAAE;AAC1B;AACA;AACA;AACA;AACA;AACA,IAAI,aAAa,CAAC,WAAW,CAAC,GAAG,WAAW,CAAC;AAC7C;AACA;AACA;AACA;AACA;AACA,IAAI,aAAa,CAAC,eAAe,CAAC,GAAG,eAAe,CAAC;AACrD,CAAC,EAAEA,qBAAa,KAAKA,qBAAa,GAAG,EAAE,CAAC,CAAC,CAAC;AACnC,MAAM,mBAAmB,SAAS,SAAS,CAAC;AACnD,IAAI,MAAM,QAAQ,GAAG;AACrB,QAAQ,IAAI,CAAC,WAAW,CAAC,uBAAuB,CAAC,CAAC;AAClD,KAAK;AACL,IAAI,MAAM,YAAY,GAAG;AACzB,QAAQ,IAAI,CAAC,WAAW,CAAC,uBAAuB,CAAC,CAAC;AAClD,KAAK;AACL,IAAI,MAAM,IAAI,GAAG;AACjB,QAAQ,IAAI,CAAC,WAAW,CAAC,uBAAuB,CAAC,CAAC;AAClD,KAAK;AACL,IAAI,MAAM,IAAI,GAAG;AACjB,QAAQ,IAAI,CAAC,WAAW,CAAC,uBAAuB,CAAC,CAAC;AAClD,KAAK;AACL,CAAC;AACW,MAAC,UAAU,GAAG,cAAc,CAAC,YAAY,EAAE;AACvD,IAAI,GAAG,EAAE,MAAM,IAAI,mBAAmB,EAAE;AACxC,CAAC,EAAE;AACH;;;;;;;;;;;;"} \ No newline at end of file diff --git a/node_modules/@capacitor/core/dist/index.js b/node_modules/@capacitor/core/dist/index.js new file mode 100644 index 0000000..2509854 --- /dev/null +++ b/node_modules/@capacitor/core/dist/index.js @@ -0,0 +1,646 @@ +/*! Capacitor: https://capacitorjs.com/ - MIT License */ +var ExceptionCode; +(function (ExceptionCode) { + /** + * API is not implemented. + * + * This usually means the API can't be used because it is not implemented for + * the current platform. + */ + ExceptionCode["Unimplemented"] = "UNIMPLEMENTED"; + /** + * API is not available. + * + * This means the API can't be used right now because: + * - it is currently missing a prerequisite, such as network connectivity + * - it requires a particular platform or browser version + */ + ExceptionCode["Unavailable"] = "UNAVAILABLE"; +})(ExceptionCode || (ExceptionCode = {})); +class CapacitorException extends Error { + constructor(message, code, data) { + super(message); + this.message = message; + this.code = code; + this.data = data; + } +} +const getPlatformId = (win) => { + var _a, _b; + if (win === null || win === void 0 ? void 0 : win.androidBridge) { + return 'android'; + } + else if ((_b = (_a = win === null || win === void 0 ? void 0 : win.webkit) === null || _a === void 0 ? void 0 : _a.messageHandlers) === null || _b === void 0 ? void 0 : _b.bridge) { + return 'ios'; + } + else { + return 'web'; + } +}; + +const createCapacitor = (win) => { + const capCustomPlatform = win.CapacitorCustomPlatform || null; + const cap = win.Capacitor || {}; + const Plugins = (cap.Plugins = cap.Plugins || {}); + const getPlatform = () => { + return capCustomPlatform !== null ? capCustomPlatform.name : getPlatformId(win); + }; + const isNativePlatform = () => getPlatform() !== 'web'; + const isPluginAvailable = (pluginName) => { + const plugin = registeredPlugins.get(pluginName); + if (plugin === null || plugin === void 0 ? void 0 : plugin.platforms.has(getPlatform())) { + // JS implementation available for the current platform. + return true; + } + if (getPluginHeader(pluginName)) { + // Native implementation available. + return true; + } + return false; + }; + const getPluginHeader = (pluginName) => { var _a; return (_a = cap.PluginHeaders) === null || _a === void 0 ? void 0 : _a.find((h) => h.name === pluginName); }; + const handleError = (err) => win.console.error(err); + const registeredPlugins = new Map(); + const registerPlugin = (pluginName, jsImplementations = {}) => { + const registeredPlugin = registeredPlugins.get(pluginName); + if (registeredPlugin) { + console.warn(`Capacitor plugin "${pluginName}" already registered. Cannot register plugins twice.`); + return registeredPlugin.proxy; + } + const platform = getPlatform(); + const pluginHeader = getPluginHeader(pluginName); + let jsImplementation; + const loadPluginImplementation = async () => { + if (!jsImplementation && platform in jsImplementations) { + jsImplementation = + typeof jsImplementations[platform] === 'function' + ? (jsImplementation = await jsImplementations[platform]()) + : (jsImplementation = jsImplementations[platform]); + } + else if (capCustomPlatform !== null && !jsImplementation && 'web' in jsImplementations) { + jsImplementation = + typeof jsImplementations['web'] === 'function' + ? (jsImplementation = await jsImplementations['web']()) + : (jsImplementation = jsImplementations['web']); + } + return jsImplementation; + }; + const createPluginMethod = (impl, prop) => { + var _a, _b; + if (pluginHeader) { + const methodHeader = pluginHeader === null || pluginHeader === void 0 ? void 0 : pluginHeader.methods.find((m) => prop === m.name); + if (methodHeader) { + if (methodHeader.rtype === 'promise') { + return (options) => cap.nativePromise(pluginName, prop.toString(), options); + } + else { + return (options, callback) => cap.nativeCallback(pluginName, prop.toString(), options, callback); + } + } + else if (impl) { + return (_a = impl[prop]) === null || _a === void 0 ? void 0 : _a.bind(impl); + } + } + else if (impl) { + return (_b = impl[prop]) === null || _b === void 0 ? void 0 : _b.bind(impl); + } + else { + throw new CapacitorException(`"${pluginName}" plugin is not implemented on ${platform}`, ExceptionCode.Unimplemented); + } + }; + const createPluginMethodWrapper = (prop) => { + let remove; + const wrapper = (...args) => { + const p = loadPluginImplementation().then((impl) => { + const fn = createPluginMethod(impl, prop); + if (fn) { + const p = fn(...args); + remove = p === null || p === void 0 ? void 0 : p.remove; + return p; + } + else { + throw new CapacitorException(`"${pluginName}.${prop}()" is not implemented on ${platform}`, ExceptionCode.Unimplemented); + } + }); + if (prop === 'addListener') { + p.remove = async () => remove(); + } + return p; + }; + // Some flair ✨ + wrapper.toString = () => `${prop.toString()}() { [capacitor code] }`; + Object.defineProperty(wrapper, 'name', { + value: prop, + writable: false, + configurable: false, + }); + return wrapper; + }; + const addListener = createPluginMethodWrapper('addListener'); + const removeListener = createPluginMethodWrapper('removeListener'); + const addListenerNative = (eventName, callback) => { + const call = addListener({ eventName }, callback); + const remove = async () => { + const callbackId = await call; + removeListener({ + eventName, + callbackId, + }, callback); + }; + const p = new Promise((resolve) => call.then(() => resolve({ remove }))); + p.remove = async () => { + console.warn(`Using addListener() without 'await' is deprecated.`); + await remove(); + }; + return p; + }; + const proxy = new Proxy({}, { + get(_, prop) { + switch (prop) { + // https://github.com/facebook/react/issues/20030 + case '$$typeof': + return undefined; + case 'toJSON': + return () => ({}); + case 'addListener': + return pluginHeader ? addListenerNative : addListener; + case 'removeListener': + return removeListener; + default: + return createPluginMethodWrapper(prop); + } + }, + }); + Plugins[pluginName] = proxy; + registeredPlugins.set(pluginName, { + name: pluginName, + proxy, + platforms: new Set([...Object.keys(jsImplementations), ...(pluginHeader ? [platform] : [])]), + }); + return proxy; + }; + // Add in convertFileSrc for web, it will already be available in native context + if (!cap.convertFileSrc) { + cap.convertFileSrc = (filePath) => filePath; + } + cap.getPlatform = getPlatform; + cap.handleError = handleError; + cap.isNativePlatform = isNativePlatform; + cap.isPluginAvailable = isPluginAvailable; + cap.registerPlugin = registerPlugin; + cap.Exception = CapacitorException; + cap.DEBUG = !!cap.DEBUG; + cap.isLoggingEnabled = !!cap.isLoggingEnabled; + return cap; +}; +const initCapacitorGlobal = (win) => (win.Capacitor = createCapacitor(win)); + +const Capacitor = /*#__PURE__*/ initCapacitorGlobal(typeof globalThis !== 'undefined' + ? globalThis + : typeof self !== 'undefined' + ? self + : typeof window !== 'undefined' + ? window + : typeof global !== 'undefined' + ? global + : {}); +const registerPlugin = Capacitor.registerPlugin; + +/** + * Base class web plugins should extend. + */ +class WebPlugin { + constructor() { + this.listeners = {}; + this.retainedEventArguments = {}; + this.windowListeners = {}; + } + addListener(eventName, listenerFunc) { + let firstListener = false; + const listeners = this.listeners[eventName]; + if (!listeners) { + this.listeners[eventName] = []; + firstListener = true; + } + this.listeners[eventName].push(listenerFunc); + // If we haven't added a window listener for this event and it requires one, + // go ahead and add it + const windowListener = this.windowListeners[eventName]; + if (windowListener && !windowListener.registered) { + this.addWindowListener(windowListener); + } + if (firstListener) { + this.sendRetainedArgumentsForEvent(eventName); + } + const remove = async () => this.removeListener(eventName, listenerFunc); + const p = Promise.resolve({ remove }); + return p; + } + async removeAllListeners() { + this.listeners = {}; + for (const listener in this.windowListeners) { + this.removeWindowListener(this.windowListeners[listener]); + } + this.windowListeners = {}; + } + notifyListeners(eventName, data, retainUntilConsumed) { + const listeners = this.listeners[eventName]; + if (!listeners) { + if (retainUntilConsumed) { + let args = this.retainedEventArguments[eventName]; + if (!args) { + args = []; + } + args.push(data); + this.retainedEventArguments[eventName] = args; + } + return; + } + listeners.forEach((listener) => listener(data)); + } + hasListeners(eventName) { + var _a; + return !!((_a = this.listeners[eventName]) === null || _a === void 0 ? void 0 : _a.length); + } + registerWindowListener(windowEventName, pluginEventName) { + this.windowListeners[pluginEventName] = { + registered: false, + windowEventName, + pluginEventName, + handler: (event) => { + this.notifyListeners(pluginEventName, event); + }, + }; + } + unimplemented(msg = 'not implemented') { + return new Capacitor.Exception(msg, ExceptionCode.Unimplemented); + } + unavailable(msg = 'not available') { + return new Capacitor.Exception(msg, ExceptionCode.Unavailable); + } + async removeListener(eventName, listenerFunc) { + const listeners = this.listeners[eventName]; + if (!listeners) { + return; + } + const index = listeners.indexOf(listenerFunc); + this.listeners[eventName].splice(index, 1); + // If there are no more listeners for this type of event, + // remove the window listener + if (!this.listeners[eventName].length) { + this.removeWindowListener(this.windowListeners[eventName]); + } + } + addWindowListener(handle) { + window.addEventListener(handle.windowEventName, handle.handler); + handle.registered = true; + } + removeWindowListener(handle) { + if (!handle) { + return; + } + window.removeEventListener(handle.windowEventName, handle.handler); + handle.registered = false; + } + sendRetainedArgumentsForEvent(eventName) { + const args = this.retainedEventArguments[eventName]; + if (!args) { + return; + } + delete this.retainedEventArguments[eventName]; + args.forEach((arg) => { + this.notifyListeners(eventName, arg); + }); + } +} + +const WebView = /*#__PURE__*/ registerPlugin('WebView'); +/******** END WEB VIEW PLUGIN ********/ +/******** COOKIES PLUGIN ********/ +/** + * Safely web encode a string value (inspired by js-cookie) + * @param str The string value to encode + */ +const encode = (str) => encodeURIComponent(str) + .replace(/%(2[346B]|5E|60|7C)/g, decodeURIComponent) + .replace(/[()]/g, escape); +/** + * Safely web decode a string value (inspired by js-cookie) + * @param str The string value to decode + */ +const decode = (str) => str.replace(/(%[\dA-F]{2})+/gi, decodeURIComponent); +class CapacitorCookiesPluginWeb extends WebPlugin { + async getCookies() { + const cookies = document.cookie; + const cookieMap = {}; + cookies.split(';').forEach((cookie) => { + if (cookie.length <= 0) + return; + // Replace first "=" with CAP_COOKIE to prevent splitting on additional "=" + let [key, value] = cookie.replace(/=/, 'CAP_COOKIE').split('CAP_COOKIE'); + key = decode(key).trim(); + value = decode(value).trim(); + cookieMap[key] = value; + }); + return cookieMap; + } + async setCookie(options) { + try { + // Safely Encoded Key/Value + const encodedKey = encode(options.key); + const encodedValue = encode(options.value); + // Clean & sanitize options + const expires = options.expires ? `; expires=${options.expires.replace('expires=', '')}` : ''; + const path = (options.path || '/').replace('path=', ''); // Default is "path=/" + const domain = options.url != null && options.url.length > 0 ? `domain=${options.url}` : ''; + document.cookie = `${encodedKey}=${encodedValue || ''}${expires}; path=${path}; ${domain};`; + } + catch (error) { + return Promise.reject(error); + } + } + async deleteCookie(options) { + try { + document.cookie = `${options.key}=; Max-Age=0`; + } + catch (error) { + return Promise.reject(error); + } + } + async clearCookies() { + try { + const cookies = document.cookie.split(';') || []; + for (const cookie of cookies) { + document.cookie = cookie.replace(/^ +/, '').replace(/=.*/, `=;expires=${new Date().toUTCString()};path=/`); + } + } + catch (error) { + return Promise.reject(error); + } + } + async clearAllCookies() { + try { + await this.clearCookies(); + } + catch (error) { + return Promise.reject(error); + } + } +} +const CapacitorCookies = registerPlugin('CapacitorCookies', { + web: () => new CapacitorCookiesPluginWeb(), +}); +// UTILITY FUNCTIONS +/** + * Read in a Blob value and return it as a base64 string + * @param blob The blob value to convert to a base64 string + */ +const readBlobAsBase64 = async (blob) => new Promise((resolve, reject) => { + const reader = new FileReader(); + reader.onload = () => { + const base64String = reader.result; + // remove prefix "data:application/pdf;base64," + resolve(base64String.indexOf(',') >= 0 ? base64String.split(',')[1] : base64String); + }; + reader.onerror = (error) => reject(error); + reader.readAsDataURL(blob); +}); +/** + * Normalize an HttpHeaders map by lowercasing all of the values + * @param headers The HttpHeaders object to normalize + */ +const normalizeHttpHeaders = (headers = {}) => { + const originalKeys = Object.keys(headers); + const loweredKeys = Object.keys(headers).map((k) => k.toLocaleLowerCase()); + const normalized = loweredKeys.reduce((acc, key, index) => { + acc[key] = headers[originalKeys[index]]; + return acc; + }, {}); + return normalized; +}; +/** + * Builds a string of url parameters that + * @param params A map of url parameters + * @param shouldEncode true if you should encodeURIComponent() the values (true by default) + */ +const buildUrlParams = (params, shouldEncode = true) => { + if (!params) + return null; + const output = Object.entries(params).reduce((accumulator, entry) => { + const [key, value] = entry; + let encodedValue; + let item; + if (Array.isArray(value)) { + item = ''; + value.forEach((str) => { + encodedValue = shouldEncode ? encodeURIComponent(str) : str; + item += `${key}=${encodedValue}&`; + }); + // last character will always be "&" so slice it off + item.slice(0, -1); + } + else { + encodedValue = shouldEncode ? encodeURIComponent(value) : value; + item = `${key}=${encodedValue}`; + } + return `${accumulator}&${item}`; + }, ''); + // Remove initial "&" from the reduce + return output.substr(1); +}; +/** + * Build the RequestInit object based on the options passed into the initial request + * @param options The Http plugin options + * @param extra Any extra RequestInit values + */ +const buildRequestInit = (options, extra = {}) => { + const output = Object.assign({ method: options.method || 'GET', headers: options.headers }, extra); + // Get the content-type + const headers = normalizeHttpHeaders(options.headers); + const type = headers['content-type'] || ''; + // If body is already a string, then pass it through as-is. + if (typeof options.data === 'string') { + output.body = options.data; + } + // Build request initializers based off of content-type + else if (type.includes('application/x-www-form-urlencoded')) { + const params = new URLSearchParams(); + for (const [key, value] of Object.entries(options.data || {})) { + params.set(key, value); + } + output.body = params.toString(); + } + else if (type.includes('multipart/form-data') || options.data instanceof FormData) { + const form = new FormData(); + if (options.data instanceof FormData) { + options.data.forEach((value, key) => { + form.append(key, value); + }); + } + else { + for (const key of Object.keys(options.data)) { + form.append(key, options.data[key]); + } + } + output.body = form; + const headers = new Headers(output.headers); + headers.delete('content-type'); // content-type will be set by `window.fetch` to includy boundary + output.headers = headers; + } + else if (type.includes('application/json') || typeof options.data === 'object') { + output.body = JSON.stringify(options.data); + } + return output; +}; +// WEB IMPLEMENTATION +class CapacitorHttpPluginWeb extends WebPlugin { + /** + * Perform an Http request given a set of options + * @param options Options to build the HTTP request + */ + async request(options) { + const requestInit = buildRequestInit(options, options.webFetchExtra); + const urlParams = buildUrlParams(options.params, options.shouldEncodeUrlParams); + const url = urlParams ? `${options.url}?${urlParams}` : options.url; + const response = await fetch(url, requestInit); + const contentType = response.headers.get('content-type') || ''; + // Default to 'text' responseType so no parsing happens + let { responseType = 'text' } = response.ok ? options : {}; + // If the response content-type is json, force the response to be json + if (contentType.includes('application/json')) { + responseType = 'json'; + } + let data; + let blob; + switch (responseType) { + case 'arraybuffer': + case 'blob': + blob = await response.blob(); + data = await readBlobAsBase64(blob); + break; + case 'json': + data = await response.json(); + break; + case 'document': + case 'text': + default: + data = await response.text(); + } + // Convert fetch headers to Capacitor HttpHeaders + const headers = {}; + response.headers.forEach((value, key) => { + headers[key] = value; + }); + return { + data, + headers, + status: response.status, + url: response.url, + }; + } + /** + * Perform an Http GET request given a set of options + * @param options Options to build the HTTP request + */ + async get(options) { + return this.request(Object.assign(Object.assign({}, options), { method: 'GET' })); + } + /** + * Perform an Http POST request given a set of options + * @param options Options to build the HTTP request + */ + async post(options) { + return this.request(Object.assign(Object.assign({}, options), { method: 'POST' })); + } + /** + * Perform an Http PUT request given a set of options + * @param options Options to build the HTTP request + */ + async put(options) { + return this.request(Object.assign(Object.assign({}, options), { method: 'PUT' })); + } + /** + * Perform an Http PATCH request given a set of options + * @param options Options to build the HTTP request + */ + async patch(options) { + return this.request(Object.assign(Object.assign({}, options), { method: 'PATCH' })); + } + /** + * Perform an Http DELETE request given a set of options + * @param options Options to build the HTTP request + */ + async delete(options) { + return this.request(Object.assign(Object.assign({}, options), { method: 'DELETE' })); + } +} +const CapacitorHttp = registerPlugin('CapacitorHttp', { + web: () => new CapacitorHttpPluginWeb(), +}); +/******** END HTTP PLUGIN ********/ +/******** SYSTEM BARS PLUGIN ********/ +/** + * Available status bar styles. + */ +var SystemBarsStyle; +(function (SystemBarsStyle) { + /** + * Light system bar content on a dark background. + * + * @since 8.0.0 + */ + SystemBarsStyle["Dark"] = "DARK"; + /** + * For dark system bar content on a light background. + * + * @since 8.0.0 + */ + SystemBarsStyle["Light"] = "LIGHT"; + /** + * The style is based on the device appearance or the underlying content. + * If the device is using Dark mode, the system bars content will be light. + * If the device is using Light mode, the system bars content will be dark. + * + * @since 8.0.0 + */ + SystemBarsStyle["Default"] = "DEFAULT"; +})(SystemBarsStyle || (SystemBarsStyle = {})); +/** + * Available system bar types. + */ +var SystemBarType; +(function (SystemBarType) { + /** + * The top status bar on both Android and iOS. + * + * @since 8.0.0 + */ + SystemBarType["StatusBar"] = "StatusBar"; + /** + * The navigation bar (or gesture bar on iOS) on both Android and iOS. + * + * @since 8.0.0 + */ + SystemBarType["NavigationBar"] = "NavigationBar"; +})(SystemBarType || (SystemBarType = {})); +class SystemBarsPluginWeb extends WebPlugin { + async setStyle() { + this.unavailable('not available for web'); + } + async setAnimation() { + this.unavailable('not available for web'); + } + async show() { + this.unavailable('not available for web'); + } + async hide() { + this.unavailable('not available for web'); + } +} +const SystemBars = registerPlugin('SystemBars', { + web: () => new SystemBarsPluginWeb(), +}); +/******** END SYSTEM BARS PLUGIN ********/ + +export { Capacitor, CapacitorCookies, CapacitorException, CapacitorHttp, ExceptionCode, SystemBarType, SystemBars, SystemBarsStyle, WebPlugin, WebView, buildRequestInit, registerPlugin }; +//# sourceMappingURL=index.js.map diff --git a/node_modules/@capacitor/core/dist/index.js.map b/node_modules/@capacitor/core/dist/index.js.map new file mode 100644 index 0000000..1ef0437 --- /dev/null +++ b/node_modules/@capacitor/core/dist/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","sources":["../build/util.js","../build/runtime.js","../build/global.js","../build/web-plugin.js","../build/core-plugins.js"],"sourcesContent":["export var ExceptionCode;\n(function (ExceptionCode) {\n /**\n * API is not implemented.\n *\n * This usually means the API can't be used because it is not implemented for\n * the current platform.\n */\n ExceptionCode[\"Unimplemented\"] = \"UNIMPLEMENTED\";\n /**\n * API is not available.\n *\n * This means the API can't be used right now because:\n * - it is currently missing a prerequisite, such as network connectivity\n * - it requires a particular platform or browser version\n */\n ExceptionCode[\"Unavailable\"] = \"UNAVAILABLE\";\n})(ExceptionCode || (ExceptionCode = {}));\nexport class CapacitorException extends Error {\n constructor(message, code, data) {\n super(message);\n this.message = message;\n this.code = code;\n this.data = data;\n }\n}\nexport const getPlatformId = (win) => {\n var _a, _b;\n if (win === null || win === void 0 ? void 0 : win.androidBridge) {\n return 'android';\n }\n else if ((_b = (_a = win === null || win === void 0 ? void 0 : win.webkit) === null || _a === void 0 ? void 0 : _a.messageHandlers) === null || _b === void 0 ? void 0 : _b.bridge) {\n return 'ios';\n }\n else {\n return 'web';\n }\n};\n//# sourceMappingURL=util.js.map","import { CapacitorException, getPlatformId, ExceptionCode } from './util';\nexport const createCapacitor = (win) => {\n const capCustomPlatform = win.CapacitorCustomPlatform || null;\n const cap = win.Capacitor || {};\n const Plugins = (cap.Plugins = cap.Plugins || {});\n const getPlatform = () => {\n return capCustomPlatform !== null ? capCustomPlatform.name : getPlatformId(win);\n };\n const isNativePlatform = () => getPlatform() !== 'web';\n const isPluginAvailable = (pluginName) => {\n const plugin = registeredPlugins.get(pluginName);\n if (plugin === null || plugin === void 0 ? void 0 : plugin.platforms.has(getPlatform())) {\n // JS implementation available for the current platform.\n return true;\n }\n if (getPluginHeader(pluginName)) {\n // Native implementation available.\n return true;\n }\n return false;\n };\n const getPluginHeader = (pluginName) => { var _a; return (_a = cap.PluginHeaders) === null || _a === void 0 ? void 0 : _a.find((h) => h.name === pluginName); };\n const handleError = (err) => win.console.error(err);\n const registeredPlugins = new Map();\n const registerPlugin = (pluginName, jsImplementations = {}) => {\n const registeredPlugin = registeredPlugins.get(pluginName);\n if (registeredPlugin) {\n console.warn(`Capacitor plugin \"${pluginName}\" already registered. Cannot register plugins twice.`);\n return registeredPlugin.proxy;\n }\n const platform = getPlatform();\n const pluginHeader = getPluginHeader(pluginName);\n let jsImplementation;\n const loadPluginImplementation = async () => {\n if (!jsImplementation && platform in jsImplementations) {\n jsImplementation =\n typeof jsImplementations[platform] === 'function'\n ? (jsImplementation = await jsImplementations[platform]())\n : (jsImplementation = jsImplementations[platform]);\n }\n else if (capCustomPlatform !== null && !jsImplementation && 'web' in jsImplementations) {\n jsImplementation =\n typeof jsImplementations['web'] === 'function'\n ? (jsImplementation = await jsImplementations['web']())\n : (jsImplementation = jsImplementations['web']);\n }\n return jsImplementation;\n };\n const createPluginMethod = (impl, prop) => {\n var _a, _b;\n if (pluginHeader) {\n const methodHeader = pluginHeader === null || pluginHeader === void 0 ? void 0 : pluginHeader.methods.find((m) => prop === m.name);\n if (methodHeader) {\n if (methodHeader.rtype === 'promise') {\n return (options) => cap.nativePromise(pluginName, prop.toString(), options);\n }\n else {\n return (options, callback) => cap.nativeCallback(pluginName, prop.toString(), options, callback);\n }\n }\n else if (impl) {\n return (_a = impl[prop]) === null || _a === void 0 ? void 0 : _a.bind(impl);\n }\n }\n else if (impl) {\n return (_b = impl[prop]) === null || _b === void 0 ? void 0 : _b.bind(impl);\n }\n else {\n throw new CapacitorException(`\"${pluginName}\" plugin is not implemented on ${platform}`, ExceptionCode.Unimplemented);\n }\n };\n const createPluginMethodWrapper = (prop) => {\n let remove;\n const wrapper = (...args) => {\n const p = loadPluginImplementation().then((impl) => {\n const fn = createPluginMethod(impl, prop);\n if (fn) {\n const p = fn(...args);\n remove = p === null || p === void 0 ? void 0 : p.remove;\n return p;\n }\n else {\n throw new CapacitorException(`\"${pluginName}.${prop}()\" is not implemented on ${platform}`, ExceptionCode.Unimplemented);\n }\n });\n if (prop === 'addListener') {\n p.remove = async () => remove();\n }\n return p;\n };\n // Some flair ✨\n wrapper.toString = () => `${prop.toString()}() { [capacitor code] }`;\n Object.defineProperty(wrapper, 'name', {\n value: prop,\n writable: false,\n configurable: false,\n });\n return wrapper;\n };\n const addListener = createPluginMethodWrapper('addListener');\n const removeListener = createPluginMethodWrapper('removeListener');\n const addListenerNative = (eventName, callback) => {\n const call = addListener({ eventName }, callback);\n const remove = async () => {\n const callbackId = await call;\n removeListener({\n eventName,\n callbackId,\n }, callback);\n };\n const p = new Promise((resolve) => call.then(() => resolve({ remove })));\n p.remove = async () => {\n console.warn(`Using addListener() without 'await' is deprecated.`);\n await remove();\n };\n return p;\n };\n const proxy = new Proxy({}, {\n get(_, prop) {\n switch (prop) {\n // https://github.com/facebook/react/issues/20030\n case '$$typeof':\n return undefined;\n case 'toJSON':\n return () => ({});\n case 'addListener':\n return pluginHeader ? addListenerNative : addListener;\n case 'removeListener':\n return removeListener;\n default:\n return createPluginMethodWrapper(prop);\n }\n },\n });\n Plugins[pluginName] = proxy;\n registeredPlugins.set(pluginName, {\n name: pluginName,\n proxy,\n platforms: new Set([...Object.keys(jsImplementations), ...(pluginHeader ? [platform] : [])]),\n });\n return proxy;\n };\n // Add in convertFileSrc for web, it will already be available in native context\n if (!cap.convertFileSrc) {\n cap.convertFileSrc = (filePath) => filePath;\n }\n cap.getPlatform = getPlatform;\n cap.handleError = handleError;\n cap.isNativePlatform = isNativePlatform;\n cap.isPluginAvailable = isPluginAvailable;\n cap.registerPlugin = registerPlugin;\n cap.Exception = CapacitorException;\n cap.DEBUG = !!cap.DEBUG;\n cap.isLoggingEnabled = !!cap.isLoggingEnabled;\n return cap;\n};\nexport const initCapacitorGlobal = (win) => (win.Capacitor = createCapacitor(win));\n//# sourceMappingURL=runtime.js.map","import { initCapacitorGlobal } from './runtime';\nexport const Capacitor = /*#__PURE__*/ initCapacitorGlobal(typeof globalThis !== 'undefined'\n ? globalThis\n : typeof self !== 'undefined'\n ? self\n : typeof window !== 'undefined'\n ? window\n : typeof global !== 'undefined'\n ? global\n : {});\nexport const registerPlugin = Capacitor.registerPlugin;\n//# sourceMappingURL=global.js.map","import { Capacitor } from './global';\nimport { ExceptionCode } from './util';\n/**\n * Base class web plugins should extend.\n */\nexport class WebPlugin {\n constructor() {\n this.listeners = {};\n this.retainedEventArguments = {};\n this.windowListeners = {};\n }\n addListener(eventName, listenerFunc) {\n let firstListener = false;\n const listeners = this.listeners[eventName];\n if (!listeners) {\n this.listeners[eventName] = [];\n firstListener = true;\n }\n this.listeners[eventName].push(listenerFunc);\n // If we haven't added a window listener for this event and it requires one,\n // go ahead and add it\n const windowListener = this.windowListeners[eventName];\n if (windowListener && !windowListener.registered) {\n this.addWindowListener(windowListener);\n }\n if (firstListener) {\n this.sendRetainedArgumentsForEvent(eventName);\n }\n const remove = async () => this.removeListener(eventName, listenerFunc);\n const p = Promise.resolve({ remove });\n return p;\n }\n async removeAllListeners() {\n this.listeners = {};\n for (const listener in this.windowListeners) {\n this.removeWindowListener(this.windowListeners[listener]);\n }\n this.windowListeners = {};\n }\n notifyListeners(eventName, data, retainUntilConsumed) {\n const listeners = this.listeners[eventName];\n if (!listeners) {\n if (retainUntilConsumed) {\n let args = this.retainedEventArguments[eventName];\n if (!args) {\n args = [];\n }\n args.push(data);\n this.retainedEventArguments[eventName] = args;\n }\n return;\n }\n listeners.forEach((listener) => listener(data));\n }\n hasListeners(eventName) {\n var _a;\n return !!((_a = this.listeners[eventName]) === null || _a === void 0 ? void 0 : _a.length);\n }\n registerWindowListener(windowEventName, pluginEventName) {\n this.windowListeners[pluginEventName] = {\n registered: false,\n windowEventName,\n pluginEventName,\n handler: (event) => {\n this.notifyListeners(pluginEventName, event);\n },\n };\n }\n unimplemented(msg = 'not implemented') {\n return new Capacitor.Exception(msg, ExceptionCode.Unimplemented);\n }\n unavailable(msg = 'not available') {\n return new Capacitor.Exception(msg, ExceptionCode.Unavailable);\n }\n async removeListener(eventName, listenerFunc) {\n const listeners = this.listeners[eventName];\n if (!listeners) {\n return;\n }\n const index = listeners.indexOf(listenerFunc);\n this.listeners[eventName].splice(index, 1);\n // If there are no more listeners for this type of event,\n // remove the window listener\n if (!this.listeners[eventName].length) {\n this.removeWindowListener(this.windowListeners[eventName]);\n }\n }\n addWindowListener(handle) {\n window.addEventListener(handle.windowEventName, handle.handler);\n handle.registered = true;\n }\n removeWindowListener(handle) {\n if (!handle) {\n return;\n }\n window.removeEventListener(handle.windowEventName, handle.handler);\n handle.registered = false;\n }\n sendRetainedArgumentsForEvent(eventName) {\n const args = this.retainedEventArguments[eventName];\n if (!args) {\n return;\n }\n delete this.retainedEventArguments[eventName];\n args.forEach((arg) => {\n this.notifyListeners(eventName, arg);\n });\n }\n}\n//# sourceMappingURL=web-plugin.js.map","import { registerPlugin } from './global';\nimport { WebPlugin } from './web-plugin';\nexport const WebView = /*#__PURE__*/ registerPlugin('WebView');\n/******** END WEB VIEW PLUGIN ********/\n/******** COOKIES PLUGIN ********/\n/**\n * Safely web encode a string value (inspired by js-cookie)\n * @param str The string value to encode\n */\nconst encode = (str) => encodeURIComponent(str)\n .replace(/%(2[346B]|5E|60|7C)/g, decodeURIComponent)\n .replace(/[()]/g, escape);\n/**\n * Safely web decode a string value (inspired by js-cookie)\n * @param str The string value to decode\n */\nconst decode = (str) => str.replace(/(%[\\dA-F]{2})+/gi, decodeURIComponent);\nexport class CapacitorCookiesPluginWeb extends WebPlugin {\n async getCookies() {\n const cookies = document.cookie;\n const cookieMap = {};\n cookies.split(';').forEach((cookie) => {\n if (cookie.length <= 0)\n return;\n // Replace first \"=\" with CAP_COOKIE to prevent splitting on additional \"=\"\n let [key, value] = cookie.replace(/=/, 'CAP_COOKIE').split('CAP_COOKIE');\n key = decode(key).trim();\n value = decode(value).trim();\n cookieMap[key] = value;\n });\n return cookieMap;\n }\n async setCookie(options) {\n try {\n // Safely Encoded Key/Value\n const encodedKey = encode(options.key);\n const encodedValue = encode(options.value);\n // Clean & sanitize options\n const expires = options.expires ? `; expires=${options.expires.replace('expires=', '')}` : '';\n const path = (options.path || '/').replace('path=', ''); // Default is \"path=/\"\n const domain = options.url != null && options.url.length > 0 ? `domain=${options.url}` : '';\n document.cookie = `${encodedKey}=${encodedValue || ''}${expires}; path=${path}; ${domain};`;\n }\n catch (error) {\n return Promise.reject(error);\n }\n }\n async deleteCookie(options) {\n try {\n document.cookie = `${options.key}=; Max-Age=0`;\n }\n catch (error) {\n return Promise.reject(error);\n }\n }\n async clearCookies() {\n try {\n const cookies = document.cookie.split(';') || [];\n for (const cookie of cookies) {\n document.cookie = cookie.replace(/^ +/, '').replace(/=.*/, `=;expires=${new Date().toUTCString()};path=/`);\n }\n }\n catch (error) {\n return Promise.reject(error);\n }\n }\n async clearAllCookies() {\n try {\n await this.clearCookies();\n }\n catch (error) {\n return Promise.reject(error);\n }\n }\n}\nexport const CapacitorCookies = registerPlugin('CapacitorCookies', {\n web: () => new CapacitorCookiesPluginWeb(),\n});\n// UTILITY FUNCTIONS\n/**\n * Read in a Blob value and return it as a base64 string\n * @param blob The blob value to convert to a base64 string\n */\nexport const readBlobAsBase64 = async (blob) => new Promise((resolve, reject) => {\n const reader = new FileReader();\n reader.onload = () => {\n const base64String = reader.result;\n // remove prefix \"data:application/pdf;base64,\"\n resolve(base64String.indexOf(',') >= 0 ? base64String.split(',')[1] : base64String);\n };\n reader.onerror = (error) => reject(error);\n reader.readAsDataURL(blob);\n});\n/**\n * Normalize an HttpHeaders map by lowercasing all of the values\n * @param headers The HttpHeaders object to normalize\n */\nconst normalizeHttpHeaders = (headers = {}) => {\n const originalKeys = Object.keys(headers);\n const loweredKeys = Object.keys(headers).map((k) => k.toLocaleLowerCase());\n const normalized = loweredKeys.reduce((acc, key, index) => {\n acc[key] = headers[originalKeys[index]];\n return acc;\n }, {});\n return normalized;\n};\n/**\n * Builds a string of url parameters that\n * @param params A map of url parameters\n * @param shouldEncode true if you should encodeURIComponent() the values (true by default)\n */\nconst buildUrlParams = (params, shouldEncode = true) => {\n if (!params)\n return null;\n const output = Object.entries(params).reduce((accumulator, entry) => {\n const [key, value] = entry;\n let encodedValue;\n let item;\n if (Array.isArray(value)) {\n item = '';\n value.forEach((str) => {\n encodedValue = shouldEncode ? encodeURIComponent(str) : str;\n item += `${key}=${encodedValue}&`;\n });\n // last character will always be \"&\" so slice it off\n item.slice(0, -1);\n }\n else {\n encodedValue = shouldEncode ? encodeURIComponent(value) : value;\n item = `${key}=${encodedValue}`;\n }\n return `${accumulator}&${item}`;\n }, '');\n // Remove initial \"&\" from the reduce\n return output.substr(1);\n};\n/**\n * Build the RequestInit object based on the options passed into the initial request\n * @param options The Http plugin options\n * @param extra Any extra RequestInit values\n */\nexport const buildRequestInit = (options, extra = {}) => {\n const output = Object.assign({ method: options.method || 'GET', headers: options.headers }, extra);\n // Get the content-type\n const headers = normalizeHttpHeaders(options.headers);\n const type = headers['content-type'] || '';\n // If body is already a string, then pass it through as-is.\n if (typeof options.data === 'string') {\n output.body = options.data;\n }\n // Build request initializers based off of content-type\n else if (type.includes('application/x-www-form-urlencoded')) {\n const params = new URLSearchParams();\n for (const [key, value] of Object.entries(options.data || {})) {\n params.set(key, value);\n }\n output.body = params.toString();\n }\n else if (type.includes('multipart/form-data') || options.data instanceof FormData) {\n const form = new FormData();\n if (options.data instanceof FormData) {\n options.data.forEach((value, key) => {\n form.append(key, value);\n });\n }\n else {\n for (const key of Object.keys(options.data)) {\n form.append(key, options.data[key]);\n }\n }\n output.body = form;\n const headers = new Headers(output.headers);\n headers.delete('content-type'); // content-type will be set by `window.fetch` to includy boundary\n output.headers = headers;\n }\n else if (type.includes('application/json') || typeof options.data === 'object') {\n output.body = JSON.stringify(options.data);\n }\n return output;\n};\n// WEB IMPLEMENTATION\nexport class CapacitorHttpPluginWeb extends WebPlugin {\n /**\n * Perform an Http request given a set of options\n * @param options Options to build the HTTP request\n */\n async request(options) {\n const requestInit = buildRequestInit(options, options.webFetchExtra);\n const urlParams = buildUrlParams(options.params, options.shouldEncodeUrlParams);\n const url = urlParams ? `${options.url}?${urlParams}` : options.url;\n const response = await fetch(url, requestInit);\n const contentType = response.headers.get('content-type') || '';\n // Default to 'text' responseType so no parsing happens\n let { responseType = 'text' } = response.ok ? options : {};\n // If the response content-type is json, force the response to be json\n if (contentType.includes('application/json')) {\n responseType = 'json';\n }\n let data;\n let blob;\n switch (responseType) {\n case 'arraybuffer':\n case 'blob':\n blob = await response.blob();\n data = await readBlobAsBase64(blob);\n break;\n case 'json':\n data = await response.json();\n break;\n case 'document':\n case 'text':\n default:\n data = await response.text();\n }\n // Convert fetch headers to Capacitor HttpHeaders\n const headers = {};\n response.headers.forEach((value, key) => {\n headers[key] = value;\n });\n return {\n data,\n headers,\n status: response.status,\n url: response.url,\n };\n }\n /**\n * Perform an Http GET request given a set of options\n * @param options Options to build the HTTP request\n */\n async get(options) {\n return this.request(Object.assign(Object.assign({}, options), { method: 'GET' }));\n }\n /**\n * Perform an Http POST request given a set of options\n * @param options Options to build the HTTP request\n */\n async post(options) {\n return this.request(Object.assign(Object.assign({}, options), { method: 'POST' }));\n }\n /**\n * Perform an Http PUT request given a set of options\n * @param options Options to build the HTTP request\n */\n async put(options) {\n return this.request(Object.assign(Object.assign({}, options), { method: 'PUT' }));\n }\n /**\n * Perform an Http PATCH request given a set of options\n * @param options Options to build the HTTP request\n */\n async patch(options) {\n return this.request(Object.assign(Object.assign({}, options), { method: 'PATCH' }));\n }\n /**\n * Perform an Http DELETE request given a set of options\n * @param options Options to build the HTTP request\n */\n async delete(options) {\n return this.request(Object.assign(Object.assign({}, options), { method: 'DELETE' }));\n }\n}\nexport const CapacitorHttp = registerPlugin('CapacitorHttp', {\n web: () => new CapacitorHttpPluginWeb(),\n});\n/******** END HTTP PLUGIN ********/\n/******** SYSTEM BARS PLUGIN ********/\n/**\n * Available status bar styles.\n */\nexport var SystemBarsStyle;\n(function (SystemBarsStyle) {\n /**\n * Light system bar content on a dark background.\n *\n * @since 8.0.0\n */\n SystemBarsStyle[\"Dark\"] = \"DARK\";\n /**\n * For dark system bar content on a light background.\n *\n * @since 8.0.0\n */\n SystemBarsStyle[\"Light\"] = \"LIGHT\";\n /**\n * The style is based on the device appearance or the underlying content.\n * If the device is using Dark mode, the system bars content will be light.\n * If the device is using Light mode, the system bars content will be dark.\n *\n * @since 8.0.0\n */\n SystemBarsStyle[\"Default\"] = \"DEFAULT\";\n})(SystemBarsStyle || (SystemBarsStyle = {}));\n/**\n * Available system bar types.\n */\nexport var SystemBarType;\n(function (SystemBarType) {\n /**\n * The top status bar on both Android and iOS.\n *\n * @since 8.0.0\n */\n SystemBarType[\"StatusBar\"] = \"StatusBar\";\n /**\n * The navigation bar (or gesture bar on iOS) on both Android and iOS.\n *\n * @since 8.0.0\n */\n SystemBarType[\"NavigationBar\"] = \"NavigationBar\";\n})(SystemBarType || (SystemBarType = {}));\nexport class SystemBarsPluginWeb extends WebPlugin {\n async setStyle() {\n this.unavailable('not available for web');\n }\n async setAnimation() {\n this.unavailable('not available for web');\n }\n async show() {\n this.unavailable('not available for web');\n }\n async hide() {\n this.unavailable('not available for web');\n }\n}\nexport const SystemBars = registerPlugin('SystemBars', {\n web: () => new SystemBarsPluginWeb(),\n});\n/******** END SYSTEM BARS PLUGIN ********/\n//# sourceMappingURL=core-plugins.js.map"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/node_modules/@capacitor/core/http.md b/node_modules/@capacitor/core/http.md new file mode 100644 index 0000000..f459597 --- /dev/null +++ b/node_modules/@capacitor/core/http.md @@ -0,0 +1,683 @@ +# CapacitorHttp + +The Capacitor Http API provides native http support via patching `fetch` and `XMLHttpRequest` to use native libraries. It also provides helper methods for native http requests without the use of `fetch` and `XMLHttpRequest`. This plugin is bundled with `@capacitor/core`. + +## Configuration + +By default, the patching of `window.fetch` and `XMLHttpRequest` to use native libraries is disabled. +If you would like to enable this feature, modify the configuration below in the `capacitor.config` file. + +| Prop | Type | Description | Default | +| ------------- | -------------------- | ------------------------------------------------------------------------------------ | ------------------ | +| **`enabled`** | boolean | Enable the patching of `fetch` and `XMLHttpRequest` to use native libraries instead. | false | + +### Example Configuration + +In `capacitor.config.json`: + +```json +{ + "plugins": { + "CapacitorHttp": { + "enabled": true + } + } +} +``` + +In `capacitor.config.ts`: + +```ts +import { CapacitorConfig } from '@capacitor/cli'; + +const config: CapacitorConfig = { + plugins: { + CapacitorHttp: { + enabled: true, + }, + }, +}; + +export default config; +``` + +## Example + +```typescript +import { CapacitorHttp } from '@capacitor/core'; + +// Example of a GET request +const doGet = () => { + const options = { + url: 'https://example.com/my/api', + headers: { 'X-Fake-Header': 'Fake-Value' }, + params: { size: 'XL' }, + }; + + const response: HttpResponse = await CapacitorHttp.get(options); + + // or... + // const response = await CapacitorHttp.request({ ...options, method: 'GET' }) +}; + +// Example of a POST request. Note: data +// can be passed as a raw JS Object (must be JSON serializable) +const doPost = () => { + const options = { + url: 'https://example.com/my/api', + headers: { 'X-Fake-Header': 'Fake-Value' }, + data: { foo: 'bar' }, + }; + + const response: HttpResponse = await CapacitorHttp.post(options); + + // or... + // const response = await CapacitorHttp.request({ ...options, method: 'POST' }) +}; +``` + +## Large File Support + +Due to the nature of the bridge, parsing and transferring large amount of data from native to the web can cause issues. Support for downloading and uploading files has been added to the [`@capacitor/file-transfer`](https://capacitorjs.com/docs/apis/file-transfer) plugin. In many cases, you may also need [`@capacitor/filesystem`](https://capacitorjs.com/docs/apis/filesystem) to generate a valid [file URI](https://capacitorjs.com/docs/apis/filesystem#geturi). + +## API + + + +* [`request(...)`](#request) +* [`get(...)`](#get) +* [`post(...)`](#post) +* [`put(...)`](#put) +* [`patch(...)`](#patch) +* [`delete(...)`](#delete) +* [Interfaces](#interfaces) +* [Type Aliases](#type-aliases) + + + + + + +****** HTTP PLUGIN ******* + +### request(...) + +```typescript +request(options: HttpOptions) => Promise +``` + +Make a Http Request to a server using native libraries. + +| Param | Type | +| ------------- | --------------------------------------------------- | +| **`options`** | HttpOptions | + +**Returns:** Promise<HttpResponse> + +-------------------- + + +### get(...) + +```typescript +get(options: HttpOptions) => Promise +``` + +Make a Http GET Request to a server using native libraries. + +| Param | Type | +| ------------- | --------------------------------------------------- | +| **`options`** | HttpOptions | + +**Returns:** Promise<HttpResponse> + +-------------------- + + +### post(...) + +```typescript +post(options: HttpOptions) => Promise +``` + +Make a Http POST Request to a server using native libraries. + +| Param | Type | +| ------------- | --------------------------------------------------- | +| **`options`** | HttpOptions | + +**Returns:** Promise<HttpResponse> + +-------------------- + + +### put(...) + +```typescript +put(options: HttpOptions) => Promise +``` + +Make a Http PUT Request to a server using native libraries. + +| Param | Type | +| ------------- | --------------------------------------------------- | +| **`options`** | HttpOptions | + +**Returns:** Promise<HttpResponse> + +-------------------- + + +### patch(...) + +```typescript +patch(options: HttpOptions) => Promise +``` + +Make a Http PATCH Request to a server using native libraries. + +| Param | Type | +| ------------- | --------------------------------------------------- | +| **`options`** | HttpOptions | + +**Returns:** Promise<HttpResponse> + +-------------------- + + +### delete(...) + +```typescript +delete(options: HttpOptions) => Promise +``` + +Make a Http DELETE Request to a server using native libraries. + +| Param | Type | +| ------------- | --------------------------------------------------- | +| **`options`** | HttpOptions | + +**Returns:** Promise<HttpResponse> + +-------------------- + + +### Interfaces + + +#### HttpResponse + +| Prop | Type | Description | +| ------------- | --------------------------------------------------- | ------------------------------------------------- | +| **`data`** | any | Additional data received with the Http response. | +| **`status`** | number | The status code received from the Http response. | +| **`headers`** | HttpHeaders | The headers received from the Http response. | +| **`url`** | string | The response URL received from the Http response. | + + +#### HttpHeaders + + +#### HttpOptions + +| Prop | Type | Description | +| --------------------------- | ------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| **`url`** | string | The URL to send the request to. | +| **`method`** | string | The Http Request method to run. (Default is GET) | +| **`params`** | HttpParams | URL parameters to append to the request. | +| **`data`** | any | Note: On Android and iOS, data can only be a string or a JSON. FormData, Blob, ArrayBuffer, and other complex types are only directly supported on web or through enabling `CapacitorHttp` in the config and using the patched `window.fetch` or `XMLHttpRequest`. If you need to send a complex type, you should serialize the data to base64 and set the `headers["Content-Type"]` and `dataType` attributes accordingly. | +| **`headers`** | HttpHeaders | Http Request headers to send with the request. | +| **`readTimeout`** | number | How long to wait to read additional data in milliseconds. Resets each time new data is received. | +| **`connectTimeout`** | number | How long to wait for the initial connection in milliseconds. | +| **`disableRedirects`** | boolean | Sets whether automatic HTTP redirects should be disabled | +| **`webFetchExtra`** | RequestInit | Extra arguments for fetch when running on the web | +| **`responseType`** | HttpResponseType | This is used to parse the response appropriately before returning it to the requestee. If the response content-type is "json", this value is ignored. | +| **`shouldEncodeUrlParams`** | boolean | Use this option if you need to keep the URL unencoded in certain cases (already encoded, azure/firebase testing, etc.). The default is _true_. | +| **`dataType`** | 'file' \| 'formData' | This is used if we've had to convert the data from a JS type that needs special handling in the native layer | + + +#### HttpParams + + +#### RequestInit + +| Prop | Type | Description | +| -------------------- | ----------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| **`body`** | BodyInit | A BodyInit object or null to set request's body. | +| **`cache`** | RequestCache | A string indicating how the request will interact with the browser's cache to set request's cache. | +| **`credentials`** | RequestCredentials | A string indicating whether credentials will be sent with the request always, never, or only when sent to a same-origin URL. Sets request's credentials. | +| **`headers`** | HeadersInit | A Headers object, an object literal, or an array of two-item arrays to set request's headers. | +| **`integrity`** | string | A cryptographic hash of the resource to be fetched by request. Sets request's integrity. | +| **`keepalive`** | boolean | A boolean to set request's keepalive. | +| **`method`** | string | A string to set request's method. | +| **`mode`** | RequestMode | A string to indicate whether the request will use CORS, or will be restricted to same-origin URLs. Sets request's mode. | +| **`redirect`** | RequestRedirect | A string indicating whether request follows redirects, results in an error upon encountering a redirect, or returns the redirect (in an opaque fashion). Sets request's redirect. | +| **`referrer`** | string | A string whose value is a same-origin URL, "about:client", or the empty string, to set request's referrer. | +| **`referrerPolicy`** | ReferrerPolicy | A referrer policy to set request's referrerPolicy. | +| **`signal`** | AbortSignal | An AbortSignal to set request's signal. | +| **`window`** | any | Can only be null. Used to disassociate request from any Window. | + + +#### Blob + +A file-like object of immutable, raw data. Blobs represent data that isn't necessarily in a JavaScript-native format. The File interface is based on Blob, inheriting blob functionality and expanding it to support files on the user's system. +`Blob` class is a global reference for `require('node:buffer').Blob` +https://nodejs.org/api/buffer.html#class-blob + +| Prop | Type | +| ---------- | ------------------- | +| **`size`** | number | +| **`type`** | string | + +| Method | Signature | +| --------------- | ----------------------------------------------------------------------------------- | +| **arrayBuffer** | () => Promise<ArrayBuffer> | +| **slice** | (start?: number, end?: number, contentType?: string) => Blob | +| **stream** | () => ReadableStream | +| **text** | () => Promise<string> | + + +#### ArrayBuffer + +Represents a raw buffer of binary data, which is used to store data for the +different typed arrays. ArrayBuffers cannot be read from or written to directly, +but can be passed to a typed array or DataView Object to interpret the raw +buffer as needed. + +| Prop | Type | Description | +| ---------------- | ------------------- | ------------------------------------------------------------------------------- | +| **`byteLength`** | number | Read-only. The length of the ArrayBuffer (in bytes). | + +| Method | Signature | Description | +| --------- | -------------------------------------------------------------------------- | --------------------------------------------------------------- | +| **slice** | (begin: number, end?: number) => ArrayBuffer | Returns a section of an ArrayBuffer. | + + +#### ReadableStream + +This Streams API interface represents a readable stream of byte data. The Fetch API offers a concrete instance of a ReadableStream through the body property of a Response object. + +| Prop | Type | +| ------------ | -------------------- | +| **`locked`** | boolean | + +| Method | Signature | +| --------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| **cancel** | (reason?: any) => Promise<void> | +| **getReader** | () => ReadableStreamDefaultReader<R> | +| **pipeThrough** | <T>(transform: ReadableWritablePair<T, R>, options?: StreamPipeOptions) => ReadableStream<T> | +| **pipeTo** | (dest: WritableStream<R>, options?: StreamPipeOptions) => Promise<void> | +| **tee** | () => [ReadableStream<R>, ReadableStream<R>] | + + +#### ReadableStreamDefaultReader + +| Method | Signature | +| --------------- | --------------------------------------------------------------------------------------------------------------- | +| **read** | () => Promise<ReadableStreamDefaultReadResult<R>> | +| **releaseLock** | () => void | + + +#### ReadableStreamDefaultReadValueResult + +| Prop | Type | +| ----------- | ------------------ | +| **`done`** | false | +| **`value`** | T | + + +#### ReadableStreamDefaultReadDoneResult + +| Prop | Type | +| ----------- | ----------------- | +| **`done`** | true | +| **`value`** | | + + +#### ReadableWritablePair + +| Prop | Type | Description | +| -------------- | ------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| **`readable`** | ReadableStream<R> | | +| **`writable`** | WritableStream<W> | Provides a convenient, chainable way of piping this readable stream through a transform stream (or any other { writable, readable } pair). It simply pipes the stream into the writable side of the supplied pair, and returns the readable side for further use. Piping a stream will lock it for the duration of the pipe, preventing any other consumer from acquiring a reader. | + + +#### WritableStream + +This Streams API interface provides a standard abstraction for writing streaming data to a destination, known as a sink. This object comes with built-in backpressure and queuing. + +| Prop | Type | +| ------------ | -------------------- | +| **`locked`** | boolean | + +| Method | Signature | +| ------------- | ---------------------------------------------------------------------------------------- | +| **abort** | (reason?: any) => Promise<void> | +| **getWriter** | () => WritableStreamDefaultWriter<W> | + + +#### WritableStreamDefaultWriter + +This Streams API interface is the object returned by WritableStream.getWriter() and once created locks the < writer to the WritableStream ensuring that no other streams can write to the underlying sink. + +| Prop | Type | +| ----------------- | ------------------------------------- | +| **`closed`** | Promise<undefined> | +| **`desiredSize`** | number | +| **`ready`** | Promise<undefined> | + +| Method | Signature | +| --------------- | ---------------------------------------- | +| **abort** | (reason?: any) => Promise<void> | +| **close** | () => Promise<void> | +| **releaseLock** | () => void | +| **write** | (chunk: W) => Promise<void> | + + +#### StreamPipeOptions + +| Prop | Type | Description | +| ------------------- | --------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| **`preventAbort`** | boolean | | +| **`preventCancel`** | boolean | | +| **`preventClose`** | boolean | Pipes this readable stream to a given writable stream destination. The way in which the piping process behaves under various error conditions can be customized with a number of passed options. It returns a promise that fulfills when the piping process completes successfully, or rejects if any errors were encountered. Piping a stream will lock it for the duration of the pipe, preventing any other consumer from acquiring a reader. Errors and closures of the source and destination streams propagate as follows: An error in this source readable stream will abort destination, unless preventAbort is truthy. The returned promise will be rejected with the source's error, or with any error that occurs during aborting the destination. An error in destination will cancel this source readable stream, unless preventCancel is truthy. The returned promise will be rejected with the destination's error, or with any error that occurs during canceling the source. When this source readable stream closes, destination will be closed, unless preventClose is truthy. The returned promise will be fulfilled once this process completes, unless an error is encountered while closing the destination, in which case it will be rejected with that error. If destination starts out closed or closing, this source readable stream will be canceled, unless preventCancel is true. The returned promise will be rejected with an error indicating piping to a closed stream failed, or with any error that occurs during canceling the source. The signal option can be set to an AbortSignal to allow aborting an ongoing pipe operation via the corresponding AbortController. In this case, this source readable stream will be canceled, and destination aborted, unless the respective options preventCancel or preventAbort are set. | +| **`signal`** | AbortSignal | | + + +#### AbortSignal + +A signal object that allows you to communicate with a DOM request (such as a Fetch) and abort it if required via an AbortController object. + +| Prop | Type | Description | +| ------------- | ----------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------- | +| **`aborted`** | boolean | Returns true if this AbortSignal's AbortController has signaled to abort, and false otherwise. | +| **`onabort`** | (this: AbortSignal, ev: Event) => any | | + +| Method | Signature | Description | +| ----------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| **addEventListener** | <K extends "abort">(type: K, listener: (this: AbortSignal, ev: AbortSignalEventMap[K]) => any, options?: boolean \| AddEventListenerOptions) => void | Appends an event listener for events whose type attribute value is type. The callback argument sets the callback that will be invoked when the event is dispatched. The options argument sets listener-specific options. For compatibility this can be a boolean, in which case the method behaves exactly as if the value was specified as options's capture. When set to true, options's capture prevents callback from being invoked when the event's eventPhase attribute value is BUBBLING_PHASE. When false (or not present), callback will not be invoked when event's eventPhase attribute value is CAPTURING_PHASE. Either way, callback will be invoked if event's eventPhase attribute value is AT_TARGET. When set to true, options's passive indicates that the callback will not cancel the event by invoking preventDefault(). This is used to enable performance optimizations described in § 2.8 Observing event listeners. When set to true, options's once indicates that the callback will only be invoked once after which the event listener will be removed. The event listener is appended to target's event listener list and is not appended if it has the same type, callback, and capture. | +| **addEventListener** | (type: string, listener: EventListenerOrEventListenerObject, options?: boolean \| AddEventListenerOptions) => void | Appends an event listener for events whose type attribute value is type. The callback argument sets the callback that will be invoked when the event is dispatched. The options argument sets listener-specific options. For compatibility this can be a boolean, in which case the method behaves exactly as if the value was specified as options's capture. When set to true, options's capture prevents callback from being invoked when the event's eventPhase attribute value is BUBBLING_PHASE. When false (or not present), callback will not be invoked when event's eventPhase attribute value is CAPTURING_PHASE. Either way, callback will be invoked if event's eventPhase attribute value is AT_TARGET. When set to true, options's passive indicates that the callback will not cancel the event by invoking preventDefault(). This is used to enable performance optimizations described in § 2.8 Observing event listeners. When set to true, options's once indicates that the callback will only be invoked once after which the event listener will be removed. The event listener is appended to target's event listener list and is not appended if it has the same type, callback, and capture. | +| **removeEventListener** | <K extends "abort">(type: K, listener: (this: AbortSignal, ev: AbortSignalEventMap[K]) => any, options?: boolean \| EventListenerOptions) => void | Removes the event listener in target's event listener list with the same type, callback, and options. | +| **removeEventListener** | (type: string, listener: EventListenerOrEventListenerObject, options?: boolean \| EventListenerOptions) => void | Removes the event listener in target's event listener list with the same type, callback, and options. | + + +#### AbortSignalEventMap + +| Prop | Type | +| ------------- | --------------------------------------- | +| **`"abort"`** | Event | + + +#### Event + +An event which takes place in the DOM. + +| Prop | Type | Description | +| ---------------------- | --------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| **`bubbles`** | boolean | Returns true or false depending on how event was initialized. True if event goes through its target's ancestors in reverse tree order, and false otherwise. | +| **`cancelBubble`** | boolean | | +| **`cancelable`** | boolean | Returns true or false depending on how event was initialized. Its return value does not always carry meaning, but true can indicate that part of the operation during which event was dispatched, can be canceled by invoking the preventDefault() method. | +| **`composed`** | boolean | Returns true or false depending on how event was initialized. True if event invokes listeners past a ShadowRoot node that is the root of its target, and false otherwise. | +| **`currentTarget`** | EventTarget | Returns the object whose event listener's callback is currently being invoked. | +| **`defaultPrevented`** | boolean | Returns true if preventDefault() was invoked successfully to indicate cancelation, and false otherwise. | +| **`eventPhase`** | number | Returns the event's phase, which is one of NONE, CAPTURING_PHASE, AT_TARGET, and BUBBLING_PHASE. | +| **`isTrusted`** | boolean | Returns true if event was dispatched by the user agent, and false otherwise. | +| **`returnValue`** | boolean | | +| **`srcElement`** | EventTarget | | +| **`target`** | EventTarget | Returns the object to which event is dispatched (its target). | +| **`timeStamp`** | number | Returns the event's timestamp as the number of milliseconds measured relative to the time origin. | +| **`type`** | string | Returns the type of event, e.g. "click", "hashchange", or "submit". | +| **`AT_TARGET`** | number | | +| **`BUBBLING_PHASE`** | number | | +| **`CAPTURING_PHASE`** | number | | +| **`NONE`** | number | | + +| Method | Signature | Description | +| ---------------------------- | ------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| **composedPath** | () => EventTarget[] | Returns the invocation target objects of event's path (objects on which listeners will be invoked), except for any nodes in shadow trees of which the shadow root's mode is "closed" that are not reachable from event's currentTarget. | +| **initEvent** | (type: string, bubbles?: boolean, cancelable?: boolean) => void | | +| **preventDefault** | () => void | If invoked when the cancelable attribute value is true, and while executing a listener for the event with passive set to false, signals to the operation that caused event to be dispatched that it needs to be canceled. | +| **stopImmediatePropagation** | () => void | Invoking this method prevents event from reaching any registered event listeners after the current one finishes running and, when dispatched in a tree, also prevents event from reaching any other objects. | +| **stopPropagation** | () => void | When dispatched in a tree, invoking this method prevents event from reaching any objects other than the current object. | + + +#### EventTarget + +EventTarget is a DOM interface implemented by objects that can receive events and may have listeners for them. +EventTarget is a DOM interface implemented by objects that can +receive events and may have listeners for them. + +| Method | Signature | Description | +| ----------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| **addEventListener** | (type: string, listener: EventListenerOrEventListenerObject \| null, options?: boolean \| AddEventListenerOptions) => void | Appends an event listener for events whose type attribute value is type. The callback argument sets the callback that will be invoked when the event is dispatched. The options argument sets listener-specific options. For compatibility this can be a boolean, in which case the method behaves exactly as if the value was specified as options's capture. When set to true, options's capture prevents callback from being invoked when the event's eventPhase attribute value is BUBBLING_PHASE. When false (or not present), callback will not be invoked when event's eventPhase attribute value is CAPTURING_PHASE. Either way, callback will be invoked if event's eventPhase attribute value is AT_TARGET. When set to true, options's passive indicates that the callback will not cancel the event by invoking preventDefault(). This is used to enable performance optimizations described in § 2.8 Observing event listeners. When set to true, options's once indicates that the callback will only be invoked once after which the event listener will be removed. The event listener is appended to target's event listener list and is not appended if it has the same type, callback, and capture. | +| **dispatchEvent** | (event: Event) => boolean | Dispatches a synthetic event event to target and returns true if either event's cancelable attribute value is false or its preventDefault() method was not invoked, and false otherwise. | +| **removeEventListener** | (type: string, callback: EventListenerOrEventListenerObject \| null, options?: EventListenerOptions \| boolean) => void | Removes the event listener in target's event listener list with the same type, callback, and options. | + + +#### EventListener + + +#### EventListenerObject + +| Method | Signature | +| --------------- | -------------------------------------------- | +| **handleEvent** | (evt: Event) => void | + + +#### AddEventListenerOptions + +| Prop | Type | +| ------------- | -------------------- | +| **`once`** | boolean | +| **`passive`** | boolean | + + +#### EventListenerOptions + +| Prop | Type | +| ------------- | -------------------- | +| **`capture`** | boolean | + + +#### ArrayBufferView + +| Prop | Type | Description | +| ---------------- | ----------------------------------------------------------- | ---------------------------------------------------------------------------- | +| **`buffer`** | ArrayBufferLike | The ArrayBuffer instance referenced by the array. | +| **`byteLength`** | number | The length in bytes of the array. | +| **`byteOffset`** | number | The offset in bytes of the array. | + + +#### ArrayBufferTypes + +Allowed ArrayBuffer types for the buffer of an ArrayBufferView and related Typed Arrays. + +| Prop | Type | +| ----------------- | --------------------------------------------------- | +| **`ArrayBuffer`** | ArrayBuffer | + + +#### FormData + +Provides a way to easily construct a set of key/value pairs representing form fields and their values, which can then be easily sent using the XMLHttpRequest.send() method. It uses the same format a form would use if the encoding type were set to "multipart/form-data". + +| Method | Signature | +| ----------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| **append** | (name: string, value: string \| Blob, fileName?: string) => void | +| **delete** | (name: string) => void | +| **get** | (name: string) => FormDataEntryValue \| null | +| **getAll** | (name: string) => FormDataEntryValue[] | +| **has** | (name: string) => boolean | +| **set** | (name: string, value: string \| Blob, fileName?: string) => void | +| **forEach** | (callbackfn: (value: FormDataEntryValue, key: string, parent: FormData) => void, thisArg?: any) => void | + + +#### File + +Provides information about files and allows JavaScript in a web page to access their content. + +| Prop | Type | +| ------------------ | ------------------- | +| **`lastModified`** | number | +| **`name`** | string | + + +#### URLSearchParams + +`URLSearchParams` class is a global reference for `require('url').URLSearchParams` +https://nodejs.org/api/url.html#class-urlsearchparams + +| Method | Signature | Description | +| ------------ | --------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------- | +| **append** | (name: string, value: string) => void | Appends a specified key/value pair as a new search parameter. | +| **delete** | (name: string) => void | Deletes the given search parameter, and its associated value, from the list of all search parameters. | +| **get** | (name: string) => string \| null | Returns the first value associated to the given search parameter. | +| **getAll** | (name: string) => string[] | Returns all the values association with a given search parameter. | +| **has** | (name: string) => boolean | Returns a Boolean indicating if such a search parameter exists. | +| **set** | (name: string, value: string) => void | Sets the value associated to a given search parameter to the given value. If there were several values, delete the others. | +| **sort** | () => void | | +| **toString** | () => string | Returns a string containing a query string suitable for use in a URL. Does not include the question mark. | +| **forEach** | (callbackfn: (value: string, key: string, parent: URLSearchParams) => void, thisArg?: any) => void | | + + +#### Uint8Array + +A typed array of 8-bit unsigned integer values. The contents are initialized to 0. If the +requested number of bytes could not be allocated an exception is raised. + +| Prop | Type | Description | +| ----------------------- | ----------------------------------------------------------- | ---------------------------------------------------------------------------- | +| **`BYTES_PER_ELEMENT`** | number | The size in bytes of each element in the array. | +| **`buffer`** | ArrayBufferLike | The ArrayBuffer instance referenced by the array. | +| **`byteLength`** | number | The length in bytes of the array. | +| **`byteOffset`** | number | The offset in bytes of the array. | +| **`length`** | number | The length of the array. | + +| Method | Signature | Description | +| ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| **copyWithin** | (target: number, start: number, end?: number) => this | Returns the this object after copying a section of the array identified by start and end to the same array starting at position target | +| **every** | (predicate: (value: number, index: number, array: Uint8Array) => unknown, thisArg?: any) => boolean | Determines whether all the members of an array satisfy the specified test. | +| **fill** | (value: number, start?: number, end?: number) => this | Returns the this object after filling the section identified by start and end with value | +| **filter** | (predicate: (value: number, index: number, array: Uint8Array) => any, thisArg?: any) => Uint8Array | Returns the elements of an array that meet the condition specified in a callback function. | +| **find** | (predicate: (value: number, index: number, obj: Uint8Array) => boolean, thisArg?: any) => number \| undefined | Returns the value of the first element in the array where predicate is true, and undefined otherwise. | +| **findIndex** | (predicate: (value: number, index: number, obj: Uint8Array) => boolean, thisArg?: any) => number | Returns the index of the first element in the array where predicate is true, and -1 otherwise. | +| **forEach** | (callbackfn: (value: number, index: number, array: Uint8Array) => void, thisArg?: any) => void | Performs the specified action for each element in an array. | +| **indexOf** | (searchElement: number, fromIndex?: number) => number | Returns the index of the first occurrence of a value in an array. | +| **join** | (separator?: string) => string | Adds all the elements of an array separated by the specified separator string. | +| **lastIndexOf** | (searchElement: number, fromIndex?: number) => number | Returns the index of the last occurrence of a value in an array. | +| **map** | (callbackfn: (value: number, index: number, array: Uint8Array) => number, thisArg?: any) => Uint8Array | Calls a defined callback function on each element of an array, and returns an array that contains the results. | +| **reduce** | (callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Uint8Array) => number) => number | Calls the specified callback function for all the elements in an array. The return value of the callback function is the accumulated result, and is provided as an argument in the next call to the callback function. | +| **reduce** | (callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Uint8Array) => number, initialValue: number) => number | | +| **reduce** | <U>(callbackfn: (previousValue: U, currentValue: number, currentIndex: number, array: Uint8Array) => U, initialValue: U) => U | Calls the specified callback function for all the elements in an array. The return value of the callback function is the accumulated result, and is provided as an argument in the next call to the callback function. | +| **reduceRight** | (callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Uint8Array) => number) => number | Calls the specified callback function for all the elements in an array, in descending order. The return value of the callback function is the accumulated result, and is provided as an argument in the next call to the callback function. | +| **reduceRight** | (callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Uint8Array) => number, initialValue: number) => number | | +| **reduceRight** | <U>(callbackfn: (previousValue: U, currentValue: number, currentIndex: number, array: Uint8Array) => U, initialValue: U) => U | Calls the specified callback function for all the elements in an array, in descending order. The return value of the callback function is the accumulated result, and is provided as an argument in the next call to the callback function. | +| **reverse** | () => Uint8Array | Reverses the elements in an Array. | +| **set** | (array: ArrayLike<number>, offset?: number) => void | Sets a value or an array of values. | +| **slice** | (start?: number, end?: number) => Uint8Array | Returns a section of an array. | +| **some** | (predicate: (value: number, index: number, array: Uint8Array) => unknown, thisArg?: any) => boolean | Determines whether the specified callback function returns true for any element of an array. | +| **sort** | (compareFn?: (a: number, b: number) => number) => this | Sorts an array. | +| **subarray** | (begin?: number, end?: number) => Uint8Array | Gets a new Uint8Array view of the ArrayBuffer store for this array, referencing the elements at begin, inclusive, up to end, exclusive. | +| **toLocaleString** | () => string | Converts a number to a string by using the current locale. | +| **toString** | () => string | Returns a string representation of an array. | +| **valueOf** | () => Uint8Array | Returns the primitive value of the specified object. | + + +#### ArrayLike + +| Prop | Type | +| ------------ | ------------------- | +| **`length`** | number | + + +#### Headers + +This Fetch API interface allows you to perform various actions on HTTP request and response headers. These actions include retrieving, setting, adding to, and removing. A Headers object has an associated header list, which is initially empty and consists of zero or more name and value pairs.  You can add to this using methods like append() (see Examples.) In all methods of this interface, header names are matched by case-insensitive byte sequence. + +| Method | Signature | +| ----------- | ----------------------------------------------------------------------------------------------------------------------- | +| **append** | (name: string, value: string) => void | +| **delete** | (name: string) => void | +| **get** | (name: string) => string \| null | +| **has** | (name: string) => boolean | +| **set** | (name: string, value: string) => void | +| **forEach** | (callbackfn: (value: string, key: string, parent: Headers) => void, thisArg?: any) => void | + + +### Type Aliases + + +#### BodyInit + +Blob | BufferSource | FormData | URLSearchParams | ReadableStream<Uint8Array> | string + + +#### ReadableStreamDefaultReadResult + +ReadableStreamDefaultReadValueResult<T> | ReadableStreamDefaultReadDoneResult + + +#### EventListenerOrEventListenerObject + +EventListener | EventListenerObject + + +#### BufferSource + +ArrayBufferView | ArrayBuffer + + +#### ArrayBufferLike + +ArrayBufferTypes[keyof ArrayBufferTypes] + + +#### FormDataEntryValue + +File | string + + +#### RequestCache + +"default" | "force-cache" | "no-cache" | "no-store" | "only-if-cached" | "reload" + + +#### RequestCredentials + +"include" | "omit" | "same-origin" + + +#### HeadersInit + +Headers | string[][] | Record<string, string> + + +#### Record + +Construct a type with a set of properties K of type T + +{ [P in K]: T; } + + +#### RequestMode + +"cors" | "navigate" | "no-cors" | "same-origin" + + +#### RequestRedirect + +"error" | "follow" | "manual" + + +#### ReferrerPolicy + +"" | "no-referrer" | "no-referrer-when-downgrade" | "origin" | "origin-when-cross-origin" | "same-origin" | "strict-origin" | "strict-origin-when-cross-origin" | "unsafe-url" + + +#### HttpResponseType + +How to parse the Http response before returning it to the client. + +'arraybuffer' | 'blob' | 'json' | 'text' | 'document' + + \ No newline at end of file diff --git a/node_modules/@capacitor/core/package.json b/node_modules/@capacitor/core/package.json new file mode 100644 index 0000000..eef113a --- /dev/null +++ b/node_modules/@capacitor/core/package.json @@ -0,0 +1,62 @@ +{ + "name": "@capacitor/core", + "version": "8.3.4", + "description": "Capacitor: Cross-platform apps with JavaScript and the web", + "homepage": "https://capacitorjs.com", + "author": "Ionic Team (https://ionic.io)", + "license": "MIT", + "repository": { + "type": "git", + "url": "git+https://github.com/ionic-team/capacitor.git" + }, + "bugs": { + "url": "https://github.com/ionic-team/capacitor/issues" + }, + "files": [ + "dist/", + "types/", + "cookies.md", + "cordova.js", + "http.md", + "system-bars.md" + ], + "main": "dist/index.cjs.js", + "module": "dist/index.js", + "types": "types/index.d.ts", + "unpkg": "dist/capacitor.js", + "scripts": { + "build": "npm run clean && npm run docgen && npm run transpile && npm run rollup", + "build:nativebridge": "tsc native-bridge.ts --target es2017 --moduleResolution node --outDir build && rollup --config rollup.bridge.config.js", + "clean": "rimraf dist", + "docgen": "docgen --api CapacitorCookiesPlugin --output-readme cookies.md && docgen --api CapacitorHttpPlugin --output-readme http.md && docgen --api SystemBarsPlugin --output-readme system-bars.md", + "prepublishOnly": "npm run build", + "rollup": "rollup --config rollup.config.js", + "transpile": "tsc", + "test": "jest", + "test.watch": "jest --watchAll", + "test.treeshaking": "node src/tests/build-treeshaking.js" + }, + "dependencies": { + "tslib": "^2.1.0" + }, + "devDependencies": { + "@capacitor/docgen": "^0.2.2", + "@rollup/plugin-node-resolve": "^10.0.0", + "@rollup/plugin-replace": "^2.4.2", + "@types/jest": "^29.5.0", + "jest": "^29.5.0", + "jest-environment-jsdom": "^29.5.0", + "jest-jasmine2": "^29.5.0", + "rimraf": "^4.4.1", + "rollup": "^2.21.0", + "rollup-plugin-terser": "^7.0.2", + "typescript": "~5.0.2" + }, + "jest": { + "preset": "ts-jest", + "testRunner": "jest-jasmine2" + }, + "publishConfig": { + "access": "public" + } +} diff --git a/node_modules/@capacitor/core/system-bars.md b/node_modules/@capacitor/core/system-bars.md new file mode 100644 index 0000000..6727507 --- /dev/null +++ b/node_modules/@capacitor/core/system-bars.md @@ -0,0 +1,260 @@ +# SystemBars + +The SystemBars API provides methods for configuring the style and visibility of the device System Bars / Status Bar. This plugin is bundled with `@capacitor/core`. + +This API differs from the [Status Bar](https://capacitorjs.com/docs/apis/status-bar) plugin in that it is only intended to support modern edge to edge use cases moving forward. For legacy functionality, use the [Status Bar](https://capacitorjs.com/docs/apis/status-bar) plugin. + +| Feature | System Bars | Status Bar | +| ------- | ----------- | ---------- | +| `setOverlaysWebView()` | Unsupported | Supported on iOS and Android <= 14 (or 15 if edge to edge opt-out is enabled) | +| `setBackgroundColor()` | Unsupported | Supported | +| `setStyle()` | Supported | Supported - top Status Bar only | +| `hide()/show()` | Supported | Supported - top Status Bar only | + +## iOS Note + +This plugin requires "View controller-based status bar appearance" +(`UIViewControllerBasedStatusBarAppearance`) set to `YES` in `Info.plist`. Read +about [Configuring iOS](https://capacitorjs.com/docs/ios/configuration) for +help. + +The status bar visibility defaults to visible and the style defaults to +`Style.Default`. You can change these defaults by adding +`UIStatusBarHidden` and/or `UIStatusBarStyle` in `Info.plist`. + +## Android Note + +Due to a [bug](https://issues.chromium.org/issues/40699457) in some older versions of Android WebView (< 140), correct safe area values are not available via the `safe-area-inset-x` CSS `env` variables. This plugin will inject the correct inset values into a new CSS variable(s) named `--safe-area-inset-x` that you can use as a fallback in your frontend styles: + +```css +html { + padding-top: var(--safe-area-inset-top, env(safe-area-inset-top, 0px)); + padding-bottom: var(--safe-area-inset-bottom, env(safe-area-inset-bottom, 0px)); + padding-left: var(--safe-area-inset-left, env(safe-area-inset-left, 0px)); + padding-right: var(--safe-area-inset-right, env(safe-area-inset-right, 0px)); +} +``` +To control this behavior, use the `insetsHandling` configuration setting. + +## Example + +```typescript +import { SystemBars, SystemBarsStyle, SystemBarType } from '@capacitor/core'; + +const setSystemBarStyleDark = async () => { + await SystemBars.setStyle({ style: SystemBarsStyle.Dark }); +}; + +const setSystemBarStyleLight = async () => { + await SystemBars.setStyle({ style: SystemBarsStyle.Light }); +}; + +const hideSystemBars = async () => { + await SystemBars.hide(); +}; + +const showSystemBars = async () => { + await SystemBars.show(); +}; + +const hideNavigationBar = async () => { + await SystemBars.hide({ + bar: SystemBarType.NavigationBar + }) +} + +// Set the Status Bar animation, only on iOS +const setStatusBarAnimation = async () => { + await SystemBars.setAnimation({ animation: "NONE" }); +} + +```` + +## Configuration +| Prop | Type | Description | Default | +| ------------- | -------------------- | ------------------------------------------------------------------------- | ------------------ | +| **`insetsHandling`** | string | Specifies how to handle problematic insets on Android. This option is only supported on Android.
`css` = Injects CSS variables (`--safe-area-inset-*`) containing correct safe area inset values into the webview.
`disable` = Disable CSS variables injection. | css | +| **`style`** | string | The style of the text and icons of the system bars. | DEFAULT | +| **`hidden`** | boolean | Hide the system bars on start. | false | +| **`animation`** | string | The type of status bar animation used when showing or hiding. This option is only supported on iOS. | FADE | + + +### Example Configuration + +In `capacitor.config.json`: + +```json +{ + "plugins": { + "SystemBars": { + "insetsHandling": "css", + "style": "DARK", + "hidden": false, + "animation": "NONE" + } + } +} +``` + +In `capacitor.config.ts`: + +```ts +import { CapacitorConfig } from '@capacitor/cli'; + +const config: CapacitorConfig = { + plugins: { + SystemBars: { + insetsHandling: "css", + style: "DARK", + hidden: false, + animation: "NONE" + }, + }, +}; + +export default config; +``` + +## API + + + +* [`setStyle(...)`](#setstyle) +* [`show(...)`](#show) +* [`hide(...)`](#hide) +* [`setAnimation(...)`](#setanimation) +* [Interfaces](#interfaces) +* [Type Aliases](#type-aliases) +* [Enums](#enums) + + + + + + +### setStyle(...) + +```typescript +setStyle(options: SystemBarsStyleOptions) => Promise +``` + +Set the current style of the system bars. + +| Param | Type | +| ------------- | ------------------------------------------------------------------------- | +| **`options`** | SystemBarsStyleOptions | + +**Since:** 8.0.0 + +-------------------- + + +### show(...) + +```typescript +show(options?: SystemBarsVisibilityOptions) => Promise +``` + +Show the system bars. + +| Param | Type | +| ------------- | ----------------------------------------------------------------------------------- | +| **`options`** | SystemBarsVisibilityOptions | + +**Since:** 8.0.0 + +-------------------- + + +### hide(...) + +```typescript +hide(options?: SystemBarsVisibilityOptions) => Promise +``` + +Hide the system bars. + +| Param | Type | +| ------------- | ----------------------------------------------------------------------------------- | +| **`options`** | SystemBarsVisibilityOptions | + +**Since:** 8.0.0 + +-------------------- + + +### setAnimation(...) + +```typescript +setAnimation(options: SystemBarsAnimationOptions) => Promise +``` + +Set the animation to use when showing / hiding the status bar. + +Only available on iOS. + +| Param | Type | +| ------------- | --------------------------------------------------------------------------------- | +| **`options`** | SystemBarsAnimationOptions | + +**Since:** 8.0.0 + +-------------------- + + +### Interfaces + + +#### SystemBarsStyleOptions + +| Prop | Type | Description | Default | Since | +| ----------- | ----------------------------------------------------------- | ----------------------------------------------- | ---------------------- | ----- | +| **`style`** | SystemBarsStyle | Style of the text and icons of the system bars. | 'DEFAULT' | 8.0.0 | +| **`bar`** | SystemBarType | The system bar to which to apply the style. | null | 8.0.0 | + + +#### SystemBarsVisibilityOptions + +| Prop | Type | Description | Default | Since | +| --------------- | ------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------- | ------------------- | ----- | +| **`bar`** | SystemBarType | The system bar to hide or show. | null | 8.0.0 | +| **`animation`** | SystemBarsAnimation | The type of status bar animation used when showing or hiding. This option is only supported on iOS. | 'FADE' | 8.0.0 | + + +#### SystemBarsAnimationOptions + +| Prop | Type | Description | Default | Since | +| --------------- | ------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------- | ------------------- | ----- | +| **`animation`** | SystemBarsAnimation | The type of status bar animation used when showing or hiding. This option is only supported on iOS. | 'FADE' | 8.0.0 | + + +### Type Aliases + + +#### SystemBarsAnimation + +Available status bar animations. iOS only. + +'FADE' | 'NONE' + + +### Enums + + +#### SystemBarsStyle + +| Members | Value | Description | Since | +| ------------- | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ----- | +| **`Dark`** | 'DARK' | Light system bar content on a dark background. | 8.0.0 | +| **`Light`** | 'LIGHT' | For dark system bar content on a light background. | 8.0.0 | +| **`Default`** | 'DEFAULT' | The style is based on the device appearance or the underlying content. If the device is using Dark mode, the system bars content will be light. If the device is using Light mode, the system bars content will be dark. | 8.0.0 | + + +#### SystemBarType + +| Members | Value | Description | Since | +| ------------------- | ---------------------------- | ------------------------------------------------------------------- | ----- | +| **`StatusBar`** | 'StatusBar' | The top status bar on both Android and iOS. | 8.0.0 | +| **`NavigationBar`** | 'NavigationBar' | The navigation bar (or gesture bar on iOS) on both Android and iOS. | 8.0.0 | + + diff --git a/node_modules/@capacitor/core/types/core-plugins.d.ts b/node_modules/@capacitor/core/types/core-plugins.d.ts new file mode 100644 index 0000000..f865b8b --- /dev/null +++ b/node_modules/@capacitor/core/types/core-plugins.d.ts @@ -0,0 +1,372 @@ +import type { Plugin } from './definitions'; +import { WebPlugin } from './web-plugin'; +/******** WEB VIEW PLUGIN ********/ +export interface WebViewPlugin extends Plugin { + setServerAssetPath(options: WebViewPath): Promise; + setServerBasePath(options: WebViewPath): Promise; + getServerBasePath(): Promise; + persistServerBasePath(): Promise; +} +export interface WebViewPath { + path: string; +} +export declare const WebView: WebViewPlugin; +export interface CapacitorCookiesPlugin { + getCookies(options?: GetCookieOptions): Promise; + /** + * Write a cookie to the device. + */ + setCookie(options: SetCookieOptions): Promise; + /** + * Delete a cookie from the device. + */ + deleteCookie(options: DeleteCookieOptions): Promise; + /** + * Clear cookies from the device at a given URL. + */ + clearCookies(options: ClearCookieOptions): Promise; + /** + * Clear all cookies on the device. + */ + clearAllCookies(): Promise; +} +interface HttpCookie { + /** + * The URL of the cookie. + */ + url?: string; + /** + * The key of the cookie. + */ + key: string; + /** + * The value of the cookie. + */ + value: string; +} +interface HttpCookieMap { + [key: string]: string; +} +interface HttpCookieExtras { + /** + * The path to write the cookie to. + */ + path?: string; + /** + * The date to expire the cookie. + */ + expires?: string; +} +export type GetCookieOptions = Omit; +export type SetCookieOptions = HttpCookie & HttpCookieExtras; +export type DeleteCookieOptions = Omit; +export type ClearCookieOptions = Omit; +export declare class CapacitorCookiesPluginWeb extends WebPlugin implements CapacitorCookiesPlugin { + getCookies(): Promise; + setCookie(options: SetCookieOptions): Promise; + deleteCookie(options: DeleteCookieOptions): Promise; + clearCookies(): Promise; + clearAllCookies(): Promise; +} +export declare const CapacitorCookies: CapacitorCookiesPlugin; +/******** END COOKIES PLUGIN ********/ +/******** HTTP PLUGIN ********/ +export interface CapacitorHttpPlugin { + /** + * Make a Http Request to a server using native libraries. + */ + request(options: HttpOptions): Promise; + /** + * Make a Http GET Request to a server using native libraries. + */ + get(options: HttpOptions): Promise; + /** + * Make a Http POST Request to a server using native libraries. + */ + post(options: HttpOptions): Promise; + /** + * Make a Http PUT Request to a server using native libraries. + */ + put(options: HttpOptions): Promise; + /** + * Make a Http PATCH Request to a server using native libraries. + */ + patch(options: HttpOptions): Promise; + /** + * Make a Http DELETE Request to a server using native libraries. + */ + delete(options: HttpOptions): Promise; +} +/** + * How to parse the Http response before returning it to the client. + */ +export type HttpResponseType = 'arraybuffer' | 'blob' | 'json' | 'text' | 'document'; +export interface HttpOptions { + /** + * The URL to send the request to. + */ + url: string; + /** + * The Http Request method to run. (Default is GET) + */ + method?: string; + /** + * URL parameters to append to the request. + */ + params?: HttpParams; + /** + * Note: On Android and iOS, data can only be a string or a JSON. + * FormData, Blob, ArrayBuffer, and other complex types are only directly supported on web + * or through enabling `CapacitorHttp` in the config and using the patched `window.fetch` or `XMLHttpRequest`. + * + * If you need to send a complex type, you should serialize the data to base64 + * and set the `headers["Content-Type"]` and `dataType` attributes accordingly. + */ + data?: any; + /** + * Http Request headers to send with the request. + */ + headers?: HttpHeaders; + /** + * How long to wait to read additional data in milliseconds. + * Resets each time new data is received. + */ + readTimeout?: number; + /** + * How long to wait for the initial connection in milliseconds. + */ + connectTimeout?: number; + /** + * Sets whether automatic HTTP redirects should be disabled + */ + disableRedirects?: boolean; + /** + * Extra arguments for fetch when running on the web + */ + webFetchExtra?: RequestInit; + /** + * This is used to parse the response appropriately before returning it to + * the requestee. If the response content-type is "json", this value is ignored. + */ + responseType?: HttpResponseType; + /** + * Use this option if you need to keep the URL unencoded in certain cases + * (already encoded, azure/firebase testing, etc.). The default is _true_. + */ + shouldEncodeUrlParams?: boolean; + /** + * This is used if we've had to convert the data from a JS type that needs + * special handling in the native layer + */ + dataType?: 'file' | 'formData'; +} +export interface HttpParams { + /** + * A key/value dictionary of URL parameters to set. + */ + [key: string]: string | string[]; +} +export interface HttpHeaders { + /** + * A key/value dictionary of Http headers. + */ + [key: string]: string; +} +export interface HttpResponse { + /** + * Additional data received with the Http response. + */ + data: any; + /** + * The status code received from the Http response. + */ + status: number; + /** + * The headers received from the Http response. + */ + headers: HttpHeaders; + /** + * The response URL received from the Http response. + */ + url: string; +} +/** + * Read in a Blob value and return it as a base64 string + * @param blob The blob value to convert to a base64 string + */ +export declare const readBlobAsBase64: (blob: Blob) => Promise; +/** + * Build the RequestInit object based on the options passed into the initial request + * @param options The Http plugin options + * @param extra Any extra RequestInit values + */ +export declare const buildRequestInit: (options: HttpOptions, extra?: RequestInit) => RequestInit; +export declare class CapacitorHttpPluginWeb extends WebPlugin implements CapacitorHttpPlugin { + /** + * Perform an Http request given a set of options + * @param options Options to build the HTTP request + */ + request(options: HttpOptions): Promise; + /** + * Perform an Http GET request given a set of options + * @param options Options to build the HTTP request + */ + get(options: HttpOptions): Promise; + /** + * Perform an Http POST request given a set of options + * @param options Options to build the HTTP request + */ + post(options: HttpOptions): Promise; + /** + * Perform an Http PUT request given a set of options + * @param options Options to build the HTTP request + */ + put(options: HttpOptions): Promise; + /** + * Perform an Http PATCH request given a set of options + * @param options Options to build the HTTP request + */ + patch(options: HttpOptions): Promise; + /** + * Perform an Http DELETE request given a set of options + * @param options Options to build the HTTP request + */ + delete(options: HttpOptions): Promise; +} +export declare const CapacitorHttp: CapacitorHttpPlugin; +/******** END HTTP PLUGIN ********/ +/******** SYSTEM BARS PLUGIN ********/ +/** + * Available status bar styles. + */ +export declare enum SystemBarsStyle { + /** + * Light system bar content on a dark background. + * + * @since 8.0.0 + */ + Dark = "DARK", + /** + * For dark system bar content on a light background. + * + * @since 8.0.0 + */ + Light = "LIGHT", + /** + * The style is based on the device appearance or the underlying content. + * If the device is using Dark mode, the system bars content will be light. + * If the device is using Light mode, the system bars content will be dark. + * + * @since 8.0.0 + */ + Default = "DEFAULT" +} +/** + * Available status bar animations. iOS only. + */ +export type SystemBarsAnimation = 'FADE' | 'NONE'; +/** + * Available system bar types. + */ +export declare enum SystemBarType { + /** + * The top status bar on both Android and iOS. + * + * @since 8.0.0 + */ + StatusBar = "StatusBar", + /** + * The navigation bar (or gesture bar on iOS) on both Android and iOS. + * + * @since 8.0.0 + */ + NavigationBar = "NavigationBar" +} +export interface SystemBarsStyleOptions { + /** + * Style of the text and icons of the system bars. + * + * @since 8.0.0 + * @default 'DEFAULT' + * @example "DARK" + */ + style: SystemBarsStyle; + /** + * The system bar to which to apply the style. + * + * + * @since 8.0.0 + * @default null + * @example SystemBarType.StatusBar + */ + bar?: SystemBarType; +} +export interface SystemBarsVisibilityOptions { + /** + * The system bar to hide or show. + * + * @since 8.0.0 + * @default null + * @example SystemBarType.StatusBar + */ + bar?: SystemBarType; + /** + * The type of status bar animation used when showing or hiding. + * + * This option is only supported on iOS. + * + * @default 'FADE' + * + * @since 8.0.0 + */ + animation?: SystemBarsAnimation; +} +export interface SystemBarsAnimationOptions { + /** + * The type of status bar animation used when showing or hiding. + * + * This option is only supported on iOS. + * + * @default 'FADE' + * + * @since 8.0.0 + */ + animation: SystemBarsAnimation; +} +export interface SystemBarsPlugin { + /** + * Set the current style of the system bars. + * + * @since 8.0.0 + */ + setStyle(options: SystemBarsStyleOptions): Promise; + /** + * Show the system bars. + * + * @since 8.0.0 + */ + show(options?: SystemBarsVisibilityOptions): Promise; + /** + * Hide the system bars. + * + * @since 8.0.0 + */ + hide(options?: SystemBarsVisibilityOptions): Promise; + /** + * Set the animation to use when showing / hiding the status bar. + * + * Only available on iOS. + * + * @since 8.0.0 + */ + setAnimation(options: SystemBarsAnimationOptions): Promise; +} +export declare class SystemBarsPluginWeb extends WebPlugin implements SystemBarsPlugin { + setStyle(): Promise; + setAnimation(): Promise; + show(): Promise; + hide(): Promise; +} +export declare const SystemBars: SystemBarsPlugin; +export {}; +/******** END SYSTEM BARS PLUGIN ********/ diff --git a/node_modules/@capacitor/core/types/definitions-internal.d.ts b/node_modules/@capacitor/core/types/definitions-internal.d.ts new file mode 100644 index 0000000..9fd7754 --- /dev/null +++ b/node_modules/@capacitor/core/types/definitions-internal.d.ts @@ -0,0 +1,171 @@ +import type { CapacitorGlobal, PluginCallback, PluginResultData, PluginResultError } from './definitions'; +export interface PluginHeaderMethod { + readonly name: string; + readonly rtype?: 'promise' | 'callback'; +} +export interface PluginHeader { + readonly name: string; + readonly methods: readonly PluginHeaderMethod[]; +} +/** + * Has all instance properties that are available and used + * by the native layer. The "Capacitor" interface it extends + * is the public one. + */ +export interface CapacitorInstance extends CapacitorGlobal { + /** + * Internal registry for all plugins assigned to the Capacitor global. + * Legacy Capacitor referenced this property directly, but as of v3 + * it should be an internal API. Still exporting on the Capacitor + * type, but with the deprecated JSDoc tag. + */ + Plugins: { + [pluginName: string]: { + [prop: string]: any; + }; + }; + PluginHeaders?: readonly PluginHeader[]; + /** + * Gets the WebView server urls set by the native web view. Defaults + * to "" if not running from a native platform. + */ + getServerUrl: () => string; + /** + * Low-level API to send data to the native layer. + * Prefer using `nativeCallback()` or `nativePromise()` instead. + * Returns the Callback Id. + */ + toNative?: (pluginName: string, methodName: string, options: any, storedCallback?: StoredCallback) => string; + /** + * Sends data over the bridge to the native layer. + * Returns the Callback Id. + */ + nativeCallback: (pluginName: string, methodName: string, options?: O, callback?: PluginCallback) => string; + /** + * Sends data over the bridge to the native layer and + * resolves the promise when it receives the data from + * the native implementation. + */ + nativePromise: (pluginName: string, methodName: string, options?: O) => Promise; + /** + * Low-level API used by the native layers to send + * data back to the webview runtime. + */ + fromNative?: (result: PluginResult) => void; + /** + * Low-level API for backwards compatibility. + */ + createEvent?: (eventName: string, eventData?: any) => Event; + /** + * Low-level API triggered from native implementations. + */ + triggerEvent?: (eventName: string, target: string, eventData?: any) => boolean; + handleError: (err: Error) => void; + handleWindowError: (msg: string | Event, url: string, lineNo: number, columnNo: number, err: Error) => void; + /** + * Low-level API used by the native bridge to log messages. + */ + logJs: (message: string, level: 'error' | 'warn' | 'info' | 'log') => void; + logToNative: (data: MessageCallData) => void; + logFromNative: (results: PluginResult) => void; + /** + * Low-level API used by the native bridge. + */ + withPlugin?: (pluginName: string, fn: (...args: any[]) => any) => void; +} +export interface MessageCallData { + type?: 'message'; + callbackId: string; + pluginId: string; + methodName: string; + options: any; +} +export interface ErrorCallData { + type: 'js.error'; + error: { + message: string; + url: string; + line: number; + col: number; + errorObject: string; + }; +} +export type CallData = MessageCallData | ErrorCallData; +/** + * A resulting call back from the native layer. + */ +export interface PluginResult { + callbackId?: string; + methodName?: string; + data: PluginResultData; + success: boolean; + error?: PluginResultError; + pluginId?: string; + save?: boolean; +} +/** + * Callback data kept on the client + * to be called after native response + */ +export interface StoredCallback { + callback?: PluginCallback; + resolve?: (...args: any[]) => any; + reject?: (...args: any[]) => any; +} +export interface CapacitorCustomPlatformInstance { + name: string; + plugins: { + [pluginName: string]: any; + }; +} +export interface WindowCapacitor { + Capacitor?: CapacitorInstance; + CapacitorSystemBarsAndroidInterface?: any; + CapacitorCookiesAndroidInterface?: any; + CapacitorCookiesDescriptor?: PropertyDescriptor; + CapacitorHttpAndroidInterface?: any; + CapacitorWebFetch?: any; + CapacitorWebXMLHttpRequest?: any; + CapacitorCustomPlatform?: CapacitorCustomPlatformInstance; + Ionic?: { + WebView?: { + getServerBasePath?: any; + setServerBasePath?: any; + setServerAssetPath?: any; + persistServerBasePath?: any; + convertFileSrc?: any; + }; + }; + WEBVIEW_SERVER_URL?: string; + androidBridge?: { + postMessage(data: string): void; + onmessage?: (event: { + data: string; + }) => void; + }; + webkit?: { + messageHandlers?: { + bridge: { + postMessage(data: any): void; + }; + }; + }; + console?: Console; + cordova?: { + fireDocumentEvent?: (eventName: string, eventData: any) => void; + }; + dispatchEvent?: any; + document?: any; + navigator?: { + app?: { + exitApp?: () => void; + }; + }; +} +export interface CapFormDataEntry { + key: string; + value: string; + type: 'base64File' | 'string'; + contentType?: string; + fileName?: string; +} diff --git a/node_modules/@capacitor/core/types/definitions.d.ts b/node_modules/@capacitor/core/types/definitions.d.ts new file mode 100644 index 0000000..ef071b4 --- /dev/null +++ b/node_modules/@capacitor/core/types/definitions.d.ts @@ -0,0 +1,76 @@ +import type { CapacitorException } from './util'; +export interface CapacitorGlobal { + /** + * The Exception class used when generating plugin Exceptions + * from bridge calls. + */ + Exception: typeof CapacitorException; + /** + * Utility function to convert a file path into a usable src depending + * on the native WebView implementation value and environment. + */ + convertFileSrc: (filePath: string) => string; + /** + * Gets the name of the platform, such as `android`, `ios`, or `web`. + */ + getPlatform: () => string; + /** + * Boolean if the platform is native or not. `android` and `ios` + * would return `true`, otherwise `false`. + */ + isNativePlatform: () => boolean; + /** + * Used to check if a platform is registered and available. + */ + isPluginAvailable: (name: string) => boolean; + registerPlugin: RegisterPlugin; + /** + * Add a listener for a plugin event. + */ + addListener?: (pluginName: string, eventName: string, callback: PluginCallback) => PluginListenerHandle; + /** + * Remove a listener to a plugin event. + */ + removeListener?: (pluginName: string, callbackId: string, eventName: string, callback: PluginCallback) => void; + DEBUG?: boolean; + isLoggingEnabled?: boolean; +} +/** + * Register plugin implementations with Capacitor. + * + * This function will create and register an instance that contains the + * implementations of the plugin. + * + * Each plugin has multiple implementations, one per platform. Each + * implementation must adhere to a common interface to ensure client code + * behaves consistently across each platform. + * + * @param pluginName The unique CamelCase name of this plugin. + * @param implementations The map of plugin implementations. + */ +export type RegisterPlugin = (pluginName: string, implementations?: Readonly) => T; +/** + * A map of plugin implementations. + * + * Each key should be the lowercased platform name as recognized by Capacitor, + * e.g. 'android', 'ios', and 'web'. Each value must be an instance of a plugin + * implementation for the respective platform. + */ +export type PluginImplementations = { + [platform: string]: (() => Promise) | any; +}; +export interface Plugin { + addListener(eventName: string, listenerFunc: (...args: any[]) => any): Promise; + removeAllListeners(): Promise; +} +export type PermissionState = 'prompt' | 'prompt-with-rationale' | 'granted' | 'denied'; +export interface PluginListenerHandle { + remove: () => Promise; +} +export interface PluginResultData { + [key: string]: any; +} +export interface PluginResultError { + message: string; +} +export type PluginCallback = (data: PluginResultData, error?: PluginResultError) => void; diff --git a/node_modules/@capacitor/core/types/global.d.ts b/node_modules/@capacitor/core/types/global.d.ts new file mode 100644 index 0000000..bc46e04 --- /dev/null +++ b/node_modules/@capacitor/core/types/global.d.ts @@ -0,0 +1,2 @@ +export declare const Capacitor: import("./definitions").CapacitorGlobal; +export declare const registerPlugin: import("./definitions").RegisterPlugin; diff --git a/node_modules/@capacitor/core/types/index.d.ts b/node_modules/@capacitor/core/types/index.d.ts new file mode 100644 index 0000000..e2967d7 --- /dev/null +++ b/node_modules/@capacitor/core/types/index.d.ts @@ -0,0 +1,6 @@ +export type { CapacitorGlobal, PermissionState, Plugin, PluginCallback, PluginImplementations, PluginListenerHandle, PluginResultData, PluginResultError, } from './definitions'; +export { Capacitor, registerPlugin } from './global'; +export { WebPlugin, ListenerCallback } from './web-plugin'; +export { SystemBars, SystemBarType, SystemBarsStyle, SystemBarsAnimation, CapacitorCookies, CapacitorHttp, WebView, buildRequestInit, } from './core-plugins'; +export type { ClearCookieOptions, DeleteCookieOptions, SetCookieOptions, HttpHeaders, HttpOptions, HttpParams, HttpResponse, HttpResponseType, WebViewPath, WebViewPlugin, SystemBarsVisibilityOptions, SystemBarsStyleOptions, } from './core-plugins'; +export { CapacitorException, ExceptionCode } from './util'; diff --git a/node_modules/@capacitor/core/types/runtime.d.ts b/node_modules/@capacitor/core/types/runtime.d.ts new file mode 100644 index 0000000..969ee48 --- /dev/null +++ b/node_modules/@capacitor/core/types/runtime.d.ts @@ -0,0 +1,9 @@ +import type { CapacitorGlobal } from './definitions'; +import type { CapacitorInstance, WindowCapacitor } from './definitions-internal'; +export interface RegisteredPlugin { + readonly name: string; + readonly proxy: any; + readonly platforms: ReadonlySet; +} +export declare const createCapacitor: (win: WindowCapacitor) => CapacitorInstance; +export declare const initCapacitorGlobal: (win: any) => CapacitorGlobal; diff --git a/node_modules/@capacitor/core/types/util.d.ts b/node_modules/@capacitor/core/types/util.d.ts new file mode 100644 index 0000000..5b9647c --- /dev/null +++ b/node_modules/@capacitor/core/types/util.d.ts @@ -0,0 +1,28 @@ +import type { WindowCapacitor } from './definitions-internal'; +export declare enum ExceptionCode { + /** + * API is not implemented. + * + * This usually means the API can't be used because it is not implemented for + * the current platform. + */ + Unimplemented = "UNIMPLEMENTED", + /** + * API is not available. + * + * This means the API can't be used right now because: + * - it is currently missing a prerequisite, such as network connectivity + * - it requires a particular platform or browser version + */ + Unavailable = "UNAVAILABLE" +} +export interface ExceptionData { + [key: string]: any; +} +export declare class CapacitorException extends Error { + readonly message: string; + readonly code?: ExceptionCode; + readonly data?: ExceptionData; + constructor(message: string, code?: ExceptionCode, data?: ExceptionData); +} +export declare const getPlatformId: (win: WindowCapacitor) => 'android' | 'ios' | 'web'; diff --git a/node_modules/@capacitor/core/types/web-plugin.d.ts b/node_modules/@capacitor/core/types/web-plugin.d.ts new file mode 100644 index 0000000..d822b45 --- /dev/null +++ b/node_modules/@capacitor/core/types/web-plugin.d.ts @@ -0,0 +1,34 @@ +import type { PluginListenerHandle, Plugin } from './definitions'; +import type { CapacitorException } from './util'; +/** + * Base class web plugins should extend. + */ +export declare class WebPlugin implements Plugin { + protected listeners: { + [eventName: string]: ListenerCallback[]; + }; + protected retainedEventArguments: { + [eventName: string]: any[]; + }; + protected windowListeners: { + [eventName: string]: WindowListenerHandle; + }; + addListener(eventName: string, listenerFunc: ListenerCallback): Promise; + removeAllListeners(): Promise; + protected notifyListeners(eventName: string, data: any, retainUntilConsumed?: boolean): void; + protected hasListeners(eventName: string): boolean; + protected registerWindowListener(windowEventName: string, pluginEventName: string): void; + protected unimplemented(msg?: string): CapacitorException; + protected unavailable(msg?: string): CapacitorException; + private removeListener; + private addWindowListener; + private removeWindowListener; + private sendRetainedArgumentsForEvent; +} +export type ListenerCallback = (err: any, ...args: any[]) => void; +export interface WindowListenerHandle { + registered: boolean; + windowEventName: string; + pluginEventName: string; + handler: (event: any) => void; +} diff --git a/node_modules/@capacitor/filesystem/CapacitorFilesystem.podspec b/node_modules/@capacitor/filesystem/CapacitorFilesystem.podspec new file mode 100644 index 0000000..57bda93 --- /dev/null +++ b/node_modules/@capacitor/filesystem/CapacitorFilesystem.podspec @@ -0,0 +1,18 @@ +require 'json' + +package = JSON.parse(File.read(File.join(__dir__, 'package.json'))) + +Pod::Spec.new do |s| + s.name = 'CapacitorFilesystem' + s.version = package['version'] + s.summary = package['description'] + s.license = package['license'] + s.homepage = package['repository']['url'] + s.author = package['author'] + s.source = { :git => package['repository']['url'], :tag => "v#{s.version}" } + s.source_files = 'ios/Sources/**/*.{swift,h,m,c,cc,mm,cpp}' + s.ios.deployment_target = '15.0' + s.dependency 'Capacitor' + s.dependency 'IONFilesystemLib', spec='~> 1.1.1' + s.swift_version = '5.1' +end diff --git a/node_modules/@capacitor/filesystem/LICENSE b/node_modules/@capacitor/filesystem/LICENSE new file mode 100644 index 0000000..774efa0 --- /dev/null +++ b/node_modules/@capacitor/filesystem/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2025 Ionic + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/node_modules/@capacitor/filesystem/Package.swift b/node_modules/@capacitor/filesystem/Package.swift new file mode 100644 index 0000000..e0e9dc2 --- /dev/null +++ b/node_modules/@capacitor/filesystem/Package.swift @@ -0,0 +1,30 @@ +// swift-tools-version: 5.9 +import PackageDescription + +let package = Package( + name: "CapacitorFilesystem", + platforms: [.iOS(.v15)], + products: [ + .library( + name: "CapacitorFilesystem", + targets: ["FilesystemPlugin"]) + ], + dependencies: [ + .package(url: "https://github.com/ionic-team/capacitor-swift-pm.git", from: "8.0.0"), + .package(url: "https://github.com/ionic-team/ion-ios-filesystem.git", from: "1.1.1") + ], + targets: [ + .target( + name: "FilesystemPlugin", + dependencies: [ + .product(name: "Capacitor", package: "capacitor-swift-pm"), + .product(name: "Cordova", package: "capacitor-swift-pm"), + .product(name: "IONFilesystemLib", package: "ion-ios-filesystem") + ], + path: "ios/Sources/FilesystemPlugin"), + .testTarget( + name: "FilesystemPluginTests", + dependencies: ["FilesystemPlugin"], + path: "ios/Tests/FilesystemPluginTests") + ] +) diff --git a/node_modules/@capacitor/filesystem/README.md b/node_modules/@capacitor/filesystem/README.md new file mode 100644 index 0000000..90c91df --- /dev/null +++ b/node_modules/@capacitor/filesystem/README.md @@ -0,0 +1,808 @@ +# @capacitor/filesystem + +The Filesystem API provides a NodeJS-like API for working with files on the device. + +## Install + +```bash +npm install @capacitor/filesystem +npx cap sync +``` + +## Apple Privacy Manifest Requirements + +Apple mandates that app developers now specify approved reasons for API usage to enhance user privacy. By May 1st, 2024, it's required to include these reasons when submitting apps to the App Store Connect. + +When using this specific plugin in your app, you must create a `PrivacyInfo.xcprivacy` file in `/ios/App` or use the VS Code Extension to generate it, specifying the usage reasons. + +For detailed steps on how to do this, please see the [Capacitor Docs](https://capacitorjs.com/docs/ios/privacy-manifest). + +**For this plugin, the required dictionary key is [NSPrivacyAccessedAPICategoryFileTimestamp](https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_use_of_required_reason_api#4278393) and the recommended reason is [C617.1](https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_use_of_required_reason_api#4278393).** + +### Example PrivacyInfo.xcprivacy + +```xml + + + + + NSPrivacyAccessedAPITypes + + + + NSPrivacyAccessedAPIType + NSPrivacyAccessedAPICategoryFileTimestamp + NSPrivacyAccessedAPITypeReasons + + C617.1 + + + + + +``` + +## Migrating from downloadFile to File Transfer plugin + +As of version 7.1.0, the `downloadFile` functionality in the Filesystem plugin has been deprecated in favor of the new [@capacitor/file-transfer](https://capacitorjs.com/docs/apis/file-transfer) plugin. + +### Installing the File Transfer plugin + +```bash +npm install @capacitor/file-transfer +npx cap sync +``` + +### Migration example + +Before (using Filesystem plugin): + +```typescript +import { Filesystem, Directory } from '@capacitor/filesystem'; + +await Filesystem.downloadFile({ + url: 'https://example.com/file.pdf', + path: 'downloaded-file.pdf', + directory: Directory.Documents, + progress: true +}); + +// Progress events +Filesystem.addListener('progress', (progress) => { + console.log(`Downloaded ${progress.bytes} of ${progress.contentLength}`); +}); +``` + +After (using File Transfer plugin): + +```typescript +import { FileTransfer } from '@capacitor/file-transfer'; +import { Filesystem, Directory } from '@capacitor/filesystem'; + +// First get the full file path using Filesystem +const fileInfo = await Filesystem.getUri({ + directory: Directory.Documents, + path: 'downloaded-file.pdf' +}); + +// Then use the FileTransfer plugin to download +await FileTransfer.downloadFile({ + url: 'https://example.com/file.pdf', + path: fileInfo.uri, + progress: true +}); + +// Progress events +FileTransfer.addListener('progress', (progress) => { + console.log(`Downloaded ${progress.bytes} of ${progress.contentLength}`); +}); +``` + +The File Transfer plugin offers improved reliability, better error handling with specific error codes, and also adds upload functionality. + +## iOS + +To have files appear in the Files app, you must also set the following keys to `YES` in `Info.plist`: + +- `UIFileSharingEnabled` (`Application supports iTunes file sharing`) +- `LSSupportsOpeningDocumentsInPlace` (`Supports opening documents in place`) + +Read about [Configuring iOS](https://capacitorjs.com/docs/ios/configuration) for help. + +## Android + +If using `Directory.Documents` or `Directory.ExternalStorage`, in Android 10 and older, this API requires the following permissions be added to your `AndroidManifest.xml`: + +```xml + + +``` + +Read about [Setting Permissions](https://capacitorjs.com/docs/android/configuration#setting-permissions) in the [Android Guide](https://capacitorjs.com/docs/android) for more information on setting Android permissions. + +Note that `Directory.ExternalStorage` is only available on Android 9 or older and `Directory.Documents` only allows to access the files/folders created by your app on Android on Android 11 and newer. + +Working with large files may require you to add `android:largeHeap="true"` to the `` tag in `AndroidManifest.xml`. + +## Understanding Directories and Files + +iOS and Android have additional layers of separation between files, such as special directories that are backed up to the Cloud, or ones for storing Documents. The Filesystem API offers a simple way to scope each operation to a specific special directory on the device. + +Additionally, the Filesystem API supports using full `file://` paths, or reading `content://` files on Android. Simply leave out the `directory` param to use a full file path. + +## Example + +```typescript +import { Filesystem, Directory, Encoding } from "@capacitor/filesystem"; + +const writeSecretFile = async () => { + await Filesystem.writeFile({ + path: "secrets/text.txt", + data: "This is a test", + directory: Directory.Documents, + encoding: Encoding.UTF8, + }); +}; + +const readSecretFile = async () => { + const contents = await Filesystem.readFile({ + path: "secrets/text.txt", + directory: Directory.Documents, + encoding: Encoding.UTF8, + }); + + console.log("secrets:", contents); +}; + +const deleteSecretFile = async () => { + await Filesystem.deleteFile({ + path: "secrets/text.txt", + directory: Directory.Documents, + }); +}; + +const readFilePath = async () => { + // Here's an example of reading a file with a full file path. Use this to + // read binary data (base64 encoded) from plugins that return File URIs, such as + // the Camera. + const contents = await Filesystem.readFile({ + path: "file:///var/mobile/Containers/Data/Application/22A433FD-D82D-4989-8BE6-9FC49DEA20BB/Documents/text.txt", + }); + + console.log("data:", contents); +}; + +const appendBinaryData = async () => { + // Here's an example of appending binary data, which should be sent to the plugin + // as base64 encoded, and without providing any `Encoding`. + await Filesystem.appendFile({ + path: "file.bin", + directory: Directory.Cache, + data: "VGhpcyBpcyBtZWFudCB0byByZXByZXNlbnQgYSBCaW5hcnkgRGF0YSBleGFtcGxlIGVuY29kZWQgaW4gQmFzZTY0Lg==" + }); +}; +``` + +## API + + + +* [`checkPermissions()`](#checkpermissions) +* [`requestPermissions()`](#requestpermissions) +* [`readFile(...)`](#readfile) +* [`readFileInChunks(...)`](#readfileinchunks) +* [`writeFile(...)`](#writefile) +* [`appendFile(...)`](#appendfile) +* [`deleteFile(...)`](#deletefile) +* [`mkdir(...)`](#mkdir) +* [`rmdir(...)`](#rmdir) +* [`readdir(...)`](#readdir) +* [`getUri(...)`](#geturi) +* [`stat(...)`](#stat) +* [`rename(...)`](#rename) +* [`copy(...)`](#copy) +* [`downloadFile(...)`](#downloadfile) +* [`addListener('progress', ...)`](#addlistenerprogress-) +* [`removeAllListeners()`](#removealllisteners) +* [Interfaces](#interfaces) +* [Type Aliases](#type-aliases) +* [Enums](#enums) + + + +For list of existing error codes, see [Errors](#errors). + + + + +### checkPermissions() + +```typescript +checkPermissions() => Promise +``` + +Check read/write permissions. +Required on Android, only when using `Directory.Documents` or +`Directory.ExternalStorage`. + +**Returns:** Promise<PermissionStatus> + +**Since:** 1.0.0 + +-------------------- + + +### requestPermissions() + +```typescript +requestPermissions() => Promise +``` + +Request read/write permissions. +Required on Android, only when using `Directory.Documents` or +`Directory.ExternalStorage`. + +**Returns:** Promise<PermissionStatus> + +**Since:** 1.0.0 + +-------------------- + + +### readFile(...) + +```typescript +readFile(options: ReadFileOptions) => Promise +``` + +Read a file from disk + +| Param | Type | +| ------------- | ----------------------------------------------------------- | +| **`options`** | ReadFileOptions | + +**Returns:** Promise<ReadFileResult> + +**Since:** 1.0.0 + +-------------------- + + +### readFileInChunks(...) + +```typescript +readFileInChunks(options: ReadFileInChunksOptions, callback: ReadFileInChunksCallback) => Promise +``` + +Read a file from disk, in chunks. +Native only (not available in web). +Use the callback to receive each read chunk. +If empty chunk is returned, it means file has been completely read. + +| Param | Type | +| -------------- | ----------------------------------------------------------------------------- | +| **`options`** | ReadFileInChunksOptions | +| **`callback`** | ReadFileInChunksCallback | + +**Returns:** Promise<string> + +**Since:** 7.1.0 + +-------------------- + + +### writeFile(...) + +```typescript +writeFile(options: WriteFileOptions) => Promise +``` + +Write a file to disk in the specified location on device + +| Param | Type | +| ------------- | ------------------------------------------------------------- | +| **`options`** | WriteFileOptions | + +**Returns:** Promise<WriteFileResult> + +**Since:** 1.0.0 + +-------------------- + + +### appendFile(...) + +```typescript +appendFile(options: AppendFileOptions) => Promise +``` + +Append to a file on disk in the specified location on device + +| Param | Type | +| ------------- | --------------------------------------------------------------- | +| **`options`** | AppendFileOptions | + +**Since:** 1.0.0 + +-------------------- + + +### deleteFile(...) + +```typescript +deleteFile(options: DeleteFileOptions) => Promise +``` + +Delete a file from disk + +| Param | Type | +| ------------- | --------------------------------------------------------------- | +| **`options`** | DeleteFileOptions | + +**Since:** 1.0.0 + +-------------------- + + +### mkdir(...) + +```typescript +mkdir(options: MkdirOptions) => Promise +``` + +Create a directory. + +| Param | Type | +| ------------- | ----------------------------------------------------- | +| **`options`** | MkdirOptions | + +**Since:** 1.0.0 + +-------------------- + + +### rmdir(...) + +```typescript +rmdir(options: RmdirOptions) => Promise +``` + +Remove a directory + +| Param | Type | +| ------------- | ----------------------------------------------------- | +| **`options`** | RmdirOptions | + +**Since:** 1.0.0 + +-------------------- + + +### readdir(...) + +```typescript +readdir(options: ReaddirOptions) => Promise +``` + +Return a list of files from the directory (not recursive) + +| Param | Type | +| ------------- | --------------------------------------------------------- | +| **`options`** | ReaddirOptions | + +**Returns:** Promise<ReaddirResult> + +**Since:** 1.0.0 + +-------------------- + + +### getUri(...) + +```typescript +getUri(options: GetUriOptions) => Promise +``` + +Return full File URI for a path and directory + +| Param | Type | +| ------------- | ------------------------------------------------------- | +| **`options`** | GetUriOptions | + +**Returns:** Promise<GetUriResult> + +**Since:** 1.0.0 + +-------------------- + + +### stat(...) + +```typescript +stat(options: StatOptions) => Promise +``` + +Return data about a file + +| Param | Type | +| ------------- | --------------------------------------------------- | +| **`options`** | StatOptions | + +**Returns:** Promise<FileInfo> + +**Since:** 1.0.0 + +-------------------- + + +### rename(...) + +```typescript +rename(options: RenameOptions) => Promise +``` + +Rename a file or directory + +| Param | Type | +| ------------- | --------------------------------------------------- | +| **`options`** | CopyOptions | + +**Since:** 1.0.0 + +-------------------- + + +### copy(...) + +```typescript +copy(options: CopyOptions) => Promise +``` + +Copy a file or directory + +| Param | Type | +| ------------- | --------------------------------------------------- | +| **`options`** | CopyOptions | + +**Returns:** Promise<CopyResult> + +**Since:** 1.0.0 + +-------------------- + + +### downloadFile(...) + +```typescript +downloadFile(options: DownloadFileOptions) => Promise +``` + +Perform a http request to a server and download the file to the specified destination. + +This method has been deprecated since version 7.1.0. +We recommend using the @capacitor/file-transfer plugin instead, in conjunction with this plugin. + +| Param | Type | +| ------------- | ------------------------------------------------------------------- | +| **`options`** | DownloadFileOptions | + +**Returns:** Promise<DownloadFileResult> + +**Since:** 5.1.0 + +-------------------- + + +### addListener('progress', ...) + +```typescript +addListener(eventName: 'progress', listenerFunc: ProgressListener) => Promise +``` + +Add a listener to file download progress events. + +This method has been deprecated since version 7.1.0. +We recommend using the @capacitor/file-transfer plugin instead, in conjunction with this plugin. + +| Param | Type | +| ------------------ | ------------------------------------------------------------- | +| **`eventName`** | 'progress' | +| **`listenerFunc`** | ProgressListener | + +**Returns:** Promise<PluginListenerHandle> + +**Since:** 5.1.0 + +-------------------- + + +### removeAllListeners() + +```typescript +removeAllListeners() => Promise +``` + +Remove all listeners for this plugin. + +This method has been deprecated since version 7.1.0. +We recommend using the @capacitor/file-transfer plugin instead, in conjunction with this plugin. + +**Since:** 5.2.0 + +-------------------- + + +### Interfaces + + +#### PermissionStatus + +| Prop | Type | +| ------------------- | ----------------------------------------------------------- | +| **`publicStorage`** | PermissionState | + + +#### ReadFileResult + +| Prop | Type | Description | Since | +| ---------- | --------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- | ----- | +| **`data`** | string \| Blob | The representation of the data contained in the file Note: Blob is only available on Web. On native, the data is returned as a string. | 1.0.0 | + + +#### ReadFileOptions + +| Prop | Type | Description | Default | Since | +| --------------- | ----------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | --------------- | ----- | +| **`path`** | string | The path of the file to read | | 1.0.0 | +| **`directory`** | Directory | The `Directory` to read the file from | | 1.0.0 | +| **`encoding`** | Encoding | The encoding to read the file in, if not provided, data is read as binary and returned as base64 encoded. Pass Encoding.UTF8 to read data as string | | 1.0.0 | +| **`offset`** | number | The offset to start reading the file from, in bytes. Native only (not available in web). Can be used in conjunction with length to partially read files. | 0 | 8.1.0 | +| **`length`** | number | The length of data to read, in bytes. Any non-positive value means to read to the end of the file. Native only (not available in web). Can be used in conjunction with offset to partially read files. | -1 | 8.1.0 | + + +#### ReadFileInChunksOptions + +| Prop | Type | Description | Since | +| --------------- | ------------------- | ---------------------------- | ----- | +| **`chunkSize`** | number | Size of the chunks in bytes. | 7.1.0 | + + +#### WriteFileResult + +| Prop | Type | Description | Since | +| --------- | ------------------- | --------------------------------------- | ----- | +| **`uri`** | string | The uri where the file was written into | 1.0.0 | + + +#### WriteFileOptions + +| Prop | Type | Description | Default | Since | +| --------------- | ----------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------ | ----- | +| **`path`** | string | The path of the file to write | | 1.0.0 | +| **`data`** | string \| Blob | The data to write Note: Blob data is only supported on Web. | | 1.0.0 | +| **`directory`** | Directory | The `Directory` to store the file in | | 1.0.0 | +| **`encoding`** | Encoding | The encoding to write the file in. If not provided, binary data will be written. For this, you must provide data as base64 encoded, so that the plugin can decode it before writing to disk. If you do not provide encoding and use non-base64 data, an error will be thrown. Pass Encoding.UTF8 to write data as string | | 1.0.0 | +| **`recursive`** | boolean | Whether to create any missing parent directories. | false | 1.0.0 | + + +#### AppendFileOptions + +| Prop | Type | Description | Since | +| --------------- | ----------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----- | +| **`path`** | string | The path of the file to append | 1.0.0 | +| **`data`** | string | The data to append | 1.0.0 | +| **`directory`** | Directory | The `Directory` to store the file in | 1.0.0 | +| **`encoding`** | Encoding | The encoding to append to the file. If not provided, binary data will be appended. For this, you must provide data as base64 encoded, so that the plugin can decode it before writing to disk. If you do not provide encoding and use non-base64 data, an error will be thrown. Pass Encoding.UTF8 to write data as string | 1.0.0 | + + +#### DeleteFileOptions + +| Prop | Type | Description | Since | +| --------------- | ----------------------------------------------- | ---------------------------------------------------------------- | ----- | +| **`path`** | string | The path of the file to delete | 1.0.0 | +| **`directory`** | Directory | The `Directory` to delete the file from | 1.0.0 | + + +#### MkdirOptions + +| Prop | Type | Description | Default | Since | +| --------------- | ----------------------------------------------- | --------------------------------------------------------------------- | ------------------ | ----- | +| **`path`** | string | The path of the new directory | | 1.0.0 | +| **`directory`** | Directory | The `Directory` to make the new directory in | | 1.0.0 | +| **`recursive`** | boolean | Whether to create any missing parent directories as well. | false | 1.0.0 | + + +#### RmdirOptions + +| Prop | Type | Description | Default | Since | +| --------------- | ----------------------------------------------- | --------------------------------------------------------------------- | ------------------ | ----- | +| **`path`** | string | The path of the directory to remove | | 1.0.0 | +| **`directory`** | Directory | The `Directory` to remove the directory from | | 1.0.0 | +| **`recursive`** | boolean | Whether to recursively remove the contents of the directory | false | 1.0.0 | + + +#### ReaddirResult + +| Prop | Type | Description | Since | +| ----------- | ----------------------- | -------------------------------------------------- | ----- | +| **`files`** | FileInfo[] | List of files and directories inside the directory | 1.0.0 | + + +#### FileInfo + +| Prop | Type | Description | Since | +| ----------- | ---------------------------------- | ------------------------------------------------------------------------------------ | ----- | +| **`name`** | string | Name of the file or directory. | 7.1.0 | +| **`type`** | 'file' \| 'directory' | Type of the file. | 4.0.0 | +| **`size`** | number | Size of the file in bytes. | 4.0.0 | +| **`ctime`** | number | Time of creation in milliseconds. It's not available on Android 7 and older devices. | 7.1.0 | +| **`mtime`** | number | Time of last modification in milliseconds. | 7.1.0 | +| **`uri`** | string | The uri of the file. | 4.0.0 | + + +#### ReaddirOptions + +| Prop | Type | Description | Since | +| --------------- | ----------------------------------------------- | ----------------------------------------------------------- | ----- | +| **`path`** | string | The path of the directory to read | 1.0.0 | +| **`directory`** | Directory | The `Directory` to list files from | 1.0.0 | + + +#### GetUriResult + +| Prop | Type | Description | Since | +| --------- | ------------------- | ------------------- | ----- | +| **`uri`** | string | The uri of the file | 1.0.0 | + + +#### GetUriOptions + +| Prop | Type | Description | Since | +| --------------- | ----------------------------------------------- | -------------------------------------------------------------- | ----- | +| **`path`** | string | The path of the file to get the URI for | 1.0.0 | +| **`directory`** | Directory | The `Directory` to get the file under | 1.0.0 | + + +#### StatOptions + +| Prop | Type | Description | Since | +| --------------- | ----------------------------------------------- | -------------------------------------------------------------- | ----- | +| **`path`** | string | The path of the file to get data about | 1.0.0 | +| **`directory`** | Directory | The `Directory` to get the file under | 1.0.0 | + + +#### CopyOptions + +| Prop | Type | Description | Since | +| ----------------- | ----------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ | ----- | +| **`from`** | string | The existing file or directory | 1.0.0 | +| **`to`** | string | The destination file or directory | 1.0.0 | +| **`directory`** | Directory | The `Directory` containing the existing file or directory | 1.0.0 | +| **`toDirectory`** | Directory | The `Directory` containing the destination file or directory. If not supplied will use the 'directory' parameter as the destination | 1.0.0 | + + +#### CopyResult + +| Prop | Type | Description | Since | +| --------- | ------------------- | -------------------------------------- | ----- | +| **`uri`** | string | The uri where the file was copied into | 4.0.0 | + + +#### DownloadFileResult + +| Prop | Type | Description | Since | +| ---------- | ------------------- | -------------------------------------------------------------------- | ----- | +| **`path`** | string | The path the file was downloaded to. | 5.1.0 | +| **`blob`** | Blob | The blob data of the downloaded file. This is only available on web. | 5.1.0 | + + +#### DownloadFileOptions + +| Prop | Type | Description | Default | Since | +| --------------- | ----------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------ | ----- | +| **`path`** | string | The path the downloaded file should be moved to. | | 5.1.0 | +| **`directory`** | Directory | The directory to write the file to. If this option is used, filePath can be a relative path rather than absolute. The default is the `DATA` directory. | | 5.1.0 | +| **`progress`** | boolean | An optional listener function to receive downloaded progress events. If this option is used, progress event should be dispatched on every chunk received. Chunks are throttled to every 100ms on Android/iOS to avoid slowdowns. | | 5.1.0 | +| **`recursive`** | boolean | Whether to create any missing parent directories. | false | 5.1.2 | + + +#### PluginListenerHandle + +| Prop | Type | +| ------------ | ----------------------------------------- | +| **`remove`** | () => Promise<void> | + + +#### ProgressStatus + +| Prop | Type | Description | Since | +| ------------------- | ------------------- | ---------------------------------------------------- | ----- | +| **`url`** | string | The url of the file being downloaded. | 5.1.0 | +| **`bytes`** | number | The number of bytes downloaded so far. | 5.1.0 | +| **`contentLength`** | number | The total number of bytes to download for this file. | 5.1.0 | + + +### Type Aliases + + +#### PermissionState + +'prompt' | 'prompt-with-rationale' | 'granted' | 'denied' + + +#### ReadFileInChunksCallback + +Callback for receiving chunks read from a file, or error if something went wrong. + +(chunkRead: ReadFileResult | null, err?: any): void + + +#### CallbackID + +string + + +#### StatResult + +FileInfo + + +#### RenameOptions + +CopyOptions + + +#### ProgressListener + +A listener function that receives progress events. + +(progress: ProgressStatus): void + + +### Enums + + +#### Directory + +| Members | Value | Description | Since | +| --------------------- | ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ----- | +| **`Documents`** | 'DOCUMENTS' | The Documents directory. On iOS it's the app's documents directory. Use this directory to store user-generated content. On Android it's the Public Documents folder, so it's accessible from other apps. It's not accessible on Android 10 unless the app enables legacy External Storage by adding `android:requestLegacyExternalStorage="true"` in the `application` tag in the `AndroidManifest.xml`. On Android 11 or newer the app can only access the files/folders the app created. | 1.0.0 | +| **`Data`** | 'DATA' | The Data directory. On iOS it will use the Documents directory. On Android it's the directory holding application files. Files will be deleted when the application is uninstalled. | 1.0.0 | +| **`Library`** | 'LIBRARY' | The Library directory. On iOS it will use the Library directory. On Android it's the directory holding application files. Files will be deleted when the application is uninstalled. | 1.1.0 | +| **`Cache`** | 'CACHE' | The Cache directory. Can be deleted in cases of low memory, so use this directory to write app-specific files. that your app can re-create easily. | 1.0.0 | +| **`External`** | 'EXTERNAL' | The external directory. On iOS it will use the Documents directory. On Android it's the directory on the primary shared/external storage device where the application can place persistent files it owns. These files are internal to the applications, and not typically visible to the user as media. Files will be deleted when the application is uninstalled. | 1.0.0 | +| **`ExternalStorage`** | 'EXTERNAL_STORAGE' | The external storage directory. On iOS it will use the Documents directory. On Android it's the primary shared/external storage directory. It's not accessible on Android 10 unless the app enables legacy External Storage by adding `android:requestLegacyExternalStorage="true"` in the `application` tag in the `AndroidManifest.xml`. It's not accessible on Android 11 or newer. | 1.0.0 | +| **`ExternalCache`** | 'EXTERNAL_CACHE' | The external cache directory. On iOS it will use the Documents directory. On Android it's the primary shared/external cache. | 7.1.0 | +| **`LibraryNoCloud`** | 'LIBRARY_NO_CLOUD' | The Library directory without cloud backup. Used in iOS. On Android it's the directory holding application files. | 7.1.0 | +| **`Temporary`** | 'TEMPORARY' | A temporary directory for iOS. On Android it's the directory holding the application cache. | 7.1.0 | + + +#### Encoding + +| Members | Value | Description | Since | +| ----------- | -------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- | ----- | +| **`UTF8`** | 'utf8' | Eight-bit UCS Transformation Format | 1.0.0 | +| **`ASCII`** | 'ascii' | Seven-bit ASCII, a.k.a. ISO646-US, a.k.a. the Basic Latin block of the Unicode character set This encoding is only supported on Android. | 1.0.0 | +| **`UTF16`** | 'utf16' | Sixteen-bit UCS Transformation Format, byte order identified by an optional byte-order mark This encoding is only supported on Android. | 1.0.0 | + + + +### Errors + +Since version 7.1.0, the plugin returns specific errors with specific codes on native Android and iOS. Web does not follow this standard for errors. + +The following table list all the plugin errors: + +| Error code | Platform(s) | Message | +|-------------------|------------------|------------------------------| +| OS-PLUG-FILE-0004 | iOS | Cordova / Capacitor bridge isn’t initialized. | +| OS-PLUG-FILE-0005 | Android, iOS | The method input parameters aren’t valid. | +| OS-PLUG-FILE-0006 | Android, iOS | Invalid path was provided. | +| OS-PLUG-FILE-0007 | Android | Unable to perform file operation, user denied permission request. | +| OS-PLUG-FILE-0008 | Android, iOS | Operation failed because file does not exist. | +| OS-PLUG-FILE-0009 | Android | Operation not supported for provided input. | +| OS-PLUG-FILE-0010 | Android, iOS | Directory already exists, cannot be overwritten. | +| OS-PLUG-FILE-0011 | Android, iOS | Missing parent directory – possibly recursive=false was passed or parent directory creation failed. | +| OS-PLUG-FILE-0012 | Android, iOS | Cannot delete directory with children; received recursive=false but directory has contents. | +| OS-PLUG-FILE-0013 | Android, iOS | The operation failed with an error. | + diff --git a/node_modules/@capacitor/filesystem/android/build.gradle b/node_modules/@capacitor/filesystem/android/build.gradle new file mode 100644 index 0000000..915b0dd --- /dev/null +++ b/node_modules/@capacitor/filesystem/android/build.gradle @@ -0,0 +1,91 @@ +ext { + capacitorVersion = System.getenv('CAPACITOR_VERSION') + junitVersion = project.hasProperty('junitVersion') ? rootProject.ext.junitVersion : '4.13.2' + androidxAppCompatVersion = project.hasProperty('androidxAppCompatVersion') ? rootProject.ext.androidxAppCompatVersion : '1.7.1' + androidxJunitVersion = project.hasProperty('androidxJunitVersion') ? rootProject.ext.androidxJunitVersion : '1.3.0' + androidxEspressoCoreVersion = project.hasProperty('androidxEspressoCoreVersion') ? rootProject.ext.androidxEspressoCoreVersion : '3.7.0' + kotlinxCoroutinesVersion = project.hasProperty('kotlinxCoroutinesVersion') ? rootProject.ext.kotlinxCoroutinesVersion : '1.10.2' +} + +buildscript { + ext.kotlin_version = project.hasProperty("kotlin_version") ? rootProject.ext.kotlin_version : '2.2.20' + repositories { + google() + mavenCentral() + maven { + url = "https://plugins.gradle.org/m2/" + } + } + dependencies { + classpath 'com.android.tools.build:gradle:8.13.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + if (System.getenv("CAP_PLUGIN_PUBLISH") == "true") { + classpath 'io.github.gradle-nexus:publish-plugin:1.3.0' + } + } +} + +apply plugin: 'com.android.library' +apply plugin: 'kotlin-android' +if (System.getenv("CAP_PLUGIN_PUBLISH") == "true") { + apply plugin: 'io.github.gradle-nexus.publish-plugin' + apply from: file('../scripts/android/publish-root.gradle') + apply from: file('../scripts/android/publish-module.gradle') +} + +android { + namespace = "com.capacitorjs.plugins.filesystem" + compileSdk = project.hasProperty('compileSdkVersion') ? rootProject.ext.compileSdkVersion : 36 + defaultConfig { + minSdkVersion project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : 24 + targetSdkVersion project.hasProperty('targetSdkVersion') ? rootProject.ext.targetSdkVersion : 36 + versionCode 1 + versionName "1.0" + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } + lintOptions { + abortOnError = false + } + compileOptions { + sourceCompatibility JavaVersion.VERSION_21 + targetCompatibility JavaVersion.VERSION_21 + } + publishing { + singleVariant("release") + } +} + +kotlin { + jvmToolchain(21) +} + +repositories { + google() + mavenCentral() +} + + +dependencies { + implementation fileTree(dir: 'libs', include: ['*.jar']) + + if (System.getenv("CAP_PLUGIN_PUBLISH") == "true") { + implementation "com.capacitorjs:core:$capacitorVersion" + } else { + implementation project(':capacitor-android') + } + + implementation "io.ionic.libs:ionfilesystem-android:1.1.0" + implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion" + + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlinxCoroutinesVersion") + + testImplementation "junit:junit:$junitVersion" + androidTestImplementation "androidx.test.ext:junit:$androidxJunitVersion" + androidTestImplementation "androidx.test.espresso:espresso-core:$androidxEspressoCoreVersion" +} diff --git a/node_modules/@capacitor/filesystem/android/src/main/AndroidManifest.xml b/node_modules/@capacitor/filesystem/android/src/main/AndroidManifest.xml new file mode 100644 index 0000000..a2f47b6 --- /dev/null +++ b/node_modules/@capacitor/filesystem/android/src/main/AndroidManifest.xml @@ -0,0 +1,2 @@ + + diff --git a/node_modules/@capacitor/filesystem/android/src/main/kotlin/com/capacitorjs/plugins/filesystem/FilesystemErrors.kt b/node_modules/@capacitor/filesystem/android/src/main/kotlin/com/capacitorjs/plugins/filesystem/FilesystemErrors.kt new file mode 100644 index 0000000..6eff078 --- /dev/null +++ b/node_modules/@capacitor/filesystem/android/src/main/kotlin/com/capacitorjs/plugins/filesystem/FilesystemErrors.kt @@ -0,0 +1,103 @@ +package com.capacitorjs.plugins.filesystem + +import io.ionic.libs.ionfilesystemlib.model.IONFILEExceptions + +object FilesystemErrors { + private fun formatErrorCode(number: Int): String { + return "OS-PLUG-FILE-" + number.toString().padStart(4, '0') + } + + data class ErrorInfo( + val code: String, + val message: String + ) + + fun invalidInputMethod(methodName: String): ErrorInfo = ErrorInfo( + code = formatErrorCode(5), + message = "The '$methodName' input parameters aren't valid." + ) + + fun invalidPath(path: String): ErrorInfo = ErrorInfo( + code = formatErrorCode(6), + message = "Invalid ${if (path.isNotBlank()) "'$path' " else ""}path." + ) + + val filePermissionsDenied: ErrorInfo = ErrorInfo( + code = formatErrorCode(7), + message = "Unable to do file operation, user denied permission request." + ) + + fun doesNotExist(methodName: String, path: String): ErrorInfo = ErrorInfo( + code = formatErrorCode(8), + message = "'$methodName' failed because file ${if (path.isNotBlank()) "at '$path' " else ""}does not exist." + ) + + fun notAllowed(methodName: String, notAllowedFor: String): ErrorInfo = ErrorInfo( + code = formatErrorCode(9), + message = "'$methodName' not supported for $notAllowedFor." + ) + + fun directoryCreationAlreadyExists(path: String): ErrorInfo = ErrorInfo( + code = formatErrorCode(10), + message = "Directory ${if (path.isNotBlank()) "at '$path' " else ""}already exists, cannot be overwritten." + ) + + val missingParentDirectories: ErrorInfo = ErrorInfo( + code = formatErrorCode(11), + message = "Missing parent directory – possibly recursive=false was passed or parent directory creation failed." + ) + + val cannotDeleteChildren: ErrorInfo = ErrorInfo( + code = formatErrorCode(12), + message = "Cannot delete directory with children; received recursive=false but directory has contents." + ) + + fun operationFailed(methodName: String, errorMessage: String): ErrorInfo = ErrorInfo( + code = formatErrorCode(13), + message = "'$methodName' failed with${if (errorMessage.isNotBlank()) ": $errorMessage" else "an unknown error."}" + ) +} + +fun Throwable.toFilesystemError(methodName: String): FilesystemErrors.ErrorInfo = when (this) { + + is IONFILEExceptions.UnresolvableUri -> FilesystemErrors.invalidPath(this.uri) + + is IONFILEExceptions.DoesNotExist -> FilesystemErrors.doesNotExist(methodName, this.path) + + is IONFILEExceptions.NotSupportedForContentScheme -> FilesystemErrors.notAllowed( + methodName, + notAllowedFor = "content:// URIs" + ) + + is IONFILEExceptions.NotSupportedForDirectory -> FilesystemErrors.notAllowed( + methodName, + notAllowedFor = "directories" + ) + + is IONFILEExceptions.NotSupportedForFiles -> FilesystemErrors.notAllowed( + methodName, + notAllowedFor = "files, only directories are supported" + ) + + is IONFILEExceptions.CreateFailed.AlreadyExists -> + FilesystemErrors.directoryCreationAlreadyExists(this.path) + + is IONFILEExceptions.CreateFailed.NoParentDirectory -> FilesystemErrors.missingParentDirectories + + is IONFILEExceptions.DeleteFailed.CannotDeleteChildren -> FilesystemErrors.cannotDeleteChildren + + is IONFILEExceptions.CopyRenameFailed.MixingFilesAndDirectories, + is IONFILEExceptions.CopyRenameFailed.LocalToContent, + is IONFILEExceptions.CopyRenameFailed.SourceAndDestinationContent -> + FilesystemErrors.notAllowed(methodName, "the provided source and destinations") + + is IONFILEExceptions.CopyRenameFailed.DestinationDirectoryExists -> + FilesystemErrors.directoryCreationAlreadyExists(this.path) + + is IONFILEExceptions.CopyRenameFailed.NoParentDirectory -> + FilesystemErrors.missingParentDirectories + + is IllegalArgumentException -> FilesystemErrors.invalidInputMethod(methodName) + + else -> FilesystemErrors.operationFailed(methodName, this.localizedMessage ?: "") +} \ No newline at end of file diff --git a/node_modules/@capacitor/filesystem/android/src/main/kotlin/com/capacitorjs/plugins/filesystem/FilesystemMethodOptions.kt b/node_modules/@capacitor/filesystem/android/src/main/kotlin/com/capacitorjs/plugins/filesystem/FilesystemMethodOptions.kt new file mode 100644 index 0000000..6abeb46 --- /dev/null +++ b/node_modules/@capacitor/filesystem/android/src/main/kotlin/com/capacitorjs/plugins/filesystem/FilesystemMethodOptions.kt @@ -0,0 +1,151 @@ +package com.capacitorjs.plugins.filesystem + +import com.getcapacitor.PluginCall +import io.ionic.libs.ionfilesystemlib.model.IONFILEConstants +import io.ionic.libs.ionfilesystemlib.model.IONFILEEncoding +import io.ionic.libs.ionfilesystemlib.model.IONFILEFolderType +import io.ionic.libs.ionfilesystemlib.model.IONFILEReadInChunksOptions +import io.ionic.libs.ionfilesystemlib.model.IONFILEReadOptions +import io.ionic.libs.ionfilesystemlib.model.IONFILESaveMode +import io.ionic.libs.ionfilesystemlib.model.IONFILESaveOptions +import io.ionic.libs.ionfilesystemlib.model.IONFILEUri + +internal const val INPUT_APPEND = "append" +private const val INPUT_PATH = "path" +private const val INPUT_DIRECTORY = "directory" +private const val INPUT_ENCODING = "encoding" +private const val INPUT_OFFSET = "offset" +private const val INPUT_LENGTH = "length" +private const val INPUT_CHUNK_SIZE = "chunkSize" +private const val INPUT_DATA = "data" +private const val INPUT_RECURSIVE = "recursive" +private const val INPUT_FROM = "from" +private const val INPUT_FROM_DIRECTORY = "directory" +private const val INPUT_TO = "to" +private const val INPUT_TO_DIRECTORY = "toDirectory" + +internal data class ReadFileOptions( + val uri: IONFILEUri.Unresolved, + val options: IONFILEReadOptions +) + +internal data class ReadFileInChunksOptions( + val uri: IONFILEUri.Unresolved, + val options: IONFILEReadInChunksOptions +) + +internal data class WriteFileOptions( + val uri: IONFILEUri.Unresolved, + val options: IONFILESaveOptions +) + +internal data class SingleUriWithRecursiveOptions( + val uri: IONFILEUri.Unresolved, + val recursive: Boolean +) + +internal data class DoubleUri( + val fromUri: IONFILEUri.Unresolved, + val toUri: IONFILEUri.Unresolved, +) + +/** + * @return [ReadFileOptions] from JSON inside [PluginCall], or null if input is invalid + */ +internal fun PluginCall.getReadFileOptions(): ReadFileOptions? { + val uri = getSingleIONFILEUri() ?: return null + val encoding = IONFILEEncoding.fromEncodingName(getString(INPUT_ENCODING)) + val offsetAndLength = getOffsetAndLength() + return ReadFileOptions( + uri = uri, + options = IONFILEReadOptions( + encoding, + offset = offsetAndLength.first, + length = offsetAndLength.second + ) + ) +} + +/** + * @return [ReadFileInChunksOptions] from JSON inside [PluginCall], or null if input is invalid + */ +internal fun PluginCall.getReadFileInChunksOptions(): ReadFileInChunksOptions? { + val uri = getSingleIONFILEUri() ?: return null + val encoding = IONFILEEncoding.fromEncodingName(getString(INPUT_ENCODING)) + val chunkSize = getInt(INPUT_CHUNK_SIZE)?.takeIf { it > 0 } ?: return null + val offsetAndLength = getOffsetAndLength() + return ReadFileInChunksOptions( + uri = uri, + options = IONFILEReadInChunksOptions( + encoding, + chunkSize = chunkSize, + offset = offsetAndLength.first, + length = offsetAndLength.second + ) + ) +} + +/** + * @return [ReadFileOptions] from JSON inside [PluginCall], or null if input is invalid + */ +internal fun PluginCall.getWriteFileOptions(): WriteFileOptions? { + val uri = getSingleIONFILEUri() ?: return null + val data = getString(INPUT_DATA) ?: return null + val recursive = getBoolean(INPUT_RECURSIVE) ?: false + val append = getBoolean(INPUT_APPEND) ?: false + val saveMode = if (append) IONFILESaveMode.APPEND else IONFILESaveMode.WRITE + val encoding = IONFILEEncoding.fromEncodingName(getString(INPUT_ENCODING)) + return WriteFileOptions( + uri = uri, + options = IONFILESaveOptions( + data = data, + encoding = encoding, + mode = saveMode, + createFileRecursive = recursive + ) + ) +} + +/** + * @return [SingleUriWithRecursiveOptions] from JSON inside [PluginCall], or null if input is invalid + */ +internal fun PluginCall.getSingleUriWithRecursiveOptions(): SingleUriWithRecursiveOptions? { + val uri = getSingleIONFILEUri() ?: return null + val recursive = getBoolean(INPUT_RECURSIVE) ?: false + return SingleUriWithRecursiveOptions(uri = uri, recursive = recursive) +} + +/** + * @return two uris in form of [DoubleUri] from JSON inside [PluginCall], or null if input is invalid + */ +internal fun PluginCall.getDoubleIONFILEUri(): DoubleUri? { + val fromPath = getString(INPUT_FROM) ?: return null + val fromFolder = IONFILEFolderType.fromStringAlias(getString(INPUT_FROM_DIRECTORY)) + val toPath = getString(INPUT_TO) ?: return null + val toFolder = getString(INPUT_TO_DIRECTORY)?.let { toDirectory -> + IONFILEFolderType.fromStringAlias(toDirectory) + } ?: fromFolder + return DoubleUri( + fromUri = IONFILEUri.Unresolved(fromFolder, fromPath), + toUri = IONFILEUri.Unresolved(toFolder, toPath), + ) +} + +/** + * return a single [IONFILEUri.Unresolved] from JSON inside [PluginCall], or null if input is invalid + */ +internal fun PluginCall.getSingleIONFILEUri(): IONFILEUri.Unresolved? { + val path = getString(INPUT_PATH) ?: return null + val directoryAlias = getString(INPUT_DIRECTORY) + return unresolvedUri(path, directoryAlias) +} + +private fun PluginCall.getOffsetAndLength(): Pair = Pair( + getInt(INPUT_OFFSET)?.takeIf { it >= 0 } ?: 0, + getInt(INPUT_LENGTH)?.takeIf { it > 0 } ?: IONFILEConstants.LENGTH_READ_TIL_EOF +) + +private fun unresolvedUri(path: String, directoryAlias: String?) = IONFILEUri.Unresolved( + parentFolder = IONFILEFolderType.fromStringAlias(directoryAlias), + uriPath = path +) diff --git a/node_modules/@capacitor/filesystem/android/src/main/kotlin/com/capacitorjs/plugins/filesystem/FilesystemMethodResults.kt b/node_modules/@capacitor/filesystem/android/src/main/kotlin/com/capacitorjs/plugins/filesystem/FilesystemMethodResults.kt new file mode 100644 index 0000000..b2c0c6a --- /dev/null +++ b/node_modules/@capacitor/filesystem/android/src/main/kotlin/com/capacitorjs/plugins/filesystem/FilesystemMethodResults.kt @@ -0,0 +1,65 @@ +package com.capacitorjs.plugins.filesystem + +import android.net.Uri +import com.getcapacitor.JSArray +import com.getcapacitor.JSObject +import io.ionic.libs.ionfilesystemlib.model.IONFILEFileType +import io.ionic.libs.ionfilesystemlib.model.IONFILEMetadataResult +import io.ionic.libs.ionfilesystemlib.model.IONFILESaveMode +import io.ionic.libs.ionfilesystemlib.model.IONFILEUri + +private val OUTPUT_DATA = "data" +private val OUTPUT_NAME = "name" +private val OUTPUT_TYPE = "type" +private val OUTPUT_SIZE = "size" +private val OUTPUT_MODIFIED_TIME = "mtime" +private val OUTPUT_CREATED_TIME = "ctime" +private val OUTPUT_URI = "uri" +private val OUTPUT_FILES = "files" + +/** + * @return a result [JSObject] for reading a file + */ +fun createReadResultObject(readData: String): JSObject = + JSObject().also { it.putOpt(OUTPUT_DATA, readData) } + + +/** + * @return a result [JSObject] for writing/append a file + */ +fun createWriteResultObject(uri: Uri, mode: IONFILESaveMode): JSObject? = + if (mode == IONFILESaveMode.APPEND) { + null + } else { + createUriResultObject(uri) + } + +/** + * @return a result [JSObject] for the list of a directories contents + */ +fun createReadDirResultObject(list: List): JSObject = JSObject().also { + it.put(OUTPUT_FILES, JSArray(list.map { child -> child.toResultObject() })) +} + +/** + * @return a result [JSObject] for stat, from the [IONFILEMetadataResult] object + */ +fun IONFILEMetadataResult.toResultObject(): JSObject = JSObject().apply { + put(OUTPUT_NAME, name) + put(OUTPUT_TYPE, if (type is IONFILEFileType.Directory) "directory" else "file") + put(OUTPUT_SIZE, size) + put(OUTPUT_MODIFIED_TIME, lastModifiedTimestamp) + put(OUTPUT_CREATED_TIME, createdTimestamp) + put(OUTPUT_URI, uri) +} + +/** + * @return a result [JSObject] based on a resolved uri [IONFILEUri.Resolved] + */ +fun IONFILEUri.Resolved.toResultObject(): JSObject = createUriResultObject(this.uri) + +/** + * @return a result [JSObject] for an Android [Uri] + */ +fun createUriResultObject(uri: Uri): JSObject = + JSObject().also { it.put(OUTPUT_URI, uri.toString()) } \ No newline at end of file diff --git a/node_modules/@capacitor/filesystem/android/src/main/kotlin/com/capacitorjs/plugins/filesystem/FilesystemPlugin.kt b/node_modules/@capacitor/filesystem/android/src/main/kotlin/com/capacitorjs/plugins/filesystem/FilesystemPlugin.kt new file mode 100644 index 0000000..fed6e14 --- /dev/null +++ b/node_modules/@capacitor/filesystem/android/src/main/kotlin/com/capacitorjs/plugins/filesystem/FilesystemPlugin.kt @@ -0,0 +1,412 @@ +package com.capacitorjs.plugins.filesystem + +import android.Manifest +import android.media.MediaScannerConnection +import android.os.Build +import android.os.Environment +import android.util.Log +import com.getcapacitor.JSObject +import com.getcapacitor.Logger +import com.getcapacitor.PermissionState +import com.getcapacitor.Plugin +import com.getcapacitor.PluginCall +import com.getcapacitor.PluginMethod +import com.getcapacitor.annotation.CapacitorPlugin +import com.getcapacitor.annotation.Permission +import com.getcapacitor.annotation.PermissionCallback +import com.getcapacitor.plugin.util.HttpRequestHandler.ProgressEmitter +import io.ionic.libs.ionfilesystemlib.IONFILEController +import io.ionic.libs.ionfilesystemlib.model.IONFILECreateOptions +import io.ionic.libs.ionfilesystemlib.model.IONFILEDeleteOptions +import io.ionic.libs.ionfilesystemlib.model.IONFILEUri +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.cancel +import kotlinx.coroutines.flow.catch +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onCompletion +import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.launch +import org.json.JSONException + +private const val PUBLIC_STORAGE = "publicStorage" +private const val PUBLIC_STORAGE_ABOVE_ANDROID_10 = "publicStorageAboveAPI29" +private const val PERMISSION_GRANTED = "granted" + +@CapacitorPlugin( + name = "Filesystem", + permissions = [ + Permission( + strings = [Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE], + alias = PUBLIC_STORAGE + ), + /* + For SDK versions 30-32 (Android 11 and Android 12) + Could be that certain files may require read permission, such as local file path to photos/videos in gallery + */ + Permission( + strings = [Manifest.permission.READ_EXTERNAL_STORAGE], + alias = PUBLIC_STORAGE_ABOVE_ANDROID_10 + ) + ] +) +class FilesystemPlugin : Plugin() { + + private var legacyImplementation: LegacyFilesystemImplementation? = null + + private val coroutineScope: CoroutineScope by lazy { CoroutineScope(Dispatchers.Main) } + private val controller: IONFILEController by lazy { IONFILEController(context.applicationContext) } + + override fun load() { + super.load() + legacyImplementation = LegacyFilesystemImplementation(context) + } + + override fun handleOnDestroy() { + super.handleOnDestroy() + coroutineScope.cancel() + } + + @PluginMethod + fun readFile(call: PluginCall) { + val input: ReadFileOptions = call.getReadFileOptions() ?: run { + call.sendError(FilesystemErrors.invalidInputMethod(call.methodName)) + return + } + runWithPermission(input.uri, call) { uri -> + controller.readFile(uri, input.options) + .onSuccess { call.sendSuccess(result = createReadResultObject(it)) } + .onFailure { call.sendError(it.toFilesystemError(call.methodName)) } + } + } + + @PluginMethod(returnType = PluginMethod.RETURN_CALLBACK) + fun readFileInChunks(call: PluginCall) { + val input: ReadFileInChunksOptions = call.getReadFileInChunksOptions() ?: run { + call.sendError(FilesystemErrors.invalidInputMethod(call.methodName)) + return + } + runWithPermission(input.uri, call) { uri -> + controller.readFileInChunks(uri, input.options) + .onEach { chunk -> + call.sendSuccess(result = createReadResultObject(chunk), keepCallback = true) + } + .onCompletion { error -> + if (error == null) { + call.sendSuccess(result = createReadResultObject("")) + } + } + .catch { + call.sendError(it.toFilesystemError(call.methodName)) + } + .launchIn(coroutineScope) + } + } + + @PluginMethod + fun writeFile(call: PluginCall) { + val input: WriteFileOptions = call.getWriteFileOptions() ?: run { + call.sendError(FilesystemErrors.invalidInputMethod(call.methodName)) + return + } + runWithPermission(input.uri, call) { uri -> + controller.saveFile(uri, input.options) + .onSuccess { uriSaved -> + // update mediaStore index only if file was written to external storage + if (uri.inExternalStorage) { + uriSaved.path?.let { + MediaScannerConnection.scanFile(context, arrayOf(it), null, null) + } + } + call.sendSuccess(result = createWriteResultObject(uriSaved, input.options.mode)) + } + .onFailure { call.sendError(it.toFilesystemError(call.methodName)) } + } + } + + @PluginMethod + fun appendFile(call: PluginCall) { + try { + call.data.putOpt(INPUT_APPEND, true) + } catch (ex: JSONException) { + Log.e(logTag, "Tried to set `append` in `PluginCall`, but got exception", ex) + call.sendError( + FilesystemErrors.operationFailed(call.methodName, ex.localizedMessage ?: "") + ) + return + } + writeFile(call) + } + + @PluginMethod + fun deleteFile(call: PluginCall) { + val input = call.getSingleIONFILEUri() ?: run { + call.sendError(FilesystemErrors.invalidInputMethod(call.methodName)) + return + } + runWithPermission(input, call) { uri -> + controller.delete(uri, IONFILEDeleteOptions(recursive = false)) + .onSuccess { call.sendSuccess() } + .onFailure { call.sendError(it.toFilesystemError(call.methodName)) } + } + } + + @PluginMethod + fun mkdir(call: PluginCall) { + val input = call.getSingleUriWithRecursiveOptions() ?: run { + call.sendError(FilesystemErrors.invalidInputMethod(call.methodName)) + return + } + runWithPermission(input.uri, call) { uri -> + controller.createDirectory(uri, IONFILECreateOptions(input.recursive)) + .onSuccess { call.sendSuccess() } + .onFailure { call.sendError(it.toFilesystemError(call.methodName)) } + } + } + + @PluginMethod + fun rmdir(call: PluginCall) { + val input = call.getSingleUriWithRecursiveOptions() ?: run { + call.sendError(FilesystemErrors.invalidInputMethod(call.methodName)) + return + } + runWithPermission(input.uri, call) { uri -> + controller.delete(uri, IONFILEDeleteOptions(input.recursive)) + .onSuccess { call.sendSuccess() } + .onFailure { call.sendError(it.toFilesystemError(call.methodName)) } + } + } + + @PluginMethod + fun readdir(call: PluginCall) { + val input = call.getSingleIONFILEUri() ?: run { + call.sendError(FilesystemErrors.invalidInputMethod(call.methodName)) + return + } + runWithPermission(input, call) { uri -> + controller.listDirectory(uri) + .onSuccess { call.sendSuccess(result = createReadDirResultObject(it)) } + .onFailure { call.sendError(it.toFilesystemError(call.methodName)) } + } + } + + @PluginMethod + fun getUri(call: PluginCall) { + val input = call.getSingleIONFILEUri() ?: run { + call.sendError(FilesystemErrors.invalidInputMethod(call.methodName)) + return + } + coroutineScope.launch { + controller.getFileUri(input) + .onSuccess { resolvedUri -> call.sendSuccess(result = resolvedUri.toResultObject()) } + .onFailure { call.sendError(it.toFilesystemError(call.methodName)) } + } + } + + @PluginMethod + fun stat(call: PluginCall) { + val input = call.getSingleIONFILEUri() ?: run { + call.sendError(FilesystemErrors.invalidInputMethod(call.methodName)) + return + } + runWithPermission(input, call) { uri -> + controller.getMetadata(uri) + .onSuccess { metadata -> call.sendSuccess(result = metadata.toResultObject()) } + .onFailure { call.sendError(it.toFilesystemError(call.methodName)) } + } + } + + @PluginMethod + fun rename(call: PluginCall) { + val input = call.getDoubleIONFILEUri() ?: run { + call.sendError(FilesystemErrors.invalidInputMethod(call.methodName)) + return + } + runWithPermission(input.fromUri, input.toUri, call) { source, destination -> + controller.move(source, destination) + .onSuccess { call.sendSuccess() } + .onFailure { call.sendError(it.toFilesystemError(call.methodName)) } + } + } + + @PluginMethod + fun copy(call: PluginCall) { + val input = call.getDoubleIONFILEUri() ?: run { + call.sendError(FilesystemErrors.invalidInputMethod(call.methodName)) + return + } + runWithPermission(input.fromUri, input.toUri, call) { source, destination -> + controller.copy(source, destination) + .onSuccess { call.sendSuccess(createUriResultObject(it)) } + .onFailure { call.sendError(it.toFilesystemError(call.methodName)) } + } + } + + @PluginMethod + @Deprecated("Use @capacitor/file-transfer plugin instead") + fun downloadFile(call: PluginCall) { + try { + val directory = call.getString("directory", Environment.DIRECTORY_DOWNLOADS) + + if (legacyImplementation?.isPublicDirectory(directory) == true && + !isStoragePermissionGranted(false) + ) { + requestAllPermissions(call, "permissionCallback") + return + } + + val emitter = ProgressEmitter { bytes: Int?, contentLength: Int? -> + val ret = JSObject() + ret.put("url", call.getString("url")) + ret.put("bytes", bytes) + ret.put("contentLength", contentLength) + notifyListeners("progress", ret) + } + + legacyImplementation?.downloadFile( + call, + bridge, + emitter, + object : LegacyFilesystemImplementation.FilesystemDownloadCallback { + override fun onSuccess(result: JSObject) { + // update mediaStore index only if file was written to external storage + if (legacyImplementation?.isPublicDirectory(directory) == true) { + MediaScannerConnection.scanFile( + context, + arrayOf(result.getString("path")), + null, + null + ) + } + call.resolve(result) + } + + override fun onError(error: Exception) { + call.reject("Error downloading file: " + error.localizedMessage, error) + } + } + ) + } catch (ex: Exception) { + call.reject("Error downloading file: " + ex.localizedMessage, ex) + } + } + + @PluginMethod + override fun checkPermissions(call: PluginCall) { + if (isStoragePermissionGranted(false)) { + call.sendSuccess(JSObject().also { it.put(PUBLIC_STORAGE, PERMISSION_GRANTED) }) + } else { + super.checkPermissions(call) + } + } + + @PluginMethod + override fun requestPermissions(call: PluginCall) { + if (isStoragePermissionGranted(false)) { + call.sendSuccess(JSObject().also { it.put(PUBLIC_STORAGE, PERMISSION_GRANTED) }) + } else { + super.requestPermissions(call) + } + } + + @PermissionCallback + private fun permissionCallback(call: PluginCall) { + if (!isStoragePermissionGranted(true)) { + Logger.debug(logTag, "User denied storage permission") + call.sendError(FilesystemErrors.filePermissionsDenied) + return + } + + when (call.methodName) { + // appendFile and writeFile have the same implementation, hence the same method is called; + // the only difference being that we add a boolean for append in the PluginCall, + // which is done before this method is called. + "appendFile", "writeFile" -> writeFile(call) + "deleteFile" -> deleteFile(call) + "mkdir" -> mkdir(call) + "rmdir" -> rmdir(call) + "rename" -> rename(call) + "copy" -> copy(call) + "readFile" -> readFile(call) + "readFileInChunks" -> readFileInChunks(call) + "readdir" -> readdir(call) + "getUri" -> getUri(call) + "stat" -> stat(call) + "downloadFile" -> downloadFile(call) + } + } + + /** + * Runs a suspend code if the app has permission to access the uri + * + * Will ask for permission if it has not been granted. + * + * May return an error if the uri is not resolvable. + * + * @param uri the uri pointing to the file / directory + * @param call the capacitor plugin call + * @param onPermissionGranted the callback to run the suspending code + */ + private fun runWithPermission( + uri: IONFILEUri.Unresolved, + call: PluginCall, + onPermissionGranted: suspend (resolvedUri: IONFILEUri.Resolved) -> Unit + ) { + coroutineScope.launch { + controller.getFileUri(uri) + .onSuccess { resolvedUri -> + // certain files like a photo/video in gallery may require read permission on Android 11 and 12. + if ( + resolvedUri.inExternalStorage + && !isStoragePermissionGranted(shouldRequestAboveAndroid10 = uri.parentFolder == null) + ) { + requestAllPermissions(call, this@FilesystemPlugin::permissionCallback.name) + } else { + onPermissionGranted(resolvedUri) + } + } + .onFailure { call.sendError(it.toFilesystemError(call.methodName)) } + } + } + + /** + * Runs a suspend code if the app has permission to access both to and from uris + * + * Will ask for permission if it has not been granted. + * + * May return an error if the uri is not resolvable. + * + * @param fromUri the source uri pointing to the file / directory + * @param toUri the destination uri pointing to the file / directory + * @param call the capacitor plugin call + * @param onPermissionGranted the callback to run the suspending code + */ + private fun runWithPermission( + fromUri: IONFILEUri.Unresolved, + toUri: IONFILEUri.Unresolved, + call: PluginCall, + onPermissionGranted: suspend (resolvedSourceUri: IONFILEUri.Resolved, resolvedDestinationUri: IONFILEUri.Resolved) -> Unit + ) { + runWithPermission(fromUri, call) { resolvedSourceUri -> + runWithPermission(toUri, call) { resolvedDestinationUri -> + onPermissionGranted(resolvedSourceUri, resolvedDestinationUri) + } + } + } + + /** + * Checks the the given permission is granted or not + * @param shouldRequestAboveAndroid10 whether or not should check for read permission above android 10 + * May vary with the kind of file path that is provided. + * @return Returns true if the app is running on Android 13 (API 33) or newer, or if the permission is already granted + * or false if it is denied. + */ + private fun isStoragePermissionGranted(shouldRequestAboveAndroid10: Boolean): Boolean = when { + Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU -> true + + Build.VERSION.SDK_INT >= Build.VERSION_CODES.R -> + !shouldRequestAboveAndroid10 || getPermissionState(PUBLIC_STORAGE_ABOVE_ANDROID_10) == PermissionState.GRANTED + + else -> getPermissionState(PUBLIC_STORAGE) == PermissionState.GRANTED + } +} \ No newline at end of file diff --git a/node_modules/@capacitor/filesystem/android/src/main/kotlin/com/capacitorjs/plugins/filesystem/LegacyFilesystemImplementation.kt b/node_modules/@capacitor/filesystem/android/src/main/kotlin/com/capacitorjs/plugins/filesystem/LegacyFilesystemImplementation.kt new file mode 100644 index 0000000..cfe09ec --- /dev/null +++ b/node_modules/@capacitor/filesystem/android/src/main/kotlin/com/capacitorjs/plugins/filesystem/LegacyFilesystemImplementation.kt @@ -0,0 +1,169 @@ +package com.capacitorjs.plugins.filesystem + +import android.content.Context +import android.net.Uri +import android.os.Environment +import android.os.Handler +import android.os.Looper +import com.getcapacitor.Bridge +import com.getcapacitor.JSObject +import com.getcapacitor.PluginCall +import com.getcapacitor.plugin.util.HttpRequestHandler.HttpURLConnectionBuilder +import com.getcapacitor.plugin.util.HttpRequestHandler.ProgressEmitter +import org.json.JSONException +import java.io.File +import java.io.FileOutputStream +import java.io.IOException +import java.net.URISyntaxException +import java.net.URL +import kotlin.concurrent.thread + +class LegacyFilesystemImplementation internal constructor(private val context: Context) { + fun downloadFile( + call: PluginCall, + bridge: Bridge, + emitter: ProgressEmitter?, + callback: FilesystemDownloadCallback + ) { + val urlString = call.getString("url", "") + val handler = Handler(Looper.getMainLooper()) + + thread { + try { + val result = + doDownloadInBackground(urlString, call, bridge, emitter) + handler.post { callback.onSuccess(result) } + } catch (error: Exception) { + handler.post { callback.onError(error) } + } + } + } + + /** + * True if the given directory string is a public storage directory, which is accessible by the user or other apps. + * @param directory the directory string. + */ + fun isPublicDirectory(directory: String?): Boolean { + return "DOCUMENTS" == directory || "EXTERNAL_STORAGE" == directory + } + + private fun getDirectory(directory: String): File? { + val c = this.context + when (directory) { + "DOCUMENTS" -> return Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS) + "DATA", "LIBRARY" -> return c.filesDir + "CACHE" -> return c.cacheDir + "EXTERNAL" -> return c.getExternalFilesDir(null) + "EXTERNAL_STORAGE" -> return Environment.getExternalStorageDirectory() + } + return null + } + + private fun getFileObject(path: String, directory: String?): File? { + if (directory == null) { + val u = Uri.parse(path) + if (u.scheme == null || u.scheme == "file") { + return File(u.path) + } + } + + val androidDirectory = this.getDirectory(directory!!) + + if (androidDirectory == null) { + return null + } else { + if (!androidDirectory.exists()) { + androidDirectory.mkdir() + } + } + + return File(androidDirectory, path) + } + + @Throws(IOException::class, URISyntaxException::class, JSONException::class) + private fun doDownloadInBackground( + urlString: String?, + call: PluginCall, + bridge: Bridge, + emitter: ProgressEmitter? + ): JSObject { + val headers = call.getObject("headers", JSObject()) + val params = call.getObject("params", JSObject()) + val connectTimeout = call.getInt("connectTimeout") + val readTimeout = call.getInt("readTimeout") + val disableRedirects = call.getBoolean("disableRedirects") ?: false + val shouldEncode = call.getBoolean("shouldEncodeUrlParams") ?: true + val progress = call.getBoolean("progress") ?: false + + val method = call.getString("method")?.uppercase() ?: "GET" + val path = call.getString("path")!! + val directory = call.getString("directory", Environment.DIRECTORY_DOWNLOADS) + + val url = URL(urlString) + val file = getFileObject(path, directory) + + val connectionBuilder = HttpURLConnectionBuilder() + .setUrl(url) + .setMethod(method) + .setHeaders(headers) + .setUrlParams(params, shouldEncode) + .setConnectTimeout(connectTimeout) + .setReadTimeout(readTimeout) + .setDisableRedirects(disableRedirects) + .openConnection() + + val connection = connectionBuilder.build() + + connection.setSSLSocketFactory(bridge) + + val connectionInputStream = connection.inputStream + val fileOutputStream = FileOutputStream(file, false) + + val contentLength = connection.getHeaderField("content-length") + var bytes = 0 + var maxBytes = 0 + + try { + maxBytes = contentLength?.toInt() ?: 0 + } catch (ignored: NumberFormatException) { + } + + val buffer = ByteArray(1024) + var len: Int + + // Throttle emitter to 100ms so it doesn't slow down app + var lastEmitTime = System.currentTimeMillis() + val minEmitIntervalMillis: Long = 100 + + while ((connectionInputStream.read(buffer).also { len = it }) > 0) { + fileOutputStream.write(buffer, 0, len) + + bytes += len + + if (progress!! && null != emitter) { + val currentTime = System.currentTimeMillis() + if (currentTime - lastEmitTime > minEmitIntervalMillis) { + emitter.emit(bytes, maxBytes) + lastEmitTime = currentTime + } + } + } + + if (progress!! && null != emitter) { + emitter.emit(bytes, maxBytes) + } + + connectionInputStream.close() + fileOutputStream.close() + + val ret = JSObject() + ret.put("path", file!!.absolutePath) + return ret + } + + interface FilesystemDownloadCallback { + fun onSuccess(result: JSObject) + + fun onError(error: Exception) + } +} diff --git a/node_modules/@capacitor/filesystem/android/src/main/kotlin/com/capacitorjs/plugins/filesystem/PluginResultExtensions.kt b/node_modules/@capacitor/filesystem/android/src/main/kotlin/com/capacitorjs/plugins/filesystem/PluginResultExtensions.kt new file mode 100644 index 0000000..7ca43b0 --- /dev/null +++ b/node_modules/@capacitor/filesystem/android/src/main/kotlin/com/capacitorjs/plugins/filesystem/PluginResultExtensions.kt @@ -0,0 +1,25 @@ +package com.capacitorjs.plugins.filesystem + +import com.getcapacitor.JSObject +import com.getcapacitor.PluginCall + +/** + * Extension function to return a successful plugin result + * @param result JSOObject with the JSON content to return + * @param keepCallback boolean to determine if callback should be kept for future calls or not + */ +internal fun PluginCall.sendSuccess(result: JSObject? = null, keepCallback: Boolean = false) { + this.setKeepAlive(keepCallback) + if (result != null) { + this.resolve(result) + } else { + this.resolve() + } +} + +/** + * Extension function to return a unsuccessful plugin result + * @param error error class representing the error to return, containing a code and message + */ +internal fun PluginCall.sendError(error: FilesystemErrors.ErrorInfo) = + this.reject(error.message, error.code) \ No newline at end of file diff --git a/node_modules/@capacitor/filesystem/dist/docs.json b/node_modules/@capacitor/filesystem/dist/docs.json new file mode 100644 index 0000000..4b397ea --- /dev/null +++ b/node_modules/@capacitor/filesystem/dist/docs.json @@ -0,0 +1,1576 @@ +{ + "api": { + "name": "FilesystemPlugin", + "slug": "filesystemplugin", + "docs": "", + "tags": [], + "methods": [ + { + "name": "checkPermissions", + "signature": "() => Promise", + "parameters": [], + "returns": "Promise", + "tags": [ + { + "name": "since", + "text": "1.0.0" + } + ], + "docs": "Check read/write permissions.\nRequired on Android, only when using `Directory.Documents` or\n`Directory.ExternalStorage`.", + "complexTypes": [ + "PermissionStatus" + ], + "slug": "checkpermissions" + }, + { + "name": "requestPermissions", + "signature": "() => Promise", + "parameters": [], + "returns": "Promise", + "tags": [ + { + "name": "since", + "text": "1.0.0" + } + ], + "docs": "Request read/write permissions.\nRequired on Android, only when using `Directory.Documents` or\n`Directory.ExternalStorage`.", + "complexTypes": [ + "PermissionStatus" + ], + "slug": "requestpermissions" + }, + { + "name": "readFile", + "signature": "(options: ReadFileOptions) => Promise", + "parameters": [ + { + "name": "options", + "docs": "", + "type": "ReadFileOptions" + } + ], + "returns": "Promise", + "tags": [ + { + "name": "since", + "text": "1.0.0" + } + ], + "docs": "Read a file from disk", + "complexTypes": [ + "ReadFileResult", + "ReadFileOptions" + ], + "slug": "readfile" + }, + { + "name": "readFileInChunks", + "signature": "(options: ReadFileInChunksOptions, callback: ReadFileInChunksCallback) => Promise", + "parameters": [ + { + "name": "options", + "docs": "", + "type": "ReadFileInChunksOptions" + }, + { + "name": "callback", + "docs": "", + "type": "ReadFileInChunksCallback" + } + ], + "returns": "Promise", + "tags": [ + { + "name": "since", + "text": "7.1.0" + } + ], + "docs": "Read a file from disk, in chunks.\nNative only (not available in web).\nUse the callback to receive each read chunk.\nIf empty chunk is returned, it means file has been completely read.", + "complexTypes": [ + "ReadFileInChunksOptions", + "ReadFileInChunksCallback", + "CallbackID" + ], + "slug": "readfileinchunks" + }, + { + "name": "writeFile", + "signature": "(options: WriteFileOptions) => Promise", + "parameters": [ + { + "name": "options", + "docs": "", + "type": "WriteFileOptions" + } + ], + "returns": "Promise", + "tags": [ + { + "name": "since", + "text": "1.0.0" + } + ], + "docs": "Write a file to disk in the specified location on device", + "complexTypes": [ + "WriteFileResult", + "WriteFileOptions" + ], + "slug": "writefile" + }, + { + "name": "appendFile", + "signature": "(options: AppendFileOptions) => Promise", + "parameters": [ + { + "name": "options", + "docs": "", + "type": "AppendFileOptions" + } + ], + "returns": "Promise", + "tags": [ + { + "name": "since", + "text": "1.0.0" + } + ], + "docs": "Append to a file on disk in the specified location on device", + "complexTypes": [ + "AppendFileOptions" + ], + "slug": "appendfile" + }, + { + "name": "deleteFile", + "signature": "(options: DeleteFileOptions) => Promise", + "parameters": [ + { + "name": "options", + "docs": "", + "type": "DeleteFileOptions" + } + ], + "returns": "Promise", + "tags": [ + { + "name": "since", + "text": "1.0.0" + } + ], + "docs": "Delete a file from disk", + "complexTypes": [ + "DeleteFileOptions" + ], + "slug": "deletefile" + }, + { + "name": "mkdir", + "signature": "(options: MkdirOptions) => Promise", + "parameters": [ + { + "name": "options", + "docs": "", + "type": "MkdirOptions" + } + ], + "returns": "Promise", + "tags": [ + { + "name": "since", + "text": "1.0.0" + } + ], + "docs": "Create a directory.", + "complexTypes": [ + "MkdirOptions" + ], + "slug": "mkdir" + }, + { + "name": "rmdir", + "signature": "(options: RmdirOptions) => Promise", + "parameters": [ + { + "name": "options", + "docs": "", + "type": "RmdirOptions" + } + ], + "returns": "Promise", + "tags": [ + { + "name": "since", + "text": "1.0.0" + } + ], + "docs": "Remove a directory", + "complexTypes": [ + "RmdirOptions" + ], + "slug": "rmdir" + }, + { + "name": "readdir", + "signature": "(options: ReaddirOptions) => Promise", + "parameters": [ + { + "name": "options", + "docs": "", + "type": "ReaddirOptions" + } + ], + "returns": "Promise", + "tags": [ + { + "name": "since", + "text": "1.0.0" + } + ], + "docs": "Return a list of files from the directory (not recursive)", + "complexTypes": [ + "ReaddirResult", + "ReaddirOptions" + ], + "slug": "readdir" + }, + { + "name": "getUri", + "signature": "(options: GetUriOptions) => Promise", + "parameters": [ + { + "name": "options", + "docs": "", + "type": "GetUriOptions" + } + ], + "returns": "Promise", + "tags": [ + { + "name": "since", + "text": "1.0.0" + } + ], + "docs": "Return full File URI for a path and directory", + "complexTypes": [ + "GetUriResult", + "GetUriOptions" + ], + "slug": "geturi" + }, + { + "name": "stat", + "signature": "(options: StatOptions) => Promise", + "parameters": [ + { + "name": "options", + "docs": "", + "type": "StatOptions" + } + ], + "returns": "Promise", + "tags": [ + { + "name": "since", + "text": "1.0.0" + } + ], + "docs": "Return data about a file", + "complexTypes": [ + "FileInfo", + "StatOptions", + "StatResult" + ], + "slug": "stat" + }, + { + "name": "rename", + "signature": "(options: RenameOptions) => Promise", + "parameters": [ + { + "name": "options", + "docs": "", + "type": "CopyOptions" + } + ], + "returns": "Promise", + "tags": [ + { + "name": "since", + "text": "1.0.0" + } + ], + "docs": "Rename a file or directory", + "complexTypes": [ + "RenameOptions" + ], + "slug": "rename" + }, + { + "name": "copy", + "signature": "(options: CopyOptions) => Promise", + "parameters": [ + { + "name": "options", + "docs": "", + "type": "CopyOptions" + } + ], + "returns": "Promise", + "tags": [ + { + "name": "since", + "text": "1.0.0" + } + ], + "docs": "Copy a file or directory", + "complexTypes": [ + "CopyResult", + "CopyOptions" + ], + "slug": "copy" + }, + { + "name": "downloadFile", + "signature": "(options: DownloadFileOptions) => Promise", + "parameters": [ + { + "name": "options", + "docs": "", + "type": "DownloadFileOptions" + } + ], + "returns": "Promise", + "tags": [ + { + "name": "since", + "text": "5.1.0" + }, + { + "name": "deprecated", + "text": "Use the" + }, + { + "name": "capacitor", + "text": "/file-transfer plugin instead." + } + ], + "docs": "Perform a http request to a server and download the file to the specified destination.\n\nThis method has been deprecated since version 7.1.0.\nWe recommend using the @capacitor/file-transfer plugin instead, in conjunction with this plugin.", + "complexTypes": [ + "DownloadFileResult", + "DownloadFileOptions" + ], + "slug": "downloadfile" + }, + { + "name": "addListener", + "signature": "(eventName: 'progress', listenerFunc: ProgressListener) => Promise", + "parameters": [ + { + "name": "eventName", + "docs": "", + "type": "'progress'" + }, + { + "name": "listenerFunc", + "docs": "", + "type": "ProgressListener" + } + ], + "returns": "Promise", + "tags": [ + { + "name": "since", + "text": "5.1.0" + }, + { + "name": "deprecated", + "text": "Use the" + }, + { + "name": "capacitor", + "text": "/file-transfer plugin instead." + } + ], + "docs": "Add a listener to file download progress events.\n\nThis method has been deprecated since version 7.1.0.\nWe recommend using the @capacitor/file-transfer plugin instead, in conjunction with this plugin.", + "complexTypes": [ + "PluginListenerHandle", + "ProgressListener" + ], + "slug": "addlistenerprogress-" + }, + { + "name": "removeAllListeners", + "signature": "() => Promise", + "parameters": [], + "returns": "Promise", + "tags": [ + { + "name": "since", + "text": "5.2.0" + }, + { + "name": "deprecated", + "text": "Use the" + }, + { + "name": "capacitor", + "text": "/file-transfer plugin instead." + } + ], + "docs": "Remove all listeners for this plugin.\n\nThis method has been deprecated since version 7.1.0.\nWe recommend using the @capacitor/file-transfer plugin instead, in conjunction with this plugin.", + "complexTypes": [], + "slug": "removealllisteners" + } + ], + "properties": [] + }, + "interfaces": [ + { + "name": "PermissionStatus", + "slug": "permissionstatus", + "docs": "", + "tags": [], + "methods": [], + "properties": [ + { + "name": "publicStorage", + "tags": [], + "docs": "", + "complexTypes": [ + "PermissionState" + ], + "type": "PermissionState" + } + ] + }, + { + "name": "ReadFileResult", + "slug": "readfileresult", + "docs": "", + "tags": [], + "methods": [], + "properties": [ + { + "name": "data", + "tags": [ + { + "text": "1.0.0", + "name": "since" + } + ], + "docs": "The representation of the data contained in the file\n\nNote: Blob is only available on Web. On native, the data is returned as a string.", + "complexTypes": [ + "Blob" + ], + "type": "string | Blob" + } + ] + }, + { + "name": "ReadFileOptions", + "slug": "readfileoptions", + "docs": "", + "tags": [], + "methods": [], + "properties": [ + { + "name": "path", + "tags": [ + { + "text": "1.0.0", + "name": "since" + } + ], + "docs": "The path of the file to read", + "complexTypes": [], + "type": "string" + }, + { + "name": "directory", + "tags": [ + { + "text": "1.0.0", + "name": "since" + } + ], + "docs": "The `Directory` to read the file from", + "complexTypes": [ + "Directory" + ], + "type": "Directory" + }, + { + "name": "encoding", + "tags": [ + { + "text": "1.0.0", + "name": "since" + } + ], + "docs": "The encoding to read the file in, if not provided, data\nis read as binary and returned as base64 encoded.\n\nPass Encoding.UTF8 to read data as string", + "complexTypes": [ + "Encoding" + ], + "type": "Encoding" + }, + { + "name": "offset", + "tags": [ + { + "text": "8.1.0", + "name": "since" + }, + { + "text": "0", + "name": "default" + } + ], + "docs": "The offset to start reading the file from, in bytes.\nNative only (not available in web).\nCan be used in conjunction with length to partially read files.", + "complexTypes": [], + "type": "number | undefined" + }, + { + "name": "length", + "tags": [ + { + "text": "8.1.0", + "name": "since" + }, + { + "text": "-1", + "name": "default" + } + ], + "docs": "The length of data to read, in bytes.\nAny non-positive value means to read to the end of the file.\nNative only (not available in web).\nCan be used in conjunction with offset to partially read files.", + "complexTypes": [], + "type": "number | undefined" + } + ] + }, + { + "name": "ReadFileInChunksOptions", + "slug": "readfileinchunksoptions", + "docs": "", + "tags": [], + "methods": [], + "properties": [ + { + "name": "chunkSize", + "tags": [ + { + "text": "7.1.0", + "name": "since" + } + ], + "docs": "Size of the chunks in bytes.", + "complexTypes": [], + "type": "number" + } + ] + }, + { + "name": "WriteFileResult", + "slug": "writefileresult", + "docs": "", + "tags": [], + "methods": [], + "properties": [ + { + "name": "uri", + "tags": [ + { + "text": "1.0.0", + "name": "since" + } + ], + "docs": "The uri where the file was written into", + "complexTypes": [], + "type": "string" + } + ] + }, + { + "name": "WriteFileOptions", + "slug": "writefileoptions", + "docs": "", + "tags": [], + "methods": [], + "properties": [ + { + "name": "path", + "tags": [ + { + "text": "1.0.0", + "name": "since" + } + ], + "docs": "The path of the file to write", + "complexTypes": [], + "type": "string" + }, + { + "name": "data", + "tags": [ + { + "text": "1.0.0", + "name": "since" + } + ], + "docs": "The data to write\n\nNote: Blob data is only supported on Web.", + "complexTypes": [ + "Blob" + ], + "type": "string | Blob" + }, + { + "name": "directory", + "tags": [ + { + "text": "1.0.0", + "name": "since" + } + ], + "docs": "The `Directory` to store the file in", + "complexTypes": [ + "Directory" + ], + "type": "Directory" + }, + { + "name": "encoding", + "tags": [ + { + "text": "1.0.0", + "name": "since" + } + ], + "docs": "The encoding to write the file in.\nIf not provided, binary data will be written. For this, you must provide data as base64 encoded,\nso that the plugin can decode it before writing to disk.\nIf you do not provide encoding and use non-base64 data, an error will be thrown.\n\nPass Encoding.UTF8 to write data as string", + "complexTypes": [ + "Encoding" + ], + "type": "Encoding" + }, + { + "name": "recursive", + "tags": [ + { + "text": "false", + "name": "default" + }, + { + "text": "1.0.0", + "name": "since" + } + ], + "docs": "Whether to create any missing parent directories.", + "complexTypes": [], + "type": "boolean | undefined" + } + ] + }, + { + "name": "AppendFileOptions", + "slug": "appendfileoptions", + "docs": "", + "tags": [], + "methods": [], + "properties": [ + { + "name": "path", + "tags": [ + { + "text": "1.0.0", + "name": "since" + } + ], + "docs": "The path of the file to append", + "complexTypes": [], + "type": "string" + }, + { + "name": "data", + "tags": [ + { + "text": "1.0.0", + "name": "since" + } + ], + "docs": "The data to append", + "complexTypes": [], + "type": "string" + }, + { + "name": "directory", + "tags": [ + { + "text": "1.0.0", + "name": "since" + } + ], + "docs": "The `Directory` to store the file in", + "complexTypes": [ + "Directory" + ], + "type": "Directory" + }, + { + "name": "encoding", + "tags": [ + { + "text": "1.0.0", + "name": "since" + } + ], + "docs": "The encoding to append to the file.\nIf not provided, binary data will be appended. For this, you must provide data as base64 encoded,\nso that the plugin can decode it before writing to disk.\nIf you do not provide encoding and use non-base64 data, an error will be thrown.\n\nPass Encoding.UTF8 to write data as string", + "complexTypes": [ + "Encoding" + ], + "type": "Encoding" + } + ] + }, + { + "name": "DeleteFileOptions", + "slug": "deletefileoptions", + "docs": "", + "tags": [], + "methods": [], + "properties": [ + { + "name": "path", + "tags": [ + { + "text": "1.0.0", + "name": "since" + } + ], + "docs": "The path of the file to delete", + "complexTypes": [], + "type": "string" + }, + { + "name": "directory", + "tags": [ + { + "text": "1.0.0", + "name": "since" + } + ], + "docs": "The `Directory` to delete the file from", + "complexTypes": [ + "Directory" + ], + "type": "Directory" + } + ] + }, + { + "name": "MkdirOptions", + "slug": "mkdiroptions", + "docs": "", + "tags": [], + "methods": [], + "properties": [ + { + "name": "path", + "tags": [ + { + "text": "1.0.0", + "name": "since" + } + ], + "docs": "The path of the new directory", + "complexTypes": [], + "type": "string" + }, + { + "name": "directory", + "tags": [ + { + "text": "1.0.0", + "name": "since" + } + ], + "docs": "The `Directory` to make the new directory in", + "complexTypes": [ + "Directory" + ], + "type": "Directory" + }, + { + "name": "recursive", + "tags": [ + { + "text": "false", + "name": "default" + }, + { + "text": "1.0.0", + "name": "since" + } + ], + "docs": "Whether to create any missing parent directories as well.", + "complexTypes": [], + "type": "boolean | undefined" + } + ] + }, + { + "name": "RmdirOptions", + "slug": "rmdiroptions", + "docs": "", + "tags": [], + "methods": [], + "properties": [ + { + "name": "path", + "tags": [ + { + "text": "1.0.0", + "name": "since" + } + ], + "docs": "The path of the directory to remove", + "complexTypes": [], + "type": "string" + }, + { + "name": "directory", + "tags": [ + { + "text": "1.0.0", + "name": "since" + } + ], + "docs": "The `Directory` to remove the directory from", + "complexTypes": [ + "Directory" + ], + "type": "Directory" + }, + { + "name": "recursive", + "tags": [ + { + "text": "false", + "name": "default" + }, + { + "text": "1.0.0", + "name": "since" + } + ], + "docs": "Whether to recursively remove the contents of the directory", + "complexTypes": [], + "type": "boolean | undefined" + } + ] + }, + { + "name": "ReaddirResult", + "slug": "readdirresult", + "docs": "", + "tags": [], + "methods": [], + "properties": [ + { + "name": "files", + "tags": [ + { + "text": "1.0.0", + "name": "since" + } + ], + "docs": "List of files and directories inside the directory", + "complexTypes": [ + "FileInfo" + ], + "type": "FileInfo[]" + } + ] + }, + { + "name": "FileInfo", + "slug": "fileinfo", + "docs": "", + "tags": [], + "methods": [], + "properties": [ + { + "name": "name", + "tags": [ + { + "text": "7.1.0", + "name": "since" + } + ], + "docs": "Name of the file or directory.", + "complexTypes": [], + "type": "string" + }, + { + "name": "type", + "tags": [ + { + "text": "4.0.0", + "name": "since" + } + ], + "docs": "Type of the file.", + "complexTypes": [], + "type": "'file' | 'directory'" + }, + { + "name": "size", + "tags": [ + { + "text": "4.0.0", + "name": "since" + } + ], + "docs": "Size of the file in bytes.", + "complexTypes": [], + "type": "number" + }, + { + "name": "ctime", + "tags": [ + { + "text": "7.1.0", + "name": "since" + } + ], + "docs": "Time of creation in milliseconds.\n\nIt's not available on Android 7 and older devices.", + "complexTypes": [], + "type": "number | undefined" + }, + { + "name": "mtime", + "tags": [ + { + "text": "7.1.0", + "name": "since" + } + ], + "docs": "Time of last modification in milliseconds.", + "complexTypes": [], + "type": "number" + }, + { + "name": "uri", + "tags": [ + { + "text": "4.0.0", + "name": "since" + } + ], + "docs": "The uri of the file.", + "complexTypes": [], + "type": "string" + } + ] + }, + { + "name": "ReaddirOptions", + "slug": "readdiroptions", + "docs": "", + "tags": [], + "methods": [], + "properties": [ + { + "name": "path", + "tags": [ + { + "text": "1.0.0", + "name": "since" + } + ], + "docs": "The path of the directory to read", + "complexTypes": [], + "type": "string" + }, + { + "name": "directory", + "tags": [ + { + "text": "1.0.0", + "name": "since" + } + ], + "docs": "The `Directory` to list files from", + "complexTypes": [ + "Directory" + ], + "type": "Directory" + } + ] + }, + { + "name": "GetUriResult", + "slug": "geturiresult", + "docs": "", + "tags": [], + "methods": [], + "properties": [ + { + "name": "uri", + "tags": [ + { + "text": "1.0.0", + "name": "since" + } + ], + "docs": "The uri of the file", + "complexTypes": [], + "type": "string" + } + ] + }, + { + "name": "GetUriOptions", + "slug": "geturioptions", + "docs": "", + "tags": [], + "methods": [], + "properties": [ + { + "name": "path", + "tags": [ + { + "text": "1.0.0", + "name": "since" + } + ], + "docs": "The path of the file to get the URI for", + "complexTypes": [], + "type": "string" + }, + { + "name": "directory", + "tags": [ + { + "text": "1.0.0", + "name": "since" + } + ], + "docs": "The `Directory` to get the file under", + "complexTypes": [ + "Directory" + ], + "type": "Directory" + } + ] + }, + { + "name": "StatOptions", + "slug": "statoptions", + "docs": "", + "tags": [], + "methods": [], + "properties": [ + { + "name": "path", + "tags": [ + { + "text": "1.0.0", + "name": "since" + } + ], + "docs": "The path of the file to get data about", + "complexTypes": [], + "type": "string" + }, + { + "name": "directory", + "tags": [ + { + "text": "1.0.0", + "name": "since" + } + ], + "docs": "The `Directory` to get the file under", + "complexTypes": [ + "Directory" + ], + "type": "Directory" + } + ] + }, + { + "name": "CopyOptions", + "slug": "copyoptions", + "docs": "", + "tags": [], + "methods": [], + "properties": [ + { + "name": "from", + "tags": [ + { + "text": "1.0.0", + "name": "since" + } + ], + "docs": "The existing file or directory", + "complexTypes": [], + "type": "string" + }, + { + "name": "to", + "tags": [ + { + "text": "1.0.0", + "name": "since" + } + ], + "docs": "The destination file or directory", + "complexTypes": [], + "type": "string" + }, + { + "name": "directory", + "tags": [ + { + "text": "1.0.0", + "name": "since" + } + ], + "docs": "The `Directory` containing the existing file or directory", + "complexTypes": [ + "Directory" + ], + "type": "Directory" + }, + { + "name": "toDirectory", + "tags": [ + { + "text": "1.0.0", + "name": "since" + } + ], + "docs": "The `Directory` containing the destination file or directory. If not supplied will use the 'directory'\nparameter as the destination", + "complexTypes": [ + "Directory" + ], + "type": "Directory" + } + ] + }, + { + "name": "CopyResult", + "slug": "copyresult", + "docs": "", + "tags": [], + "methods": [], + "properties": [ + { + "name": "uri", + "tags": [ + { + "text": "4.0.0", + "name": "since" + } + ], + "docs": "The uri where the file was copied into", + "complexTypes": [], + "type": "string" + } + ] + }, + { + "name": "DownloadFileResult", + "slug": "downloadfileresult", + "docs": "", + "tags": [], + "methods": [], + "properties": [ + { + "name": "path", + "tags": [ + { + "text": "5.1.0", + "name": "since" + } + ], + "docs": "The path the file was downloaded to.", + "complexTypes": [], + "type": "string | undefined" + }, + { + "name": "blob", + "tags": [ + { + "text": "5.1.0", + "name": "since" + } + ], + "docs": "The blob data of the downloaded file.\nThis is only available on web.", + "complexTypes": [ + "Blob" + ], + "type": "Blob" + } + ] + }, + { + "name": "DownloadFileOptions", + "slug": "downloadfileoptions", + "docs": "", + "tags": [], + "methods": [], + "properties": [ + { + "name": "path", + "tags": [ + { + "text": "5.1.0", + "name": "since" + } + ], + "docs": "The path the downloaded file should be moved to.", + "complexTypes": [], + "type": "string" + }, + { + "name": "directory", + "tags": [ + { + "text": "5.1.0", + "name": "since" + } + ], + "docs": "The directory to write the file to.\nIf this option is used, filePath can be a relative path rather than absolute.\nThe default is the `DATA` directory.", + "complexTypes": [ + "Directory" + ], + "type": "Directory" + }, + { + "name": "progress", + "tags": [ + { + "text": "5.1.0", + "name": "since" + } + ], + "docs": "An optional listener function to receive downloaded progress events.\nIf this option is used, progress event should be dispatched on every chunk received.\nChunks are throttled to every 100ms on Android/iOS to avoid slowdowns.", + "complexTypes": [], + "type": "boolean | undefined" + }, + { + "name": "recursive", + "tags": [ + { + "text": "false", + "name": "default" + }, + { + "text": "5.1.2", + "name": "since" + } + ], + "docs": "Whether to create any missing parent directories.", + "complexTypes": [], + "type": "boolean | undefined" + } + ] + }, + { + "name": "PluginListenerHandle", + "slug": "pluginlistenerhandle", + "docs": "", + "tags": [], + "methods": [], + "properties": [ + { + "name": "remove", + "tags": [], + "docs": "", + "complexTypes": [], + "type": "() => Promise" + } + ] + }, + { + "name": "ProgressStatus", + "slug": "progressstatus", + "docs": "", + "tags": [], + "methods": [], + "properties": [ + { + "name": "url", + "tags": [ + { + "text": "5.1.0", + "name": "since" + } + ], + "docs": "The url of the file being downloaded.", + "complexTypes": [], + "type": "string" + }, + { + "name": "bytes", + "tags": [ + { + "text": "5.1.0", + "name": "since" + } + ], + "docs": "The number of bytes downloaded so far.", + "complexTypes": [], + "type": "number" + }, + { + "name": "contentLength", + "tags": [ + { + "text": "5.1.0", + "name": "since" + } + ], + "docs": "The total number of bytes to download for this file.", + "complexTypes": [], + "type": "number" + } + ] + } + ], + "enums": [ + { + "name": "Directory", + "slug": "directory", + "members": [ + { + "name": "Documents", + "value": "'DOCUMENTS'", + "tags": [ + { + "text": "1.0.0", + "name": "since" + } + ], + "docs": "The Documents directory.\nOn iOS it's the app's documents directory.\nUse this directory to store user-generated content.\nOn Android it's the Public Documents folder, so it's accessible from other apps.\nIt's not accessible on Android 10 unless the app enables legacy External Storage\nby adding `android:requestLegacyExternalStorage=\"true\"` in the `application` tag\nin the `AndroidManifest.xml`.\nOn Android 11 or newer the app can only access the files/folders the app created." + }, + { + "name": "Data", + "value": "'DATA'", + "tags": [ + { + "text": "1.0.0", + "name": "since" + } + ], + "docs": "The Data directory.\nOn iOS it will use the Documents directory.\nOn Android it's the directory holding application files.\nFiles will be deleted when the application is uninstalled." + }, + { + "name": "Library", + "value": "'LIBRARY'", + "tags": [ + { + "text": "1.1.0", + "name": "since" + } + ], + "docs": "The Library directory.\nOn iOS it will use the Library directory.\nOn Android it's the directory holding application files.\nFiles will be deleted when the application is uninstalled." + }, + { + "name": "Cache", + "value": "'CACHE'", + "tags": [ + { + "text": "1.0.0", + "name": "since" + } + ], + "docs": "The Cache directory.\nCan be deleted in cases of low memory, so use this directory to write app-specific files.\nthat your app can re-create easily." + }, + { + "name": "External", + "value": "'EXTERNAL'", + "tags": [ + { + "text": "1.0.0", + "name": "since" + } + ], + "docs": "The external directory.\nOn iOS it will use the Documents directory.\nOn Android it's the directory on the primary shared/external\nstorage device where the application can place persistent files it owns.\nThese files are internal to the applications, and not typically visible\nto the user as media.\nFiles will be deleted when the application is uninstalled." + }, + { + "name": "ExternalStorage", + "value": "'EXTERNAL_STORAGE'", + "tags": [ + { + "text": "1.0.0", + "name": "since" + } + ], + "docs": "The external storage directory.\nOn iOS it will use the Documents directory.\nOn Android it's the primary shared/external storage directory.\nIt's not accessible on Android 10 unless the app enables legacy External Storage\nby adding `android:requestLegacyExternalStorage=\"true\"` in the `application` tag\nin the `AndroidManifest.xml`.\nIt's not accessible on Android 11 or newer." + }, + { + "name": "ExternalCache", + "value": "'EXTERNAL_CACHE'", + "tags": [ + { + "text": "7.1.0", + "name": "since" + } + ], + "docs": "The external cache directory.\nOn iOS it will use the Documents directory.\nOn Android it's the primary shared/external cache." + }, + { + "name": "LibraryNoCloud", + "value": "'LIBRARY_NO_CLOUD'", + "tags": [ + { + "text": "7.1.0", + "name": "since" + } + ], + "docs": "The Library directory without cloud backup. Used in iOS.\nOn Android it's the directory holding application files." + }, + { + "name": "Temporary", + "value": "'TEMPORARY'", + "tags": [ + { + "text": "7.1.0", + "name": "since" + } + ], + "docs": "A temporary directory for iOS.\nOn Android it's the directory holding the application cache." + } + ] + }, + { + "name": "Encoding", + "slug": "encoding", + "members": [ + { + "name": "UTF8", + "value": "'utf8'", + "tags": [ + { + "text": "1.0.0", + "name": "since" + } + ], + "docs": "Eight-bit UCS Transformation Format" + }, + { + "name": "ASCII", + "value": "'ascii'", + "tags": [ + { + "text": "1.0.0", + "name": "since" + } + ], + "docs": "Seven-bit ASCII, a.k.a. ISO646-US, a.k.a. the Basic Latin block of the\nUnicode character set\nThis encoding is only supported on Android." + }, + { + "name": "UTF16", + "value": "'utf16'", + "tags": [ + { + "text": "1.0.0", + "name": "since" + } + ], + "docs": "Sixteen-bit UCS Transformation Format, byte order identified by an\noptional byte-order mark\nThis encoding is only supported on Android." + } + ] + } + ], + "typeAliases": [ + { + "name": "PermissionState", + "slug": "permissionstate", + "docs": "", + "types": [ + { + "text": "'prompt'", + "complexTypes": [] + }, + { + "text": "'prompt-with-rationale'", + "complexTypes": [] + }, + { + "text": "'granted'", + "complexTypes": [] + }, + { + "text": "'denied'", + "complexTypes": [] + } + ] + }, + { + "name": "ReadFileInChunksCallback", + "slug": "readfileinchunkscallback", + "docs": "Callback for receiving chunks read from a file, or error if something went wrong.", + "types": [ + { + "text": "(chunkRead: ReadFileResult | null, err?: any): void", + "complexTypes": [ + "ReadFileResult" + ] + } + ] + }, + { + "name": "CallbackID", + "slug": "callbackid", + "docs": "", + "types": [ + { + "text": "string", + "complexTypes": [] + } + ] + }, + { + "name": "StatResult", + "slug": "statresult", + "docs": "", + "types": [ + { + "text": "FileInfo", + "complexTypes": [ + "FileInfo" + ] + } + ] + }, + { + "name": "RenameOptions", + "slug": "renameoptions", + "docs": "", + "types": [ + { + "text": "CopyOptions", + "complexTypes": [ + "CopyOptions" + ] + } + ] + }, + { + "name": "ProgressListener", + "slug": "progresslistener", + "docs": "A listener function that receives progress events.", + "types": [ + { + "text": "(progress: ProgressStatus): void", + "complexTypes": [ + "ProgressStatus" + ] + } + ] + } + ], + "pluginConfigs": [] +} \ No newline at end of file diff --git a/node_modules/@capacitor/filesystem/dist/esm/definitions.d.ts b/node_modules/@capacitor/filesystem/dist/esm/definitions.d.ts new file mode 100644 index 0000000..5f45e42 --- /dev/null +++ b/node_modules/@capacitor/filesystem/dist/esm/definitions.d.ts @@ -0,0 +1,698 @@ +import type { HttpOptions, PermissionState, PluginListenerHandle } from '@capacitor/core'; +export type CallbackID = string; +export interface PermissionStatus { + publicStorage: PermissionState; +} +export declare enum Directory { + /** + * The Documents directory. + * On iOS it's the app's documents directory. + * Use this directory to store user-generated content. + * On Android it's the Public Documents folder, so it's accessible from other apps. + * It's not accessible on Android 10 unless the app enables legacy External Storage + * by adding `android:requestLegacyExternalStorage="true"` in the `application` tag + * in the `AndroidManifest.xml`. + * On Android 11 or newer the app can only access the files/folders the app created. + * + * @since 1.0.0 + */ + Documents = "DOCUMENTS", + /** + * The Data directory. + * On iOS it will use the Documents directory. + * On Android it's the directory holding application files. + * Files will be deleted when the application is uninstalled. + * + * @since 1.0.0 + */ + Data = "DATA", + /** + * The Library directory. + * On iOS it will use the Library directory. + * On Android it's the directory holding application files. + * Files will be deleted when the application is uninstalled. + * + * @since 1.1.0 + */ + Library = "LIBRARY", + /** + * The Cache directory. + * Can be deleted in cases of low memory, so use this directory to write app-specific files. + * that your app can re-create easily. + * + * @since 1.0.0 + */ + Cache = "CACHE", + /** + * The external directory. + * On iOS it will use the Documents directory. + * On Android it's the directory on the primary shared/external + * storage device where the application can place persistent files it owns. + * These files are internal to the applications, and not typically visible + * to the user as media. + * Files will be deleted when the application is uninstalled. + * + * @since 1.0.0 + */ + External = "EXTERNAL", + /** + * The external storage directory. + * On iOS it will use the Documents directory. + * On Android it's the primary shared/external storage directory. + * It's not accessible on Android 10 unless the app enables legacy External Storage + * by adding `android:requestLegacyExternalStorage="true"` in the `application` tag + * in the `AndroidManifest.xml`. + * It's not accessible on Android 11 or newer. + * + * @since 1.0.0 + */ + ExternalStorage = "EXTERNAL_STORAGE", + /** + * The external cache directory. + * On iOS it will use the Documents directory. + * On Android it's the primary shared/external cache. + * + * @since 7.1.0 + */ + ExternalCache = "EXTERNAL_CACHE", + /** + * The Library directory without cloud backup. Used in iOS. + * On Android it's the directory holding application files. + * + * @since 7.1.0 + */ + LibraryNoCloud = "LIBRARY_NO_CLOUD", + /** + * A temporary directory for iOS. + * On Android it's the directory holding the application cache. + * + * @since 7.1.0 + */ + Temporary = "TEMPORARY" +} +export declare enum Encoding { + /** + * Eight-bit UCS Transformation Format + * + * @since 1.0.0 + */ + UTF8 = "utf8", + /** + * Seven-bit ASCII, a.k.a. ISO646-US, a.k.a. the Basic Latin block of the + * Unicode character set + * This encoding is only supported on Android. + * + * @since 1.0.0 + */ + ASCII = "ascii", + /** + * Sixteen-bit UCS Transformation Format, byte order identified by an + * optional byte-order mark + * This encoding is only supported on Android. + * + * @since 1.0.0 + */ + UTF16 = "utf16" +} +export interface WriteFileOptions { + /** + * The path of the file to write + * + * @since 1.0.0 + */ + path: string; + /** + * The data to write + * + * Note: Blob data is only supported on Web. + * + * @since 1.0.0 + */ + data: string | Blob; + /** + * The `Directory` to store the file in + * + * @since 1.0.0 + */ + directory?: Directory; + /** + * The encoding to write the file in. + * If not provided, binary data will be written. For this, you must provide data as base64 encoded, + * so that the plugin can decode it before writing to disk. + * If you do not provide encoding and use non-base64 data, an error will be thrown. + * + * Pass Encoding.UTF8 to write data as string + * + * @since 1.0.0 + */ + encoding?: Encoding; + /** + * Whether to create any missing parent directories. + * + * @default false + * @since 1.0.0 + */ + recursive?: boolean; +} +export interface AppendFileOptions { + /** + * The path of the file to append + * + * @since 1.0.0 + */ + path: string; + /** + * The data to append + * + * @since 1.0.0 + */ + data: string; + /** + * The `Directory` to store the file in + * + * @since 1.0.0 + */ + directory?: Directory; + /** + * The encoding to append to the file. + * If not provided, binary data will be appended. For this, you must provide data as base64 encoded, + * so that the plugin can decode it before writing to disk. + * If you do not provide encoding and use non-base64 data, an error will be thrown. + * + * Pass Encoding.UTF8 to write data as string + * + * @since 1.0.0 + */ + encoding?: Encoding; +} +export interface ReadFileOptions { + /** + * The path of the file to read + * + * @since 1.0.0 + */ + path: string; + /** + * The `Directory` to read the file from + * + * @since 1.0.0 + */ + directory?: Directory; + /** + * The encoding to read the file in, if not provided, data + * is read as binary and returned as base64 encoded. + * + * Pass Encoding.UTF8 to read data as string + * + * @since 1.0.0 + */ + encoding?: Encoding; + /** + * The offset to start reading the file from, in bytes. + * Native only (not available in web). + * Can be used in conjunction with length to partially read files. + * + * @since 8.1.0 + * @default 0 + */ + offset?: number; + /** + * The length of data to read, in bytes. + * Any non-positive value means to read to the end of the file. + * Native only (not available in web). + * Can be used in conjunction with offset to partially read files. + * + * @since 8.1.0 + * @default -1 + */ + length?: number; +} +export interface ReadFileInChunksOptions extends ReadFileOptions { + /** + * Size of the chunks in bytes. + * + * @since 7.1.0 + */ + chunkSize: number; +} +export interface DeleteFileOptions { + /** + * The path of the file to delete + * + * @since 1.0.0 + */ + path: string; + /** + * The `Directory` to delete the file from + * + * @since 1.0.0 + */ + directory?: Directory; +} +export interface MkdirOptions { + /** + * The path of the new directory + * + * @since 1.0.0 + */ + path: string; + /** + * The `Directory` to make the new directory in + * + * @since 1.0.0 + */ + directory?: Directory; + /** + * Whether to create any missing parent directories as well. + * + * @default false + * @since 1.0.0 + */ + recursive?: boolean; +} +export interface RmdirOptions { + /** + * The path of the directory to remove + * + * @since 1.0.0 + */ + path: string; + /** + * The `Directory` to remove the directory from + * + * @since 1.0.0 + */ + directory?: Directory; + /** + * Whether to recursively remove the contents of the directory + * + * @default false + * @since 1.0.0 + */ + recursive?: boolean; +} +export interface ReaddirOptions { + /** + * The path of the directory to read + * + * @since 1.0.0 + */ + path: string; + /** + * The `Directory` to list files from + * + * @since 1.0.0 + */ + directory?: Directory; +} +export interface GetUriOptions { + /** + * The path of the file to get the URI for + * + * @since 1.0.0 + */ + path: string; + /** + * The `Directory` to get the file under + * + * @since 1.0.0 + */ + directory: Directory; +} +export interface StatOptions { + /** + * The path of the file to get data about + * + * @since 1.0.0 + */ + path: string; + /** + * The `Directory` to get the file under + * + * @since 1.0.0 + */ + directory?: Directory; +} +export interface CopyOptions { + /** + * The existing file or directory + * + * @since 1.0.0 + */ + from: string; + /** + * The destination file or directory + * + * @since 1.0.0 + */ + to: string; + /** + * The `Directory` containing the existing file or directory + * + * @since 1.0.0 + */ + directory?: Directory; + /** + * The `Directory` containing the destination file or directory. If not supplied will use the 'directory' + * parameter as the destination + * + * @since 1.0.0 + */ + toDirectory?: Directory; +} +export type RenameOptions = CopyOptions; +export interface ReadFileResult { + /** + * The representation of the data contained in the file + * + * Note: Blob is only available on Web. On native, the data is returned as a string. + * + * @since 1.0.0 + */ + data: string | Blob; +} +export interface WriteFileResult { + /** + * The uri where the file was written into + * + * @since 1.0.0 + */ + uri: string; +} +export interface ReaddirResult { + /** + * List of files and directories inside the directory + * + * @since 1.0.0 + */ + files: FileInfo[]; +} +export interface FileInfo { + /** + * Name of the file or directory. + * + * @since 7.1.0 + */ + name: string; + /** + * Type of the file. + * + * @since 4.0.0 + */ + type: 'directory' | 'file'; + /** + * Size of the file in bytes. + * + * @since 4.0.0 + */ + size: number; + /** + * Time of creation in milliseconds. + * + * It's not available on Android 7 and older devices. + * + * @since 7.1.0 + */ + ctime?: number; + /** + * Time of last modification in milliseconds. + * + * @since 7.1.0 + */ + mtime: number; + /** + * The uri of the file. + * + * @since 4.0.0 + */ + uri: string; +} +export interface GetUriResult { + /** + * The uri of the file + * + * @since 1.0.0 + */ + uri: string; +} +export type StatResult = FileInfo; +export interface CopyResult { + /** + * The uri where the file was copied into + * + * @since 4.0.0 + */ + uri: string; +} +export interface DownloadFileOptions extends HttpOptions { + /** + * The path the downloaded file should be moved to. + * + * @since 5.1.0 + */ + path: string; + /** + * The directory to write the file to. + * If this option is used, filePath can be a relative path rather than absolute. + * The default is the `DATA` directory. + * + * @since 5.1.0 + */ + directory?: Directory; + /** + * An optional listener function to receive downloaded progress events. + * If this option is used, progress event should be dispatched on every chunk received. + * Chunks are throttled to every 100ms on Android/iOS to avoid slowdowns. + * + * @since 5.1.0 + */ + progress?: boolean; + /** + * Whether to create any missing parent directories. + * + * @default false + * @since 5.1.2 + */ + recursive?: boolean; +} +export interface DownloadFileResult { + /** + * The path the file was downloaded to. + * + * @since 5.1.0 + */ + path?: string; + /** + * The blob data of the downloaded file. + * This is only available on web. + * + * @since 5.1.0 + */ + blob?: Blob; +} +export interface ProgressStatus { + /** + * The url of the file being downloaded. + * + * @since 5.1.0 + */ + url: string; + /** + * The number of bytes downloaded so far. + * + * @since 5.1.0 + */ + bytes: number; + /** + * The total number of bytes to download for this file. + * + * @since 5.1.0 + */ + contentLength: number; +} +/** + * Callback for receiving chunks read from a file, or error if something went wrong. + * + * @since 7.1.0 + */ +export type ReadFileInChunksCallback = (chunkRead: ReadFileResult | null, err?: any) => void; +/** + * A listener function that receives progress events. + * + * @since 5.1.0 + */ +export type ProgressListener = (progress: ProgressStatus) => void; +export interface FilesystemPlugin { + /** + * Check read/write permissions. + * Required on Android, only when using `Directory.Documents` or + * `Directory.ExternalStorage`. + * + * @since 1.0.0 + */ + checkPermissions(): Promise; + /** + * Request read/write permissions. + * Required on Android, only when using `Directory.Documents` or + * `Directory.ExternalStorage`. + * + * @since 1.0.0 + */ + requestPermissions(): Promise; + /** + * Read a file from disk + * + * @since 1.0.0 + */ + readFile(options: ReadFileOptions): Promise; + /** + * Read a file from disk, in chunks. + * Native only (not available in web). + * Use the callback to receive each read chunk. + * If empty chunk is returned, it means file has been completely read. + * + * @since 7.1.0 + */ + readFileInChunks(options: ReadFileInChunksOptions, callback: ReadFileInChunksCallback): Promise; + /** + * Write a file to disk in the specified location on device + * + * @since 1.0.0 + */ + writeFile(options: WriteFileOptions): Promise; + /** + * Append to a file on disk in the specified location on device + * + * @since 1.0.0 + */ + appendFile(options: AppendFileOptions): Promise; + /** + * Delete a file from disk + * + * @since 1.0.0 + */ + deleteFile(options: DeleteFileOptions): Promise; + /** + * Create a directory. + * + * @since 1.0.0 + */ + mkdir(options: MkdirOptions): Promise; + /** + * Remove a directory + * + * @since 1.0.0 + */ + rmdir(options: RmdirOptions): Promise; + /** + * Return a list of files from the directory (not recursive) + * + * @since 1.0.0 + */ + readdir(options: ReaddirOptions): Promise; + /** + * Return full File URI for a path and directory + * + * @since 1.0.0 + */ + getUri(options: GetUriOptions): Promise; + /** + * Return data about a file + * + * @since 1.0.0 + */ + stat(options: StatOptions): Promise; + /** + * Rename a file or directory + * + * @since 1.0.0 + */ + rename(options: RenameOptions): Promise; + /** + * Copy a file or directory + * + * @since 1.0.0 + */ + copy(options: CopyOptions): Promise; + /** + * Perform a http request to a server and download the file to the specified destination. + * + * This method has been deprecated since version 7.1.0. + * We recommend using the @capacitor/file-transfer plugin instead, in conjunction with this plugin. + * + * @since 5.1.0 + * @deprecated Use the @capacitor/file-transfer plugin instead. + */ + downloadFile(options: DownloadFileOptions): Promise; + /** + * Add a listener to file download progress events. + * + * This method has been deprecated since version 7.1.0. + * We recommend using the @capacitor/file-transfer plugin instead, in conjunction with this plugin. + * + * @since 5.1.0 + * @deprecated Use the @capacitor/file-transfer plugin instead. + */ + addListener(eventName: 'progress', listenerFunc: ProgressListener): Promise; + /** + * Remove all listeners for this plugin. + * + * This method has been deprecated since version 7.1.0. + * We recommend using the @capacitor/file-transfer plugin instead, in conjunction with this plugin. + * + * @since 5.2.0 + * @deprecated Use the @capacitor/file-transfer plugin instead. + */ + removeAllListeners(): Promise; +} +/** + * Structure for errors returned by the plugin. + * + * `code` follows "OS-PLUG-FILE-XXXX" format + * + * @since 1.0.0 + */ +export type PluginError = { + code: string; + message: string; +}; +/** + * @deprecated Use `ReadFileOptions`. + * @since 1.0.0 + */ +export type FileReadOptions = ReadFileOptions; +/** + * @deprecated Use `ReadFileResult`. + * @since 1.0.0 + */ +export type FileReadResult = ReadFileResult; +/** + * @deprecated Use `WriteFileOptions`. + * @since 1.0.0 + */ +export type FileWriteOptions = WriteFileOptions; +/** + * @deprecated Use `WriteFileResult`. + * @since 1.0.0 + */ +export type FileWriteResult = WriteFileResult; +/** + * @deprecated Use `AppendFileOptions`. + * @since 1.0.0 + */ +export type FileAppendOptions = AppendFileOptions; +/** + * @deprecated Use `DeleteFileOptions`. + * @since 1.0.0 + */ +export type FileDeleteOptions = DeleteFileOptions; +/** + * @deprecated Use `Directory`. + * @since 1.0.0 + */ +export declare const FilesystemDirectory: typeof Directory; +/** + * @deprecated Use `Encoding`. + * @since 1.0.0 + */ +export declare const FilesystemEncoding: typeof Encoding; diff --git a/node_modules/@capacitor/filesystem/dist/esm/definitions.js b/node_modules/@capacitor/filesystem/dist/esm/definitions.js new file mode 100644 index 0000000..bed6b17 --- /dev/null +++ b/node_modules/@capacitor/filesystem/dist/esm/definitions.js @@ -0,0 +1,124 @@ +export var Directory; +(function (Directory) { + /** + * The Documents directory. + * On iOS it's the app's documents directory. + * Use this directory to store user-generated content. + * On Android it's the Public Documents folder, so it's accessible from other apps. + * It's not accessible on Android 10 unless the app enables legacy External Storage + * by adding `android:requestLegacyExternalStorage="true"` in the `application` tag + * in the `AndroidManifest.xml`. + * On Android 11 or newer the app can only access the files/folders the app created. + * + * @since 1.0.0 + */ + Directory["Documents"] = "DOCUMENTS"; + /** + * The Data directory. + * On iOS it will use the Documents directory. + * On Android it's the directory holding application files. + * Files will be deleted when the application is uninstalled. + * + * @since 1.0.0 + */ + Directory["Data"] = "DATA"; + /** + * The Library directory. + * On iOS it will use the Library directory. + * On Android it's the directory holding application files. + * Files will be deleted when the application is uninstalled. + * + * @since 1.1.0 + */ + Directory["Library"] = "LIBRARY"; + /** + * The Cache directory. + * Can be deleted in cases of low memory, so use this directory to write app-specific files. + * that your app can re-create easily. + * + * @since 1.0.0 + */ + Directory["Cache"] = "CACHE"; + /** + * The external directory. + * On iOS it will use the Documents directory. + * On Android it's the directory on the primary shared/external + * storage device where the application can place persistent files it owns. + * These files are internal to the applications, and not typically visible + * to the user as media. + * Files will be deleted when the application is uninstalled. + * + * @since 1.0.0 + */ + Directory["External"] = "EXTERNAL"; + /** + * The external storage directory. + * On iOS it will use the Documents directory. + * On Android it's the primary shared/external storage directory. + * It's not accessible on Android 10 unless the app enables legacy External Storage + * by adding `android:requestLegacyExternalStorage="true"` in the `application` tag + * in the `AndroidManifest.xml`. + * It's not accessible on Android 11 or newer. + * + * @since 1.0.0 + */ + Directory["ExternalStorage"] = "EXTERNAL_STORAGE"; + /** + * The external cache directory. + * On iOS it will use the Documents directory. + * On Android it's the primary shared/external cache. + * + * @since 7.1.0 + */ + Directory["ExternalCache"] = "EXTERNAL_CACHE"; + /** + * The Library directory without cloud backup. Used in iOS. + * On Android it's the directory holding application files. + * + * @since 7.1.0 + */ + Directory["LibraryNoCloud"] = "LIBRARY_NO_CLOUD"; + /** + * A temporary directory for iOS. + * On Android it's the directory holding the application cache. + * + * @since 7.1.0 + */ + Directory["Temporary"] = "TEMPORARY"; +})(Directory || (Directory = {})); +export var Encoding; +(function (Encoding) { + /** + * Eight-bit UCS Transformation Format + * + * @since 1.0.0 + */ + Encoding["UTF8"] = "utf8"; + /** + * Seven-bit ASCII, a.k.a. ISO646-US, a.k.a. the Basic Latin block of the + * Unicode character set + * This encoding is only supported on Android. + * + * @since 1.0.0 + */ + Encoding["ASCII"] = "ascii"; + /** + * Sixteen-bit UCS Transformation Format, byte order identified by an + * optional byte-order mark + * This encoding is only supported on Android. + * + * @since 1.0.0 + */ + Encoding["UTF16"] = "utf16"; +})(Encoding || (Encoding = {})); +/** + * @deprecated Use `Directory`. + * @since 1.0.0 + */ +export const FilesystemDirectory = Directory; +/** + * @deprecated Use `Encoding`. + * @since 1.0.0 + */ +export const FilesystemEncoding = Encoding; +//# sourceMappingURL=definitions.js.map \ No newline at end of file diff --git a/node_modules/@capacitor/filesystem/dist/esm/definitions.js.map b/node_modules/@capacitor/filesystem/dist/esm/definitions.js.map new file mode 100644 index 0000000..d2eb73a --- /dev/null +++ b/node_modules/@capacitor/filesystem/dist/esm/definitions.js.map @@ -0,0 +1 @@ +{"version":3,"file":"definitions.js","sourceRoot":"","sources":["../../src/definitions.ts"],"names":[],"mappings":"AAQA,MAAM,CAAN,IAAY,SA8FX;AA9FD,WAAY,SAAS;IACnB;;;;;;;;;;;OAWG;IACH,oCAAuB,CAAA;IAEvB;;;;;;;OAOG;IACH,0BAAa,CAAA;IAEb;;;;;;;OAOG;IACH,gCAAmB,CAAA;IAEnB;;;;;;OAMG;IACH,4BAAe,CAAA;IAEf;;;;;;;;;;OAUG;IACH,kCAAqB,CAAA;IAErB;;;;;;;;;;OAUG;IAEH,iDAAoC,CAAA;IACpC;;;;;;OAMG;IACH,6CAAgC,CAAA;IAEhC;;;;;OAKG;IACH,gDAAmC,CAAA;IAEnC;;;;;OAKG;IACH,oCAAuB,CAAA;AACzB,CAAC,EA9FW,SAAS,KAAT,SAAS,QA8FpB;AAED,MAAM,CAAN,IAAY,QAyBX;AAzBD,WAAY,QAAQ;IAClB;;;;OAIG;IACH,yBAAa,CAAA;IAEb;;;;;;OAMG;IACH,2BAAe,CAAA;IAEf;;;;;;OAMG;IACH,2BAAe,CAAA;AACjB,CAAC,EAzBW,QAAQ,KAAR,QAAQ,QAyBnB;AAwoBD;;;GAGG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,SAAS,CAAC;AAE7C;;;GAGG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,QAAQ,CAAC","sourcesContent":["import type { HttpOptions, PermissionState, PluginListenerHandle } from '@capacitor/core';\n\nexport type CallbackID = string;\n\nexport interface PermissionStatus {\n publicStorage: PermissionState;\n}\n\nexport enum Directory {\n /**\n * The Documents directory.\n * On iOS it's the app's documents directory.\n * Use this directory to store user-generated content.\n * On Android it's the Public Documents folder, so it's accessible from other apps.\n * It's not accessible on Android 10 unless the app enables legacy External Storage\n * by adding `android:requestLegacyExternalStorage=\"true\"` in the `application` tag\n * in the `AndroidManifest.xml`.\n * On Android 11 or newer the app can only access the files/folders the app created.\n *\n * @since 1.0.0\n */\n Documents = 'DOCUMENTS',\n\n /**\n * The Data directory.\n * On iOS it will use the Documents directory.\n * On Android it's the directory holding application files.\n * Files will be deleted when the application is uninstalled.\n *\n * @since 1.0.0\n */\n Data = 'DATA',\n\n /**\n * The Library directory.\n * On iOS it will use the Library directory.\n * On Android it's the directory holding application files.\n * Files will be deleted when the application is uninstalled.\n *\n * @since 1.1.0\n */\n Library = 'LIBRARY',\n\n /**\n * The Cache directory.\n * Can be deleted in cases of low memory, so use this directory to write app-specific files.\n * that your app can re-create easily.\n *\n * @since 1.0.0\n */\n Cache = 'CACHE',\n\n /**\n * The external directory.\n * On iOS it will use the Documents directory.\n * On Android it's the directory on the primary shared/external\n * storage device where the application can place persistent files it owns.\n * These files are internal to the applications, and not typically visible\n * to the user as media.\n * Files will be deleted when the application is uninstalled.\n *\n * @since 1.0.0\n */\n External = 'EXTERNAL',\n\n /**\n * The external storage directory.\n * On iOS it will use the Documents directory.\n * On Android it's the primary shared/external storage directory.\n * It's not accessible on Android 10 unless the app enables legacy External Storage\n * by adding `android:requestLegacyExternalStorage=\"true\"` in the `application` tag\n * in the `AndroidManifest.xml`.\n * It's not accessible on Android 11 or newer.\n *\n * @since 1.0.0\n */\n\n ExternalStorage = 'EXTERNAL_STORAGE',\n /**\n * The external cache directory.\n * On iOS it will use the Documents directory.\n * On Android it's the primary shared/external cache.\n *\n * @since 7.1.0\n */\n ExternalCache = 'EXTERNAL_CACHE',\n\n /**\n * The Library directory without cloud backup. Used in iOS.\n * On Android it's the directory holding application files.\n *\n * @since 7.1.0\n */\n LibraryNoCloud = 'LIBRARY_NO_CLOUD',\n\n /**\n * A temporary directory for iOS.\n * On Android it's the directory holding the application cache.\n *\n * @since 7.1.0\n */\n Temporary = 'TEMPORARY',\n}\n\nexport enum Encoding {\n /**\n * Eight-bit UCS Transformation Format\n *\n * @since 1.0.0\n */\n UTF8 = 'utf8',\n\n /**\n * Seven-bit ASCII, a.k.a. ISO646-US, a.k.a. the Basic Latin block of the\n * Unicode character set\n * This encoding is only supported on Android.\n *\n * @since 1.0.0\n */\n ASCII = 'ascii',\n\n /**\n * Sixteen-bit UCS Transformation Format, byte order identified by an\n * optional byte-order mark\n * This encoding is only supported on Android.\n *\n * @since 1.0.0\n */\n UTF16 = 'utf16',\n}\n\nexport interface WriteFileOptions {\n /**\n * The path of the file to write\n *\n * @since 1.0.0\n */\n path: string;\n\n /**\n * The data to write\n *\n * Note: Blob data is only supported on Web.\n *\n * @since 1.0.0\n */\n data: string | Blob;\n\n /**\n * The `Directory` to store the file in\n *\n * @since 1.0.0\n */\n directory?: Directory;\n\n /**\n * The encoding to write the file in.\n * If not provided, binary data will be written. For this, you must provide data as base64 encoded,\n * so that the plugin can decode it before writing to disk.\n * If you do not provide encoding and use non-base64 data, an error will be thrown.\n *\n * Pass Encoding.UTF8 to write data as string\n *\n * @since 1.0.0\n */\n encoding?: Encoding;\n\n /**\n * Whether to create any missing parent directories.\n *\n * @default false\n * @since 1.0.0\n */\n recursive?: boolean;\n}\n\nexport interface AppendFileOptions {\n /**\n * The path of the file to append\n *\n * @since 1.0.0\n */\n path: string;\n\n /**\n * The data to append\n *\n * @since 1.0.0\n */\n data: string;\n\n /**\n * The `Directory` to store the file in\n *\n * @since 1.0.0\n */\n directory?: Directory;\n\n /**\n * The encoding to append to the file.\n * If not provided, binary data will be appended. For this, you must provide data as base64 encoded,\n * so that the plugin can decode it before writing to disk.\n * If you do not provide encoding and use non-base64 data, an error will be thrown.\n *\n * Pass Encoding.UTF8 to write data as string\n *\n * @since 1.0.0\n */\n encoding?: Encoding;\n}\n\nexport interface ReadFileOptions {\n /**\n * The path of the file to read\n *\n * @since 1.0.0\n */\n path: string;\n\n /**\n * The `Directory` to read the file from\n *\n * @since 1.0.0\n */\n directory?: Directory;\n\n /**\n * The encoding to read the file in, if not provided, data\n * is read as binary and returned as base64 encoded.\n *\n * Pass Encoding.UTF8 to read data as string\n *\n * @since 1.0.0\n */\n encoding?: Encoding;\n\n /**\n * The offset to start reading the file from, in bytes.\n * Native only (not available in web).\n * Can be used in conjunction with length to partially read files.\n *\n * @since 8.1.0\n * @default 0\n */\n offset?: number;\n\n /**\n * The length of data to read, in bytes.\n * Any non-positive value means to read to the end of the file.\n * Native only (not available in web).\n * Can be used in conjunction with offset to partially read files.\n *\n * @since 8.1.0\n * @default -1\n */\n length?: number;\n}\n\nexport interface ReadFileInChunksOptions extends ReadFileOptions {\n /**\n * Size of the chunks in bytes.\n *\n * @since 7.1.0\n */\n chunkSize: number;\n}\n\nexport interface DeleteFileOptions {\n /**\n * The path of the file to delete\n *\n * @since 1.0.0\n */\n path: string;\n\n /**\n * The `Directory` to delete the file from\n *\n * @since 1.0.0\n */\n directory?: Directory;\n}\n\nexport interface MkdirOptions {\n /**\n * The path of the new directory\n *\n * @since 1.0.0\n */\n path: string;\n\n /**\n * The `Directory` to make the new directory in\n *\n * @since 1.0.0\n */\n directory?: Directory;\n\n /**\n * Whether to create any missing parent directories as well.\n *\n * @default false\n * @since 1.0.0\n */\n recursive?: boolean;\n}\n\nexport interface RmdirOptions {\n /**\n * The path of the directory to remove\n *\n * @since 1.0.0\n */\n path: string;\n\n /**\n * The `Directory` to remove the directory from\n *\n * @since 1.0.0\n */\n directory?: Directory;\n\n /**\n * Whether to recursively remove the contents of the directory\n *\n * @default false\n * @since 1.0.0\n */\n recursive?: boolean;\n}\n\nexport interface ReaddirOptions {\n /**\n * The path of the directory to read\n *\n * @since 1.0.0\n */\n path: string;\n\n /**\n * The `Directory` to list files from\n *\n * @since 1.0.0\n */\n directory?: Directory;\n}\n\nexport interface GetUriOptions {\n /**\n * The path of the file to get the URI for\n *\n * @since 1.0.0\n */\n path: string;\n\n /**\n * The `Directory` to get the file under\n *\n * @since 1.0.0\n */\n directory: Directory;\n}\n\nexport interface StatOptions {\n /**\n * The path of the file to get data about\n *\n * @since 1.0.0\n */\n path: string;\n\n /**\n * The `Directory` to get the file under\n *\n * @since 1.0.0\n */\n directory?: Directory;\n}\n\nexport interface CopyOptions {\n /**\n * The existing file or directory\n *\n * @since 1.0.0\n */\n from: string;\n\n /**\n * The destination file or directory\n *\n * @since 1.0.0\n */\n to: string;\n\n /**\n * The `Directory` containing the existing file or directory\n *\n * @since 1.0.0\n */\n directory?: Directory;\n\n /**\n * The `Directory` containing the destination file or directory. If not supplied will use the 'directory'\n * parameter as the destination\n *\n * @since 1.0.0\n */\n toDirectory?: Directory;\n}\n\nexport type RenameOptions = CopyOptions;\n\nexport interface ReadFileResult {\n /**\n * The representation of the data contained in the file\n *\n * Note: Blob is only available on Web. On native, the data is returned as a string.\n *\n * @since 1.0.0\n */\n data: string | Blob;\n}\n\nexport interface WriteFileResult {\n /**\n * The uri where the file was written into\n *\n * @since 1.0.0\n */\n uri: string;\n}\n\nexport interface ReaddirResult {\n /**\n * List of files and directories inside the directory\n *\n * @since 1.0.0\n */\n files: FileInfo[];\n}\n\nexport interface FileInfo {\n /**\n * Name of the file or directory.\n *\n * @since 7.1.0\n */\n name: string;\n\n /**\n * Type of the file.\n *\n * @since 4.0.0\n */\n type: 'directory' | 'file';\n\n /**\n * Size of the file in bytes.\n *\n * @since 4.0.0\n */\n size: number;\n\n /**\n * Time of creation in milliseconds.\n *\n * It's not available on Android 7 and older devices.\n *\n * @since 7.1.0\n */\n ctime?: number;\n\n /**\n * Time of last modification in milliseconds.\n *\n * @since 7.1.0\n */\n mtime: number;\n\n /**\n * The uri of the file.\n *\n * @since 4.0.0\n */\n uri: string;\n}\n\nexport interface GetUriResult {\n /**\n * The uri of the file\n *\n * @since 1.0.0\n */\n uri: string;\n}\n\nexport type StatResult = FileInfo;\nexport interface CopyResult {\n /**\n * The uri where the file was copied into\n *\n * @since 4.0.0\n */\n uri: string;\n}\n\nexport interface DownloadFileOptions extends HttpOptions {\n /**\n * The path the downloaded file should be moved to.\n *\n * @since 5.1.0\n */\n path: string;\n /**\n * The directory to write the file to.\n * If this option is used, filePath can be a relative path rather than absolute.\n * The default is the `DATA` directory.\n *\n * @since 5.1.0\n */\n directory?: Directory;\n /**\n * An optional listener function to receive downloaded progress events.\n * If this option is used, progress event should be dispatched on every chunk received.\n * Chunks are throttled to every 100ms on Android/iOS to avoid slowdowns.\n *\n * @since 5.1.0\n */\n progress?: boolean;\n /**\n * Whether to create any missing parent directories.\n *\n * @default false\n * @since 5.1.2\n */\n recursive?: boolean;\n}\n\nexport interface DownloadFileResult {\n /**\n * The path the file was downloaded to.\n *\n * @since 5.1.0\n */\n path?: string;\n /**\n * The blob data of the downloaded file.\n * This is only available on web.\n *\n * @since 5.1.0\n */\n blob?: Blob;\n}\n\nexport interface ProgressStatus {\n /**\n * The url of the file being downloaded.\n *\n * @since 5.1.0\n */\n url: string;\n /**\n * The number of bytes downloaded so far.\n *\n * @since 5.1.0\n */\n bytes: number;\n /**\n * The total number of bytes to download for this file.\n *\n * @since 5.1.0\n */\n contentLength: number;\n}\n\n/**\n * Callback for receiving chunks read from a file, or error if something went wrong.\n *\n * @since 7.1.0\n */\nexport type ReadFileInChunksCallback = (chunkRead: ReadFileResult | null, err?: any) => void;\n\n/**\n * A listener function that receives progress events.\n *\n * @since 5.1.0\n */\nexport type ProgressListener = (progress: ProgressStatus) => void;\n\nexport interface FilesystemPlugin {\n /**\n * Check read/write permissions.\n * Required on Android, only when using `Directory.Documents` or\n * `Directory.ExternalStorage`.\n *\n * @since 1.0.0\n */\n checkPermissions(): Promise;\n\n /**\n * Request read/write permissions.\n * Required on Android, only when using `Directory.Documents` or\n * `Directory.ExternalStorage`.\n *\n * @since 1.0.0\n */\n requestPermissions(): Promise;\n\n /**\n * Read a file from disk\n *\n * @since 1.0.0\n */\n readFile(options: ReadFileOptions): Promise;\n\n /**\n * Read a file from disk, in chunks.\n * Native only (not available in web).\n * Use the callback to receive each read chunk.\n * If empty chunk is returned, it means file has been completely read.\n *\n * @since 7.1.0\n */\n readFileInChunks(options: ReadFileInChunksOptions, callback: ReadFileInChunksCallback): Promise;\n\n /**\n * Write a file to disk in the specified location on device\n *\n * @since 1.0.0\n */\n writeFile(options: WriteFileOptions): Promise;\n\n /**\n * Append to a file on disk in the specified location on device\n *\n * @since 1.0.0\n */\n appendFile(options: AppendFileOptions): Promise;\n\n /**\n * Delete a file from disk\n *\n * @since 1.0.0\n */\n deleteFile(options: DeleteFileOptions): Promise;\n\n /**\n * Create a directory.\n *\n * @since 1.0.0\n */\n mkdir(options: MkdirOptions): Promise;\n\n /**\n * Remove a directory\n *\n * @since 1.0.0\n */\n rmdir(options: RmdirOptions): Promise;\n\n /**\n * Return a list of files from the directory (not recursive)\n *\n * @since 1.0.0\n */\n readdir(options: ReaddirOptions): Promise;\n\n /**\n * Return full File URI for a path and directory\n *\n * @since 1.0.0\n */\n getUri(options: GetUriOptions): Promise;\n\n /**\n * Return data about a file\n *\n * @since 1.0.0\n */\n stat(options: StatOptions): Promise;\n\n /**\n * Rename a file or directory\n *\n * @since 1.0.0\n */\n rename(options: RenameOptions): Promise;\n\n /**\n * Copy a file or directory\n *\n * @since 1.0.0\n */\n copy(options: CopyOptions): Promise;\n\n /**\n * Perform a http request to a server and download the file to the specified destination.\n *\n * This method has been deprecated since version 7.1.0.\n * We recommend using the @capacitor/file-transfer plugin instead, in conjunction with this plugin.\n *\n * @since 5.1.0\n * @deprecated Use the @capacitor/file-transfer plugin instead.\n */\n downloadFile(options: DownloadFileOptions): Promise;\n\n /**\n * Add a listener to file download progress events.\n *\n * This method has been deprecated since version 7.1.0.\n * We recommend using the @capacitor/file-transfer plugin instead, in conjunction with this plugin.\n *\n * @since 5.1.0\n * @deprecated Use the @capacitor/file-transfer plugin instead.\n */\n addListener(eventName: 'progress', listenerFunc: ProgressListener): Promise;\n\n /**\n * Remove all listeners for this plugin.\n *\n * This method has been deprecated since version 7.1.0.\n * We recommend using the @capacitor/file-transfer plugin instead, in conjunction with this plugin.\n *\n * @since 5.2.0\n * @deprecated Use the @capacitor/file-transfer plugin instead.\n */\n removeAllListeners(): Promise;\n}\n\n/**\n * Structure for errors returned by the plugin.\n *\n * `code` follows \"OS-PLUG-FILE-XXXX\" format\n *\n * @since 1.0.0\n */\nexport type PluginError = {\n code: string;\n message: string;\n};\n\n/**\n * @deprecated Use `ReadFileOptions`.\n * @since 1.0.0\n */\nexport type FileReadOptions = ReadFileOptions;\n\n/**\n * @deprecated Use `ReadFileResult`.\n * @since 1.0.0\n */\nexport type FileReadResult = ReadFileResult;\n\n/**\n * @deprecated Use `WriteFileOptions`.\n * @since 1.0.0\n */\nexport type FileWriteOptions = WriteFileOptions;\n\n/**\n * @deprecated Use `WriteFileResult`.\n * @since 1.0.0\n */\nexport type FileWriteResult = WriteFileResult;\n\n/**\n * @deprecated Use `AppendFileOptions`.\n * @since 1.0.0\n */\nexport type FileAppendOptions = AppendFileOptions;\n\n/**\n * @deprecated Use `DeleteFileOptions`.\n * @since 1.0.0\n */\nexport type FileDeleteOptions = DeleteFileOptions;\n\n/**\n * @deprecated Use `Directory`.\n * @since 1.0.0\n */\nexport const FilesystemDirectory = Directory;\n\n/**\n * @deprecated Use `Encoding`.\n * @since 1.0.0\n */\nexport const FilesystemEncoding = Encoding;\n"]} \ No newline at end of file diff --git a/node_modules/@capacitor/filesystem/dist/esm/index.d.ts b/node_modules/@capacitor/filesystem/dist/esm/index.d.ts new file mode 100644 index 0000000..db60658 --- /dev/null +++ b/node_modules/@capacitor/filesystem/dist/esm/index.d.ts @@ -0,0 +1,4 @@ +import type { FilesystemPlugin } from './definitions'; +declare const Filesystem: FilesystemPlugin; +export * from './definitions'; +export { Filesystem }; diff --git a/node_modules/@capacitor/filesystem/dist/esm/index.js b/node_modules/@capacitor/filesystem/dist/esm/index.js new file mode 100644 index 0000000..ffc0972 --- /dev/null +++ b/node_modules/@capacitor/filesystem/dist/esm/index.js @@ -0,0 +1,9 @@ +import { registerPlugin } from '@capacitor/core'; +import { exposeSynapse } from '@capacitor/synapse'; +const Filesystem = registerPlugin('Filesystem', { + web: () => import('./web').then((m) => new m.FilesystemWeb()), +}); +exposeSynapse(); +export * from './definitions'; +export { Filesystem }; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/node_modules/@capacitor/filesystem/dist/esm/index.js.map b/node_modules/@capacitor/filesystem/dist/esm/index.js.map new file mode 100644 index 0000000..69606f5 --- /dev/null +++ b/node_modules/@capacitor/filesystem/dist/esm/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAInD,MAAM,UAAU,GAAG,cAAc,CAAmB,YAAY,EAAE;IAChE,GAAG,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,aAAa,EAAE,CAAC;CAC9D,CAAC,CAAC;AAEH,aAAa,EAAE,CAAC;AAEhB,cAAc,eAAe,CAAC;AAC9B,OAAO,EAAE,UAAU,EAAE,CAAC","sourcesContent":["import { registerPlugin } from '@capacitor/core';\nimport { exposeSynapse } from '@capacitor/synapse';\n\nimport type { FilesystemPlugin } from './definitions';\n\nconst Filesystem = registerPlugin('Filesystem', {\n web: () => import('./web').then((m) => new m.FilesystemWeb()),\n});\n\nexposeSynapse();\n\nexport * from './definitions';\nexport { Filesystem };\n"]} \ No newline at end of file diff --git a/node_modules/@capacitor/filesystem/dist/esm/web.d.ts b/node_modules/@capacitor/filesystem/dist/esm/web.d.ts new file mode 100644 index 0000000..9616744 --- /dev/null +++ b/node_modules/@capacitor/filesystem/dist/esm/web.d.ts @@ -0,0 +1,99 @@ +import { WebPlugin } from '@capacitor/core'; +import type { AppendFileOptions, CopyOptions, CopyResult, DeleteFileOptions, FilesystemPlugin, GetUriOptions, GetUriResult, MkdirOptions, PermissionStatus, ReadFileOptions, ReadFileResult, ReaddirOptions, ReaddirResult, RenameOptions, RmdirOptions, StatOptions, StatResult, WriteFileOptions, WriteFileResult, ReadFileInChunksOptions, CallbackID, DownloadFileOptions, DownloadFileResult, ReadFileInChunksCallback } from './definitions'; +export declare class FilesystemWeb extends WebPlugin implements FilesystemPlugin { + readFileInChunks(_options: ReadFileInChunksOptions, _callback: ReadFileInChunksCallback): Promise; + DB_VERSION: number; + DB_NAME: string; + private _writeCmds; + private _db?; + static _debug: boolean; + initDb(): Promise; + static doUpgrade(event: IDBVersionChangeEvent): void; + dbRequest(cmd: string, args: any[]): Promise; + dbIndexRequest(indexName: string, cmd: string, args: [any]): Promise; + private getPath; + clear(): Promise; + /** + * Read a file from disk + * @param options options for the file read + * @return a promise that resolves with the read file data result + */ + readFile(options: ReadFileOptions): Promise; + /** + * Write a file to disk in the specified location on device + * @param options options for the file write + * @return a promise that resolves with the file write result + */ + writeFile(options: WriteFileOptions): Promise; + /** + * Append to a file on disk in the specified location on device + * @param options options for the file append + * @return a promise that resolves with the file write result + */ + appendFile(options: AppendFileOptions): Promise; + /** + * Delete a file from disk + * @param options options for the file delete + * @return a promise that resolves with the deleted file data result + */ + deleteFile(options: DeleteFileOptions): Promise; + /** + * Create a directory. + * @param options options for the mkdir + * @return a promise that resolves with the mkdir result + */ + mkdir(options: MkdirOptions): Promise; + /** + * Remove a directory + * @param options the options for the directory remove + */ + rmdir(options: RmdirOptions): Promise; + /** + * Return a list of files from the directory (not recursive) + * @param options the options for the readdir operation + * @return a promise that resolves with the readdir directory listing result + */ + readdir(options: ReaddirOptions): Promise; + /** + * Return full File URI for a path and directory + * @param options the options for the stat operation + * @return a promise that resolves with the file stat result + */ + getUri(options: GetUriOptions): Promise; + /** + * Return data about a file + * @param options the options for the stat operation + * @return a promise that resolves with the file stat result + */ + stat(options: StatOptions): Promise; + /** + * Rename a file or directory + * @param options the options for the rename operation + * @return a promise that resolves with the rename result + */ + rename(options: RenameOptions): Promise; + /** + * Copy a file or directory + * @param options the options for the copy operation + * @return a promise that resolves with the copy result + */ + copy(options: CopyOptions): Promise; + requestPermissions(): Promise; + checkPermissions(): Promise; + /** + * Function that can perform a copy or a rename + * @param options the options for the rename operation + * @param doRename whether to perform a rename or copy operation + * @return a promise that resolves with the result + */ + private _copy; + /** + * Function that performs a http request to a server and downloads the file to the specified destination + * + * @deprecated Use the @capacitor/file-transfer plugin instead. + * @param options the options for the download operation + * @returns a promise that resolves with the download file result + */ + downloadFile: (options: DownloadFileOptions) => Promise; + private isBase64String; +} diff --git a/node_modules/@capacitor/filesystem/dist/esm/web.js b/node_modules/@capacitor/filesystem/dist/esm/web.js new file mode 100644 index 0000000..de518c3 --- /dev/null +++ b/node_modules/@capacitor/filesystem/dist/esm/web.js @@ -0,0 +1,596 @@ +import { WebPlugin, buildRequestInit } from '@capacitor/core'; +import { Encoding } from './definitions'; +function resolve(path) { + const posix = path.split('/').filter((item) => item !== '.'); + const newPosix = []; + posix.forEach((item) => { + if (item === '..' && newPosix.length > 0 && newPosix[newPosix.length - 1] !== '..') { + newPosix.pop(); + } + else { + newPosix.push(item); + } + }); + return newPosix.join('/'); +} +function isPathParent(parent, children) { + parent = resolve(parent); + children = resolve(children); + const pathsA = parent.split('/'); + const pathsB = children.split('/'); + return parent !== children && pathsA.every((value, index) => value === pathsB[index]); +} +export class FilesystemWeb extends WebPlugin { + constructor() { + super(...arguments); + this.DB_VERSION = 1; + this.DB_NAME = 'Disc'; + this._writeCmds = ['add', 'put', 'delete']; + /** + * Function that performs a http request to a server and downloads the file to the specified destination + * + * @deprecated Use the @capacitor/file-transfer plugin instead. + * @param options the options for the download operation + * @returns a promise that resolves with the download file result + */ + this.downloadFile = async (options) => { + var _a, _b; + const requestInit = buildRequestInit(options, options.webFetchExtra); + const response = await fetch(options.url, requestInit); + let blob; + if (!options.progress) + blob = await response.blob(); + else if (!(response === null || response === void 0 ? void 0 : response.body)) + blob = new Blob(); + else { + const reader = response.body.getReader(); + let bytes = 0; + const chunks = []; + const contentType = response.headers.get('content-type'); + const contentLength = parseInt(response.headers.get('content-length') || '0', 10); + while (true) { + const { done, value } = await reader.read(); + if (done) + break; + chunks.push(value); + bytes += (value === null || value === void 0 ? void 0 : value.length) || 0; + const status = { + url: options.url, + bytes, + contentLength, + }; + this.notifyListeners('progress', status); + } + const allChunks = new Uint8Array(bytes); + let position = 0; + for (const chunk of chunks) { + if (typeof chunk === 'undefined') + continue; + allChunks.set(chunk, position); + position += chunk.length; + } + blob = new Blob([allChunks.buffer], { type: contentType || undefined }); + } + const result = await this.writeFile({ + path: options.path, + directory: (_a = options.directory) !== null && _a !== void 0 ? _a : undefined, + recursive: (_b = options.recursive) !== null && _b !== void 0 ? _b : false, + data: blob, + }); + return { path: result.uri, blob }; + }; + } + readFileInChunks(_options, _callback) { + throw this.unavailable('Method not implemented.'); + } + async initDb() { + if (this._db !== undefined) { + return this._db; + } + if (!('indexedDB' in window)) { + throw this.unavailable("This browser doesn't support IndexedDB"); + } + return new Promise((resolve, reject) => { + const request = indexedDB.open(this.DB_NAME, this.DB_VERSION); + request.onupgradeneeded = FilesystemWeb.doUpgrade; + request.onsuccess = () => { + this._db = request.result; + resolve(request.result); + }; + request.onerror = () => reject(request.error); + request.onblocked = () => { + console.warn('db blocked'); + }; + }); + } + static doUpgrade(event) { + const eventTarget = event.target; + const db = eventTarget.result; + switch (event.oldVersion) { + case 0: + case 1: + default: { + if (db.objectStoreNames.contains('FileStorage')) { + db.deleteObjectStore('FileStorage'); + } + const store = db.createObjectStore('FileStorage', { keyPath: 'path' }); + store.createIndex('by_folder', 'folder'); + } + } + } + async dbRequest(cmd, args) { + const readFlag = this._writeCmds.indexOf(cmd) !== -1 ? 'readwrite' : 'readonly'; + return this.initDb().then((conn) => { + return new Promise((resolve, reject) => { + const tx = conn.transaction(['FileStorage'], readFlag); + const store = tx.objectStore('FileStorage'); + const req = store[cmd](...args); + req.onsuccess = () => resolve(req.result); + req.onerror = () => reject(req.error); + }); + }); + } + async dbIndexRequest(indexName, cmd, args) { + const readFlag = this._writeCmds.indexOf(cmd) !== -1 ? 'readwrite' : 'readonly'; + return this.initDb().then((conn) => { + return new Promise((resolve, reject) => { + const tx = conn.transaction(['FileStorage'], readFlag); + const store = tx.objectStore('FileStorage'); + const index = store.index(indexName); + const req = index[cmd](...args); + req.onsuccess = () => resolve(req.result); + req.onerror = () => reject(req.error); + }); + }); + } + getPath(directory, uriPath) { + const cleanedUriPath = uriPath !== undefined ? uriPath.replace(/^[/]+|[/]+$/g, '') : ''; + let fsPath = ''; + if (directory !== undefined) + fsPath += '/' + directory; + if (uriPath !== '') + fsPath += '/' + cleanedUriPath; + return fsPath; + } + async clear() { + const conn = await this.initDb(); + const tx = conn.transaction(['FileStorage'], 'readwrite'); + const store = tx.objectStore('FileStorage'); + store.clear(); + } + /** + * Read a file from disk + * @param options options for the file read + * @return a promise that resolves with the read file data result + */ + async readFile(options) { + const path = this.getPath(options.directory, options.path); + // const encoding = options.encoding; + const entry = (await this.dbRequest('get', [path])); + if (entry === undefined) + throw Error('File does not exist.'); + return { data: entry.content ? entry.content : '' }; + } + /** + * Write a file to disk in the specified location on device + * @param options options for the file write + * @return a promise that resolves with the file write result + */ + async writeFile(options) { + const path = this.getPath(options.directory, options.path); + let data = options.data; + const encoding = options.encoding; + const doRecursive = options.recursive; + const occupiedEntry = (await this.dbRequest('get', [path])); + if (occupiedEntry && occupiedEntry.type === 'directory') + throw Error('The supplied path is a directory.'); + const parentPath = path.substr(0, path.lastIndexOf('/')); + const parentEntry = (await this.dbRequest('get', [parentPath])); + if (parentEntry === undefined) { + const subDirIndex = parentPath.indexOf('/', 1); + if (subDirIndex !== -1) { + const parentArgPath = parentPath.substr(subDirIndex); + await this.mkdir({ + path: parentArgPath, + directory: options.directory, + recursive: doRecursive, + }); + } + } + if (!encoding && !(data instanceof Blob)) { + data = data.indexOf(',') >= 0 ? data.split(',')[1] : data; + if (!this.isBase64String(data)) + throw Error('The supplied data is not valid base64 content.'); + } + const now = Date.now(); + const pathObj = { + path: path, + folder: parentPath, + type: 'file', + size: data instanceof Blob ? data.size : data.length, + ctime: now, + mtime: now, + content: data, + }; + await this.dbRequest('put', [pathObj]); + return { + uri: pathObj.path, + }; + } + /** + * Append to a file on disk in the specified location on device + * @param options options for the file append + * @return a promise that resolves with the file write result + */ + async appendFile(options) { + const path = this.getPath(options.directory, options.path); + let data = options.data; + const encoding = options.encoding; + const parentPath = path.substr(0, path.lastIndexOf('/')); + const now = Date.now(); + let ctime = now; + const occupiedEntry = (await this.dbRequest('get', [path])); + if (occupiedEntry && occupiedEntry.type === 'directory') + throw Error('The supplied path is a directory.'); + const parentEntry = (await this.dbRequest('get', [parentPath])); + if (parentEntry === undefined) { + const subDirIndex = parentPath.indexOf('/', 1); + if (subDirIndex !== -1) { + const parentArgPath = parentPath.substr(subDirIndex); + await this.mkdir({ + path: parentArgPath, + directory: options.directory, + recursive: true, + }); + } + } + if (!encoding && !this.isBase64String(data)) + throw Error('The supplied data is not valid base64 content.'); + if (occupiedEntry !== undefined) { + if (occupiedEntry.content instanceof Blob) { + throw Error('The occupied entry contains a Blob object which cannot be appended to.'); + } + if (occupiedEntry.content !== undefined && !encoding) { + data = btoa(atob(occupiedEntry.content) + atob(data)); + } + else { + data = occupiedEntry.content + data; + } + ctime = occupiedEntry.ctime; + } + const pathObj = { + path: path, + folder: parentPath, + type: 'file', + size: data.length, + ctime: ctime, + mtime: now, + content: data, + }; + await this.dbRequest('put', [pathObj]); + } + /** + * Delete a file from disk + * @param options options for the file delete + * @return a promise that resolves with the deleted file data result + */ + async deleteFile(options) { + const path = this.getPath(options.directory, options.path); + const entry = (await this.dbRequest('get', [path])); + if (entry === undefined) + throw Error('File does not exist.'); + const entries = await this.dbIndexRequest('by_folder', 'getAllKeys', [IDBKeyRange.only(path)]); + if (entries.length !== 0) + throw Error('Folder is not empty.'); + await this.dbRequest('delete', [path]); + } + /** + * Create a directory. + * @param options options for the mkdir + * @return a promise that resolves with the mkdir result + */ + async mkdir(options) { + const path = this.getPath(options.directory, options.path); + const doRecursive = options.recursive; + const parentPath = path.substr(0, path.lastIndexOf('/')); + const depth = (path.match(/\//g) || []).length; + const parentEntry = (await this.dbRequest('get', [parentPath])); + const occupiedEntry = (await this.dbRequest('get', [path])); + if (depth === 1) + throw Error('Cannot create Root directory'); + if (occupiedEntry !== undefined) + throw Error('Current directory does already exist.'); + if (!doRecursive && depth !== 2 && parentEntry === undefined) + throw Error('Parent directory must exist'); + if (doRecursive && depth !== 2 && parentEntry === undefined) { + const parentArgPath = parentPath.substr(parentPath.indexOf('/', 1)); + await this.mkdir({ + path: parentArgPath, + directory: options.directory, + recursive: doRecursive, + }); + } + const now = Date.now(); + const pathObj = { + path: path, + folder: parentPath, + type: 'directory', + size: 0, + ctime: now, + mtime: now, + }; + await this.dbRequest('put', [pathObj]); + } + /** + * Remove a directory + * @param options the options for the directory remove + */ + async rmdir(options) { + const { path, directory, recursive } = options; + const fullPath = this.getPath(directory, path); + const entry = (await this.dbRequest('get', [fullPath])); + if (entry === undefined) + throw Error('Folder does not exist.'); + if (entry.type !== 'directory') + throw Error('Requested path is not a directory'); + const readDirResult = await this.readdir({ path, directory }); + if (readDirResult.files.length !== 0 && !recursive) + throw Error('Folder is not empty'); + for (const entry of readDirResult.files) { + const entryPath = `${path}/${entry.name}`; + const entryObj = await this.stat({ path: entryPath, directory }); + if (entryObj.type === 'file') { + await this.deleteFile({ path: entryPath, directory }); + } + else { + await this.rmdir({ path: entryPath, directory, recursive }); + } + } + await this.dbRequest('delete', [fullPath]); + } + /** + * Return a list of files from the directory (not recursive) + * @param options the options for the readdir operation + * @return a promise that resolves with the readdir directory listing result + */ + async readdir(options) { + const path = this.getPath(options.directory, options.path); + const entry = (await this.dbRequest('get', [path])); + if (options.path !== '' && entry === undefined) + throw Error('Folder does not exist.'); + const entries = await this.dbIndexRequest('by_folder', 'getAllKeys', [IDBKeyRange.only(path)]); + const files = await Promise.all(entries.map(async (e) => { + let subEntry = (await this.dbRequest('get', [e])); + if (subEntry === undefined) { + subEntry = (await this.dbRequest('get', [e + '/'])); + } + return { + name: e.substring(path.length + 1), + type: subEntry.type, + size: subEntry.size, + ctime: subEntry.ctime, + mtime: subEntry.mtime, + uri: subEntry.path, + }; + })); + return { files: files }; + } + /** + * Return full File URI for a path and directory + * @param options the options for the stat operation + * @return a promise that resolves with the file stat result + */ + async getUri(options) { + const path = this.getPath(options.directory, options.path); + let entry = (await this.dbRequest('get', [path])); + if (entry === undefined) { + entry = (await this.dbRequest('get', [path + '/'])); + } + return { + uri: (entry === null || entry === void 0 ? void 0 : entry.path) || path, + }; + } + /** + * Return data about a file + * @param options the options for the stat operation + * @return a promise that resolves with the file stat result + */ + async stat(options) { + const path = this.getPath(options.directory, options.path); + let entry = (await this.dbRequest('get', [path])); + if (entry === undefined) { + entry = (await this.dbRequest('get', [path + '/'])); + } + if (entry === undefined) + throw Error('Entry does not exist.'); + return { + name: entry.path.substring(path.length + 1), + type: entry.type, + size: entry.size, + ctime: entry.ctime, + mtime: entry.mtime, + uri: entry.path, + }; + } + /** + * Rename a file or directory + * @param options the options for the rename operation + * @return a promise that resolves with the rename result + */ + async rename(options) { + await this._copy(options, true); + return; + } + /** + * Copy a file or directory + * @param options the options for the copy operation + * @return a promise that resolves with the copy result + */ + async copy(options) { + return this._copy(options, false); + } + async requestPermissions() { + return { publicStorage: 'granted' }; + } + async checkPermissions() { + return { publicStorage: 'granted' }; + } + /** + * Function that can perform a copy or a rename + * @param options the options for the rename operation + * @param doRename whether to perform a rename or copy operation + * @return a promise that resolves with the result + */ + async _copy(options, doRename = false) { + let { toDirectory } = options; + const { to, from, directory: fromDirectory } = options; + if (!to || !from) { + throw Error('Both to and from must be provided'); + } + // If no "to" directory is provided, use the "from" directory + if (!toDirectory) { + toDirectory = fromDirectory; + } + const fromPath = this.getPath(fromDirectory, from); + const toPath = this.getPath(toDirectory, to); + // Test that the "to" and "from" locations are different + if (fromPath === toPath) { + return { + uri: toPath, + }; + } + if (isPathParent(fromPath, toPath)) { + throw Error('To path cannot contain the from path'); + } + // Check the state of the "to" location + let toObj; + try { + toObj = await this.stat({ + path: to, + directory: toDirectory, + }); + } + catch (e) { + // To location does not exist, ensure the directory containing "to" location exists and is a directory + const toPathComponents = to.split('/'); + toPathComponents.pop(); + const toPath = toPathComponents.join('/'); + // Check the containing directory of the "to" location exists + if (toPathComponents.length > 0) { + const toParentDirectory = await this.stat({ + path: toPath, + directory: toDirectory, + }); + if (toParentDirectory.type !== 'directory') { + throw new Error('Parent directory of the to path is a file'); + } + } + } + // Cannot overwrite a directory + if (toObj && toObj.type === 'directory') { + throw new Error('Cannot overwrite a directory with a file'); + } + // Ensure the "from" object exists + const fromObj = await this.stat({ + path: from, + directory: fromDirectory, + }); + // Set the mtime/ctime of the supplied path + const updateTime = async (path, ctime, mtime) => { + const fullPath = this.getPath(toDirectory, path); + const entry = (await this.dbRequest('get', [fullPath])); + entry.ctime = ctime; + entry.mtime = mtime; + await this.dbRequest('put', [entry]); + }; + const ctime = fromObj.ctime ? fromObj.ctime : Date.now(); + switch (fromObj.type) { + // The "from" object is a file + case 'file': { + // Read the file + const file = await this.readFile({ + path: from, + directory: fromDirectory, + }); + // Optionally remove the file + if (doRename) { + await this.deleteFile({ + path: from, + directory: fromDirectory, + }); + } + let encoding; + if (!(file.data instanceof Blob) && !this.isBase64String(file.data)) { + encoding = Encoding.UTF8; + } + // Write the file to the new location + const writeResult = await this.writeFile({ + path: to, + directory: toDirectory, + data: file.data, + encoding: encoding, + }); + // Copy the mtime/ctime of a renamed file + if (doRename) { + await updateTime(to, ctime, fromObj.mtime); + } + // Resolve promise + return writeResult; + } + case 'directory': { + if (toObj) { + throw Error('Cannot move a directory over an existing object'); + } + try { + // Create the to directory + await this.mkdir({ + path: to, + directory: toDirectory, + recursive: false, + }); + // Copy the mtime/ctime of a renamed directory + if (doRename) { + await updateTime(to, ctime, fromObj.mtime); + } + } + catch (e) { + // ignore + } + // Iterate over the contents of the from location + const contents = (await this.readdir({ + path: from, + directory: fromDirectory, + })).files; + for (const filename of contents) { + // Move item from the from directory to the to directory + await this._copy({ + from: `${from}/${filename.name}`, + to: `${to}/${filename.name}`, + directory: fromDirectory, + toDirectory, + }, doRename); + } + // Optionally remove the original from directory + if (doRename) { + await this.rmdir({ + path: from, + directory: fromDirectory, + }); + } + } + } + return { + uri: toPath, + }; + } + isBase64String(str) { + try { + return btoa(atob(str)) == str; + } + catch (err) { + return false; + } + } +} +FilesystemWeb._debug = true; +//# sourceMappingURL=web.js.map \ No newline at end of file diff --git a/node_modules/@capacitor/filesystem/dist/esm/web.js.map b/node_modules/@capacitor/filesystem/dist/esm/web.js.map new file mode 100644 index 0000000..78b24f9 --- /dev/null +++ b/node_modules/@capacitor/filesystem/dist/esm/web.js.map @@ -0,0 +1 @@ +{"version":3,"file":"web.js","sourceRoot":"","sources":["../../src/web.ts"],"names":[],"mappings":"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","sourcesContent":["import { WebPlugin, buildRequestInit } from '@capacitor/core';\n\nimport type {\n AppendFileOptions,\n CopyOptions,\n CopyResult,\n DeleteFileOptions,\n FilesystemPlugin,\n GetUriOptions,\n GetUriResult,\n MkdirOptions,\n PermissionStatus,\n ReadFileOptions,\n ReadFileResult,\n ReaddirOptions,\n ReaddirResult,\n RenameOptions,\n RmdirOptions,\n StatOptions,\n StatResult,\n WriteFileOptions,\n WriteFileResult,\n Directory,\n ReadFileInChunksOptions,\n CallbackID,\n DownloadFileOptions,\n DownloadFileResult,\n ProgressStatus,\n ReadFileInChunksCallback,\n} from './definitions';\nimport { Encoding } from './definitions';\n\nfunction resolve(path: string): string {\n const posix = path.split('/').filter((item) => item !== '.');\n const newPosix: string[] = [];\n\n posix.forEach((item) => {\n if (item === '..' && newPosix.length > 0 && newPosix[newPosix.length - 1] !== '..') {\n newPosix.pop();\n } else {\n newPosix.push(item);\n }\n });\n\n return newPosix.join('/');\n}\nfunction isPathParent(parent: string, children: string): boolean {\n parent = resolve(parent);\n children = resolve(children);\n const pathsA = parent.split('/');\n const pathsB = children.split('/');\n\n return parent !== children && pathsA.every((value, index) => value === pathsB[index]);\n}\n\nexport class FilesystemWeb extends WebPlugin implements FilesystemPlugin {\n readFileInChunks(_options: ReadFileInChunksOptions, _callback: ReadFileInChunksCallback): Promise {\n throw this.unavailable('Method not implemented.');\n }\n DB_VERSION = 1;\n DB_NAME = 'Disc';\n\n private _writeCmds: string[] = ['add', 'put', 'delete'];\n private _db?: IDBDatabase;\n static _debug = true;\n async initDb(): Promise {\n if (this._db !== undefined) {\n return this._db;\n }\n if (!('indexedDB' in window)) {\n throw this.unavailable(\"This browser doesn't support IndexedDB\");\n }\n\n return new Promise((resolve, reject) => {\n const request = indexedDB.open(this.DB_NAME, this.DB_VERSION);\n request.onupgradeneeded = FilesystemWeb.doUpgrade;\n request.onsuccess = () => {\n this._db = request.result;\n resolve(request.result);\n };\n request.onerror = () => reject(request.error);\n request.onblocked = () => {\n console.warn('db blocked');\n };\n });\n }\n\n static doUpgrade(event: IDBVersionChangeEvent): void {\n const eventTarget = event.target as IDBOpenDBRequest;\n const db = eventTarget.result;\n switch (event.oldVersion) {\n case 0:\n case 1:\n default: {\n if (db.objectStoreNames.contains('FileStorage')) {\n db.deleteObjectStore('FileStorage');\n }\n const store = db.createObjectStore('FileStorage', { keyPath: 'path' });\n store.createIndex('by_folder', 'folder');\n }\n }\n }\n\n async dbRequest(cmd: string, args: any[]): Promise {\n const readFlag = this._writeCmds.indexOf(cmd) !== -1 ? 'readwrite' : 'readonly';\n return this.initDb().then((conn: IDBDatabase) => {\n return new Promise((resolve, reject) => {\n const tx: IDBTransaction = conn.transaction(['FileStorage'], readFlag);\n const store: any = tx.objectStore('FileStorage');\n const req = store[cmd](...args);\n req.onsuccess = () => resolve(req.result);\n req.onerror = () => reject(req.error);\n });\n });\n }\n\n async dbIndexRequest(indexName: string, cmd: string, args: [any]): Promise {\n const readFlag = this._writeCmds.indexOf(cmd) !== -1 ? 'readwrite' : 'readonly';\n return this.initDb().then((conn: IDBDatabase) => {\n return new Promise((resolve, reject) => {\n const tx: IDBTransaction = conn.transaction(['FileStorage'], readFlag);\n const store: IDBObjectStore = tx.objectStore('FileStorage');\n const index: any = store.index(indexName);\n const req = index[cmd](...args) as any;\n req.onsuccess = () => resolve(req.result);\n req.onerror = () => reject(req.error);\n });\n });\n }\n\n private getPath(directory: Directory | undefined, uriPath: string | undefined): string {\n const cleanedUriPath = uriPath !== undefined ? uriPath.replace(/^[/]+|[/]+$/g, '') : '';\n let fsPath = '';\n if (directory !== undefined) fsPath += '/' + directory;\n if (uriPath !== '') fsPath += '/' + cleanedUriPath;\n return fsPath;\n }\n\n async clear(): Promise {\n const conn: IDBDatabase = await this.initDb();\n const tx: IDBTransaction = conn.transaction(['FileStorage'], 'readwrite');\n const store: IDBObjectStore = tx.objectStore('FileStorage');\n store.clear();\n }\n\n /**\n * Read a file from disk\n * @param options options for the file read\n * @return a promise that resolves with the read file data result\n */\n async readFile(options: ReadFileOptions): Promise {\n const path: string = this.getPath(options.directory, options.path);\n // const encoding = options.encoding;\n\n const entry = (await this.dbRequest('get', [path])) as EntryObj;\n if (entry === undefined) throw Error('File does not exist.');\n return { data: entry.content ? entry.content : '' };\n }\n\n /**\n * Write a file to disk in the specified location on device\n * @param options options for the file write\n * @return a promise that resolves with the file write result\n */\n async writeFile(options: WriteFileOptions): Promise {\n const path: string = this.getPath(options.directory, options.path);\n let data = options.data;\n const encoding = options.encoding;\n const doRecursive = options.recursive;\n\n const occupiedEntry = (await this.dbRequest('get', [path])) as EntryObj;\n if (occupiedEntry && occupiedEntry.type === 'directory') throw Error('The supplied path is a directory.');\n\n const parentPath = path.substr(0, path.lastIndexOf('/'));\n\n const parentEntry = (await this.dbRequest('get', [parentPath])) as EntryObj;\n if (parentEntry === undefined) {\n const subDirIndex = parentPath.indexOf('/', 1);\n if (subDirIndex !== -1) {\n const parentArgPath = parentPath.substr(subDirIndex);\n await this.mkdir({\n path: parentArgPath,\n directory: options.directory,\n recursive: doRecursive,\n });\n }\n }\n\n if (!encoding && !(data instanceof Blob)) {\n data = data.indexOf(',') >= 0 ? data.split(',')[1] : data;\n if (!this.isBase64String(data)) throw Error('The supplied data is not valid base64 content.');\n }\n\n const now = Date.now();\n const pathObj: EntryObj = {\n path: path,\n folder: parentPath,\n type: 'file',\n size: data instanceof Blob ? data.size : data.length,\n ctime: now,\n mtime: now,\n content: data,\n };\n await this.dbRequest('put', [pathObj]);\n return {\n uri: pathObj.path,\n };\n }\n\n /**\n * Append to a file on disk in the specified location on device\n * @param options options for the file append\n * @return a promise that resolves with the file write result\n */\n async appendFile(options: AppendFileOptions): Promise {\n const path: string = this.getPath(options.directory, options.path);\n let data = options.data;\n const encoding = options.encoding;\n const parentPath = path.substr(0, path.lastIndexOf('/'));\n\n const now = Date.now();\n let ctime = now;\n\n const occupiedEntry = (await this.dbRequest('get', [path])) as EntryObj;\n if (occupiedEntry && occupiedEntry.type === 'directory') throw Error('The supplied path is a directory.');\n\n const parentEntry = (await this.dbRequest('get', [parentPath])) as EntryObj;\n if (parentEntry === undefined) {\n const subDirIndex = parentPath.indexOf('/', 1);\n if (subDirIndex !== -1) {\n const parentArgPath = parentPath.substr(subDirIndex);\n await this.mkdir({\n path: parentArgPath,\n directory: options.directory,\n recursive: true,\n });\n }\n }\n\n if (!encoding && !this.isBase64String(data)) throw Error('The supplied data is not valid base64 content.');\n\n if (occupiedEntry !== undefined) {\n if (occupiedEntry.content instanceof Blob) {\n throw Error('The occupied entry contains a Blob object which cannot be appended to.');\n }\n\n if (occupiedEntry.content !== undefined && !encoding) {\n data = btoa(atob(occupiedEntry.content) + atob(data));\n } else {\n data = occupiedEntry.content + data;\n }\n ctime = occupiedEntry.ctime;\n }\n const pathObj: EntryObj = {\n path: path,\n folder: parentPath,\n type: 'file',\n size: data.length,\n ctime: ctime,\n mtime: now,\n content: data,\n };\n await this.dbRequest('put', [pathObj]);\n }\n\n /**\n * Delete a file from disk\n * @param options options for the file delete\n * @return a promise that resolves with the deleted file data result\n */\n async deleteFile(options: DeleteFileOptions): Promise {\n const path: string = this.getPath(options.directory, options.path);\n\n const entry = (await this.dbRequest('get', [path])) as EntryObj;\n if (entry === undefined) throw Error('File does not exist.');\n const entries = await this.dbIndexRequest('by_folder', 'getAllKeys', [IDBKeyRange.only(path)]);\n if (entries.length !== 0) throw Error('Folder is not empty.');\n\n await this.dbRequest('delete', [path]);\n }\n\n /**\n * Create a directory.\n * @param options options for the mkdir\n * @return a promise that resolves with the mkdir result\n */\n async mkdir(options: MkdirOptions): Promise {\n const path: string = this.getPath(options.directory, options.path);\n const doRecursive = options.recursive;\n const parentPath = path.substr(0, path.lastIndexOf('/'));\n\n const depth = (path.match(/\\//g) || []).length;\n const parentEntry = (await this.dbRequest('get', [parentPath])) as EntryObj;\n const occupiedEntry = (await this.dbRequest('get', [path])) as EntryObj;\n if (depth === 1) throw Error('Cannot create Root directory');\n if (occupiedEntry !== undefined) throw Error('Current directory does already exist.');\n if (!doRecursive && depth !== 2 && parentEntry === undefined) throw Error('Parent directory must exist');\n\n if (doRecursive && depth !== 2 && parentEntry === undefined) {\n const parentArgPath = parentPath.substr(parentPath.indexOf('/', 1));\n await this.mkdir({\n path: parentArgPath,\n directory: options.directory,\n recursive: doRecursive,\n });\n }\n const now = Date.now();\n const pathObj: EntryObj = {\n path: path,\n folder: parentPath,\n type: 'directory',\n size: 0,\n ctime: now,\n mtime: now,\n };\n await this.dbRequest('put', [pathObj]);\n }\n\n /**\n * Remove a directory\n * @param options the options for the directory remove\n */\n async rmdir(options: RmdirOptions): Promise {\n const { path, directory, recursive } = options;\n const fullPath: string = this.getPath(directory, path);\n\n const entry = (await this.dbRequest('get', [fullPath])) as EntryObj;\n\n if (entry === undefined) throw Error('Folder does not exist.');\n\n if (entry.type !== 'directory') throw Error('Requested path is not a directory');\n\n const readDirResult = await this.readdir({ path, directory });\n\n if (readDirResult.files.length !== 0 && !recursive) throw Error('Folder is not empty');\n\n for (const entry of readDirResult.files) {\n const entryPath = `${path}/${entry.name}`;\n const entryObj = await this.stat({ path: entryPath, directory });\n if (entryObj.type === 'file') {\n await this.deleteFile({ path: entryPath, directory });\n } else {\n await this.rmdir({ path: entryPath, directory, recursive });\n }\n }\n\n await this.dbRequest('delete', [fullPath]);\n }\n\n /**\n * Return a list of files from the directory (not recursive)\n * @param options the options for the readdir operation\n * @return a promise that resolves with the readdir directory listing result\n */\n async readdir(options: ReaddirOptions): Promise {\n const path: string = this.getPath(options.directory, options.path);\n\n const entry = (await this.dbRequest('get', [path])) as EntryObj;\n if (options.path !== '' && entry === undefined) throw Error('Folder does not exist.');\n\n const entries: string[] = await this.dbIndexRequest('by_folder', 'getAllKeys', [IDBKeyRange.only(path)]);\n const files = await Promise.all(\n entries.map(async (e) => {\n let subEntry = (await this.dbRequest('get', [e])) as EntryObj;\n if (subEntry === undefined) {\n subEntry = (await this.dbRequest('get', [e + '/'])) as EntryObj;\n }\n return {\n name: e.substring(path.length + 1),\n type: subEntry.type,\n size: subEntry.size,\n ctime: subEntry.ctime,\n mtime: subEntry.mtime,\n uri: subEntry.path,\n };\n }),\n );\n return { files: files };\n }\n\n /**\n * Return full File URI for a path and directory\n * @param options the options for the stat operation\n * @return a promise that resolves with the file stat result\n */\n async getUri(options: GetUriOptions): Promise {\n const path: string = this.getPath(options.directory, options.path);\n\n let entry = (await this.dbRequest('get', [path])) as EntryObj;\n if (entry === undefined) {\n entry = (await this.dbRequest('get', [path + '/'])) as EntryObj;\n }\n return {\n uri: entry?.path || path,\n };\n }\n\n /**\n * Return data about a file\n * @param options the options for the stat operation\n * @return a promise that resolves with the file stat result\n */\n async stat(options: StatOptions): Promise {\n const path: string = this.getPath(options.directory, options.path);\n\n let entry = (await this.dbRequest('get', [path])) as EntryObj;\n if (entry === undefined) {\n entry = (await this.dbRequest('get', [path + '/'])) as EntryObj;\n }\n if (entry === undefined) throw Error('Entry does not exist.');\n\n return {\n name: entry.path.substring(path.length + 1),\n type: entry.type,\n size: entry.size,\n ctime: entry.ctime,\n mtime: entry.mtime,\n uri: entry.path,\n };\n }\n\n /**\n * Rename a file or directory\n * @param options the options for the rename operation\n * @return a promise that resolves with the rename result\n */\n async rename(options: RenameOptions): Promise {\n await this._copy(options, true);\n return;\n }\n\n /**\n * Copy a file or directory\n * @param options the options for the copy operation\n * @return a promise that resolves with the copy result\n */\n async copy(options: CopyOptions): Promise {\n return this._copy(options, false);\n }\n\n async requestPermissions(): Promise {\n return { publicStorage: 'granted' };\n }\n\n async checkPermissions(): Promise {\n return { publicStorage: 'granted' };\n }\n\n /**\n * Function that can perform a copy or a rename\n * @param options the options for the rename operation\n * @param doRename whether to perform a rename or copy operation\n * @return a promise that resolves with the result\n */\n private async _copy(options: CopyOptions, doRename = false): Promise {\n let { toDirectory } = options;\n const { to, from, directory: fromDirectory } = options;\n\n if (!to || !from) {\n throw Error('Both to and from must be provided');\n }\n\n // If no \"to\" directory is provided, use the \"from\" directory\n if (!toDirectory) {\n toDirectory = fromDirectory;\n }\n\n const fromPath = this.getPath(fromDirectory, from);\n const toPath = this.getPath(toDirectory, to);\n\n // Test that the \"to\" and \"from\" locations are different\n if (fromPath === toPath) {\n return {\n uri: toPath,\n };\n }\n\n if (isPathParent(fromPath, toPath)) {\n throw Error('To path cannot contain the from path');\n }\n\n // Check the state of the \"to\" location\n let toObj;\n try {\n toObj = await this.stat({\n path: to,\n directory: toDirectory,\n });\n } catch (e) {\n // To location does not exist, ensure the directory containing \"to\" location exists and is a directory\n const toPathComponents = to.split('/');\n toPathComponents.pop();\n const toPath = toPathComponents.join('/');\n\n // Check the containing directory of the \"to\" location exists\n if (toPathComponents.length > 0) {\n const toParentDirectory = await this.stat({\n path: toPath,\n directory: toDirectory,\n });\n\n if (toParentDirectory.type !== 'directory') {\n throw new Error('Parent directory of the to path is a file');\n }\n }\n }\n\n // Cannot overwrite a directory\n if (toObj && toObj.type === 'directory') {\n throw new Error('Cannot overwrite a directory with a file');\n }\n\n // Ensure the \"from\" object exists\n const fromObj = await this.stat({\n path: from,\n directory: fromDirectory,\n });\n\n // Set the mtime/ctime of the supplied path\n const updateTime = async (path: string, ctime: number, mtime: number) => {\n const fullPath: string = this.getPath(toDirectory, path);\n const entry = (await this.dbRequest('get', [fullPath])) as EntryObj;\n entry.ctime = ctime;\n entry.mtime = mtime;\n await this.dbRequest('put', [entry]);\n };\n\n const ctime = fromObj.ctime ? fromObj.ctime : Date.now();\n\n switch (fromObj.type) {\n // The \"from\" object is a file\n case 'file': {\n // Read the file\n const file = await this.readFile({\n path: from,\n directory: fromDirectory,\n });\n\n // Optionally remove the file\n if (doRename) {\n await this.deleteFile({\n path: from,\n directory: fromDirectory,\n });\n }\n\n let encoding;\n if (!(file.data instanceof Blob) && !this.isBase64String(file.data)) {\n encoding = Encoding.UTF8;\n }\n\n // Write the file to the new location\n const writeResult = await this.writeFile({\n path: to,\n directory: toDirectory,\n data: file.data,\n encoding: encoding,\n });\n\n // Copy the mtime/ctime of a renamed file\n if (doRename) {\n await updateTime(to, ctime, fromObj.mtime);\n }\n\n // Resolve promise\n return writeResult;\n }\n case 'directory': {\n if (toObj) {\n throw Error('Cannot move a directory over an existing object');\n }\n\n try {\n // Create the to directory\n await this.mkdir({\n path: to,\n directory: toDirectory,\n recursive: false,\n });\n\n // Copy the mtime/ctime of a renamed directory\n if (doRename) {\n await updateTime(to, ctime, fromObj.mtime);\n }\n } catch (e) {\n // ignore\n }\n\n // Iterate over the contents of the from location\n const contents = (\n await this.readdir({\n path: from,\n directory: fromDirectory,\n })\n ).files;\n\n for (const filename of contents) {\n // Move item from the from directory to the to directory\n await this._copy(\n {\n from: `${from}/${filename.name}`,\n to: `${to}/${filename.name}`,\n directory: fromDirectory,\n toDirectory,\n },\n doRename,\n );\n }\n\n // Optionally remove the original from directory\n if (doRename) {\n await this.rmdir({\n path: from,\n directory: fromDirectory,\n });\n }\n }\n }\n return {\n uri: toPath,\n };\n }\n\n /**\n * Function that performs a http request to a server and downloads the file to the specified destination\n *\n * @deprecated Use the @capacitor/file-transfer plugin instead.\n * @param options the options for the download operation\n * @returns a promise that resolves with the download file result\n */\n public downloadFile = async (options: DownloadFileOptions): Promise => {\n const requestInit = buildRequestInit(options, options.webFetchExtra);\n const response = await fetch(options.url, requestInit);\n let blob: Blob;\n\n if (!options.progress) blob = await response.blob();\n else if (!response?.body) blob = new Blob();\n else {\n const reader = response.body.getReader();\n\n let bytes = 0;\n const chunks: (Uint8Array | undefined)[] = [];\n\n const contentType: string | null = response.headers.get('content-type');\n const contentLength: number = parseInt(response.headers.get('content-length') || '0', 10);\n\n while (true) {\n const { done, value } = await reader.read();\n\n if (done) break;\n\n chunks.push(value);\n bytes += value?.length || 0;\n\n const status: ProgressStatus = {\n url: options.url,\n bytes,\n contentLength,\n };\n\n this.notifyListeners('progress', status);\n }\n\n const allChunks = new Uint8Array(bytes);\n let position = 0;\n for (const chunk of chunks) {\n if (typeof chunk === 'undefined') continue;\n\n allChunks.set(chunk, position);\n position += chunk.length;\n }\n\n blob = new Blob([allChunks.buffer], { type: contentType || undefined });\n }\n\n const result = await this.writeFile({\n path: options.path,\n directory: options.directory ?? undefined,\n recursive: options.recursive ?? false,\n data: blob,\n });\n\n return { path: result.uri, blob };\n };\n\n private isBase64String(str: string): boolean {\n try {\n return btoa(atob(str)) == str;\n } catch (err) {\n return false;\n }\n }\n}\n\ninterface EntryObj {\n path: string;\n folder: string;\n type: 'directory' | 'file';\n size: number;\n ctime: number;\n mtime: number;\n uri?: string;\n content?: string | Blob;\n}\n"]} \ No newline at end of file diff --git a/node_modules/@capacitor/filesystem/dist/plugin.cjs.js b/node_modules/@capacitor/filesystem/dist/plugin.cjs.js new file mode 100644 index 0000000..1113e43 --- /dev/null +++ b/node_modules/@capacitor/filesystem/dist/plugin.cjs.js @@ -0,0 +1,737 @@ +'use strict'; + +var core = require('@capacitor/core'); +var synapse = require('@capacitor/synapse'); + +exports.Directory = void 0; +(function (Directory) { + /** + * The Documents directory. + * On iOS it's the app's documents directory. + * Use this directory to store user-generated content. + * On Android it's the Public Documents folder, so it's accessible from other apps. + * It's not accessible on Android 10 unless the app enables legacy External Storage + * by adding `android:requestLegacyExternalStorage="true"` in the `application` tag + * in the `AndroidManifest.xml`. + * On Android 11 or newer the app can only access the files/folders the app created. + * + * @since 1.0.0 + */ + Directory["Documents"] = "DOCUMENTS"; + /** + * The Data directory. + * On iOS it will use the Documents directory. + * On Android it's the directory holding application files. + * Files will be deleted when the application is uninstalled. + * + * @since 1.0.0 + */ + Directory["Data"] = "DATA"; + /** + * The Library directory. + * On iOS it will use the Library directory. + * On Android it's the directory holding application files. + * Files will be deleted when the application is uninstalled. + * + * @since 1.1.0 + */ + Directory["Library"] = "LIBRARY"; + /** + * The Cache directory. + * Can be deleted in cases of low memory, so use this directory to write app-specific files. + * that your app can re-create easily. + * + * @since 1.0.0 + */ + Directory["Cache"] = "CACHE"; + /** + * The external directory. + * On iOS it will use the Documents directory. + * On Android it's the directory on the primary shared/external + * storage device where the application can place persistent files it owns. + * These files are internal to the applications, and not typically visible + * to the user as media. + * Files will be deleted when the application is uninstalled. + * + * @since 1.0.0 + */ + Directory["External"] = "EXTERNAL"; + /** + * The external storage directory. + * On iOS it will use the Documents directory. + * On Android it's the primary shared/external storage directory. + * It's not accessible on Android 10 unless the app enables legacy External Storage + * by adding `android:requestLegacyExternalStorage="true"` in the `application` tag + * in the `AndroidManifest.xml`. + * It's not accessible on Android 11 or newer. + * + * @since 1.0.0 + */ + Directory["ExternalStorage"] = "EXTERNAL_STORAGE"; + /** + * The external cache directory. + * On iOS it will use the Documents directory. + * On Android it's the primary shared/external cache. + * + * @since 7.1.0 + */ + Directory["ExternalCache"] = "EXTERNAL_CACHE"; + /** + * The Library directory without cloud backup. Used in iOS. + * On Android it's the directory holding application files. + * + * @since 7.1.0 + */ + Directory["LibraryNoCloud"] = "LIBRARY_NO_CLOUD"; + /** + * A temporary directory for iOS. + * On Android it's the directory holding the application cache. + * + * @since 7.1.0 + */ + Directory["Temporary"] = "TEMPORARY"; +})(exports.Directory || (exports.Directory = {})); +exports.Encoding = void 0; +(function (Encoding) { + /** + * Eight-bit UCS Transformation Format + * + * @since 1.0.0 + */ + Encoding["UTF8"] = "utf8"; + /** + * Seven-bit ASCII, a.k.a. ISO646-US, a.k.a. the Basic Latin block of the + * Unicode character set + * This encoding is only supported on Android. + * + * @since 1.0.0 + */ + Encoding["ASCII"] = "ascii"; + /** + * Sixteen-bit UCS Transformation Format, byte order identified by an + * optional byte-order mark + * This encoding is only supported on Android. + * + * @since 1.0.0 + */ + Encoding["UTF16"] = "utf16"; +})(exports.Encoding || (exports.Encoding = {})); +/** + * @deprecated Use `Directory`. + * @since 1.0.0 + */ +const FilesystemDirectory = exports.Directory; +/** + * @deprecated Use `Encoding`. + * @since 1.0.0 + */ +const FilesystemEncoding = exports.Encoding; + +const Filesystem = core.registerPlugin('Filesystem', { + web: () => Promise.resolve().then(function () { return web; }).then((m) => new m.FilesystemWeb()), +}); +synapse.exposeSynapse(); + +function resolve(path) { + const posix = path.split('/').filter((item) => item !== '.'); + const newPosix = []; + posix.forEach((item) => { + if (item === '..' && newPosix.length > 0 && newPosix[newPosix.length - 1] !== '..') { + newPosix.pop(); + } + else { + newPosix.push(item); + } + }); + return newPosix.join('/'); +} +function isPathParent(parent, children) { + parent = resolve(parent); + children = resolve(children); + const pathsA = parent.split('/'); + const pathsB = children.split('/'); + return parent !== children && pathsA.every((value, index) => value === pathsB[index]); +} +class FilesystemWeb extends core.WebPlugin { + constructor() { + super(...arguments); + this.DB_VERSION = 1; + this.DB_NAME = 'Disc'; + this._writeCmds = ['add', 'put', 'delete']; + /** + * Function that performs a http request to a server and downloads the file to the specified destination + * + * @deprecated Use the @capacitor/file-transfer plugin instead. + * @param options the options for the download operation + * @returns a promise that resolves with the download file result + */ + this.downloadFile = async (options) => { + var _a, _b; + const requestInit = core.buildRequestInit(options, options.webFetchExtra); + const response = await fetch(options.url, requestInit); + let blob; + if (!options.progress) + blob = await response.blob(); + else if (!(response === null || response === void 0 ? void 0 : response.body)) + blob = new Blob(); + else { + const reader = response.body.getReader(); + let bytes = 0; + const chunks = []; + const contentType = response.headers.get('content-type'); + const contentLength = parseInt(response.headers.get('content-length') || '0', 10); + while (true) { + const { done, value } = await reader.read(); + if (done) + break; + chunks.push(value); + bytes += (value === null || value === void 0 ? void 0 : value.length) || 0; + const status = { + url: options.url, + bytes, + contentLength, + }; + this.notifyListeners('progress', status); + } + const allChunks = new Uint8Array(bytes); + let position = 0; + for (const chunk of chunks) { + if (typeof chunk === 'undefined') + continue; + allChunks.set(chunk, position); + position += chunk.length; + } + blob = new Blob([allChunks.buffer], { type: contentType || undefined }); + } + const result = await this.writeFile({ + path: options.path, + directory: (_a = options.directory) !== null && _a !== void 0 ? _a : undefined, + recursive: (_b = options.recursive) !== null && _b !== void 0 ? _b : false, + data: blob, + }); + return { path: result.uri, blob }; + }; + } + readFileInChunks(_options, _callback) { + throw this.unavailable('Method not implemented.'); + } + async initDb() { + if (this._db !== undefined) { + return this._db; + } + if (!('indexedDB' in window)) { + throw this.unavailable("This browser doesn't support IndexedDB"); + } + return new Promise((resolve, reject) => { + const request = indexedDB.open(this.DB_NAME, this.DB_VERSION); + request.onupgradeneeded = FilesystemWeb.doUpgrade; + request.onsuccess = () => { + this._db = request.result; + resolve(request.result); + }; + request.onerror = () => reject(request.error); + request.onblocked = () => { + console.warn('db blocked'); + }; + }); + } + static doUpgrade(event) { + const eventTarget = event.target; + const db = eventTarget.result; + switch (event.oldVersion) { + case 0: + case 1: + default: { + if (db.objectStoreNames.contains('FileStorage')) { + db.deleteObjectStore('FileStorage'); + } + const store = db.createObjectStore('FileStorage', { keyPath: 'path' }); + store.createIndex('by_folder', 'folder'); + } + } + } + async dbRequest(cmd, args) { + const readFlag = this._writeCmds.indexOf(cmd) !== -1 ? 'readwrite' : 'readonly'; + return this.initDb().then((conn) => { + return new Promise((resolve, reject) => { + const tx = conn.transaction(['FileStorage'], readFlag); + const store = tx.objectStore('FileStorage'); + const req = store[cmd](...args); + req.onsuccess = () => resolve(req.result); + req.onerror = () => reject(req.error); + }); + }); + } + async dbIndexRequest(indexName, cmd, args) { + const readFlag = this._writeCmds.indexOf(cmd) !== -1 ? 'readwrite' : 'readonly'; + return this.initDb().then((conn) => { + return new Promise((resolve, reject) => { + const tx = conn.transaction(['FileStorage'], readFlag); + const store = tx.objectStore('FileStorage'); + const index = store.index(indexName); + const req = index[cmd](...args); + req.onsuccess = () => resolve(req.result); + req.onerror = () => reject(req.error); + }); + }); + } + getPath(directory, uriPath) { + const cleanedUriPath = uriPath !== undefined ? uriPath.replace(/^[/]+|[/]+$/g, '') : ''; + let fsPath = ''; + if (directory !== undefined) + fsPath += '/' + directory; + if (uriPath !== '') + fsPath += '/' + cleanedUriPath; + return fsPath; + } + async clear() { + const conn = await this.initDb(); + const tx = conn.transaction(['FileStorage'], 'readwrite'); + const store = tx.objectStore('FileStorage'); + store.clear(); + } + /** + * Read a file from disk + * @param options options for the file read + * @return a promise that resolves with the read file data result + */ + async readFile(options) { + const path = this.getPath(options.directory, options.path); + // const encoding = options.encoding; + const entry = (await this.dbRequest('get', [path])); + if (entry === undefined) + throw Error('File does not exist.'); + return { data: entry.content ? entry.content : '' }; + } + /** + * Write a file to disk in the specified location on device + * @param options options for the file write + * @return a promise that resolves with the file write result + */ + async writeFile(options) { + const path = this.getPath(options.directory, options.path); + let data = options.data; + const encoding = options.encoding; + const doRecursive = options.recursive; + const occupiedEntry = (await this.dbRequest('get', [path])); + if (occupiedEntry && occupiedEntry.type === 'directory') + throw Error('The supplied path is a directory.'); + const parentPath = path.substr(0, path.lastIndexOf('/')); + const parentEntry = (await this.dbRequest('get', [parentPath])); + if (parentEntry === undefined) { + const subDirIndex = parentPath.indexOf('/', 1); + if (subDirIndex !== -1) { + const parentArgPath = parentPath.substr(subDirIndex); + await this.mkdir({ + path: parentArgPath, + directory: options.directory, + recursive: doRecursive, + }); + } + } + if (!encoding && !(data instanceof Blob)) { + data = data.indexOf(',') >= 0 ? data.split(',')[1] : data; + if (!this.isBase64String(data)) + throw Error('The supplied data is not valid base64 content.'); + } + const now = Date.now(); + const pathObj = { + path: path, + folder: parentPath, + type: 'file', + size: data instanceof Blob ? data.size : data.length, + ctime: now, + mtime: now, + content: data, + }; + await this.dbRequest('put', [pathObj]); + return { + uri: pathObj.path, + }; + } + /** + * Append to a file on disk in the specified location on device + * @param options options for the file append + * @return a promise that resolves with the file write result + */ + async appendFile(options) { + const path = this.getPath(options.directory, options.path); + let data = options.data; + const encoding = options.encoding; + const parentPath = path.substr(0, path.lastIndexOf('/')); + const now = Date.now(); + let ctime = now; + const occupiedEntry = (await this.dbRequest('get', [path])); + if (occupiedEntry && occupiedEntry.type === 'directory') + throw Error('The supplied path is a directory.'); + const parentEntry = (await this.dbRequest('get', [parentPath])); + if (parentEntry === undefined) { + const subDirIndex = parentPath.indexOf('/', 1); + if (subDirIndex !== -1) { + const parentArgPath = parentPath.substr(subDirIndex); + await this.mkdir({ + path: parentArgPath, + directory: options.directory, + recursive: true, + }); + } + } + if (!encoding && !this.isBase64String(data)) + throw Error('The supplied data is not valid base64 content.'); + if (occupiedEntry !== undefined) { + if (occupiedEntry.content instanceof Blob) { + throw Error('The occupied entry contains a Blob object which cannot be appended to.'); + } + if (occupiedEntry.content !== undefined && !encoding) { + data = btoa(atob(occupiedEntry.content) + atob(data)); + } + else { + data = occupiedEntry.content + data; + } + ctime = occupiedEntry.ctime; + } + const pathObj = { + path: path, + folder: parentPath, + type: 'file', + size: data.length, + ctime: ctime, + mtime: now, + content: data, + }; + await this.dbRequest('put', [pathObj]); + } + /** + * Delete a file from disk + * @param options options for the file delete + * @return a promise that resolves with the deleted file data result + */ + async deleteFile(options) { + const path = this.getPath(options.directory, options.path); + const entry = (await this.dbRequest('get', [path])); + if (entry === undefined) + throw Error('File does not exist.'); + const entries = await this.dbIndexRequest('by_folder', 'getAllKeys', [IDBKeyRange.only(path)]); + if (entries.length !== 0) + throw Error('Folder is not empty.'); + await this.dbRequest('delete', [path]); + } + /** + * Create a directory. + * @param options options for the mkdir + * @return a promise that resolves with the mkdir result + */ + async mkdir(options) { + const path = this.getPath(options.directory, options.path); + const doRecursive = options.recursive; + const parentPath = path.substr(0, path.lastIndexOf('/')); + const depth = (path.match(/\//g) || []).length; + const parentEntry = (await this.dbRequest('get', [parentPath])); + const occupiedEntry = (await this.dbRequest('get', [path])); + if (depth === 1) + throw Error('Cannot create Root directory'); + if (occupiedEntry !== undefined) + throw Error('Current directory does already exist.'); + if (!doRecursive && depth !== 2 && parentEntry === undefined) + throw Error('Parent directory must exist'); + if (doRecursive && depth !== 2 && parentEntry === undefined) { + const parentArgPath = parentPath.substr(parentPath.indexOf('/', 1)); + await this.mkdir({ + path: parentArgPath, + directory: options.directory, + recursive: doRecursive, + }); + } + const now = Date.now(); + const pathObj = { + path: path, + folder: parentPath, + type: 'directory', + size: 0, + ctime: now, + mtime: now, + }; + await this.dbRequest('put', [pathObj]); + } + /** + * Remove a directory + * @param options the options for the directory remove + */ + async rmdir(options) { + const { path, directory, recursive } = options; + const fullPath = this.getPath(directory, path); + const entry = (await this.dbRequest('get', [fullPath])); + if (entry === undefined) + throw Error('Folder does not exist.'); + if (entry.type !== 'directory') + throw Error('Requested path is not a directory'); + const readDirResult = await this.readdir({ path, directory }); + if (readDirResult.files.length !== 0 && !recursive) + throw Error('Folder is not empty'); + for (const entry of readDirResult.files) { + const entryPath = `${path}/${entry.name}`; + const entryObj = await this.stat({ path: entryPath, directory }); + if (entryObj.type === 'file') { + await this.deleteFile({ path: entryPath, directory }); + } + else { + await this.rmdir({ path: entryPath, directory, recursive }); + } + } + await this.dbRequest('delete', [fullPath]); + } + /** + * Return a list of files from the directory (not recursive) + * @param options the options for the readdir operation + * @return a promise that resolves with the readdir directory listing result + */ + async readdir(options) { + const path = this.getPath(options.directory, options.path); + const entry = (await this.dbRequest('get', [path])); + if (options.path !== '' && entry === undefined) + throw Error('Folder does not exist.'); + const entries = await this.dbIndexRequest('by_folder', 'getAllKeys', [IDBKeyRange.only(path)]); + const files = await Promise.all(entries.map(async (e) => { + let subEntry = (await this.dbRequest('get', [e])); + if (subEntry === undefined) { + subEntry = (await this.dbRequest('get', [e + '/'])); + } + return { + name: e.substring(path.length + 1), + type: subEntry.type, + size: subEntry.size, + ctime: subEntry.ctime, + mtime: subEntry.mtime, + uri: subEntry.path, + }; + })); + return { files: files }; + } + /** + * Return full File URI for a path and directory + * @param options the options for the stat operation + * @return a promise that resolves with the file stat result + */ + async getUri(options) { + const path = this.getPath(options.directory, options.path); + let entry = (await this.dbRequest('get', [path])); + if (entry === undefined) { + entry = (await this.dbRequest('get', [path + '/'])); + } + return { + uri: (entry === null || entry === void 0 ? void 0 : entry.path) || path, + }; + } + /** + * Return data about a file + * @param options the options for the stat operation + * @return a promise that resolves with the file stat result + */ + async stat(options) { + const path = this.getPath(options.directory, options.path); + let entry = (await this.dbRequest('get', [path])); + if (entry === undefined) { + entry = (await this.dbRequest('get', [path + '/'])); + } + if (entry === undefined) + throw Error('Entry does not exist.'); + return { + name: entry.path.substring(path.length + 1), + type: entry.type, + size: entry.size, + ctime: entry.ctime, + mtime: entry.mtime, + uri: entry.path, + }; + } + /** + * Rename a file or directory + * @param options the options for the rename operation + * @return a promise that resolves with the rename result + */ + async rename(options) { + await this._copy(options, true); + return; + } + /** + * Copy a file or directory + * @param options the options for the copy operation + * @return a promise that resolves with the copy result + */ + async copy(options) { + return this._copy(options, false); + } + async requestPermissions() { + return { publicStorage: 'granted' }; + } + async checkPermissions() { + return { publicStorage: 'granted' }; + } + /** + * Function that can perform a copy or a rename + * @param options the options for the rename operation + * @param doRename whether to perform a rename or copy operation + * @return a promise that resolves with the result + */ + async _copy(options, doRename = false) { + let { toDirectory } = options; + const { to, from, directory: fromDirectory } = options; + if (!to || !from) { + throw Error('Both to and from must be provided'); + } + // If no "to" directory is provided, use the "from" directory + if (!toDirectory) { + toDirectory = fromDirectory; + } + const fromPath = this.getPath(fromDirectory, from); + const toPath = this.getPath(toDirectory, to); + // Test that the "to" and "from" locations are different + if (fromPath === toPath) { + return { + uri: toPath, + }; + } + if (isPathParent(fromPath, toPath)) { + throw Error('To path cannot contain the from path'); + } + // Check the state of the "to" location + let toObj; + try { + toObj = await this.stat({ + path: to, + directory: toDirectory, + }); + } + catch (e) { + // To location does not exist, ensure the directory containing "to" location exists and is a directory + const toPathComponents = to.split('/'); + toPathComponents.pop(); + const toPath = toPathComponents.join('/'); + // Check the containing directory of the "to" location exists + if (toPathComponents.length > 0) { + const toParentDirectory = await this.stat({ + path: toPath, + directory: toDirectory, + }); + if (toParentDirectory.type !== 'directory') { + throw new Error('Parent directory of the to path is a file'); + } + } + } + // Cannot overwrite a directory + if (toObj && toObj.type === 'directory') { + throw new Error('Cannot overwrite a directory with a file'); + } + // Ensure the "from" object exists + const fromObj = await this.stat({ + path: from, + directory: fromDirectory, + }); + // Set the mtime/ctime of the supplied path + const updateTime = async (path, ctime, mtime) => { + const fullPath = this.getPath(toDirectory, path); + const entry = (await this.dbRequest('get', [fullPath])); + entry.ctime = ctime; + entry.mtime = mtime; + await this.dbRequest('put', [entry]); + }; + const ctime = fromObj.ctime ? fromObj.ctime : Date.now(); + switch (fromObj.type) { + // The "from" object is a file + case 'file': { + // Read the file + const file = await this.readFile({ + path: from, + directory: fromDirectory, + }); + // Optionally remove the file + if (doRename) { + await this.deleteFile({ + path: from, + directory: fromDirectory, + }); + } + let encoding; + if (!(file.data instanceof Blob) && !this.isBase64String(file.data)) { + encoding = exports.Encoding.UTF8; + } + // Write the file to the new location + const writeResult = await this.writeFile({ + path: to, + directory: toDirectory, + data: file.data, + encoding: encoding, + }); + // Copy the mtime/ctime of a renamed file + if (doRename) { + await updateTime(to, ctime, fromObj.mtime); + } + // Resolve promise + return writeResult; + } + case 'directory': { + if (toObj) { + throw Error('Cannot move a directory over an existing object'); + } + try { + // Create the to directory + await this.mkdir({ + path: to, + directory: toDirectory, + recursive: false, + }); + // Copy the mtime/ctime of a renamed directory + if (doRename) { + await updateTime(to, ctime, fromObj.mtime); + } + } + catch (e) { + // ignore + } + // Iterate over the contents of the from location + const contents = (await this.readdir({ + path: from, + directory: fromDirectory, + })).files; + for (const filename of contents) { + // Move item from the from directory to the to directory + await this._copy({ + from: `${from}/${filename.name}`, + to: `${to}/${filename.name}`, + directory: fromDirectory, + toDirectory, + }, doRename); + } + // Optionally remove the original from directory + if (doRename) { + await this.rmdir({ + path: from, + directory: fromDirectory, + }); + } + } + } + return { + uri: toPath, + }; + } + isBase64String(str) { + try { + return btoa(atob(str)) == str; + } + catch (err) { + return false; + } + } +} +FilesystemWeb._debug = true; + +var web = /*#__PURE__*/Object.freeze({ + __proto__: null, + FilesystemWeb: FilesystemWeb +}); + +exports.Filesystem = Filesystem; +exports.FilesystemDirectory = FilesystemDirectory; +exports.FilesystemEncoding = FilesystemEncoding; +//# sourceMappingURL=plugin.cjs.js.map diff --git a/node_modules/@capacitor/filesystem/dist/plugin.cjs.js.map b/node_modules/@capacitor/filesystem/dist/plugin.cjs.js.map new file mode 100644 index 0000000..5c8230a --- /dev/null +++ b/node_modules/@capacitor/filesystem/dist/plugin.cjs.js.map @@ -0,0 +1 @@ +{"version":3,"file":"plugin.cjs.js","sources":["esm/definitions.js","esm/index.js","esm/web.js"],"sourcesContent":["export var Directory;\n(function (Directory) {\n /**\n * The Documents directory.\n * On iOS it's the app's documents directory.\n * Use this directory to store user-generated content.\n * On Android it's the Public Documents folder, so it's accessible from other apps.\n * It's not accessible on Android 10 unless the app enables legacy External Storage\n * by adding `android:requestLegacyExternalStorage=\"true\"` in the `application` tag\n * in the `AndroidManifest.xml`.\n * On Android 11 or newer the app can only access the files/folders the app created.\n *\n * @since 1.0.0\n */\n Directory[\"Documents\"] = \"DOCUMENTS\";\n /**\n * The Data directory.\n * On iOS it will use the Documents directory.\n * On Android it's the directory holding application files.\n * Files will be deleted when the application is uninstalled.\n *\n * @since 1.0.0\n */\n Directory[\"Data\"] = \"DATA\";\n /**\n * The Library directory.\n * On iOS it will use the Library directory.\n * On Android it's the directory holding application files.\n * Files will be deleted when the application is uninstalled.\n *\n * @since 1.1.0\n */\n Directory[\"Library\"] = \"LIBRARY\";\n /**\n * The Cache directory.\n * Can be deleted in cases of low memory, so use this directory to write app-specific files.\n * that your app can re-create easily.\n *\n * @since 1.0.0\n */\n Directory[\"Cache\"] = \"CACHE\";\n /**\n * The external directory.\n * On iOS it will use the Documents directory.\n * On Android it's the directory on the primary shared/external\n * storage device where the application can place persistent files it owns.\n * These files are internal to the applications, and not typically visible\n * to the user as media.\n * Files will be deleted when the application is uninstalled.\n *\n * @since 1.0.0\n */\n Directory[\"External\"] = \"EXTERNAL\";\n /**\n * The external storage directory.\n * On iOS it will use the Documents directory.\n * On Android it's the primary shared/external storage directory.\n * It's not accessible on Android 10 unless the app enables legacy External Storage\n * by adding `android:requestLegacyExternalStorage=\"true\"` in the `application` tag\n * in the `AndroidManifest.xml`.\n * It's not accessible on Android 11 or newer.\n *\n * @since 1.0.0\n */\n Directory[\"ExternalStorage\"] = \"EXTERNAL_STORAGE\";\n /**\n * The external cache directory.\n * On iOS it will use the Documents directory.\n * On Android it's the primary shared/external cache.\n *\n * @since 7.1.0\n */\n Directory[\"ExternalCache\"] = \"EXTERNAL_CACHE\";\n /**\n * The Library directory without cloud backup. Used in iOS.\n * On Android it's the directory holding application files.\n *\n * @since 7.1.0\n */\n Directory[\"LibraryNoCloud\"] = \"LIBRARY_NO_CLOUD\";\n /**\n * A temporary directory for iOS.\n * On Android it's the directory holding the application cache.\n *\n * @since 7.1.0\n */\n Directory[\"Temporary\"] = \"TEMPORARY\";\n})(Directory || (Directory = {}));\nexport var Encoding;\n(function (Encoding) {\n /**\n * Eight-bit UCS Transformation Format\n *\n * @since 1.0.0\n */\n Encoding[\"UTF8\"] = \"utf8\";\n /**\n * Seven-bit ASCII, a.k.a. ISO646-US, a.k.a. the Basic Latin block of the\n * Unicode character set\n * This encoding is only supported on Android.\n *\n * @since 1.0.0\n */\n Encoding[\"ASCII\"] = \"ascii\";\n /**\n * Sixteen-bit UCS Transformation Format, byte order identified by an\n * optional byte-order mark\n * This encoding is only supported on Android.\n *\n * @since 1.0.0\n */\n Encoding[\"UTF16\"] = \"utf16\";\n})(Encoding || (Encoding = {}));\n/**\n * @deprecated Use `Directory`.\n * @since 1.0.0\n */\nexport const FilesystemDirectory = Directory;\n/**\n * @deprecated Use `Encoding`.\n * @since 1.0.0\n */\nexport const FilesystemEncoding = Encoding;\n//# sourceMappingURL=definitions.js.map","import { registerPlugin } from '@capacitor/core';\nimport { exposeSynapse } from '@capacitor/synapse';\nconst Filesystem = registerPlugin('Filesystem', {\n web: () => import('./web').then((m) => new m.FilesystemWeb()),\n});\nexposeSynapse();\nexport * from './definitions';\nexport { Filesystem };\n//# sourceMappingURL=index.js.map","import { WebPlugin, buildRequestInit } from '@capacitor/core';\nimport { Encoding } from './definitions';\nfunction resolve(path) {\n const posix = path.split('/').filter((item) => item !== '.');\n const newPosix = [];\n posix.forEach((item) => {\n if (item === '..' && newPosix.length > 0 && newPosix[newPosix.length - 1] !== '..') {\n newPosix.pop();\n }\n else {\n newPosix.push(item);\n }\n });\n return newPosix.join('/');\n}\nfunction isPathParent(parent, children) {\n parent = resolve(parent);\n children = resolve(children);\n const pathsA = parent.split('/');\n const pathsB = children.split('/');\n return parent !== children && pathsA.every((value, index) => value === pathsB[index]);\n}\nexport class FilesystemWeb extends WebPlugin {\n constructor() {\n super(...arguments);\n this.DB_VERSION = 1;\n this.DB_NAME = 'Disc';\n this._writeCmds = ['add', 'put', 'delete'];\n /**\n * Function that performs a http request to a server and downloads the file to the specified destination\n *\n * @deprecated Use the @capacitor/file-transfer plugin instead.\n * @param options the options for the download operation\n * @returns a promise that resolves with the download file result\n */\n this.downloadFile = async (options) => {\n var _a, _b;\n const requestInit = buildRequestInit(options, options.webFetchExtra);\n const response = await fetch(options.url, requestInit);\n let blob;\n if (!options.progress)\n blob = await response.blob();\n else if (!(response === null || response === void 0 ? void 0 : response.body))\n blob = new Blob();\n else {\n const reader = response.body.getReader();\n let bytes = 0;\n const chunks = [];\n const contentType = response.headers.get('content-type');\n const contentLength = parseInt(response.headers.get('content-length') || '0', 10);\n while (true) {\n const { done, value } = await reader.read();\n if (done)\n break;\n chunks.push(value);\n bytes += (value === null || value === void 0 ? void 0 : value.length) || 0;\n const status = {\n url: options.url,\n bytes,\n contentLength,\n };\n this.notifyListeners('progress', status);\n }\n const allChunks = new Uint8Array(bytes);\n let position = 0;\n for (const chunk of chunks) {\n if (typeof chunk === 'undefined')\n continue;\n allChunks.set(chunk, position);\n position += chunk.length;\n }\n blob = new Blob([allChunks.buffer], { type: contentType || undefined });\n }\n const result = await this.writeFile({\n path: options.path,\n directory: (_a = options.directory) !== null && _a !== void 0 ? _a : undefined,\n recursive: (_b = options.recursive) !== null && _b !== void 0 ? _b : false,\n data: blob,\n });\n return { path: result.uri, blob };\n };\n }\n readFileInChunks(_options, _callback) {\n throw this.unavailable('Method not implemented.');\n }\n async initDb() {\n if (this._db !== undefined) {\n return this._db;\n }\n if (!('indexedDB' in window)) {\n throw this.unavailable(\"This browser doesn't support IndexedDB\");\n }\n return new Promise((resolve, reject) => {\n const request = indexedDB.open(this.DB_NAME, this.DB_VERSION);\n request.onupgradeneeded = FilesystemWeb.doUpgrade;\n request.onsuccess = () => {\n this._db = request.result;\n resolve(request.result);\n };\n request.onerror = () => reject(request.error);\n request.onblocked = () => {\n console.warn('db blocked');\n };\n });\n }\n static doUpgrade(event) {\n const eventTarget = event.target;\n const db = eventTarget.result;\n switch (event.oldVersion) {\n case 0:\n case 1:\n default: {\n if (db.objectStoreNames.contains('FileStorage')) {\n db.deleteObjectStore('FileStorage');\n }\n const store = db.createObjectStore('FileStorage', { keyPath: 'path' });\n store.createIndex('by_folder', 'folder');\n }\n }\n }\n async dbRequest(cmd, args) {\n const readFlag = this._writeCmds.indexOf(cmd) !== -1 ? 'readwrite' : 'readonly';\n return this.initDb().then((conn) => {\n return new Promise((resolve, reject) => {\n const tx = conn.transaction(['FileStorage'], readFlag);\n const store = tx.objectStore('FileStorage');\n const req = store[cmd](...args);\n req.onsuccess = () => resolve(req.result);\n req.onerror = () => reject(req.error);\n });\n });\n }\n async dbIndexRequest(indexName, cmd, args) {\n const readFlag = this._writeCmds.indexOf(cmd) !== -1 ? 'readwrite' : 'readonly';\n return this.initDb().then((conn) => {\n return new Promise((resolve, reject) => {\n const tx = conn.transaction(['FileStorage'], readFlag);\n const store = tx.objectStore('FileStorage');\n const index = store.index(indexName);\n const req = index[cmd](...args);\n req.onsuccess = () => resolve(req.result);\n req.onerror = () => reject(req.error);\n });\n });\n }\n getPath(directory, uriPath) {\n const cleanedUriPath = uriPath !== undefined ? uriPath.replace(/^[/]+|[/]+$/g, '') : '';\n let fsPath = '';\n if (directory !== undefined)\n fsPath += '/' + directory;\n if (uriPath !== '')\n fsPath += '/' + cleanedUriPath;\n return fsPath;\n }\n async clear() {\n const conn = await this.initDb();\n const tx = conn.transaction(['FileStorage'], 'readwrite');\n const store = tx.objectStore('FileStorage');\n store.clear();\n }\n /**\n * Read a file from disk\n * @param options options for the file read\n * @return a promise that resolves with the read file data result\n */\n async readFile(options) {\n const path = this.getPath(options.directory, options.path);\n // const encoding = options.encoding;\n const entry = (await this.dbRequest('get', [path]));\n if (entry === undefined)\n throw Error('File does not exist.');\n return { data: entry.content ? entry.content : '' };\n }\n /**\n * Write a file to disk in the specified location on device\n * @param options options for the file write\n * @return a promise that resolves with the file write result\n */\n async writeFile(options) {\n const path = this.getPath(options.directory, options.path);\n let data = options.data;\n const encoding = options.encoding;\n const doRecursive = options.recursive;\n const occupiedEntry = (await this.dbRequest('get', [path]));\n if (occupiedEntry && occupiedEntry.type === 'directory')\n throw Error('The supplied path is a directory.');\n const parentPath = path.substr(0, path.lastIndexOf('/'));\n const parentEntry = (await this.dbRequest('get', [parentPath]));\n if (parentEntry === undefined) {\n const subDirIndex = parentPath.indexOf('/', 1);\n if (subDirIndex !== -1) {\n const parentArgPath = parentPath.substr(subDirIndex);\n await this.mkdir({\n path: parentArgPath,\n directory: options.directory,\n recursive: doRecursive,\n });\n }\n }\n if (!encoding && !(data instanceof Blob)) {\n data = data.indexOf(',') >= 0 ? data.split(',')[1] : data;\n if (!this.isBase64String(data))\n throw Error('The supplied data is not valid base64 content.');\n }\n const now = Date.now();\n const pathObj = {\n path: path,\n folder: parentPath,\n type: 'file',\n size: data instanceof Blob ? data.size : data.length,\n ctime: now,\n mtime: now,\n content: data,\n };\n await this.dbRequest('put', [pathObj]);\n return {\n uri: pathObj.path,\n };\n }\n /**\n * Append to a file on disk in the specified location on device\n * @param options options for the file append\n * @return a promise that resolves with the file write result\n */\n async appendFile(options) {\n const path = this.getPath(options.directory, options.path);\n let data = options.data;\n const encoding = options.encoding;\n const parentPath = path.substr(0, path.lastIndexOf('/'));\n const now = Date.now();\n let ctime = now;\n const occupiedEntry = (await this.dbRequest('get', [path]));\n if (occupiedEntry && occupiedEntry.type === 'directory')\n throw Error('The supplied path is a directory.');\n const parentEntry = (await this.dbRequest('get', [parentPath]));\n if (parentEntry === undefined) {\n const subDirIndex = parentPath.indexOf('/', 1);\n if (subDirIndex !== -1) {\n const parentArgPath = parentPath.substr(subDirIndex);\n await this.mkdir({\n path: parentArgPath,\n directory: options.directory,\n recursive: true,\n });\n }\n }\n if (!encoding && !this.isBase64String(data))\n throw Error('The supplied data is not valid base64 content.');\n if (occupiedEntry !== undefined) {\n if (occupiedEntry.content instanceof Blob) {\n throw Error('The occupied entry contains a Blob object which cannot be appended to.');\n }\n if (occupiedEntry.content !== undefined && !encoding) {\n data = btoa(atob(occupiedEntry.content) + atob(data));\n }\n else {\n data = occupiedEntry.content + data;\n }\n ctime = occupiedEntry.ctime;\n }\n const pathObj = {\n path: path,\n folder: parentPath,\n type: 'file',\n size: data.length,\n ctime: ctime,\n mtime: now,\n content: data,\n };\n await this.dbRequest('put', [pathObj]);\n }\n /**\n * Delete a file from disk\n * @param options options for the file delete\n * @return a promise that resolves with the deleted file data result\n */\n async deleteFile(options) {\n const path = this.getPath(options.directory, options.path);\n const entry = (await this.dbRequest('get', [path]));\n if (entry === undefined)\n throw Error('File does not exist.');\n const entries = await this.dbIndexRequest('by_folder', 'getAllKeys', [IDBKeyRange.only(path)]);\n if (entries.length !== 0)\n throw Error('Folder is not empty.');\n await this.dbRequest('delete', [path]);\n }\n /**\n * Create a directory.\n * @param options options for the mkdir\n * @return a promise that resolves with the mkdir result\n */\n async mkdir(options) {\n const path = this.getPath(options.directory, options.path);\n const doRecursive = options.recursive;\n const parentPath = path.substr(0, path.lastIndexOf('/'));\n const depth = (path.match(/\\//g) || []).length;\n const parentEntry = (await this.dbRequest('get', [parentPath]));\n const occupiedEntry = (await this.dbRequest('get', [path]));\n if (depth === 1)\n throw Error('Cannot create Root directory');\n if (occupiedEntry !== undefined)\n throw Error('Current directory does already exist.');\n if (!doRecursive && depth !== 2 && parentEntry === undefined)\n throw Error('Parent directory must exist');\n if (doRecursive && depth !== 2 && parentEntry === undefined) {\n const parentArgPath = parentPath.substr(parentPath.indexOf('/', 1));\n await this.mkdir({\n path: parentArgPath,\n directory: options.directory,\n recursive: doRecursive,\n });\n }\n const now = Date.now();\n const pathObj = {\n path: path,\n folder: parentPath,\n type: 'directory',\n size: 0,\n ctime: now,\n mtime: now,\n };\n await this.dbRequest('put', [pathObj]);\n }\n /**\n * Remove a directory\n * @param options the options for the directory remove\n */\n async rmdir(options) {\n const { path, directory, recursive } = options;\n const fullPath = this.getPath(directory, path);\n const entry = (await this.dbRequest('get', [fullPath]));\n if (entry === undefined)\n throw Error('Folder does not exist.');\n if (entry.type !== 'directory')\n throw Error('Requested path is not a directory');\n const readDirResult = await this.readdir({ path, directory });\n if (readDirResult.files.length !== 0 && !recursive)\n throw Error('Folder is not empty');\n for (const entry of readDirResult.files) {\n const entryPath = `${path}/${entry.name}`;\n const entryObj = await this.stat({ path: entryPath, directory });\n if (entryObj.type === 'file') {\n await this.deleteFile({ path: entryPath, directory });\n }\n else {\n await this.rmdir({ path: entryPath, directory, recursive });\n }\n }\n await this.dbRequest('delete', [fullPath]);\n }\n /**\n * Return a list of files from the directory (not recursive)\n * @param options the options for the readdir operation\n * @return a promise that resolves with the readdir directory listing result\n */\n async readdir(options) {\n const path = this.getPath(options.directory, options.path);\n const entry = (await this.dbRequest('get', [path]));\n if (options.path !== '' && entry === undefined)\n throw Error('Folder does not exist.');\n const entries = await this.dbIndexRequest('by_folder', 'getAllKeys', [IDBKeyRange.only(path)]);\n const files = await Promise.all(entries.map(async (e) => {\n let subEntry = (await this.dbRequest('get', [e]));\n if (subEntry === undefined) {\n subEntry = (await this.dbRequest('get', [e + '/']));\n }\n return {\n name: e.substring(path.length + 1),\n type: subEntry.type,\n size: subEntry.size,\n ctime: subEntry.ctime,\n mtime: subEntry.mtime,\n uri: subEntry.path,\n };\n }));\n return { files: files };\n }\n /**\n * Return full File URI for a path and directory\n * @param options the options for the stat operation\n * @return a promise that resolves with the file stat result\n */\n async getUri(options) {\n const path = this.getPath(options.directory, options.path);\n let entry = (await this.dbRequest('get', [path]));\n if (entry === undefined) {\n entry = (await this.dbRequest('get', [path + '/']));\n }\n return {\n uri: (entry === null || entry === void 0 ? void 0 : entry.path) || path,\n };\n }\n /**\n * Return data about a file\n * @param options the options for the stat operation\n * @return a promise that resolves with the file stat result\n */\n async stat(options) {\n const path = this.getPath(options.directory, options.path);\n let entry = (await this.dbRequest('get', [path]));\n if (entry === undefined) {\n entry = (await this.dbRequest('get', [path + '/']));\n }\n if (entry === undefined)\n throw Error('Entry does not exist.');\n return {\n name: entry.path.substring(path.length + 1),\n type: entry.type,\n size: entry.size,\n ctime: entry.ctime,\n mtime: entry.mtime,\n uri: entry.path,\n };\n }\n /**\n * Rename a file or directory\n * @param options the options for the rename operation\n * @return a promise that resolves with the rename result\n */\n async rename(options) {\n await this._copy(options, true);\n return;\n }\n /**\n * Copy a file or directory\n * @param options the options for the copy operation\n * @return a promise that resolves with the copy result\n */\n async copy(options) {\n return this._copy(options, false);\n }\n async requestPermissions() {\n return { publicStorage: 'granted' };\n }\n async checkPermissions() {\n return { publicStorage: 'granted' };\n }\n /**\n * Function that can perform a copy or a rename\n * @param options the options for the rename operation\n * @param doRename whether to perform a rename or copy operation\n * @return a promise that resolves with the result\n */\n async _copy(options, doRename = false) {\n let { toDirectory } = options;\n const { to, from, directory: fromDirectory } = options;\n if (!to || !from) {\n throw Error('Both to and from must be provided');\n }\n // If no \"to\" directory is provided, use the \"from\" directory\n if (!toDirectory) {\n toDirectory = fromDirectory;\n }\n const fromPath = this.getPath(fromDirectory, from);\n const toPath = this.getPath(toDirectory, to);\n // Test that the \"to\" and \"from\" locations are different\n if (fromPath === toPath) {\n return {\n uri: toPath,\n };\n }\n if (isPathParent(fromPath, toPath)) {\n throw Error('To path cannot contain the from path');\n }\n // Check the state of the \"to\" location\n let toObj;\n try {\n toObj = await this.stat({\n path: to,\n directory: toDirectory,\n });\n }\n catch (e) {\n // To location does not exist, ensure the directory containing \"to\" location exists and is a directory\n const toPathComponents = to.split('/');\n toPathComponents.pop();\n const toPath = toPathComponents.join('/');\n // Check the containing directory of the \"to\" location exists\n if (toPathComponents.length > 0) {\n const toParentDirectory = await this.stat({\n path: toPath,\n directory: toDirectory,\n });\n if (toParentDirectory.type !== 'directory') {\n throw new Error('Parent directory of the to path is a file');\n }\n }\n }\n // Cannot overwrite a directory\n if (toObj && toObj.type === 'directory') {\n throw new Error('Cannot overwrite a directory with a file');\n }\n // Ensure the \"from\" object exists\n const fromObj = await this.stat({\n path: from,\n directory: fromDirectory,\n });\n // Set the mtime/ctime of the supplied path\n const updateTime = async (path, ctime, mtime) => {\n const fullPath = this.getPath(toDirectory, path);\n const entry = (await this.dbRequest('get', [fullPath]));\n entry.ctime = ctime;\n entry.mtime = mtime;\n await this.dbRequest('put', [entry]);\n };\n const ctime = fromObj.ctime ? fromObj.ctime : Date.now();\n switch (fromObj.type) {\n // The \"from\" object is a file\n case 'file': {\n // Read the file\n const file = await this.readFile({\n path: from,\n directory: fromDirectory,\n });\n // Optionally remove the file\n if (doRename) {\n await this.deleteFile({\n path: from,\n directory: fromDirectory,\n });\n }\n let encoding;\n if (!(file.data instanceof Blob) && !this.isBase64String(file.data)) {\n encoding = Encoding.UTF8;\n }\n // Write the file to the new location\n const writeResult = await this.writeFile({\n path: to,\n directory: toDirectory,\n data: file.data,\n encoding: encoding,\n });\n // Copy the mtime/ctime of a renamed file\n if (doRename) {\n await updateTime(to, ctime, fromObj.mtime);\n }\n // Resolve promise\n return writeResult;\n }\n case 'directory': {\n if (toObj) {\n throw Error('Cannot move a directory over an existing object');\n }\n try {\n // Create the to directory\n await this.mkdir({\n path: to,\n directory: toDirectory,\n recursive: false,\n });\n // Copy the mtime/ctime of a renamed directory\n if (doRename) {\n await updateTime(to, ctime, fromObj.mtime);\n }\n }\n catch (e) {\n // ignore\n }\n // Iterate over the contents of the from location\n const contents = (await this.readdir({\n path: from,\n directory: fromDirectory,\n })).files;\n for (const filename of contents) {\n // Move item from the from directory to the to directory\n await this._copy({\n from: `${from}/${filename.name}`,\n to: `${to}/${filename.name}`,\n directory: fromDirectory,\n toDirectory,\n }, doRename);\n }\n // Optionally remove the original from directory\n if (doRename) {\n await this.rmdir({\n path: from,\n directory: fromDirectory,\n });\n }\n }\n }\n return {\n uri: toPath,\n };\n }\n isBase64String(str) {\n try {\n return btoa(atob(str)) == str;\n }\n catch (err) {\n return false;\n }\n }\n}\nFilesystemWeb._debug = true;\n//# sourceMappingURL=web.js.map"],"names":["Directory","Encoding","registerPlugin","exposeSynapse","WebPlugin","buildRequestInit"],"mappings":"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"} \ No newline at end of file diff --git a/node_modules/@capacitor/filesystem/dist/plugin.js b/node_modules/@capacitor/filesystem/dist/plugin.js new file mode 100644 index 0000000..94dddf9 --- /dev/null +++ b/node_modules/@capacitor/filesystem/dist/plugin.js @@ -0,0 +1,739 @@ +var capacitorFilesystemPluginCapacitor = (function (exports, core, synapse) { + 'use strict'; + + exports.Directory = void 0; + (function (Directory) { + /** + * The Documents directory. + * On iOS it's the app's documents directory. + * Use this directory to store user-generated content. + * On Android it's the Public Documents folder, so it's accessible from other apps. + * It's not accessible on Android 10 unless the app enables legacy External Storage + * by adding `android:requestLegacyExternalStorage="true"` in the `application` tag + * in the `AndroidManifest.xml`. + * On Android 11 or newer the app can only access the files/folders the app created. + * + * @since 1.0.0 + */ + Directory["Documents"] = "DOCUMENTS"; + /** + * The Data directory. + * On iOS it will use the Documents directory. + * On Android it's the directory holding application files. + * Files will be deleted when the application is uninstalled. + * + * @since 1.0.0 + */ + Directory["Data"] = "DATA"; + /** + * The Library directory. + * On iOS it will use the Library directory. + * On Android it's the directory holding application files. + * Files will be deleted when the application is uninstalled. + * + * @since 1.1.0 + */ + Directory["Library"] = "LIBRARY"; + /** + * The Cache directory. + * Can be deleted in cases of low memory, so use this directory to write app-specific files. + * that your app can re-create easily. + * + * @since 1.0.0 + */ + Directory["Cache"] = "CACHE"; + /** + * The external directory. + * On iOS it will use the Documents directory. + * On Android it's the directory on the primary shared/external + * storage device where the application can place persistent files it owns. + * These files are internal to the applications, and not typically visible + * to the user as media. + * Files will be deleted when the application is uninstalled. + * + * @since 1.0.0 + */ + Directory["External"] = "EXTERNAL"; + /** + * The external storage directory. + * On iOS it will use the Documents directory. + * On Android it's the primary shared/external storage directory. + * It's not accessible on Android 10 unless the app enables legacy External Storage + * by adding `android:requestLegacyExternalStorage="true"` in the `application` tag + * in the `AndroidManifest.xml`. + * It's not accessible on Android 11 or newer. + * + * @since 1.0.0 + */ + Directory["ExternalStorage"] = "EXTERNAL_STORAGE"; + /** + * The external cache directory. + * On iOS it will use the Documents directory. + * On Android it's the primary shared/external cache. + * + * @since 7.1.0 + */ + Directory["ExternalCache"] = "EXTERNAL_CACHE"; + /** + * The Library directory without cloud backup. Used in iOS. + * On Android it's the directory holding application files. + * + * @since 7.1.0 + */ + Directory["LibraryNoCloud"] = "LIBRARY_NO_CLOUD"; + /** + * A temporary directory for iOS. + * On Android it's the directory holding the application cache. + * + * @since 7.1.0 + */ + Directory["Temporary"] = "TEMPORARY"; + })(exports.Directory || (exports.Directory = {})); + exports.Encoding = void 0; + (function (Encoding) { + /** + * Eight-bit UCS Transformation Format + * + * @since 1.0.0 + */ + Encoding["UTF8"] = "utf8"; + /** + * Seven-bit ASCII, a.k.a. ISO646-US, a.k.a. the Basic Latin block of the + * Unicode character set + * This encoding is only supported on Android. + * + * @since 1.0.0 + */ + Encoding["ASCII"] = "ascii"; + /** + * Sixteen-bit UCS Transformation Format, byte order identified by an + * optional byte-order mark + * This encoding is only supported on Android. + * + * @since 1.0.0 + */ + Encoding["UTF16"] = "utf16"; + })(exports.Encoding || (exports.Encoding = {})); + /** + * @deprecated Use `Directory`. + * @since 1.0.0 + */ + const FilesystemDirectory = exports.Directory; + /** + * @deprecated Use `Encoding`. + * @since 1.0.0 + */ + const FilesystemEncoding = exports.Encoding; + + const Filesystem = core.registerPlugin('Filesystem', { + web: () => Promise.resolve().then(function () { return web; }).then((m) => new m.FilesystemWeb()), + }); + synapse.exposeSynapse(); + + function resolve(path) { + const posix = path.split('/').filter((item) => item !== '.'); + const newPosix = []; + posix.forEach((item) => { + if (item === '..' && newPosix.length > 0 && newPosix[newPosix.length - 1] !== '..') { + newPosix.pop(); + } + else { + newPosix.push(item); + } + }); + return newPosix.join('/'); + } + function isPathParent(parent, children) { + parent = resolve(parent); + children = resolve(children); + const pathsA = parent.split('/'); + const pathsB = children.split('/'); + return parent !== children && pathsA.every((value, index) => value === pathsB[index]); + } + class FilesystemWeb extends core.WebPlugin { + constructor() { + super(...arguments); + this.DB_VERSION = 1; + this.DB_NAME = 'Disc'; + this._writeCmds = ['add', 'put', 'delete']; + /** + * Function that performs a http request to a server and downloads the file to the specified destination + * + * @deprecated Use the @capacitor/file-transfer plugin instead. + * @param options the options for the download operation + * @returns a promise that resolves with the download file result + */ + this.downloadFile = async (options) => { + var _a, _b; + const requestInit = core.buildRequestInit(options, options.webFetchExtra); + const response = await fetch(options.url, requestInit); + let blob; + if (!options.progress) + blob = await response.blob(); + else if (!(response === null || response === void 0 ? void 0 : response.body)) + blob = new Blob(); + else { + const reader = response.body.getReader(); + let bytes = 0; + const chunks = []; + const contentType = response.headers.get('content-type'); + const contentLength = parseInt(response.headers.get('content-length') || '0', 10); + while (true) { + const { done, value } = await reader.read(); + if (done) + break; + chunks.push(value); + bytes += (value === null || value === void 0 ? void 0 : value.length) || 0; + const status = { + url: options.url, + bytes, + contentLength, + }; + this.notifyListeners('progress', status); + } + const allChunks = new Uint8Array(bytes); + let position = 0; + for (const chunk of chunks) { + if (typeof chunk === 'undefined') + continue; + allChunks.set(chunk, position); + position += chunk.length; + } + blob = new Blob([allChunks.buffer], { type: contentType || undefined }); + } + const result = await this.writeFile({ + path: options.path, + directory: (_a = options.directory) !== null && _a !== void 0 ? _a : undefined, + recursive: (_b = options.recursive) !== null && _b !== void 0 ? _b : false, + data: blob, + }); + return { path: result.uri, blob }; + }; + } + readFileInChunks(_options, _callback) { + throw this.unavailable('Method not implemented.'); + } + async initDb() { + if (this._db !== undefined) { + return this._db; + } + if (!('indexedDB' in window)) { + throw this.unavailable("This browser doesn't support IndexedDB"); + } + return new Promise((resolve, reject) => { + const request = indexedDB.open(this.DB_NAME, this.DB_VERSION); + request.onupgradeneeded = FilesystemWeb.doUpgrade; + request.onsuccess = () => { + this._db = request.result; + resolve(request.result); + }; + request.onerror = () => reject(request.error); + request.onblocked = () => { + console.warn('db blocked'); + }; + }); + } + static doUpgrade(event) { + const eventTarget = event.target; + const db = eventTarget.result; + switch (event.oldVersion) { + case 0: + case 1: + default: { + if (db.objectStoreNames.contains('FileStorage')) { + db.deleteObjectStore('FileStorage'); + } + const store = db.createObjectStore('FileStorage', { keyPath: 'path' }); + store.createIndex('by_folder', 'folder'); + } + } + } + async dbRequest(cmd, args) { + const readFlag = this._writeCmds.indexOf(cmd) !== -1 ? 'readwrite' : 'readonly'; + return this.initDb().then((conn) => { + return new Promise((resolve, reject) => { + const tx = conn.transaction(['FileStorage'], readFlag); + const store = tx.objectStore('FileStorage'); + const req = store[cmd](...args); + req.onsuccess = () => resolve(req.result); + req.onerror = () => reject(req.error); + }); + }); + } + async dbIndexRequest(indexName, cmd, args) { + const readFlag = this._writeCmds.indexOf(cmd) !== -1 ? 'readwrite' : 'readonly'; + return this.initDb().then((conn) => { + return new Promise((resolve, reject) => { + const tx = conn.transaction(['FileStorage'], readFlag); + const store = tx.objectStore('FileStorage'); + const index = store.index(indexName); + const req = index[cmd](...args); + req.onsuccess = () => resolve(req.result); + req.onerror = () => reject(req.error); + }); + }); + } + getPath(directory, uriPath) { + const cleanedUriPath = uriPath !== undefined ? uriPath.replace(/^[/]+|[/]+$/g, '') : ''; + let fsPath = ''; + if (directory !== undefined) + fsPath += '/' + directory; + if (uriPath !== '') + fsPath += '/' + cleanedUriPath; + return fsPath; + } + async clear() { + const conn = await this.initDb(); + const tx = conn.transaction(['FileStorage'], 'readwrite'); + const store = tx.objectStore('FileStorage'); + store.clear(); + } + /** + * Read a file from disk + * @param options options for the file read + * @return a promise that resolves with the read file data result + */ + async readFile(options) { + const path = this.getPath(options.directory, options.path); + // const encoding = options.encoding; + const entry = (await this.dbRequest('get', [path])); + if (entry === undefined) + throw Error('File does not exist.'); + return { data: entry.content ? entry.content : '' }; + } + /** + * Write a file to disk in the specified location on device + * @param options options for the file write + * @return a promise that resolves with the file write result + */ + async writeFile(options) { + const path = this.getPath(options.directory, options.path); + let data = options.data; + const encoding = options.encoding; + const doRecursive = options.recursive; + const occupiedEntry = (await this.dbRequest('get', [path])); + if (occupiedEntry && occupiedEntry.type === 'directory') + throw Error('The supplied path is a directory.'); + const parentPath = path.substr(0, path.lastIndexOf('/')); + const parentEntry = (await this.dbRequest('get', [parentPath])); + if (parentEntry === undefined) { + const subDirIndex = parentPath.indexOf('/', 1); + if (subDirIndex !== -1) { + const parentArgPath = parentPath.substr(subDirIndex); + await this.mkdir({ + path: parentArgPath, + directory: options.directory, + recursive: doRecursive, + }); + } + } + if (!encoding && !(data instanceof Blob)) { + data = data.indexOf(',') >= 0 ? data.split(',')[1] : data; + if (!this.isBase64String(data)) + throw Error('The supplied data is not valid base64 content.'); + } + const now = Date.now(); + const pathObj = { + path: path, + folder: parentPath, + type: 'file', + size: data instanceof Blob ? data.size : data.length, + ctime: now, + mtime: now, + content: data, + }; + await this.dbRequest('put', [pathObj]); + return { + uri: pathObj.path, + }; + } + /** + * Append to a file on disk in the specified location on device + * @param options options for the file append + * @return a promise that resolves with the file write result + */ + async appendFile(options) { + const path = this.getPath(options.directory, options.path); + let data = options.data; + const encoding = options.encoding; + const parentPath = path.substr(0, path.lastIndexOf('/')); + const now = Date.now(); + let ctime = now; + const occupiedEntry = (await this.dbRequest('get', [path])); + if (occupiedEntry && occupiedEntry.type === 'directory') + throw Error('The supplied path is a directory.'); + const parentEntry = (await this.dbRequest('get', [parentPath])); + if (parentEntry === undefined) { + const subDirIndex = parentPath.indexOf('/', 1); + if (subDirIndex !== -1) { + const parentArgPath = parentPath.substr(subDirIndex); + await this.mkdir({ + path: parentArgPath, + directory: options.directory, + recursive: true, + }); + } + } + if (!encoding && !this.isBase64String(data)) + throw Error('The supplied data is not valid base64 content.'); + if (occupiedEntry !== undefined) { + if (occupiedEntry.content instanceof Blob) { + throw Error('The occupied entry contains a Blob object which cannot be appended to.'); + } + if (occupiedEntry.content !== undefined && !encoding) { + data = btoa(atob(occupiedEntry.content) + atob(data)); + } + else { + data = occupiedEntry.content + data; + } + ctime = occupiedEntry.ctime; + } + const pathObj = { + path: path, + folder: parentPath, + type: 'file', + size: data.length, + ctime: ctime, + mtime: now, + content: data, + }; + await this.dbRequest('put', [pathObj]); + } + /** + * Delete a file from disk + * @param options options for the file delete + * @return a promise that resolves with the deleted file data result + */ + async deleteFile(options) { + const path = this.getPath(options.directory, options.path); + const entry = (await this.dbRequest('get', [path])); + if (entry === undefined) + throw Error('File does not exist.'); + const entries = await this.dbIndexRequest('by_folder', 'getAllKeys', [IDBKeyRange.only(path)]); + if (entries.length !== 0) + throw Error('Folder is not empty.'); + await this.dbRequest('delete', [path]); + } + /** + * Create a directory. + * @param options options for the mkdir + * @return a promise that resolves with the mkdir result + */ + async mkdir(options) { + const path = this.getPath(options.directory, options.path); + const doRecursive = options.recursive; + const parentPath = path.substr(0, path.lastIndexOf('/')); + const depth = (path.match(/\//g) || []).length; + const parentEntry = (await this.dbRequest('get', [parentPath])); + const occupiedEntry = (await this.dbRequest('get', [path])); + if (depth === 1) + throw Error('Cannot create Root directory'); + if (occupiedEntry !== undefined) + throw Error('Current directory does already exist.'); + if (!doRecursive && depth !== 2 && parentEntry === undefined) + throw Error('Parent directory must exist'); + if (doRecursive && depth !== 2 && parentEntry === undefined) { + const parentArgPath = parentPath.substr(parentPath.indexOf('/', 1)); + await this.mkdir({ + path: parentArgPath, + directory: options.directory, + recursive: doRecursive, + }); + } + const now = Date.now(); + const pathObj = { + path: path, + folder: parentPath, + type: 'directory', + size: 0, + ctime: now, + mtime: now, + }; + await this.dbRequest('put', [pathObj]); + } + /** + * Remove a directory + * @param options the options for the directory remove + */ + async rmdir(options) { + const { path, directory, recursive } = options; + const fullPath = this.getPath(directory, path); + const entry = (await this.dbRequest('get', [fullPath])); + if (entry === undefined) + throw Error('Folder does not exist.'); + if (entry.type !== 'directory') + throw Error('Requested path is not a directory'); + const readDirResult = await this.readdir({ path, directory }); + if (readDirResult.files.length !== 0 && !recursive) + throw Error('Folder is not empty'); + for (const entry of readDirResult.files) { + const entryPath = `${path}/${entry.name}`; + const entryObj = await this.stat({ path: entryPath, directory }); + if (entryObj.type === 'file') { + await this.deleteFile({ path: entryPath, directory }); + } + else { + await this.rmdir({ path: entryPath, directory, recursive }); + } + } + await this.dbRequest('delete', [fullPath]); + } + /** + * Return a list of files from the directory (not recursive) + * @param options the options for the readdir operation + * @return a promise that resolves with the readdir directory listing result + */ + async readdir(options) { + const path = this.getPath(options.directory, options.path); + const entry = (await this.dbRequest('get', [path])); + if (options.path !== '' && entry === undefined) + throw Error('Folder does not exist.'); + const entries = await this.dbIndexRequest('by_folder', 'getAllKeys', [IDBKeyRange.only(path)]); + const files = await Promise.all(entries.map(async (e) => { + let subEntry = (await this.dbRequest('get', [e])); + if (subEntry === undefined) { + subEntry = (await this.dbRequest('get', [e + '/'])); + } + return { + name: e.substring(path.length + 1), + type: subEntry.type, + size: subEntry.size, + ctime: subEntry.ctime, + mtime: subEntry.mtime, + uri: subEntry.path, + }; + })); + return { files: files }; + } + /** + * Return full File URI for a path and directory + * @param options the options for the stat operation + * @return a promise that resolves with the file stat result + */ + async getUri(options) { + const path = this.getPath(options.directory, options.path); + let entry = (await this.dbRequest('get', [path])); + if (entry === undefined) { + entry = (await this.dbRequest('get', [path + '/'])); + } + return { + uri: (entry === null || entry === void 0 ? void 0 : entry.path) || path, + }; + } + /** + * Return data about a file + * @param options the options for the stat operation + * @return a promise that resolves with the file stat result + */ + async stat(options) { + const path = this.getPath(options.directory, options.path); + let entry = (await this.dbRequest('get', [path])); + if (entry === undefined) { + entry = (await this.dbRequest('get', [path + '/'])); + } + if (entry === undefined) + throw Error('Entry does not exist.'); + return { + name: entry.path.substring(path.length + 1), + type: entry.type, + size: entry.size, + ctime: entry.ctime, + mtime: entry.mtime, + uri: entry.path, + }; + } + /** + * Rename a file or directory + * @param options the options for the rename operation + * @return a promise that resolves with the rename result + */ + async rename(options) { + await this._copy(options, true); + return; + } + /** + * Copy a file or directory + * @param options the options for the copy operation + * @return a promise that resolves with the copy result + */ + async copy(options) { + return this._copy(options, false); + } + async requestPermissions() { + return { publicStorage: 'granted' }; + } + async checkPermissions() { + return { publicStorage: 'granted' }; + } + /** + * Function that can perform a copy or a rename + * @param options the options for the rename operation + * @param doRename whether to perform a rename or copy operation + * @return a promise that resolves with the result + */ + async _copy(options, doRename = false) { + let { toDirectory } = options; + const { to, from, directory: fromDirectory } = options; + if (!to || !from) { + throw Error('Both to and from must be provided'); + } + // If no "to" directory is provided, use the "from" directory + if (!toDirectory) { + toDirectory = fromDirectory; + } + const fromPath = this.getPath(fromDirectory, from); + const toPath = this.getPath(toDirectory, to); + // Test that the "to" and "from" locations are different + if (fromPath === toPath) { + return { + uri: toPath, + }; + } + if (isPathParent(fromPath, toPath)) { + throw Error('To path cannot contain the from path'); + } + // Check the state of the "to" location + let toObj; + try { + toObj = await this.stat({ + path: to, + directory: toDirectory, + }); + } + catch (e) { + // To location does not exist, ensure the directory containing "to" location exists and is a directory + const toPathComponents = to.split('/'); + toPathComponents.pop(); + const toPath = toPathComponents.join('/'); + // Check the containing directory of the "to" location exists + if (toPathComponents.length > 0) { + const toParentDirectory = await this.stat({ + path: toPath, + directory: toDirectory, + }); + if (toParentDirectory.type !== 'directory') { + throw new Error('Parent directory of the to path is a file'); + } + } + } + // Cannot overwrite a directory + if (toObj && toObj.type === 'directory') { + throw new Error('Cannot overwrite a directory with a file'); + } + // Ensure the "from" object exists + const fromObj = await this.stat({ + path: from, + directory: fromDirectory, + }); + // Set the mtime/ctime of the supplied path + const updateTime = async (path, ctime, mtime) => { + const fullPath = this.getPath(toDirectory, path); + const entry = (await this.dbRequest('get', [fullPath])); + entry.ctime = ctime; + entry.mtime = mtime; + await this.dbRequest('put', [entry]); + }; + const ctime = fromObj.ctime ? fromObj.ctime : Date.now(); + switch (fromObj.type) { + // The "from" object is a file + case 'file': { + // Read the file + const file = await this.readFile({ + path: from, + directory: fromDirectory, + }); + // Optionally remove the file + if (doRename) { + await this.deleteFile({ + path: from, + directory: fromDirectory, + }); + } + let encoding; + if (!(file.data instanceof Blob) && !this.isBase64String(file.data)) { + encoding = exports.Encoding.UTF8; + } + // Write the file to the new location + const writeResult = await this.writeFile({ + path: to, + directory: toDirectory, + data: file.data, + encoding: encoding, + }); + // Copy the mtime/ctime of a renamed file + if (doRename) { + await updateTime(to, ctime, fromObj.mtime); + } + // Resolve promise + return writeResult; + } + case 'directory': { + if (toObj) { + throw Error('Cannot move a directory over an existing object'); + } + try { + // Create the to directory + await this.mkdir({ + path: to, + directory: toDirectory, + recursive: false, + }); + // Copy the mtime/ctime of a renamed directory + if (doRename) { + await updateTime(to, ctime, fromObj.mtime); + } + } + catch (e) { + // ignore + } + // Iterate over the contents of the from location + const contents = (await this.readdir({ + path: from, + directory: fromDirectory, + })).files; + for (const filename of contents) { + // Move item from the from directory to the to directory + await this._copy({ + from: `${from}/${filename.name}`, + to: `${to}/${filename.name}`, + directory: fromDirectory, + toDirectory, + }, doRename); + } + // Optionally remove the original from directory + if (doRename) { + await this.rmdir({ + path: from, + directory: fromDirectory, + }); + } + } + } + return { + uri: toPath, + }; + } + isBase64String(str) { + try { + return btoa(atob(str)) == str; + } + catch (err) { + return false; + } + } + } + FilesystemWeb._debug = true; + + var web = /*#__PURE__*/Object.freeze({ + __proto__: null, + FilesystemWeb: FilesystemWeb + }); + + exports.Filesystem = Filesystem; + exports.FilesystemDirectory = FilesystemDirectory; + exports.FilesystemEncoding = FilesystemEncoding; + + return exports; + +})({}, capacitorExports, synapse); +//# sourceMappingURL=plugin.js.map diff --git a/node_modules/@capacitor/filesystem/dist/plugin.js.map b/node_modules/@capacitor/filesystem/dist/plugin.js.map new file mode 100644 index 0000000..e3e7261 --- /dev/null +++ b/node_modules/@capacitor/filesystem/dist/plugin.js.map @@ -0,0 +1 @@ +{"version":3,"file":"plugin.js","sources":["esm/definitions.js","esm/index.js","esm/web.js"],"sourcesContent":["export var Directory;\n(function (Directory) {\n /**\n * The Documents directory.\n * On iOS it's the app's documents directory.\n * Use this directory to store user-generated content.\n * On Android it's the Public Documents folder, so it's accessible from other apps.\n * It's not accessible on Android 10 unless the app enables legacy External Storage\n * by adding `android:requestLegacyExternalStorage=\"true\"` in the `application` tag\n * in the `AndroidManifest.xml`.\n * On Android 11 or newer the app can only access the files/folders the app created.\n *\n * @since 1.0.0\n */\n Directory[\"Documents\"] = \"DOCUMENTS\";\n /**\n * The Data directory.\n * On iOS it will use the Documents directory.\n * On Android it's the directory holding application files.\n * Files will be deleted when the application is uninstalled.\n *\n * @since 1.0.0\n */\n Directory[\"Data\"] = \"DATA\";\n /**\n * The Library directory.\n * On iOS it will use the Library directory.\n * On Android it's the directory holding application files.\n * Files will be deleted when the application is uninstalled.\n *\n * @since 1.1.0\n */\n Directory[\"Library\"] = \"LIBRARY\";\n /**\n * The Cache directory.\n * Can be deleted in cases of low memory, so use this directory to write app-specific files.\n * that your app can re-create easily.\n *\n * @since 1.0.0\n */\n Directory[\"Cache\"] = \"CACHE\";\n /**\n * The external directory.\n * On iOS it will use the Documents directory.\n * On Android it's the directory on the primary shared/external\n * storage device where the application can place persistent files it owns.\n * These files are internal to the applications, and not typically visible\n * to the user as media.\n * Files will be deleted when the application is uninstalled.\n *\n * @since 1.0.0\n */\n Directory[\"External\"] = \"EXTERNAL\";\n /**\n * The external storage directory.\n * On iOS it will use the Documents directory.\n * On Android it's the primary shared/external storage directory.\n * It's not accessible on Android 10 unless the app enables legacy External Storage\n * by adding `android:requestLegacyExternalStorage=\"true\"` in the `application` tag\n * in the `AndroidManifest.xml`.\n * It's not accessible on Android 11 or newer.\n *\n * @since 1.0.0\n */\n Directory[\"ExternalStorage\"] = \"EXTERNAL_STORAGE\";\n /**\n * The external cache directory.\n * On iOS it will use the Documents directory.\n * On Android it's the primary shared/external cache.\n *\n * @since 7.1.0\n */\n Directory[\"ExternalCache\"] = \"EXTERNAL_CACHE\";\n /**\n * The Library directory without cloud backup. Used in iOS.\n * On Android it's the directory holding application files.\n *\n * @since 7.1.0\n */\n Directory[\"LibraryNoCloud\"] = \"LIBRARY_NO_CLOUD\";\n /**\n * A temporary directory for iOS.\n * On Android it's the directory holding the application cache.\n *\n * @since 7.1.0\n */\n Directory[\"Temporary\"] = \"TEMPORARY\";\n})(Directory || (Directory = {}));\nexport var Encoding;\n(function (Encoding) {\n /**\n * Eight-bit UCS Transformation Format\n *\n * @since 1.0.0\n */\n Encoding[\"UTF8\"] = \"utf8\";\n /**\n * Seven-bit ASCII, a.k.a. ISO646-US, a.k.a. the Basic Latin block of the\n * Unicode character set\n * This encoding is only supported on Android.\n *\n * @since 1.0.0\n */\n Encoding[\"ASCII\"] = \"ascii\";\n /**\n * Sixteen-bit UCS Transformation Format, byte order identified by an\n * optional byte-order mark\n * This encoding is only supported on Android.\n *\n * @since 1.0.0\n */\n Encoding[\"UTF16\"] = \"utf16\";\n})(Encoding || (Encoding = {}));\n/**\n * @deprecated Use `Directory`.\n * @since 1.0.0\n */\nexport const FilesystemDirectory = Directory;\n/**\n * @deprecated Use `Encoding`.\n * @since 1.0.0\n */\nexport const FilesystemEncoding = Encoding;\n//# sourceMappingURL=definitions.js.map","import { registerPlugin } from '@capacitor/core';\nimport { exposeSynapse } from '@capacitor/synapse';\nconst Filesystem = registerPlugin('Filesystem', {\n web: () => import('./web').then((m) => new m.FilesystemWeb()),\n});\nexposeSynapse();\nexport * from './definitions';\nexport { Filesystem };\n//# sourceMappingURL=index.js.map","import { WebPlugin, buildRequestInit } from '@capacitor/core';\nimport { Encoding } from './definitions';\nfunction resolve(path) {\n const posix = path.split('/').filter((item) => item !== '.');\n const newPosix = [];\n posix.forEach((item) => {\n if (item === '..' && newPosix.length > 0 && newPosix[newPosix.length - 1] !== '..') {\n newPosix.pop();\n }\n else {\n newPosix.push(item);\n }\n });\n return newPosix.join('/');\n}\nfunction isPathParent(parent, children) {\n parent = resolve(parent);\n children = resolve(children);\n const pathsA = parent.split('/');\n const pathsB = children.split('/');\n return parent !== children && pathsA.every((value, index) => value === pathsB[index]);\n}\nexport class FilesystemWeb extends WebPlugin {\n constructor() {\n super(...arguments);\n this.DB_VERSION = 1;\n this.DB_NAME = 'Disc';\n this._writeCmds = ['add', 'put', 'delete'];\n /**\n * Function that performs a http request to a server and downloads the file to the specified destination\n *\n * @deprecated Use the @capacitor/file-transfer plugin instead.\n * @param options the options for the download operation\n * @returns a promise that resolves with the download file result\n */\n this.downloadFile = async (options) => {\n var _a, _b;\n const requestInit = buildRequestInit(options, options.webFetchExtra);\n const response = await fetch(options.url, requestInit);\n let blob;\n if (!options.progress)\n blob = await response.blob();\n else if (!(response === null || response === void 0 ? void 0 : response.body))\n blob = new Blob();\n else {\n const reader = response.body.getReader();\n let bytes = 0;\n const chunks = [];\n const contentType = response.headers.get('content-type');\n const contentLength = parseInt(response.headers.get('content-length') || '0', 10);\n while (true) {\n const { done, value } = await reader.read();\n if (done)\n break;\n chunks.push(value);\n bytes += (value === null || value === void 0 ? void 0 : value.length) || 0;\n const status = {\n url: options.url,\n bytes,\n contentLength,\n };\n this.notifyListeners('progress', status);\n }\n const allChunks = new Uint8Array(bytes);\n let position = 0;\n for (const chunk of chunks) {\n if (typeof chunk === 'undefined')\n continue;\n allChunks.set(chunk, position);\n position += chunk.length;\n }\n blob = new Blob([allChunks.buffer], { type: contentType || undefined });\n }\n const result = await this.writeFile({\n path: options.path,\n directory: (_a = options.directory) !== null && _a !== void 0 ? _a : undefined,\n recursive: (_b = options.recursive) !== null && _b !== void 0 ? _b : false,\n data: blob,\n });\n return { path: result.uri, blob };\n };\n }\n readFileInChunks(_options, _callback) {\n throw this.unavailable('Method not implemented.');\n }\n async initDb() {\n if (this._db !== undefined) {\n return this._db;\n }\n if (!('indexedDB' in window)) {\n throw this.unavailable(\"This browser doesn't support IndexedDB\");\n }\n return new Promise((resolve, reject) => {\n const request = indexedDB.open(this.DB_NAME, this.DB_VERSION);\n request.onupgradeneeded = FilesystemWeb.doUpgrade;\n request.onsuccess = () => {\n this._db = request.result;\n resolve(request.result);\n };\n request.onerror = () => reject(request.error);\n request.onblocked = () => {\n console.warn('db blocked');\n };\n });\n }\n static doUpgrade(event) {\n const eventTarget = event.target;\n const db = eventTarget.result;\n switch (event.oldVersion) {\n case 0:\n case 1:\n default: {\n if (db.objectStoreNames.contains('FileStorage')) {\n db.deleteObjectStore('FileStorage');\n }\n const store = db.createObjectStore('FileStorage', { keyPath: 'path' });\n store.createIndex('by_folder', 'folder');\n }\n }\n }\n async dbRequest(cmd, args) {\n const readFlag = this._writeCmds.indexOf(cmd) !== -1 ? 'readwrite' : 'readonly';\n return this.initDb().then((conn) => {\n return new Promise((resolve, reject) => {\n const tx = conn.transaction(['FileStorage'], readFlag);\n const store = tx.objectStore('FileStorage');\n const req = store[cmd](...args);\n req.onsuccess = () => resolve(req.result);\n req.onerror = () => reject(req.error);\n });\n });\n }\n async dbIndexRequest(indexName, cmd, args) {\n const readFlag = this._writeCmds.indexOf(cmd) !== -1 ? 'readwrite' : 'readonly';\n return this.initDb().then((conn) => {\n return new Promise((resolve, reject) => {\n const tx = conn.transaction(['FileStorage'], readFlag);\n const store = tx.objectStore('FileStorage');\n const index = store.index(indexName);\n const req = index[cmd](...args);\n req.onsuccess = () => resolve(req.result);\n req.onerror = () => reject(req.error);\n });\n });\n }\n getPath(directory, uriPath) {\n const cleanedUriPath = uriPath !== undefined ? uriPath.replace(/^[/]+|[/]+$/g, '') : '';\n let fsPath = '';\n if (directory !== undefined)\n fsPath += '/' + directory;\n if (uriPath !== '')\n fsPath += '/' + cleanedUriPath;\n return fsPath;\n }\n async clear() {\n const conn = await this.initDb();\n const tx = conn.transaction(['FileStorage'], 'readwrite');\n const store = tx.objectStore('FileStorage');\n store.clear();\n }\n /**\n * Read a file from disk\n * @param options options for the file read\n * @return a promise that resolves with the read file data result\n */\n async readFile(options) {\n const path = this.getPath(options.directory, options.path);\n // const encoding = options.encoding;\n const entry = (await this.dbRequest('get', [path]));\n if (entry === undefined)\n throw Error('File does not exist.');\n return { data: entry.content ? entry.content : '' };\n }\n /**\n * Write a file to disk in the specified location on device\n * @param options options for the file write\n * @return a promise that resolves with the file write result\n */\n async writeFile(options) {\n const path = this.getPath(options.directory, options.path);\n let data = options.data;\n const encoding = options.encoding;\n const doRecursive = options.recursive;\n const occupiedEntry = (await this.dbRequest('get', [path]));\n if (occupiedEntry && occupiedEntry.type === 'directory')\n throw Error('The supplied path is a directory.');\n const parentPath = path.substr(0, path.lastIndexOf('/'));\n const parentEntry = (await this.dbRequest('get', [parentPath]));\n if (parentEntry === undefined) {\n const subDirIndex = parentPath.indexOf('/', 1);\n if (subDirIndex !== -1) {\n const parentArgPath = parentPath.substr(subDirIndex);\n await this.mkdir({\n path: parentArgPath,\n directory: options.directory,\n recursive: doRecursive,\n });\n }\n }\n if (!encoding && !(data instanceof Blob)) {\n data = data.indexOf(',') >= 0 ? data.split(',')[1] : data;\n if (!this.isBase64String(data))\n throw Error('The supplied data is not valid base64 content.');\n }\n const now = Date.now();\n const pathObj = {\n path: path,\n folder: parentPath,\n type: 'file',\n size: data instanceof Blob ? data.size : data.length,\n ctime: now,\n mtime: now,\n content: data,\n };\n await this.dbRequest('put', [pathObj]);\n return {\n uri: pathObj.path,\n };\n }\n /**\n * Append to a file on disk in the specified location on device\n * @param options options for the file append\n * @return a promise that resolves with the file write result\n */\n async appendFile(options) {\n const path = this.getPath(options.directory, options.path);\n let data = options.data;\n const encoding = options.encoding;\n const parentPath = path.substr(0, path.lastIndexOf('/'));\n const now = Date.now();\n let ctime = now;\n const occupiedEntry = (await this.dbRequest('get', [path]));\n if (occupiedEntry && occupiedEntry.type === 'directory')\n throw Error('The supplied path is a directory.');\n const parentEntry = (await this.dbRequest('get', [parentPath]));\n if (parentEntry === undefined) {\n const subDirIndex = parentPath.indexOf('/', 1);\n if (subDirIndex !== -1) {\n const parentArgPath = parentPath.substr(subDirIndex);\n await this.mkdir({\n path: parentArgPath,\n directory: options.directory,\n recursive: true,\n });\n }\n }\n if (!encoding && !this.isBase64String(data))\n throw Error('The supplied data is not valid base64 content.');\n if (occupiedEntry !== undefined) {\n if (occupiedEntry.content instanceof Blob) {\n throw Error('The occupied entry contains a Blob object which cannot be appended to.');\n }\n if (occupiedEntry.content !== undefined && !encoding) {\n data = btoa(atob(occupiedEntry.content) + atob(data));\n }\n else {\n data = occupiedEntry.content + data;\n }\n ctime = occupiedEntry.ctime;\n }\n const pathObj = {\n path: path,\n folder: parentPath,\n type: 'file',\n size: data.length,\n ctime: ctime,\n mtime: now,\n content: data,\n };\n await this.dbRequest('put', [pathObj]);\n }\n /**\n * Delete a file from disk\n * @param options options for the file delete\n * @return a promise that resolves with the deleted file data result\n */\n async deleteFile(options) {\n const path = this.getPath(options.directory, options.path);\n const entry = (await this.dbRequest('get', [path]));\n if (entry === undefined)\n throw Error('File does not exist.');\n const entries = await this.dbIndexRequest('by_folder', 'getAllKeys', [IDBKeyRange.only(path)]);\n if (entries.length !== 0)\n throw Error('Folder is not empty.');\n await this.dbRequest('delete', [path]);\n }\n /**\n * Create a directory.\n * @param options options for the mkdir\n * @return a promise that resolves with the mkdir result\n */\n async mkdir(options) {\n const path = this.getPath(options.directory, options.path);\n const doRecursive = options.recursive;\n const parentPath = path.substr(0, path.lastIndexOf('/'));\n const depth = (path.match(/\\//g) || []).length;\n const parentEntry = (await this.dbRequest('get', [parentPath]));\n const occupiedEntry = (await this.dbRequest('get', [path]));\n if (depth === 1)\n throw Error('Cannot create Root directory');\n if (occupiedEntry !== undefined)\n throw Error('Current directory does already exist.');\n if (!doRecursive && depth !== 2 && parentEntry === undefined)\n throw Error('Parent directory must exist');\n if (doRecursive && depth !== 2 && parentEntry === undefined) {\n const parentArgPath = parentPath.substr(parentPath.indexOf('/', 1));\n await this.mkdir({\n path: parentArgPath,\n directory: options.directory,\n recursive: doRecursive,\n });\n }\n const now = Date.now();\n const pathObj = {\n path: path,\n folder: parentPath,\n type: 'directory',\n size: 0,\n ctime: now,\n mtime: now,\n };\n await this.dbRequest('put', [pathObj]);\n }\n /**\n * Remove a directory\n * @param options the options for the directory remove\n */\n async rmdir(options) {\n const { path, directory, recursive } = options;\n const fullPath = this.getPath(directory, path);\n const entry = (await this.dbRequest('get', [fullPath]));\n if (entry === undefined)\n throw Error('Folder does not exist.');\n if (entry.type !== 'directory')\n throw Error('Requested path is not a directory');\n const readDirResult = await this.readdir({ path, directory });\n if (readDirResult.files.length !== 0 && !recursive)\n throw Error('Folder is not empty');\n for (const entry of readDirResult.files) {\n const entryPath = `${path}/${entry.name}`;\n const entryObj = await this.stat({ path: entryPath, directory });\n if (entryObj.type === 'file') {\n await this.deleteFile({ path: entryPath, directory });\n }\n else {\n await this.rmdir({ path: entryPath, directory, recursive });\n }\n }\n await this.dbRequest('delete', [fullPath]);\n }\n /**\n * Return a list of files from the directory (not recursive)\n * @param options the options for the readdir operation\n * @return a promise that resolves with the readdir directory listing result\n */\n async readdir(options) {\n const path = this.getPath(options.directory, options.path);\n const entry = (await this.dbRequest('get', [path]));\n if (options.path !== '' && entry === undefined)\n throw Error('Folder does not exist.');\n const entries = await this.dbIndexRequest('by_folder', 'getAllKeys', [IDBKeyRange.only(path)]);\n const files = await Promise.all(entries.map(async (e) => {\n let subEntry = (await this.dbRequest('get', [e]));\n if (subEntry === undefined) {\n subEntry = (await this.dbRequest('get', [e + '/']));\n }\n return {\n name: e.substring(path.length + 1),\n type: subEntry.type,\n size: subEntry.size,\n ctime: subEntry.ctime,\n mtime: subEntry.mtime,\n uri: subEntry.path,\n };\n }));\n return { files: files };\n }\n /**\n * Return full File URI for a path and directory\n * @param options the options for the stat operation\n * @return a promise that resolves with the file stat result\n */\n async getUri(options) {\n const path = this.getPath(options.directory, options.path);\n let entry = (await this.dbRequest('get', [path]));\n if (entry === undefined) {\n entry = (await this.dbRequest('get', [path + '/']));\n }\n return {\n uri: (entry === null || entry === void 0 ? void 0 : entry.path) || path,\n };\n }\n /**\n * Return data about a file\n * @param options the options for the stat operation\n * @return a promise that resolves with the file stat result\n */\n async stat(options) {\n const path = this.getPath(options.directory, options.path);\n let entry = (await this.dbRequest('get', [path]));\n if (entry === undefined) {\n entry = (await this.dbRequest('get', [path + '/']));\n }\n if (entry === undefined)\n throw Error('Entry does not exist.');\n return {\n name: entry.path.substring(path.length + 1),\n type: entry.type,\n size: entry.size,\n ctime: entry.ctime,\n mtime: entry.mtime,\n uri: entry.path,\n };\n }\n /**\n * Rename a file or directory\n * @param options the options for the rename operation\n * @return a promise that resolves with the rename result\n */\n async rename(options) {\n await this._copy(options, true);\n return;\n }\n /**\n * Copy a file or directory\n * @param options the options for the copy operation\n * @return a promise that resolves with the copy result\n */\n async copy(options) {\n return this._copy(options, false);\n }\n async requestPermissions() {\n return { publicStorage: 'granted' };\n }\n async checkPermissions() {\n return { publicStorage: 'granted' };\n }\n /**\n * Function that can perform a copy or a rename\n * @param options the options for the rename operation\n * @param doRename whether to perform a rename or copy operation\n * @return a promise that resolves with the result\n */\n async _copy(options, doRename = false) {\n let { toDirectory } = options;\n const { to, from, directory: fromDirectory } = options;\n if (!to || !from) {\n throw Error('Both to and from must be provided');\n }\n // If no \"to\" directory is provided, use the \"from\" directory\n if (!toDirectory) {\n toDirectory = fromDirectory;\n }\n const fromPath = this.getPath(fromDirectory, from);\n const toPath = this.getPath(toDirectory, to);\n // Test that the \"to\" and \"from\" locations are different\n if (fromPath === toPath) {\n return {\n uri: toPath,\n };\n }\n if (isPathParent(fromPath, toPath)) {\n throw Error('To path cannot contain the from path');\n }\n // Check the state of the \"to\" location\n let toObj;\n try {\n toObj = await this.stat({\n path: to,\n directory: toDirectory,\n });\n }\n catch (e) {\n // To location does not exist, ensure the directory containing \"to\" location exists and is a directory\n const toPathComponents = to.split('/');\n toPathComponents.pop();\n const toPath = toPathComponents.join('/');\n // Check the containing directory of the \"to\" location exists\n if (toPathComponents.length > 0) {\n const toParentDirectory = await this.stat({\n path: toPath,\n directory: toDirectory,\n });\n if (toParentDirectory.type !== 'directory') {\n throw new Error('Parent directory of the to path is a file');\n }\n }\n }\n // Cannot overwrite a directory\n if (toObj && toObj.type === 'directory') {\n throw new Error('Cannot overwrite a directory with a file');\n }\n // Ensure the \"from\" object exists\n const fromObj = await this.stat({\n path: from,\n directory: fromDirectory,\n });\n // Set the mtime/ctime of the supplied path\n const updateTime = async (path, ctime, mtime) => {\n const fullPath = this.getPath(toDirectory, path);\n const entry = (await this.dbRequest('get', [fullPath]));\n entry.ctime = ctime;\n entry.mtime = mtime;\n await this.dbRequest('put', [entry]);\n };\n const ctime = fromObj.ctime ? fromObj.ctime : Date.now();\n switch (fromObj.type) {\n // The \"from\" object is a file\n case 'file': {\n // Read the file\n const file = await this.readFile({\n path: from,\n directory: fromDirectory,\n });\n // Optionally remove the file\n if (doRename) {\n await this.deleteFile({\n path: from,\n directory: fromDirectory,\n });\n }\n let encoding;\n if (!(file.data instanceof Blob) && !this.isBase64String(file.data)) {\n encoding = Encoding.UTF8;\n }\n // Write the file to the new location\n const writeResult = await this.writeFile({\n path: to,\n directory: toDirectory,\n data: file.data,\n encoding: encoding,\n });\n // Copy the mtime/ctime of a renamed file\n if (doRename) {\n await updateTime(to, ctime, fromObj.mtime);\n }\n // Resolve promise\n return writeResult;\n }\n case 'directory': {\n if (toObj) {\n throw Error('Cannot move a directory over an existing object');\n }\n try {\n // Create the to directory\n await this.mkdir({\n path: to,\n directory: toDirectory,\n recursive: false,\n });\n // Copy the mtime/ctime of a renamed directory\n if (doRename) {\n await updateTime(to, ctime, fromObj.mtime);\n }\n }\n catch (e) {\n // ignore\n }\n // Iterate over the contents of the from location\n const contents = (await this.readdir({\n path: from,\n directory: fromDirectory,\n })).files;\n for (const filename of contents) {\n // Move item from the from directory to the to directory\n await this._copy({\n from: `${from}/${filename.name}`,\n to: `${to}/${filename.name}`,\n directory: fromDirectory,\n toDirectory,\n }, doRename);\n }\n // Optionally remove the original from directory\n if (doRename) {\n await this.rmdir({\n path: from,\n directory: fromDirectory,\n });\n }\n }\n }\n return {\n uri: toPath,\n };\n }\n isBase64String(str) {\n try {\n return btoa(atob(str)) == str;\n }\n catch (err) {\n return false;\n }\n }\n}\nFilesystemWeb._debug = true;\n//# sourceMappingURL=web.js.map"],"names":["Directory","Encoding","registerPlugin","exposeSynapse","WebPlugin","buildRequestInit"],"mappings":"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"} \ No newline at end of file diff --git a/node_modules/@capacitor/filesystem/ios/Sources/FilesystemPlugin/CAPPluginCall+Accelerators.swift b/node_modules/@capacitor/filesystem/ios/Sources/FilesystemPlugin/CAPPluginCall+Accelerators.swift new file mode 100644 index 0000000..a942c95 --- /dev/null +++ b/node_modules/@capacitor/filesystem/ios/Sources/FilesystemPlugin/CAPPluginCall+Accelerators.swift @@ -0,0 +1,73 @@ +import Capacitor +import IONFilesystemLib + +extension CAPPluginCall { + func getEncoding(_ key: String) -> IONFILEEncoding { + if let encodingParameter = getString(key) { + .string(encoding: .create(from: encodingParameter)) + } else { + .byteBuffer + } + } + + func getSearchPath(_ key: String) -> IONFILESearchPath { + getSearchPath(key, withDefaultSearchPath: .raw, andDefaultDirectoryType: .document) + } + + func getSearchPath(_ key: String, withDefault defaultValue: IONFILESearchPath) -> IONFILESearchPath { + getSearchPath(key, withDefaultSearchPath: defaultValue) + } + + func getEncodingMapper() -> IONFILEEncodingValueMapper? { + guard let data: String = getString(Constants.MethodParameter.data) else { + return nil + } + return switch getEncoding(Constants.MethodParameter.encoding) { + case .byteBuffer: + if let base64Data = Data.capacitor.data(base64EncodedOrDataUrl: data) { + .byteBuffer(value: base64Data) + } else { + nil + } + case .string(encoding: let stringEncoding): + .string(encoding: stringEncoding, value: data) + @unknown default: nil + } + } + + func getIONFileMethod() -> IONFileMethod { + return IONFileMethod(rawValue: self.methodName) ?? IONFileMethod.getUri + } + + func handleSuccess(_ data: PluginCallResultData?, _ keepCallAlive: Bool = false) { + keepAlive = keepCallAlive + if let data { + resolve(data) + } else { + resolve() + } + } + + func handlePermissionSuccess() { + handleSuccess([Constants.ResultDataKey.publicStorage: Constants.ResultDataValue.granted]) + } + + func handleError(_ error: FilesystemError) { + let errorPair = error.toCodeMessagePair() + reject(errorPair.message, errorPair.code) + } + + private func getSearchPath( + _ key: String, withDefaultSearchPath defaultSearchPath: IONFILESearchPath, andDefaultDirectoryType defaultDirectoryType: IONFILEDirectoryType? = nil + ) -> IONFILESearchPath { + guard let directoryParameter = getString(key), directoryParameter.isEmpty == false else { + return defaultSearchPath + } + + return if let type = IONFILEDirectoryType.create(from: directoryParameter) ?? defaultDirectoryType { + .directory(type: type) + } else { + defaultSearchPath + } + } +} diff --git a/node_modules/@capacitor/filesystem/ios/Sources/FilesystemPlugin/FilesystemConstants.swift b/node_modules/@capacitor/filesystem/ios/Sources/FilesystemPlugin/FilesystemConstants.swift new file mode 100644 index 0000000..9b3e3d2 --- /dev/null +++ b/node_modules/@capacitor/filesystem/ios/Sources/FilesystemPlugin/FilesystemConstants.swift @@ -0,0 +1,63 @@ +struct Constants { + struct ConfigurationValue { + static let endOfFile = "" + } + + struct DirectoryTypeValue { + static let cache = "CACHE" + static let data = "DATA" + static let documents = "DOCUMENTS" + static let external = "EXTERNAL" + static let externalCache = "EXTERNAL_CACHE" + static let externalStorage = "EXTERNAL_STORAGE" + static let library = "LIBRARY" + static let libraryNoCloud = "LIBRARY_NO_CLOUD" + static let temporary = "TEMPORARY" + } + + struct FileItemTypeValue { + static let directory = "directory" + static let file = "file" + static let fallback = "" + } + + struct MethodParameter { + static let data = "data" + static let directory = "directory" + static let encoding = "encoding" + static let chunkSize = "chunkSize" + static let offset = "offset" + static let length = "length" + static let from = "from" + static let path = "path" + static let recursive = "recursive" + static let to = "to" + static let toDirectory = "toDirectory" + } + + struct ResultDataKey { + static let data = "data" + static let files = "files" + static let uri = "uri" + static let publicStorage = "publicStorage" + } + + struct ResultDataValue { + static let granted = "granted" + } + + struct ItemAttributeJSONKey { + static let ctime = "ctime" + static let mtime = "mtime" + static let name = "name" + static let size = "size" + static let type = "type" + static let uri = "uri" + } + + struct StringEncodingValue { + static let ascii = "ascii" + static let utf16 = "utf16" + static let utf8 = "utf8" + } +} diff --git a/node_modules/@capacitor/filesystem/ios/Sources/FilesystemPlugin/FilesystemError.swift b/node_modules/@capacitor/filesystem/ios/Sources/FilesystemPlugin/FilesystemError.swift new file mode 100644 index 0000000..030e336 --- /dev/null +++ b/node_modules/@capacitor/filesystem/ios/Sources/FilesystemPlugin/FilesystemError.swift @@ -0,0 +1,57 @@ +enum IONFileMethod: String { + case readFile + case readFileInChunks + case writeFile + case appendFile + case deleteFile + case mkdir + case rmdir + case readdir + case stat + case getUri + case rename + case copy +} + +enum FilesystemError: Error { + case bridgeNotInitialised + case invalidInput(method: IONFileMethod) + case invalidPath(_ path: String) + case fileNotFound(method: IONFileMethod, _ path: String) + case directoryAlreadyExists(_ path: String) + case parentDirectoryMissing + case cannotDeleteChildren + case operationFailed(method: IONFileMethod, _ error: Error) + + func toCodeMessagePair() -> (code: String, message: String) { + ("OS-PLUG-FILE-\(String(format: "%04d", code))", description) + } +} + +private extension FilesystemError { + var code: Int { + switch self { + case .bridgeNotInitialised: 4 + case .invalidInput: 5 + case .invalidPath: 6 + case .fileNotFound: 8 + case .directoryAlreadyExists: 10 + case .parentDirectoryMissing: 11 + case .cannotDeleteChildren: 12 + case .operationFailed: 13 + } + } + + var description: String { + switch self { + case .bridgeNotInitialised: "Capacitor bridge isn't initialized." + case .invalidInput(let method): "The '\(method.rawValue)' input parameters aren't valid." + case .invalidPath(let path): "Invalid \(!path.isEmpty ? "'" + path + "' " : "")path." + case .fileNotFound(let method, let path): "'\(method.rawValue)' failed because file\(!path.isEmpty ? " at '" + path + "' " : "") does not exist." + case .directoryAlreadyExists(let path): "Directory\(!path.isEmpty ? " at '" + path + "' " : "") already exists, cannot be overwritten." + case .parentDirectoryMissing: "Missing parent directory - possibly recursive=false was passed or parent directory creation failed." + case .cannotDeleteChildren: "Cannot delete directory with children; received recursive=false but directory has contents." + case .operationFailed(let method, let error): "'\(method.rawValue)' failed with: \(error.localizedDescription)" + } + } +} diff --git a/node_modules/@capacitor/filesystem/ios/Sources/FilesystemPlugin/FilesystemLocationResolver.swift b/node_modules/@capacitor/filesystem/ios/Sources/FilesystemPlugin/FilesystemLocationResolver.swift new file mode 100644 index 0000000..c96f69e --- /dev/null +++ b/node_modules/@capacitor/filesystem/ios/Sources/FilesystemPlugin/FilesystemLocationResolver.swift @@ -0,0 +1,39 @@ +import Capacitor +import Foundation +import IONFilesystemLib + +struct FilesystemLocationResolver { + let service: FileService + + func resolveSinglePath(from call: CAPPluginCall) -> Result { + guard let path = call.getString(Constants.MethodParameter.path) else { + return .failure(.invalidInput(method: call.getIONFileMethod())) + } + + let directory = call.getSearchPath(Constants.MethodParameter.directory) + return resolveURL(path: path, directory: directory) + } + + func resolveDualPaths(from call: CAPPluginCall) -> Result<(source: URL, destination: URL), FilesystemError> { + guard let fromPath = call.getString(Constants.MethodParameter.from), let toPath = call.getString(Constants.MethodParameter.to) else { + return .failure(.invalidInput(method: call.getIONFileMethod())) + } + + let fromDirectory = call.getSearchPath(Constants.MethodParameter.directory) + let toDirectory = call.getSearchPath(Constants.MethodParameter.toDirectory, withDefault: fromDirectory) + + return resolveURL(path: fromPath, directory: fromDirectory) + .flatMap { sourceURL in + resolveURL(path: toPath, directory: toDirectory) + .map { (source: sourceURL, destination: $0) } + } + } + + private func resolveURL(path: String, directory: IONFILESearchPath) -> Result { + return if let url = try? service.getFileURL(atPath: path, withSearchPath: directory) { + .success(url) + } else { + .failure(.invalidPath(path)) + } + } +} diff --git a/node_modules/@capacitor/filesystem/ios/Sources/FilesystemPlugin/FilesystemOperation.swift b/node_modules/@capacitor/filesystem/ios/Sources/FilesystemPlugin/FilesystemOperation.swift new file mode 100644 index 0000000..cba3570 --- /dev/null +++ b/node_modules/@capacitor/filesystem/ios/Sources/FilesystemPlugin/FilesystemOperation.swift @@ -0,0 +1,24 @@ +import Foundation +import IONFilesystemLib + +enum FilesystemOperation { + // Read Operations + case readFile(url: URL, encoding: IONFILEEncoding, offset: Int, length: Int) + case readFileInChunks(url: URL, encoding: IONFILEEncoding, chunkSize: Int, offset: Int, length: Int) + case readdir(url: URL) + case stat(url: URL) + case getUri(url: URL) + + // Write Operations + case write(url: URL, encodingMapper: IONFILEEncodingValueMapper, recursive: Bool) + case append(url: URL, encodingMapper: IONFILEEncodingValueMapper, recursive: Bool) + + // Directory Operations + case mkdir(url: URL, recursive: Bool) + case rmdir(url: URL, recursive: Bool) + + // File Management Operations + case delete(url: URL) + case rename(source: URL, destination: URL) + case copy(source: URL, destination: URL) +} diff --git a/node_modules/@capacitor/filesystem/ios/Sources/FilesystemPlugin/FilesystemOperationExecutor.swift b/node_modules/@capacitor/filesystem/ios/Sources/FilesystemPlugin/FilesystemOperationExecutor.swift new file mode 100644 index 0000000..c5eea30 --- /dev/null +++ b/node_modules/@capacitor/filesystem/ios/Sources/FilesystemPlugin/FilesystemOperationExecutor.swift @@ -0,0 +1,116 @@ +import Capacitor +import Foundation +import IONFilesystemLib +import Combine + +class FilesystemOperationExecutor { + let service: FileService + private var cancellables = Set() + + init(service: FileService) { + self.service = service + } + + func execute(_ operation: FilesystemOperation, _ call: CAPPluginCall) { + do { + var resultData: PluginCallResultData? + + switch operation { + case .readFile(let url, let encoding, let offset, let length): + let data = try service.readEntireFile(atURL: url, withEncoding: encoding, andOffset: offset, andLength: length).textValue + resultData = [Constants.ResultDataKey.data: data] + case .readFileInChunks(let url, let encoding, let chunkSize, let offset, let length): + try processFileInChunks(at: url, withEncoding: encoding, chunkSize: chunkSize, offset: offset, length: length, for: operation, call) + return + case .write(let url, let encodingMapper, let recursive): + try service.saveFile(atURL: url, withEncodingAndData: encodingMapper, includeIntermediateDirectories: recursive) + resultData = [Constants.ResultDataKey.uri: url.absoluteString] + case .append(let url, let encodingMapper, let recursive): + try service.appendData(encodingMapper, atURL: url, includeIntermediateDirectories: recursive) + case .delete(let url): + try service.deleteFile(atURL: url) + case .mkdir(let url, let recursive): + try service.createDirectory(atURL: url, includeIntermediateDirectories: recursive) + case .rmdir(let url, let recursive): + try service.removeDirectory(atURL: url, includeIntermediateDirectories: recursive) + case .readdir(let url): + let directoryAttributes = try service.listDirectory(atURL: url) + .map { try fetchItemAttributesJSObject(using: service, atURL: $0) } + resultData = [Constants.ResultDataKey.files: directoryAttributes] + case .stat(let url): + resultData = try fetchItemAttributesJSObject(using: service, atURL: url) + case .getUri(let url): + resultData = [Constants.ResultDataKey.uri: url.absoluteString] + case .rename(let source, let destination): + try service.renameItem(fromURL: source, toURL: destination) + case .copy(let source, let destination): + try service.copyItem(fromURL: source, toURL: destination) + resultData = [Constants.ResultDataKey.uri: destination.absoluteString] + } + + call.handleSuccess(resultData) + } catch { + call.handleError(mapError(error, for: operation)) + } + } +} + +private extension FilesystemOperationExecutor { + func processFileInChunks(at url: URL, withEncoding encoding: IONFILEEncoding, chunkSize: Int, offset: Int, length: Int, for operation: FilesystemOperation, _ call: CAPPluginCall) throws { + let chunkSizeToUse = chunkSizeToUse(basedOn: chunkSize, and: encoding) + try service.readFileInChunks(atURL: url, withEncoding: encoding, andChunkSize: chunkSizeToUse, andOffset: offset, andLength: length) + .sink(receiveCompletion: { completion in + switch completion { + case .finished: + call.handleSuccess([Constants.ResultDataKey.data: Constants.ConfigurationValue.endOfFile]) + case .failure(let error): + call.handleError(self.mapError(error, for: operation)) + } + }, receiveValue: { + call.handleSuccess([Constants.ResultDataKey.data: $0.textValue], true) + }) + .store(in: &cancellables) + } + + private func chunkSizeToUse(basedOn chunkSize: Int, and encoding: IONFILEEncoding) -> Int { + // When dealing with byte buffers, we need chunk size that are multiples of 3 + // We're treating byte buffers as base64 data, and size multiple of 3 makes it so that chunks can be concatenated + encoding == .byteBuffer ? chunkSize - chunkSize % 3 + 3 : chunkSize + } + + func mapError(_ error: Error, for operation: FilesystemOperation) -> FilesystemError { + var path = "" + var method: IONFileMethod = IONFileMethod.getUri + switch operation { + case .readFile(let url, _, _, _): path = url.absoluteString; method = .readFile + case .readFileInChunks(let url, _, _, _, _): path = url.absoluteString; method = .readFileInChunks + case .write(let url, _, _): path = url.absoluteString; method = .writeFile + case .append(let url, _, _): path = url.absoluteString; method = .appendFile + case .delete(let url): path = url.absoluteString; method = .deleteFile + case .mkdir(let url, _): path = url.absoluteString; method = .mkdir + case .rmdir(let url, _): path = url.absoluteString; method = .rmdir + case .readdir(let url): path = url.absoluteString; method = .readdir + case .stat(let url): path = url.absoluteString; method = .stat + case .getUri(let url): return FilesystemError.invalidPath(url.absoluteString) + case .rename(let sourceUrl, _): path = sourceUrl.absoluteString; method = .rename + case .copy(let sourceUrl, _): path = sourceUrl.absoluteString; method = .copy + } + + return mapError(error, withPath: path, andMethod: method) + } + + private func mapError(_ error: Error, withPath path: String, andMethod method: IONFileMethod) -> FilesystemError { + return switch error { + case IONFILEDirectoryManagerError.notEmpty: .cannotDeleteChildren + case IONFILEDirectoryManagerError.alreadyExists: .directoryAlreadyExists(path) + case IONFILEFileManagerError.missingParentFolder: .parentDirectoryMissing + case IONFILEFileManagerError.fileNotFound: .fileNotFound(method: method, path) + default: .operationFailed(method: method, error) + } + } + + func fetchItemAttributesJSObject(using service: FileService, atURL url: URL) throws -> IONFILEItemAttributeModel.JSResult { + let attributes = try service.getItemAttributes(atURL: url) + return attributes.toJSResult(with: url) + } +} diff --git a/node_modules/@capacitor/filesystem/ios/Sources/FilesystemPlugin/FilesystemPlugin.swift b/node_modules/@capacitor/filesystem/ios/Sources/FilesystemPlugin/FilesystemPlugin.swift new file mode 100644 index 0000000..c743510 --- /dev/null +++ b/node_modules/@capacitor/filesystem/ios/Sources/FilesystemPlugin/FilesystemPlugin.swift @@ -0,0 +1,233 @@ +import Foundation +import Capacitor +import IONFilesystemLib + +typealias FileService = any IONFILEDirectoryManager & IONFILEFileManager + +/** + * Please read the Capacitor iOS Plugin Development Guide + * here: https://capacitorjs.com/docs/plugins/ios + */ +@objc(FilesystemPlugin) +public class FilesystemPlugin: CAPPlugin, CAPBridgedPlugin { + public let identifier = "FilesystemPlugin" + public let jsName = "Filesystem" + public let pluginMethods: [CAPPluginMethod] = [ + CAPPluginMethod(name: "readFile", returnType: CAPPluginReturnPromise), + CAPPluginMethod(name: "readFileInChunks", returnType: CAPPluginReturnCallback), + CAPPluginMethod(name: "writeFile", returnType: CAPPluginReturnPromise), + CAPPluginMethod(name: "appendFile", returnType: CAPPluginReturnPromise), + CAPPluginMethod(name: "deleteFile", returnType: CAPPluginReturnPromise), + CAPPluginMethod(name: "mkdir", returnType: CAPPluginReturnPromise), + CAPPluginMethod(name: "rmdir", returnType: CAPPluginReturnPromise), + CAPPluginMethod(name: "readdir", returnType: CAPPluginReturnPromise), + CAPPluginMethod(name: "getUri", returnType: CAPPluginReturnPromise), + CAPPluginMethod(name: "stat", returnType: CAPPluginReturnPromise), + CAPPluginMethod(name: "rename", returnType: CAPPluginReturnPromise), + CAPPluginMethod(name: "copy", returnType: CAPPluginReturnPromise), + CAPPluginMethod(name: "checkPermissions", returnType: CAPPluginReturnPromise), + CAPPluginMethod(name: "requestPermissions", returnType: CAPPluginReturnPromise), + CAPPluginMethod(name: "downloadFile", returnType: CAPPluginReturnPromise) + ] + + private let legacyImplementation = LegacyFilesystemImplementation() + + private var fileService: FileService? + + override public func load() { + self.fileService = IONFILEManager() + } + + func getService() -> Result { + if fileService == nil { load() } + return fileService.map(Result.success) ?? .failure(.bridgeNotInitialised) + } + + @objc override public func checkPermissions(_ call: CAPPluginCall) { + call.handlePermissionSuccess() + } + + @objc override public func requestPermissions(_ call: CAPPluginCall) { + call.handlePermissionSuccess() + } +} + +// MARK: - Public API Methods +private extension FilesystemPlugin { + /** + * Read a file from the filesystem. + */ + @objc func readFile(_ call: CAPPluginCall) { + let encoding = call.getEncoding(Constants.MethodParameter.encoding) + let offset = call.getInt(Constants.MethodParameter.offset) ?? 0 + let length = call.getInt(Constants.MethodParameter.length) ?? -1 + performSinglePathOperation(call) { + .readFile(url: $0, encoding: encoding, offset: offset, length: length) + } + } + + @objc func readFileInChunks(_ call: CAPPluginCall) { + let encoding = call.getEncoding(Constants.MethodParameter.encoding) + guard let chunkSize = call.getInt(Constants.MethodParameter.chunkSize) else { + return call.handleError(.invalidInput(method: call.getIONFileMethod())) + } + let offset = call.getInt(Constants.MethodParameter.offset) ?? 0 + let length = call.getInt(Constants.MethodParameter.length) ?? -1 + performSinglePathOperation(call) { + .readFileInChunks(url: $0, encoding: encoding, chunkSize: chunkSize, offset: offset, length: length) + } + } + + /** + * Write a file to the filesystem. + */ + @objc func writeFile(_ call: CAPPluginCall) { + guard let encodingMapper = call.getEncodingMapper() else { + return call.handleError(.invalidInput(method: call.getIONFileMethod())) + } + let recursive = call.getBool(Constants.MethodParameter.recursive, false) + + performSinglePathOperation(call) { + .write(url: $0, encodingMapper: encodingMapper, recursive: recursive) + } + } + + /** + * Append to a file. + */ + @objc func appendFile(_ call: CAPPluginCall) { + guard let encodingMapper = call.getEncodingMapper() else { + return call.handleError(.invalidInput(method: call.getIONFileMethod())) + } + let recursive = call.getBool(Constants.MethodParameter.recursive, false) + + performSinglePathOperation(call) { + .append(url: $0, encodingMapper: encodingMapper, recursive: recursive) + } + } + + /** + * Delete a file. + */ + @objc func deleteFile(_ call: CAPPluginCall) { + performSinglePathOperation(call) { + .delete(url: $0) + } + } + + /** + * Make a new directory, optionally creating parent folders first. + */ + @objc func mkdir(_ call: CAPPluginCall) { + let recursive = call.getBool(Constants.MethodParameter.recursive, false) + + performSinglePathOperation(call) { + .mkdir(url: $0, recursive: recursive) + } + } + + /** + * Remove a directory. + */ + @objc func rmdir(_ call: CAPPluginCall) { + let recursive = call.getBool(Constants.MethodParameter.recursive, false) + + performSinglePathOperation(call) { + .rmdir(url: $0, recursive: recursive) + } + } + + /** + * Read the contents of a directory. + */ + @objc func readdir(_ call: CAPPluginCall) { + performSinglePathOperation(call) { + .readdir(url: $0) + } + } + + @objc func stat(_ call: CAPPluginCall) { + performSinglePathOperation(call) { + .stat(url: $0) + } + } + + @objc func getUri(_ call: CAPPluginCall) { + performSinglePathOperation(call) { + .getUri(url: $0) + } + } + + /** + * Rename a file or directory. + */ + @objc func rename(_ call: CAPPluginCall) { + performDualPathOperation(call) { + .rename(source: $0, destination: $1) + } + } + + /** + * Copy a file or directory. + */ + @objc func copy(_ call: CAPPluginCall) { + performDualPathOperation(call) { + .copy(source: $0, destination: $1) + } + } + + /** + * [DEPRECATED] Download a file + */ + @available(*, deprecated, message: "Use @capacitor/file-transfer plugin instead.") + @objc func downloadFile(_ call: CAPPluginCall) { + guard let url = call.getString("url") else { return call.reject("Must provide a URL") } + let progressEmitter: LegacyFilesystemImplementation.ProgressEmitter = { bytes, contentLength in + self.notifyListeners("progress", data: [ + "url": url, + "bytes": bytes, + "contentLength": contentLength + ]) + } + + do { + try legacyImplementation.downloadFile(call: call, emitter: progressEmitter, config: bridge?.config) + } catch let error { + call.reject(error.localizedDescription) + } + } +} + +// MARK: - Operation Execution +private extension FilesystemPlugin { + func performSinglePathOperation(_ call: CAPPluginCall, operationBuilder: (URL) -> FilesystemOperation) { + executeOperation(call) { service in + FilesystemLocationResolver(service: service) + .resolveSinglePath(from: call) + .map { operationBuilder($0) } + } + } + + func performDualPathOperation(_ call: CAPPluginCall, operationBuilder: (URL, URL) -> FilesystemOperation) { + executeOperation(call) { service in + FilesystemLocationResolver(service: service) + .resolveDualPaths(from: call) + .map { operationBuilder($0.source, $0.destination) } + } + } + + func executeOperation(_ call: CAPPluginCall, operationProvider: (FileService) -> Result) { + switch getService() { + case .success(let service): + switch operationProvider(service) { + case .success(let operation): + let executor = FilesystemOperationExecutor(service: service) + executor.execute(operation, call) + case .failure(let error): + call.handleError(error) + } + case .failure(let error): + call.handleError(error) + } + } +} diff --git a/node_modules/@capacitor/filesystem/ios/Sources/FilesystemPlugin/IONFileStructures+Converters.swift b/node_modules/@capacitor/filesystem/ios/Sources/FilesystemPlugin/IONFileStructures+Converters.swift new file mode 100644 index 0000000..ce2ed24 --- /dev/null +++ b/node_modules/@capacitor/filesystem/ios/Sources/FilesystemPlugin/IONFileStructures+Converters.swift @@ -0,0 +1,60 @@ +import Foundation +import IONFilesystemLib + +extension IONFILEStringEncoding { + static func create(from text: String) -> Self { + switch text { + case Constants.StringEncodingValue.ascii: .ascii + case Constants.StringEncodingValue.utf16: .utf16 + case Constants.StringEncodingValue.utf8: .utf8 + default: .utf8 + } + } +} + +extension IONFILEDirectoryType { + static func create(from text: String) -> Self? { + switch text { + case Constants.DirectoryTypeValue.cache: .cache + case Constants.DirectoryTypeValue.data, Constants.DirectoryTypeValue.documents, Constants.DirectoryTypeValue.external, Constants.DirectoryTypeValue.externalCache, Constants.DirectoryTypeValue.externalStorage: .document + case Constants.DirectoryTypeValue.library: .library + case Constants.DirectoryTypeValue.libraryNoCloud: .notSyncedLibrary + case Constants.DirectoryTypeValue.temporary: .temporary + default: nil + } + } +} + +extension IONFILEEncodingValueMapper { + var textValue: String { + switch self { + case .byteBuffer(let data): data.base64EncodedString() + case .string(_, let text): text + @unknown default: "" + } + } +} + +extension IONFILEItemAttributeModel { + typealias JSResult = [String: Any] + func toJSResult(with url: URL) -> JSResult { + [ + Constants.ItemAttributeJSONKey.name: url.lastPathComponent, + Constants.ItemAttributeJSONKey.type: type.description, + Constants.ItemAttributeJSONKey.size: size, + Constants.ItemAttributeJSONKey.ctime: UInt64(creationDateTimestamp.rounded()), + Constants.ItemAttributeJSONKey.mtime: UInt64(modificationDateTimestamp.rounded()), + Constants.ItemAttributeJSONKey.uri: url.absoluteString + ] + } +} + +extension IONFILEItemType { + var description: String { + switch self { + case .directory: Constants.FileItemTypeValue.directory + case .file: Constants.FileItemTypeValue.file + @unknown default: Constants.FileItemTypeValue.fallback + } + } +} diff --git a/node_modules/@capacitor/filesystem/ios/Sources/FilesystemPlugin/LegacyFilesystemImplementation.swift b/node_modules/@capacitor/filesystem/ios/Sources/FilesystemPlugin/LegacyFilesystemImplementation.swift new file mode 100644 index 0000000..b9dad01 --- /dev/null +++ b/node_modules/@capacitor/filesystem/ios/Sources/FilesystemPlugin/LegacyFilesystemImplementation.swift @@ -0,0 +1,183 @@ +import Foundation +import Capacitor + +@objc public class LegacyFilesystemImplementation: NSObject { + + public typealias ProgressEmitter = (_ bytes: Int64, _ contentLength: Int64) -> Void + + // swiftlint:disable function_body_length + @objc public func downloadFile(call: CAPPluginCall, emitter: @escaping ProgressEmitter, config: InstanceConfiguration?) throws { + let directory = call.getString("directory", "DOCUMENTS") + guard let path = call.getString("path") else { + call.reject("Invalid file path") + return + } + guard var urlString = call.getString("url") else { throw URLError(.badURL) } + + func handleDownload(downloadLocation: URL?, response: URLResponse?, error: Error?) { + if let error = error { + CAPLog.print("Error on download file", String(describing: downloadLocation), String(describing: response), String(describing: error)) + call.reject(error.localizedDescription, "DOWNLOAD", error, nil) + return + } + + if let httpResponse = response as? HTTPURLResponse { + if !(200...299).contains(httpResponse.statusCode) { + CAPLog.print("Error downloading file:", urlString, httpResponse) + call.reject("Error downloading file: \(urlString)", "DOWNLOAD") + return + } + HttpRequestHandler.setCookiesFromResponse(httpResponse, config) + } + + guard let location = downloadLocation else { + call.reject("Unable to get file after downloading") + return + } + + let fileManager = FileManager.default + + if let foundDir = getDirectory(directory: directory) { + let dir = fileManager.urls(for: foundDir, in: .userDomainMask).first + + do { + let dest = dir!.appendingPathComponent(path) + CAPLog.print("Attempting to write to file destination: \(dest.absoluteString)") + + if !FileManager.default.fileExists(atPath: dest.deletingLastPathComponent().absoluteString) { + try FileManager.default.createDirectory(at: dest.deletingLastPathComponent(), withIntermediateDirectories: true, attributes: nil) + } + + if FileManager.default.fileExists(atPath: dest.relativePath) { + do { + CAPLog.print("File already exists. Attempting to remove file before writing.") + try fileManager.removeItem(at: dest) + } catch let error { + call.reject("Unable to remove existing file: \(error.localizedDescription)") + return + } + } + + try fileManager.moveItem(at: location, to: dest) + CAPLog.print("Downloaded file successfully! \(dest.absoluteString)") + call.resolve(["path": dest.absoluteString]) + } catch let error { + call.reject("Unable to download file: \(error.localizedDescription)", "DOWNLOAD", error) + return + } + } else { + call.reject("Unable to download file. Couldn't find directory \(directory)") + } + } + + let method = call.getString("method", "GET") + + let headers = (call.getObject("headers") ?? [:]) as [String: Any] + let params = (call.getObject("params") ?? [:]) as [String: Any] + let responseType = call.getString("responseType", "text") + let connectTimeout = call.getDouble("connectTimeout") + let readTimeout = call.getDouble("readTimeout") + + if urlString == urlString.removingPercentEncoding { + guard let encodedUrlString = urlString.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) else { throw URLError(.badURL) } + urlString = encodedUrlString + } + + let progress = call.getBool("progress", false) + + let request = try HttpRequestHandler.CapacitorHttpRequestBuilder() + .setUrl(urlString) + .setMethod(method) + .setUrlParams(params) + .openConnection() + .build() + + request.setRequestHeaders(headers) + + // Timeouts in iOS are in seconds. So read the value in millis and divide by 1000 + let timeout = (connectTimeout ?? readTimeout ?? 600000.0) / 1000.0 + request.setTimeout(timeout) + + if let data = call.options["data"] as? JSValue { + do { + try request.setRequestBody(data) + } catch { + // Explicitly reject if the http request body was not set successfully, + // so as to not send a known malformed request, and to provide the developer with additional context. + call.reject(error.localizedDescription, (error as NSError).domain, error, nil) + return + } + } + + var session: URLSession! + var task: URLSessionDownloadTask! + let urlRequest = request.getUrlRequest() + + if progress { + class ProgressDelegate: NSObject, URLSessionDataDelegate, URLSessionDownloadDelegate { + private var handler: (URL?, URLResponse?, Error?) -> Void + private var downloadLocation: URL? + private var response: URLResponse? + private var emitter: (Int64, Int64) -> Void + private var lastEmitTimestamp: TimeInterval = 0.0 + + init(downloadHandler: @escaping (URL?, URLResponse?, Error?) -> Void, progressEmitter: @escaping (Int64, Int64) -> Void) { + handler = downloadHandler + emitter = progressEmitter + } + + func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) { + let currentTimestamp = Date().timeIntervalSince1970 + let timeElapsed = currentTimestamp - lastEmitTimestamp + + if totalBytesExpectedToWrite > 0 { + if timeElapsed >= 0.1 { + emitter(totalBytesWritten, totalBytesExpectedToWrite) + lastEmitTimestamp = currentTimestamp + } + } else { + emitter(totalBytesWritten, 0) + lastEmitTimestamp = currentTimestamp + } + } + + func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) { + downloadLocation = location + handler(downloadLocation, downloadTask.response, downloadTask.error) + } + + func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) { + if error != nil { + handler(downloadLocation, task.response, error) + } + } + } + + let progressDelegate = ProgressDelegate(downloadHandler: handleDownload, progressEmitter: emitter) + session = URLSession(configuration: .default, delegate: progressDelegate, delegateQueue: nil) + task = session.downloadTask(with: urlRequest) + } else { + task = URLSession.shared.downloadTask(with: urlRequest, completionHandler: handleDownload) + } + + task.resume() + } + // swiftlint:enable function_body_length + + /** + * Get the SearchPathDirectory corresponding to the JS string + */ + private func getDirectory(directory: String?) -> FileManager.SearchPathDirectory? { + if let directory = directory { + switch directory { + case "CACHE": + return .cachesDirectory + case "LIBRARY": + return .libraryDirectory + default: + return .documentDirectory + } + } + return nil + } +} diff --git a/node_modules/@capacitor/filesystem/ios/Tests/FilesystemPluginTests/FilesystemPluginTests.swift b/node_modules/@capacitor/filesystem/ios/Tests/FilesystemPluginTests/FilesystemPluginTests.swift new file mode 100644 index 0000000..a625af9 --- /dev/null +++ b/node_modules/@capacitor/filesystem/ios/Tests/FilesystemPluginTests/FilesystemPluginTests.swift @@ -0,0 +1,12 @@ +import XCTest +@testable import FilesystemPlugin + +final class FilesystemPluginTests: XCTestCase { + func testExample() throws { + // XCTest Documentation + // https://developer.apple.com/documentation/xctest + + // Defining Test Cases and Test Methods + // https://developer.apple.com/documentation/xctest/defining_test_cases_and_test_methods + } +} diff --git a/node_modules/@capacitor/filesystem/package.json b/node_modules/@capacitor/filesystem/package.json new file mode 100644 index 0000000..fbbacf4 --- /dev/null +++ b/node_modules/@capacitor/filesystem/package.json @@ -0,0 +1,91 @@ +{ + "name": "@capacitor/filesystem", + "version": "8.1.2", + "description": "The Filesystem API provides a NodeJS-like API for working with files on the device.", + "main": "dist/plugin.cjs.js", + "module": "dist/esm/index.js", + "types": "dist/esm/index.d.ts", + "unpkg": "dist/plugin.js", + "files": [ + "android/src/main/", + "android/build.gradle", + "dist/", + "ios/Sources", + "ios/Tests", + "Package.swift", + "CapacitorFilesystem.podspec" + ], + "author": "Outsystems", + "license": "MIT", + "repository": { + "type": "git", + "url": "https://github.com/ionic-team/capacitor-filesystem.git" + }, + "bugs": { + "url": "https://github.com/ionic-team/capacitor-filesystem/issues" + }, + "keywords": [ + "capacitor", + "plugin", + "native" + ], + "scripts": { + "verify": "npm run verify:ios && npm run verify:android && npm run verify:web", + "verify:ios": "xcodebuild -scheme CapacitorFilesystem -destination generic/platform=iOS", + "verify:android": "cd android && ./gradlew clean build test && cd ..", + "verify:web": "npm run build", + "lint": "npm run eslint && npm run prettier -- --check && npm run swiftlint -- lint", + "fmt": "npm run eslint -- --fix && npm run prettier -- --write && npm run swiftlint -- --fix --format", + "eslint": "eslint . --ext ts", + "prettier": "prettier \"**/*.{css,html,ts,js,java}\" --plugin=prettier-plugin-java", + "swiftlint": "node-swiftlint", + "docgen": "docgen --api FilesystemPlugin --output-readme README.md --output-json dist/docs.json", + "build": "npm run clean && npm run docgen && tsc && rollup -c rollup.config.mjs", + "clean": "rimraf ./dist", + "watch": "tsc --watch", + "prepublishOnly": "npm run build", + "publish:cocoapod": "pod trunk push ./CapacitorFilesystem.podspec --allow-warnings" + }, + "dependencies": { + "@capacitor/synapse": "^1.0.4" + }, + "devDependencies": { + "@capacitor/android": "^8.0.0", + "@capacitor/core": "^8.0.0", + "@capacitor/docgen": "^0.3.0", + "@capacitor/ios": "^8.0.0", + "@ionic/eslint-config": "^0.4.0", + "@ionic/prettier-config": "^4.0.0", + "@ionic/swiftlint-config": "^2.0.0", + "@semantic-release/changelog": "^6.0.3", + "@semantic-release/exec": "^7.1.0", + "@semantic-release/git": "^10.0.1", + "@semantic-release/github": "^12.0.2", + "@semantic-release/npm": "^13.1.2", + "@types/node": "^24.10.1", + "eslint": "^8.56.0", + "prettier": "^3.6.2", + "prettier-plugin-java": "^2.7.7", + "rimraf": "^6.1.2", + "rollup": "^4.53.3", + "semantic-release": "^25.0.2", + "swiftlint": "^2.0.0", + "typescript": "~5.9.3" + }, + "peerDependencies": { + "@capacitor/core": ">=8.0.0" + }, + "prettier": "@ionic/prettier-config", + "swiftlint": "@ionic/swiftlint-config", + "eslintConfig": { + "extends": "@ionic/eslint-config/recommended" + }, + "capacitor": { + "ios": { + "src": "ios" + }, + "android": { + "src": "android" + } + } +} diff --git a/node_modules/@capacitor/share/CapacitorShare.podspec b/node_modules/@capacitor/share/CapacitorShare.podspec new file mode 100644 index 0000000..3165a1e --- /dev/null +++ b/node_modules/@capacitor/share/CapacitorShare.podspec @@ -0,0 +1,17 @@ +require 'json' + +package = JSON.parse(File.read(File.join(__dir__, 'package.json'))) + +Pod::Spec.new do |s| + s.name = 'CapacitorShare' + s.version = package['version'] + s.summary = package['description'] + s.license = package['license'] + s.homepage = 'https://capacitorjs.com' + s.author = package['author'] + s.source = { :git => 'https://github.com/ionic-team/capacitor-plugins.git', :tag => package['name'] + '@' + package['version'] } + s.source_files = 'ios/Sources/**/*.{swift,h,m,c,cc,mm,cpp}', 'share/ios/Sources/**/*.{swift,h,m,c,cc,mm,cpp}' + s.ios.deployment_target = '15.0' + s.dependency 'Capacitor' + s.swift_version = '5.1' +end diff --git a/node_modules/@capacitor/share/LICENSE b/node_modules/@capacitor/share/LICENSE new file mode 100644 index 0000000..e73c9ca --- /dev/null +++ b/node_modules/@capacitor/share/LICENSE @@ -0,0 +1,23 @@ +Copyright 2020-present Ionic +https://ionic.io + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/node_modules/@capacitor/share/Package.swift b/node_modules/@capacitor/share/Package.swift new file mode 100644 index 0000000..b331df9 --- /dev/null +++ b/node_modules/@capacitor/share/Package.swift @@ -0,0 +1,28 @@ +// swift-tools-version: 5.9 +import PackageDescription + +let package = Package( + name: "CapacitorShare", + platforms: [.iOS(.v15)], + products: [ + .library( + name: "CapacitorShare", + targets: ["SharePlugin"]) + ], + dependencies: [ + .package(url: "https://github.com/ionic-team/capacitor-swift-pm.git", from: "8.0.0") + ], + targets: [ + .target( + name: "SharePlugin", + dependencies: [ + .product(name: "Capacitor", package: "capacitor-swift-pm"), + .product(name: "Cordova", package: "capacitor-swift-pm") + ], + path: "ios/Sources/SharePlugin"), + .testTarget( + name: "SharePluginTests", + dependencies: ["SharePlugin"], + path: "ios/Tests/SharePluginTests") + ] +) diff --git a/node_modules/@capacitor/share/README.md b/node_modules/@capacitor/share/README.md new file mode 100644 index 0000000..f85503a --- /dev/null +++ b/node_modules/@capacitor/share/README.md @@ -0,0 +1,129 @@ +# @capacitor/share + +The Share API provides methods for sharing content in any sharing-enabled apps the user may have installed. + +The Share API works on iOS, Android, and the Web (using the new [Web Share +API](https://web.dev/web-share/)), though web support is currently spotty. + +## Install + +```bash +npm install @capacitor/share +npx cap sync +``` +## Android + +By default, Capacitor apps only allow to share files from caches folder. To make other Android folders shareable, they have to be added in `android/app/src/main/res/xml/file_paths.xml` file. Check the Specifying Available Files section in [FileProvider docs](https://developer.android.com/reference/androidx/core/content/FileProvider) for the available locations. + +## Example + +```typescript +import { Share } from '@capacitor/share'; + +await Share.share({ + title: 'See cool stuff', + text: 'Really awesome thing you need to see right meow', + url: 'http://ionicframework.com/', + dialogTitle: 'Share with buddies', +}); + +// Share text only +await Share.share({ + text: 'Really awesome thing you need to see right meow', +}); + +// Share url only +await Share.share({ + url: 'http://ionicframework.com/', +}); + +// Share local file using url parameter +const photo = await Camera.getPhoto(options); +await Share.share({ + url: photo.path, +}); + +// Share multiple files using files parameter +const { photos } = await Camera.pickImages(options); +await Share.share({ + files: photos.map(photo => photo.path!), +}); +``` + +Each platform uses a different set of fields, but you should supply them all. + +## API + + + +* [`canShare()`](#canshare) +* [`share(...)`](#share) +* [Interfaces](#interfaces) + + + + + + +### canShare() + +```typescript +canShare() => Promise +``` + +Check if sharing is supported. + +**Returns:** Promise<CanShareResult> + +**Since:** 1.1.0 + +-------------------- + + +### share(...) + +```typescript +share(options: ShareOptions) => Promise +``` + +Show a Share modal for sharing content with other apps + +| Param | Type | +| ------------- | ----------------------------------------------------- | +| **`options`** | ShareOptions | + +**Returns:** Promise<ShareResult> + +**Since:** 1.0.0 + +-------------------- + + +### Interfaces + + +#### CanShareResult + +| Prop | Type | Description | Since | +| ----------- | -------------------- | ------------------------------------ | ----- | +| **`value`** | boolean | Whether sharing is supported or not. | 1.1.0 | + + +#### ShareResult + +| Prop | Type | Description | Since | +| ------------------ | ------------------- | ------------------------------------------------------------------------------------------------------------------------ | ----- | +| **`activityType`** | string | Identifier of the app that received the share action. Can be an empty string in some cases. On web it will be undefined. | 1.0.0 | + + +#### ShareOptions + +| Prop | Type | Description | Since | +| ----------------- | --------------------- | ----------------------------------------------------------------------------------- | ----- | +| **`title`** | string | Set a title for any message. This will be the subject if sharing to email | 1.0.0 | +| **`text`** | string | Set some text to share | 1.0.0 | +| **`url`** | string | Set a URL to share, can be http, https or file:// URL | 1.0.0 | +| **`files`** | string[] | Array of file:// URLs of the files to be shared. Only supported on iOS and Android. | 4.1.0 | +| **`dialogTitle`** | string | Set a title for the share modal. This option is only supported on Android. | 1.0.0 | + + diff --git a/node_modules/@capacitor/share/android/build.gradle b/node_modules/@capacitor/share/android/build.gradle new file mode 100644 index 0000000..f10714c --- /dev/null +++ b/node_modules/@capacitor/share/android/build.gradle @@ -0,0 +1,81 @@ +ext { + capacitorVersion = System.getenv('CAPACITOR_VERSION') + junitVersion = project.hasProperty('junitVersion') ? rootProject.ext.junitVersion : '4.13.2' + androidxAppCompatVersion = project.hasProperty('androidxAppCompatVersion') ? rootProject.ext.androidxAppCompatVersion : '1.7.1' + androidxCoreVersion = project.hasProperty('androidxCoreVersion') ? rootProject.ext.androidxCoreVersion : '1.17.0' + androidxJunitVersion = project.hasProperty('androidxJunitVersion') ? rootProject.ext.androidxJunitVersion : '1.3.0' + androidxEspressoCoreVersion = project.hasProperty('androidxEspressoCoreVersion') ? rootProject.ext.androidxEspressoCoreVersion : '3.7.0' +} + +buildscript { + repositories { + google() + mavenCentral() + maven { + url = "https://plugins.gradle.org/m2/" + } + } + dependencies { + classpath 'com.android.tools.build:gradle:8.13.0' + if (System.getenv("CAP_PLUGIN_PUBLISH") == "true") { + classpath 'io.github.gradle-nexus:publish-plugin:1.3.0' + } + } +} + +apply plugin: 'com.android.library' +if (System.getenv("CAP_PLUGIN_PUBLISH") == "true") { + apply plugin: 'io.github.gradle-nexus.publish-plugin' + apply from: file('../../scripts/android/publish-root.gradle') + apply from: file('../../scripts/android/publish-module.gradle') +} + +android { + namespace = "com.capacitorjs.plugins.share" + compileSdk = project.hasProperty('compileSdkVersion') ? rootProject.ext.compileSdkVersion : 36 + defaultConfig { + minSdkVersion project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : 24 + targetSdkVersion project.hasProperty('targetSdkVersion') ? rootProject.ext.targetSdkVersion : 36 + versionCode 1 + versionName "1.0" + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } + lintOptions { + abortOnError = false + } + compileOptions { + sourceCompatibility JavaVersion.VERSION_21 + targetCompatibility JavaVersion.VERSION_21 + } + publishing { + singleVariant("release") + } +} + +repositories { + google() + mavenCentral() +} + + +dependencies { + implementation fileTree(dir: 'libs', include: ['*.jar']) + + if (System.getenv("CAP_PLUGIN_PUBLISH") == "true") { + implementation "com.capacitorjs:core:$capacitorVersion" + } else { + implementation project(':capacitor-android') + } + + implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion" + implementation "androidx.core:core:$androidxCoreVersion" + testImplementation "junit:junit:$junitVersion" + androidTestImplementation "androidx.test.ext:junit:$androidxJunitVersion" + androidTestImplementation "androidx.test.espresso:espresso-core:$androidxEspressoCoreVersion" +} diff --git a/node_modules/@capacitor/share/android/src/main/AndroidManifest.xml b/node_modules/@capacitor/share/android/src/main/AndroidManifest.xml new file mode 100644 index 0000000..a2f47b6 --- /dev/null +++ b/node_modules/@capacitor/share/android/src/main/AndroidManifest.xml @@ -0,0 +1,2 @@ + + diff --git a/node_modules/@capacitor/share/android/src/main/java/com/capacitorjs/plugins/share/SharePlugin.java b/node_modules/@capacitor/share/android/src/main/java/com/capacitorjs/plugins/share/SharePlugin.java new file mode 100644 index 0000000..dcfa338 --- /dev/null +++ b/node_modules/@capacitor/share/android/src/main/java/com/capacitorjs/plugins/share/SharePlugin.java @@ -0,0 +1,210 @@ +package com.capacitorjs.plugins.share; + +import android.app.Activity; +import android.app.PendingIntent; +import android.content.*; +import android.net.Uri; +import android.os.Build; +import android.webkit.MimeTypeMap; +import androidx.activity.result.ActivityResult; +import androidx.core.content.ContextCompat; +import androidx.core.content.FileProvider; +import com.getcapacitor.JSArray; +import com.getcapacitor.JSObject; +import com.getcapacitor.Plugin; +import com.getcapacitor.PluginCall; +import com.getcapacitor.PluginMethod; +import com.getcapacitor.annotation.ActivityCallback; +import com.getcapacitor.annotation.CapacitorPlugin; +import java.io.File; +import java.util.ArrayList; +import java.util.List; +import org.json.JSONException; + +@CapacitorPlugin(name = "Share") +public class SharePlugin extends Plugin { + + private BroadcastReceiver broadcastReceiver; + private boolean stopped = false; + private boolean isPresenting = false; + private ComponentName chosenComponent; + + @Override + public void load() { + broadcastReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + chosenComponent = intent.getParcelableExtra(Intent.EXTRA_CHOSEN_COMPONENT, ComponentName.class); + } else { + chosenComponent = getParcelableExtraLegacy(intent, Intent.EXTRA_CHOSEN_COMPONENT); + } + } + }; + ContextCompat.registerReceiver( + getContext(), + broadcastReceiver, + new IntentFilter(Intent.EXTRA_CHOSEN_COMPONENT), + ContextCompat.RECEIVER_EXPORTED + ); + } + + @SuppressWarnings("deprecation") + private ComponentName getParcelableExtraLegacy(Intent intent, String string) { + return intent.getParcelableExtra(string); + } + + @ActivityCallback + private void activityResult(PluginCall call, ActivityResult result) { + if (result.getResultCode() == Activity.RESULT_CANCELED && !stopped) { + call.reject("Share canceled"); + } else { + JSObject callResult = new JSObject(); + callResult.put("activityType", chosenComponent != null ? chosenComponent.getPackageName() : ""); + call.resolve(callResult); + } + isPresenting = false; + } + + @PluginMethod + public void canShare(PluginCall call) { + JSObject callResult = new JSObject(); + callResult.put("value", true); + call.resolve(callResult); + } + + @PluginMethod + public void share(PluginCall call) { + if (!isPresenting) { + String title = call.getString("title", ""); + String text = call.getString("text"); + String url = call.getString("url"); + JSArray files = call.getArray("files"); + String dialogTitle = call.getString("dialogTitle", "Share"); + + if (text == null && url == null && (files == null || files.length() == 0)) { + call.reject("Must provide a URL or Message or files"); + return; + } + + if (url != null && !isFileUrl(url) && !isHttpUrl(url)) { + call.reject("Unsupported url"); + return; + } + + Intent intent = new Intent(files != null && files.length() > 1 ? Intent.ACTION_SEND_MULTIPLE : Intent.ACTION_SEND); + + if (text != null) { + // If they supplied both fields, concat them + if (url != null && isHttpUrl(url)) text = text + " " + url; + intent.putExtra(Intent.EXTRA_TEXT, text); + intent.setTypeAndNormalize("text/plain"); + } + + if (url != null && isHttpUrl(url) && text == null) { + intent.putExtra(Intent.EXTRA_TEXT, url); + intent.setTypeAndNormalize("text/plain"); + } else if (url != null && isFileUrl(url)) { + JSArray filesArray = new JSArray(); + filesArray.put(url); + shareFiles(filesArray, intent, call); + } + + if (title != null) { + intent.putExtra(Intent.EXTRA_SUBJECT, title); + } + + if (files != null && files.length() != 0) { + shareFiles(files, intent, call); + } + int flags = PendingIntent.FLAG_UPDATE_CURRENT; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + flags = flags | PendingIntent.FLAG_MUTABLE; + } + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) { + flags = flags | PendingIntent.FLAG_ALLOW_UNSAFE_IMPLICIT_INTENT; + } + + // requestCode parameter is not used. Providing 0 + PendingIntent pi = PendingIntent.getBroadcast(getContext(), 0, new Intent(Intent.EXTRA_CHOSEN_COMPONENT), flags); + Intent chooser = Intent.createChooser(intent, dialogTitle, pi.getIntentSender()); + chosenComponent = null; + chooser.addCategory(Intent.CATEGORY_DEFAULT); + stopped = false; + isPresenting = true; + startActivityForResult(call, chooser, "activityResult"); + } else { + call.reject("Can't share while sharing is in progress"); + } + } + + private void shareFiles(JSArray files, Intent intent, PluginCall call) { + List filesList; + ArrayList fileUris = new ArrayList<>(); + try { + filesList = files.toList(); + for (int i = 0; i < filesList.size(); i++) { + String file = (String) filesList.get(i); + if (isFileUrl(file)) { + String type = getMimeType(file); + if (type == null || filesList.size() > 1) { + type = "*/*"; + } + intent.setType(type); + + Uri fileUrl = FileProvider.getUriForFile( + getActivity(), + getContext().getPackageName() + ".fileprovider", + new File(Uri.parse(file).getPath()) + ); + fileUris.add(fileUrl); + } else { + call.reject("only file urls are supported"); + return; + } + } + if (fileUris.size() > 1) { + intent.putExtra(Intent.EXTRA_STREAM, fileUris); + } else if (fileUris.size() == 1) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { + intent.setClipData(ClipData.newRawUri("", fileUris.get(0))); + } + intent.putExtra(Intent.EXTRA_STREAM, fileUris.get(0)); + } + intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + } catch (Exception ex) { + call.reject(ex.getLocalizedMessage()); + return; + } + } + + @Override + protected void handleOnDestroy() { + if (broadcastReceiver != null) { + getActivity().unregisterReceiver(broadcastReceiver); + } + } + + @Override + protected void handleOnStop() { + super.handleOnStop(); + stopped = true; + } + + private String getMimeType(String url) { + String type = null; + String extension = MimeTypeMap.getFileExtensionFromUrl(url); + if (extension != null) { + type = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension); + } + return type; + } + + private boolean isFileUrl(String url) { + return url.startsWith("file:"); + } + + private boolean isHttpUrl(String url) { + return url.startsWith("http"); + } +} diff --git a/node_modules/@capacitor/share/dist/docs.json b/node_modules/@capacitor/share/dist/docs.json new file mode 100644 index 0000000..e14884d --- /dev/null +++ b/node_modules/@capacitor/share/dist/docs.json @@ -0,0 +1,168 @@ +{ + "api": { + "name": "SharePlugin", + "slug": "shareplugin", + "docs": "", + "tags": [], + "methods": [ + { + "name": "canShare", + "signature": "() => Promise", + "parameters": [], + "returns": "Promise", + "tags": [ + { + "name": "since", + "text": "1.1.0" + } + ], + "docs": "Check if sharing is supported.", + "complexTypes": [ + "CanShareResult" + ], + "slug": "canshare" + }, + { + "name": "share", + "signature": "(options: ShareOptions) => Promise", + "parameters": [ + { + "name": "options", + "docs": "", + "type": "ShareOptions" + } + ], + "returns": "Promise", + "tags": [ + { + "name": "since", + "text": "1.0.0" + } + ], + "docs": "Show a Share modal for sharing content with other apps", + "complexTypes": [ + "ShareResult", + "ShareOptions" + ], + "slug": "share" + } + ], + "properties": [] + }, + "interfaces": [ + { + "name": "CanShareResult", + "slug": "canshareresult", + "docs": "", + "tags": [], + "methods": [], + "properties": [ + { + "name": "value", + "tags": [ + { + "text": "1.1.0", + "name": "since" + } + ], + "docs": "Whether sharing is supported or not.", + "complexTypes": [], + "type": "boolean" + } + ] + }, + { + "name": "ShareResult", + "slug": "shareresult", + "docs": "", + "tags": [], + "methods": [], + "properties": [ + { + "name": "activityType", + "tags": [ + { + "text": "1.0.0", + "name": "since" + } + ], + "docs": "Identifier of the app that received the share action.\nCan be an empty string in some cases.\n\nOn web it will be undefined.", + "complexTypes": [], + "type": "string | undefined" + } + ] + }, + { + "name": "ShareOptions", + "slug": "shareoptions", + "docs": "", + "tags": [], + "methods": [], + "properties": [ + { + "name": "title", + "tags": [ + { + "text": "1.0.0", + "name": "since" + } + ], + "docs": "Set a title for any message. This will be the subject\nif sharing to email", + "complexTypes": [], + "type": "string | undefined" + }, + { + "name": "text", + "tags": [ + { + "text": "1.0.0", + "name": "since" + } + ], + "docs": "Set some text to share", + "complexTypes": [], + "type": "string | undefined" + }, + { + "name": "url", + "tags": [ + { + "text": "1.0.0", + "name": "since" + } + ], + "docs": "Set a URL to share, can be http, https or file:// URL", + "complexTypes": [], + "type": "string | undefined" + }, + { + "name": "files", + "tags": [ + { + "text": "4.1.0", + "name": "since" + } + ], + "docs": "Array of file:// URLs of the files to be shared.\nOnly supported on iOS and Android.", + "complexTypes": [], + "type": "string[] | undefined" + }, + { + "name": "dialogTitle", + "tags": [ + { + "text": "1.0.0", + "name": "since" + } + ], + "docs": "Set a title for the share modal.\nThis option is only supported on Android.", + "complexTypes": [], + "type": "string | undefined" + } + ] + } + ], + "enums": [], + "typeAliases": [], + "pluginConfigs": [] +} \ No newline at end of file diff --git a/node_modules/@capacitor/share/dist/esm/definitions.d.ts b/node_modules/@capacitor/share/dist/esm/definitions.d.ts new file mode 100644 index 0000000..64f6870 --- /dev/null +++ b/node_modules/@capacitor/share/dist/esm/definitions.d.ts @@ -0,0 +1,68 @@ +export interface ShareOptions { + /** + * Set a title for any message. This will be the subject + * if sharing to email + * + * @since 1.0.0 + */ + title?: string; + /** + * Set some text to share + * + * @since 1.0.0 + */ + text?: string; + /** + * Set a URL to share, can be http, https or file:// URL + * + * @since 1.0.0 + */ + url?: string; + /** + * Array of file:// URLs of the files to be shared. + * Only supported on iOS and Android. + * + * @since 4.1.0 + */ + files?: string[]; + /** + * Set a title for the share modal. + * This option is only supported on Android. + * + * @since 1.0.0 + */ + dialogTitle?: string; +} +export interface ShareResult { + /** + * Identifier of the app that received the share action. + * Can be an empty string in some cases. + * + * On web it will be undefined. + * + * @since 1.0.0 + */ + activityType?: string; +} +export interface CanShareResult { + /** + * Whether sharing is supported or not. + * + * @since 1.1.0 + */ + value: boolean; +} +export interface SharePlugin { + /** + * Check if sharing is supported. + * + * @since 1.1.0 + */ + canShare(): Promise; + /** + * Show a Share modal for sharing content with other apps + * + * @since 1.0.0 + */ + share(options: ShareOptions): Promise; +} diff --git a/node_modules/@capacitor/share/dist/esm/definitions.js b/node_modules/@capacitor/share/dist/esm/definitions.js new file mode 100644 index 0000000..497acb5 --- /dev/null +++ b/node_modules/@capacitor/share/dist/esm/definitions.js @@ -0,0 +1,2 @@ +export {}; +//# sourceMappingURL=definitions.js.map \ No newline at end of file diff --git a/node_modules/@capacitor/share/dist/esm/definitions.js.map b/node_modules/@capacitor/share/dist/esm/definitions.js.map new file mode 100644 index 0000000..8b1e3e5 --- /dev/null +++ b/node_modules/@capacitor/share/dist/esm/definitions.js.map @@ -0,0 +1 @@ +{"version":3,"file":"definitions.js","sourceRoot":"","sources":["../../src/definitions.ts"],"names":[],"mappings":"","sourcesContent":["export interface ShareOptions {\n /**\n * Set a title for any message. This will be the subject\n * if sharing to email\n *\n * @since 1.0.0\n */\n title?: string;\n\n /**\n * Set some text to share\n *\n * @since 1.0.0\n */\n text?: string;\n\n /**\n * Set a URL to share, can be http, https or file:// URL\n *\n * @since 1.0.0\n */\n url?: string;\n\n /**\n * Array of file:// URLs of the files to be shared.\n * Only supported on iOS and Android.\n *\n * @since 4.1.0\n */\n files?: string[];\n\n /**\n * Set a title for the share modal.\n * This option is only supported on Android.\n *\n * @since 1.0.0\n */\n dialogTitle?: string;\n}\n\nexport interface ShareResult {\n /**\n * Identifier of the app that received the share action.\n * Can be an empty string in some cases.\n *\n * On web it will be undefined.\n *\n * @since 1.0.0\n */\n activityType?: string;\n}\n\nexport interface CanShareResult {\n /**\n * Whether sharing is supported or not.\n *\n * @since 1.1.0\n */\n value: boolean;\n}\n\nexport interface SharePlugin {\n /**\n * Check if sharing is supported.\n *\n * @since 1.1.0\n */\n canShare(): Promise;\n\n /**\n * Show a Share modal for sharing content with other apps\n *\n * @since 1.0.0\n */\n share(options: ShareOptions): Promise;\n}\n"]} \ No newline at end of file diff --git a/node_modules/@capacitor/share/dist/esm/index.d.ts b/node_modules/@capacitor/share/dist/esm/index.d.ts new file mode 100644 index 0000000..13ef473 --- /dev/null +++ b/node_modules/@capacitor/share/dist/esm/index.d.ts @@ -0,0 +1,4 @@ +import type { SharePlugin } from './definitions'; +declare const Share: SharePlugin; +export * from './definitions'; +export { Share }; diff --git a/node_modules/@capacitor/share/dist/esm/index.js b/node_modules/@capacitor/share/dist/esm/index.js new file mode 100644 index 0000000..87a9983 --- /dev/null +++ b/node_modules/@capacitor/share/dist/esm/index.js @@ -0,0 +1,7 @@ +import { registerPlugin } from '@capacitor/core'; +const Share = registerPlugin('Share', { + web: () => import('./web').then((m) => new m.ShareWeb()), +}); +export * from './definitions'; +export { Share }; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/node_modules/@capacitor/share/dist/esm/index.js.map b/node_modules/@capacitor/share/dist/esm/index.js.map new file mode 100644 index 0000000..2d7acf5 --- /dev/null +++ b/node_modules/@capacitor/share/dist/esm/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAIjD,MAAM,KAAK,GAAG,cAAc,CAAc,OAAO,EAAE;IACjD,GAAG,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,CAAC;CACzD,CAAC,CAAC;AAEH,cAAc,eAAe,CAAC;AAC9B,OAAO,EAAE,KAAK,EAAE,CAAC","sourcesContent":["import { registerPlugin } from '@capacitor/core';\n\nimport type { SharePlugin } from './definitions';\n\nconst Share = registerPlugin('Share', {\n web: () => import('./web').then((m) => new m.ShareWeb()),\n});\n\nexport * from './definitions';\nexport { Share };\n"]} \ No newline at end of file diff --git a/node_modules/@capacitor/share/dist/esm/web.d.ts b/node_modules/@capacitor/share/dist/esm/web.d.ts new file mode 100644 index 0000000..bf6c8ee --- /dev/null +++ b/node_modules/@capacitor/share/dist/esm/web.d.ts @@ -0,0 +1,6 @@ +import { WebPlugin } from '@capacitor/core'; +import type { CanShareResult, ShareOptions, SharePlugin, ShareResult } from './definitions'; +export declare class ShareWeb extends WebPlugin implements SharePlugin { + canShare(): Promise; + share(options: ShareOptions): Promise; +} diff --git a/node_modules/@capacitor/share/dist/esm/web.js b/node_modules/@capacitor/share/dist/esm/web.js new file mode 100644 index 0000000..8ea8d45 --- /dev/null +++ b/node_modules/@capacitor/share/dist/esm/web.js @@ -0,0 +1,23 @@ +import { WebPlugin } from '@capacitor/core'; +export class ShareWeb extends WebPlugin { + async canShare() { + if (typeof navigator === 'undefined' || !navigator.share) { + return { value: false }; + } + else { + return { value: true }; + } + } + async share(options) { + if (typeof navigator === 'undefined' || !navigator.share) { + throw this.unavailable('Share API not available in this browser'); + } + await navigator.share({ + title: options.title, + text: options.text, + url: options.url, + }); + return {}; + } +} +//# sourceMappingURL=web.js.map \ No newline at end of file diff --git a/node_modules/@capacitor/share/dist/esm/web.js.map b/node_modules/@capacitor/share/dist/esm/web.js.map new file mode 100644 index 0000000..766bcf2 --- /dev/null +++ b/node_modules/@capacitor/share/dist/esm/web.js.map @@ -0,0 +1 @@ +{"version":3,"file":"web.js","sourceRoot":"","sources":["../../src/web.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAI5C,MAAM,OAAO,QAAS,SAAQ,SAAS;IACrC,KAAK,CAAC,QAAQ;QACZ,IAAI,OAAO,SAAS,KAAK,WAAW,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,CAAC;YACzD,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC;QAC1B,CAAC;aAAM,CAAC;YACN,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;QACzB,CAAC;IACH,CAAC;IACD,KAAK,CAAC,KAAK,CAAC,OAAqB;QAC/B,IAAI,OAAO,SAAS,KAAK,WAAW,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,CAAC;YACzD,MAAM,IAAI,CAAC,WAAW,CAAC,yCAAyC,CAAC,CAAC;QACpE,CAAC;QAED,MAAM,SAAS,CAAC,KAAK,CAAC;YACpB,KAAK,EAAE,OAAO,CAAC,KAAK;YACpB,IAAI,EAAE,OAAO,CAAC,IAAI;YAClB,GAAG,EAAE,OAAO,CAAC,GAAG;SACjB,CAAC,CAAC;QACH,OAAO,EAAE,CAAC;IACZ,CAAC;CACF","sourcesContent":["import { WebPlugin } from '@capacitor/core';\n\nimport type { CanShareResult, ShareOptions, SharePlugin, ShareResult } from './definitions';\n\nexport class ShareWeb extends WebPlugin implements SharePlugin {\n async canShare(): Promise {\n if (typeof navigator === 'undefined' || !navigator.share) {\n return { value: false };\n } else {\n return { value: true };\n }\n }\n async share(options: ShareOptions): Promise {\n if (typeof navigator === 'undefined' || !navigator.share) {\n throw this.unavailable('Share API not available in this browser');\n }\n\n await navigator.share({\n title: options.title,\n text: options.text,\n url: options.url,\n });\n return {};\n }\n}\n"]} \ No newline at end of file diff --git a/node_modules/@capacitor/share/dist/plugin.cjs.js b/node_modules/@capacitor/share/dist/plugin.cjs.js new file mode 100644 index 0000000..55cb8ba --- /dev/null +++ b/node_modules/@capacitor/share/dist/plugin.cjs.js @@ -0,0 +1,37 @@ +'use strict'; + +var core = require('@capacitor/core'); + +const Share = core.registerPlugin('Share', { + web: () => Promise.resolve().then(function () { return web; }).then((m) => new m.ShareWeb()), +}); + +class ShareWeb extends core.WebPlugin { + async canShare() { + if (typeof navigator === 'undefined' || !navigator.share) { + return { value: false }; + } + else { + return { value: true }; + } + } + async share(options) { + if (typeof navigator === 'undefined' || !navigator.share) { + throw this.unavailable('Share API not available in this browser'); + } + await navigator.share({ + title: options.title, + text: options.text, + url: options.url, + }); + return {}; + } +} + +var web = /*#__PURE__*/Object.freeze({ + __proto__: null, + ShareWeb: ShareWeb +}); + +exports.Share = Share; +//# sourceMappingURL=plugin.cjs.js.map diff --git a/node_modules/@capacitor/share/dist/plugin.cjs.js.map b/node_modules/@capacitor/share/dist/plugin.cjs.js.map new file mode 100644 index 0000000..2748228 --- /dev/null +++ b/node_modules/@capacitor/share/dist/plugin.cjs.js.map @@ -0,0 +1 @@ +{"version":3,"file":"plugin.cjs.js","sources":["esm/index.js","esm/web.js"],"sourcesContent":["import { registerPlugin } from '@capacitor/core';\nconst Share = registerPlugin('Share', {\n web: () => import('./web').then((m) => new m.ShareWeb()),\n});\nexport * from './definitions';\nexport { Share };\n//# sourceMappingURL=index.js.map","import { WebPlugin } from '@capacitor/core';\nexport class ShareWeb extends WebPlugin {\n async canShare() {\n if (typeof navigator === 'undefined' || !navigator.share) {\n return { value: false };\n }\n else {\n return { value: true };\n }\n }\n async share(options) {\n if (typeof navigator === 'undefined' || !navigator.share) {\n throw this.unavailable('Share API not available in this browser');\n }\n await navigator.share({\n title: options.title,\n text: options.text,\n url: options.url,\n });\n return {};\n }\n}\n//# sourceMappingURL=web.js.map"],"names":["registerPlugin","WebPlugin"],"mappings":";;;;AACK,MAAC,KAAK,GAAGA,mBAAc,CAAC,OAAO,EAAE;AACtC,IAAI,GAAG,EAAE,MAAM,mDAAe,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,QAAQ,EAAE,CAAC;AAC5D,CAAC;;ACFM,MAAM,QAAQ,SAASC,cAAS,CAAC;AACxC,IAAI,MAAM,QAAQ,GAAG;AACrB,QAAQ,IAAI,OAAO,SAAS,KAAK,WAAW,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE;AAClE,YAAY,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE;AACnC,QAAQ;AACR,aAAa;AACb,YAAY,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE;AAClC,QAAQ;AACR,IAAI;AACJ,IAAI,MAAM,KAAK,CAAC,OAAO,EAAE;AACzB,QAAQ,IAAI,OAAO,SAAS,KAAK,WAAW,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE;AAClE,YAAY,MAAM,IAAI,CAAC,WAAW,CAAC,yCAAyC,CAAC;AAC7E,QAAQ;AACR,QAAQ,MAAM,SAAS,CAAC,KAAK,CAAC;AAC9B,YAAY,KAAK,EAAE,OAAO,CAAC,KAAK;AAChC,YAAY,IAAI,EAAE,OAAO,CAAC,IAAI;AAC9B,YAAY,GAAG,EAAE,OAAO,CAAC,GAAG;AAC5B,SAAS,CAAC;AACV,QAAQ,OAAO,EAAE;AACjB,IAAI;AACJ;;;;;;;;;"} \ No newline at end of file diff --git a/node_modules/@capacitor/share/dist/plugin.js b/node_modules/@capacitor/share/dist/plugin.js new file mode 100644 index 0000000..5df1258 --- /dev/null +++ b/node_modules/@capacitor/share/dist/plugin.js @@ -0,0 +1,40 @@ +var capacitorShare = (function (exports, core) { + 'use strict'; + + const Share = core.registerPlugin('Share', { + web: () => Promise.resolve().then(function () { return web; }).then((m) => new m.ShareWeb()), + }); + + class ShareWeb extends core.WebPlugin { + async canShare() { + if (typeof navigator === 'undefined' || !navigator.share) { + return { value: false }; + } + else { + return { value: true }; + } + } + async share(options) { + if (typeof navigator === 'undefined' || !navigator.share) { + throw this.unavailable('Share API not available in this browser'); + } + await navigator.share({ + title: options.title, + text: options.text, + url: options.url, + }); + return {}; + } + } + + var web = /*#__PURE__*/Object.freeze({ + __proto__: null, + ShareWeb: ShareWeb + }); + + exports.Share = Share; + + return exports; + +})({}, capacitorExports); +//# sourceMappingURL=plugin.js.map diff --git a/node_modules/@capacitor/share/dist/plugin.js.map b/node_modules/@capacitor/share/dist/plugin.js.map new file mode 100644 index 0000000..049161c --- /dev/null +++ b/node_modules/@capacitor/share/dist/plugin.js.map @@ -0,0 +1 @@ +{"version":3,"file":"plugin.js","sources":["esm/index.js","esm/web.js"],"sourcesContent":["import { registerPlugin } from '@capacitor/core';\nconst Share = registerPlugin('Share', {\n web: () => import('./web').then((m) => new m.ShareWeb()),\n});\nexport * from './definitions';\nexport { Share };\n//# sourceMappingURL=index.js.map","import { WebPlugin } from '@capacitor/core';\nexport class ShareWeb extends WebPlugin {\n async canShare() {\n if (typeof navigator === 'undefined' || !navigator.share) {\n return { value: false };\n }\n else {\n return { value: true };\n }\n }\n async share(options) {\n if (typeof navigator === 'undefined' || !navigator.share) {\n throw this.unavailable('Share API not available in this browser');\n }\n await navigator.share({\n title: options.title,\n text: options.text,\n url: options.url,\n });\n return {};\n }\n}\n//# sourceMappingURL=web.js.map"],"names":["registerPlugin","WebPlugin"],"mappings":";;;AACK,UAAC,KAAK,GAAGA,mBAAc,CAAC,OAAO,EAAE;IACtC,IAAI,GAAG,EAAE,MAAM,mDAAe,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,QAAQ,EAAE,CAAC;IAC5D,CAAC;;ICFM,MAAM,QAAQ,SAASC,cAAS,CAAC;IACxC,IAAI,MAAM,QAAQ,GAAG;IACrB,QAAQ,IAAI,OAAO,SAAS,KAAK,WAAW,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE;IAClE,YAAY,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE;IACnC,QAAQ;IACR,aAAa;IACb,YAAY,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE;IAClC,QAAQ;IACR,IAAI;IACJ,IAAI,MAAM,KAAK,CAAC,OAAO,EAAE;IACzB,QAAQ,IAAI,OAAO,SAAS,KAAK,WAAW,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE;IAClE,YAAY,MAAM,IAAI,CAAC,WAAW,CAAC,yCAAyC,CAAC;IAC7E,QAAQ;IACR,QAAQ,MAAM,SAAS,CAAC,KAAK,CAAC;IAC9B,YAAY,KAAK,EAAE,OAAO,CAAC,KAAK;IAChC,YAAY,IAAI,EAAE,OAAO,CAAC,IAAI;IAC9B,YAAY,GAAG,EAAE,OAAO,CAAC,GAAG;IAC5B,SAAS,CAAC;IACV,QAAQ,OAAO,EAAE;IACjB,IAAI;IACJ;;;;;;;;;;;;;;;"} \ No newline at end of file diff --git a/node_modules/@capacitor/share/ios/Sources/SharePlugin/SharePlugin.swift b/node_modules/@capacitor/share/ios/Sources/SharePlugin/SharePlugin.swift new file mode 100644 index 0000000..73aa61b --- /dev/null +++ b/node_modules/@capacitor/share/ios/Sources/SharePlugin/SharePlugin.swift @@ -0,0 +1,75 @@ +import Foundation +import Capacitor + +@objc(SharePlugin) +public class SharePlugin: CAPPlugin, CAPBridgedPlugin { + public let identifier = "SharePlugin" + public let jsName = "Share" + public let pluginMethods: [CAPPluginMethod] = [ + CAPPluginMethod(name: "canShare", returnType: CAPPluginReturnPromise), + CAPPluginMethod(name: "share", returnType: CAPPluginReturnPromise) + ] + + @objc func canShare(_ call: CAPPluginCall) { + call.resolve([ + "value": true + ]) + } + + @objc func share(_ call: CAPPluginCall) { + var items = [Any]() + + if let text = call.getString("text") { + items.append(text) + } + + if let url = call.getString("url"), let urlObj = URL(string: url) { + items.append(urlObj) + } + + let title = call.getString("title") + + if let files = call.getArray("files") { + files.forEach { file in + if let url = file as? String, let fileUrl = URL(string: url) { + items.append(fileUrl) + } + } + } + + if items.count == 0 { + call.reject("Must provide at least url, text or files") + return + } + + DispatchQueue.main.async { [weak self] in + let actionController = UIActivityViewController(activityItems: items, applicationActivities: nil) + + if title != nil { + actionController.setValue(title, forKey: "subject") + } + + actionController.completionWithItemsHandler = { (activityType, completed, _ returnedItems, activityError) in + if activityError != nil { + call.reject("Error sharing item", nil, activityError) + return + } + + if completed { + call.resolve([ + "activityType": activityType?.rawValue ?? "" + ]) + } else { + call.reject("Share canceled") + } + + } + if self?.bridge?.viewController?.presentedViewController != nil { + call.reject("Can't share while sharing is in progress") + return + } + self?.setCenteredPopover(actionController) + self?.bridge?.viewController?.present(actionController, animated: true, completion: nil) + } + } +} diff --git a/node_modules/@capacitor/share/ios/Tests/SharePluginTests/PluginTests.swift b/node_modules/@capacitor/share/ios/Tests/SharePluginTests/PluginTests.swift new file mode 100644 index 0000000..1ee0e58 --- /dev/null +++ b/node_modules/@capacitor/share/ios/Tests/SharePluginTests/PluginTests.swift @@ -0,0 +1,5 @@ +import XCTest +@testable import SharePlugin + +class ShareTests: XCTestCase { +} diff --git a/node_modules/@capacitor/share/package.json b/node_modules/@capacitor/share/package.json new file mode 100644 index 0000000..7cb14bd --- /dev/null +++ b/node_modules/@capacitor/share/package.json @@ -0,0 +1,85 @@ +{ + "name": "@capacitor/share", + "version": "8.0.1", + "description": "The Share API provides methods for sharing content in any sharing-enabled apps the user may have installed.", + "main": "dist/plugin.cjs.js", + "module": "dist/esm/index.js", + "types": "dist/esm/index.d.ts", + "unpkg": "dist/plugin.js", + "files": [ + "android/src/main/", + "android/build.gradle", + "dist/", + "ios/Sources", + "ios/Tests", + "Package.swift", + "CapacitorShare.podspec" + ], + "author": "Ionic ", + "license": "MIT", + "repository": { + "type": "git", + "url": "git+https://github.com/ionic-team/capacitor-plugins.git" + }, + "bugs": { + "url": "https://github.com/ionic-team/capacitor-plugins/issues" + }, + "keywords": [ + "capacitor", + "plugin", + "native" + ], + "scripts": { + "verify": "npm run verify:ios && npm run verify:android && npm run verify:web", + "verify:ios": "xcodebuild build -scheme CapacitorShare -destination generic/platform=iOS", + "verify:android": "cd android && ./gradlew clean build test && cd ..", + "verify:web": "npm run build", + "lint": "npm run eslint && npm run prettier -- --check && npm run swiftlint -- lint", + "fmt": "npm run eslint -- --fix && npm run prettier -- --write && npm run swiftlint -- --fix --format", + "eslint": "eslint . --ext ts", + "prettier": "prettier \"**/*.{css,html,ts,js,java}\" --plugin=prettier-plugin-java", + "swiftlint": "node-swiftlint", + "docgen": "docgen --api SharePlugin --output-readme README.md --output-json dist/docs.json", + "build": "npm run clean && npm run docgen && tsc && rollup -c rollup.config.mjs", + "clean": "rimraf ./dist", + "watch": "tsc --watch", + "prepublishOnly": "npm run build", + "publish:cocoapod": "pod trunk push ./CapacitorShare.podspec --allow-warnings" + }, + "devDependencies": { + "@capacitor/android": "^8.0.0", + "@capacitor/core": "^8.0.0", + "@capacitor/docgen": "0.3.0", + "@capacitor/ios": "^8.0.0", + "@ionic/eslint-config": "^0.4.0", + "@ionic/prettier-config": "^4.0.0", + "@ionic/swiftlint-config": "^2.0.0", + "eslint": "^8.57.1", + "prettier": "^3.6.2", + "prettier-plugin-java": "^2.7.7", + "rimraf": "^6.1.0", + "rollup": "^4.53.2", + "swiftlint": "^2.0.0", + "typescript": "^5.9.3" + }, + "peerDependencies": { + "@capacitor/core": ">=8.0.0" + }, + "prettier": "@ionic/prettier-config", + "swiftlint": "@ionic/swiftlint-config", + "eslintConfig": { + "extends": "@ionic/eslint-config/recommended" + }, + "capacitor": { + "ios": { + "src": "ios" + }, + "android": { + "src": "android" + } + }, + "publishConfig": { + "access": "public" + }, + "gitHead": "bf4fe8c9ace79237c048c9b5ee0ab7455042bc86" +} diff --git a/node_modules/@capawesome/capacitor-file-picker/CapawesomeCapacitorFilePicker.podspec b/node_modules/@capawesome/capacitor-file-picker/CapawesomeCapacitorFilePicker.podspec new file mode 100644 index 0000000..5ffd2e9 --- /dev/null +++ b/node_modules/@capawesome/capacitor-file-picker/CapawesomeCapacitorFilePicker.podspec @@ -0,0 +1,17 @@ +require 'json' + +package = JSON.parse(File.read(File.join(__dir__, 'package.json'))) + +Pod::Spec.new do |s| + s.name = 'CapawesomeCapacitorFilePicker' + s.version = package['version'] + s.summary = package['description'] + s.license = package['license'] + s.homepage = package['repository']['url'] + s.author = package['author'] + s.source = { :git => package['repository']['url'], :tag => s.version.to_s } + s.source_files = 'ios/Plugin/**/*.{swift,h,m,c,cc,mm,cpp}' + s.ios.deployment_target = '15.0' + s.dependency 'Capacitor' + s.swift_version = '5.1' +end diff --git a/node_modules/@capawesome/capacitor-file-picker/LICENSE b/node_modules/@capawesome/capacitor-file-picker/LICENSE new file mode 100644 index 0000000..cd7f770 --- /dev/null +++ b/node_modules/@capawesome/capacitor-file-picker/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021 Robin Genz + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/node_modules/@capawesome/capacitor-file-picker/Package.swift b/node_modules/@capawesome/capacitor-file-picker/Package.swift new file mode 100644 index 0000000..fc50a07 --- /dev/null +++ b/node_modules/@capawesome/capacitor-file-picker/Package.swift @@ -0,0 +1,28 @@ +// swift-tools-version: 5.9 +import PackageDescription + +let package = Package( + name: "CapawesomeCapacitorFilePicker", + platforms: [.iOS(.v15)], + products: [ + .library( + name: "CapawesomeCapacitorFilePicker", + targets: ["FilePickerPlugin"]) + ], + dependencies: [ + .package(url: "https://github.com/ionic-team/capacitor-swift-pm.git", from: "8.0.0") + ], + targets: [ + .target( + name: "FilePickerPlugin", + dependencies: [ + .product(name: "Capacitor", package: "capacitor-swift-pm"), + .product(name: "Cordova", package: "capacitor-swift-pm") + ], + path: "ios/Plugin"), + .testTarget( + name: "FilePickerPluginTests", + dependencies: ["FilePickerPlugin"], + path: "ios/PluginTests") + ] +) diff --git a/node_modules/@capawesome/capacitor-file-picker/README.md b/node_modules/@capawesome/capacitor-file-picker/README.md new file mode 100644 index 0000000..1ac3f1a --- /dev/null +++ b/node_modules/@capawesome/capacitor-file-picker/README.md @@ -0,0 +1,516 @@ +# @capawesome/capacitor-file-picker + +Capacitor plugin that allows the user to select a file, directory, image, or video from the device's file system or gallery. + + + +## Features + +We are proud to offer one of the most complete and feature-rich Capacitor plugins for file picking. Here are some of the key features: + +- 🖥️ **Cross-platform**: Supports Android, iOS and Web. +- 📂 **Directory picking**: Allows users to select a directory to retrieve all files. +- 🖼️ **Image picking**: Lets users select one or more images from the gallery. +- 🎥 **Video picking**: Lets users select one or more videos from the gallery. +- 📄 **File picking**: Lets users select one or more miscellaneous files from the file system. +- 📸 **HEIC to JPEG conversion**: Converts HEIC images to JPEG format on iOS. +- 📜 **File metadata**: Retrieves metadata such as file size, name, mime type, and last modified timestamp. +- 📦 **CocoaPods & SPM**: Supports CocoaPods and Swift Package Manager for iOS. +- 🔁 **Up-to-date**: Always supports the latest Capacitor version. + +Missing a feature? Just [open an issue](https://github.com/capawesome-team/capacitor-plugins/issues) and we'll take a look! + +## Newsletter + +Stay up to date with the latest news and updates about the Capawesome, Capacitor, and Ionic ecosystem by subscribing to our [Capawesome Newsletter](https://cloud.capawesome.io/newsletter/). + +## Compatibility + +| Plugin Version | Capacitor Version | Status | +| -------------- | ----------------- | -------------- | +| 8.x.x | >=8.x.x | Active support | +| 6.x.x | 6.x.x | Deprecated | +| 5.x.x | 5.x.x | Deprecated | + +## Installation + +```bash +npm install @capawesome/capacitor-file-picker +npx cap sync +``` + +### Android + +#### Permissions + +This API requires the following permissions be added to your `AndroidManifest.xml` before or after the `application` tag: + +```xml + + + + +``` + +### iOS + +#### Entitlements + +To use this plugin with Mac Catalyst, your app must have the `com.apple.security.files.user-selected.read-only` entitlement enabled. This allows the app to read files selected by the user. Check out the [Apple documentation](https://developer.apple.com/documentation/bundleresources/entitlements/com.apple.security.files.user-selected.read-only) for more information. + +```xml +com.apple.security.files.user-selected.read-only + +``` + +If you don't want to use the plugin with Mac Catalyst, you can skip this step. + +## Configuration + +No configuration required for this plugin. + +## Usage + +```typescript +import { FilePicker } from '@capawesome/capacitor-file-picker'; + +const appendFileToFormData = async () => { + const result = await FilePicker.pickFiles(); + const file = result.files[0]; + + const formData = new FormData(); + if (file.blob) { + const rawFile = new File(file.blob, file.name, { + type: file.mimeType, + }); + formData.append('file', rawFile, file.name); + } +}; + +const checkPermissions = async () => { + const result = await FilePicker.checkPermissions(); +}; + +const copyFile = async () => { + const result = await FilePicker.copyFile({ + from: 'path/to/file', + to: 'path/to/destination', + }); +}; + +const pickFiles = async () => { + const result = await FilePicker.pickFiles({ + types: ['image/png'], + }); +}; + +const pickDirectory = async () => { + const result = await FilePicker.pickDirectory(); +}; + +const pickImages = async () => { + const result = await FilePicker.pickImages(); +}; + +const pickMedia = async () => { + const result = await FilePicker.pickMedia(); +}; + +const pickVideos = async () => { + const result = await FilePicker.pickVideos(); +}; + +const requestPermissions = async () => { + const result = await FilePicker.requestPermissions(); +}; +``` + +## API + + + +* [`checkPermissions()`](#checkpermissions) +* [`convertHeicToJpeg(...)`](#convertheictojpeg) +* [`copyFile(...)`](#copyfile) +* [`pickFiles(...)`](#pickfiles) +* [`pickDirectory()`](#pickdirectory) +* [`pickImages(...)`](#pickimages) +* [`pickMedia(...)`](#pickmedia) +* [`pickVideos(...)`](#pickvideos) +* [`requestPermissions(...)`](#requestpermissions) +* [`addListener('pickerDismissed', ...)`](#addlistenerpickerdismissed-) +* [`removeAllListeners()`](#removealllisteners) +* [Interfaces](#interfaces) +* [Type Aliases](#type-aliases) + + + + + + +### checkPermissions() + +```typescript +checkPermissions() => Promise +``` + +Check permissions to access files. + +Only available on Android. + +**Returns:** Promise<PermissionStatus> + +**Since:** 6.1.0 + +-------------------- + + +### convertHeicToJpeg(...) + +```typescript +convertHeicToJpeg(options: ConvertHeicToJpegOptions) => Promise +``` + +Convert a HEIC image to JPEG. + +Only available on iOS. + +| Param | Type | +| ------------- | ----------------------------------------------------------------------------- | +| **`options`** | ConvertHeicToJpegOptions | + +**Returns:** Promise<ConvertHeicToJpegResult> + +**Since:** 0.6.0 + +-------------------- + + +### copyFile(...) + +```typescript +copyFile(options: CopyFileOptions) => Promise +``` + +Copy a file to a new location. + +| Param | Type | +| ------------- | ----------------------------------------------------------- | +| **`options`** | CopyFileOptions | + +**Since:** 7.1.0 + +-------------------- + + +### pickFiles(...) + +```typescript +pickFiles(options?: PickFilesOptions | undefined) => Promise +``` + +Open the file picker that allows the user to select one or more files. + +| Param | Type | +| ------------- | ------------------------------------------------------------- | +| **`options`** | PickFilesOptions | + +**Returns:** Promise<PickFilesResult> + +-------------------- + + +### pickDirectory() + +```typescript +pickDirectory() => Promise +``` + +Open a picker dialog that allows the user to select a directory. + +Only available on Android and iOS. + +**Returns:** Promise<PickDirectoryResult> + +**Since:** 6.2.0 + +-------------------- + + +### pickImages(...) + +```typescript +pickImages(options?: PickMediaOptions | undefined) => Promise +``` + +Pick one or more images from the gallery. + +On iOS 13 and older it only allows to pick one image. + +Only available on Android and iOS. + +| Param | Type | +| ------------- | ------------------------------------------------------------- | +| **`options`** | PickMediaOptions | + +**Returns:** Promise<PickFilesResult> + +**Since:** 0.5.3 + +-------------------- + + +### pickMedia(...) + +```typescript +pickMedia(options?: PickMediaOptions | undefined) => Promise +``` + +Pick one or more images or videos from the gallery. + +On iOS 13 and older it only allows to pick one image or video. + +Only available on Android and iOS. + +| Param | Type | +| ------------- | ------------------------------------------------------------- | +| **`options`** | PickMediaOptions | + +**Returns:** Promise<PickFilesResult> + +**Since:** 0.5.3 + +-------------------- + + +### pickVideos(...) + +```typescript +pickVideos(options?: PickMediaOptions | undefined) => Promise +``` + +Pick one or more videos from the gallery. + +On iOS 13 and older it only allows to pick one video. + +Only available on Android and iOS. + +| Param | Type | +| ------------- | ------------------------------------------------------------- | +| **`options`** | PickMediaOptions | + +**Returns:** Promise<PickFilesResult> + +**Since:** 0.5.3 + +-------------------- + + +### requestPermissions(...) + +```typescript +requestPermissions(options?: RequestPermissionsOptions | undefined) => Promise +``` + +Request permissions to access files. + +Only available on Android. + +| Param | Type | +| ------------- | ------------------------------------------------------------------------------- | +| **`options`** | RequestPermissionsOptions | + +**Returns:** Promise<PermissionStatus> + +**Since:** 6.1.0 + +-------------------- + + +### addListener('pickerDismissed', ...) + +```typescript +addListener(eventName: 'pickerDismissed', listenerFunc: () => void) => Promise +``` + +Called when the file picker is dismissed. + +Only available on iOS. + +| Param | Type | +| ------------------ | ------------------------------ | +| **`eventName`** | 'pickerDismissed' | +| **`listenerFunc`** | () => void | + +**Returns:** Promise<PluginListenerHandle> + +**Since:** 0.6.2 + +-------------------- + + +### removeAllListeners() + +```typescript +removeAllListeners() => Promise +``` + +Remove all listeners for this plugin. + +**Since:** 0.6.2 + +-------------------- + + +### Interfaces + + +#### PermissionStatus + +| Prop | Type | Description | Since | +| ------------------------- | ----------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- | ----- | +| **`accessMediaLocation`** | PermissionState | Permission state for accessing media location. On Android, this requests/checks the `ACCESS_MEDIA_LOCATION` permission. | 6.1.0 | +| **`readExternalStorage`** | PermissionState | Permission state for reading external storage. On Android, this requests/checks the `READ_EXTERNAL_STORAGE` permission. | 6.1.0 | + + +#### ConvertHeicToJpegResult + +| Prop | Type | Description | Since | +| ---------- | ------------------- | ------------------------------------- | ----- | +| **`path`** | string | The path of the converted JPEG image. | 0.6.0 | + + +#### ConvertHeicToJpegOptions + +| Prop | Type | Description | Since | +| ---------- | ------------------- | --------------------------- | ----- | +| **`path`** | string | The path of the HEIC image. | 0.6.0 | + + +#### CopyFileOptions + +| Prop | Type | Description | Default | Since | +| --------------- | -------------------- | --------------------------------------------------------------- | ----------------- | ----- | +| **`from`** | string | The path of the file to copy. | | 7.1.0 | +| **`overwrite`** | boolean | Whether to overwrite if the file at destination already exists. | true | 7.2.0 | +| **`to`** | string | The path to copy the file to. | | 7.1.0 | + + +#### PickFilesResult + +| Prop | Type | +| ----------- | ------------------------- | +| **`files`** | PickedFile[] | + + +#### PickedFile + +| Prop | Type | Description | Since | +| ---------------- | ------------------- | -------------------------------------------------------------------------------------------------------------------- | ----- | +| **`blob`** | Blob | The Blob instance of the file. Only available on Web. | | +| **`data`** | string | The Base64 string representation of the data contained in the file. Is only provided if `readData` is set to `true`. | | +| **`duration`** | number | The duration of the video in seconds. Only available on Android and iOS. | 0.5.3 | +| **`height`** | number | The height of the image or video in pixels. Only available on Android and iOS. | 0.5.3 | +| **`mimeType`** | string | The mime type of the file. | | +| **`modifiedAt`** | number | The last modified timestamp of the file in milliseconds. | 0.5.9 | +| **`name`** | string | The name of the file. | | +| **`path`** | string | The path of the file. Only available on Android and iOS. | | +| **`size`** | number | The size of the file in bytes. | | +| **`width`** | number | The width of the image or video in pixels. Only available on Android and iOS. | 0.5.3 | + + +#### PickFilesOptions + +| Prop | Type | Description | Default | Since | +| -------------- | --------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------ | ----- | +| **`types`** | string[] | List of accepted file types. Look at [IANA Media Types](https://www.iana.org/assignments/media-types/media-types.xhtml) for a complete list of standard media types. This option is ignored if `limit` is set. | | | +| **`limit`** | number | The maximum number of files that the user can select. Setting this to `0` sets the selection limit to unlimited. Currently, only `0` and `1` are supported. | 0 | 6.0.0 | +| **`readData`** | boolean | Whether to read the file data. **Attention**: Reading large files can lead to app crashes. It's therefore not recommended to use this option. Instead, use the [fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch) to load the file as a blob, see [this example](https://capawesome.io/blog/the-file-handling-guide-for-capacitor/#read-a-file). | false | | + + +#### PickDirectoryResult + +| Prop | Type | Description | Since | +| ---------- | ------------------- | ----------------------------------- | ----- | +| **`path`** | string | The path to the selected directory. | 6.2.0 | + + +#### PickMediaOptions + +| Prop | Type | Description | Default | Since | +| --------------------- | -------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------ | ----- | +| **`readData`** | boolean | Whether to read the file data. | false | | +| **`skipTranscoding`** | boolean | Whether to avoid transcoding, if possible. On iOS, for example, HEIC images are automatically transcoded to JPEG. Only available on iOS. | true | | +| **`limit`** | number | The maximum number of files that the user can select. Setting this to `0` sets the selection limit to unlimited. On Android and Web, only `0` and `1` are supported. | 0 | 5.2.0 | +| **`ordered`** | boolean | Whether an ordered number is displayed instead of a check mark in the selection badge. Only available on iOS (15+). | false | 5.3.0 | + + +#### RequestPermissionsOptions + +| Prop | Type | Description | Default | Since | +| ----------------- | ----------------------------- | --------------------------- | ----------------------------------------------------------- | ----- | +| **`permissions`** | PermissionType[] | The permissions to request. | ["accessMediaLocation", "readExternalStorage"] | 6.1.0 | + + +#### PluginListenerHandle + +| Prop | Type | +| ------------ | ----------------------------------------- | +| **`remove`** | () => Promise<void> | + + +### Type Aliases + + +#### PermissionState + +'prompt' | 'prompt-with-rationale' | 'granted' | 'denied' + + +#### PickImagesOptions + +PickMediaOptions + + +#### PickImagesResult + +PickMediaResult + + +#### PickMediaResult + +PickFilesResult + + +#### PickVideosOptions + +PickMediaOptions + + +#### PickVideosResult + +PickMediaResult + + +#### PermissionType + +'accessMediaLocation' | 'readExternalStorage' + + + +## Changelog + +See [CHANGELOG.md](https://github.com/capawesome-team/capacitor-plugins/blob/main/packages/file-picker/CHANGELOG.md). + +## License + +See [LICENSE](https://github.com/capawesome-team/capacitor-plugins/blob/main/packages/file-picker/LICENSE). + +## Credits + +This plugin is based on the [Capacitor File Picker](https://github.com/capawesome-team/capacitor-file-picker) plugin. +Thanks to everyone who contributed to the project! diff --git a/node_modules/@capawesome/capacitor-file-picker/android/build.gradle b/node_modules/@capawesome/capacitor-file-picker/android/build.gradle new file mode 100644 index 0000000..f6031d7 --- /dev/null +++ b/node_modules/@capawesome/capacitor-file-picker/android/build.gradle @@ -0,0 +1,58 @@ +ext { + junitVersion = project.hasProperty('junitVersion') ? rootProject.ext.junitVersion : '4.13.2' + androidxAppCompatVersion = project.hasProperty('androidxAppCompatVersion') ? rootProject.ext.androidxAppCompatVersion : '1.7.1' + androidxJunitVersion = project.hasProperty('androidxJunitVersion') ? rootProject.ext.androidxJunitVersion : '1.3.0' + androidxEspressoCoreVersion = project.hasProperty('androidxEspressoCoreVersion') ? rootProject.ext.androidxEspressoCoreVersion : '3.7.0' +} + +buildscript { + repositories { + google() + mavenCentral() + } + dependencies { + classpath 'com.android.tools.build:gradle:8.13.0' + } +} + +apply plugin: 'com.android.library' + +android { + namespace = "io.capawesome.capacitorjs.plugins.filepicker" + compileSdk = project.hasProperty('compileSdkVersion') ? rootProject.ext.compileSdkVersion : 36 + defaultConfig { + minSdkVersion project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : 24 + targetSdkVersion project.hasProperty('targetSdkVersion') ? rootProject.ext.targetSdkVersion : 36 + versionCode 1 + versionName "1.0" + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } + lintOptions { + abortOnError = false + } + compileOptions { + sourceCompatibility JavaVersion.VERSION_21 + targetCompatibility JavaVersion.VERSION_21 + } +} + +repositories { + google() + mavenCentral() +} + + +dependencies { + implementation fileTree(dir: 'libs', include: ['*.jar']) + implementation project(':capacitor-android') + implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion" + testImplementation "junit:junit:$junitVersion" + androidTestImplementation "androidx.test.ext:junit:$androidxJunitVersion" + androidTestImplementation "androidx.test.espresso:espresso-core:$androidxEspressoCoreVersion" +} diff --git a/node_modules/@capawesome/capacitor-file-picker/android/src/main/AndroidManifest.xml b/node_modules/@capawesome/capacitor-file-picker/android/src/main/AndroidManifest.xml new file mode 100644 index 0000000..a2f47b6 --- /dev/null +++ b/node_modules/@capawesome/capacitor-file-picker/android/src/main/AndroidManifest.xml @@ -0,0 +1,2 @@ + + diff --git a/node_modules/@capawesome/capacitor-file-picker/android/src/main/java/io/capawesome/capacitorjs/plugins/filepicker/FilePicker.java b/node_modules/@capawesome/capacitor-file-picker/android/src/main/java/io/capawesome/capacitorjs/plugins/filepicker/FilePicker.java new file mode 100644 index 0000000..563c630 --- /dev/null +++ b/node_modules/@capawesome/capacitor-file-picker/android/src/main/java/io/capawesome/capacitorjs/plugins/filepicker/FilePicker.java @@ -0,0 +1,208 @@ +package io.capawesome.capacitorjs.plugins.filepicker; + +import android.content.ContentResolver; +import android.database.Cursor; +import android.graphics.BitmapFactory; +import android.media.MediaMetadataRetriever; +import android.net.Uri; +import android.provider.DocumentsContract; +import android.provider.OpenableColumns; +import android.util.Base64; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.core.content.FileProvider; +import com.getcapacitor.Logger; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.Objects; + +public class FilePicker { + + public static final String TAG = "FilePicker"; + private final FilePickerPlugin plugin; + + FilePicker(FilePickerPlugin plugin) { + this.plugin = plugin; + } + + public void copyFile(@NonNull Uri from, @NonNull Uri to, Boolean shouldOverwrite) throws Exception { + if (!shouldOverwrite) { + File file = new File(Objects.requireNonNull(to.getPath())); + if (!file.exists()) { + throw new Exception(FilePickerPlugin.ERROR_FILE_ALREADY_EXISTS); + } + } + InputStream inputStream = plugin.getBridge().getContext().getContentResolver().openInputStream(from); + OutputStream outputStream = plugin.getBridge().getContext().getContentResolver().openOutputStream(to); + if (inputStream == null || outputStream == null) { + throw new Exception(FilePickerPlugin.ERROR_COPY_FILE_FAILED); + } + byte[] buffer = new byte[1024]; + int length; + while ((length = inputStream.read(buffer)) > 0) { + outputStream.write(buffer, 0, length); + } + outputStream.close(); + inputStream.close(); + } + + public String getPathFromUri(@NonNull Uri uri) { + return uri.toString(); + } + + public Uri getUriByPath(@NonNull String path) { + Uri uri = Uri.parse(path); + if (uri.getScheme() != null && uri.getScheme().equals(ContentResolver.SCHEME_CONTENT)) { + return uri; + } else if (uri.getScheme() == null || uri.getScheme().equals(ContentResolver.SCHEME_FILE)) { + return FileProvider.getUriForFile( + plugin.getActivity(), + plugin.getContext().getPackageName() + ".fileprovider", + new File(uri.getPath()) + ); + } else { + return FileProvider.getUriForFile(plugin.getActivity(), plugin.getContext().getPackageName() + ".fileprovider", new File(path)); + } + } + + public String getNameFromUri(@NonNull Uri uri) { + String displayName = ""; + String[] projection = { OpenableColumns.DISPLAY_NAME }; + Cursor cursor = plugin.getBridge().getContext().getContentResolver().query(uri, projection, null, null, null); + if (cursor != null) { + cursor.moveToFirst(); + int columnIdx = cursor.getColumnIndex(projection[0]); + displayName = cursor.getString(columnIdx); + cursor.close(); + } + if (displayName == null || displayName.length() < 1) { + displayName = uri.getLastPathSegment(); + } + return displayName; + } + + public String getDataFromUri(@NonNull Uri uri) { + try { + InputStream stream = plugin.getBridge().getActivity().getContentResolver().openInputStream(uri); + byte[] bytes = getBytesFromInputStream(stream); + return Base64.encodeToString(bytes, Base64.NO_WRAP); + } catch (FileNotFoundException e) { + Logger.error(TAG, "openInputStream failed.", e); + } catch (IOException e) { + Logger.error(TAG, "getBytesFromInputStream failed.", e); + } + return ""; + } + + @Nullable + public String getMimeTypeFromUri(@NonNull Uri uri) { + return plugin.getBridge().getContext().getContentResolver().getType(uri); + } + + @Nullable + public Long getModifiedAtFromUri(@NonNull Uri uri) { + try { + long modifiedAt = 0; + Cursor cursor = plugin.getBridge().getContext().getContentResolver().query(uri, null, null, null, null); + if (cursor != null) { + cursor.moveToFirst(); + int columnIdx = cursor.getColumnIndex(DocumentsContract.Document.COLUMN_LAST_MODIFIED); + modifiedAt = cursor.getLong(columnIdx); + cursor.close(); + } + return modifiedAt; + } catch (Exception e) { + Logger.error(TAG, "getModifiedAtFromUri failed.", e); + return null; + } + } + + public long getSizeFromUri(@NonNull Uri uri) { + long size = 0; + String[] projection = { OpenableColumns.SIZE }; + Cursor cursor = plugin.getBridge().getContext().getContentResolver().query(uri, projection, null, null, null); + if (cursor != null) { + cursor.moveToFirst(); + int columnIdx = cursor.getColumnIndex(projection[0]); + size = cursor.getLong(columnIdx); + cursor.close(); + } + return size; + } + + @Nullable + public Long getDurationFromUri(@NonNull Uri uri) { + if (isVideoUri(uri)) { + MediaMetadataRetriever retriever = new MediaMetadataRetriever(); + retriever.setDataSource(plugin.getBridge().getContext(), uri); + String time = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION); + long durationMs = Long.parseLong(time); + try { + retriever.release(); + } catch (Exception e) { + Logger.error(TAG, "MediaMetadataRetriever.release() failed.", e); + } + return durationMs / 1000l; + } + return null; + } + + @Nullable + public FileResolution getHeightAndWidthFromUri(@NonNull Uri uri) { + if (isImageUri(uri)) { + BitmapFactory.Options options = new BitmapFactory.Options(); + options.inJustDecodeBounds = true; + try { + BitmapFactory.decodeStream(plugin.getBridge().getContext().getContentResolver().openInputStream(uri), null, options); + return new FileResolution(options.outHeight, options.outWidth); + } catch (FileNotFoundException exception) { + exception.printStackTrace(); + return null; + } + } else if (isVideoUri(uri)) { + MediaMetadataRetriever retriever = new MediaMetadataRetriever(); + retriever.setDataSource(plugin.getBridge().getContext(), uri); + int width = Integer.valueOf(retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_WIDTH)); + int height = Integer.valueOf(retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT)); + try { + retriever.release(); + } catch (Exception e) { + Logger.error(TAG, "MediaMetadataRetriever.release() failed.", e); + } + return new FileResolution(height, width); + } + return null; + } + + private boolean isImageUri(Uri uri) { + String mimeType = getMimeTypeFromUri(uri); + if (mimeType == null) { + return false; + } + return mimeType.startsWith("image"); + } + + private boolean isVideoUri(Uri uri) { + String mimeType = getMimeTypeFromUri(uri); + if (mimeType == null) { + return false; + } + return mimeType.startsWith("video"); + } + + /** + * Source: https://stackoverflow.com/a/17861016/16289814 + */ + private static byte[] getBytesFromInputStream(InputStream is) throws IOException { + ByteArrayOutputStream os = new ByteArrayOutputStream(); + byte[] buffer = new byte[0xFFFF]; + for (int len = is.read(buffer); len != -1; len = is.read(buffer)) { + os.write(buffer, 0, len); + } + return os.toByteArray(); + } +} diff --git a/node_modules/@capawesome/capacitor-file-picker/android/src/main/java/io/capawesome/capacitorjs/plugins/filepicker/FilePickerPlugin.java b/node_modules/@capawesome/capacitor-file-picker/android/src/main/java/io/capawesome/capacitorjs/plugins/filepicker/FilePickerPlugin.java new file mode 100644 index 0000000..57ac7be --- /dev/null +++ b/node_modules/@capawesome/capacitor-file-picker/android/src/main/java/io/capawesome/capacitorjs/plugins/filepicker/FilePickerPlugin.java @@ -0,0 +1,341 @@ +package io.capawesome.capacitorjs.plugins.filepicker; + +import android.Manifest; +import android.app.Activity; +import android.content.Intent; +import android.net.Uri; +import android.os.Bundle; +import android.os.Parcelable; +import android.util.Log; +import androidx.activity.result.ActivityResult; +import androidx.annotation.Nullable; +import com.getcapacitor.JSArray; +import com.getcapacitor.JSObject; +import com.getcapacitor.Logger; +import com.getcapacitor.Plugin; +import com.getcapacitor.PluginCall; +import com.getcapacitor.PluginMethod; +import com.getcapacitor.annotation.ActivityCallback; +import com.getcapacitor.annotation.CapacitorPlugin; +import com.getcapacitor.annotation.Permission; +import com.getcapacitor.annotation.PermissionCallback; +import java.util.ArrayList; +import java.util.List; +import org.json.JSONException; + +@CapacitorPlugin( + name = "FilePicker", + permissions = { + @Permission(strings = { Manifest.permission.ACCESS_MEDIA_LOCATION }, alias = FilePickerPlugin.PERMISSION_ACCESS_MEDIA_LOCATION), + @Permission(strings = { Manifest.permission.READ_EXTERNAL_STORAGE }, alias = FilePickerPlugin.PERMISSION_READ_EXTERNAL_STORAGE) + } +) +public class FilePickerPlugin extends Plugin { + + public static final String ERROR_COPY_FILE_FAILED = "copyFile failed."; + public static final String ERROR_FILE_ALREADY_EXISTS = "File already exists."; + public static final String ERROR_FROM_MISSING = "from must be provided."; + public static final String ERROR_TO_MISSING = "to must be provided."; + public static final String ERROR_PICK_FILE_FAILED = "pickFiles failed."; + public static final String ERROR_PICK_FILE_CANCELED = "pickFiles canceled."; + public static final String ERROR_PICK_DIRECTORY_FAILED = "pickDirectory failed."; + public static final String ERROR_PICK_DIRECTORY_CANCELED = "pickDirectory canceled."; + public static final String PERMISSION_ACCESS_MEDIA_LOCATION = "accessMediaLocation"; + public static final String PERMISSION_READ_EXTERNAL_STORAGE = "readExternalStorage"; + public static final String TAG = "FilePickerPlugin"; + + private FilePicker implementation; + + public void load() { + implementation = new FilePicker(this); + } + + @Override + @PluginMethod + public void checkPermissions(PluginCall call) { + super.checkPermissions(call); + } + + @PluginMethod + public void convertHeicToJpeg(PluginCall call) { + call.unimplemented("Not implemented on Android."); + } + + @PluginMethod + public void copyFile(PluginCall call) { + try { + String from = call.getString("from"); + if (from == null) { + call.reject(ERROR_FROM_MISSING); + return; + } + Uri fromUri = implementation.getUriByPath(from); + String to = call.getString("to"); + if (to == null) { + call.reject(ERROR_TO_MISSING); + return; + } + Uri toUri = implementation.getUriByPath(to); + Boolean shouldOverwrite = call.getBoolean("overwrite", true); + + implementation.copyFile(fromUri, toUri, shouldOverwrite); + + call.resolve(); + } catch (Exception ex) { + String message = ex.getMessage(); + Log.e(TAG, message); + call.reject(message); + } + } + + @PluginMethod + public void pickFiles(PluginCall call) { + try { + int limit = call.getInt("limit", 0); + JSArray types = call.getArray("types", null); + String[] parsedTypes = parseTypesOption(types); + + Intent intent = new Intent(Intent.ACTION_GET_CONTENT); + intent.setType("*/*"); + intent.addCategory(Intent.CATEGORY_OPENABLE); + intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, limit == 0); + if (limit == 1 && parsedTypes != null && parsedTypes.length > 0) { + intent.putExtra(Intent.EXTRA_MIME_TYPES, parsedTypes); + } + + startActivityForResult(call, intent, "pickFilesResult"); + } catch (Exception ex) { + String message = ex.getMessage(); + Log.e(TAG, message); + call.reject(message); + } + } + + @PluginMethod + public void pickDirectory(PluginCall call) { + try { + Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE); + startActivityForResult(call, intent, "pickDirectoryResult"); + } catch (Exception ex) { + String message = ex.getMessage(); + Log.e(TAG, message); + call.reject(message); + } + } + + @PluginMethod + public void pickImages(PluginCall call) { + try { + int limit = call.getInt("limit", 0); + + Intent intent = new Intent(Intent.ACTION_PICK); + intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, limit == 0); + intent.setType("image/*"); + intent.putExtra("multi-pick", limit == 0); + intent.putExtra(Intent.EXTRA_MIME_TYPES, new String[] { "image/*" }); + + startActivityForResult(call, intent, "pickFilesResult"); + } catch (Exception ex) { + String message = ex.getMessage(); + Log.e(TAG, message); + call.reject(message); + } + } + + @PluginMethod + public void pickMedia(PluginCall call) { + try { + int limit = call.getInt("limit", 0); + + Intent intent = new Intent(Intent.ACTION_PICK); + intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, limit == 0); + intent.setType("*/*"); + intent.putExtra("multi-pick", limit == 0); + intent.putExtra(Intent.EXTRA_MIME_TYPES, new String[] { "image/*", "video/*" }); + + startActivityForResult(call, intent, "pickFilesResult"); + } catch (Exception ex) { + String message = ex.getMessage(); + Log.e(TAG, message); + call.reject(message); + } + } + + @PluginMethod + public void pickVideos(PluginCall call) { + try { + int limit = call.getInt("limit", 0); + + Intent intent = new Intent(Intent.ACTION_PICK); + intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, limit == 0); + intent.setType("video/*"); + intent.putExtra("multi-pick", limit == 0); + intent.putExtra(Intent.EXTRA_MIME_TYPES, new String[] { "video/*" }); + + startActivityForResult(call, intent, "pickFilesResult"); + } catch (Exception ex) { + String message = ex.getMessage(); + Log.e(TAG, message); + call.reject(message); + } + } + + @Override + @PluginMethod + public void requestPermissions(PluginCall call) { + List permissionsList = new ArrayList<>(); + permissionsList.add(PERMISSION_ACCESS_MEDIA_LOCATION); + permissionsList.add(PERMISSION_READ_EXTERNAL_STORAGE); + + JSArray permissions = call.getArray("permissions"); + if (permissions != null) { + try { + permissionsList = permissions.toList(); + } catch (JSONException e) {} + } + + requestPermissionForAliases(permissionsList.toArray(new String[0]), call, "permissionsCallback"); + } + + @Nullable + private String[] parseTypesOption(@Nullable JSArray types) { + if (types == null) { + return null; + } + try { + List typesList = types.toList(); + if (typesList.contains("text/csv")) { + typesList.add("text/comma-separated-values"); + } + return typesList.toArray(new String[0]); + } catch (JSONException exception) { + Logger.error("parseTypesOption failed.", exception); + return null; + } + } + + @PermissionCallback + private void permissionsCallback(PluginCall call) { + this.checkPermissions(call); + } + + @ActivityCallback + private void pickFilesResult(PluginCall call, ActivityResult result) { + try { + if (call == null) { + return; + } + boolean readData = call.getBoolean("readData", false); + int resultCode = result.getResultCode(); + switch (resultCode) { + case Activity.RESULT_OK: + JSObject callResult = createPickFilesResult(result.getData(), readData); + call.resolve(callResult); + break; + case Activity.RESULT_CANCELED: + call.reject(ERROR_PICK_FILE_CANCELED); + break; + default: + call.reject(ERROR_PICK_FILE_FAILED); + } + } catch (Exception ex) { + String message = ex.getMessage(); + Log.e(TAG, message); + call.reject(message); + } + } + + @ActivityCallback + private void pickDirectoryResult(PluginCall call, ActivityResult result) { + try { + int resultCode = result.getResultCode(); + switch (resultCode) { + case Activity.RESULT_OK: + JSObject callResult = createPickDirectoryResult(result.getData()); + call.resolve(callResult); + break; + case Activity.RESULT_CANCELED: + call.reject(ERROR_PICK_DIRECTORY_CANCELED); + break; + default: + call.reject(ERROR_PICK_DIRECTORY_FAILED); + } + } catch (Exception ex) { + String message = ex.getMessage(); + Log.e(TAG, message); + call.reject(message); + } + } + + private JSObject createPickFilesResult(@Nullable Intent data, boolean readData) { + JSObject callResult = new JSObject(); + List filesResultList = new ArrayList<>(); + if (data == null) { + callResult.put("files", JSArray.from(filesResultList)); + return callResult; + } + List uris = new ArrayList<>(); + if (data.getClipData() == null && data.getData() == null && data.getExtras() != null) { + Bundle bundle = data.getExtras(); + if (bundle.containsKey("selectedItems")) { + ArrayList selectedItems = bundle.getParcelableArrayList("selectedItems"); + if (selectedItems != null) { + for (Parcelable selectedItem : selectedItems) { + if (selectedItem instanceof Uri) { + uris.add((Uri) selectedItem); + } + } + } + } + } else if (data.getClipData() == null) { + Uri uri = data.getData(); + uris.add(uri); + } else { + for (int i = 0; i < data.getClipData().getItemCount(); i++) { + Uri uri = data.getClipData().getItemAt(i).getUri(); + uris.add(uri); + } + } + for (int i = 0; i < uris.size(); i++) { + Uri uri = uris.get(i); + if (uri == null) { + continue; + } + JSObject fileResult = new JSObject(); + if (readData) { + fileResult.put("data", implementation.getDataFromUri(uri)); + } + Long duration = implementation.getDurationFromUri(uri); + if (duration != null) { + fileResult.put("duration", duration); + } + FileResolution resolution = implementation.getHeightAndWidthFromUri(uri); + if (resolution != null) { + fileResult.put("height", resolution.height); + fileResult.put("width", resolution.width); + } + fileResult.put("mimeType", implementation.getMimeTypeFromUri(uri)); + Long modifiedAt = implementation.getModifiedAtFromUri(uri); + if (modifiedAt != null) { + fileResult.put("modifiedAt", modifiedAt); + } + fileResult.put("name", implementation.getNameFromUri(uri)); + fileResult.put("path", implementation.getPathFromUri(uri)); + fileResult.put("size", implementation.getSizeFromUri(uri)); + filesResultList.add(fileResult); + } + callResult.put("files", JSArray.from(filesResultList.toArray())); + return callResult; + } + + private JSObject createPickDirectoryResult(@Nullable Intent data) { + JSObject callResult = new JSObject(); + if (data != null) { + Uri uri = data.getData(); + if (uri != null) { + callResult.put("path", implementation.getPathFromUri(uri)); + } + } + return callResult; + } +} diff --git a/node_modules/@capawesome/capacitor-file-picker/android/src/main/java/io/capawesome/capacitorjs/plugins/filepicker/FileResolution.java b/node_modules/@capawesome/capacitor-file-picker/android/src/main/java/io/capawesome/capacitorjs/plugins/filepicker/FileResolution.java new file mode 100644 index 0000000..ed87b8b --- /dev/null +++ b/node_modules/@capawesome/capacitor-file-picker/android/src/main/java/io/capawesome/capacitorjs/plugins/filepicker/FileResolution.java @@ -0,0 +1,12 @@ +package io.capawesome.capacitorjs.plugins.filepicker; + +public class FileResolution { + + public int height; + public int width; + + public FileResolution(int height, int width) { + this.height = height; + this.width = width; + } +} diff --git a/node_modules/@capawesome/capacitor-file-picker/android/src/main/res/.gitkeep b/node_modules/@capawesome/capacitor-file-picker/android/src/main/res/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/node_modules/@capawesome/capacitor-file-picker/dist/docs.json b/node_modules/@capawesome/capacitor-file-picker/dist/docs.json new file mode 100644 index 0000000..587b9b8 --- /dev/null +++ b/node_modules/@capawesome/capacitor-file-picker/dist/docs.json @@ -0,0 +1,849 @@ +{ + "api": { + "name": "FilePickerPlugin", + "slug": "filepickerplugin", + "docs": "", + "tags": [], + "methods": [ + { + "name": "checkPermissions", + "signature": "() => Promise", + "parameters": [], + "returns": "Promise", + "tags": [ + { + "name": "since", + "text": "6.1.0" + } + ], + "docs": "Check permissions to access files.\n\nOnly available on Android.", + "complexTypes": [ + "PermissionStatus" + ], + "slug": "checkpermissions" + }, + { + "name": "convertHeicToJpeg", + "signature": "(options: ConvertHeicToJpegOptions) => Promise", + "parameters": [ + { + "name": "options", + "docs": "", + "type": "ConvertHeicToJpegOptions" + } + ], + "returns": "Promise", + "tags": [ + { + "name": "since", + "text": "0.6.0" + } + ], + "docs": "Convert a HEIC image to JPEG.\n\nOnly available on iOS.", + "complexTypes": [ + "ConvertHeicToJpegResult", + "ConvertHeicToJpegOptions" + ], + "slug": "convertheictojpeg" + }, + { + "name": "copyFile", + "signature": "(options: CopyFileOptions) => Promise", + "parameters": [ + { + "name": "options", + "docs": "", + "type": "CopyFileOptions" + } + ], + "returns": "Promise", + "tags": [ + { + "name": "since", + "text": "7.1.0" + } + ], + "docs": "Copy a file to a new location.", + "complexTypes": [ + "CopyFileOptions" + ], + "slug": "copyfile" + }, + { + "name": "pickFiles", + "signature": "(options?: PickFilesOptions | undefined) => Promise", + "parameters": [ + { + "name": "options", + "docs": "", + "type": "PickFilesOptions | undefined" + } + ], + "returns": "Promise", + "tags": [], + "docs": "Open the file picker that allows the user to select one or more files.", + "complexTypes": [ + "PickFilesResult", + "PickFilesOptions" + ], + "slug": "pickfiles" + }, + { + "name": "pickDirectory", + "signature": "() => Promise", + "parameters": [], + "returns": "Promise", + "tags": [ + { + "name": "since", + "text": "6.2.0" + } + ], + "docs": "Open a picker dialog that allows the user to select a directory.\n\nOnly available on Android and iOS.", + "complexTypes": [ + "PickDirectoryResult" + ], + "slug": "pickdirectory" + }, + { + "name": "pickImages", + "signature": "(options?: PickMediaOptions | undefined) => Promise", + "parameters": [ + { + "name": "options", + "docs": "", + "type": "PickMediaOptions | undefined" + } + ], + "returns": "Promise", + "tags": [ + { + "name": "since", + "text": "0.5.3" + } + ], + "docs": "Pick one or more images from the gallery.\n\nOn iOS 13 and older it only allows to pick one image.\n\nOnly available on Android and iOS.", + "complexTypes": [ + "PickFilesResult", + "PickImagesOptions", + "PickImagesResult" + ], + "slug": "pickimages" + }, + { + "name": "pickMedia", + "signature": "(options?: PickMediaOptions | undefined) => Promise", + "parameters": [ + { + "name": "options", + "docs": "", + "type": "PickMediaOptions | undefined" + } + ], + "returns": "Promise", + "tags": [ + { + "name": "since", + "text": "0.5.3" + } + ], + "docs": "Pick one or more images or videos from the gallery.\n\nOn iOS 13 and older it only allows to pick one image or video.\n\nOnly available on Android and iOS.", + "complexTypes": [ + "PickFilesResult", + "PickMediaOptions", + "PickMediaResult" + ], + "slug": "pickmedia" + }, + { + "name": "pickVideos", + "signature": "(options?: PickMediaOptions | undefined) => Promise", + "parameters": [ + { + "name": "options", + "docs": "", + "type": "PickMediaOptions | undefined" + } + ], + "returns": "Promise", + "tags": [ + { + "name": "since", + "text": "0.5.3" + } + ], + "docs": "Pick one or more videos from the gallery.\n\nOn iOS 13 and older it only allows to pick one video.\n\nOnly available on Android and iOS.", + "complexTypes": [ + "PickFilesResult", + "PickVideosOptions", + "PickVideosResult" + ], + "slug": "pickvideos" + }, + { + "name": "requestPermissions", + "signature": "(options?: RequestPermissionsOptions | undefined) => Promise", + "parameters": [ + { + "name": "options", + "docs": "", + "type": "RequestPermissionsOptions | undefined" + } + ], + "returns": "Promise", + "tags": [ + { + "name": "since", + "text": "6.1.0" + } + ], + "docs": "Request permissions to access files.\n\nOnly available on Android.", + "complexTypes": [ + "PermissionStatus", + "RequestPermissionsOptions" + ], + "slug": "requestpermissions" + }, + { + "name": "addListener", + "signature": "(eventName: 'pickerDismissed', listenerFunc: () => void) => Promise", + "parameters": [ + { + "name": "eventName", + "docs": "", + "type": "'pickerDismissed'" + }, + { + "name": "listenerFunc", + "docs": "", + "type": "() => void" + } + ], + "returns": "Promise", + "tags": [ + { + "name": "since", + "text": "0.6.2" + } + ], + "docs": "Called when the file picker is dismissed.\n\nOnly available on iOS.", + "complexTypes": [ + "PluginListenerHandle" + ], + "slug": "addlistenerpickerdismissed-" + }, + { + "name": "removeAllListeners", + "signature": "() => Promise", + "parameters": [], + "returns": "Promise", + "tags": [ + { + "name": "since", + "text": "0.6.2" + } + ], + "docs": "Remove all listeners for this plugin.", + "complexTypes": [], + "slug": "removealllisteners" + } + ], + "properties": [] + }, + "interfaces": [ + { + "name": "PermissionStatus", + "slug": "permissionstatus", + "docs": "", + "tags": [ + { + "text": "6.1.0", + "name": "since" + } + ], + "methods": [], + "properties": [ + { + "name": "accessMediaLocation", + "tags": [ + { + "text": "6.1.0", + "name": "since" + } + ], + "docs": "Permission state for accessing media location.\n\nOn Android, this requests/checks the `ACCESS_MEDIA_LOCATION` permission.", + "complexTypes": [ + "PermissionState" + ], + "type": "PermissionState" + }, + { + "name": "readExternalStorage", + "tags": [ + { + "text": "6.1.0", + "name": "since" + } + ], + "docs": "Permission state for reading external storage.\n\nOn Android, this requests/checks the `READ_EXTERNAL_STORAGE` permission.", + "complexTypes": [ + "PermissionState" + ], + "type": "PermissionState" + } + ] + }, + { + "name": "ConvertHeicToJpegResult", + "slug": "convertheictojpegresult", + "docs": "", + "tags": [ + { + "text": "0.6.0", + "name": "since" + } + ], + "methods": [], + "properties": [ + { + "name": "path", + "tags": [ + { + "text": "'/path/to/image.jpeg'", + "name": "example" + }, + { + "text": "0.6.0", + "name": "since" + } + ], + "docs": "The path of the converted JPEG image.", + "complexTypes": [], + "type": "string" + } + ] + }, + { + "name": "ConvertHeicToJpegOptions", + "slug": "convertheictojpegoptions", + "docs": "", + "tags": [ + { + "text": "0.6.0", + "name": "since" + } + ], + "methods": [], + "properties": [ + { + "name": "path", + "tags": [ + { + "text": "'/path/to/image.heic'", + "name": "example" + }, + { + "text": "0.6.0", + "name": "since" + } + ], + "docs": "The path of the HEIC image.", + "complexTypes": [], + "type": "string" + } + ] + }, + { + "name": "CopyFileOptions", + "slug": "copyfileoptions", + "docs": "", + "tags": [ + { + "text": "7.1.0", + "name": "since" + } + ], + "methods": [], + "properties": [ + { + "name": "from", + "tags": [ + { + "text": "'/path/to/file.txt'", + "name": "example" + }, + { + "text": "7.1.0", + "name": "since" + } + ], + "docs": "The path of the file to copy.", + "complexTypes": [], + "type": "string" + }, + { + "name": "overwrite", + "tags": [ + { + "text": "true", + "name": "default" + }, + { + "text": "false", + "name": "example" + }, + { + "text": "7.2.0", + "name": "since" + } + ], + "docs": "Whether to overwrite if the file at destination already exists.", + "complexTypes": [], + "type": "boolean | undefined" + }, + { + "name": "to", + "tags": [ + { + "text": "'/path/to/new-file.txt'", + "name": "example" + }, + { + "text": "7.1.0", + "name": "since" + } + ], + "docs": "The path to copy the file to.", + "complexTypes": [], + "type": "string" + } + ] + }, + { + "name": "PickFilesResult", + "slug": "pickfilesresult", + "docs": "", + "tags": [], + "methods": [], + "properties": [ + { + "name": "files", + "tags": [], + "docs": "", + "complexTypes": [ + "PickedFile" + ], + "type": "PickedFile[]" + } + ] + }, + { + "name": "PickedFile", + "slug": "pickedfile", + "docs": "", + "tags": [], + "methods": [], + "properties": [ + { + "name": "blob", + "tags": [], + "docs": "The Blob instance of the file.\n\nOnly available on Web.", + "complexTypes": [ + "Blob" + ], + "type": "Blob" + }, + { + "name": "data", + "tags": [], + "docs": "The Base64 string representation of the data contained in the file.\n\nIs only provided if `readData` is set to `true`.", + "complexTypes": [], + "type": "string | undefined" + }, + { + "name": "duration", + "tags": [ + { + "text": "0.5.3", + "name": "since" + } + ], + "docs": "The duration of the video in seconds.\n\nOnly available on Android and iOS.", + "complexTypes": [], + "type": "number | undefined" + }, + { + "name": "height", + "tags": [ + { + "text": "0.5.3", + "name": "since" + } + ], + "docs": "The height of the image or video in pixels.\n\nOnly available on Android and iOS.", + "complexTypes": [], + "type": "number | undefined" + }, + { + "name": "mimeType", + "tags": [], + "docs": "The mime type of the file.", + "complexTypes": [], + "type": "string" + }, + { + "name": "modifiedAt", + "tags": [ + { + "text": "0.5.9", + "name": "since" + } + ], + "docs": "The last modified timestamp of the file in milliseconds.", + "complexTypes": [], + "type": "number | undefined" + }, + { + "name": "name", + "tags": [], + "docs": "The name of the file.", + "complexTypes": [], + "type": "string" + }, + { + "name": "path", + "tags": [], + "docs": "The path of the file.\n\nOnly available on Android and iOS.", + "complexTypes": [], + "type": "string | undefined" + }, + { + "name": "size", + "tags": [], + "docs": "The size of the file in bytes.", + "complexTypes": [], + "type": "number" + }, + { + "name": "width", + "tags": [ + { + "text": "0.5.3", + "name": "since" + } + ], + "docs": "The width of the image or video in pixels.\n\nOnly available on Android and iOS.", + "complexTypes": [], + "type": "number | undefined" + } + ] + }, + { + "name": "PickFilesOptions", + "slug": "pickfilesoptions", + "docs": "", + "tags": [], + "methods": [], + "properties": [ + { + "name": "types", + "tags": [ + { + "text": "['image/png', 'application/pdf']", + "name": "example" + } + ], + "docs": "List of accepted file types.\nLook at [IANA Media Types](https://www.iana.org/assignments/media-types/media-types.xhtml) for a complete list of standard media types.\n\nThis option is ignored if `limit` is set.", + "complexTypes": [], + "type": "string[] | undefined" + }, + { + "name": "limit", + "tags": [ + { + "text": "0", + "name": "default" + }, + { + "text": "1", + "name": "example" + }, + { + "text": "6.0.0", + "name": "since" + } + ], + "docs": "The maximum number of files that the user can select.\nSetting this to `0` sets the selection limit to unlimited.\n\nCurrently, only `0` and `1` are supported.", + "complexTypes": [], + "type": "number | undefined" + }, + { + "name": "readData", + "tags": [ + { + "text": "false", + "name": "default" + } + ], + "docs": "Whether to read the file data.\n\n**Attention**: Reading large files can lead to app crashes.\nIt's therefore not recommended to use this option.\nInstead, use the [fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch)\nto load the file as a blob, see [this example](https://capawesome.io/blog/the-file-handling-guide-for-capacitor/#read-a-file).", + "complexTypes": [], + "type": "boolean | undefined" + } + ] + }, + { + "name": "PickDirectoryResult", + "slug": "pickdirectoryresult", + "docs": "", + "tags": [], + "methods": [], + "properties": [ + { + "name": "path", + "tags": [ + { + "text": "6.2.0", + "name": "since" + } + ], + "docs": "The path to the selected directory.", + "complexTypes": [], + "type": "string" + } + ] + }, + { + "name": "PickMediaOptions", + "slug": "pickmediaoptions", + "docs": "", + "tags": [ + { + "text": "0.5.3", + "name": "since" + } + ], + "methods": [], + "properties": [ + { + "name": "readData", + "tags": [ + { + "text": "false", + "name": "default" + } + ], + "docs": "Whether to read the file data.", + "complexTypes": [], + "type": "boolean | undefined" + }, + { + "name": "skipTranscoding", + "tags": [ + { + "text": "true", + "name": "default" + }, + { + "text": "https ://developer.apple.com/documentation/photokit/phpickerconfiguration/assetrepresentationmode/current", + "name": "see" + } + ], + "docs": "Whether to avoid transcoding, if possible.\n\nOn iOS, for example, HEIC images are automatically transcoded to JPEG.\n\nOnly available on iOS.", + "complexTypes": [], + "type": "boolean | undefined" + }, + { + "name": "limit", + "tags": [ + { + "text": "0", + "name": "default" + }, + { + "text": "1", + "name": "example" + }, + { + "text": "5.2.0", + "name": "since" + } + ], + "docs": "The maximum number of files that the user can select.\nSetting this to `0` sets the selection limit to unlimited.\n\nOn Android and Web, only `0` and `1` are supported.", + "complexTypes": [], + "type": "number | undefined" + }, + { + "name": "ordered", + "tags": [ + { + "text": "false", + "name": "default" + }, + { + "text": "5.3.0", + "name": "since" + } + ], + "docs": "Whether an ordered number is displayed instead of a check mark in the selection badge.\n\nOnly available on iOS (15+).", + "complexTypes": [], + "type": "boolean | undefined" + } + ] + }, + { + "name": "RequestPermissionsOptions", + "slug": "requestpermissionsoptions", + "docs": "", + "tags": [ + { + "text": "6.1.0", + "name": "since" + } + ], + "methods": [], + "properties": [ + { + "name": "permissions", + "tags": [ + { + "text": "6.1.0", + "name": "since" + }, + { + "text": "[\"accessMediaLocation\", \"readExternalStorage\"]", + "name": "default" + } + ], + "docs": "The permissions to request.", + "complexTypes": [ + "PermissionType" + ], + "type": "PermissionType[] | undefined" + } + ] + }, + { + "name": "PluginListenerHandle", + "slug": "pluginlistenerhandle", + "docs": "", + "tags": [], + "methods": [], + "properties": [ + { + "name": "remove", + "tags": [], + "docs": "", + "complexTypes": [], + "type": "() => Promise" + } + ] + } + ], + "enums": [], + "typeAliases": [ + { + "name": "PermissionState", + "slug": "permissionstate", + "docs": "", + "types": [ + { + "text": "'prompt'", + "complexTypes": [] + }, + { + "text": "'prompt-with-rationale'", + "complexTypes": [] + }, + { + "text": "'granted'", + "complexTypes": [] + }, + { + "text": "'denied'", + "complexTypes": [] + } + ] + }, + { + "name": "PickImagesOptions", + "slug": "pickimagesoptions", + "docs": "", + "types": [ + { + "text": "PickMediaOptions", + "complexTypes": [ + "PickMediaOptions" + ] + } + ] + }, + { + "name": "PickImagesResult", + "slug": "pickimagesresult", + "docs": "", + "types": [ + { + "text": "PickMediaResult", + "complexTypes": [ + "PickMediaResult" + ] + } + ] + }, + { + "name": "PickMediaResult", + "slug": "pickmediaresult", + "docs": "", + "types": [ + { + "text": "PickFilesResult", + "complexTypes": [ + "PickFilesResult" + ] + } + ] + }, + { + "name": "PickVideosOptions", + "slug": "pickvideosoptions", + "docs": "", + "types": [ + { + "text": "PickMediaOptions", + "complexTypes": [ + "PickMediaOptions" + ] + } + ] + }, + { + "name": "PickVideosResult", + "slug": "pickvideosresult", + "docs": "", + "types": [ + { + "text": "PickMediaResult", + "complexTypes": [ + "PickMediaResult" + ] + } + ] + }, + { + "name": "PermissionType", + "slug": "permissiontype", + "docs": "", + "types": [ + { + "text": "'accessMediaLocation'", + "complexTypes": [] + }, + { + "text": "'readExternalStorage'", + "complexTypes": [] + } + ] + } + ], + "pluginConfigs": [] +} \ No newline at end of file diff --git a/node_modules/@capawesome/capacitor-file-picker/dist/esm/definitions.d.ts b/node_modules/@capawesome/capacitor-file-picker/dist/esm/definitions.d.ts new file mode 100644 index 0000000..6794abd --- /dev/null +++ b/node_modules/@capawesome/capacitor-file-picker/dist/esm/definitions.d.ts @@ -0,0 +1,345 @@ +import type { PluginListenerHandle } from '@capacitor/core'; +export interface FilePickerPlugin { + /** + * Check permissions to access files. + * + * Only available on Android. + * + * @since 6.1.0 + */ + checkPermissions(): Promise; + /** + * Convert a HEIC image to JPEG. + * + * Only available on iOS. + * + * @since 0.6.0 + */ + convertHeicToJpeg(options: ConvertHeicToJpegOptions): Promise; + /** + * Copy a file to a new location. + * + * @since 7.1.0 + */ + copyFile(options: CopyFileOptions): Promise; + /** + * Open the file picker that allows the user to select one or more files. + */ + pickFiles(options?: PickFilesOptions): Promise; + /** + * Open a picker dialog that allows the user to select a directory. + * + * Only available on Android and iOS. + * + * @since 6.2.0 + */ + pickDirectory(): Promise; + /** + * Pick one or more images from the gallery. + * + * On iOS 13 and older it only allows to pick one image. + * + * Only available on Android and iOS. + * + * @since 0.5.3 + */ + pickImages(options?: PickImagesOptions): Promise; + /** + * Pick one or more images or videos from the gallery. + * + * On iOS 13 and older it only allows to pick one image or video. + * + * Only available on Android and iOS. + * + * @since 0.5.3 + */ + pickMedia(options?: PickMediaOptions): Promise; + /** + * Pick one or more videos from the gallery. + * + * On iOS 13 and older it only allows to pick one video. + * + * Only available on Android and iOS. + * + * @since 0.5.3 + */ + pickVideos(options?: PickVideosOptions): Promise; + /** + * Request permissions to access files. + * + * Only available on Android. + * + * @since 6.1.0 + */ + requestPermissions(options?: RequestPermissionsOptions): Promise; + /** + * Called when the file picker is dismissed. + * + * Only available on iOS. + * + * @since 0.6.2 + */ + addListener(eventName: 'pickerDismissed', listenerFunc: () => void): Promise; + /** + * Remove all listeners for this plugin. + * + * @since 0.6.2 + */ + removeAllListeners(): Promise; +} +/** + * @since 0.6.0 + */ +export interface ConvertHeicToJpegOptions { + /** + * The path of the HEIC image. + * + * @example '/path/to/image.heic' + * @since 0.6.0 + */ + path: string; +} +/** + * @since 0.6.0 + */ +export interface ConvertHeicToJpegResult { + /** + * The path of the converted JPEG image. + * + * @example '/path/to/image.jpeg' + * @since 0.6.0 + */ + path: string; +} +/** + * @since 7.1.0 + */ +export interface CopyFileOptions { + /** + * The path of the file to copy. + * + * @example '/path/to/file.txt' + * @since 7.1.0 + */ + from: string; + /** + * Whether to overwrite if the file at destination already exists. + * + * @default true + * @example false + * @since 7.2.0 + */ + overwrite?: boolean; + /** + * The path to copy the file to. + * + * @example '/path/to/new-file.txt' + * @since 7.1.0 + */ + to: string; +} +/** + * @since 6.1.0 + */ +export interface PermissionStatus { + /** + * Permission state for accessing media location. + * + * On Android, this requests/checks the `ACCESS_MEDIA_LOCATION` permission. + * + * @since 6.1.0 + */ + accessMediaLocation: PermissionState; + /** + * Permission state for reading external storage. + * + * On Android, this requests/checks the `READ_EXTERNAL_STORAGE` permission. + * + * @since 6.1.0 + */ + readExternalStorage: PermissionState; +} +export interface PickFilesOptions { + /** + * List of accepted file types. + * Look at [IANA Media Types](https://www.iana.org/assignments/media-types/media-types.xhtml) for a complete list of standard media types. + * + * This option is ignored if `limit` is set. + * + * @example ['image/png', 'application/pdf'] + */ + types?: string[]; + /** + * The maximum number of files that the user can select. + * Setting this to `0` sets the selection limit to unlimited. + * + * Currently, only `0` and `1` are supported. + * + * @default 0 + * @example 1 + * @since 6.0.0 + */ + limit?: number; + /** + * Whether to read the file data. + * + * **Attention**: Reading large files can lead to app crashes. + * It's therefore not recommended to use this option. + * Instead, use the [fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch) + * to load the file as a blob, see [this example](https://capawesome.io/blog/the-file-handling-guide-for-capacitor/#read-a-file). + * + * @default false + */ + readData?: boolean; +} +export interface PickFilesResult { + files: PickedFile[]; +} +export interface PickedFile { + /** + * The Blob instance of the file. + * + * Only available on Web. + */ + blob?: Blob; + /** + * The Base64 string representation of the data contained in the file. + * + * Is only provided if `readData` is set to `true`. + */ + data?: string; + /** + * The duration of the video in seconds. + * + * Only available on Android and iOS. + * + * @since 0.5.3 + */ + duration?: number; + /** + * The height of the image or video in pixels. + * + * Only available on Android and iOS. + * + * @since 0.5.3 + */ + height?: number; + /** + * The mime type of the file. + */ + mimeType: string; + /** + * The last modified timestamp of the file in milliseconds. + * + * @since 0.5.9 + */ + modifiedAt?: number; + /** + * The name of the file. + */ + name: string; + /** + * The path of the file. + * + * Only available on Android and iOS. + */ + path?: string; + /** + * The size of the file in bytes. + */ + size: number; + /** + * The width of the image or video in pixels. + * + * Only available on Android and iOS. + * + * @since 0.5.3 + */ + width?: number; +} +/** + * @since 0.5.3 + */ +export interface PickMediaOptions { + /** + * Whether to read the file data. + * + * @default false + */ + readData?: boolean; + /** + * Whether to avoid transcoding, if possible. + * + * On iOS, for example, HEIC images are automatically transcoded to JPEG. + * + * Only available on iOS. + * + * @default true + * @see https://developer.apple.com/documentation/photokit/phpickerconfiguration/assetrepresentationmode/current + */ + skipTranscoding?: boolean; + /** + * The maximum number of files that the user can select. + * Setting this to `0` sets the selection limit to unlimited. + * + * On Android and Web, only `0` and `1` are supported. + * + * @default 0 + * @example 1 + * @since 5.2.0 + */ + limit?: number; + /** + * Whether an ordered number is displayed instead of a check mark in the selection badge. + * + * Only available on iOS (15+). + * + * @default false + * @since 5.3.0 + */ + ordered?: boolean; +} +export interface PickDirectoryResult { + /** + * The path to the selected directory. + * + * @since 6.2.0 + */ + path: string; +} +/** + * @since 0.5.3 + */ +export type PickMediaResult = PickFilesResult; +/** + * @since 0.5.3 + */ +export type PickImagesOptions = PickMediaOptions; +/** + * @since 0.5.3 + */ +export type PickImagesResult = PickMediaResult; +/** + * @since 0.5.3 + */ +export type PickVideosOptions = PickMediaOptions; +/** + * @since 0.5.3 + */ +export type PickVideosResult = PickMediaResult; +/** + * @since 6.1.0 + */ +export interface RequestPermissionsOptions { + /** + * The permissions to request. + * + * @since 6.1.0 + * @default ["accessMediaLocation", "readExternalStorage"] + */ + permissions?: PermissionType[]; +} +/** + * @since 6.1.0 + */ +export type PermissionType = 'accessMediaLocation' | 'readExternalStorage'; diff --git a/node_modules/@capawesome/capacitor-file-picker/dist/esm/definitions.js b/node_modules/@capawesome/capacitor-file-picker/dist/esm/definitions.js new file mode 100644 index 0000000..497acb5 --- /dev/null +++ b/node_modules/@capawesome/capacitor-file-picker/dist/esm/definitions.js @@ -0,0 +1,2 @@ +export {}; +//# sourceMappingURL=definitions.js.map \ No newline at end of file diff --git a/node_modules/@capawesome/capacitor-file-picker/dist/esm/definitions.js.map b/node_modules/@capawesome/capacitor-file-picker/dist/esm/definitions.js.map new file mode 100644 index 0000000..f6d421a --- /dev/null +++ b/node_modules/@capawesome/capacitor-file-picker/dist/esm/definitions.js.map @@ -0,0 +1 @@ +{"version":3,"file":"definitions.js","sourceRoot":"","sources":["../../src/definitions.ts"],"names":[],"mappings":"","sourcesContent":["import type { PluginListenerHandle } from '@capacitor/core';\n\nexport interface FilePickerPlugin {\n /**\n * Check permissions to access files.\n *\n * Only available on Android.\n *\n * @since 6.1.0\n */\n checkPermissions(): Promise;\n /**\n * Convert a HEIC image to JPEG.\n *\n * Only available on iOS.\n *\n * @since 0.6.0\n */\n convertHeicToJpeg(\n options: ConvertHeicToJpegOptions,\n ): Promise;\n /**\n * Copy a file to a new location.\n *\n * @since 7.1.0\n */\n copyFile(options: CopyFileOptions): Promise;\n /**\n * Open the file picker that allows the user to select one or more files.\n */\n pickFiles(options?: PickFilesOptions): Promise;\n /**\n * Open a picker dialog that allows the user to select a directory.\n *\n * Only available on Android and iOS.\n *\n * @since 6.2.0\n */\n pickDirectory(): Promise;\n /**\n * Pick one or more images from the gallery.\n *\n * On iOS 13 and older it only allows to pick one image.\n *\n * Only available on Android and iOS.\n *\n * @since 0.5.3\n */\n pickImages(options?: PickImagesOptions): Promise;\n /**\n * Pick one or more images or videos from the gallery.\n *\n * On iOS 13 and older it only allows to pick one image or video.\n *\n * Only available on Android and iOS.\n *\n * @since 0.5.3\n */\n pickMedia(options?: PickMediaOptions): Promise;\n /**\n * Pick one or more videos from the gallery.\n *\n * On iOS 13 and older it only allows to pick one video.\n *\n * Only available on Android and iOS.\n *\n * @since 0.5.3\n */\n pickVideos(options?: PickVideosOptions): Promise;\n /**\n * Request permissions to access files.\n *\n * Only available on Android.\n *\n * @since 6.1.0\n */\n requestPermissions(\n options?: RequestPermissionsOptions,\n ): Promise;\n /**\n * Called when the file picker is dismissed.\n *\n * Only available on iOS.\n *\n * @since 0.6.2\n */\n addListener(\n eventName: 'pickerDismissed',\n listenerFunc: () => void,\n ): Promise;\n /**\n * Remove all listeners for this plugin.\n *\n * @since 0.6.2\n */\n removeAllListeners(): Promise;\n}\n\n/**\n * @since 0.6.0\n */\nexport interface ConvertHeicToJpegOptions {\n /**\n * The path of the HEIC image.\n *\n * @example '/path/to/image.heic'\n * @since 0.6.0\n */\n path: string;\n}\n\n/**\n * @since 0.6.0\n */\nexport interface ConvertHeicToJpegResult {\n /**\n * The path of the converted JPEG image.\n *\n * @example '/path/to/image.jpeg'\n * @since 0.6.0\n */\n path: string;\n}\n\n/**\n * @since 7.1.0\n */\nexport interface CopyFileOptions {\n /**\n * The path of the file to copy.\n *\n * @example '/path/to/file.txt'\n * @since 7.1.0\n */\n from: string;\n /**\n * Whether to overwrite if the file at destination already exists.\n *\n * @default true\n * @example false\n * @since 7.2.0\n */\n overwrite?: boolean;\n /**\n * The path to copy the file to.\n *\n * @example '/path/to/new-file.txt'\n * @since 7.1.0\n */\n to: string;\n}\n\n/**\n * @since 6.1.0\n */\nexport interface PermissionStatus {\n /**\n * Permission state for accessing media location.\n *\n * On Android, this requests/checks the `ACCESS_MEDIA_LOCATION` permission.\n *\n * @since 6.1.0\n */\n accessMediaLocation: PermissionState;\n /**\n * Permission state for reading external storage.\n *\n * On Android, this requests/checks the `READ_EXTERNAL_STORAGE` permission.\n *\n * @since 6.1.0\n */\n readExternalStorage: PermissionState;\n}\n\nexport interface PickFilesOptions {\n /**\n * List of accepted file types.\n * Look at [IANA Media Types](https://www.iana.org/assignments/media-types/media-types.xhtml) for a complete list of standard media types.\n *\n * This option is ignored if `limit` is set.\n *\n * @example ['image/png', 'application/pdf']\n */\n types?: string[];\n /**\n * The maximum number of files that the user can select.\n * Setting this to `0` sets the selection limit to unlimited.\n *\n * Currently, only `0` and `1` are supported.\n *\n * @default 0\n * @example 1\n * @since 6.0.0\n */\n limit?: number;\n /**\n * Whether to read the file data.\n *\n * **Attention**: Reading large files can lead to app crashes.\n * It's therefore not recommended to use this option.\n * Instead, use the [fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch)\n * to load the file as a blob, see [this example](https://capawesome.io/blog/the-file-handling-guide-for-capacitor/#read-a-file).\n *\n * @default false\n */\n readData?: boolean;\n}\n\nexport interface PickFilesResult {\n files: PickedFile[];\n}\n\nexport interface PickedFile {\n /**\n * The Blob instance of the file.\n *\n * Only available on Web.\n */\n blob?: Blob;\n /**\n * The Base64 string representation of the data contained in the file.\n *\n * Is only provided if `readData` is set to `true`.\n */\n data?: string;\n /**\n * The duration of the video in seconds.\n *\n * Only available on Android and iOS.\n *\n * @since 0.5.3\n */\n duration?: number;\n /**\n * The height of the image or video in pixels.\n *\n * Only available on Android and iOS.\n *\n * @since 0.5.3\n */\n height?: number;\n /**\n * The mime type of the file.\n */\n mimeType: string;\n /**\n * The last modified timestamp of the file in milliseconds.\n *\n * @since 0.5.9\n */\n modifiedAt?: number;\n /**\n * The name of the file.\n */\n name: string;\n /**\n * The path of the file.\n *\n * Only available on Android and iOS.\n */\n path?: string;\n /**\n * The size of the file in bytes.\n */\n size: number;\n /**\n * The width of the image or video in pixels.\n *\n * Only available on Android and iOS.\n *\n * @since 0.5.3\n */\n width?: number;\n}\n\n/**\n * @since 0.5.3\n */\nexport interface PickMediaOptions {\n /**\n * Whether to read the file data.\n *\n * @default false\n */\n readData?: boolean;\n /**\n * Whether to avoid transcoding, if possible.\n *\n * On iOS, for example, HEIC images are automatically transcoded to JPEG.\n *\n * Only available on iOS.\n *\n * @default true\n * @see https://developer.apple.com/documentation/photokit/phpickerconfiguration/assetrepresentationmode/current\n */\n skipTranscoding?: boolean;\n /**\n * The maximum number of files that the user can select.\n * Setting this to `0` sets the selection limit to unlimited.\n *\n * On Android and Web, only `0` and `1` are supported.\n *\n * @default 0\n * @example 1\n * @since 5.2.0\n */\n limit?: number;\n /**\n * Whether an ordered number is displayed instead of a check mark in the selection badge.\n *\n * Only available on iOS (15+).\n *\n * @default false\n * @since 5.3.0\n */\n ordered?: boolean;\n}\n\nexport interface PickDirectoryResult {\n /**\n * The path to the selected directory.\n *\n * @since 6.2.0\n */\n path: string;\n}\n\n/**\n * @since 0.5.3\n */\nexport type PickMediaResult = PickFilesResult;\n\n/**\n * @since 0.5.3\n */\nexport type PickImagesOptions = PickMediaOptions;\n\n/**\n * @since 0.5.3\n */\nexport type PickImagesResult = PickMediaResult;\n\n/**\n * @since 0.5.3\n */\nexport type PickVideosOptions = PickMediaOptions;\n\n/**\n * @since 0.5.3\n */\nexport type PickVideosResult = PickMediaResult;\n\n/**\n * @since 6.1.0\n */\nexport interface RequestPermissionsOptions {\n /**\n * The permissions to request.\n *\n * @since 6.1.0\n * @default [\"accessMediaLocation\", \"readExternalStorage\"]\n */\n permissions?: PermissionType[];\n}\n\n/**\n * @since 6.1.0\n */\nexport type PermissionType = 'accessMediaLocation' | 'readExternalStorage';\n"]} \ No newline at end of file diff --git a/node_modules/@capawesome/capacitor-file-picker/dist/esm/index.d.ts b/node_modules/@capawesome/capacitor-file-picker/dist/esm/index.d.ts new file mode 100644 index 0000000..2d93eb8 --- /dev/null +++ b/node_modules/@capawesome/capacitor-file-picker/dist/esm/index.d.ts @@ -0,0 +1,4 @@ +import type { FilePickerPlugin } from './definitions'; +declare const FilePicker: FilePickerPlugin; +export * from './definitions'; +export { FilePicker }; diff --git a/node_modules/@capawesome/capacitor-file-picker/dist/esm/index.js b/node_modules/@capawesome/capacitor-file-picker/dist/esm/index.js new file mode 100644 index 0000000..f2653d5 --- /dev/null +++ b/node_modules/@capawesome/capacitor-file-picker/dist/esm/index.js @@ -0,0 +1,9 @@ +import { registerPlugin } from '@capacitor/core'; +// See https://github.com/capawesome-team/capacitor-plugins/issues/14 +import * as web from './web'; +const FilePicker = registerPlugin('FilePicker', { + web: () => new web.FilePickerWeb(), +}); +export * from './definitions'; +export { FilePicker }; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/node_modules/@capawesome/capacitor-file-picker/dist/esm/index.js.map b/node_modules/@capawesome/capacitor-file-picker/dist/esm/index.js.map new file mode 100644 index 0000000..6eae421 --- /dev/null +++ b/node_modules/@capawesome/capacitor-file-picker/dist/esm/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAGjD,qEAAqE;AACrE,OAAO,KAAK,GAAG,MAAM,OAAO,CAAC;AAE7B,MAAM,UAAU,GAAG,cAAc,CAAmB,YAAY,EAAE;IAChE,GAAG,EAAE,GAAG,EAAE,CAAC,IAAI,GAAG,CAAC,aAAa,EAAE;CACnC,CAAC,CAAC;AAEH,cAAc,eAAe,CAAC;AAC9B,OAAO,EAAE,UAAU,EAAE,CAAC","sourcesContent":["import { registerPlugin } from '@capacitor/core';\n\nimport type { FilePickerPlugin } from './definitions';\n// See https://github.com/capawesome-team/capacitor-plugins/issues/14\nimport * as web from './web';\n\nconst FilePicker = registerPlugin('FilePicker', {\n web: () => new web.FilePickerWeb(),\n});\n\nexport * from './definitions';\nexport { FilePicker };\n"]} \ No newline at end of file diff --git a/node_modules/@capawesome/capacitor-file-picker/dist/esm/web.d.ts b/node_modules/@capawesome/capacitor-file-picker/dist/esm/web.d.ts new file mode 100644 index 0000000..bd15a9c --- /dev/null +++ b/node_modules/@capawesome/capacitor-file-picker/dist/esm/web.d.ts @@ -0,0 +1,20 @@ +import { WebPlugin } from '@capacitor/core'; +import type { ConvertHeicToJpegOptions, ConvertHeicToJpegResult, CopyFileOptions, FilePickerPlugin, PermissionStatus, PickDirectoryResult, PickFilesOptions, PickFilesResult, PickImagesOptions, PickImagesResult, PickMediaOptions, PickMediaResult, PickVideosOptions, PickVideosResult, RequestPermissionsOptions } from './definitions'; +export declare class FilePickerWeb extends WebPlugin implements FilePickerPlugin { + readonly ERROR_PICK_FILE_CANCELED = "pickFiles canceled."; + checkPermissions(): Promise; + convertHeicToJpeg(_options: ConvertHeicToJpegOptions): Promise; + copyFile(_options: CopyFileOptions): Promise; + pickFiles(options?: PickFilesOptions): Promise; + pickDirectory(): Promise; + pickImages(options?: PickImagesOptions): Promise; + pickMedia(options?: PickMediaOptions): Promise; + pickVideos(options?: PickVideosOptions): Promise; + requestPermissions(_options?: RequestPermissionsOptions): Promise; + private openFilePicker; + private getDataFromFile; + private getNameFromUrl; + private getMimeTypeFromUrl; + private getSizeFromUrl; + private wait; +} diff --git a/node_modules/@capawesome/capacitor-file-picker/dist/esm/web.js b/node_modules/@capawesome/capacitor-file-picker/dist/esm/web.js new file mode 100644 index 0000000..c393a82 --- /dev/null +++ b/node_modules/@capawesome/capacitor-file-picker/dist/esm/web.js @@ -0,0 +1,132 @@ +import { WebPlugin } from '@capacitor/core'; +export class FilePickerWeb extends WebPlugin { + constructor() { + super(...arguments); + this.ERROR_PICK_FILE_CANCELED = 'pickFiles canceled.'; + } + async checkPermissions() { + throw this.unimplemented('Not implemented on web.'); + } + async convertHeicToJpeg(_options) { + throw this.unimplemented('Not implemented on web.'); + } + async copyFile(_options) { + throw this.unimplemented('Not implemented on web.'); + } + async pickFiles(options) { + const pickedFiles = await this.openFilePicker(options); + if (!pickedFiles) { + throw new Error(this.ERROR_PICK_FILE_CANCELED); + } + const result = { + files: [], + }; + for (const pickedFile of pickedFiles) { + const file = { + blob: pickedFile, + modifiedAt: pickedFile.lastModified, + mimeType: this.getMimeTypeFromUrl(pickedFile), + name: this.getNameFromUrl(pickedFile), + path: undefined, + size: this.getSizeFromUrl(pickedFile), + }; + if (options === null || options === void 0 ? void 0 : options.readData) { + file.data = await this.getDataFromFile(pickedFile); + } + result.files.push(file); + } + return result; + } + async pickDirectory() { + throw this.unimplemented('Not implemented on web.'); + } + async pickImages(options) { + return this.pickFiles(Object.assign({ types: ['image/*'] }, options)); + } + async pickMedia(options) { + return this.pickFiles(Object.assign({ types: ['image/*', 'video/*'] }, options)); + } + async pickVideos(options) { + return this.pickFiles(Object.assign({ types: ['video/*'] }, options)); + } + async requestPermissions(_options) { + throw this.unimplemented('Not implemented on web.'); + } + async openFilePicker(options) { + var _a; + const accept = ((_a = options === null || options === void 0 ? void 0 : options.types) === null || _a === void 0 ? void 0 : _a.join(',')) || ''; + const limit = (options === null || options === void 0 ? void 0 : options.limit) === undefined ? 0 : options.limit; + return new Promise(resolve => { + let onChangeFired = false; + const input = document.createElement('input'); + input.type = 'file'; + input.accept = accept; + input.multiple = limit === 0; + const hasCancelEvent = 'oncancel' in input; + const onChangeHandler = () => { + onChangeFired = true; + removeAllListeners(); + const files = Array.from(input.files || []); + resolve(files); + }; + const onCancelHandler = () => { + removeAllListeners(); + resolve(undefined); + }; + const onFocusHandler = async () => { + await this.wait(500); + if (onChangeFired) { + return; + } + removeAllListeners(); + resolve(undefined); + }; + const removeAllListeners = () => { + input.removeEventListener('change', onChangeHandler); + if (hasCancelEvent) { + input.removeEventListener('cancel', onCancelHandler); + } + else { + window.removeEventListener('focus', onFocusHandler); + } + }; + input.addEventListener('change', onChangeHandler, { once: true }); + if (hasCancelEvent) { + input.addEventListener('cancel', onCancelHandler, { once: true }); + } + else { + // Workaround to detect when Cancel is selected in the File Selection dialog box. + window.addEventListener('focus', onFocusHandler, { once: true }); + } + input.click(); + }); + } + async getDataFromFile(file) { + return new Promise((resolve, reject) => { + const reader = new FileReader(); + reader.readAsDataURL(file); + reader.onload = () => { + const result = typeof reader.result === 'string' ? reader.result : ''; + const splittedResult = result.split('base64,'); + const base64 = splittedResult[1] || ''; + resolve(base64); + }; + reader.onerror = error => { + reject(error); + }; + }); + } + getNameFromUrl(file) { + return file.name; + } + getMimeTypeFromUrl(file) { + return file.type; + } + getSizeFromUrl(file) { + return file.size; + } + async wait(delayMs) { + return new Promise(resolve => setTimeout(resolve, delayMs)); + } +} +//# sourceMappingURL=web.js.map \ No newline at end of file diff --git a/node_modules/@capawesome/capacitor-file-picker/dist/esm/web.js.map b/node_modules/@capawesome/capacitor-file-picker/dist/esm/web.js.map new file mode 100644 index 0000000..694e062 --- /dev/null +++ b/node_modules/@capawesome/capacitor-file-picker/dist/esm/web.js.map @@ -0,0 +1 @@ +{"version":3,"file":"web.js","sourceRoot":"","sources":["../../src/web.ts"],"names":[],"mappings":"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","sourcesContent":["import { WebPlugin } from '@capacitor/core';\n\nimport type {\n ConvertHeicToJpegOptions,\n ConvertHeicToJpegResult,\n CopyFileOptions,\n FilePickerPlugin,\n PermissionStatus,\n PickDirectoryResult,\n PickFilesOptions,\n PickFilesResult,\n PickImagesOptions,\n PickImagesResult,\n PickMediaOptions,\n PickMediaResult,\n PickVideosOptions,\n PickVideosResult,\n PickedFile,\n RequestPermissionsOptions,\n} from './definitions';\n\nexport class FilePickerWeb extends WebPlugin implements FilePickerPlugin {\n public readonly ERROR_PICK_FILE_CANCELED = 'pickFiles canceled.';\n\n public async checkPermissions(): Promise {\n throw this.unimplemented('Not implemented on web.');\n }\n\n public async convertHeicToJpeg(\n _options: ConvertHeicToJpegOptions,\n ): Promise {\n throw this.unimplemented('Not implemented on web.');\n }\n\n public async copyFile(_options: CopyFileOptions): Promise {\n throw this.unimplemented('Not implemented on web.');\n }\n\n public async pickFiles(options?: PickFilesOptions): Promise {\n const pickedFiles = await this.openFilePicker(options);\n if (!pickedFiles) {\n throw new Error(this.ERROR_PICK_FILE_CANCELED);\n }\n const result: PickFilesResult = {\n files: [],\n };\n for (const pickedFile of pickedFiles) {\n const file: PickedFile = {\n blob: pickedFile,\n modifiedAt: pickedFile.lastModified,\n mimeType: this.getMimeTypeFromUrl(pickedFile),\n name: this.getNameFromUrl(pickedFile),\n path: undefined,\n size: this.getSizeFromUrl(pickedFile),\n };\n if (options?.readData) {\n file.data = await this.getDataFromFile(pickedFile);\n }\n result.files.push(file);\n }\n return result;\n }\n\n public async pickDirectory(): Promise {\n throw this.unimplemented('Not implemented on web.');\n }\n\n public async pickImages(\n options?: PickImagesOptions,\n ): Promise {\n return this.pickFiles({ types: ['image/*'], ...options });\n }\n\n public async pickMedia(options?: PickMediaOptions): Promise {\n return this.pickFiles({ types: ['image/*', 'video/*'], ...options });\n }\n\n public async pickVideos(\n options?: PickVideosOptions,\n ): Promise {\n return this.pickFiles({ types: ['video/*'], ...options });\n }\n\n public async requestPermissions(\n _options?: RequestPermissionsOptions,\n ): Promise {\n throw this.unimplemented('Not implemented on web.');\n }\n\n private async openFilePicker(\n options?: PickFilesOptions,\n ): Promise {\n const accept = options?.types?.join(',') || '';\n const limit = options?.limit === undefined ? 0 : options.limit;\n return new Promise(resolve => {\n let onChangeFired = false;\n const input = document.createElement('input');\n input.type = 'file';\n input.accept = accept;\n input.multiple = limit === 0;\n\n const hasCancelEvent = 'oncancel' in input;\n\n const onChangeHandler = () => {\n onChangeFired = true;\n removeAllListeners();\n\n const files = Array.from(input.files || []);\n resolve(files);\n };\n const onCancelHandler = () => {\n removeAllListeners();\n resolve(undefined);\n };\n const onFocusHandler = async () => {\n await this.wait(500);\n if (onChangeFired) {\n return;\n }\n removeAllListeners();\n resolve(undefined);\n };\n const removeAllListeners = () => {\n input.removeEventListener('change', onChangeHandler);\n if (hasCancelEvent) {\n input.removeEventListener('cancel', onCancelHandler);\n } else {\n window.removeEventListener('focus', onFocusHandler);\n }\n };\n\n input.addEventListener('change', onChangeHandler, { once: true });\n if (hasCancelEvent) {\n input.addEventListener('cancel', onCancelHandler, { once: true });\n } else {\n // Workaround to detect when Cancel is selected in the File Selection dialog box.\n window.addEventListener('focus', onFocusHandler, { once: true });\n }\n input.click();\n });\n }\n\n private async getDataFromFile(file: File): Promise {\n return new Promise((resolve, reject) => {\n const reader = new FileReader();\n reader.readAsDataURL(file);\n reader.onload = () => {\n const result = typeof reader.result === 'string' ? reader.result : '';\n const splittedResult = result.split('base64,');\n const base64 = splittedResult[1] || '';\n resolve(base64);\n };\n reader.onerror = error => {\n reject(error);\n };\n });\n }\n\n private getNameFromUrl(file: File): string {\n return file.name;\n }\n\n private getMimeTypeFromUrl(file: File): string {\n return file.type;\n }\n\n private getSizeFromUrl(file: File): number {\n return file.size;\n }\n\n private async wait(delayMs: number): Promise {\n return new Promise(resolve => setTimeout(resolve, delayMs));\n }\n}\n"]} \ No newline at end of file diff --git a/node_modules/@capawesome/capacitor-file-picker/dist/plugin.cjs.js b/node_modules/@capawesome/capacitor-file-picker/dist/plugin.cjs.js new file mode 100644 index 0000000..3d2efe4 --- /dev/null +++ b/node_modules/@capawesome/capacitor-file-picker/dist/plugin.cjs.js @@ -0,0 +1,141 @@ +'use strict'; + +var core = require('@capacitor/core'); + +class FilePickerWeb extends core.WebPlugin { + constructor() { + super(...arguments); + this.ERROR_PICK_FILE_CANCELED = 'pickFiles canceled.'; + } + async checkPermissions() { + throw this.unimplemented('Not implemented on web.'); + } + async convertHeicToJpeg(_options) { + throw this.unimplemented('Not implemented on web.'); + } + async copyFile(_options) { + throw this.unimplemented('Not implemented on web.'); + } + async pickFiles(options) { + const pickedFiles = await this.openFilePicker(options); + if (!pickedFiles) { + throw new Error(this.ERROR_PICK_FILE_CANCELED); + } + const result = { + files: [], + }; + for (const pickedFile of pickedFiles) { + const file = { + blob: pickedFile, + modifiedAt: pickedFile.lastModified, + mimeType: this.getMimeTypeFromUrl(pickedFile), + name: this.getNameFromUrl(pickedFile), + path: undefined, + size: this.getSizeFromUrl(pickedFile), + }; + if (options === null || options === void 0 ? void 0 : options.readData) { + file.data = await this.getDataFromFile(pickedFile); + } + result.files.push(file); + } + return result; + } + async pickDirectory() { + throw this.unimplemented('Not implemented on web.'); + } + async pickImages(options) { + return this.pickFiles(Object.assign({ types: ['image/*'] }, options)); + } + async pickMedia(options) { + return this.pickFiles(Object.assign({ types: ['image/*', 'video/*'] }, options)); + } + async pickVideos(options) { + return this.pickFiles(Object.assign({ types: ['video/*'] }, options)); + } + async requestPermissions(_options) { + throw this.unimplemented('Not implemented on web.'); + } + async openFilePicker(options) { + var _a; + const accept = ((_a = options === null || options === void 0 ? void 0 : options.types) === null || _a === void 0 ? void 0 : _a.join(',')) || ''; + const limit = (options === null || options === void 0 ? void 0 : options.limit) === undefined ? 0 : options.limit; + return new Promise(resolve => { + let onChangeFired = false; + const input = document.createElement('input'); + input.type = 'file'; + input.accept = accept; + input.multiple = limit === 0; + const hasCancelEvent = 'oncancel' in input; + const onChangeHandler = () => { + onChangeFired = true; + removeAllListeners(); + const files = Array.from(input.files || []); + resolve(files); + }; + const onCancelHandler = () => { + removeAllListeners(); + resolve(undefined); + }; + const onFocusHandler = async () => { + await this.wait(500); + if (onChangeFired) { + return; + } + removeAllListeners(); + resolve(undefined); + }; + const removeAllListeners = () => { + input.removeEventListener('change', onChangeHandler); + if (hasCancelEvent) { + input.removeEventListener('cancel', onCancelHandler); + } + else { + window.removeEventListener('focus', onFocusHandler); + } + }; + input.addEventListener('change', onChangeHandler, { once: true }); + if (hasCancelEvent) { + input.addEventListener('cancel', onCancelHandler, { once: true }); + } + else { + // Workaround to detect when Cancel is selected in the File Selection dialog box. + window.addEventListener('focus', onFocusHandler, { once: true }); + } + input.click(); + }); + } + async getDataFromFile(file) { + return new Promise((resolve, reject) => { + const reader = new FileReader(); + reader.readAsDataURL(file); + reader.onload = () => { + const result = typeof reader.result === 'string' ? reader.result : ''; + const splittedResult = result.split('base64,'); + const base64 = splittedResult[1] || ''; + resolve(base64); + }; + reader.onerror = error => { + reject(error); + }; + }); + } + getNameFromUrl(file) { + return file.name; + } + getMimeTypeFromUrl(file) { + return file.type; + } + getSizeFromUrl(file) { + return file.size; + } + async wait(delayMs) { + return new Promise(resolve => setTimeout(resolve, delayMs)); + } +} + +const FilePicker = core.registerPlugin('FilePicker', { + web: () => new FilePickerWeb(), +}); + +exports.FilePicker = FilePicker; +//# sourceMappingURL=plugin.cjs.js.map diff --git a/node_modules/@capawesome/capacitor-file-picker/dist/plugin.cjs.js.map b/node_modules/@capawesome/capacitor-file-picker/dist/plugin.cjs.js.map new file mode 100644 index 0000000..24b60d7 --- /dev/null +++ b/node_modules/@capawesome/capacitor-file-picker/dist/plugin.cjs.js.map @@ -0,0 +1 @@ +{"version":3,"file":"plugin.cjs.js","sources":["esm/web.js","esm/index.js"],"sourcesContent":["import { WebPlugin } from '@capacitor/core';\nexport class FilePickerWeb extends WebPlugin {\n constructor() {\n super(...arguments);\n this.ERROR_PICK_FILE_CANCELED = 'pickFiles canceled.';\n }\n async checkPermissions() {\n throw this.unimplemented('Not implemented on web.');\n }\n async convertHeicToJpeg(_options) {\n throw this.unimplemented('Not implemented on web.');\n }\n async copyFile(_options) {\n throw this.unimplemented('Not implemented on web.');\n }\n async pickFiles(options) {\n const pickedFiles = await this.openFilePicker(options);\n if (!pickedFiles) {\n throw new Error(this.ERROR_PICK_FILE_CANCELED);\n }\n const result = {\n files: [],\n };\n for (const pickedFile of pickedFiles) {\n const file = {\n blob: pickedFile,\n modifiedAt: pickedFile.lastModified,\n mimeType: this.getMimeTypeFromUrl(pickedFile),\n name: this.getNameFromUrl(pickedFile),\n path: undefined,\n size: this.getSizeFromUrl(pickedFile),\n };\n if (options === null || options === void 0 ? void 0 : options.readData) {\n file.data = await this.getDataFromFile(pickedFile);\n }\n result.files.push(file);\n }\n return result;\n }\n async pickDirectory() {\n throw this.unimplemented('Not implemented on web.');\n }\n async pickImages(options) {\n return this.pickFiles(Object.assign({ types: ['image/*'] }, options));\n }\n async pickMedia(options) {\n return this.pickFiles(Object.assign({ types: ['image/*', 'video/*'] }, options));\n }\n async pickVideos(options) {\n return this.pickFiles(Object.assign({ types: ['video/*'] }, options));\n }\n async requestPermissions(_options) {\n throw this.unimplemented('Not implemented on web.');\n }\n async openFilePicker(options) {\n var _a;\n const accept = ((_a = options === null || options === void 0 ? void 0 : options.types) === null || _a === void 0 ? void 0 : _a.join(',')) || '';\n const limit = (options === null || options === void 0 ? void 0 : options.limit) === undefined ? 0 : options.limit;\n return new Promise(resolve => {\n let onChangeFired = false;\n const input = document.createElement('input');\n input.type = 'file';\n input.accept = accept;\n input.multiple = limit === 0;\n const hasCancelEvent = 'oncancel' in input;\n const onChangeHandler = () => {\n onChangeFired = true;\n removeAllListeners();\n const files = Array.from(input.files || []);\n resolve(files);\n };\n const onCancelHandler = () => {\n removeAllListeners();\n resolve(undefined);\n };\n const onFocusHandler = async () => {\n await this.wait(500);\n if (onChangeFired) {\n return;\n }\n removeAllListeners();\n resolve(undefined);\n };\n const removeAllListeners = () => {\n input.removeEventListener('change', onChangeHandler);\n if (hasCancelEvent) {\n input.removeEventListener('cancel', onCancelHandler);\n }\n else {\n window.removeEventListener('focus', onFocusHandler);\n }\n };\n input.addEventListener('change', onChangeHandler, { once: true });\n if (hasCancelEvent) {\n input.addEventListener('cancel', onCancelHandler, { once: true });\n }\n else {\n // Workaround to detect when Cancel is selected in the File Selection dialog box.\n window.addEventListener('focus', onFocusHandler, { once: true });\n }\n input.click();\n });\n }\n async getDataFromFile(file) {\n return new Promise((resolve, reject) => {\n const reader = new FileReader();\n reader.readAsDataURL(file);\n reader.onload = () => {\n const result = typeof reader.result === 'string' ? reader.result : '';\n const splittedResult = result.split('base64,');\n const base64 = splittedResult[1] || '';\n resolve(base64);\n };\n reader.onerror = error => {\n reject(error);\n };\n });\n }\n getNameFromUrl(file) {\n return file.name;\n }\n getMimeTypeFromUrl(file) {\n return file.type;\n }\n getSizeFromUrl(file) {\n return file.size;\n }\n async wait(delayMs) {\n return new Promise(resolve => setTimeout(resolve, delayMs));\n }\n}\n//# sourceMappingURL=web.js.map","import { registerPlugin } from '@capacitor/core';\n// See https://github.com/capawesome-team/capacitor-plugins/issues/14\nimport * as web from './web';\nconst FilePicker = registerPlugin('FilePicker', {\n web: () => new web.FilePickerWeb(),\n});\nexport * from './definitions';\nexport { FilePicker };\n//# sourceMappingURL=index.js.map"],"names":["WebPlugin","registerPlugin","web.FilePickerWeb"],"mappings":"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"} \ No newline at end of file diff --git a/node_modules/@capawesome/capacitor-file-picker/dist/plugin.js b/node_modules/@capawesome/capacitor-file-picker/dist/plugin.js new file mode 100644 index 0000000..2105627 --- /dev/null +++ b/node_modules/@capawesome/capacitor-file-picker/dist/plugin.js @@ -0,0 +1,144 @@ +var capacitorFilePicker = (function (exports, core) { + 'use strict'; + + class FilePickerWeb extends core.WebPlugin { + constructor() { + super(...arguments); + this.ERROR_PICK_FILE_CANCELED = 'pickFiles canceled.'; + } + async checkPermissions() { + throw this.unimplemented('Not implemented on web.'); + } + async convertHeicToJpeg(_options) { + throw this.unimplemented('Not implemented on web.'); + } + async copyFile(_options) { + throw this.unimplemented('Not implemented on web.'); + } + async pickFiles(options) { + const pickedFiles = await this.openFilePicker(options); + if (!pickedFiles) { + throw new Error(this.ERROR_PICK_FILE_CANCELED); + } + const result = { + files: [], + }; + for (const pickedFile of pickedFiles) { + const file = { + blob: pickedFile, + modifiedAt: pickedFile.lastModified, + mimeType: this.getMimeTypeFromUrl(pickedFile), + name: this.getNameFromUrl(pickedFile), + path: undefined, + size: this.getSizeFromUrl(pickedFile), + }; + if (options === null || options === void 0 ? void 0 : options.readData) { + file.data = await this.getDataFromFile(pickedFile); + } + result.files.push(file); + } + return result; + } + async pickDirectory() { + throw this.unimplemented('Not implemented on web.'); + } + async pickImages(options) { + return this.pickFiles(Object.assign({ types: ['image/*'] }, options)); + } + async pickMedia(options) { + return this.pickFiles(Object.assign({ types: ['image/*', 'video/*'] }, options)); + } + async pickVideos(options) { + return this.pickFiles(Object.assign({ types: ['video/*'] }, options)); + } + async requestPermissions(_options) { + throw this.unimplemented('Not implemented on web.'); + } + async openFilePicker(options) { + var _a; + const accept = ((_a = options === null || options === void 0 ? void 0 : options.types) === null || _a === void 0 ? void 0 : _a.join(',')) || ''; + const limit = (options === null || options === void 0 ? void 0 : options.limit) === undefined ? 0 : options.limit; + return new Promise(resolve => { + let onChangeFired = false; + const input = document.createElement('input'); + input.type = 'file'; + input.accept = accept; + input.multiple = limit === 0; + const hasCancelEvent = 'oncancel' in input; + const onChangeHandler = () => { + onChangeFired = true; + removeAllListeners(); + const files = Array.from(input.files || []); + resolve(files); + }; + const onCancelHandler = () => { + removeAllListeners(); + resolve(undefined); + }; + const onFocusHandler = async () => { + await this.wait(500); + if (onChangeFired) { + return; + } + removeAllListeners(); + resolve(undefined); + }; + const removeAllListeners = () => { + input.removeEventListener('change', onChangeHandler); + if (hasCancelEvent) { + input.removeEventListener('cancel', onCancelHandler); + } + else { + window.removeEventListener('focus', onFocusHandler); + } + }; + input.addEventListener('change', onChangeHandler, { once: true }); + if (hasCancelEvent) { + input.addEventListener('cancel', onCancelHandler, { once: true }); + } + else { + // Workaround to detect when Cancel is selected in the File Selection dialog box. + window.addEventListener('focus', onFocusHandler, { once: true }); + } + input.click(); + }); + } + async getDataFromFile(file) { + return new Promise((resolve, reject) => { + const reader = new FileReader(); + reader.readAsDataURL(file); + reader.onload = () => { + const result = typeof reader.result === 'string' ? reader.result : ''; + const splittedResult = result.split('base64,'); + const base64 = splittedResult[1] || ''; + resolve(base64); + }; + reader.onerror = error => { + reject(error); + }; + }); + } + getNameFromUrl(file) { + return file.name; + } + getMimeTypeFromUrl(file) { + return file.type; + } + getSizeFromUrl(file) { + return file.size; + } + async wait(delayMs) { + return new Promise(resolve => setTimeout(resolve, delayMs)); + } + } + + const FilePicker = core.registerPlugin('FilePicker', { + web: () => new FilePickerWeb(), + }); + + exports.FilePicker = FilePicker; + + return exports; + +})({}, capacitorExports); +//# sourceMappingURL=plugin.js.map diff --git a/node_modules/@capawesome/capacitor-file-picker/dist/plugin.js.map b/node_modules/@capawesome/capacitor-file-picker/dist/plugin.js.map new file mode 100644 index 0000000..3247c06 --- /dev/null +++ b/node_modules/@capawesome/capacitor-file-picker/dist/plugin.js.map @@ -0,0 +1 @@ +{"version":3,"file":"plugin.js","sources":["esm/web.js","esm/index.js"],"sourcesContent":["import { WebPlugin } from '@capacitor/core';\nexport class FilePickerWeb extends WebPlugin {\n constructor() {\n super(...arguments);\n this.ERROR_PICK_FILE_CANCELED = 'pickFiles canceled.';\n }\n async checkPermissions() {\n throw this.unimplemented('Not implemented on web.');\n }\n async convertHeicToJpeg(_options) {\n throw this.unimplemented('Not implemented on web.');\n }\n async copyFile(_options) {\n throw this.unimplemented('Not implemented on web.');\n }\n async pickFiles(options) {\n const pickedFiles = await this.openFilePicker(options);\n if (!pickedFiles) {\n throw new Error(this.ERROR_PICK_FILE_CANCELED);\n }\n const result = {\n files: [],\n };\n for (const pickedFile of pickedFiles) {\n const file = {\n blob: pickedFile,\n modifiedAt: pickedFile.lastModified,\n mimeType: this.getMimeTypeFromUrl(pickedFile),\n name: this.getNameFromUrl(pickedFile),\n path: undefined,\n size: this.getSizeFromUrl(pickedFile),\n };\n if (options === null || options === void 0 ? void 0 : options.readData) {\n file.data = await this.getDataFromFile(pickedFile);\n }\n result.files.push(file);\n }\n return result;\n }\n async pickDirectory() {\n throw this.unimplemented('Not implemented on web.');\n }\n async pickImages(options) {\n return this.pickFiles(Object.assign({ types: ['image/*'] }, options));\n }\n async pickMedia(options) {\n return this.pickFiles(Object.assign({ types: ['image/*', 'video/*'] }, options));\n }\n async pickVideos(options) {\n return this.pickFiles(Object.assign({ types: ['video/*'] }, options));\n }\n async requestPermissions(_options) {\n throw this.unimplemented('Not implemented on web.');\n }\n async openFilePicker(options) {\n var _a;\n const accept = ((_a = options === null || options === void 0 ? void 0 : options.types) === null || _a === void 0 ? void 0 : _a.join(',')) || '';\n const limit = (options === null || options === void 0 ? void 0 : options.limit) === undefined ? 0 : options.limit;\n return new Promise(resolve => {\n let onChangeFired = false;\n const input = document.createElement('input');\n input.type = 'file';\n input.accept = accept;\n input.multiple = limit === 0;\n const hasCancelEvent = 'oncancel' in input;\n const onChangeHandler = () => {\n onChangeFired = true;\n removeAllListeners();\n const files = Array.from(input.files || []);\n resolve(files);\n };\n const onCancelHandler = () => {\n removeAllListeners();\n resolve(undefined);\n };\n const onFocusHandler = async () => {\n await this.wait(500);\n if (onChangeFired) {\n return;\n }\n removeAllListeners();\n resolve(undefined);\n };\n const removeAllListeners = () => {\n input.removeEventListener('change', onChangeHandler);\n if (hasCancelEvent) {\n input.removeEventListener('cancel', onCancelHandler);\n }\n else {\n window.removeEventListener('focus', onFocusHandler);\n }\n };\n input.addEventListener('change', onChangeHandler, { once: true });\n if (hasCancelEvent) {\n input.addEventListener('cancel', onCancelHandler, { once: true });\n }\n else {\n // Workaround to detect when Cancel is selected in the File Selection dialog box.\n window.addEventListener('focus', onFocusHandler, { once: true });\n }\n input.click();\n });\n }\n async getDataFromFile(file) {\n return new Promise((resolve, reject) => {\n const reader = new FileReader();\n reader.readAsDataURL(file);\n reader.onload = () => {\n const result = typeof reader.result === 'string' ? reader.result : '';\n const splittedResult = result.split('base64,');\n const base64 = splittedResult[1] || '';\n resolve(base64);\n };\n reader.onerror = error => {\n reject(error);\n };\n });\n }\n getNameFromUrl(file) {\n return file.name;\n }\n getMimeTypeFromUrl(file) {\n return file.type;\n }\n getSizeFromUrl(file) {\n return file.size;\n }\n async wait(delayMs) {\n return new Promise(resolve => setTimeout(resolve, delayMs));\n }\n}\n//# sourceMappingURL=web.js.map","import { registerPlugin } from '@capacitor/core';\n// See https://github.com/capawesome-team/capacitor-plugins/issues/14\nimport * as web from './web';\nconst FilePicker = registerPlugin('FilePicker', {\n web: () => new web.FilePickerWeb(),\n});\nexport * from './definitions';\nexport { FilePicker };\n//# sourceMappingURL=index.js.map"],"names":["WebPlugin","registerPlugin","web.FilePickerWeb"],"mappings":";;;IACO,MAAM,aAAa,SAASA,cAAS,CAAC;IAC7C,IAAI,WAAW,GAAG;IAClB,QAAQ,KAAK,CAAC,GAAG,SAAS,CAAC;IAC3B,QAAQ,IAAI,CAAC,wBAAwB,GAAG,qBAAqB;IAC7D,IAAI;IACJ,IAAI,MAAM,gBAAgB,GAAG;IAC7B,QAAQ,MAAM,IAAI,CAAC,aAAa,CAAC,yBAAyB,CAAC;IAC3D,IAAI;IACJ,IAAI,MAAM,iBAAiB,CAAC,QAAQ,EAAE;IACtC,QAAQ,MAAM,IAAI,CAAC,aAAa,CAAC,yBAAyB,CAAC;IAC3D,IAAI;IACJ,IAAI,MAAM,QAAQ,CAAC,QAAQ,EAAE;IAC7B,QAAQ,MAAM,IAAI,CAAC,aAAa,CAAC,yBAAyB,CAAC;IAC3D,IAAI;IACJ,IAAI,MAAM,SAAS,CAAC,OAAO,EAAE;IAC7B,QAAQ,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC;IAC9D,QAAQ,IAAI,CAAC,WAAW,EAAE;IAC1B,YAAY,MAAM,IAAI,KAAK,CAAC,IAAI,CAAC,wBAAwB,CAAC;IAC1D,QAAQ;IACR,QAAQ,MAAM,MAAM,GAAG;IACvB,YAAY,KAAK,EAAE,EAAE;IACrB,SAAS;IACT,QAAQ,KAAK,MAAM,UAAU,IAAI,WAAW,EAAE;IAC9C,YAAY,MAAM,IAAI,GAAG;IACzB,gBAAgB,IAAI,EAAE,UAAU;IAChC,gBAAgB,UAAU,EAAE,UAAU,CAAC,YAAY;IACnD,gBAAgB,QAAQ,EAAE,IAAI,CAAC,kBAAkB,CAAC,UAAU,CAAC;IAC7D,gBAAgB,IAAI,EAAE,IAAI,CAAC,cAAc,CAAC,UAAU,CAAC;IACrD,gBAAgB,IAAI,EAAE,SAAS;IAC/B,gBAAgB,IAAI,EAAE,IAAI,CAAC,cAAc,CAAC,UAAU,CAAC;IACrD,aAAa;IACb,YAAY,IAAI,OAAO,KAAK,IAAI,IAAI,OAAO,KAAK,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,QAAQ,EAAE;IACpF,gBAAgB,IAAI,CAAC,IAAI,GAAG,MAAM,IAAI,CAAC,eAAe,CAAC,UAAU,CAAC;IAClE,YAAY;IACZ,YAAY,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC;IACnC,QAAQ;IACR,QAAQ,OAAO,MAAM;IACrB,IAAI;IACJ,IAAI,MAAM,aAAa,GAAG;IAC1B,QAAQ,MAAM,IAAI,CAAC,aAAa,CAAC,yBAAyB,CAAC;IAC3D,IAAI;IACJ,IAAI,MAAM,UAAU,CAAC,OAAO,EAAE;IAC9B,QAAQ,OAAO,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,CAAC,SAAS,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;IAC7E,IAAI;IACJ,IAAI,MAAM,SAAS,CAAC,OAAO,EAAE;IAC7B,QAAQ,OAAO,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,CAAC,SAAS,EAAE,SAAS,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;IACxF,IAAI;IACJ,IAAI,MAAM,UAAU,CAAC,OAAO,EAAE;IAC9B,QAAQ,OAAO,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,CAAC,SAAS,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;IAC7E,IAAI;IACJ,IAAI,MAAM,kBAAkB,CAAC,QAAQ,EAAE;IACvC,QAAQ,MAAM,IAAI,CAAC,aAAa,CAAC,yBAAyB,CAAC;IAC3D,IAAI;IACJ,IAAI,MAAM,cAAc,CAAC,OAAO,EAAE;IAClC,QAAQ,IAAI,EAAE;IACd,QAAQ,MAAM,MAAM,GAAG,CAAC,CAAC,EAAE,GAAG,OAAO,KAAK,IAAI,IAAI,OAAO,KAAK,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,KAAK,MAAM,IAAI,IAAI,EAAE,KAAK,MAAM,GAAG,MAAM,GAAG,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE;IACvJ,QAAQ,MAAM,KAAK,GAAG,CAAC,OAAO,KAAK,IAAI,IAAI,OAAO,KAAK,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,KAAK,MAAM,SAAS,GAAG,CAAC,GAAG,OAAO,CAAC,KAAK;IACzH,QAAQ,OAAO,IAAI,OAAO,CAAC,OAAO,IAAI;IACtC,YAAY,IAAI,aAAa,GAAG,KAAK;IACrC,YAAY,MAAM,KAAK,GAAG,QAAQ,CAAC,aAAa,CAAC,OAAO,CAAC;IACzD,YAAY,KAAK,CAAC,IAAI,GAAG,MAAM;IAC/B,YAAY,KAAK,CAAC,MAAM,GAAG,MAAM;IACjC,YAAY,KAAK,CAAC,QAAQ,GAAG,KAAK,KAAK,CAAC;IACxC,YAAY,MAAM,cAAc,GAAG,UAAU,IAAI,KAAK;IACtD,YAAY,MAAM,eAAe,GAAG,MAAM;IAC1C,gBAAgB,aAAa,GAAG,IAAI;IACpC,gBAAgB,kBAAkB,EAAE;IACpC,gBAAgB,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,IAAI,EAAE,CAAC;IAC3D,gBAAgB,OAAO,CAAC,KAAK,CAAC;IAC9B,YAAY,CAAC;IACb,YAAY,MAAM,eAAe,GAAG,MAAM;IAC1C,gBAAgB,kBAAkB,EAAE;IACpC,gBAAgB,OAAO,CAAC,SAAS,CAAC;IAClC,YAAY,CAAC;IACb,YAAY,MAAM,cAAc,GAAG,YAAY;IAC/C,gBAAgB,MAAM,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC;IACpC,gBAAgB,IAAI,aAAa,EAAE;IACnC,oBAAoB;IACpB,gBAAgB;IAChB,gBAAgB,kBAAkB,EAAE;IACpC,gBAAgB,OAAO,CAAC,SAAS,CAAC;IAClC,YAAY,CAAC;IACb,YAAY,MAAM,kBAAkB,GAAG,MAAM;IAC7C,gBAAgB,KAAK,CAAC,mBAAmB,CAAC,QAAQ,EAAE,eAAe,CAAC;IACpE,gBAAgB,IAAI,cAAc,EAAE;IACpC,oBAAoB,KAAK,CAAC,mBAAmB,CAAC,QAAQ,EAAE,eAAe,CAAC;IACxE,gBAAgB;IAChB,qBAAqB;IACrB,oBAAoB,MAAM,CAAC,mBAAmB,CAAC,OAAO,EAAE,cAAc,CAAC;IACvE,gBAAgB;IAChB,YAAY,CAAC;IACb,YAAY,KAAK,CAAC,gBAAgB,CAAC,QAAQ,EAAE,eAAe,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;IAC7E,YAAY,IAAI,cAAc,EAAE;IAChC,gBAAgB,KAAK,CAAC,gBAAgB,CAAC,QAAQ,EAAE,eAAe,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;IACjF,YAAY;IACZ,iBAAiB;IACjB;IACA,gBAAgB,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,cAAc,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;IAChF,YAAY;IACZ,YAAY,KAAK,CAAC,KAAK,EAAE;IACzB,QAAQ,CAAC,CAAC;IACV,IAAI;IACJ,IAAI,MAAM,eAAe,CAAC,IAAI,EAAE;IAChC,QAAQ,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,KAAK;IAChD,YAAY,MAAM,MAAM,GAAG,IAAI,UAAU,EAAE;IAC3C,YAAY,MAAM,CAAC,aAAa,CAAC,IAAI,CAAC;IACtC,YAAY,MAAM,CAAC,MAAM,GAAG,MAAM;IAClC,gBAAgB,MAAM,MAAM,GAAG,OAAO,MAAM,CAAC,MAAM,KAAK,QAAQ,GAAG,MAAM,CAAC,MAAM,GAAG,EAAE;IACrF,gBAAgB,MAAM,cAAc,GAAG,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC;IAC9D,gBAAgB,MAAM,MAAM,GAAG,cAAc,CAAC,CAAC,CAAC,IAAI,EAAE;IACtD,gBAAgB,OAAO,CAAC,MAAM,CAAC;IAC/B,YAAY,CAAC;IACb,YAAY,MAAM,CAAC,OAAO,GAAG,KAAK,IAAI;IACtC,gBAAgB,MAAM,CAAC,KAAK,CAAC;IAC7B,YAAY,CAAC;IACb,QAAQ,CAAC,CAAC;IACV,IAAI;IACJ,IAAI,cAAc,CAAC,IAAI,EAAE;IACzB,QAAQ,OAAO,IAAI,CAAC,IAAI;IACxB,IAAI;IACJ,IAAI,kBAAkB,CAAC,IAAI,EAAE;IAC7B,QAAQ,OAAO,IAAI,CAAC,IAAI;IACxB,IAAI;IACJ,IAAI,cAAc,CAAC,IAAI,EAAE;IACzB,QAAQ,OAAO,IAAI,CAAC,IAAI;IACxB,IAAI;IACJ,IAAI,MAAM,IAAI,CAAC,OAAO,EAAE;IACxB,QAAQ,OAAO,IAAI,OAAO,CAAC,OAAO,IAAI,UAAU,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IACnE,IAAI;IACJ;;AC/HK,UAAC,UAAU,GAAGC,mBAAc,CAAC,YAAY,EAAE;IAChD,IAAI,GAAG,EAAE,MAAM,IAAIC,aAAiB,EAAE;IACtC,CAAC;;;;;;;;;;"} \ No newline at end of file diff --git a/node_modules/@capawesome/capacitor-file-picker/ios/Plugin/Classes/Enums/CustomError.swift b/node_modules/@capawesome/capacitor-file-picker/ios/Plugin/Classes/Enums/CustomError.swift new file mode 100644 index 0000000..f6ce0c9 --- /dev/null +++ b/node_modules/@capawesome/capacitor-file-picker/ios/Plugin/Classes/Enums/CustomError.swift @@ -0,0 +1,26 @@ +import Foundation + +public enum CustomError: Error { + case fileAlreadyExists + case fromMissing + case invalidPath + case toMissing + case unknown +} + +extension CustomError: LocalizedError { + public var errorDescription: String? { + switch self { + case .fileAlreadyExists: + return NSLocalizedString("File already exists.", comment: "fileAlreadyExists") + case .fromMissing: + return NSLocalizedString("from must be provided.", comment: "fromMissing") + case .invalidPath: + return NSLocalizedString("Invalid path provided.", comment: "invalidPath") + case .toMissing: + return NSLocalizedString("to must be provided.", comment: "toMissing") + case .unknown: + return NSLocalizedString("An unknown error occurred.", comment: "unknown") + } + } +} diff --git a/node_modules/@capawesome/capacitor-file-picker/ios/Plugin/Classes/Options/CopyFileOptions.swift b/node_modules/@capawesome/capacitor-file-picker/ios/Plugin/Classes/Options/CopyFileOptions.swift new file mode 100644 index 0000000..555794e --- /dev/null +++ b/node_modules/@capawesome/capacitor-file-picker/ios/Plugin/Classes/Options/CopyFileOptions.swift @@ -0,0 +1,39 @@ +import Capacitor + +@objc public class CopyFileOptions: NSObject { + private let fromUrl: URL + private var overwrite = true + private let toUrl: URL + + init(_ call: CAPPluginCall) throws { + guard let from = call.getString("from") else { + throw CustomError.fromMissing + } + guard let fromUrl = URL(string: from) else { + throw CustomError.invalidPath + } + self.fromUrl = fromUrl + + self.overwrite = call.getBool("overwrite", self.overwrite) + + guard let to = call.getString("to") else { + throw CustomError.toMissing + } + guard let toUrl = URL(string: to) else { + throw CustomError.invalidPath + } + self.toUrl = toUrl + } + + func getFromUrl() -> URL { + return fromUrl + } + + func getOverwrite() -> Bool { + return overwrite + } + + func getToUrl() -> URL { + return toUrl + } +} diff --git a/node_modules/@capawesome/capacitor-file-picker/ios/Plugin/FilePicker.swift b/node_modules/@capawesome/capacitor-file-picker/ios/Plugin/FilePicker.swift new file mode 100644 index 0000000..5f964ea --- /dev/null +++ b/node_modules/@capawesome/capacitor-file-picker/ios/Plugin/FilePicker.swift @@ -0,0 +1,432 @@ +import Foundation +import PhotosUI +import Photos +import Capacitor +import UIKit +import MobileCoreServices + +@objc public class FilePicker: NSObject { + private var plugin: FilePickerPlugin? + private var invokedMethod: String? + + init(_ plugin: FilePickerPlugin?) { + super.init() + self.plugin = plugin + } + + @objc func copyFile(_ options: CopyFileOptions, completion: @escaping (Error?) -> Void) throws { + let fileManager = FileManager.default + let fromUrl = options.getFromUrl() + let toUrl = options.getToUrl() + let toFolderUrl = toUrl.deletingLastPathComponent() + let shouldOverwrite = options.getOverwrite() + + if !fileManager.fileExists(atPath: toFolderUrl.path) { + try fileManager.createDirectory(at: toFolderUrl, withIntermediateDirectories: true, attributes: nil) + } + + if fileManager.fileExists(atPath: toUrl.path) { + if shouldOverwrite { + try fileManager.removeItem(at: toUrl) + } else { + completion(CustomError.fileAlreadyExists) + return + } + } + + try fileManager.copyItem(at: fromUrl, to: toUrl) + completion(nil) + } + + public func convertHeicToJpeg(_ sourceUrl: URL) throws -> URL? { + let heicImage = UIImage(named: sourceUrl.path) + guard let heicImage = heicImage else { + return nil + } + let jpegImageData = heicImage.jpegData(compressionQuality: 0.9) + let directory = try self.createUniqueTemporaryDirectory() + let filenameWithoutExtension = sourceUrl.deletingPathExtension().lastPathComponent + let targetUrl = directory.appendingPathComponent("\(filenameWithoutExtension).jpeg") + do { + try deleteFile(targetUrl) + } + try jpegImageData?.write(to: targetUrl) + return targetUrl + } + + public func openDocumentPicker(limit: Int, documentTypes: [String]) { + invokedMethod = "pickFiles" + DispatchQueue.main.async { + let picker = UIDocumentPickerViewController(documentTypes: documentTypes, in: .import) + picker.delegate = self + picker.allowsMultipleSelection = limit == 0 + picker.modalPresentationStyle = .fullScreen + self.presentViewController(picker) + } + } + + public func openDirectoryPicker() { + invokedMethod = "pickDirectory" + DispatchQueue.main.async { + if #available(iOS 14.0, *) { + let picker = UIDocumentPickerViewController(forOpeningContentTypes: [.folder]) + picker.delegate = self + picker.modalPresentationStyle = .fullScreen + self.presentViewController(picker) + } else { + let documentTypes = [kUTTypeFolder as String] + let picker = UIDocumentPickerViewController(documentTypes: documentTypes, in: .open) + picker.delegate = self + picker.modalPresentationStyle = .fullScreen + self.presentViewController(picker) + } + } + } + + public func openImagePicker(limit: Int, skipTranscoding: Bool, ordered: Bool) { + DispatchQueue.main.async { + if #available(iOS 14, *) { + var configuration = PHPickerConfiguration(photoLibrary: PHPhotoLibrary.shared()) + configuration.selectionLimit = limit + + if #available(iOS 15, *) { + configuration.selection = ordered ? .ordered : .default + } + + configuration.filter = .images + configuration.preferredAssetRepresentationMode = skipTranscoding ? .current : .automatic + let picker = PHPickerViewController(configuration: configuration) + picker.delegate = self + picker.modalPresentationStyle = .fullScreen + self.presentViewController(picker) + } else { + let picker = UIImagePickerController() + picker.delegate = self + picker.sourceType = .photoLibrary + picker.modalPresentationStyle = .fullScreen + self.presentViewController(picker) + } + } + } + + public func openMediaPicker(limit: Int, skipTranscoding: Bool, ordered: Bool) { + DispatchQueue.main.async { + if #available(iOS 14, *) { + var configuration = PHPickerConfiguration(photoLibrary: PHPhotoLibrary.shared()) + configuration.selectionLimit = limit + + if #available(iOS 15, *) { + configuration.selection = ordered ? .ordered : .default + } + + configuration.preferredAssetRepresentationMode = skipTranscoding ? .current : .automatic + let picker = PHPickerViewController(configuration: configuration) + picker.delegate = self + picker.modalPresentationStyle = .fullScreen + self.presentViewController(picker) + } else { + let picker = UIImagePickerController() + picker.delegate = self + picker.mediaTypes = ["public.movie", "public.image"] + picker.modalPresentationStyle = .fullScreen + self.presentViewController(picker) + } + } + } + + public func openVideoPicker(limit: Int, skipTranscoding: Bool, ordered: Bool) { + DispatchQueue.main.async { + if #available(iOS 14, *) { + var configuration = PHPickerConfiguration(photoLibrary: PHPhotoLibrary.shared()) + configuration.selectionLimit = limit + + if #available(iOS 15, *) { + configuration.selection = ordered ? .ordered : .default + } + + configuration.filter = .videos + configuration.preferredAssetRepresentationMode = skipTranscoding ? .current : .automatic + let picker = PHPickerViewController(configuration: configuration) + picker.delegate = self + picker.modalPresentationStyle = .fullScreen + self.presentViewController(picker) + } else { + let picker = UIImagePickerController() + picker.delegate = self + picker.mediaTypes = ["public.movie"] + picker.modalPresentationStyle = .fullScreen + self.presentViewController(picker) + } + } + } + + public func getPathFromUrl(_ url: URL) -> String { + return url.absoluteString + } + + public func getNameFromUrl(_ url: URL) -> String { + return url.lastPathComponent + } + + public func getDataFromUrl(_ url: URL) throws -> String { + let data = try Data(contentsOf: url) + return data.base64EncodedString() + } + + public func getModifiedAtFromUrl(_ url: URL) -> Int? { + do { + let attributes = try FileManager.default.attributesOfItem(atPath: url.path) + if let modifiedDateInSec = (attributes[.modificationDate] as? Date)?.timeIntervalSince1970 { + return Int(modifiedDateInSec * 1000.0) + } else { + return nil + } + } catch let error as NSError { + CAPLog.print("getModifiedAtFromUrl failed.", error.localizedDescription) + return nil + } + } + + public func getMimeTypeFromUrl(_ url: URL) -> String { + let fileExtension = url.pathExtension as CFString + guard let extUTI = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, fileExtension, nil)?.takeUnretainedValue() else { + return "" + } + guard let mimeUTI = UTTypeCopyPreferredTagWithClass(extUTI, kUTTagClassMIMEType) else { + return "" + } + return mimeUTI.takeRetainedValue() as String + } + + public func getSizeFromUrl(_ url: URL) throws -> Int { + let values = try url.resourceValues(forKeys: [.fileSizeKey]) + return values.fileSize ?? 0 + } + + public func getDurationFromUrl(_ url: URL) -> Int? { + if isVideoUrl(url) { + let asset = AVAsset(url: url) + let duration = asset.duration + let durationTime = CMTimeGetSeconds(duration) + return Int(round(durationTime)) + } + return nil + } + + public func getHeightAndWidthFromUrl(_ url: URL) -> (Int?, Int?) { + if isImageUrl(url) { + if let imageSource = CGImageSourceCreateWithURL(url as CFURL, nil) { + if let imageProperties = CGImageSourceCopyPropertiesAtIndex(imageSource, 0, nil) as Dictionary? { + return getHeightAndWidthFromImageProperties(imageProperties) + } + } + } else if isVideoUrl(url) { + guard let track = AVURLAsset(url: url).tracks(withMediaType: AVMediaType.video).first else { return (nil, nil) } + let size = track.naturalSize.applying(track.preferredTransform) + let height = abs(Int(size.height)) + let width = abs(Int(size.width)) + return (height, width) + } + return (nil, nil) + } + + public func getHeightAndWidthFromImageProperties(_ properties: [NSObject: AnyObject]) -> (Int?, Int?) { + let width = properties[kCGImagePropertyPixelWidth] as? Int + let height = properties[kCGImagePropertyPixelHeight] as? Int + let orientation = properties[kCGImagePropertyOrientation] as? Int ?? UIImage.Orientation.up.rawValue + switch orientation { + case UIImage.Orientation.left.rawValue, UIImage.Orientation.right.rawValue, UIImage.Orientation.leftMirrored.rawValue, UIImage.Orientation.rightMirrored.rawValue: + return (width, height) + default: + return (height, width) + } + } + + public func getFileUrlByPath(_ path: String) -> URL? { + guard let url = URL.init(string: path) else { + return nil + } + if FileManager.default.fileExists(atPath: url.path) { + return url + } else { + return nil + } + } + + private func presentViewController(_ viewControllerToPresent: UIViewController) { + self.plugin?.bridge?.viewController?.present(viewControllerToPresent, animated: true, completion: nil) + } + + private func dismissViewController(_ viewControllerToPresent: UIViewController, completion: (() -> Void)? = nil) { + viewControllerToPresent.dismiss(animated: true, completion: completion) + plugin?.notifyPickerDismissedListener() + } + + private func isImageUrl(_ url: URL) -> Bool { + let mimeType = self.getMimeTypeFromUrl(url) + return mimeType.hasPrefix("image") + } + + private func isVideoUrl(_ url: URL) -> Bool { + let mimeType = self.getMimeTypeFromUrl(url) + return mimeType.hasPrefix("video") + } + + private func saveTemporaryFile(_ sourceUrl: URL) throws -> URL { + let directory = try self.createUniqueTemporaryDirectory() + let targetUrl = directory.appendingPathComponent(sourceUrl.lastPathComponent) + do { + try deleteFile(targetUrl) + } + try FileManager.default.copyItem(at: sourceUrl, to: targetUrl) + return targetUrl + } + + private func createUniqueTemporaryDirectory() throws -> URL { + let uniqueFolderName = UUID().uuidString + var directory = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(uniqueFolderName) + if let cachesDirectory = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask).first { + directory = cachesDirectory.appendingPathComponent(uniqueFolderName) + } + try FileManager.default.createDirectory(at: directory, withIntermediateDirectories: true, attributes: nil) + return directory + } + + private func deleteFile(_ url: URL) throws { + if FileManager.default.fileExists(atPath: url.path) { + try FileManager.default.removeItem(atPath: url.path) + } + } +} + +extension FilePicker: UIDocumentPickerDelegate { + public func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) { + if invokedMethod == "pickFiles" { + do { + let temporaryUrls = try urls.map { try saveTemporaryFile($0) } + plugin?.handleDocumentPickerResult(urls: temporaryUrls, error: nil) + } catch { + plugin?.handleDocumentPickerResult(urls: nil, error: self.plugin?.errorTemporaryCopyFailed) + } + } else if invokedMethod == "pickDirectory" { + plugin?.handleDirectoryPickerResult(path: urls.first?.absoluteString, error: nil) + } else { + return + } + plugin?.notifyPickerDismissedListener() + } + + public func documentPickerWasCancelled(_ controller: UIDocumentPickerViewController) { + if invokedMethod == "pickFiles" { + plugin?.handleDocumentPickerResult(urls: nil, error: nil) + } else if invokedMethod == "pickDirectory" { + plugin?.handleDirectoryPickerResult(path: nil, error: nil) + } else { + return + } + plugin?.notifyPickerDismissedListener() + } +} + +extension FilePicker: UIImagePickerControllerDelegate, UINavigationControllerDelegate, UIPopoverPresentationControllerDelegate { + public func imagePickerControllerDidCancel(_ picker: UIImagePickerController) { + dismissViewController(picker) + plugin?.handleDocumentPickerResult(urls: nil, error: nil) + } + + public func popoverPresentationControllerDidDismissPopover(_ popoverPresentationController: UIPopoverPresentationController) { + plugin?.handleDocumentPickerResult(urls: nil, error: nil) + } + + public func presentationControllerDidDismiss(_ presentationController: UIPresentationController) { + plugin?.handleDocumentPickerResult(urls: nil, error: nil) + } + + public func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey: Any]) { + dismissViewController(picker) { + if let url = info[.mediaURL] as? URL { + do { + let temporaryUrl = try self.saveTemporaryFile(url) + self.plugin?.handleDocumentPickerResult(urls: [temporaryUrl], error: nil) + } catch { + self.plugin?.handleDocumentPickerResult(urls: nil, error: self.plugin?.errorTemporaryCopyFailed) + } + } else { + self.plugin?.handleDocumentPickerResult(urls: nil, error: nil) + } + } + } +} + +@available(iOS 14, *) +extension FilePicker: PHPickerViewControllerDelegate { + public func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) { + dismissViewController(picker) + if results.first == nil { + self.plugin?.handleDocumentPickerResult(urls: nil, error: nil) + return + } + var temporaryUrls = [URL?](repeating: nil, count: results.count) + var errorMessage: String? + let dispatchGroup = DispatchGroup() + for (index, result) in results.enumerated() { + if errorMessage != nil { + break + } + if result.itemProvider.hasItemConformingToTypeIdentifier(UTType.movie.identifier) { + dispatchGroup.enter() + result.itemProvider.loadFileRepresentation(forTypeIdentifier: UTType.movie.identifier, completionHandler: { url, error in + defer { + dispatchGroup.leave() + } + if let error = error { + errorMessage = error.localizedDescription + return + } + guard let url = url else { + errorMessage = self.plugin?.errorUnknown + return + } + do { + let temporaryUrl = try self.saveTemporaryFile(url) + temporaryUrls[index] = temporaryUrl + } catch { + errorMessage = self.plugin?.errorTemporaryCopyFailed + } + }) + } else if result.itemProvider.hasItemConformingToTypeIdentifier(UTType.image.identifier) { + dispatchGroup.enter() + result.itemProvider.loadFileRepresentation(forTypeIdentifier: UTType.image.identifier, completionHandler: { url, error in + defer { + dispatchGroup.leave() + } + if let error = error { + errorMessage = error.localizedDescription + return + } + guard let url = url else { + errorMessage = self.plugin?.errorUnknown + return + } + do { + let temporaryUrl = try self.saveTemporaryFile(url) + temporaryUrls[index] = temporaryUrl + } catch { + errorMessage = self.plugin?.errorTemporaryCopyFailed + } + }) + } else { + errorMessage = self.plugin?.errorUnsupportedFileTypeIdentifier + } + } + dispatchGroup.notify(queue: .main) { + if let errorMessage = errorMessage { + self.plugin?.handleDocumentPickerResult(urls: nil, error: errorMessage) + return + } + + let finalUrls: [URL] = temporaryUrls.compactMap { $0 } + self.plugin?.handleDocumentPickerResult(urls: finalUrls, error: nil) + } + } +} diff --git a/node_modules/@capawesome/capacitor-file-picker/ios/Plugin/FilePickerPlugin.swift b/node_modules/@capawesome/capacitor-file-picker/ios/Plugin/FilePickerPlugin.swift new file mode 100644 index 0000000..23c6522 --- /dev/null +++ b/node_modules/@capawesome/capacitor-file-picker/ios/Plugin/FilePickerPlugin.swift @@ -0,0 +1,202 @@ +import Foundation +import Capacitor +import UIKit +import MobileCoreServices + +/** + * Please read the Capacitor iOS Plugin Development Guide + * here: https://capacitorjs.com/docs/plugins/ios + */ +@objc(FilePickerPlugin) +public class FilePickerPlugin: CAPPlugin, CAPBridgedPlugin { + public let identifier = "FilePickerPlugin" + public let jsName = "FilePicker" + public let pluginMethods: [CAPPluginMethod] = [ + CAPPluginMethod(name: "convertHeicToJpeg", returnType: CAPPluginReturnPromise), + CAPPluginMethod(name: "copyFile", returnType: CAPPluginReturnPromise), + CAPPluginMethod(name: "pickFiles", returnType: CAPPluginReturnPromise), + CAPPluginMethod(name: "pickImages", returnType: CAPPluginReturnPromise), + CAPPluginMethod(name: "pickMedia", returnType: CAPPluginReturnPromise), + CAPPluginMethod(name: "pickVideos", returnType: CAPPluginReturnPromise), + CAPPluginMethod(name: "pickDirectory", returnType: CAPPluginReturnPromise) + ] + public let errorPathMissing = "path must be provided." + public let errorFileNotExist = "File does not exist." + public let errorConvertFailed = "File could not be converted." + public let errorPickFileCanceled = "pickFiles canceled." + public let errorPickDirectoryCanceled = "pickDirectory canceled." + public let errorUnknown = "Unknown error occurred." + public let errorTemporaryCopyFailed = "An unknown error occurred while creating a temporary copy of the file." + public let errorUnsupportedFileTypeIdentifier = "Unsupported file type identifier." + public let pickerDismissedEvent = "pickerDismissed" + private var implementation: FilePicker? + private var savedCall: CAPPluginCall? + + override public func load() { + self.implementation = FilePicker(self) + } + + @objc func convertHeicToJpeg(_ call: CAPPluginCall) { + guard let path = call.getString("path") else { + call.reject(errorPathMissing) + return + } + guard let url = implementation?.getFileUrlByPath(path) else { + call.reject(errorFileNotExist) + return + } + + do { + let jpegUrl = try implementation?.convertHeicToJpeg(url) + guard let jpegUrl = jpegUrl else { + call.reject(errorConvertFailed) + return + } + + var result = JSObject() + result["path"] = jpegUrl.absoluteString + call.resolve(result) + } catch let error as NSError { + call.reject(error.localizedDescription, nil, error) + } + } + + @objc func copyFile(_ call: CAPPluginCall) { + do { + let options = try CopyFileOptions(call) + try implementation?.copyFile(options) { error in + if let error = error { + call.reject(error.localizedDescription) + return + } + call.resolve() + } + } catch { + call.reject(error.localizedDescription) + } + } + + @objc func pickFiles(_ call: CAPPluginCall) { + savedCall = call + + let limit = call.getInt("limit", 0) + let types = call.getArray("types", String.self) ?? [] + let parsedTypes = parseTypesOption(types) + let documentTypes = parsedTypes.isEmpty ? ["public.data"] : parsedTypes + + implementation?.openDocumentPicker(limit: limit, documentTypes: documentTypes) + } + + @objc func pickDirectory(_ call: CAPPluginCall) { + savedCall = call + implementation?.openDirectoryPicker() + } + + @objc func pickImages(_ call: CAPPluginCall) { + savedCall = call + + let limit = call.getInt("limit", 0) + let skipTranscoding = call.getBool("skipTranscoding", true) + let ordered = call.getBool("ordered", false) + + implementation?.openImagePicker(limit: limit, skipTranscoding: skipTranscoding, ordered: ordered) + } + + @objc func pickMedia(_ call: CAPPluginCall) { + savedCall = call + + let limit = call.getInt("limit", 0) + let skipTranscoding = call.getBool("skipTranscoding", true) + let ordered = call.getBool("ordered", false) + + implementation?.openMediaPicker(limit: limit, skipTranscoding: skipTranscoding, ordered: ordered) + } + + @objc func pickVideos(_ call: CAPPluginCall) { + savedCall = call + + let limit = call.getInt("limit", 0) + let skipTranscoding = call.getBool("skipTranscoding", true) + let ordered = call.getBool("ordered", false) + + implementation?.openVideoPicker(limit: limit, skipTranscoding: skipTranscoding, ordered: ordered) + } + + @objc func notifyPickerDismissedListener() { + notifyListeners(pickerDismissedEvent, data: nil) + } + + @objc func handleDocumentPickerResult(urls: [URL]?, error: String?) { + guard let savedCall = savedCall else { + return + } + if let error = error { + savedCall.reject(error) + return + } + guard let urls = urls else { + savedCall.reject(errorPickFileCanceled) + return + } + let readData = savedCall.getBool("readData", false) + do { + var result = JSObject() + let filesResult = try urls.map {(url: URL) -> JSObject in + var file = JSObject() + if readData == true { + file["data"] = try implementation?.getDataFromUrl(url) ?? "" + } + let duration = implementation?.getDurationFromUrl(url) + if let duration = duration { + file["duration"] = duration + } + let (height, width) = implementation?.getHeightAndWidthFromUrl(url) ?? (nil, nil) + if let height = height { + file["height"] = height + } + if let width = width { + file["width"] = width + } + file["modifiedAt"] = implementation?.getModifiedAtFromUrl(url) ?? 0 + file["mimeType"] = implementation?.getMimeTypeFromUrl(url) ?? "" + file["name"] = implementation?.getNameFromUrl(url) ?? "" + file["path"] = implementation?.getPathFromUrl(url) ?? "" + file["size"] = try implementation?.getSizeFromUrl(url) ?? -1 + return file + } + result["files"] = filesResult + savedCall.resolve(result) + } catch let error as NSError { + savedCall.reject(error.localizedDescription, nil, error) + return + } + } + + @objc func handleDirectoryPickerResult(path: String?, error: String?) { + guard let savedCall = savedCall else { + return + } + if let error = error { + savedCall.reject(error) + return + } + guard let path = path else { + savedCall.reject(errorPickDirectoryCanceled) + return + } + var result = JSObject() + result["path"] = path + savedCall.resolve(result) + } + + private func parseTypesOption(_ types: [String]) -> [String] { + var parsedTypes: [String] = [] + for (_, type) in types.enumerated() { + guard let utType: String = UTTypeCreatePreferredIdentifierForTag(kUTTagClassMIMEType, type as CFString, nil)?.takeRetainedValue() as String? else { + continue + } + parsedTypes.append(utType) + } + return parsedTypes + } +} diff --git a/node_modules/@capawesome/capacitor-file-picker/ios/Plugin/Info.plist b/node_modules/@capawesome/capacitor-file-picker/ios/Plugin/Info.plist new file mode 100644 index 0000000..1007fd9 --- /dev/null +++ b/node_modules/@capawesome/capacitor-file-picker/ios/Plugin/Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleVersion + $(CURRENT_PROJECT_VERSION) + NSPrincipalClass + + + diff --git a/node_modules/@capawesome/capacitor-file-picker/package.json b/node_modules/@capawesome/capacitor-file-picker/package.json new file mode 100644 index 0000000..8b76334 --- /dev/null +++ b/node_modules/@capawesome/capacitor-file-picker/package.json @@ -0,0 +1,99 @@ +{ + "name": "@capawesome/capacitor-file-picker", + "version": "8.0.2", + "description": "Capacitor plugin that allows the user to select a file.", + "main": "dist/plugin.cjs.js", + "module": "dist/esm/index.js", + "types": "dist/esm/index.d.ts", + "unpkg": "dist/plugin.js", + "files": [ + "android/src/main/", + "android/build.gradle", + "dist/", + "ios/Plugin/", + "CapawesomeCapacitorFilePicker.podspec", + "Package.swift" + ], + "author": "Robin Genz ", + "license": "MIT", + "repository": { + "type": "git", + "url": "git+https://github.com/capawesome-team/capacitor-plugins.git" + }, + "bugs": { + "url": "https://github.com/capawesome-team/capacitor-plugins/issues" + }, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/capawesome-team/" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/capawesome" + } + ], + "homepage": "https://capawesome.io/plugins/file-picker/", + "keywords": [ + "capacitor", + "plugin", + "native", + "ionic", + "android", + "ios", + "web", + "file picker" + ], + "scripts": { + "verify": "npm run verify:ios && npm run verify:android && npm run verify:web", + "verify:ios": "cd ios && pod install && xcodebuild -workspace Plugin.xcworkspace -scheme Plugin -destination generic/platform=iOS && cd ..", + "verify:android": "cd android && ./gradlew clean build test && cd ..", + "verify:web": "npm run build", + "lint": "npm run eslint && npm run prettier -- --check && npm run swiftlint -- lint", + "fmt": "npm run eslint -- --fix && npm run prettier -- --write && npm run swiftlint -- --fix --format", + "eslint": "eslint . --ext ts", + "prettier": "prettier \"**/*.{css,html,ts,js,java}\"", + "swiftlint": "node-swiftlint", + "docgen": "docgen --api FilePickerPlugin --output-readme README.md --output-json dist/docs.json", + "build": "npm run clean && npm run docgen && tsc && rollup -c rollup.config.mjs", + "clean": "rimraf ./dist", + "watch": "tsc --watch", + "ios:pod:install": "cd ios && pod install --repo-update && cd ..", + "ios:spm:install": "cd ios && swift package resolve && cd ..", + "prepublishOnly": "npm run build" + }, + "devDependencies": { + "@capacitor/android": "8.0.0", + "@capacitor/cli": "8.0.0", + "@capacitor/core": "8.0.0", + "@capacitor/docgen": "0.3.1", + "@capacitor/ios": "8.0.0", + "@ionic/eslint-config": "0.4.0", + "@ionic/swiftlint-config": "2.0.0", + "eslint": "8.57.0", + "prettier": "3.4.2", + "prettier-plugin-java": "2.6.7", + "rimraf": "6.1.2", + "rollup": "4.53.3", + "swiftlint": "2.0.0", + "typescript": "5.9.3" + }, + "peerDependencies": { + "@capacitor/core": ">=8.0.0" + }, + "swiftlint": "@ionic/swiftlint-config", + "eslintConfig": { + "extends": "@ionic/eslint-config/recommended" + }, + "capacitor": { + "ios": { + "src": "ios" + }, + "android": { + "src": "android" + } + }, + "publishConfig": { + "access": "public" + } +} diff --git a/node_modules/@esbuild/linux-arm64/README.md b/node_modules/@esbuild/linux-arm64/README.md new file mode 100644 index 0000000..0d52dd1 --- /dev/null +++ b/node_modules/@esbuild/linux-arm64/README.md @@ -0,0 +1,3 @@ +# esbuild + +This is the Linux ARM 64-bit binary for esbuild, a JavaScript bundler and minifier. See https://github.com/evanw/esbuild for details. diff --git a/node_modules/@esbuild/linux-arm64/bin/.l2s.esbuild0001 b/node_modules/@esbuild/linux-arm64/bin/.l2s.esbuild0001 new file mode 100755 index 0000000..bc38e73 Binary files /dev/null and b/node_modules/@esbuild/linux-arm64/bin/.l2s.esbuild0001 differ diff --git a/node_modules/@esbuild/linux-arm64/bin/.l2s.esbuild0001.0002 b/node_modules/@esbuild/linux-arm64/bin/.l2s.esbuild0001.0002 new file mode 100755 index 0000000..bc38e73 Binary files /dev/null and b/node_modules/@esbuild/linux-arm64/bin/.l2s.esbuild0001.0002 differ diff --git a/node_modules/@esbuild/linux-arm64/bin/esbuild b/node_modules/@esbuild/linux-arm64/bin/esbuild new file mode 100755 index 0000000..bc38e73 Binary files /dev/null and b/node_modules/@esbuild/linux-arm64/bin/esbuild differ diff --git a/node_modules/@esbuild/linux-arm64/package.json b/node_modules/@esbuild/linux-arm64/package.json new file mode 100644 index 0000000..945123d --- /dev/null +++ b/node_modules/@esbuild/linux-arm64/package.json @@ -0,0 +1,20 @@ +{ + "name": "@esbuild/linux-arm64", + "version": "0.21.5", + "description": "The Linux ARM 64-bit binary for esbuild, a JavaScript bundler.", + "repository": { + "type": "git", + "url": "git+https://github.com/evanw/esbuild.git" + }, + "license": "MIT", + "preferUnplugged": true, + "engines": { + "node": ">=12" + }, + "os": [ + "linux" + ], + "cpu": [ + "arm64" + ] +} diff --git a/node_modules/@rollup/rollup-linux-arm64-gnu/README.md b/node_modules/@rollup/rollup-linux-arm64-gnu/README.md new file mode 100644 index 0000000..48e68cb --- /dev/null +++ b/node_modules/@rollup/rollup-linux-arm64-gnu/README.md @@ -0,0 +1,3 @@ +# `@rollup/rollup-linux-arm64-gnu` + +This is the **aarch64-unknown-linux-gnu** binary for `rollup` diff --git a/node_modules/@rollup/rollup-linux-arm64-gnu/package.json b/node_modules/@rollup/rollup-linux-arm64-gnu/package.json new file mode 100644 index 0000000..5d2d57a --- /dev/null +++ b/node_modules/@rollup/rollup-linux-arm64-gnu/package.json @@ -0,0 +1,25 @@ +{ + "name": "@rollup/rollup-linux-arm64-gnu", + "version": "4.60.4", + "os": [ + "linux" + ], + "cpu": [ + "arm64" + ], + "files": [ + "rollup.linux-arm64-gnu.node" + ], + "description": "Native bindings for Rollup", + "author": "Lukas Taegert-Atkinson", + "homepage": "https://rollupjs.org/", + "license": "MIT", + "repository": { + "type": "git", + "url": "git+https://github.com/rollup/rollup.git" + }, + "libc": [ + "glibc" + ], + "main": "./rollup.linux-arm64-gnu.node" +} \ No newline at end of file diff --git a/node_modules/@rollup/rollup-linux-arm64-gnu/rollup.linux-arm64-gnu.node b/node_modules/@rollup/rollup-linux-arm64-gnu/rollup.linux-arm64-gnu.node new file mode 100644 index 0000000..9d5bdf9 Binary files /dev/null and b/node_modules/@rollup/rollup-linux-arm64-gnu/rollup.linux-arm64-gnu.node differ diff --git a/node_modules/@rollup/rollup-linux-arm64-musl/README.md b/node_modules/@rollup/rollup-linux-arm64-musl/README.md new file mode 100644 index 0000000..3db2751 --- /dev/null +++ b/node_modules/@rollup/rollup-linux-arm64-musl/README.md @@ -0,0 +1,3 @@ +# `@rollup/rollup-linux-arm64-musl` + +This is the **aarch64-unknown-linux-musl** binary for `rollup` diff --git a/node_modules/@rollup/rollup-linux-arm64-musl/package.json b/node_modules/@rollup/rollup-linux-arm64-musl/package.json new file mode 100644 index 0000000..c473f61 --- /dev/null +++ b/node_modules/@rollup/rollup-linux-arm64-musl/package.json @@ -0,0 +1,25 @@ +{ + "name": "@rollup/rollup-linux-arm64-musl", + "version": "4.60.4", + "os": [ + "linux" + ], + "cpu": [ + "arm64" + ], + "files": [ + "rollup.linux-arm64-musl.node" + ], + "description": "Native bindings for Rollup", + "author": "Lukas Taegert-Atkinson", + "homepage": "https://rollupjs.org/", + "license": "MIT", + "repository": { + "type": "git", + "url": "git+https://github.com/rollup/rollup.git" + }, + "libc": [ + "musl" + ], + "main": "./rollup.linux-arm64-musl.node" +} \ No newline at end of file diff --git a/node_modules/@rollup/rollup-linux-arm64-musl/rollup.linux-arm64-musl.node b/node_modules/@rollup/rollup-linux-arm64-musl/rollup.linux-arm64-musl.node new file mode 100644 index 0000000..39d3052 Binary files /dev/null and b/node_modules/@rollup/rollup-linux-arm64-musl/rollup.linux-arm64-musl.node differ diff --git a/node_modules/@types/estree/LICENSE b/node_modules/@types/estree/LICENSE new file mode 100644 index 0000000..9e841e7 --- /dev/null +++ b/node_modules/@types/estree/LICENSE @@ -0,0 +1,21 @@ + MIT License + + Copyright (c) Microsoft Corporation. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE diff --git a/node_modules/@types/estree/README.md b/node_modules/@types/estree/README.md new file mode 100644 index 0000000..2af760b --- /dev/null +++ b/node_modules/@types/estree/README.md @@ -0,0 +1,15 @@ +# Installation +> `npm install --save @types/estree` + +# Summary +This package contains type definitions for estree (https://github.com/estree/estree). + +# Details +Files were exported from https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/estree. + +### Additional Details + * Last updated: Fri, 06 Jun 2025 00:04:33 GMT + * Dependencies: none + +# Credits +These definitions were written by [RReverser](https://github.com/RReverser). diff --git a/node_modules/@types/estree/flow.d.ts b/node_modules/@types/estree/flow.d.ts new file mode 100644 index 0000000..9d001a9 --- /dev/null +++ b/node_modules/@types/estree/flow.d.ts @@ -0,0 +1,167 @@ +declare namespace ESTree { + interface FlowTypeAnnotation extends Node {} + + interface FlowBaseTypeAnnotation extends FlowTypeAnnotation {} + + interface FlowLiteralTypeAnnotation extends FlowTypeAnnotation, Literal {} + + interface FlowDeclaration extends Declaration {} + + interface AnyTypeAnnotation extends FlowBaseTypeAnnotation {} + + interface ArrayTypeAnnotation extends FlowTypeAnnotation { + elementType: FlowTypeAnnotation; + } + + interface BooleanLiteralTypeAnnotation extends FlowLiteralTypeAnnotation {} + + interface BooleanTypeAnnotation extends FlowBaseTypeAnnotation {} + + interface ClassImplements extends Node { + id: Identifier; + typeParameters?: TypeParameterInstantiation | null; + } + + interface ClassProperty { + key: Expression; + value?: Expression | null; + typeAnnotation?: TypeAnnotation | null; + computed: boolean; + static: boolean; + } + + interface DeclareClass extends FlowDeclaration { + id: Identifier; + typeParameters?: TypeParameterDeclaration | null; + body: ObjectTypeAnnotation; + extends: InterfaceExtends[]; + } + + interface DeclareFunction extends FlowDeclaration { + id: Identifier; + } + + interface DeclareModule extends FlowDeclaration { + id: Literal | Identifier; + body: BlockStatement; + } + + interface DeclareVariable extends FlowDeclaration { + id: Identifier; + } + + interface FunctionTypeAnnotation extends FlowTypeAnnotation { + params: FunctionTypeParam[]; + returnType: FlowTypeAnnotation; + rest?: FunctionTypeParam | null; + typeParameters?: TypeParameterDeclaration | null; + } + + interface FunctionTypeParam { + name: Identifier; + typeAnnotation: FlowTypeAnnotation; + optional: boolean; + } + + interface GenericTypeAnnotation extends FlowTypeAnnotation { + id: Identifier | QualifiedTypeIdentifier; + typeParameters?: TypeParameterInstantiation | null; + } + + interface InterfaceExtends extends Node { + id: Identifier | QualifiedTypeIdentifier; + typeParameters?: TypeParameterInstantiation | null; + } + + interface InterfaceDeclaration extends FlowDeclaration { + id: Identifier; + typeParameters?: TypeParameterDeclaration | null; + extends: InterfaceExtends[]; + body: ObjectTypeAnnotation; + } + + interface IntersectionTypeAnnotation extends FlowTypeAnnotation { + types: FlowTypeAnnotation[]; + } + + interface MixedTypeAnnotation extends FlowBaseTypeAnnotation {} + + interface NullableTypeAnnotation extends FlowTypeAnnotation { + typeAnnotation: TypeAnnotation; + } + + interface NumberLiteralTypeAnnotation extends FlowLiteralTypeAnnotation {} + + interface NumberTypeAnnotation extends FlowBaseTypeAnnotation {} + + interface StringLiteralTypeAnnotation extends FlowLiteralTypeAnnotation {} + + interface StringTypeAnnotation extends FlowBaseTypeAnnotation {} + + interface TupleTypeAnnotation extends FlowTypeAnnotation { + types: FlowTypeAnnotation[]; + } + + interface TypeofTypeAnnotation extends FlowTypeAnnotation { + argument: FlowTypeAnnotation; + } + + interface TypeAlias extends FlowDeclaration { + id: Identifier; + typeParameters?: TypeParameterDeclaration | null; + right: FlowTypeAnnotation; + } + + interface TypeAnnotation extends Node { + typeAnnotation: FlowTypeAnnotation; + } + + interface TypeCastExpression extends Expression { + expression: Expression; + typeAnnotation: TypeAnnotation; + } + + interface TypeParameterDeclaration extends Node { + params: Identifier[]; + } + + interface TypeParameterInstantiation extends Node { + params: FlowTypeAnnotation[]; + } + + interface ObjectTypeAnnotation extends FlowTypeAnnotation { + properties: ObjectTypeProperty[]; + indexers: ObjectTypeIndexer[]; + callProperties: ObjectTypeCallProperty[]; + } + + interface ObjectTypeCallProperty extends Node { + value: FunctionTypeAnnotation; + static: boolean; + } + + interface ObjectTypeIndexer extends Node { + id: Identifier; + key: FlowTypeAnnotation; + value: FlowTypeAnnotation; + static: boolean; + } + + interface ObjectTypeProperty extends Node { + key: Expression; + value: FlowTypeAnnotation; + optional: boolean; + static: boolean; + } + + interface QualifiedTypeIdentifier extends Node { + qualification: Identifier | QualifiedTypeIdentifier; + id: Identifier; + } + + interface UnionTypeAnnotation extends FlowTypeAnnotation { + types: FlowTypeAnnotation[]; + } + + interface VoidTypeAnnotation extends FlowBaseTypeAnnotation {} +} diff --git a/node_modules/@types/estree/index.d.ts b/node_modules/@types/estree/index.d.ts new file mode 100644 index 0000000..2bc66fb --- /dev/null +++ b/node_modules/@types/estree/index.d.ts @@ -0,0 +1,694 @@ +// This definition file follows a somewhat unusual format. ESTree allows +// runtime type checks based on the `type` parameter. In order to explain this +// to typescript we want to use discriminated union types: +// https://github.com/Microsoft/TypeScript/pull/9163 +// +// For ESTree this is a bit tricky because the high level interfaces like +// Node or Function are pulling double duty. We want to pass common fields down +// to the interfaces that extend them (like Identifier or +// ArrowFunctionExpression), but you can't extend a type union or enforce +// common fields on them. So we've split the high level interfaces into two +// types, a base type which passes down inherited fields, and a type union of +// all types which extend the base type. Only the type union is exported, and +// the union is how other types refer to the collection of inheriting types. +// +// This makes the definitions file here somewhat more difficult to maintain, +// but it has the notable advantage of making ESTree much easier to use as +// an end user. + +export interface BaseNodeWithoutComments { + // Every leaf interface that extends BaseNode must specify a type property. + // The type property should be a string literal. For example, Identifier + // has: `type: "Identifier"` + type: string; + loc?: SourceLocation | null | undefined; + range?: [number, number] | undefined; +} + +export interface BaseNode extends BaseNodeWithoutComments { + leadingComments?: Comment[] | undefined; + trailingComments?: Comment[] | undefined; +} + +export interface NodeMap { + AssignmentProperty: AssignmentProperty; + CatchClause: CatchClause; + Class: Class; + ClassBody: ClassBody; + Expression: Expression; + Function: Function; + Identifier: Identifier; + Literal: Literal; + MethodDefinition: MethodDefinition; + ModuleDeclaration: ModuleDeclaration; + ModuleSpecifier: ModuleSpecifier; + Pattern: Pattern; + PrivateIdentifier: PrivateIdentifier; + Program: Program; + Property: Property; + PropertyDefinition: PropertyDefinition; + SpreadElement: SpreadElement; + Statement: Statement; + Super: Super; + SwitchCase: SwitchCase; + TemplateElement: TemplateElement; + VariableDeclarator: VariableDeclarator; +} + +export type Node = NodeMap[keyof NodeMap]; + +export interface Comment extends BaseNodeWithoutComments { + type: "Line" | "Block"; + value: string; +} + +export interface SourceLocation { + source?: string | null | undefined; + start: Position; + end: Position; +} + +export interface Position { + /** >= 1 */ + line: number; + /** >= 0 */ + column: number; +} + +export interface Program extends BaseNode { + type: "Program"; + sourceType: "script" | "module"; + body: Array; + comments?: Comment[] | undefined; +} + +export interface Directive extends BaseNode { + type: "ExpressionStatement"; + expression: Literal; + directive: string; +} + +export interface BaseFunction extends BaseNode { + params: Pattern[]; + generator?: boolean | undefined; + async?: boolean | undefined; + // The body is either BlockStatement or Expression because arrow functions + // can have a body that's either. FunctionDeclarations and + // FunctionExpressions have only BlockStatement bodies. + body: BlockStatement | Expression; +} + +export type Function = FunctionDeclaration | FunctionExpression | ArrowFunctionExpression; + +export type Statement = + | ExpressionStatement + | BlockStatement + | StaticBlock + | EmptyStatement + | DebuggerStatement + | WithStatement + | ReturnStatement + | LabeledStatement + | BreakStatement + | ContinueStatement + | IfStatement + | SwitchStatement + | ThrowStatement + | TryStatement + | WhileStatement + | DoWhileStatement + | ForStatement + | ForInStatement + | ForOfStatement + | Declaration; + +export interface BaseStatement extends BaseNode {} + +export interface EmptyStatement extends BaseStatement { + type: "EmptyStatement"; +} + +export interface BlockStatement extends BaseStatement { + type: "BlockStatement"; + body: Statement[]; + innerComments?: Comment[] | undefined; +} + +export interface StaticBlock extends Omit { + type: "StaticBlock"; +} + +export interface ExpressionStatement extends BaseStatement { + type: "ExpressionStatement"; + expression: Expression; +} + +export interface IfStatement extends BaseStatement { + type: "IfStatement"; + test: Expression; + consequent: Statement; + alternate?: Statement | null | undefined; +} + +export interface LabeledStatement extends BaseStatement { + type: "LabeledStatement"; + label: Identifier; + body: Statement; +} + +export interface BreakStatement extends BaseStatement { + type: "BreakStatement"; + label?: Identifier | null | undefined; +} + +export interface ContinueStatement extends BaseStatement { + type: "ContinueStatement"; + label?: Identifier | null | undefined; +} + +export interface WithStatement extends BaseStatement { + type: "WithStatement"; + object: Expression; + body: Statement; +} + +export interface SwitchStatement extends BaseStatement { + type: "SwitchStatement"; + discriminant: Expression; + cases: SwitchCase[]; +} + +export interface ReturnStatement extends BaseStatement { + type: "ReturnStatement"; + argument?: Expression | null | undefined; +} + +export interface ThrowStatement extends BaseStatement { + type: "ThrowStatement"; + argument: Expression; +} + +export interface TryStatement extends BaseStatement { + type: "TryStatement"; + block: BlockStatement; + handler?: CatchClause | null | undefined; + finalizer?: BlockStatement | null | undefined; +} + +export interface WhileStatement extends BaseStatement { + type: "WhileStatement"; + test: Expression; + body: Statement; +} + +export interface DoWhileStatement extends BaseStatement { + type: "DoWhileStatement"; + body: Statement; + test: Expression; +} + +export interface ForStatement extends BaseStatement { + type: "ForStatement"; + init?: VariableDeclaration | Expression | null | undefined; + test?: Expression | null | undefined; + update?: Expression | null | undefined; + body: Statement; +} + +export interface BaseForXStatement extends BaseStatement { + left: VariableDeclaration | Pattern; + right: Expression; + body: Statement; +} + +export interface ForInStatement extends BaseForXStatement { + type: "ForInStatement"; +} + +export interface DebuggerStatement extends BaseStatement { + type: "DebuggerStatement"; +} + +export type Declaration = FunctionDeclaration | VariableDeclaration | ClassDeclaration; + +export interface BaseDeclaration extends BaseStatement {} + +export interface MaybeNamedFunctionDeclaration extends BaseFunction, BaseDeclaration { + type: "FunctionDeclaration"; + /** It is null when a function declaration is a part of the `export default function` statement */ + id: Identifier | null; + body: BlockStatement; +} + +export interface FunctionDeclaration extends MaybeNamedFunctionDeclaration { + id: Identifier; +} + +export interface VariableDeclaration extends BaseDeclaration { + type: "VariableDeclaration"; + declarations: VariableDeclarator[]; + kind: "var" | "let" | "const" | "using" | "await using"; +} + +export interface VariableDeclarator extends BaseNode { + type: "VariableDeclarator"; + id: Pattern; + init?: Expression | null | undefined; +} + +export interface ExpressionMap { + ArrayExpression: ArrayExpression; + ArrowFunctionExpression: ArrowFunctionExpression; + AssignmentExpression: AssignmentExpression; + AwaitExpression: AwaitExpression; + BinaryExpression: BinaryExpression; + CallExpression: CallExpression; + ChainExpression: ChainExpression; + ClassExpression: ClassExpression; + ConditionalExpression: ConditionalExpression; + FunctionExpression: FunctionExpression; + Identifier: Identifier; + ImportExpression: ImportExpression; + Literal: Literal; + LogicalExpression: LogicalExpression; + MemberExpression: MemberExpression; + MetaProperty: MetaProperty; + NewExpression: NewExpression; + ObjectExpression: ObjectExpression; + SequenceExpression: SequenceExpression; + TaggedTemplateExpression: TaggedTemplateExpression; + TemplateLiteral: TemplateLiteral; + ThisExpression: ThisExpression; + UnaryExpression: UnaryExpression; + UpdateExpression: UpdateExpression; + YieldExpression: YieldExpression; +} + +export type Expression = ExpressionMap[keyof ExpressionMap]; + +export interface BaseExpression extends BaseNode {} + +export type ChainElement = SimpleCallExpression | MemberExpression; + +export interface ChainExpression extends BaseExpression { + type: "ChainExpression"; + expression: ChainElement; +} + +export interface ThisExpression extends BaseExpression { + type: "ThisExpression"; +} + +export interface ArrayExpression extends BaseExpression { + type: "ArrayExpression"; + elements: Array; +} + +export interface ObjectExpression extends BaseExpression { + type: "ObjectExpression"; + properties: Array; +} + +export interface PrivateIdentifier extends BaseNode { + type: "PrivateIdentifier"; + name: string; +} + +export interface Property extends BaseNode { + type: "Property"; + key: Expression | PrivateIdentifier; + value: Expression | Pattern; // Could be an AssignmentProperty + kind: "init" | "get" | "set"; + method: boolean; + shorthand: boolean; + computed: boolean; +} + +export interface PropertyDefinition extends BaseNode { + type: "PropertyDefinition"; + key: Expression | PrivateIdentifier; + value?: Expression | null | undefined; + computed: boolean; + static: boolean; +} + +export interface FunctionExpression extends BaseFunction, BaseExpression { + id?: Identifier | null | undefined; + type: "FunctionExpression"; + body: BlockStatement; +} + +export interface SequenceExpression extends BaseExpression { + type: "SequenceExpression"; + expressions: Expression[]; +} + +export interface UnaryExpression extends BaseExpression { + type: "UnaryExpression"; + operator: UnaryOperator; + prefix: true; + argument: Expression; +} + +export interface BinaryExpression extends BaseExpression { + type: "BinaryExpression"; + operator: BinaryOperator; + left: Expression | PrivateIdentifier; + right: Expression; +} + +export interface AssignmentExpression extends BaseExpression { + type: "AssignmentExpression"; + operator: AssignmentOperator; + left: Pattern | MemberExpression; + right: Expression; +} + +export interface UpdateExpression extends BaseExpression { + type: "UpdateExpression"; + operator: UpdateOperator; + argument: Expression; + prefix: boolean; +} + +export interface LogicalExpression extends BaseExpression { + type: "LogicalExpression"; + operator: LogicalOperator; + left: Expression; + right: Expression; +} + +export interface ConditionalExpression extends BaseExpression { + type: "ConditionalExpression"; + test: Expression; + alternate: Expression; + consequent: Expression; +} + +export interface BaseCallExpression extends BaseExpression { + callee: Expression | Super; + arguments: Array; +} +export type CallExpression = SimpleCallExpression | NewExpression; + +export interface SimpleCallExpression extends BaseCallExpression { + type: "CallExpression"; + optional: boolean; +} + +export interface NewExpression extends BaseCallExpression { + type: "NewExpression"; +} + +export interface MemberExpression extends BaseExpression, BasePattern { + type: "MemberExpression"; + object: Expression | Super; + property: Expression | PrivateIdentifier; + computed: boolean; + optional: boolean; +} + +export type Pattern = Identifier | ObjectPattern | ArrayPattern | RestElement | AssignmentPattern | MemberExpression; + +export interface BasePattern extends BaseNode {} + +export interface SwitchCase extends BaseNode { + type: "SwitchCase"; + test?: Expression | null | undefined; + consequent: Statement[]; +} + +export interface CatchClause extends BaseNode { + type: "CatchClause"; + param: Pattern | null; + body: BlockStatement; +} + +export interface Identifier extends BaseNode, BaseExpression, BasePattern { + type: "Identifier"; + name: string; +} + +export type Literal = SimpleLiteral | RegExpLiteral | BigIntLiteral; + +export interface SimpleLiteral extends BaseNode, BaseExpression { + type: "Literal"; + value: string | boolean | number | null; + raw?: string | undefined; +} + +export interface RegExpLiteral extends BaseNode, BaseExpression { + type: "Literal"; + value?: RegExp | null | undefined; + regex: { + pattern: string; + flags: string; + }; + raw?: string | undefined; +} + +export interface BigIntLiteral extends BaseNode, BaseExpression { + type: "Literal"; + value?: bigint | null | undefined; + bigint: string; + raw?: string | undefined; +} + +export type UnaryOperator = "-" | "+" | "!" | "~" | "typeof" | "void" | "delete"; + +export type BinaryOperator = + | "==" + | "!=" + | "===" + | "!==" + | "<" + | "<=" + | ">" + | ">=" + | "<<" + | ">>" + | ">>>" + | "+" + | "-" + | "*" + | "/" + | "%" + | "**" + | "|" + | "^" + | "&" + | "in" + | "instanceof"; + +export type LogicalOperator = "||" | "&&" | "??"; + +export type AssignmentOperator = + | "=" + | "+=" + | "-=" + | "*=" + | "/=" + | "%=" + | "**=" + | "<<=" + | ">>=" + | ">>>=" + | "|=" + | "^=" + | "&=" + | "||=" + | "&&=" + | "??="; + +export type UpdateOperator = "++" | "--"; + +export interface ForOfStatement extends BaseForXStatement { + type: "ForOfStatement"; + await: boolean; +} + +export interface Super extends BaseNode { + type: "Super"; +} + +export interface SpreadElement extends BaseNode { + type: "SpreadElement"; + argument: Expression; +} + +export interface ArrowFunctionExpression extends BaseExpression, BaseFunction { + type: "ArrowFunctionExpression"; + expression: boolean; + body: BlockStatement | Expression; +} + +export interface YieldExpression extends BaseExpression { + type: "YieldExpression"; + argument?: Expression | null | undefined; + delegate: boolean; +} + +export interface TemplateLiteral extends BaseExpression { + type: "TemplateLiteral"; + quasis: TemplateElement[]; + expressions: Expression[]; +} + +export interface TaggedTemplateExpression extends BaseExpression { + type: "TaggedTemplateExpression"; + tag: Expression; + quasi: TemplateLiteral; +} + +export interface TemplateElement extends BaseNode { + type: "TemplateElement"; + tail: boolean; + value: { + /** It is null when the template literal is tagged and the text has an invalid escape (e.g. - tag`\unicode and \u{55}`) */ + cooked?: string | null | undefined; + raw: string; + }; +} + +export interface AssignmentProperty extends Property { + value: Pattern; + kind: "init"; + method: boolean; // false +} + +export interface ObjectPattern extends BasePattern { + type: "ObjectPattern"; + properties: Array; +} + +export interface ArrayPattern extends BasePattern { + type: "ArrayPattern"; + elements: Array; +} + +export interface RestElement extends BasePattern { + type: "RestElement"; + argument: Pattern; +} + +export interface AssignmentPattern extends BasePattern { + type: "AssignmentPattern"; + left: Pattern; + right: Expression; +} + +export type Class = ClassDeclaration | ClassExpression; +export interface BaseClass extends BaseNode { + superClass?: Expression | null | undefined; + body: ClassBody; +} + +export interface ClassBody extends BaseNode { + type: "ClassBody"; + body: Array; +} + +export interface MethodDefinition extends BaseNode { + type: "MethodDefinition"; + key: Expression | PrivateIdentifier; + value: FunctionExpression; + kind: "constructor" | "method" | "get" | "set"; + computed: boolean; + static: boolean; +} + +export interface MaybeNamedClassDeclaration extends BaseClass, BaseDeclaration { + type: "ClassDeclaration"; + /** It is null when a class declaration is a part of the `export default class` statement */ + id: Identifier | null; +} + +export interface ClassDeclaration extends MaybeNamedClassDeclaration { + id: Identifier; +} + +export interface ClassExpression extends BaseClass, BaseExpression { + type: "ClassExpression"; + id?: Identifier | null | undefined; +} + +export interface MetaProperty extends BaseExpression { + type: "MetaProperty"; + meta: Identifier; + property: Identifier; +} + +export type ModuleDeclaration = + | ImportDeclaration + | ExportNamedDeclaration + | ExportDefaultDeclaration + | ExportAllDeclaration; +export interface BaseModuleDeclaration extends BaseNode {} + +export type ModuleSpecifier = ImportSpecifier | ImportDefaultSpecifier | ImportNamespaceSpecifier | ExportSpecifier; +export interface BaseModuleSpecifier extends BaseNode { + local: Identifier; +} + +export interface ImportDeclaration extends BaseModuleDeclaration { + type: "ImportDeclaration"; + specifiers: Array; + attributes: ImportAttribute[]; + source: Literal; +} + +export interface ImportSpecifier extends BaseModuleSpecifier { + type: "ImportSpecifier"; + imported: Identifier | Literal; +} + +export interface ImportAttribute extends BaseNode { + type: "ImportAttribute"; + key: Identifier | Literal; + value: Literal; +} + +export interface ImportExpression extends BaseExpression { + type: "ImportExpression"; + source: Expression; + options?: Expression | null | undefined; +} + +export interface ImportDefaultSpecifier extends BaseModuleSpecifier { + type: "ImportDefaultSpecifier"; +} + +export interface ImportNamespaceSpecifier extends BaseModuleSpecifier { + type: "ImportNamespaceSpecifier"; +} + +export interface ExportNamedDeclaration extends BaseModuleDeclaration { + type: "ExportNamedDeclaration"; + declaration?: Declaration | null | undefined; + specifiers: ExportSpecifier[]; + attributes: ImportAttribute[]; + source?: Literal | null | undefined; +} + +export interface ExportSpecifier extends Omit { + type: "ExportSpecifier"; + local: Identifier | Literal; + exported: Identifier | Literal; +} + +export interface ExportDefaultDeclaration extends BaseModuleDeclaration { + type: "ExportDefaultDeclaration"; + declaration: MaybeNamedFunctionDeclaration | MaybeNamedClassDeclaration | Expression; +} + +export interface ExportAllDeclaration extends BaseModuleDeclaration { + type: "ExportAllDeclaration"; + exported: Identifier | Literal | null; + attributes: ImportAttribute[]; + source: Literal; +} + +export interface AwaitExpression extends BaseExpression { + type: "AwaitExpression"; + argument: Expression; +} diff --git a/node_modules/@types/estree/package.json b/node_modules/@types/estree/package.json new file mode 100644 index 0000000..68c0782 --- /dev/null +++ b/node_modules/@types/estree/package.json @@ -0,0 +1,27 @@ +{ + "name": "@types/estree", + "version": "1.0.8", + "description": "TypeScript definitions for estree", + "homepage": "https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/estree", + "license": "MIT", + "contributors": [ + { + "name": "RReverser", + "githubUsername": "RReverser", + "url": "https://github.com/RReverser" + } + ], + "main": "", + "types": "index.d.ts", + "repository": { + "type": "git", + "url": "https://github.com/DefinitelyTyped/DefinitelyTyped.git", + "directory": "types/estree" + }, + "scripts": {}, + "dependencies": {}, + "peerDependencies": {}, + "typesPublisherContentHash": "7a167b6e4a4d9f6e9a2cb9fd3fc45c885f89cbdeb44b3e5961bb057a45c082fd", + "typeScriptVersion": "5.1", + "nonNpm": true +} \ No newline at end of file diff --git a/node_modules/@vue/reactivity/LICENSE b/node_modules/@vue/reactivity/LICENSE new file mode 100644 index 0000000..15f1f7e --- /dev/null +++ b/node_modules/@vue/reactivity/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2018-present, Yuxi (Evan) You + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/node_modules/@vue/reactivity/README.md b/node_modules/@vue/reactivity/README.md new file mode 100644 index 0000000..4eda9a3 --- /dev/null +++ b/node_modules/@vue/reactivity/README.md @@ -0,0 +1,19 @@ +# @vue/reactivity + +## Usage Note + +This package is inlined into Global & Browser ESM builds of user-facing renderers (e.g. `@vue/runtime-dom`), but also published as a package that can be used standalone. The standalone build should not be used alongside a pre-bundled build of a user-facing renderer, as they will have different internal storage for reactivity connections. A user-facing renderer should re-export all APIs from this package. + +For full exposed APIs, see `src/index.ts`. You can also run `yarn build reactivity --types` from repo root, which will generate an API report at `temp/reactivity.api.md`. + +## Credits + +The implementation of this module is inspired by the following prior art in the JavaScript ecosystem: + +- [Meteor Tracker](https://docs.meteor.com/api/tracker.html) +- [nx-js/observer-util](https://github.com/nx-js/observer-util) +- [salesforce/observable-membrane](https://github.com/salesforce/observable-membrane) + +## Caveats + +- Built-in objects are not observed except for `Array`, `Map`, `WeakMap`, `Set` and `WeakSet`. diff --git a/node_modules/@vue/reactivity/dist/reactivity.cjs.js b/node_modules/@vue/reactivity/dist/reactivity.cjs.js new file mode 100644 index 0000000..fde74f6 --- /dev/null +++ b/node_modules/@vue/reactivity/dist/reactivity.cjs.js @@ -0,0 +1,932 @@ +'use strict'; + +Object.defineProperty(exports, '__esModule', { value: true }); + +var shared = require('@vue/shared'); + +const targetMap = new WeakMap(); +const effectStack = []; +let activeEffect; +const ITERATE_KEY = Symbol('iterate' ); +const MAP_KEY_ITERATE_KEY = Symbol('Map key iterate' ); +function isEffect(fn) { + return fn && fn._isEffect === true; +} +function effect(fn, options = shared.EMPTY_OBJ) { + if (isEffect(fn)) { + fn = fn.raw; + } + const effect = createReactiveEffect(fn, options); + if (!options.lazy) { + effect(); + } + return effect; +} +function stop(effect) { + if (effect.active) { + cleanup(effect); + if (effect.options.onStop) { + effect.options.onStop(); + } + effect.active = false; + } +} +let uid = 0; +function createReactiveEffect(fn, options) { + const effect = function reactiveEffect() { + if (!effect.active) { + return fn(); + } + if (!effectStack.includes(effect)) { + cleanup(effect); + try { + enableTracking(); + effectStack.push(effect); + activeEffect = effect; + return fn(); + } + finally { + effectStack.pop(); + resetTracking(); + activeEffect = effectStack[effectStack.length - 1]; + } + } + }; + effect.id = uid++; + effect.allowRecurse = !!options.allowRecurse; + effect._isEffect = true; + effect.active = true; + effect.raw = fn; + effect.deps = []; + effect.options = options; + return effect; +} +function cleanup(effect) { + const { deps } = effect; + if (deps.length) { + for (let i = 0; i < deps.length; i++) { + deps[i].delete(effect); + } + deps.length = 0; + } +} +let shouldTrack = true; +const trackStack = []; +function pauseTracking() { + trackStack.push(shouldTrack); + shouldTrack = false; +} +function enableTracking() { + trackStack.push(shouldTrack); + shouldTrack = true; +} +function resetTracking() { + const last = trackStack.pop(); + shouldTrack = last === undefined ? true : last; +} +function track(target, type, key) { + if (!shouldTrack || activeEffect === undefined) { + return; + } + let depsMap = targetMap.get(target); + if (!depsMap) { + targetMap.set(target, (depsMap = new Map())); + } + let dep = depsMap.get(key); + if (!dep) { + depsMap.set(key, (dep = new Set())); + } + if (!dep.has(activeEffect)) { + dep.add(activeEffect); + activeEffect.deps.push(dep); + if (activeEffect.options.onTrack) { + activeEffect.options.onTrack({ + effect: activeEffect, + target, + type, + key + }); + } + } +} +function trigger(target, type, key, newValue, oldValue, oldTarget) { + const depsMap = targetMap.get(target); + if (!depsMap) { + // never been tracked + return; + } + const effects = new Set(); + const add = (effectsToAdd) => { + if (effectsToAdd) { + effectsToAdd.forEach(effect => { + if (effect !== activeEffect || effect.allowRecurse) { + effects.add(effect); + } + }); + } + }; + if (type === "clear" /* CLEAR */) { + // collection being cleared + // trigger all effects for target + depsMap.forEach(add); + } + else if (key === 'length' && shared.isArray(target)) { + depsMap.forEach((dep, key) => { + if (key === 'length' || key >= newValue) { + add(dep); + } + }); + } + else { + // schedule runs for SET | ADD | DELETE + if (key !== void 0) { + add(depsMap.get(key)); + } + // also run for iteration key on ADD | DELETE | Map.SET + switch (type) { + case "add" /* ADD */: + if (!shared.isArray(target)) { + add(depsMap.get(ITERATE_KEY)); + if (shared.isMap(target)) { + add(depsMap.get(MAP_KEY_ITERATE_KEY)); + } + } + else if (shared.isIntegerKey(key)) { + // new index added to array -> length changes + add(depsMap.get('length')); + } + break; + case "delete" /* DELETE */: + if (!shared.isArray(target)) { + add(depsMap.get(ITERATE_KEY)); + if (shared.isMap(target)) { + add(depsMap.get(MAP_KEY_ITERATE_KEY)); + } + } + break; + case "set" /* SET */: + if (shared.isMap(target)) { + add(depsMap.get(ITERATE_KEY)); + } + break; + } + } + const run = (effect) => { + if (effect.options.onTrigger) { + effect.options.onTrigger({ + effect, + target, + key, + type, + newValue, + oldValue, + oldTarget + }); + } + if (effect.options.scheduler) { + effect.options.scheduler(effect); + } + else { + effect(); + } + }; + effects.forEach(run); +} + +const isNonTrackableKeys = /*#__PURE__*/ shared.makeMap(`__proto__,__v_isRef,__isVue`); +const builtInSymbols = new Set(Object.getOwnPropertyNames(Symbol) + .map(key => Symbol[key]) + .filter(shared.isSymbol)); +const get = /*#__PURE__*/ createGetter(); +const shallowGet = /*#__PURE__*/ createGetter(false, true); +const readonlyGet = /*#__PURE__*/ createGetter(true); +const shallowReadonlyGet = /*#__PURE__*/ createGetter(true, true); +const arrayInstrumentations = /*#__PURE__*/ createArrayInstrumentations(); +function createArrayInstrumentations() { + const instrumentations = {}; + ['includes', 'indexOf', 'lastIndexOf'].forEach(key => { + instrumentations[key] = function (...args) { + const arr = toRaw(this); + for (let i = 0, l = this.length; i < l; i++) { + track(arr, "get" /* GET */, i + ''); + } + // we run the method using the original args first (which may be reactive) + const res = arr[key](...args); + if (res === -1 || res === false) { + // if that didn't work, run it again using raw values. + return arr[key](...args.map(toRaw)); + } + else { + return res; + } + }; + }); + ['push', 'pop', 'shift', 'unshift', 'splice'].forEach(key => { + instrumentations[key] = function (...args) { + pauseTracking(); + const res = toRaw(this)[key].apply(this, args); + resetTracking(); + return res; + }; + }); + return instrumentations; +} +function createGetter(isReadonly = false, shallow = false) { + return function get(target, key, receiver) { + if (key === "__v_isReactive" /* IS_REACTIVE */) { + return !isReadonly; + } + else if (key === "__v_isReadonly" /* IS_READONLY */) { + return isReadonly; + } + else if (key === "__v_raw" /* RAW */ && + receiver === + (isReadonly + ? shallow + ? shallowReadonlyMap + : readonlyMap + : shallow + ? shallowReactiveMap + : reactiveMap).get(target)) { + return target; + } + const targetIsArray = shared.isArray(target); + if (!isReadonly && targetIsArray && shared.hasOwn(arrayInstrumentations, key)) { + return Reflect.get(arrayInstrumentations, key, receiver); + } + const res = Reflect.get(target, key, receiver); + if (shared.isSymbol(key) ? builtInSymbols.has(key) : isNonTrackableKeys(key)) { + return res; + } + if (!isReadonly) { + track(target, "get" /* GET */, key); + } + if (shallow) { + return res; + } + if (isRef(res)) { + // ref unwrapping - does not apply for Array + integer key. + const shouldUnwrap = !targetIsArray || !shared.isIntegerKey(key); + return shouldUnwrap ? res.value : res; + } + if (shared.isObject(res)) { + // Convert returned value into a proxy as well. we do the isObject check + // here to avoid invalid value warning. Also need to lazy access readonly + // and reactive here to avoid circular dependency. + return isReadonly ? readonly(res) : reactive(res); + } + return res; + }; +} +const set = /*#__PURE__*/ createSetter(); +const shallowSet = /*#__PURE__*/ createSetter(true); +function createSetter(shallow = false) { + return function set(target, key, value, receiver) { + let oldValue = target[key]; + if (!shallow) { + value = toRaw(value); + oldValue = toRaw(oldValue); + if (!shared.isArray(target) && isRef(oldValue) && !isRef(value)) { + oldValue.value = value; + return true; + } + } + const hadKey = shared.isArray(target) && shared.isIntegerKey(key) + ? Number(key) < target.length + : shared.hasOwn(target, key); + const result = Reflect.set(target, key, value, receiver); + // don't trigger if target is something up in the prototype chain of original + if (target === toRaw(receiver)) { + if (!hadKey) { + trigger(target, "add" /* ADD */, key, value); + } + else if (shared.hasChanged(value, oldValue)) { + trigger(target, "set" /* SET */, key, value, oldValue); + } + } + return result; + }; +} +function deleteProperty(target, key) { + const hadKey = shared.hasOwn(target, key); + const oldValue = target[key]; + const result = Reflect.deleteProperty(target, key); + if (result && hadKey) { + trigger(target, "delete" /* DELETE */, key, undefined, oldValue); + } + return result; +} +function has(target, key) { + const result = Reflect.has(target, key); + if (!shared.isSymbol(key) || !builtInSymbols.has(key)) { + track(target, "has" /* HAS */, key); + } + return result; +} +function ownKeys(target) { + track(target, "iterate" /* ITERATE */, shared.isArray(target) ? 'length' : ITERATE_KEY); + return Reflect.ownKeys(target); +} +const mutableHandlers = { + get, + set, + deleteProperty, + has, + ownKeys +}; +const readonlyHandlers = { + get: readonlyGet, + set(target, key) { + { + console.warn(`Set operation on key "${String(key)}" failed: target is readonly.`, target); + } + return true; + }, + deleteProperty(target, key) { + { + console.warn(`Delete operation on key "${String(key)}" failed: target is readonly.`, target); + } + return true; + } +}; +const shallowReactiveHandlers = /*#__PURE__*/ shared.extend({}, mutableHandlers, { + get: shallowGet, + set: shallowSet +}); +// Props handlers are special in the sense that it should not unwrap top-level +// refs (in order to allow refs to be explicitly passed down), but should +// retain the reactivity of the normal readonly object. +const shallowReadonlyHandlers = /*#__PURE__*/ shared.extend({}, readonlyHandlers, { + get: shallowReadonlyGet +}); + +const toReactive = (value) => shared.isObject(value) ? reactive(value) : value; +const toReadonly = (value) => shared.isObject(value) ? readonly(value) : value; +const toShallow = (value) => value; +const getProto = (v) => Reflect.getPrototypeOf(v); +function get$1(target, key, isReadonly = false, isShallow = false) { + // #1772: readonly(reactive(Map)) should return readonly + reactive version + // of the value + target = target["__v_raw" /* RAW */]; + const rawTarget = toRaw(target); + const rawKey = toRaw(key); + if (key !== rawKey) { + !isReadonly && track(rawTarget, "get" /* GET */, key); + } + !isReadonly && track(rawTarget, "get" /* GET */, rawKey); + const { has } = getProto(rawTarget); + const wrap = isShallow ? toShallow : isReadonly ? toReadonly : toReactive; + if (has.call(rawTarget, key)) { + return wrap(target.get(key)); + } + else if (has.call(rawTarget, rawKey)) { + return wrap(target.get(rawKey)); + } + else if (target !== rawTarget) { + // #3602 readonly(reactive(Map)) + // ensure that the nested reactive `Map` can do tracking for itself + target.get(key); + } +} +function has$1(key, isReadonly = false) { + const target = this["__v_raw" /* RAW */]; + const rawTarget = toRaw(target); + const rawKey = toRaw(key); + if (key !== rawKey) { + !isReadonly && track(rawTarget, "has" /* HAS */, key); + } + !isReadonly && track(rawTarget, "has" /* HAS */, rawKey); + return key === rawKey + ? target.has(key) + : target.has(key) || target.has(rawKey); +} +function size(target, isReadonly = false) { + target = target["__v_raw" /* RAW */]; + !isReadonly && track(toRaw(target), "iterate" /* ITERATE */, ITERATE_KEY); + return Reflect.get(target, 'size', target); +} +function add(value) { + value = toRaw(value); + const target = toRaw(this); + const proto = getProto(target); + const hadKey = proto.has.call(target, value); + if (!hadKey) { + target.add(value); + trigger(target, "add" /* ADD */, value, value); + } + return this; +} +function set$1(key, value) { + value = toRaw(value); + const target = toRaw(this); + const { has, get } = getProto(target); + let hadKey = has.call(target, key); + if (!hadKey) { + key = toRaw(key); + hadKey = has.call(target, key); + } + else { + checkIdentityKeys(target, has, key); + } + const oldValue = get.call(target, key); + target.set(key, value); + if (!hadKey) { + trigger(target, "add" /* ADD */, key, value); + } + else if (shared.hasChanged(value, oldValue)) { + trigger(target, "set" /* SET */, key, value, oldValue); + } + return this; +} +function deleteEntry(key) { + const target = toRaw(this); + const { has, get } = getProto(target); + let hadKey = has.call(target, key); + if (!hadKey) { + key = toRaw(key); + hadKey = has.call(target, key); + } + else { + checkIdentityKeys(target, has, key); + } + const oldValue = get ? get.call(target, key) : undefined; + // forward the operation before queueing reactions + const result = target.delete(key); + if (hadKey) { + trigger(target, "delete" /* DELETE */, key, undefined, oldValue); + } + return result; +} +function clear() { + const target = toRaw(this); + const hadItems = target.size !== 0; + const oldTarget = shared.isMap(target) + ? new Map(target) + : new Set(target) + ; + // forward the operation before queueing reactions + const result = target.clear(); + if (hadItems) { + trigger(target, "clear" /* CLEAR */, undefined, undefined, oldTarget); + } + return result; +} +function createForEach(isReadonly, isShallow) { + return function forEach(callback, thisArg) { + const observed = this; + const target = observed["__v_raw" /* RAW */]; + const rawTarget = toRaw(target); + const wrap = isShallow ? toShallow : isReadonly ? toReadonly : toReactive; + !isReadonly && track(rawTarget, "iterate" /* ITERATE */, ITERATE_KEY); + return target.forEach((value, key) => { + // important: make sure the callback is + // 1. invoked with the reactive map as `this` and 3rd arg + // 2. the value received should be a corresponding reactive/readonly. + return callback.call(thisArg, wrap(value), wrap(key), observed); + }); + }; +} +function createIterableMethod(method, isReadonly, isShallow) { + return function (...args) { + const target = this["__v_raw" /* RAW */]; + const rawTarget = toRaw(target); + const targetIsMap = shared.isMap(rawTarget); + const isPair = method === 'entries' || (method === Symbol.iterator && targetIsMap); + const isKeyOnly = method === 'keys' && targetIsMap; + const innerIterator = target[method](...args); + const wrap = isShallow ? toShallow : isReadonly ? toReadonly : toReactive; + !isReadonly && + track(rawTarget, "iterate" /* ITERATE */, isKeyOnly ? MAP_KEY_ITERATE_KEY : ITERATE_KEY); + // return a wrapped iterator which returns observed versions of the + // values emitted from the real iterator + return { + // iterator protocol + next() { + const { value, done } = innerIterator.next(); + return done + ? { value, done } + : { + value: isPair ? [wrap(value[0]), wrap(value[1])] : wrap(value), + done + }; + }, + // iterable protocol + [Symbol.iterator]() { + return this; + } + }; + }; +} +function createReadonlyMethod(type) { + return function (...args) { + { + const key = args[0] ? `on key "${args[0]}" ` : ``; + console.warn(`${shared.capitalize(type)} operation ${key}failed: target is readonly.`, toRaw(this)); + } + return type === "delete" /* DELETE */ ? false : this; + }; +} +function createInstrumentations() { + const mutableInstrumentations = { + get(key) { + return get$1(this, key); + }, + get size() { + return size(this); + }, + has: has$1, + add, + set: set$1, + delete: deleteEntry, + clear, + forEach: createForEach(false, false) + }; + const shallowInstrumentations = { + get(key) { + return get$1(this, key, false, true); + }, + get size() { + return size(this); + }, + has: has$1, + add, + set: set$1, + delete: deleteEntry, + clear, + forEach: createForEach(false, true) + }; + const readonlyInstrumentations = { + get(key) { + return get$1(this, key, true); + }, + get size() { + return size(this, true); + }, + has(key) { + return has$1.call(this, key, true); + }, + add: createReadonlyMethod("add" /* ADD */), + set: createReadonlyMethod("set" /* SET */), + delete: createReadonlyMethod("delete" /* DELETE */), + clear: createReadonlyMethod("clear" /* CLEAR */), + forEach: createForEach(true, false) + }; + const shallowReadonlyInstrumentations = { + get(key) { + return get$1(this, key, true, true); + }, + get size() { + return size(this, true); + }, + has(key) { + return has$1.call(this, key, true); + }, + add: createReadonlyMethod("add" /* ADD */), + set: createReadonlyMethod("set" /* SET */), + delete: createReadonlyMethod("delete" /* DELETE */), + clear: createReadonlyMethod("clear" /* CLEAR */), + forEach: createForEach(true, true) + }; + const iteratorMethods = ['keys', 'values', 'entries', Symbol.iterator]; + iteratorMethods.forEach(method => { + mutableInstrumentations[method] = createIterableMethod(method, false, false); + readonlyInstrumentations[method] = createIterableMethod(method, true, false); + shallowInstrumentations[method] = createIterableMethod(method, false, true); + shallowReadonlyInstrumentations[method] = createIterableMethod(method, true, true); + }); + return [ + mutableInstrumentations, + readonlyInstrumentations, + shallowInstrumentations, + shallowReadonlyInstrumentations + ]; +} +const [mutableInstrumentations, readonlyInstrumentations, shallowInstrumentations, shallowReadonlyInstrumentations] = /* #__PURE__*/ createInstrumentations(); +function createInstrumentationGetter(isReadonly, shallow) { + const instrumentations = shallow + ? isReadonly + ? shallowReadonlyInstrumentations + : shallowInstrumentations + : isReadonly + ? readonlyInstrumentations + : mutableInstrumentations; + return (target, key, receiver) => { + if (key === "__v_isReactive" /* IS_REACTIVE */) { + return !isReadonly; + } + else if (key === "__v_isReadonly" /* IS_READONLY */) { + return isReadonly; + } + else if (key === "__v_raw" /* RAW */) { + return target; + } + return Reflect.get(shared.hasOwn(instrumentations, key) && key in target + ? instrumentations + : target, key, receiver); + }; +} +const mutableCollectionHandlers = { + get: /*#__PURE__*/ createInstrumentationGetter(false, false) +}; +const shallowCollectionHandlers = { + get: /*#__PURE__*/ createInstrumentationGetter(false, true) +}; +const readonlyCollectionHandlers = { + get: /*#__PURE__*/ createInstrumentationGetter(true, false) +}; +const shallowReadonlyCollectionHandlers = { + get: /*#__PURE__*/ createInstrumentationGetter(true, true) +}; +function checkIdentityKeys(target, has, key) { + const rawKey = toRaw(key); + if (rawKey !== key && has.call(target, rawKey)) { + const type = shared.toRawType(target); + console.warn(`Reactive ${type} contains both the raw and reactive ` + + `versions of the same object${type === `Map` ? ` as keys` : ``}, ` + + `which can lead to inconsistencies. ` + + `Avoid differentiating between the raw and reactive versions ` + + `of an object and only use the reactive version if possible.`); + } +} + +const reactiveMap = new WeakMap(); +const shallowReactiveMap = new WeakMap(); +const readonlyMap = new WeakMap(); +const shallowReadonlyMap = new WeakMap(); +function targetTypeMap(rawType) { + switch (rawType) { + case 'Object': + case 'Array': + return 1 /* COMMON */; + case 'Map': + case 'Set': + case 'WeakMap': + case 'WeakSet': + return 2 /* COLLECTION */; + default: + return 0 /* INVALID */; + } +} +function getTargetType(value) { + return value["__v_skip" /* SKIP */] || !Object.isExtensible(value) + ? 0 /* INVALID */ + : targetTypeMap(shared.toRawType(value)); +} +function reactive(target) { + // if trying to observe a readonly proxy, return the readonly version. + if (target && target["__v_isReadonly" /* IS_READONLY */]) { + return target; + } + return createReactiveObject(target, false, mutableHandlers, mutableCollectionHandlers, reactiveMap); +} +/** + * Return a shallowly-reactive copy of the original object, where only the root + * level properties are reactive. It also does not auto-unwrap refs (even at the + * root level). + */ +function shallowReactive(target) { + return createReactiveObject(target, false, shallowReactiveHandlers, shallowCollectionHandlers, shallowReactiveMap); +} +/** + * Creates a readonly copy of the original object. Note the returned copy is not + * made reactive, but `readonly` can be called on an already reactive object. + */ +function readonly(target) { + return createReactiveObject(target, true, readonlyHandlers, readonlyCollectionHandlers, readonlyMap); +} +/** + * Returns a reactive-copy of the original object, where only the root level + * properties are readonly, and does NOT unwrap refs nor recursively convert + * returned properties. + * This is used for creating the props proxy object for stateful components. + */ +function shallowReadonly(target) { + return createReactiveObject(target, true, shallowReadonlyHandlers, shallowReadonlyCollectionHandlers, shallowReadonlyMap); +} +function createReactiveObject(target, isReadonly, baseHandlers, collectionHandlers, proxyMap) { + if (!shared.isObject(target)) { + { + console.warn(`value cannot be made reactive: ${String(target)}`); + } + return target; + } + // target is already a Proxy, return it. + // exception: calling readonly() on a reactive object + if (target["__v_raw" /* RAW */] && + !(isReadonly && target["__v_isReactive" /* IS_REACTIVE */])) { + return target; + } + // target already has corresponding Proxy + const existingProxy = proxyMap.get(target); + if (existingProxy) { + return existingProxy; + } + // only a whitelist of value types can be observed. + const targetType = getTargetType(target); + if (targetType === 0 /* INVALID */) { + return target; + } + const proxy = new Proxy(target, targetType === 2 /* COLLECTION */ ? collectionHandlers : baseHandlers); + proxyMap.set(target, proxy); + return proxy; +} +function isReactive(value) { + if (isReadonly(value)) { + return isReactive(value["__v_raw" /* RAW */]); + } + return !!(value && value["__v_isReactive" /* IS_REACTIVE */]); +} +function isReadonly(value) { + return !!(value && value["__v_isReadonly" /* IS_READONLY */]); +} +function isProxy(value) { + return isReactive(value) || isReadonly(value); +} +function toRaw(observed) { + return ((observed && toRaw(observed["__v_raw" /* RAW */])) || observed); +} +function markRaw(value) { + shared.def(value, "__v_skip" /* SKIP */, true); + return value; +} + +const convert = (val) => shared.isObject(val) ? reactive(val) : val; +function isRef(r) { + return Boolean(r && r.__v_isRef === true); +} +function ref(value) { + return createRef(value); +} +function shallowRef(value) { + return createRef(value, true); +} +class RefImpl { + constructor(value, _shallow = false) { + this._shallow = _shallow; + this.__v_isRef = true; + this._rawValue = _shallow ? value : toRaw(value); + this._value = _shallow ? value : convert(value); + } + get value() { + track(toRaw(this), "get" /* GET */, 'value'); + return this._value; + } + set value(newVal) { + newVal = this._shallow ? newVal : toRaw(newVal); + if (shared.hasChanged(newVal, this._rawValue)) { + this._rawValue = newVal; + this._value = this._shallow ? newVal : convert(newVal); + trigger(toRaw(this), "set" /* SET */, 'value', newVal); + } + } +} +function createRef(rawValue, shallow = false) { + if (isRef(rawValue)) { + return rawValue; + } + return new RefImpl(rawValue, shallow); +} +function triggerRef(ref) { + trigger(toRaw(ref), "set" /* SET */, 'value', ref.value ); +} +function unref(ref) { + return isRef(ref) ? ref.value : ref; +} +const shallowUnwrapHandlers = { + get: (target, key, receiver) => unref(Reflect.get(target, key, receiver)), + set: (target, key, value, receiver) => { + const oldValue = target[key]; + if (isRef(oldValue) && !isRef(value)) { + oldValue.value = value; + return true; + } + else { + return Reflect.set(target, key, value, receiver); + } + } +}; +function proxyRefs(objectWithRefs) { + return isReactive(objectWithRefs) + ? objectWithRefs + : new Proxy(objectWithRefs, shallowUnwrapHandlers); +} +class CustomRefImpl { + constructor(factory) { + this.__v_isRef = true; + const { get, set } = factory(() => track(this, "get" /* GET */, 'value'), () => trigger(this, "set" /* SET */, 'value')); + this._get = get; + this._set = set; + } + get value() { + return this._get(); + } + set value(newVal) { + this._set(newVal); + } +} +function customRef(factory) { + return new CustomRefImpl(factory); +} +function toRefs(object) { + if (!isProxy(object)) { + console.warn(`toRefs() expects a reactive object but received a plain one.`); + } + const ret = shared.isArray(object) ? new Array(object.length) : {}; + for (const key in object) { + ret[key] = toRef(object, key); + } + return ret; +} +class ObjectRefImpl { + constructor(_object, _key) { + this._object = _object; + this._key = _key; + this.__v_isRef = true; + } + get value() { + return this._object[this._key]; + } + set value(newVal) { + this._object[this._key] = newVal; + } +} +function toRef(object, key) { + return isRef(object[key]) + ? object[key] + : new ObjectRefImpl(object, key); +} + +class ComputedRefImpl { + constructor(getter, _setter, isReadonly) { + this._setter = _setter; + this._dirty = true; + this.__v_isRef = true; + this.effect = effect(getter, { + lazy: true, + scheduler: () => { + if (!this._dirty) { + this._dirty = true; + trigger(toRaw(this), "set" /* SET */, 'value'); + } + } + }); + this["__v_isReadonly" /* IS_READONLY */] = isReadonly; + } + get value() { + // the computed ref may get wrapped by other proxies e.g. readonly() #3376 + const self = toRaw(this); + if (self._dirty) { + self._value = this.effect(); + self._dirty = false; + } + track(self, "get" /* GET */, 'value'); + return self._value; + } + set value(newValue) { + this._setter(newValue); + } +} +function computed(getterOrOptions) { + let getter; + let setter; + if (shared.isFunction(getterOrOptions)) { + getter = getterOrOptions; + setter = () => { + console.warn('Write operation failed: computed value is readonly'); + } + ; + } + else { + getter = getterOrOptions.get; + setter = getterOrOptions.set; + } + return new ComputedRefImpl(getter, setter, shared.isFunction(getterOrOptions) || !getterOrOptions.set); +} + +exports.ITERATE_KEY = ITERATE_KEY; +exports.computed = computed; +exports.customRef = customRef; +exports.effect = effect; +exports.enableTracking = enableTracking; +exports.isProxy = isProxy; +exports.isReactive = isReactive; +exports.isReadonly = isReadonly; +exports.isRef = isRef; +exports.markRaw = markRaw; +exports.pauseTracking = pauseTracking; +exports.proxyRefs = proxyRefs; +exports.reactive = reactive; +exports.readonly = readonly; +exports.ref = ref; +exports.resetTracking = resetTracking; +exports.shallowReactive = shallowReactive; +exports.shallowReadonly = shallowReadonly; +exports.shallowRef = shallowRef; +exports.stop = stop; +exports.toRaw = toRaw; +exports.toRef = toRef; +exports.toRefs = toRefs; +exports.track = track; +exports.trigger = trigger; +exports.triggerRef = triggerRef; +exports.unref = unref; diff --git a/node_modules/@vue/reactivity/dist/reactivity.cjs.prod.js b/node_modules/@vue/reactivity/dist/reactivity.cjs.prod.js new file mode 100644 index 0000000..09dd02b --- /dev/null +++ b/node_modules/@vue/reactivity/dist/reactivity.cjs.prod.js @@ -0,0 +1,873 @@ +'use strict'; + +Object.defineProperty(exports, '__esModule', { value: true }); + +var shared = require('@vue/shared'); + +const targetMap = new WeakMap(); +const effectStack = []; +let activeEffect; +const ITERATE_KEY = Symbol(''); +const MAP_KEY_ITERATE_KEY = Symbol(''); +function isEffect(fn) { + return fn && fn._isEffect === true; +} +function effect(fn, options = shared.EMPTY_OBJ) { + if (isEffect(fn)) { + fn = fn.raw; + } + const effect = createReactiveEffect(fn, options); + if (!options.lazy) { + effect(); + } + return effect; +} +function stop(effect) { + if (effect.active) { + cleanup(effect); + if (effect.options.onStop) { + effect.options.onStop(); + } + effect.active = false; + } +} +let uid = 0; +function createReactiveEffect(fn, options) { + const effect = function reactiveEffect() { + if (!effect.active) { + return fn(); + } + if (!effectStack.includes(effect)) { + cleanup(effect); + try { + enableTracking(); + effectStack.push(effect); + activeEffect = effect; + return fn(); + } + finally { + effectStack.pop(); + resetTracking(); + activeEffect = effectStack[effectStack.length - 1]; + } + } + }; + effect.id = uid++; + effect.allowRecurse = !!options.allowRecurse; + effect._isEffect = true; + effect.active = true; + effect.raw = fn; + effect.deps = []; + effect.options = options; + return effect; +} +function cleanup(effect) { + const { deps } = effect; + if (deps.length) { + for (let i = 0; i < deps.length; i++) { + deps[i].delete(effect); + } + deps.length = 0; + } +} +let shouldTrack = true; +const trackStack = []; +function pauseTracking() { + trackStack.push(shouldTrack); + shouldTrack = false; +} +function enableTracking() { + trackStack.push(shouldTrack); + shouldTrack = true; +} +function resetTracking() { + const last = trackStack.pop(); + shouldTrack = last === undefined ? true : last; +} +function track(target, type, key) { + if (!shouldTrack || activeEffect === undefined) { + return; + } + let depsMap = targetMap.get(target); + if (!depsMap) { + targetMap.set(target, (depsMap = new Map())); + } + let dep = depsMap.get(key); + if (!dep) { + depsMap.set(key, (dep = new Set())); + } + if (!dep.has(activeEffect)) { + dep.add(activeEffect); + activeEffect.deps.push(dep); + } +} +function trigger(target, type, key, newValue, oldValue, oldTarget) { + const depsMap = targetMap.get(target); + if (!depsMap) { + // never been tracked + return; + } + const effects = new Set(); + const add = (effectsToAdd) => { + if (effectsToAdd) { + effectsToAdd.forEach(effect => { + if (effect !== activeEffect || effect.allowRecurse) { + effects.add(effect); + } + }); + } + }; + if (type === "clear" /* CLEAR */) { + // collection being cleared + // trigger all effects for target + depsMap.forEach(add); + } + else if (key === 'length' && shared.isArray(target)) { + depsMap.forEach((dep, key) => { + if (key === 'length' || key >= newValue) { + add(dep); + } + }); + } + else { + // schedule runs for SET | ADD | DELETE + if (key !== void 0) { + add(depsMap.get(key)); + } + // also run for iteration key on ADD | DELETE | Map.SET + switch (type) { + case "add" /* ADD */: + if (!shared.isArray(target)) { + add(depsMap.get(ITERATE_KEY)); + if (shared.isMap(target)) { + add(depsMap.get(MAP_KEY_ITERATE_KEY)); + } + } + else if (shared.isIntegerKey(key)) { + // new index added to array -> length changes + add(depsMap.get('length')); + } + break; + case "delete" /* DELETE */: + if (!shared.isArray(target)) { + add(depsMap.get(ITERATE_KEY)); + if (shared.isMap(target)) { + add(depsMap.get(MAP_KEY_ITERATE_KEY)); + } + } + break; + case "set" /* SET */: + if (shared.isMap(target)) { + add(depsMap.get(ITERATE_KEY)); + } + break; + } + } + const run = (effect) => { + if (effect.options.scheduler) { + effect.options.scheduler(effect); + } + else { + effect(); + } + }; + effects.forEach(run); +} + +const isNonTrackableKeys = /*#__PURE__*/ shared.makeMap(`__proto__,__v_isRef,__isVue`); +const builtInSymbols = new Set(Object.getOwnPropertyNames(Symbol) + .map(key => Symbol[key]) + .filter(shared.isSymbol)); +const get = /*#__PURE__*/ createGetter(); +const shallowGet = /*#__PURE__*/ createGetter(false, true); +const readonlyGet = /*#__PURE__*/ createGetter(true); +const shallowReadonlyGet = /*#__PURE__*/ createGetter(true, true); +const arrayInstrumentations = /*#__PURE__*/ createArrayInstrumentations(); +function createArrayInstrumentations() { + const instrumentations = {}; + ['includes', 'indexOf', 'lastIndexOf'].forEach(key => { + instrumentations[key] = function (...args) { + const arr = toRaw(this); + for (let i = 0, l = this.length; i < l; i++) { + track(arr, "get" /* GET */, i + ''); + } + // we run the method using the original args first (which may be reactive) + const res = arr[key](...args); + if (res === -1 || res === false) { + // if that didn't work, run it again using raw values. + return arr[key](...args.map(toRaw)); + } + else { + return res; + } + }; + }); + ['push', 'pop', 'shift', 'unshift', 'splice'].forEach(key => { + instrumentations[key] = function (...args) { + pauseTracking(); + const res = toRaw(this)[key].apply(this, args); + resetTracking(); + return res; + }; + }); + return instrumentations; +} +function createGetter(isReadonly = false, shallow = false) { + return function get(target, key, receiver) { + if (key === "__v_isReactive" /* IS_REACTIVE */) { + return !isReadonly; + } + else if (key === "__v_isReadonly" /* IS_READONLY */) { + return isReadonly; + } + else if (key === "__v_raw" /* RAW */ && + receiver === + (isReadonly + ? shallow + ? shallowReadonlyMap + : readonlyMap + : shallow + ? shallowReactiveMap + : reactiveMap).get(target)) { + return target; + } + const targetIsArray = shared.isArray(target); + if (!isReadonly && targetIsArray && shared.hasOwn(arrayInstrumentations, key)) { + return Reflect.get(arrayInstrumentations, key, receiver); + } + const res = Reflect.get(target, key, receiver); + if (shared.isSymbol(key) ? builtInSymbols.has(key) : isNonTrackableKeys(key)) { + return res; + } + if (!isReadonly) { + track(target, "get" /* GET */, key); + } + if (shallow) { + return res; + } + if (isRef(res)) { + // ref unwrapping - does not apply for Array + integer key. + const shouldUnwrap = !targetIsArray || !shared.isIntegerKey(key); + return shouldUnwrap ? res.value : res; + } + if (shared.isObject(res)) { + // Convert returned value into a proxy as well. we do the isObject check + // here to avoid invalid value warning. Also need to lazy access readonly + // and reactive here to avoid circular dependency. + return isReadonly ? readonly(res) : reactive(res); + } + return res; + }; +} +const set = /*#__PURE__*/ createSetter(); +const shallowSet = /*#__PURE__*/ createSetter(true); +function createSetter(shallow = false) { + return function set(target, key, value, receiver) { + let oldValue = target[key]; + if (!shallow) { + value = toRaw(value); + oldValue = toRaw(oldValue); + if (!shared.isArray(target) && isRef(oldValue) && !isRef(value)) { + oldValue.value = value; + return true; + } + } + const hadKey = shared.isArray(target) && shared.isIntegerKey(key) + ? Number(key) < target.length + : shared.hasOwn(target, key); + const result = Reflect.set(target, key, value, receiver); + // don't trigger if target is something up in the prototype chain of original + if (target === toRaw(receiver)) { + if (!hadKey) { + trigger(target, "add" /* ADD */, key, value); + } + else if (shared.hasChanged(value, oldValue)) { + trigger(target, "set" /* SET */, key, value); + } + } + return result; + }; +} +function deleteProperty(target, key) { + const hadKey = shared.hasOwn(target, key); + target[key]; + const result = Reflect.deleteProperty(target, key); + if (result && hadKey) { + trigger(target, "delete" /* DELETE */, key, undefined); + } + return result; +} +function has(target, key) { + const result = Reflect.has(target, key); + if (!shared.isSymbol(key) || !builtInSymbols.has(key)) { + track(target, "has" /* HAS */, key); + } + return result; +} +function ownKeys(target) { + track(target, "iterate" /* ITERATE */, shared.isArray(target) ? 'length' : ITERATE_KEY); + return Reflect.ownKeys(target); +} +const mutableHandlers = { + get, + set, + deleteProperty, + has, + ownKeys +}; +const readonlyHandlers = { + get: readonlyGet, + set(target, key) { + return true; + }, + deleteProperty(target, key) { + return true; + } +}; +const shallowReactiveHandlers = /*#__PURE__*/ shared.extend({}, mutableHandlers, { + get: shallowGet, + set: shallowSet +}); +// Props handlers are special in the sense that it should not unwrap top-level +// refs (in order to allow refs to be explicitly passed down), but should +// retain the reactivity of the normal readonly object. +const shallowReadonlyHandlers = /*#__PURE__*/ shared.extend({}, readonlyHandlers, { + get: shallowReadonlyGet +}); + +const toReactive = (value) => shared.isObject(value) ? reactive(value) : value; +const toReadonly = (value) => shared.isObject(value) ? readonly(value) : value; +const toShallow = (value) => value; +const getProto = (v) => Reflect.getPrototypeOf(v); +function get$1(target, key, isReadonly = false, isShallow = false) { + // #1772: readonly(reactive(Map)) should return readonly + reactive version + // of the value + target = target["__v_raw" /* RAW */]; + const rawTarget = toRaw(target); + const rawKey = toRaw(key); + if (key !== rawKey) { + !isReadonly && track(rawTarget, "get" /* GET */, key); + } + !isReadonly && track(rawTarget, "get" /* GET */, rawKey); + const { has } = getProto(rawTarget); + const wrap = isShallow ? toShallow : isReadonly ? toReadonly : toReactive; + if (has.call(rawTarget, key)) { + return wrap(target.get(key)); + } + else if (has.call(rawTarget, rawKey)) { + return wrap(target.get(rawKey)); + } + else if (target !== rawTarget) { + // #3602 readonly(reactive(Map)) + // ensure that the nested reactive `Map` can do tracking for itself + target.get(key); + } +} +function has$1(key, isReadonly = false) { + const target = this["__v_raw" /* RAW */]; + const rawTarget = toRaw(target); + const rawKey = toRaw(key); + if (key !== rawKey) { + !isReadonly && track(rawTarget, "has" /* HAS */, key); + } + !isReadonly && track(rawTarget, "has" /* HAS */, rawKey); + return key === rawKey + ? target.has(key) + : target.has(key) || target.has(rawKey); +} +function size(target, isReadonly = false) { + target = target["__v_raw" /* RAW */]; + !isReadonly && track(toRaw(target), "iterate" /* ITERATE */, ITERATE_KEY); + return Reflect.get(target, 'size', target); +} +function add(value) { + value = toRaw(value); + const target = toRaw(this); + const proto = getProto(target); + const hadKey = proto.has.call(target, value); + if (!hadKey) { + target.add(value); + trigger(target, "add" /* ADD */, value, value); + } + return this; +} +function set$1(key, value) { + value = toRaw(value); + const target = toRaw(this); + const { has, get } = getProto(target); + let hadKey = has.call(target, key); + if (!hadKey) { + key = toRaw(key); + hadKey = has.call(target, key); + } + const oldValue = get.call(target, key); + target.set(key, value); + if (!hadKey) { + trigger(target, "add" /* ADD */, key, value); + } + else if (shared.hasChanged(value, oldValue)) { + trigger(target, "set" /* SET */, key, value); + } + return this; +} +function deleteEntry(key) { + const target = toRaw(this); + const { has, get } = getProto(target); + let hadKey = has.call(target, key); + if (!hadKey) { + key = toRaw(key); + hadKey = has.call(target, key); + } + get ? get.call(target, key) : undefined; + // forward the operation before queueing reactions + const result = target.delete(key); + if (hadKey) { + trigger(target, "delete" /* DELETE */, key, undefined); + } + return result; +} +function clear() { + const target = toRaw(this); + const hadItems = target.size !== 0; + // forward the operation before queueing reactions + const result = target.clear(); + if (hadItems) { + trigger(target, "clear" /* CLEAR */, undefined, undefined); + } + return result; +} +function createForEach(isReadonly, isShallow) { + return function forEach(callback, thisArg) { + const observed = this; + const target = observed["__v_raw" /* RAW */]; + const rawTarget = toRaw(target); + const wrap = isShallow ? toShallow : isReadonly ? toReadonly : toReactive; + !isReadonly && track(rawTarget, "iterate" /* ITERATE */, ITERATE_KEY); + return target.forEach((value, key) => { + // important: make sure the callback is + // 1. invoked with the reactive map as `this` and 3rd arg + // 2. the value received should be a corresponding reactive/readonly. + return callback.call(thisArg, wrap(value), wrap(key), observed); + }); + }; +} +function createIterableMethod(method, isReadonly, isShallow) { + return function (...args) { + const target = this["__v_raw" /* RAW */]; + const rawTarget = toRaw(target); + const targetIsMap = shared.isMap(rawTarget); + const isPair = method === 'entries' || (method === Symbol.iterator && targetIsMap); + const isKeyOnly = method === 'keys' && targetIsMap; + const innerIterator = target[method](...args); + const wrap = isShallow ? toShallow : isReadonly ? toReadonly : toReactive; + !isReadonly && + track(rawTarget, "iterate" /* ITERATE */, isKeyOnly ? MAP_KEY_ITERATE_KEY : ITERATE_KEY); + // return a wrapped iterator which returns observed versions of the + // values emitted from the real iterator + return { + // iterator protocol + next() { + const { value, done } = innerIterator.next(); + return done + ? { value, done } + : { + value: isPair ? [wrap(value[0]), wrap(value[1])] : wrap(value), + done + }; + }, + // iterable protocol + [Symbol.iterator]() { + return this; + } + }; + }; +} +function createReadonlyMethod(type) { + return function (...args) { + return type === "delete" /* DELETE */ ? false : this; + }; +} +function createInstrumentations() { + const mutableInstrumentations = { + get(key) { + return get$1(this, key); + }, + get size() { + return size(this); + }, + has: has$1, + add, + set: set$1, + delete: deleteEntry, + clear, + forEach: createForEach(false, false) + }; + const shallowInstrumentations = { + get(key) { + return get$1(this, key, false, true); + }, + get size() { + return size(this); + }, + has: has$1, + add, + set: set$1, + delete: deleteEntry, + clear, + forEach: createForEach(false, true) + }; + const readonlyInstrumentations = { + get(key) { + return get$1(this, key, true); + }, + get size() { + return size(this, true); + }, + has(key) { + return has$1.call(this, key, true); + }, + add: createReadonlyMethod("add" /* ADD */), + set: createReadonlyMethod("set" /* SET */), + delete: createReadonlyMethod("delete" /* DELETE */), + clear: createReadonlyMethod("clear" /* CLEAR */), + forEach: createForEach(true, false) + }; + const shallowReadonlyInstrumentations = { + get(key) { + return get$1(this, key, true, true); + }, + get size() { + return size(this, true); + }, + has(key) { + return has$1.call(this, key, true); + }, + add: createReadonlyMethod("add" /* ADD */), + set: createReadonlyMethod("set" /* SET */), + delete: createReadonlyMethod("delete" /* DELETE */), + clear: createReadonlyMethod("clear" /* CLEAR */), + forEach: createForEach(true, true) + }; + const iteratorMethods = ['keys', 'values', 'entries', Symbol.iterator]; + iteratorMethods.forEach(method => { + mutableInstrumentations[method] = createIterableMethod(method, false, false); + readonlyInstrumentations[method] = createIterableMethod(method, true, false); + shallowInstrumentations[method] = createIterableMethod(method, false, true); + shallowReadonlyInstrumentations[method] = createIterableMethod(method, true, true); + }); + return [ + mutableInstrumentations, + readonlyInstrumentations, + shallowInstrumentations, + shallowReadonlyInstrumentations + ]; +} +const [mutableInstrumentations, readonlyInstrumentations, shallowInstrumentations, shallowReadonlyInstrumentations] = /* #__PURE__*/ createInstrumentations(); +function createInstrumentationGetter(isReadonly, shallow) { + const instrumentations = shallow + ? isReadonly + ? shallowReadonlyInstrumentations + : shallowInstrumentations + : isReadonly + ? readonlyInstrumentations + : mutableInstrumentations; + return (target, key, receiver) => { + if (key === "__v_isReactive" /* IS_REACTIVE */) { + return !isReadonly; + } + else if (key === "__v_isReadonly" /* IS_READONLY */) { + return isReadonly; + } + else if (key === "__v_raw" /* RAW */) { + return target; + } + return Reflect.get(shared.hasOwn(instrumentations, key) && key in target + ? instrumentations + : target, key, receiver); + }; +} +const mutableCollectionHandlers = { + get: /*#__PURE__*/ createInstrumentationGetter(false, false) +}; +const shallowCollectionHandlers = { + get: /*#__PURE__*/ createInstrumentationGetter(false, true) +}; +const readonlyCollectionHandlers = { + get: /*#__PURE__*/ createInstrumentationGetter(true, false) +}; +const shallowReadonlyCollectionHandlers = { + get: /*#__PURE__*/ createInstrumentationGetter(true, true) +}; + +const reactiveMap = new WeakMap(); +const shallowReactiveMap = new WeakMap(); +const readonlyMap = new WeakMap(); +const shallowReadonlyMap = new WeakMap(); +function targetTypeMap(rawType) { + switch (rawType) { + case 'Object': + case 'Array': + return 1 /* COMMON */; + case 'Map': + case 'Set': + case 'WeakMap': + case 'WeakSet': + return 2 /* COLLECTION */; + default: + return 0 /* INVALID */; + } +} +function getTargetType(value) { + return value["__v_skip" /* SKIP */] || !Object.isExtensible(value) + ? 0 /* INVALID */ + : targetTypeMap(shared.toRawType(value)); +} +function reactive(target) { + // if trying to observe a readonly proxy, return the readonly version. + if (target && target["__v_isReadonly" /* IS_READONLY */]) { + return target; + } + return createReactiveObject(target, false, mutableHandlers, mutableCollectionHandlers, reactiveMap); +} +/** + * Return a shallowly-reactive copy of the original object, where only the root + * level properties are reactive. It also does not auto-unwrap refs (even at the + * root level). + */ +function shallowReactive(target) { + return createReactiveObject(target, false, shallowReactiveHandlers, shallowCollectionHandlers, shallowReactiveMap); +} +/** + * Creates a readonly copy of the original object. Note the returned copy is not + * made reactive, but `readonly` can be called on an already reactive object. + */ +function readonly(target) { + return createReactiveObject(target, true, readonlyHandlers, readonlyCollectionHandlers, readonlyMap); +} +/** + * Returns a reactive-copy of the original object, where only the root level + * properties are readonly, and does NOT unwrap refs nor recursively convert + * returned properties. + * This is used for creating the props proxy object for stateful components. + */ +function shallowReadonly(target) { + return createReactiveObject(target, true, shallowReadonlyHandlers, shallowReadonlyCollectionHandlers, shallowReadonlyMap); +} +function createReactiveObject(target, isReadonly, baseHandlers, collectionHandlers, proxyMap) { + if (!shared.isObject(target)) { + return target; + } + // target is already a Proxy, return it. + // exception: calling readonly() on a reactive object + if (target["__v_raw" /* RAW */] && + !(isReadonly && target["__v_isReactive" /* IS_REACTIVE */])) { + return target; + } + // target already has corresponding Proxy + const existingProxy = proxyMap.get(target); + if (existingProxy) { + return existingProxy; + } + // only a whitelist of value types can be observed. + const targetType = getTargetType(target); + if (targetType === 0 /* INVALID */) { + return target; + } + const proxy = new Proxy(target, targetType === 2 /* COLLECTION */ ? collectionHandlers : baseHandlers); + proxyMap.set(target, proxy); + return proxy; +} +function isReactive(value) { + if (isReadonly(value)) { + return isReactive(value["__v_raw" /* RAW */]); + } + return !!(value && value["__v_isReactive" /* IS_REACTIVE */]); +} +function isReadonly(value) { + return !!(value && value["__v_isReadonly" /* IS_READONLY */]); +} +function isProxy(value) { + return isReactive(value) || isReadonly(value); +} +function toRaw(observed) { + return ((observed && toRaw(observed["__v_raw" /* RAW */])) || observed); +} +function markRaw(value) { + shared.def(value, "__v_skip" /* SKIP */, true); + return value; +} + +const convert = (val) => shared.isObject(val) ? reactive(val) : val; +function isRef(r) { + return Boolean(r && r.__v_isRef === true); +} +function ref(value) { + return createRef(value); +} +function shallowRef(value) { + return createRef(value, true); +} +class RefImpl { + constructor(value, _shallow = false) { + this._shallow = _shallow; + this.__v_isRef = true; + this._rawValue = _shallow ? value : toRaw(value); + this._value = _shallow ? value : convert(value); + } + get value() { + track(toRaw(this), "get" /* GET */, 'value'); + return this._value; + } + set value(newVal) { + newVal = this._shallow ? newVal : toRaw(newVal); + if (shared.hasChanged(newVal, this._rawValue)) { + this._rawValue = newVal; + this._value = this._shallow ? newVal : convert(newVal); + trigger(toRaw(this), "set" /* SET */, 'value', newVal); + } + } +} +function createRef(rawValue, shallow = false) { + if (isRef(rawValue)) { + return rawValue; + } + return new RefImpl(rawValue, shallow); +} +function triggerRef(ref) { + trigger(toRaw(ref), "set" /* SET */, 'value', void 0); +} +function unref(ref) { + return isRef(ref) ? ref.value : ref; +} +const shallowUnwrapHandlers = { + get: (target, key, receiver) => unref(Reflect.get(target, key, receiver)), + set: (target, key, value, receiver) => { + const oldValue = target[key]; + if (isRef(oldValue) && !isRef(value)) { + oldValue.value = value; + return true; + } + else { + return Reflect.set(target, key, value, receiver); + } + } +}; +function proxyRefs(objectWithRefs) { + return isReactive(objectWithRefs) + ? objectWithRefs + : new Proxy(objectWithRefs, shallowUnwrapHandlers); +} +class CustomRefImpl { + constructor(factory) { + this.__v_isRef = true; + const { get, set } = factory(() => track(this, "get" /* GET */, 'value'), () => trigger(this, "set" /* SET */, 'value')); + this._get = get; + this._set = set; + } + get value() { + return this._get(); + } + set value(newVal) { + this._set(newVal); + } +} +function customRef(factory) { + return new CustomRefImpl(factory); +} +function toRefs(object) { + const ret = shared.isArray(object) ? new Array(object.length) : {}; + for (const key in object) { + ret[key] = toRef(object, key); + } + return ret; +} +class ObjectRefImpl { + constructor(_object, _key) { + this._object = _object; + this._key = _key; + this.__v_isRef = true; + } + get value() { + return this._object[this._key]; + } + set value(newVal) { + this._object[this._key] = newVal; + } +} +function toRef(object, key) { + return isRef(object[key]) + ? object[key] + : new ObjectRefImpl(object, key); +} + +class ComputedRefImpl { + constructor(getter, _setter, isReadonly) { + this._setter = _setter; + this._dirty = true; + this.__v_isRef = true; + this.effect = effect(getter, { + lazy: true, + scheduler: () => { + if (!this._dirty) { + this._dirty = true; + trigger(toRaw(this), "set" /* SET */, 'value'); + } + } + }); + this["__v_isReadonly" /* IS_READONLY */] = isReadonly; + } + get value() { + // the computed ref may get wrapped by other proxies e.g. readonly() #3376 + const self = toRaw(this); + if (self._dirty) { + self._value = this.effect(); + self._dirty = false; + } + track(self, "get" /* GET */, 'value'); + return self._value; + } + set value(newValue) { + this._setter(newValue); + } +} +function computed(getterOrOptions) { + let getter; + let setter; + if (shared.isFunction(getterOrOptions)) { + getter = getterOrOptions; + setter = shared.NOOP; + } + else { + getter = getterOrOptions.get; + setter = getterOrOptions.set; + } + return new ComputedRefImpl(getter, setter, shared.isFunction(getterOrOptions) || !getterOrOptions.set); +} + +exports.ITERATE_KEY = ITERATE_KEY; +exports.computed = computed; +exports.customRef = customRef; +exports.effect = effect; +exports.enableTracking = enableTracking; +exports.isProxy = isProxy; +exports.isReactive = isReactive; +exports.isReadonly = isReadonly; +exports.isRef = isRef; +exports.markRaw = markRaw; +exports.pauseTracking = pauseTracking; +exports.proxyRefs = proxyRefs; +exports.reactive = reactive; +exports.readonly = readonly; +exports.ref = ref; +exports.resetTracking = resetTracking; +exports.shallowReactive = shallowReactive; +exports.shallowReadonly = shallowReadonly; +exports.shallowRef = shallowRef; +exports.stop = stop; +exports.toRaw = toRaw; +exports.toRef = toRef; +exports.toRefs = toRefs; +exports.track = track; +exports.trigger = trigger; +exports.triggerRef = triggerRef; +exports.unref = unref; diff --git a/node_modules/@vue/reactivity/dist/reactivity.d.ts b/node_modules/@vue/reactivity/dist/reactivity.d.ts new file mode 100644 index 0000000..8934716 --- /dev/null +++ b/node_modules/@vue/reactivity/dist/reactivity.d.ts @@ -0,0 +1,323 @@ + +declare type BaseTypes = string | number | boolean; + +declare type Builtin = Primitive | Function | Date | Error | RegExp; + +declare type CollectionTypes = IterableCollections | WeakCollections; + +export declare function computed(getter: ComputedGetter): ComputedRef; + +export declare function computed(options: WritableComputedOptions): WritableComputedRef; + +export declare type ComputedGetter = (ctx?: any) => T; + +export declare interface ComputedRef extends WritableComputedRef { + readonly value: T; +} + +export declare type ComputedSetter = (v: T) => void; + +export declare function customRef(factory: CustomRefFactory): Ref; + +declare type CustomRefFactory = (track: () => void, trigger: () => void) => { + get: () => T; + set: (value: T) => void; +}; + +export declare type DebuggerEvent = { + effect: ReactiveEffect; + target: object; + type: TrackOpTypes | TriggerOpTypes; + key: any; +} & DebuggerEventExtraInfo; + +declare interface DebuggerEventExtraInfo { + newValue?: any; + oldValue?: any; + oldTarget?: Map | Set; +} + +export declare type DeepReadonly = T extends Builtin ? T : T extends Map ? ReadonlyMap, DeepReadonly> : T extends ReadonlyMap ? ReadonlyMap, DeepReadonly> : T extends WeakMap ? WeakMap, DeepReadonly> : T extends Set ? ReadonlySet> : T extends ReadonlySet ? ReadonlySet> : T extends WeakSet ? WeakSet> : T extends Promise ? Promise> : T extends {} ? { + readonly [K in keyof T]: DeepReadonly; +} : Readonly; + +declare type Dep = Set; + +export declare function effect(fn: () => T, options?: ReactiveEffectOptions): ReactiveEffect; + +export declare function enableTracking(): void; + +export declare function isProxy(value: unknown): boolean; + +export declare function isReactive(value: unknown): boolean; + +export declare function isReadonly(value: unknown): boolean; + +export declare function isRef(r: Ref | unknown): r is Ref; + +declare type IterableCollections = Map | Set; + +export declare const ITERATE_KEY: unique symbol; + +export declare function markRaw(value: T): T; + +export declare function pauseTracking(): void; + +declare type Primitive = string | number | boolean | bigint | symbol | undefined | null; + +export declare function proxyRefs(objectWithRefs: T): ShallowUnwrapRef; + +/** + * Creates a reactive copy of the original object. + * + * The reactive conversion is "deep"—it affects all nested properties. In the + * ES2015 Proxy based implementation, the returned proxy is **not** equal to the + * original object. It is recommended to work exclusively with the reactive + * proxy and avoid relying on the original object. + * + * A reactive object also automatically unwraps refs contained in it, so you + * don't need to use `.value` when accessing and mutating their value: + * + * ```js + * const count = ref(0) + * const obj = reactive({ + * count + * }) + * + * obj.count++ + * obj.count // -> 1 + * count.value // -> 1 + * ``` + */ +export declare function reactive(target: T): UnwrapNestedRefs; + +export declare interface ReactiveEffect { + (): T; + _isEffect: true; + id: number; + active: boolean; + raw: () => T; + deps: Array; + options: ReactiveEffectOptions; + allowRecurse: boolean; +} + +export declare interface ReactiveEffectOptions { + lazy?: boolean; + scheduler?: (job: ReactiveEffect) => void; + onTrack?: (event: DebuggerEvent) => void; + onTrigger?: (event: DebuggerEvent) => void; + onStop?: () => void; + /** + * Indicates whether the job is allowed to recursively trigger itself when + * managed by the scheduler. + * + * By default, a job cannot trigger itself because some built-in method calls, + * e.g. Array.prototype.push actually performs reads as well (#1740) which + * can lead to confusing infinite loops. + * The allowed cases are component update functions and watch callbacks. + * Component update functions may update child component props, which in turn + * trigger flush: "pre" watch callbacks that mutates state that the parent + * relies on (#1801). Watch callbacks doesn't track its dependencies so if it + * triggers itself again, it's likely intentional and it is the user's + * responsibility to perform recursive state mutation that eventually + * stabilizes (#1727). + */ + allowRecurse?: boolean; +} + +export declare const enum ReactiveFlags { + SKIP = "__v_skip", + IS_REACTIVE = "__v_isReactive", + IS_READONLY = "__v_isReadonly", + RAW = "__v_raw" +} + +/** + * Creates a readonly copy of the original object. Note the returned copy is not + * made reactive, but `readonly` can be called on an already reactive object. + */ +export declare function readonly(target: T): DeepReadonly>; + +export declare interface Ref { + value: T; + /** + * Type differentiator only. + * We need this to be in public d.ts but don't want it to show up in IDE + * autocomplete, so we use a private Symbol instead. + */ + [RefSymbol]: true; + /* Excluded from this release type: _shallow */ +} + +export declare function ref(value: T): ToRef; + +export declare function ref(value: T): Ref>; + +export declare function ref(): Ref; + +declare const RefSymbol: unique symbol; + +/** + * This is a special exported interface for other packages to declare + * additional types that should bail out for ref unwrapping. For example + * \@vue/runtime-dom can declare it like so in its d.ts: + * + * ``` ts + * declare module '@vue/reactivity' { + * export interface RefUnwrapBailTypes { + * runtimeDOMBailTypes: Node | Window + * } + * } + * ``` + * + * Note that api-extractor somehow refuses to include `declare module` + * augmentations in its generated d.ts, so we have to manually append them + * to the final generated d.ts in our build process. + */ +export declare interface RefUnwrapBailTypes { +} + +export declare function resetTracking(): void; + +/** + * Return a shallowly-reactive copy of the original object, where only the root + * level properties are reactive. It also does not auto-unwrap refs (even at the + * root level). + */ +export declare function shallowReactive(target: T): T; + +/** + * Returns a reactive-copy of the original object, where only the root level + * properties are readonly, and does NOT unwrap refs nor recursively convert + * returned properties. + * This is used for creating the props proxy object for stateful components. + */ +export declare function shallowReadonly(target: T): Readonly<{ + [K in keyof T]: UnwrapNestedRefs; +}>; + +export declare function shallowRef(value: T): T extends Ref ? T : Ref; + +export declare function shallowRef(value: T): Ref; + +export declare function shallowRef(): Ref; + +export declare type ShallowUnwrapRef = { + [K in keyof T]: T[K] extends Ref ? V : T[K] extends Ref | undefined ? unknown extends V ? undefined : V | undefined : T[K]; +}; + +declare function stop_2(effect: ReactiveEffect): void; +export { stop_2 as stop } + +declare type SymbolExtract = (T extends { + [Symbol.asyncIterator]: infer V; +} ? { + [Symbol.asyncIterator]: V; +} : {}) & (T extends { + [Symbol.hasInstance]: infer V; +} ? { + [Symbol.hasInstance]: V; +} : {}) & (T extends { + [Symbol.isConcatSpreadable]: infer V; +} ? { + [Symbol.isConcatSpreadable]: V; +} : {}) & (T extends { + [Symbol.iterator]: infer V; +} ? { + [Symbol.iterator]: V; +} : {}) & (T extends { + [Symbol.match]: infer V; +} ? { + [Symbol.match]: V; +} : {}) & (T extends { + [Symbol.matchAll]: infer V; +} ? { + [Symbol.matchAll]: V; +} : {}) & (T extends { + [Symbol.replace]: infer V; +} ? { + [Symbol.replace]: V; +} : {}) & (T extends { + [Symbol.search]: infer V; +} ? { + [Symbol.search]: V; +} : {}) & (T extends { + [Symbol.species]: infer V; +} ? { + [Symbol.species]: V; +} : {}) & (T extends { + [Symbol.split]: infer V; +} ? { + [Symbol.split]: V; +} : {}) & (T extends { + [Symbol.toPrimitive]: infer V; +} ? { + [Symbol.toPrimitive]: V; +} : {}) & (T extends { + [Symbol.toStringTag]: infer V; +} ? { + [Symbol.toStringTag]: V; +} : {}) & (T extends { + [Symbol.unscopables]: infer V; +} ? { + [Symbol.unscopables]: V; +} : {}); + +export declare function toRaw(observed: T): T; + +declare type ToRef = [T] extends [Ref] ? T : Ref>; + +export declare function toRef(object: T, key: K): ToRef; + +export declare type ToRefs = { + [K in keyof T]: T[K] extends Ref ? T[K] : Ref>; +}; + +export declare function toRefs(object: T): ToRefs; + +export declare function track(target: object, type: TrackOpTypes, key: unknown): void; + +export declare const enum TrackOpTypes { + GET = "get", + HAS = "has", + ITERATE = "iterate" +} + +export declare function trigger(target: object, type: TriggerOpTypes, key?: unknown, newValue?: unknown, oldValue?: unknown, oldTarget?: Map | Set): void; + +export declare const enum TriggerOpTypes { + SET = "set", + ADD = "add", + DELETE = "delete", + CLEAR = "clear" +} + +export declare function triggerRef(ref: Ref): void; + +export declare function unref(ref: T | Ref): T; + +export declare type UnwrapNestedRefs = T extends Ref ? T : UnwrapRef; + +declare type UnwrappedObject = { + [P in keyof T]: UnwrapRef; +} & SymbolExtract; + +export declare type UnwrapRef = T extends Ref ? UnwrapRefSimple : UnwrapRefSimple; + +declare type UnwrapRefSimple = T extends Function | CollectionTypes | BaseTypes | Ref | RefUnwrapBailTypes[keyof RefUnwrapBailTypes] ? T : T extends Array ? { + [K in keyof T]: UnwrapRefSimple; +} : T extends object ? UnwrappedObject : T; + +declare type WeakCollections = WeakMap | WeakSet; + +export declare interface WritableComputedOptions { + get: ComputedGetter; + set: ComputedSetter; +} + +export declare interface WritableComputedRef extends Ref { + readonly effect: ReactiveEffect; +} + +export { } diff --git a/node_modules/@vue/reactivity/dist/reactivity.esm-browser.js b/node_modules/@vue/reactivity/dist/reactivity.esm-browser.js new file mode 100644 index 0000000..3ac4354 --- /dev/null +++ b/node_modules/@vue/reactivity/dist/reactivity.esm-browser.js @@ -0,0 +1,959 @@ +/** + * Make a map and return a function for checking if a key + * is in that map. + * IMPORTANT: all calls of this function must be prefixed with + * \/\*#\_\_PURE\_\_\*\/ + * So that rollup can tree-shake them if necessary. + */ +function makeMap(str, expectsLowerCase) { + const map = Object.create(null); + const list = str.split(','); + for (let i = 0; i < list.length; i++) { + map[list[i]] = true; + } + return expectsLowerCase ? val => !!map[val.toLowerCase()] : val => !!map[val]; +} + +const EMPTY_OBJ = Object.freeze({}) + ; +Object.freeze([]) ; +const extend = Object.assign; +const hasOwnProperty = Object.prototype.hasOwnProperty; +const hasOwn = (val, key) => hasOwnProperty.call(val, key); +const isArray = Array.isArray; +const isMap = (val) => toTypeString(val) === '[object Map]'; +const isFunction = (val) => typeof val === 'function'; +const isString = (val) => typeof val === 'string'; +const isSymbol = (val) => typeof val === 'symbol'; +const isObject = (val) => val !== null && typeof val === 'object'; +const objectToString = Object.prototype.toString; +const toTypeString = (value) => objectToString.call(value); +const toRawType = (value) => { + // extract "RawType" from strings like "[object RawType]" + return toTypeString(value).slice(8, -1); +}; +const isIntegerKey = (key) => isString(key) && + key !== 'NaN' && + key[0] !== '-' && + '' + parseInt(key, 10) === key; +const cacheStringFunction = (fn) => { + const cache = Object.create(null); + return ((str) => { + const hit = cache[str]; + return hit || (cache[str] = fn(str)); + }); +}; +/** + * @private + */ +const capitalize = cacheStringFunction((str) => str.charAt(0).toUpperCase() + str.slice(1)); +// compare whether a value has changed, accounting for NaN. +const hasChanged = (value, oldValue) => value !== oldValue && (value === value || oldValue === oldValue); +const def = (obj, key, value) => { + Object.defineProperty(obj, key, { + configurable: true, + enumerable: false, + value + }); +}; + +const targetMap = new WeakMap(); +const effectStack = []; +let activeEffect; +const ITERATE_KEY = Symbol('iterate' ); +const MAP_KEY_ITERATE_KEY = Symbol('Map key iterate' ); +function isEffect(fn) { + return fn && fn._isEffect === true; +} +function effect(fn, options = EMPTY_OBJ) { + if (isEffect(fn)) { + fn = fn.raw; + } + const effect = createReactiveEffect(fn, options); + if (!options.lazy) { + effect(); + } + return effect; +} +function stop(effect) { + if (effect.active) { + cleanup(effect); + if (effect.options.onStop) { + effect.options.onStop(); + } + effect.active = false; + } +} +let uid = 0; +function createReactiveEffect(fn, options) { + const effect = function reactiveEffect() { + if (!effect.active) { + return fn(); + } + if (!effectStack.includes(effect)) { + cleanup(effect); + try { + enableTracking(); + effectStack.push(effect); + activeEffect = effect; + return fn(); + } + finally { + effectStack.pop(); + resetTracking(); + activeEffect = effectStack[effectStack.length - 1]; + } + } + }; + effect.id = uid++; + effect.allowRecurse = !!options.allowRecurse; + effect._isEffect = true; + effect.active = true; + effect.raw = fn; + effect.deps = []; + effect.options = options; + return effect; +} +function cleanup(effect) { + const { deps } = effect; + if (deps.length) { + for (let i = 0; i < deps.length; i++) { + deps[i].delete(effect); + } + deps.length = 0; + } +} +let shouldTrack = true; +const trackStack = []; +function pauseTracking() { + trackStack.push(shouldTrack); + shouldTrack = false; +} +function enableTracking() { + trackStack.push(shouldTrack); + shouldTrack = true; +} +function resetTracking() { + const last = trackStack.pop(); + shouldTrack = last === undefined ? true : last; +} +function track(target, type, key) { + if (!shouldTrack || activeEffect === undefined) { + return; + } + let depsMap = targetMap.get(target); + if (!depsMap) { + targetMap.set(target, (depsMap = new Map())); + } + let dep = depsMap.get(key); + if (!dep) { + depsMap.set(key, (dep = new Set())); + } + if (!dep.has(activeEffect)) { + dep.add(activeEffect); + activeEffect.deps.push(dep); + if (activeEffect.options.onTrack) { + activeEffect.options.onTrack({ + effect: activeEffect, + target, + type, + key + }); + } + } +} +function trigger(target, type, key, newValue, oldValue, oldTarget) { + const depsMap = targetMap.get(target); + if (!depsMap) { + // never been tracked + return; + } + const effects = new Set(); + const add = (effectsToAdd) => { + if (effectsToAdd) { + effectsToAdd.forEach(effect => { + if (effect !== activeEffect || effect.allowRecurse) { + effects.add(effect); + } + }); + } + }; + if (type === "clear" /* CLEAR */) { + // collection being cleared + // trigger all effects for target + depsMap.forEach(add); + } + else if (key === 'length' && isArray(target)) { + depsMap.forEach((dep, key) => { + if (key === 'length' || key >= newValue) { + add(dep); + } + }); + } + else { + // schedule runs for SET | ADD | DELETE + if (key !== void 0) { + add(depsMap.get(key)); + } + // also run for iteration key on ADD | DELETE | Map.SET + switch (type) { + case "add" /* ADD */: + if (!isArray(target)) { + add(depsMap.get(ITERATE_KEY)); + if (isMap(target)) { + add(depsMap.get(MAP_KEY_ITERATE_KEY)); + } + } + else if (isIntegerKey(key)) { + // new index added to array -> length changes + add(depsMap.get('length')); + } + break; + case "delete" /* DELETE */: + if (!isArray(target)) { + add(depsMap.get(ITERATE_KEY)); + if (isMap(target)) { + add(depsMap.get(MAP_KEY_ITERATE_KEY)); + } + } + break; + case "set" /* SET */: + if (isMap(target)) { + add(depsMap.get(ITERATE_KEY)); + } + break; + } + } + const run = (effect) => { + if (effect.options.onTrigger) { + effect.options.onTrigger({ + effect, + target, + key, + type, + newValue, + oldValue, + oldTarget + }); + } + if (effect.options.scheduler) { + effect.options.scheduler(effect); + } + else { + effect(); + } + }; + effects.forEach(run); +} + +const isNonTrackableKeys = /*#__PURE__*/ makeMap(`__proto__,__v_isRef,__isVue`); +const builtInSymbols = new Set(Object.getOwnPropertyNames(Symbol) + .map(key => Symbol[key]) + .filter(isSymbol)); +const get = /*#__PURE__*/ createGetter(); +const shallowGet = /*#__PURE__*/ createGetter(false, true); +const readonlyGet = /*#__PURE__*/ createGetter(true); +const shallowReadonlyGet = /*#__PURE__*/ createGetter(true, true); +const arrayInstrumentations = /*#__PURE__*/ createArrayInstrumentations(); +function createArrayInstrumentations() { + const instrumentations = {}; + ['includes', 'indexOf', 'lastIndexOf'].forEach(key => { + instrumentations[key] = function (...args) { + const arr = toRaw(this); + for (let i = 0, l = this.length; i < l; i++) { + track(arr, "get" /* GET */, i + ''); + } + // we run the method using the original args first (which may be reactive) + const res = arr[key](...args); + if (res === -1 || res === false) { + // if that didn't work, run it again using raw values. + return arr[key](...args.map(toRaw)); + } + else { + return res; + } + }; + }); + ['push', 'pop', 'shift', 'unshift', 'splice'].forEach(key => { + instrumentations[key] = function (...args) { + pauseTracking(); + const res = toRaw(this)[key].apply(this, args); + resetTracking(); + return res; + }; + }); + return instrumentations; +} +function createGetter(isReadonly = false, shallow = false) { + return function get(target, key, receiver) { + if (key === "__v_isReactive" /* IS_REACTIVE */) { + return !isReadonly; + } + else if (key === "__v_isReadonly" /* IS_READONLY */) { + return isReadonly; + } + else if (key === "__v_raw" /* RAW */ && + receiver === + (isReadonly + ? shallow + ? shallowReadonlyMap + : readonlyMap + : shallow + ? shallowReactiveMap + : reactiveMap).get(target)) { + return target; + } + const targetIsArray = isArray(target); + if (!isReadonly && targetIsArray && hasOwn(arrayInstrumentations, key)) { + return Reflect.get(arrayInstrumentations, key, receiver); + } + const res = Reflect.get(target, key, receiver); + if (isSymbol(key) ? builtInSymbols.has(key) : isNonTrackableKeys(key)) { + return res; + } + if (!isReadonly) { + track(target, "get" /* GET */, key); + } + if (shallow) { + return res; + } + if (isRef(res)) { + // ref unwrapping - does not apply for Array + integer key. + const shouldUnwrap = !targetIsArray || !isIntegerKey(key); + return shouldUnwrap ? res.value : res; + } + if (isObject(res)) { + // Convert returned value into a proxy as well. we do the isObject check + // here to avoid invalid value warning. Also need to lazy access readonly + // and reactive here to avoid circular dependency. + return isReadonly ? readonly(res) : reactive(res); + } + return res; + }; +} +const set = /*#__PURE__*/ createSetter(); +const shallowSet = /*#__PURE__*/ createSetter(true); +function createSetter(shallow = false) { + return function set(target, key, value, receiver) { + let oldValue = target[key]; + if (!shallow) { + value = toRaw(value); + oldValue = toRaw(oldValue); + if (!isArray(target) && isRef(oldValue) && !isRef(value)) { + oldValue.value = value; + return true; + } + } + const hadKey = isArray(target) && isIntegerKey(key) + ? Number(key) < target.length + : hasOwn(target, key); + const result = Reflect.set(target, key, value, receiver); + // don't trigger if target is something up in the prototype chain of original + if (target === toRaw(receiver)) { + if (!hadKey) { + trigger(target, "add" /* ADD */, key, value); + } + else if (hasChanged(value, oldValue)) { + trigger(target, "set" /* SET */, key, value, oldValue); + } + } + return result; + }; +} +function deleteProperty(target, key) { + const hadKey = hasOwn(target, key); + const oldValue = target[key]; + const result = Reflect.deleteProperty(target, key); + if (result && hadKey) { + trigger(target, "delete" /* DELETE */, key, undefined, oldValue); + } + return result; +} +function has(target, key) { + const result = Reflect.has(target, key); + if (!isSymbol(key) || !builtInSymbols.has(key)) { + track(target, "has" /* HAS */, key); + } + return result; +} +function ownKeys(target) { + track(target, "iterate" /* ITERATE */, isArray(target) ? 'length' : ITERATE_KEY); + return Reflect.ownKeys(target); +} +const mutableHandlers = { + get, + set, + deleteProperty, + has, + ownKeys +}; +const readonlyHandlers = { + get: readonlyGet, + set(target, key) { + { + console.warn(`Set operation on key "${String(key)}" failed: target is readonly.`, target); + } + return true; + }, + deleteProperty(target, key) { + { + console.warn(`Delete operation on key "${String(key)}" failed: target is readonly.`, target); + } + return true; + } +}; +const shallowReactiveHandlers = /*#__PURE__*/ extend({}, mutableHandlers, { + get: shallowGet, + set: shallowSet +}); +// Props handlers are special in the sense that it should not unwrap top-level +// refs (in order to allow refs to be explicitly passed down), but should +// retain the reactivity of the normal readonly object. +const shallowReadonlyHandlers = /*#__PURE__*/ extend({}, readonlyHandlers, { + get: shallowReadonlyGet +}); + +const toReactive = (value) => isObject(value) ? reactive(value) : value; +const toReadonly = (value) => isObject(value) ? readonly(value) : value; +const toShallow = (value) => value; +const getProto = (v) => Reflect.getPrototypeOf(v); +function get$1(target, key, isReadonly = false, isShallow = false) { + // #1772: readonly(reactive(Map)) should return readonly + reactive version + // of the value + target = target["__v_raw" /* RAW */]; + const rawTarget = toRaw(target); + const rawKey = toRaw(key); + if (key !== rawKey) { + !isReadonly && track(rawTarget, "get" /* GET */, key); + } + !isReadonly && track(rawTarget, "get" /* GET */, rawKey); + const { has } = getProto(rawTarget); + const wrap = isShallow ? toShallow : isReadonly ? toReadonly : toReactive; + if (has.call(rawTarget, key)) { + return wrap(target.get(key)); + } + else if (has.call(rawTarget, rawKey)) { + return wrap(target.get(rawKey)); + } + else if (target !== rawTarget) { + // #3602 readonly(reactive(Map)) + // ensure that the nested reactive `Map` can do tracking for itself + target.get(key); + } +} +function has$1(key, isReadonly = false) { + const target = this["__v_raw" /* RAW */]; + const rawTarget = toRaw(target); + const rawKey = toRaw(key); + if (key !== rawKey) { + !isReadonly && track(rawTarget, "has" /* HAS */, key); + } + !isReadonly && track(rawTarget, "has" /* HAS */, rawKey); + return key === rawKey + ? target.has(key) + : target.has(key) || target.has(rawKey); +} +function size(target, isReadonly = false) { + target = target["__v_raw" /* RAW */]; + !isReadonly && track(toRaw(target), "iterate" /* ITERATE */, ITERATE_KEY); + return Reflect.get(target, 'size', target); +} +function add(value) { + value = toRaw(value); + const target = toRaw(this); + const proto = getProto(target); + const hadKey = proto.has.call(target, value); + if (!hadKey) { + target.add(value); + trigger(target, "add" /* ADD */, value, value); + } + return this; +} +function set$1(key, value) { + value = toRaw(value); + const target = toRaw(this); + const { has, get } = getProto(target); + let hadKey = has.call(target, key); + if (!hadKey) { + key = toRaw(key); + hadKey = has.call(target, key); + } + else { + checkIdentityKeys(target, has, key); + } + const oldValue = get.call(target, key); + target.set(key, value); + if (!hadKey) { + trigger(target, "add" /* ADD */, key, value); + } + else if (hasChanged(value, oldValue)) { + trigger(target, "set" /* SET */, key, value, oldValue); + } + return this; +} +function deleteEntry(key) { + const target = toRaw(this); + const { has, get } = getProto(target); + let hadKey = has.call(target, key); + if (!hadKey) { + key = toRaw(key); + hadKey = has.call(target, key); + } + else { + checkIdentityKeys(target, has, key); + } + const oldValue = get ? get.call(target, key) : undefined; + // forward the operation before queueing reactions + const result = target.delete(key); + if (hadKey) { + trigger(target, "delete" /* DELETE */, key, undefined, oldValue); + } + return result; +} +function clear() { + const target = toRaw(this); + const hadItems = target.size !== 0; + const oldTarget = isMap(target) + ? new Map(target) + : new Set(target) + ; + // forward the operation before queueing reactions + const result = target.clear(); + if (hadItems) { + trigger(target, "clear" /* CLEAR */, undefined, undefined, oldTarget); + } + return result; +} +function createForEach(isReadonly, isShallow) { + return function forEach(callback, thisArg) { + const observed = this; + const target = observed["__v_raw" /* RAW */]; + const rawTarget = toRaw(target); + const wrap = isShallow ? toShallow : isReadonly ? toReadonly : toReactive; + !isReadonly && track(rawTarget, "iterate" /* ITERATE */, ITERATE_KEY); + return target.forEach((value, key) => { + // important: make sure the callback is + // 1. invoked with the reactive map as `this` and 3rd arg + // 2. the value received should be a corresponding reactive/readonly. + return callback.call(thisArg, wrap(value), wrap(key), observed); + }); + }; +} +function createIterableMethod(method, isReadonly, isShallow) { + return function (...args) { + const target = this["__v_raw" /* RAW */]; + const rawTarget = toRaw(target); + const targetIsMap = isMap(rawTarget); + const isPair = method === 'entries' || (method === Symbol.iterator && targetIsMap); + const isKeyOnly = method === 'keys' && targetIsMap; + const innerIterator = target[method](...args); + const wrap = isShallow ? toShallow : isReadonly ? toReadonly : toReactive; + !isReadonly && + track(rawTarget, "iterate" /* ITERATE */, isKeyOnly ? MAP_KEY_ITERATE_KEY : ITERATE_KEY); + // return a wrapped iterator which returns observed versions of the + // values emitted from the real iterator + return { + // iterator protocol + next() { + const { value, done } = innerIterator.next(); + return done + ? { value, done } + : { + value: isPair ? [wrap(value[0]), wrap(value[1])] : wrap(value), + done + }; + }, + // iterable protocol + [Symbol.iterator]() { + return this; + } + }; + }; +} +function createReadonlyMethod(type) { + return function (...args) { + { + const key = args[0] ? `on key "${args[0]}" ` : ``; + console.warn(`${capitalize(type)} operation ${key}failed: target is readonly.`, toRaw(this)); + } + return type === "delete" /* DELETE */ ? false : this; + }; +} +function createInstrumentations() { + const mutableInstrumentations = { + get(key) { + return get$1(this, key); + }, + get size() { + return size(this); + }, + has: has$1, + add, + set: set$1, + delete: deleteEntry, + clear, + forEach: createForEach(false, false) + }; + const shallowInstrumentations = { + get(key) { + return get$1(this, key, false, true); + }, + get size() { + return size(this); + }, + has: has$1, + add, + set: set$1, + delete: deleteEntry, + clear, + forEach: createForEach(false, true) + }; + const readonlyInstrumentations = { + get(key) { + return get$1(this, key, true); + }, + get size() { + return size(this, true); + }, + has(key) { + return has$1.call(this, key, true); + }, + add: createReadonlyMethod("add" /* ADD */), + set: createReadonlyMethod("set" /* SET */), + delete: createReadonlyMethod("delete" /* DELETE */), + clear: createReadonlyMethod("clear" /* CLEAR */), + forEach: createForEach(true, false) + }; + const shallowReadonlyInstrumentations = { + get(key) { + return get$1(this, key, true, true); + }, + get size() { + return size(this, true); + }, + has(key) { + return has$1.call(this, key, true); + }, + add: createReadonlyMethod("add" /* ADD */), + set: createReadonlyMethod("set" /* SET */), + delete: createReadonlyMethod("delete" /* DELETE */), + clear: createReadonlyMethod("clear" /* CLEAR */), + forEach: createForEach(true, true) + }; + const iteratorMethods = ['keys', 'values', 'entries', Symbol.iterator]; + iteratorMethods.forEach(method => { + mutableInstrumentations[method] = createIterableMethod(method, false, false); + readonlyInstrumentations[method] = createIterableMethod(method, true, false); + shallowInstrumentations[method] = createIterableMethod(method, false, true); + shallowReadonlyInstrumentations[method] = createIterableMethod(method, true, true); + }); + return [ + mutableInstrumentations, + readonlyInstrumentations, + shallowInstrumentations, + shallowReadonlyInstrumentations + ]; +} +const [mutableInstrumentations, readonlyInstrumentations, shallowInstrumentations, shallowReadonlyInstrumentations] = /* #__PURE__*/ createInstrumentations(); +function createInstrumentationGetter(isReadonly, shallow) { + const instrumentations = shallow + ? isReadonly + ? shallowReadonlyInstrumentations + : shallowInstrumentations + : isReadonly + ? readonlyInstrumentations + : mutableInstrumentations; + return (target, key, receiver) => { + if (key === "__v_isReactive" /* IS_REACTIVE */) { + return !isReadonly; + } + else if (key === "__v_isReadonly" /* IS_READONLY */) { + return isReadonly; + } + else if (key === "__v_raw" /* RAW */) { + return target; + } + return Reflect.get(hasOwn(instrumentations, key) && key in target + ? instrumentations + : target, key, receiver); + }; +} +const mutableCollectionHandlers = { + get: /*#__PURE__*/ createInstrumentationGetter(false, false) +}; +const shallowCollectionHandlers = { + get: /*#__PURE__*/ createInstrumentationGetter(false, true) +}; +const readonlyCollectionHandlers = { + get: /*#__PURE__*/ createInstrumentationGetter(true, false) +}; +const shallowReadonlyCollectionHandlers = { + get: /*#__PURE__*/ createInstrumentationGetter(true, true) +}; +function checkIdentityKeys(target, has, key) { + const rawKey = toRaw(key); + if (rawKey !== key && has.call(target, rawKey)) { + const type = toRawType(target); + console.warn(`Reactive ${type} contains both the raw and reactive ` + + `versions of the same object${type === `Map` ? ` as keys` : ``}, ` + + `which can lead to inconsistencies. ` + + `Avoid differentiating between the raw and reactive versions ` + + `of an object and only use the reactive version if possible.`); + } +} + +const reactiveMap = new WeakMap(); +const shallowReactiveMap = new WeakMap(); +const readonlyMap = new WeakMap(); +const shallowReadonlyMap = new WeakMap(); +function targetTypeMap(rawType) { + switch (rawType) { + case 'Object': + case 'Array': + return 1 /* COMMON */; + case 'Map': + case 'Set': + case 'WeakMap': + case 'WeakSet': + return 2 /* COLLECTION */; + default: + return 0 /* INVALID */; + } +} +function getTargetType(value) { + return value["__v_skip" /* SKIP */] || !Object.isExtensible(value) + ? 0 /* INVALID */ + : targetTypeMap(toRawType(value)); +} +function reactive(target) { + // if trying to observe a readonly proxy, return the readonly version. + if (target && target["__v_isReadonly" /* IS_READONLY */]) { + return target; + } + return createReactiveObject(target, false, mutableHandlers, mutableCollectionHandlers, reactiveMap); +} +/** + * Return a shallowly-reactive copy of the original object, where only the root + * level properties are reactive. It also does not auto-unwrap refs (even at the + * root level). + */ +function shallowReactive(target) { + return createReactiveObject(target, false, shallowReactiveHandlers, shallowCollectionHandlers, shallowReactiveMap); +} +/** + * Creates a readonly copy of the original object. Note the returned copy is not + * made reactive, but `readonly` can be called on an already reactive object. + */ +function readonly(target) { + return createReactiveObject(target, true, readonlyHandlers, readonlyCollectionHandlers, readonlyMap); +} +/** + * Returns a reactive-copy of the original object, where only the root level + * properties are readonly, and does NOT unwrap refs nor recursively convert + * returned properties. + * This is used for creating the props proxy object for stateful components. + */ +function shallowReadonly(target) { + return createReactiveObject(target, true, shallowReadonlyHandlers, shallowReadonlyCollectionHandlers, shallowReadonlyMap); +} +function createReactiveObject(target, isReadonly, baseHandlers, collectionHandlers, proxyMap) { + if (!isObject(target)) { + { + console.warn(`value cannot be made reactive: ${String(target)}`); + } + return target; + } + // target is already a Proxy, return it. + // exception: calling readonly() on a reactive object + if (target["__v_raw" /* RAW */] && + !(isReadonly && target["__v_isReactive" /* IS_REACTIVE */])) { + return target; + } + // target already has corresponding Proxy + const existingProxy = proxyMap.get(target); + if (existingProxy) { + return existingProxy; + } + // only a whitelist of value types can be observed. + const targetType = getTargetType(target); + if (targetType === 0 /* INVALID */) { + return target; + } + const proxy = new Proxy(target, targetType === 2 /* COLLECTION */ ? collectionHandlers : baseHandlers); + proxyMap.set(target, proxy); + return proxy; +} +function isReactive(value) { + if (isReadonly(value)) { + return isReactive(value["__v_raw" /* RAW */]); + } + return !!(value && value["__v_isReactive" /* IS_REACTIVE */]); +} +function isReadonly(value) { + return !!(value && value["__v_isReadonly" /* IS_READONLY */]); +} +function isProxy(value) { + return isReactive(value) || isReadonly(value); +} +function toRaw(observed) { + return ((observed && toRaw(observed["__v_raw" /* RAW */])) || observed); +} +function markRaw(value) { + def(value, "__v_skip" /* SKIP */, true); + return value; +} + +const convert = (val) => isObject(val) ? reactive(val) : val; +function isRef(r) { + return Boolean(r && r.__v_isRef === true); +} +function ref(value) { + return createRef(value); +} +function shallowRef(value) { + return createRef(value, true); +} +class RefImpl { + constructor(value, _shallow = false) { + this._shallow = _shallow; + this.__v_isRef = true; + this._rawValue = _shallow ? value : toRaw(value); + this._value = _shallow ? value : convert(value); + } + get value() { + track(toRaw(this), "get" /* GET */, 'value'); + return this._value; + } + set value(newVal) { + newVal = this._shallow ? newVal : toRaw(newVal); + if (hasChanged(newVal, this._rawValue)) { + this._rawValue = newVal; + this._value = this._shallow ? newVal : convert(newVal); + trigger(toRaw(this), "set" /* SET */, 'value', newVal); + } + } +} +function createRef(rawValue, shallow = false) { + if (isRef(rawValue)) { + return rawValue; + } + return new RefImpl(rawValue, shallow); +} +function triggerRef(ref) { + trigger(toRaw(ref), "set" /* SET */, 'value', ref.value ); +} +function unref(ref) { + return isRef(ref) ? ref.value : ref; +} +const shallowUnwrapHandlers = { + get: (target, key, receiver) => unref(Reflect.get(target, key, receiver)), + set: (target, key, value, receiver) => { + const oldValue = target[key]; + if (isRef(oldValue) && !isRef(value)) { + oldValue.value = value; + return true; + } + else { + return Reflect.set(target, key, value, receiver); + } + } +}; +function proxyRefs(objectWithRefs) { + return isReactive(objectWithRefs) + ? objectWithRefs + : new Proxy(objectWithRefs, shallowUnwrapHandlers); +} +class CustomRefImpl { + constructor(factory) { + this.__v_isRef = true; + const { get, set } = factory(() => track(this, "get" /* GET */, 'value'), () => trigger(this, "set" /* SET */, 'value')); + this._get = get; + this._set = set; + } + get value() { + return this._get(); + } + set value(newVal) { + this._set(newVal); + } +} +function customRef(factory) { + return new CustomRefImpl(factory); +} +function toRefs(object) { + if (!isProxy(object)) { + console.warn(`toRefs() expects a reactive object but received a plain one.`); + } + const ret = isArray(object) ? new Array(object.length) : {}; + for (const key in object) { + ret[key] = toRef(object, key); + } + return ret; +} +class ObjectRefImpl { + constructor(_object, _key) { + this._object = _object; + this._key = _key; + this.__v_isRef = true; + } + get value() { + return this._object[this._key]; + } + set value(newVal) { + this._object[this._key] = newVal; + } +} +function toRef(object, key) { + return isRef(object[key]) + ? object[key] + : new ObjectRefImpl(object, key); +} + +class ComputedRefImpl { + constructor(getter, _setter, isReadonly) { + this._setter = _setter; + this._dirty = true; + this.__v_isRef = true; + this.effect = effect(getter, { + lazy: true, + scheduler: () => { + if (!this._dirty) { + this._dirty = true; + trigger(toRaw(this), "set" /* SET */, 'value'); + } + } + }); + this["__v_isReadonly" /* IS_READONLY */] = isReadonly; + } + get value() { + // the computed ref may get wrapped by other proxies e.g. readonly() #3376 + const self = toRaw(this); + if (self._dirty) { + self._value = this.effect(); + self._dirty = false; + } + track(self, "get" /* GET */, 'value'); + return self._value; + } + set value(newValue) { + this._setter(newValue); + } +} +function computed(getterOrOptions) { + let getter; + let setter; + if (isFunction(getterOrOptions)) { + getter = getterOrOptions; + setter = () => { + console.warn('Write operation failed: computed value is readonly'); + } + ; + } + else { + getter = getterOrOptions.get; + setter = getterOrOptions.set; + } + return new ComputedRefImpl(getter, setter, isFunction(getterOrOptions) || !getterOrOptions.set); +} + +export { ITERATE_KEY, computed, customRef, effect, enableTracking, isProxy, isReactive, isReadonly, isRef, markRaw, pauseTracking, proxyRefs, reactive, readonly, ref, resetTracking, shallowReactive, shallowReadonly, shallowRef, stop, toRaw, toRef, toRefs, track, trigger, triggerRef, unref }; diff --git a/node_modules/@vue/reactivity/dist/reactivity.esm-browser.prod.js b/node_modules/@vue/reactivity/dist/reactivity.esm-browser.prod.js new file mode 100644 index 0000000..23a076b --- /dev/null +++ b/node_modules/@vue/reactivity/dist/reactivity.esm-browser.prod.js @@ -0,0 +1 @@ +function t(t,e){const n=Object.create(null),r=t.split(",");for(let s=0;s!!n[t.toLowerCase()]:t=>!!n[t]}const e={},n=()=>{},r=Object.assign,s=Object.prototype.hasOwnProperty,i=(t,e)=>s.call(t,e),o=Array.isArray,c=t=>"[object Map]"===h(t),u=t=>"function"==typeof t,a=t=>"symbol"==typeof t,l=t=>null!==t&&"object"==typeof t,f=Object.prototype.toString,h=t=>f.call(t),_=t=>"string"==typeof t&&"NaN"!==t&&"-"!==t[0]&&""+parseInt(t,10)===t,d=(t,e)=>t!==e&&(t==t||e==e),v=new WeakMap,g=[];let p;const y=Symbol(""),w=Symbol("");function R(t,n=e){(function(t){return t&&!0===t._isEffect})(t)&&(t=t.raw);const r=function(t,e){const n=function(){if(!n.active)return t();if(!g.includes(n)){E(n);try{return O(),g.push(n),p=n,t()}finally{g.pop(),M(),p=g[g.length-1]}}};return n.id=k++,n.allowRecurse=!!e.allowRecurse,n._isEffect=!0,n.active=!0,n.raw=t,n.deps=[],n.options=e,n}(t,n);return n.lazy||r(),r}function b(t){t.active&&(E(t),t.options.onStop&&t.options.onStop(),t.active=!1)}let k=0;function E(t){const{deps:e}=t;if(e.length){for(let n=0;n{t&&t.forEach((t=>{(t!==p||t.allowRecurse)&&a.add(t)}))};if("clear"===e)u.forEach(l);else if("length"===n&&o(t))u.forEach(((t,e)=>{("length"===e||e>=r)&&l(t)}));else switch(void 0!==n&&l(u.get(n)),e){case"add":o(t)?_(n)&&l(u.get("length")):(l(u.get(y)),c(t)&&l(u.get(w)));break;case"delete":o(t)||(l(u.get(y)),c(t)&&l(u.get(w)));break;case"set":c(t)&&l(u.get(y))}a.forEach((t=>{t.options.scheduler?t.options.scheduler(t):t()}))}const z=t("__proto__,__v_isRef,__isVue"),W=new Set(Object.getOwnPropertyNames(Symbol).map((t=>Symbol[t])).filter(a)),A=C(),N=C(!1,!0),V=C(!0),I=C(!0,!0),K=B();function B(){const t={};return["includes","indexOf","lastIndexOf"].forEach((e=>{t[e]=function(...t){const n=Mt(this);for(let e=0,s=this.length;e{t[e]=function(...t){m();const n=Mt(this)[e].apply(this,t);return M(),n}})),t}function C(t=!1,e=!1){return function(n,r,s){if("__v_isReactive"===r)return!t;if("__v_isReadonly"===r)return t;if("__v_raw"===r&&s===(t?e?yt:pt:e?gt:vt).get(n))return n;const c=o(n);if(!t&&c&&i(K,r))return Reflect.get(K,r,s);const u=Reflect.get(n,r,s);if(a(r)?W.has(r):z(r))return u;if(t||P(n,0,r),e)return u;if(zt(u)){return!c||!_(r)?u.value:u}return l(u)?t?kt(u):Rt(u):u}}function L(t=!1){return function(e,n,r,s){let c=e[n];if(!t&&(r=Mt(r),c=Mt(c),!o(e)&&zt(c)&&!zt(r)))return c.value=r,!0;const u=o(e)&&_(n)?Number(n)!0,deleteProperty:(t,e)=>!0},F=r({},q,{get:N,set:L(!0)}),G=r({},D,{get:I}),H=t=>l(t)?Rt(t):t,J=t=>l(t)?kt(t):t,Q=t=>t,T=t=>Reflect.getPrototypeOf(t);function U(t,e,n=!1,r=!1){const s=Mt(t=t.__v_raw),i=Mt(e);e!==i&&!n&&P(s,0,e),!n&&P(s,0,i);const{has:o}=T(s),c=r?Q:n?J:H;return o.call(s,e)?c(t.get(e)):o.call(s,i)?c(t.get(i)):void(t!==s&&t.get(e))}function X(t,e=!1){const n=this.__v_raw,r=Mt(n),s=Mt(t);return t!==s&&!e&&P(r,0,t),!e&&P(r,0,s),t===s?n.has(t):n.has(t)||n.has(s)}function Y(t,e=!1){return t=t.__v_raw,!e&&P(Mt(t),0,y),Reflect.get(t,"size",t)}function Z(t){t=Mt(t);const e=Mt(this);return T(e).has.call(e,t)||(e.add(t),x(e,"add",t,t)),this}function $(t,e){e=Mt(e);const n=Mt(this),{has:r,get:s}=T(n);let i=r.call(n,t);i||(t=Mt(t),i=r.call(n,t));const o=s.call(n,t);return n.set(t,e),i?d(e,o)&&x(n,"set",t,e):x(n,"add",t,e),this}function tt(t){const e=Mt(this),{has:n,get:r}=T(e);let s=n.call(e,t);s||(t=Mt(t),s=n.call(e,t)),r&&r.call(e,t);const i=e.delete(t);return s&&x(e,"delete",t,void 0),i}function et(){const t=Mt(this),e=0!==t.size,n=t.clear();return e&&x(t,"clear",void 0,void 0),n}function nt(t,e){return function(n,r){const s=this,i=s.__v_raw,o=Mt(i),c=e?Q:t?J:H;return!t&&P(o,0,y),i.forEach(((t,e)=>n.call(r,c(t),c(e),s)))}}function rt(t,e,n){return function(...r){const s=this.__v_raw,i=Mt(s),o=c(i),u="entries"===t||t===Symbol.iterator&&o,a="keys"===t&&o,l=s[t](...r),f=n?Q:e?J:H;return!e&&P(i,0,a?w:y),{next(){const{value:t,done:e}=l.next();return e?{value:t,done:e}:{value:u?[f(t[0]),f(t[1])]:f(t),done:e}},[Symbol.iterator](){return this}}}}function st(t){return function(...e){return"delete"!==t&&this}}function it(){const t={get(t){return U(this,t)},get size(){return Y(this)},has:X,add:Z,set:$,delete:tt,clear:et,forEach:nt(!1,!1)},e={get(t){return U(this,t,!1,!0)},get size(){return Y(this)},has:X,add:Z,set:$,delete:tt,clear:et,forEach:nt(!1,!0)},n={get(t){return U(this,t,!0)},get size(){return Y(this,!0)},has(t){return X.call(this,t,!0)},add:st("add"),set:st("set"),delete:st("delete"),clear:st("clear"),forEach:nt(!0,!1)},r={get(t){return U(this,t,!0,!0)},get size(){return Y(this,!0)},has(t){return X.call(this,t,!0)},add:st("add"),set:st("set"),delete:st("delete"),clear:st("clear"),forEach:nt(!0,!0)};return["keys","values","entries",Symbol.iterator].forEach((s=>{t[s]=rt(s,!1,!1),n[s]=rt(s,!0,!1),e[s]=rt(s,!1,!0),r[s]=rt(s,!0,!0)})),[t,n,e,r]}const[ot,ct,ut,at]=it();function lt(t,e){const n=e?t?at:ut:t?ct:ot;return(e,r,s)=>"__v_isReactive"===r?!t:"__v_isReadonly"===r?t:"__v_raw"===r?e:Reflect.get(i(n,r)&&r in e?n:e,r,s)}const ft={get:lt(!1,!1)},ht={get:lt(!1,!0)},_t={get:lt(!0,!1)},dt={get:lt(!0,!0)},vt=new WeakMap,gt=new WeakMap,pt=new WeakMap,yt=new WeakMap;function wt(t){return t.__v_skip||!Object.isExtensible(t)?0:function(t){switch(t){case"Object":case"Array":return 1;case"Map":case"Set":case"WeakMap":case"WeakSet":return 2;default:return 0}}((t=>h(t).slice(8,-1))(t))}function Rt(t){return t&&t.__v_isReadonly?t:St(t,!1,q,ft,vt)}function bt(t){return St(t,!1,F,ht,gt)}function kt(t){return St(t,!0,D,_t,pt)}function Et(t){return St(t,!0,G,dt,yt)}function St(t,e,n,r,s){if(!l(t))return t;if(t.__v_raw&&(!e||!t.__v_isReactive))return t;const i=s.get(t);if(i)return i;const o=wt(t);if(0===o)return t;const c=new Proxy(t,2===o?r:n);return s.set(t,c),c}function jt(t){return mt(t)?jt(t.__v_raw):!(!t||!t.__v_isReactive)}function mt(t){return!(!t||!t.__v_isReadonly)}function Ot(t){return jt(t)||mt(t)}function Mt(t){return t&&Mt(t.__v_raw)||t}function Pt(t){return((t,e,n)=>{Object.defineProperty(t,e,{configurable:!0,enumerable:!1,value:n})})(t,"__v_skip",!0),t}const xt=t=>l(t)?Rt(t):t;function zt(t){return Boolean(t&&!0===t.__v_isRef)}function Wt(t){return Vt(t)}function At(t){return Vt(t,!0)}class Nt{constructor(t,e=!1){this._shallow=e,this.__v_isRef=!0,this._rawValue=e?t:Mt(t),this._value=e?t:xt(t)}get value(){return P(Mt(this),0,"value"),this._value}set value(t){t=this._shallow?t:Mt(t),d(t,this._rawValue)&&(this._rawValue=t,this._value=this._shallow?t:xt(t),x(Mt(this),"set","value",t))}}function Vt(t,e=!1){return zt(t)?t:new Nt(t,e)}function It(t){x(Mt(t),"set","value",void 0)}function Kt(t){return zt(t)?t.value:t}const Bt={get:(t,e,n)=>Kt(Reflect.get(t,e,n)),set:(t,e,n,r)=>{const s=t[e];return zt(s)&&!zt(n)?(s.value=n,!0):Reflect.set(t,e,n,r)}};function Ct(t){return jt(t)?t:new Proxy(t,Bt)}class Lt{constructor(t){this.__v_isRef=!0;const{get:e,set:n}=t((()=>P(this,0,"value")),(()=>x(this,"set","value")));this._get=e,this._set=n}get value(){return this._get()}set value(t){this._set(t)}}function qt(t){return new Lt(t)}function Dt(t){const e=o(t)?new Array(t.length):{};for(const n in t)e[n]=Gt(t,n);return e}class Ft{constructor(t,e){this._object=t,this._key=e,this.__v_isRef=!0}get value(){return this._object[this._key]}set value(t){this._object[this._key]=t}}function Gt(t,e){return zt(t[e])?t[e]:new Ft(t,e)}class Ht{constructor(t,e,n){this._setter=e,this._dirty=!0,this.__v_isRef=!0,this.effect=R(t,{lazy:!0,scheduler:()=>{this._dirty||(this._dirty=!0,x(Mt(this),"set","value"))}}),this.__v_isReadonly=n}get value(){const t=Mt(this);return t._dirty&&(t._value=this.effect(),t._dirty=!1),P(t,0,"value"),t._value}set value(t){this._setter(t)}}function Jt(t){let e,r;return u(t)?(e=t,r=n):(e=t.get,r=t.set),new Ht(e,r,u(t)||!t.set)}export{y as ITERATE_KEY,Jt as computed,qt as customRef,R as effect,O as enableTracking,Ot as isProxy,jt as isReactive,mt as isReadonly,zt as isRef,Pt as markRaw,m as pauseTracking,Ct as proxyRefs,Rt as reactive,kt as readonly,Wt as ref,M as resetTracking,bt as shallowReactive,Et as shallowReadonly,At as shallowRef,b as stop,Mt as toRaw,Gt as toRef,Dt as toRefs,P as track,x as trigger,It as triggerRef,Kt as unref}; diff --git a/node_modules/@vue/reactivity/dist/reactivity.esm-bundler.js b/node_modules/@vue/reactivity/dist/reactivity.esm-bundler.js new file mode 100644 index 0000000..559ef5f --- /dev/null +++ b/node_modules/@vue/reactivity/dist/reactivity.esm-bundler.js @@ -0,0 +1,904 @@ +import { EMPTY_OBJ, isArray, isMap, isIntegerKey, isSymbol, extend, hasOwn, isObject, hasChanged, makeMap, capitalize, toRawType, def, isFunction, NOOP } from '@vue/shared'; + +const targetMap = new WeakMap(); +const effectStack = []; +let activeEffect; +const ITERATE_KEY = Symbol((process.env.NODE_ENV !== 'production') ? 'iterate' : ''); +const MAP_KEY_ITERATE_KEY = Symbol((process.env.NODE_ENV !== 'production') ? 'Map key iterate' : ''); +function isEffect(fn) { + return fn && fn._isEffect === true; +} +function effect(fn, options = EMPTY_OBJ) { + if (isEffect(fn)) { + fn = fn.raw; + } + const effect = createReactiveEffect(fn, options); + if (!options.lazy) { + effect(); + } + return effect; +} +function stop(effect) { + if (effect.active) { + cleanup(effect); + if (effect.options.onStop) { + effect.options.onStop(); + } + effect.active = false; + } +} +let uid = 0; +function createReactiveEffect(fn, options) { + const effect = function reactiveEffect() { + if (!effect.active) { + return fn(); + } + if (!effectStack.includes(effect)) { + cleanup(effect); + try { + enableTracking(); + effectStack.push(effect); + activeEffect = effect; + return fn(); + } + finally { + effectStack.pop(); + resetTracking(); + activeEffect = effectStack[effectStack.length - 1]; + } + } + }; + effect.id = uid++; + effect.allowRecurse = !!options.allowRecurse; + effect._isEffect = true; + effect.active = true; + effect.raw = fn; + effect.deps = []; + effect.options = options; + return effect; +} +function cleanup(effect) { + const { deps } = effect; + if (deps.length) { + for (let i = 0; i < deps.length; i++) { + deps[i].delete(effect); + } + deps.length = 0; + } +} +let shouldTrack = true; +const trackStack = []; +function pauseTracking() { + trackStack.push(shouldTrack); + shouldTrack = false; +} +function enableTracking() { + trackStack.push(shouldTrack); + shouldTrack = true; +} +function resetTracking() { + const last = trackStack.pop(); + shouldTrack = last === undefined ? true : last; +} +function track(target, type, key) { + if (!shouldTrack || activeEffect === undefined) { + return; + } + let depsMap = targetMap.get(target); + if (!depsMap) { + targetMap.set(target, (depsMap = new Map())); + } + let dep = depsMap.get(key); + if (!dep) { + depsMap.set(key, (dep = new Set())); + } + if (!dep.has(activeEffect)) { + dep.add(activeEffect); + activeEffect.deps.push(dep); + if ((process.env.NODE_ENV !== 'production') && activeEffect.options.onTrack) { + activeEffect.options.onTrack({ + effect: activeEffect, + target, + type, + key + }); + } + } +} +function trigger(target, type, key, newValue, oldValue, oldTarget) { + const depsMap = targetMap.get(target); + if (!depsMap) { + // never been tracked + return; + } + const effects = new Set(); + const add = (effectsToAdd) => { + if (effectsToAdd) { + effectsToAdd.forEach(effect => { + if (effect !== activeEffect || effect.allowRecurse) { + effects.add(effect); + } + }); + } + }; + if (type === "clear" /* CLEAR */) { + // collection being cleared + // trigger all effects for target + depsMap.forEach(add); + } + else if (key === 'length' && isArray(target)) { + depsMap.forEach((dep, key) => { + if (key === 'length' || key >= newValue) { + add(dep); + } + }); + } + else { + // schedule runs for SET | ADD | DELETE + if (key !== void 0) { + add(depsMap.get(key)); + } + // also run for iteration key on ADD | DELETE | Map.SET + switch (type) { + case "add" /* ADD */: + if (!isArray(target)) { + add(depsMap.get(ITERATE_KEY)); + if (isMap(target)) { + add(depsMap.get(MAP_KEY_ITERATE_KEY)); + } + } + else if (isIntegerKey(key)) { + // new index added to array -> length changes + add(depsMap.get('length')); + } + break; + case "delete" /* DELETE */: + if (!isArray(target)) { + add(depsMap.get(ITERATE_KEY)); + if (isMap(target)) { + add(depsMap.get(MAP_KEY_ITERATE_KEY)); + } + } + break; + case "set" /* SET */: + if (isMap(target)) { + add(depsMap.get(ITERATE_KEY)); + } + break; + } + } + const run = (effect) => { + if ((process.env.NODE_ENV !== 'production') && effect.options.onTrigger) { + effect.options.onTrigger({ + effect, + target, + key, + type, + newValue, + oldValue, + oldTarget + }); + } + if (effect.options.scheduler) { + effect.options.scheduler(effect); + } + else { + effect(); + } + }; + effects.forEach(run); +} + +const isNonTrackableKeys = /*#__PURE__*/ makeMap(`__proto__,__v_isRef,__isVue`); +const builtInSymbols = new Set(Object.getOwnPropertyNames(Symbol) + .map(key => Symbol[key]) + .filter(isSymbol)); +const get = /*#__PURE__*/ createGetter(); +const shallowGet = /*#__PURE__*/ createGetter(false, true); +const readonlyGet = /*#__PURE__*/ createGetter(true); +const shallowReadonlyGet = /*#__PURE__*/ createGetter(true, true); +const arrayInstrumentations = /*#__PURE__*/ createArrayInstrumentations(); +function createArrayInstrumentations() { + const instrumentations = {}; + ['includes', 'indexOf', 'lastIndexOf'].forEach(key => { + instrumentations[key] = function (...args) { + const arr = toRaw(this); + for (let i = 0, l = this.length; i < l; i++) { + track(arr, "get" /* GET */, i + ''); + } + // we run the method using the original args first (which may be reactive) + const res = arr[key](...args); + if (res === -1 || res === false) { + // if that didn't work, run it again using raw values. + return arr[key](...args.map(toRaw)); + } + else { + return res; + } + }; + }); + ['push', 'pop', 'shift', 'unshift', 'splice'].forEach(key => { + instrumentations[key] = function (...args) { + pauseTracking(); + const res = toRaw(this)[key].apply(this, args); + resetTracking(); + return res; + }; + }); + return instrumentations; +} +function createGetter(isReadonly = false, shallow = false) { + return function get(target, key, receiver) { + if (key === "__v_isReactive" /* IS_REACTIVE */) { + return !isReadonly; + } + else if (key === "__v_isReadonly" /* IS_READONLY */) { + return isReadonly; + } + else if (key === "__v_raw" /* RAW */ && + receiver === + (isReadonly + ? shallow + ? shallowReadonlyMap + : readonlyMap + : shallow + ? shallowReactiveMap + : reactiveMap).get(target)) { + return target; + } + const targetIsArray = isArray(target); + if (!isReadonly && targetIsArray && hasOwn(arrayInstrumentations, key)) { + return Reflect.get(arrayInstrumentations, key, receiver); + } + const res = Reflect.get(target, key, receiver); + if (isSymbol(key) ? builtInSymbols.has(key) : isNonTrackableKeys(key)) { + return res; + } + if (!isReadonly) { + track(target, "get" /* GET */, key); + } + if (shallow) { + return res; + } + if (isRef(res)) { + // ref unwrapping - does not apply for Array + integer key. + const shouldUnwrap = !targetIsArray || !isIntegerKey(key); + return shouldUnwrap ? res.value : res; + } + if (isObject(res)) { + // Convert returned value into a proxy as well. we do the isObject check + // here to avoid invalid value warning. Also need to lazy access readonly + // and reactive here to avoid circular dependency. + return isReadonly ? readonly(res) : reactive(res); + } + return res; + }; +} +const set = /*#__PURE__*/ createSetter(); +const shallowSet = /*#__PURE__*/ createSetter(true); +function createSetter(shallow = false) { + return function set(target, key, value, receiver) { + let oldValue = target[key]; + if (!shallow) { + value = toRaw(value); + oldValue = toRaw(oldValue); + if (!isArray(target) && isRef(oldValue) && !isRef(value)) { + oldValue.value = value; + return true; + } + } + const hadKey = isArray(target) && isIntegerKey(key) + ? Number(key) < target.length + : hasOwn(target, key); + const result = Reflect.set(target, key, value, receiver); + // don't trigger if target is something up in the prototype chain of original + if (target === toRaw(receiver)) { + if (!hadKey) { + trigger(target, "add" /* ADD */, key, value); + } + else if (hasChanged(value, oldValue)) { + trigger(target, "set" /* SET */, key, value, oldValue); + } + } + return result; + }; +} +function deleteProperty(target, key) { + const hadKey = hasOwn(target, key); + const oldValue = target[key]; + const result = Reflect.deleteProperty(target, key); + if (result && hadKey) { + trigger(target, "delete" /* DELETE */, key, undefined, oldValue); + } + return result; +} +function has(target, key) { + const result = Reflect.has(target, key); + if (!isSymbol(key) || !builtInSymbols.has(key)) { + track(target, "has" /* HAS */, key); + } + return result; +} +function ownKeys(target) { + track(target, "iterate" /* ITERATE */, isArray(target) ? 'length' : ITERATE_KEY); + return Reflect.ownKeys(target); +} +const mutableHandlers = { + get, + set, + deleteProperty, + has, + ownKeys +}; +const readonlyHandlers = { + get: readonlyGet, + set(target, key) { + if ((process.env.NODE_ENV !== 'production')) { + console.warn(`Set operation on key "${String(key)}" failed: target is readonly.`, target); + } + return true; + }, + deleteProperty(target, key) { + if ((process.env.NODE_ENV !== 'production')) { + console.warn(`Delete operation on key "${String(key)}" failed: target is readonly.`, target); + } + return true; + } +}; +const shallowReactiveHandlers = /*#__PURE__*/ extend({}, mutableHandlers, { + get: shallowGet, + set: shallowSet +}); +// Props handlers are special in the sense that it should not unwrap top-level +// refs (in order to allow refs to be explicitly passed down), but should +// retain the reactivity of the normal readonly object. +const shallowReadonlyHandlers = /*#__PURE__*/ extend({}, readonlyHandlers, { + get: shallowReadonlyGet +}); + +const toReactive = (value) => isObject(value) ? reactive(value) : value; +const toReadonly = (value) => isObject(value) ? readonly(value) : value; +const toShallow = (value) => value; +const getProto = (v) => Reflect.getPrototypeOf(v); +function get$1(target, key, isReadonly = false, isShallow = false) { + // #1772: readonly(reactive(Map)) should return readonly + reactive version + // of the value + target = target["__v_raw" /* RAW */]; + const rawTarget = toRaw(target); + const rawKey = toRaw(key); + if (key !== rawKey) { + !isReadonly && track(rawTarget, "get" /* GET */, key); + } + !isReadonly && track(rawTarget, "get" /* GET */, rawKey); + const { has } = getProto(rawTarget); + const wrap = isShallow ? toShallow : isReadonly ? toReadonly : toReactive; + if (has.call(rawTarget, key)) { + return wrap(target.get(key)); + } + else if (has.call(rawTarget, rawKey)) { + return wrap(target.get(rawKey)); + } + else if (target !== rawTarget) { + // #3602 readonly(reactive(Map)) + // ensure that the nested reactive `Map` can do tracking for itself + target.get(key); + } +} +function has$1(key, isReadonly = false) { + const target = this["__v_raw" /* RAW */]; + const rawTarget = toRaw(target); + const rawKey = toRaw(key); + if (key !== rawKey) { + !isReadonly && track(rawTarget, "has" /* HAS */, key); + } + !isReadonly && track(rawTarget, "has" /* HAS */, rawKey); + return key === rawKey + ? target.has(key) + : target.has(key) || target.has(rawKey); +} +function size(target, isReadonly = false) { + target = target["__v_raw" /* RAW */]; + !isReadonly && track(toRaw(target), "iterate" /* ITERATE */, ITERATE_KEY); + return Reflect.get(target, 'size', target); +} +function add(value) { + value = toRaw(value); + const target = toRaw(this); + const proto = getProto(target); + const hadKey = proto.has.call(target, value); + if (!hadKey) { + target.add(value); + trigger(target, "add" /* ADD */, value, value); + } + return this; +} +function set$1(key, value) { + value = toRaw(value); + const target = toRaw(this); + const { has, get } = getProto(target); + let hadKey = has.call(target, key); + if (!hadKey) { + key = toRaw(key); + hadKey = has.call(target, key); + } + else if ((process.env.NODE_ENV !== 'production')) { + checkIdentityKeys(target, has, key); + } + const oldValue = get.call(target, key); + target.set(key, value); + if (!hadKey) { + trigger(target, "add" /* ADD */, key, value); + } + else if (hasChanged(value, oldValue)) { + trigger(target, "set" /* SET */, key, value, oldValue); + } + return this; +} +function deleteEntry(key) { + const target = toRaw(this); + const { has, get } = getProto(target); + let hadKey = has.call(target, key); + if (!hadKey) { + key = toRaw(key); + hadKey = has.call(target, key); + } + else if ((process.env.NODE_ENV !== 'production')) { + checkIdentityKeys(target, has, key); + } + const oldValue = get ? get.call(target, key) : undefined; + // forward the operation before queueing reactions + const result = target.delete(key); + if (hadKey) { + trigger(target, "delete" /* DELETE */, key, undefined, oldValue); + } + return result; +} +function clear() { + const target = toRaw(this); + const hadItems = target.size !== 0; + const oldTarget = (process.env.NODE_ENV !== 'production') + ? isMap(target) + ? new Map(target) + : new Set(target) + : undefined; + // forward the operation before queueing reactions + const result = target.clear(); + if (hadItems) { + trigger(target, "clear" /* CLEAR */, undefined, undefined, oldTarget); + } + return result; +} +function createForEach(isReadonly, isShallow) { + return function forEach(callback, thisArg) { + const observed = this; + const target = observed["__v_raw" /* RAW */]; + const rawTarget = toRaw(target); + const wrap = isShallow ? toShallow : isReadonly ? toReadonly : toReactive; + !isReadonly && track(rawTarget, "iterate" /* ITERATE */, ITERATE_KEY); + return target.forEach((value, key) => { + // important: make sure the callback is + // 1. invoked with the reactive map as `this` and 3rd arg + // 2. the value received should be a corresponding reactive/readonly. + return callback.call(thisArg, wrap(value), wrap(key), observed); + }); + }; +} +function createIterableMethod(method, isReadonly, isShallow) { + return function (...args) { + const target = this["__v_raw" /* RAW */]; + const rawTarget = toRaw(target); + const targetIsMap = isMap(rawTarget); + const isPair = method === 'entries' || (method === Symbol.iterator && targetIsMap); + const isKeyOnly = method === 'keys' && targetIsMap; + const innerIterator = target[method](...args); + const wrap = isShallow ? toShallow : isReadonly ? toReadonly : toReactive; + !isReadonly && + track(rawTarget, "iterate" /* ITERATE */, isKeyOnly ? MAP_KEY_ITERATE_KEY : ITERATE_KEY); + // return a wrapped iterator which returns observed versions of the + // values emitted from the real iterator + return { + // iterator protocol + next() { + const { value, done } = innerIterator.next(); + return done + ? { value, done } + : { + value: isPair ? [wrap(value[0]), wrap(value[1])] : wrap(value), + done + }; + }, + // iterable protocol + [Symbol.iterator]() { + return this; + } + }; + }; +} +function createReadonlyMethod(type) { + return function (...args) { + if ((process.env.NODE_ENV !== 'production')) { + const key = args[0] ? `on key "${args[0]}" ` : ``; + console.warn(`${capitalize(type)} operation ${key}failed: target is readonly.`, toRaw(this)); + } + return type === "delete" /* DELETE */ ? false : this; + }; +} +function createInstrumentations() { + const mutableInstrumentations = { + get(key) { + return get$1(this, key); + }, + get size() { + return size(this); + }, + has: has$1, + add, + set: set$1, + delete: deleteEntry, + clear, + forEach: createForEach(false, false) + }; + const shallowInstrumentations = { + get(key) { + return get$1(this, key, false, true); + }, + get size() { + return size(this); + }, + has: has$1, + add, + set: set$1, + delete: deleteEntry, + clear, + forEach: createForEach(false, true) + }; + const readonlyInstrumentations = { + get(key) { + return get$1(this, key, true); + }, + get size() { + return size(this, true); + }, + has(key) { + return has$1.call(this, key, true); + }, + add: createReadonlyMethod("add" /* ADD */), + set: createReadonlyMethod("set" /* SET */), + delete: createReadonlyMethod("delete" /* DELETE */), + clear: createReadonlyMethod("clear" /* CLEAR */), + forEach: createForEach(true, false) + }; + const shallowReadonlyInstrumentations = { + get(key) { + return get$1(this, key, true, true); + }, + get size() { + return size(this, true); + }, + has(key) { + return has$1.call(this, key, true); + }, + add: createReadonlyMethod("add" /* ADD */), + set: createReadonlyMethod("set" /* SET */), + delete: createReadonlyMethod("delete" /* DELETE */), + clear: createReadonlyMethod("clear" /* CLEAR */), + forEach: createForEach(true, true) + }; + const iteratorMethods = ['keys', 'values', 'entries', Symbol.iterator]; + iteratorMethods.forEach(method => { + mutableInstrumentations[method] = createIterableMethod(method, false, false); + readonlyInstrumentations[method] = createIterableMethod(method, true, false); + shallowInstrumentations[method] = createIterableMethod(method, false, true); + shallowReadonlyInstrumentations[method] = createIterableMethod(method, true, true); + }); + return [ + mutableInstrumentations, + readonlyInstrumentations, + shallowInstrumentations, + shallowReadonlyInstrumentations + ]; +} +const [mutableInstrumentations, readonlyInstrumentations, shallowInstrumentations, shallowReadonlyInstrumentations] = /* #__PURE__*/ createInstrumentations(); +function createInstrumentationGetter(isReadonly, shallow) { + const instrumentations = shallow + ? isReadonly + ? shallowReadonlyInstrumentations + : shallowInstrumentations + : isReadonly + ? readonlyInstrumentations + : mutableInstrumentations; + return (target, key, receiver) => { + if (key === "__v_isReactive" /* IS_REACTIVE */) { + return !isReadonly; + } + else if (key === "__v_isReadonly" /* IS_READONLY */) { + return isReadonly; + } + else if (key === "__v_raw" /* RAW */) { + return target; + } + return Reflect.get(hasOwn(instrumentations, key) && key in target + ? instrumentations + : target, key, receiver); + }; +} +const mutableCollectionHandlers = { + get: /*#__PURE__*/ createInstrumentationGetter(false, false) +}; +const shallowCollectionHandlers = { + get: /*#__PURE__*/ createInstrumentationGetter(false, true) +}; +const readonlyCollectionHandlers = { + get: /*#__PURE__*/ createInstrumentationGetter(true, false) +}; +const shallowReadonlyCollectionHandlers = { + get: /*#__PURE__*/ createInstrumentationGetter(true, true) +}; +function checkIdentityKeys(target, has, key) { + const rawKey = toRaw(key); + if (rawKey !== key && has.call(target, rawKey)) { + const type = toRawType(target); + console.warn(`Reactive ${type} contains both the raw and reactive ` + + `versions of the same object${type === `Map` ? ` as keys` : ``}, ` + + `which can lead to inconsistencies. ` + + `Avoid differentiating between the raw and reactive versions ` + + `of an object and only use the reactive version if possible.`); + } +} + +const reactiveMap = new WeakMap(); +const shallowReactiveMap = new WeakMap(); +const readonlyMap = new WeakMap(); +const shallowReadonlyMap = new WeakMap(); +function targetTypeMap(rawType) { + switch (rawType) { + case 'Object': + case 'Array': + return 1 /* COMMON */; + case 'Map': + case 'Set': + case 'WeakMap': + case 'WeakSet': + return 2 /* COLLECTION */; + default: + return 0 /* INVALID */; + } +} +function getTargetType(value) { + return value["__v_skip" /* SKIP */] || !Object.isExtensible(value) + ? 0 /* INVALID */ + : targetTypeMap(toRawType(value)); +} +function reactive(target) { + // if trying to observe a readonly proxy, return the readonly version. + if (target && target["__v_isReadonly" /* IS_READONLY */]) { + return target; + } + return createReactiveObject(target, false, mutableHandlers, mutableCollectionHandlers, reactiveMap); +} +/** + * Return a shallowly-reactive copy of the original object, where only the root + * level properties are reactive. It also does not auto-unwrap refs (even at the + * root level). + */ +function shallowReactive(target) { + return createReactiveObject(target, false, shallowReactiveHandlers, shallowCollectionHandlers, shallowReactiveMap); +} +/** + * Creates a readonly copy of the original object. Note the returned copy is not + * made reactive, but `readonly` can be called on an already reactive object. + */ +function readonly(target) { + return createReactiveObject(target, true, readonlyHandlers, readonlyCollectionHandlers, readonlyMap); +} +/** + * Returns a reactive-copy of the original object, where only the root level + * properties are readonly, and does NOT unwrap refs nor recursively convert + * returned properties. + * This is used for creating the props proxy object for stateful components. + */ +function shallowReadonly(target) { + return createReactiveObject(target, true, shallowReadonlyHandlers, shallowReadonlyCollectionHandlers, shallowReadonlyMap); +} +function createReactiveObject(target, isReadonly, baseHandlers, collectionHandlers, proxyMap) { + if (!isObject(target)) { + if ((process.env.NODE_ENV !== 'production')) { + console.warn(`value cannot be made reactive: ${String(target)}`); + } + return target; + } + // target is already a Proxy, return it. + // exception: calling readonly() on a reactive object + if (target["__v_raw" /* RAW */] && + !(isReadonly && target["__v_isReactive" /* IS_REACTIVE */])) { + return target; + } + // target already has corresponding Proxy + const existingProxy = proxyMap.get(target); + if (existingProxy) { + return existingProxy; + } + // only a whitelist of value types can be observed. + const targetType = getTargetType(target); + if (targetType === 0 /* INVALID */) { + return target; + } + const proxy = new Proxy(target, targetType === 2 /* COLLECTION */ ? collectionHandlers : baseHandlers); + proxyMap.set(target, proxy); + return proxy; +} +function isReactive(value) { + if (isReadonly(value)) { + return isReactive(value["__v_raw" /* RAW */]); + } + return !!(value && value["__v_isReactive" /* IS_REACTIVE */]); +} +function isReadonly(value) { + return !!(value && value["__v_isReadonly" /* IS_READONLY */]); +} +function isProxy(value) { + return isReactive(value) || isReadonly(value); +} +function toRaw(observed) { + return ((observed && toRaw(observed["__v_raw" /* RAW */])) || observed); +} +function markRaw(value) { + def(value, "__v_skip" /* SKIP */, true); + return value; +} + +const convert = (val) => isObject(val) ? reactive(val) : val; +function isRef(r) { + return Boolean(r && r.__v_isRef === true); +} +function ref(value) { + return createRef(value); +} +function shallowRef(value) { + return createRef(value, true); +} +class RefImpl { + constructor(value, _shallow = false) { + this._shallow = _shallow; + this.__v_isRef = true; + this._rawValue = _shallow ? value : toRaw(value); + this._value = _shallow ? value : convert(value); + } + get value() { + track(toRaw(this), "get" /* GET */, 'value'); + return this._value; + } + set value(newVal) { + newVal = this._shallow ? newVal : toRaw(newVal); + if (hasChanged(newVal, this._rawValue)) { + this._rawValue = newVal; + this._value = this._shallow ? newVal : convert(newVal); + trigger(toRaw(this), "set" /* SET */, 'value', newVal); + } + } +} +function createRef(rawValue, shallow = false) { + if (isRef(rawValue)) { + return rawValue; + } + return new RefImpl(rawValue, shallow); +} +function triggerRef(ref) { + trigger(toRaw(ref), "set" /* SET */, 'value', (process.env.NODE_ENV !== 'production') ? ref.value : void 0); +} +function unref(ref) { + return isRef(ref) ? ref.value : ref; +} +const shallowUnwrapHandlers = { + get: (target, key, receiver) => unref(Reflect.get(target, key, receiver)), + set: (target, key, value, receiver) => { + const oldValue = target[key]; + if (isRef(oldValue) && !isRef(value)) { + oldValue.value = value; + return true; + } + else { + return Reflect.set(target, key, value, receiver); + } + } +}; +function proxyRefs(objectWithRefs) { + return isReactive(objectWithRefs) + ? objectWithRefs + : new Proxy(objectWithRefs, shallowUnwrapHandlers); +} +class CustomRefImpl { + constructor(factory) { + this.__v_isRef = true; + const { get, set } = factory(() => track(this, "get" /* GET */, 'value'), () => trigger(this, "set" /* SET */, 'value')); + this._get = get; + this._set = set; + } + get value() { + return this._get(); + } + set value(newVal) { + this._set(newVal); + } +} +function customRef(factory) { + return new CustomRefImpl(factory); +} +function toRefs(object) { + if ((process.env.NODE_ENV !== 'production') && !isProxy(object)) { + console.warn(`toRefs() expects a reactive object but received a plain one.`); + } + const ret = isArray(object) ? new Array(object.length) : {}; + for (const key in object) { + ret[key] = toRef(object, key); + } + return ret; +} +class ObjectRefImpl { + constructor(_object, _key) { + this._object = _object; + this._key = _key; + this.__v_isRef = true; + } + get value() { + return this._object[this._key]; + } + set value(newVal) { + this._object[this._key] = newVal; + } +} +function toRef(object, key) { + return isRef(object[key]) + ? object[key] + : new ObjectRefImpl(object, key); +} + +class ComputedRefImpl { + constructor(getter, _setter, isReadonly) { + this._setter = _setter; + this._dirty = true; + this.__v_isRef = true; + this.effect = effect(getter, { + lazy: true, + scheduler: () => { + if (!this._dirty) { + this._dirty = true; + trigger(toRaw(this), "set" /* SET */, 'value'); + } + } + }); + this["__v_isReadonly" /* IS_READONLY */] = isReadonly; + } + get value() { + // the computed ref may get wrapped by other proxies e.g. readonly() #3376 + const self = toRaw(this); + if (self._dirty) { + self._value = this.effect(); + self._dirty = false; + } + track(self, "get" /* GET */, 'value'); + return self._value; + } + set value(newValue) { + this._setter(newValue); + } +} +function computed(getterOrOptions) { + let getter; + let setter; + if (isFunction(getterOrOptions)) { + getter = getterOrOptions; + setter = (process.env.NODE_ENV !== 'production') + ? () => { + console.warn('Write operation failed: computed value is readonly'); + } + : NOOP; + } + else { + getter = getterOrOptions.get; + setter = getterOrOptions.set; + } + return new ComputedRefImpl(getter, setter, isFunction(getterOrOptions) || !getterOrOptions.set); +} + +export { ITERATE_KEY, computed, customRef, effect, enableTracking, isProxy, isReactive, isReadonly, isRef, markRaw, pauseTracking, proxyRefs, reactive, readonly, ref, resetTracking, shallowReactive, shallowReadonly, shallowRef, stop, toRaw, toRef, toRefs, track, trigger, triggerRef, unref }; diff --git a/node_modules/@vue/reactivity/dist/reactivity.global.js b/node_modules/@vue/reactivity/dist/reactivity.global.js new file mode 100644 index 0000000..943d379 --- /dev/null +++ b/node_modules/@vue/reactivity/dist/reactivity.global.js @@ -0,0 +1,994 @@ +var VueReactivity = (function (exports) { + 'use strict'; + + /** + * Make a map and return a function for checking if a key + * is in that map. + * IMPORTANT: all calls of this function must be prefixed with + * \/\*#\_\_PURE\_\_\*\/ + * So that rollup can tree-shake them if necessary. + */ + function makeMap(str, expectsLowerCase) { + const map = Object.create(null); + const list = str.split(','); + for (let i = 0; i < list.length; i++) { + map[list[i]] = true; + } + return expectsLowerCase ? val => !!map[val.toLowerCase()] : val => !!map[val]; + } + + const EMPTY_OBJ = Object.freeze({}) + ; + Object.freeze([]) ; + const extend = Object.assign; + const hasOwnProperty = Object.prototype.hasOwnProperty; + const hasOwn = (val, key) => hasOwnProperty.call(val, key); + const isArray = Array.isArray; + const isMap = (val) => toTypeString(val) === '[object Map]'; + const isFunction = (val) => typeof val === 'function'; + const isString = (val) => typeof val === 'string'; + const isSymbol = (val) => typeof val === 'symbol'; + const isObject = (val) => val !== null && typeof val === 'object'; + const objectToString = Object.prototype.toString; + const toTypeString = (value) => objectToString.call(value); + const toRawType = (value) => { + // extract "RawType" from strings like "[object RawType]" + return toTypeString(value).slice(8, -1); + }; + const isIntegerKey = (key) => isString(key) && + key !== 'NaN' && + key[0] !== '-' && + '' + parseInt(key, 10) === key; + const cacheStringFunction = (fn) => { + const cache = Object.create(null); + return ((str) => { + const hit = cache[str]; + return hit || (cache[str] = fn(str)); + }); + }; + /** + * @private + */ + const capitalize = cacheStringFunction((str) => str.charAt(0).toUpperCase() + str.slice(1)); + // compare whether a value has changed, accounting for NaN. + const hasChanged = (value, oldValue) => value !== oldValue && (value === value || oldValue === oldValue); + const def = (obj, key, value) => { + Object.defineProperty(obj, key, { + configurable: true, + enumerable: false, + value + }); + }; + + const targetMap = new WeakMap(); + const effectStack = []; + let activeEffect; + const ITERATE_KEY = Symbol('iterate' ); + const MAP_KEY_ITERATE_KEY = Symbol('Map key iterate' ); + function isEffect(fn) { + return fn && fn._isEffect === true; + } + function effect(fn, options = EMPTY_OBJ) { + if (isEffect(fn)) { + fn = fn.raw; + } + const effect = createReactiveEffect(fn, options); + if (!options.lazy) { + effect(); + } + return effect; + } + function stop(effect) { + if (effect.active) { + cleanup(effect); + if (effect.options.onStop) { + effect.options.onStop(); + } + effect.active = false; + } + } + let uid = 0; + function createReactiveEffect(fn, options) { + const effect = function reactiveEffect() { + if (!effect.active) { + return fn(); + } + if (!effectStack.includes(effect)) { + cleanup(effect); + try { + enableTracking(); + effectStack.push(effect); + activeEffect = effect; + return fn(); + } + finally { + effectStack.pop(); + resetTracking(); + activeEffect = effectStack[effectStack.length - 1]; + } + } + }; + effect.id = uid++; + effect.allowRecurse = !!options.allowRecurse; + effect._isEffect = true; + effect.active = true; + effect.raw = fn; + effect.deps = []; + effect.options = options; + return effect; + } + function cleanup(effect) { + const { deps } = effect; + if (deps.length) { + for (let i = 0; i < deps.length; i++) { + deps[i].delete(effect); + } + deps.length = 0; + } + } + let shouldTrack = true; + const trackStack = []; + function pauseTracking() { + trackStack.push(shouldTrack); + shouldTrack = false; + } + function enableTracking() { + trackStack.push(shouldTrack); + shouldTrack = true; + } + function resetTracking() { + const last = trackStack.pop(); + shouldTrack = last === undefined ? true : last; + } + function track(target, type, key) { + if (!shouldTrack || activeEffect === undefined) { + return; + } + let depsMap = targetMap.get(target); + if (!depsMap) { + targetMap.set(target, (depsMap = new Map())); + } + let dep = depsMap.get(key); + if (!dep) { + depsMap.set(key, (dep = new Set())); + } + if (!dep.has(activeEffect)) { + dep.add(activeEffect); + activeEffect.deps.push(dep); + if (activeEffect.options.onTrack) { + activeEffect.options.onTrack({ + effect: activeEffect, + target, + type, + key + }); + } + } + } + function trigger(target, type, key, newValue, oldValue, oldTarget) { + const depsMap = targetMap.get(target); + if (!depsMap) { + // never been tracked + return; + } + const effects = new Set(); + const add = (effectsToAdd) => { + if (effectsToAdd) { + effectsToAdd.forEach(effect => { + if (effect !== activeEffect || effect.allowRecurse) { + effects.add(effect); + } + }); + } + }; + if (type === "clear" /* CLEAR */) { + // collection being cleared + // trigger all effects for target + depsMap.forEach(add); + } + else if (key === 'length' && isArray(target)) { + depsMap.forEach((dep, key) => { + if (key === 'length' || key >= newValue) { + add(dep); + } + }); + } + else { + // schedule runs for SET | ADD | DELETE + if (key !== void 0) { + add(depsMap.get(key)); + } + // also run for iteration key on ADD | DELETE | Map.SET + switch (type) { + case "add" /* ADD */: + if (!isArray(target)) { + add(depsMap.get(ITERATE_KEY)); + if (isMap(target)) { + add(depsMap.get(MAP_KEY_ITERATE_KEY)); + } + } + else if (isIntegerKey(key)) { + // new index added to array -> length changes + add(depsMap.get('length')); + } + break; + case "delete" /* DELETE */: + if (!isArray(target)) { + add(depsMap.get(ITERATE_KEY)); + if (isMap(target)) { + add(depsMap.get(MAP_KEY_ITERATE_KEY)); + } + } + break; + case "set" /* SET */: + if (isMap(target)) { + add(depsMap.get(ITERATE_KEY)); + } + break; + } + } + const run = (effect) => { + if (effect.options.onTrigger) { + effect.options.onTrigger({ + effect, + target, + key, + type, + newValue, + oldValue, + oldTarget + }); + } + if (effect.options.scheduler) { + effect.options.scheduler(effect); + } + else { + effect(); + } + }; + effects.forEach(run); + } + + const isNonTrackableKeys = /*#__PURE__*/ makeMap(`__proto__,__v_isRef,__isVue`); + const builtInSymbols = new Set(Object.getOwnPropertyNames(Symbol) + .map(key => Symbol[key]) + .filter(isSymbol)); + const get = /*#__PURE__*/ createGetter(); + const shallowGet = /*#__PURE__*/ createGetter(false, true); + const readonlyGet = /*#__PURE__*/ createGetter(true); + const shallowReadonlyGet = /*#__PURE__*/ createGetter(true, true); + const arrayInstrumentations = /*#__PURE__*/ createArrayInstrumentations(); + function createArrayInstrumentations() { + const instrumentations = {}; + ['includes', 'indexOf', 'lastIndexOf'].forEach(key => { + instrumentations[key] = function (...args) { + const arr = toRaw(this); + for (let i = 0, l = this.length; i < l; i++) { + track(arr, "get" /* GET */, i + ''); + } + // we run the method using the original args first (which may be reactive) + const res = arr[key](...args); + if (res === -1 || res === false) { + // if that didn't work, run it again using raw values. + return arr[key](...args.map(toRaw)); + } + else { + return res; + } + }; + }); + ['push', 'pop', 'shift', 'unshift', 'splice'].forEach(key => { + instrumentations[key] = function (...args) { + pauseTracking(); + const res = toRaw(this)[key].apply(this, args); + resetTracking(); + return res; + }; + }); + return instrumentations; + } + function createGetter(isReadonly = false, shallow = false) { + return function get(target, key, receiver) { + if (key === "__v_isReactive" /* IS_REACTIVE */) { + return !isReadonly; + } + else if (key === "__v_isReadonly" /* IS_READONLY */) { + return isReadonly; + } + else if (key === "__v_raw" /* RAW */ && + receiver === + (isReadonly + ? shallow + ? shallowReadonlyMap + : readonlyMap + : shallow + ? shallowReactiveMap + : reactiveMap).get(target)) { + return target; + } + const targetIsArray = isArray(target); + if (!isReadonly && targetIsArray && hasOwn(arrayInstrumentations, key)) { + return Reflect.get(arrayInstrumentations, key, receiver); + } + const res = Reflect.get(target, key, receiver); + if (isSymbol(key) ? builtInSymbols.has(key) : isNonTrackableKeys(key)) { + return res; + } + if (!isReadonly) { + track(target, "get" /* GET */, key); + } + if (shallow) { + return res; + } + if (isRef(res)) { + // ref unwrapping - does not apply for Array + integer key. + const shouldUnwrap = !targetIsArray || !isIntegerKey(key); + return shouldUnwrap ? res.value : res; + } + if (isObject(res)) { + // Convert returned value into a proxy as well. we do the isObject check + // here to avoid invalid value warning. Also need to lazy access readonly + // and reactive here to avoid circular dependency. + return isReadonly ? readonly(res) : reactive(res); + } + return res; + }; + } + const set = /*#__PURE__*/ createSetter(); + const shallowSet = /*#__PURE__*/ createSetter(true); + function createSetter(shallow = false) { + return function set(target, key, value, receiver) { + let oldValue = target[key]; + if (!shallow) { + value = toRaw(value); + oldValue = toRaw(oldValue); + if (!isArray(target) && isRef(oldValue) && !isRef(value)) { + oldValue.value = value; + return true; + } + } + const hadKey = isArray(target) && isIntegerKey(key) + ? Number(key) < target.length + : hasOwn(target, key); + const result = Reflect.set(target, key, value, receiver); + // don't trigger if target is something up in the prototype chain of original + if (target === toRaw(receiver)) { + if (!hadKey) { + trigger(target, "add" /* ADD */, key, value); + } + else if (hasChanged(value, oldValue)) { + trigger(target, "set" /* SET */, key, value, oldValue); + } + } + return result; + }; + } + function deleteProperty(target, key) { + const hadKey = hasOwn(target, key); + const oldValue = target[key]; + const result = Reflect.deleteProperty(target, key); + if (result && hadKey) { + trigger(target, "delete" /* DELETE */, key, undefined, oldValue); + } + return result; + } + function has(target, key) { + const result = Reflect.has(target, key); + if (!isSymbol(key) || !builtInSymbols.has(key)) { + track(target, "has" /* HAS */, key); + } + return result; + } + function ownKeys(target) { + track(target, "iterate" /* ITERATE */, isArray(target) ? 'length' : ITERATE_KEY); + return Reflect.ownKeys(target); + } + const mutableHandlers = { + get, + set, + deleteProperty, + has, + ownKeys + }; + const readonlyHandlers = { + get: readonlyGet, + set(target, key) { + { + console.warn(`Set operation on key "${String(key)}" failed: target is readonly.`, target); + } + return true; + }, + deleteProperty(target, key) { + { + console.warn(`Delete operation on key "${String(key)}" failed: target is readonly.`, target); + } + return true; + } + }; + const shallowReactiveHandlers = /*#__PURE__*/ extend({}, mutableHandlers, { + get: shallowGet, + set: shallowSet + }); + // Props handlers are special in the sense that it should not unwrap top-level + // refs (in order to allow refs to be explicitly passed down), but should + // retain the reactivity of the normal readonly object. + const shallowReadonlyHandlers = /*#__PURE__*/ extend({}, readonlyHandlers, { + get: shallowReadonlyGet + }); + + const toReactive = (value) => isObject(value) ? reactive(value) : value; + const toReadonly = (value) => isObject(value) ? readonly(value) : value; + const toShallow = (value) => value; + const getProto = (v) => Reflect.getPrototypeOf(v); + function get$1(target, key, isReadonly = false, isShallow = false) { + // #1772: readonly(reactive(Map)) should return readonly + reactive version + // of the value + target = target["__v_raw" /* RAW */]; + const rawTarget = toRaw(target); + const rawKey = toRaw(key); + if (key !== rawKey) { + !isReadonly && track(rawTarget, "get" /* GET */, key); + } + !isReadonly && track(rawTarget, "get" /* GET */, rawKey); + const { has } = getProto(rawTarget); + const wrap = isShallow ? toShallow : isReadonly ? toReadonly : toReactive; + if (has.call(rawTarget, key)) { + return wrap(target.get(key)); + } + else if (has.call(rawTarget, rawKey)) { + return wrap(target.get(rawKey)); + } + else if (target !== rawTarget) { + // #3602 readonly(reactive(Map)) + // ensure that the nested reactive `Map` can do tracking for itself + target.get(key); + } + } + function has$1(key, isReadonly = false) { + const target = this["__v_raw" /* RAW */]; + const rawTarget = toRaw(target); + const rawKey = toRaw(key); + if (key !== rawKey) { + !isReadonly && track(rawTarget, "has" /* HAS */, key); + } + !isReadonly && track(rawTarget, "has" /* HAS */, rawKey); + return key === rawKey + ? target.has(key) + : target.has(key) || target.has(rawKey); + } + function size(target, isReadonly = false) { + target = target["__v_raw" /* RAW */]; + !isReadonly && track(toRaw(target), "iterate" /* ITERATE */, ITERATE_KEY); + return Reflect.get(target, 'size', target); + } + function add(value) { + value = toRaw(value); + const target = toRaw(this); + const proto = getProto(target); + const hadKey = proto.has.call(target, value); + if (!hadKey) { + target.add(value); + trigger(target, "add" /* ADD */, value, value); + } + return this; + } + function set$1(key, value) { + value = toRaw(value); + const target = toRaw(this); + const { has, get } = getProto(target); + let hadKey = has.call(target, key); + if (!hadKey) { + key = toRaw(key); + hadKey = has.call(target, key); + } + else { + checkIdentityKeys(target, has, key); + } + const oldValue = get.call(target, key); + target.set(key, value); + if (!hadKey) { + trigger(target, "add" /* ADD */, key, value); + } + else if (hasChanged(value, oldValue)) { + trigger(target, "set" /* SET */, key, value, oldValue); + } + return this; + } + function deleteEntry(key) { + const target = toRaw(this); + const { has, get } = getProto(target); + let hadKey = has.call(target, key); + if (!hadKey) { + key = toRaw(key); + hadKey = has.call(target, key); + } + else { + checkIdentityKeys(target, has, key); + } + const oldValue = get ? get.call(target, key) : undefined; + // forward the operation before queueing reactions + const result = target.delete(key); + if (hadKey) { + trigger(target, "delete" /* DELETE */, key, undefined, oldValue); + } + return result; + } + function clear() { + const target = toRaw(this); + const hadItems = target.size !== 0; + const oldTarget = isMap(target) + ? new Map(target) + : new Set(target) + ; + // forward the operation before queueing reactions + const result = target.clear(); + if (hadItems) { + trigger(target, "clear" /* CLEAR */, undefined, undefined, oldTarget); + } + return result; + } + function createForEach(isReadonly, isShallow) { + return function forEach(callback, thisArg) { + const observed = this; + const target = observed["__v_raw" /* RAW */]; + const rawTarget = toRaw(target); + const wrap = isShallow ? toShallow : isReadonly ? toReadonly : toReactive; + !isReadonly && track(rawTarget, "iterate" /* ITERATE */, ITERATE_KEY); + return target.forEach((value, key) => { + // important: make sure the callback is + // 1. invoked with the reactive map as `this` and 3rd arg + // 2. the value received should be a corresponding reactive/readonly. + return callback.call(thisArg, wrap(value), wrap(key), observed); + }); + }; + } + function createIterableMethod(method, isReadonly, isShallow) { + return function (...args) { + const target = this["__v_raw" /* RAW */]; + const rawTarget = toRaw(target); + const targetIsMap = isMap(rawTarget); + const isPair = method === 'entries' || (method === Symbol.iterator && targetIsMap); + const isKeyOnly = method === 'keys' && targetIsMap; + const innerIterator = target[method](...args); + const wrap = isShallow ? toShallow : isReadonly ? toReadonly : toReactive; + !isReadonly && + track(rawTarget, "iterate" /* ITERATE */, isKeyOnly ? MAP_KEY_ITERATE_KEY : ITERATE_KEY); + // return a wrapped iterator which returns observed versions of the + // values emitted from the real iterator + return { + // iterator protocol + next() { + const { value, done } = innerIterator.next(); + return done + ? { value, done } + : { + value: isPair ? [wrap(value[0]), wrap(value[1])] : wrap(value), + done + }; + }, + // iterable protocol + [Symbol.iterator]() { + return this; + } + }; + }; + } + function createReadonlyMethod(type) { + return function (...args) { + { + const key = args[0] ? `on key "${args[0]}" ` : ``; + console.warn(`${capitalize(type)} operation ${key}failed: target is readonly.`, toRaw(this)); + } + return type === "delete" /* DELETE */ ? false : this; + }; + } + function createInstrumentations() { + const mutableInstrumentations = { + get(key) { + return get$1(this, key); + }, + get size() { + return size(this); + }, + has: has$1, + add, + set: set$1, + delete: deleteEntry, + clear, + forEach: createForEach(false, false) + }; + const shallowInstrumentations = { + get(key) { + return get$1(this, key, false, true); + }, + get size() { + return size(this); + }, + has: has$1, + add, + set: set$1, + delete: deleteEntry, + clear, + forEach: createForEach(false, true) + }; + const readonlyInstrumentations = { + get(key) { + return get$1(this, key, true); + }, + get size() { + return size(this, true); + }, + has(key) { + return has$1.call(this, key, true); + }, + add: createReadonlyMethod("add" /* ADD */), + set: createReadonlyMethod("set" /* SET */), + delete: createReadonlyMethod("delete" /* DELETE */), + clear: createReadonlyMethod("clear" /* CLEAR */), + forEach: createForEach(true, false) + }; + const shallowReadonlyInstrumentations = { + get(key) { + return get$1(this, key, true, true); + }, + get size() { + return size(this, true); + }, + has(key) { + return has$1.call(this, key, true); + }, + add: createReadonlyMethod("add" /* ADD */), + set: createReadonlyMethod("set" /* SET */), + delete: createReadonlyMethod("delete" /* DELETE */), + clear: createReadonlyMethod("clear" /* CLEAR */), + forEach: createForEach(true, true) + }; + const iteratorMethods = ['keys', 'values', 'entries', Symbol.iterator]; + iteratorMethods.forEach(method => { + mutableInstrumentations[method] = createIterableMethod(method, false, false); + readonlyInstrumentations[method] = createIterableMethod(method, true, false); + shallowInstrumentations[method] = createIterableMethod(method, false, true); + shallowReadonlyInstrumentations[method] = createIterableMethod(method, true, true); + }); + return [ + mutableInstrumentations, + readonlyInstrumentations, + shallowInstrumentations, + shallowReadonlyInstrumentations + ]; + } + const [mutableInstrumentations, readonlyInstrumentations, shallowInstrumentations, shallowReadonlyInstrumentations] = /* #__PURE__*/ createInstrumentations(); + function createInstrumentationGetter(isReadonly, shallow) { + const instrumentations = shallow + ? isReadonly + ? shallowReadonlyInstrumentations + : shallowInstrumentations + : isReadonly + ? readonlyInstrumentations + : mutableInstrumentations; + return (target, key, receiver) => { + if (key === "__v_isReactive" /* IS_REACTIVE */) { + return !isReadonly; + } + else if (key === "__v_isReadonly" /* IS_READONLY */) { + return isReadonly; + } + else if (key === "__v_raw" /* RAW */) { + return target; + } + return Reflect.get(hasOwn(instrumentations, key) && key in target + ? instrumentations + : target, key, receiver); + }; + } + const mutableCollectionHandlers = { + get: /*#__PURE__*/ createInstrumentationGetter(false, false) + }; + const shallowCollectionHandlers = { + get: /*#__PURE__*/ createInstrumentationGetter(false, true) + }; + const readonlyCollectionHandlers = { + get: /*#__PURE__*/ createInstrumentationGetter(true, false) + }; + const shallowReadonlyCollectionHandlers = { + get: /*#__PURE__*/ createInstrumentationGetter(true, true) + }; + function checkIdentityKeys(target, has, key) { + const rawKey = toRaw(key); + if (rawKey !== key && has.call(target, rawKey)) { + const type = toRawType(target); + console.warn(`Reactive ${type} contains both the raw and reactive ` + + `versions of the same object${type === `Map` ? ` as keys` : ``}, ` + + `which can lead to inconsistencies. ` + + `Avoid differentiating between the raw and reactive versions ` + + `of an object and only use the reactive version if possible.`); + } + } + + const reactiveMap = new WeakMap(); + const shallowReactiveMap = new WeakMap(); + const readonlyMap = new WeakMap(); + const shallowReadonlyMap = new WeakMap(); + function targetTypeMap(rawType) { + switch (rawType) { + case 'Object': + case 'Array': + return 1 /* COMMON */; + case 'Map': + case 'Set': + case 'WeakMap': + case 'WeakSet': + return 2 /* COLLECTION */; + default: + return 0 /* INVALID */; + } + } + function getTargetType(value) { + return value["__v_skip" /* SKIP */] || !Object.isExtensible(value) + ? 0 /* INVALID */ + : targetTypeMap(toRawType(value)); + } + function reactive(target) { + // if trying to observe a readonly proxy, return the readonly version. + if (target && target["__v_isReadonly" /* IS_READONLY */]) { + return target; + } + return createReactiveObject(target, false, mutableHandlers, mutableCollectionHandlers, reactiveMap); + } + /** + * Return a shallowly-reactive copy of the original object, where only the root + * level properties are reactive. It also does not auto-unwrap refs (even at the + * root level). + */ + function shallowReactive(target) { + return createReactiveObject(target, false, shallowReactiveHandlers, shallowCollectionHandlers, shallowReactiveMap); + } + /** + * Creates a readonly copy of the original object. Note the returned copy is not + * made reactive, but `readonly` can be called on an already reactive object. + */ + function readonly(target) { + return createReactiveObject(target, true, readonlyHandlers, readonlyCollectionHandlers, readonlyMap); + } + /** + * Returns a reactive-copy of the original object, where only the root level + * properties are readonly, and does NOT unwrap refs nor recursively convert + * returned properties. + * This is used for creating the props proxy object for stateful components. + */ + function shallowReadonly(target) { + return createReactiveObject(target, true, shallowReadonlyHandlers, shallowReadonlyCollectionHandlers, shallowReadonlyMap); + } + function createReactiveObject(target, isReadonly, baseHandlers, collectionHandlers, proxyMap) { + if (!isObject(target)) { + { + console.warn(`value cannot be made reactive: ${String(target)}`); + } + return target; + } + // target is already a Proxy, return it. + // exception: calling readonly() on a reactive object + if (target["__v_raw" /* RAW */] && + !(isReadonly && target["__v_isReactive" /* IS_REACTIVE */])) { + return target; + } + // target already has corresponding Proxy + const existingProxy = proxyMap.get(target); + if (existingProxy) { + return existingProxy; + } + // only a whitelist of value types can be observed. + const targetType = getTargetType(target); + if (targetType === 0 /* INVALID */) { + return target; + } + const proxy = new Proxy(target, targetType === 2 /* COLLECTION */ ? collectionHandlers : baseHandlers); + proxyMap.set(target, proxy); + return proxy; + } + function isReactive(value) { + if (isReadonly(value)) { + return isReactive(value["__v_raw" /* RAW */]); + } + return !!(value && value["__v_isReactive" /* IS_REACTIVE */]); + } + function isReadonly(value) { + return !!(value && value["__v_isReadonly" /* IS_READONLY */]); + } + function isProxy(value) { + return isReactive(value) || isReadonly(value); + } + function toRaw(observed) { + return ((observed && toRaw(observed["__v_raw" /* RAW */])) || observed); + } + function markRaw(value) { + def(value, "__v_skip" /* SKIP */, true); + return value; + } + + const convert = (val) => isObject(val) ? reactive(val) : val; + function isRef(r) { + return Boolean(r && r.__v_isRef === true); + } + function ref(value) { + return createRef(value); + } + function shallowRef(value) { + return createRef(value, true); + } + class RefImpl { + constructor(value, _shallow = false) { + this._shallow = _shallow; + this.__v_isRef = true; + this._rawValue = _shallow ? value : toRaw(value); + this._value = _shallow ? value : convert(value); + } + get value() { + track(toRaw(this), "get" /* GET */, 'value'); + return this._value; + } + set value(newVal) { + newVal = this._shallow ? newVal : toRaw(newVal); + if (hasChanged(newVal, this._rawValue)) { + this._rawValue = newVal; + this._value = this._shallow ? newVal : convert(newVal); + trigger(toRaw(this), "set" /* SET */, 'value', newVal); + } + } + } + function createRef(rawValue, shallow = false) { + if (isRef(rawValue)) { + return rawValue; + } + return new RefImpl(rawValue, shallow); + } + function triggerRef(ref) { + trigger(toRaw(ref), "set" /* SET */, 'value', ref.value ); + } + function unref(ref) { + return isRef(ref) ? ref.value : ref; + } + const shallowUnwrapHandlers = { + get: (target, key, receiver) => unref(Reflect.get(target, key, receiver)), + set: (target, key, value, receiver) => { + const oldValue = target[key]; + if (isRef(oldValue) && !isRef(value)) { + oldValue.value = value; + return true; + } + else { + return Reflect.set(target, key, value, receiver); + } + } + }; + function proxyRefs(objectWithRefs) { + return isReactive(objectWithRefs) + ? objectWithRefs + : new Proxy(objectWithRefs, shallowUnwrapHandlers); + } + class CustomRefImpl { + constructor(factory) { + this.__v_isRef = true; + const { get, set } = factory(() => track(this, "get" /* GET */, 'value'), () => trigger(this, "set" /* SET */, 'value')); + this._get = get; + this._set = set; + } + get value() { + return this._get(); + } + set value(newVal) { + this._set(newVal); + } + } + function customRef(factory) { + return new CustomRefImpl(factory); + } + function toRefs(object) { + if (!isProxy(object)) { + console.warn(`toRefs() expects a reactive object but received a plain one.`); + } + const ret = isArray(object) ? new Array(object.length) : {}; + for (const key in object) { + ret[key] = toRef(object, key); + } + return ret; + } + class ObjectRefImpl { + constructor(_object, _key) { + this._object = _object; + this._key = _key; + this.__v_isRef = true; + } + get value() { + return this._object[this._key]; + } + set value(newVal) { + this._object[this._key] = newVal; + } + } + function toRef(object, key) { + return isRef(object[key]) + ? object[key] + : new ObjectRefImpl(object, key); + } + + class ComputedRefImpl { + constructor(getter, _setter, isReadonly) { + this._setter = _setter; + this._dirty = true; + this.__v_isRef = true; + this.effect = effect(getter, { + lazy: true, + scheduler: () => { + if (!this._dirty) { + this._dirty = true; + trigger(toRaw(this), "set" /* SET */, 'value'); + } + } + }); + this["__v_isReadonly" /* IS_READONLY */] = isReadonly; + } + get value() { + // the computed ref may get wrapped by other proxies e.g. readonly() #3376 + const self = toRaw(this); + if (self._dirty) { + self._value = this.effect(); + self._dirty = false; + } + track(self, "get" /* GET */, 'value'); + return self._value; + } + set value(newValue) { + this._setter(newValue); + } + } + function computed(getterOrOptions) { + let getter; + let setter; + if (isFunction(getterOrOptions)) { + getter = getterOrOptions; + setter = () => { + console.warn('Write operation failed: computed value is readonly'); + } + ; + } + else { + getter = getterOrOptions.get; + setter = getterOrOptions.set; + } + return new ComputedRefImpl(getter, setter, isFunction(getterOrOptions) || !getterOrOptions.set); + } + + exports.ITERATE_KEY = ITERATE_KEY; + exports.computed = computed; + exports.customRef = customRef; + exports.effect = effect; + exports.enableTracking = enableTracking; + exports.isProxy = isProxy; + exports.isReactive = isReactive; + exports.isReadonly = isReadonly; + exports.isRef = isRef; + exports.markRaw = markRaw; + exports.pauseTracking = pauseTracking; + exports.proxyRefs = proxyRefs; + exports.reactive = reactive; + exports.readonly = readonly; + exports.ref = ref; + exports.resetTracking = resetTracking; + exports.shallowReactive = shallowReactive; + exports.shallowReadonly = shallowReadonly; + exports.shallowRef = shallowRef; + exports.stop = stop; + exports.toRaw = toRaw; + exports.toRef = toRef; + exports.toRefs = toRefs; + exports.track = track; + exports.trigger = trigger; + exports.triggerRef = triggerRef; + exports.unref = unref; + + Object.defineProperty(exports, '__esModule', { value: true }); + + return exports; + +}({})); diff --git a/node_modules/@vue/reactivity/dist/reactivity.global.prod.js b/node_modules/@vue/reactivity/dist/reactivity.global.prod.js new file mode 100644 index 0000000..b0abd91 --- /dev/null +++ b/node_modules/@vue/reactivity/dist/reactivity.global.prod.js @@ -0,0 +1 @@ +var VueReactivity=function(t){"use strict";function e(t,e){const n=Object.create(null),r=t.split(",");for(let s=0;s!!n[t.toLowerCase()]:t=>!!n[t]}const n={},r=()=>{},s=Object.assign,i=Object.prototype.hasOwnProperty,o=(t,e)=>i.call(t,e),c=Array.isArray,u=t=>"[object Map]"===_(t),a=t=>"function"==typeof t,l=t=>"symbol"==typeof t,f=t=>null!==t&&"object"==typeof t,h=Object.prototype.toString,_=t=>h.call(t),d=t=>"string"==typeof t&&"NaN"!==t&&"-"!==t[0]&&""+parseInt(t,10)===t,v=(t,e)=>t!==e&&(t==t||e==e),g=new WeakMap,p=[];let y;const w=Symbol(""),R=Symbol("");function b(t,e=n){(function(t){return t&&!0===t._isEffect})(t)&&(t=t.raw);const r=function(t,e){const n=function(){if(!n.active)return t();if(!p.includes(n)){E(n);try{return O(),p.push(n),y=n,t()}finally{p.pop(),P(),y=p[p.length-1]}}};return n.id=k++,n.allowRecurse=!!e.allowRecurse,n._isEffect=!0,n.active=!0,n.raw=t,n.deps=[],n.options=e,n}(t,e);return e.lazy||r(),r}let k=0;function E(t){const{deps:e}=t;if(e.length){for(let n=0;n{t&&t.forEach((t=>{(t!==y||t.allowRecurse)&&a.add(t)}))};if("clear"===e)o.forEach(l);else if("length"===n&&c(t))o.forEach(((t,e)=>{("length"===e||e>=r)&&l(t)}));else switch(void 0!==n&&l(o.get(n)),e){case"add":c(t)?d(n)&&l(o.get("length")):(l(o.get(w)),u(t)&&l(o.get(R)));break;case"delete":c(t)||(l(o.get(w)),u(t)&&l(o.get(R)));break;case"set":u(t)&&l(o.get(w))}a.forEach((t=>{t.options.scheduler?t.options.scheduler(t):t()}))}const z=e("__proto__,__v_isRef,__isVue"),W=new Set(Object.getOwnPropertyNames(Symbol).map((t=>Symbol[t])).filter(l)),A=B(),T=B(!1,!0),V=B(!0),N=B(!0,!0),I=K();function K(){const t={};return["includes","indexOf","lastIndexOf"].forEach((e=>{t[e]=function(...t){const n=St(this);for(let e=0,s=this.length;e{t[e]=function(...t){j();const n=St(this)[e].apply(this,t);return P(),n}})),t}function B(t=!1,e=!1){return function(n,r,s){if("__v_isReactive"===r)return!t;if("__v_isReadonly"===r)return t;if("__v_raw"===r&&s===(t?e?yt:pt:e?gt:vt).get(n))return n;const i=c(n);if(!t&&i&&o(I,r))return Reflect.get(I,r,s);const u=Reflect.get(n,r,s);if(l(r)?W.has(r):z(r))return u;if(t||M(n,0,r),e)return u;if(Ot(u)){return!i||!d(r)?u.value:u}return f(u)?t?bt(u):Rt(u):u}}function C(t=!1){return function(e,n,r,s){let i=e[n];if(!t&&(r=St(r),i=St(i),!c(e)&&Ot(i)&&!Ot(r)))return i.value=r,!0;const u=c(e)&&d(n)?Number(n)!0,deleteProperty:(t,e)=>!0},q=s({},L,{get:T,set:C(!0)}),D=s({},Y,{get:N}),F=t=>f(t)?Rt(t):t,G=t=>f(t)?bt(t):t,H=t=>t,J=t=>Reflect.getPrototypeOf(t);function Q(t,e,n=!1,r=!1){const s=St(t=t.__v_raw),i=St(e);e!==i&&!n&&M(s,0,e),!n&&M(s,0,i);const{has:o}=J(s),c=r?H:n?G:F;return o.call(s,e)?c(t.get(e)):o.call(s,i)?c(t.get(i)):void(t!==s&&t.get(e))}function U(t,e=!1){const n=this.__v_raw,r=St(n),s=St(t);return t!==s&&!e&&M(r,0,t),!e&&M(r,0,s),t===s?n.has(t):n.has(t)||n.has(s)}function X(t,e=!1){return t=t.__v_raw,!e&&M(St(t),0,w),Reflect.get(t,"size",t)}function Z(t){t=St(t);const e=St(this);return J(e).has.call(e,t)||(e.add(t),x(e,"add",t,t)),this}function $(t,e){e=St(e);const n=St(this),{has:r,get:s}=J(n);let i=r.call(n,t);i||(t=St(t),i=r.call(n,t));const o=s.call(n,t);return n.set(t,e),i?v(e,o)&&x(n,"set",t,e):x(n,"add",t,e),this}function tt(t){const e=St(this),{has:n,get:r}=J(e);let s=n.call(e,t);s||(t=St(t),s=n.call(e,t)),r&&r.call(e,t);const i=e.delete(t);return s&&x(e,"delete",t,void 0),i}function et(){const t=St(this),e=0!==t.size,n=t.clear();return e&&x(t,"clear",void 0,void 0),n}function nt(t,e){return function(n,r){const s=this,i=s.__v_raw,o=St(i),c=e?H:t?G:F;return!t&&M(o,0,w),i.forEach(((t,e)=>n.call(r,c(t),c(e),s)))}}function rt(t,e,n){return function(...r){const s=this.__v_raw,i=St(s),o=u(i),c="entries"===t||t===Symbol.iterator&&o,a="keys"===t&&o,l=s[t](...r),f=n?H:e?G:F;return!e&&M(i,0,a?R:w),{next(){const{value:t,done:e}=l.next();return e?{value:t,done:e}:{value:c?[f(t[0]),f(t[1])]:f(t),done:e}},[Symbol.iterator](){return this}}}}function st(t){return function(...e){return"delete"!==t&&this}}function it(){const t={get(t){return Q(this,t)},get size(){return X(this)},has:U,add:Z,set:$,delete:tt,clear:et,forEach:nt(!1,!1)},e={get(t){return Q(this,t,!1,!0)},get size(){return X(this)},has:U,add:Z,set:$,delete:tt,clear:et,forEach:nt(!1,!0)},n={get(t){return Q(this,t,!0)},get size(){return X(this,!0)},has(t){return U.call(this,t,!0)},add:st("add"),set:st("set"),delete:st("delete"),clear:st("clear"),forEach:nt(!0,!1)},r={get(t){return Q(this,t,!0,!0)},get size(){return X(this,!0)},has(t){return U.call(this,t,!0)},add:st("add"),set:st("set"),delete:st("delete"),clear:st("clear"),forEach:nt(!0,!0)};return["keys","values","entries",Symbol.iterator].forEach((s=>{t[s]=rt(s,!1,!1),n[s]=rt(s,!0,!1),e[s]=rt(s,!1,!0),r[s]=rt(s,!0,!0)})),[t,n,e,r]}const[ot,ct,ut,at]=it();function lt(t,e){const n=e?t?at:ut:t?ct:ot;return(e,r,s)=>"__v_isReactive"===r?!t:"__v_isReadonly"===r?t:"__v_raw"===r?e:Reflect.get(o(n,r)&&r in e?n:e,r,s)}const ft={get:lt(!1,!1)},ht={get:lt(!1,!0)},_t={get:lt(!0,!1)},dt={get:lt(!0,!0)},vt=new WeakMap,gt=new WeakMap,pt=new WeakMap,yt=new WeakMap;function wt(t){return t.__v_skip||!Object.isExtensible(t)?0:function(t){switch(t){case"Object":case"Array":return 1;case"Map":case"Set":case"WeakMap":case"WeakSet":return 2;default:return 0}}((t=>_(t).slice(8,-1))(t))}function Rt(t){return t&&t.__v_isReadonly?t:kt(t,!1,L,ft,vt)}function bt(t){return kt(t,!0,Y,_t,pt)}function kt(t,e,n,r,s){if(!f(t))return t;if(t.__v_raw&&(!e||!t.__v_isReactive))return t;const i=s.get(t);if(i)return i;const o=wt(t);if(0===o)return t;const c=new Proxy(t,2===o?r:n);return s.set(t,c),c}function Et(t){return mt(t)?Et(t.__v_raw):!(!t||!t.__v_isReactive)}function mt(t){return!(!t||!t.__v_isReadonly)}function St(t){return t&&St(t.__v_raw)||t}const jt=t=>f(t)?Rt(t):t;function Ot(t){return Boolean(t&&!0===t.__v_isRef)}class Pt{constructor(t,e=!1){this._shallow=e,this.__v_isRef=!0,this._rawValue=e?t:St(t),this._value=e?t:jt(t)}get value(){return M(St(this),0,"value"),this._value}set value(t){t=this._shallow?t:St(t),v(t,this._rawValue)&&(this._rawValue=t,this._value=this._shallow?t:jt(t),x(St(this),"set","value",t))}}function Mt(t,e=!1){return Ot(t)?t:new Pt(t,e)}function xt(t){return Ot(t)?t.value:t}const zt={get:(t,e,n)=>xt(Reflect.get(t,e,n)),set:(t,e,n,r)=>{const s=t[e];return Ot(s)&&!Ot(n)?(s.value=n,!0):Reflect.set(t,e,n,r)}};class Wt{constructor(t){this.__v_isRef=!0;const{get:e,set:n}=t((()=>M(this,0,"value")),(()=>x(this,"set","value")));this._get=e,this._set=n}get value(){return this._get()}set value(t){this._set(t)}}class At{constructor(t,e){this._object=t,this._key=e,this.__v_isRef=!0}get value(){return this._object[this._key]}set value(t){this._object[this._key]=t}}function Tt(t,e){return Ot(t[e])?t[e]:new At(t,e)}class Vt{constructor(t,e,n){this._setter=e,this._dirty=!0,this.__v_isRef=!0,this.effect=b(t,{lazy:!0,scheduler:()=>{this._dirty||(this._dirty=!0,x(St(this),"set","value"))}}),this.__v_isReadonly=n}get value(){const t=St(this);return t._dirty&&(t._value=this.effect(),t._dirty=!1),M(t,0,"value"),t._value}set value(t){this._setter(t)}}return t.ITERATE_KEY=w,t.computed=function(t){let e,n;return a(t)?(e=t,n=r):(e=t.get,n=t.set),new Vt(e,n,a(t)||!t.set)},t.customRef=function(t){return new Wt(t)},t.effect=b,t.enableTracking=O,t.isProxy=function(t){return Et(t)||mt(t)},t.isReactive=Et,t.isReadonly=mt,t.isRef=Ot,t.markRaw=function(t){return((t,e,n)=>{Object.defineProperty(t,e,{configurable:!0,enumerable:!1,value:n})})(t,"__v_skip",!0),t},t.pauseTracking=j,t.proxyRefs=function(t){return Et(t)?t:new Proxy(t,zt)},t.reactive=Rt,t.readonly=bt,t.ref=function(t){return Mt(t)},t.resetTracking=P,t.shallowReactive=function(t){return kt(t,!1,q,ht,gt)},t.shallowReadonly=function(t){return kt(t,!0,D,dt,yt)},t.shallowRef=function(t){return Mt(t,!0)},t.stop=function(t){t.active&&(E(t),t.options.onStop&&t.options.onStop(),t.active=!1)},t.toRaw=St,t.toRef=Tt,t.toRefs=function(t){const e=c(t)?new Array(t.length):{};for(const n in t)e[n]=Tt(t,n);return e},t.track=M,t.trigger=x,t.triggerRef=function(t){x(St(t),"set","value",void 0)},t.unref=xt,Object.defineProperty(t,"__esModule",{value:!0}),t}({}); diff --git a/node_modules/@vue/reactivity/index.js b/node_modules/@vue/reactivity/index.js new file mode 100644 index 0000000..04a8ba5 --- /dev/null +++ b/node_modules/@vue/reactivity/index.js @@ -0,0 +1,7 @@ +'use strict' + +if (process.env.NODE_ENV === 'production') { + module.exports = require('./dist/reactivity.cjs.prod.js') +} else { + module.exports = require('./dist/reactivity.cjs.js') +} diff --git a/node_modules/@vue/reactivity/package.json b/node_modules/@vue/reactivity/package.json new file mode 100644 index 0000000..c96c789 --- /dev/null +++ b/node_modules/@vue/reactivity/package.json @@ -0,0 +1,41 @@ +{ + "name": "@vue/reactivity", + "version": "3.1.5", + "description": "@vue/reactivity", + "main": "index.js", + "module": "dist/reactivity.esm-bundler.js", + "types": "dist/reactivity.d.ts", + "unpkg": "dist/reactivity.global.js", + "jsdelivr": "dist/reactivity.global.js", + "files": [ + "index.js", + "dist" + ], + "sideEffects": false, + "repository": { + "type": "git", + "url": "git+https://github.com/vuejs/vue-next.git", + "directory": "packages/reactivity" + }, + "buildOptions": { + "name": "VueReactivity", + "formats": [ + "esm-bundler", + "esm-browser", + "cjs", + "global" + ] + }, + "keywords": [ + "vue" + ], + "author": "Evan You", + "license": "MIT", + "bugs": { + "url": "https://github.com/vuejs/vue-next/issues" + }, + "homepage": "https://github.com/vuejs/vue-next/tree/master/packages/reactivity#readme", + "dependencies": { + "@vue/shared": "3.1.5" + } +} diff --git a/node_modules/@vue/shared/LICENSE b/node_modules/@vue/shared/LICENSE new file mode 100644 index 0000000..15f1f7e --- /dev/null +++ b/node_modules/@vue/shared/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2018-present, Yuxi (Evan) You + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/node_modules/@vue/shared/README.md b/node_modules/@vue/shared/README.md new file mode 100644 index 0000000..1d01f2f --- /dev/null +++ b/node_modules/@vue/shared/README.md @@ -0,0 +1,3 @@ +# @vue/shared + +Internal utility functions and constants shared across `@vue` packages. diff --git a/node_modules/@vue/shared/dist/shared.cjs.js b/node_modules/@vue/shared/dist/shared.cjs.js new file mode 100644 index 0000000..390639d --- /dev/null +++ b/node_modules/@vue/shared/dist/shared.cjs.js @@ -0,0 +1,568 @@ +'use strict'; + +Object.defineProperty(exports, '__esModule', { value: true }); + +/** + * Make a map and return a function for checking if a key + * is in that map. + * IMPORTANT: all calls of this function must be prefixed with + * \/\*#\_\_PURE\_\_\*\/ + * So that rollup can tree-shake them if necessary. + */ +function makeMap(str, expectsLowerCase) { + const map = Object.create(null); + const list = str.split(','); + for (let i = 0; i < list.length; i++) { + map[list[i]] = true; + } + return expectsLowerCase ? val => !!map[val.toLowerCase()] : val => !!map[val]; +} + +/** + * dev only flag -> name mapping + */ +const PatchFlagNames = { + [1 /* TEXT */]: `TEXT`, + [2 /* CLASS */]: `CLASS`, + [4 /* STYLE */]: `STYLE`, + [8 /* PROPS */]: `PROPS`, + [16 /* FULL_PROPS */]: `FULL_PROPS`, + [32 /* HYDRATE_EVENTS */]: `HYDRATE_EVENTS`, + [64 /* STABLE_FRAGMENT */]: `STABLE_FRAGMENT`, + [128 /* KEYED_FRAGMENT */]: `KEYED_FRAGMENT`, + [256 /* UNKEYED_FRAGMENT */]: `UNKEYED_FRAGMENT`, + [512 /* NEED_PATCH */]: `NEED_PATCH`, + [1024 /* DYNAMIC_SLOTS */]: `DYNAMIC_SLOTS`, + [2048 /* DEV_ROOT_FRAGMENT */]: `DEV_ROOT_FRAGMENT`, + [-1 /* HOISTED */]: `HOISTED`, + [-2 /* BAIL */]: `BAIL` +}; + +/** + * Dev only + */ +const slotFlagsText = { + [1 /* STABLE */]: 'STABLE', + [2 /* DYNAMIC */]: 'DYNAMIC', + [3 /* FORWARDED */]: 'FORWARDED' +}; + +const GLOBALS_WHITE_LISTED = 'Infinity,undefined,NaN,isFinite,isNaN,parseFloat,parseInt,decodeURI,' + + 'decodeURIComponent,encodeURI,encodeURIComponent,Math,Number,Date,Array,' + + 'Object,Boolean,String,RegExp,Map,Set,JSON,Intl,BigInt'; +const isGloballyWhitelisted = /*#__PURE__*/ makeMap(GLOBALS_WHITE_LISTED); + +const range = 2; +function generateCodeFrame(source, start = 0, end = source.length) { + // Split the content into individual lines but capture the newline sequence + // that separated each line. This is important because the actual sequence is + // needed to properly take into account the full line length for offset + // comparison + let lines = source.split(/(\r?\n)/); + // Separate the lines and newline sequences into separate arrays for easier referencing + const newlineSequences = lines.filter((_, idx) => idx % 2 === 1); + lines = lines.filter((_, idx) => idx % 2 === 0); + let count = 0; + const res = []; + for (let i = 0; i < lines.length; i++) { + count += + lines[i].length + + ((newlineSequences[i] && newlineSequences[i].length) || 0); + if (count >= start) { + for (let j = i - range; j <= i + range || end > count; j++) { + if (j < 0 || j >= lines.length) + continue; + const line = j + 1; + res.push(`${line}${' '.repeat(Math.max(3 - String(line).length, 0))}| ${lines[j]}`); + const lineLength = lines[j].length; + const newLineSeqLength = (newlineSequences[j] && newlineSequences[j].length) || 0; + if (j === i) { + // push underline + const pad = start - (count - (lineLength + newLineSeqLength)); + const length = Math.max(1, end > count ? lineLength - pad : end - start); + res.push(` | ` + ' '.repeat(pad) + '^'.repeat(length)); + } + else if (j > i) { + if (end > count) { + const length = Math.max(Math.min(end - count, lineLength), 1); + res.push(` | ` + '^'.repeat(length)); + } + count += lineLength + newLineSeqLength; + } + } + break; + } + } + return res.join('\n'); +} + +/** + * On the client we only need to offer special cases for boolean attributes that + * have different names from their corresponding dom properties: + * - itemscope -> N/A + * - allowfullscreen -> allowFullscreen + * - formnovalidate -> formNoValidate + * - ismap -> isMap + * - nomodule -> noModule + * - novalidate -> noValidate + * - readonly -> readOnly + */ +const specialBooleanAttrs = `itemscope,allowfullscreen,formnovalidate,ismap,nomodule,novalidate,readonly`; +const isSpecialBooleanAttr = /*#__PURE__*/ makeMap(specialBooleanAttrs); +/** + * The full list is needed during SSR to produce the correct initial markup. + */ +const isBooleanAttr = /*#__PURE__*/ makeMap(specialBooleanAttrs + + `,async,autofocus,autoplay,controls,default,defer,disabled,hidden,` + + `loop,open,required,reversed,scoped,seamless,` + + `checked,muted,multiple,selected`); +const unsafeAttrCharRE = /[>/="'\u0009\u000a\u000c\u0020]/; +const attrValidationCache = {}; +function isSSRSafeAttrName(name) { + if (attrValidationCache.hasOwnProperty(name)) { + return attrValidationCache[name]; + } + const isUnsafe = unsafeAttrCharRE.test(name); + if (isUnsafe) { + console.error(`unsafe attribute name: ${name}`); + } + return (attrValidationCache[name] = !isUnsafe); +} +const propsToAttrMap = { + acceptCharset: 'accept-charset', + className: 'class', + htmlFor: 'for', + httpEquiv: 'http-equiv' +}; +/** + * CSS properties that accept plain numbers + */ +const isNoUnitNumericStyleProp = /*#__PURE__*/ makeMap(`animation-iteration-count,border-image-outset,border-image-slice,` + + `border-image-width,box-flex,box-flex-group,box-ordinal-group,column-count,` + + `columns,flex,flex-grow,flex-positive,flex-shrink,flex-negative,flex-order,` + + `grid-row,grid-row-end,grid-row-span,grid-row-start,grid-column,` + + `grid-column-end,grid-column-span,grid-column-start,font-weight,line-clamp,` + + `line-height,opacity,order,orphans,tab-size,widows,z-index,zoom,` + + // SVG + `fill-opacity,flood-opacity,stop-opacity,stroke-dasharray,stroke-dashoffset,` + + `stroke-miterlimit,stroke-opacity,stroke-width`); +/** + * Known attributes, this is used for stringification of runtime static nodes + * so that we don't stringify bindings that cannot be set from HTML. + * Don't also forget to allow `data-*` and `aria-*`! + * Generated from https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes + */ +const isKnownAttr = /*#__PURE__*/ makeMap(`accept,accept-charset,accesskey,action,align,allow,alt,async,` + + `autocapitalize,autocomplete,autofocus,autoplay,background,bgcolor,` + + `border,buffered,capture,challenge,charset,checked,cite,class,code,` + + `codebase,color,cols,colspan,content,contenteditable,contextmenu,controls,` + + `coords,crossorigin,csp,data,datetime,decoding,default,defer,dir,dirname,` + + `disabled,download,draggable,dropzone,enctype,enterkeyhint,for,form,` + + `formaction,formenctype,formmethod,formnovalidate,formtarget,headers,` + + `height,hidden,high,href,hreflang,http-equiv,icon,id,importance,integrity,` + + `ismap,itemprop,keytype,kind,label,lang,language,loading,list,loop,low,` + + `manifest,max,maxlength,minlength,media,min,multiple,muted,name,novalidate,` + + `open,optimum,pattern,ping,placeholder,poster,preload,radiogroup,readonly,` + + `referrerpolicy,rel,required,reversed,rows,rowspan,sandbox,scope,scoped,` + + `selected,shape,size,sizes,slot,span,spellcheck,src,srcdoc,srclang,srcset,` + + `start,step,style,summary,tabindex,target,title,translate,type,usemap,` + + `value,width,wrap`); + +function normalizeStyle(value) { + if (isArray(value)) { + const res = {}; + for (let i = 0; i < value.length; i++) { + const item = value[i]; + const normalized = normalizeStyle(isString(item) ? parseStringStyle(item) : item); + if (normalized) { + for (const key in normalized) { + res[key] = normalized[key]; + } + } + } + return res; + } + else if (isObject(value)) { + return value; + } +} +const listDelimiterRE = /;(?![^(]*\))/g; +const propertyDelimiterRE = /:(.+)/; +function parseStringStyle(cssText) { + const ret = {}; + cssText.split(listDelimiterRE).forEach(item => { + if (item) { + const tmp = item.split(propertyDelimiterRE); + tmp.length > 1 && (ret[tmp[0].trim()] = tmp[1].trim()); + } + }); + return ret; +} +function stringifyStyle(styles) { + let ret = ''; + if (!styles) { + return ret; + } + for (const key in styles) { + const value = styles[key]; + const normalizedKey = key.startsWith(`--`) ? key : hyphenate(key); + if (isString(value) || + (typeof value === 'number' && isNoUnitNumericStyleProp(normalizedKey))) { + // only render valid values + ret += `${normalizedKey}:${value};`; + } + } + return ret; +} +function normalizeClass(value) { + let res = ''; + if (isString(value)) { + res = value; + } + else if (isArray(value)) { + for (let i = 0; i < value.length; i++) { + const normalized = normalizeClass(value[i]); + if (normalized) { + res += normalized + ' '; + } + } + } + else if (isObject(value)) { + for (const name in value) { + if (value[name]) { + res += name + ' '; + } + } + } + return res.trim(); +} + +// These tag configs are shared between compiler-dom and runtime-dom, so they +// https://developer.mozilla.org/en-US/docs/Web/HTML/Element +const HTML_TAGS = 'html,body,base,head,link,meta,style,title,address,article,aside,footer,' + + 'header,h1,h2,h3,h4,h5,h6,hgroup,nav,section,div,dd,dl,dt,figcaption,' + + 'figure,picture,hr,img,li,main,ol,p,pre,ul,a,b,abbr,bdi,bdo,br,cite,code,' + + 'data,dfn,em,i,kbd,mark,q,rp,rt,rtc,ruby,s,samp,small,span,strong,sub,sup,' + + 'time,u,var,wbr,area,audio,map,track,video,embed,object,param,source,' + + 'canvas,script,noscript,del,ins,caption,col,colgroup,table,thead,tbody,td,' + + 'th,tr,button,datalist,fieldset,form,input,label,legend,meter,optgroup,' + + 'option,output,progress,select,textarea,details,dialog,menu,' + + 'summary,template,blockquote,iframe,tfoot'; +// https://developer.mozilla.org/en-US/docs/Web/SVG/Element +const SVG_TAGS = 'svg,animate,animateMotion,animateTransform,circle,clipPath,color-profile,' + + 'defs,desc,discard,ellipse,feBlend,feColorMatrix,feComponentTransfer,' + + 'feComposite,feConvolveMatrix,feDiffuseLighting,feDisplacementMap,' + + 'feDistanceLight,feDropShadow,feFlood,feFuncA,feFuncB,feFuncG,feFuncR,' + + 'feGaussianBlur,feImage,feMerge,feMergeNode,feMorphology,feOffset,' + + 'fePointLight,feSpecularLighting,feSpotLight,feTile,feTurbulence,filter,' + + 'foreignObject,g,hatch,hatchpath,image,line,linearGradient,marker,mask,' + + 'mesh,meshgradient,meshpatch,meshrow,metadata,mpath,path,pattern,' + + 'polygon,polyline,radialGradient,rect,set,solidcolor,stop,switch,symbol,' + + 'text,textPath,title,tspan,unknown,use,view'; +const VOID_TAGS = 'area,base,br,col,embed,hr,img,input,link,meta,param,source,track,wbr'; +const isHTMLTag = /*#__PURE__*/ makeMap(HTML_TAGS); +const isSVGTag = /*#__PURE__*/ makeMap(SVG_TAGS); +const isVoidTag = /*#__PURE__*/ makeMap(VOID_TAGS); + +const escapeRE = /["'&<>]/; +function escapeHtml(string) { + const str = '' + string; + const match = escapeRE.exec(str); + if (!match) { + return str; + } + let html = ''; + let escaped; + let index; + let lastIndex = 0; + for (index = match.index; index < str.length; index++) { + switch (str.charCodeAt(index)) { + case 34: // " + escaped = '"'; + break; + case 38: // & + escaped = '&'; + break; + case 39: // ' + escaped = '''; + break; + case 60: // < + escaped = '<'; + break; + case 62: // > + escaped = '>'; + break; + default: + continue; + } + if (lastIndex !== index) { + html += str.substring(lastIndex, index); + } + lastIndex = index + 1; + html += escaped; + } + return lastIndex !== index ? html + str.substring(lastIndex, index) : html; +} +// https://www.w3.org/TR/html52/syntax.html#comments +const commentStripRE = /^-?>||--!>| looseEqual(item, val)); +} + +/** + * For converting {{ interpolation }} values to displayed strings. + * @private + */ +const toDisplayString = (val) => { + return val == null + ? '' + : isObject(val) + ? JSON.stringify(val, replacer, 2) + : String(val); +}; +const replacer = (_key, val) => { + if (isMap(val)) { + return { + [`Map(${val.size})`]: [...val.entries()].reduce((entries, [key, val]) => { + entries[`${key} =>`] = val; + return entries; + }, {}) + }; + } + else if (isSet(val)) { + return { + [`Set(${val.size})`]: [...val.values()] + }; + } + else if (isObject(val) && !isArray(val) && !isPlainObject(val)) { + return String(val); + } + return val; +}; + +/** + * List of @babel/parser plugins that are used for template expression + * transforms and SFC script transforms. By default we enable proposals slated + * for ES2020. This will need to be updated as the spec moves forward. + * Full list at https://babeljs.io/docs/en/next/babel-parser#plugins + */ +const babelParserDefaultPlugins = [ + 'bigInt', + 'optionalChaining', + 'nullishCoalescingOperator' +]; +const EMPTY_OBJ = Object.freeze({}) + ; +const EMPTY_ARR = Object.freeze([]) ; +const NOOP = () => { }; +/** + * Always return false. + */ +const NO = () => false; +const onRE = /^on[^a-z]/; +const isOn = (key) => onRE.test(key); +const isModelListener = (key) => key.startsWith('onUpdate:'); +const extend = Object.assign; +const remove = (arr, el) => { + const i = arr.indexOf(el); + if (i > -1) { + arr.splice(i, 1); + } +}; +const hasOwnProperty = Object.prototype.hasOwnProperty; +const hasOwn = (val, key) => hasOwnProperty.call(val, key); +const isArray = Array.isArray; +const isMap = (val) => toTypeString(val) === '[object Map]'; +const isSet = (val) => toTypeString(val) === '[object Set]'; +const isDate = (val) => val instanceof Date; +const isFunction = (val) => typeof val === 'function'; +const isString = (val) => typeof val === 'string'; +const isSymbol = (val) => typeof val === 'symbol'; +const isObject = (val) => val !== null && typeof val === 'object'; +const isPromise = (val) => { + return isObject(val) && isFunction(val.then) && isFunction(val.catch); +}; +const objectToString = Object.prototype.toString; +const toTypeString = (value) => objectToString.call(value); +const toRawType = (value) => { + // extract "RawType" from strings like "[object RawType]" + return toTypeString(value).slice(8, -1); +}; +const isPlainObject = (val) => toTypeString(val) === '[object Object]'; +const isIntegerKey = (key) => isString(key) && + key !== 'NaN' && + key[0] !== '-' && + '' + parseInt(key, 10) === key; +const isReservedProp = /*#__PURE__*/ makeMap( +// the leading comma is intentional so empty string "" is also included +',key,ref,' + + 'onVnodeBeforeMount,onVnodeMounted,' + + 'onVnodeBeforeUpdate,onVnodeUpdated,' + + 'onVnodeBeforeUnmount,onVnodeUnmounted'); +const cacheStringFunction = (fn) => { + const cache = Object.create(null); + return ((str) => { + const hit = cache[str]; + return hit || (cache[str] = fn(str)); + }); +}; +const camelizeRE = /-(\w)/g; +/** + * @private + */ +const camelize = cacheStringFunction((str) => { + return str.replace(camelizeRE, (_, c) => (c ? c.toUpperCase() : '')); +}); +const hyphenateRE = /\B([A-Z])/g; +/** + * @private + */ +const hyphenate = cacheStringFunction((str) => str.replace(hyphenateRE, '-$1').toLowerCase()); +/** + * @private + */ +const capitalize = cacheStringFunction((str) => str.charAt(0).toUpperCase() + str.slice(1)); +/** + * @private + */ +const toHandlerKey = cacheStringFunction((str) => (str ? `on${capitalize(str)}` : ``)); +// compare whether a value has changed, accounting for NaN. +const hasChanged = (value, oldValue) => value !== oldValue && (value === value || oldValue === oldValue); +const invokeArrayFns = (fns, arg) => { + for (let i = 0; i < fns.length; i++) { + fns[i](arg); + } +}; +const def = (obj, key, value) => { + Object.defineProperty(obj, key, { + configurable: true, + enumerable: false, + value + }); +}; +const toNumber = (val) => { + const n = parseFloat(val); + return isNaN(n) ? val : n; +}; +let _globalThis; +const getGlobalThis = () => { + return (_globalThis || + (_globalThis = + typeof globalThis !== 'undefined' + ? globalThis + : typeof self !== 'undefined' + ? self + : typeof window !== 'undefined' + ? window + : typeof global !== 'undefined' + ? global + : {})); +}; + +exports.EMPTY_ARR = EMPTY_ARR; +exports.EMPTY_OBJ = EMPTY_OBJ; +exports.NO = NO; +exports.NOOP = NOOP; +exports.PatchFlagNames = PatchFlagNames; +exports.babelParserDefaultPlugins = babelParserDefaultPlugins; +exports.camelize = camelize; +exports.capitalize = capitalize; +exports.def = def; +exports.escapeHtml = escapeHtml; +exports.escapeHtmlComment = escapeHtmlComment; +exports.extend = extend; +exports.generateCodeFrame = generateCodeFrame; +exports.getGlobalThis = getGlobalThis; +exports.hasChanged = hasChanged; +exports.hasOwn = hasOwn; +exports.hyphenate = hyphenate; +exports.invokeArrayFns = invokeArrayFns; +exports.isArray = isArray; +exports.isBooleanAttr = isBooleanAttr; +exports.isDate = isDate; +exports.isFunction = isFunction; +exports.isGloballyWhitelisted = isGloballyWhitelisted; +exports.isHTMLTag = isHTMLTag; +exports.isIntegerKey = isIntegerKey; +exports.isKnownAttr = isKnownAttr; +exports.isMap = isMap; +exports.isModelListener = isModelListener; +exports.isNoUnitNumericStyleProp = isNoUnitNumericStyleProp; +exports.isObject = isObject; +exports.isOn = isOn; +exports.isPlainObject = isPlainObject; +exports.isPromise = isPromise; +exports.isReservedProp = isReservedProp; +exports.isSSRSafeAttrName = isSSRSafeAttrName; +exports.isSVGTag = isSVGTag; +exports.isSet = isSet; +exports.isSpecialBooleanAttr = isSpecialBooleanAttr; +exports.isString = isString; +exports.isSymbol = isSymbol; +exports.isVoidTag = isVoidTag; +exports.looseEqual = looseEqual; +exports.looseIndexOf = looseIndexOf; +exports.makeMap = makeMap; +exports.normalizeClass = normalizeClass; +exports.normalizeStyle = normalizeStyle; +exports.objectToString = objectToString; +exports.parseStringStyle = parseStringStyle; +exports.propsToAttrMap = propsToAttrMap; +exports.remove = remove; +exports.slotFlagsText = slotFlagsText; +exports.stringifyStyle = stringifyStyle; +exports.toDisplayString = toDisplayString; +exports.toHandlerKey = toHandlerKey; +exports.toNumber = toNumber; +exports.toRawType = toRawType; +exports.toTypeString = toTypeString; diff --git a/node_modules/@vue/shared/dist/shared.cjs.prod.js b/node_modules/@vue/shared/dist/shared.cjs.prod.js new file mode 100644 index 0000000..0b55626 --- /dev/null +++ b/node_modules/@vue/shared/dist/shared.cjs.prod.js @@ -0,0 +1,567 @@ +'use strict'; + +Object.defineProperty(exports, '__esModule', { value: true }); + +/** + * Make a map and return a function for checking if a key + * is in that map. + * IMPORTANT: all calls of this function must be prefixed with + * \/\*#\_\_PURE\_\_\*\/ + * So that rollup can tree-shake them if necessary. + */ +function makeMap(str, expectsLowerCase) { + const map = Object.create(null); + const list = str.split(','); + for (let i = 0; i < list.length; i++) { + map[list[i]] = true; + } + return expectsLowerCase ? val => !!map[val.toLowerCase()] : val => !!map[val]; +} + +/** + * dev only flag -> name mapping + */ +const PatchFlagNames = { + [1 /* TEXT */]: `TEXT`, + [2 /* CLASS */]: `CLASS`, + [4 /* STYLE */]: `STYLE`, + [8 /* PROPS */]: `PROPS`, + [16 /* FULL_PROPS */]: `FULL_PROPS`, + [32 /* HYDRATE_EVENTS */]: `HYDRATE_EVENTS`, + [64 /* STABLE_FRAGMENT */]: `STABLE_FRAGMENT`, + [128 /* KEYED_FRAGMENT */]: `KEYED_FRAGMENT`, + [256 /* UNKEYED_FRAGMENT */]: `UNKEYED_FRAGMENT`, + [512 /* NEED_PATCH */]: `NEED_PATCH`, + [1024 /* DYNAMIC_SLOTS */]: `DYNAMIC_SLOTS`, + [2048 /* DEV_ROOT_FRAGMENT */]: `DEV_ROOT_FRAGMENT`, + [-1 /* HOISTED */]: `HOISTED`, + [-2 /* BAIL */]: `BAIL` +}; + +/** + * Dev only + */ +const slotFlagsText = { + [1 /* STABLE */]: 'STABLE', + [2 /* DYNAMIC */]: 'DYNAMIC', + [3 /* FORWARDED */]: 'FORWARDED' +}; + +const GLOBALS_WHITE_LISTED = 'Infinity,undefined,NaN,isFinite,isNaN,parseFloat,parseInt,decodeURI,' + + 'decodeURIComponent,encodeURI,encodeURIComponent,Math,Number,Date,Array,' + + 'Object,Boolean,String,RegExp,Map,Set,JSON,Intl,BigInt'; +const isGloballyWhitelisted = /*#__PURE__*/ makeMap(GLOBALS_WHITE_LISTED); + +const range = 2; +function generateCodeFrame(source, start = 0, end = source.length) { + // Split the content into individual lines but capture the newline sequence + // that separated each line. This is important because the actual sequence is + // needed to properly take into account the full line length for offset + // comparison + let lines = source.split(/(\r?\n)/); + // Separate the lines and newline sequences into separate arrays for easier referencing + const newlineSequences = lines.filter((_, idx) => idx % 2 === 1); + lines = lines.filter((_, idx) => idx % 2 === 0); + let count = 0; + const res = []; + for (let i = 0; i < lines.length; i++) { + count += + lines[i].length + + ((newlineSequences[i] && newlineSequences[i].length) || 0); + if (count >= start) { + for (let j = i - range; j <= i + range || end > count; j++) { + if (j < 0 || j >= lines.length) + continue; + const line = j + 1; + res.push(`${line}${' '.repeat(Math.max(3 - String(line).length, 0))}| ${lines[j]}`); + const lineLength = lines[j].length; + const newLineSeqLength = (newlineSequences[j] && newlineSequences[j].length) || 0; + if (j === i) { + // push underline + const pad = start - (count - (lineLength + newLineSeqLength)); + const length = Math.max(1, end > count ? lineLength - pad : end - start); + res.push(` | ` + ' '.repeat(pad) + '^'.repeat(length)); + } + else if (j > i) { + if (end > count) { + const length = Math.max(Math.min(end - count, lineLength), 1); + res.push(` | ` + '^'.repeat(length)); + } + count += lineLength + newLineSeqLength; + } + } + break; + } + } + return res.join('\n'); +} + +/** + * On the client we only need to offer special cases for boolean attributes that + * have different names from their corresponding dom properties: + * - itemscope -> N/A + * - allowfullscreen -> allowFullscreen + * - formnovalidate -> formNoValidate + * - ismap -> isMap + * - nomodule -> noModule + * - novalidate -> noValidate + * - readonly -> readOnly + */ +const specialBooleanAttrs = `itemscope,allowfullscreen,formnovalidate,ismap,nomodule,novalidate,readonly`; +const isSpecialBooleanAttr = /*#__PURE__*/ makeMap(specialBooleanAttrs); +/** + * The full list is needed during SSR to produce the correct initial markup. + */ +const isBooleanAttr = /*#__PURE__*/ makeMap(specialBooleanAttrs + + `,async,autofocus,autoplay,controls,default,defer,disabled,hidden,` + + `loop,open,required,reversed,scoped,seamless,` + + `checked,muted,multiple,selected`); +const unsafeAttrCharRE = /[>/="'\u0009\u000a\u000c\u0020]/; +const attrValidationCache = {}; +function isSSRSafeAttrName(name) { + if (attrValidationCache.hasOwnProperty(name)) { + return attrValidationCache[name]; + } + const isUnsafe = unsafeAttrCharRE.test(name); + if (isUnsafe) { + console.error(`unsafe attribute name: ${name}`); + } + return (attrValidationCache[name] = !isUnsafe); +} +const propsToAttrMap = { + acceptCharset: 'accept-charset', + className: 'class', + htmlFor: 'for', + httpEquiv: 'http-equiv' +}; +/** + * CSS properties that accept plain numbers + */ +const isNoUnitNumericStyleProp = /*#__PURE__*/ makeMap(`animation-iteration-count,border-image-outset,border-image-slice,` + + `border-image-width,box-flex,box-flex-group,box-ordinal-group,column-count,` + + `columns,flex,flex-grow,flex-positive,flex-shrink,flex-negative,flex-order,` + + `grid-row,grid-row-end,grid-row-span,grid-row-start,grid-column,` + + `grid-column-end,grid-column-span,grid-column-start,font-weight,line-clamp,` + + `line-height,opacity,order,orphans,tab-size,widows,z-index,zoom,` + + // SVG + `fill-opacity,flood-opacity,stop-opacity,stroke-dasharray,stroke-dashoffset,` + + `stroke-miterlimit,stroke-opacity,stroke-width`); +/** + * Known attributes, this is used for stringification of runtime static nodes + * so that we don't stringify bindings that cannot be set from HTML. + * Don't also forget to allow `data-*` and `aria-*`! + * Generated from https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes + */ +const isKnownAttr = /*#__PURE__*/ makeMap(`accept,accept-charset,accesskey,action,align,allow,alt,async,` + + `autocapitalize,autocomplete,autofocus,autoplay,background,bgcolor,` + + `border,buffered,capture,challenge,charset,checked,cite,class,code,` + + `codebase,color,cols,colspan,content,contenteditable,contextmenu,controls,` + + `coords,crossorigin,csp,data,datetime,decoding,default,defer,dir,dirname,` + + `disabled,download,draggable,dropzone,enctype,enterkeyhint,for,form,` + + `formaction,formenctype,formmethod,formnovalidate,formtarget,headers,` + + `height,hidden,high,href,hreflang,http-equiv,icon,id,importance,integrity,` + + `ismap,itemprop,keytype,kind,label,lang,language,loading,list,loop,low,` + + `manifest,max,maxlength,minlength,media,min,multiple,muted,name,novalidate,` + + `open,optimum,pattern,ping,placeholder,poster,preload,radiogroup,readonly,` + + `referrerpolicy,rel,required,reversed,rows,rowspan,sandbox,scope,scoped,` + + `selected,shape,size,sizes,slot,span,spellcheck,src,srcdoc,srclang,srcset,` + + `start,step,style,summary,tabindex,target,title,translate,type,usemap,` + + `value,width,wrap`); + +function normalizeStyle(value) { + if (isArray(value)) { + const res = {}; + for (let i = 0; i < value.length; i++) { + const item = value[i]; + const normalized = normalizeStyle(isString(item) ? parseStringStyle(item) : item); + if (normalized) { + for (const key in normalized) { + res[key] = normalized[key]; + } + } + } + return res; + } + else if (isObject(value)) { + return value; + } +} +const listDelimiterRE = /;(?![^(]*\))/g; +const propertyDelimiterRE = /:(.+)/; +function parseStringStyle(cssText) { + const ret = {}; + cssText.split(listDelimiterRE).forEach(item => { + if (item) { + const tmp = item.split(propertyDelimiterRE); + tmp.length > 1 && (ret[tmp[0].trim()] = tmp[1].trim()); + } + }); + return ret; +} +function stringifyStyle(styles) { + let ret = ''; + if (!styles) { + return ret; + } + for (const key in styles) { + const value = styles[key]; + const normalizedKey = key.startsWith(`--`) ? key : hyphenate(key); + if (isString(value) || + (typeof value === 'number' && isNoUnitNumericStyleProp(normalizedKey))) { + // only render valid values + ret += `${normalizedKey}:${value};`; + } + } + return ret; +} +function normalizeClass(value) { + let res = ''; + if (isString(value)) { + res = value; + } + else if (isArray(value)) { + for (let i = 0; i < value.length; i++) { + const normalized = normalizeClass(value[i]); + if (normalized) { + res += normalized + ' '; + } + } + } + else if (isObject(value)) { + for (const name in value) { + if (value[name]) { + res += name + ' '; + } + } + } + return res.trim(); +} + +// These tag configs are shared between compiler-dom and runtime-dom, so they +// https://developer.mozilla.org/en-US/docs/Web/HTML/Element +const HTML_TAGS = 'html,body,base,head,link,meta,style,title,address,article,aside,footer,' + + 'header,h1,h2,h3,h4,h5,h6,hgroup,nav,section,div,dd,dl,dt,figcaption,' + + 'figure,picture,hr,img,li,main,ol,p,pre,ul,a,b,abbr,bdi,bdo,br,cite,code,' + + 'data,dfn,em,i,kbd,mark,q,rp,rt,rtc,ruby,s,samp,small,span,strong,sub,sup,' + + 'time,u,var,wbr,area,audio,map,track,video,embed,object,param,source,' + + 'canvas,script,noscript,del,ins,caption,col,colgroup,table,thead,tbody,td,' + + 'th,tr,button,datalist,fieldset,form,input,label,legend,meter,optgroup,' + + 'option,output,progress,select,textarea,details,dialog,menu,' + + 'summary,template,blockquote,iframe,tfoot'; +// https://developer.mozilla.org/en-US/docs/Web/SVG/Element +const SVG_TAGS = 'svg,animate,animateMotion,animateTransform,circle,clipPath,color-profile,' + + 'defs,desc,discard,ellipse,feBlend,feColorMatrix,feComponentTransfer,' + + 'feComposite,feConvolveMatrix,feDiffuseLighting,feDisplacementMap,' + + 'feDistanceLight,feDropShadow,feFlood,feFuncA,feFuncB,feFuncG,feFuncR,' + + 'feGaussianBlur,feImage,feMerge,feMergeNode,feMorphology,feOffset,' + + 'fePointLight,feSpecularLighting,feSpotLight,feTile,feTurbulence,filter,' + + 'foreignObject,g,hatch,hatchpath,image,line,linearGradient,marker,mask,' + + 'mesh,meshgradient,meshpatch,meshrow,metadata,mpath,path,pattern,' + + 'polygon,polyline,radialGradient,rect,set,solidcolor,stop,switch,symbol,' + + 'text,textPath,title,tspan,unknown,use,view'; +const VOID_TAGS = 'area,base,br,col,embed,hr,img,input,link,meta,param,source,track,wbr'; +const isHTMLTag = /*#__PURE__*/ makeMap(HTML_TAGS); +const isSVGTag = /*#__PURE__*/ makeMap(SVG_TAGS); +const isVoidTag = /*#__PURE__*/ makeMap(VOID_TAGS); + +const escapeRE = /["'&<>]/; +function escapeHtml(string) { + const str = '' + string; + const match = escapeRE.exec(str); + if (!match) { + return str; + } + let html = ''; + let escaped; + let index; + let lastIndex = 0; + for (index = match.index; index < str.length; index++) { + switch (str.charCodeAt(index)) { + case 34: // " + escaped = '"'; + break; + case 38: // & + escaped = '&'; + break; + case 39: // ' + escaped = '''; + break; + case 60: // < + escaped = '<'; + break; + case 62: // > + escaped = '>'; + break; + default: + continue; + } + if (lastIndex !== index) { + html += str.substring(lastIndex, index); + } + lastIndex = index + 1; + html += escaped; + } + return lastIndex !== index ? html + str.substring(lastIndex, index) : html; +} +// https://www.w3.org/TR/html52/syntax.html#comments +const commentStripRE = /^-?>||--!>| looseEqual(item, val)); +} + +/** + * For converting {{ interpolation }} values to displayed strings. + * @private + */ +const toDisplayString = (val) => { + return val == null + ? '' + : isObject(val) + ? JSON.stringify(val, replacer, 2) + : String(val); +}; +const replacer = (_key, val) => { + if (isMap(val)) { + return { + [`Map(${val.size})`]: [...val.entries()].reduce((entries, [key, val]) => { + entries[`${key} =>`] = val; + return entries; + }, {}) + }; + } + else if (isSet(val)) { + return { + [`Set(${val.size})`]: [...val.values()] + }; + } + else if (isObject(val) && !isArray(val) && !isPlainObject(val)) { + return String(val); + } + return val; +}; + +/** + * List of @babel/parser plugins that are used for template expression + * transforms and SFC script transforms. By default we enable proposals slated + * for ES2020. This will need to be updated as the spec moves forward. + * Full list at https://babeljs.io/docs/en/next/babel-parser#plugins + */ +const babelParserDefaultPlugins = [ + 'bigInt', + 'optionalChaining', + 'nullishCoalescingOperator' +]; +const EMPTY_OBJ = {}; +const EMPTY_ARR = []; +const NOOP = () => { }; +/** + * Always return false. + */ +const NO = () => false; +const onRE = /^on[^a-z]/; +const isOn = (key) => onRE.test(key); +const isModelListener = (key) => key.startsWith('onUpdate:'); +const extend = Object.assign; +const remove = (arr, el) => { + const i = arr.indexOf(el); + if (i > -1) { + arr.splice(i, 1); + } +}; +const hasOwnProperty = Object.prototype.hasOwnProperty; +const hasOwn = (val, key) => hasOwnProperty.call(val, key); +const isArray = Array.isArray; +const isMap = (val) => toTypeString(val) === '[object Map]'; +const isSet = (val) => toTypeString(val) === '[object Set]'; +const isDate = (val) => val instanceof Date; +const isFunction = (val) => typeof val === 'function'; +const isString = (val) => typeof val === 'string'; +const isSymbol = (val) => typeof val === 'symbol'; +const isObject = (val) => val !== null && typeof val === 'object'; +const isPromise = (val) => { + return isObject(val) && isFunction(val.then) && isFunction(val.catch); +}; +const objectToString = Object.prototype.toString; +const toTypeString = (value) => objectToString.call(value); +const toRawType = (value) => { + // extract "RawType" from strings like "[object RawType]" + return toTypeString(value).slice(8, -1); +}; +const isPlainObject = (val) => toTypeString(val) === '[object Object]'; +const isIntegerKey = (key) => isString(key) && + key !== 'NaN' && + key[0] !== '-' && + '' + parseInt(key, 10) === key; +const isReservedProp = /*#__PURE__*/ makeMap( +// the leading comma is intentional so empty string "" is also included +',key,ref,' + + 'onVnodeBeforeMount,onVnodeMounted,' + + 'onVnodeBeforeUpdate,onVnodeUpdated,' + + 'onVnodeBeforeUnmount,onVnodeUnmounted'); +const cacheStringFunction = (fn) => { + const cache = Object.create(null); + return ((str) => { + const hit = cache[str]; + return hit || (cache[str] = fn(str)); + }); +}; +const camelizeRE = /-(\w)/g; +/** + * @private + */ +const camelize = cacheStringFunction((str) => { + return str.replace(camelizeRE, (_, c) => (c ? c.toUpperCase() : '')); +}); +const hyphenateRE = /\B([A-Z])/g; +/** + * @private + */ +const hyphenate = cacheStringFunction((str) => str.replace(hyphenateRE, '-$1').toLowerCase()); +/** + * @private + */ +const capitalize = cacheStringFunction((str) => str.charAt(0).toUpperCase() + str.slice(1)); +/** + * @private + */ +const toHandlerKey = cacheStringFunction((str) => (str ? `on${capitalize(str)}` : ``)); +// compare whether a value has changed, accounting for NaN. +const hasChanged = (value, oldValue) => value !== oldValue && (value === value || oldValue === oldValue); +const invokeArrayFns = (fns, arg) => { + for (let i = 0; i < fns.length; i++) { + fns[i](arg); + } +}; +const def = (obj, key, value) => { + Object.defineProperty(obj, key, { + configurable: true, + enumerable: false, + value + }); +}; +const toNumber = (val) => { + const n = parseFloat(val); + return isNaN(n) ? val : n; +}; +let _globalThis; +const getGlobalThis = () => { + return (_globalThis || + (_globalThis = + typeof globalThis !== 'undefined' + ? globalThis + : typeof self !== 'undefined' + ? self + : typeof window !== 'undefined' + ? window + : typeof global !== 'undefined' + ? global + : {})); +}; + +exports.EMPTY_ARR = EMPTY_ARR; +exports.EMPTY_OBJ = EMPTY_OBJ; +exports.NO = NO; +exports.NOOP = NOOP; +exports.PatchFlagNames = PatchFlagNames; +exports.babelParserDefaultPlugins = babelParserDefaultPlugins; +exports.camelize = camelize; +exports.capitalize = capitalize; +exports.def = def; +exports.escapeHtml = escapeHtml; +exports.escapeHtmlComment = escapeHtmlComment; +exports.extend = extend; +exports.generateCodeFrame = generateCodeFrame; +exports.getGlobalThis = getGlobalThis; +exports.hasChanged = hasChanged; +exports.hasOwn = hasOwn; +exports.hyphenate = hyphenate; +exports.invokeArrayFns = invokeArrayFns; +exports.isArray = isArray; +exports.isBooleanAttr = isBooleanAttr; +exports.isDate = isDate; +exports.isFunction = isFunction; +exports.isGloballyWhitelisted = isGloballyWhitelisted; +exports.isHTMLTag = isHTMLTag; +exports.isIntegerKey = isIntegerKey; +exports.isKnownAttr = isKnownAttr; +exports.isMap = isMap; +exports.isModelListener = isModelListener; +exports.isNoUnitNumericStyleProp = isNoUnitNumericStyleProp; +exports.isObject = isObject; +exports.isOn = isOn; +exports.isPlainObject = isPlainObject; +exports.isPromise = isPromise; +exports.isReservedProp = isReservedProp; +exports.isSSRSafeAttrName = isSSRSafeAttrName; +exports.isSVGTag = isSVGTag; +exports.isSet = isSet; +exports.isSpecialBooleanAttr = isSpecialBooleanAttr; +exports.isString = isString; +exports.isSymbol = isSymbol; +exports.isVoidTag = isVoidTag; +exports.looseEqual = looseEqual; +exports.looseIndexOf = looseIndexOf; +exports.makeMap = makeMap; +exports.normalizeClass = normalizeClass; +exports.normalizeStyle = normalizeStyle; +exports.objectToString = objectToString; +exports.parseStringStyle = parseStringStyle; +exports.propsToAttrMap = propsToAttrMap; +exports.remove = remove; +exports.slotFlagsText = slotFlagsText; +exports.stringifyStyle = stringifyStyle; +exports.toDisplayString = toDisplayString; +exports.toHandlerKey = toHandlerKey; +exports.toNumber = toNumber; +exports.toRawType = toRawType; +exports.toTypeString = toTypeString; diff --git a/node_modules/@vue/shared/dist/shared.d.ts b/node_modules/@vue/shared/dist/shared.d.ts new file mode 100644 index 0000000..b2b60a4 --- /dev/null +++ b/node_modules/@vue/shared/dist/shared.d.ts @@ -0,0 +1,325 @@ + +/** + * List of @babel/parser plugins that are used for template expression + * transforms and SFC script transforms. By default we enable proposals slated + * for ES2020. This will need to be updated as the spec moves forward. + * Full list at https://babeljs.io/docs/en/next/babel-parser#plugins + */ +export declare const babelParserDefaultPlugins: readonly ["bigInt", "optionalChaining", "nullishCoalescingOperator"]; + +/** + * @private + */ +export declare const camelize: (str: string) => string; + +/** + * @private + */ +export declare const capitalize: (str: string) => string; + +export declare const def: (obj: object, key: string | symbol, value: any) => void; + +export declare const EMPTY_ARR: readonly never[]; + +export declare const EMPTY_OBJ: { + readonly [key: string]: any; +}; + +export declare function escapeHtml(string: unknown): string; + +export declare function escapeHtmlComment(src: string): string; + +export declare const extend: { + (target: T, source: U): T & U; + (target: T_1, source1: U_1, source2: V): T_1 & U_1 & V; + (target: T_2, source1: U_2, source2: V_1, source3: W): T_2 & U_2 & V_1 & W; + (target: object, ...sources: any[]): any; +}; + +export declare function generateCodeFrame(source: string, start?: number, end?: number): string; + +export declare const getGlobalThis: () => any; + +export declare const hasChanged: (value: any, oldValue: any) => boolean; + +export declare const hasOwn: (val: object, key: string | symbol) => key is never; + +/** + * @private + */ +export declare const hyphenate: (str: string) => string; + +export declare const invokeArrayFns: (fns: Function[], arg?: any) => void; + +export declare const isArray: (arg: any) => arg is any[]; + +/** + * The full list is needed during SSR to produce the correct initial markup. + */ +export declare const isBooleanAttr: (key: string) => boolean; + +export declare const isDate: (val: unknown) => val is Date; + +export declare const isFunction: (val: unknown) => val is Function; + +export declare const isGloballyWhitelisted: (key: string) => boolean; + +export declare const isHTMLTag: (key: string) => boolean; + +export declare const isIntegerKey: (key: unknown) => boolean; + +/** + * Known attributes, this is used for stringification of runtime static nodes + * so that we don't stringify bindings that cannot be set from HTML. + * Don't also forget to allow `data-*` and `aria-*`! + * Generated from https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes + */ +export declare const isKnownAttr: (key: string) => boolean; + +export declare const isMap: (val: unknown) => val is Map; + +export declare const isModelListener: (key: string) => boolean; + +/** + * CSS properties that accept plain numbers + */ +export declare const isNoUnitNumericStyleProp: (key: string) => boolean; + +export declare const isObject: (val: unknown) => val is Record; + +export declare const isOn: (key: string) => boolean; + +export declare const isPlainObject: (val: unknown) => val is object; + +export declare const isPromise: (val: unknown) => val is Promise; + +export declare const isReservedProp: (key: string) => boolean; + +export declare const isSet: (val: unknown) => val is Set; + +export declare const isSpecialBooleanAttr: (key: string) => boolean; + +export declare function isSSRSafeAttrName(name: string): boolean; + +export declare const isString: (val: unknown) => val is string; + +export declare const isSVGTag: (key: string) => boolean; + +export declare const isSymbol: (val: unknown) => val is symbol; + +export declare const isVoidTag: (key: string) => boolean; + +export declare function looseEqual(a: any, b: any): boolean; + +export declare function looseIndexOf(arr: any[], val: any): number; + +/** + * Make a map and return a function for checking if a key + * is in that map. + * IMPORTANT: all calls of this function must be prefixed with + * \/\*#\_\_PURE\_\_\*\/ + * So that rollup can tree-shake them if necessary. + */ +export declare function makeMap(str: string, expectsLowerCase?: boolean): (key: string) => boolean; + +/** + * Always return false. + */ +export declare const NO: () => boolean; + +export declare const NOOP: () => void; + +export declare function normalizeClass(value: unknown): string; + +export declare type NormalizedStyle = Record; + +export declare function normalizeStyle(value: unknown): NormalizedStyle | undefined; + +export declare const objectToString: () => string; + +export declare function parseStringStyle(cssText: string): NormalizedStyle; + +/** + * dev only flag -> name mapping + */ +export declare const PatchFlagNames: { + [x: number]: string; +}; + +/** + * Patch flags are optimization hints generated by the compiler. + * when a block with dynamicChildren is encountered during diff, the algorithm + * enters "optimized mode". In this mode, we know that the vdom is produced by + * a render function generated by the compiler, so the algorithm only needs to + * handle updates explicitly marked by these patch flags. + * + * Patch flags can be combined using the | bitwise operator and can be checked + * using the & operator, e.g. + * + * ```js + * const flag = TEXT | CLASS + * if (flag & TEXT) { ... } + * ``` + * + * Check the `patchElement` function in '../../runtime-core/src/renderer.ts' to see how the + * flags are handled during diff. + */ +export declare const enum PatchFlags { + /** + * Indicates an element with dynamic textContent (children fast path) + */ + TEXT = 1, + /** + * Indicates an element with dynamic class binding. + */ + CLASS = 2, + /** + * Indicates an element with dynamic style + * The compiler pre-compiles static string styles into static objects + * + detects and hoists inline static objects + * e.g. style="color: red" and :style="{ color: 'red' }" both get hoisted as + * const style = { color: 'red' } + * render() { return e('div', { style }) } + */ + STYLE = 4, + /** + * Indicates an element that has non-class/style dynamic props. + * Can also be on a component that has any dynamic props (includes + * class/style). when this flag is present, the vnode also has a dynamicProps + * array that contains the keys of the props that may change so the runtime + * can diff them faster (without having to worry about removed props) + */ + PROPS = 8, + /** + * Indicates an element with props with dynamic keys. When keys change, a full + * diff is always needed to remove the old key. This flag is mutually + * exclusive with CLASS, STYLE and PROPS. + */ + FULL_PROPS = 16, + /** + * Indicates an element with event listeners (which need to be attached + * during hydration) + */ + HYDRATE_EVENTS = 32, + /** + * Indicates a fragment whose children order doesn't change. + */ + STABLE_FRAGMENT = 64, + /** + * Indicates a fragment with keyed or partially keyed children + */ + KEYED_FRAGMENT = 128, + /** + * Indicates a fragment with unkeyed children. + */ + UNKEYED_FRAGMENT = 256, + /** + * Indicates an element that only needs non-props patching, e.g. ref or + * directives (onVnodeXXX hooks). since every patched vnode checks for refs + * and onVnodeXXX hooks, it simply marks the vnode so that a parent block + * will track it. + */ + NEED_PATCH = 512, + /** + * Indicates a component with dynamic slots (e.g. slot that references a v-for + * iterated value, or dynamic slot names). + * Components with this flag are always force updated. + */ + DYNAMIC_SLOTS = 1024, + /** + * Indicates a fragment that was created only because the user has placed + * comments at the root level of a template. This is a dev-only flag since + * comments are stripped in production. + */ + DEV_ROOT_FRAGMENT = 2048, + /** + * SPECIAL FLAGS ------------------------------------------------------------- + * Special flags are negative integers. They are never matched against using + * bitwise operators (bitwise matching should only happen in branches where + * patchFlag > 0), and are mutually exclusive. When checking for a special + * flag, simply check patchFlag === FLAG. + */ + /** + * Indicates a hoisted static vnode. This is a hint for hydration to skip + * the entire sub tree since static content never needs to be updated. + */ + HOISTED = -1, + /** + * A special flag that indicates that the diffing algorithm should bail out + * of optimized mode. For example, on block fragments created by renderSlot() + * when encountering non-compiler generated slots (i.e. manually written + * render functions, which should always be fully diffed) + * OR manually cloneVNodes + */ + BAIL = -2 +} + +export declare const propsToAttrMap: Record; + +export declare const remove: (arr: T[], el: T) => void; + +export declare const enum ShapeFlags { + ELEMENT = 1, + FUNCTIONAL_COMPONENT = 2, + STATEFUL_COMPONENT = 4, + TEXT_CHILDREN = 8, + ARRAY_CHILDREN = 16, + SLOTS_CHILDREN = 32, + TELEPORT = 64, + SUSPENSE = 128, + COMPONENT_SHOULD_KEEP_ALIVE = 256, + COMPONENT_KEPT_ALIVE = 512, + COMPONENT = 6 +} + +export declare const enum SlotFlags { + /** + * Stable slots that only reference slot props or context state. The slot + * can fully capture its own dependencies so when passed down the parent won't + * need to force the child to update. + */ + STABLE = 1, + /** + * Slots that reference scope variables (v-for or an outer slot prop), or + * has conditional structure (v-if, v-for). The parent will need to force + * the child to update because the slot does not fully capture its dependencies. + */ + DYNAMIC = 2, + /** + * `` being forwarded into a child component. Whether the parent needs + * to update the child is dependent on what kind of slots the parent itself + * received. This has to be refined at runtime, when the child's vnode + * is being created (in `normalizeChildren`) + */ + FORWARDED = 3 +} + +/** + * Dev only + */ +export declare const slotFlagsText: { + 1: string; + 2: string; + 3: string; +}; + +export declare function stringifyStyle(styles: NormalizedStyle | undefined): string; + +/** + * For converting {{ interpolation }} values to displayed strings. + * @private + */ +export declare const toDisplayString: (val: unknown) => string; + +/** + * @private + */ +export declare const toHandlerKey: (str: string) => string; + +export declare const toNumber: (val: any) => any; + +export declare const toRawType: (value: unknown) => string; + +export declare const toTypeString: (value: unknown) => string; + +export { } diff --git a/node_modules/@vue/shared/dist/shared.esm-bundler.js b/node_modules/@vue/shared/dist/shared.esm-bundler.js new file mode 100644 index 0000000..bea615d --- /dev/null +++ b/node_modules/@vue/shared/dist/shared.esm-bundler.js @@ -0,0 +1,509 @@ +/** + * Make a map and return a function for checking if a key + * is in that map. + * IMPORTANT: all calls of this function must be prefixed with + * \/\*#\_\_PURE\_\_\*\/ + * So that rollup can tree-shake them if necessary. + */ +function makeMap(str, expectsLowerCase) { + const map = Object.create(null); + const list = str.split(','); + for (let i = 0; i < list.length; i++) { + map[list[i]] = true; + } + return expectsLowerCase ? val => !!map[val.toLowerCase()] : val => !!map[val]; +} + +/** + * dev only flag -> name mapping + */ +const PatchFlagNames = { + [1 /* TEXT */]: `TEXT`, + [2 /* CLASS */]: `CLASS`, + [4 /* STYLE */]: `STYLE`, + [8 /* PROPS */]: `PROPS`, + [16 /* FULL_PROPS */]: `FULL_PROPS`, + [32 /* HYDRATE_EVENTS */]: `HYDRATE_EVENTS`, + [64 /* STABLE_FRAGMENT */]: `STABLE_FRAGMENT`, + [128 /* KEYED_FRAGMENT */]: `KEYED_FRAGMENT`, + [256 /* UNKEYED_FRAGMENT */]: `UNKEYED_FRAGMENT`, + [512 /* NEED_PATCH */]: `NEED_PATCH`, + [1024 /* DYNAMIC_SLOTS */]: `DYNAMIC_SLOTS`, + [2048 /* DEV_ROOT_FRAGMENT */]: `DEV_ROOT_FRAGMENT`, + [-1 /* HOISTED */]: `HOISTED`, + [-2 /* BAIL */]: `BAIL` +}; + +/** + * Dev only + */ +const slotFlagsText = { + [1 /* STABLE */]: 'STABLE', + [2 /* DYNAMIC */]: 'DYNAMIC', + [3 /* FORWARDED */]: 'FORWARDED' +}; + +const GLOBALS_WHITE_LISTED = 'Infinity,undefined,NaN,isFinite,isNaN,parseFloat,parseInt,decodeURI,' + + 'decodeURIComponent,encodeURI,encodeURIComponent,Math,Number,Date,Array,' + + 'Object,Boolean,String,RegExp,Map,Set,JSON,Intl,BigInt'; +const isGloballyWhitelisted = /*#__PURE__*/ makeMap(GLOBALS_WHITE_LISTED); + +const range = 2; +function generateCodeFrame(source, start = 0, end = source.length) { + // Split the content into individual lines but capture the newline sequence + // that separated each line. This is important because the actual sequence is + // needed to properly take into account the full line length for offset + // comparison + let lines = source.split(/(\r?\n)/); + // Separate the lines and newline sequences into separate arrays for easier referencing + const newlineSequences = lines.filter((_, idx) => idx % 2 === 1); + lines = lines.filter((_, idx) => idx % 2 === 0); + let count = 0; + const res = []; + for (let i = 0; i < lines.length; i++) { + count += + lines[i].length + + ((newlineSequences[i] && newlineSequences[i].length) || 0); + if (count >= start) { + for (let j = i - range; j <= i + range || end > count; j++) { + if (j < 0 || j >= lines.length) + continue; + const line = j + 1; + res.push(`${line}${' '.repeat(Math.max(3 - String(line).length, 0))}| ${lines[j]}`); + const lineLength = lines[j].length; + const newLineSeqLength = (newlineSequences[j] && newlineSequences[j].length) || 0; + if (j === i) { + // push underline + const pad = start - (count - (lineLength + newLineSeqLength)); + const length = Math.max(1, end > count ? lineLength - pad : end - start); + res.push(` | ` + ' '.repeat(pad) + '^'.repeat(length)); + } + else if (j > i) { + if (end > count) { + const length = Math.max(Math.min(end - count, lineLength), 1); + res.push(` | ` + '^'.repeat(length)); + } + count += lineLength + newLineSeqLength; + } + } + break; + } + } + return res.join('\n'); +} + +/** + * On the client we only need to offer special cases for boolean attributes that + * have different names from their corresponding dom properties: + * - itemscope -> N/A + * - allowfullscreen -> allowFullscreen + * - formnovalidate -> formNoValidate + * - ismap -> isMap + * - nomodule -> noModule + * - novalidate -> noValidate + * - readonly -> readOnly + */ +const specialBooleanAttrs = `itemscope,allowfullscreen,formnovalidate,ismap,nomodule,novalidate,readonly`; +const isSpecialBooleanAttr = /*#__PURE__*/ makeMap(specialBooleanAttrs); +/** + * The full list is needed during SSR to produce the correct initial markup. + */ +const isBooleanAttr = /*#__PURE__*/ makeMap(specialBooleanAttrs + + `,async,autofocus,autoplay,controls,default,defer,disabled,hidden,` + + `loop,open,required,reversed,scoped,seamless,` + + `checked,muted,multiple,selected`); +const unsafeAttrCharRE = /[>/="'\u0009\u000a\u000c\u0020]/; +const attrValidationCache = {}; +function isSSRSafeAttrName(name) { + if (attrValidationCache.hasOwnProperty(name)) { + return attrValidationCache[name]; + } + const isUnsafe = unsafeAttrCharRE.test(name); + if (isUnsafe) { + console.error(`unsafe attribute name: ${name}`); + } + return (attrValidationCache[name] = !isUnsafe); +} +const propsToAttrMap = { + acceptCharset: 'accept-charset', + className: 'class', + htmlFor: 'for', + httpEquiv: 'http-equiv' +}; +/** + * CSS properties that accept plain numbers + */ +const isNoUnitNumericStyleProp = /*#__PURE__*/ makeMap(`animation-iteration-count,border-image-outset,border-image-slice,` + + `border-image-width,box-flex,box-flex-group,box-ordinal-group,column-count,` + + `columns,flex,flex-grow,flex-positive,flex-shrink,flex-negative,flex-order,` + + `grid-row,grid-row-end,grid-row-span,grid-row-start,grid-column,` + + `grid-column-end,grid-column-span,grid-column-start,font-weight,line-clamp,` + + `line-height,opacity,order,orphans,tab-size,widows,z-index,zoom,` + + // SVG + `fill-opacity,flood-opacity,stop-opacity,stroke-dasharray,stroke-dashoffset,` + + `stroke-miterlimit,stroke-opacity,stroke-width`); +/** + * Known attributes, this is used for stringification of runtime static nodes + * so that we don't stringify bindings that cannot be set from HTML. + * Don't also forget to allow `data-*` and `aria-*`! + * Generated from https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes + */ +const isKnownAttr = /*#__PURE__*/ makeMap(`accept,accept-charset,accesskey,action,align,allow,alt,async,` + + `autocapitalize,autocomplete,autofocus,autoplay,background,bgcolor,` + + `border,buffered,capture,challenge,charset,checked,cite,class,code,` + + `codebase,color,cols,colspan,content,contenteditable,contextmenu,controls,` + + `coords,crossorigin,csp,data,datetime,decoding,default,defer,dir,dirname,` + + `disabled,download,draggable,dropzone,enctype,enterkeyhint,for,form,` + + `formaction,formenctype,formmethod,formnovalidate,formtarget,headers,` + + `height,hidden,high,href,hreflang,http-equiv,icon,id,importance,integrity,` + + `ismap,itemprop,keytype,kind,label,lang,language,loading,list,loop,low,` + + `manifest,max,maxlength,minlength,media,min,multiple,muted,name,novalidate,` + + `open,optimum,pattern,ping,placeholder,poster,preload,radiogroup,readonly,` + + `referrerpolicy,rel,required,reversed,rows,rowspan,sandbox,scope,scoped,` + + `selected,shape,size,sizes,slot,span,spellcheck,src,srcdoc,srclang,srcset,` + + `start,step,style,summary,tabindex,target,title,translate,type,usemap,` + + `value,width,wrap`); + +function normalizeStyle(value) { + if (isArray(value)) { + const res = {}; + for (let i = 0; i < value.length; i++) { + const item = value[i]; + const normalized = normalizeStyle(isString(item) ? parseStringStyle(item) : item); + if (normalized) { + for (const key in normalized) { + res[key] = normalized[key]; + } + } + } + return res; + } + else if (isObject(value)) { + return value; + } +} +const listDelimiterRE = /;(?![^(]*\))/g; +const propertyDelimiterRE = /:(.+)/; +function parseStringStyle(cssText) { + const ret = {}; + cssText.split(listDelimiterRE).forEach(item => { + if (item) { + const tmp = item.split(propertyDelimiterRE); + tmp.length > 1 && (ret[tmp[0].trim()] = tmp[1].trim()); + } + }); + return ret; +} +function stringifyStyle(styles) { + let ret = ''; + if (!styles) { + return ret; + } + for (const key in styles) { + const value = styles[key]; + const normalizedKey = key.startsWith(`--`) ? key : hyphenate(key); + if (isString(value) || + (typeof value === 'number' && isNoUnitNumericStyleProp(normalizedKey))) { + // only render valid values + ret += `${normalizedKey}:${value};`; + } + } + return ret; +} +function normalizeClass(value) { + let res = ''; + if (isString(value)) { + res = value; + } + else if (isArray(value)) { + for (let i = 0; i < value.length; i++) { + const normalized = normalizeClass(value[i]); + if (normalized) { + res += normalized + ' '; + } + } + } + else if (isObject(value)) { + for (const name in value) { + if (value[name]) { + res += name + ' '; + } + } + } + return res.trim(); +} + +// These tag configs are shared between compiler-dom and runtime-dom, so they +// https://developer.mozilla.org/en-US/docs/Web/HTML/Element +const HTML_TAGS = 'html,body,base,head,link,meta,style,title,address,article,aside,footer,' + + 'header,h1,h2,h3,h4,h5,h6,hgroup,nav,section,div,dd,dl,dt,figcaption,' + + 'figure,picture,hr,img,li,main,ol,p,pre,ul,a,b,abbr,bdi,bdo,br,cite,code,' + + 'data,dfn,em,i,kbd,mark,q,rp,rt,rtc,ruby,s,samp,small,span,strong,sub,sup,' + + 'time,u,var,wbr,area,audio,map,track,video,embed,object,param,source,' + + 'canvas,script,noscript,del,ins,caption,col,colgroup,table,thead,tbody,td,' + + 'th,tr,button,datalist,fieldset,form,input,label,legend,meter,optgroup,' + + 'option,output,progress,select,textarea,details,dialog,menu,' + + 'summary,template,blockquote,iframe,tfoot'; +// https://developer.mozilla.org/en-US/docs/Web/SVG/Element +const SVG_TAGS = 'svg,animate,animateMotion,animateTransform,circle,clipPath,color-profile,' + + 'defs,desc,discard,ellipse,feBlend,feColorMatrix,feComponentTransfer,' + + 'feComposite,feConvolveMatrix,feDiffuseLighting,feDisplacementMap,' + + 'feDistanceLight,feDropShadow,feFlood,feFuncA,feFuncB,feFuncG,feFuncR,' + + 'feGaussianBlur,feImage,feMerge,feMergeNode,feMorphology,feOffset,' + + 'fePointLight,feSpecularLighting,feSpotLight,feTile,feTurbulence,filter,' + + 'foreignObject,g,hatch,hatchpath,image,line,linearGradient,marker,mask,' + + 'mesh,meshgradient,meshpatch,meshrow,metadata,mpath,path,pattern,' + + 'polygon,polyline,radialGradient,rect,set,solidcolor,stop,switch,symbol,' + + 'text,textPath,title,tspan,unknown,use,view'; +const VOID_TAGS = 'area,base,br,col,embed,hr,img,input,link,meta,param,source,track,wbr'; +const isHTMLTag = /*#__PURE__*/ makeMap(HTML_TAGS); +const isSVGTag = /*#__PURE__*/ makeMap(SVG_TAGS); +const isVoidTag = /*#__PURE__*/ makeMap(VOID_TAGS); + +const escapeRE = /["'&<>]/; +function escapeHtml(string) { + const str = '' + string; + const match = escapeRE.exec(str); + if (!match) { + return str; + } + let html = ''; + let escaped; + let index; + let lastIndex = 0; + for (index = match.index; index < str.length; index++) { + switch (str.charCodeAt(index)) { + case 34: // " + escaped = '"'; + break; + case 38: // & + escaped = '&'; + break; + case 39: // ' + escaped = '''; + break; + case 60: // < + escaped = '<'; + break; + case 62: // > + escaped = '>'; + break; + default: + continue; + } + if (lastIndex !== index) { + html += str.substring(lastIndex, index); + } + lastIndex = index + 1; + html += escaped; + } + return lastIndex !== index ? html + str.substring(lastIndex, index) : html; +} +// https://www.w3.org/TR/html52/syntax.html#comments +const commentStripRE = /^-?>||--!>| looseEqual(item, val)); +} + +/** + * For converting {{ interpolation }} values to displayed strings. + * @private + */ +const toDisplayString = (val) => { + return val == null + ? '' + : isObject(val) + ? JSON.stringify(val, replacer, 2) + : String(val); +}; +const replacer = (_key, val) => { + if (isMap(val)) { + return { + [`Map(${val.size})`]: [...val.entries()].reduce((entries, [key, val]) => { + entries[`${key} =>`] = val; + return entries; + }, {}) + }; + } + else if (isSet(val)) { + return { + [`Set(${val.size})`]: [...val.values()] + }; + } + else if (isObject(val) && !isArray(val) && !isPlainObject(val)) { + return String(val); + } + return val; +}; + +/** + * List of @babel/parser plugins that are used for template expression + * transforms and SFC script transforms. By default we enable proposals slated + * for ES2020. This will need to be updated as the spec moves forward. + * Full list at https://babeljs.io/docs/en/next/babel-parser#plugins + */ +const babelParserDefaultPlugins = [ + 'bigInt', + 'optionalChaining', + 'nullishCoalescingOperator' +]; +const EMPTY_OBJ = (process.env.NODE_ENV !== 'production') + ? Object.freeze({}) + : {}; +const EMPTY_ARR = (process.env.NODE_ENV !== 'production') ? Object.freeze([]) : []; +const NOOP = () => { }; +/** + * Always return false. + */ +const NO = () => false; +const onRE = /^on[^a-z]/; +const isOn = (key) => onRE.test(key); +const isModelListener = (key) => key.startsWith('onUpdate:'); +const extend = Object.assign; +const remove = (arr, el) => { + const i = arr.indexOf(el); + if (i > -1) { + arr.splice(i, 1); + } +}; +const hasOwnProperty = Object.prototype.hasOwnProperty; +const hasOwn = (val, key) => hasOwnProperty.call(val, key); +const isArray = Array.isArray; +const isMap = (val) => toTypeString(val) === '[object Map]'; +const isSet = (val) => toTypeString(val) === '[object Set]'; +const isDate = (val) => val instanceof Date; +const isFunction = (val) => typeof val === 'function'; +const isString = (val) => typeof val === 'string'; +const isSymbol = (val) => typeof val === 'symbol'; +const isObject = (val) => val !== null && typeof val === 'object'; +const isPromise = (val) => { + return isObject(val) && isFunction(val.then) && isFunction(val.catch); +}; +const objectToString = Object.prototype.toString; +const toTypeString = (value) => objectToString.call(value); +const toRawType = (value) => { + // extract "RawType" from strings like "[object RawType]" + return toTypeString(value).slice(8, -1); +}; +const isPlainObject = (val) => toTypeString(val) === '[object Object]'; +const isIntegerKey = (key) => isString(key) && + key !== 'NaN' && + key[0] !== '-' && + '' + parseInt(key, 10) === key; +const isReservedProp = /*#__PURE__*/ makeMap( +// the leading comma is intentional so empty string "" is also included +',key,ref,' + + 'onVnodeBeforeMount,onVnodeMounted,' + + 'onVnodeBeforeUpdate,onVnodeUpdated,' + + 'onVnodeBeforeUnmount,onVnodeUnmounted'); +const cacheStringFunction = (fn) => { + const cache = Object.create(null); + return ((str) => { + const hit = cache[str]; + return hit || (cache[str] = fn(str)); + }); +}; +const camelizeRE = /-(\w)/g; +/** + * @private + */ +const camelize = cacheStringFunction((str) => { + return str.replace(camelizeRE, (_, c) => (c ? c.toUpperCase() : '')); +}); +const hyphenateRE = /\B([A-Z])/g; +/** + * @private + */ +const hyphenate = cacheStringFunction((str) => str.replace(hyphenateRE, '-$1').toLowerCase()); +/** + * @private + */ +const capitalize = cacheStringFunction((str) => str.charAt(0).toUpperCase() + str.slice(1)); +/** + * @private + */ +const toHandlerKey = cacheStringFunction((str) => (str ? `on${capitalize(str)}` : ``)); +// compare whether a value has changed, accounting for NaN. +const hasChanged = (value, oldValue) => value !== oldValue && (value === value || oldValue === oldValue); +const invokeArrayFns = (fns, arg) => { + for (let i = 0; i < fns.length; i++) { + fns[i](arg); + } +}; +const def = (obj, key, value) => { + Object.defineProperty(obj, key, { + configurable: true, + enumerable: false, + value + }); +}; +const toNumber = (val) => { + const n = parseFloat(val); + return isNaN(n) ? val : n; +}; +let _globalThis; +const getGlobalThis = () => { + return (_globalThis || + (_globalThis = + typeof globalThis !== 'undefined' + ? globalThis + : typeof self !== 'undefined' + ? self + : typeof window !== 'undefined' + ? window + : typeof global !== 'undefined' + ? global + : {})); +}; + +export { EMPTY_ARR, EMPTY_OBJ, NO, NOOP, PatchFlagNames, babelParserDefaultPlugins, camelize, capitalize, def, escapeHtml, escapeHtmlComment, extend, generateCodeFrame, getGlobalThis, hasChanged, hasOwn, hyphenate, invokeArrayFns, isArray, isBooleanAttr, isDate, isFunction, isGloballyWhitelisted, isHTMLTag, isIntegerKey, isKnownAttr, isMap, isModelListener, isNoUnitNumericStyleProp, isObject, isOn, isPlainObject, isPromise, isReservedProp, isSSRSafeAttrName, isSVGTag, isSet, isSpecialBooleanAttr, isString, isSymbol, isVoidTag, looseEqual, looseIndexOf, makeMap, normalizeClass, normalizeStyle, objectToString, parseStringStyle, propsToAttrMap, remove, slotFlagsText, stringifyStyle, toDisplayString, toHandlerKey, toNumber, toRawType, toTypeString }; diff --git a/node_modules/@vue/shared/index.js b/node_modules/@vue/shared/index.js new file mode 100644 index 0000000..a2ee43e --- /dev/null +++ b/node_modules/@vue/shared/index.js @@ -0,0 +1,7 @@ +'use strict' + +if (process.env.NODE_ENV === 'production') { + module.exports = require('./dist/shared.cjs.prod.js') +} else { + module.exports = require('./dist/shared.cjs.js') +} diff --git a/node_modules/@vue/shared/package.json b/node_modules/@vue/shared/package.json new file mode 100644 index 0000000..038cb8d --- /dev/null +++ b/node_modules/@vue/shared/package.json @@ -0,0 +1,32 @@ +{ + "name": "@vue/shared", + "version": "3.1.5", + "description": "internal utils shared across @vue packages", + "main": "index.js", + "module": "dist/shared.esm-bundler.js", + "types": "dist/shared.d.ts", + "files": [ + "index.js", + "dist" + ], + "buildOptions": { + "formats": [ + "esm-bundler", + "cjs" + ] + }, + "repository": { + "type": "git", + "url": "git+https://github.com/vuejs/vue-next.git", + "directory": "packages/shared" + }, + "keywords": [ + "vue" + ], + "author": "Evan You", + "license": "MIT", + "bugs": { + "url": "https://github.com/vuejs/vue-next/issues" + }, + "homepage": "https://github.com/vuejs/vue-next/tree/master/packages/shared#readme" +} diff --git a/node_modules/alpinejs/builds/cdn.js b/node_modules/alpinejs/builds/cdn.js new file mode 100644 index 0000000..a54e7e0 --- /dev/null +++ b/node_modules/alpinejs/builds/cdn.js @@ -0,0 +1,7 @@ +import Alpine from './../src/index' + +window.Alpine = Alpine + +queueMicrotask(() => { + Alpine.start() +}) diff --git a/node_modules/alpinejs/builds/module.js b/node_modules/alpinejs/builds/module.js new file mode 100644 index 0000000..1d9d6a7 --- /dev/null +++ b/node_modules/alpinejs/builds/module.js @@ -0,0 +1,5 @@ +import Alpine from './../src/index' + +export default Alpine + +export { Alpine } diff --git a/node_modules/alpinejs/dist/cdn.js b/node_modules/alpinejs/dist/cdn.js new file mode 100644 index 0000000..3813721 --- /dev/null +++ b/node_modules/alpinejs/dist/cdn.js @@ -0,0 +1,3525 @@ +(() => { + // packages/alpinejs/src/scheduler.js + var flushPending = false; + var flushing = false; + var queue = []; + var lastFlushedIndex = -1; + var transactionActive = false; + function scheduler(callback) { + queueJob(callback); + } + function startTransaction() { + transactionActive = true; + } + function commitTransaction() { + transactionActive = false; + queueFlush(); + } + function queueJob(job) { + if (!queue.includes(job)) + queue.push(job); + queueFlush(); + } + function dequeueJob(job) { + let index = queue.indexOf(job); + if (index !== -1 && index > lastFlushedIndex) + queue.splice(index, 1); + } + function queueFlush() { + if (!flushing && !flushPending) { + if (transactionActive) + return; + flushPending = true; + queueMicrotask(flushJobs); + } + } + function flushJobs() { + flushPending = false; + flushing = true; + for (let i = 0; i < queue.length; i++) { + queue[i](); + lastFlushedIndex = i; + } + queue.length = 0; + lastFlushedIndex = -1; + flushing = false; + } + + // packages/alpinejs/src/reactivity.js + var reactive; + var effect; + var release; + var raw; + var shouldSchedule = true; + function disableEffectScheduling(callback) { + shouldSchedule = false; + callback(); + shouldSchedule = true; + } + function setReactivityEngine(engine) { + reactive = engine.reactive; + release = engine.release; + effect = (callback) => engine.effect(callback, { scheduler: (task) => { + if (shouldSchedule) { + scheduler(task); + } else { + task(); + } + } }); + raw = engine.raw; + } + function overrideEffect(override) { + effect = override; + } + function elementBoundEffect(el) { + let cleanup2 = () => { + }; + let wrappedEffect = (callback) => { + let effectReference = effect(callback); + if (!el._x_effects) { + el._x_effects = /* @__PURE__ */ new Set(); + el._x_runEffects = () => { + el._x_effects.forEach((i) => i()); + }; + } + el._x_effects.add(effectReference); + cleanup2 = () => { + if (effectReference === void 0) + return; + el._x_effects.delete(effectReference); + release(effectReference); + }; + return effectReference; + }; + return [wrappedEffect, () => { + cleanup2(); + }]; + } + function watch(getter, callback) { + let firstTime = true; + let oldValue; + let oldValueJSON; + let effectReference = effect(() => { + let value = getter(); + let newJSON = JSON.stringify(value); + if (!firstTime) { + if (typeof value === "object" || value !== oldValue) { + let previousValue = typeof oldValue === "object" ? JSON.parse(oldValueJSON) : oldValue; + queueMicrotask(() => { + callback(value, previousValue); + }); + } + } + oldValue = value; + oldValueJSON = newJSON; + firstTime = false; + }); + return () => release(effectReference); + } + async function transaction(callback) { + startTransaction(); + try { + await callback(); + await Promise.resolve(); + } finally { + commitTransaction(); + } + } + + // packages/alpinejs/src/mutation.js + var onAttributeAddeds = []; + var onElRemoveds = []; + var onElAddeds = []; + function onElAdded(callback) { + onElAddeds.push(callback); + } + function onElRemoved(el, callback) { + if (typeof callback === "function") { + if (!el._x_cleanups) + el._x_cleanups = []; + el._x_cleanups.push(callback); + } else { + callback = el; + onElRemoveds.push(callback); + } + } + function onAttributesAdded(callback) { + onAttributeAddeds.push(callback); + } + function onAttributeRemoved(el, name, callback) { + if (!el._x_attributeCleanups) + el._x_attributeCleanups = {}; + if (!el._x_attributeCleanups[name]) + el._x_attributeCleanups[name] = []; + el._x_attributeCleanups[name].push(callback); + } + function cleanupAttributes(el, names) { + if (!el._x_attributeCleanups) + return; + Object.entries(el._x_attributeCleanups).forEach(([name, value]) => { + if (names === void 0 || names.includes(name)) { + value.forEach((i) => i()); + delete el._x_attributeCleanups[name]; + } + }); + } + function cleanupElement(el) { + el._x_effects?.forEach(dequeueJob); + while (el._x_cleanups?.length) + el._x_cleanups.pop()(); + } + var observer = new MutationObserver(onMutate); + var currentlyObserving = false; + function startObservingMutations() { + observer.observe(document, { subtree: true, childList: true, attributes: true, attributeOldValue: true }); + currentlyObserving = true; + } + function stopObservingMutations() { + flushObserver(); + observer.disconnect(); + currentlyObserving = false; + } + var queuedMutations = []; + function flushObserver() { + let records = observer.takeRecords(); + queuedMutations.push(() => records.length > 0 && onMutate(records)); + let queueLengthWhenTriggered = queuedMutations.length; + queueMicrotask(() => { + if (queuedMutations.length === queueLengthWhenTriggered) { + while (queuedMutations.length > 0) + queuedMutations.shift()(); + } + }); + } + function mutateDom(callback) { + if (!currentlyObserving) + return callback(); + stopObservingMutations(); + let result = callback(); + startObservingMutations(); + return result; + } + var isCollecting = false; + var deferredMutations = []; + function deferMutations() { + isCollecting = true; + } + function flushAndStopDeferringMutations() { + isCollecting = false; + onMutate(deferredMutations); + deferredMutations = []; + } + function onMutate(mutations) { + if (isCollecting) { + deferredMutations = deferredMutations.concat(mutations); + return; + } + let addedNodes = []; + let removedNodes = /* @__PURE__ */ new Set(); + let addedAttributes = /* @__PURE__ */ new Map(); + let removedAttributes = /* @__PURE__ */ new Map(); + for (let i = 0; i < mutations.length; i++) { + if (mutations[i].target._x_ignoreMutationObserver) + continue; + if (mutations[i].type === "childList") { + mutations[i].removedNodes.forEach((node) => { + if (node.nodeType !== 1) + return; + if (!node._x_marker) + return; + removedNodes.add(node); + }); + mutations[i].addedNodes.forEach((node) => { + if (node.nodeType !== 1) + return; + if (removedNodes.has(node)) { + removedNodes.delete(node); + return; + } + if (node._x_marker) + return; + addedNodes.push(node); + }); + } + if (mutations[i].type === "attributes") { + let el = mutations[i].target; + let name = mutations[i].attributeName; + let oldValue = mutations[i].oldValue; + let add2 = () => { + if (!addedAttributes.has(el)) + addedAttributes.set(el, []); + addedAttributes.get(el).push({ name, value: el.getAttribute(name) }); + }; + let remove = () => { + if (!removedAttributes.has(el)) + removedAttributes.set(el, []); + removedAttributes.get(el).push(name); + }; + if (el.hasAttribute(name) && oldValue === null) { + add2(); + } else if (el.hasAttribute(name)) { + remove(); + add2(); + } else { + remove(); + } + } + } + removedAttributes.forEach((attrs, el) => { + cleanupAttributes(el, attrs); + }); + addedAttributes.forEach((attrs, el) => { + onAttributeAddeds.forEach((i) => i(el, attrs)); + }); + for (let node of removedNodes) { + if (addedNodes.some((i) => i.contains(node))) + continue; + onElRemoveds.forEach((i) => i(node)); + } + for (let node of addedNodes) { + if (!node.isConnected) + continue; + onElAddeds.forEach((i) => i(node)); + } + addedNodes = null; + removedNodes = null; + addedAttributes = null; + removedAttributes = null; + } + + // packages/alpinejs/src/scope.js + function scope(node) { + return mergeProxies(closestDataStack(node)); + } + function addScopeToNode(node, data2, referenceNode) { + node._x_dataStack = [data2, ...closestDataStack(referenceNode || node)]; + return () => { + node._x_dataStack = node._x_dataStack.filter((i) => i !== data2); + }; + } + function closestDataStack(node) { + if (node._x_dataStack) + return node._x_dataStack; + if (typeof ShadowRoot === "function" && node instanceof ShadowRoot) { + return closestDataStack(node.host); + } + if (!node.parentNode) { + return []; + } + return closestDataStack(node.parentNode); + } + function mergeProxies(objects) { + return new Proxy({ objects }, mergeProxyTrap); + } + function keyInPrototypeChain(obj, key) { + if (obj === null || obj === Object.prototype) + return null; + if (Object.prototype.hasOwnProperty.call(obj, key)) + return obj; + return keyInPrototypeChain(Object.getPrototypeOf(obj), key); + } + var mergeProxyTrap = { + ownKeys({ objects }) { + return Array.from( + new Set(objects.flatMap((i) => Object.keys(i))) + ); + }, + has({ objects }, name) { + if (name == Symbol.unscopables) + return false; + return objects.some( + (obj) => Object.prototype.hasOwnProperty.call(obj, name) || Reflect.has(obj, name) + ); + }, + get({ objects }, name, thisProxy) { + if (name == "toJSON") + return collapseProxies; + return Reflect.get( + objects.find( + (obj) => Reflect.has(obj, name) + ) || {}, + name, + thisProxy + ); + }, + set({ objects }, name, value, thisProxy) { + let target; + for (const obj of objects) { + target = keyInPrototypeChain(obj, name); + if (target) + break; + } + if (!target) + target = objects[objects.length - 1]; + const descriptor = Object.getOwnPropertyDescriptor(target, name); + if (descriptor?.set && descriptor?.get) + return descriptor.set.call(thisProxy, value) || true; + return Reflect.set(target, name, value); + } + }; + function collapseProxies() { + let keys = Reflect.ownKeys(this); + return keys.reduce((acc, key) => { + acc[key] = Reflect.get(this, key); + return acc; + }, {}); + } + + // packages/alpinejs/src/interceptor.js + function initInterceptors(data2) { + let isObject3 = (val) => typeof val === "object" && !Array.isArray(val) && val !== null; + let recurse = (obj, basePath = "") => { + Object.entries(Object.getOwnPropertyDescriptors(obj)).forEach(([key, { value, enumerable }]) => { + if (enumerable === false || value === void 0) + return; + if (typeof value === "object" && value !== null && value.__v_skip) + return; + let path = basePath === "" ? key : `${basePath}.${key}`; + if (typeof value === "object" && value !== null && value._x_interceptor) { + obj[key] = value.initialize(data2, path, key); + } else { + if (isObject3(value) && value !== obj && !(value instanceof Element)) { + recurse(value, path); + } + } + }); + }; + return recurse(data2); + } + function interceptor(callback, mutateObj = () => { + }) { + let obj = { + initialValue: void 0, + _x_interceptor: true, + initialize(data2, path, key) { + return callback(this.initialValue, () => get(data2, path), (value) => set(data2, path, value), path, key); + } + }; + mutateObj(obj); + return (initialValue) => { + if (typeof initialValue === "object" && initialValue !== null && initialValue._x_interceptor) { + let initialize = obj.initialize.bind(obj); + obj.initialize = (data2, path, key) => { + let innerValue = initialValue.initialize(data2, path, key); + obj.initialValue = innerValue; + return initialize(data2, path, key); + }; + } else { + obj.initialValue = initialValue; + } + return obj; + }; + } + function get(obj, path) { + return path.split(".").reduce((carry, segment) => carry[segment], obj); + } + function set(obj, path, value) { + if (typeof path === "string") + path = path.split("."); + if (path.length === 1) + obj[path[0]] = value; + else if (path.length === 0) + throw error; + else { + if (obj[path[0]]) + return set(obj[path[0]], path.slice(1), value); + else { + obj[path[0]] = {}; + return set(obj[path[0]], path.slice(1), value); + } + } + } + + // packages/alpinejs/src/magics.js + var magics = {}; + function magic(name, callback) { + magics[name] = callback; + } + function injectMagics(obj, el) { + let memoizedUtilities = getUtilities(el); + Object.entries(magics).forEach(([name, callback]) => { + Object.defineProperty(obj, `$${name}`, { + get() { + return callback(el, memoizedUtilities); + }, + enumerable: false + }); + }); + return obj; + } + function getUtilities(el) { + let [utilities, cleanup2] = getElementBoundUtilities(el); + let utils = { interceptor, ...utilities }; + onElRemoved(el, cleanup2); + return utils; + } + + // packages/alpinejs/src/utils/error.js + function tryCatch(el, expression, callback, ...args) { + try { + return callback(...args); + } catch (e) { + handleError(e, el, expression); + } + } + function handleError(...args) { + return errorHandler(...args); + } + var errorHandler = normalErrorHandler; + function setErrorHandler(handler4) { + errorHandler = handler4; + } + function normalErrorHandler(error2, el, expression = void 0) { + error2 = Object.assign( + error2 ?? { message: "No error message given." }, + { el, expression } + ); + console.warn(`Alpine Expression Error: ${error2.message} + +${expression ? 'Expression: "' + expression + '"\n\n' : ""}`, el); + setTimeout(() => { + throw error2; + }, 0); + } + + // packages/alpinejs/src/evaluator.js + var shouldAutoEvaluateFunctions = true; + function dontAutoEvaluateFunctions(callback) { + let cache = shouldAutoEvaluateFunctions; + shouldAutoEvaluateFunctions = false; + let result = callback(); + shouldAutoEvaluateFunctions = cache; + return result; + } + function evaluate(el, expression, extras = {}) { + let result; + evaluateLater(el, expression)((value) => result = value, extras); + return result; + } + function evaluateLater(...args) { + return theEvaluatorFunction(...args); + } + var theEvaluatorFunction = () => { + }; + function setEvaluator(newEvaluator) { + theEvaluatorFunction = newEvaluator; + } + var theRawEvaluatorFunction; + function setRawEvaluator(newEvaluator) { + theRawEvaluatorFunction = newEvaluator; + } + function normalEvaluator(el, expression) { + let overriddenMagics = {}; + injectMagics(overriddenMagics, el); + let dataStack = [overriddenMagics, ...closestDataStack(el)]; + let evaluator = typeof expression === "function" ? generateEvaluatorFromFunction(dataStack, expression) : generateEvaluatorFromString(dataStack, expression, el); + return tryCatch.bind(null, el, expression, evaluator); + } + function generateEvaluatorFromFunction(dataStack, func) { + return (receiver = () => { + }, { scope: scope2 = {}, params = [], context } = {}) => { + if (!shouldAutoEvaluateFunctions) { + runIfTypeOfFunction(receiver, func, mergeProxies([scope2, ...dataStack]), params); + return; + } + let result = func.apply(mergeProxies([scope2, ...dataStack]), params); + runIfTypeOfFunction(receiver, result); + }; + } + var evaluatorMemo = {}; + function generateFunctionFromString(expression, el) { + if (evaluatorMemo[expression]) { + return evaluatorMemo[expression]; + } + let AsyncFunction = Object.getPrototypeOf(async function() { + }).constructor; + let rightSideSafeExpression = /^[\n\s]*if.*\(.*\)/.test(expression.trim()) || /^(let|const)\s/.test(expression.trim()) ? `(async()=>{ ${expression} })()` : expression; + const safeAsyncFunction = () => { + try { + let func2 = new AsyncFunction( + ["__self", "scope"], + `with (scope) { __self.result = ${rightSideSafeExpression} }; __self.finished = true; return __self.result;` + ); + Object.defineProperty(func2, "name", { + value: `[Alpine] ${expression}` + }); + return func2; + } catch (error2) { + handleError(error2, el, expression); + return Promise.resolve(); + } + }; + let func = safeAsyncFunction(); + evaluatorMemo[expression] = func; + return func; + } + function generateEvaluatorFromString(dataStack, expression, el) { + let func = generateFunctionFromString(expression, el); + return (receiver = () => { + }, { scope: scope2 = {}, params = [], context } = {}) => { + func.result = void 0; + func.finished = false; + let completeScope = mergeProxies([scope2, ...dataStack]); + if (typeof func === "function") { + let promise = func.call(context, func, completeScope).catch((error2) => handleError(error2, el, expression)); + if (func.finished) { + runIfTypeOfFunction(receiver, func.result, completeScope, params, el); + func.result = void 0; + } else { + promise.then((result) => { + runIfTypeOfFunction(receiver, result, completeScope, params, el); + }).catch((error2) => handleError(error2, el, expression)).finally(() => func.result = void 0); + } + } + }; + } + function runIfTypeOfFunction(receiver, value, scope2, params, el) { + if (shouldAutoEvaluateFunctions && typeof value === "function") { + let result = value.apply(scope2, params); + if (result instanceof Promise) { + result.then((i) => runIfTypeOfFunction(receiver, i, scope2, params)).catch((error2) => handleError(error2, el, value)); + } else { + receiver(result); + } + } else if (typeof value === "object" && value instanceof Promise) { + value.then((i) => receiver(i)); + } else { + receiver(value); + } + } + function evaluateRaw(...args) { + return theRawEvaluatorFunction(...args); + } + function normalRawEvaluator(el, expression, extras = {}) { + let overriddenMagics = {}; + injectMagics(overriddenMagics, el); + let dataStack = [overriddenMagics, ...closestDataStack(el)]; + let scope2 = mergeProxies([extras.scope ?? {}, ...dataStack]); + let params = extras.params ?? []; + if (expression.includes("await")) { + let AsyncFunction = Object.getPrototypeOf(async function() { + }).constructor; + let rightSideSafeExpression = /^[\n\s]*if.*\(.*\)/.test(expression.trim()) || /^(let|const)\s/.test(expression.trim()) ? `(async()=>{ ${expression} })()` : expression; + let func = new AsyncFunction( + ["scope"], + `with (scope) { let __result = ${rightSideSafeExpression}; return __result }` + ); + let result = func.call(extras.context, scope2); + return result; + } else { + let rightSideSafeExpression = /^[\n\s]*if.*\(.*\)/.test(expression.trim()) || /^(let|const)\s/.test(expression.trim()) ? `(()=>{ ${expression} })()` : expression; + let func = new Function( + ["scope"], + `with (scope) { let __result = ${rightSideSafeExpression}; return __result }` + ); + let result = func.call(extras.context, scope2); + if (typeof result === "function" && shouldAutoEvaluateFunctions) { + return result.apply(scope2, params); + } + return result; + } + } + + // packages/alpinejs/src/directives.js + var prefixAsString = "x-"; + function prefix(subject = "") { + return prefixAsString + subject; + } + function setPrefix(newPrefix) { + prefixAsString = newPrefix; + } + var directiveHandlers = {}; + function directive(name, callback) { + directiveHandlers[name] = callback; + return { + before(directive2) { + if (!directiveHandlers[directive2]) { + console.warn(String.raw`Cannot find directive \`${directive2}\`. \`${name}\` will use the default order of execution`); + return; + } + const pos = directiveOrder.indexOf(directive2); + directiveOrder.splice(pos >= 0 ? pos : directiveOrder.indexOf("DEFAULT"), 0, name); + } + }; + } + function directiveExists(name) { + return Object.keys(directiveHandlers).includes(name); + } + function directives(el, attributes, originalAttributeOverride) { + attributes = Array.from(attributes); + if (el._x_virtualDirectives) { + let vAttributes = Object.entries(el._x_virtualDirectives).map(([name, value]) => ({ name, value })); + let staticAttributes = attributesOnly(vAttributes); + vAttributes = vAttributes.map((attribute) => { + if (staticAttributes.find((attr) => attr.name === attribute.name)) { + return { + name: `x-bind:${attribute.name}`, + value: `"${attribute.value}"` + }; + } + return attribute; + }); + attributes = attributes.concat(vAttributes); + } + let transformedAttributeMap = {}; + let directives2 = attributes.map(toTransformedAttributes((newName, oldName) => transformedAttributeMap[newName] = oldName)).filter(outNonAlpineAttributes).map(toParsedDirectives(transformedAttributeMap, originalAttributeOverride)).sort(byPriority); + return directives2.map((directive2) => { + return getDirectiveHandler(el, directive2); + }); + } + function attributesOnly(attributes) { + return Array.from(attributes).map(toTransformedAttributes()).filter((attr) => !outNonAlpineAttributes(attr)); + } + var isDeferringHandlers = false; + var directiveHandlerStacks = /* @__PURE__ */ new Map(); + var currentHandlerStackKey = Symbol(); + function deferHandlingDirectives(callback) { + isDeferringHandlers = true; + let key = Symbol(); + currentHandlerStackKey = key; + directiveHandlerStacks.set(key, []); + let flushHandlers = () => { + while (directiveHandlerStacks.get(key).length) + directiveHandlerStacks.get(key).shift()(); + directiveHandlerStacks.delete(key); + }; + let stopDeferring = () => { + isDeferringHandlers = false; + flushHandlers(); + }; + callback(flushHandlers); + stopDeferring(); + } + function getElementBoundUtilities(el) { + let cleanups = []; + let cleanup2 = (callback) => cleanups.push(callback); + let [effect3, cleanupEffect] = elementBoundEffect(el); + cleanups.push(cleanupEffect); + let utilities = { + Alpine: alpine_default, + effect: effect3, + cleanup: cleanup2, + evaluateLater: evaluateLater.bind(evaluateLater, el), + evaluate: evaluate.bind(evaluate, el) + }; + let doCleanup = () => cleanups.forEach((i) => i()); + return [utilities, doCleanup]; + } + function getDirectiveHandler(el, directive2) { + let noop = () => { + }; + let handler4 = directiveHandlers[directive2.type] || noop; + let [utilities, cleanup2] = getElementBoundUtilities(el); + onAttributeRemoved(el, directive2.original, cleanup2); + let fullHandler = () => { + if (el._x_ignore || el._x_ignoreSelf) + return; + handler4.inline && handler4.inline(el, directive2, utilities); + handler4 = handler4.bind(handler4, el, directive2, utilities); + isDeferringHandlers ? directiveHandlerStacks.get(currentHandlerStackKey).push(handler4) : handler4(); + }; + fullHandler.runCleanups = cleanup2; + return fullHandler; + } + var startingWith = (subject, replacement) => ({ name, value }) => { + if (name.startsWith(subject)) + name = name.replace(subject, replacement); + return { name, value }; + }; + var into = (i) => i; + function toTransformedAttributes(callback = () => { + }) { + return ({ name, value }) => { + let { name: newName, value: newValue } = attributeTransformers.reduce((carry, transform) => { + return transform(carry); + }, { name, value }); + if (newName !== name) + callback(newName, name); + return { name: newName, value: newValue }; + }; + } + var attributeTransformers = []; + function mapAttributes(callback) { + attributeTransformers.push(callback); + } + function outNonAlpineAttributes({ name }) { + return alpineAttributeRegex().test(name); + } + var alpineAttributeRegex = () => new RegExp(`^${prefixAsString}([^:^.]+)\\b`); + function toParsedDirectives(transformedAttributeMap, originalAttributeOverride) { + return ({ name, value }) => { + if (name === value) + value = ""; + let typeMatch = name.match(alpineAttributeRegex()); + let valueMatch = name.match(/:([a-zA-Z0-9\-_:]+)/); + let modifiers = name.match(/\.[^.\]]+(?=[^\]]*$)/g) || []; + let original = originalAttributeOverride || transformedAttributeMap[name] || name; + return { + type: typeMatch ? typeMatch[1] : null, + value: valueMatch ? valueMatch[1] : null, + modifiers: modifiers.map((i) => i.replace(".", "")), + expression: value, + original + }; + }; + } + var DEFAULT = "DEFAULT"; + var directiveOrder = [ + "ignore", + "ref", + "id", + "data", + "anchor", + "bind", + "init", + "for", + "model", + "modelable", + "transition", + "show", + "if", + DEFAULT, + "teleport" + ]; + function byPriority(a, b) { + let typeA = directiveOrder.indexOf(a.type) === -1 ? DEFAULT : a.type; + let typeB = directiveOrder.indexOf(b.type) === -1 ? DEFAULT : b.type; + return directiveOrder.indexOf(typeA) - directiveOrder.indexOf(typeB); + } + + // packages/alpinejs/src/utils/dispatch.js + function dispatch(el, name, detail = {}, options = {}) { + return el.dispatchEvent( + new CustomEvent(name, { + detail, + bubbles: true, + // Allows events to pass the shadow DOM barrier. + composed: true, + cancelable: true, + // Allows overriding the default event options. + ...options + }) + ); + } + + // packages/alpinejs/src/utils/walk.js + function walk(el, callback) { + if (typeof ShadowRoot === "function" && el instanceof ShadowRoot) { + Array.from(el.children).forEach((el2) => walk(el2, callback)); + return; + } + let skip = false; + callback(el, () => skip = true); + if (skip) + return; + let node = el.firstElementChild; + while (node) { + walk(node, callback, false); + node = node.nextElementSibling; + } + } + + // packages/alpinejs/src/utils/warn.js + function warn(message, ...args) { + console.warn(`Alpine Warning: ${message}`, ...args); + } + + // packages/alpinejs/src/lifecycle.js + var started = false; + function start() { + if (started) + warn("Alpine has already been initialized on this page. Calling Alpine.start() more than once can cause problems."); + started = true; + if (!document.body) + warn("Unable to initialize. Trying to load Alpine before `` is available. Did you forget to add `defer` in Alpine's ` +``` + +#### Webpack / Browserify / Babel + +There are several ways to use [Webpack](https://webpack.js.org/), [Browserify](http://browserify.org/) or [Babel](https://babeljs.io/). For more information on using these tools, please refer to the corresponding project's documentation. In the script, including jQuery will usually look like this: + +```js +import $ from "jquery"; +``` + +If you need to use jQuery in a file that's not an ECMAScript module, you can use the CommonJS syntax: + +```js +var $ = require( "jquery" ); +``` + +#### AMD (Asynchronous Module Definition) + +AMD is a module format built for the browser. For more information, we recommend [require.js' documentation](https://requirejs.org/docs/whyamd.html). + +```js +define( [ "jquery" ], function( $ ) { + +} ); +``` + +### Node + +To include jQuery in [Node](https://nodejs.org/), first install with npm. + +```sh +npm install jquery +``` + +For jQuery to work in Node, a window with a document is required. Since no such window exists natively in Node, one can be mocked by tools such as [jsdom](https://github.com/jsdom/jsdom). This can be useful for testing purposes. + +```js +const { JSDOM } = require( "jsdom" ); +const { window } = new JSDOM( "" ); +const $ = require( "jquery" )( window ); +``` diff --git a/node_modules/jquery/bower.json b/node_modules/jquery/bower.json new file mode 100644 index 0000000..95798d5 --- /dev/null +++ b/node_modules/jquery/bower.json @@ -0,0 +1,14 @@ +{ + "name": "jquery", + "main": "dist/jquery.js", + "license": "MIT", + "ignore": [ + "package.json" + ], + "keywords": [ + "jquery", + "javascript", + "browser", + "library" + ] +} \ No newline at end of file diff --git a/node_modules/jquery/dist/jquery.js b/node_modules/jquery/dist/jquery.js new file mode 100644 index 0000000..1a86433 --- /dev/null +++ b/node_modules/jquery/dist/jquery.js @@ -0,0 +1,10716 @@ +/*! + * jQuery JavaScript Library v3.7.1 + * https://jquery.com/ + * + * Copyright OpenJS Foundation and other contributors + * Released under the MIT license + * https://jquery.org/license + * + * Date: 2023-08-28T13:37Z + */ +( function( global, factory ) { + + "use strict"; + + if ( typeof module === "object" && typeof module.exports === "object" ) { + + // For CommonJS and CommonJS-like environments where a proper `window` + // is present, execute the factory and get jQuery. + // For environments that do not have a `window` with a `document` + // (such as Node.js), expose a factory as module.exports. + // This accentuates the need for the creation of a real `window`. + // e.g. var jQuery = require("jquery")(window); + // See ticket trac-14549 for more info. + module.exports = global.document ? + factory( global, true ) : + function( w ) { + if ( !w.document ) { + throw new Error( "jQuery requires a window with a document" ); + } + return factory( w ); + }; + } else { + factory( global ); + } + +// Pass this if window is not defined yet +} )( typeof window !== "undefined" ? window : this, function( window, noGlobal ) { + +// Edge <= 12 - 13+, Firefox <=18 - 45+, IE 10 - 11, Safari 5.1 - 9+, iOS 6 - 9.1 +// throw exceptions when non-strict code (e.g., ASP.NET 4.5) accesses strict mode +// arguments.callee.caller (trac-13335). But as of jQuery 3.0 (2016), strict mode should be common +// enough that all such attempts are guarded in a try block. +"use strict"; + +var arr = []; + +var getProto = Object.getPrototypeOf; + +var slice = arr.slice; + +var flat = arr.flat ? function( array ) { + return arr.flat.call( array ); +} : function( array ) { + return arr.concat.apply( [], array ); +}; + + +var push = arr.push; + +var indexOf = arr.indexOf; + +var class2type = {}; + +var toString = class2type.toString; + +var hasOwn = class2type.hasOwnProperty; + +var fnToString = hasOwn.toString; + +var ObjectFunctionString = fnToString.call( Object ); + +var support = {}; + +var isFunction = function isFunction( obj ) { + + // Support: Chrome <=57, Firefox <=52 + // In some browsers, typeof returns "function" for HTML elements + // (i.e., `typeof document.createElement( "object" ) === "function"`). + // We don't want to classify *any* DOM node as a function. + // Support: QtWeb <=3.8.5, WebKit <=534.34, wkhtmltopdf tool <=0.12.5 + // Plus for old WebKit, typeof returns "function" for HTML collections + // (e.g., `typeof document.getElementsByTagName("div") === "function"`). (gh-4756) + return typeof obj === "function" && typeof obj.nodeType !== "number" && + typeof obj.item !== "function"; + }; + + +var isWindow = function isWindow( obj ) { + return obj != null && obj === obj.window; + }; + + +var document = window.document; + + + + var preservedScriptAttributes = { + type: true, + src: true, + nonce: true, + noModule: true + }; + + function DOMEval( code, node, doc ) { + doc = doc || document; + + var i, val, + script = doc.createElement( "script" ); + + script.text = code; + if ( node ) { + for ( i in preservedScriptAttributes ) { + + // Support: Firefox 64+, Edge 18+ + // Some browsers don't support the "nonce" property on scripts. + // On the other hand, just using `getAttribute` is not enough as + // the `nonce` attribute is reset to an empty string whenever it + // becomes browsing-context connected. + // See https://github.com/whatwg/html/issues/2369 + // See https://html.spec.whatwg.org/#nonce-attributes + // The `node.getAttribute` check was added for the sake of + // `jQuery.globalEval` so that it can fake a nonce-containing node + // via an object. + val = node[ i ] || node.getAttribute && node.getAttribute( i ); + if ( val ) { + script.setAttribute( i, val ); + } + } + } + doc.head.appendChild( script ).parentNode.removeChild( script ); + } + + +function toType( obj ) { + if ( obj == null ) { + return obj + ""; + } + + // Support: Android <=2.3 only (functionish RegExp) + return typeof obj === "object" || typeof obj === "function" ? + class2type[ toString.call( obj ) ] || "object" : + typeof obj; +} +/* global Symbol */ +// Defining this global in .eslintrc.json would create a danger of using the global +// unguarded in another place, it seems safer to define global only for this module + + + +var version = "3.7.1", + + rhtmlSuffix = /HTML$/i, + + // Define a local copy of jQuery + jQuery = function( selector, context ) { + + // The jQuery object is actually just the init constructor 'enhanced' + // Need init if jQuery is called (just allow error to be thrown if not included) + return new jQuery.fn.init( selector, context ); + }; + +jQuery.fn = jQuery.prototype = { + + // The current version of jQuery being used + jquery: version, + + constructor: jQuery, + + // The default length of a jQuery object is 0 + length: 0, + + toArray: function() { + return slice.call( this ); + }, + + // Get the Nth element in the matched element set OR + // Get the whole matched element set as a clean array + get: function( num ) { + + // Return all the elements in a clean array + if ( num == null ) { + return slice.call( this ); + } + + // Return just the one element from the set + return num < 0 ? this[ num + this.length ] : this[ num ]; + }, + + // Take an array of elements and push it onto the stack + // (returning the new matched element set) + pushStack: function( elems ) { + + // Build a new jQuery matched element set + var ret = jQuery.merge( this.constructor(), elems ); + + // Add the old object onto the stack (as a reference) + ret.prevObject = this; + + // Return the newly-formed element set + return ret; + }, + + // Execute a callback for every element in the matched set. + each: function( callback ) { + return jQuery.each( this, callback ); + }, + + map: function( callback ) { + return this.pushStack( jQuery.map( this, function( elem, i ) { + return callback.call( elem, i, elem ); + } ) ); + }, + + slice: function() { + return this.pushStack( slice.apply( this, arguments ) ); + }, + + first: function() { + return this.eq( 0 ); + }, + + last: function() { + return this.eq( -1 ); + }, + + even: function() { + return this.pushStack( jQuery.grep( this, function( _elem, i ) { + return ( i + 1 ) % 2; + } ) ); + }, + + odd: function() { + return this.pushStack( jQuery.grep( this, function( _elem, i ) { + return i % 2; + } ) ); + }, + + eq: function( i ) { + var len = this.length, + j = +i + ( i < 0 ? len : 0 ); + return this.pushStack( j >= 0 && j < len ? [ this[ j ] ] : [] ); + }, + + end: function() { + return this.prevObject || this.constructor(); + }, + + // For internal use only. + // Behaves like an Array's method, not like a jQuery method. + push: push, + sort: arr.sort, + splice: arr.splice +}; + +jQuery.extend = jQuery.fn.extend = function() { + var options, name, src, copy, copyIsArray, clone, + target = arguments[ 0 ] || {}, + i = 1, + length = arguments.length, + deep = false; + + // Handle a deep copy situation + if ( typeof target === "boolean" ) { + deep = target; + + // Skip the boolean and the target + target = arguments[ i ] || {}; + i++; + } + + // Handle case when target is a string or something (possible in deep copy) + if ( typeof target !== "object" && !isFunction( target ) ) { + target = {}; + } + + // Extend jQuery itself if only one argument is passed + if ( i === length ) { + target = this; + i--; + } + + for ( ; i < length; i++ ) { + + // Only deal with non-null/undefined values + if ( ( options = arguments[ i ] ) != null ) { + + // Extend the base object + for ( name in options ) { + copy = options[ name ]; + + // Prevent Object.prototype pollution + // Prevent never-ending loop + if ( name === "__proto__" || target === copy ) { + continue; + } + + // Recurse if we're merging plain objects or arrays + if ( deep && copy && ( jQuery.isPlainObject( copy ) || + ( copyIsArray = Array.isArray( copy ) ) ) ) { + src = target[ name ]; + + // Ensure proper type for the source value + if ( copyIsArray && !Array.isArray( src ) ) { + clone = []; + } else if ( !copyIsArray && !jQuery.isPlainObject( src ) ) { + clone = {}; + } else { + clone = src; + } + copyIsArray = false; + + // Never move original objects, clone them + target[ name ] = jQuery.extend( deep, clone, copy ); + + // Don't bring in undefined values + } else if ( copy !== undefined ) { + target[ name ] = copy; + } + } + } + } + + // Return the modified object + return target; +}; + +jQuery.extend( { + + // Unique for each copy of jQuery on the page + expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ), + + // Assume jQuery is ready without the ready module + isReady: true, + + error: function( msg ) { + throw new Error( msg ); + }, + + noop: function() {}, + + isPlainObject: function( obj ) { + var proto, Ctor; + + // Detect obvious negatives + // Use toString instead of jQuery.type to catch host objects + if ( !obj || toString.call( obj ) !== "[object Object]" ) { + return false; + } + + proto = getProto( obj ); + + // Objects with no prototype (e.g., `Object.create( null )`) are plain + if ( !proto ) { + return true; + } + + // Objects with prototype are plain iff they were constructed by a global Object function + Ctor = hasOwn.call( proto, "constructor" ) && proto.constructor; + return typeof Ctor === "function" && fnToString.call( Ctor ) === ObjectFunctionString; + }, + + isEmptyObject: function( obj ) { + var name; + + for ( name in obj ) { + return false; + } + return true; + }, + + // Evaluates a script in a provided context; falls back to the global one + // if not specified. + globalEval: function( code, options, doc ) { + DOMEval( code, { nonce: options && options.nonce }, doc ); + }, + + each: function( obj, callback ) { + var length, i = 0; + + if ( isArrayLike( obj ) ) { + length = obj.length; + for ( ; i < length; i++ ) { + if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { + break; + } + } + } else { + for ( i in obj ) { + if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { + break; + } + } + } + + return obj; + }, + + + // Retrieve the text value of an array of DOM nodes + text: function( elem ) { + var node, + ret = "", + i = 0, + nodeType = elem.nodeType; + + if ( !nodeType ) { + + // If no nodeType, this is expected to be an array + while ( ( node = elem[ i++ ] ) ) { + + // Do not traverse comment nodes + ret += jQuery.text( node ); + } + } + if ( nodeType === 1 || nodeType === 11 ) { + return elem.textContent; + } + if ( nodeType === 9 ) { + return elem.documentElement.textContent; + } + if ( nodeType === 3 || nodeType === 4 ) { + return elem.nodeValue; + } + + // Do not include comment or processing instruction nodes + + return ret; + }, + + // results is for internal usage only + makeArray: function( arr, results ) { + var ret = results || []; + + if ( arr != null ) { + if ( isArrayLike( Object( arr ) ) ) { + jQuery.merge( ret, + typeof arr === "string" ? + [ arr ] : arr + ); + } else { + push.call( ret, arr ); + } + } + + return ret; + }, + + inArray: function( elem, arr, i ) { + return arr == null ? -1 : indexOf.call( arr, elem, i ); + }, + + isXMLDoc: function( elem ) { + var namespace = elem && elem.namespaceURI, + docElem = elem && ( elem.ownerDocument || elem ).documentElement; + + // Assume HTML when documentElement doesn't yet exist, such as inside + // document fragments. + return !rhtmlSuffix.test( namespace || docElem && docElem.nodeName || "HTML" ); + }, + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + merge: function( first, second ) { + var len = +second.length, + j = 0, + i = first.length; + + for ( ; j < len; j++ ) { + first[ i++ ] = second[ j ]; + } + + first.length = i; + + return first; + }, + + grep: function( elems, callback, invert ) { + var callbackInverse, + matches = [], + i = 0, + length = elems.length, + callbackExpect = !invert; + + // Go through the array, only saving the items + // that pass the validator function + for ( ; i < length; i++ ) { + callbackInverse = !callback( elems[ i ], i ); + if ( callbackInverse !== callbackExpect ) { + matches.push( elems[ i ] ); + } + } + + return matches; + }, + + // arg is for internal usage only + map: function( elems, callback, arg ) { + var length, value, + i = 0, + ret = []; + + // Go through the array, translating each of the items to their new values + if ( isArrayLike( elems ) ) { + length = elems.length; + for ( ; i < length; i++ ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret.push( value ); + } + } + + // Go through every key on the object, + } else { + for ( i in elems ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret.push( value ); + } + } + } + + // Flatten any nested arrays + return flat( ret ); + }, + + // A global GUID counter for objects + guid: 1, + + // jQuery.support is not used in Core but other projects attach their + // properties to it so it needs to exist. + support: support +} ); + +if ( typeof Symbol === "function" ) { + jQuery.fn[ Symbol.iterator ] = arr[ Symbol.iterator ]; +} + +// Populate the class2type map +jQuery.each( "Boolean Number String Function Array Date RegExp Object Error Symbol".split( " " ), + function( _i, name ) { + class2type[ "[object " + name + "]" ] = name.toLowerCase(); + } ); + +function isArrayLike( obj ) { + + // Support: real iOS 8.2 only (not reproducible in simulator) + // `in` check used to prevent JIT error (gh-2145) + // hasOwn isn't used here due to false negatives + // regarding Nodelist length in IE + var length = !!obj && "length" in obj && obj.length, + type = toType( obj ); + + if ( isFunction( obj ) || isWindow( obj ) ) { + return false; + } + + return type === "array" || length === 0 || + typeof length === "number" && length > 0 && ( length - 1 ) in obj; +} + + +function nodeName( elem, name ) { + + return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase(); + +} +var pop = arr.pop; + + +var sort = arr.sort; + + +var splice = arr.splice; + + +var whitespace = "[\\x20\\t\\r\\n\\f]"; + + +var rtrimCSS = new RegExp( + "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", + "g" +); + + + + +// Note: an element does not contain itself +jQuery.contains = function( a, b ) { + var bup = b && b.parentNode; + + return a === bup || !!( bup && bup.nodeType === 1 && ( + + // Support: IE 9 - 11+ + // IE doesn't have `contains` on SVG. + a.contains ? + a.contains( bup ) : + a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16 + ) ); +}; + + + + +// CSS string/identifier serialization +// https://drafts.csswg.org/cssom/#common-serializing-idioms +var rcssescape = /([\0-\x1f\x7f]|^-?\d)|^-$|[^\x80-\uFFFF\w-]/g; + +function fcssescape( ch, asCodePoint ) { + if ( asCodePoint ) { + + // U+0000 NULL becomes U+FFFD REPLACEMENT CHARACTER + if ( ch === "\0" ) { + return "\uFFFD"; + } + + // Control characters and (dependent upon position) numbers get escaped as code points + return ch.slice( 0, -1 ) + "\\" + ch.charCodeAt( ch.length - 1 ).toString( 16 ) + " "; + } + + // Other potentially-special ASCII characters get backslash-escaped + return "\\" + ch; +} + +jQuery.escapeSelector = function( sel ) { + return ( sel + "" ).replace( rcssescape, fcssescape ); +}; + + + + +var preferredDoc = document, + pushNative = push; + +( function() { + +var i, + Expr, + outermostContext, + sortInput, + hasDuplicate, + push = pushNative, + + // Local document vars + document, + documentElement, + documentIsHTML, + rbuggyQSA, + matches, + + // Instance-specific data + expando = jQuery.expando, + dirruns = 0, + done = 0, + classCache = createCache(), + tokenCache = createCache(), + compilerCache = createCache(), + nonnativeSelectorCache = createCache(), + sortOrder = function( a, b ) { + if ( a === b ) { + hasDuplicate = true; + } + return 0; + }, + + booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|" + + "loop|multiple|open|readonly|required|scoped", + + // Regular expressions + + // https://www.w3.org/TR/css-syntax-3/#ident-token-diagram + identifier = "(?:\\\\[\\da-fA-F]{1,6}" + whitespace + + "?|\\\\[^\\r\\n\\f]|[\\w-]|[^\0-\\x7f])+", + + // Attribute selectors: https://www.w3.org/TR/selectors/#attribute-selectors + attributes = "\\[" + whitespace + "*(" + identifier + ")(?:" + whitespace + + + // Operator (capture 2) + "*([*^$|!~]?=)" + whitespace + + + // "Attribute values must be CSS identifiers [capture 5] or strings [capture 3 or capture 4]" + "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + + whitespace + "*\\]", + + pseudos = ":(" + identifier + ")(?:\\((" + + + // To reduce the number of selectors needing tokenize in the preFilter, prefer arguments: + // 1. quoted (capture 3; capture 4 or capture 5) + "('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" + + + // 2. simple (capture 6) + "((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" + + + // 3. anything else (capture 2) + ".*" + + ")\\)|)", + + // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter + rwhitespace = new RegExp( whitespace + "+", "g" ), + + rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ), + rleadingCombinator = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + + whitespace + "*" ), + rdescend = new RegExp( whitespace + "|>" ), + + rpseudo = new RegExp( pseudos ), + ridentifier = new RegExp( "^" + identifier + "$" ), + + matchExpr = { + ID: new RegExp( "^#(" + identifier + ")" ), + CLASS: new RegExp( "^\\.(" + identifier + ")" ), + TAG: new RegExp( "^(" + identifier + "|[*])" ), + ATTR: new RegExp( "^" + attributes ), + PSEUDO: new RegExp( "^" + pseudos ), + CHILD: new RegExp( + "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + + whitespace + "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + + whitespace + "*(\\d+)|))" + whitespace + "*\\)|)", "i" ), + bool: new RegExp( "^(?:" + booleans + ")$", "i" ), + + // For use in libraries implementing .is() + // We use this for POS matching in `select` + needsContext: new RegExp( "^" + whitespace + + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + whitespace + + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" ) + }, + + rinputs = /^(?:input|select|textarea|button)$/i, + rheader = /^h\d$/i, + + // Easily-parseable/retrievable ID or TAG or CLASS selectors + rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/, + + rsibling = /[+~]/, + + // CSS escapes + // https://www.w3.org/TR/CSS21/syndata.html#escaped-characters + runescape = new RegExp( "\\\\[\\da-fA-F]{1,6}" + whitespace + + "?|\\\\([^\\r\\n\\f])", "g" ), + funescape = function( escape, nonHex ) { + var high = "0x" + escape.slice( 1 ) - 0x10000; + + if ( nonHex ) { + + // Strip the backslash prefix from a non-hex escape sequence + return nonHex; + } + + // Replace a hexadecimal escape sequence with the encoded Unicode code point + // Support: IE <=11+ + // For values outside the Basic Multilingual Plane (BMP), manually construct a + // surrogate pair + return high < 0 ? + String.fromCharCode( high + 0x10000 ) : + String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 ); + }, + + // Used for iframes; see `setDocument`. + // Support: IE 9 - 11+, Edge 12 - 18+ + // Removing the function wrapper causes a "Permission Denied" + // error in IE/Edge. + unloadHandler = function() { + setDocument(); + }, + + inDisabledFieldset = addCombinator( + function( elem ) { + return elem.disabled === true && nodeName( elem, "fieldset" ); + }, + { dir: "parentNode", next: "legend" } + ); + +// Support: IE <=9 only +// Accessing document.activeElement can throw unexpectedly +// https://bugs.jquery.com/ticket/13393 +function safeActiveElement() { + try { + return document.activeElement; + } catch ( err ) { } +} + +// Optimize for push.apply( _, NodeList ) +try { + push.apply( + ( arr = slice.call( preferredDoc.childNodes ) ), + preferredDoc.childNodes + ); + + // Support: Android <=4.0 + // Detect silently failing push.apply + // eslint-disable-next-line no-unused-expressions + arr[ preferredDoc.childNodes.length ].nodeType; +} catch ( e ) { + push = { + apply: function( target, els ) { + pushNative.apply( target, slice.call( els ) ); + }, + call: function( target ) { + pushNative.apply( target, slice.call( arguments, 1 ) ); + } + }; +} + +function find( selector, context, results, seed ) { + var m, i, elem, nid, match, groups, newSelector, + newContext = context && context.ownerDocument, + + // nodeType defaults to 9, since context defaults to document + nodeType = context ? context.nodeType : 9; + + results = results || []; + + // Return early from calls with invalid selector or context + if ( typeof selector !== "string" || !selector || + nodeType !== 1 && nodeType !== 9 && nodeType !== 11 ) { + + return results; + } + + // Try to shortcut find operations (as opposed to filters) in HTML documents + if ( !seed ) { + setDocument( context ); + context = context || document; + + if ( documentIsHTML ) { + + // If the selector is sufficiently simple, try using a "get*By*" DOM method + // (excepting DocumentFragment context, where the methods don't exist) + if ( nodeType !== 11 && ( match = rquickExpr.exec( selector ) ) ) { + + // ID selector + if ( ( m = match[ 1 ] ) ) { + + // Document context + if ( nodeType === 9 ) { + if ( ( elem = context.getElementById( m ) ) ) { + + // Support: IE 9 only + // getElementById can match elements by name instead of ID + if ( elem.id === m ) { + push.call( results, elem ); + return results; + } + } else { + return results; + } + + // Element context + } else { + + // Support: IE 9 only + // getElementById can match elements by name instead of ID + if ( newContext && ( elem = newContext.getElementById( m ) ) && + find.contains( context, elem ) && + elem.id === m ) { + + push.call( results, elem ); + return results; + } + } + + // Type selector + } else if ( match[ 2 ] ) { + push.apply( results, context.getElementsByTagName( selector ) ); + return results; + + // Class selector + } else if ( ( m = match[ 3 ] ) && context.getElementsByClassName ) { + push.apply( results, context.getElementsByClassName( m ) ); + return results; + } + } + + // Take advantage of querySelectorAll + if ( !nonnativeSelectorCache[ selector + " " ] && + ( !rbuggyQSA || !rbuggyQSA.test( selector ) ) ) { + + newSelector = selector; + newContext = context; + + // qSA considers elements outside a scoping root when evaluating child or + // descendant combinators, which is not what we want. + // In such cases, we work around the behavior by prefixing every selector in the + // list with an ID selector referencing the scope context. + // The technique has to be used as well when a leading combinator is used + // as such selectors are not recognized by querySelectorAll. + // Thanks to Andrew Dupont for this technique. + if ( nodeType === 1 && + ( rdescend.test( selector ) || rleadingCombinator.test( selector ) ) ) { + + // Expand context for sibling selectors + newContext = rsibling.test( selector ) && testContext( context.parentNode ) || + context; + + // We can use :scope instead of the ID hack if the browser + // supports it & if we're not changing the context. + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when + // strict-comparing two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( newContext != context || !support.scope ) { + + // Capture the context ID, setting it first if necessary + if ( ( nid = context.getAttribute( "id" ) ) ) { + nid = jQuery.escapeSelector( nid ); + } else { + context.setAttribute( "id", ( nid = expando ) ); + } + } + + // Prefix every selector in the list + groups = tokenize( selector ); + i = groups.length; + while ( i-- ) { + groups[ i ] = ( nid ? "#" + nid : ":scope" ) + " " + + toSelector( groups[ i ] ); + } + newSelector = groups.join( "," ); + } + + try { + push.apply( results, + newContext.querySelectorAll( newSelector ) + ); + return results; + } catch ( qsaError ) { + nonnativeSelectorCache( selector, true ); + } finally { + if ( nid === expando ) { + context.removeAttribute( "id" ); + } + } + } + } + } + + // All others + return select( selector.replace( rtrimCSS, "$1" ), context, results, seed ); +} + +/** + * Create key-value caches of limited size + * @returns {function(string, object)} Returns the Object data after storing it on itself with + * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength) + * deleting the oldest entry + */ +function createCache() { + var keys = []; + + function cache( key, value ) { + + // Use (key + " ") to avoid collision with native prototype properties + // (see https://github.com/jquery/sizzle/issues/157) + if ( keys.push( key + " " ) > Expr.cacheLength ) { + + // Only keep the most recent entries + delete cache[ keys.shift() ]; + } + return ( cache[ key + " " ] = value ); + } + return cache; +} + +/** + * Mark a function for special use by jQuery selector module + * @param {Function} fn The function to mark + */ +function markFunction( fn ) { + fn[ expando ] = true; + return fn; +} + +/** + * Support testing using an element + * @param {Function} fn Passed the created element and returns a boolean result + */ +function assert( fn ) { + var el = document.createElement( "fieldset" ); + + try { + return !!fn( el ); + } catch ( e ) { + return false; + } finally { + + // Remove from its parent by default + if ( el.parentNode ) { + el.parentNode.removeChild( el ); + } + + // release memory in IE + el = null; + } +} + +/** + * Returns a function to use in pseudos for input types + * @param {String} type + */ +function createInputPseudo( type ) { + return function( elem ) { + return nodeName( elem, "input" ) && elem.type === type; + }; +} + +/** + * Returns a function to use in pseudos for buttons + * @param {String} type + */ +function createButtonPseudo( type ) { + return function( elem ) { + return ( nodeName( elem, "input" ) || nodeName( elem, "button" ) ) && + elem.type === type; + }; +} + +/** + * Returns a function to use in pseudos for :enabled/:disabled + * @param {Boolean} disabled true for :disabled; false for :enabled + */ +function createDisabledPseudo( disabled ) { + + // Known :disabled false positives: fieldset[disabled] > legend:nth-of-type(n+2) :can-disable + return function( elem ) { + + // Only certain elements can match :enabled or :disabled + // https://html.spec.whatwg.org/multipage/scripting.html#selector-enabled + // https://html.spec.whatwg.org/multipage/scripting.html#selector-disabled + if ( "form" in elem ) { + + // Check for inherited disabledness on relevant non-disabled elements: + // * listed form-associated elements in a disabled fieldset + // https://html.spec.whatwg.org/multipage/forms.html#category-listed + // https://html.spec.whatwg.org/multipage/forms.html#concept-fe-disabled + // * option elements in a disabled optgroup + // https://html.spec.whatwg.org/multipage/forms.html#concept-option-disabled + // All such elements have a "form" property. + if ( elem.parentNode && elem.disabled === false ) { + + // Option elements defer to a parent optgroup if present + if ( "label" in elem ) { + if ( "label" in elem.parentNode ) { + return elem.parentNode.disabled === disabled; + } else { + return elem.disabled === disabled; + } + } + + // Support: IE 6 - 11+ + // Use the isDisabled shortcut property to check for disabled fieldset ancestors + return elem.isDisabled === disabled || + + // Where there is no isDisabled, check manually + elem.isDisabled !== !disabled && + inDisabledFieldset( elem ) === disabled; + } + + return elem.disabled === disabled; + + // Try to winnow out elements that can't be disabled before trusting the disabled property. + // Some victims get caught in our net (label, legend, menu, track), but it shouldn't + // even exist on them, let alone have a boolean value. + } else if ( "label" in elem ) { + return elem.disabled === disabled; + } + + // Remaining elements are neither :enabled nor :disabled + return false; + }; +} + +/** + * Returns a function to use in pseudos for positionals + * @param {Function} fn + */ +function createPositionalPseudo( fn ) { + return markFunction( function( argument ) { + argument = +argument; + return markFunction( function( seed, matches ) { + var j, + matchIndexes = fn( [], seed.length, argument ), + i = matchIndexes.length; + + // Match elements found at the specified indexes + while ( i-- ) { + if ( seed[ ( j = matchIndexes[ i ] ) ] ) { + seed[ j ] = !( matches[ j ] = seed[ j ] ); + } + } + } ); + } ); +} + +/** + * Checks a node for validity as a jQuery selector context + * @param {Element|Object=} context + * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value + */ +function testContext( context ) { + return context && typeof context.getElementsByTagName !== "undefined" && context; +} + +/** + * Sets document-related variables once based on the current document + * @param {Element|Object} [node] An element or document object to use to set the document + * @returns {Object} Returns the current document + */ +function setDocument( node ) { + var subWindow, + doc = node ? node.ownerDocument || node : preferredDoc; + + // Return early if doc is invalid or already selected + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( doc == document || doc.nodeType !== 9 || !doc.documentElement ) { + return document; + } + + // Update global variables + document = doc; + documentElement = document.documentElement; + documentIsHTML = !jQuery.isXMLDoc( document ); + + // Support: iOS 7 only, IE 9 - 11+ + // Older browsers didn't support unprefixed `matches`. + matches = documentElement.matches || + documentElement.webkitMatchesSelector || + documentElement.msMatchesSelector; + + // Support: IE 9 - 11+, Edge 12 - 18+ + // Accessing iframe documents after unload throws "permission denied" errors + // (see trac-13936). + // Limit the fix to IE & Edge Legacy; despite Edge 15+ implementing `matches`, + // all IE 9+ and Edge Legacy versions implement `msMatchesSelector` as well. + if ( documentElement.msMatchesSelector && + + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + preferredDoc != document && + ( subWindow = document.defaultView ) && subWindow.top !== subWindow ) { + + // Support: IE 9 - 11+, Edge 12 - 18+ + subWindow.addEventListener( "unload", unloadHandler ); + } + + // Support: IE <10 + // Check if getElementById returns elements by name + // The broken getElementById methods don't pick up programmatically-set names, + // so use a roundabout getElementsByName test + support.getById = assert( function( el ) { + documentElement.appendChild( el ).id = jQuery.expando; + return !document.getElementsByName || + !document.getElementsByName( jQuery.expando ).length; + } ); + + // Support: IE 9 only + // Check to see if it's possible to do matchesSelector + // on a disconnected node. + support.disconnectedMatch = assert( function( el ) { + return matches.call( el, "*" ); + } ); + + // Support: IE 9 - 11+, Edge 12 - 18+ + // IE/Edge don't support the :scope pseudo-class. + support.scope = assert( function() { + return document.querySelectorAll( ":scope" ); + } ); + + // Support: Chrome 105 - 111 only, Safari 15.4 - 16.3 only + // Make sure the `:has()` argument is parsed unforgivingly. + // We include `*` in the test to detect buggy implementations that are + // _selectively_ forgiving (specifically when the list includes at least + // one valid selector). + // Note that we treat complete lack of support for `:has()` as if it were + // spec-compliant support, which is fine because use of `:has()` in such + // environments will fail in the qSA path and fall back to jQuery traversal + // anyway. + support.cssHas = assert( function() { + try { + document.querySelector( ":has(*,:jqfake)" ); + return false; + } catch ( e ) { + return true; + } + } ); + + // ID filter and find + if ( support.getById ) { + Expr.filter.ID = function( id ) { + var attrId = id.replace( runescape, funescape ); + return function( elem ) { + return elem.getAttribute( "id" ) === attrId; + }; + }; + Expr.find.ID = function( id, context ) { + if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { + var elem = context.getElementById( id ); + return elem ? [ elem ] : []; + } + }; + } else { + Expr.filter.ID = function( id ) { + var attrId = id.replace( runescape, funescape ); + return function( elem ) { + var node = typeof elem.getAttributeNode !== "undefined" && + elem.getAttributeNode( "id" ); + return node && node.value === attrId; + }; + }; + + // Support: IE 6 - 7 only + // getElementById is not reliable as a find shortcut + Expr.find.ID = function( id, context ) { + if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { + var node, i, elems, + elem = context.getElementById( id ); + + if ( elem ) { + + // Verify the id attribute + node = elem.getAttributeNode( "id" ); + if ( node && node.value === id ) { + return [ elem ]; + } + + // Fall back on getElementsByName + elems = context.getElementsByName( id ); + i = 0; + while ( ( elem = elems[ i++ ] ) ) { + node = elem.getAttributeNode( "id" ); + if ( node && node.value === id ) { + return [ elem ]; + } + } + } + + return []; + } + }; + } + + // Tag + Expr.find.TAG = function( tag, context ) { + if ( typeof context.getElementsByTagName !== "undefined" ) { + return context.getElementsByTagName( tag ); + + // DocumentFragment nodes don't have gEBTN + } else { + return context.querySelectorAll( tag ); + } + }; + + // Class + Expr.find.CLASS = function( className, context ) { + if ( typeof context.getElementsByClassName !== "undefined" && documentIsHTML ) { + return context.getElementsByClassName( className ); + } + }; + + /* QSA/matchesSelector + ---------------------------------------------------------------------- */ + + // QSA and matchesSelector support + + rbuggyQSA = []; + + // Build QSA regex + // Regex strategy adopted from Diego Perini + assert( function( el ) { + + var input; + + documentElement.appendChild( el ).innerHTML = + "" + + ""; + + // Support: iOS <=7 - 8 only + // Boolean attributes and "value" are not treated correctly in some XML documents + if ( !el.querySelectorAll( "[selected]" ).length ) { + rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" ); + } + + // Support: iOS <=7 - 8 only + if ( !el.querySelectorAll( "[id~=" + expando + "-]" ).length ) { + rbuggyQSA.push( "~=" ); + } + + // Support: iOS 8 only + // https://bugs.webkit.org/show_bug.cgi?id=136851 + // In-page `selector#id sibling-combinator selector` fails + if ( !el.querySelectorAll( "a#" + expando + "+*" ).length ) { + rbuggyQSA.push( ".#.+[+~]" ); + } + + // Support: Chrome <=105+, Firefox <=104+, Safari <=15.4+ + // In some of the document kinds, these selectors wouldn't work natively. + // This is probably OK but for backwards compatibility we want to maintain + // handling them through jQuery traversal in jQuery 3.x. + if ( !el.querySelectorAll( ":checked" ).length ) { + rbuggyQSA.push( ":checked" ); + } + + // Support: Windows 8 Native Apps + // The type and name attributes are restricted during .innerHTML assignment + input = document.createElement( "input" ); + input.setAttribute( "type", "hidden" ); + el.appendChild( input ).setAttribute( "name", "D" ); + + // Support: IE 9 - 11+ + // IE's :disabled selector does not pick up the children of disabled fieldsets + // Support: Chrome <=105+, Firefox <=104+, Safari <=15.4+ + // In some of the document kinds, these selectors wouldn't work natively. + // This is probably OK but for backwards compatibility we want to maintain + // handling them through jQuery traversal in jQuery 3.x. + documentElement.appendChild( el ).disabled = true; + if ( el.querySelectorAll( ":disabled" ).length !== 2 ) { + rbuggyQSA.push( ":enabled", ":disabled" ); + } + + // Support: IE 11+, Edge 15 - 18+ + // IE 11/Edge don't find elements on a `[name='']` query in some cases. + // Adding a temporary attribute to the document before the selection works + // around the issue. + // Interestingly, IE 10 & older don't seem to have the issue. + input = document.createElement( "input" ); + input.setAttribute( "name", "" ); + el.appendChild( input ); + if ( !el.querySelectorAll( "[name='']" ).length ) { + rbuggyQSA.push( "\\[" + whitespace + "*name" + whitespace + "*=" + + whitespace + "*(?:''|\"\")" ); + } + } ); + + if ( !support.cssHas ) { + + // Support: Chrome 105 - 110+, Safari 15.4 - 16.3+ + // Our regular `try-catch` mechanism fails to detect natively-unsupported + // pseudo-classes inside `:has()` (such as `:has(:contains("Foo"))`) + // in browsers that parse the `:has()` argument as a forgiving selector list. + // https://drafts.csswg.org/selectors/#relational now requires the argument + // to be parsed unforgivingly, but browsers have not yet fully adjusted. + rbuggyQSA.push( ":has" ); + } + + rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join( "|" ) ); + + /* Sorting + ---------------------------------------------------------------------- */ + + // Document order sorting + sortOrder = function( a, b ) { + + // Flag for duplicate removal + if ( a === b ) { + hasDuplicate = true; + return 0; + } + + // Sort on method existence if only one input has compareDocumentPosition + var compare = !a.compareDocumentPosition - !b.compareDocumentPosition; + if ( compare ) { + return compare; + } + + // Calculate position if both inputs belong to the same document + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + compare = ( a.ownerDocument || a ) == ( b.ownerDocument || b ) ? + a.compareDocumentPosition( b ) : + + // Otherwise we know they are disconnected + 1; + + // Disconnected nodes + if ( compare & 1 || + ( !support.sortDetached && b.compareDocumentPosition( a ) === compare ) ) { + + // Choose the first element that is related to our preferred document + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( a === document || a.ownerDocument == preferredDoc && + find.contains( preferredDoc, a ) ) { + return -1; + } + + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( b === document || b.ownerDocument == preferredDoc && + find.contains( preferredDoc, b ) ) { + return 1; + } + + // Maintain original order + return sortInput ? + ( indexOf.call( sortInput, a ) - indexOf.call( sortInput, b ) ) : + 0; + } + + return compare & 4 ? -1 : 1; + }; + + return document; +} + +find.matches = function( expr, elements ) { + return find( expr, null, null, elements ); +}; + +find.matchesSelector = function( elem, expr ) { + setDocument( elem ); + + if ( documentIsHTML && + !nonnativeSelectorCache[ expr + " " ] && + ( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) { + + try { + var ret = matches.call( elem, expr ); + + // IE 9's matchesSelector returns false on disconnected nodes + if ( ret || support.disconnectedMatch || + + // As well, disconnected nodes are said to be in a document + // fragment in IE 9 + elem.document && elem.document.nodeType !== 11 ) { + return ret; + } + } catch ( e ) { + nonnativeSelectorCache( expr, true ); + } + } + + return find( expr, document, null, [ elem ] ).length > 0; +}; + +find.contains = function( context, elem ) { + + // Set document vars if needed + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( ( context.ownerDocument || context ) != document ) { + setDocument( context ); + } + return jQuery.contains( context, elem ); +}; + + +find.attr = function( elem, name ) { + + // Set document vars if needed + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( ( elem.ownerDocument || elem ) != document ) { + setDocument( elem ); + } + + var fn = Expr.attrHandle[ name.toLowerCase() ], + + // Don't get fooled by Object.prototype properties (see trac-13807) + val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ? + fn( elem, name, !documentIsHTML ) : + undefined; + + if ( val !== undefined ) { + return val; + } + + return elem.getAttribute( name ); +}; + +find.error = function( msg ) { + throw new Error( "Syntax error, unrecognized expression: " + msg ); +}; + +/** + * Document sorting and removing duplicates + * @param {ArrayLike} results + */ +jQuery.uniqueSort = function( results ) { + var elem, + duplicates = [], + j = 0, + i = 0; + + // Unless we *know* we can detect duplicates, assume their presence + // + // Support: Android <=4.0+ + // Testing for detecting duplicates is unpredictable so instead assume we can't + // depend on duplicate detection in all browsers without a stable sort. + hasDuplicate = !support.sortStable; + sortInput = !support.sortStable && slice.call( results, 0 ); + sort.call( results, sortOrder ); + + if ( hasDuplicate ) { + while ( ( elem = results[ i++ ] ) ) { + if ( elem === results[ i ] ) { + j = duplicates.push( i ); + } + } + while ( j-- ) { + splice.call( results, duplicates[ j ], 1 ); + } + } + + // Clear input after sorting to release objects + // See https://github.com/jquery/sizzle/pull/225 + sortInput = null; + + return results; +}; + +jQuery.fn.uniqueSort = function() { + return this.pushStack( jQuery.uniqueSort( slice.apply( this ) ) ); +}; + +Expr = jQuery.expr = { + + // Can be adjusted by the user + cacheLength: 50, + + createPseudo: markFunction, + + match: matchExpr, + + attrHandle: {}, + + find: {}, + + relative: { + ">": { dir: "parentNode", first: true }, + " ": { dir: "parentNode" }, + "+": { dir: "previousSibling", first: true }, + "~": { dir: "previousSibling" } + }, + + preFilter: { + ATTR: function( match ) { + match[ 1 ] = match[ 1 ].replace( runescape, funescape ); + + // Move the given value to match[3] whether quoted or unquoted + match[ 3 ] = ( match[ 3 ] || match[ 4 ] || match[ 5 ] || "" ) + .replace( runescape, funescape ); + + if ( match[ 2 ] === "~=" ) { + match[ 3 ] = " " + match[ 3 ] + " "; + } + + return match.slice( 0, 4 ); + }, + + CHILD: function( match ) { + + /* matches from matchExpr["CHILD"] + 1 type (only|nth|...) + 2 what (child|of-type) + 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...) + 4 xn-component of xn+y argument ([+-]?\d*n|) + 5 sign of xn-component + 6 x of xn-component + 7 sign of y-component + 8 y of y-component + */ + match[ 1 ] = match[ 1 ].toLowerCase(); + + if ( match[ 1 ].slice( 0, 3 ) === "nth" ) { + + // nth-* requires argument + if ( !match[ 3 ] ) { + find.error( match[ 0 ] ); + } + + // numeric x and y parameters for Expr.filter.CHILD + // remember that false/true cast respectively to 0/1 + match[ 4 ] = +( match[ 4 ] ? + match[ 5 ] + ( match[ 6 ] || 1 ) : + 2 * ( match[ 3 ] === "even" || match[ 3 ] === "odd" ) + ); + match[ 5 ] = +( ( match[ 7 ] + match[ 8 ] ) || match[ 3 ] === "odd" ); + + // other types prohibit arguments + } else if ( match[ 3 ] ) { + find.error( match[ 0 ] ); + } + + return match; + }, + + PSEUDO: function( match ) { + var excess, + unquoted = !match[ 6 ] && match[ 2 ]; + + if ( matchExpr.CHILD.test( match[ 0 ] ) ) { + return null; + } + + // Accept quoted arguments as-is + if ( match[ 3 ] ) { + match[ 2 ] = match[ 4 ] || match[ 5 ] || ""; + + // Strip excess characters from unquoted arguments + } else if ( unquoted && rpseudo.test( unquoted ) && + + // Get excess from tokenize (recursively) + ( excess = tokenize( unquoted, true ) ) && + + // advance to the next closing parenthesis + ( excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length ) ) { + + // excess is a negative index + match[ 0 ] = match[ 0 ].slice( 0, excess ); + match[ 2 ] = unquoted.slice( 0, excess ); + } + + // Return only captures needed by the pseudo filter method (type and argument) + return match.slice( 0, 3 ); + } + }, + + filter: { + + TAG: function( nodeNameSelector ) { + var expectedNodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase(); + return nodeNameSelector === "*" ? + function() { + return true; + } : + function( elem ) { + return nodeName( elem, expectedNodeName ); + }; + }, + + CLASS: function( className ) { + var pattern = classCache[ className + " " ]; + + return pattern || + ( pattern = new RegExp( "(^|" + whitespace + ")" + className + + "(" + whitespace + "|$)" ) ) && + classCache( className, function( elem ) { + return pattern.test( + typeof elem.className === "string" && elem.className || + typeof elem.getAttribute !== "undefined" && + elem.getAttribute( "class" ) || + "" + ); + } ); + }, + + ATTR: function( name, operator, check ) { + return function( elem ) { + var result = find.attr( elem, name ); + + if ( result == null ) { + return operator === "!="; + } + if ( !operator ) { + return true; + } + + result += ""; + + if ( operator === "=" ) { + return result === check; + } + if ( operator === "!=" ) { + return result !== check; + } + if ( operator === "^=" ) { + return check && result.indexOf( check ) === 0; + } + if ( operator === "*=" ) { + return check && result.indexOf( check ) > -1; + } + if ( operator === "$=" ) { + return check && result.slice( -check.length ) === check; + } + if ( operator === "~=" ) { + return ( " " + result.replace( rwhitespace, " " ) + " " ) + .indexOf( check ) > -1; + } + if ( operator === "|=" ) { + return result === check || result.slice( 0, check.length + 1 ) === check + "-"; + } + + return false; + }; + }, + + CHILD: function( type, what, _argument, first, last ) { + var simple = type.slice( 0, 3 ) !== "nth", + forward = type.slice( -4 ) !== "last", + ofType = what === "of-type"; + + return first === 1 && last === 0 ? + + // Shortcut for :nth-*(n) + function( elem ) { + return !!elem.parentNode; + } : + + function( elem, _context, xml ) { + var cache, outerCache, node, nodeIndex, start, + dir = simple !== forward ? "nextSibling" : "previousSibling", + parent = elem.parentNode, + name = ofType && elem.nodeName.toLowerCase(), + useCache = !xml && !ofType, + diff = false; + + if ( parent ) { + + // :(first|last|only)-(child|of-type) + if ( simple ) { + while ( dir ) { + node = elem; + while ( ( node = node[ dir ] ) ) { + if ( ofType ? + nodeName( node, name ) : + node.nodeType === 1 ) { + + return false; + } + } + + // Reverse direction for :only-* (if we haven't yet done so) + start = dir = type === "only" && !start && "nextSibling"; + } + return true; + } + + start = [ forward ? parent.firstChild : parent.lastChild ]; + + // non-xml :nth-child(...) stores cache data on `parent` + if ( forward && useCache ) { + + // Seek `elem` from a previously-cached index + outerCache = parent[ expando ] || ( parent[ expando ] = {} ); + cache = outerCache[ type ] || []; + nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; + diff = nodeIndex && cache[ 2 ]; + node = nodeIndex && parent.childNodes[ nodeIndex ]; + + while ( ( node = ++nodeIndex && node && node[ dir ] || + + // Fallback to seeking `elem` from the start + ( diff = nodeIndex = 0 ) || start.pop() ) ) { + + // When found, cache indexes on `parent` and break + if ( node.nodeType === 1 && ++diff && node === elem ) { + outerCache[ type ] = [ dirruns, nodeIndex, diff ]; + break; + } + } + + } else { + + // Use previously-cached element index if available + if ( useCache ) { + outerCache = elem[ expando ] || ( elem[ expando ] = {} ); + cache = outerCache[ type ] || []; + nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; + diff = nodeIndex; + } + + // xml :nth-child(...) + // or :nth-last-child(...) or :nth(-last)?-of-type(...) + if ( diff === false ) { + + // Use the same loop as above to seek `elem` from the start + while ( ( node = ++nodeIndex && node && node[ dir ] || + ( diff = nodeIndex = 0 ) || start.pop() ) ) { + + if ( ( ofType ? + nodeName( node, name ) : + node.nodeType === 1 ) && + ++diff ) { + + // Cache the index of each encountered element + if ( useCache ) { + outerCache = node[ expando ] || + ( node[ expando ] = {} ); + outerCache[ type ] = [ dirruns, diff ]; + } + + if ( node === elem ) { + break; + } + } + } + } + } + + // Incorporate the offset, then check against cycle size + diff -= last; + return diff === first || ( diff % first === 0 && diff / first >= 0 ); + } + }; + }, + + PSEUDO: function( pseudo, argument ) { + + // pseudo-class names are case-insensitive + // https://www.w3.org/TR/selectors/#pseudo-classes + // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters + // Remember that setFilters inherits from pseudos + var args, + fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] || + find.error( "unsupported pseudo: " + pseudo ); + + // The user may use createPseudo to indicate that + // arguments are needed to create the filter function + // just as jQuery does + if ( fn[ expando ] ) { + return fn( argument ); + } + + // But maintain support for old signatures + if ( fn.length > 1 ) { + args = [ pseudo, pseudo, "", argument ]; + return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ? + markFunction( function( seed, matches ) { + var idx, + matched = fn( seed, argument ), + i = matched.length; + while ( i-- ) { + idx = indexOf.call( seed, matched[ i ] ); + seed[ idx ] = !( matches[ idx ] = matched[ i ] ); + } + } ) : + function( elem ) { + return fn( elem, 0, args ); + }; + } + + return fn; + } + }, + + pseudos: { + + // Potentially complex pseudos + not: markFunction( function( selector ) { + + // Trim the selector passed to compile + // to avoid treating leading and trailing + // spaces as combinators + var input = [], + results = [], + matcher = compile( selector.replace( rtrimCSS, "$1" ) ); + + return matcher[ expando ] ? + markFunction( function( seed, matches, _context, xml ) { + var elem, + unmatched = matcher( seed, null, xml, [] ), + i = seed.length; + + // Match elements unmatched by `matcher` + while ( i-- ) { + if ( ( elem = unmatched[ i ] ) ) { + seed[ i ] = !( matches[ i ] = elem ); + } + } + } ) : + function( elem, _context, xml ) { + input[ 0 ] = elem; + matcher( input, null, xml, results ); + + // Don't keep the element + // (see https://github.com/jquery/sizzle/issues/299) + input[ 0 ] = null; + return !results.pop(); + }; + } ), + + has: markFunction( function( selector ) { + return function( elem ) { + return find( selector, elem ).length > 0; + }; + } ), + + contains: markFunction( function( text ) { + text = text.replace( runescape, funescape ); + return function( elem ) { + return ( elem.textContent || jQuery.text( elem ) ).indexOf( text ) > -1; + }; + } ), + + // "Whether an element is represented by a :lang() selector + // is based solely on the element's language value + // being equal to the identifier C, + // or beginning with the identifier C immediately followed by "-". + // The matching of C against the element's language value is performed case-insensitively. + // The identifier C does not have to be a valid language name." + // https://www.w3.org/TR/selectors/#lang-pseudo + lang: markFunction( function( lang ) { + + // lang value must be a valid identifier + if ( !ridentifier.test( lang || "" ) ) { + find.error( "unsupported lang: " + lang ); + } + lang = lang.replace( runescape, funescape ).toLowerCase(); + return function( elem ) { + var elemLang; + do { + if ( ( elemLang = documentIsHTML ? + elem.lang : + elem.getAttribute( "xml:lang" ) || elem.getAttribute( "lang" ) ) ) { + + elemLang = elemLang.toLowerCase(); + return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0; + } + } while ( ( elem = elem.parentNode ) && elem.nodeType === 1 ); + return false; + }; + } ), + + // Miscellaneous + target: function( elem ) { + var hash = window.location && window.location.hash; + return hash && hash.slice( 1 ) === elem.id; + }, + + root: function( elem ) { + return elem === documentElement; + }, + + focus: function( elem ) { + return elem === safeActiveElement() && + document.hasFocus() && + !!( elem.type || elem.href || ~elem.tabIndex ); + }, + + // Boolean properties + enabled: createDisabledPseudo( false ), + disabled: createDisabledPseudo( true ), + + checked: function( elem ) { + + // In CSS3, :checked should return both checked and selected elements + // https://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked + return ( nodeName( elem, "input" ) && !!elem.checked ) || + ( nodeName( elem, "option" ) && !!elem.selected ); + }, + + selected: function( elem ) { + + // Support: IE <=11+ + // Accessing the selectedIndex property + // forces the browser to treat the default option as + // selected when in an optgroup. + if ( elem.parentNode ) { + // eslint-disable-next-line no-unused-expressions + elem.parentNode.selectedIndex; + } + + return elem.selected === true; + }, + + // Contents + empty: function( elem ) { + + // https://www.w3.org/TR/selectors/#empty-pseudo + // :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5), + // but not by others (comment: 8; processing instruction: 7; etc.) + // nodeType < 6 works because attributes (2) do not appear as children + for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { + if ( elem.nodeType < 6 ) { + return false; + } + } + return true; + }, + + parent: function( elem ) { + return !Expr.pseudos.empty( elem ); + }, + + // Element/input types + header: function( elem ) { + return rheader.test( elem.nodeName ); + }, + + input: function( elem ) { + return rinputs.test( elem.nodeName ); + }, + + button: function( elem ) { + return nodeName( elem, "input" ) && elem.type === "button" || + nodeName( elem, "button" ); + }, + + text: function( elem ) { + var attr; + return nodeName( elem, "input" ) && elem.type === "text" && + + // Support: IE <10 only + // New HTML5 attribute values (e.g., "search") appear + // with elem.type === "text" + ( ( attr = elem.getAttribute( "type" ) ) == null || + attr.toLowerCase() === "text" ); + }, + + // Position-in-collection + first: createPositionalPseudo( function() { + return [ 0 ]; + } ), + + last: createPositionalPseudo( function( _matchIndexes, length ) { + return [ length - 1 ]; + } ), + + eq: createPositionalPseudo( function( _matchIndexes, length, argument ) { + return [ argument < 0 ? argument + length : argument ]; + } ), + + even: createPositionalPseudo( function( matchIndexes, length ) { + var i = 0; + for ( ; i < length; i += 2 ) { + matchIndexes.push( i ); + } + return matchIndexes; + } ), + + odd: createPositionalPseudo( function( matchIndexes, length ) { + var i = 1; + for ( ; i < length; i += 2 ) { + matchIndexes.push( i ); + } + return matchIndexes; + } ), + + lt: createPositionalPseudo( function( matchIndexes, length, argument ) { + var i; + + if ( argument < 0 ) { + i = argument + length; + } else if ( argument > length ) { + i = length; + } else { + i = argument; + } + + for ( ; --i >= 0; ) { + matchIndexes.push( i ); + } + return matchIndexes; + } ), + + gt: createPositionalPseudo( function( matchIndexes, length, argument ) { + var i = argument < 0 ? argument + length : argument; + for ( ; ++i < length; ) { + matchIndexes.push( i ); + } + return matchIndexes; + } ) + } +}; + +Expr.pseudos.nth = Expr.pseudos.eq; + +// Add button/input type pseudos +for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) { + Expr.pseudos[ i ] = createInputPseudo( i ); +} +for ( i in { submit: true, reset: true } ) { + Expr.pseudos[ i ] = createButtonPseudo( i ); +} + +// Easy API for creating new setFilters +function setFilters() {} +setFilters.prototype = Expr.filters = Expr.pseudos; +Expr.setFilters = new setFilters(); + +function tokenize( selector, parseOnly ) { + var matched, match, tokens, type, + soFar, groups, preFilters, + cached = tokenCache[ selector + " " ]; + + if ( cached ) { + return parseOnly ? 0 : cached.slice( 0 ); + } + + soFar = selector; + groups = []; + preFilters = Expr.preFilter; + + while ( soFar ) { + + // Comma and first run + if ( !matched || ( match = rcomma.exec( soFar ) ) ) { + if ( match ) { + + // Don't consume trailing commas as valid + soFar = soFar.slice( match[ 0 ].length ) || soFar; + } + groups.push( ( tokens = [] ) ); + } + + matched = false; + + // Combinators + if ( ( match = rleadingCombinator.exec( soFar ) ) ) { + matched = match.shift(); + tokens.push( { + value: matched, + + // Cast descendant combinators to space + type: match[ 0 ].replace( rtrimCSS, " " ) + } ); + soFar = soFar.slice( matched.length ); + } + + // Filters + for ( type in Expr.filter ) { + if ( ( match = matchExpr[ type ].exec( soFar ) ) && ( !preFilters[ type ] || + ( match = preFilters[ type ]( match ) ) ) ) { + matched = match.shift(); + tokens.push( { + value: matched, + type: type, + matches: match + } ); + soFar = soFar.slice( matched.length ); + } + } + + if ( !matched ) { + break; + } + } + + // Return the length of the invalid excess + // if we're just parsing + // Otherwise, throw an error or return tokens + if ( parseOnly ) { + return soFar.length; + } + + return soFar ? + find.error( selector ) : + + // Cache the tokens + tokenCache( selector, groups ).slice( 0 ); +} + +function toSelector( tokens ) { + var i = 0, + len = tokens.length, + selector = ""; + for ( ; i < len; i++ ) { + selector += tokens[ i ].value; + } + return selector; +} + +function addCombinator( matcher, combinator, base ) { + var dir = combinator.dir, + skip = combinator.next, + key = skip || dir, + checkNonElements = base && key === "parentNode", + doneName = done++; + + return combinator.first ? + + // Check against closest ancestor/preceding element + function( elem, context, xml ) { + while ( ( elem = elem[ dir ] ) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + return matcher( elem, context, xml ); + } + } + return false; + } : + + // Check against all ancestor/preceding elements + function( elem, context, xml ) { + var oldCache, outerCache, + newCache = [ dirruns, doneName ]; + + // We can't set arbitrary data on XML nodes, so they don't benefit from combinator caching + if ( xml ) { + while ( ( elem = elem[ dir ] ) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + if ( matcher( elem, context, xml ) ) { + return true; + } + } + } + } else { + while ( ( elem = elem[ dir ] ) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + outerCache = elem[ expando ] || ( elem[ expando ] = {} ); + + if ( skip && nodeName( elem, skip ) ) { + elem = elem[ dir ] || elem; + } else if ( ( oldCache = outerCache[ key ] ) && + oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) { + + // Assign to newCache so results back-propagate to previous elements + return ( newCache[ 2 ] = oldCache[ 2 ] ); + } else { + + // Reuse newcache so results back-propagate to previous elements + outerCache[ key ] = newCache; + + // A match means we're done; a fail means we have to keep checking + if ( ( newCache[ 2 ] = matcher( elem, context, xml ) ) ) { + return true; + } + } + } + } + } + return false; + }; +} + +function elementMatcher( matchers ) { + return matchers.length > 1 ? + function( elem, context, xml ) { + var i = matchers.length; + while ( i-- ) { + if ( !matchers[ i ]( elem, context, xml ) ) { + return false; + } + } + return true; + } : + matchers[ 0 ]; +} + +function multipleContexts( selector, contexts, results ) { + var i = 0, + len = contexts.length; + for ( ; i < len; i++ ) { + find( selector, contexts[ i ], results ); + } + return results; +} + +function condense( unmatched, map, filter, context, xml ) { + var elem, + newUnmatched = [], + i = 0, + len = unmatched.length, + mapped = map != null; + + for ( ; i < len; i++ ) { + if ( ( elem = unmatched[ i ] ) ) { + if ( !filter || filter( elem, context, xml ) ) { + newUnmatched.push( elem ); + if ( mapped ) { + map.push( i ); + } + } + } + } + + return newUnmatched; +} + +function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) { + if ( postFilter && !postFilter[ expando ] ) { + postFilter = setMatcher( postFilter ); + } + if ( postFinder && !postFinder[ expando ] ) { + postFinder = setMatcher( postFinder, postSelector ); + } + return markFunction( function( seed, results, context, xml ) { + var temp, i, elem, matcherOut, + preMap = [], + postMap = [], + preexisting = results.length, + + // Get initial elements from seed or context + elems = seed || + multipleContexts( selector || "*", + context.nodeType ? [ context ] : context, [] ), + + // Prefilter to get matcher input, preserving a map for seed-results synchronization + matcherIn = preFilter && ( seed || !selector ) ? + condense( elems, preMap, preFilter, context, xml ) : + elems; + + if ( matcher ) { + + // If we have a postFinder, or filtered seed, or non-seed postFilter + // or preexisting results, + matcherOut = postFinder || ( seed ? preFilter : preexisting || postFilter ) ? + + // ...intermediate processing is necessary + [] : + + // ...otherwise use results directly + results; + + // Find primary matches + matcher( matcherIn, matcherOut, context, xml ); + } else { + matcherOut = matcherIn; + } + + // Apply postFilter + if ( postFilter ) { + temp = condense( matcherOut, postMap ); + postFilter( temp, [], context, xml ); + + // Un-match failing elements by moving them back to matcherIn + i = temp.length; + while ( i-- ) { + if ( ( elem = temp[ i ] ) ) { + matcherOut[ postMap[ i ] ] = !( matcherIn[ postMap[ i ] ] = elem ); + } + } + } + + if ( seed ) { + if ( postFinder || preFilter ) { + if ( postFinder ) { + + // Get the final matcherOut by condensing this intermediate into postFinder contexts + temp = []; + i = matcherOut.length; + while ( i-- ) { + if ( ( elem = matcherOut[ i ] ) ) { + + // Restore matcherIn since elem is not yet a final match + temp.push( ( matcherIn[ i ] = elem ) ); + } + } + postFinder( null, ( matcherOut = [] ), temp, xml ); + } + + // Move matched elements from seed to results to keep them synchronized + i = matcherOut.length; + while ( i-- ) { + if ( ( elem = matcherOut[ i ] ) && + ( temp = postFinder ? indexOf.call( seed, elem ) : preMap[ i ] ) > -1 ) { + + seed[ temp ] = !( results[ temp ] = elem ); + } + } + } + + // Add elements to results, through postFinder if defined + } else { + matcherOut = condense( + matcherOut === results ? + matcherOut.splice( preexisting, matcherOut.length ) : + matcherOut + ); + if ( postFinder ) { + postFinder( null, results, matcherOut, xml ); + } else { + push.apply( results, matcherOut ); + } + } + } ); +} + +function matcherFromTokens( tokens ) { + var checkContext, matcher, j, + len = tokens.length, + leadingRelative = Expr.relative[ tokens[ 0 ].type ], + implicitRelative = leadingRelative || Expr.relative[ " " ], + i = leadingRelative ? 1 : 0, + + // The foundational matcher ensures that elements are reachable from top-level context(s) + matchContext = addCombinator( function( elem ) { + return elem === checkContext; + }, implicitRelative, true ), + matchAnyContext = addCombinator( function( elem ) { + return indexOf.call( checkContext, elem ) > -1; + }, implicitRelative, true ), + matchers = [ function( elem, context, xml ) { + + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + var ret = ( !leadingRelative && ( xml || context != outermostContext ) ) || ( + ( checkContext = context ).nodeType ? + matchContext( elem, context, xml ) : + matchAnyContext( elem, context, xml ) ); + + // Avoid hanging onto element + // (see https://github.com/jquery/sizzle/issues/299) + checkContext = null; + return ret; + } ]; + + for ( ; i < len; i++ ) { + if ( ( matcher = Expr.relative[ tokens[ i ].type ] ) ) { + matchers = [ addCombinator( elementMatcher( matchers ), matcher ) ]; + } else { + matcher = Expr.filter[ tokens[ i ].type ].apply( null, tokens[ i ].matches ); + + // Return special upon seeing a positional matcher + if ( matcher[ expando ] ) { + + // Find the next relative operator (if any) for proper handling + j = ++i; + for ( ; j < len; j++ ) { + if ( Expr.relative[ tokens[ j ].type ] ) { + break; + } + } + return setMatcher( + i > 1 && elementMatcher( matchers ), + i > 1 && toSelector( + + // If the preceding token was a descendant combinator, insert an implicit any-element `*` + tokens.slice( 0, i - 1 ) + .concat( { value: tokens[ i - 2 ].type === " " ? "*" : "" } ) + ).replace( rtrimCSS, "$1" ), + matcher, + i < j && matcherFromTokens( tokens.slice( i, j ) ), + j < len && matcherFromTokens( ( tokens = tokens.slice( j ) ) ), + j < len && toSelector( tokens ) + ); + } + matchers.push( matcher ); + } + } + + return elementMatcher( matchers ); +} + +function matcherFromGroupMatchers( elementMatchers, setMatchers ) { + var bySet = setMatchers.length > 0, + byElement = elementMatchers.length > 0, + superMatcher = function( seed, context, xml, results, outermost ) { + var elem, j, matcher, + matchedCount = 0, + i = "0", + unmatched = seed && [], + setMatched = [], + contextBackup = outermostContext, + + // We must always have either seed elements or outermost context + elems = seed || byElement && Expr.find.TAG( "*", outermost ), + + // Use integer dirruns iff this is the outermost matcher + dirrunsUnique = ( dirruns += contextBackup == null ? 1 : Math.random() || 0.1 ), + len = elems.length; + + if ( outermost ) { + + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + outermostContext = context == document || context || outermost; + } + + // Add elements passing elementMatchers directly to results + // Support: iOS <=7 - 9 only + // Tolerate NodeList properties (IE: "length"; Safari: ) matching + // elements by id. (see trac-14142) + for ( ; i !== len && ( elem = elems[ i ] ) != null; i++ ) { + if ( byElement && elem ) { + j = 0; + + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( !context && elem.ownerDocument != document ) { + setDocument( elem ); + xml = !documentIsHTML; + } + while ( ( matcher = elementMatchers[ j++ ] ) ) { + if ( matcher( elem, context || document, xml ) ) { + push.call( results, elem ); + break; + } + } + if ( outermost ) { + dirruns = dirrunsUnique; + } + } + + // Track unmatched elements for set filters + if ( bySet ) { + + // They will have gone through all possible matchers + if ( ( elem = !matcher && elem ) ) { + matchedCount--; + } + + // Lengthen the array for every element, matched or not + if ( seed ) { + unmatched.push( elem ); + } + } + } + + // `i` is now the count of elements visited above, and adding it to `matchedCount` + // makes the latter nonnegative. + matchedCount += i; + + // Apply set filters to unmatched elements + // NOTE: This can be skipped if there are no unmatched elements (i.e., `matchedCount` + // equals `i`), unless we didn't visit _any_ elements in the above loop because we have + // no element matchers and no seed. + // Incrementing an initially-string "0" `i` allows `i` to remain a string only in that + // case, which will result in a "00" `matchedCount` that differs from `i` but is also + // numerically zero. + if ( bySet && i !== matchedCount ) { + j = 0; + while ( ( matcher = setMatchers[ j++ ] ) ) { + matcher( unmatched, setMatched, context, xml ); + } + + if ( seed ) { + + // Reintegrate element matches to eliminate the need for sorting + if ( matchedCount > 0 ) { + while ( i-- ) { + if ( !( unmatched[ i ] || setMatched[ i ] ) ) { + setMatched[ i ] = pop.call( results ); + } + } + } + + // Discard index placeholder values to get only actual matches + setMatched = condense( setMatched ); + } + + // Add matches to results + push.apply( results, setMatched ); + + // Seedless set matches succeeding multiple successful matchers stipulate sorting + if ( outermost && !seed && setMatched.length > 0 && + ( matchedCount + setMatchers.length ) > 1 ) { + + jQuery.uniqueSort( results ); + } + } + + // Override manipulation of globals by nested matchers + if ( outermost ) { + dirruns = dirrunsUnique; + outermostContext = contextBackup; + } + + return unmatched; + }; + + return bySet ? + markFunction( superMatcher ) : + superMatcher; +} + +function compile( selector, match /* Internal Use Only */ ) { + var i, + setMatchers = [], + elementMatchers = [], + cached = compilerCache[ selector + " " ]; + + if ( !cached ) { + + // Generate a function of recursive functions that can be used to check each element + if ( !match ) { + match = tokenize( selector ); + } + i = match.length; + while ( i-- ) { + cached = matcherFromTokens( match[ i ] ); + if ( cached[ expando ] ) { + setMatchers.push( cached ); + } else { + elementMatchers.push( cached ); + } + } + + // Cache the compiled function + cached = compilerCache( selector, + matcherFromGroupMatchers( elementMatchers, setMatchers ) ); + + // Save selector and tokenization + cached.selector = selector; + } + return cached; +} + +/** + * A low-level selection function that works with jQuery's compiled + * selector functions + * @param {String|Function} selector A selector or a pre-compiled + * selector function built with jQuery selector compile + * @param {Element} context + * @param {Array} [results] + * @param {Array} [seed] A set of elements to match against + */ +function select( selector, context, results, seed ) { + var i, tokens, token, type, find, + compiled = typeof selector === "function" && selector, + match = !seed && tokenize( ( selector = compiled.selector || selector ) ); + + results = results || []; + + // Try to minimize operations if there is only one selector in the list and no seed + // (the latter of which guarantees us context) + if ( match.length === 1 ) { + + // Reduce context if the leading compound selector is an ID + tokens = match[ 0 ] = match[ 0 ].slice( 0 ); + if ( tokens.length > 2 && ( token = tokens[ 0 ] ).type === "ID" && + context.nodeType === 9 && documentIsHTML && Expr.relative[ tokens[ 1 ].type ] ) { + + context = ( Expr.find.ID( + token.matches[ 0 ].replace( runescape, funescape ), + context + ) || [] )[ 0 ]; + if ( !context ) { + return results; + + // Precompiled matchers will still verify ancestry, so step up a level + } else if ( compiled ) { + context = context.parentNode; + } + + selector = selector.slice( tokens.shift().value.length ); + } + + // Fetch a seed set for right-to-left matching + i = matchExpr.needsContext.test( selector ) ? 0 : tokens.length; + while ( i-- ) { + token = tokens[ i ]; + + // Abort if we hit a combinator + if ( Expr.relative[ ( type = token.type ) ] ) { + break; + } + if ( ( find = Expr.find[ type ] ) ) { + + // Search, expanding context for leading sibling combinators + if ( ( seed = find( + token.matches[ 0 ].replace( runescape, funescape ), + rsibling.test( tokens[ 0 ].type ) && + testContext( context.parentNode ) || context + ) ) ) { + + // If seed is empty or no tokens remain, we can return early + tokens.splice( i, 1 ); + selector = seed.length && toSelector( tokens ); + if ( !selector ) { + push.apply( results, seed ); + return results; + } + + break; + } + } + } + } + + // Compile and execute a filtering function if one is not provided + // Provide `match` to avoid retokenization if we modified the selector above + ( compiled || compile( selector, match ) )( + seed, + context, + !documentIsHTML, + results, + !context || rsibling.test( selector ) && testContext( context.parentNode ) || context + ); + return results; +} + +// One-time assignments + +// Support: Android <=4.0 - 4.1+ +// Sort stability +support.sortStable = expando.split( "" ).sort( sortOrder ).join( "" ) === expando; + +// Initialize against the default document +setDocument(); + +// Support: Android <=4.0 - 4.1+ +// Detached nodes confoundingly follow *each other* +support.sortDetached = assert( function( el ) { + + // Should return 1, but returns 4 (following) + return el.compareDocumentPosition( document.createElement( "fieldset" ) ) & 1; +} ); + +jQuery.find = find; + +// Deprecated +jQuery.expr[ ":" ] = jQuery.expr.pseudos; +jQuery.unique = jQuery.uniqueSort; + +// These have always been private, but they used to be documented as part of +// Sizzle so let's maintain them for now for backwards compatibility purposes. +find.compile = compile; +find.select = select; +find.setDocument = setDocument; +find.tokenize = tokenize; + +find.escape = jQuery.escapeSelector; +find.getText = jQuery.text; +find.isXML = jQuery.isXMLDoc; +find.selectors = jQuery.expr; +find.support = jQuery.support; +find.uniqueSort = jQuery.uniqueSort; + + /* eslint-enable */ + +} )(); + + +var dir = function( elem, dir, until ) { + var matched = [], + truncate = until !== undefined; + + while ( ( elem = elem[ dir ] ) && elem.nodeType !== 9 ) { + if ( elem.nodeType === 1 ) { + if ( truncate && jQuery( elem ).is( until ) ) { + break; + } + matched.push( elem ); + } + } + return matched; +}; + + +var siblings = function( n, elem ) { + var matched = []; + + for ( ; n; n = n.nextSibling ) { + if ( n.nodeType === 1 && n !== elem ) { + matched.push( n ); + } + } + + return matched; +}; + + +var rneedsContext = jQuery.expr.match.needsContext; + +var rsingleTag = ( /^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i ); + + + +// Implement the identical functionality for filter and not +function winnow( elements, qualifier, not ) { + if ( isFunction( qualifier ) ) { + return jQuery.grep( elements, function( elem, i ) { + return !!qualifier.call( elem, i, elem ) !== not; + } ); + } + + // Single element + if ( qualifier.nodeType ) { + return jQuery.grep( elements, function( elem ) { + return ( elem === qualifier ) !== not; + } ); + } + + // Arraylike of elements (jQuery, arguments, Array) + if ( typeof qualifier !== "string" ) { + return jQuery.grep( elements, function( elem ) { + return ( indexOf.call( qualifier, elem ) > -1 ) !== not; + } ); + } + + // Filtered directly for both simple and complex selectors + return jQuery.filter( qualifier, elements, not ); +} + +jQuery.filter = function( expr, elems, not ) { + var elem = elems[ 0 ]; + + if ( not ) { + expr = ":not(" + expr + ")"; + } + + if ( elems.length === 1 && elem.nodeType === 1 ) { + return jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : []; + } + + return jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) { + return elem.nodeType === 1; + } ) ); +}; + +jQuery.fn.extend( { + find: function( selector ) { + var i, ret, + len = this.length, + self = this; + + if ( typeof selector !== "string" ) { + return this.pushStack( jQuery( selector ).filter( function() { + for ( i = 0; i < len; i++ ) { + if ( jQuery.contains( self[ i ], this ) ) { + return true; + } + } + } ) ); + } + + ret = this.pushStack( [] ); + + for ( i = 0; i < len; i++ ) { + jQuery.find( selector, self[ i ], ret ); + } + + return len > 1 ? jQuery.uniqueSort( ret ) : ret; + }, + filter: function( selector ) { + return this.pushStack( winnow( this, selector || [], false ) ); + }, + not: function( selector ) { + return this.pushStack( winnow( this, selector || [], true ) ); + }, + is: function( selector ) { + return !!winnow( + this, + + // If this is a positional/relative selector, check membership in the returned set + // so $("p:first").is("p:last") won't return true for a doc with two "p". + typeof selector === "string" && rneedsContext.test( selector ) ? + jQuery( selector ) : + selector || [], + false + ).length; + } +} ); + + +// Initialize a jQuery object + + +// A central reference to the root jQuery(document) +var rootjQuery, + + // A simple way to check for HTML strings + // Prioritize #id over to avoid XSS via location.hash (trac-9521) + // Strict HTML recognition (trac-11290: must start with <) + // Shortcut simple #id case for speed + rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/, + + init = jQuery.fn.init = function( selector, context, root ) { + var match, elem; + + // HANDLE: $(""), $(null), $(undefined), $(false) + if ( !selector ) { + return this; + } + + // Method init() accepts an alternate rootjQuery + // so migrate can support jQuery.sub (gh-2101) + root = root || rootjQuery; + + // Handle HTML strings + if ( typeof selector === "string" ) { + if ( selector[ 0 ] === "<" && + selector[ selector.length - 1 ] === ">" && + selector.length >= 3 ) { + + // Assume that strings that start and end with <> are HTML and skip the regex check + match = [ null, selector, null ]; + + } else { + match = rquickExpr.exec( selector ); + } + + // Match html or make sure no context is specified for #id + if ( match && ( match[ 1 ] || !context ) ) { + + // HANDLE: $(html) -> $(array) + if ( match[ 1 ] ) { + context = context instanceof jQuery ? context[ 0 ] : context; + + // Option to run scripts is true for back-compat + // Intentionally let the error be thrown if parseHTML is not present + jQuery.merge( this, jQuery.parseHTML( + match[ 1 ], + context && context.nodeType ? context.ownerDocument || context : document, + true + ) ); + + // HANDLE: $(html, props) + if ( rsingleTag.test( match[ 1 ] ) && jQuery.isPlainObject( context ) ) { + for ( match in context ) { + + // Properties of context are called as methods if possible + if ( isFunction( this[ match ] ) ) { + this[ match ]( context[ match ] ); + + // ...and otherwise set as attributes + } else { + this.attr( match, context[ match ] ); + } + } + } + + return this; + + // HANDLE: $(#id) + } else { + elem = document.getElementById( match[ 2 ] ); + + if ( elem ) { + + // Inject the element directly into the jQuery object + this[ 0 ] = elem; + this.length = 1; + } + return this; + } + + // HANDLE: $(expr, $(...)) + } else if ( !context || context.jquery ) { + return ( context || root ).find( selector ); + + // HANDLE: $(expr, context) + // (which is just equivalent to: $(context).find(expr) + } else { + return this.constructor( context ).find( selector ); + } + + // HANDLE: $(DOMElement) + } else if ( selector.nodeType ) { + this[ 0 ] = selector; + this.length = 1; + return this; + + // HANDLE: $(function) + // Shortcut for document ready + } else if ( isFunction( selector ) ) { + return root.ready !== undefined ? + root.ready( selector ) : + + // Execute immediately if ready is not present + selector( jQuery ); + } + + return jQuery.makeArray( selector, this ); + }; + +// Give the init function the jQuery prototype for later instantiation +init.prototype = jQuery.fn; + +// Initialize central reference +rootjQuery = jQuery( document ); + + +var rparentsprev = /^(?:parents|prev(?:Until|All))/, + + // Methods guaranteed to produce a unique set when starting from a unique set + guaranteedUnique = { + children: true, + contents: true, + next: true, + prev: true + }; + +jQuery.fn.extend( { + has: function( target ) { + var targets = jQuery( target, this ), + l = targets.length; + + return this.filter( function() { + var i = 0; + for ( ; i < l; i++ ) { + if ( jQuery.contains( this, targets[ i ] ) ) { + return true; + } + } + } ); + }, + + closest: function( selectors, context ) { + var cur, + i = 0, + l = this.length, + matched = [], + targets = typeof selectors !== "string" && jQuery( selectors ); + + // Positional selectors never match, since there's no _selection_ context + if ( !rneedsContext.test( selectors ) ) { + for ( ; i < l; i++ ) { + for ( cur = this[ i ]; cur && cur !== context; cur = cur.parentNode ) { + + // Always skip document fragments + if ( cur.nodeType < 11 && ( targets ? + targets.index( cur ) > -1 : + + // Don't pass non-elements to jQuery#find + cur.nodeType === 1 && + jQuery.find.matchesSelector( cur, selectors ) ) ) { + + matched.push( cur ); + break; + } + } + } + } + + return this.pushStack( matched.length > 1 ? jQuery.uniqueSort( matched ) : matched ); + }, + + // Determine the position of an element within the set + index: function( elem ) { + + // No argument, return index in parent + if ( !elem ) { + return ( this[ 0 ] && this[ 0 ].parentNode ) ? this.first().prevAll().length : -1; + } + + // Index in selector + if ( typeof elem === "string" ) { + return indexOf.call( jQuery( elem ), this[ 0 ] ); + } + + // Locate the position of the desired element + return indexOf.call( this, + + // If it receives a jQuery object, the first element is used + elem.jquery ? elem[ 0 ] : elem + ); + }, + + add: function( selector, context ) { + return this.pushStack( + jQuery.uniqueSort( + jQuery.merge( this.get(), jQuery( selector, context ) ) + ) + ); + }, + + addBack: function( selector ) { + return this.add( selector == null ? + this.prevObject : this.prevObject.filter( selector ) + ); + } +} ); + +function sibling( cur, dir ) { + while ( ( cur = cur[ dir ] ) && cur.nodeType !== 1 ) {} + return cur; +} + +jQuery.each( { + parent: function( elem ) { + var parent = elem.parentNode; + return parent && parent.nodeType !== 11 ? parent : null; + }, + parents: function( elem ) { + return dir( elem, "parentNode" ); + }, + parentsUntil: function( elem, _i, until ) { + return dir( elem, "parentNode", until ); + }, + next: function( elem ) { + return sibling( elem, "nextSibling" ); + }, + prev: function( elem ) { + return sibling( elem, "previousSibling" ); + }, + nextAll: function( elem ) { + return dir( elem, "nextSibling" ); + }, + prevAll: function( elem ) { + return dir( elem, "previousSibling" ); + }, + nextUntil: function( elem, _i, until ) { + return dir( elem, "nextSibling", until ); + }, + prevUntil: function( elem, _i, until ) { + return dir( elem, "previousSibling", until ); + }, + siblings: function( elem ) { + return siblings( ( elem.parentNode || {} ).firstChild, elem ); + }, + children: function( elem ) { + return siblings( elem.firstChild ); + }, + contents: function( elem ) { + if ( elem.contentDocument != null && + + // Support: IE 11+ + // elements with no `data` attribute has an object + // `contentDocument` with a `null` prototype. + getProto( elem.contentDocument ) ) { + + return elem.contentDocument; + } + + // Support: IE 9 - 11 only, iOS 7 only, Android Browser <=4.3 only + // Treat the template element as a regular one in browsers that + // don't support it. + if ( nodeName( elem, "template" ) ) { + elem = elem.content || elem; + } + + return jQuery.merge( [], elem.childNodes ); + } +}, function( name, fn ) { + jQuery.fn[ name ] = function( until, selector ) { + var matched = jQuery.map( this, fn, until ); + + if ( name.slice( -5 ) !== "Until" ) { + selector = until; + } + + if ( selector && typeof selector === "string" ) { + matched = jQuery.filter( selector, matched ); + } + + if ( this.length > 1 ) { + + // Remove duplicates + if ( !guaranteedUnique[ name ] ) { + jQuery.uniqueSort( matched ); + } + + // Reverse order for parents* and prev-derivatives + if ( rparentsprev.test( name ) ) { + matched.reverse(); + } + } + + return this.pushStack( matched ); + }; +} ); +var rnothtmlwhite = ( /[^\x20\t\r\n\f]+/g ); + + + +// Convert String-formatted options into Object-formatted ones +function createOptions( options ) { + var object = {}; + jQuery.each( options.match( rnothtmlwhite ) || [], function( _, flag ) { + object[ flag ] = true; + } ); + return object; +} + +/* + * Create a callback list using the following parameters: + * + * options: an optional list of space-separated options that will change how + * the callback list behaves or a more traditional option object + * + * By default a callback list will act like an event callback list and can be + * "fired" multiple times. + * + * Possible options: + * + * once: will ensure the callback list can only be fired once (like a Deferred) + * + * memory: will keep track of previous values and will call any callback added + * after the list has been fired right away with the latest "memorized" + * values (like a Deferred) + * + * unique: will ensure a callback can only be added once (no duplicate in the list) + * + * stopOnFalse: interrupt callings when a callback returns false + * + */ +jQuery.Callbacks = function( options ) { + + // Convert options from String-formatted to Object-formatted if needed + // (we check in cache first) + options = typeof options === "string" ? + createOptions( options ) : + jQuery.extend( {}, options ); + + var // Flag to know if list is currently firing + firing, + + // Last fire value for non-forgettable lists + memory, + + // Flag to know if list was already fired + fired, + + // Flag to prevent firing + locked, + + // Actual callback list + list = [], + + // Queue of execution data for repeatable lists + queue = [], + + // Index of currently firing callback (modified by add/remove as needed) + firingIndex = -1, + + // Fire callbacks + fire = function() { + + // Enforce single-firing + locked = locked || options.once; + + // Execute callbacks for all pending executions, + // respecting firingIndex overrides and runtime changes + fired = firing = true; + for ( ; queue.length; firingIndex = -1 ) { + memory = queue.shift(); + while ( ++firingIndex < list.length ) { + + // Run callback and check for early termination + if ( list[ firingIndex ].apply( memory[ 0 ], memory[ 1 ] ) === false && + options.stopOnFalse ) { + + // Jump to end and forget the data so .add doesn't re-fire + firingIndex = list.length; + memory = false; + } + } + } + + // Forget the data if we're done with it + if ( !options.memory ) { + memory = false; + } + + firing = false; + + // Clean up if we're done firing for good + if ( locked ) { + + // Keep an empty list if we have data for future add calls + if ( memory ) { + list = []; + + // Otherwise, this object is spent + } else { + list = ""; + } + } + }, + + // Actual Callbacks object + self = { + + // Add a callback or a collection of callbacks to the list + add: function() { + if ( list ) { + + // If we have memory from a past run, we should fire after adding + if ( memory && !firing ) { + firingIndex = list.length - 1; + queue.push( memory ); + } + + ( function add( args ) { + jQuery.each( args, function( _, arg ) { + if ( isFunction( arg ) ) { + if ( !options.unique || !self.has( arg ) ) { + list.push( arg ); + } + } else if ( arg && arg.length && toType( arg ) !== "string" ) { + + // Inspect recursively + add( arg ); + } + } ); + } )( arguments ); + + if ( memory && !firing ) { + fire(); + } + } + return this; + }, + + // Remove a callback from the list + remove: function() { + jQuery.each( arguments, function( _, arg ) { + var index; + while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) { + list.splice( index, 1 ); + + // Handle firing indexes + if ( index <= firingIndex ) { + firingIndex--; + } + } + } ); + return this; + }, + + // Check if a given callback is in the list. + // If no argument is given, return whether or not list has callbacks attached. + has: function( fn ) { + return fn ? + jQuery.inArray( fn, list ) > -1 : + list.length > 0; + }, + + // Remove all callbacks from the list + empty: function() { + if ( list ) { + list = []; + } + return this; + }, + + // Disable .fire and .add + // Abort any current/pending executions + // Clear all callbacks and values + disable: function() { + locked = queue = []; + list = memory = ""; + return this; + }, + disabled: function() { + return !list; + }, + + // Disable .fire + // Also disable .add unless we have memory (since it would have no effect) + // Abort any pending executions + lock: function() { + locked = queue = []; + if ( !memory && !firing ) { + list = memory = ""; + } + return this; + }, + locked: function() { + return !!locked; + }, + + // Call all callbacks with the given context and arguments + fireWith: function( context, args ) { + if ( !locked ) { + args = args || []; + args = [ context, args.slice ? args.slice() : args ]; + queue.push( args ); + if ( !firing ) { + fire(); + } + } + return this; + }, + + // Call all the callbacks with the given arguments + fire: function() { + self.fireWith( this, arguments ); + return this; + }, + + // To know if the callbacks have already been called at least once + fired: function() { + return !!fired; + } + }; + + return self; +}; + + +function Identity( v ) { + return v; +} +function Thrower( ex ) { + throw ex; +} + +function adoptValue( value, resolve, reject, noValue ) { + var method; + + try { + + // Check for promise aspect first to privilege synchronous behavior + if ( value && isFunction( ( method = value.promise ) ) ) { + method.call( value ).done( resolve ).fail( reject ); + + // Other thenables + } else if ( value && isFunction( ( method = value.then ) ) ) { + method.call( value, resolve, reject ); + + // Other non-thenables + } else { + + // Control `resolve` arguments by letting Array#slice cast boolean `noValue` to integer: + // * false: [ value ].slice( 0 ) => resolve( value ) + // * true: [ value ].slice( 1 ) => resolve() + resolve.apply( undefined, [ value ].slice( noValue ) ); + } + + // For Promises/A+, convert exceptions into rejections + // Since jQuery.when doesn't unwrap thenables, we can skip the extra checks appearing in + // Deferred#then to conditionally suppress rejection. + } catch ( value ) { + + // Support: Android 4.0 only + // Strict mode functions invoked without .call/.apply get global-object context + reject.apply( undefined, [ value ] ); + } +} + +jQuery.extend( { + + Deferred: function( func ) { + var tuples = [ + + // action, add listener, callbacks, + // ... .then handlers, argument index, [final state] + [ "notify", "progress", jQuery.Callbacks( "memory" ), + jQuery.Callbacks( "memory" ), 2 ], + [ "resolve", "done", jQuery.Callbacks( "once memory" ), + jQuery.Callbacks( "once memory" ), 0, "resolved" ], + [ "reject", "fail", jQuery.Callbacks( "once memory" ), + jQuery.Callbacks( "once memory" ), 1, "rejected" ] + ], + state = "pending", + promise = { + state: function() { + return state; + }, + always: function() { + deferred.done( arguments ).fail( arguments ); + return this; + }, + "catch": function( fn ) { + return promise.then( null, fn ); + }, + + // Keep pipe for back-compat + pipe: function( /* fnDone, fnFail, fnProgress */ ) { + var fns = arguments; + + return jQuery.Deferred( function( newDefer ) { + jQuery.each( tuples, function( _i, tuple ) { + + // Map tuples (progress, done, fail) to arguments (done, fail, progress) + var fn = isFunction( fns[ tuple[ 4 ] ] ) && fns[ tuple[ 4 ] ]; + + // deferred.progress(function() { bind to newDefer or newDefer.notify }) + // deferred.done(function() { bind to newDefer or newDefer.resolve }) + // deferred.fail(function() { bind to newDefer or newDefer.reject }) + deferred[ tuple[ 1 ] ]( function() { + var returned = fn && fn.apply( this, arguments ); + if ( returned && isFunction( returned.promise ) ) { + returned.promise() + .progress( newDefer.notify ) + .done( newDefer.resolve ) + .fail( newDefer.reject ); + } else { + newDefer[ tuple[ 0 ] + "With" ]( + this, + fn ? [ returned ] : arguments + ); + } + } ); + } ); + fns = null; + } ).promise(); + }, + then: function( onFulfilled, onRejected, onProgress ) { + var maxDepth = 0; + function resolve( depth, deferred, handler, special ) { + return function() { + var that = this, + args = arguments, + mightThrow = function() { + var returned, then; + + // Support: Promises/A+ section 2.3.3.3.3 + // https://promisesaplus.com/#point-59 + // Ignore double-resolution attempts + if ( depth < maxDepth ) { + return; + } + + returned = handler.apply( that, args ); + + // Support: Promises/A+ section 2.3.1 + // https://promisesaplus.com/#point-48 + if ( returned === deferred.promise() ) { + throw new TypeError( "Thenable self-resolution" ); + } + + // Support: Promises/A+ sections 2.3.3.1, 3.5 + // https://promisesaplus.com/#point-54 + // https://promisesaplus.com/#point-75 + // Retrieve `then` only once + then = returned && + + // Support: Promises/A+ section 2.3.4 + // https://promisesaplus.com/#point-64 + // Only check objects and functions for thenability + ( typeof returned === "object" || + typeof returned === "function" ) && + returned.then; + + // Handle a returned thenable + if ( isFunction( then ) ) { + + // Special processors (notify) just wait for resolution + if ( special ) { + then.call( + returned, + resolve( maxDepth, deferred, Identity, special ), + resolve( maxDepth, deferred, Thrower, special ) + ); + + // Normal processors (resolve) also hook into progress + } else { + + // ...and disregard older resolution values + maxDepth++; + + then.call( + returned, + resolve( maxDepth, deferred, Identity, special ), + resolve( maxDepth, deferred, Thrower, special ), + resolve( maxDepth, deferred, Identity, + deferred.notifyWith ) + ); + } + + // Handle all other returned values + } else { + + // Only substitute handlers pass on context + // and multiple values (non-spec behavior) + if ( handler !== Identity ) { + that = undefined; + args = [ returned ]; + } + + // Process the value(s) + // Default process is resolve + ( special || deferred.resolveWith )( that, args ); + } + }, + + // Only normal processors (resolve) catch and reject exceptions + process = special ? + mightThrow : + function() { + try { + mightThrow(); + } catch ( e ) { + + if ( jQuery.Deferred.exceptionHook ) { + jQuery.Deferred.exceptionHook( e, + process.error ); + } + + // Support: Promises/A+ section 2.3.3.3.4.1 + // https://promisesaplus.com/#point-61 + // Ignore post-resolution exceptions + if ( depth + 1 >= maxDepth ) { + + // Only substitute handlers pass on context + // and multiple values (non-spec behavior) + if ( handler !== Thrower ) { + that = undefined; + args = [ e ]; + } + + deferred.rejectWith( that, args ); + } + } + }; + + // Support: Promises/A+ section 2.3.3.3.1 + // https://promisesaplus.com/#point-57 + // Re-resolve promises immediately to dodge false rejection from + // subsequent errors + if ( depth ) { + process(); + } else { + + // Call an optional hook to record the error, in case of exception + // since it's otherwise lost when execution goes async + if ( jQuery.Deferred.getErrorHook ) { + process.error = jQuery.Deferred.getErrorHook(); + + // The deprecated alias of the above. While the name suggests + // returning the stack, not an error instance, jQuery just passes + // it directly to `console.warn` so both will work; an instance + // just better cooperates with source maps. + } else if ( jQuery.Deferred.getStackHook ) { + process.error = jQuery.Deferred.getStackHook(); + } + window.setTimeout( process ); + } + }; + } + + return jQuery.Deferred( function( newDefer ) { + + // progress_handlers.add( ... ) + tuples[ 0 ][ 3 ].add( + resolve( + 0, + newDefer, + isFunction( onProgress ) ? + onProgress : + Identity, + newDefer.notifyWith + ) + ); + + // fulfilled_handlers.add( ... ) + tuples[ 1 ][ 3 ].add( + resolve( + 0, + newDefer, + isFunction( onFulfilled ) ? + onFulfilled : + Identity + ) + ); + + // rejected_handlers.add( ... ) + tuples[ 2 ][ 3 ].add( + resolve( + 0, + newDefer, + isFunction( onRejected ) ? + onRejected : + Thrower + ) + ); + } ).promise(); + }, + + // Get a promise for this deferred + // If obj is provided, the promise aspect is added to the object + promise: function( obj ) { + return obj != null ? jQuery.extend( obj, promise ) : promise; + } + }, + deferred = {}; + + // Add list-specific methods + jQuery.each( tuples, function( i, tuple ) { + var list = tuple[ 2 ], + stateString = tuple[ 5 ]; + + // promise.progress = list.add + // promise.done = list.add + // promise.fail = list.add + promise[ tuple[ 1 ] ] = list.add; + + // Handle state + if ( stateString ) { + list.add( + function() { + + // state = "resolved" (i.e., fulfilled) + // state = "rejected" + state = stateString; + }, + + // rejected_callbacks.disable + // fulfilled_callbacks.disable + tuples[ 3 - i ][ 2 ].disable, + + // rejected_handlers.disable + // fulfilled_handlers.disable + tuples[ 3 - i ][ 3 ].disable, + + // progress_callbacks.lock + tuples[ 0 ][ 2 ].lock, + + // progress_handlers.lock + tuples[ 0 ][ 3 ].lock + ); + } + + // progress_handlers.fire + // fulfilled_handlers.fire + // rejected_handlers.fire + list.add( tuple[ 3 ].fire ); + + // deferred.notify = function() { deferred.notifyWith(...) } + // deferred.resolve = function() { deferred.resolveWith(...) } + // deferred.reject = function() { deferred.rejectWith(...) } + deferred[ tuple[ 0 ] ] = function() { + deferred[ tuple[ 0 ] + "With" ]( this === deferred ? undefined : this, arguments ); + return this; + }; + + // deferred.notifyWith = list.fireWith + // deferred.resolveWith = list.fireWith + // deferred.rejectWith = list.fireWith + deferred[ tuple[ 0 ] + "With" ] = list.fireWith; + } ); + + // Make the deferred a promise + promise.promise( deferred ); + + // Call given func if any + if ( func ) { + func.call( deferred, deferred ); + } + + // All done! + return deferred; + }, + + // Deferred helper + when: function( singleValue ) { + var + + // count of uncompleted subordinates + remaining = arguments.length, + + // count of unprocessed arguments + i = remaining, + + // subordinate fulfillment data + resolveContexts = Array( i ), + resolveValues = slice.call( arguments ), + + // the primary Deferred + primary = jQuery.Deferred(), + + // subordinate callback factory + updateFunc = function( i ) { + return function( value ) { + resolveContexts[ i ] = this; + resolveValues[ i ] = arguments.length > 1 ? slice.call( arguments ) : value; + if ( !( --remaining ) ) { + primary.resolveWith( resolveContexts, resolveValues ); + } + }; + }; + + // Single- and empty arguments are adopted like Promise.resolve + if ( remaining <= 1 ) { + adoptValue( singleValue, primary.done( updateFunc( i ) ).resolve, primary.reject, + !remaining ); + + // Use .then() to unwrap secondary thenables (cf. gh-3000) + if ( primary.state() === "pending" || + isFunction( resolveValues[ i ] && resolveValues[ i ].then ) ) { + + return primary.then(); + } + } + + // Multiple arguments are aggregated like Promise.all array elements + while ( i-- ) { + adoptValue( resolveValues[ i ], updateFunc( i ), primary.reject ); + } + + return primary.promise(); + } +} ); + + +// These usually indicate a programmer mistake during development, +// warn about them ASAP rather than swallowing them by default. +var rerrorNames = /^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/; + +// If `jQuery.Deferred.getErrorHook` is defined, `asyncError` is an error +// captured before the async barrier to get the original error cause +// which may otherwise be hidden. +jQuery.Deferred.exceptionHook = function( error, asyncError ) { + + // Support: IE 8 - 9 only + // Console exists when dev tools are open, which can happen at any time + if ( window.console && window.console.warn && error && rerrorNames.test( error.name ) ) { + window.console.warn( "jQuery.Deferred exception: " + error.message, + error.stack, asyncError ); + } +}; + + + + +jQuery.readyException = function( error ) { + window.setTimeout( function() { + throw error; + } ); +}; + + + + +// The deferred used on DOM ready +var readyList = jQuery.Deferred(); + +jQuery.fn.ready = function( fn ) { + + readyList + .then( fn ) + + // Wrap jQuery.readyException in a function so that the lookup + // happens at the time of error handling instead of callback + // registration. + .catch( function( error ) { + jQuery.readyException( error ); + } ); + + return this; +}; + +jQuery.extend( { + + // Is the DOM ready to be used? Set to true once it occurs. + isReady: false, + + // A counter to track how many items to wait for before + // the ready event fires. See trac-6781 + readyWait: 1, + + // Handle when the DOM is ready + ready: function( wait ) { + + // Abort if there are pending holds or we're already ready + if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) { + return; + } + + // Remember that the DOM is ready + jQuery.isReady = true; + + // If a normal DOM Ready event fired, decrement, and wait if need be + if ( wait !== true && --jQuery.readyWait > 0 ) { + return; + } + + // If there are functions bound, to execute + readyList.resolveWith( document, [ jQuery ] ); + } +} ); + +jQuery.ready.then = readyList.then; + +// The ready event handler and self cleanup method +function completed() { + document.removeEventListener( "DOMContentLoaded", completed ); + window.removeEventListener( "load", completed ); + jQuery.ready(); +} + +// Catch cases where $(document).ready() is called +// after the browser event has already occurred. +// Support: IE <=9 - 10 only +// Older IE sometimes signals "interactive" too soon +if ( document.readyState === "complete" || + ( document.readyState !== "loading" && !document.documentElement.doScroll ) ) { + + // Handle it asynchronously to allow scripts the opportunity to delay ready + window.setTimeout( jQuery.ready ); + +} else { + + // Use the handy event callback + document.addEventListener( "DOMContentLoaded", completed ); + + // A fallback to window.onload, that will always work + window.addEventListener( "load", completed ); +} + + + + +// Multifunctional method to get and set values of a collection +// The value/s can optionally be executed if it's a function +var access = function( elems, fn, key, value, chainable, emptyGet, raw ) { + var i = 0, + len = elems.length, + bulk = key == null; + + // Sets many values + if ( toType( key ) === "object" ) { + chainable = true; + for ( i in key ) { + access( elems, fn, i, key[ i ], true, emptyGet, raw ); + } + + // Sets one value + } else if ( value !== undefined ) { + chainable = true; + + if ( !isFunction( value ) ) { + raw = true; + } + + if ( bulk ) { + + // Bulk operations run against the entire set + if ( raw ) { + fn.call( elems, value ); + fn = null; + + // ...except when executing function values + } else { + bulk = fn; + fn = function( elem, _key, value ) { + return bulk.call( jQuery( elem ), value ); + }; + } + } + + if ( fn ) { + for ( ; i < len; i++ ) { + fn( + elems[ i ], key, raw ? + value : + value.call( elems[ i ], i, fn( elems[ i ], key ) ) + ); + } + } + } + + if ( chainable ) { + return elems; + } + + // Gets + if ( bulk ) { + return fn.call( elems ); + } + + return len ? fn( elems[ 0 ], key ) : emptyGet; +}; + + +// Matches dashed string for camelizing +var rmsPrefix = /^-ms-/, + rdashAlpha = /-([a-z])/g; + +// Used by camelCase as callback to replace() +function fcamelCase( _all, letter ) { + return letter.toUpperCase(); +} + +// Convert dashed to camelCase; used by the css and data modules +// Support: IE <=9 - 11, Edge 12 - 15 +// Microsoft forgot to hump their vendor prefix (trac-9572) +function camelCase( string ) { + return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); +} +var acceptData = function( owner ) { + + // Accepts only: + // - Node + // - Node.ELEMENT_NODE + // - Node.DOCUMENT_NODE + // - Object + // - Any + return owner.nodeType === 1 || owner.nodeType === 9 || !( +owner.nodeType ); +}; + + + + +function Data() { + this.expando = jQuery.expando + Data.uid++; +} + +Data.uid = 1; + +Data.prototype = { + + cache: function( owner ) { + + // Check if the owner object already has a cache + var value = owner[ this.expando ]; + + // If not, create one + if ( !value ) { + value = {}; + + // We can accept data for non-element nodes in modern browsers, + // but we should not, see trac-8335. + // Always return an empty object. + if ( acceptData( owner ) ) { + + // If it is a node unlikely to be stringify-ed or looped over + // use plain assignment + if ( owner.nodeType ) { + owner[ this.expando ] = value; + + // Otherwise secure it in a non-enumerable property + // configurable must be true to allow the property to be + // deleted when data is removed + } else { + Object.defineProperty( owner, this.expando, { + value: value, + configurable: true + } ); + } + } + } + + return value; + }, + set: function( owner, data, value ) { + var prop, + cache = this.cache( owner ); + + // Handle: [ owner, key, value ] args + // Always use camelCase key (gh-2257) + if ( typeof data === "string" ) { + cache[ camelCase( data ) ] = value; + + // Handle: [ owner, { properties } ] args + } else { + + // Copy the properties one-by-one to the cache object + for ( prop in data ) { + cache[ camelCase( prop ) ] = data[ prop ]; + } + } + return cache; + }, + get: function( owner, key ) { + return key === undefined ? + this.cache( owner ) : + + // Always use camelCase key (gh-2257) + owner[ this.expando ] && owner[ this.expando ][ camelCase( key ) ]; + }, + access: function( owner, key, value ) { + + // In cases where either: + // + // 1. No key was specified + // 2. A string key was specified, but no value provided + // + // Take the "read" path and allow the get method to determine + // which value to return, respectively either: + // + // 1. The entire cache object + // 2. The data stored at the key + // + if ( key === undefined || + ( ( key && typeof key === "string" ) && value === undefined ) ) { + + return this.get( owner, key ); + } + + // When the key is not a string, or both a key and value + // are specified, set or extend (existing objects) with either: + // + // 1. An object of properties + // 2. A key and value + // + this.set( owner, key, value ); + + // Since the "set" path can have two possible entry points + // return the expected data based on which path was taken[*] + return value !== undefined ? value : key; + }, + remove: function( owner, key ) { + var i, + cache = owner[ this.expando ]; + + if ( cache === undefined ) { + return; + } + + if ( key !== undefined ) { + + // Support array or space separated string of keys + if ( Array.isArray( key ) ) { + + // If key is an array of keys... + // We always set camelCase keys, so remove that. + key = key.map( camelCase ); + } else { + key = camelCase( key ); + + // If a key with the spaces exists, use it. + // Otherwise, create an array by matching non-whitespace + key = key in cache ? + [ key ] : + ( key.match( rnothtmlwhite ) || [] ); + } + + i = key.length; + + while ( i-- ) { + delete cache[ key[ i ] ]; + } + } + + // Remove the expando if there's no more data + if ( key === undefined || jQuery.isEmptyObject( cache ) ) { + + // Support: Chrome <=35 - 45 + // Webkit & Blink performance suffers when deleting properties + // from DOM nodes, so set to undefined instead + // https://bugs.chromium.org/p/chromium/issues/detail?id=378607 (bug restricted) + if ( owner.nodeType ) { + owner[ this.expando ] = undefined; + } else { + delete owner[ this.expando ]; + } + } + }, + hasData: function( owner ) { + var cache = owner[ this.expando ]; + return cache !== undefined && !jQuery.isEmptyObject( cache ); + } +}; +var dataPriv = new Data(); + +var dataUser = new Data(); + + + +// Implementation Summary +// +// 1. Enforce API surface and semantic compatibility with 1.9.x branch +// 2. Improve the module's maintainability by reducing the storage +// paths to a single mechanism. +// 3. Use the same single mechanism to support "private" and "user" data. +// 4. _Never_ expose "private" data to user code (TODO: Drop _data, _removeData) +// 5. Avoid exposing implementation details on user objects (eg. expando properties) +// 6. Provide a clear path for implementation upgrade to WeakMap in 2014 + +var rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/, + rmultiDash = /[A-Z]/g; + +function getData( data ) { + if ( data === "true" ) { + return true; + } + + if ( data === "false" ) { + return false; + } + + if ( data === "null" ) { + return null; + } + + // Only convert to a number if it doesn't change the string + if ( data === +data + "" ) { + return +data; + } + + if ( rbrace.test( data ) ) { + return JSON.parse( data ); + } + + return data; +} + +function dataAttr( elem, key, data ) { + var name; + + // If nothing was found internally, try to fetch any + // data from the HTML5 data-* attribute + if ( data === undefined && elem.nodeType === 1 ) { + name = "data-" + key.replace( rmultiDash, "-$&" ).toLowerCase(); + data = elem.getAttribute( name ); + + if ( typeof data === "string" ) { + try { + data = getData( data ); + } catch ( e ) {} + + // Make sure we set the data so it isn't changed later + dataUser.set( elem, key, data ); + } else { + data = undefined; + } + } + return data; +} + +jQuery.extend( { + hasData: function( elem ) { + return dataUser.hasData( elem ) || dataPriv.hasData( elem ); + }, + + data: function( elem, name, data ) { + return dataUser.access( elem, name, data ); + }, + + removeData: function( elem, name ) { + dataUser.remove( elem, name ); + }, + + // TODO: Now that all calls to _data and _removeData have been replaced + // with direct calls to dataPriv methods, these can be deprecated. + _data: function( elem, name, data ) { + return dataPriv.access( elem, name, data ); + }, + + _removeData: function( elem, name ) { + dataPriv.remove( elem, name ); + } +} ); + +jQuery.fn.extend( { + data: function( key, value ) { + var i, name, data, + elem = this[ 0 ], + attrs = elem && elem.attributes; + + // Gets all values + if ( key === undefined ) { + if ( this.length ) { + data = dataUser.get( elem ); + + if ( elem.nodeType === 1 && !dataPriv.get( elem, "hasDataAttrs" ) ) { + i = attrs.length; + while ( i-- ) { + + // Support: IE 11 only + // The attrs elements can be null (trac-14894) + if ( attrs[ i ] ) { + name = attrs[ i ].name; + if ( name.indexOf( "data-" ) === 0 ) { + name = camelCase( name.slice( 5 ) ); + dataAttr( elem, name, data[ name ] ); + } + } + } + dataPriv.set( elem, "hasDataAttrs", true ); + } + } + + return data; + } + + // Sets multiple values + if ( typeof key === "object" ) { + return this.each( function() { + dataUser.set( this, key ); + } ); + } + + return access( this, function( value ) { + var data; + + // The calling jQuery object (element matches) is not empty + // (and therefore has an element appears at this[ 0 ]) and the + // `value` parameter was not undefined. An empty jQuery object + // will result in `undefined` for elem = this[ 0 ] which will + // throw an exception if an attempt to read a data cache is made. + if ( elem && value === undefined ) { + + // Attempt to get data from the cache + // The key will always be camelCased in Data + data = dataUser.get( elem, key ); + if ( data !== undefined ) { + return data; + } + + // Attempt to "discover" the data in + // HTML5 custom data-* attrs + data = dataAttr( elem, key ); + if ( data !== undefined ) { + return data; + } + + // We tried really hard, but the data doesn't exist. + return; + } + + // Set the data... + this.each( function() { + + // We always store the camelCased key + dataUser.set( this, key, value ); + } ); + }, null, value, arguments.length > 1, null, true ); + }, + + removeData: function( key ) { + return this.each( function() { + dataUser.remove( this, key ); + } ); + } +} ); + + +jQuery.extend( { + queue: function( elem, type, data ) { + var queue; + + if ( elem ) { + type = ( type || "fx" ) + "queue"; + queue = dataPriv.get( elem, type ); + + // Speed up dequeue by getting out quickly if this is just a lookup + if ( data ) { + if ( !queue || Array.isArray( data ) ) { + queue = dataPriv.access( elem, type, jQuery.makeArray( data ) ); + } else { + queue.push( data ); + } + } + return queue || []; + } + }, + + dequeue: function( elem, type ) { + type = type || "fx"; + + var queue = jQuery.queue( elem, type ), + startLength = queue.length, + fn = queue.shift(), + hooks = jQuery._queueHooks( elem, type ), + next = function() { + jQuery.dequeue( elem, type ); + }; + + // If the fx queue is dequeued, always remove the progress sentinel + if ( fn === "inprogress" ) { + fn = queue.shift(); + startLength--; + } + + if ( fn ) { + + // Add a progress sentinel to prevent the fx queue from being + // automatically dequeued + if ( type === "fx" ) { + queue.unshift( "inprogress" ); + } + + // Clear up the last queue stop function + delete hooks.stop; + fn.call( elem, next, hooks ); + } + + if ( !startLength && hooks ) { + hooks.empty.fire(); + } + }, + + // Not public - generate a queueHooks object, or return the current one + _queueHooks: function( elem, type ) { + var key = type + "queueHooks"; + return dataPriv.get( elem, key ) || dataPriv.access( elem, key, { + empty: jQuery.Callbacks( "once memory" ).add( function() { + dataPriv.remove( elem, [ type + "queue", key ] ); + } ) + } ); + } +} ); + +jQuery.fn.extend( { + queue: function( type, data ) { + var setter = 2; + + if ( typeof type !== "string" ) { + data = type; + type = "fx"; + setter--; + } + + if ( arguments.length < setter ) { + return jQuery.queue( this[ 0 ], type ); + } + + return data === undefined ? + this : + this.each( function() { + var queue = jQuery.queue( this, type, data ); + + // Ensure a hooks for this queue + jQuery._queueHooks( this, type ); + + if ( type === "fx" && queue[ 0 ] !== "inprogress" ) { + jQuery.dequeue( this, type ); + } + } ); + }, + dequeue: function( type ) { + return this.each( function() { + jQuery.dequeue( this, type ); + } ); + }, + clearQueue: function( type ) { + return this.queue( type || "fx", [] ); + }, + + // Get a promise resolved when queues of a certain type + // are emptied (fx is the type by default) + promise: function( type, obj ) { + var tmp, + count = 1, + defer = jQuery.Deferred(), + elements = this, + i = this.length, + resolve = function() { + if ( !( --count ) ) { + defer.resolveWith( elements, [ elements ] ); + } + }; + + if ( typeof type !== "string" ) { + obj = type; + type = undefined; + } + type = type || "fx"; + + while ( i-- ) { + tmp = dataPriv.get( elements[ i ], type + "queueHooks" ); + if ( tmp && tmp.empty ) { + count++; + tmp.empty.add( resolve ); + } + } + resolve(); + return defer.promise( obj ); + } +} ); +var pnum = ( /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/ ).source; + +var rcssNum = new RegExp( "^(?:([+-])=|)(" + pnum + ")([a-z%]*)$", "i" ); + + +var cssExpand = [ "Top", "Right", "Bottom", "Left" ]; + +var documentElement = document.documentElement; + + + + var isAttached = function( elem ) { + return jQuery.contains( elem.ownerDocument, elem ); + }, + composed = { composed: true }; + + // Support: IE 9 - 11+, Edge 12 - 18+, iOS 10.0 - 10.2 only + // Check attachment across shadow DOM boundaries when possible (gh-3504) + // Support: iOS 10.0-10.2 only + // Early iOS 10 versions support `attachShadow` but not `getRootNode`, + // leading to errors. We need to check for `getRootNode`. + if ( documentElement.getRootNode ) { + isAttached = function( elem ) { + return jQuery.contains( elem.ownerDocument, elem ) || + elem.getRootNode( composed ) === elem.ownerDocument; + }; + } +var isHiddenWithinTree = function( elem, el ) { + + // isHiddenWithinTree might be called from jQuery#filter function; + // in that case, element will be second argument + elem = el || elem; + + // Inline style trumps all + return elem.style.display === "none" || + elem.style.display === "" && + + // Otherwise, check computed style + // Support: Firefox <=43 - 45 + // Disconnected elements can have computed display: none, so first confirm that elem is + // in the document. + isAttached( elem ) && + + jQuery.css( elem, "display" ) === "none"; + }; + + + +function adjustCSS( elem, prop, valueParts, tween ) { + var adjusted, scale, + maxIterations = 20, + currentValue = tween ? + function() { + return tween.cur(); + } : + function() { + return jQuery.css( elem, prop, "" ); + }, + initial = currentValue(), + unit = valueParts && valueParts[ 3 ] || ( jQuery.cssNumber[ prop ] ? "" : "px" ), + + // Starting value computation is required for potential unit mismatches + initialInUnit = elem.nodeType && + ( jQuery.cssNumber[ prop ] || unit !== "px" && +initial ) && + rcssNum.exec( jQuery.css( elem, prop ) ); + + if ( initialInUnit && initialInUnit[ 3 ] !== unit ) { + + // Support: Firefox <=54 + // Halve the iteration target value to prevent interference from CSS upper bounds (gh-2144) + initial = initial / 2; + + // Trust units reported by jQuery.css + unit = unit || initialInUnit[ 3 ]; + + // Iteratively approximate from a nonzero starting point + initialInUnit = +initial || 1; + + while ( maxIterations-- ) { + + // Evaluate and update our best guess (doubling guesses that zero out). + // Finish if the scale equals or crosses 1 (making the old*new product non-positive). + jQuery.style( elem, prop, initialInUnit + unit ); + if ( ( 1 - scale ) * ( 1 - ( scale = currentValue() / initial || 0.5 ) ) <= 0 ) { + maxIterations = 0; + } + initialInUnit = initialInUnit / scale; + + } + + initialInUnit = initialInUnit * 2; + jQuery.style( elem, prop, initialInUnit + unit ); + + // Make sure we update the tween properties later on + valueParts = valueParts || []; + } + + if ( valueParts ) { + initialInUnit = +initialInUnit || +initial || 0; + + // Apply relative offset (+=/-=) if specified + adjusted = valueParts[ 1 ] ? + initialInUnit + ( valueParts[ 1 ] + 1 ) * valueParts[ 2 ] : + +valueParts[ 2 ]; + if ( tween ) { + tween.unit = unit; + tween.start = initialInUnit; + tween.end = adjusted; + } + } + return adjusted; +} + + +var defaultDisplayMap = {}; + +function getDefaultDisplay( elem ) { + var temp, + doc = elem.ownerDocument, + nodeName = elem.nodeName, + display = defaultDisplayMap[ nodeName ]; + + if ( display ) { + return display; + } + + temp = doc.body.appendChild( doc.createElement( nodeName ) ); + display = jQuery.css( temp, "display" ); + + temp.parentNode.removeChild( temp ); + + if ( display === "none" ) { + display = "block"; + } + defaultDisplayMap[ nodeName ] = display; + + return display; +} + +function showHide( elements, show ) { + var display, elem, + values = [], + index = 0, + length = elements.length; + + // Determine new display value for elements that need to change + for ( ; index < length; index++ ) { + elem = elements[ index ]; + if ( !elem.style ) { + continue; + } + + display = elem.style.display; + if ( show ) { + + // Since we force visibility upon cascade-hidden elements, an immediate (and slow) + // check is required in this first loop unless we have a nonempty display value (either + // inline or about-to-be-restored) + if ( display === "none" ) { + values[ index ] = dataPriv.get( elem, "display" ) || null; + if ( !values[ index ] ) { + elem.style.display = ""; + } + } + if ( elem.style.display === "" && isHiddenWithinTree( elem ) ) { + values[ index ] = getDefaultDisplay( elem ); + } + } else { + if ( display !== "none" ) { + values[ index ] = "none"; + + // Remember what we're overwriting + dataPriv.set( elem, "display", display ); + } + } + } + + // Set the display of the elements in a second loop to avoid constant reflow + for ( index = 0; index < length; index++ ) { + if ( values[ index ] != null ) { + elements[ index ].style.display = values[ index ]; + } + } + + return elements; +} + +jQuery.fn.extend( { + show: function() { + return showHide( this, true ); + }, + hide: function() { + return showHide( this ); + }, + toggle: function( state ) { + if ( typeof state === "boolean" ) { + return state ? this.show() : this.hide(); + } + + return this.each( function() { + if ( isHiddenWithinTree( this ) ) { + jQuery( this ).show(); + } else { + jQuery( this ).hide(); + } + } ); + } +} ); +var rcheckableType = ( /^(?:checkbox|radio)$/i ); + +var rtagName = ( /<([a-z][^\/\0>\x20\t\r\n\f]*)/i ); + +var rscriptType = ( /^$|^module$|\/(?:java|ecma)script/i ); + + + +( function() { + var fragment = document.createDocumentFragment(), + div = fragment.appendChild( document.createElement( "div" ) ), + input = document.createElement( "input" ); + + // Support: Android 4.0 - 4.3 only + // Check state lost if the name is set (trac-11217) + // Support: Windows Web Apps (WWA) + // `name` and `type` must use .setAttribute for WWA (trac-14901) + input.setAttribute( "type", "radio" ); + input.setAttribute( "checked", "checked" ); + input.setAttribute( "name", "t" ); + + div.appendChild( input ); + + // Support: Android <=4.1 only + // Older WebKit doesn't clone checked state correctly in fragments + support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked; + + // Support: IE <=11 only + // Make sure textarea (and checkbox) defaultValue is properly cloned + div.innerHTML = ""; + support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue; + + // Support: IE <=9 only + // IE <=9 replaces "; + support.option = !!div.lastChild; +} )(); + + +// We have to close these tags to support XHTML (trac-13200) +var wrapMap = { + + // XHTML parsers do not magically insert elements in the + // same way that tag soup parsers do. So we cannot shorten + // this by omitting or other required elements. + thead: [ 1, "", "
" ], + col: [ 2, "", "
" ], + tr: [ 2, "", "
" ], + td: [ 3, "", "
" ], + + _default: [ 0, "", "" ] +}; + +wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; +wrapMap.th = wrapMap.td; + +// Support: IE <=9 only +if ( !support.option ) { + wrapMap.optgroup = wrapMap.option = [ 1, "" ]; +} + + +function getAll( context, tag ) { + + // Support: IE <=9 - 11 only + // Use typeof to avoid zero-argument method invocation on host objects (trac-15151) + var ret; + + if ( typeof context.getElementsByTagName !== "undefined" ) { + ret = context.getElementsByTagName( tag || "*" ); + + } else if ( typeof context.querySelectorAll !== "undefined" ) { + ret = context.querySelectorAll( tag || "*" ); + + } else { + ret = []; + } + + if ( tag === undefined || tag && nodeName( context, tag ) ) { + return jQuery.merge( [ context ], ret ); + } + + return ret; +} + + +// Mark scripts as having already been evaluated +function setGlobalEval( elems, refElements ) { + var i = 0, + l = elems.length; + + for ( ; i < l; i++ ) { + dataPriv.set( + elems[ i ], + "globalEval", + !refElements || dataPriv.get( refElements[ i ], "globalEval" ) + ); + } +} + + +var rhtml = /<|&#?\w+;/; + +function buildFragment( elems, context, scripts, selection, ignored ) { + var elem, tmp, tag, wrap, attached, j, + fragment = context.createDocumentFragment(), + nodes = [], + i = 0, + l = elems.length; + + for ( ; i < l; i++ ) { + elem = elems[ i ]; + + if ( elem || elem === 0 ) { + + // Add nodes directly + if ( toType( elem ) === "object" ) { + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem ); + + // Convert non-html into a text node + } else if ( !rhtml.test( elem ) ) { + nodes.push( context.createTextNode( elem ) ); + + // Convert html into DOM nodes + } else { + tmp = tmp || fragment.appendChild( context.createElement( "div" ) ); + + // Deserialize a standard representation + tag = ( rtagName.exec( elem ) || [ "", "" ] )[ 1 ].toLowerCase(); + wrap = wrapMap[ tag ] || wrapMap._default; + tmp.innerHTML = wrap[ 1 ] + jQuery.htmlPrefilter( elem ) + wrap[ 2 ]; + + // Descend through wrappers to the right content + j = wrap[ 0 ]; + while ( j-- ) { + tmp = tmp.lastChild; + } + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( nodes, tmp.childNodes ); + + // Remember the top-level container + tmp = fragment.firstChild; + + // Ensure the created nodes are orphaned (trac-12392) + tmp.textContent = ""; + } + } + } + + // Remove wrapper from fragment + fragment.textContent = ""; + + i = 0; + while ( ( elem = nodes[ i++ ] ) ) { + + // Skip elements already in the context collection (trac-4087) + if ( selection && jQuery.inArray( elem, selection ) > -1 ) { + if ( ignored ) { + ignored.push( elem ); + } + continue; + } + + attached = isAttached( elem ); + + // Append to fragment + tmp = getAll( fragment.appendChild( elem ), "script" ); + + // Preserve script evaluation history + if ( attached ) { + setGlobalEval( tmp ); + } + + // Capture executables + if ( scripts ) { + j = 0; + while ( ( elem = tmp[ j++ ] ) ) { + if ( rscriptType.test( elem.type || "" ) ) { + scripts.push( elem ); + } + } + } + } + + return fragment; +} + + +var rtypenamespace = /^([^.]*)(?:\.(.+)|)/; + +function returnTrue() { + return true; +} + +function returnFalse() { + return false; +} + +function on( elem, types, selector, data, fn, one ) { + var origFn, type; + + // Types can be a map of types/handlers + if ( typeof types === "object" ) { + + // ( types-Object, selector, data ) + if ( typeof selector !== "string" ) { + + // ( types-Object, data ) + data = data || selector; + selector = undefined; + } + for ( type in types ) { + on( elem, type, selector, data, types[ type ], one ); + } + return elem; + } + + if ( data == null && fn == null ) { + + // ( types, fn ) + fn = selector; + data = selector = undefined; + } else if ( fn == null ) { + if ( typeof selector === "string" ) { + + // ( types, selector, fn ) + fn = data; + data = undefined; + } else { + + // ( types, data, fn ) + fn = data; + data = selector; + selector = undefined; + } + } + if ( fn === false ) { + fn = returnFalse; + } else if ( !fn ) { + return elem; + } + + if ( one === 1 ) { + origFn = fn; + fn = function( event ) { + + // Can use an empty set, since event contains the info + jQuery().off( event ); + return origFn.apply( this, arguments ); + }; + + // Use same guid so caller can remove using origFn + fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ ); + } + return elem.each( function() { + jQuery.event.add( this, types, fn, data, selector ); + } ); +} + +/* + * Helper functions for managing events -- not part of the public interface. + * Props to Dean Edwards' addEvent library for many of the ideas. + */ +jQuery.event = { + + global: {}, + + add: function( elem, types, handler, data, selector ) { + + var handleObjIn, eventHandle, tmp, + events, t, handleObj, + special, handlers, type, namespaces, origType, + elemData = dataPriv.get( elem ); + + // Only attach events to objects that accept data + if ( !acceptData( elem ) ) { + return; + } + + // Caller can pass in an object of custom data in lieu of the handler + if ( handler.handler ) { + handleObjIn = handler; + handler = handleObjIn.handler; + selector = handleObjIn.selector; + } + + // Ensure that invalid selectors throw exceptions at attach time + // Evaluate against documentElement in case elem is a non-element node (e.g., document) + if ( selector ) { + jQuery.find.matchesSelector( documentElement, selector ); + } + + // Make sure that the handler has a unique ID, used to find/remove it later + if ( !handler.guid ) { + handler.guid = jQuery.guid++; + } + + // Init the element's event structure and main handler, if this is the first + if ( !( events = elemData.events ) ) { + events = elemData.events = Object.create( null ); + } + if ( !( eventHandle = elemData.handle ) ) { + eventHandle = elemData.handle = function( e ) { + + // Discard the second event of a jQuery.event.trigger() and + // when an event is called after a page has unloaded + return typeof jQuery !== "undefined" && jQuery.event.triggered !== e.type ? + jQuery.event.dispatch.apply( elem, arguments ) : undefined; + }; + } + + // Handle multiple events separated by a space + types = ( types || "" ).match( rnothtmlwhite ) || [ "" ]; + t = types.length; + while ( t-- ) { + tmp = rtypenamespace.exec( types[ t ] ) || []; + type = origType = tmp[ 1 ]; + namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); + + // There *must* be a type, no attaching namespace-only handlers + if ( !type ) { + continue; + } + + // If event changes its type, use the special event handlers for the changed type + special = jQuery.event.special[ type ] || {}; + + // If selector defined, determine special event api type, otherwise given type + type = ( selector ? special.delegateType : special.bindType ) || type; + + // Update special based on newly reset type + special = jQuery.event.special[ type ] || {}; + + // handleObj is passed to all event handlers + handleObj = jQuery.extend( { + type: type, + origType: origType, + data: data, + handler: handler, + guid: handler.guid, + selector: selector, + needsContext: selector && jQuery.expr.match.needsContext.test( selector ), + namespace: namespaces.join( "." ) + }, handleObjIn ); + + // Init the event handler queue if we're the first + if ( !( handlers = events[ type ] ) ) { + handlers = events[ type ] = []; + handlers.delegateCount = 0; + + // Only use addEventListener if the special events handler returns false + if ( !special.setup || + special.setup.call( elem, data, namespaces, eventHandle ) === false ) { + + if ( elem.addEventListener ) { + elem.addEventListener( type, eventHandle ); + } + } + } + + if ( special.add ) { + special.add.call( elem, handleObj ); + + if ( !handleObj.handler.guid ) { + handleObj.handler.guid = handler.guid; + } + } + + // Add to the element's handler list, delegates in front + if ( selector ) { + handlers.splice( handlers.delegateCount++, 0, handleObj ); + } else { + handlers.push( handleObj ); + } + + // Keep track of which events have ever been used, for event optimization + jQuery.event.global[ type ] = true; + } + + }, + + // Detach an event or set of events from an element + remove: function( elem, types, handler, selector, mappedTypes ) { + + var j, origCount, tmp, + events, t, handleObj, + special, handlers, type, namespaces, origType, + elemData = dataPriv.hasData( elem ) && dataPriv.get( elem ); + + if ( !elemData || !( events = elemData.events ) ) { + return; + } + + // Once for each type.namespace in types; type may be omitted + types = ( types || "" ).match( rnothtmlwhite ) || [ "" ]; + t = types.length; + while ( t-- ) { + tmp = rtypenamespace.exec( types[ t ] ) || []; + type = origType = tmp[ 1 ]; + namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); + + // Unbind all events (on this namespace, if provided) for the element + if ( !type ) { + for ( type in events ) { + jQuery.event.remove( elem, type + types[ t ], handler, selector, true ); + } + continue; + } + + special = jQuery.event.special[ type ] || {}; + type = ( selector ? special.delegateType : special.bindType ) || type; + handlers = events[ type ] || []; + tmp = tmp[ 2 ] && + new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ); + + // Remove matching events + origCount = j = handlers.length; + while ( j-- ) { + handleObj = handlers[ j ]; + + if ( ( mappedTypes || origType === handleObj.origType ) && + ( !handler || handler.guid === handleObj.guid ) && + ( !tmp || tmp.test( handleObj.namespace ) ) && + ( !selector || selector === handleObj.selector || + selector === "**" && handleObj.selector ) ) { + handlers.splice( j, 1 ); + + if ( handleObj.selector ) { + handlers.delegateCount--; + } + if ( special.remove ) { + special.remove.call( elem, handleObj ); + } + } + } + + // Remove generic event handler if we removed something and no more handlers exist + // (avoids potential for endless recursion during removal of special event handlers) + if ( origCount && !handlers.length ) { + if ( !special.teardown || + special.teardown.call( elem, namespaces, elemData.handle ) === false ) { + + jQuery.removeEvent( elem, type, elemData.handle ); + } + + delete events[ type ]; + } + } + + // Remove data and the expando if it's no longer used + if ( jQuery.isEmptyObject( events ) ) { + dataPriv.remove( elem, "handle events" ); + } + }, + + dispatch: function( nativeEvent ) { + + var i, j, ret, matched, handleObj, handlerQueue, + args = new Array( arguments.length ), + + // Make a writable jQuery.Event from the native event object + event = jQuery.event.fix( nativeEvent ), + + handlers = ( + dataPriv.get( this, "events" ) || Object.create( null ) + )[ event.type ] || [], + special = jQuery.event.special[ event.type ] || {}; + + // Use the fix-ed jQuery.Event rather than the (read-only) native event + args[ 0 ] = event; + + for ( i = 1; i < arguments.length; i++ ) { + args[ i ] = arguments[ i ]; + } + + event.delegateTarget = this; + + // Call the preDispatch hook for the mapped type, and let it bail if desired + if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) { + return; + } + + // Determine handlers + handlerQueue = jQuery.event.handlers.call( this, event, handlers ); + + // Run delegates first; they may want to stop propagation beneath us + i = 0; + while ( ( matched = handlerQueue[ i++ ] ) && !event.isPropagationStopped() ) { + event.currentTarget = matched.elem; + + j = 0; + while ( ( handleObj = matched.handlers[ j++ ] ) && + !event.isImmediatePropagationStopped() ) { + + // If the event is namespaced, then each handler is only invoked if it is + // specially universal or its namespaces are a superset of the event's. + if ( !event.rnamespace || handleObj.namespace === false || + event.rnamespace.test( handleObj.namespace ) ) { + + event.handleObj = handleObj; + event.data = handleObj.data; + + ret = ( ( jQuery.event.special[ handleObj.origType ] || {} ).handle || + handleObj.handler ).apply( matched.elem, args ); + + if ( ret !== undefined ) { + if ( ( event.result = ret ) === false ) { + event.preventDefault(); + event.stopPropagation(); + } + } + } + } + } + + // Call the postDispatch hook for the mapped type + if ( special.postDispatch ) { + special.postDispatch.call( this, event ); + } + + return event.result; + }, + + handlers: function( event, handlers ) { + var i, handleObj, sel, matchedHandlers, matchedSelectors, + handlerQueue = [], + delegateCount = handlers.delegateCount, + cur = event.target; + + // Find delegate handlers + if ( delegateCount && + + // Support: IE <=9 + // Black-hole SVG instance trees (trac-13180) + cur.nodeType && + + // Support: Firefox <=42 + // Suppress spec-violating clicks indicating a non-primary pointer button (trac-3861) + // https://www.w3.org/TR/DOM-Level-3-Events/#event-type-click + // Support: IE 11 only + // ...but not arrow key "clicks" of radio inputs, which can have `button` -1 (gh-2343) + !( event.type === "click" && event.button >= 1 ) ) { + + for ( ; cur !== this; cur = cur.parentNode || this ) { + + // Don't check non-elements (trac-13208) + // Don't process clicks on disabled elements (trac-6911, trac-8165, trac-11382, trac-11764) + if ( cur.nodeType === 1 && !( event.type === "click" && cur.disabled === true ) ) { + matchedHandlers = []; + matchedSelectors = {}; + for ( i = 0; i < delegateCount; i++ ) { + handleObj = handlers[ i ]; + + // Don't conflict with Object.prototype properties (trac-13203) + sel = handleObj.selector + " "; + + if ( matchedSelectors[ sel ] === undefined ) { + matchedSelectors[ sel ] = handleObj.needsContext ? + jQuery( sel, this ).index( cur ) > -1 : + jQuery.find( sel, this, null, [ cur ] ).length; + } + if ( matchedSelectors[ sel ] ) { + matchedHandlers.push( handleObj ); + } + } + if ( matchedHandlers.length ) { + handlerQueue.push( { elem: cur, handlers: matchedHandlers } ); + } + } + } + } + + // Add the remaining (directly-bound) handlers + cur = this; + if ( delegateCount < handlers.length ) { + handlerQueue.push( { elem: cur, handlers: handlers.slice( delegateCount ) } ); + } + + return handlerQueue; + }, + + addProp: function( name, hook ) { + Object.defineProperty( jQuery.Event.prototype, name, { + enumerable: true, + configurable: true, + + get: isFunction( hook ) ? + function() { + if ( this.originalEvent ) { + return hook( this.originalEvent ); + } + } : + function() { + if ( this.originalEvent ) { + return this.originalEvent[ name ]; + } + }, + + set: function( value ) { + Object.defineProperty( this, name, { + enumerable: true, + configurable: true, + writable: true, + value: value + } ); + } + } ); + }, + + fix: function( originalEvent ) { + return originalEvent[ jQuery.expando ] ? + originalEvent : + new jQuery.Event( originalEvent ); + }, + + special: { + load: { + + // Prevent triggered image.load events from bubbling to window.load + noBubble: true + }, + click: { + + // Utilize native event to ensure correct state for checkable inputs + setup: function( data ) { + + // For mutual compressibility with _default, replace `this` access with a local var. + // `|| data` is dead code meant only to preserve the variable through minification. + var el = this || data; + + // Claim the first handler + if ( rcheckableType.test( el.type ) && + el.click && nodeName( el, "input" ) ) { + + // dataPriv.set( el, "click", ... ) + leverageNative( el, "click", true ); + } + + // Return false to allow normal processing in the caller + return false; + }, + trigger: function( data ) { + + // For mutual compressibility with _default, replace `this` access with a local var. + // `|| data` is dead code meant only to preserve the variable through minification. + var el = this || data; + + // Force setup before triggering a click + if ( rcheckableType.test( el.type ) && + el.click && nodeName( el, "input" ) ) { + + leverageNative( el, "click" ); + } + + // Return non-false to allow normal event-path propagation + return true; + }, + + // For cross-browser consistency, suppress native .click() on links + // Also prevent it if we're currently inside a leveraged native-event stack + _default: function( event ) { + var target = event.target; + return rcheckableType.test( target.type ) && + target.click && nodeName( target, "input" ) && + dataPriv.get( target, "click" ) || + nodeName( target, "a" ); + } + }, + + beforeunload: { + postDispatch: function( event ) { + + // Support: Firefox 20+ + // Firefox doesn't alert if the returnValue field is not set. + if ( event.result !== undefined && event.originalEvent ) { + event.originalEvent.returnValue = event.result; + } + } + } + } +}; + +// Ensure the presence of an event listener that handles manually-triggered +// synthetic events by interrupting progress until reinvoked in response to +// *native* events that it fires directly, ensuring that state changes have +// already occurred before other listeners are invoked. +function leverageNative( el, type, isSetup ) { + + // Missing `isSetup` indicates a trigger call, which must force setup through jQuery.event.add + if ( !isSetup ) { + if ( dataPriv.get( el, type ) === undefined ) { + jQuery.event.add( el, type, returnTrue ); + } + return; + } + + // Register the controller as a special universal handler for all event namespaces + dataPriv.set( el, type, false ); + jQuery.event.add( el, type, { + namespace: false, + handler: function( event ) { + var result, + saved = dataPriv.get( this, type ); + + if ( ( event.isTrigger & 1 ) && this[ type ] ) { + + // Interrupt processing of the outer synthetic .trigger()ed event + if ( !saved ) { + + // Store arguments for use when handling the inner native event + // There will always be at least one argument (an event object), so this array + // will not be confused with a leftover capture object. + saved = slice.call( arguments ); + dataPriv.set( this, type, saved ); + + // Trigger the native event and capture its result + this[ type ](); + result = dataPriv.get( this, type ); + dataPriv.set( this, type, false ); + + if ( saved !== result ) { + + // Cancel the outer synthetic event + event.stopImmediatePropagation(); + event.preventDefault(); + + return result; + } + + // If this is an inner synthetic event for an event with a bubbling surrogate + // (focus or blur), assume that the surrogate already propagated from triggering + // the native event and prevent that from happening again here. + // This technically gets the ordering wrong w.r.t. to `.trigger()` (in which the + // bubbling surrogate propagates *after* the non-bubbling base), but that seems + // less bad than duplication. + } else if ( ( jQuery.event.special[ type ] || {} ).delegateType ) { + event.stopPropagation(); + } + + // If this is a native event triggered above, everything is now in order + // Fire an inner synthetic event with the original arguments + } else if ( saved ) { + + // ...and capture the result + dataPriv.set( this, type, jQuery.event.trigger( + saved[ 0 ], + saved.slice( 1 ), + this + ) ); + + // Abort handling of the native event by all jQuery handlers while allowing + // native handlers on the same element to run. On target, this is achieved + // by stopping immediate propagation just on the jQuery event. However, + // the native event is re-wrapped by a jQuery one on each level of the + // propagation so the only way to stop it for jQuery is to stop it for + // everyone via native `stopPropagation()`. This is not a problem for + // focus/blur which don't bubble, but it does also stop click on checkboxes + // and radios. We accept this limitation. + event.stopPropagation(); + event.isImmediatePropagationStopped = returnTrue; + } + } + } ); +} + +jQuery.removeEvent = function( elem, type, handle ) { + + // This "if" is needed for plain objects + if ( elem.removeEventListener ) { + elem.removeEventListener( type, handle ); + } +}; + +jQuery.Event = function( src, props ) { + + // Allow instantiation without the 'new' keyword + if ( !( this instanceof jQuery.Event ) ) { + return new jQuery.Event( src, props ); + } + + // Event object + if ( src && src.type ) { + this.originalEvent = src; + this.type = src.type; + + // Events bubbling up the document may have been marked as prevented + // by a handler lower down the tree; reflect the correct value. + this.isDefaultPrevented = src.defaultPrevented || + src.defaultPrevented === undefined && + + // Support: Android <=2.3 only + src.returnValue === false ? + returnTrue : + returnFalse; + + // Create target properties + // Support: Safari <=6 - 7 only + // Target should not be a text node (trac-504, trac-13143) + this.target = ( src.target && src.target.nodeType === 3 ) ? + src.target.parentNode : + src.target; + + this.currentTarget = src.currentTarget; + this.relatedTarget = src.relatedTarget; + + // Event type + } else { + this.type = src; + } + + // Put explicitly provided properties onto the event object + if ( props ) { + jQuery.extend( this, props ); + } + + // Create a timestamp if incoming event doesn't have one + this.timeStamp = src && src.timeStamp || Date.now(); + + // Mark it as fixed + this[ jQuery.expando ] = true; +}; + +// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding +// https://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html +jQuery.Event.prototype = { + constructor: jQuery.Event, + isDefaultPrevented: returnFalse, + isPropagationStopped: returnFalse, + isImmediatePropagationStopped: returnFalse, + isSimulated: false, + + preventDefault: function() { + var e = this.originalEvent; + + this.isDefaultPrevented = returnTrue; + + if ( e && !this.isSimulated ) { + e.preventDefault(); + } + }, + stopPropagation: function() { + var e = this.originalEvent; + + this.isPropagationStopped = returnTrue; + + if ( e && !this.isSimulated ) { + e.stopPropagation(); + } + }, + stopImmediatePropagation: function() { + var e = this.originalEvent; + + this.isImmediatePropagationStopped = returnTrue; + + if ( e && !this.isSimulated ) { + e.stopImmediatePropagation(); + } + + this.stopPropagation(); + } +}; + +// Includes all common event props including KeyEvent and MouseEvent specific props +jQuery.each( { + altKey: true, + bubbles: true, + cancelable: true, + changedTouches: true, + ctrlKey: true, + detail: true, + eventPhase: true, + metaKey: true, + pageX: true, + pageY: true, + shiftKey: true, + view: true, + "char": true, + code: true, + charCode: true, + key: true, + keyCode: true, + button: true, + buttons: true, + clientX: true, + clientY: true, + offsetX: true, + offsetY: true, + pointerId: true, + pointerType: true, + screenX: true, + screenY: true, + targetTouches: true, + toElement: true, + touches: true, + which: true +}, jQuery.event.addProp ); + +jQuery.each( { focus: "focusin", blur: "focusout" }, function( type, delegateType ) { + + function focusMappedHandler( nativeEvent ) { + if ( document.documentMode ) { + + // Support: IE 11+ + // Attach a single focusin/focusout handler on the document while someone wants + // focus/blur. This is because the former are synchronous in IE while the latter + // are async. In other browsers, all those handlers are invoked synchronously. + + // `handle` from private data would already wrap the event, but we need + // to change the `type` here. + var handle = dataPriv.get( this, "handle" ), + event = jQuery.event.fix( nativeEvent ); + event.type = nativeEvent.type === "focusin" ? "focus" : "blur"; + event.isSimulated = true; + + // First, handle focusin/focusout + handle( nativeEvent ); + + // ...then, handle focus/blur + // + // focus/blur don't bubble while focusin/focusout do; simulate the former by only + // invoking the handler at the lower level. + if ( event.target === event.currentTarget ) { + + // The setup part calls `leverageNative`, which, in turn, calls + // `jQuery.event.add`, so event handle will already have been set + // by this point. + handle( event ); + } + } else { + + // For non-IE browsers, attach a single capturing handler on the document + // while someone wants focusin/focusout. + jQuery.event.simulate( delegateType, nativeEvent.target, + jQuery.event.fix( nativeEvent ) ); + } + } + + jQuery.event.special[ type ] = { + + // Utilize native event if possible so blur/focus sequence is correct + setup: function() { + + var attaches; + + // Claim the first handler + // dataPriv.set( this, "focus", ... ) + // dataPriv.set( this, "blur", ... ) + leverageNative( this, type, true ); + + if ( document.documentMode ) { + + // Support: IE 9 - 11+ + // We use the same native handler for focusin & focus (and focusout & blur) + // so we need to coordinate setup & teardown parts between those events. + // Use `delegateType` as the key as `type` is already used by `leverageNative`. + attaches = dataPriv.get( this, delegateType ); + if ( !attaches ) { + this.addEventListener( delegateType, focusMappedHandler ); + } + dataPriv.set( this, delegateType, ( attaches || 0 ) + 1 ); + } else { + + // Return false to allow normal processing in the caller + return false; + } + }, + trigger: function() { + + // Force setup before trigger + leverageNative( this, type ); + + // Return non-false to allow normal event-path propagation + return true; + }, + + teardown: function() { + var attaches; + + if ( document.documentMode ) { + attaches = dataPriv.get( this, delegateType ) - 1; + if ( !attaches ) { + this.removeEventListener( delegateType, focusMappedHandler ); + dataPriv.remove( this, delegateType ); + } else { + dataPriv.set( this, delegateType, attaches ); + } + } else { + + // Return false to indicate standard teardown should be applied + return false; + } + }, + + // Suppress native focus or blur if we're currently inside + // a leveraged native-event stack + _default: function( event ) { + return dataPriv.get( event.target, type ); + }, + + delegateType: delegateType + }; + + // Support: Firefox <=44 + // Firefox doesn't have focus(in | out) events + // Related ticket - https://bugzilla.mozilla.org/show_bug.cgi?id=687787 + // + // Support: Chrome <=48 - 49, Safari <=9.0 - 9.1 + // focus(in | out) events fire after focus & blur events, + // which is spec violation - http://www.w3.org/TR/DOM-Level-3-Events/#events-focusevent-event-order + // Related ticket - https://bugs.chromium.org/p/chromium/issues/detail?id=449857 + // + // Support: IE 9 - 11+ + // To preserve relative focusin/focus & focusout/blur event order guaranteed on the 3.x branch, + // attach a single handler for both events in IE. + jQuery.event.special[ delegateType ] = { + setup: function() { + + // Handle: regular nodes (via `this.ownerDocument`), window + // (via `this.document`) & document (via `this`). + var doc = this.ownerDocument || this.document || this, + dataHolder = document.documentMode ? this : doc, + attaches = dataPriv.get( dataHolder, delegateType ); + + // Support: IE 9 - 11+ + // We use the same native handler for focusin & focus (and focusout & blur) + // so we need to coordinate setup & teardown parts between those events. + // Use `delegateType` as the key as `type` is already used by `leverageNative`. + if ( !attaches ) { + if ( document.documentMode ) { + this.addEventListener( delegateType, focusMappedHandler ); + } else { + doc.addEventListener( type, focusMappedHandler, true ); + } + } + dataPriv.set( dataHolder, delegateType, ( attaches || 0 ) + 1 ); + }, + teardown: function() { + var doc = this.ownerDocument || this.document || this, + dataHolder = document.documentMode ? this : doc, + attaches = dataPriv.get( dataHolder, delegateType ) - 1; + + if ( !attaches ) { + if ( document.documentMode ) { + this.removeEventListener( delegateType, focusMappedHandler ); + } else { + doc.removeEventListener( type, focusMappedHandler, true ); + } + dataPriv.remove( dataHolder, delegateType ); + } else { + dataPriv.set( dataHolder, delegateType, attaches ); + } + } + }; +} ); + +// Create mouseenter/leave events using mouseover/out and event-time checks +// so that event delegation works in jQuery. +// Do the same for pointerenter/pointerleave and pointerover/pointerout +// +// Support: Safari 7 only +// Safari sends mouseenter too often; see: +// https://bugs.chromium.org/p/chromium/issues/detail?id=470258 +// for the description of the bug (it existed in older Chrome versions as well). +jQuery.each( { + mouseenter: "mouseover", + mouseleave: "mouseout", + pointerenter: "pointerover", + pointerleave: "pointerout" +}, function( orig, fix ) { + jQuery.event.special[ orig ] = { + delegateType: fix, + bindType: fix, + + handle: function( event ) { + var ret, + target = this, + related = event.relatedTarget, + handleObj = event.handleObj; + + // For mouseenter/leave call the handler if related is outside the target. + // NB: No relatedTarget if the mouse left/entered the browser window + if ( !related || ( related !== target && !jQuery.contains( target, related ) ) ) { + event.type = handleObj.origType; + ret = handleObj.handler.apply( this, arguments ); + event.type = fix; + } + return ret; + } + }; +} ); + +jQuery.fn.extend( { + + on: function( types, selector, data, fn ) { + return on( this, types, selector, data, fn ); + }, + one: function( types, selector, data, fn ) { + return on( this, types, selector, data, fn, 1 ); + }, + off: function( types, selector, fn ) { + var handleObj, type; + if ( types && types.preventDefault && types.handleObj ) { + + // ( event ) dispatched jQuery.Event + handleObj = types.handleObj; + jQuery( types.delegateTarget ).off( + handleObj.namespace ? + handleObj.origType + "." + handleObj.namespace : + handleObj.origType, + handleObj.selector, + handleObj.handler + ); + return this; + } + if ( typeof types === "object" ) { + + // ( types-object [, selector] ) + for ( type in types ) { + this.off( type, selector, types[ type ] ); + } + return this; + } + if ( selector === false || typeof selector === "function" ) { + + // ( types [, fn] ) + fn = selector; + selector = undefined; + } + if ( fn === false ) { + fn = returnFalse; + } + return this.each( function() { + jQuery.event.remove( this, types, fn, selector ); + } ); + } +} ); + + +var + + // Support: IE <=10 - 11, Edge 12 - 13 only + // In IE/Edge using regex groups here causes severe slowdowns. + // See https://connect.microsoft.com/IE/feedback/details/1736512/ + rnoInnerhtml = /\s*$/g; + +// Prefer a tbody over its parent table for containing new rows +function manipulationTarget( elem, content ) { + if ( nodeName( elem, "table" ) && + nodeName( content.nodeType !== 11 ? content : content.firstChild, "tr" ) ) { + + return jQuery( elem ).children( "tbody" )[ 0 ] || elem; + } + + return elem; +} + +// Replace/restore the type attribute of script elements for safe DOM manipulation +function disableScript( elem ) { + elem.type = ( elem.getAttribute( "type" ) !== null ) + "/" + elem.type; + return elem; +} +function restoreScript( elem ) { + if ( ( elem.type || "" ).slice( 0, 5 ) === "true/" ) { + elem.type = elem.type.slice( 5 ); + } else { + elem.removeAttribute( "type" ); + } + + return elem; +} + +function cloneCopyEvent( src, dest ) { + var i, l, type, pdataOld, udataOld, udataCur, events; + + if ( dest.nodeType !== 1 ) { + return; + } + + // 1. Copy private data: events, handlers, etc. + if ( dataPriv.hasData( src ) ) { + pdataOld = dataPriv.get( src ); + events = pdataOld.events; + + if ( events ) { + dataPriv.remove( dest, "handle events" ); + + for ( type in events ) { + for ( i = 0, l = events[ type ].length; i < l; i++ ) { + jQuery.event.add( dest, type, events[ type ][ i ] ); + } + } + } + } + + // 2. Copy user data + if ( dataUser.hasData( src ) ) { + udataOld = dataUser.access( src ); + udataCur = jQuery.extend( {}, udataOld ); + + dataUser.set( dest, udataCur ); + } +} + +// Fix IE bugs, see support tests +function fixInput( src, dest ) { + var nodeName = dest.nodeName.toLowerCase(); + + // Fails to persist the checked state of a cloned checkbox or radio button. + if ( nodeName === "input" && rcheckableType.test( src.type ) ) { + dest.checked = src.checked; + + // Fails to return the selected option to the default selected state when cloning options + } else if ( nodeName === "input" || nodeName === "textarea" ) { + dest.defaultValue = src.defaultValue; + } +} + +function domManip( collection, args, callback, ignored ) { + + // Flatten any nested arrays + args = flat( args ); + + var fragment, first, scripts, hasScripts, node, doc, + i = 0, + l = collection.length, + iNoClone = l - 1, + value = args[ 0 ], + valueIsFunction = isFunction( value ); + + // We can't cloneNode fragments that contain checked, in WebKit + if ( valueIsFunction || + ( l > 1 && typeof value === "string" && + !support.checkClone && rchecked.test( value ) ) ) { + return collection.each( function( index ) { + var self = collection.eq( index ); + if ( valueIsFunction ) { + args[ 0 ] = value.call( this, index, self.html() ); + } + domManip( self, args, callback, ignored ); + } ); + } + + if ( l ) { + fragment = buildFragment( args, collection[ 0 ].ownerDocument, false, collection, ignored ); + first = fragment.firstChild; + + if ( fragment.childNodes.length === 1 ) { + fragment = first; + } + + // Require either new content or an interest in ignored elements to invoke the callback + if ( first || ignored ) { + scripts = jQuery.map( getAll( fragment, "script" ), disableScript ); + hasScripts = scripts.length; + + // Use the original fragment for the last item + // instead of the first because it can end up + // being emptied incorrectly in certain situations (trac-8070). + for ( ; i < l; i++ ) { + node = fragment; + + if ( i !== iNoClone ) { + node = jQuery.clone( node, true, true ); + + // Keep references to cloned scripts for later restoration + if ( hasScripts ) { + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( scripts, getAll( node, "script" ) ); + } + } + + callback.call( collection[ i ], node, i ); + } + + if ( hasScripts ) { + doc = scripts[ scripts.length - 1 ].ownerDocument; + + // Re-enable scripts + jQuery.map( scripts, restoreScript ); + + // Evaluate executable scripts on first document insertion + for ( i = 0; i < hasScripts; i++ ) { + node = scripts[ i ]; + if ( rscriptType.test( node.type || "" ) && + !dataPriv.access( node, "globalEval" ) && + jQuery.contains( doc, node ) ) { + + if ( node.src && ( node.type || "" ).toLowerCase() !== "module" ) { + + // Optional AJAX dependency, but won't run scripts if not present + if ( jQuery._evalUrl && !node.noModule ) { + jQuery._evalUrl( node.src, { + nonce: node.nonce || node.getAttribute( "nonce" ) + }, doc ); + } + } else { + + // Unwrap a CDATA section containing script contents. This shouldn't be + // needed as in XML documents they're already not visible when + // inspecting element contents and in HTML documents they have no + // meaning but we're preserving that logic for backwards compatibility. + // This will be removed completely in 4.0. See gh-4904. + DOMEval( node.textContent.replace( rcleanScript, "" ), node, doc ); + } + } + } + } + } + } + + return collection; +} + +function remove( elem, selector, keepData ) { + var node, + nodes = selector ? jQuery.filter( selector, elem ) : elem, + i = 0; + + for ( ; ( node = nodes[ i ] ) != null; i++ ) { + if ( !keepData && node.nodeType === 1 ) { + jQuery.cleanData( getAll( node ) ); + } + + if ( node.parentNode ) { + if ( keepData && isAttached( node ) ) { + setGlobalEval( getAll( node, "script" ) ); + } + node.parentNode.removeChild( node ); + } + } + + return elem; +} + +jQuery.extend( { + htmlPrefilter: function( html ) { + return html; + }, + + clone: function( elem, dataAndEvents, deepDataAndEvents ) { + var i, l, srcElements, destElements, + clone = elem.cloneNode( true ), + inPage = isAttached( elem ); + + // Fix IE cloning issues + if ( !support.noCloneChecked && ( elem.nodeType === 1 || elem.nodeType === 11 ) && + !jQuery.isXMLDoc( elem ) ) { + + // We eschew jQuery#find here for performance reasons: + // https://jsperf.com/getall-vs-sizzle/2 + destElements = getAll( clone ); + srcElements = getAll( elem ); + + for ( i = 0, l = srcElements.length; i < l; i++ ) { + fixInput( srcElements[ i ], destElements[ i ] ); + } + } + + // Copy the events from the original to the clone + if ( dataAndEvents ) { + if ( deepDataAndEvents ) { + srcElements = srcElements || getAll( elem ); + destElements = destElements || getAll( clone ); + + for ( i = 0, l = srcElements.length; i < l; i++ ) { + cloneCopyEvent( srcElements[ i ], destElements[ i ] ); + } + } else { + cloneCopyEvent( elem, clone ); + } + } + + // Preserve script evaluation history + destElements = getAll( clone, "script" ); + if ( destElements.length > 0 ) { + setGlobalEval( destElements, !inPage && getAll( elem, "script" ) ); + } + + // Return the cloned set + return clone; + }, + + cleanData: function( elems ) { + var data, elem, type, + special = jQuery.event.special, + i = 0; + + for ( ; ( elem = elems[ i ] ) !== undefined; i++ ) { + if ( acceptData( elem ) ) { + if ( ( data = elem[ dataPriv.expando ] ) ) { + if ( data.events ) { + for ( type in data.events ) { + if ( special[ type ] ) { + jQuery.event.remove( elem, type ); + + // This is a shortcut to avoid jQuery.event.remove's overhead + } else { + jQuery.removeEvent( elem, type, data.handle ); + } + } + } + + // Support: Chrome <=35 - 45+ + // Assign undefined instead of using delete, see Data#remove + elem[ dataPriv.expando ] = undefined; + } + if ( elem[ dataUser.expando ] ) { + + // Support: Chrome <=35 - 45+ + // Assign undefined instead of using delete, see Data#remove + elem[ dataUser.expando ] = undefined; + } + } + } + } +} ); + +jQuery.fn.extend( { + detach: function( selector ) { + return remove( this, selector, true ); + }, + + remove: function( selector ) { + return remove( this, selector ); + }, + + text: function( value ) { + return access( this, function( value ) { + return value === undefined ? + jQuery.text( this ) : + this.empty().each( function() { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + this.textContent = value; + } + } ); + }, null, value, arguments.length ); + }, + + append: function() { + return domManip( this, arguments, function( elem ) { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + var target = manipulationTarget( this, elem ); + target.appendChild( elem ); + } + } ); + }, + + prepend: function() { + return domManip( this, arguments, function( elem ) { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + var target = manipulationTarget( this, elem ); + target.insertBefore( elem, target.firstChild ); + } + } ); + }, + + before: function() { + return domManip( this, arguments, function( elem ) { + if ( this.parentNode ) { + this.parentNode.insertBefore( elem, this ); + } + } ); + }, + + after: function() { + return domManip( this, arguments, function( elem ) { + if ( this.parentNode ) { + this.parentNode.insertBefore( elem, this.nextSibling ); + } + } ); + }, + + empty: function() { + var elem, + i = 0; + + for ( ; ( elem = this[ i ] ) != null; i++ ) { + if ( elem.nodeType === 1 ) { + + // Prevent memory leaks + jQuery.cleanData( getAll( elem, false ) ); + + // Remove any remaining nodes + elem.textContent = ""; + } + } + + return this; + }, + + clone: function( dataAndEvents, deepDataAndEvents ) { + dataAndEvents = dataAndEvents == null ? false : dataAndEvents; + deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents; + + return this.map( function() { + return jQuery.clone( this, dataAndEvents, deepDataAndEvents ); + } ); + }, + + html: function( value ) { + return access( this, function( value ) { + var elem = this[ 0 ] || {}, + i = 0, + l = this.length; + + if ( value === undefined && elem.nodeType === 1 ) { + return elem.innerHTML; + } + + // See if we can take a shortcut and just use innerHTML + if ( typeof value === "string" && !rnoInnerhtml.test( value ) && + !wrapMap[ ( rtagName.exec( value ) || [ "", "" ] )[ 1 ].toLowerCase() ] ) { + + value = jQuery.htmlPrefilter( value ); + + try { + for ( ; i < l; i++ ) { + elem = this[ i ] || {}; + + // Remove element nodes and prevent memory leaks + if ( elem.nodeType === 1 ) { + jQuery.cleanData( getAll( elem, false ) ); + elem.innerHTML = value; + } + } + + elem = 0; + + // If using innerHTML throws an exception, use the fallback method + } catch ( e ) {} + } + + if ( elem ) { + this.empty().append( value ); + } + }, null, value, arguments.length ); + }, + + replaceWith: function() { + var ignored = []; + + // Make the changes, replacing each non-ignored context element with the new content + return domManip( this, arguments, function( elem ) { + var parent = this.parentNode; + + if ( jQuery.inArray( this, ignored ) < 0 ) { + jQuery.cleanData( getAll( this ) ); + if ( parent ) { + parent.replaceChild( elem, this ); + } + } + + // Force callback invocation + }, ignored ); + } +} ); + +jQuery.each( { + appendTo: "append", + prependTo: "prepend", + insertBefore: "before", + insertAfter: "after", + replaceAll: "replaceWith" +}, function( name, original ) { + jQuery.fn[ name ] = function( selector ) { + var elems, + ret = [], + insert = jQuery( selector ), + last = insert.length - 1, + i = 0; + + for ( ; i <= last; i++ ) { + elems = i === last ? this : this.clone( true ); + jQuery( insert[ i ] )[ original ]( elems ); + + // Support: Android <=4.0 only, PhantomJS 1 only + // .get() because push.apply(_, arraylike) throws on ancient WebKit + push.apply( ret, elems.get() ); + } + + return this.pushStack( ret ); + }; +} ); +var rnumnonpx = new RegExp( "^(" + pnum + ")(?!px)[a-z%]+$", "i" ); + +var rcustomProp = /^--/; + + +var getStyles = function( elem ) { + + // Support: IE <=11 only, Firefox <=30 (trac-15098, trac-14150) + // IE throws on elements created in popups + // FF meanwhile throws on frame elements through "defaultView.getComputedStyle" + var view = elem.ownerDocument.defaultView; + + if ( !view || !view.opener ) { + view = window; + } + + return view.getComputedStyle( elem ); + }; + +var swap = function( elem, options, callback ) { + var ret, name, + old = {}; + + // Remember the old values, and insert the new ones + for ( name in options ) { + old[ name ] = elem.style[ name ]; + elem.style[ name ] = options[ name ]; + } + + ret = callback.call( elem ); + + // Revert the old values + for ( name in options ) { + elem.style[ name ] = old[ name ]; + } + + return ret; +}; + + +var rboxStyle = new RegExp( cssExpand.join( "|" ), "i" ); + + + +( function() { + + // Executing both pixelPosition & boxSizingReliable tests require only one layout + // so they're executed at the same time to save the second computation. + function computeStyleTests() { + + // This is a singleton, we need to execute it only once + if ( !div ) { + return; + } + + container.style.cssText = "position:absolute;left:-11111px;width:60px;" + + "margin-top:1px;padding:0;border:0"; + div.style.cssText = + "position:relative;display:block;box-sizing:border-box;overflow:scroll;" + + "margin:auto;border:1px;padding:1px;" + + "width:60%;top:1%"; + documentElement.appendChild( container ).appendChild( div ); + + var divStyle = window.getComputedStyle( div ); + pixelPositionVal = divStyle.top !== "1%"; + + // Support: Android 4.0 - 4.3 only, Firefox <=3 - 44 + reliableMarginLeftVal = roundPixelMeasures( divStyle.marginLeft ) === 12; + + // Support: Android 4.0 - 4.3 only, Safari <=9.1 - 10.1, iOS <=7.0 - 9.3 + // Some styles come back with percentage values, even though they shouldn't + div.style.right = "60%"; + pixelBoxStylesVal = roundPixelMeasures( divStyle.right ) === 36; + + // Support: IE 9 - 11 only + // Detect misreporting of content dimensions for box-sizing:border-box elements + boxSizingReliableVal = roundPixelMeasures( divStyle.width ) === 36; + + // Support: IE 9 only + // Detect overflow:scroll screwiness (gh-3699) + // Support: Chrome <=64 + // Don't get tricked when zoom affects offsetWidth (gh-4029) + div.style.position = "absolute"; + scrollboxSizeVal = roundPixelMeasures( div.offsetWidth / 3 ) === 12; + + documentElement.removeChild( container ); + + // Nullify the div so it wouldn't be stored in the memory and + // it will also be a sign that checks already performed + div = null; + } + + function roundPixelMeasures( measure ) { + return Math.round( parseFloat( measure ) ); + } + + var pixelPositionVal, boxSizingReliableVal, scrollboxSizeVal, pixelBoxStylesVal, + reliableTrDimensionsVal, reliableMarginLeftVal, + container = document.createElement( "div" ), + div = document.createElement( "div" ); + + // Finish early in limited (non-browser) environments + if ( !div.style ) { + return; + } + + // Support: IE <=9 - 11 only + // Style of cloned element affects source element cloned (trac-8908) + div.style.backgroundClip = "content-box"; + div.cloneNode( true ).style.backgroundClip = ""; + support.clearCloneStyle = div.style.backgroundClip === "content-box"; + + jQuery.extend( support, { + boxSizingReliable: function() { + computeStyleTests(); + return boxSizingReliableVal; + }, + pixelBoxStyles: function() { + computeStyleTests(); + return pixelBoxStylesVal; + }, + pixelPosition: function() { + computeStyleTests(); + return pixelPositionVal; + }, + reliableMarginLeft: function() { + computeStyleTests(); + return reliableMarginLeftVal; + }, + scrollboxSize: function() { + computeStyleTests(); + return scrollboxSizeVal; + }, + + // Support: IE 9 - 11+, Edge 15 - 18+ + // IE/Edge misreport `getComputedStyle` of table rows with width/height + // set in CSS while `offset*` properties report correct values. + // Behavior in IE 9 is more subtle than in newer versions & it passes + // some versions of this test; make sure not to make it pass there! + // + // Support: Firefox 70+ + // Only Firefox includes border widths + // in computed dimensions. (gh-4529) + reliableTrDimensions: function() { + var table, tr, trChild, trStyle; + if ( reliableTrDimensionsVal == null ) { + table = document.createElement( "table" ); + tr = document.createElement( "tr" ); + trChild = document.createElement( "div" ); + + table.style.cssText = "position:absolute;left:-11111px;border-collapse:separate"; + tr.style.cssText = "box-sizing:content-box;border:1px solid"; + + // Support: Chrome 86+ + // Height set through cssText does not get applied. + // Computed height then comes back as 0. + tr.style.height = "1px"; + trChild.style.height = "9px"; + + // Support: Android 8 Chrome 86+ + // In our bodyBackground.html iframe, + // display for all div elements is set to "inline", + // which causes a problem only in Android 8 Chrome 86. + // Ensuring the div is `display: block` + // gets around this issue. + trChild.style.display = "block"; + + documentElement + .appendChild( table ) + .appendChild( tr ) + .appendChild( trChild ); + + trStyle = window.getComputedStyle( tr ); + reliableTrDimensionsVal = ( parseInt( trStyle.height, 10 ) + + parseInt( trStyle.borderTopWidth, 10 ) + + parseInt( trStyle.borderBottomWidth, 10 ) ) === tr.offsetHeight; + + documentElement.removeChild( table ); + } + return reliableTrDimensionsVal; + } + } ); +} )(); + + +function curCSS( elem, name, computed ) { + var width, minWidth, maxWidth, ret, + isCustomProp = rcustomProp.test( name ), + + // Support: Firefox 51+ + // Retrieving style before computed somehow + // fixes an issue with getting wrong values + // on detached elements + style = elem.style; + + computed = computed || getStyles( elem ); + + // getPropertyValue is needed for: + // .css('filter') (IE 9 only, trac-12537) + // .css('--customProperty) (gh-3144) + if ( computed ) { + + // Support: IE <=9 - 11+ + // IE only supports `"float"` in `getPropertyValue`; in computed styles + // it's only available as `"cssFloat"`. We no longer modify properties + // sent to `.css()` apart from camelCasing, so we need to check both. + // Normally, this would create difference in behavior: if + // `getPropertyValue` returns an empty string, the value returned + // by `.css()` would be `undefined`. This is usually the case for + // disconnected elements. However, in IE even disconnected elements + // with no styles return `"none"` for `getPropertyValue( "float" )` + ret = computed.getPropertyValue( name ) || computed[ name ]; + + if ( isCustomProp && ret ) { + + // Support: Firefox 105+, Chrome <=105+ + // Spec requires trimming whitespace for custom properties (gh-4926). + // Firefox only trims leading whitespace. Chrome just collapses + // both leading & trailing whitespace to a single space. + // + // Fall back to `undefined` if empty string returned. + // This collapses a missing definition with property defined + // and set to an empty string but there's no standard API + // allowing us to differentiate them without a performance penalty + // and returning `undefined` aligns with older jQuery. + // + // rtrimCSS treats U+000D CARRIAGE RETURN and U+000C FORM FEED + // as whitespace while CSS does not, but this is not a problem + // because CSS preprocessing replaces them with U+000A LINE FEED + // (which *is* CSS whitespace) + // https://www.w3.org/TR/css-syntax-3/#input-preprocessing + ret = ret.replace( rtrimCSS, "$1" ) || undefined; + } + + if ( ret === "" && !isAttached( elem ) ) { + ret = jQuery.style( elem, name ); + } + + // A tribute to the "awesome hack by Dean Edwards" + // Android Browser returns percentage for some values, + // but width seems to be reliably pixels. + // This is against the CSSOM draft spec: + // https://drafts.csswg.org/cssom/#resolved-values + if ( !support.pixelBoxStyles() && rnumnonpx.test( ret ) && rboxStyle.test( name ) ) { + + // Remember the original values + width = style.width; + minWidth = style.minWidth; + maxWidth = style.maxWidth; + + // Put in the new values to get a computed value out + style.minWidth = style.maxWidth = style.width = ret; + ret = computed.width; + + // Revert the changed values + style.width = width; + style.minWidth = minWidth; + style.maxWidth = maxWidth; + } + } + + return ret !== undefined ? + + // Support: IE <=9 - 11 only + // IE returns zIndex value as an integer. + ret + "" : + ret; +} + + +function addGetHookIf( conditionFn, hookFn ) { + + // Define the hook, we'll check on the first run if it's really needed. + return { + get: function() { + if ( conditionFn() ) { + + // Hook not needed (or it's not possible to use it due + // to missing dependency), remove it. + delete this.get; + return; + } + + // Hook needed; redefine it so that the support test is not executed again. + return ( this.get = hookFn ).apply( this, arguments ); + } + }; +} + + +var cssPrefixes = [ "Webkit", "Moz", "ms" ], + emptyStyle = document.createElement( "div" ).style, + vendorProps = {}; + +// Return a vendor-prefixed property or undefined +function vendorPropName( name ) { + + // Check for vendor prefixed names + var capName = name[ 0 ].toUpperCase() + name.slice( 1 ), + i = cssPrefixes.length; + + while ( i-- ) { + name = cssPrefixes[ i ] + capName; + if ( name in emptyStyle ) { + return name; + } + } +} + +// Return a potentially-mapped jQuery.cssProps or vendor prefixed property +function finalPropName( name ) { + var final = jQuery.cssProps[ name ] || vendorProps[ name ]; + + if ( final ) { + return final; + } + if ( name in emptyStyle ) { + return name; + } + return vendorProps[ name ] = vendorPropName( name ) || name; +} + + +var + + // Swappable if display is none or starts with table + // except "table", "table-cell", or "table-caption" + // See here for display values: https://developer.mozilla.org/en-US/docs/CSS/display + rdisplayswap = /^(none|table(?!-c[ea]).+)/, + cssShow = { position: "absolute", visibility: "hidden", display: "block" }, + cssNormalTransform = { + letterSpacing: "0", + fontWeight: "400" + }; + +function setPositiveNumber( _elem, value, subtract ) { + + // Any relative (+/-) values have already been + // normalized at this point + var matches = rcssNum.exec( value ); + return matches ? + + // Guard against undefined "subtract", e.g., when used as in cssHooks + Math.max( 0, matches[ 2 ] - ( subtract || 0 ) ) + ( matches[ 3 ] || "px" ) : + value; +} + +function boxModelAdjustment( elem, dimension, box, isBorderBox, styles, computedVal ) { + var i = dimension === "width" ? 1 : 0, + extra = 0, + delta = 0, + marginDelta = 0; + + // Adjustment may not be necessary + if ( box === ( isBorderBox ? "border" : "content" ) ) { + return 0; + } + + for ( ; i < 4; i += 2 ) { + + // Both box models exclude margin + // Count margin delta separately to only add it after scroll gutter adjustment. + // This is needed to make negative margins work with `outerHeight( true )` (gh-3982). + if ( box === "margin" ) { + marginDelta += jQuery.css( elem, box + cssExpand[ i ], true, styles ); + } + + // If we get here with a content-box, we're seeking "padding" or "border" or "margin" + if ( !isBorderBox ) { + + // Add padding + delta += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); + + // For "border" or "margin", add border + if ( box !== "padding" ) { + delta += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); + + // But still keep track of it otherwise + } else { + extra += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); + } + + // If we get here with a border-box (content + padding + border), we're seeking "content" or + // "padding" or "margin" + } else { + + // For "content", subtract padding + if ( box === "content" ) { + delta -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); + } + + // For "content" or "padding", subtract border + if ( box !== "margin" ) { + delta -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); + } + } + } + + // Account for positive content-box scroll gutter when requested by providing computedVal + if ( !isBorderBox && computedVal >= 0 ) { + + // offsetWidth/offsetHeight is a rounded sum of content, padding, scroll gutter, and border + // Assuming integer scroll gutter, subtract the rest and round down + delta += Math.max( 0, Math.ceil( + elem[ "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] - + computedVal - + delta - + extra - + 0.5 + + // If offsetWidth/offsetHeight is unknown, then we can't determine content-box scroll gutter + // Use an explicit zero to avoid NaN (gh-3964) + ) ) || 0; + } + + return delta + marginDelta; +} + +function getWidthOrHeight( elem, dimension, extra ) { + + // Start with computed style + var styles = getStyles( elem ), + + // To avoid forcing a reflow, only fetch boxSizing if we need it (gh-4322). + // Fake content-box until we know it's needed to know the true value. + boxSizingNeeded = !support.boxSizingReliable() || extra, + isBorderBox = boxSizingNeeded && + jQuery.css( elem, "boxSizing", false, styles ) === "border-box", + valueIsBorderBox = isBorderBox, + + val = curCSS( elem, dimension, styles ), + offsetProp = "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ); + + // Support: Firefox <=54 + // Return a confounding non-pixel value or feign ignorance, as appropriate. + if ( rnumnonpx.test( val ) ) { + if ( !extra ) { + return val; + } + val = "auto"; + } + + + // Support: IE 9 - 11 only + // Use offsetWidth/offsetHeight for when box sizing is unreliable. + // In those cases, the computed value can be trusted to be border-box. + if ( ( !support.boxSizingReliable() && isBorderBox || + + // Support: IE 10 - 11+, Edge 15 - 18+ + // IE/Edge misreport `getComputedStyle` of table rows with width/height + // set in CSS while `offset*` properties report correct values. + // Interestingly, in some cases IE 9 doesn't suffer from this issue. + !support.reliableTrDimensions() && nodeName( elem, "tr" ) || + + // Fall back to offsetWidth/offsetHeight when value is "auto" + // This happens for inline elements with no explicit setting (gh-3571) + val === "auto" || + + // Support: Android <=4.1 - 4.3 only + // Also use offsetWidth/offsetHeight for misreported inline dimensions (gh-3602) + !parseFloat( val ) && jQuery.css( elem, "display", false, styles ) === "inline" ) && + + // Make sure the element is visible & connected + elem.getClientRects().length ) { + + isBorderBox = jQuery.css( elem, "boxSizing", false, styles ) === "border-box"; + + // Where available, offsetWidth/offsetHeight approximate border box dimensions. + // Where not available (e.g., SVG), assume unreliable box-sizing and interpret the + // retrieved value as a content box dimension. + valueIsBorderBox = offsetProp in elem; + if ( valueIsBorderBox ) { + val = elem[ offsetProp ]; + } + } + + // Normalize "" and auto + val = parseFloat( val ) || 0; + + // Adjust for the element's box model + return ( val + + boxModelAdjustment( + elem, + dimension, + extra || ( isBorderBox ? "border" : "content" ), + valueIsBorderBox, + styles, + + // Provide the current computed size to request scroll gutter calculation (gh-3589) + val + ) + ) + "px"; +} + +jQuery.extend( { + + // Add in style property hooks for overriding the default + // behavior of getting and setting a style property + cssHooks: { + opacity: { + get: function( elem, computed ) { + if ( computed ) { + + // We should always get a number back from opacity + var ret = curCSS( elem, "opacity" ); + return ret === "" ? "1" : ret; + } + } + } + }, + + // Don't automatically add "px" to these possibly-unitless properties + cssNumber: { + animationIterationCount: true, + aspectRatio: true, + borderImageSlice: true, + columnCount: true, + flexGrow: true, + flexShrink: true, + fontWeight: true, + gridArea: true, + gridColumn: true, + gridColumnEnd: true, + gridColumnStart: true, + gridRow: true, + gridRowEnd: true, + gridRowStart: true, + lineHeight: true, + opacity: true, + order: true, + orphans: true, + scale: true, + widows: true, + zIndex: true, + zoom: true, + + // SVG-related + fillOpacity: true, + floodOpacity: true, + stopOpacity: true, + strokeMiterlimit: true, + strokeOpacity: true + }, + + // Add in properties whose names you wish to fix before + // setting or getting the value + cssProps: {}, + + // Get and set the style property on a DOM Node + style: function( elem, name, value, extra ) { + + // Don't set styles on text and comment nodes + if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) { + return; + } + + // Make sure that we're working with the right name + var ret, type, hooks, + origName = camelCase( name ), + isCustomProp = rcustomProp.test( name ), + style = elem.style; + + // Make sure that we're working with the right name. We don't + // want to query the value if it is a CSS custom property + // since they are user-defined. + if ( !isCustomProp ) { + name = finalPropName( origName ); + } + + // Gets hook for the prefixed version, then unprefixed version + hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; + + // Check if we're setting a value + if ( value !== undefined ) { + type = typeof value; + + // Convert "+=" or "-=" to relative numbers (trac-7345) + if ( type === "string" && ( ret = rcssNum.exec( value ) ) && ret[ 1 ] ) { + value = adjustCSS( elem, name, ret ); + + // Fixes bug trac-9237 + type = "number"; + } + + // Make sure that null and NaN values aren't set (trac-7116) + if ( value == null || value !== value ) { + return; + } + + // If a number was passed in, add the unit (except for certain CSS properties) + // The isCustomProp check can be removed in jQuery 4.0 when we only auto-append + // "px" to a few hardcoded values. + if ( type === "number" && !isCustomProp ) { + value += ret && ret[ 3 ] || ( jQuery.cssNumber[ origName ] ? "" : "px" ); + } + + // background-* props affect original clone's values + if ( !support.clearCloneStyle && value === "" && name.indexOf( "background" ) === 0 ) { + style[ name ] = "inherit"; + } + + // If a hook was provided, use that value, otherwise just set the specified value + if ( !hooks || !( "set" in hooks ) || + ( value = hooks.set( elem, value, extra ) ) !== undefined ) { + + if ( isCustomProp ) { + style.setProperty( name, value ); + } else { + style[ name ] = value; + } + } + + } else { + + // If a hook was provided get the non-computed value from there + if ( hooks && "get" in hooks && + ( ret = hooks.get( elem, false, extra ) ) !== undefined ) { + + return ret; + } + + // Otherwise just get the value from the style object + return style[ name ]; + } + }, + + css: function( elem, name, extra, styles ) { + var val, num, hooks, + origName = camelCase( name ), + isCustomProp = rcustomProp.test( name ); + + // Make sure that we're working with the right name. We don't + // want to modify the value if it is a CSS custom property + // since they are user-defined. + if ( !isCustomProp ) { + name = finalPropName( origName ); + } + + // Try prefixed name followed by the unprefixed name + hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; + + // If a hook was provided get the computed value from there + if ( hooks && "get" in hooks ) { + val = hooks.get( elem, true, extra ); + } + + // Otherwise, if a way to get the computed value exists, use that + if ( val === undefined ) { + val = curCSS( elem, name, styles ); + } + + // Convert "normal" to computed value + if ( val === "normal" && name in cssNormalTransform ) { + val = cssNormalTransform[ name ]; + } + + // Make numeric if forced or a qualifier was provided and val looks numeric + if ( extra === "" || extra ) { + num = parseFloat( val ); + return extra === true || isFinite( num ) ? num || 0 : val; + } + + return val; + } +} ); + +jQuery.each( [ "height", "width" ], function( _i, dimension ) { + jQuery.cssHooks[ dimension ] = { + get: function( elem, computed, extra ) { + if ( computed ) { + + // Certain elements can have dimension info if we invisibly show them + // but it must have a current display style that would benefit + return rdisplayswap.test( jQuery.css( elem, "display" ) ) && + + // Support: Safari 8+ + // Table columns in Safari have non-zero offsetWidth & zero + // getBoundingClientRect().width unless display is changed. + // Support: IE <=11 only + // Running getBoundingClientRect on a disconnected node + // in IE throws an error. + ( !elem.getClientRects().length || !elem.getBoundingClientRect().width ) ? + swap( elem, cssShow, function() { + return getWidthOrHeight( elem, dimension, extra ); + } ) : + getWidthOrHeight( elem, dimension, extra ); + } + }, + + set: function( elem, value, extra ) { + var matches, + styles = getStyles( elem ), + + // Only read styles.position if the test has a chance to fail + // to avoid forcing a reflow. + scrollboxSizeBuggy = !support.scrollboxSize() && + styles.position === "absolute", + + // To avoid forcing a reflow, only fetch boxSizing if we need it (gh-3991) + boxSizingNeeded = scrollboxSizeBuggy || extra, + isBorderBox = boxSizingNeeded && + jQuery.css( elem, "boxSizing", false, styles ) === "border-box", + subtract = extra ? + boxModelAdjustment( + elem, + dimension, + extra, + isBorderBox, + styles + ) : + 0; + + // Account for unreliable border-box dimensions by comparing offset* to computed and + // faking a content-box to get border and padding (gh-3699) + if ( isBorderBox && scrollboxSizeBuggy ) { + subtract -= Math.ceil( + elem[ "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] - + parseFloat( styles[ dimension ] ) - + boxModelAdjustment( elem, dimension, "border", false, styles ) - + 0.5 + ); + } + + // Convert to pixels if value adjustment is needed + if ( subtract && ( matches = rcssNum.exec( value ) ) && + ( matches[ 3 ] || "px" ) !== "px" ) { + + elem.style[ dimension ] = value; + value = jQuery.css( elem, dimension ); + } + + return setPositiveNumber( elem, value, subtract ); + } + }; +} ); + +jQuery.cssHooks.marginLeft = addGetHookIf( support.reliableMarginLeft, + function( elem, computed ) { + if ( computed ) { + return ( parseFloat( curCSS( elem, "marginLeft" ) ) || + elem.getBoundingClientRect().left - + swap( elem, { marginLeft: 0 }, function() { + return elem.getBoundingClientRect().left; + } ) + ) + "px"; + } + } +); + +// These hooks are used by animate to expand properties +jQuery.each( { + margin: "", + padding: "", + border: "Width" +}, function( prefix, suffix ) { + jQuery.cssHooks[ prefix + suffix ] = { + expand: function( value ) { + var i = 0, + expanded = {}, + + // Assumes a single number if not a string + parts = typeof value === "string" ? value.split( " " ) : [ value ]; + + for ( ; i < 4; i++ ) { + expanded[ prefix + cssExpand[ i ] + suffix ] = + parts[ i ] || parts[ i - 2 ] || parts[ 0 ]; + } + + return expanded; + } + }; + + if ( prefix !== "margin" ) { + jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber; + } +} ); + +jQuery.fn.extend( { + css: function( name, value ) { + return access( this, function( elem, name, value ) { + var styles, len, + map = {}, + i = 0; + + if ( Array.isArray( name ) ) { + styles = getStyles( elem ); + len = name.length; + + for ( ; i < len; i++ ) { + map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles ); + } + + return map; + } + + return value !== undefined ? + jQuery.style( elem, name, value ) : + jQuery.css( elem, name ); + }, name, value, arguments.length > 1 ); + } +} ); + + +function Tween( elem, options, prop, end, easing ) { + return new Tween.prototype.init( elem, options, prop, end, easing ); +} +jQuery.Tween = Tween; + +Tween.prototype = { + constructor: Tween, + init: function( elem, options, prop, end, easing, unit ) { + this.elem = elem; + this.prop = prop; + this.easing = easing || jQuery.easing._default; + this.options = options; + this.start = this.now = this.cur(); + this.end = end; + this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" ); + }, + cur: function() { + var hooks = Tween.propHooks[ this.prop ]; + + return hooks && hooks.get ? + hooks.get( this ) : + Tween.propHooks._default.get( this ); + }, + run: function( percent ) { + var eased, + hooks = Tween.propHooks[ this.prop ]; + + if ( this.options.duration ) { + this.pos = eased = jQuery.easing[ this.easing ]( + percent, this.options.duration * percent, 0, 1, this.options.duration + ); + } else { + this.pos = eased = percent; + } + this.now = ( this.end - this.start ) * eased + this.start; + + if ( this.options.step ) { + this.options.step.call( this.elem, this.now, this ); + } + + if ( hooks && hooks.set ) { + hooks.set( this ); + } else { + Tween.propHooks._default.set( this ); + } + return this; + } +}; + +Tween.prototype.init.prototype = Tween.prototype; + +Tween.propHooks = { + _default: { + get: function( tween ) { + var result; + + // Use a property on the element directly when it is not a DOM element, + // or when there is no matching style property that exists. + if ( tween.elem.nodeType !== 1 || + tween.elem[ tween.prop ] != null && tween.elem.style[ tween.prop ] == null ) { + return tween.elem[ tween.prop ]; + } + + // Passing an empty string as a 3rd parameter to .css will automatically + // attempt a parseFloat and fallback to a string if the parse fails. + // Simple values such as "10px" are parsed to Float; + // complex values such as "rotate(1rad)" are returned as-is. + result = jQuery.css( tween.elem, tween.prop, "" ); + + // Empty strings, null, undefined and "auto" are converted to 0. + return !result || result === "auto" ? 0 : result; + }, + set: function( tween ) { + + // Use step hook for back compat. + // Use cssHook if its there. + // Use .style if available and use plain properties where available. + if ( jQuery.fx.step[ tween.prop ] ) { + jQuery.fx.step[ tween.prop ]( tween ); + } else if ( tween.elem.nodeType === 1 && ( + jQuery.cssHooks[ tween.prop ] || + tween.elem.style[ finalPropName( tween.prop ) ] != null ) ) { + jQuery.style( tween.elem, tween.prop, tween.now + tween.unit ); + } else { + tween.elem[ tween.prop ] = tween.now; + } + } + } +}; + +// Support: IE <=9 only +// Panic based approach to setting things on disconnected nodes +Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = { + set: function( tween ) { + if ( tween.elem.nodeType && tween.elem.parentNode ) { + tween.elem[ tween.prop ] = tween.now; + } + } +}; + +jQuery.easing = { + linear: function( p ) { + return p; + }, + swing: function( p ) { + return 0.5 - Math.cos( p * Math.PI ) / 2; + }, + _default: "swing" +}; + +jQuery.fx = Tween.prototype.init; + +// Back compat <1.8 extension point +jQuery.fx.step = {}; + + + + +var + fxNow, inProgress, + rfxtypes = /^(?:toggle|show|hide)$/, + rrun = /queueHooks$/; + +function schedule() { + if ( inProgress ) { + if ( document.hidden === false && window.requestAnimationFrame ) { + window.requestAnimationFrame( schedule ); + } else { + window.setTimeout( schedule, jQuery.fx.interval ); + } + + jQuery.fx.tick(); + } +} + +// Animations created synchronously will run synchronously +function createFxNow() { + window.setTimeout( function() { + fxNow = undefined; + } ); + return ( fxNow = Date.now() ); +} + +// Generate parameters to create a standard animation +function genFx( type, includeWidth ) { + var which, + i = 0, + attrs = { height: type }; + + // If we include width, step value is 1 to do all cssExpand values, + // otherwise step value is 2 to skip over Left and Right + includeWidth = includeWidth ? 1 : 0; + for ( ; i < 4; i += 2 - includeWidth ) { + which = cssExpand[ i ]; + attrs[ "margin" + which ] = attrs[ "padding" + which ] = type; + } + + if ( includeWidth ) { + attrs.opacity = attrs.width = type; + } + + return attrs; +} + +function createTween( value, prop, animation ) { + var tween, + collection = ( Animation.tweeners[ prop ] || [] ).concat( Animation.tweeners[ "*" ] ), + index = 0, + length = collection.length; + for ( ; index < length; index++ ) { + if ( ( tween = collection[ index ].call( animation, prop, value ) ) ) { + + // We're done with this property + return tween; + } + } +} + +function defaultPrefilter( elem, props, opts ) { + var prop, value, toggle, hooks, oldfire, propTween, restoreDisplay, display, + isBox = "width" in props || "height" in props, + anim = this, + orig = {}, + style = elem.style, + hidden = elem.nodeType && isHiddenWithinTree( elem ), + dataShow = dataPriv.get( elem, "fxshow" ); + + // Queue-skipping animations hijack the fx hooks + if ( !opts.queue ) { + hooks = jQuery._queueHooks( elem, "fx" ); + if ( hooks.unqueued == null ) { + hooks.unqueued = 0; + oldfire = hooks.empty.fire; + hooks.empty.fire = function() { + if ( !hooks.unqueued ) { + oldfire(); + } + }; + } + hooks.unqueued++; + + anim.always( function() { + + // Ensure the complete handler is called before this completes + anim.always( function() { + hooks.unqueued--; + if ( !jQuery.queue( elem, "fx" ).length ) { + hooks.empty.fire(); + } + } ); + } ); + } + + // Detect show/hide animations + for ( prop in props ) { + value = props[ prop ]; + if ( rfxtypes.test( value ) ) { + delete props[ prop ]; + toggle = toggle || value === "toggle"; + if ( value === ( hidden ? "hide" : "show" ) ) { + + // Pretend to be hidden if this is a "show" and + // there is still data from a stopped show/hide + if ( value === "show" && dataShow && dataShow[ prop ] !== undefined ) { + hidden = true; + + // Ignore all other no-op show/hide data + } else { + continue; + } + } + orig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop ); + } + } + + // Bail out if this is a no-op like .hide().hide() + propTween = !jQuery.isEmptyObject( props ); + if ( !propTween && jQuery.isEmptyObject( orig ) ) { + return; + } + + // Restrict "overflow" and "display" styles during box animations + if ( isBox && elem.nodeType === 1 ) { + + // Support: IE <=9 - 11, Edge 12 - 15 + // Record all 3 overflow attributes because IE does not infer the shorthand + // from identically-valued overflowX and overflowY and Edge just mirrors + // the overflowX value there. + opts.overflow = [ style.overflow, style.overflowX, style.overflowY ]; + + // Identify a display type, preferring old show/hide data over the CSS cascade + restoreDisplay = dataShow && dataShow.display; + if ( restoreDisplay == null ) { + restoreDisplay = dataPriv.get( elem, "display" ); + } + display = jQuery.css( elem, "display" ); + if ( display === "none" ) { + if ( restoreDisplay ) { + display = restoreDisplay; + } else { + + // Get nonempty value(s) by temporarily forcing visibility + showHide( [ elem ], true ); + restoreDisplay = elem.style.display || restoreDisplay; + display = jQuery.css( elem, "display" ); + showHide( [ elem ] ); + } + } + + // Animate inline elements as inline-block + if ( display === "inline" || display === "inline-block" && restoreDisplay != null ) { + if ( jQuery.css( elem, "float" ) === "none" ) { + + // Restore the original display value at the end of pure show/hide animations + if ( !propTween ) { + anim.done( function() { + style.display = restoreDisplay; + } ); + if ( restoreDisplay == null ) { + display = style.display; + restoreDisplay = display === "none" ? "" : display; + } + } + style.display = "inline-block"; + } + } + } + + if ( opts.overflow ) { + style.overflow = "hidden"; + anim.always( function() { + style.overflow = opts.overflow[ 0 ]; + style.overflowX = opts.overflow[ 1 ]; + style.overflowY = opts.overflow[ 2 ]; + } ); + } + + // Implement show/hide animations + propTween = false; + for ( prop in orig ) { + + // General show/hide setup for this element animation + if ( !propTween ) { + if ( dataShow ) { + if ( "hidden" in dataShow ) { + hidden = dataShow.hidden; + } + } else { + dataShow = dataPriv.access( elem, "fxshow", { display: restoreDisplay } ); + } + + // Store hidden/visible for toggle so `.stop().toggle()` "reverses" + if ( toggle ) { + dataShow.hidden = !hidden; + } + + // Show elements before animating them + if ( hidden ) { + showHide( [ elem ], true ); + } + + /* eslint-disable no-loop-func */ + + anim.done( function() { + + /* eslint-enable no-loop-func */ + + // The final step of a "hide" animation is actually hiding the element + if ( !hidden ) { + showHide( [ elem ] ); + } + dataPriv.remove( elem, "fxshow" ); + for ( prop in orig ) { + jQuery.style( elem, prop, orig[ prop ] ); + } + } ); + } + + // Per-property setup + propTween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim ); + if ( !( prop in dataShow ) ) { + dataShow[ prop ] = propTween.start; + if ( hidden ) { + propTween.end = propTween.start; + propTween.start = 0; + } + } + } +} + +function propFilter( props, specialEasing ) { + var index, name, easing, value, hooks; + + // camelCase, specialEasing and expand cssHook pass + for ( index in props ) { + name = camelCase( index ); + easing = specialEasing[ name ]; + value = props[ index ]; + if ( Array.isArray( value ) ) { + easing = value[ 1 ]; + value = props[ index ] = value[ 0 ]; + } + + if ( index !== name ) { + props[ name ] = value; + delete props[ index ]; + } + + hooks = jQuery.cssHooks[ name ]; + if ( hooks && "expand" in hooks ) { + value = hooks.expand( value ); + delete props[ name ]; + + // Not quite $.extend, this won't overwrite existing keys. + // Reusing 'index' because we have the correct "name" + for ( index in value ) { + if ( !( index in props ) ) { + props[ index ] = value[ index ]; + specialEasing[ index ] = easing; + } + } + } else { + specialEasing[ name ] = easing; + } + } +} + +function Animation( elem, properties, options ) { + var result, + stopped, + index = 0, + length = Animation.prefilters.length, + deferred = jQuery.Deferred().always( function() { + + // Don't match elem in the :animated selector + delete tick.elem; + } ), + tick = function() { + if ( stopped ) { + return false; + } + var currentTime = fxNow || createFxNow(), + remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ), + + // Support: Android 2.3 only + // Archaic crash bug won't allow us to use `1 - ( 0.5 || 0 )` (trac-12497) + temp = remaining / animation.duration || 0, + percent = 1 - temp, + index = 0, + length = animation.tweens.length; + + for ( ; index < length; index++ ) { + animation.tweens[ index ].run( percent ); + } + + deferred.notifyWith( elem, [ animation, percent, remaining ] ); + + // If there's more to do, yield + if ( percent < 1 && length ) { + return remaining; + } + + // If this was an empty animation, synthesize a final progress notification + if ( !length ) { + deferred.notifyWith( elem, [ animation, 1, 0 ] ); + } + + // Resolve the animation and report its conclusion + deferred.resolveWith( elem, [ animation ] ); + return false; + }, + animation = deferred.promise( { + elem: elem, + props: jQuery.extend( {}, properties ), + opts: jQuery.extend( true, { + specialEasing: {}, + easing: jQuery.easing._default + }, options ), + originalProperties: properties, + originalOptions: options, + startTime: fxNow || createFxNow(), + duration: options.duration, + tweens: [], + createTween: function( prop, end ) { + var tween = jQuery.Tween( elem, animation.opts, prop, end, + animation.opts.specialEasing[ prop ] || animation.opts.easing ); + animation.tweens.push( tween ); + return tween; + }, + stop: function( gotoEnd ) { + var index = 0, + + // If we are going to the end, we want to run all the tweens + // otherwise we skip this part + length = gotoEnd ? animation.tweens.length : 0; + if ( stopped ) { + return this; + } + stopped = true; + for ( ; index < length; index++ ) { + animation.tweens[ index ].run( 1 ); + } + + // Resolve when we played the last frame; otherwise, reject + if ( gotoEnd ) { + deferred.notifyWith( elem, [ animation, 1, 0 ] ); + deferred.resolveWith( elem, [ animation, gotoEnd ] ); + } else { + deferred.rejectWith( elem, [ animation, gotoEnd ] ); + } + return this; + } + } ), + props = animation.props; + + propFilter( props, animation.opts.specialEasing ); + + for ( ; index < length; index++ ) { + result = Animation.prefilters[ index ].call( animation, elem, props, animation.opts ); + if ( result ) { + if ( isFunction( result.stop ) ) { + jQuery._queueHooks( animation.elem, animation.opts.queue ).stop = + result.stop.bind( result ); + } + return result; + } + } + + jQuery.map( props, createTween, animation ); + + if ( isFunction( animation.opts.start ) ) { + animation.opts.start.call( elem, animation ); + } + + // Attach callbacks from options + animation + .progress( animation.opts.progress ) + .done( animation.opts.done, animation.opts.complete ) + .fail( animation.opts.fail ) + .always( animation.opts.always ); + + jQuery.fx.timer( + jQuery.extend( tick, { + elem: elem, + anim: animation, + queue: animation.opts.queue + } ) + ); + + return animation; +} + +jQuery.Animation = jQuery.extend( Animation, { + + tweeners: { + "*": [ function( prop, value ) { + var tween = this.createTween( prop, value ); + adjustCSS( tween.elem, prop, rcssNum.exec( value ), tween ); + return tween; + } ] + }, + + tweener: function( props, callback ) { + if ( isFunction( props ) ) { + callback = props; + props = [ "*" ]; + } else { + props = props.match( rnothtmlwhite ); + } + + var prop, + index = 0, + length = props.length; + + for ( ; index < length; index++ ) { + prop = props[ index ]; + Animation.tweeners[ prop ] = Animation.tweeners[ prop ] || []; + Animation.tweeners[ prop ].unshift( callback ); + } + }, + + prefilters: [ defaultPrefilter ], + + prefilter: function( callback, prepend ) { + if ( prepend ) { + Animation.prefilters.unshift( callback ); + } else { + Animation.prefilters.push( callback ); + } + } +} ); + +jQuery.speed = function( speed, easing, fn ) { + var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : { + complete: fn || !fn && easing || + isFunction( speed ) && speed, + duration: speed, + easing: fn && easing || easing && !isFunction( easing ) && easing + }; + + // Go to the end state if fx are off + if ( jQuery.fx.off ) { + opt.duration = 0; + + } else { + if ( typeof opt.duration !== "number" ) { + if ( opt.duration in jQuery.fx.speeds ) { + opt.duration = jQuery.fx.speeds[ opt.duration ]; + + } else { + opt.duration = jQuery.fx.speeds._default; + } + } + } + + // Normalize opt.queue - true/undefined/null -> "fx" + if ( opt.queue == null || opt.queue === true ) { + opt.queue = "fx"; + } + + // Queueing + opt.old = opt.complete; + + opt.complete = function() { + if ( isFunction( opt.old ) ) { + opt.old.call( this ); + } + + if ( opt.queue ) { + jQuery.dequeue( this, opt.queue ); + } + }; + + return opt; +}; + +jQuery.fn.extend( { + fadeTo: function( speed, to, easing, callback ) { + + // Show any hidden elements after setting opacity to 0 + return this.filter( isHiddenWithinTree ).css( "opacity", 0 ).show() + + // Animate to the value specified + .end().animate( { opacity: to }, speed, easing, callback ); + }, + animate: function( prop, speed, easing, callback ) { + var empty = jQuery.isEmptyObject( prop ), + optall = jQuery.speed( speed, easing, callback ), + doAnimation = function() { + + // Operate on a copy of prop so per-property easing won't be lost + var anim = Animation( this, jQuery.extend( {}, prop ), optall ); + + // Empty animations, or finishing resolves immediately + if ( empty || dataPriv.get( this, "finish" ) ) { + anim.stop( true ); + } + }; + + doAnimation.finish = doAnimation; + + return empty || optall.queue === false ? + this.each( doAnimation ) : + this.queue( optall.queue, doAnimation ); + }, + stop: function( type, clearQueue, gotoEnd ) { + var stopQueue = function( hooks ) { + var stop = hooks.stop; + delete hooks.stop; + stop( gotoEnd ); + }; + + if ( typeof type !== "string" ) { + gotoEnd = clearQueue; + clearQueue = type; + type = undefined; + } + if ( clearQueue ) { + this.queue( type || "fx", [] ); + } + + return this.each( function() { + var dequeue = true, + index = type != null && type + "queueHooks", + timers = jQuery.timers, + data = dataPriv.get( this ); + + if ( index ) { + if ( data[ index ] && data[ index ].stop ) { + stopQueue( data[ index ] ); + } + } else { + for ( index in data ) { + if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) { + stopQueue( data[ index ] ); + } + } + } + + for ( index = timers.length; index--; ) { + if ( timers[ index ].elem === this && + ( type == null || timers[ index ].queue === type ) ) { + + timers[ index ].anim.stop( gotoEnd ); + dequeue = false; + timers.splice( index, 1 ); + } + } + + // Start the next in the queue if the last step wasn't forced. + // Timers currently will call their complete callbacks, which + // will dequeue but only if they were gotoEnd. + if ( dequeue || !gotoEnd ) { + jQuery.dequeue( this, type ); + } + } ); + }, + finish: function( type ) { + if ( type !== false ) { + type = type || "fx"; + } + return this.each( function() { + var index, + data = dataPriv.get( this ), + queue = data[ type + "queue" ], + hooks = data[ type + "queueHooks" ], + timers = jQuery.timers, + length = queue ? queue.length : 0; + + // Enable finishing flag on private data + data.finish = true; + + // Empty the queue first + jQuery.queue( this, type, [] ); + + if ( hooks && hooks.stop ) { + hooks.stop.call( this, true ); + } + + // Look for any active animations, and finish them + for ( index = timers.length; index--; ) { + if ( timers[ index ].elem === this && timers[ index ].queue === type ) { + timers[ index ].anim.stop( true ); + timers.splice( index, 1 ); + } + } + + // Look for any animations in the old queue and finish them + for ( index = 0; index < length; index++ ) { + if ( queue[ index ] && queue[ index ].finish ) { + queue[ index ].finish.call( this ); + } + } + + // Turn off finishing flag + delete data.finish; + } ); + } +} ); + +jQuery.each( [ "toggle", "show", "hide" ], function( _i, name ) { + var cssFn = jQuery.fn[ name ]; + jQuery.fn[ name ] = function( speed, easing, callback ) { + return speed == null || typeof speed === "boolean" ? + cssFn.apply( this, arguments ) : + this.animate( genFx( name, true ), speed, easing, callback ); + }; +} ); + +// Generate shortcuts for custom animations +jQuery.each( { + slideDown: genFx( "show" ), + slideUp: genFx( "hide" ), + slideToggle: genFx( "toggle" ), + fadeIn: { opacity: "show" }, + fadeOut: { opacity: "hide" }, + fadeToggle: { opacity: "toggle" } +}, function( name, props ) { + jQuery.fn[ name ] = function( speed, easing, callback ) { + return this.animate( props, speed, easing, callback ); + }; +} ); + +jQuery.timers = []; +jQuery.fx.tick = function() { + var timer, + i = 0, + timers = jQuery.timers; + + fxNow = Date.now(); + + for ( ; i < timers.length; i++ ) { + timer = timers[ i ]; + + // Run the timer and safely remove it when done (allowing for external removal) + if ( !timer() && timers[ i ] === timer ) { + timers.splice( i--, 1 ); + } + } + + if ( !timers.length ) { + jQuery.fx.stop(); + } + fxNow = undefined; +}; + +jQuery.fx.timer = function( timer ) { + jQuery.timers.push( timer ); + jQuery.fx.start(); +}; + +jQuery.fx.interval = 13; +jQuery.fx.start = function() { + if ( inProgress ) { + return; + } + + inProgress = true; + schedule(); +}; + +jQuery.fx.stop = function() { + inProgress = null; +}; + +jQuery.fx.speeds = { + slow: 600, + fast: 200, + + // Default speed + _default: 400 +}; + + +// Based off of the plugin by Clint Helfers, with permission. +jQuery.fn.delay = function( time, type ) { + time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time; + type = type || "fx"; + + return this.queue( type, function( next, hooks ) { + var timeout = window.setTimeout( next, time ); + hooks.stop = function() { + window.clearTimeout( timeout ); + }; + } ); +}; + + +( function() { + var input = document.createElement( "input" ), + select = document.createElement( "select" ), + opt = select.appendChild( document.createElement( "option" ) ); + + input.type = "checkbox"; + + // Support: Android <=4.3 only + // Default value for a checkbox should be "on" + support.checkOn = input.value !== ""; + + // Support: IE <=11 only + // Must access selectedIndex to make default options select + support.optSelected = opt.selected; + + // Support: IE <=11 only + // An input loses its value after becoming a radio + input = document.createElement( "input" ); + input.value = "t"; + input.type = "radio"; + support.radioValue = input.value === "t"; +} )(); + + +var boolHook, + attrHandle = jQuery.expr.attrHandle; + +jQuery.fn.extend( { + attr: function( name, value ) { + return access( this, jQuery.attr, name, value, arguments.length > 1 ); + }, + + removeAttr: function( name ) { + return this.each( function() { + jQuery.removeAttr( this, name ); + } ); + } +} ); + +jQuery.extend( { + attr: function( elem, name, value ) { + var ret, hooks, + nType = elem.nodeType; + + // Don't get/set attributes on text, comment and attribute nodes + if ( nType === 3 || nType === 8 || nType === 2 ) { + return; + } + + // Fallback to prop when attributes are not supported + if ( typeof elem.getAttribute === "undefined" ) { + return jQuery.prop( elem, name, value ); + } + + // Attribute hooks are determined by the lowercase version + // Grab necessary hook if one is defined + if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { + hooks = jQuery.attrHooks[ name.toLowerCase() ] || + ( jQuery.expr.match.bool.test( name ) ? boolHook : undefined ); + } + + if ( value !== undefined ) { + if ( value === null ) { + jQuery.removeAttr( elem, name ); + return; + } + + if ( hooks && "set" in hooks && + ( ret = hooks.set( elem, value, name ) ) !== undefined ) { + return ret; + } + + elem.setAttribute( name, value + "" ); + return value; + } + + if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) { + return ret; + } + + ret = jQuery.find.attr( elem, name ); + + // Non-existent attributes return null, we normalize to undefined + return ret == null ? undefined : ret; + }, + + attrHooks: { + type: { + set: function( elem, value ) { + if ( !support.radioValue && value === "radio" && + nodeName( elem, "input" ) ) { + var val = elem.value; + elem.setAttribute( "type", value ); + if ( val ) { + elem.value = val; + } + return value; + } + } + } + }, + + removeAttr: function( elem, value ) { + var name, + i = 0, + + // Attribute names can contain non-HTML whitespace characters + // https://html.spec.whatwg.org/multipage/syntax.html#attributes-2 + attrNames = value && value.match( rnothtmlwhite ); + + if ( attrNames && elem.nodeType === 1 ) { + while ( ( name = attrNames[ i++ ] ) ) { + elem.removeAttribute( name ); + } + } + } +} ); + +// Hooks for boolean attributes +boolHook = { + set: function( elem, value, name ) { + if ( value === false ) { + + // Remove boolean attributes when set to false + jQuery.removeAttr( elem, name ); + } else { + elem.setAttribute( name, name ); + } + return name; + } +}; + +jQuery.each( jQuery.expr.match.bool.source.match( /\w+/g ), function( _i, name ) { + var getter = attrHandle[ name ] || jQuery.find.attr; + + attrHandle[ name ] = function( elem, name, isXML ) { + var ret, handle, + lowercaseName = name.toLowerCase(); + + if ( !isXML ) { + + // Avoid an infinite loop by temporarily removing this function from the getter + handle = attrHandle[ lowercaseName ]; + attrHandle[ lowercaseName ] = ret; + ret = getter( elem, name, isXML ) != null ? + lowercaseName : + null; + attrHandle[ lowercaseName ] = handle; + } + return ret; + }; +} ); + + + + +var rfocusable = /^(?:input|select|textarea|button)$/i, + rclickable = /^(?:a|area)$/i; + +jQuery.fn.extend( { + prop: function( name, value ) { + return access( this, jQuery.prop, name, value, arguments.length > 1 ); + }, + + removeProp: function( name ) { + return this.each( function() { + delete this[ jQuery.propFix[ name ] || name ]; + } ); + } +} ); + +jQuery.extend( { + prop: function( elem, name, value ) { + var ret, hooks, + nType = elem.nodeType; + + // Don't get/set properties on text, comment and attribute nodes + if ( nType === 3 || nType === 8 || nType === 2 ) { + return; + } + + if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { + + // Fix name and attach hooks + name = jQuery.propFix[ name ] || name; + hooks = jQuery.propHooks[ name ]; + } + + if ( value !== undefined ) { + if ( hooks && "set" in hooks && + ( ret = hooks.set( elem, value, name ) ) !== undefined ) { + return ret; + } + + return ( elem[ name ] = value ); + } + + if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) { + return ret; + } + + return elem[ name ]; + }, + + propHooks: { + tabIndex: { + get: function( elem ) { + + // Support: IE <=9 - 11 only + // elem.tabIndex doesn't always return the + // correct value when it hasn't been explicitly set + // Use proper attribute retrieval (trac-12072) + var tabindex = jQuery.find.attr( elem, "tabindex" ); + + if ( tabindex ) { + return parseInt( tabindex, 10 ); + } + + if ( + rfocusable.test( elem.nodeName ) || + rclickable.test( elem.nodeName ) && + elem.href + ) { + return 0; + } + + return -1; + } + } + }, + + propFix: { + "for": "htmlFor", + "class": "className" + } +} ); + +// Support: IE <=11 only +// Accessing the selectedIndex property +// forces the browser to respect setting selected +// on the option +// The getter ensures a default option is selected +// when in an optgroup +// eslint rule "no-unused-expressions" is disabled for this code +// since it considers such accessions noop +if ( !support.optSelected ) { + jQuery.propHooks.selected = { + get: function( elem ) { + + /* eslint no-unused-expressions: "off" */ + + var parent = elem.parentNode; + if ( parent && parent.parentNode ) { + parent.parentNode.selectedIndex; + } + return null; + }, + set: function( elem ) { + + /* eslint no-unused-expressions: "off" */ + + var parent = elem.parentNode; + if ( parent ) { + parent.selectedIndex; + + if ( parent.parentNode ) { + parent.parentNode.selectedIndex; + } + } + } + }; +} + +jQuery.each( [ + "tabIndex", + "readOnly", + "maxLength", + "cellSpacing", + "cellPadding", + "rowSpan", + "colSpan", + "useMap", + "frameBorder", + "contentEditable" +], function() { + jQuery.propFix[ this.toLowerCase() ] = this; +} ); + + + + + // Strip and collapse whitespace according to HTML spec + // https://infra.spec.whatwg.org/#strip-and-collapse-ascii-whitespace + function stripAndCollapse( value ) { + var tokens = value.match( rnothtmlwhite ) || []; + return tokens.join( " " ); + } + + +function getClass( elem ) { + return elem.getAttribute && elem.getAttribute( "class" ) || ""; +} + +function classesToArray( value ) { + if ( Array.isArray( value ) ) { + return value; + } + if ( typeof value === "string" ) { + return value.match( rnothtmlwhite ) || []; + } + return []; +} + +jQuery.fn.extend( { + addClass: function( value ) { + var classNames, cur, curValue, className, i, finalValue; + + if ( isFunction( value ) ) { + return this.each( function( j ) { + jQuery( this ).addClass( value.call( this, j, getClass( this ) ) ); + } ); + } + + classNames = classesToArray( value ); + + if ( classNames.length ) { + return this.each( function() { + curValue = getClass( this ); + cur = this.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " ); + + if ( cur ) { + for ( i = 0; i < classNames.length; i++ ) { + className = classNames[ i ]; + if ( cur.indexOf( " " + className + " " ) < 0 ) { + cur += className + " "; + } + } + + // Only assign if different to avoid unneeded rendering. + finalValue = stripAndCollapse( cur ); + if ( curValue !== finalValue ) { + this.setAttribute( "class", finalValue ); + } + } + } ); + } + + return this; + }, + + removeClass: function( value ) { + var classNames, cur, curValue, className, i, finalValue; + + if ( isFunction( value ) ) { + return this.each( function( j ) { + jQuery( this ).removeClass( value.call( this, j, getClass( this ) ) ); + } ); + } + + if ( !arguments.length ) { + return this.attr( "class", "" ); + } + + classNames = classesToArray( value ); + + if ( classNames.length ) { + return this.each( function() { + curValue = getClass( this ); + + // This expression is here for better compressibility (see addClass) + cur = this.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " ); + + if ( cur ) { + for ( i = 0; i < classNames.length; i++ ) { + className = classNames[ i ]; + + // Remove *all* instances + while ( cur.indexOf( " " + className + " " ) > -1 ) { + cur = cur.replace( " " + className + " ", " " ); + } + } + + // Only assign if different to avoid unneeded rendering. + finalValue = stripAndCollapse( cur ); + if ( curValue !== finalValue ) { + this.setAttribute( "class", finalValue ); + } + } + } ); + } + + return this; + }, + + toggleClass: function( value, stateVal ) { + var classNames, className, i, self, + type = typeof value, + isValidValue = type === "string" || Array.isArray( value ); + + if ( isFunction( value ) ) { + return this.each( function( i ) { + jQuery( this ).toggleClass( + value.call( this, i, getClass( this ), stateVal ), + stateVal + ); + } ); + } + + if ( typeof stateVal === "boolean" && isValidValue ) { + return stateVal ? this.addClass( value ) : this.removeClass( value ); + } + + classNames = classesToArray( value ); + + return this.each( function() { + if ( isValidValue ) { + + // Toggle individual class names + self = jQuery( this ); + + for ( i = 0; i < classNames.length; i++ ) { + className = classNames[ i ]; + + // Check each className given, space separated list + if ( self.hasClass( className ) ) { + self.removeClass( className ); + } else { + self.addClass( className ); + } + } + + // Toggle whole class name + } else if ( value === undefined || type === "boolean" ) { + className = getClass( this ); + if ( className ) { + + // Store className if set + dataPriv.set( this, "__className__", className ); + } + + // If the element has a class name or if we're passed `false`, + // then remove the whole classname (if there was one, the above saved it). + // Otherwise bring back whatever was previously saved (if anything), + // falling back to the empty string if nothing was stored. + if ( this.setAttribute ) { + this.setAttribute( "class", + className || value === false ? + "" : + dataPriv.get( this, "__className__" ) || "" + ); + } + } + } ); + }, + + hasClass: function( selector ) { + var className, elem, + i = 0; + + className = " " + selector + " "; + while ( ( elem = this[ i++ ] ) ) { + if ( elem.nodeType === 1 && + ( " " + stripAndCollapse( getClass( elem ) ) + " " ).indexOf( className ) > -1 ) { + return true; + } + } + + return false; + } +} ); + + + + +var rreturn = /\r/g; + +jQuery.fn.extend( { + val: function( value ) { + var hooks, ret, valueIsFunction, + elem = this[ 0 ]; + + if ( !arguments.length ) { + if ( elem ) { + hooks = jQuery.valHooks[ elem.type ] || + jQuery.valHooks[ elem.nodeName.toLowerCase() ]; + + if ( hooks && + "get" in hooks && + ( ret = hooks.get( elem, "value" ) ) !== undefined + ) { + return ret; + } + + ret = elem.value; + + // Handle most common string cases + if ( typeof ret === "string" ) { + return ret.replace( rreturn, "" ); + } + + // Handle cases where value is null/undef or number + return ret == null ? "" : ret; + } + + return; + } + + valueIsFunction = isFunction( value ); + + return this.each( function( i ) { + var val; + + if ( this.nodeType !== 1 ) { + return; + } + + if ( valueIsFunction ) { + val = value.call( this, i, jQuery( this ).val() ); + } else { + val = value; + } + + // Treat null/undefined as ""; convert numbers to string + if ( val == null ) { + val = ""; + + } else if ( typeof val === "number" ) { + val += ""; + + } else if ( Array.isArray( val ) ) { + val = jQuery.map( val, function( value ) { + return value == null ? "" : value + ""; + } ); + } + + hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ]; + + // If set returns undefined, fall back to normal setting + if ( !hooks || !( "set" in hooks ) || hooks.set( this, val, "value" ) === undefined ) { + this.value = val; + } + } ); + } +} ); + +jQuery.extend( { + valHooks: { + option: { + get: function( elem ) { + + var val = jQuery.find.attr( elem, "value" ); + return val != null ? + val : + + // Support: IE <=10 - 11 only + // option.text throws exceptions (trac-14686, trac-14858) + // Strip and collapse whitespace + // https://html.spec.whatwg.org/#strip-and-collapse-whitespace + stripAndCollapse( jQuery.text( elem ) ); + } + }, + select: { + get: function( elem ) { + var value, option, i, + options = elem.options, + index = elem.selectedIndex, + one = elem.type === "select-one", + values = one ? null : [], + max = one ? index + 1 : options.length; + + if ( index < 0 ) { + i = max; + + } else { + i = one ? index : 0; + } + + // Loop through all the selected options + for ( ; i < max; i++ ) { + option = options[ i ]; + + // Support: IE <=9 only + // IE8-9 doesn't update selected after form reset (trac-2551) + if ( ( option.selected || i === index ) && + + // Don't return options that are disabled or in a disabled optgroup + !option.disabled && + ( !option.parentNode.disabled || + !nodeName( option.parentNode, "optgroup" ) ) ) { + + // Get the specific value for the option + value = jQuery( option ).val(); + + // We don't need an array for one selects + if ( one ) { + return value; + } + + // Multi-Selects return an array + values.push( value ); + } + } + + return values; + }, + + set: function( elem, value ) { + var optionSet, option, + options = elem.options, + values = jQuery.makeArray( value ), + i = options.length; + + while ( i-- ) { + option = options[ i ]; + + /* eslint-disable no-cond-assign */ + + if ( option.selected = + jQuery.inArray( jQuery.valHooks.option.get( option ), values ) > -1 + ) { + optionSet = true; + } + + /* eslint-enable no-cond-assign */ + } + + // Force browsers to behave consistently when non-matching value is set + if ( !optionSet ) { + elem.selectedIndex = -1; + } + return values; + } + } + } +} ); + +// Radios and checkboxes getter/setter +jQuery.each( [ "radio", "checkbox" ], function() { + jQuery.valHooks[ this ] = { + set: function( elem, value ) { + if ( Array.isArray( value ) ) { + return ( elem.checked = jQuery.inArray( jQuery( elem ).val(), value ) > -1 ); + } + } + }; + if ( !support.checkOn ) { + jQuery.valHooks[ this ].get = function( elem ) { + return elem.getAttribute( "value" ) === null ? "on" : elem.value; + }; + } +} ); + + + + +// Return jQuery for attributes-only inclusion +var location = window.location; + +var nonce = { guid: Date.now() }; + +var rquery = ( /\?/ ); + + + +// Cross-browser xml parsing +jQuery.parseXML = function( data ) { + var xml, parserErrorElem; + if ( !data || typeof data !== "string" ) { + return null; + } + + // Support: IE 9 - 11 only + // IE throws on parseFromString with invalid input. + try { + xml = ( new window.DOMParser() ).parseFromString( data, "text/xml" ); + } catch ( e ) {} + + parserErrorElem = xml && xml.getElementsByTagName( "parsererror" )[ 0 ]; + if ( !xml || parserErrorElem ) { + jQuery.error( "Invalid XML: " + ( + parserErrorElem ? + jQuery.map( parserErrorElem.childNodes, function( el ) { + return el.textContent; + } ).join( "\n" ) : + data + ) ); + } + return xml; +}; + + +var rfocusMorph = /^(?:focusinfocus|focusoutblur)$/, + stopPropagationCallback = function( e ) { + e.stopPropagation(); + }; + +jQuery.extend( jQuery.event, { + + trigger: function( event, data, elem, onlyHandlers ) { + + var i, cur, tmp, bubbleType, ontype, handle, special, lastElement, + eventPath = [ elem || document ], + type = hasOwn.call( event, "type" ) ? event.type : event, + namespaces = hasOwn.call( event, "namespace" ) ? event.namespace.split( "." ) : []; + + cur = lastElement = tmp = elem = elem || document; + + // Don't do events on text and comment nodes + if ( elem.nodeType === 3 || elem.nodeType === 8 ) { + return; + } + + // focus/blur morphs to focusin/out; ensure we're not firing them right now + if ( rfocusMorph.test( type + jQuery.event.triggered ) ) { + return; + } + + if ( type.indexOf( "." ) > -1 ) { + + // Namespaced trigger; create a regexp to match event type in handle() + namespaces = type.split( "." ); + type = namespaces.shift(); + namespaces.sort(); + } + ontype = type.indexOf( ":" ) < 0 && "on" + type; + + // Caller can pass in a jQuery.Event object, Object, or just an event type string + event = event[ jQuery.expando ] ? + event : + new jQuery.Event( type, typeof event === "object" && event ); + + // Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true) + event.isTrigger = onlyHandlers ? 2 : 3; + event.namespace = namespaces.join( "." ); + event.rnamespace = event.namespace ? + new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ) : + null; + + // Clean up the event in case it is being reused + event.result = undefined; + if ( !event.target ) { + event.target = elem; + } + + // Clone any incoming data and prepend the event, creating the handler arg list + data = data == null ? + [ event ] : + jQuery.makeArray( data, [ event ] ); + + // Allow special events to draw outside the lines + special = jQuery.event.special[ type ] || {}; + if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) { + return; + } + + // Determine event propagation path in advance, per W3C events spec (trac-9951) + // Bubble up to document, then to window; watch for a global ownerDocument var (trac-9724) + if ( !onlyHandlers && !special.noBubble && !isWindow( elem ) ) { + + bubbleType = special.delegateType || type; + if ( !rfocusMorph.test( bubbleType + type ) ) { + cur = cur.parentNode; + } + for ( ; cur; cur = cur.parentNode ) { + eventPath.push( cur ); + tmp = cur; + } + + // Only add window if we got to document (e.g., not plain obj or detached DOM) + if ( tmp === ( elem.ownerDocument || document ) ) { + eventPath.push( tmp.defaultView || tmp.parentWindow || window ); + } + } + + // Fire handlers on the event path + i = 0; + while ( ( cur = eventPath[ i++ ] ) && !event.isPropagationStopped() ) { + lastElement = cur; + event.type = i > 1 ? + bubbleType : + special.bindType || type; + + // jQuery handler + handle = ( dataPriv.get( cur, "events" ) || Object.create( null ) )[ event.type ] && + dataPriv.get( cur, "handle" ); + if ( handle ) { + handle.apply( cur, data ); + } + + // Native handler + handle = ontype && cur[ ontype ]; + if ( handle && handle.apply && acceptData( cur ) ) { + event.result = handle.apply( cur, data ); + if ( event.result === false ) { + event.preventDefault(); + } + } + } + event.type = type; + + // If nobody prevented the default action, do it now + if ( !onlyHandlers && !event.isDefaultPrevented() ) { + + if ( ( !special._default || + special._default.apply( eventPath.pop(), data ) === false ) && + acceptData( elem ) ) { + + // Call a native DOM method on the target with the same name as the event. + // Don't do default actions on window, that's where global variables be (trac-6170) + if ( ontype && isFunction( elem[ type ] ) && !isWindow( elem ) ) { + + // Don't re-trigger an onFOO event when we call its FOO() method + tmp = elem[ ontype ]; + + if ( tmp ) { + elem[ ontype ] = null; + } + + // Prevent re-triggering of the same event, since we already bubbled it above + jQuery.event.triggered = type; + + if ( event.isPropagationStopped() ) { + lastElement.addEventListener( type, stopPropagationCallback ); + } + + elem[ type ](); + + if ( event.isPropagationStopped() ) { + lastElement.removeEventListener( type, stopPropagationCallback ); + } + + jQuery.event.triggered = undefined; + + if ( tmp ) { + elem[ ontype ] = tmp; + } + } + } + } + + return event.result; + }, + + // Piggyback on a donor event to simulate a different one + // Used only for `focus(in | out)` events + simulate: function( type, elem, event ) { + var e = jQuery.extend( + new jQuery.Event(), + event, + { + type: type, + isSimulated: true + } + ); + + jQuery.event.trigger( e, null, elem ); + } + +} ); + +jQuery.fn.extend( { + + trigger: function( type, data ) { + return this.each( function() { + jQuery.event.trigger( type, data, this ); + } ); + }, + triggerHandler: function( type, data ) { + var elem = this[ 0 ]; + if ( elem ) { + return jQuery.event.trigger( type, data, elem, true ); + } + } +} ); + + +var + rbracket = /\[\]$/, + rCRLF = /\r?\n/g, + rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i, + rsubmittable = /^(?:input|select|textarea|keygen)/i; + +function buildParams( prefix, obj, traditional, add ) { + var name; + + if ( Array.isArray( obj ) ) { + + // Serialize array item. + jQuery.each( obj, function( i, v ) { + if ( traditional || rbracket.test( prefix ) ) { + + // Treat each array item as a scalar. + add( prefix, v ); + + } else { + + // Item is non-scalar (array or object), encode its numeric index. + buildParams( + prefix + "[" + ( typeof v === "object" && v != null ? i : "" ) + "]", + v, + traditional, + add + ); + } + } ); + + } else if ( !traditional && toType( obj ) === "object" ) { + + // Serialize object item. + for ( name in obj ) { + buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add ); + } + + } else { + + // Serialize scalar item. + add( prefix, obj ); + } +} + +// Serialize an array of form elements or a set of +// key/values into a query string +jQuery.param = function( a, traditional ) { + var prefix, + s = [], + add = function( key, valueOrFunction ) { + + // If value is a function, invoke it and use its return value + var value = isFunction( valueOrFunction ) ? + valueOrFunction() : + valueOrFunction; + + s[ s.length ] = encodeURIComponent( key ) + "=" + + encodeURIComponent( value == null ? "" : value ); + }; + + if ( a == null ) { + return ""; + } + + // If an array was passed in, assume that it is an array of form elements. + if ( Array.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) { + + // Serialize the form elements + jQuery.each( a, function() { + add( this.name, this.value ); + } ); + + } else { + + // If traditional, encode the "old" way (the way 1.3.2 or older + // did it), otherwise encode params recursively. + for ( prefix in a ) { + buildParams( prefix, a[ prefix ], traditional, add ); + } + } + + // Return the resulting serialization + return s.join( "&" ); +}; + +jQuery.fn.extend( { + serialize: function() { + return jQuery.param( this.serializeArray() ); + }, + serializeArray: function() { + return this.map( function() { + + // Can add propHook for "elements" to filter or add form elements + var elements = jQuery.prop( this, "elements" ); + return elements ? jQuery.makeArray( elements ) : this; + } ).filter( function() { + var type = this.type; + + // Use .is( ":disabled" ) so that fieldset[disabled] works + return this.name && !jQuery( this ).is( ":disabled" ) && + rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) && + ( this.checked || !rcheckableType.test( type ) ); + } ).map( function( _i, elem ) { + var val = jQuery( this ).val(); + + if ( val == null ) { + return null; + } + + if ( Array.isArray( val ) ) { + return jQuery.map( val, function( val ) { + return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; + } ); + } + + return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; + } ).get(); + } +} ); + + +var + r20 = /%20/g, + rhash = /#.*$/, + rantiCache = /([?&])_=[^&]*/, + rheaders = /^(.*?):[ \t]*([^\r\n]*)$/mg, + + // trac-7653, trac-8125, trac-8152: local protocol detection + rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/, + rnoContent = /^(?:GET|HEAD)$/, + rprotocol = /^\/\//, + + /* Prefilters + * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example) + * 2) These are called: + * - BEFORE asking for a transport + * - AFTER param serialization (s.data is a string if s.processData is true) + * 3) key is the dataType + * 4) the catchall symbol "*" can be used + * 5) execution will start with transport dataType and THEN continue down to "*" if needed + */ + prefilters = {}, + + /* Transports bindings + * 1) key is the dataType + * 2) the catchall symbol "*" can be used + * 3) selection will start with transport dataType and THEN go to "*" if needed + */ + transports = {}, + + // Avoid comment-prolog char sequence (trac-10098); must appease lint and evade compression + allTypes = "*/".concat( "*" ), + + // Anchor tag for parsing the document origin + originAnchor = document.createElement( "a" ); + +originAnchor.href = location.href; + +// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport +function addToPrefiltersOrTransports( structure ) { + + // dataTypeExpression is optional and defaults to "*" + return function( dataTypeExpression, func ) { + + if ( typeof dataTypeExpression !== "string" ) { + func = dataTypeExpression; + dataTypeExpression = "*"; + } + + var dataType, + i = 0, + dataTypes = dataTypeExpression.toLowerCase().match( rnothtmlwhite ) || []; + + if ( isFunction( func ) ) { + + // For each dataType in the dataTypeExpression + while ( ( dataType = dataTypes[ i++ ] ) ) { + + // Prepend if requested + if ( dataType[ 0 ] === "+" ) { + dataType = dataType.slice( 1 ) || "*"; + ( structure[ dataType ] = structure[ dataType ] || [] ).unshift( func ); + + // Otherwise append + } else { + ( structure[ dataType ] = structure[ dataType ] || [] ).push( func ); + } + } + } + }; +} + +// Base inspection function for prefilters and transports +function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) { + + var inspected = {}, + seekingTransport = ( structure === transports ); + + function inspect( dataType ) { + var selected; + inspected[ dataType ] = true; + jQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) { + var dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR ); + if ( typeof dataTypeOrTransport === "string" && + !seekingTransport && !inspected[ dataTypeOrTransport ] ) { + + options.dataTypes.unshift( dataTypeOrTransport ); + inspect( dataTypeOrTransport ); + return false; + } else if ( seekingTransport ) { + return !( selected = dataTypeOrTransport ); + } + } ); + return selected; + } + + return inspect( options.dataTypes[ 0 ] ) || !inspected[ "*" ] && inspect( "*" ); +} + +// A special extend for ajax options +// that takes "flat" options (not to be deep extended) +// Fixes trac-9887 +function ajaxExtend( target, src ) { + var key, deep, + flatOptions = jQuery.ajaxSettings.flatOptions || {}; + + for ( key in src ) { + if ( src[ key ] !== undefined ) { + ( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ]; + } + } + if ( deep ) { + jQuery.extend( true, target, deep ); + } + + return target; +} + +/* Handles responses to an ajax request: + * - finds the right dataType (mediates between content-type and expected dataType) + * - returns the corresponding response + */ +function ajaxHandleResponses( s, jqXHR, responses ) { + + var ct, type, finalDataType, firstDataType, + contents = s.contents, + dataTypes = s.dataTypes; + + // Remove auto dataType and get content-type in the process + while ( dataTypes[ 0 ] === "*" ) { + dataTypes.shift(); + if ( ct === undefined ) { + ct = s.mimeType || jqXHR.getResponseHeader( "Content-Type" ); + } + } + + // Check if we're dealing with a known content-type + if ( ct ) { + for ( type in contents ) { + if ( contents[ type ] && contents[ type ].test( ct ) ) { + dataTypes.unshift( type ); + break; + } + } + } + + // Check to see if we have a response for the expected dataType + if ( dataTypes[ 0 ] in responses ) { + finalDataType = dataTypes[ 0 ]; + } else { + + // Try convertible dataTypes + for ( type in responses ) { + if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[ 0 ] ] ) { + finalDataType = type; + break; + } + if ( !firstDataType ) { + firstDataType = type; + } + } + + // Or just use first one + finalDataType = finalDataType || firstDataType; + } + + // If we found a dataType + // We add the dataType to the list if needed + // and return the corresponding response + if ( finalDataType ) { + if ( finalDataType !== dataTypes[ 0 ] ) { + dataTypes.unshift( finalDataType ); + } + return responses[ finalDataType ]; + } +} + +/* Chain conversions given the request and the original response + * Also sets the responseXXX fields on the jqXHR instance + */ +function ajaxConvert( s, response, jqXHR, isSuccess ) { + var conv2, current, conv, tmp, prev, + converters = {}, + + // Work with a copy of dataTypes in case we need to modify it for conversion + dataTypes = s.dataTypes.slice(); + + // Create converters map with lowercased keys + if ( dataTypes[ 1 ] ) { + for ( conv in s.converters ) { + converters[ conv.toLowerCase() ] = s.converters[ conv ]; + } + } + + current = dataTypes.shift(); + + // Convert to each sequential dataType + while ( current ) { + + if ( s.responseFields[ current ] ) { + jqXHR[ s.responseFields[ current ] ] = response; + } + + // Apply the dataFilter if provided + if ( !prev && isSuccess && s.dataFilter ) { + response = s.dataFilter( response, s.dataType ); + } + + prev = current; + current = dataTypes.shift(); + + if ( current ) { + + // There's only work to do if current dataType is non-auto + if ( current === "*" ) { + + current = prev; + + // Convert response if prev dataType is non-auto and differs from current + } else if ( prev !== "*" && prev !== current ) { + + // Seek a direct converter + conv = converters[ prev + " " + current ] || converters[ "* " + current ]; + + // If none found, seek a pair + if ( !conv ) { + for ( conv2 in converters ) { + + // If conv2 outputs current + tmp = conv2.split( " " ); + if ( tmp[ 1 ] === current ) { + + // If prev can be converted to accepted input + conv = converters[ prev + " " + tmp[ 0 ] ] || + converters[ "* " + tmp[ 0 ] ]; + if ( conv ) { + + // Condense equivalence converters + if ( conv === true ) { + conv = converters[ conv2 ]; + + // Otherwise, insert the intermediate dataType + } else if ( converters[ conv2 ] !== true ) { + current = tmp[ 0 ]; + dataTypes.unshift( tmp[ 1 ] ); + } + break; + } + } + } + } + + // Apply converter (if not an equivalence) + if ( conv !== true ) { + + // Unless errors are allowed to bubble, catch and return them + if ( conv && s.throws ) { + response = conv( response ); + } else { + try { + response = conv( response ); + } catch ( e ) { + return { + state: "parsererror", + error: conv ? e : "No conversion from " + prev + " to " + current + }; + } + } + } + } + } + } + + return { state: "success", data: response }; +} + +jQuery.extend( { + + // Counter for holding the number of active queries + active: 0, + + // Last-Modified header cache for next request + lastModified: {}, + etag: {}, + + ajaxSettings: { + url: location.href, + type: "GET", + isLocal: rlocalProtocol.test( location.protocol ), + global: true, + processData: true, + async: true, + contentType: "application/x-www-form-urlencoded; charset=UTF-8", + + /* + timeout: 0, + data: null, + dataType: null, + username: null, + password: null, + cache: null, + throws: false, + traditional: false, + headers: {}, + */ + + accepts: { + "*": allTypes, + text: "text/plain", + html: "text/html", + xml: "application/xml, text/xml", + json: "application/json, text/javascript" + }, + + contents: { + xml: /\bxml\b/, + html: /\bhtml/, + json: /\bjson\b/ + }, + + responseFields: { + xml: "responseXML", + text: "responseText", + json: "responseJSON" + }, + + // Data converters + // Keys separate source (or catchall "*") and destination types with a single space + converters: { + + // Convert anything to text + "* text": String, + + // Text to html (true = no transformation) + "text html": true, + + // Evaluate text as a json expression + "text json": JSON.parse, + + // Parse text as xml + "text xml": jQuery.parseXML + }, + + // For options that shouldn't be deep extended: + // you can add your own custom options here if + // and when you create one that shouldn't be + // deep extended (see ajaxExtend) + flatOptions: { + url: true, + context: true + } + }, + + // Creates a full fledged settings object into target + // with both ajaxSettings and settings fields. + // If target is omitted, writes into ajaxSettings. + ajaxSetup: function( target, settings ) { + return settings ? + + // Building a settings object + ajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) : + + // Extending ajaxSettings + ajaxExtend( jQuery.ajaxSettings, target ); + }, + + ajaxPrefilter: addToPrefiltersOrTransports( prefilters ), + ajaxTransport: addToPrefiltersOrTransports( transports ), + + // Main method + ajax: function( url, options ) { + + // If url is an object, simulate pre-1.5 signature + if ( typeof url === "object" ) { + options = url; + url = undefined; + } + + // Force options to be an object + options = options || {}; + + var transport, + + // URL without anti-cache param + cacheURL, + + // Response headers + responseHeadersString, + responseHeaders, + + // timeout handle + timeoutTimer, + + // Url cleanup var + urlAnchor, + + // Request state (becomes false upon send and true upon completion) + completed, + + // To know if global events are to be dispatched + fireGlobals, + + // Loop variable + i, + + // uncached part of the url + uncached, + + // Create the final options object + s = jQuery.ajaxSetup( {}, options ), + + // Callbacks context + callbackContext = s.context || s, + + // Context for global events is callbackContext if it is a DOM node or jQuery collection + globalEventContext = s.context && + ( callbackContext.nodeType || callbackContext.jquery ) ? + jQuery( callbackContext ) : + jQuery.event, + + // Deferreds + deferred = jQuery.Deferred(), + completeDeferred = jQuery.Callbacks( "once memory" ), + + // Status-dependent callbacks + statusCode = s.statusCode || {}, + + // Headers (they are sent all at once) + requestHeaders = {}, + requestHeadersNames = {}, + + // Default abort message + strAbort = "canceled", + + // Fake xhr + jqXHR = { + readyState: 0, + + // Builds headers hashtable if needed + getResponseHeader: function( key ) { + var match; + if ( completed ) { + if ( !responseHeaders ) { + responseHeaders = {}; + while ( ( match = rheaders.exec( responseHeadersString ) ) ) { + responseHeaders[ match[ 1 ].toLowerCase() + " " ] = + ( responseHeaders[ match[ 1 ].toLowerCase() + " " ] || [] ) + .concat( match[ 2 ] ); + } + } + match = responseHeaders[ key.toLowerCase() + " " ]; + } + return match == null ? null : match.join( ", " ); + }, + + // Raw string + getAllResponseHeaders: function() { + return completed ? responseHeadersString : null; + }, + + // Caches the header + setRequestHeader: function( name, value ) { + if ( completed == null ) { + name = requestHeadersNames[ name.toLowerCase() ] = + requestHeadersNames[ name.toLowerCase() ] || name; + requestHeaders[ name ] = value; + } + return this; + }, + + // Overrides response content-type header + overrideMimeType: function( type ) { + if ( completed == null ) { + s.mimeType = type; + } + return this; + }, + + // Status-dependent callbacks + statusCode: function( map ) { + var code; + if ( map ) { + if ( completed ) { + + // Execute the appropriate callbacks + jqXHR.always( map[ jqXHR.status ] ); + } else { + + // Lazy-add the new callbacks in a way that preserves old ones + for ( code in map ) { + statusCode[ code ] = [ statusCode[ code ], map[ code ] ]; + } + } + } + return this; + }, + + // Cancel the request + abort: function( statusText ) { + var finalText = statusText || strAbort; + if ( transport ) { + transport.abort( finalText ); + } + done( 0, finalText ); + return this; + } + }; + + // Attach deferreds + deferred.promise( jqXHR ); + + // Add protocol if not provided (prefilters might expect it) + // Handle falsy url in the settings object (trac-10093: consistency with old signature) + // We also use the url parameter if available + s.url = ( ( url || s.url || location.href ) + "" ) + .replace( rprotocol, location.protocol + "//" ); + + // Alias method option to type as per ticket trac-12004 + s.type = options.method || options.type || s.method || s.type; + + // Extract dataTypes list + s.dataTypes = ( s.dataType || "*" ).toLowerCase().match( rnothtmlwhite ) || [ "" ]; + + // A cross-domain request is in order when the origin doesn't match the current origin. + if ( s.crossDomain == null ) { + urlAnchor = document.createElement( "a" ); + + // Support: IE <=8 - 11, Edge 12 - 15 + // IE throws exception on accessing the href property if url is malformed, + // e.g. http://example.com:80x/ + try { + urlAnchor.href = s.url; + + // Support: IE <=8 - 11 only + // Anchor's host property isn't correctly set when s.url is relative + urlAnchor.href = urlAnchor.href; + s.crossDomain = originAnchor.protocol + "//" + originAnchor.host !== + urlAnchor.protocol + "//" + urlAnchor.host; + } catch ( e ) { + + // If there is an error parsing the URL, assume it is crossDomain, + // it can be rejected by the transport if it is invalid + s.crossDomain = true; + } + } + + // Convert data if not already a string + if ( s.data && s.processData && typeof s.data !== "string" ) { + s.data = jQuery.param( s.data, s.traditional ); + } + + // Apply prefilters + inspectPrefiltersOrTransports( prefilters, s, options, jqXHR ); + + // If request was aborted inside a prefilter, stop there + if ( completed ) { + return jqXHR; + } + + // We can fire global events as of now if asked to + // Don't fire events if jQuery.event is undefined in an AMD-usage scenario (trac-15118) + fireGlobals = jQuery.event && s.global; + + // Watch for a new set of requests + if ( fireGlobals && jQuery.active++ === 0 ) { + jQuery.event.trigger( "ajaxStart" ); + } + + // Uppercase the type + s.type = s.type.toUpperCase(); + + // Determine if request has content + s.hasContent = !rnoContent.test( s.type ); + + // Save the URL in case we're toying with the If-Modified-Since + // and/or If-None-Match header later on + // Remove hash to simplify url manipulation + cacheURL = s.url.replace( rhash, "" ); + + // More options handling for requests with no content + if ( !s.hasContent ) { + + // Remember the hash so we can put it back + uncached = s.url.slice( cacheURL.length ); + + // If data is available and should be processed, append data to url + if ( s.data && ( s.processData || typeof s.data === "string" ) ) { + cacheURL += ( rquery.test( cacheURL ) ? "&" : "?" ) + s.data; + + // trac-9682: remove data so that it's not used in an eventual retry + delete s.data; + } + + // Add or update anti-cache param if needed + if ( s.cache === false ) { + cacheURL = cacheURL.replace( rantiCache, "$1" ); + uncached = ( rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + ( nonce.guid++ ) + + uncached; + } + + // Put hash and anti-cache on the URL that will be requested (gh-1732) + s.url = cacheURL + uncached; + + // Change '%20' to '+' if this is encoded form body content (gh-2658) + } else if ( s.data && s.processData && + ( s.contentType || "" ).indexOf( "application/x-www-form-urlencoded" ) === 0 ) { + s.data = s.data.replace( r20, "+" ); + } + + // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. + if ( s.ifModified ) { + if ( jQuery.lastModified[ cacheURL ] ) { + jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ cacheURL ] ); + } + if ( jQuery.etag[ cacheURL ] ) { + jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ cacheURL ] ); + } + } + + // Set the correct header, if data is being sent + if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) { + jqXHR.setRequestHeader( "Content-Type", s.contentType ); + } + + // Set the Accepts header for the server, depending on the dataType + jqXHR.setRequestHeader( + "Accept", + s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[ 0 ] ] ? + s.accepts[ s.dataTypes[ 0 ] ] + + ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) : + s.accepts[ "*" ] + ); + + // Check for headers option + for ( i in s.headers ) { + jqXHR.setRequestHeader( i, s.headers[ i ] ); + } + + // Allow custom headers/mimetypes and early abort + if ( s.beforeSend && + ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || completed ) ) { + + // Abort if not done already and return + return jqXHR.abort(); + } + + // Aborting is no longer a cancellation + strAbort = "abort"; + + // Install callbacks on deferreds + completeDeferred.add( s.complete ); + jqXHR.done( s.success ); + jqXHR.fail( s.error ); + + // Get transport + transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR ); + + // If no transport, we auto-abort + if ( !transport ) { + done( -1, "No Transport" ); + } else { + jqXHR.readyState = 1; + + // Send global event + if ( fireGlobals ) { + globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] ); + } + + // If request was aborted inside ajaxSend, stop there + if ( completed ) { + return jqXHR; + } + + // Timeout + if ( s.async && s.timeout > 0 ) { + timeoutTimer = window.setTimeout( function() { + jqXHR.abort( "timeout" ); + }, s.timeout ); + } + + try { + completed = false; + transport.send( requestHeaders, done ); + } catch ( e ) { + + // Rethrow post-completion exceptions + if ( completed ) { + throw e; + } + + // Propagate others as results + done( -1, e ); + } + } + + // Callback for when everything is done + function done( status, nativeStatusText, responses, headers ) { + var isSuccess, success, error, response, modified, + statusText = nativeStatusText; + + // Ignore repeat invocations + if ( completed ) { + return; + } + + completed = true; + + // Clear timeout if it exists + if ( timeoutTimer ) { + window.clearTimeout( timeoutTimer ); + } + + // Dereference transport for early garbage collection + // (no matter how long the jqXHR object will be used) + transport = undefined; + + // Cache response headers + responseHeadersString = headers || ""; + + // Set readyState + jqXHR.readyState = status > 0 ? 4 : 0; + + // Determine if successful + isSuccess = status >= 200 && status < 300 || status === 304; + + // Get response data + if ( responses ) { + response = ajaxHandleResponses( s, jqXHR, responses ); + } + + // Use a noop converter for missing script but not if jsonp + if ( !isSuccess && + jQuery.inArray( "script", s.dataTypes ) > -1 && + jQuery.inArray( "json", s.dataTypes ) < 0 ) { + s.converters[ "text script" ] = function() {}; + } + + // Convert no matter what (that way responseXXX fields are always set) + response = ajaxConvert( s, response, jqXHR, isSuccess ); + + // If successful, handle type chaining + if ( isSuccess ) { + + // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. + if ( s.ifModified ) { + modified = jqXHR.getResponseHeader( "Last-Modified" ); + if ( modified ) { + jQuery.lastModified[ cacheURL ] = modified; + } + modified = jqXHR.getResponseHeader( "etag" ); + if ( modified ) { + jQuery.etag[ cacheURL ] = modified; + } + } + + // if no content + if ( status === 204 || s.type === "HEAD" ) { + statusText = "nocontent"; + + // if not modified + } else if ( status === 304 ) { + statusText = "notmodified"; + + // If we have data, let's convert it + } else { + statusText = response.state; + success = response.data; + error = response.error; + isSuccess = !error; + } + } else { + + // Extract error from statusText and normalize for non-aborts + error = statusText; + if ( status || !statusText ) { + statusText = "error"; + if ( status < 0 ) { + status = 0; + } + } + } + + // Set data for the fake xhr object + jqXHR.status = status; + jqXHR.statusText = ( nativeStatusText || statusText ) + ""; + + // Success/Error + if ( isSuccess ) { + deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] ); + } else { + deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] ); + } + + // Status-dependent callbacks + jqXHR.statusCode( statusCode ); + statusCode = undefined; + + if ( fireGlobals ) { + globalEventContext.trigger( isSuccess ? "ajaxSuccess" : "ajaxError", + [ jqXHR, s, isSuccess ? success : error ] ); + } + + // Complete + completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] ); + + if ( fireGlobals ) { + globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] ); + + // Handle the global AJAX counter + if ( !( --jQuery.active ) ) { + jQuery.event.trigger( "ajaxStop" ); + } + } + } + + return jqXHR; + }, + + getJSON: function( url, data, callback ) { + return jQuery.get( url, data, callback, "json" ); + }, + + getScript: function( url, callback ) { + return jQuery.get( url, undefined, callback, "script" ); + } +} ); + +jQuery.each( [ "get", "post" ], function( _i, method ) { + jQuery[ method ] = function( url, data, callback, type ) { + + // Shift arguments if data argument was omitted + if ( isFunction( data ) ) { + type = type || callback; + callback = data; + data = undefined; + } + + // The url can be an options object (which then must have .url) + return jQuery.ajax( jQuery.extend( { + url: url, + type: method, + dataType: type, + data: data, + success: callback + }, jQuery.isPlainObject( url ) && url ) ); + }; +} ); + +jQuery.ajaxPrefilter( function( s ) { + var i; + for ( i in s.headers ) { + if ( i.toLowerCase() === "content-type" ) { + s.contentType = s.headers[ i ] || ""; + } + } +} ); + + +jQuery._evalUrl = function( url, options, doc ) { + return jQuery.ajax( { + url: url, + + // Make this explicit, since user can override this through ajaxSetup (trac-11264) + type: "GET", + dataType: "script", + cache: true, + async: false, + global: false, + + // Only evaluate the response if it is successful (gh-4126) + // dataFilter is not invoked for failure responses, so using it instead + // of the default converter is kludgy but it works. + converters: { + "text script": function() {} + }, + dataFilter: function( response ) { + jQuery.globalEval( response, options, doc ); + } + } ); +}; + + +jQuery.fn.extend( { + wrapAll: function( html ) { + var wrap; + + if ( this[ 0 ] ) { + if ( isFunction( html ) ) { + html = html.call( this[ 0 ] ); + } + + // The elements to wrap the target around + wrap = jQuery( html, this[ 0 ].ownerDocument ).eq( 0 ).clone( true ); + + if ( this[ 0 ].parentNode ) { + wrap.insertBefore( this[ 0 ] ); + } + + wrap.map( function() { + var elem = this; + + while ( elem.firstElementChild ) { + elem = elem.firstElementChild; + } + + return elem; + } ).append( this ); + } + + return this; + }, + + wrapInner: function( html ) { + if ( isFunction( html ) ) { + return this.each( function( i ) { + jQuery( this ).wrapInner( html.call( this, i ) ); + } ); + } + + return this.each( function() { + var self = jQuery( this ), + contents = self.contents(); + + if ( contents.length ) { + contents.wrapAll( html ); + + } else { + self.append( html ); + } + } ); + }, + + wrap: function( html ) { + var htmlIsFunction = isFunction( html ); + + return this.each( function( i ) { + jQuery( this ).wrapAll( htmlIsFunction ? html.call( this, i ) : html ); + } ); + }, + + unwrap: function( selector ) { + this.parent( selector ).not( "body" ).each( function() { + jQuery( this ).replaceWith( this.childNodes ); + } ); + return this; + } +} ); + + +jQuery.expr.pseudos.hidden = function( elem ) { + return !jQuery.expr.pseudos.visible( elem ); +}; +jQuery.expr.pseudos.visible = function( elem ) { + return !!( elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length ); +}; + + + + +jQuery.ajaxSettings.xhr = function() { + try { + return new window.XMLHttpRequest(); + } catch ( e ) {} +}; + +var xhrSuccessStatus = { + + // File protocol always yields status code 0, assume 200 + 0: 200, + + // Support: IE <=9 only + // trac-1450: sometimes IE returns 1223 when it should be 204 + 1223: 204 + }, + xhrSupported = jQuery.ajaxSettings.xhr(); + +support.cors = !!xhrSupported && ( "withCredentials" in xhrSupported ); +support.ajax = xhrSupported = !!xhrSupported; + +jQuery.ajaxTransport( function( options ) { + var callback, errorCallback; + + // Cross domain only allowed if supported through XMLHttpRequest + if ( support.cors || xhrSupported && !options.crossDomain ) { + return { + send: function( headers, complete ) { + var i, + xhr = options.xhr(); + + xhr.open( + options.type, + options.url, + options.async, + options.username, + options.password + ); + + // Apply custom fields if provided + if ( options.xhrFields ) { + for ( i in options.xhrFields ) { + xhr[ i ] = options.xhrFields[ i ]; + } + } + + // Override mime type if needed + if ( options.mimeType && xhr.overrideMimeType ) { + xhr.overrideMimeType( options.mimeType ); + } + + // X-Requested-With header + // For cross-domain requests, seeing as conditions for a preflight are + // akin to a jigsaw puzzle, we simply never set it to be sure. + // (it can always be set on a per-request basis or even using ajaxSetup) + // For same-domain requests, won't change header if already provided. + if ( !options.crossDomain && !headers[ "X-Requested-With" ] ) { + headers[ "X-Requested-With" ] = "XMLHttpRequest"; + } + + // Set headers + for ( i in headers ) { + xhr.setRequestHeader( i, headers[ i ] ); + } + + // Callback + callback = function( type ) { + return function() { + if ( callback ) { + callback = errorCallback = xhr.onload = + xhr.onerror = xhr.onabort = xhr.ontimeout = + xhr.onreadystatechange = null; + + if ( type === "abort" ) { + xhr.abort(); + } else if ( type === "error" ) { + + // Support: IE <=9 only + // On a manual native abort, IE9 throws + // errors on any property access that is not readyState + if ( typeof xhr.status !== "number" ) { + complete( 0, "error" ); + } else { + complete( + + // File: protocol always yields status 0; see trac-8605, trac-14207 + xhr.status, + xhr.statusText + ); + } + } else { + complete( + xhrSuccessStatus[ xhr.status ] || xhr.status, + xhr.statusText, + + // Support: IE <=9 only + // IE9 has no XHR2 but throws on binary (trac-11426) + // For XHR2 non-text, let the caller handle it (gh-2498) + ( xhr.responseType || "text" ) !== "text" || + typeof xhr.responseText !== "string" ? + { binary: xhr.response } : + { text: xhr.responseText }, + xhr.getAllResponseHeaders() + ); + } + } + }; + }; + + // Listen to events + xhr.onload = callback(); + errorCallback = xhr.onerror = xhr.ontimeout = callback( "error" ); + + // Support: IE 9 only + // Use onreadystatechange to replace onabort + // to handle uncaught aborts + if ( xhr.onabort !== undefined ) { + xhr.onabort = errorCallback; + } else { + xhr.onreadystatechange = function() { + + // Check readyState before timeout as it changes + if ( xhr.readyState === 4 ) { + + // Allow onerror to be called first, + // but that will not handle a native abort + // Also, save errorCallback to a variable + // as xhr.onerror cannot be accessed + window.setTimeout( function() { + if ( callback ) { + errorCallback(); + } + } ); + } + }; + } + + // Create the abort callback + callback = callback( "abort" ); + + try { + + // Do send the request (this may raise an exception) + xhr.send( options.hasContent && options.data || null ); + } catch ( e ) { + + // trac-14683: Only rethrow if this hasn't been notified as an error yet + if ( callback ) { + throw e; + } + } + }, + + abort: function() { + if ( callback ) { + callback(); + } + } + }; + } +} ); + + + + +// Prevent auto-execution of scripts when no explicit dataType was provided (See gh-2432) +jQuery.ajaxPrefilter( function( s ) { + if ( s.crossDomain ) { + s.contents.script = false; + } +} ); + +// Install script dataType +jQuery.ajaxSetup( { + accepts: { + script: "text/javascript, application/javascript, " + + "application/ecmascript, application/x-ecmascript" + }, + contents: { + script: /\b(?:java|ecma)script\b/ + }, + converters: { + "text script": function( text ) { + jQuery.globalEval( text ); + return text; + } + } +} ); + +// Handle cache's special case and crossDomain +jQuery.ajaxPrefilter( "script", function( s ) { + if ( s.cache === undefined ) { + s.cache = false; + } + if ( s.crossDomain ) { + s.type = "GET"; + } +} ); + +// Bind script tag hack transport +jQuery.ajaxTransport( "script", function( s ) { + + // This transport only deals with cross domain or forced-by-attrs requests + if ( s.crossDomain || s.scriptAttrs ) { + var script, callback; + return { + send: function( _, complete ) { + script = jQuery( "