@capgo/cli 7.87.0 → 7.88.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.
- package/README.md +9 -0
- package/dist/index.js +623 -396
- package/dist/package.json +12 -1
- package/dist/src/build/onboarding/apple-api.d.ts +106 -0
- package/dist/src/build/onboarding/command.d.ts +1 -0
- package/dist/src/build/onboarding/csr.d.ts +33 -0
- package/dist/src/build/onboarding/file-picker.d.ts +10 -0
- package/dist/src/build/onboarding/progress.d.ts +19 -0
- package/dist/src/build/onboarding/types.d.ts +37 -0
- package/dist/src/build/onboarding/ui/app.d.ts +10 -0
- package/dist/src/build/onboarding/ui/components.d.ts +25 -0
- package/dist/src/build/request.d.ts +16 -1
- package/dist/src/sdk.js +229 -229
- package/package.json +12 -1
- package/skills/native-builds/SKILL.md +60 -1
package/dist/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@capgo/cli",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "7.
|
|
4
|
+
"version": "7.88.0",
|
|
5
5
|
"description": "A CLI to upload to capgo servers",
|
|
6
6
|
"author": "Martin martin@capgo.app",
|
|
7
7
|
"license": "Apache 2.0",
|
|
@@ -91,8 +91,11 @@
|
|
|
91
91
|
"@supabase/supabase-js": "^2.79.0",
|
|
92
92
|
"@tanstack/intent": "^0.0.23",
|
|
93
93
|
"@types/adm-zip": "^0.5.7",
|
|
94
|
+
"@types/jsonwebtoken": "^9.0.10",
|
|
94
95
|
"@types/node": "^25.0.0",
|
|
96
|
+
"@types/node-forge": "^1.3.14",
|
|
95
97
|
"@types/prettyjson": "^0.0.33",
|
|
98
|
+
"@types/react": "^18.3.28",
|
|
96
99
|
"@types/tmp": "^0.2.6",
|
|
97
100
|
"@vercel/ncc": "^0.38.4",
|
|
98
101
|
"adm-zip": "^0.5.16",
|
|
@@ -111,5 +114,13 @@
|
|
|
111
114
|
"typescript": "^5.9.3",
|
|
112
115
|
"ws": "^8.18.3",
|
|
113
116
|
"zod": "^4.3.6"
|
|
117
|
+
},
|
|
118
|
+
"dependencies": {
|
|
119
|
+
"@inkjs/ui": "^2.0.0",
|
|
120
|
+
"ink": "^5.2.1",
|
|
121
|
+
"ink-spinner": "^5.0.0",
|
|
122
|
+
"jsonwebtoken": "^9.0.3",
|
|
123
|
+
"node-forge": "^1.3.3",
|
|
124
|
+
"react": "^18.3.1"
|
|
114
125
|
}
|
|
115
126
|
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generate a JWT for App Store Connect API authentication.
|
|
3
|
+
* Uses ES256 algorithm with the .p8 private key.
|
|
4
|
+
*/
|
|
5
|
+
export declare function generateJwt(keyId: string, issuerId: string, p8Content: string): string;
|
|
6
|
+
/**
|
|
7
|
+
* Verify the API key works and try to detect the team ID from existing certificates.
|
|
8
|
+
* Throws on 401/403 with a user-friendly message.
|
|
9
|
+
*/
|
|
10
|
+
export declare function verifyApiKey(token: string): Promise<{
|
|
11
|
+
valid: true;
|
|
12
|
+
teamId: string;
|
|
13
|
+
}>;
|
|
14
|
+
/**
|
|
15
|
+
* List all iOS distribution certificates.
|
|
16
|
+
*/
|
|
17
|
+
export declare function listDistributionCerts(token: string): Promise<Array<{
|
|
18
|
+
id: string;
|
|
19
|
+
name: string;
|
|
20
|
+
serialNumber: string;
|
|
21
|
+
expirationDate: string;
|
|
22
|
+
}>>;
|
|
23
|
+
/**
|
|
24
|
+
* Revoke (delete) a certificate by ID.
|
|
25
|
+
*/
|
|
26
|
+
export declare function revokeCertificate(token: string, certId: string): Promise<void>;
|
|
27
|
+
/**
|
|
28
|
+
* Error thrown when certificate limit is reached.
|
|
29
|
+
* Contains the existing certificates so the UI can ask the user which to revoke.
|
|
30
|
+
*/
|
|
31
|
+
export declare class CertificateLimitError extends Error {
|
|
32
|
+
readonly certificates: Array<{
|
|
33
|
+
id: string;
|
|
34
|
+
name: string;
|
|
35
|
+
serialNumber: string;
|
|
36
|
+
expirationDate: string;
|
|
37
|
+
}>;
|
|
38
|
+
constructor(certificates: Array<{
|
|
39
|
+
id: string;
|
|
40
|
+
name: string;
|
|
41
|
+
serialNumber: string;
|
|
42
|
+
expirationDate: string;
|
|
43
|
+
}>);
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Create a distribution certificate using a CSR.
|
|
47
|
+
* Returns the certificate ID, base64 DER content, expiration date, and team ID.
|
|
48
|
+
*
|
|
49
|
+
* Throws CertificateLimitError if the limit is reached, so the UI can ask
|
|
50
|
+
* the user which certificate to revoke.
|
|
51
|
+
*/
|
|
52
|
+
export declare function createCertificate(token: string, csrPem: string): Promise<{
|
|
53
|
+
certificateId: string;
|
|
54
|
+
certificateContent: string;
|
|
55
|
+
expirationDate: string;
|
|
56
|
+
teamId: string;
|
|
57
|
+
}>;
|
|
58
|
+
/**
|
|
59
|
+
* Find an existing bundle ID or register a new one.
|
|
60
|
+
* Returns the Apple resource ID needed for profile creation.
|
|
61
|
+
*/
|
|
62
|
+
export declare function ensureBundleId(token: string, identifier: string): Promise<{
|
|
63
|
+
bundleIdResourceId: string;
|
|
64
|
+
}>;
|
|
65
|
+
/**
|
|
66
|
+
* Get the profile name we use for a given appId.
|
|
67
|
+
*/
|
|
68
|
+
export declare function getCapgoProfileName(appId: string): string;
|
|
69
|
+
/**
|
|
70
|
+
* Find existing provisioning profiles matching our naming convention.
|
|
71
|
+
* Only returns profiles we created (named "Capgo <appId> AppStore").
|
|
72
|
+
*/
|
|
73
|
+
export declare function findCapgoProfiles(token: string, appId: string): Promise<Array<{
|
|
74
|
+
id: string;
|
|
75
|
+
name: string;
|
|
76
|
+
profileType: string;
|
|
77
|
+
}>>;
|
|
78
|
+
/**
|
|
79
|
+
* Delete a provisioning profile by ID.
|
|
80
|
+
*/
|
|
81
|
+
export declare function deleteProfile(token: string, profileId: string): Promise<void>;
|
|
82
|
+
/**
|
|
83
|
+
* Create an App Store provisioning profile linking a certificate and bundle ID.
|
|
84
|
+
* Returns the base64 mobileprovision content.
|
|
85
|
+
*
|
|
86
|
+
* Throws a DuplicateProfileError if duplicate profiles exist, so the caller
|
|
87
|
+
* can ask the user whether to delete them and retry.
|
|
88
|
+
*/
|
|
89
|
+
export declare class DuplicateProfileError extends Error {
|
|
90
|
+
readonly profiles: Array<{
|
|
91
|
+
id: string;
|
|
92
|
+
name: string;
|
|
93
|
+
profileType: string;
|
|
94
|
+
}>;
|
|
95
|
+
constructor(profiles: Array<{
|
|
96
|
+
id: string;
|
|
97
|
+
name: string;
|
|
98
|
+
profileType: string;
|
|
99
|
+
}>);
|
|
100
|
+
}
|
|
101
|
+
export declare function createProfile(token: string, bundleIdResourceId: string, certificateId: string, appId: string): Promise<{
|
|
102
|
+
profileId: string;
|
|
103
|
+
profileName: string;
|
|
104
|
+
profileContent: string;
|
|
105
|
+
expirationDate: string;
|
|
106
|
+
}>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function onboardingCommand(): Promise<void>;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
export interface CsrResult {
|
|
2
|
+
csrPem: string;
|
|
3
|
+
privateKeyPem: string;
|
|
4
|
+
}
|
|
5
|
+
export interface P12Result {
|
|
6
|
+
p12Base64: string;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Generate a 2048-bit RSA key pair and a Certificate Signing Request.
|
|
10
|
+
* The CSR is what Apple needs to create a distribution certificate.
|
|
11
|
+
* The private key must be kept to later create the .p12 file.
|
|
12
|
+
*/
|
|
13
|
+
export declare function generateCsr(): CsrResult;
|
|
14
|
+
/**
|
|
15
|
+
* Create a PKCS#12 (.p12) file from Apple's certificate response and the private key.
|
|
16
|
+
*
|
|
17
|
+
* @param certificateContentBase64 - The `certificateContent` field from Apple's
|
|
18
|
+
* POST /v1/certificates response (base64-encoded DER certificate)
|
|
19
|
+
* @param privateKeyPem - The PEM-encoded private key from generateCsr()
|
|
20
|
+
* @param password - Optional password for the .p12 file (defaults to DEFAULT_P12_PASSWORD)
|
|
21
|
+
*/
|
|
22
|
+
/**
|
|
23
|
+
* Extract the Apple team ID from a certificate's subject OU field.
|
|
24
|
+
* More reliable than parsing the certificate name string.
|
|
25
|
+
*/
|
|
26
|
+
export declare function extractTeamIdFromCert(certificateContentBase64: string): string;
|
|
27
|
+
/**
|
|
28
|
+
* Default P12 password. node-forge P12 with empty password is incompatible
|
|
29
|
+
* with macOS `security import` (MAC verification fails). Using a known
|
|
30
|
+
* non-empty password avoids this issue.
|
|
31
|
+
*/
|
|
32
|
+
export declare const DEFAULT_P12_PASSWORD = "capgo";
|
|
33
|
+
export declare function createP12(certificateContentBase64: string, privateKeyPem: string, password?: string): P12Result;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Returns true if we're on macOS and can use the native file picker.
|
|
3
|
+
*/
|
|
4
|
+
export declare function canUseFilePicker(): boolean;
|
|
5
|
+
/**
|
|
6
|
+
* Open the macOS native file picker dialog filtered to .p8 files.
|
|
7
|
+
* Returns the selected file path, or null if the user cancelled.
|
|
8
|
+
* Non-blocking — uses async execFile so Ink spinners keep animating.
|
|
9
|
+
*/
|
|
10
|
+
export declare function openFilePicker(): Promise<string | null>;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { OnboardingProgress, OnboardingStep } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Load onboarding progress for an app. Returns null if no progress file exists.
|
|
4
|
+
*/
|
|
5
|
+
export declare function loadProgress(appId: string, baseDir?: string): Promise<OnboardingProgress | null>;
|
|
6
|
+
/**
|
|
7
|
+
* Save onboarding progress. Creates the onboarding directory if needed.
|
|
8
|
+
* File is written with mode 0o600, directory with 0o700.
|
|
9
|
+
*/
|
|
10
|
+
export declare function saveProgress(appId: string, progress: OnboardingProgress, baseDir?: string): Promise<void>;
|
|
11
|
+
/**
|
|
12
|
+
* Delete the progress file for an app (called on successful completion).
|
|
13
|
+
*/
|
|
14
|
+
export declare function deleteProgress(appId: string, baseDir?: string): Promise<void>;
|
|
15
|
+
/**
|
|
16
|
+
* Determine the first incomplete step based on saved progress.
|
|
17
|
+
* Returns the step to resume from.
|
|
18
|
+
*/
|
|
19
|
+
export declare function getResumeStep(progress: OnboardingProgress | null): OnboardingStep;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
export type Platform = 'ios' | 'android';
|
|
2
|
+
export type OnboardingStep = 'welcome' | 'platform-select' | 'credentials-exist' | 'backing-up' | 'api-key-instructions' | 'p8-method-select' | 'input-p8-path' | 'input-key-id' | 'input-issuer-id' | 'verifying-key' | 'creating-certificate' | 'cert-limit-prompt' | 'revoking-certificate' | 'creating-profile' | 'duplicate-profile-prompt' | 'deleting-duplicate-profiles' | 'saving-credentials' | 'ask-build' | 'requesting-build' | 'build-complete' | 'no-platform' | 'error';
|
|
3
|
+
export interface ApiKeyData {
|
|
4
|
+
keyId: string;
|
|
5
|
+
issuerId: string;
|
|
6
|
+
}
|
|
7
|
+
export interface CertificateData {
|
|
8
|
+
certificateId: string;
|
|
9
|
+
expirationDate: string;
|
|
10
|
+
teamId: string;
|
|
11
|
+
p12Base64: string;
|
|
12
|
+
}
|
|
13
|
+
export interface ProfileData {
|
|
14
|
+
profileId: string;
|
|
15
|
+
profileName: string;
|
|
16
|
+
profileBase64: string;
|
|
17
|
+
}
|
|
18
|
+
export interface OnboardingProgress {
|
|
19
|
+
platform: Platform;
|
|
20
|
+
appId: string;
|
|
21
|
+
startedAt: string;
|
|
22
|
+
/** Path to the .p8 file on disk (content is NOT stored, only the path) */
|
|
23
|
+
p8Path?: string;
|
|
24
|
+
/** Partial input — saved incrementally so resume works mid-flow */
|
|
25
|
+
keyId?: string;
|
|
26
|
+
issuerId?: string;
|
|
27
|
+
completedSteps: {
|
|
28
|
+
apiKeyVerified?: ApiKeyData;
|
|
29
|
+
certificateCreated?: CertificateData;
|
|
30
|
+
profileCreated?: ProfileData;
|
|
31
|
+
};
|
|
32
|
+
/** Temporary — wiped after .p12 creation */
|
|
33
|
+
_privateKeyPem?: string;
|
|
34
|
+
}
|
|
35
|
+
/** Maps each step to a progress percentage (0-100) */
|
|
36
|
+
export declare const STEP_PROGRESS: Record<OnboardingStep, number>;
|
|
37
|
+
export declare function getPhaseLabel(step: OnboardingStep): string;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { FC } from 'react';
|
|
2
|
+
import type { OnboardingProgress } from '../types.js';
|
|
3
|
+
interface AppProps {
|
|
4
|
+
appId: string;
|
|
5
|
+
initialProgress: OnboardingProgress | null;
|
|
6
|
+
/** Resolved iOS directory from capacitor.config (defaults to 'ios') */
|
|
7
|
+
iosDir: string;
|
|
8
|
+
}
|
|
9
|
+
declare const OnboardingApp: FC<AppProps>;
|
|
10
|
+
export default OnboardingApp;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { FC } from 'react';
|
|
2
|
+
export declare const Divider: FC<{
|
|
3
|
+
width?: number;
|
|
4
|
+
}>;
|
|
5
|
+
export declare const SpinnerLine: FC<{
|
|
6
|
+
text: string;
|
|
7
|
+
}>;
|
|
8
|
+
export declare const SuccessLine: FC<{
|
|
9
|
+
text: string;
|
|
10
|
+
detail?: string;
|
|
11
|
+
}>;
|
|
12
|
+
export declare const ErrorLine: FC<{
|
|
13
|
+
text: string;
|
|
14
|
+
}>;
|
|
15
|
+
/**
|
|
16
|
+
* Custom TextInput that filters out specific characters (e.g. '=').
|
|
17
|
+
* @inkjs/ui's TextInput is uncontrolled and can't filter keystrokes,
|
|
18
|
+
* so we build a minimal one with Ink's useInput.
|
|
19
|
+
*/
|
|
20
|
+
export declare const FilteredTextInput: FC<{
|
|
21
|
+
placeholder?: string;
|
|
22
|
+
filter?: string;
|
|
23
|
+
onSubmit: (value: string) => void;
|
|
24
|
+
}>;
|
|
25
|
+
export declare const Header: FC;
|
|
@@ -26,6 +26,21 @@
|
|
|
26
26
|
* - Use `build credentials clear` to remove saved credentials
|
|
27
27
|
*/
|
|
28
28
|
import type { BuildOptionsPayload, BuildRequestOptions, BuildRequestResult } from '../schemas/build';
|
|
29
|
+
/**
|
|
30
|
+
* Callback interface for build logging.
|
|
31
|
+
* Allows callers (like the onboarding UI) to capture log output
|
|
32
|
+
* without stdout/stderr interception hacks.
|
|
33
|
+
*/
|
|
34
|
+
export interface BuildLogger {
|
|
35
|
+
info: (msg: string) => void;
|
|
36
|
+
error: (msg: string) => void;
|
|
37
|
+
warn: (msg: string) => void;
|
|
38
|
+
success: (msg: string) => void;
|
|
39
|
+
/** Called with build log lines streamed from the builder */
|
|
40
|
+
buildLog: (msg: string) => void;
|
|
41
|
+
/** Called with upload progress percentage (0-100) */
|
|
42
|
+
uploadProgress: (percent: number) => void;
|
|
43
|
+
}
|
|
29
44
|
export type { BuildCredentials, BuildRequestOptions, BuildRequestResponse, BuildRequestResult } from '../schemas/build';
|
|
30
45
|
/**
|
|
31
46
|
* Extract native node_modules roots that contain platform folders.
|
|
@@ -74,5 +89,5 @@ export declare function splitPayload(mergedCredentials: Record<string, string |
|
|
|
74
89
|
buildOptions: BuildOptionsPayload;
|
|
75
90
|
buildCredentials: Record<string, string>;
|
|
76
91
|
};
|
|
77
|
-
export declare function requestBuildInternal(appId: string, options: BuildRequestOptions, silent?: boolean): Promise<BuildRequestResult>;
|
|
92
|
+
export declare function requestBuildInternal(appId: string, options: BuildRequestOptions, silent?: boolean, logger?: BuildLogger): Promise<BuildRequestResult>;
|
|
78
93
|
export declare function requestBuildCommand(appId: string, options: BuildRequestOptions): Promise<void>;
|