@otakit/capacitor-updater 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +183 -0
  3. package/UpdatekitUpdater.podspec +18 -0
  4. package/android/build.gradle +49 -0
  5. package/android/src/main/AndroidManifest.xml +3 -0
  6. package/android/src/main/java/com/updatekit/updater/BundleInfo.java +100 -0
  7. package/android/src/main/java/com/updatekit/updater/BundleStatus.java +28 -0
  8. package/android/src/main/java/com/updatekit/updater/BundleStore.java +264 -0
  9. package/android/src/main/java/com/updatekit/updater/DateUtils.java +17 -0
  10. package/android/src/main/java/com/updatekit/updater/HashUtils.java +32 -0
  11. package/android/src/main/java/com/updatekit/updater/HostedManifestKeys.java +37 -0
  12. package/android/src/main/java/com/updatekit/updater/ManifestClient.java +209 -0
  13. package/android/src/main/java/com/updatekit/updater/ManifestVerifier.java +146 -0
  14. package/android/src/main/java/com/updatekit/updater/StatsClient.java +80 -0
  15. package/android/src/main/java/com/updatekit/updater/UpdaterPlugin.java +963 -0
  16. package/android/src/main/java/com/updatekit/updater/ZipUtils.java +72 -0
  17. package/dist/esm/definitions.d.ts +229 -0
  18. package/dist/esm/definitions.d.ts.map +1 -0
  19. package/dist/esm/definitions.js +17 -0
  20. package/dist/esm/definitions.js.map +1 -0
  21. package/dist/esm/index.d.ts +5 -0
  22. package/dist/esm/index.d.ts.map +1 -0
  23. package/dist/esm/index.js +85 -0
  24. package/dist/esm/index.js.map +1 -0
  25. package/dist/esm/web.d.ts +25 -0
  26. package/dist/esm/web.d.ts.map +1 -0
  27. package/dist/esm/web.js +56 -0
  28. package/dist/esm/web.js.map +1 -0
  29. package/dist/plugin.cjs.js +165 -0
  30. package/dist/plugin.cjs.js.map +1 -0
  31. package/dist/plugin.js +168 -0
  32. package/dist/plugin.js.map +1 -0
  33. package/ios/Sources/UpdaterPlugin/BundleInfo.swift +39 -0
  34. package/ios/Sources/UpdaterPlugin/BundleStatus.swift +9 -0
  35. package/ios/Sources/UpdaterPlugin/BundleStore.swift +233 -0
  36. package/ios/Sources/UpdaterPlugin/Downloader.swift +120 -0
  37. package/ios/Sources/UpdaterPlugin/HashUtils.swift +33 -0
  38. package/ios/Sources/UpdaterPlugin/HostedManifestKeys.swift +23 -0
  39. package/ios/Sources/UpdaterPlugin/ManifestClient.swift +161 -0
  40. package/ios/Sources/UpdaterPlugin/ManifestVerifier.swift +115 -0
  41. package/ios/Sources/UpdaterPlugin/StatsClient.swift +66 -0
  42. package/ios/Sources/UpdaterPlugin/UpdaterPlugin.m +15 -0
  43. package/ios/Sources/UpdaterPlugin/UpdaterPlugin.swift +913 -0
  44. package/ios/Sources/UpdaterPlugin/ZipUtils.swift +90 -0
  45. package/package.json +85 -0
