@hot-updater/android-helper 1.1.4 → 1.2.0-rc.1

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.d.cts CHANGED
@@ -1,9 +1,10 @@
1
- import { NativeBuildAndroidScheme, NativeBuildOptions } from "@hot-updater/plugin-core";
1
+ import { CredentialRequest, CredentialResolver, Credentials } from "@hot-updater/cli-tools";
2
+ import { NativeBuildAndroidScheme } from "@hot-updater/plugin-core";
2
3
  //#region src/utils/enrichNativeBuildAndroidScheme.d.ts
3
4
  /**
4
5
  * Validated scheme filled nullish values with default values.
5
6
  */
6
- type EnrichedNativeBuildAndroidScheme = Required<NativeBuildAndroidScheme> & {
7
+ type EnrichedNativeBuildAndroidScheme = Required<Omit<NativeBuildAndroidScheme, "signing">> & Pick<NativeBuildAndroidScheme, "signing"> & {
7
8
  hotUpdaterSchemeName: string;
8
9
  };
9
10
  declare const enrichNativeBuildAndroidScheme: ({ schemeConfig, hotUpdaterSchemeName }: {
@@ -12,28 +13,247 @@ declare const enrichNativeBuildAndroidScheme: ({ schemeConfig, hotUpdaterSchemeN
12
13
  }) => Promise<EnrichedNativeBuildAndroidScheme>;
13
14
  //#endregion
14
15
  //#region src/buildAndroid.d.ts
15
- declare const buildAndroid: ({ schemeConfig }: {
16
+ declare const buildAndroid: ({ schemeConfig, minBundleId, credentials }: {
16
17
  schemeConfig: EnrichedNativeBuildAndroidScheme;
18
+ /** The MIN_BUNDLE_ID the build compiles in. */
19
+ minBundleId?: string;
20
+ /** Resolves the scheme's `signing` keystore, when it signs with one. */
21
+ credentials?: Pick<CredentialResolver, "resolve">;
17
22
  }) => Promise<{
18
23
  buildDirectory: string;
19
24
  buildArtifactPath: string;
25
+ /** What the built artifact reports, or undefined without aapt2. */
26
+ builtApp?: {
27
+ appVersion: string | null;
28
+ /** undefined when the artifact's channel cannot be read exactly. */
29
+ channel?: string | null;
30
+ /** The manifest's `versionCode`. */
31
+ buildNumber: string | null;
32
+ };
20
33
  }>;
21
34
  //#endregion
22
- //#region src/types.d.ts
23
- interface AndroidNativeRunOptions extends NativeBuildOptions {
24
- device?: string | boolean;
25
- port?: string;
26
- mainActivity?: string;
27
- user?: string;
35
+ //#region src/uploadToPlay.d.ts
36
+ /**
37
+ * Google Play refused the upload: it already has a bundle or APK with the
38
+ * `.aab`'s version code, from this or another upload, and takes each version
39
+ * code once.
40
+ */
41
+ declare class PlayVersionCodeUsedError extends Error {
42
+ readonly name = "PlayVersionCodeUsedError";
43
+ constructor(options?: ErrorOptions);
28
44
  }
45
+ /**
46
+ * Whether Google Play's internal testing track already releases the
47
+ * `.aab`'s version code, as when a reused native build was uploaded
48
+ * before. It reads the track in an edit it then deletes, changing nothing.
49
+ */
50
+ declare const findPlayInternalRelease: ({ versionCode, packageName, serviceAccount: { json }, fetch }: {
51
+ versionCode: number;
52
+ /** The application ID the `.aab` was built with. */
53
+ packageName: string;
54
+ serviceAccount: Credentials["play-service-account"];
55
+ fetch?: typeof globalThis.fetch;
56
+ }) => Promise<boolean>;
57
+ /**
58
+ * Throws when the `.aab` is signed with the Android debug keystore, which
59
+ * Google Play refuses: a release build type left on `signingConfigs.debug`,
60
+ * as React Native's template ships it. It reads the signer with the JDK's
61
+ * `keytool`, which Gradle needs too; without one it checks nothing.
62
+ */
63
+ declare const assertPlaySigned: (aabPath: string) => Promise<void>;
64
+ interface UploadToPlayResult {
65
+ /** The version code Google Play read from the `.aab`. */
66
+ versionCode: number;
67
+ /** The release's status: `draft` on an app Play Console has not published. */
68
+ status: "completed" | "draft";
69
+ }
70
+ /**
71
+ * Uploads an `.aab` to Google Play's internal testing track with the Google
72
+ * Play Developer API: it opens an edit, uploads the bundle, releases its
73
+ * version code to the internal track, and commits the edit, which it
74
+ * deletes again when any step fails. The service account stays in memory.
75
+ */
76
+ declare const uploadToPlay: ({ aabPath, packageName, serviceAccount: { json }, fetch, commitRetryDelayMs }: {
77
+ aabPath: string;
78
+ /** The application ID the `.aab` was built with. */
79
+ packageName: string;
80
+ serviceAccount: Credentials["play-service-account"];
81
+ fetch?: typeof globalThis.fetch;
82
+ /** The first wait before committing again an edit Google is processing. */
83
+ commitRetryDelayMs?: number;
84
+ }) => Promise<UploadToPlayResult>;
85
+ /**
86
+ * The Play service account a scheme's `.aab` uploads with: the
87
+ * `play-service-account` item. It reads only the config, before the native
88
+ * projects are written, and throws for a scheme whose build Google Play
89
+ * would not take as a release: an `.apk`, which Play takes only as an `.aab`
90
+ * from new apps, or a debug variant, which Play refuses.
91
+ */
92
+ declare const resolvePlayUploadServiceAccount: ({ scheme, androidScheme }: {
93
+ /** The scheme's name. */
94
+ scheme: string;
95
+ androidScheme: NativeBuildAndroidScheme;
96
+ }) => CredentialRequest<"play-service-account">;
29
97
  //#endregion
30
- //#region src/runAndroid.d.ts
31
- declare const runAndroid: ({ schemeConfig, runOption }: {
32
- schemeConfig: EnrichedNativeBuildAndroidScheme;
33
- runOption: AndroidNativeRunOptions;
98
+ //#region src/utils/extractBuiltInBundle.d.ts
99
+ /**
100
+ * Copies the JavaScript bundle React Native's Gradle build packed into an
101
+ * `.apk` (`assets/index.android.bundle`) or an `.aab`
102
+ * (`base/assets/index.android.bundle`) to `outputPath`: the built-in bundle,
103
+ * byte for byte, which no rebuild reproduces. It reads only the archive's
104
+ * directory and that entry, streamed, so a large artifact stays on disk.
105
+ */
106
+ declare const extractBuiltInBundle: ({ artifactPath, outputPath }: {
107
+ artifactPath: string;
108
+ outputPath: string;
109
+ }) => Promise<void>;
110
+ //#endregion
111
+ //#region src/utils/readBuiltApp.d.ts
112
+ /**
113
+ * What the built `.apk` or `.aab` reports at runtime: the `versionName` and
114
+ * the `com.hotupdater.CHANNEL` meta-data Gradle merged into its manifest,
115
+ * from flavors, build types and `versionNameSuffix`. Without aapt2 it
116
+ * returns undefined, and the build reports the project's values.
117
+ */
118
+ declare const readBuiltApp: ({ artifactPath, androidProjectPath }: {
119
+ artifactPath: string;
120
+ androidProjectPath: string;
34
121
  }) => Promise<{
35
- buildDirectory: string;
36
- buildArtifactPath: string;
37
- }>;
122
+ appVersion: string | null;
123
+ /** undefined when the artifact's channel cannot be read exactly. */
124
+ channel?: string | null;
125
+ /** The manifest's `versionCode`. */
126
+ buildNumber: string | null;
127
+ } | undefined>;
128
+ /**
129
+ * The application ID of the built `.apk` or `.aab`, the package name Google
130
+ * Play files it under, with the suffixes flavors and build types add.
131
+ * undefined without aapt2.
132
+ */
133
+ declare const readBuiltPackageName: ({ artifactPath, androidProjectPath }: {
134
+ artifactPath: string;
135
+ androidProjectPath: string;
136
+ }) => Promise<string | undefined>;
137
+ /**
138
+ * The version code of the built `.apk` or `.aab`, which Google Play files
139
+ * its releases by. undefined without aapt2, or when the manifest has none.
140
+ */
141
+ declare const readBuiltVersionCode: ({ artifactPath, androidProjectPath }: {
142
+ artifactPath: string;
143
+ androidProjectPath: string;
144
+ }) => Promise<number | undefined>;
145
+ //#endregion
146
+ //#region src/google/types.d.ts
147
+ /** What stopped Hot Updater from issuing the Play service account key. */
148
+ type PlayServiceAccountErrorCode =
149
+ /** No OAuth client to sign in with, or Google refused it. */
150
+ "sign-in-not-configured" |
151
+ /** The browser sign-in was cancelled, refused, or timed out. */
152
+ "sign-in-cancelled" |
153
+ /** The account unticked a scope the setup needs on Google's consent screen. */
154
+ "scope-not-granted" |
155
+ /** The developer account ID names no Play Console account. */
156
+ "developer-not-found" |
157
+ /** The Google Account is no admin of the Play Console developer account. */
158
+ "not-play-admin" |
159
+ /** Google Play has no app with the package name in the developer account. */
160
+ "app-not-found" |
161
+ /** The Google Account may not create a Google Cloud project. */
162
+ "project-create-denied" |
163
+ /** The Google Account has no Google Cloud project quota left. */
164
+ "project-quota" |
165
+ /** The Google Account may not enable APIs or create service accounts in the project. */
166
+ "project-access-denied" |
167
+ /** Google is still enabling an API, or it is disabled in the OAuth client's project. */
168
+ "api-not-enabled" |
169
+ /** An organization policy (`iam.disableServiceAccountKeyCreation`) forbids keys. */
170
+ "key-creation-disabled";
171
+ /** A named failure of `issuePlayServiceAccount`, with what to do in its message. */
172
+ declare class PlayServiceAccountError extends Error {
173
+ readonly code: PlayServiceAccountErrorCode;
174
+ constructor(code: PlayServiceAccountErrorCode, message: string, options?: {
175
+ cause?: unknown;
176
+ });
177
+ }
178
+ /**
179
+ * A Google OAuth client of type "Desktop app". Google treats an installed
180
+ * app's client secret as public, so it ships with the client ID.
181
+ */
182
+ interface GoogleOAuthClient {
183
+ readonly clientId: string;
184
+ readonly clientSecret?: string;
185
+ }
186
+ /** The environment variables that replace Hot Updater's Google OAuth client. */
187
+ declare const GOOGLE_OAUTH_CLIENT_ENV_NAMES: {
188
+ readonly clientId: "HOT_UPDATER_GOOGLE_OAUTH_CLIENT_ID";
189
+ readonly clientSecret: "HOT_UPDATER_GOOGLE_OAUTH_CLIENT_SECRET";
190
+ };
191
+ /** The service account Hot Updater creates, `hot-updater-play@<project>.iam.gserviceaccount.com`. */
192
+ declare const PLAY_SERVICE_ACCOUNT_ID = "hot-updater-play";
193
+ /** Where a Play Console admin finds the developer account ID. */
194
+ declare const PLAY_CONSOLE_URL = "https://play.google.com/console";
195
+ //#endregion
196
+ //#region src/playServiceAccount.d.ts
197
+ /**
198
+ * Hot Updater's Google OAuth client, a "Desktop app" client the sign-in
199
+ * opens Google's consent screen for. Empty in a build that has none, where
200
+ * `HOT_UPDATER_GOOGLE_OAUTH_CLIENT_ID` and `_SECRET` name one.
201
+ */
202
+ declare const HOT_UPDATER_GOOGLE_OAUTH_CLIENT: GoogleOAuthClient;
203
+ /** A Google Cloud project the signed-in account can use. */
204
+ interface GoogleCloudProject {
205
+ readonly projectId: string;
206
+ readonly displayName?: string;
207
+ }
208
+ interface IssuePlayServiceAccountRequest {
209
+ /** The app's package name in Google Play, which the service account may release. */
210
+ readonly packageName: string;
211
+ /** The OAuth client to sign in with; Hot Updater's unless set. */
212
+ readonly oauthClient?: GoogleOAuthClient;
213
+ /** Sees the sign-in URL, to print it and open it in a browser. */
214
+ readonly onSignInUrl: (url: string) => Promise<void> | void;
215
+ /** Asks for the Play Console developer account ID, after the sign-in. */
216
+ readonly askDeveloperId: () => Promise<string>;
217
+ /**
218
+ * Sees the account's projects when there are any, and returns the one to
219
+ * create the service account in, or undefined to create a project.
220
+ */
221
+ readonly chooseProject: (projects: readonly GoogleCloudProject[]) => Promise<string | undefined>;
222
+ /** Reports each step, such as "Creating the service account". */
223
+ readonly onStep?: (message: string) => void;
224
+ }
225
+ /**
226
+ * A Play service account's JSON key, just created, with the access token
227
+ * of the sign-in it was created in. `revoke` deletes the key while the
228
+ * sign-in lasts, and `dispose` ends the sign-in.
229
+ */
230
+ interface IssuedPlayServiceAccount {
231
+ /** The JSON key file, as Google Cloud downloads it. */
232
+ readonly json: string;
233
+ /** The service account's email, the Play Console user it releases as. */
234
+ readonly email: string;
235
+ readonly projectId: string;
236
+ readonly developerId: string;
237
+ /** The key's ID, as Google Cloud lists it under the service account's keys. */
238
+ readonly keyId: string;
239
+ /** Deletes the key with the same sign-in; whether Google Cloud did. */
240
+ revoke(): Promise<boolean>;
241
+ /** Ends the sign-in: Google revokes its access token. */
242
+ dispose(): Promise<void>;
243
+ }
244
+ /**
245
+ * Signs in with Google and issues a service account key that releases the
246
+ * app to Google Play: the developer signs in on Google's own consent
247
+ * screen, in a browser, and the caller never sees the password. Nothing of
248
+ * the sign-in outlives `dispose`.
249
+ */
250
+ type IssuePlayServiceAccount = (request: IssuePlayServiceAccountRequest) => Promise<IssuedPlayServiceAccount>;
251
+ /**
252
+ * Hot Updater's issuer, the one place that picks how it is done: Google's
253
+ * OAuth for installed apps, then the Cloud Resource Manager, Service Usage,
254
+ * IAM, and Play Developer APIs. Another implementation of
255
+ * `IssuePlayServiceAccount` replaces it here without touching its callers.
256
+ */
257
+ declare const issuePlayServiceAccount: IssuePlayServiceAccount;
38
258
  //#endregion
39
- export { type AndroidNativeRunOptions, type EnrichedNativeBuildAndroidScheme, buildAndroid, enrichNativeBuildAndroidScheme, runAndroid };
259
+ export { type EnrichedNativeBuildAndroidScheme, GOOGLE_OAUTH_CLIENT_ENV_NAMES, type GoogleCloudProject, type GoogleOAuthClient, HOT_UPDATER_GOOGLE_OAUTH_CLIENT, type IssuePlayServiceAccount, type IssuePlayServiceAccountRequest, type IssuedPlayServiceAccount, PLAY_CONSOLE_URL, PLAY_SERVICE_ACCOUNT_ID, PlayServiceAccountError, type PlayServiceAccountErrorCode, PlayVersionCodeUsedError, type UploadToPlayResult, assertPlaySigned, buildAndroid, enrichNativeBuildAndroidScheme, extractBuiltInBundle, findPlayInternalRelease, issuePlayServiceAccount, readBuiltApp, readBuiltPackageName, readBuiltVersionCode, resolvePlayUploadServiceAccount, uploadToPlay };
package/dist/index.d.mts CHANGED
@@ -1,9 +1,11 @@
1
- import { NativeBuildAndroidScheme, NativeBuildOptions } from "@hot-updater/plugin-core";
1
+ import { CredentialRequest, CredentialResolver, Credentials } from "@hot-updater/cli-tools";
2
+ import crypto from "crypto";
3
+ import { NativeBuildAndroidScheme } from "@hot-updater/plugin-core";
2
4
  //#region src/utils/enrichNativeBuildAndroidScheme.d.ts
3
5
  /**
4
6
  * Validated scheme filled nullish values with default values.
5
7
  */
6
- type EnrichedNativeBuildAndroidScheme = Required<NativeBuildAndroidScheme> & {
8
+ type EnrichedNativeBuildAndroidScheme = Required<Omit<NativeBuildAndroidScheme, "signing">> & Pick<NativeBuildAndroidScheme, "signing"> & {
7
9
  hotUpdaterSchemeName: string;
8
10
  };
9
11
  declare const enrichNativeBuildAndroidScheme: ({ schemeConfig, hotUpdaterSchemeName }: {
@@ -12,28 +14,247 @@ declare const enrichNativeBuildAndroidScheme: ({ schemeConfig, hotUpdaterSchemeN
12
14
  }) => Promise<EnrichedNativeBuildAndroidScheme>;
13
15
  //#endregion
14
16
  //#region src/buildAndroid.d.ts
15
- declare const buildAndroid: ({ schemeConfig }: {
17
+ declare const buildAndroid: ({ schemeConfig, minBundleId, credentials }: {
16
18
  schemeConfig: EnrichedNativeBuildAndroidScheme;
19
+ /** The MIN_BUNDLE_ID the build compiles in. */
20
+ minBundleId?: string;
21
+ /** Resolves the scheme's `signing` keystore, when it signs with one. */
22
+ credentials?: Pick<CredentialResolver, "resolve">;
17
23
  }) => Promise<{
18
24
  buildDirectory: string;
19
25
  buildArtifactPath: string;
26
+ /** What the built artifact reports, or undefined without aapt2. */
27
+ builtApp?: {
28
+ appVersion: string | null;
29
+ /** undefined when the artifact's channel cannot be read exactly. */
30
+ channel?: string | null;
31
+ /** The manifest's `versionCode`. */
32
+ buildNumber: string | null;
33
+ };
20
34
  }>;
21
35
  //#endregion
22
- //#region src/types.d.ts
23
- interface AndroidNativeRunOptions extends NativeBuildOptions {
24
- device?: string | boolean;
25
- port?: string;
26
- mainActivity?: string;
27
- user?: string;
36
+ //#region src/uploadToPlay.d.ts
37
+ /**
38
+ * Google Play refused the upload: it already has a bundle or APK with the
39
+ * `.aab`'s version code, from this or another upload, and takes each version
40
+ * code once.
41
+ */
42
+ declare class PlayVersionCodeUsedError extends Error {
43
+ readonly name = "PlayVersionCodeUsedError";
44
+ constructor(options?: ErrorOptions);
28
45
  }
46
+ /**
47
+ * Whether Google Play's internal testing track already releases the
48
+ * `.aab`'s version code, as when a reused native build was uploaded
49
+ * before. It reads the track in an edit it then deletes, changing nothing.
50
+ */
51
+ declare const findPlayInternalRelease: ({ versionCode, packageName, serviceAccount: { json }, fetch }: {
52
+ versionCode: number;
53
+ /** The application ID the `.aab` was built with. */
54
+ packageName: string;
55
+ serviceAccount: Credentials["play-service-account"];
56
+ fetch?: typeof globalThis.fetch;
57
+ }) => Promise<boolean>;
58
+ /**
59
+ * Throws when the `.aab` is signed with the Android debug keystore, which
60
+ * Google Play refuses: a release build type left on `signingConfigs.debug`,
61
+ * as React Native's template ships it. It reads the signer with the JDK's
62
+ * `keytool`, which Gradle needs too; without one it checks nothing.
63
+ */
64
+ declare const assertPlaySigned: (aabPath: string) => Promise<void>;
65
+ interface UploadToPlayResult {
66
+ /** The version code Google Play read from the `.aab`. */
67
+ versionCode: number;
68
+ /** The release's status: `draft` on an app Play Console has not published. */
69
+ status: "completed" | "draft";
70
+ }
71
+ /**
72
+ * Uploads an `.aab` to Google Play's internal testing track with the Google
73
+ * Play Developer API: it opens an edit, uploads the bundle, releases its
74
+ * version code to the internal track, and commits the edit, which it
75
+ * deletes again when any step fails. The service account stays in memory.
76
+ */
77
+ declare const uploadToPlay: ({ aabPath, packageName, serviceAccount: { json }, fetch, commitRetryDelayMs }: {
78
+ aabPath: string;
79
+ /** The application ID the `.aab` was built with. */
80
+ packageName: string;
81
+ serviceAccount: Credentials["play-service-account"];
82
+ fetch?: typeof globalThis.fetch;
83
+ /** The first wait before committing again an edit Google is processing. */
84
+ commitRetryDelayMs?: number;
85
+ }) => Promise<UploadToPlayResult>;
86
+ /**
87
+ * The Play service account a scheme's `.aab` uploads with: the
88
+ * `play-service-account` item. It reads only the config, before the native
89
+ * projects are written, and throws for a scheme whose build Google Play
90
+ * would not take as a release: an `.apk`, which Play takes only as an `.aab`
91
+ * from new apps, or a debug variant, which Play refuses.
92
+ */
93
+ declare const resolvePlayUploadServiceAccount: ({ scheme, androidScheme }: {
94
+ /** The scheme's name. */
95
+ scheme: string;
96
+ androidScheme: NativeBuildAndroidScheme;
97
+ }) => CredentialRequest<"play-service-account">;
29
98
  //#endregion
30
- //#region src/runAndroid.d.ts
31
- declare const runAndroid: ({ schemeConfig, runOption }: {
32
- schemeConfig: EnrichedNativeBuildAndroidScheme;
33
- runOption: AndroidNativeRunOptions;
99
+ //#region src/utils/extractBuiltInBundle.d.ts
100
+ /**
101
+ * Copies the JavaScript bundle React Native's Gradle build packed into an
102
+ * `.apk` (`assets/index.android.bundle`) or an `.aab`
103
+ * (`base/assets/index.android.bundle`) to `outputPath`: the built-in bundle,
104
+ * byte for byte, which no rebuild reproduces. It reads only the archive's
105
+ * directory and that entry, streamed, so a large artifact stays on disk.
106
+ */
107
+ declare const extractBuiltInBundle: ({ artifactPath, outputPath }: {
108
+ artifactPath: string;
109
+ outputPath: string;
110
+ }) => Promise<void>;
111
+ //#endregion
112
+ //#region src/utils/readBuiltApp.d.ts
113
+ /**
114
+ * What the built `.apk` or `.aab` reports at runtime: the `versionName` and
115
+ * the `com.hotupdater.CHANNEL` meta-data Gradle merged into its manifest,
116
+ * from flavors, build types and `versionNameSuffix`. Without aapt2 it
117
+ * returns undefined, and the build reports the project's values.
118
+ */
119
+ declare const readBuiltApp: ({ artifactPath, androidProjectPath }: {
120
+ artifactPath: string;
121
+ androidProjectPath: string;
34
122
  }) => Promise<{
35
- buildDirectory: string;
36
- buildArtifactPath: string;
37
- }>;
123
+ appVersion: string | null;
124
+ /** undefined when the artifact's channel cannot be read exactly. */
125
+ channel?: string | null;
126
+ /** The manifest's `versionCode`. */
127
+ buildNumber: string | null;
128
+ } | undefined>;
129
+ /**
130
+ * The application ID of the built `.apk` or `.aab`, the package name Google
131
+ * Play files it under, with the suffixes flavors and build types add.
132
+ * undefined without aapt2.
133
+ */
134
+ declare const readBuiltPackageName: ({ artifactPath, androidProjectPath }: {
135
+ artifactPath: string;
136
+ androidProjectPath: string;
137
+ }) => Promise<string | undefined>;
138
+ /**
139
+ * The version code of the built `.apk` or `.aab`, which Google Play files
140
+ * its releases by. undefined without aapt2, or when the manifest has none.
141
+ */
142
+ declare const readBuiltVersionCode: ({ artifactPath, androidProjectPath }: {
143
+ artifactPath: string;
144
+ androidProjectPath: string;
145
+ }) => Promise<number | undefined>;
146
+ //#endregion
147
+ //#region src/google/types.d.ts
148
+ /** What stopped Hot Updater from issuing the Play service account key. */
149
+ type PlayServiceAccountErrorCode =
150
+ /** No OAuth client to sign in with, or Google refused it. */
151
+ "sign-in-not-configured" |
152
+ /** The browser sign-in was cancelled, refused, or timed out. */
153
+ "sign-in-cancelled" |
154
+ /** The account unticked a scope the setup needs on Google's consent screen. */
155
+ "scope-not-granted" |
156
+ /** The developer account ID names no Play Console account. */
157
+ "developer-not-found" |
158
+ /** The Google Account is no admin of the Play Console developer account. */
159
+ "not-play-admin" |
160
+ /** Google Play has no app with the package name in the developer account. */
161
+ "app-not-found" |
162
+ /** The Google Account may not create a Google Cloud project. */
163
+ "project-create-denied" |
164
+ /** The Google Account has no Google Cloud project quota left. */
165
+ "project-quota" |
166
+ /** The Google Account may not enable APIs or create service accounts in the project. */
167
+ "project-access-denied" |
168
+ /** Google is still enabling an API, or it is disabled in the OAuth client's project. */
169
+ "api-not-enabled" |
170
+ /** An organization policy (`iam.disableServiceAccountKeyCreation`) forbids keys. */
171
+ "key-creation-disabled";
172
+ /** A named failure of `issuePlayServiceAccount`, with what to do in its message. */
173
+ declare class PlayServiceAccountError extends Error {
174
+ readonly code: PlayServiceAccountErrorCode;
175
+ constructor(code: PlayServiceAccountErrorCode, message: string, options?: {
176
+ cause?: unknown;
177
+ });
178
+ }
179
+ /**
180
+ * A Google OAuth client of type "Desktop app". Google treats an installed
181
+ * app's client secret as public, so it ships with the client ID.
182
+ */
183
+ interface GoogleOAuthClient {
184
+ readonly clientId: string;
185
+ readonly clientSecret?: string;
186
+ }
187
+ /** The environment variables that replace Hot Updater's Google OAuth client. */
188
+ declare const GOOGLE_OAUTH_CLIENT_ENV_NAMES: {
189
+ readonly clientId: "HOT_UPDATER_GOOGLE_OAUTH_CLIENT_ID";
190
+ readonly clientSecret: "HOT_UPDATER_GOOGLE_OAUTH_CLIENT_SECRET";
191
+ };
192
+ /** The service account Hot Updater creates, `hot-updater-play@<project>.iam.gserviceaccount.com`. */
193
+ declare const PLAY_SERVICE_ACCOUNT_ID = "hot-updater-play";
194
+ /** Where a Play Console admin finds the developer account ID. */
195
+ declare const PLAY_CONSOLE_URL = "https://play.google.com/console";
196
+ //#endregion
197
+ //#region src/playServiceAccount.d.ts
198
+ /**
199
+ * Hot Updater's Google OAuth client, a "Desktop app" client the sign-in
200
+ * opens Google's consent screen for. Empty in a build that has none, where
201
+ * `HOT_UPDATER_GOOGLE_OAUTH_CLIENT_ID` and `_SECRET` name one.
202
+ */
203
+ declare const HOT_UPDATER_GOOGLE_OAUTH_CLIENT: GoogleOAuthClient;
204
+ /** A Google Cloud project the signed-in account can use. */
205
+ interface GoogleCloudProject {
206
+ readonly projectId: string;
207
+ readonly displayName?: string;
208
+ }
209
+ interface IssuePlayServiceAccountRequest {
210
+ /** The app's package name in Google Play, which the service account may release. */
211
+ readonly packageName: string;
212
+ /** The OAuth client to sign in with; Hot Updater's unless set. */
213
+ readonly oauthClient?: GoogleOAuthClient;
214
+ /** Sees the sign-in URL, to print it and open it in a browser. */
215
+ readonly onSignInUrl: (url: string) => Promise<void> | void;
216
+ /** Asks for the Play Console developer account ID, after the sign-in. */
217
+ readonly askDeveloperId: () => Promise<string>;
218
+ /**
219
+ * Sees the account's projects when there are any, and returns the one to
220
+ * create the service account in, or undefined to create a project.
221
+ */
222
+ readonly chooseProject: (projects: readonly GoogleCloudProject[]) => Promise<string | undefined>;
223
+ /** Reports each step, such as "Creating the service account". */
224
+ readonly onStep?: (message: string) => void;
225
+ }
226
+ /**
227
+ * A Play service account's JSON key, just created, with the access token
228
+ * of the sign-in it was created in. `revoke` deletes the key while the
229
+ * sign-in lasts, and `dispose` ends the sign-in.
230
+ */
231
+ interface IssuedPlayServiceAccount {
232
+ /** The JSON key file, as Google Cloud downloads it. */
233
+ readonly json: string;
234
+ /** The service account's email, the Play Console user it releases as. */
235
+ readonly email: string;
236
+ readonly projectId: string;
237
+ readonly developerId: string;
238
+ /** The key's ID, as Google Cloud lists it under the service account's keys. */
239
+ readonly keyId: string;
240
+ /** Deletes the key with the same sign-in; whether Google Cloud did. */
241
+ revoke(): Promise<boolean>;
242
+ /** Ends the sign-in: Google revokes its access token. */
243
+ dispose(): Promise<void>;
244
+ }
245
+ /**
246
+ * Signs in with Google and issues a service account key that releases the
247
+ * app to Google Play: the developer signs in on Google's own consent
248
+ * screen, in a browser, and the caller never sees the password. Nothing of
249
+ * the sign-in outlives `dispose`.
250
+ */
251
+ type IssuePlayServiceAccount = (request: IssuePlayServiceAccountRequest) => Promise<IssuedPlayServiceAccount>;
252
+ /**
253
+ * Hot Updater's issuer, the one place that picks how it is done: Google's
254
+ * OAuth for installed apps, then the Cloud Resource Manager, Service Usage,
255
+ * IAM, and Play Developer APIs. Another implementation of
256
+ * `IssuePlayServiceAccount` replaces it here without touching its callers.
257
+ */
258
+ declare const issuePlayServiceAccount: IssuePlayServiceAccount;
38
259
  //#endregion
39
- export { type AndroidNativeRunOptions, type EnrichedNativeBuildAndroidScheme, buildAndroid, enrichNativeBuildAndroidScheme, runAndroid };
260
+ export { type EnrichedNativeBuildAndroidScheme, GOOGLE_OAUTH_CLIENT_ENV_NAMES, type GoogleCloudProject, type GoogleOAuthClient, HOT_UPDATER_GOOGLE_OAUTH_CLIENT, type IssuePlayServiceAccount, type IssuePlayServiceAccountRequest, type IssuedPlayServiceAccount, PLAY_CONSOLE_URL, PLAY_SERVICE_ACCOUNT_ID, PlayServiceAccountError, type PlayServiceAccountErrorCode, PlayVersionCodeUsedError, type UploadToPlayResult, assertPlaySigned, buildAndroid, enrichNativeBuildAndroidScheme, extractBuiltInBundle, findPlayInternalRelease, issuePlayServiceAccount, readBuiltApp, readBuiltPackageName, readBuiltVersionCode, resolvePlayUploadServiceAccount, uploadToPlay };