@hot-updater/android-helper 1.2.0-rc.5 → 1.2.0-rc.6
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.
- package/dist/index.cjs +60 -34
- package/dist/index.d.cts +13 -6
- package/dist/index.d.mts +13 -6
- package/dist/index.mjs +60 -34
- package/package.json +4 -4
package/dist/index.cjs
CHANGED
|
@@ -1208,8 +1208,10 @@ const RESOURCE_MANAGER_API = "https://cloudresourcemanager.googleapis.com";
|
|
|
1208
1208
|
const SERVICE_USAGE_API = "https://serviceusage.googleapis.com";
|
|
1209
1209
|
const IAM_API = "https://iam.googleapis.com/v1";
|
|
1210
1210
|
const GCLOUD_INSTALL_URL = "https://cloud.google.com/sdk/docs/install";
|
|
1211
|
+
/** The Google Play Android Developer API, which the service account calls. */
|
|
1212
|
+
const PLAY_API = "androidpublisher.googleapis.com";
|
|
1211
1213
|
/** IAM creates the service account; the Play Developer API is what it calls. */
|
|
1212
|
-
const SERVICES = ["iam.googleapis.com",
|
|
1214
|
+
const SERVICES = ["iam.googleapis.com", PLAY_API];
|
|
1213
1215
|
const KEY_CREATION_CONSTRAINT = "constraints/iam.disableServiceAccountKeyCreation";
|
|
1214
1216
|
/** Retries while Google enables an API or creates a service account. */
|
|
1215
1217
|
const PROPAGATION_ATTEMPTS = 12;
|
|
@@ -1238,11 +1240,8 @@ const activeAccount = async (run) => (await run("gcloud", [
|
|
|
1238
1240
|
"--filter=status:ACTIVE",
|
|
1239
1241
|
"--format=value(account)"
|
|
1240
1242
|
])).trim().split("\n")[0]?.trim() || void 0;
|
|
1241
|
-
/**
|
|
1242
|
-
|
|
1243
|
-
* active. Stops before any change when gcloud is not installed.
|
|
1244
|
-
*/
|
|
1245
|
-
const signInWithGcloud = async ({ run, onStep }) => {
|
|
1243
|
+
/** Stops before anything else, a prompt included, when gcloud is not installed. */
|
|
1244
|
+
const requireGcloud = async (run) => {
|
|
1246
1245
|
try {
|
|
1247
1246
|
await run("gcloud", ["--version"]);
|
|
1248
1247
|
} catch (error) {
|
|
@@ -1252,6 +1251,9 @@ const signInWithGcloud = async ({ run, onStep }) => {
|
|
|
1252
1251
|
GCLOUD_INSTALL_URL
|
|
1253
1252
|
].join("\n"), { cause: error });
|
|
1254
1253
|
}
|
|
1254
|
+
};
|
|
1255
|
+
/** gcloud's access token, after `gcloud auth login` when no account is active. */
|
|
1256
|
+
const signInWithGcloud = async ({ run, onStep }) => {
|
|
1255
1257
|
let account = await activeAccount(run);
|
|
1256
1258
|
if (account === void 0) {
|
|
1257
1259
|
await run("gcloud", ["auth", "login"], { interactive: true }).catch(() => {});
|
|
@@ -1267,11 +1269,12 @@ const signInWithGcloud = async ({ run, onStep }) => {
|
|
|
1267
1269
|
* `IssuePlayServiceAccount` with the gcloud CLI's sign-in and Google's own
|
|
1268
1270
|
* APIs:
|
|
1269
1271
|
*
|
|
1270
|
-
* 1. gcloud
|
|
1271
|
-
*
|
|
1272
|
-
*
|
|
1273
|
-
*
|
|
1274
|
-
*
|
|
1272
|
+
* 1. once gcloud is found, `askPackageName` names the app, and gcloud's
|
|
1273
|
+
* Google Account, signed in with `gcloud auth login` when none is
|
|
1274
|
+
* active, the access token the Google Cloud steps use;
|
|
1275
|
+
* 2. the account's only project with the Play Developer API, else the one
|
|
1276
|
+
* `chooseProject` picks, else a new one, gets the IAM and Play Developer
|
|
1277
|
+
* APIs enabled, and the service account `hot-updater-play` its JSON key;
|
|
1275
1278
|
* 3. the developer invites the service account in Play Console, which
|
|
1276
1279
|
* `onInvite` opens: gcloud's token may not manage Google Play users;
|
|
1277
1280
|
* 4. the key itself opens an edit of the app until Google Play lets it,
|
|
@@ -1281,7 +1284,9 @@ const signInWithGcloud = async ({ run, onStep }) => {
|
|
|
1281
1284
|
* service account.
|
|
1282
1285
|
*/
|
|
1283
1286
|
const createGoogleKeyIssuer = ({ fetch = globalThis.fetch, sleep = sleepFor, run = runWithExeca } = {}) => async (request) => {
|
|
1284
|
-
const {
|
|
1287
|
+
const { onStep = () => {} } = request;
|
|
1288
|
+
await requireGcloud(run);
|
|
1289
|
+
const packageName = await request.askPackageName();
|
|
1285
1290
|
const accessToken = await signInWithGcloud({
|
|
1286
1291
|
run,
|
|
1287
1292
|
onStep
|
|
@@ -1297,7 +1302,7 @@ const createGoogleKeyIssuer = ({ fetch = globalThis.fetch, sleep = sleepFor, run
|
|
|
1297
1302
|
onStep
|
|
1298
1303
|
});
|
|
1299
1304
|
const { projectId } = project;
|
|
1300
|
-
onStep(`Enabling the
|
|
1305
|
+
onStep(`Enabling the APIs in ${projectId}`);
|
|
1301
1306
|
await enableServices({
|
|
1302
1307
|
google,
|
|
1303
1308
|
projectId,
|
|
@@ -1408,32 +1413,53 @@ const listProjects = async (google) => {
|
|
|
1408
1413
|
} while (pageToken);
|
|
1409
1414
|
return projects;
|
|
1410
1415
|
};
|
|
1411
|
-
/**
|
|
1416
|
+
/** Service Usage reads of the projects' Play Developer API, at most this many at once. */
|
|
1417
|
+
const API_CHECK_CONCURRENCY = 8;
|
|
1418
|
+
/**
|
|
1419
|
+
* Whether each project has the Google Play Developer API enabled, by one
|
|
1420
|
+
* Service Usage read each; a project this account may not read counts as
|
|
1421
|
+
* without it.
|
|
1422
|
+
*/
|
|
1423
|
+
const withPlayApiState = async (google, projects) => {
|
|
1424
|
+
const states = [];
|
|
1425
|
+
for (let start = 0; start < projects.length; start += API_CHECK_CONCURRENCY) states.push(...await Promise.all(projects.slice(start, start + API_CHECK_CONCURRENCY).map(({ projectId }) => google("Reading the project's APIs", "GET", `${SERVICE_USAGE_API}/v1/projects/${encodeURIComponent(projectId)}/services/${PLAY_API}`).then(({ state }) => state === "ENABLED", () => false))));
|
|
1426
|
+
return projects.map((project, index) => ({
|
|
1427
|
+
...project,
|
|
1428
|
+
playApiEnabled: states[index]
|
|
1429
|
+
}));
|
|
1430
|
+
};
|
|
1431
|
+
/** The display name of the project Hot Updater creates. */
|
|
1412
1432
|
const PROJECT_DISPLAY_NAME = "Hot Updater Play";
|
|
1413
1433
|
/**
|
|
1414
|
-
* The project the service account goes in
|
|
1415
|
-
*
|
|
1416
|
-
*
|
|
1434
|
+
* The project the service account goes in: a new one for an account
|
|
1435
|
+
* without projects; the only project with the Play Developer API, without
|
|
1436
|
+
* asking; else the one the developer picks, or a new one.
|
|
1417
1437
|
*/
|
|
1418
1438
|
const chooseProject = async ({ google, request, sleep, onStep }) => {
|
|
1419
|
-
const
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
projectId,
|
|
1432
|
-
...displayName ? { displayName } : {}
|
|
1433
|
-
})));
|
|
1434
|
-
if (chosen === void 0) throw error;
|
|
1435
|
-
return projects.find((project) => project.projectId === chosen) ?? { projectId: chosen };
|
|
1439
|
+
const listed = await listProjects(google);
|
|
1440
|
+
if (listed.length === 0) return createProject({
|
|
1441
|
+
google,
|
|
1442
|
+
sleep,
|
|
1443
|
+
onStep
|
|
1444
|
+
});
|
|
1445
|
+
const projects = await withPlayApiState(google, listed);
|
|
1446
|
+
const enabled = projects.filter(({ playApiEnabled }) => playApiEnabled);
|
|
1447
|
+
if (enabled.length === 1) {
|
|
1448
|
+
const [only] = enabled;
|
|
1449
|
+
onStep(`Using ${only.projectId}, the project with the Play Developer API`);
|
|
1450
|
+
return only;
|
|
1436
1451
|
}
|
|
1452
|
+
const chosen = await request.chooseProject(projects.map(({ projectId, displayName, playApiEnabled }) => ({
|
|
1453
|
+
projectId,
|
|
1454
|
+
...displayName ? { displayName } : {},
|
|
1455
|
+
playApiEnabled
|
|
1456
|
+
})));
|
|
1457
|
+
if (chosen === null) return createProject({
|
|
1458
|
+
google,
|
|
1459
|
+
sleep,
|
|
1460
|
+
onStep
|
|
1461
|
+
});
|
|
1462
|
+
return projects.find((project) => project.projectId === chosen) ?? { projectId: chosen };
|
|
1437
1463
|
};
|
|
1438
1464
|
/** A new project, `hot-updater-play-<random>`, once Google has created it. */
|
|
1439
1465
|
const createProject = async ({ google, sleep, onStep }) => {
|
package/dist/index.d.cts
CHANGED
|
@@ -187,21 +187,28 @@ declare const PLAY_SERVICE_ACCOUNT_ID = "hot-updater-play";
|
|
|
187
187
|
interface GoogleCloudProject {
|
|
188
188
|
readonly projectId: string;
|
|
189
189
|
readonly displayName?: string;
|
|
190
|
+
/** Whether the Google Play Android Developer API is enabled in it. */
|
|
191
|
+
readonly playApiEnabled: boolean;
|
|
190
192
|
}
|
|
191
193
|
interface IssuePlayServiceAccountRequest {
|
|
192
|
-
/**
|
|
193
|
-
|
|
194
|
+
/**
|
|
195
|
+
* Asks for the app's package name in Google Play, which the service
|
|
196
|
+
* account may release: after the sign-in's own tool is found, before
|
|
197
|
+
* anything else.
|
|
198
|
+
*/
|
|
199
|
+
readonly askPackageName: () => Promise<string>;
|
|
194
200
|
/**
|
|
195
201
|
* Sees Play Console's page that invites the service account `email`, to
|
|
196
202
|
* print it and open it in a browser; the issuer then waits for the invite.
|
|
197
203
|
*/
|
|
198
204
|
readonly onInvite: (url: string, email: string) => Promise<void> | void;
|
|
199
205
|
/**
|
|
200
|
-
* Sees the account's projects when
|
|
201
|
-
*
|
|
202
|
-
*
|
|
206
|
+
* Sees the account's projects when no one of them is the obvious home of
|
|
207
|
+
* the service account, the only one with the Google Play Developer API,
|
|
208
|
+
* and returns the project ID to create it in, or null for a new project.
|
|
209
|
+
* Never called for an account without projects: a new one is created.
|
|
203
210
|
*/
|
|
204
|
-
readonly chooseProject: (projects: readonly GoogleCloudProject[]) => Promise<string |
|
|
211
|
+
readonly chooseProject: (projects: readonly GoogleCloudProject[]) => Promise<string | null>;
|
|
205
212
|
/** Reports each step, such as "Creating the service account". */
|
|
206
213
|
readonly onStep?: (message: string) => void;
|
|
207
214
|
}
|
package/dist/index.d.mts
CHANGED
|
@@ -188,21 +188,28 @@ declare const PLAY_SERVICE_ACCOUNT_ID = "hot-updater-play";
|
|
|
188
188
|
interface GoogleCloudProject {
|
|
189
189
|
readonly projectId: string;
|
|
190
190
|
readonly displayName?: string;
|
|
191
|
+
/** Whether the Google Play Android Developer API is enabled in it. */
|
|
192
|
+
readonly playApiEnabled: boolean;
|
|
191
193
|
}
|
|
192
194
|
interface IssuePlayServiceAccountRequest {
|
|
193
|
-
/**
|
|
194
|
-
|
|
195
|
+
/**
|
|
196
|
+
* Asks for the app's package name in Google Play, which the service
|
|
197
|
+
* account may release: after the sign-in's own tool is found, before
|
|
198
|
+
* anything else.
|
|
199
|
+
*/
|
|
200
|
+
readonly askPackageName: () => Promise<string>;
|
|
195
201
|
/**
|
|
196
202
|
* Sees Play Console's page that invites the service account `email`, to
|
|
197
203
|
* print it and open it in a browser; the issuer then waits for the invite.
|
|
198
204
|
*/
|
|
199
205
|
readonly onInvite: (url: string, email: string) => Promise<void> | void;
|
|
200
206
|
/**
|
|
201
|
-
* Sees the account's projects when
|
|
202
|
-
*
|
|
203
|
-
*
|
|
207
|
+
* Sees the account's projects when no one of them is the obvious home of
|
|
208
|
+
* the service account, the only one with the Google Play Developer API,
|
|
209
|
+
* and returns the project ID to create it in, or null for a new project.
|
|
210
|
+
* Never called for an account without projects: a new one is created.
|
|
204
211
|
*/
|
|
205
|
-
readonly chooseProject: (projects: readonly GoogleCloudProject[]) => Promise<string |
|
|
212
|
+
readonly chooseProject: (projects: readonly GoogleCloudProject[]) => Promise<string | null>;
|
|
206
213
|
/** Reports each step, such as "Creating the service account". */
|
|
207
214
|
readonly onStep?: (message: string) => void;
|
|
208
215
|
}
|
package/dist/index.mjs
CHANGED
|
@@ -1179,8 +1179,10 @@ const RESOURCE_MANAGER_API = "https://cloudresourcemanager.googleapis.com";
|
|
|
1179
1179
|
const SERVICE_USAGE_API = "https://serviceusage.googleapis.com";
|
|
1180
1180
|
const IAM_API = "https://iam.googleapis.com/v1";
|
|
1181
1181
|
const GCLOUD_INSTALL_URL = "https://cloud.google.com/sdk/docs/install";
|
|
1182
|
+
/** The Google Play Android Developer API, which the service account calls. */
|
|
1183
|
+
const PLAY_API = "androidpublisher.googleapis.com";
|
|
1182
1184
|
/** IAM creates the service account; the Play Developer API is what it calls. */
|
|
1183
|
-
const SERVICES = ["iam.googleapis.com",
|
|
1185
|
+
const SERVICES = ["iam.googleapis.com", PLAY_API];
|
|
1184
1186
|
const KEY_CREATION_CONSTRAINT = "constraints/iam.disableServiceAccountKeyCreation";
|
|
1185
1187
|
/** Retries while Google enables an API or creates a service account. */
|
|
1186
1188
|
const PROPAGATION_ATTEMPTS = 12;
|
|
@@ -1209,11 +1211,8 @@ const activeAccount = async (run) => (await run("gcloud", [
|
|
|
1209
1211
|
"--filter=status:ACTIVE",
|
|
1210
1212
|
"--format=value(account)"
|
|
1211
1213
|
])).trim().split("\n")[0]?.trim() || void 0;
|
|
1212
|
-
/**
|
|
1213
|
-
|
|
1214
|
-
* active. Stops before any change when gcloud is not installed.
|
|
1215
|
-
*/
|
|
1216
|
-
const signInWithGcloud = async ({ run, onStep }) => {
|
|
1214
|
+
/** Stops before anything else, a prompt included, when gcloud is not installed. */
|
|
1215
|
+
const requireGcloud = async (run) => {
|
|
1217
1216
|
try {
|
|
1218
1217
|
await run("gcloud", ["--version"]);
|
|
1219
1218
|
} catch (error) {
|
|
@@ -1223,6 +1222,9 @@ const signInWithGcloud = async ({ run, onStep }) => {
|
|
|
1223
1222
|
GCLOUD_INSTALL_URL
|
|
1224
1223
|
].join("\n"), { cause: error });
|
|
1225
1224
|
}
|
|
1225
|
+
};
|
|
1226
|
+
/** gcloud's access token, after `gcloud auth login` when no account is active. */
|
|
1227
|
+
const signInWithGcloud = async ({ run, onStep }) => {
|
|
1226
1228
|
let account = await activeAccount(run);
|
|
1227
1229
|
if (account === void 0) {
|
|
1228
1230
|
await run("gcloud", ["auth", "login"], { interactive: true }).catch(() => {});
|
|
@@ -1238,11 +1240,12 @@ const signInWithGcloud = async ({ run, onStep }) => {
|
|
|
1238
1240
|
* `IssuePlayServiceAccount` with the gcloud CLI's sign-in and Google's own
|
|
1239
1241
|
* APIs:
|
|
1240
1242
|
*
|
|
1241
|
-
* 1. gcloud
|
|
1242
|
-
*
|
|
1243
|
-
*
|
|
1244
|
-
*
|
|
1245
|
-
*
|
|
1243
|
+
* 1. once gcloud is found, `askPackageName` names the app, and gcloud's
|
|
1244
|
+
* Google Account, signed in with `gcloud auth login` when none is
|
|
1245
|
+
* active, the access token the Google Cloud steps use;
|
|
1246
|
+
* 2. the account's only project with the Play Developer API, else the one
|
|
1247
|
+
* `chooseProject` picks, else a new one, gets the IAM and Play Developer
|
|
1248
|
+
* APIs enabled, and the service account `hot-updater-play` its JSON key;
|
|
1246
1249
|
* 3. the developer invites the service account in Play Console, which
|
|
1247
1250
|
* `onInvite` opens: gcloud's token may not manage Google Play users;
|
|
1248
1251
|
* 4. the key itself opens an edit of the app until Google Play lets it,
|
|
@@ -1252,7 +1255,9 @@ const signInWithGcloud = async ({ run, onStep }) => {
|
|
|
1252
1255
|
* service account.
|
|
1253
1256
|
*/
|
|
1254
1257
|
const createGoogleKeyIssuer = ({ fetch = globalThis.fetch, sleep = sleepFor, run = runWithExeca } = {}) => async (request) => {
|
|
1255
|
-
const {
|
|
1258
|
+
const { onStep = () => {} } = request;
|
|
1259
|
+
await requireGcloud(run);
|
|
1260
|
+
const packageName = await request.askPackageName();
|
|
1256
1261
|
const accessToken = await signInWithGcloud({
|
|
1257
1262
|
run,
|
|
1258
1263
|
onStep
|
|
@@ -1268,7 +1273,7 @@ const createGoogleKeyIssuer = ({ fetch = globalThis.fetch, sleep = sleepFor, run
|
|
|
1268
1273
|
onStep
|
|
1269
1274
|
});
|
|
1270
1275
|
const { projectId } = project;
|
|
1271
|
-
onStep(`Enabling the
|
|
1276
|
+
onStep(`Enabling the APIs in ${projectId}`);
|
|
1272
1277
|
await enableServices({
|
|
1273
1278
|
google,
|
|
1274
1279
|
projectId,
|
|
@@ -1379,32 +1384,53 @@ const listProjects = async (google) => {
|
|
|
1379
1384
|
} while (pageToken);
|
|
1380
1385
|
return projects;
|
|
1381
1386
|
};
|
|
1382
|
-
/**
|
|
1387
|
+
/** Service Usage reads of the projects' Play Developer API, at most this many at once. */
|
|
1388
|
+
const API_CHECK_CONCURRENCY = 8;
|
|
1389
|
+
/**
|
|
1390
|
+
* Whether each project has the Google Play Developer API enabled, by one
|
|
1391
|
+
* Service Usage read each; a project this account may not read counts as
|
|
1392
|
+
* without it.
|
|
1393
|
+
*/
|
|
1394
|
+
const withPlayApiState = async (google, projects) => {
|
|
1395
|
+
const states = [];
|
|
1396
|
+
for (let start = 0; start < projects.length; start += API_CHECK_CONCURRENCY) states.push(...await Promise.all(projects.slice(start, start + API_CHECK_CONCURRENCY).map(({ projectId }) => google("Reading the project's APIs", "GET", `${SERVICE_USAGE_API}/v1/projects/${encodeURIComponent(projectId)}/services/${PLAY_API}`).then(({ state }) => state === "ENABLED", () => false))));
|
|
1397
|
+
return projects.map((project, index) => ({
|
|
1398
|
+
...project,
|
|
1399
|
+
playApiEnabled: states[index]
|
|
1400
|
+
}));
|
|
1401
|
+
};
|
|
1402
|
+
/** The display name of the project Hot Updater creates. */
|
|
1383
1403
|
const PROJECT_DISPLAY_NAME = "Hot Updater Play";
|
|
1384
1404
|
/**
|
|
1385
|
-
* The project the service account goes in
|
|
1386
|
-
*
|
|
1387
|
-
*
|
|
1405
|
+
* The project the service account goes in: a new one for an account
|
|
1406
|
+
* without projects; the only project with the Play Developer API, without
|
|
1407
|
+
* asking; else the one the developer picks, or a new one.
|
|
1388
1408
|
*/
|
|
1389
1409
|
const chooseProject = async ({ google, request, sleep, onStep }) => {
|
|
1390
|
-
const
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
projectId,
|
|
1403
|
-
...displayName ? { displayName } : {}
|
|
1404
|
-
})));
|
|
1405
|
-
if (chosen === void 0) throw error;
|
|
1406
|
-
return projects.find((project) => project.projectId === chosen) ?? { projectId: chosen };
|
|
1410
|
+
const listed = await listProjects(google);
|
|
1411
|
+
if (listed.length === 0) return createProject({
|
|
1412
|
+
google,
|
|
1413
|
+
sleep,
|
|
1414
|
+
onStep
|
|
1415
|
+
});
|
|
1416
|
+
const projects = await withPlayApiState(google, listed);
|
|
1417
|
+
const enabled = projects.filter(({ playApiEnabled }) => playApiEnabled);
|
|
1418
|
+
if (enabled.length === 1) {
|
|
1419
|
+
const [only] = enabled;
|
|
1420
|
+
onStep(`Using ${only.projectId}, the project with the Play Developer API`);
|
|
1421
|
+
return only;
|
|
1407
1422
|
}
|
|
1423
|
+
const chosen = await request.chooseProject(projects.map(({ projectId, displayName, playApiEnabled }) => ({
|
|
1424
|
+
projectId,
|
|
1425
|
+
...displayName ? { displayName } : {},
|
|
1426
|
+
playApiEnabled
|
|
1427
|
+
})));
|
|
1428
|
+
if (chosen === null) return createProject({
|
|
1429
|
+
google,
|
|
1430
|
+
sleep,
|
|
1431
|
+
onStep
|
|
1432
|
+
});
|
|
1433
|
+
return projects.find((project) => project.projectId === chosen) ?? { projectId: chosen };
|
|
1408
1434
|
};
|
|
1409
1435
|
/** A new project, `hot-updater-play-<random>`, once Google has created it. */
|
|
1410
1436
|
const createProject = async ({ google, sleep, onStep }) => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hot-updater/android-helper",
|
|
3
|
-
"version": "1.2.0-rc.
|
|
3
|
+
"version": "1.2.0-rc.6",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "dist/index.cjs",
|
|
6
6
|
"module": "dist/index.mjs",
|
|
@@ -29,9 +29,9 @@
|
|
|
29
29
|
"dependencies": {
|
|
30
30
|
"execa": "9.5.2",
|
|
31
31
|
"jszip": "^3.10.1",
|
|
32
|
-
"@hot-updater/cli-tools": "1.2.0-rc.
|
|
33
|
-
"@hot-updater/plugin-core": "1.2.0-rc.
|
|
34
|
-
"@hot-updater/protocol": "1.2.0-rc.
|
|
32
|
+
"@hot-updater/cli-tools": "1.2.0-rc.6",
|
|
33
|
+
"@hot-updater/plugin-core": "1.2.0-rc.6",
|
|
34
|
+
"@hot-updater/protocol": "1.2.0-rc.6"
|
|
35
35
|
},
|
|
36
36
|
"devDependencies": {
|
|
37
37
|
"@types/node": "^20"
|