@@ -0,0 +1,72 @@
1
+ package com.updatekit.updater;
2
+
3
+ import java.io.File;
4
+ import java.io.FileInputStream;
5
+ import java.io.FileOutputStream;
6
+ import java.util.zip.ZipEntry;
7
+ import java.util.zip.ZipInputStream;
8
+
9
+ final class ZipUtils {
10
+
11
+ private static final int MAX_FILES = 10_000;
12
+ private static final long MAX_TOTAL_SIZE = 500_000_000L; // 500MB
13
+
14
+ void extractSecurely(File zipFile, File destination) throws Exception {
15
+ String canonicalDestination = destination.getCanonicalPath();
16
+ String destinationPrefix = canonicalDestination.endsWith(File.separator)
17
+ ? canonicalDestination
18
+ : canonicalDestination + File.separator;
19
+
20
+ int fileCount = 0;
21
+ long totalSize = 0L;
22
+
23
+ try (ZipInputStream zis = new ZipInputStream(new FileInputStream(zipFile))) {
24
+ ZipEntry entry;
25
+ while ((entry = zis.getNextEntry()) != null) {
26
+ String name = entry.getName();
27
+ if (name.contains("..") || name.startsWith("/") || name.startsWith("\\")) {
28
+ throw new SecurityException("Zip path traversal attempt: " + name);
29
+ }
30
+
31
+ File outFile = new File(destination, name);
32
+ String outPath = outFile.getCanonicalPath();
33
+ if (!(outPath.equals(canonicalDestination) || outPath.startsWith(destinationPrefix))) {
34
+ throw new SecurityException("Zip entry escapes destination: " + name);
35
+ }
36
+
37
+ if (entry.isDirectory()) {
38
+ if (!outFile.exists() && !outFile.mkdirs()) {
39
+ throw new IllegalStateException(
40
+ "Cannot create directory: " + outFile.getAbsolutePath()
41
+ );
42
+ }
43
+ continue;
44
+ }
45
+
46
+ fileCount++;
47
+ if (fileCount > MAX_FILES) {
48
+ throw new SecurityException("Zip contains too many files");
49
+ }
50
+
51
+ File parent = outFile.getParentFile();
52
+ if (parent != null && !parent.exists() && !parent.mkdirs()) {
53
+ throw new IllegalStateException("Cannot create parent: " + parent.getAbsolutePath());
54
+ }
55
+
56
+ long entrySize = 0;
57
+ try (FileOutputStream output = new FileOutputStream(outFile)) {
58
+ byte[] buffer = new byte[8192];
59
+ int read;
60
+ while ((read = zis.read(buffer)) > 0) {
61
+ output.write(buffer, 0, read);
62
+ entrySize += read;
63
+ if (totalSize + entrySize > MAX_TOTAL_SIZE) {
64
+ throw new SecurityException("Zip extracted content exceeds max size");
65
+ }
66
+ }
67
+ }
68
+ totalSize += entrySize;
69
+ }
70
+ }
71
+ }
72
+ }
@@ -0,0 +1,229 @@
1
+ import type { PluginListenerHandle } from '@capacitor/core';
2
+ /**
3
+ * Bundle status enum.
4
+ */
5
+ export declare enum BundleStatus {
6
+ /** Factory-installed bundle */
7
+ BUILTIN = "builtin",
8
+ /** Downloaded and staged, awaiting activation */
9
+ PENDING = "pending",
10
+ /** Active but not yet confirmed */
11
+ TRIAL = "trial",
12
+ /** Confirmed working */
13
+ SUCCESS = "success",
14
+ /** Failed (hash mismatch, extraction error, rollback) */
15
+ ERROR = "error"
16
+ }
17
+ export interface BundleInfo {
18
+ /** Unique bundle identifier */
19
+ id: string;
20
+ /** Semantic version string */
21
+ version: string;
22
+ /** Current status of the bundle */
23
+ status: BundleStatus;
24
+ /** ISO timestamp when bundle was downloaded */
25
+ downloadedAt?: string;
26
+ /** SHA-256 hash of the bundle */
27
+ sha256?: string;
28
+ /** Channel this bundle was released to (if known) */
29
+ channel?: string;
30
+ /** Release history ID associated with this bundle (if known) */
31
+ releaseId?: string;
32
+ }
33
+ export interface LatestVersion {
34
+ /** Version string */
35
+ version: string;
36
+ /** Download URL */
37
+ url: string;
38
+ /** SHA-256 checksum */
39
+ sha256: string;
40
+ /** Bundle size in bytes */
41
+ size: number;
42
+ /** True when this exact update is already staged locally. */
43
+ downloaded?: boolean;
44
+ /** Release history ID associated with this manifest */
45
+ releaseId?: string;
46
+ /** Minimum native build required */
47
+ minNativeBuild?: number;
48
+ }
49
+ export interface BundleListResult {
50
+ bundles: BundleInfo[];
51
+ }
52
+ export interface OtaKitState {
53
+ current: BundleInfo;
54
+ staged: BundleInfo | null;
55
+ builtinVersion: string;
56
+ }
57
+ export interface OtaKitDebugState extends OtaKitState {
58
+ fallback: BundleInfo;
59
+ }
60
+ export type OtaKitUpdateMode = 'manual' | 'next-launch' | 'immediate';
61
+ export interface OtaKitManifestKey {
62
+ kid: string;
63
+ key: string;
64
+ }
65
+ /**
66
+ * Plugin configuration for capacitor.config.ts.
67
+ */
68
+ export interface OtaKitConfig {
69
+ /** OtaKit app ID used for manifest and stats requests. */
70
+ appId: string;
71
+ /** Optional named release track. Omit to use the base channel. */
72
+ channel?: string;
73
+ /** Overall update behavior. Defaults to next-launch. */
74
+ updateMode?: OtaKitUpdateMode;
75
+ /** Milliseconds to wait for notifyAppReady(). Defaults to 10000. */
76
+ appReadyTimeout?: number;
77
+ /** Custom API base URL for self-hosted or custom servers. */
78
+ serverUrl?: string;
79
+ /** Custom manifest verification keys for self-hosted or custom trust. */
80
+ manifestKeys?: OtaKitManifestKey[];
81
+ /** Allow HTTP only for localhost development. Defaults to false. */
82
+ allowInsecureUrls?: boolean;
83
+ }
84
+ export interface OtaKitDebugApi {
85
+ /**
86
+ * Check the server for a newer version without downloading it.
87
+ * You can optionally pass { channel } for a one-off debug override.
88
+ */
89
+ check(options?: {
90
+ channel?: string;
91
+ }): Promise<LatestVersion | null>;
92
+ /**
93
+ * Check the server and download the latest bundle if available.
94
+ * Ensures the latest bundle is staged for later activation.
95
+ */
96
+ download(options?: {
97
+ channel?: string;
98
+ }): Promise<BundleInfo | null>;
99
+ /**
100
+ * Reset to the builtin bundle and reload the WebView.
101
+ *
102
+ * **WARNING: TERMINAL OPERATION**
103
+ * Code after this call may not execute. The WebView will reload.
104
+ */
105
+ reset(): Promise<void>;
106
+ /**
107
+ * List downloaded OTA bundles stored on the device.
108
+ */
109
+ listBundles(): Promise<BundleListResult>;
110
+ /**
111
+ * Delete a downloaded bundle that is not active or protected by rollback.
112
+ */
113
+ deleteBundle(options: {
114
+ bundleId: string;
115
+ }): Promise<void>;
116
+ /**
117
+ * Get the most recent failed update information for diagnostics.
118
+ */
119
+ getLastFailure(): Promise<BundleInfo | null>;
120
+ }
121
+ export type OtaKitEvent = 'downloadStarted' | 'downloadComplete' | 'downloadFailed' | 'updateAvailable' | 'noUpdateAvailable' | 'appReady' | 'rollback';
122
+ export interface OtaKitPlugin {
123
+ /**
124
+ * Inspect the current updater state needed by normal app code.
125
+ */
126
+ getState(): Promise<OtaKitState>;
127
+ /**
128
+ * Check the configured channel for a newer version without downloading it.
129
+ * When `downloaded` is true, the latest update is already staged locally.
130
+ */
131
+ check(): Promise<LatestVersion | null>;
132
+ /**
133
+ * Check the configured channel and download the latest bundle if available.
134
+ * The latest bundle is staged for later activation. If it is already staged,
135
+ * the existing staged bundle is returned without re-downloading it.
136
+ */
137
+ download(): Promise<BundleInfo | null>;
138
+ /**
139
+ * Activate the currently staged bundle and reload the WebView.
140
+ *
141
+ * **WARNING: TERMINAL OPERATION**
142
+ * Code after this call may not execute. The WebView will reload.
143
+ */
144
+ apply(): Promise<void>;
145
+ /**
146
+ * Friendly manual-mode helper.
147
+ * Bring the app to the newest available update now.
148
+ * If the newest update is already staged, apply it.
149
+ * Otherwise download it and apply it.
150
+ *
151
+ * **WARNING: TERMINAL OPERATION**
152
+ * Code after this call may not execute if an update is applied.
153
+ */
154
+ update(): Promise<void>;
155
+ /**
156
+ * **CRITICAL**: Call this when your app has successfully started.
157
+ * Must be called within appReadyTimeout (default 10s) or rollback occurs.
158
+ *
159
+ * This confirms the current bundle is working and:
160
+ * - Marks the bundle as SUCCESS
161
+ * - Updates the fallback bundle pointer
162
+ * - Removes the older fallback bundle once the new bundle proves healthy
163
+ */
164
+ notifyAppReady(): Promise<void>;
165
+ /**
166
+ * Manual inspection and control methods intended for debugging and support.
167
+ */
168
+ debug: OtaKitDebugApi;
169
+ /**
170
+ * Add listener for update events
171
+ */
172
+ addListener(event: 'downloadStarted', callback: (data: {
173
+ version: string;
174
+ }) => void): Promise<PluginListenerHandle>;
175
+ addListener(event: 'downloadComplete', callback: (data: BundleInfo) => void): Promise<PluginListenerHandle>;
176
+ addListener(event: 'downloadFailed', callback: (data: {
177
+ version: string;
178
+ error: string;
179
+ }) => void): Promise<PluginListenerHandle>;
180
+ addListener(event: 'updateAvailable', callback: (data: LatestVersion) => void): Promise<PluginListenerHandle>;
181
+ addListener(event: 'noUpdateAvailable', callback: () => void): Promise<PluginListenerHandle>;
182
+ addListener(event: 'appReady', callback: (data: BundleInfo) => void): Promise<PluginListenerHandle>;
183
+ addListener(event: 'rollback', callback: (data: {
184
+ from: BundleInfo;
185
+ to: BundleInfo;
186
+ reason?: string;
187
+ }) => void): Promise<PluginListenerHandle>;
188
+ /**
189
+ * Remove all listeners for this plugin
190
+ */
191
+ removeAllListeners(): Promise<void>;
192
+ }
193
+ export interface OtaKitBridgePlugin {
194
+ check(): Promise<LatestVersion | null>;
195
+ download(): Promise<BundleInfo | null>;
196
+ apply(): Promise<void>;
197
+ notifyAppReady(): Promise<void>;
198
+ debugGetState(): Promise<OtaKitDebugState>;
199
+ debugCheck(options?: {
200
+ channel?: string;
201
+ }): Promise<LatestVersion | null>;
202
+ debugDownload(options?: {
203
+ channel?: string;
204
+ }): Promise<BundleInfo | null>;
205
+ debugReset(): Promise<void>;
206
+ debugListBundles(): Promise<BundleListResult>;
207
+ debugDeleteBundle(options: {
208
+ bundleId: string;
209
+ }): Promise<void>;
210
+ debugGetLastFailure(): Promise<BundleInfo | null>;
211
+ addListener(event: 'downloadStarted', callback: (data: {
212
+ version: string;
213
+ }) => void): Promise<PluginListenerHandle>;
214
+ addListener(event: 'downloadComplete', callback: (data: BundleInfo) => void): Promise<PluginListenerHandle>;
215
+ addListener(event: 'downloadFailed', callback: (data: {
216
+ version: string;
217
+ error: string;
218
+ }) => void): Promise<PluginListenerHandle>;
219
+ addListener(event: 'updateAvailable', callback: (data: LatestVersion) => void): Promise<PluginListenerHandle>;
220
+ addListener(event: 'noUpdateAvailable', callback: () => void): Promise<PluginListenerHandle>;
221
+ addListener(event: 'appReady', callback: (data: BundleInfo) => void): Promise<PluginListenerHandle>;
222
+ addListener(event: 'rollback', callback: (data: {
223
+ from: BundleInfo;
224
+ to: BundleInfo;
225
+ reason?: string;
226
+ }) => void): Promise<PluginListenerHandle>;
227
+ removeAllListeners(): Promise<void>;
228
+ }
229
+ //# sourceMappingURL=definitions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"definitions.d.ts","sourceRoot":"","sources":["../../src/definitions.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Bundle status enum.
3
+ */
4
+ export var BundleStatus;
5
+ (function (BundleStatus) {
6
+ /** Factory-installed bundle */
7
+ BundleStatus["BUILTIN"] = "builtin";
8
+ /** Downloaded and staged, awaiting activation */
9
+ BundleStatus["PENDING"] = "pending";
10
+ /** Active but not yet confirmed */
11
+ BundleStatus["TRIAL"] = "trial";
12
+ /** Confirmed working */
13
+ BundleStatus["SUCCESS"] = "success";
14
+ /** Failed (hash mismatch, extraction error, rollback) */
15
+ BundleStatus["ERROR"] = "error";
16
+ })(BundleStatus || (BundleStatus = {}));
17
+ //# sourceMappingURL=definitions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"definitions.js","sourceRoot":"","sources":["../../src/definitions.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,MAAM,CAAN,IAAY,YAWX;AAXD,WAAY,YAAY;IACtB,+BAA+B;IAC/B,mCAAmB,CAAA;IACnB,iDAAiD;IACjD,mCAAmB,CAAA;IACnB,mCAAmC;IACnC,+BAAe,CAAA;IACf,wBAAwB;IACxB,mCAAmB,CAAA;IACnB,yDAAyD;IACzD,+BAAe,CAAA;AACjB,CAAC,EAXW,YAAY,KAAZ,YAAY,QAWvB"}
@@ -0,0 +1,5 @@
1
+ import type { OtaKitPlugin } from './definitions';
2
+ declare const OtaKit: OtaKitPlugin;
3
+ export * from './definitions';
4
+ export { OtaKit };
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAEV,YAAY,EAKb,MAAM,eAAe,CAAC;AA6EvB,QAAA,MAAM,MAAM,EAAE,YAoBb,CAAC;AAEF,cAAc,eAAe,CAAC;AAC9B,OAAO,EAAE,MAAM,EAAE,CAAC"}
@@ -0,0 +1,85 @@
1
+ import { registerPlugin } from '@capacitor/core';
2
+ const NativeOtaKit = registerPlugin('OtaKit', {
3
+ web: () => import('./web').then((m) => new m.OtaKitWeb()),
4
+ });
5
+ /**
6
+ * Check if result is an empty object (iOS returns {} instead of null)
7
+ */
8
+ function isEmptyObject(obj) {
9
+ return obj !== null && typeof obj === 'object' && Object.keys(obj).length === 0;
10
+ }
11
+ /**
12
+ * Wrapped plugin that normalizes null returns from native code.
13
+ * iOS call.resolve() without arguments returns {} instead of null.
14
+ */
15
+ function normalizeNullable(value) {
16
+ return isEmptyObject(value) ? null : value;
17
+ }
18
+ function toPublicState(value) {
19
+ return {
20
+ current: value.current,
21
+ staged: value.staged,
22
+ builtinVersion: value.builtinVersion,
23
+ };
24
+ }
25
+ async function getState() {
26
+ return toPublicState(await NativeOtaKit.debugGetState());
27
+ }
28
+ async function check() {
29
+ return normalizeNullable(await NativeOtaKit.check());
30
+ }
31
+ async function download() {
32
+ return normalizeNullable(await NativeOtaKit.download());
33
+ }
34
+ function apply() {
35
+ return NativeOtaKit.apply();
36
+ }
37
+ async function update() {
38
+ const state = await getState();
39
+ let latest;
40
+ try {
41
+ latest = await check();
42
+ }
43
+ catch (error) {
44
+ if (state.staged) {
45
+ await apply();
46
+ return;
47
+ }
48
+ throw error;
49
+ }
50
+ if (latest) {
51
+ if (latest.downloaded) {
52
+ await apply();
53
+ return;
54
+ }
55
+ const bundle = await download();
56
+ if (bundle) {
57
+ await apply();
58
+ }
59
+ return;
60
+ }
61
+ if (state.staged) {
62
+ await apply();
63
+ }
64
+ }
65
+ const OtaKit = {
66
+ getState,
67
+ check,
68
+ download,
69
+ apply,
70
+ update,
71
+ notifyAppReady: () => NativeOtaKit.notifyAppReady(),
72
+ debug: {
73
+ check: async (options) => normalizeNullable(await NativeOtaKit.debugCheck(options)),
74
+ download: async (options) => normalizeNullable(await NativeOtaKit.debugDownload(options)),
75
+ reset: () => NativeOtaKit.debugReset(),
76
+ listBundles: () => NativeOtaKit.debugListBundles(),
77
+ deleteBundle: (options) => NativeOtaKit.debugDeleteBundle(options),
78
+ getLastFailure: async () => normalizeNullable(await NativeOtaKit.debugGetLastFailure()),
79
+ },
80
+ addListener: NativeOtaKit.addListener.bind(NativeOtaKit),
81
+ removeAllListeners: () => NativeOtaKit.removeAllListeners(),
82
+ };
83
+ export * from './definitions';
84
+ export { OtaKit };
85
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ import { WebPlugin } from '@capacitor/core';
2
+ import type { OtaKitBridgePlugin, BundleInfo, BundleListResult, LatestVersion, OtaKitDebugState } from './definitions';
3
+ /**
4
+ * Web implementation of the native bridge.
5
+ * Most methods are no-ops since OTA updates don't apply to web
6
+ */
7
+ export declare class OtaKitWeb extends WebPlugin implements OtaKitBridgePlugin {
8
+ private readonly BUILTIN_BUNDLE;
9
+ debugGetState(): Promise<OtaKitDebugState>;
10
+ check(): Promise<LatestVersion | null>;
11
+ download(): Promise<BundleInfo | null>;
12
+ apply(): Promise<void>;
13
+ debugCheck(): Promise<LatestVersion | null>;
14
+ debugDownload(_options?: {
15
+ channel?: string;
16
+ }): Promise<BundleInfo | null>;
17
+ notifyAppReady(): Promise<void>;
18
+ debugReset(): Promise<void>;
19
+ debugListBundles(): Promise<BundleListResult>;
20
+ debugDeleteBundle(_options: {
21
+ bundleId: string;
22
+ }): Promise<void>;
23
+ debugGetLastFailure(): Promise<BundleInfo | null>;
24
+ }
25
+ //# sourceMappingURL=web.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"web.d.ts","sourceRoot":"","sources":["../../src/web.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAE5C,OAAO,KAAK,EACV,kBAAkB,EAClB,UAAU,EACV,gBAAgB,EAChB,aAAa,EAEb,gBAAgB,EACjB,MAAM,eAAe,CAAC;AAEvB;;;GAGG;AACH,qBAAa,SAAU,SAAQ,SAAU,YAAW,kBAAkB;IACpE,OAAO,CAAC,QAAQ,CAAC,cAAc,CAI7B;IAEI,aAAa,IAAI,OAAO,CAAC,gBAAgB,CAAC;IAS1C,KAAK,IAAI,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC;IAKtC,QAAQ,IAAI,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC;IAKtC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAKtB,UAAU,IAAI,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC;IAK3C,aAAa,CAAC,QAAQ,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC;IAK1E,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC;IAI/B,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAI3B,gBAAgB,IAAI,OAAO,CAAC,gBAAgB,CAAC;IAI7C,iBAAiB,CAAC,QAAQ,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAIhE,mBAAmB,IAAI,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC;CAGxD"}
@@ -0,0 +1,56 @@
1
+ import { WebPlugin } from '@capacitor/core';
2
+ /**
3
+ * Web implementation of the native bridge.
4
+ * Most methods are no-ops since OTA updates don't apply to web
5
+ */
6
+ export class OtaKitWeb extends WebPlugin {
7
+ BUILTIN_BUNDLE = {
8
+ id: 'builtin',
9
+ version: '0.0.0',
10
+ status: 'builtin',
11
+ };
12
+ async debugGetState() {
13
+ return {
14
+ current: this.BUILTIN_BUNDLE,
15
+ fallback: this.BUILTIN_BUNDLE,
16
+ staged: null,
17
+ builtinVersion: this.BUILTIN_BUNDLE.version,
18
+ };
19
+ }
20
+ async check() {
21
+ console.warn('OtaKit.check() is not supported on web');
22
+ return null;
23
+ }
24
+ async download() {
25
+ console.warn('OtaKit.download() is not supported on web');
26
+ return null;
27
+ }
28
+ async apply() {
29
+ console.warn('OtaKit.apply() is not supported on web');
30
+ throw new Error('OtaKit.apply() is not supported on web');
31
+ }
32
+ async debugCheck() {
33
+ console.warn('OtaKit.debug.check() is not supported on web');
34
+ return null;
35
+ }
36
+ async debugDownload(_options) {
37
+ console.warn('OtaKit.debug.download() is not supported on web');
38
+ return null;
39
+ }
40
+ async notifyAppReady() {
41
+ // No-op on web, but don't warn - apps should call this unconditionally
42
+ }
43
+ async debugReset() {
44
+ console.warn('OtaKit.debug.reset() is not supported on web');
45
+ }
46
+ async debugListBundles() {
47
+ return { bundles: [] };
48
+ }
49
+ async debugDeleteBundle(_options) {
50
+ console.warn('OtaKit.debug.deleteBundle() is not supported on web');
51
+ }
52
+ async debugGetLastFailure() {
53
+ return null;
54
+ }
55
+ }
56
+ //# sourceMappingURL=web.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"web.js","sourceRoot":"","sources":["../../src/web.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAW5C;;;GAGG;AACH,MAAM,OAAO,SAAU,SAAQ,SAAS;IACrB,cAAc,GAAe;QAC5C,EAAE,EAAE,SAAS;QACb,OAAO,EAAE,OAAO;QAChB,MAAM,EAAE,SAAyB;KAClC,CAAC;IAEF,KAAK,CAAC,aAAa;QACjB,OAAO;YACL,OAAO,EAAE,IAAI,CAAC,cAAc;YAC5B,QAAQ,EAAE,IAAI,CAAC,cAAc;YAC7B,MAAM,EAAE,IAAI;YACZ,cAAc,EAAE,IAAI,CAAC,cAAc,CAAC,OAAO;SAC5C,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,KAAK;QACT,OAAO,CAAC,IAAI,CAAC,wCAAwC,CAAC,CAAC;QACvD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,KAAK,CAAC,QAAQ;QACZ,OAAO,CAAC,IAAI,CAAC,2CAA2C,CAAC,CAAC;QAC1D,OAAO,IAAI,CAAC;IACd,CAAC;IAED,KAAK,CAAC,KAAK;QACT,OAAO,CAAC,IAAI,CAAC,wCAAwC,CAAC,CAAC;QACvD,MAAM,IAAI,KAAK,CAAC,wCAAwC,CAAC,CAAC;IAC5D,CAAC;IAED,KAAK,CAAC,UAAU;QACd,OAAO,CAAC,IAAI,CAAC,8CAA8C,CAAC,CAAC;QAC7D,OAAO,IAAI,CAAC;IACd,CAAC;IAED,KAAK,CAAC,aAAa,CAAC,QAA+B;QACjD,OAAO,CAAC,IAAI,CAAC,iDAAiD,CAAC,CAAC;QAChE,OAAO,IAAI,CAAC;IACd,CAAC;IAED,KAAK,CAAC,cAAc;QAClB,uEAAuE;IACzE,CAAC;IAED,KAAK,CAAC,UAAU;QACd,OAAO,CAAC,IAAI,CAAC,8CAA8C,CAAC,CAAC;IAC/D,CAAC;IAED,KAAK,CAAC,gBAAgB;QACpB,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;IACzB,CAAC;IAED,KAAK,CAAC,iBAAiB,CAAC,QAA8B;QACpD,OAAO,CAAC,IAAI,CAAC,qDAAqD,CAAC,CAAC;IACtE,CAAC;IAED,KAAK,CAAC,mBAAmB;QACvB,OAAO,IAAI,CAAC;IACd,CAAC;CACF"}