capacitor-ota 1.0.0 → 1.0.2
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.
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { };
|
package/dist/cli/ota.mjs
ADDED
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
#!/usr/bin/env npx tsx
|
|
2
|
+
import { existsSync, mkdtempSync, readFileSync, rmSync, statSync, writeFileSync } from "fs";
|
|
3
|
+
import { basename, join, resolve } from "path";
|
|
4
|
+
import { homedir, tmpdir } from "os";
|
|
5
|
+
import { execSync } from "child_process";
|
|
6
|
+
|
|
7
|
+
//#region cli/ota.ts
|
|
8
|
+
/**
|
|
9
|
+
* OTA Service CLI
|
|
10
|
+
*
|
|
11
|
+
* Usage:
|
|
12
|
+
* npx tsx cli/ota.ts <command> [options]
|
|
13
|
+
*
|
|
14
|
+
* Commands:
|
|
15
|
+
* login Login and save token
|
|
16
|
+
* apps List all apps
|
|
17
|
+
* versions <app_id> List versions for an app
|
|
18
|
+
* upload <app_id> <path> Upload a new version (directory or zip)
|
|
19
|
+
* delete <version_id> Delete a version
|
|
20
|
+
* rollback <version_id> Rollback to a version
|
|
21
|
+
*/
|
|
22
|
+
const CONFIG_PATH = resolve(homedir(), ".ota-cli.json");
|
|
23
|
+
const DEFAULT_URL = "https://ota-service.srvrun.workers.dev";
|
|
24
|
+
function loadConfig() {
|
|
25
|
+
if (existsSync(CONFIG_PATH)) return JSON.parse(readFileSync(CONFIG_PATH, "utf-8"));
|
|
26
|
+
return { url: DEFAULT_URL };
|
|
27
|
+
}
|
|
28
|
+
function saveConfig(config) {
|
|
29
|
+
writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2));
|
|
30
|
+
}
|
|
31
|
+
async function api(method, path, body, formData) {
|
|
32
|
+
const config = loadConfig();
|
|
33
|
+
const headers = {};
|
|
34
|
+
if (config.token) headers["Authorization"] = `Bearer ${config.token}`;
|
|
35
|
+
if (body && !formData) headers["Content-Type"] = "application/json";
|
|
36
|
+
const response = await fetch(`${config.url}${path}`, {
|
|
37
|
+
method,
|
|
38
|
+
headers,
|
|
39
|
+
body: formData || (body ? JSON.stringify(body) : void 0)
|
|
40
|
+
});
|
|
41
|
+
if (!response.ok) {
|
|
42
|
+
const error = await response.json().catch(() => ({ message: response.statusText }));
|
|
43
|
+
throw new Error(error.message || `HTTP ${response.status}`);
|
|
44
|
+
}
|
|
45
|
+
return response.json();
|
|
46
|
+
}
|
|
47
|
+
async function login(username, password) {
|
|
48
|
+
const config = loadConfig();
|
|
49
|
+
config.token = (await api("POST", "/api/auth/login", {
|
|
50
|
+
username,
|
|
51
|
+
password
|
|
52
|
+
})).token;
|
|
53
|
+
saveConfig(config);
|
|
54
|
+
console.log("✅ Login successful! Token saved.");
|
|
55
|
+
}
|
|
56
|
+
async function listApps() {
|
|
57
|
+
const apps = await api("GET", "/api/apps");
|
|
58
|
+
if (apps.length === 0) {
|
|
59
|
+
console.log("No apps found.");
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
console.log("\n📱 Apps:\n");
|
|
63
|
+
console.log("ID Name Created");
|
|
64
|
+
console.log("─".repeat(50));
|
|
65
|
+
for (const app of apps) {
|
|
66
|
+
const date = new Date(app.created_at).toLocaleDateString();
|
|
67
|
+
console.log(`${app.id.padEnd(14)} ${app.name.padEnd(14)} ${date}`);
|
|
68
|
+
}
|
|
69
|
+
console.log();
|
|
70
|
+
}
|
|
71
|
+
async function listVersions(appId) {
|
|
72
|
+
const versions = await api("GET", `/api/versions?app_id=${appId}`);
|
|
73
|
+
if (versions.length === 0) {
|
|
74
|
+
console.log("No versions found.");
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
console.log("\n📦 Versions:\n");
|
|
78
|
+
console.log("ID Version Channel Active Downloads Created");
|
|
79
|
+
console.log("─".repeat(65));
|
|
80
|
+
for (const v of versions) {
|
|
81
|
+
const date = new Date(v.created_at).toLocaleDateString();
|
|
82
|
+
const active = v.is_active ? "✅" : " ";
|
|
83
|
+
console.log(`${String(v.id).padEnd(6)}${v.version.padEnd(11)}${v.channel.padEnd(13)}${active.padEnd(8)}${String(v.downloads).padEnd(11)}${date}`);
|
|
84
|
+
}
|
|
85
|
+
console.log();
|
|
86
|
+
}
|
|
87
|
+
function zipDirectory(dirPath) {
|
|
88
|
+
const zipPath = join(mkdtempSync(join(tmpdir(), "ota-")), "bundle.zip");
|
|
89
|
+
execSync(`cd "${dirPath}" && zip -r "${zipPath}" .`, { stdio: "pipe" });
|
|
90
|
+
return zipPath;
|
|
91
|
+
}
|
|
92
|
+
async function upload(appId, inputPath, options) {
|
|
93
|
+
const absolutePath = resolve(inputPath);
|
|
94
|
+
if (!existsSync(absolutePath)) throw new Error(`Path not found: ${absolutePath}`);
|
|
95
|
+
const stat = statSync(absolutePath);
|
|
96
|
+
let zipPath;
|
|
97
|
+
let tempDir = null;
|
|
98
|
+
if (stat.isDirectory()) {
|
|
99
|
+
console.log(`\n📦 Zipping directory: ${basename(absolutePath)}...`);
|
|
100
|
+
zipPath = zipDirectory(absolutePath);
|
|
101
|
+
tempDir = resolve(zipPath, "..");
|
|
102
|
+
} else if (absolutePath.endsWith(".zip")) zipPath = absolutePath;
|
|
103
|
+
else throw new Error("Input must be a directory or a .zip file");
|
|
104
|
+
const fileBuffer = readFileSync(zipPath);
|
|
105
|
+
const blob = new Blob([fileBuffer], { type: "application/zip" });
|
|
106
|
+
const formData = new FormData();
|
|
107
|
+
formData.append("app_id", appId);
|
|
108
|
+
formData.append("version", options.version || "1.0.0");
|
|
109
|
+
formData.append("channel", options.channel || "production");
|
|
110
|
+
formData.append("bundle", blob, "bundle.zip");
|
|
111
|
+
if (options.capacitorAppId) formData.append("capacitor_app_id", options.capacitorAppId);
|
|
112
|
+
if (options.minNativeVersion) formData.append("min_native_version", options.minNativeVersion);
|
|
113
|
+
if (options.releaseNotes) formData.append("release_notes", options.releaseNotes);
|
|
114
|
+
console.log(`📤 Uploading...`);
|
|
115
|
+
const result = await api("POST", "/api/versions/upload", void 0, formData);
|
|
116
|
+
if (tempDir) rmSync(tempDir, {
|
|
117
|
+
recursive: true,
|
|
118
|
+
force: true
|
|
119
|
+
});
|
|
120
|
+
console.log(`\n✅ Upload successful!`);
|
|
121
|
+
console.log(` Version: ${result.version}`);
|
|
122
|
+
console.log(` Checksum: ${result.checksum}\n`);
|
|
123
|
+
}
|
|
124
|
+
async function deleteVersion(versionId) {
|
|
125
|
+
await api("DELETE", `/api/versions/${versionId}`);
|
|
126
|
+
console.log(`✅ Version ${versionId} deleted.`);
|
|
127
|
+
}
|
|
128
|
+
async function rollback(versionId) {
|
|
129
|
+
await api("POST", `/api/versions/${versionId}/rollback`);
|
|
130
|
+
console.log(`✅ Rolled back to version ${versionId}.`);
|
|
131
|
+
}
|
|
132
|
+
async function setUrl(url) {
|
|
133
|
+
const config = loadConfig();
|
|
134
|
+
config.url = url;
|
|
135
|
+
saveConfig(config);
|
|
136
|
+
console.log(`✅ URL set to: ${url}`);
|
|
137
|
+
}
|
|
138
|
+
async function showConfig() {
|
|
139
|
+
const config = loadConfig();
|
|
140
|
+
console.log("\n⚙️ Config:\n");
|
|
141
|
+
console.log(` URL: ${config.url}`);
|
|
142
|
+
console.log(` Token: ${config.token ? "********" : "(not set)"}\n`);
|
|
143
|
+
}
|
|
144
|
+
function printHelp() {
|
|
145
|
+
console.log(`
|
|
146
|
+
OTA Service CLI
|
|
147
|
+
|
|
148
|
+
Usage:
|
|
149
|
+
ota <command> [options]
|
|
150
|
+
|
|
151
|
+
Commands:
|
|
152
|
+
login <username> <password> Login and save token
|
|
153
|
+
apps List all apps
|
|
154
|
+
versions <app_id> List versions for an app
|
|
155
|
+
upload <app_id> <path> Upload a new version (directory or .zip)
|
|
156
|
+
--version, -v <version> Version number (default: 1.0.0)
|
|
157
|
+
--channel, -c <channel> Channel (default: production)
|
|
158
|
+
--capacitor-app-id <id> Capacitor app ID for static JSON
|
|
159
|
+
--min-native <version> Minimum native version
|
|
160
|
+
--notes <text> Release notes
|
|
161
|
+
delete <version_id> Delete a version
|
|
162
|
+
rollback <version_id> Rollback to a version
|
|
163
|
+
config Show current config
|
|
164
|
+
set-url <url> Set API URL
|
|
165
|
+
|
|
166
|
+
Examples:
|
|
167
|
+
ota login admin password123
|
|
168
|
+
ota apps
|
|
169
|
+
ota versions 9fa3a103d8d0
|
|
170
|
+
ota upload 9fa3a103d8d0 ./dist -v 1.0.1 --capacitor-app-id com.example.app
|
|
171
|
+
ota upload 9fa3a103d8d0 ./bundle.zip -v 1.0.2
|
|
172
|
+
ota delete 5
|
|
173
|
+
ota rollback 3
|
|
174
|
+
`);
|
|
175
|
+
}
|
|
176
|
+
function parseArgs(args) {
|
|
177
|
+
const command = args[0] || "help";
|
|
178
|
+
const positional = [];
|
|
179
|
+
const options = {};
|
|
180
|
+
for (let i = 1; i < args.length; i++) {
|
|
181
|
+
const arg = args[i];
|
|
182
|
+
if (arg.startsWith("--")) {
|
|
183
|
+
const key = arg.slice(2);
|
|
184
|
+
options[key] = args[++i] || "";
|
|
185
|
+
} else if (arg.startsWith("-")) {
|
|
186
|
+
const key = arg.slice(1);
|
|
187
|
+
options[key] = args[++i] || "";
|
|
188
|
+
} else positional.push(arg);
|
|
189
|
+
}
|
|
190
|
+
return {
|
|
191
|
+
command,
|
|
192
|
+
positional,
|
|
193
|
+
options
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
async function main() {
|
|
197
|
+
const { command, positional, options } = parseArgs(process.argv.slice(2));
|
|
198
|
+
try {
|
|
199
|
+
switch (command) {
|
|
200
|
+
case "login":
|
|
201
|
+
if (positional.length < 2) throw new Error("Usage: ota login <username> <password>");
|
|
202
|
+
await login(positional[0], positional[1]);
|
|
203
|
+
break;
|
|
204
|
+
case "apps":
|
|
205
|
+
await listApps();
|
|
206
|
+
break;
|
|
207
|
+
case "versions":
|
|
208
|
+
if (positional.length < 1) throw new Error("Usage: ota versions <app_id>");
|
|
209
|
+
await listVersions(positional[0]);
|
|
210
|
+
break;
|
|
211
|
+
case "upload":
|
|
212
|
+
if (positional.length < 2) throw new Error("Usage: ota upload <app_id> <path> [options]");
|
|
213
|
+
await upload(positional[0], positional[1], {
|
|
214
|
+
version: options["version"] || options["v"],
|
|
215
|
+
channel: options["channel"] || options["c"],
|
|
216
|
+
capacitorAppId: options["capacitor-app-id"],
|
|
217
|
+
minNativeVersion: options["min-native"],
|
|
218
|
+
releaseNotes: options["notes"]
|
|
219
|
+
});
|
|
220
|
+
break;
|
|
221
|
+
case "delete":
|
|
222
|
+
if (positional.length < 1) throw new Error("Usage: ota delete <version_id>");
|
|
223
|
+
await deleteVersion(positional[0]);
|
|
224
|
+
break;
|
|
225
|
+
case "rollback":
|
|
226
|
+
if (positional.length < 1) throw new Error("Usage: ota rollback <version_id>");
|
|
227
|
+
await rollback(positional[0]);
|
|
228
|
+
break;
|
|
229
|
+
case "config":
|
|
230
|
+
await showConfig();
|
|
231
|
+
break;
|
|
232
|
+
case "set-url":
|
|
233
|
+
if (positional.length < 1) throw new Error("Usage: ota set-url <url>");
|
|
234
|
+
await setUrl(positional[0]);
|
|
235
|
+
break;
|
|
236
|
+
case "help":
|
|
237
|
+
case "--help":
|
|
238
|
+
case "-h":
|
|
239
|
+
printHelp();
|
|
240
|
+
break;
|
|
241
|
+
default:
|
|
242
|
+
console.error(`Unknown command: ${command}`);
|
|
243
|
+
printHelp();
|
|
244
|
+
process.exit(1);
|
|
245
|
+
}
|
|
246
|
+
} catch (error) {
|
|
247
|
+
console.error(`\n❌ Error: ${error instanceof Error ? error.message : error}\n`);
|
|
248
|
+
process.exit(1);
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
main();
|
|
252
|
+
|
|
253
|
+
//#endregion
|
|
254
|
+
export { };
|
|
@@ -55,7 +55,8 @@ var OtaUpdater = class {
|
|
|
55
55
|
if (!isNativePlatform()) return;
|
|
56
56
|
try {
|
|
57
57
|
const { CapacitorUpdater } = await import("@capgo/capacitor-updater");
|
|
58
|
-
await CapacitorUpdater.notifyAppReady();
|
|
58
|
+
const result = await CapacitorUpdater.notifyAppReady();
|
|
59
|
+
if (result?.bundle?.version) this.state.currentVersion = result.bundle.version;
|
|
59
60
|
} catch {}
|
|
60
61
|
}
|
|
61
62
|
async check() {
|
package/package.json
CHANGED
|
@@ -1,21 +1,25 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "capacitor-ota",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"type": "module",
|
|
5
|
-
"main": "dist/index.mjs",
|
|
6
|
-
"types": "dist/index.d.mts",
|
|
5
|
+
"main": "dist/src/index.mjs",
|
|
6
|
+
"types": "dist/src/index.d.mts",
|
|
7
7
|
"exports": {
|
|
8
8
|
".": {
|
|
9
|
-
"import": "./dist/index.mjs",
|
|
10
|
-
"types": "./dist/index.d.mts"
|
|
9
|
+
"import": "./dist/src/index.mjs",
|
|
10
|
+
"types": "./dist/src/index.d.mts"
|
|
11
11
|
}
|
|
12
12
|
},
|
|
13
|
+
"bin": {
|
|
14
|
+
"capacitor-ota": "./dist/cli/ota.mjs",
|
|
15
|
+
"ota": "./dist/cli/ota.mjs"
|
|
16
|
+
},
|
|
13
17
|
"files": [
|
|
14
18
|
"dist"
|
|
15
19
|
],
|
|
16
20
|
"scripts": {
|
|
17
|
-
"build": "tsdown
|
|
18
|
-
"dev": "tsdown
|
|
21
|
+
"build": "tsdown",
|
|
22
|
+
"dev": "tsdown --watch",
|
|
19
23
|
"panel:dev": "vite dev --host",
|
|
20
24
|
"panel:build": "vite build",
|
|
21
25
|
"panel:preview": "vite preview",
|
|
File without changes
|