native-update 1.4.5 → 1.4.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -283,8 +283,8 @@ async function handlePurchaseComplete() {
283
283
 
284
284
  ## Links
285
285
 
286
- - [Full Documentation](./docs/)
287
- - [API Reference](./docs/api/)
286
+ - [Full Documentation](https://nativeupdate.aoneahsan.com/docs)
287
+ - [API Reference](https://nativeupdate.aoneahsan.com/docs/api/API)
288
288
  - [Example Apps](./example-apps/)
289
- - [CLI Reference](./docs/cli-reference.md)
290
- - [Security Guide](./docs/guides/security-best-practices.md)
289
+ - [CLI Reference](https://nativeupdate.aoneahsan.com/docs/cli-reference)
290
+ - [Security Guide](https://nativeupdate.aoneahsan.com/docs/guides/security-best-practices)
package/Readme.md CHANGED
@@ -15,49 +15,49 @@
15
15
 
16
16
  ## 📚 Documentation
17
17
 
18
- - **[AI Integration Guide](./AI-INTEGRATION-GUIDE.md)** - Quick reference for AI development agents (Claude, Cursor, Copilot)
18
+ - **[AI Integration Guide](https://nativeupdate.aoneahsan.com/docs/AI-INTEGRATION-GUIDE)** - Quick reference for AI development agents (Claude, Cursor, Copilot)
19
19
 
20
20
  ### Getting Started
21
21
 
22
- - **[Installation Guide](./docs/getting-started/installation.md)** - Step-by-step installation instructions
23
- - **[Quick Start Guide](./docs/getting-started/quick-start.md)** - Get up and running in minutes
24
- - **[Configuration Guide](./docs/getting-started/configuration.md)** - Detailed configuration options
25
- - **[End-to-End Workflow](./docs/guides/end-to-end-workflow.md)** - Complete setup to production guide
22
+ - **[Installation Guide](https://nativeupdate.aoneahsan.com/docs/getting-started/installation)** - Step-by-step installation instructions
23
+ - **[Quick Start Guide](https://nativeupdate.aoneahsan.com/docs/getting-started/quick-start)** - Get up and running in minutes
24
+ - **[Configuration Guide](https://nativeupdate.aoneahsan.com/docs/getting-started/configuration)** - Detailed configuration options
25
+ - **[End-to-End Workflow](https://nativeupdate.aoneahsan.com/docs/guides/end-to-end-workflow)** - Complete setup to production guide
26
26
 
27
27
  ### Dashboard & Management
28
28
 
29
- - **[Dashboard Guide](./docs/guides/dashboard-guide.md)** - Complete dashboard user guide
30
- - **[Channel Management](./docs/guides/channel-management.md)** - Dev/staging/production channels
31
- - **[Admin Panel](./docs/guides/admin-panel.md)** - Super-admin documentation
29
+ - **[Dashboard Guide](https://nativeupdate.aoneahsan.com/docs/guides/dashboard-guide)** - Complete dashboard user guide
30
+ - **[Channel Management](https://nativeupdate.aoneahsan.com/docs/guides/channel-management)** - Dev/staging/production channels
31
+ - **[Admin Panel](https://nativeupdate.aoneahsan.com/docs/guides/admin-panel)** - Super-admin documentation
32
32
 
33
33
  ### Features Documentation
34
34
 
35
- - **[Live Updates (OTA)](./docs/features/live-updates.md)** - Deploy web updates instantly
36
- - **[App Updates](./docs/features/app-updates.md)** - Native app store update management
37
- - **[App Reviews](./docs/features/app-reviews.md)** - In-app review integration
38
- - **[Background Updates](./docs/background-updates.md)** - Background update management
35
+ - **[Live Updates (OTA)](https://nativeupdate.aoneahsan.com/docs/features/live-updates)** - Deploy web updates instantly
36
+ - **[App Updates](https://nativeupdate.aoneahsan.com/docs/features/app-updates)** - Native app store update management
37
+ - **[App Reviews](https://nativeupdate.aoneahsan.com/docs/features/app-reviews)** - In-app review integration
38
+ - **[Background Updates](https://nativeupdate.aoneahsan.com/docs/background-updates)** - Background update management
39
39
 
40
40
  ### Guides & Best Practices
41
41
 
42
- - **[Security Best Practices](./docs/guides/security-best-practices.md)** - Implement secure updates
43
- - **[Deployment Guide](./docs/guides/deployment-guide.md)** - Deployment procedures
44
- - **[Migration Guide](./docs/MIGRATION.md)** - Migrate from other solutions
45
- - **[Production Readiness](./docs/production-readiness.md)** - Production deployment checklist
46
- - **[Bundle Signing](./docs/BUNDLE_SIGNING.md)** - Cryptographic signing guide
47
- - **[Troubleshooting](./docs/guides/troubleshooting.md)** - Common issues and solutions
42
+ - **[Security Best Practices](https://nativeupdate.aoneahsan.com/docs/guides/security-best-practices)** - Implement secure updates
43
+ - **[Deployment Guide](https://nativeupdate.aoneahsan.com/docs/guides/deployment-guide)** - Deployment procedures
44
+ - **[Migration Guide](https://nativeupdate.aoneahsan.com/docs/MIGRATION)** - Migrate from other solutions
45
+ - **[Production Readiness](https://nativeupdate.aoneahsan.com/docs/production-readiness)** - Production deployment checklist
46
+ - **[Bundle Signing](https://nativeupdate.aoneahsan.com/docs/BUNDLE_SIGNING)** - Cryptographic signing guide
47
+ - **[Troubleshooting](https://nativeupdate.aoneahsan.com/docs/guides/troubleshooting)** - Common issues and solutions
48
48
 
49
49
  ### API Reference
50
50
 
51
- - **[Live Update API](./docs/api/live-update-api.md)** - Complete API for OTA updates
52
- - **[App Update API](./docs/api/app-update-api.md)** - Native app update methods
53
- - **[App Review API](./docs/api/app-review-api.md)** - Review request methods
54
- - **[Events API](./docs/api/events-api.md)** - Event listeners and handlers
55
- - **[CLI Reference](./docs/cli-reference.md)** - Command-line tools documentation
51
+ - **[Live Update API](https://nativeupdate.aoneahsan.com/docs/api/live-update-api)** - Complete API for OTA updates
52
+ - **[App Update API](https://nativeupdate.aoneahsan.com/docs/api/app-update-api)** - Native app update methods
53
+ - **[App Review API](https://nativeupdate.aoneahsan.com/docs/api/app-review-api)** - Review request methods
54
+ - **[Events API](https://nativeupdate.aoneahsan.com/docs/api/events-api)** - Event listeners and handlers
55
+ - **[CLI Reference](https://nativeupdate.aoneahsan.com/docs/cli-reference)** - Command-line tools documentation
56
56
 
57
57
  ### Examples
58
58
 
59
- - **[Basic Usage](./docs/examples/basic-usage.md)** - Simple implementation examples
60
- - **[Advanced Scenarios](./docs/examples/advanced-scenarios.md)** - Complex use cases
59
+ - **[Basic Usage](https://nativeupdate.aoneahsan.com/docs/examples/basic-usage)** - Simple implementation examples
60
+ - **[Advanced Scenarios](https://nativeupdate.aoneahsan.com/docs/examples/advanced-scenarios)** - Complex use cases
61
61
 
62
62
  ---
63
63
 
@@ -89,7 +89,7 @@ Native Update supports three deployment channels:
89
89
  | **Staging** | QA/Beta testing | Configurable | 1 hour |
90
90
  | **Production** | Live users | No (consent) | Daily |
91
91
 
92
- See [Channel Management Guide](./docs/guides/channel-management.md) for detailed configuration.
92
+ See [Channel Management Guide](https://nativeupdate.aoneahsan.com/docs/guides/channel-management) for detailed configuration.
93
93
 
94
94
  ---
95
95
 
@@ -395,7 +395,7 @@ npx native-update backend create express --with-admin
395
395
  - Generate keys: `npx native-update keys generate --type rsa --size 4096`
396
396
  - Supports RSA (2048/4096) and EC (256/384) keys
397
397
  - Creates timestamped key pairs with proper permissions
398
- - See [Key Management Guide](./docs/guides/key-management.md) for detailed instructions
398
+ - See [Key Management Guide](https://nativeupdate.aoneahsan.com/docs/guides/key-management) for detailed instructions
399
399
 
400
400
  ✅ **Backend Templates**
401
401
  - Express.js: `npx native-update backend create express --with-admin`
@@ -410,7 +410,7 @@ npx native-update backend create express --with-admin
410
410
  ✅ **Migration Tools**
411
411
  - From CodePush: `npx native-update migrate --from codepush`
412
412
 
413
- See [CLI Reference](./docs/cli-reference.md) for complete documentation.
413
+ See [CLI Reference](https://nativeupdate.aoneahsan.com/docs/cli-reference) for complete documentation.
414
414
 
415
415
  ## 🏗️ Development Status
416
416
 
@@ -459,12 +459,12 @@ See [CLI Reference](./docs/cli-reference.md) for complete documentation.
459
459
  ## 🚀 Getting Started with Development
460
460
 
461
461
  1. **Understand the Architecture**:
462
- - Review the documentation in `/docs/`
462
+ - Review the documentation at `https://nativeupdate.aoneahsan.com/docs`
463
463
  - Study the TypeScript interfaces in `/src/definitions.ts`
464
- - Check the [ROADMAP.md](./ROADMAP.md) for development priorities
464
+ - Check the [ROADMAP.md](https://nativeupdate.aoneahsan.com/docs/ROADMAP) for development priorities
465
465
 
466
466
  2. **Build Required Infrastructure**:
467
- - Set up an update server (see [server requirements](./docs/server-requirements.md))
467
+ - Set up an update server (see [server requirements](https://nativeupdate.aoneahsan.com/docs/server-requirements))
468
468
  - Implement bundle storage solution
469
469
  - Create signing infrastructure
470
470
 
@@ -494,8 +494,8 @@ This package is **open-source** and created by **Ahsan Mahmood** for the develop
494
494
 
495
495
  - **[NPM Package](https://www.npmjs.com/package/native-update)** - Package and versions
496
496
  - **[Website](https://nativeupdate.aoneahsan.com)** - Official website and dashboard
497
- - **[Documentation](./docs/README.md)** - Comprehensive documentation
498
- - **[Examples](./docs/examples/)** - Real-world usage examples
497
+ - **[Documentation](https://nativeupdate.aoneahsan.com/docs)** - Comprehensive documentation
498
+ - **[Examples](https://nativeupdate.aoneahsan.com/docs/examples/basic-usage)** - Real-world usage examples
499
499
 
500
500
  ### Professional Support
501
501
 
package/dist/plugin.js CHANGED
@@ -1,3 +1,3 @@
1
- /*! Native Update Plugin v1.4.5 | MIT License */
1
+ /*! Native Update Plugin v1.4.7 | MIT License */
2
2
  !function(e,t,r,a){var i,n,s,o,l,c,d,u,h,g,p,f;!function(e){e.APP_UPDATE="app_update",e.LIVE_UPDATE="live_update",e.BOTH="both"}(i||(i={})),function(e){e.MIN="min",e.LOW="low",e.DEFAULT="default",e.HIGH="high",e.MAX="max"}(n||(n={})),function(e){e.IMMEDIATE="immediate",e.BACKGROUND="background",e.MANUAL="manual"}(s||(s={})),function(e){e.IMMEDIATE="immediate",e.ON_NEXT_RESTART="on_next_restart",e.ON_NEXT_RESUME="on_next_resume"}(o||(o={})),function(e){e.IMMEDIATE="immediate",e.ON_NEXT_RESTART="on_next_restart",e.ON_NEXT_RESUME="on_next_resume"}(l||(l={})),function(e){e.SHA256="SHA-256",e.SHA512="SHA-512"}(c||(c={})),function(e){e.UP_TO_DATE="UP_TO_DATE",e.UPDATE_AVAILABLE="UPDATE_AVAILABLE",e.UPDATE_INSTALLED="UPDATE_INSTALLED",e.ERROR="ERROR"}(d||(d={})),function(e){e.PENDING="PENDING",e.DOWNLOADING="DOWNLOADING",e.READY="READY",e.ACTIVE="ACTIVE",e.FAILED="FAILED"}(u||(u={})),function(e){e.UNKNOWN="UNKNOWN",e.PENDING="PENDING",e.DOWNLOADING="DOWNLOADING",e.DOWNLOADED="DOWNLOADED",e.INSTALLING="INSTALLING",e.INSTALLED="INSTALLED",e.FAILED="FAILED",e.CANCELED="CANCELED"}(h||(h={})),function(e){e.NETWORK_ERROR="NETWORK_ERROR",e.SERVER_ERROR="SERVER_ERROR",e.TIMEOUT_ERROR="TIMEOUT_ERROR",e.DOWNLOAD_ERROR="DOWNLOAD_ERROR",e.STORAGE_ERROR="STORAGE_ERROR",e.SIZE_LIMIT_EXCEEDED="SIZE_LIMIT_EXCEEDED",e.VERIFICATION_ERROR="VERIFICATION_ERROR",e.CHECKSUM_ERROR="CHECKSUM_ERROR",e.SIGNATURE_ERROR="SIGNATURE_ERROR",e.INSECURE_URL="INSECURE_URL",e.INVALID_CERTIFICATE="INVALID_CERTIFICATE",e.PATH_TRAVERSAL="PATH_TRAVERSAL",e.INSTALL_ERROR="INSTALL_ERROR",e.ROLLBACK_ERROR="ROLLBACK_ERROR",e.VERSION_MISMATCH="VERSION_MISMATCH",e.PERMISSION_DENIED="PERMISSION_DENIED",e.UPDATE_NOT_AVAILABLE="UPDATE_NOT_AVAILABLE",e.UPDATE_IN_PROGRESS="UPDATE_IN_PROGRESS",e.UPDATE_CANCELLED="UPDATE_CANCELLED",e.PLATFORM_NOT_SUPPORTED="PLATFORM_NOT_SUPPORTED",e.REVIEW_NOT_SUPPORTED="REVIEW_NOT_SUPPORTED",e.QUOTA_EXCEEDED="QUOTA_EXCEEDED",e.CONDITIONS_NOT_MET="CONDITIONS_NOT_MET",e.INVALID_CONFIG="INVALID_CONFIG",e.NOT_CONFIGURED="NOT_CONFIGURED",e.UNKNOWN_ERROR="UNKNOWN_ERROR"}(g||(g={}));class m{constructor(){this.config=this.getDefaultConfig()}static getInstance(){return m.instance||(m.instance=new m),m.instance}getDefaultConfig(){return{filesystem:null,preferences:null,baseUrl:"",allowedHosts:[],maxBundleSize:104857600,downloadTimeout:3e4,retryAttempts:3,retryDelay:1e3,enableSignatureValidation:!0,publicKey:"",cacheExpiration:864e5,enableLogging:!1,serverUrl:"",channel:"production",appId:"",autoCheck:!0,autoUpdate:!1,updateStrategy:"background",requireSignature:!0,checksumAlgorithm:"SHA-256",checkInterval:864e5,security:{enforceHttps:!0,validateInputs:!0,secureStorage:!0,logSecurityEvents:!1},promptAfterPositiveEvents:!1,maxPromptsPerVersion:1,minimumDaysSinceLastPrompt:7,isPremiumUser:!1,appStoreId:"",iosAppId:"",packageName:"",webReviewUrl:"",minimumVersion:"1.0.0",backendType:"http",firestore:null,enableDeltaUpdates:!0,enableStagedRollouts:!0,enableEncryption:!1,encryptionKey:"",encryptionSalt:""}}configure(e){this.config=Object.assign(Object.assign({},this.config),e),this.validateConfig()}validateConfig(){if(this.config.baseUrl&&!this.config.baseUrl.startsWith("https://"))throw new Error("baseUrl must use HTTPS protocol for security");if(this.config.maxBundleSize<=0)throw new Error("maxBundleSize must be greater than 0");if(this.config.downloadTimeout<=0)throw new Error("downloadTimeout must be greater than 0");if(this.config.retryAttempts<0)throw new Error("retryAttempts must be non-negative");if(this.config.retryDelay<0)throw new Error("retryDelay must be non-negative")}get(e){return this.config[e]}set(e,t){this.config[e]=t}getAll(){return Object.assign({},this.config)}isConfigured(){return!(!this.config.filesystem||!this.config.preferences)}}e.LogLevel=void 0,(p=e.LogLevel||(e.LogLevel={}))[p.DEBUG=0]="DEBUG",p[p.INFO=1]="INFO",p[p.WARN=2]="WARN",p[p.ERROR=3]="ERROR";class w{constructor(e){this.configManager=m.getInstance(),this.context=e||"NativeUpdate"}static getInstance(){return w.instance||(w.instance=new w),w.instance}shouldLog(){return this.configManager.get("enableLogging")}sanitize(e){if("string"==typeof e){let t=e;return t=t.replace(/\/[^\s]+\/([\w.-]+)$/g,"/<path>/$1"),t=t.replace(/https?:\/\/[^:]+:[^@]+@/g,"https://***:***@"),t=t.replace(/[a-zA-Z0-9]{32,}/g,"<redacted>"),t}if("object"==typeof e&&null!==e){if(Array.isArray(e))return e.map(e=>this.sanitize(e));{const t={},r=e;for(const e in r)t[e]=e.toLowerCase().includes("key")||e.toLowerCase().includes("secret")||e.toLowerCase().includes("password")||e.toLowerCase().includes("token")?"<redacted>":this.sanitize(r[e]);return t}}return e}log(t,r){this.logWithLevel(e.LogLevel.INFO,t,r)}logWithLevel(t,r,a){if(!this.shouldLog())return;const i=(new Date).toISOString(),n=a?this.sanitize(a):void 0,s={timestamp:i,level:e.LogLevel[t],context:this.context,message:r};switch(void 0!==n&&(s.data=n),t){case e.LogLevel.DEBUG:console.debug(`[${this.context}]`,s);break;case e.LogLevel.INFO:console.info(`[${this.context}]`,s);break;case e.LogLevel.WARN:console.warn(`[${this.context}]`,s);break;case e.LogLevel.ERROR:console.error(`[${this.context}]`,s)}}debug(t,r){this.logWithLevel(e.LogLevel.DEBUG,t,r)}info(t,r){this.logWithLevel(e.LogLevel.INFO,t,r)}warn(t,r){this.logWithLevel(e.LogLevel.WARN,t,r)}error(t,r){const a=r instanceof Error?{name:r.name,message:r.message,stack:r.stack}:r;this.logWithLevel(e.LogLevel.ERROR,t,a)}}e.ErrorCode=void 0,(f=e.ErrorCode||(e.ErrorCode={})).NOT_CONFIGURED="NOT_CONFIGURED",f.INVALID_CONFIG="INVALID_CONFIG",f.MISSING_DEPENDENCY="MISSING_DEPENDENCY",f.NETWORK_ERROR="NETWORK_ERROR",f.SERVER_ERROR="SERVER_ERROR",f.DOWNLOAD_FAILED="DOWNLOAD_FAILED",f.DOWNLOAD_TIMEOUT="DOWNLOAD_TIMEOUT",f.INVALID_URL="INVALID_URL",f.UNAUTHORIZED_HOST="UNAUTHORIZED_HOST",f.BUNDLE_TOO_LARGE="BUNDLE_TOO_LARGE",f.CHECKSUM_MISMATCH="CHECKSUM_MISMATCH",f.SIGNATURE_INVALID="SIGNATURE_INVALID",f.VERSION_DOWNGRADE="VERSION_DOWNGRADE",f.INVALID_BUNDLE_FORMAT="INVALID_BUNDLE_FORMAT",f.VALIDATION_ERROR="VALIDATION_ERROR",f.STORAGE_FULL="STORAGE_FULL",f.FILE_NOT_FOUND="FILE_NOT_FOUND",f.PERMISSION_DENIED="PERMISSION_DENIED",f.UPDATE_FAILED="UPDATE_FAILED",f.ROLLBACK_FAILED="ROLLBACK_FAILED",f.BUNDLE_NOT_READY="BUNDLE_NOT_READY",f.UPDATE_NOT_AVAILABLE="UPDATE_NOT_AVAILABLE",f.PLATFORM_NOT_SUPPORTED="PLATFORM_NOT_SUPPORTED",f.NATIVE_ERROR="NATIVE_ERROR";class y extends Error{constructor(e,t,r,a){super(t),this.code=e,this.message=t,this.details=r,this.originalError=a,this.name="NativeUpdateError",Object.setPrototypeOf(this,y.prototype)}toJSON(){return{name:this.name,code:this.code,message:this.message,details:this.details,stack:this.stack}}}class E extends y{constructor(e,t,r,a){super(e,t,r,a),this.name="DownloadError"}}class A extends y{constructor(e,t,r){super(e,t,r),this.name="ValidationError"}}class v extends y{constructor(e,t,r,a){super(e,t,r,a),this.name="StorageError"}}class I extends y{constructor(e,t,r,a){super(e,t,r,a),this.name="UpdateError"}}class D{constructor(){this.configManager=m.getInstance(),this.logger=w.getInstance()}static getInstance(){return D.instance||(D.instance=new D),D.instance}static validateUrl(e){try{return"https:"===new URL(e).protocol}catch(e){return!1}}static validateChecksum(e){return/^[a-f0-9]{64}$/i.test(e)}static sanitizeInput(e){return e?e.replace(/<[^>]*>/g,"").replace(/[^\w\s/.-]/g,""):""}static validateBundleSize(e){return e>0&&e<=104857600}async calculateChecksum(e){const t=await crypto.subtle.digest("SHA-256",e);return Array.from(new Uint8Array(t)).map(e=>e.toString(16).padStart(2,"0")).join("")}async verifyChecksum(e,t){if(!t)return this.logger.warn("No checksum provided for verification"),!0;const r=await this.calculateChecksum(e),a=r===t.toLowerCase();return a||this.logger.error("Checksum verification failed",{expected:t,actual:r}),a}async validateChecksum(e,t){return this.verifyChecksum(e,t)}async verifySignature(t,r){if(!this.configManager.get("enableSignatureValidation"))return!0;const a=this.configManager.get("publicKey");if(!a)throw new A(e.ErrorCode.SIGNATURE_INVALID,"Public key not configured for signature validation");try{const e=await crypto.subtle.importKey("spki",this.pemToArrayBuffer(a),{name:"RSA-PSS",hash:"SHA-256"},!1,["verify"]),i=await crypto.subtle.verify({name:"RSA-PSS",saltLength:32},e,this.base64ToArrayBuffer(r),t);return i||this.logger.error("Signature verification failed"),i}catch(e){return this.logger.error("Signature verification error",e),!1}}pemToArrayBuffer(e){const t=e.replace(/-----BEGIN PUBLIC KEY-----/g,"").replace(/-----END PUBLIC KEY-----/g,"").replace(/\s/g,"");return this.base64ToArrayBuffer(t)}base64ToArrayBuffer(e){const t=atob(e),r=new Uint8Array(t.length);for(let e=0;e<t.length;e++)r[e]=t.charCodeAt(e);return r.buffer}sanitizePath(e){return e.split("/").filter(e=>".."!==e&&"."!==e).join("/").replace(/^\/+/,"")}validateBundleId(t){if(!t||"string"!=typeof t)throw new A(e.ErrorCode.INVALID_BUNDLE_FORMAT,"Bundle ID must be a non-empty string");if(!/^[a-zA-Z0-9\-_.]+$/.test(t))throw new A(e.ErrorCode.INVALID_BUNDLE_FORMAT,"Bundle ID contains invalid characters");if(t.length>100)throw new A(e.ErrorCode.INVALID_BUNDLE_FORMAT,"Bundle ID is too long (max 100 characters)")}validateVersion(t){if(!t||"string"!=typeof t)throw new A(e.ErrorCode.INVALID_BUNDLE_FORMAT,"Version must be a non-empty string");if(!/^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/.test(t))throw new A(e.ErrorCode.INVALID_BUNDLE_FORMAT,"Version must follow semantic versioning format (e.g., 1.2.3)")}isVersionDowngrade(e,t){const r=this.parseVersion(e),a=this.parseVersion(t);return a.major<r.major||!(a.major>r.major)&&(a.minor<r.minor||!(a.minor>r.minor)&&a.patch<r.patch)}parseVersion(e){const t=e.split("-")[0].split(".");return{major:parseInt(t[0],10)||0,minor:parseInt(t[1],10)||0,patch:parseInt(t[2],10)||0}}validateUrl(t){if(!t||"string"!=typeof t)throw new A(e.ErrorCode.INVALID_URL,"URL must be a non-empty string");let r;try{r=new URL(t)}catch(t){throw new A(e.ErrorCode.INVALID_URL,"Invalid URL format")}if("https:"!==r.protocol)throw new A(e.ErrorCode.INVALID_URL,"Only HTTPS URLs are allowed");const a=this.configManager.get("allowedHosts");if(a.length>0&&!a.includes(r.hostname))throw new A(e.ErrorCode.UNAUTHORIZED_HOST,`Host ${r.hostname} is not in the allowed hosts list`);if([/^localhost$/i,/^127\./,/^10\./,/^172\.(1[6-9]|2[0-9]|3[0-1])\./,/^192\.168\./,/^::1$/,/^fc00:/i,/^fe80:/i].some(e=>e.test(r.hostname)))throw new A(e.ErrorCode.UNAUTHORIZED_HOST,"Private/local addresses are not allowed")}validateFileSize(t){if("number"!=typeof t||t<0)throw new A(e.ErrorCode.INVALID_BUNDLE_FORMAT,"File size must be a non-negative number");const r=this.configManager.get("maxBundleSize");if(t>r)throw new A(e.ErrorCode.BUNDLE_TOO_LARGE,`File size ${t} exceeds maximum allowed size of ${r} bytes`)}generateSecureId(){const e=new Uint8Array(16);return crypto.getRandomValues(e),Array.from(e,e=>e.toString(16).padStart(2,"0")).join("")}async validateCertificatePin(e,t){const r=this.configManager.certificatePins;if(!r||!Array.isArray(r)||0===r.length)return!0;const a=r.filter(t=>t.hostname===e);if(0===a.length)return!0;const i=await this.calculateCertificateHash(t),n=a.some(e=>e.sha256===i);return n||this.logger.error("Certificate pinning validation failed",{hostname:e,expectedPins:a.map(e=>e.sha256),actualHash:i}),n}async calculateCertificateHash(e){const t=(new TextEncoder).encode(e),r=await crypto.subtle.digest("SHA-256",t),a=Array.from(new Uint8Array(r));return"sha256/"+btoa(String.fromCharCode(...a))}validateMetadata(t){if(t&&"object"!=typeof t)throw new A(e.ErrorCode.INVALID_BUNDLE_FORMAT,"Metadata must be an object");if(JSON.stringify(t||{}).length>10240)throw new A(e.ErrorCode.INVALID_BUNDLE_FORMAT,"Metadata is too large (max 10KB)")}}class b{constructor(){this.STORAGE_KEY="capacitor_native_update_bundles",this.ACTIVE_BUNDLE_KEY="capacitor_native_update_active",this.preferences=null,this.cache=new Map,this.cacheExpiry=0,this.logger=w.getInstance(),this.configManager=m.getInstance()}async initialize(){if(this.preferences=this.configManager.get("preferences"),!this.preferences)throw new v(e.ErrorCode.MISSING_DEPENDENCY,"Preferences not configured. Please configure the plugin first.");await this.loadCache()}async loadCache(){if(!(Date.now()<this.cacheExpiry))try{const{value:e}=await this.preferences.get({key:this.STORAGE_KEY});if(e){const t=JSON.parse(e);this.cache.clear(),t.forEach(e=>this.cache.set(e.bundleId,e))}this.cacheExpiry=Date.now()+5e3}catch(e){this.logger.error("Failed to load bundles from storage",e),this.cache.clear()}}async saveCache(){try{const e=Array.from(this.cache.values());await this.preferences.set({key:this.STORAGE_KEY,value:JSON.stringify(e)}),this.logger.debug("Saved bundles to storage",{count:e.length})}catch(t){throw new v(e.ErrorCode.STORAGE_FULL,"Failed to save bundles to storage",void 0,t)}}async saveBundleInfo(e){this.validateBundleInfo(e),this.cache.set(e.bundleId,e),await this.saveCache(),this.logger.info("Bundle saved",{bundleId:e.bundleId,version:e.version})}validateBundleInfo(t){if(!t.bundleId||"string"!=typeof t.bundleId)throw new v(e.ErrorCode.INVALID_BUNDLE_FORMAT,"Invalid bundle ID");if(!t.version||"string"!=typeof t.version)throw new v(e.ErrorCode.INVALID_BUNDLE_FORMAT,"Invalid bundle version");if(!t.path||"string"!=typeof t.path)throw new v(e.ErrorCode.INVALID_BUNDLE_FORMAT,"Invalid bundle path");if("number"!=typeof t.size||t.size<0)throw new v(e.ErrorCode.INVALID_BUNDLE_FORMAT,"Invalid bundle size")}async getAllBundles(){return await this.loadCache(),Array.from(this.cache.values())}async getBundle(t){if(!t)throw new v(e.ErrorCode.INVALID_BUNDLE_FORMAT,"Bundle ID is required");return await this.loadCache(),this.cache.get(t)||null}async deleteBundle(t){if(!t)throw new v(e.ErrorCode.INVALID_BUNDLE_FORMAT,"Bundle ID is required");await this.loadCache(),this.cache.get(t)?(this.cache.delete(t),await this.saveCache(),await this.getActiveBundleId()===t&&await this.clearActiveBundle(),this.logger.info("Bundle deleted",{bundleId:t})):this.logger.warn("Attempted to delete non-existent bundle",{bundleId:t})}async getActiveBundle(){const e=await this.getActiveBundleId();return e?this.getBundle(e):null}async setActiveBundle(t){if(!t)throw new v(e.ErrorCode.INVALID_BUNDLE_FORMAT,"Bundle ID is required");const r=await this.getBundle(t);if(!r)throw new v(e.ErrorCode.FILE_NOT_FOUND,`Bundle ${t} not found`);const a=await this.getActiveBundle();a&&a.bundleId!==t&&(a.status="READY",await this.saveBundleInfo(a)),r.status="ACTIVE",await this.saveBundleInfo(r),await this.preferences.set({key:this.ACTIVE_BUNDLE_KEY,value:t}),this.logger.info("Active bundle set",{bundleId:t,version:r.version})}async getActiveBundleId(){try{const{value:e}=await this.preferences.get({key:this.ACTIVE_BUNDLE_KEY});return e}catch(e){return this.logger.error("Failed to get active bundle ID",e),null}}async clearActiveBundle(){await this.preferences.remove({key:this.ACTIVE_BUNDLE_KEY}),this.logger.info("Active bundle cleared")}async clearAllBundles(){await this.preferences.remove({key:this.STORAGE_KEY}),await this.preferences.remove({key:this.ACTIVE_BUNDLE_KEY}),this.cache.clear(),this.cacheExpiry=0,this.logger.info("All bundles cleared")}async cleanupOldBundles(t){if(t<1)throw new v(e.ErrorCode.INVALID_CONFIG,"Keep count must be at least 1");const r=await this.getAllBundles(),a=await this.getActiveBundleId(),i=r.sort((e,t)=>t.downloadTime-e.downloadTime),n=new Set;a&&n.add(a);let s=n.size;for(const e of i){if(s>=t)break;n.has(e.bundleId)||(n.add(e.bundleId),s++)}let o=0;for(const e of r)n.has(e.bundleId)||(await this.deleteBundle(e.bundleId),o++);o>0&&this.logger.info("Cleaned up old bundles",{deleted:o,kept:s})}async getBundlesOlderThan(t){if(t<0)throw new v(e.ErrorCode.INVALID_CONFIG,"Timestamp must be non-negative");return(await this.getAllBundles()).filter(e=>e.downloadTime<t)}async markBundleAsVerified(t){const r=await this.getBundle(t);if(!r)throw new v(e.ErrorCode.FILE_NOT_FOUND,`Bundle ${t} not found`);r.verified=!0,await this.saveBundleInfo(r),this.logger.info("Bundle marked as verified",{bundleId:t})}async getTotalStorageUsed(){return(await this.getAllBundles()).reduce((e,t)=>e+t.size,0)}async isStorageLimitExceeded(e=0){const t=await this.getTotalStorageUsed();let r=3*this.configManager.get("maxBundleSize");try{if("storage"in navigator&&"estimate"in navigator.storage){const e=await navigator.storage.estimate();e.quota&&(r=Math.max(r,e.quota-104857600))}}catch(e){this.logger.warn("Storage API not available for quota check, using config limit")}return t+e>r}createDefaultBundle(){return{bundleId:"default",version:"1.0.0",path:"/",downloadTime:Date.now(),size:0,status:"ACTIVE",checksum:"",verified:!0}}async cleanExpiredBundles(){const e=this.configManager.get("cacheExpiration"),t=Date.now()-e,r=await this.getBundlesOlderThan(t);for(const e of r){const t=await this.getActiveBundleId();e.bundleId!==t&&await this.deleteBundle(e.bundleId)}}}class N{constructor(){this.activeDownloads=new Map,this.filesystem=null,this.logger=w.getInstance(),this.configManager=m.getInstance()}async initialize(){if(this.filesystem=this.configManager.get("filesystem"),!this.filesystem)throw new E(e.ErrorCode.MISSING_DEPENDENCY,"Filesystem not configured. Please configure the plugin first.")}validateUrl(t){try{const r=new URL(t);if("https:"!==r.protocol)throw new A(e.ErrorCode.INVALID_URL,"Only HTTPS URLs are allowed for security reasons");const a=this.configManager.get("allowedHosts");if(a.length>0&&!a.includes(r.hostname))throw new A(e.ErrorCode.UNAUTHORIZED_HOST,`Host ${r.hostname} is not in the allowed hosts list`)}catch(t){if(t instanceof A)throw t;throw new A(e.ErrorCode.INVALID_URL,"Invalid URL format")}}async download(t,r,a){if(this.validateUrl(t),!r)throw new A(e.ErrorCode.INVALID_BUNDLE_FORMAT,"Bundle ID is required");if(this.activeDownloads.has(r))throw new E(e.ErrorCode.DOWNLOAD_FAILED,`Download already in progress for bundle ${r}`);const i=new AbortController,n={controller:i,startTime:Date.now()};this.activeDownloads.set(r,n);try{const s=this.configManager.get("downloadTimeout"),o=setTimeout(()=>i.abort(),s),l={"Cache-Control":"no-cache",Accept:"application/octet-stream, application/zip"};n.resumePosition&&n.resumePosition>0&&(l.Range=`bytes=${n.resumePosition}-`);const c=await fetch(t,{signal:i.signal,headers:l});if(clearTimeout(o),!c.ok)throw new E(e.ErrorCode.DOWNLOAD_FAILED,`Download failed: ${c.status} ${c.statusText}`,{status:c.status,statusText:c.statusText});const d=c.headers.get("content-type");if(d&&!this.isValidContentType(d))throw new A(e.ErrorCode.INVALID_BUNDLE_FORMAT,`Invalid content type: ${d}`);const u=c.headers.get("content-length"),h=u?parseInt(u,10):0;if(h>this.configManager.get("maxBundleSize"))throw new A(e.ErrorCode.BUNDLE_TOO_LARGE,`Bundle size ${h} exceeds maximum allowed size`);if(!h||!c.body){const e=await c.blob();return this.validateBlobSize(e),e}const g=c.body.getReader(),p=[];let f=0;for(;;){const{done:t,value:i}=await g.read();if(t)break;if(p.push(i),f+=i.length,f>this.configManager.get("maxBundleSize"))throw new A(e.ErrorCode.BUNDLE_TOO_LARGE,"Download size exceeds maximum allowed size");if(a){const e=n.resumePosition||0,t=e+f,i=e+h;a({percent:Math.round(t/i*100),bytesDownloaded:t,totalBytes:i,bundleId:r})}}const m=new Blob(p);return this.validateBlobSize(m),this.logger.info("Download completed",{bundleId:r,size:m.size,duration:Date.now()-n.startTime}),m}catch(t){if(t instanceof Error&&"AbortError"===t.name){const r=Date.now()-n.startTime>=this.configManager.get("downloadTimeout");throw new E(r?e.ErrorCode.DOWNLOAD_TIMEOUT:e.ErrorCode.DOWNLOAD_FAILED,r?"Download timed out":"Download cancelled",void 0,t)}throw t}finally{this.activeDownloads.delete(r)}}async resumeDownload(e,t,r,a){const i=this.activeDownloads.get(t);i&&(i.resumePosition=r.size);try{const i=await this.download(e,t,a);return new Blob([r,i])}catch(e){throw this.activeDownloads.delete(t),e}}async canResume(e){try{return"bytes"===(await fetch(e,{method:"HEAD"})).headers.get("Accept-Ranges")}catch(e){return!1}}isValidContentType(e){return["application/octet-stream","application/zip","application/x-zip-compressed","application/x-zip"].some(t=>e.includes(t))}validateBlobSize(t){if(0===t.size)throw new A(e.ErrorCode.INVALID_BUNDLE_FORMAT,"Downloaded file is empty");if(t.size>this.configManager.get("maxBundleSize"))throw new A(e.ErrorCode.BUNDLE_TOO_LARGE,`File size ${t.size} exceeds maximum allowed size`)}cancelDownload(e){const t=this.activeDownloads.get(e);t&&(t.controller.abort(),this.activeDownloads.delete(e),this.logger.info("Download cancelled",{bundleId:e}))}cancelAllDownloads(){for(const e of this.activeDownloads.values())e.controller.abort();const e=this.activeDownloads.size;this.activeDownloads.clear(),e>0&&this.logger.info("All downloads cancelled",{count:e})}isDownloading(e){return this.activeDownloads.has(e)}getActiveDownloadCount(){return this.activeDownloads.size}async downloadWithRetry(t,r,a){const i=this.configManager.get("retryAttempts"),n=this.configManager.get("retryDelay");let s=null;for(let e=0;e<i;e++)try{if(e>0){const t=Math.min(n*Math.pow(2,e-1),3e4);await new Promise(e=>setTimeout(e,t)),this.logger.debug("Retrying download",{bundleId:r,attempt:e,delay:t})}return await this.download(t,r,a)}catch(t){if(s=t,t instanceof A||t instanceof Error&&"AbortError"===t.name)throw t;this.logger.warn(`Download attempt ${e+1} failed`,{bundleId:r,error:t})}throw new E(e.ErrorCode.DOWNLOAD_FAILED,"Download failed after all retries",{attempts:i},s||void 0)}async blobToArrayBuffer(e){return e.arrayBuffer()}async saveBlob(t,a){if(!this.filesystem)throw new E(e.ErrorCode.MISSING_DEPENDENCY,"Filesystem not initialized");const i=await this.blobToArrayBuffer(a),n=btoa(String.fromCharCode(...new Uint8Array(i))),s=`bundles/${t}/bundle.zip`;return await this.filesystem.writeFile({path:s,data:n,directory:r.Directory.Data,recursive:!0}),this.logger.debug("Bundle saved to filesystem",{bundleId:t,path:s,size:a.size}),s}async loadBlob(t){if(!this.filesystem)throw new E(e.ErrorCode.MISSING_DEPENDENCY,"Filesystem not initialized");try{const e=`bundles/${t}/bundle.zip`,a=await this.filesystem.readFile({path:e,directory:r.Directory.Data}),i=atob(a.data),n=new Uint8Array(i.length);for(let e=0;e<i.length;e++)n[e]=i.charCodeAt(e);return new Blob([n],{type:"application/zip"})}catch(e){return this.logger.debug("Failed to load bundle from filesystem",{bundleId:t,error:e}),null}}async deleteBlob(t){if(!this.filesystem)throw new E(e.ErrorCode.MISSING_DEPENDENCY,"Filesystem not initialized");try{const e=`bundles/${t}`;await this.filesystem.rmdir({path:e,directory:r.Directory.Data,recursive:!0}),this.logger.debug("Bundle deleted from filesystem",{bundleId:t})}catch(e){this.logger.warn("Failed to delete bundle from filesystem",{bundleId:t,error:e})}}}function C(e){const t=Math.floor(e.nanoseconds/1e6);return new Date(1e3*e.seconds+t)}const U="manifests";function R(e,t){return`${e}_${t}`}class _{constructor(e){var t;this.cache=new Map,this.config={projectId:e.projectId,databaseId:e.databaseId||"(default)",appId:e.appId,channel:e.channel,cacheDuration:e.cacheDuration||3e5,enableOffline:null===(t=e.enableOffline)||void 0===t||t},this.logger=w.getInstance()}static getInstance(e){if(!_.instance&&e&&(_.instance=new _(e)),!_.instance)throw new Error("FirestoreClient not initialized. Call with config first.");return _.instance}static resetInstance(){_.instance=null}getBaseUrl(){return`https://firestore.googleapis.com/v1/projects/${this.config.projectId}/databases/${this.config.databaseId}/documents`}async getDocument(e,t){const r=`${e}/${t}`,a=this.getFromCache(r);if(null!==a)return this.logger.debug("Firestore cache hit",{collection:e,documentId:t}),a;const i=`${this.getBaseUrl()}/${e}/${t}`;try{this.logger.debug("Fetching Firestore document",{url:i});const a=await fetch(i,{method:"GET",headers:{"Content-Type":"application/json"}});if(404===a.status)return this.logger.debug("Firestore document not found",{collection:e,documentId:t}),null;if(!a.ok)throw new Error(`Firestore error: ${a.status} ${a.statusText}`);const n=await a.json(),s=this.parseDocument(n);return this.setCache(r,s),s}catch(e){this.logger.error("Firestore fetch error",e);const t=this.getFromCache(r,!0);if(null!==t)return this.logger.warn("Using stale cache due to fetch error"),t;throw e}}async getManifest(){const e=R(this.config.appId,this.config.channel);return this.getDocument(U,e)}async getManifestFor(e,t){const r=R(e,t);return this.getDocument(U,r)}parseDocument(e){return this.parseValue({mapValue:{fields:e.fields}})}parseValue(e){if("stringValue"in e)return e.stringValue;if("integerValue"in e)return parseInt(e.integerValue,10);if("doubleValue"in e)return e.doubleValue;if("booleanValue"in e)return e.booleanValue;if("nullValue"in e)return null;if("timestampValue"in e)return this.parseTimestamp(e.timestampValue);if("mapValue"in e){const t={},r=e.mapValue.fields||{};for(const[e,a]of Object.entries(r))t[e]=this.parseValue(a);return t}return"arrayValue"in e?(e.arrayValue.values||[]).map(e=>this.parseValue(e)):null}parseTimestamp(e){const t=new Date(e);return{seconds:Math.floor(t.getTime()/1e3),nanoseconds:t.getTime()%1e3*1e6}}getFromCache(e,t=!1){const r=this.cache.get(e);return r&&(Date.now()<r.expiresAt||t)?r.data:null}setCache(e,t){const r=Date.now();this.cache.set(e,{data:t,timestamp:r,expiresAt:r+this.config.cacheDuration})}clearCache(){this.cache.clear(),this.logger.debug("Firestore cache cleared")}clearCacheEntry(e,t){this.cache.delete(`${e}/${t}`)}getCacheStats(){return{size:this.cache.size,keys:Array.from(this.cache.keys())}}getConfig(){return Object.assign({},this.config)}setChannel(e){this.config.channel=e,this.clearCache()}isConfigured(){return!!(this.config.projectId&&this.config.appId&&this.config.channel)}}_.instance=null;class L{constructor(e){this.firestoreClient=e,this.logger=w.getInstance()}async checkForUpdates(e){const{currentVersion:t,deviceInfo:r,checkDeltas:a=!0}=e;try{e.forceRefresh&&this.firestoreClient.clearCache();const i=await this.firestoreClient.getManifest();if(!i)return this.logger.debug("No manifest found"),{updateAvailable:!1};if(!this.isNewerVersion(t,i.current.version))return{updateAvailable:!1,version:i.current.version};const n=await this.checkRolloutEligibility(i.rollout,r);if(!n.eligible)return{updateAvailable:!0,version:i.current.version,rolloutEligible:!1,rolloutReason:n.reason};const s={updateAvailable:!0,version:i.current.version,bundleUrl:i.current.bundleUrl,minNativeVersion:i.current.minNativeVersion,releaseNotes:i.current.releaseNotes,signature:i.current.signature,checksum:i.current.checksum,mandatory:i.current.mandatory,size:i.current.size,rolloutEligible:!0};if(a&&i.deltas){const e=i.deltas[t];e?(s.delta={available:!0,patchUrl:e.patchUrl,patchSize:e.patchSize,patchChecksum:e.patchChecksum,targetChecksum:e.targetChecksum},this.logger.debug("Delta update available",{from:t,to:i.current.version,patchSize:e.patchSize})):s.delta={available:!1}}return s}catch(e){throw this.logger.error("Error checking for updates",e),e}}async checkRolloutEligibility(e,t){var r,a;if(!e.enabled)return{eligible:!0,reason:"Rollout not enabled, all devices eligible"};const i=Date.now();if(i<C(e.startTime).getTime())return{eligible:!1,reason:"Rollout not started yet"};if(e.endTime&&i>C(e.endTime).getTime())return{eligible:!1,reason:"Rollout ended"};if("scheduled"===(null===(r=e.schedule)||void 0===r?void 0:r.type)&&e.schedule.scheduledTime&&i<C(e.schedule.scheduledTime).getTime())return{eligible:!1,reason:"Scheduled for later"};if(e.targetSegments){const r=this.checkSegments(e.targetSegments,t);if(!r.eligible)return r}let n=e.percentage;"gradual"===(null===(a=e.schedule)||void 0===a?void 0:a.type)&&(n=this.calculateGradualPercentage(e));const s=await this.getDevicePercentile(t.deviceId);return s>n?{eligible:!1,reason:`Device percentile ${s.toFixed(1)}% > rollout ${n}%`}:{eligible:!0,reason:"All checks passed"}}checkSegments(e,t){return e.platforms&&e.platforms.length>0&&!e.platforms.includes(t.platform)?{eligible:!1,reason:`Platform ${t.platform} not targeted`}:e.minAppVersion&&this.compareVersions(t.appVersion,e.minAppVersion)<0?{eligible:!1,reason:`App version below minimum ${e.minAppVersion}`}:e.maxAppVersion&&this.compareVersions(t.appVersion,e.maxAppVersion)>0?{eligible:!1,reason:`App version above maximum ${e.maxAppVersion}`}:e.deviceIds&&e.deviceIds.length>0&&!e.deviceIds.includes(t.deviceId)?{eligible:!1,reason:"Device not in whitelist"}:!(e.regions&&e.regions.length>0)||t.region&&e.regions.includes(t.region)?{eligible:!0,reason:"Segment checks passed"}:{eligible:!1,reason:`Region ${t.region||"unknown"} not targeted`}}calculateGradualPercentage(e){var t,r;if(!(null===(t=e.schedule)||void 0===t?void 0:t.gradualSteps)||!(null===(r=e.schedule)||void 0===r?void 0:r.gradualInterval))return e.percentage;const a=C(e.startTime).getTime(),i=(Date.now()-a)/36e5,n=Math.floor(i/e.schedule.gradualInterval),s=e.schedule.gradualSteps;return n>=s.length?s[s.length-1]:s[n]}async getDevicePercentile(e){const t=await this.hashString(e);return this.hashToPercentile(t)}async hashString(e){const t=(new TextEncoder).encode(e),r=await crypto.subtle.digest("SHA-256",t);return Array.from(new Uint8Array(r)).map(e=>e.toString(16).padStart(2,"0")).join("")}hashToPercentile(e){return parseInt(e.substring(0,8),16)/parseInt("ffffffff",16)*100}compareVersions(e,t){const r=e.split("-")[0],a=t.split("-")[0],i=r.split(".").map(Number),n=a.split(".").map(Number);for(let e=0;e<Math.max(i.length,n.length);e++){const t=i[e]||0,r=n[e]||0;if(t>r)return 1;if(t<r)return-1}const s=e.includes("-"),o=t.includes("-");return s&&!o?-1:!s&&o?1:0}isNewerVersion(e,t){return this.compareVersions(e,t)<0}async getManifest(){return this.firestoreClient.getManifest()}async getManifestFor(e,t){return this.firestoreClient.getManifestFor(e,t)}clearCache(){this.firestoreClient.clearCache()}}class S{constructor(){this.VERSION_CHECK_CACHE_KEY="capacitor_native_update_version_cache",this.CACHE_DURATION=3e5,this.preferences=null,this.memoryCache=new Map,this.firestoreClient=null,this.manifestReader=null,this.logger=w.getInstance(),this.configManager=m.getInstance(),this.securityValidator=D.getInstance()}static compareVersions(e,t){try{const[r,a]=e.split("-"),[i,n]=t.split("-"),s=r.split(".").map(Number),o=i.split(".").map(Number);for(let e=0;e<3;e++){const t=s[e]||0,r=o[e]||0;if(t>r)return 1;if(t<r)return-1}return a&&!n?-1:!a&&n?1:a&&n?a.localeCompare(n):0}catch(r){return e===t?0:e>t?1:-1}}static isValidVersion(e){return/^\d+\.\d+\.\d+(-[a-zA-Z0-9.-]+)?(\+[a-zA-Z0-9.-]+)?$/.test(e)}static shouldUpdate(e,t,r){return!(r&&S.compareVersions(e,r)<0)&&S.compareVersions(e,t)<0}async initialize(){if(this.preferences=this.configManager.get("preferences"),!this.preferences)throw new A(e.ErrorCode.MISSING_DEPENDENCY,"Preferences not configured. Please configure the plugin first.");if("firestore"===this.configManager.get("backendType")){const t=this.configManager.get("firestore");if(!t)throw new A(e.ErrorCode.INVALID_CONFIG,"Firestore configuration required when using firestore backend");this.firestoreClient=new _(t),this.manifestReader=new L(this.firestoreClient),this.logger.debug("Firestore backend initialized")}}async checkForUpdatesFromFirestore(t,r){if(!this.manifestReader)throw new A(e.ErrorCode.INVALID_CONFIG,"Firestore backend not initialized. Call initialize() first or configure firestore backend.");this.securityValidator.validateVersion(t);const a={currentVersion:t,deviceInfo:r,checkDeltas:this.configManager.get("enableDeltaUpdates")};try{const e=await this.manifestReader.checkForUpdates(a);return e&&this.logger.info("Firestore update check completed",{currentVersion:t,latestVersion:e.version,updateAvailable:e.updateAvailable,eligible:e.rolloutEligible}),e}catch(e){return this.logger.error("Failed to check for updates from Firestore",e),null}}async checkForUpdatesAuto(t,r){if("firestore"===(this.configManager.get("backendType")||"http")){if(!r)throw new A(e.ErrorCode.INVALID_CONFIG,"Device info is required for Firestore backend");return this.checkForUpdatesFromFirestore(t,r)}const a=this.configManager.get("serverUrl"),i=this.configManager.get("channel")||"production",n=this.configManager.get("appId");if(!a||!n)throw new A(e.ErrorCode.INVALID_CONFIG,"Server URL and App ID are required for HTTP backend");return this.checkForUpdates(a,i,t,n)}async checkForUpdates(t,r,a,i){if(this.securityValidator.validateUrl(t),this.securityValidator.validateVersion(a),!r||!i)throw new A(e.ErrorCode.INVALID_CONFIG,"Channel and appId are required");const n=`${r}-${i}`,s=await this.getCachedVersionInfo(n);if(s&&s.channel===r&&Date.now()-s.timestamp<this.CACHE_DURATION)return this.logger.debug("Returning cached version info",{channel:r,version:s.data.version}),s.data;try{const s=new URL(`${t}/check`);s.searchParams.append("channel",r),s.searchParams.append("version",a),s.searchParams.append("appId",i),s.searchParams.append("platform","web");const o=await fetch(s.toString(),{method:"GET",headers:{"Content-Type":"application/json","X-App-Version":a,"X-App-Id":i},signal:AbortSignal.timeout(this.configManager.get("downloadTimeout"))});if(!o.ok)throw new Error(`Version check failed: ${o.status}`);const l=await o.json();if(!l.version)throw new A(e.ErrorCode.INVALID_BUNDLE_FORMAT,"No version in server response");return this.securityValidator.validateVersion(l.version),l.bundleUrl&&this.securityValidator.validateUrl(l.bundleUrl),l.minAppVersion&&this.securityValidator.validateVersion(l.minAppVersion),await this.cacheVersionInfo(n,r,l),this.logger.info("Version check completed",{channel:r,currentVersion:a,latestVersion:l.version,updateAvailable:this.isNewerVersion(l.version,a)}),l}catch(e){return this.logger.error("Failed to check for updates",e),null}}isNewerVersion(e,t){try{const r=this.parseVersion(e),a=this.parseVersion(t);return r.major!==a.major?r.major>a.major:r.minor!==a.minor?r.minor>a.minor:r.patch!==a.patch?r.patch>a.patch:!(r.prerelease&&!a.prerelease||(r.prerelease||!a.prerelease)&&(!r.prerelease||!a.prerelease||!(r.prerelease>a.prerelease)))}catch(r){return this.logger.error("Failed to compare versions",{version1:e,version2:t,error:r}),!1}}isUpdateMandatory(e,t){if(!t)return!1;try{return this.securityValidator.validateVersion(e),this.securityValidator.validateVersion(t),!this.isNewerVersion(e,t)&&e!==t}catch(e){return this.logger.error("Failed to check mandatory update",e),!1}}parseVersion(t){const r=t.match(/^(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?(?:\+([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?$/);if(!r)throw new A(e.ErrorCode.INVALID_BUNDLE_FORMAT,"Invalid version format");return{major:parseInt(r[1],10),minor:parseInt(r[2],10),patch:parseInt(r[3],10),prerelease:r[4],build:r[5]}}buildVersionString(e){let t=`${e.major}.${e.minor}.${e.patch}`;return e.prerelease&&(t+=`-${e.prerelease}`),e.build&&(t+=`+${e.build}`),t}isCompatibleWithNativeVersion(e,t,r){if(!r)return!0;try{const a=r[e];return!a||(this.securityValidator.validateVersion(t),this.securityValidator.validateVersion(a),!this.isNewerVersion(a,t))}catch(e){return this.logger.error("Failed to check compatibility",e),!1}}async getCachedVersionInfo(e){const t=this.memoryCache.get(e);if(t&&Date.now()-t.timestamp<this.CACHE_DURATION)return t;try{const{value:t}=await this.preferences.get({key:this.VERSION_CHECK_CACHE_KEY});if(!t)return null;const r=JSON.parse(t)[e];if(r&&Date.now()-r.timestamp<this.CACHE_DURATION)return this.memoryCache.set(e,r),r}catch(e){this.logger.debug("Failed to load cached version info",e)}return null}async cacheVersionInfo(e,t,r){const a={channel:t,data:r,timestamp:Date.now()};this.memoryCache.set(e,a);try{const{value:t}=await this.preferences.get({key:this.VERSION_CHECK_CACHE_KEY}),r=t?JSON.parse(t):{},i=Date.now();for(const e in r)i-r[e].timestamp>2*this.CACHE_DURATION&&delete r[e];r[e]=a,await this.preferences.set({key:this.VERSION_CHECK_CACHE_KEY,value:JSON.stringify(r)})}catch(e){this.logger.warn("Failed to cache version info",e)}}async clearVersionCache(){this.memoryCache.clear();try{await this.preferences.remove({key:this.VERSION_CHECK_CACHE_KEY})}catch(e){this.logger.warn("Failed to clear version cache",e)}}shouldBlockDowngrade(e,t){try{return this.securityValidator.isVersionDowngrade(e,t)}catch(e){return this.logger.error("Failed to check downgrade",e),!0}}}class O{constructor(e){this.cachedAppInfo=null,this.CACHE_DURATION=6e4,this.config=e,this.logger=new w("AppUpdateChecker")}async checkServerVersion(e){if(!this.config.updateUrl)return{};try{const e=await this.getCurrentVersion(),t=new URL(`${this.config.updateUrl}/app-version`);t.searchParams.append("platform",this.getPlatform()),t.searchParams.append("current",e),this.config.channel&&t.searchParams.append("channel",this.config.channel);const r=await fetch(t.toString(),{method:"GET",headers:{Accept:"application/json","X-App-Version":e,"X-App-Platform":this.getPlatform()}});if(!r.ok)throw new Error(`Server returned ${r.status}`);const a=await r.json();return{availableVersion:a.version,updatePriority:a.priority,releaseNotes:a.releaseNotes,updateSize:a.size,updateURL:a.downloadUrl}}catch(e){return this.logger.error("Failed to check server version",e),{}}}compareVersions(e,t){const r=e.split(".").map(Number),a=t.split(".").map(Number);for(let e=0;e<Math.max(r.length,a.length);e++){const t=r[e]||0,i=a[e]||0;if(t>i)return 1;if(t<i)return-1}return 0}isUpdateRequired(e,t,r){return this.compareVersions(e,t)<0||!!(r&&this.compareVersions(e,r)<0)}determineUpdatePriority(e,t){const[r,a]=e.split(".").map(Number);return r>0?5:a>0&&t&&t>30?4:a>0?3:1}async getCurrentVersion(){if(this.cachedAppInfo&&Date.now()-this.cachedAppInfo.timestamp<this.CACHE_DURATION)return this.cachedAppInfo.version;try{const{App:e}=await Promise.resolve().then(function(){return K}),t=await e.getInfo();return this.cachedAppInfo={version:t.version,build:t.build,name:t.name,id:t.id,timestamp:Date.now()},this.logger.debug("Got app info from Capacitor",{version:t.version,build:t.build}),t.version}catch(e){this.logger.debug("Failed to get app info from Capacitor, using fallback",e);const t=this.config.appVersion;if("string"==typeof t)return t;if("undefined"!=typeof window){const e=window;if("string"==typeof e.APP_VERSION)return e.APP_VERSION}return"1.0.0"}}async getCurrentBuild(){if(this.cachedAppInfo&&Date.now()-this.cachedAppInfo.timestamp<this.CACHE_DURATION)return this.cachedAppInfo.build;try{const{App:e}=await Promise.resolve().then(function(){return K}),t=await e.getInfo();return this.cachedAppInfo={version:t.version,build:t.build,name:t.name,id:t.id,timestamp:Date.now()},t.build}catch(e){return"1"}}async getAppInfo(){if(this.cachedAppInfo&&Date.now()-this.cachedAppInfo.timestamp<this.CACHE_DURATION)return this.cachedAppInfo;try{const{App:e}=await Promise.resolve().then(function(){return K}),t=await e.getInfo();return this.cachedAppInfo={version:t.version,build:t.build,name:t.name,id:t.id,timestamp:Date.now()},this.cachedAppInfo}catch(e){return{version:"1.0.0",build:"1",name:"App",id:"com.app",timestamp:Date.now()}}}clearCache(){this.cachedAppInfo=null}getPlatform(){if("undefined"!=typeof window){const e=window.navigator.userAgent;if(/android/i.test(e))return"android";if(/iPad|iPhone|iPod/.test(e))return"ios"}return"web"}}var T;!function(e){e[e.UNKNOWN=0]="UNKNOWN",e[e.PENDING=1]="PENDING",e[e.DOWNLOADING=2]="DOWNLOADING",e[e.INSTALLING=3]="INSTALLING",e[e.INSTALLED=4]="INSTALLED",e[e.FAILED=5]="FAILED",e[e.CANCELED=6]="CANCELED",e[e.DOWNLOADED=11]="DOWNLOADED"}(T||(T={}));class M{constructor(e){this.logger=new w("AppUpdateInstaller"),this.currentState={installStatus:T.UNKNOWN,packageName:"",availableVersion:""}}async startImmediateUpdate(){if(this.logger.log("Starting immediate update installation"),this.updateState(T.PENDING),this.isAndroid())this.logger.log("Triggering Android immediate update");else{if(!this.isIOS())throw new Error("Immediate updates not supported on web platform");this.logger.log("Opening iOS App Store for update")}}async startFlexibleUpdate(){if(this.logger.log("Starting flexible update download"),this.updateState(T.DOWNLOADING),this.isWeb())this.simulateFlexibleUpdate();else{if(!this.isAndroid())throw new Error("Flexible updates not supported on iOS");this.logger.log("Starting Android flexible update")}}async completeFlexibleUpdate(){if(this.logger.log("Completing flexible update installation"),this.currentState.installStatus!==T.DOWNLOADED)throw new Error("Update not ready for installation");this.updateState(T.INSTALLING),this.isAndroid()?this.logger.log("Completing Android update installation"):setTimeout(()=>{this.updateState(T.INSTALLED)},1e3)}async cancelUpdate(){this.logger.log("Cancelling update"),this.currentState.installStatus===T.DOWNLOADING&&this.updateState(T.CANCELED)}async getInstallState(){return Object.assign({},this.currentState)}onProgress(e){this.progressCallback=e}updateState(e,t){this.currentState.installStatus=e,void 0!==t&&(this.currentState.installErrorCode=t),this.logger.log("Update state changed",this.currentState)}simulateFlexibleUpdate(){let e=0;const t=52428800,r=1048576,a=setInterval(()=>{e+=r,e>=t&&(e=t,clearInterval(a),this.updateState(T.DOWNLOADED));const i={bytesDownloaded:e,totalBytesToDownload:t,percentComplete:Math.round(e/t*100),downloadSpeed:r,estimatedTime:Math.ceil((t-e)/r)};this.progressCallback&&this.progressCallback(i)},1e3)}isAndroid(){return"undefined"!=typeof window&&/android/i.test(window.navigator.userAgent)}isIOS(){return"undefined"!=typeof window&&/iPad|iPhone|iPod/.test(window.navigator.userAgent)}isWeb(){return!this.isAndroid()&&!this.isIOS()}}class V{constructor(e){this.config=e,this.logger=new w("PlatformAppUpdate"),this.platform=t.Capacitor.getPlatform()}async checkForUpdate(e){this.logger.log("Checking for platform update: "+this.platform);const t=await this.getVersionInfo(),r={updateAvailable:!1,currentVersion:t.currentVersion,availableVersion:t.currentVersion};if("android"===this.platform)return r;if("ios"===this.platform)return r;if(this.config.webUpdateUrl)try{const e=await fetch(this.config.webUpdateUrl),a=await e.json();a.version&&a.version!==t.currentVersion&&(r.updateAvailable=!0,r.availableVersion=a.version,r.releaseNotes=a.releaseNotes,r.updateURL=a.downloadUrl)}catch(e){this.logger.error("Failed to check web update",e)}return r}async getVersionInfo(){return{currentVersion:"1.0.0",buildNumber:"1",packageName:"com.example.app",platform:this.platform,minimumVersion:this.config.minimumVersion}}async getAppStoreUrl(){const e=this.platform;let t="";if("ios"===e){const e=this.config.appStoreId||this.config.iosAppId;if(!e)throw new Error("App Store ID not configured");t=`https://apps.apple.com/app/id${e}`}else t="android"===e?`https://play.google.com/store/apps/details?id=${this.config.packageName||(await this.getVersionInfo()).packageName}`:this.config.webUpdateUrl||window.location.origin;return{url:t,platform:e}}async openUrl(e){if("undefined"==typeof window||!window.open)throw new Error("Cannot open URL on this platform");window.open(e,"_blank")}isUpdateSupported(){return"android"===this.platform||"ios"!==this.platform}getUpdateCapabilities(){const e={immediateUpdate:!1,flexibleUpdate:!1,backgroundDownload:!1,inAppReview:!1};return"android"===this.platform?(e.immediateUpdate=!0,e.flexibleUpdate=!0,e.backgroundDownload=!0,e.inAppReview=!0):"ios"===this.platform&&(e.inAppReview=!0),e}}class B{constructor(e){this.listeners=new Map,this.config=e,this.logger=new w("AppUpdateManager"),this.checker=new O(e),this.installer=new M(e),this.platformUpdate=new V(e)}async checkAppUpdate(e){try{this.logger.log("Checking for app updates",e);const t=await this.platformUpdate.checkForUpdate(e);if(!t.updateAvailable&&this.config.updateUrl){const r=await this.checker.checkServerVersion(e);return this.mergeUpdateInfo(t,r)}return t}catch(e){throw this.logger.error("Failed to check app update",e),e}}async startImmediateUpdate(){try{this.logger.log("Starting immediate update");const e=await this.checkAppUpdate();if(!e.immediateUpdateAllowed)throw new Error("Immediate update not allowed");await this.installer.startImmediateUpdate(),this.emit("appUpdateStateChanged",{installStatus:1,packageName:this.config.packageName||"",availableVersion:e.availableVersion||""})}catch(e){throw this.logger.error("Failed to start immediate update",e),e}}async startFlexibleUpdate(){try{this.logger.log("Starting flexible update");const e=await this.checkAppUpdate();if(!e.flexibleUpdateAllowed)throw new Error("Flexible update not allowed");await this.installer.startFlexibleUpdate(),this.installer.onProgress(e=>{this.emit("appUpdateProgress",e)}),this.emit("appUpdateStateChanged",{installStatus:2,packageName:this.config.packageName||"",availableVersion:e.availableVersion||""})}catch(e){throw this.logger.error("Failed to start flexible update",e),e}}async completeFlexibleUpdate(){try{this.logger.log("Completing flexible update"),await this.installer.completeFlexibleUpdate(),this.emit("appUpdateStateChanged",{installStatus:3,packageName:this.config.packageName||"",availableVersion:""})}catch(e){throw this.logger.error("Failed to complete flexible update",e),e}}async getVersionInfo(){try{return this.logger.log("Getting version info"),await this.platformUpdate.getVersionInfo()}catch(e){throw this.logger.error("Failed to get version info",e),e}}async isMinimumVersionMet(){try{this.logger.log("Checking minimum version");const e=await this.getVersionInfo(),t=this.config.minimumVersion||"0.0.0",r=this.checker.compareVersions(e.currentVersion,t)>=0;return{isMet:r,currentVersion:e.currentVersion,minimumVersion:t,updateRequired:!r&&!0===this.config.enforceMinVersion}}catch(e){throw this.logger.error("Failed to check minimum version",e),e}}async getAppUpdateInfo(){return this.checkAppUpdate()}async performImmediateUpdate(){return this.startImmediateUpdate()}async openAppStore(e){try{this.logger.log("Opening app store");const e=await this.getAppStoreUrl();await this.platformUpdate.openUrl(e.url)}catch(e){throw this.logger.error("Failed to open app store",e),e}}async getAppStoreUrl(){try{return this.logger.log("Getting app store URL"),await this.platformUpdate.getAppStoreUrl()}catch(e){throw this.logger.error("Failed to get app store URL",e),e}}async getUpdateInstallState(){try{return this.logger.log("Getting update install state"),await this.installer.getInstallState()}catch(e){throw this.logger.error("Failed to get update install state",e),e}}addListener(e,t){return this.listeners.has(e)||this.listeners.set(e,new Set),this.listeners.get(e).add(t),{remove:async()=>{const r=this.listeners.get(e);r&&r.delete(t)}}}async removeAllListeners(e){e?this.listeners.delete(e):this.listeners.clear()}emit(e,t){const r=this.listeners.get(e);r&&r.forEach(r=>{try{r(t)}catch(t){this.logger.error(`Error in ${e} listener`,t)}})}mergeUpdateInfo(e,t){return Object.assign(Object.assign(Object.assign({},e),t),{updateAvailable:e.updateAvailable||!!t.availableVersion,availableVersion:t.availableVersion||e.availableVersion})}}class k{constructor(){this.config=null,this.status={enabled:!1,isRunning:!1,checkCount:0,failureCount:0},this.deps={},this.logger=w.getInstance(),this.configManager=m.getInstance()}setDependencies(e){this.deps=e}configure(e){this.config=e,this.status.enabled=e.enabled}getStatus(){return Object.assign({},this.status)}async performCheck(){var e;if(!(null===(e=this.config)||void 0===e?void 0:e.enabled))return{success:!1,updatesFound:!1,notificationSent:!1,error:{code:g.INVALID_CONFIG,message:"Background updates not enabled"}};this.status.isRunning=!0,this.status.checkCount++;try{const e=await this.checkForUpdates();return this.status.lastCheckTime=Date.now(),this.status.isRunning=!1,this.status.lastError=void 0,e}catch(e){return this.status.failureCount++,this.status.isRunning=!1,this.status.lastError={code:g.UNKNOWN_ERROR,message:e instanceof Error?e.message:"Unknown error"},{success:!1,updatesFound:!1,notificationSent:!1,error:this.status.lastError}}}async checkForUpdates(){var e,t,r,a,n,s;const o=[];let l,c;((null===(e=this.config)||void 0===e?void 0:e.updateTypes.includes(i.APP_UPDATE))||(null===(t=this.config)||void 0===t?void 0:t.updateTypes.includes(i.BOTH)))&&o.push(this.checkAppUpdate()),((null===(r=this.config)||void 0===r?void 0:r.updateTypes.includes(i.LIVE_UPDATE))||(null===(a=this.config)||void 0===a?void 0:a.updateTypes.includes(i.BOTH)))&&o.push(this.checkLiveUpdate());const d=await Promise.allSettled(o);"fulfilled"===(null===(n=d[0])||void 0===n?void 0:n.status)&&(l=d[0].value),"fulfilled"===(null===(s=d[1])||void 0===s?void 0:s.status)&&(c=d[1].value);const u=(null==l?void 0:l.updateAvailable)||(null==c?void 0:c.available)||!1;let h=!1;return u&&(h=await this.sendNotification(l,c)),{success:!0,updatesFound:u,appUpdate:l,liveUpdate:c,notificationSent:h}}async checkAppUpdate(){if(this.deps.appUpdateManager)try{return await this.deps.appUpdateManager.getAppUpdateInfo()}catch(e){this.logger.error("Failed to check app update via manager",e)}const e=this.configManager.get("baseUrl")||this.configManager.get("serverUrl");if(e)try{const t=await this.getCurrentAppVersion(),r=await fetch(`${e}/app-version`,{method:"GET",headers:{"Content-Type":"application/json","X-Current-Version":t,"X-Platform":this.getPlatform()}});if(r.ok){const e=await r.json(),a=e.version||e.latestVersion,i=a&&this.compareVersions(t,a)<0;return{updateAvailable:i,currentVersion:t,availableVersion:i?a:void 0,updatePriority:e.priority}}}catch(e){this.logger.error("Failed to check app update via server",e)}return{updateAvailable:!1,currentVersion:await this.getCurrentAppVersion()}}async checkLiveUpdate(){let e="1.0.0";if(this.deps.bundleManager)try{const t=await this.deps.bundleManager.getActiveBundle();t&&(e=t.version)}catch(e){}if(this.deps.versionManager)try{const t=this.configManager.get("serverUrl"),r=this.configManager.get("channel")||"production",a=this.configManager.get("appId");if(t&&a){const i=await this.deps.versionManager.checkForUpdates(t,r,e,a);if(i)return i}}catch(e){this.logger.error("Failed to check live update via VersionManager",e)}const t=this.configManager.get("baseUrl")||this.configManager.get("serverUrl");if(t)try{const r=await fetch(`${t}/updates/latest`,{method:"GET",headers:{"Content-Type":"application/json","X-Current-Version":e}});if(r.ok){const t=await r.json(),a=t.version||t.latestVersion,i=a&&this.compareVersions(e,a)<0;return{available:i,version:a,url:i?t.url:void 0,notes:t.notes||t.releaseNotes,size:t.size,checksum:t.checksum}}}catch(e){this.logger.error("Failed to check live update via server",e)}return{available:!1}}async sendNotification(e,t){var r;if(!(null===(r=this.config)||void 0===r?void 0:r.notificationPreferences))return!1;const a=this.config.notificationPreferences;let i=a.title||"Update Available",n=a.description||"";if((null==e?void 0:e.updateAvailable)?(i="App Update Available",n=`Version ${e.availableVersion} is ready to install.`):(null==t?void 0:t.available)&&(i="New Update Available",n=`Version ${t.version} is ready to download. ${t.notes||""}`),"undefined"!=typeof window&&"Notification"in window)try{if("granted"===Notification.permission)return new Notification(i,{body:n}),!0}catch(e){this.logger.error("Failed to send notification",e)}return this.logger.info("Background update notification",{title:i,body:n}),!1}async getCurrentAppVersion(){try{const{App:e}=await Promise.resolve().then(function(){return K});return(await e.getInfo()).version}catch(e){return"1.0.0"}}getPlatform(){if("undefined"!=typeof window){const e=window.navigator.userAgent;if(/android/i.test(e))return"android";if(/iPad|iPhone|iPod/.test(e))return"ios"}return"web"}calculateNextCheckTime(){var e;return Date.now()+((null===(e=this.config)||void 0===e?void 0:e.checkInterval)||864e5)}shouldRespectBatteryOptimization(){var e,t;return null===(t=null===(e=this.config)||void 0===e?void 0:e.respectBatteryOptimization)||void 0===t||t}isNetworkConditionMet(){return"undefined"==typeof navigator||!("onLine"in navigator)||navigator.onLine}isBatteryLevelSufficient(){return!0}compareVersions(e,t){const r=e.split(".").map(Number),a=t.split(".").map(Number);for(let e=0;e<Math.max(r.length,a.length);e++){const t=r[e]||0,i=a[e]||0;if(t>i)return 1;if(t<i)return-1}return 0}}class F{constructor(){this.listeners=new Map}static getInstance(){return F.instance||(F.instance=new F),F.instance}addListener(e,t){return this.listeners.has(e)||this.listeners.set(e,new Set),this.listeners.get(e).add(t),()=>{const r=this.listeners.get(e);r&&(r.delete(t),0===r.size&&this.listeners.delete(e))}}emit(e,t){const r=this.listeners.get(e);r&&r.forEach(r=>{try{r(t)}catch(t){console.error(`Error in event listener for ${e}:`,t)}})}removeListeners(e){this.listeners.delete(e)}removeAllListeners(){this.listeners.clear()}listenerCount(e){var t;return(null===(t=this.listeners.get(e))||void 0===t?void 0:t.size)||0}eventNames(){return Array.from(this.listeners.keys())}}class P{constructor(){this.bundleManager=null,this.downloadManager=null,this.versionManager=null,this.appUpdateManager=null,this.backgroundScheduler=null,this.initialized=!1,this.configManager=m.getInstance(),this.logger=w.getInstance(),this.securityValidator=D.getInstance(),this.eventEmitter=F.getInstance()}static getInstance(){return P.instance||(P.instance=new P),P.instance}async initialize(e){var t,i;if(this.initialized)this.logger.warn("Plugin already initialized");else try{this.configManager.configure(e),e.filesystem||(e.filesystem=r.Filesystem),e.preferences||(e.preferences=a.Preferences),this.bundleManager=new b,await this.bundleManager.initialize(),this.downloadManager=new N,await this.downloadManager.initialize(),this.versionManager=new S,await this.versionManager.initialize(),this.appUpdateManager=new B({serverUrl:e.serverUrl||e.baseUrl||"",channel:e.channel||"production",autoCheck:null===(t=e.autoCheck)||void 0===t||t,autoUpdate:null!==(i=e.autoUpdate)&&void 0!==i&&i,updateStrategy:e.updateStrategy,publicKey:e.publicKey,requireSignature:e.requireSignature,checksumAlgorithm:e.checksumAlgorithm,checkInterval:e.checkInterval,security:e.security}),this.setupAppUpdateEventBridge(),this.backgroundScheduler=new k,this.backgroundScheduler.setDependencies({appUpdateManager:this.appUpdateManager,versionManager:this.versionManager,bundleManager:this.bundleManager}),this.initialized=!0,this.logger.info("Plugin initialized successfully")}catch(e){throw this.logger.error("Failed to initialize plugin",e),e}}isInitialized(){return this.initialized&&this.configManager.isConfigured()}ensureInitialized(){if(!this.isInitialized())throw new y(e.ErrorCode.NOT_CONFIGURED,"Plugin not initialized. Please call initialize() first.")}getBundleManager(){return this.ensureInitialized(),this.bundleManager}getDownloadManager(){return this.ensureInitialized(),this.downloadManager}getVersionManager(){return this.ensureInitialized(),this.versionManager}getConfigManager(){return this.configManager}getLogger(){return this.logger}getSecurityValidator(){return this.securityValidator}getAppUpdateManager(){return this.ensureInitialized(),this.appUpdateManager}getEventEmitter(){return this.eventEmitter}getBackgroundScheduler(){return this.ensureInitialized(),this.backgroundScheduler}async reset(){this.logger.info("Resetting plugin state"),this.bundleManager&&await this.bundleManager.clearAllBundles(),this.versionManager&&await this.versionManager.clearVersionCache(),this.downloadManager&&this.downloadManager.cancelAllDownloads(),this.bundleManager=null,this.downloadManager=null,this.versionManager=null,this.appUpdateManager=null,this.backgroundScheduler=null,this.initialized=!1,this.eventEmitter.removeAllListeners(),this.logger.info("Plugin reset complete")}async cleanup(){this.logger.info("Cleaning up plugin resources"),this.downloadManager&&this.downloadManager.cancelAllDownloads(),this.bundleManager&&await this.bundleManager.cleanExpiredBundles(),this.logger.info("Cleanup complete")}setupAppUpdateEventBridge(){this.appUpdateManager&&(this.appUpdateManager.addListener("appUpdateStateChanged",e=>{this.eventEmitter.emit("appUpdateStateChanged",e)}),this.appUpdateManager.addListener("appUpdateProgress",e=>{this.eventEmitter.emit("appUpdateProgress",e)}))}}const z={algorithm:"AES-GCM",keyLength:256,ivLength:12,tagLength:128};class x{static async calculateChecksum(e){const t=new TextEncoder,r="string"==typeof e?t.encode(e):e,a=await crypto.subtle.digest("SHA-256",r);return Array.from(new Uint8Array(a)).map(e=>e.toString(16).padStart(2,"0")).join("")}static async verifySignature(e,t,r){try{const a=this.base64ToArrayBuffer(t),i=this.base64ToArrayBuffer(r),n=await crypto.subtle.importKey("spki",i,{name:"RSA-PSS",hash:"SHA-256"},!1,["verify"]),s=new TextEncoder,o="string"==typeof e?s.encode(e):e;return await crypto.subtle.verify({name:"RSA-PSS",saltLength:32},n,a,o)}catch(e){return console.error("Signature verification failed:",e),!1}}static base64ToArrayBuffer(e){const t=atob(e),r=new Uint8Array(t.length);for(let e=0;e<t.length;e++)r[e]=t.charCodeAt(e);return r.buffer}static generateNonce(e=16){const t=new Uint8Array(e);return crypto.getRandomValues(t),Array.from(t,e=>e.toString(16).padStart(2,"0")).join("")}static isValidChecksum(e,t="SHA-256"){return e.length===("SHA-256"===t?64:128)&&/^[a-f0-9]+$/i.test(e)}static async deriveKey(e,t,r=256){const a=(new TextEncoder).encode(e),i=await crypto.subtle.importKey("raw",a,"PBKDF2",!1,["deriveKey"]);return crypto.subtle.deriveKey({name:"PBKDF2",salt:t,iterations:1e5,hash:"SHA-256"},i,{name:"AES-GCM",length:r},!1,["encrypt","decrypt"])}static async importKey(e,t=256){const r="string"==typeof e?this.base64ToArrayBuffer(e):e;return crypto.subtle.importKey("raw",r,{name:"AES-GCM",length:t},!1,["encrypt","decrypt"])}static async encrypt(e,t,r={}){const a=Object.assign(Object.assign({},z),r),i=crypto.getRandomValues(new Uint8Array(a.ivLength));let n;n=e instanceof Uint8Array?e:new Uint8Array(e);const s=await crypto.subtle.encrypt({name:"AES-GCM",iv:i,tagLength:a.tagLength},t,n),o=new Uint8Array(i),l=new ArrayBuffer(o.length);return new Uint8Array(l).set(o),{iv:this.arrayBufferToBase64(l),data:this.arrayBufferToBase64(s),algorithm:`AES-${a.keyLength}-GCM`}}static async decrypt(e,t,r={}){const a=Object.assign(Object.assign({},z),r),i=new Uint8Array(this.base64ToArrayBuffer(e.iv)),n=this.base64ToArrayBuffer(e.data);return crypto.subtle.decrypt({name:"AES-GCM",iv:i,tagLength:a.tagLength},t,n)}static async encryptBundle(e,t,r){const a=r?new Uint8Array(r):crypto.getRandomValues(new Uint8Array(16)),i=a.buffer.slice(a.byteOffset,a.byteOffset+a.byteLength),n=await this.deriveKey(t,i);return{encrypted:await this.encrypt(e,n),salt:this.arrayBufferToBase64(i)}}static async decryptBundle(e,t,r){const a=this.base64ToArrayBuffer(r),i=await this.deriveKey(t,a);return this.decrypt(e,i)}static isEncryptedBundle(e){return"object"==typeof e&&null!==e&&"iv"in e&&"data"in e&&"algorithm"in e&&"string"==typeof e.iv&&"string"==typeof e.data&&"string"==typeof e.algorithm}static generateEncryptionKey(e=256){const t=crypto.getRandomValues(new Uint8Array(e/8));return this.arrayBufferToBase64(t.buffer)}static generateSalt(e=16){const t=crypto.getRandomValues(new Uint8Array(e));return this.arrayBufferToBase64(t.buffer)}static arrayBufferToBase64(e){const t=new Uint8Array(e);let r="";for(let e=0;e<t.length;e++)r+=String.fromCharCode(t[e]);return btoa(r)}}class G{constructor(){this.initialized=!1,this.windowEventListeners=new Map,this.pluginManager=P.getInstance()}async initialize(e){await this.pluginManager.initialize(e),this.initialized=!0,this.setupWindowEventBridge()}isInitialized(){return this.initialized&&this.pluginManager.isInitialized()}async reset(){await this.pluginManager.reset()}async cleanup(){await this.pluginManager.cleanup()}async configure(e){var t;let r;r="config"in e&&"object"==typeof e.config?e.config:{baseUrl:null===(t=e.liveUpdate)||void 0===t?void 0:t.serverUrl},this.initialized?this.pluginManager.getConfigManager().configure(r):await this.initialize(r)}async getSecurityInfo(){return{enforceHttps:!0,certificatePinning:{enabled:!1,pins:[]},validateInputs:!0,secureStorage:!0}}async sync(e){const t=this.pluginManager.getBundleManager(),r=this.pluginManager.getConfigManager(),a=this.pluginManager.getDownloadManager(),i=this.pluginManager.getEventEmitter();try{const n=await t.getActiveBundle(),s=(null==n?void 0:n.version)||"1.0.0",o=r.get("baseUrl");if(!o)return{status:d.UP_TO_DATE,version:s};const l=(null==e?void 0:e.channel)||r.get("channel")||"production";let c=null;try{const e=await fetch(`${o}/updates/latest`,{method:"GET",headers:{"Content-Type":"application/json","X-Current-Version":s,"X-Channel":l}});if(e.ok){const t=await e.json(),r=t.version||t.latestVersion;r&&this.compareVersions(s,r)<0&&(c={version:r,url:t.url||t.downloadUrl,mandatory:t.mandatory,notes:t.notes||t.releaseNotes,checksum:t.checksum,signature:t.signature})}}catch(e){return{status:d.UP_TO_DATE,version:s}}if(!c)return{status:d.UP_TO_DATE,version:s};if("immediate"===(null==e?void 0:e.updateMode)||void 0===(null==e?void 0:e.updateMode)){i.emit("updateStateChanged",{status:u.DOWNLOADING,bundleId:c.version,version:c.version});const e=e=>{i.emit("downloadProgress",e)},r=await a.downloadWithRetry(c.url,c.version,e);let n=await r.arrayBuffer();n=await this.decryptBundleIfNeeded(n),await this.validateBundleData(n,c.checksum,c.signature);const s=new Blob([n],{type:r.type}),o=await a.saveBlob(c.version,s),l={bundleId:c.version,version:c.version,path:o,downloadTime:Date.now(),size:s.size,status:u.READY,checksum:c.checksum||"",verified:!0};return await t.saveBundleInfo(l),await t.setActiveBundle(c.version),i.emit("updateStateChanged",{status:u.ACTIVE,bundleId:c.version,version:c.version}),{status:d.UPDATE_INSTALLED,version:c.version,description:c.notes,mandatory:c.mandatory}}return{status:d.UPDATE_AVAILABLE,version:c.version,description:c.notes,mandatory:c.mandatory}}catch(e){return{status:d.ERROR,error:{code:g.UNKNOWN_ERROR,message:e instanceof Error?e.message:"Sync failed"}}}}async download(e){const t=this.pluginManager.getDownloadManager(),r=this.pluginManager.getBundleManager(),a=await t.downloadWithRetry(e.url,e.version),i=await t.saveBlob(e.version,a),n={bundleId:e.version,version:e.version,path:i,downloadTime:Date.now(),size:a.size,status:u.READY,checksum:e.checksum,signature:e.signature,verified:!1};return await r.saveBundleInfo(n),n}async set(e){const t=this.pluginManager.getBundleManager();await t.setActiveBundle(e.bundleId)}async reload(){"undefined"!=typeof window&&window.location.reload()}async current(){const t=this.pluginManager.getBundleManager(),r=await t.getActiveBundle();if(!r)throw new y(e.ErrorCode.FILE_NOT_FOUND,"No active bundle found");return r}async list(){return this.pluginManager.getBundleManager().getAllBundles()}async delete(e){const t=this.pluginManager.getBundleManager();if(e.bundleId)await t.deleteBundle(e.bundleId);else if(void 0!==e.keepVersions){const r=(await t.getAllBundles()).sort((e,t)=>t.downloadTime-e.downloadTime);for(let a=e.keepVersions;a<r.length;a++)await t.deleteBundle(r[a].bundleId)}}async notifyAppReady(){const e=this.pluginManager.getBundleManager(),t=await e.getActiveBundle();t&&(t.status=u.ACTIVE,await e.saveBundleInfo(t))}async getLatest(){return{available:!1}}async setChannel(e){const t=this.pluginManager.getConfigManager().get("preferences");t&&await t.set({key:"update_channel",value:e})}async setUpdateUrl(e){this.pluginManager.getConfigManager().configure({baseUrl:e})}async validateUpdate(e){const t=this.pluginManager.getSecurityValidator();try{const r=await t.validateChecksum(new ArrayBuffer(0),e.checksum);return{isValid:r,details:{checksumValid:r,signatureValid:!0,sizeValid:!0,versionValid:!0}}}catch(e){return{isValid:!1,error:e instanceof Error?e.message:"Validation failed"}}}async checkForUpdate(){const t=this.pluginManager.getBundleManager(),r=this.pluginManager.getConfigManager();try{const e=await t.getActiveBundle(),a=(null==e?void 0:e.version)||"1.0.0",i=r.get("baseUrl");if(!i)return{available:!1,currentVersion:a};try{const e=await fetch(`${i}/updates/latest`,{method:"GET",headers:{"Content-Type":"application/json","X-Current-Version":a}});if(!e.ok)return{available:!1,currentVersion:a};const t=await e.json(),r=t.version||t.latestVersion,n=this.compareVersions(a,r)<0;return{available:n,currentVersion:a,latestVersion:n?r:void 0,url:n?t.url:void 0,mandatory:t.mandatory,notes:t.notes||t.releaseNotes,size:t.size,checksum:t.checksum,signature:t.signature}}catch(e){return{available:!1,currentVersion:a}}}catch(t){throw new y(e.ErrorCode.NETWORK_ERROR,t instanceof Error?t.message:"Failed to check for updates")}}async downloadUpdate(t){const r=this.pluginManager.getDownloadManager(),a=this.pluginManager.getBundleManager(),i=this.pluginManager.getEventEmitter();let n;if(!((null==t?void 0:t.url)&&(null==t?void 0:t.version)||(n=await this.checkForUpdate(),n.available&&n.url)))throw new y(e.ErrorCode.UPDATE_NOT_AVAILABLE,"No update available to download");const s=(null==t?void 0:t.url)||(null==n?void 0:n.url)||"",o=(null==t?void 0:t.version)||(null==n?void 0:n.latestVersion)||"",l=(null==t?void 0:t.checksum)||(null==n?void 0:n.checksum)||"",c=(null==t?void 0:t.signature)||(null==n?void 0:n.signature)||"";if(!s||!o)throw new y(e.ErrorCode.INVALID_CONFIG,"URL and version are required for download");const d=await r.downloadWithRetry(s,o,e=>{i.emit("downloadProgress",e),(null==t?void 0:t.onProgress)&&t.onProgress(e)});let h=await d.arrayBuffer();h=await this.decryptBundleIfNeeded(h),await this.validateBundleData(h,l,c||void 0);const g=new Blob([h],{type:d.type}),p={bundleId:o,version:o,path:await r.saveBlob(o,g),downloadTime:Date.now(),size:g.size,status:u.READY,checksum:l,verified:!0};return await a.saveBundleInfo(p),p}async applyUpdate(t){const r=this.pluginManager.getBundleManager();let a=t;if(!a){const t=(await r.getAllBundles()).filter(e=>e.status===u.READY).sort((e,t)=>t.downloadTime-e.downloadTime);if(0===t.length)throw new y(e.ErrorCode.FILE_NOT_FOUND,"No ready bundle found to apply");a=t[0].bundleId}const i=await r.getBundle(a);if(!i)throw new y(e.ErrorCode.FILE_NOT_FOUND,`Bundle ${a} not found`);await this.set(i),await this.reload()}async cancelDownload(e){this.pluginManager.getDownloadManager().cancelDownload(e)}async cancelAllDownloads(){this.pluginManager.getDownloadManager().cancelAllDownloads()}async isDownloading(e){return this.pluginManager.getDownloadManager().isDownloading(e)}async getActiveDownloadCount(){return this.pluginManager.getDownloadManager().getActiveDownloadCount()}compareVersions(e,t){const r=e.split(".").map(Number),a=t.split(".").map(Number);for(let e=0;e<Math.max(r.length,a.length);e++){const t=r[e]||0,i=a[e]||0;if(t<i)return-1;if(t>i)return 1}return 0}async decryptBundleIfNeeded(t){const r=this.pluginManager.getConfigManager(),a=r.get("enableEncryption"),i=r.get("encryptionKey"),n=r.get("encryptionSalt");if(!a)return t;if(!i)throw new y(e.ErrorCode.INVALID_CONFIG,"Encryption is enabled but encryptionKey is not configured");if(!n)throw new y(e.ErrorCode.INVALID_CONFIG,"Encryption is enabled but encryptionSalt is not configured");try{const r=(new TextDecoder).decode(t),a=JSON.parse(r);if(!x.isEncryptedBundle(a))throw new y(e.ErrorCode.VALIDATION_ERROR,"Encryption is enabled but bundle is not encrypted");return await x.decryptBundle(a,i,n)}catch(t){if(t instanceof y)throw t;throw new y(e.ErrorCode.VALIDATION_ERROR,`Failed to decrypt bundle: ${t instanceof Error?t.message:"Unknown error"}`)}}async validateBundleData(t,r,a){const i=this.pluginManager.getSecurityValidator(),n=this.pluginManager.getConfigManager();if(r&&!await i.verifyChecksum(t,r))throw new y(e.ErrorCode.CHECKSUM_MISMATCH,"Bundle checksum verification failed");const s=n.get("requireSignature"),o=n.get("publicKey");if(s){if(!o)throw new y(e.ErrorCode.INVALID_CONFIG,"Signature verification required but publicKey is not configured");if(!a)throw new y(e.ErrorCode.SIGNATURE_INVALID,"Signature verification required but no signature provided");if(!await i.verifySignature(t,a))throw new y(e.ErrorCode.SIGNATURE_INVALID,"Bundle signature verification failed")}return!0}async getAppUpdateInfo(){return this.pluginManager.getAppUpdateManager().getAppUpdateInfo()}async performImmediateUpdate(){return this.pluginManager.getAppUpdateManager().performImmediateUpdate()}async startFlexibleUpdate(){return this.pluginManager.getAppUpdateManager().startFlexibleUpdate()}async completeFlexibleUpdate(){return this.pluginManager.getAppUpdateManager().completeFlexibleUpdate()}async openAppStore(e){return this.pluginManager.getAppUpdateManager().openAppStore(e)}async requestReview(){return{displayed:!1,error:"Reviews are not supported on web"}}async canRequestReview(){return{canRequest:!1,reason:"Reviews are not supported on web"}}async enableBackgroundUpdates(e){this.pluginManager.getBackgroundScheduler().configure(e);const t=this.pluginManager.getConfigManager().get("preferences");t&&await t.set({key:"background_update_config",value:JSON.stringify(e)})}async disableBackgroundUpdates(){this.pluginManager.getBackgroundScheduler().configure({enabled:!1,checkInterval:0,updateTypes:[]});const e=this.pluginManager.getConfigManager().get("preferences");e&&await e.remove({key:"background_update_config"})}async getBackgroundUpdateStatus(){return this.pluginManager.getBackgroundScheduler().getStatus()}async scheduleBackgroundCheck(t){throw new y(e.ErrorCode.PLATFORM_NOT_SUPPORTED,"Background updates are not supported on web")}async triggerBackgroundCheck(){return this.pluginManager.getBackgroundScheduler().performCheck()}async setNotificationPreferences(e){const t=this.pluginManager.getConfigManager().get("preferences");t&&await t.set({key:"notification_preferences",value:JSON.stringify(e)})}async getNotificationPermissions(){return{granted:!1,canRequest:!1}}async requestNotificationPermissions(){return!1}async addListener(e,t){const r=this.pluginManager.getEventEmitter().addListener(e,t);return{remove:async()=>{r()}}}async removeAllListeners(){this.pluginManager.getEventEmitter().removeAllListeners()}setupWindowEventBridge(){const e=this.pluginManager.getEventEmitter();["appUpdateAvailable","appUpdateProgress","appUpdateReady","appUpdateFailed","appUpdateNotificationClicked","appUpdateInstallClicked"].forEach(t=>{const r=r=>{e.emit(t,r.detail)};window.addEventListener(t,r),this.windowEventListeners.set(t,r)})}}const $=t.registerPlugin("NativeUpdate",{web:()=>new G}),H=t.registerPlugin("App",{web:()=>Promise.resolve().then(function(){return W}).then(e=>new e.AppWeb)});var K=Object.freeze({__proto__:null,App:H}),W=Object.freeze({__proto__:null,AppWeb:class extends t.WebPlugin{constructor(){super(),this.handleVisibilityChange=()=>{const e={isActive:!0!==document.hidden};this.notifyListeners("appStateChange",e),document.hidden?this.notifyListeners("pause",null):this.notifyListeners("resume",null)},document.addEventListener("visibilitychange",this.handleVisibilityChange,!1)}exitApp(){throw this.unimplemented("Not implemented on web.")}async getInfo(){throw this.unimplemented("Not implemented on web.")}async getLaunchUrl(){return{url:""}}async getState(){return{isActive:!0!==document.hidden}}async minimizeApp(){throw this.unimplemented("Not implemented on web.")}async toggleBackButtonHandler(){throw this.unimplemented("Not implemented on web.")}}});e.BundleManager=b,e.CacheManager=class{constructor(){this.filesystem=null,this.memoryCache=new Map,this.CACHE_DIR="cache",this.logger=w.getInstance(),this.configManager=m.getInstance()}async initialize(){if(this.filesystem=this.configManager.get("filesystem"),!this.filesystem)throw new Error("Filesystem not configured");try{await this.filesystem.mkdir({path:this.CACHE_DIR,directory:r.Directory.Data,recursive:!0})}catch(e){this.logger.debug("Cache directory may already exist",e)}await this.cleanExpiredCache()}async set(e,t,r){const a=Date.now()+(r||this.configManager.get("cacheExpiration")),i={data:t,timestamp:Date.now(),expiry:a};this.memoryCache.set(e,i),this.shouldPersist(t)&&await this.persistToFile(e,i),this.logger.debug("Cache entry set",{key:e,expiry:new Date(a)})}async get(e){const t=this.memoryCache.get(e);if(t){if(Date.now()<t.expiry)return t.data;this.memoryCache.delete(e)}const r=await this.loadFromFile(e);if(r){if(Date.now()<r.expiry)return this.memoryCache.set(e,r),r.data;await this.removeFile(e)}return null}async has(e){return null!==await this.get(e)}async remove(e){this.memoryCache.delete(e),await this.removeFile(e),this.logger.debug("Cache entry removed",{key:e})}async clear(){this.memoryCache.clear();try{await this.filesystem.rmdir({path:this.CACHE_DIR,directory:r.Directory.Data,recursive:!0}),await this.filesystem.mkdir({path:this.CACHE_DIR,directory:r.Directory.Data,recursive:!0})}catch(e){this.logger.warn("Failed to clear cache directory",e)}this.logger.info("Cache cleared")}async cleanExpiredCache(){const e=Date.now();let t=0;for(const[r,a]of this.memoryCache)e>=a.expiry&&(this.memoryCache.delete(r),t++);try{const a=await this.filesystem.readdir({path:this.CACHE_DIR,directory:r.Directory.Data});for(const r of a.files){const a=r.name.replace(".json",""),i=await this.loadFromFile(a);(!i||e>=i.expiry)&&(await this.removeFile(a),t++)}}catch(e){this.logger.debug("Failed to clean filesystem cache",e)}t>0&&this.logger.info("Cleaned expired cache entries",{count:t})}async getStats(){let e=0,t=0;try{const a=await this.filesystem.readdir({path:this.CACHE_DIR,directory:r.Directory.Data});e=a.files.length;for(const e of a.files)t+=(await this.filesystem.stat({path:`${this.CACHE_DIR}/${e.name}`,directory:r.Directory.Data})).size||0}catch(e){this.logger.debug("Failed to get cache stats",e)}return{memoryEntries:this.memoryCache.size,fileEntries:e,totalSize:t}}async cacheBundleMetadata(e){const t=`bundle_meta_${e.bundleId}`;await this.set(t,e,864e5)}async getCachedBundleMetadata(e){return this.get(`bundle_meta_${e}`)}shouldPersist(e){return"object"==typeof e||"string"==typeof e&&e.length>1024}async persistToFile(e,t){if(this.filesystem)try{const a=`${this.CACHE_DIR}/${e}.json`,i=JSON.stringify(t);await this.filesystem.writeFile({path:a,data:i,directory:r.Directory.Data,encoding:r.Encoding.UTF8})}catch(t){this.logger.warn("Failed to persist cache to file",{key:e,error:t})}}async loadFromFile(e){if(!this.filesystem)return null;try{const t=`${this.CACHE_DIR}/${e}.json`,a=await this.filesystem.readFile({path:t,directory:r.Directory.Data,encoding:r.Encoding.UTF8});return JSON.parse(a.data)}catch(e){return null}}async removeFile(e){if(this.filesystem)try{const t=`${this.CACHE_DIR}/${e}.json`;await this.filesystem.deleteFile({path:t,directory:r.Directory.Data})}catch(t){this.logger.debug("Failed to remove cache file",{key:e,error:t})}}},e.ConfigManager=m,e.ConfigurationError=class extends y{constructor(t,r){super(e.ErrorCode.INVALID_CONFIG,t,r),this.name="ConfigurationError"}},e.CryptoUtils=x,e.DownloadError=E,e.DownloadManager=N,e.Logger=w,e.NativeUpdate=$,e.NativeUpdateError=y,e.PluginManager=P,e.SecurityValidator=D,e.StorageError=v,e.UpdateErrorClass=I,e.UpdateManager=class{constructor(){this.filesystem=null,this.updateInProgress=!1,this.currentState=null,this.pluginManager=P.getInstance(),this.securityValidator=D.getInstance()}async initialize(){if(this.filesystem=this.pluginManager.getConfigManager().get("filesystem"),!this.filesystem)throw new I(e.ErrorCode.MISSING_DEPENDENCY,"Filesystem not configured")}async applyUpdate(t,r){if(this.updateInProgress)throw new I(e.ErrorCode.UPDATE_FAILED,"Another update is already in progress");const a=this.pluginManager.getLogger(),i=this.pluginManager.getBundleManager();try{this.updateInProgress=!0,a.info("Starting bundle update",{bundleId:t});const n=await i.getBundle(t);if(!n)throw new I(e.ErrorCode.FILE_NOT_FOUND,`Bundle ${t} not found`);if("READY"!==n.status&&"ACTIVE"!==n.status)throw new I(e.ErrorCode.BUNDLE_NOT_READY,`Bundle ${t} is not ready for installation`);const s=await i.getActiveBundle();this.currentState={currentBundle:s,newBundle:n,backupPath:null,startTime:Date.now()},await this.validateUpdate(s,n,r),s&&"default"!==s.bundleId&&(this.currentState.backupPath=await this.createBackup(s)),await this.performUpdate(n),await this.verifyUpdate(n),await i.setActiveBundle(t),(null==r?void 0:r.cleanupOldBundles)&&await i.cleanupOldBundles(r.keepBundleCount||3),a.info("Bundle update completed successfully",{bundleId:t,version:n.version,duration:Date.now()-this.currentState.startTime}),this.currentState=null}catch(e){throw a.error("Bundle update failed",e),this.currentState&&await this.rollback(),e}finally{this.updateInProgress=!1}}async validateUpdate(t,r,a){const i=this.pluginManager.getLogger(),n=this.pluginManager.getVersionManager();if(t&&!(null==a?void 0:a.allowDowngrade)&&n.shouldBlockDowngrade(t.version,r.version))throw new A(e.ErrorCode.VERSION_DOWNGRADE,`Cannot downgrade from ${t.version} to ${r.version}`);if(!r.verified){i.warn("Bundle not verified, verifying now",{bundleId:r.bundleId});const t=this.pluginManager.getDownloadManager(),a=await t.loadBlob(r.bundleId);if(!a)throw new I(e.ErrorCode.FILE_NOT_FOUND,"Bundle data not found");const n=await a.arrayBuffer();if(!await this.securityValidator.verifyChecksum(n,r.checksum))throw new A(e.ErrorCode.CHECKSUM_MISMATCH,"Bundle checksum verification failed");if(r.signature&&!await this.securityValidator.verifySignature(n,r.signature))throw new A(e.ErrorCode.SIGNATURE_INVALID,"Bundle signature verification failed");await this.pluginManager.getBundleManager().markBundleAsVerified(r.bundleId)}i.debug("Bundle validation passed",{bundleId:r.bundleId})}async createBackup(t){const a=`backups/${t.bundleId}_${Date.now()}`,i=this.pluginManager.getLogger();try{return await this.filesystem.mkdir({path:a,directory:r.Directory.Data,recursive:!0}),await this.filesystem.copy({from:t.path,to:a,directory:r.Directory.Data}),i.info("Backup created",{bundleId:t.bundleId,backupPath:a}),a}catch(t){throw i.error("Failed to create backup",t),new I(e.ErrorCode.UPDATE_FAILED,"Failed to create backup",void 0,t)}}async performUpdate(t){const a=this.pluginManager.getLogger();try{const e=`active/${t.bundleId}`;await this.filesystem.mkdir({path:e,directory:r.Directory.Data,recursive:!0}),await this.filesystem.copy({from:t.path,to:e,directory:r.Directory.Data}),t.path=e,a.debug("Bundle files installed",{bundleId:t.bundleId,targetPath:e})}catch(t){throw new I(e.ErrorCode.UPDATE_FAILED,"Failed to install bundle files",void 0,t)}}async verifyUpdate(t){try{const e=`${t.path}/index.html`;await this.filesystem.stat({path:e,directory:r.Directory.Data})}catch(t){throw new I(e.ErrorCode.UPDATE_FAILED,"Bundle verification failed after installation",void 0,t)}}async rollback(){var t;if(!this.currentState)throw new I(e.ErrorCode.ROLLBACK_FAILED,"No update state to rollback");const a=this.pluginManager.getLogger();a.warn("Starting rollback",{from:this.currentState.newBundle.bundleId,to:(null===(t=this.currentState.currentBundle)||void 0===t?void 0:t.bundleId)||"default"});try{const e=this.pluginManager.getBundleManager();if(this.currentState.backupPath&&this.currentState.currentBundle){const t=`active/${this.currentState.currentBundle.bundleId}`;await this.filesystem.copy({from:this.currentState.backupPath,to:t,directory:r.Directory.Data}),this.currentState.currentBundle.path=t,await e.saveBundleInfo(this.currentState.currentBundle)}this.currentState.currentBundle?await e.setActiveBundle(this.currentState.currentBundle.bundleId):await e.clearActiveBundle(),a.info("Rollback completed successfully")}catch(t){throw a.error("Rollback failed",t),new I(e.ErrorCode.ROLLBACK_FAILED,"Failed to rollback update",void 0,t)}finally{if(this.currentState.backupPath)try{await this.filesystem.rmdir({path:this.currentState.backupPath,directory:r.Directory.Data,recursive:!0})}catch(e){a.warn("Failed to clean up backup",e)}}}getUpdateProgress(){var e,t;return{inProgress:this.updateInProgress,bundleId:null===(e=this.currentState)||void 0===e?void 0:e.newBundle.bundleId,startTime:null===(t=this.currentState)||void 0===t?void 0:t.startTime}}async cancelUpdate(){this.updateInProgress&&this.currentState&&(this.pluginManager.getLogger().warn("Cancelling update",{bundleId:this.currentState.newBundle.bundleId}),await this.rollback(),this.updateInProgress=!1,this.currentState=null)}},e.ValidationError=A,e.VersionManager=S}({},capacitorExports,capacitorFilesystem,capacitorPreferences);
3
3
  //# sourceMappingURL=plugin.js.map
@@ -763,6 +763,6 @@ Key takeaways for implementing app reviews:
763
763
 
764
764
  ## Next Steps
765
765
 
766
- - Review the [Quick Start Guide](./QUICK_START.md)
767
- - Check the [API Reference](./api/app-review-api.md)
766
+ - Review the [Quick Start Guide](https://nativeupdate.aoneahsan.com/docs/QUICK_START)
767
+ - Check the [API Reference](https://nativeupdate.aoneahsan.com/docs/api/app-review-api)
768
768
  - See example implementation in the `/example` directory
@@ -30,7 +30,7 @@ This creates:
30
30
  - `public-{timestamp}.pem` - Include in your app
31
31
  - Proper file permissions (600) are set automatically
32
32
 
33
- For detailed key management instructions, see the [Key Management Guide](./guides/key-management.md).
33
+ For detailed key management instructions, see the [Key Management Guide](https://nativeupdate.aoneahsan.com/docs/guides/key-management).
34
34
 
35
35
  ### 2. Secure Private Key
36
36
 
@@ -669,7 +669,7 @@ class UpdateHealthCheck {
669
669
 
670
670
  ## Next Steps
671
671
 
672
- - Read the [Native App Updates Guide](./NATIVE_UPDATES_GUIDE.md)
673
- - Learn about [App Review Integration](./APP_REVIEW_GUIDE.md)
674
- - Check out [Security Best Practices](./guides/security-best-practices.md)
675
- - See [Bundle Signing Documentation](./BUNDLE_SIGNING.md)
672
+ - Read the [Native App Updates Guide](https://nativeupdate.aoneahsan.com/docs/NATIVE_UPDATES_GUIDE)
673
+ - Learn about [App Review Integration](https://nativeupdate.aoneahsan.com/docs/APP_REVIEW_GUIDE)
674
+ - Check out [Security Best Practices](https://nativeupdate.aoneahsan.com/docs/guides/security-best-practices)
675
+ - See [Bundle Signing Documentation](https://nativeupdate.aoneahsan.com/docs/BUNDLE_SIGNING)
package/docs/MIGRATION.md CHANGED
@@ -188,5 +188,5 @@ await NativeUpdate.configure(config);
188
188
  ### Getting Help
189
189
 
190
190
  - Check our example app in the `/example` directory for implementation patterns
191
- - Review the [API documentation](./api/live-update-api.md)
191
+ - Review the [API documentation](https://nativeupdate.aoneahsan.com/docs/api/live-update-api)
192
192
  - File issues on GitHub for migration problems
@@ -689,7 +689,7 @@ if (!config.appStoreId) {
689
689
 
690
690
  ## Next Steps
691
691
 
692
- - Learn about [Live Updates (OTA)](./LIVE_UPDATES_GUIDE.md)
693
- - Implement [App Review Features](./APP_REVIEW_GUIDE.md)
694
- - Review [Security Guidelines](./guides/security-best-practices.md)
695
- - Check [API Reference](./api/app-update-api.md)
692
+ - Learn about [Live Updates (OTA)](https://nativeupdate.aoneahsan.com/docs/LIVE_UPDATES_GUIDE)
693
+ - Implement [App Review Features](https://nativeupdate.aoneahsan.com/docs/APP_REVIEW_GUIDE)
694
+ - Review [Security Guidelines](https://nativeupdate.aoneahsan.com/docs/guides/security-best-practices)
695
+ - Check [API Reference](https://nativeupdate.aoneahsan.com/docs/api/app-update-api)
@@ -556,11 +556,11 @@ Now that you have the basics working:
556
556
  - Rollback capabilities
557
557
 
558
558
  3. **Deep Dive**:
559
- - [Live Updates Guide](./LIVE_UPDATES_GUIDE.md) - Complete OTA implementation
560
- - [Native Updates Guide](./NATIVE_UPDATES_GUIDE.md) - Platform-specific details
561
- - [App Review Guide](./APP_REVIEW_GUIDE.md) - Maximize review rates
562
- - [Security Guide](./guides/security-best-practices.md) - Best practices
563
- - [API Reference](./api/live-update-api.md) - All methods and options
559
+ - [Live Updates Guide](https://nativeupdate.aoneahsan.com/docs/LIVE_UPDATES_GUIDE) - Complete OTA implementation
560
+ - [Native Updates Guide](https://nativeupdate.aoneahsan.com/docs/NATIVE_UPDATES_GUIDE) - Platform-specific details
561
+ - [App Review Guide](https://nativeupdate.aoneahsan.com/docs/APP_REVIEW_GUIDE) - Maximize review rates
562
+ - [Security Guide](https://nativeupdate.aoneahsan.com/docs/guides/security-best-practices) - Best practices
563
+ - [API Reference](https://nativeupdate.aoneahsan.com/docs/api/live-update-api) - All methods and options
564
564
 
565
565
  ## Troubleshooting
566
566
 
package/docs/README.md CHANGED
@@ -21,47 +21,47 @@ Created by **Ahsan Mahmood** and open-sourced for the developer community, this
21
21
 
22
22
  ### Getting Started
23
23
 
24
- - [**Installation**](./getting-started/installation.md) - How to install and set up the plugin
25
- - [**Quick Start**](./getting-started/quick-start.md) - Get up and running in minutes
26
- - [**Configuration**](./getting-started/configuration.md) - Detailed configuration options
27
- - [**End-to-End Workflow**](./guides/end-to-end-workflow.md) - Complete setup to production guide
24
+ - [**Installation**](https://nativeupdate.aoneahsan.com/docs/getting-started/installation) - How to install and set up the plugin
25
+ - [**Quick Start**](https://nativeupdate.aoneahsan.com/docs/getting-started/quick-start) - Get up and running in minutes
26
+ - [**Configuration**](https://nativeupdate.aoneahsan.com/docs/getting-started/configuration) - Detailed configuration options
27
+ - [**End-to-End Workflow**](https://nativeupdate.aoneahsan.com/docs/guides/end-to-end-workflow) - Complete setup to production guide
28
28
 
29
29
  ### Dashboard & Management
30
30
 
31
- - [**Dashboard Guide**](./guides/dashboard-guide.md) - Complete dashboard user guide
32
- - [**Channel Management**](./guides/channel-management.md) - Production/staging/development channels
33
- - [**Admin Panel**](./guides/admin-panel.md) - Super-admin documentation
31
+ - [**Dashboard Guide**](https://nativeupdate.aoneahsan.com/docs/guides/dashboard-guide) - Complete dashboard user guide
32
+ - [**Channel Management**](https://nativeupdate.aoneahsan.com/docs/guides/channel-management) - Production/staging/development channels
33
+ - [**Admin Panel**](https://nativeupdate.aoneahsan.com/docs/guides/admin-panel) - Super-admin documentation
34
34
 
35
35
  ### Features
36
36
 
37
- - [**Live Updates**](./features/live-updates.md) - Deploy JavaScript/HTML/CSS updates instantly
38
- - [**App Updates**](./features/app-updates.md) - Native app store update management
39
- - [**App Reviews**](./features/app-reviews.md) - In-app review requests
37
+ - [**Live Updates**](https://nativeupdate.aoneahsan.com/docs/features/live-updates) - Deploy JavaScript/HTML/CSS updates instantly
38
+ - [**App Updates**](https://nativeupdate.aoneahsan.com/docs/features/app-updates) - Native app store update management
39
+ - [**App Reviews**](https://nativeupdate.aoneahsan.com/docs/features/app-reviews) - In-app review requests
40
40
 
41
41
  ### Guides
42
42
 
43
- - [**Security Best Practices**](./guides/security-best-practices.md) - Implement secure updates
44
- - [**Key Management**](./guides/key-management.md) - Generate and manage signing keys
45
- - [**Deployment Guide**](./guides/deployment-guide.md) - Deploy to production
46
- - [**Testing Guide**](./guides/testing-guide.md) - Testing your update implementation
47
- - [**Troubleshooting**](./guides/troubleshooting.md) - Common issues and solutions
48
- - [**Migration from CodePush**](./guides/migration-from-codepush.md) - Migrate from CodePush
43
+ - [**Security Best Practices**](https://nativeupdate.aoneahsan.com/docs/guides/security-best-practices) - Implement secure updates
44
+ - [**Key Management**](https://nativeupdate.aoneahsan.com/docs/guides/key-management) - Generate and manage signing keys
45
+ - [**Deployment Guide**](https://nativeupdate.aoneahsan.com/docs/guides/deployment-guide) - Deploy to production
46
+ - [**Testing Guide**](https://nativeupdate.aoneahsan.com/docs/guides/testing-guide) - Testing your update implementation
47
+ - [**Troubleshooting**](https://nativeupdate.aoneahsan.com/docs/guides/troubleshooting) - Common issues and solutions
48
+ - [**Migration from CodePush**](https://nativeupdate.aoneahsan.com/docs/guides/migration-from-codepush) - Migrate from CodePush
49
49
 
50
50
  ### API Reference
51
51
 
52
- - [**Live Update API**](./api/live-update-api.md) - Complete API for OTA updates
53
- - [**App Update API**](./api/app-update-api.md) - Native app update methods
54
- - [**App Review API**](./api/app-review-api.md) - Review request methods
55
- - [**Events API**](./api/events-api.md) - Event listeners and handlers
52
+ - [**Live Update API**](https://nativeupdate.aoneahsan.com/docs/api/live-update-api) - Complete API for OTA updates
53
+ - [**App Update API**](https://nativeupdate.aoneahsan.com/docs/api/app-update-api) - Native app update methods
54
+ - [**App Review API**](https://nativeupdate.aoneahsan.com/docs/api/app-review-api) - Review request methods
55
+ - [**Events API**](https://nativeupdate.aoneahsan.com/docs/api/events-api) - Event listeners and handlers
56
56
 
57
57
  ### Examples
58
58
 
59
- - [**Basic Usage**](./examples/basic-usage.md) - Simple implementation examples
60
- - [**Advanced Scenarios**](./examples/advanced-scenarios.md) - Complex use cases and framework integrations
59
+ - [**Basic Usage**](https://nativeupdate.aoneahsan.com/docs/examples/basic-usage) - Simple implementation examples
60
+ - [**Advanced Scenarios**](https://nativeupdate.aoneahsan.com/docs/examples/advanced-scenarios) - Complex use cases and framework integrations
61
61
 
62
62
  ### Production
63
63
 
64
- - [**Production Readiness**](./production-readiness.md) - Checklist and best practices for production deployment
64
+ - [**Production Readiness**](https://nativeupdate.aoneahsan.com/docs/production-readiness) - Checklist and best practices for production deployment
65
65
 
66
66
  ## 🚀 Quick Links
67
67
 
@@ -73,7 +73,7 @@ await NativeUpdate.openAppStore({
73
73
 
74
74
  ## Events
75
75
 
76
- App update events are available for monitoring the native app update process. See the [Events API Reference](./events-api.md#app-update-events) for complete documentation of the following events:
76
+ App update events are available for monitoring the native app update process. See the [Events API Reference](https://nativeupdate.aoneahsan.com/docs/api/events-api#app-update-events) for complete documentation of the following events:
77
77
 
78
78
  - `appUpdateStateChanged` - Fired when update state changes
79
79
  - `appUpdateProgress` - Monitor download progress for flexible updates
@@ -104,7 +104,7 @@ npx native-update keys generate --output ./my-keys --type rsa --size 4096
104
104
  - NEVER commit private keys to version control
105
105
  - Store private keys in secure locations with restricted access
106
106
  - Use environment variables or key management services in production
107
- - See [Key Management Guide](./guides/key-management.md) for best practices
107
+ - See [Key Management Guide](https://nativeupdate.aoneahsan.com/docs/guides/key-management) for best practices
108
108
 
109
109
  ### Backend Templates
110
110
 
@@ -389,6 +389,6 @@ class UpdateMetrics {
389
389
 
390
390
  ## Next Steps
391
391
 
392
- - Review [Basic Usage](./basic-usage.md) for framework-specific implementations
393
- - See the [API Reference](../api/live-update-api.md) for detailed method documentation
394
- - Check [Basic Usage](./basic-usage.md) for simpler examples
392
+ - Review [Basic Usage](https://nativeupdate.aoneahsan.com/docs/examples/basic-usage) for framework-specific implementations
393
+ - See the [API Reference](https://nativeupdate.aoneahsan.com/docs/api/live-update-api) for detailed method documentation
394
+ - Check [Basic Usage](https://nativeupdate.aoneahsan.com/docs/examples/basic-usage) for simpler examples
@@ -200,7 +200,7 @@ function cleanup() {
200
200
 
201
201
  ## Next Steps
202
202
 
203
- - See [Advanced Scenarios](./advanced-scenarios.md) for more complex use cases
204
- - Read the [Live Update API Reference](../api/live-update-api.md) for complete live update methods
205
- - Read the [App Update API Reference](../api/app-update-api.md) for native update methods
206
- - Read the [App Review API Reference](../api/app-review-api.md) for review request methods
203
+ - See [Advanced Scenarios](https://nativeupdate.aoneahsan.com/docs/examples/advanced-scenarios) for more complex use cases
204
+ - Read the [Live Update API Reference](https://nativeupdate.aoneahsan.com/docs/api/live-update-api) for complete live update methods
205
+ - Read the [App Update API Reference](https://nativeupdate.aoneahsan.com/docs/api/app-update-api) for native update methods
206
+ - Read the [App Review API Reference](https://nativeupdate.aoneahsan.com/docs/api/app-review-api) for review request methods
@@ -965,10 +965,10 @@ async function monitorReviewSuccess() {
965
965
 
966
966
  ## Next Steps
967
967
 
968
- - Implement [Security Best Practices](../guides/security-best-practices.md)
969
- - Review the [API Reference](../api/app-review-api.md)
970
- - Configure [Live Updates](./live-updates.md)
971
- - Review [API Reference](../api/app-review-api.md)
968
+ - Implement [Security Best Practices](https://nativeupdate.aoneahsan.com/docs/guides/security-best-practices)
969
+ - Review the [API Reference](https://nativeupdate.aoneahsan.com/docs/api/app-review-api)
970
+ - Configure [Live Updates](https://nativeupdate.aoneahsan.com/docs/features/live-updates)
971
+ - Review [API Reference](https://nativeupdate.aoneahsan.com/docs/api/app-review-api)
972
972
 
973
973
  ---
974
974
 
@@ -775,10 +775,10 @@ async function trackUpdateMetrics(event: string, data: any) {
775
775
 
776
776
  ## Next Steps
777
777
 
778
- - Configure [App Reviews](./app-reviews.md) for user feedback
779
- - Implement [Security Best Practices](../guides/security-best-practices.md)
780
- - Review [Testing Guide](../guides/testing-guide.md)
781
- - Review [API Reference](../api/app-update-api.md)
778
+ - Configure [App Reviews](https://nativeupdate.aoneahsan.com/docs/features/app-reviews) for user feedback
779
+ - Implement [Security Best Practices](https://nativeupdate.aoneahsan.com/docs/guides/security-best-practices)
780
+ - Review [Testing Guide](https://nativeupdate.aoneahsan.com/docs/guides/testing-guide)
781
+ - Review [API Reference](https://nativeupdate.aoneahsan.com/docs/api/app-update-api)
782
782
 
783
783
  ---
784
784
 
@@ -633,9 +633,9 @@ async function loadFeature(featureName: string) {
633
633
  ## Next Steps
634
634
 
635
635
  - Set up your update server (see backend-template folder)
636
- - Implement [Security Best Practices](../guides/security-best-practices.md)
637
- - Configure [App Updates](./app-updates.md) for native changes
638
- - Explore [API Reference](../api/live-update-api.md)
636
+ - Implement [Security Best Practices](https://nativeupdate.aoneahsan.com/docs/guides/security-best-practices)
637
+ - Configure [App Updates](https://nativeupdate.aoneahsan.com/docs/features/app-updates) for native changes
638
+ - Explore [API Reference](https://nativeupdate.aoneahsan.com/docs/api/live-update-api)
639
639
 
640
640
  ---
641
641
 
@@ -460,9 +460,9 @@ try {
460
460
 
461
461
  ## Next Steps
462
462
 
463
- - Implement [Security Best Practices](../guides/security-best-practices.md)
463
+ - Implement [Security Best Practices](https://nativeupdate.aoneahsan.com/docs/guides/security-best-practices)
464
464
  - Set up your update server (see backend-template folder)
465
- - Explore [Advanced Features](../features/live-updates.md)
465
+ - Explore [Advanced Features](https://nativeupdate.aoneahsan.com/docs/features/live-updates)
466
466
 
467
467
  ---
468
468
 
@@ -282,16 +282,16 @@ import type {
282
282
 
283
283
  After successful installation:
284
284
 
285
- 1. Read the [Quick Start Guide](./quick-start.md) for basic usage
286
- 2. Configure the plugin with your [update server settings](./configuration.md)
287
- 3. Implement [security best practices](../guides/security-best-practices.md)
285
+ 1. Read the [Quick Start Guide](https://nativeupdate.aoneahsan.com/docs/getting-started/quick-start) for basic usage
286
+ 2. Configure the plugin with your [update server settings](https://nativeupdate.aoneahsan.com/docs/getting-started/configuration)
287
+ 3. Implement [security best practices](https://nativeupdate.aoneahsan.com/docs/guides/security-best-practices)
288
288
  4. Set up your update server (see backend-template folder)
289
289
 
290
290
  ## Support
291
291
 
292
292
  If you encounter any issues during installation:
293
293
 
294
- - Check our [Testing Guide](../guides/testing-guide.md)
294
+ - Check our [Testing Guide](https://nativeupdate.aoneahsan.com/docs/guides/testing-guide)
295
295
  - Visit [nativeupdate.aoneahsan.com/contact](https://nativeupdate.aoneahsan.com/contact) for support
296
296
  - Email aoneahsan@gmail.com with detailed information about your setup
297
297
 
@@ -10,7 +10,7 @@
10
10
  > - **Version Management**: Handle versioning, channels, and rollback mechanisms
11
11
  > - **Analytics & Monitoring**: Track update success rates and handle failures
12
12
  >
13
- > **This is NOT a complete solution** - it's a foundation that requires substantial additional development. See our [Server Requirements](../server-requirements.md) guide for detailed backend implementation requirements.
13
+ > **This is NOT a complete solution** - it's a foundation that requires substantial additional development. See our [Server Requirements](https://nativeupdate.aoneahsan.com/docs/server-requirements) guide for detailed backend implementation requirements.
14
14
 
15
15
  Get up and running with Capacitor Native Update in just a few minutes! This guide covers the most common use cases.
16
16
 
@@ -366,7 +366,7 @@ yarn dev
366
366
 
367
367
  ### Creating and Deploying Updates
368
368
 
369
- 1. **Generate signing keys** (see [Key Management Guide](../guides/key-management.md) for details):
369
+ 1. **Generate signing keys** (see [Key Management Guide](https://nativeupdate.aoneahsan.com/docs/guides/key-management) for details):
370
370
  ```bash
371
371
  npx native-update keys generate --type rsa --size 4096
372
372
  ```
@@ -401,10 +401,10 @@ npx native-update monitor --server http://localhost:3000
401
401
  Now that you have the basics working:
402
402
 
403
403
  1. Deploy your backend to production
404
- 2. Implement [Security Best Practices](../guides/security-best-practices.md)
405
- 3. Configure [Advanced Options](./configuration.md)
406
- 4. Explore [API Reference](../api/live-update-api.md) for all available methods
407
- 5. See [CLI Reference](../cli-reference.md) for all available commands
404
+ 2. Implement [Security Best Practices](https://nativeupdate.aoneahsan.com/docs/guides/security-best-practices)
405
+ 3. Configure [Advanced Options](https://nativeupdate.aoneahsan.com/docs/getting-started/configuration)
406
+ 4. Explore [API Reference](https://nativeupdate.aoneahsan.com/docs/api/live-update-api) for all available methods
407
+ 5. See [CLI Reference](https://nativeupdate.aoneahsan.com/docs/cli-reference) for all available commands
408
408
 
409
409
  ## Quick Reference
410
410
 
@@ -178,6 +178,6 @@ SIGNING_PUBLIC_KEY_PATH=./keys/public.pem
178
178
 
179
179
  ## Related Documentation
180
180
 
181
- - [Deployment Guide](./deployment-guide.md) - Full deployment instructions
182
- - [Security Best Practices](./security-best-practices.md) - Security recommendations
183
- - [Key Management](./key-management.md) - Managing signing keys
181
+ - [Deployment Guide](https://nativeupdate.aoneahsan.com/docs/guides/deployment-guide) - Full deployment instructions
182
+ - [Security Best Practices](https://nativeupdate.aoneahsan.com/docs/guides/security-best-practices) - Security recommendations
183
+ - [Key Management](https://nativeupdate.aoneahsan.com/docs/guides/key-management) - Managing signing keys
@@ -263,6 +263,6 @@ Planned admin features:
263
263
 
264
264
  ## Related Documentation
265
265
 
266
- - [Dashboard Guide](./dashboard-guide.md) - Regular user dashboard
267
- - [Channel Management](./channel-management.md) - Managing update channels
268
- - [Security Best Practices](./security-best-practices.md) - Security guidelines
266
+ - [Dashboard Guide](https://nativeupdate.aoneahsan.com/docs/guides/dashboard-guide) - Regular user dashboard
267
+ - [Channel Management](https://nativeupdate.aoneahsan.com/docs/guides/channel-management) - Managing update channels
268
+ - [Security Best Practices](https://nativeupdate.aoneahsan.com/docs/guides/security-best-practices) - Security guidelines
@@ -337,7 +337,7 @@ Users see release notes before updating. Make them:
337
337
 
338
338
  ## Related Documentation
339
339
 
340
- - [Quick Start Guide](../getting-started/quick-start.md)
341
- - [Configuration Guide](../getting-started/configuration.md)
342
- - [Deployment Guide](./deployment-guide.md)
343
- - [Production Readiness](../production-readiness.md)
340
+ - [Quick Start Guide](https://nativeupdate.aoneahsan.com/docs/getting-started/quick-start)
341
+ - [Configuration Guide](https://nativeupdate.aoneahsan.com/docs/getting-started/configuration)
342
+ - [Deployment Guide](https://nativeupdate.aoneahsan.com/docs/guides/deployment-guide)
343
+ - [Production Readiness](https://nativeupdate.aoneahsan.com/docs/production-readiness)
@@ -354,12 +354,12 @@ Use this URL in your app configuration.
354
354
  ## Support
355
355
 
356
356
  - **Email**: aoneahsan@gmail.com
357
- - **Documentation**: [docs folder](../README.md)
357
+ - **Documentation**: [docs folder](https://nativeupdate.aoneahsan.com/docs)
358
358
  - **Website**: [nativeupdate.aoneahsan.com](https://nativeupdate.aoneahsan.com)
359
359
 
360
360
  ## Related Documentation
361
361
 
362
- - [Channel Management](./channel-management.md)
363
- - [Quick Start Guide](../getting-started/quick-start.md)
364
- - [Configuration Guide](../getting-started/configuration.md)
365
- - [End-to-End Workflow](./end-to-end-workflow.md)
362
+ - [Channel Management](https://nativeupdate.aoneahsan.com/docs/guides/channel-management)
363
+ - [Quick Start Guide](https://nativeupdate.aoneahsan.com/docs/getting-started/quick-start)
364
+ - [Configuration Guide](https://nativeupdate.aoneahsan.com/docs/getting-started/configuration)
365
+ - [End-to-End Workflow](https://nativeupdate.aoneahsan.com/docs/guides/end-to-end-workflow)
@@ -479,10 +479,10 @@ export default App;
479
479
 
480
480
  ## Next Steps
481
481
 
482
- - [Channel Management](./channel-management.md) - Advanced channel configuration
483
- - [Dashboard Guide](./dashboard-guide.md) - Full dashboard documentation
484
- - [Security Best Practices](./security-best-practices.md) - Secure your updates
485
- - [API Reference](../api/API.md) - Complete API documentation
482
+ - [Channel Management](https://nativeupdate.aoneahsan.com/docs/guides/channel-management) - Advanced channel configuration
483
+ - [Dashboard Guide](https://nativeupdate.aoneahsan.com/docs/guides/dashboard-guide) - Full dashboard documentation
484
+ - [Security Best Practices](https://nativeupdate.aoneahsan.com/docs/guides/security-best-practices) - Secure your updates
485
+ - [API Reference](https://nativeupdate.aoneahsan.com/docs/api/API) - Complete API documentation
486
486
 
487
487
  ## Support
488
488
 
@@ -275,9 +275,9 @@ cat intermediate.crt root.crt > chain.pem
275
275
 
276
276
  ## Next Steps
277
277
 
278
- - Review [Security Best Practices](./security-best-practices.md)
279
- - Implement [Bundle Signing](../BUNDLE_SIGNING.md)
280
- - Set up [Deployment Guide](./deployment-guide.md) for production deployment
278
+ - Review [Security Best Practices](https://nativeupdate.aoneahsan.com/docs/guides/security-best-practices)
279
+ - Implement [Bundle Signing](https://nativeupdate.aoneahsan.com/docs/BUNDLE_SIGNING)
280
+ - Set up [Deployment Guide](https://nativeupdate.aoneahsan.com/docs/guides/deployment-guide) for production deployment
281
281
 
282
282
  ---
283
283
 
@@ -140,6 +140,6 @@ npx native-update bundle sign bundle.zip --key private-key.pem
140
140
 
141
141
  ## Need Help?
142
142
 
143
- - See [Testing Guide](../guides/testing-guide.md)
144
- - Check [Server Requirements](../server-requirements.md)
145
- - Review [Security Best Practices](./security-best-practices.md)
143
+ - See [Testing Guide](https://nativeupdate.aoneahsan.com/docs/guides/testing-guide)
144
+ - Check [Server Requirements](https://nativeupdate.aoneahsan.com/docs/server-requirements)
145
+ - Review [Security Best Practices](https://nativeupdate.aoneahsan.com/docs/guides/security-best-practices)
@@ -1047,7 +1047,7 @@ const productionSecurityConfig = {
1047
1047
 
1048
1048
  ## Next Steps
1049
1049
 
1050
- - Review [Production Readiness](../production-readiness.md) checklist
1050
+ - Review [Production Readiness](https://nativeupdate.aoneahsan.com/docs/production-readiness) checklist
1051
1051
  - Implement proper monitoring and analytics
1052
1052
  - Set up incident response procedures
1053
1053
  - Configure update server security (see backend-template folder)
@@ -446,9 +446,9 @@ async function testAPI() {
446
446
  If you can't resolve your issue:
447
447
 
448
448
  1. **Check existing documentation**
449
- - [Dashboard Guide](./dashboard-guide.md)
450
- - [Channel Management](./channel-management.md)
451
- - [API Reference](../api/API.md)
449
+ - [Dashboard Guide](https://nativeupdate.aoneahsan.com/docs/guides/dashboard-guide)
450
+ - [Channel Management](https://nativeupdate.aoneahsan.com/docs/guides/channel-management)
451
+ - [API Reference](https://nativeupdate.aoneahsan.com/docs/api/API)
452
452
 
453
453
  2. **Gather information**
454
454
  - Plugin version
@@ -0,0 +1,21 @@
1
+ # Capacitor + Capawesome + Trapeze Rollout Note (2026-03-01)
2
+
3
+ - Rollout target: nested `website/` app.
4
+ - App identity used from project context:
5
+ - App ID / bundle: `com.aoneahsan.nativeupdate`
6
+ - Host domain: `nativeupdate.aoneahsan.com`
7
+ - Implemented:
8
+ - Added `website/capacitor.config.ts`
9
+ - Added `website/apps-config.yaml`
10
+ - Added native platforms: `website/android/`, `website/ios/`
11
+ - Added scripts: `typecheck`, `cap:*`, `sync:apps-config`, `mobile:sync`
12
+ - Added deps: `@capacitor/android`, `@capacitor/ios`, `@trapezedev/configure`
13
+ - Updated `website/eslint.config.js` ignores for `android/**` and `ios/**`
14
+ - Verification:
15
+ - `cd website && yarn typecheck`
16
+ - `cd website && yarn lint`
17
+ - `cd website && yarn build`
18
+ - `cd website && npx cap add android`
19
+ - `cd website && npx cap add ios`
20
+ - `cd website && yarn mobile:sync`
21
+ - Result: pass.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "native-update",
3
- "version": "1.4.5",
3
+ "version": "1.4.7",
4
4
  "engines": {
5
5
  "node": ">=24.13.0"
6
6
  },