shipthis 0.0.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/README.md +894 -0
- package/bin/alias.sh +10 -0
- package/bin/dev.cmd +3 -0
- package/bin/dev.js +7 -0
- package/bin/dev.tsc.js +15 -0
- package/bin/loader.js +20 -0
- package/bin/run.cmd +3 -0
- package/bin/run.js +5 -0
- package/bin/run.tsc.js +15 -0
- package/dist/App-DFPMSEZF.js +21 -0
- package/dist/AppleBundleIdDetails-CuhAbVEp.js +61 -0
- package/dist/NextSteps-CK9zHOCt.js +18 -0
- package/dist/RunWithSpinner-BVXNWGD3.js +27 -0
- package/dist/StatusTable-CxuX_R1D.js +38 -0
- package/dist/Table-CvM6pccN.js +101 -0
- package/dist/Title-BCQtayg6.js +6 -0
- package/dist/UserCredentialsTable-DHeRI4h6.js +76 -0
- package/dist/baseAppleCommand-BXUu-026.js +10 -0
- package/dist/baseGameCommand-xrD2WDDN.js +599 -0
- package/dist/cacheKeys-CShA-ZjE.js +9 -0
- package/dist/commands/apple/apiKey/create.js +88 -0
- package/dist/commands/apple/apiKey/export.js +66 -0
- package/dist/commands/apple/apiKey/import.js +70 -0
- package/dist/commands/apple/apiKey/status.js +108 -0
- package/dist/commands/apple/certificate/create.js +118 -0
- package/dist/commands/apple/certificate/export.js +66 -0
- package/dist/commands/apple/certificate/import.js +70 -0
- package/dist/commands/apple/certificate/status.js +116 -0
- package/dist/commands/apple/login.js +74 -0
- package/dist/commands/apple/status.js +50 -0
- package/dist/commands/dashboard.js +32 -0
- package/dist/commands/game/build/download.js +78 -0
- package/dist/commands/game/build/list.js +83 -0
- package/dist/commands/game/create.js +59 -0
- package/dist/commands/game/details.js +89 -0
- package/dist/commands/game/export.js +52 -0
- package/dist/commands/game/ios/app/addTester.js +111 -0
- package/dist/commands/game/ios/app/create.js +104 -0
- package/dist/commands/game/ios/app/status.js +52 -0
- package/dist/commands/game/ios/app/sync.js +81 -0
- package/dist/commands/game/ios/profile/create.js +110 -0
- package/dist/commands/game/ios/profile/export.js +68 -0
- package/dist/commands/game/ios/profile/import.js +77 -0
- package/dist/commands/game/ios/profile/status.js +183 -0
- package/dist/commands/game/ios/status.js +79 -0
- package/dist/commands/game/job/list.js +80 -0
- package/dist/commands/game/job/status.js +297 -0
- package/dist/commands/game/list.js +69 -0
- package/dist/commands/game/ship.js +67 -0
- package/dist/commands/game/status.js +76 -0
- package/dist/commands/game/wizard.js +124 -0
- package/dist/commands/login.js +63 -0
- package/dist/commands/status.js +80 -0
- package/dist/export-CujqsTR_.js +36 -0
- package/dist/git-DREGq-jc.js +32 -0
- package/dist/import-Q-KO61ll.js +38 -0
- package/dist/index-DKsVctbw.js +125 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/run.js +3 -0
- package/dist/upload-CUlWmNbS.js +60 -0
- package/dist/useAppleApp-BmwYu7qG.js +32 -0
- package/dist/useAppleBundleId-DCJnfNWr.js +64 -0
- package/dist/useBuilds-Dh_PWwCf.js +41 -0
- package/dist/useJob-CCkqCMvF.js +34 -0
- package/oclif.manifest.json +1510 -0
- package/package.json +167 -0
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { jsx } from 'react/jsx-runtime';
|
|
2
|
+
import { render } from 'ink';
|
|
3
|
+
import { Flags } from '@oclif/core';
|
|
4
|
+
import { A as App } from '../../../../App-DFPMSEZF.js';
|
|
5
|
+
import 'ink-spinner';
|
|
6
|
+
import { a as getInput, b as generatePackageName } from '../../../../index-DKsVctbw.js';
|
|
7
|
+
import 'react';
|
|
8
|
+
import { d as BaseGameCommand, l as getGodotAppleBundleIdentifier, m as BundleId, k as App$1 } from '../../../../baseGameCommand-xrD2WDDN.js';
|
|
9
|
+
import 'luxon';
|
|
10
|
+
import '@tanstack/react-query';
|
|
11
|
+
import 'axios';
|
|
12
|
+
import 'fs';
|
|
13
|
+
import 'socket.io-client';
|
|
14
|
+
import 'string-length';
|
|
15
|
+
import 'strip-ansi';
|
|
16
|
+
import { R as RunWithSpinner } from '../../../../RunWithSpinner-BVXNWGD3.js';
|
|
17
|
+
import 'path';
|
|
18
|
+
import '@expo/apple-utils/build/index.js';
|
|
19
|
+
import 'crypto';
|
|
20
|
+
import 'readline-sync';
|
|
21
|
+
import 'node:readline';
|
|
22
|
+
import 'isomorphic-git';
|
|
23
|
+
import 'ini';
|
|
24
|
+
import 'deepmerge';
|
|
25
|
+
|
|
26
|
+
class GameIosAppCreate extends BaseGameCommand {
|
|
27
|
+
static args = {};
|
|
28
|
+
static description = "Creates an App and BundleId in the Apple Developer Portal. If --gameId is not provided it will look in the current directory.";
|
|
29
|
+
static examples = ["<%= config.bin %> <%= command.id %>"];
|
|
30
|
+
static flags = {
|
|
31
|
+
quiet: Flags.boolean({ char: "q", description: "Avoid output except for interactions and errors" }),
|
|
32
|
+
gameId: Flags.string({ char: "g", description: "The ID of the game" }),
|
|
33
|
+
appName: Flags.string({ char: "n", description: "The name of the App in the Apple Developer Portal" }),
|
|
34
|
+
bundleId: Flags.string({ char: "b", description: "The BundleId in the Apple Developer Portal" }),
|
|
35
|
+
force: Flags.boolean({ char: "f" })
|
|
36
|
+
// not used but don't remove or the wizard breaks
|
|
37
|
+
};
|
|
38
|
+
async run() {
|
|
39
|
+
const game = await this.getGame();
|
|
40
|
+
const authState = await this.refreshAppleAuthState();
|
|
41
|
+
const ctx = authState.context;
|
|
42
|
+
const { flags } = this;
|
|
43
|
+
const { appName, bundleId } = flags;
|
|
44
|
+
const getAppName = async () => {
|
|
45
|
+
if (appName) return appName;
|
|
46
|
+
const suggestedName = game.name;
|
|
47
|
+
const question = `Please enter the name of the App in the Apple Developer Portal, or press enter to use ${suggestedName}: `;
|
|
48
|
+
const enteredName = await getInput(question);
|
|
49
|
+
return enteredName || suggestedName;
|
|
50
|
+
};
|
|
51
|
+
const getBundleIdentifier = async () => {
|
|
52
|
+
if (bundleId) return bundleId;
|
|
53
|
+
const generatedBundleId = generatePackageName(game.name);
|
|
54
|
+
const suggestedBundleId = game.details?.iosBundleId || getGodotAppleBundleIdentifier() || generatedBundleId || "com.example.game";
|
|
55
|
+
const question = `Please enter the BundleId in the Apple Developer Portal, or press enter to use ${suggestedBundleId}: `;
|
|
56
|
+
const enteredBundleId = await getInput(question);
|
|
57
|
+
return enteredBundleId || suggestedBundleId;
|
|
58
|
+
};
|
|
59
|
+
const name = await getAppName();
|
|
60
|
+
const iosBundleId = await getBundleIdentifier();
|
|
61
|
+
const createApp = async () => {
|
|
62
|
+
this.log(`Checking for ${iosBundleId} in apple portal...`);
|
|
63
|
+
let bundleId2 = await BundleId.findAsync(ctx, { identifier: iosBundleId });
|
|
64
|
+
if (!bundleId2) {
|
|
65
|
+
this.log(`Creating BundleId ${iosBundleId} in apple portal...`);
|
|
66
|
+
bundleId2 = await BundleId.createAsync(ctx, {
|
|
67
|
+
identifier: iosBundleId,
|
|
68
|
+
name
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
let app = await App$1.findAsync(ctx, {
|
|
72
|
+
bundleId: iosBundleId
|
|
73
|
+
});
|
|
74
|
+
if (!app) {
|
|
75
|
+
this.log(`Creating App ${iosBundleId} in apple portal...`);
|
|
76
|
+
app = await App$1.createAsync(ctx, {
|
|
77
|
+
bundleId: iosBundleId,
|
|
78
|
+
name,
|
|
79
|
+
primaryLocale: "en-US"
|
|
80
|
+
// TODO
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
await this.updateGame({ details: { ...game.details, iosBundleId } });
|
|
84
|
+
};
|
|
85
|
+
const handleComplete = async () => {
|
|
86
|
+
await this.config.runCommand("game:ios:app:sync", ["--gameId", game.id]);
|
|
87
|
+
process.exit(0);
|
|
88
|
+
};
|
|
89
|
+
if (this.flags.quiet) return await createApp();
|
|
90
|
+
render(
|
|
91
|
+
/* @__PURE__ */ jsx(App, { children: /* @__PURE__ */ jsx(
|
|
92
|
+
RunWithSpinner,
|
|
93
|
+
{
|
|
94
|
+
msgInProgress: "Creating App and BundleId in the Apple Developer Portal",
|
|
95
|
+
msgComplete: "App and BundleId created",
|
|
96
|
+
executeMethod: createApp,
|
|
97
|
+
onComplete: handleComplete
|
|
98
|
+
}
|
|
99
|
+
) })
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export { GameIosAppCreate as default };
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
2
|
+
import { render } from 'ink';
|
|
3
|
+
import { Flags } from '@oclif/core';
|
|
4
|
+
import { A as App } from '../../../../App-DFPMSEZF.js';
|
|
5
|
+
import 'ink-spinner';
|
|
6
|
+
import 'crypto';
|
|
7
|
+
import 'fs';
|
|
8
|
+
import 'readline-sync';
|
|
9
|
+
import 'node:readline';
|
|
10
|
+
import 'react';
|
|
11
|
+
import 'axios';
|
|
12
|
+
import '@tanstack/react-query';
|
|
13
|
+
import { d as BaseGameCommand } from '../../../../baseGameCommand-xrD2WDDN.js';
|
|
14
|
+
import 'luxon';
|
|
15
|
+
import 'socket.io-client';
|
|
16
|
+
import '@expo/apple-utils/build/index.js';
|
|
17
|
+
import 'isomorphic-git';
|
|
18
|
+
import { A as AppleAppDetails, a as AppleBundleIdDetails } from '../../../../AppleBundleIdDetails-CuhAbVEp.js';
|
|
19
|
+
import 'string-length';
|
|
20
|
+
import 'strip-ansi';
|
|
21
|
+
import { N as NextSteps } from '../../../../NextSteps-CK9zHOCt.js';
|
|
22
|
+
import 'path';
|
|
23
|
+
import 'ini';
|
|
24
|
+
import 'deepmerge';
|
|
25
|
+
import '../../../../useAppleApp-BmwYu7qG.js';
|
|
26
|
+
import '../../../../Title-BCQtayg6.js';
|
|
27
|
+
import '../../../../Table-CvM6pccN.js';
|
|
28
|
+
import '../../../../useAppleBundleId-DCJnfNWr.js';
|
|
29
|
+
|
|
30
|
+
class GameIosAppStatus extends BaseGameCommand {
|
|
31
|
+
static args = {};
|
|
32
|
+
static description = "Shows the Game iOS App status. If --gameId is not provided it will look in the current directory.";
|
|
33
|
+
static examples = ["<%= config.bin %> <%= command.id %>"];
|
|
34
|
+
static flags = {
|
|
35
|
+
gameId: Flags.string({ char: "g", description: "The ID of the game" })
|
|
36
|
+
};
|
|
37
|
+
async run() {
|
|
38
|
+
const game = await this.getGame();
|
|
39
|
+
const authState = await this.refreshAppleAuthState();
|
|
40
|
+
const ctx = authState.context;
|
|
41
|
+
const steps = [];
|
|
42
|
+
render(
|
|
43
|
+
/* @__PURE__ */ jsxs(App, { children: [
|
|
44
|
+
/* @__PURE__ */ jsx(AppleAppDetails, { iosBundleId: game.details?.iosBundleId, ctx }),
|
|
45
|
+
/* @__PURE__ */ jsx(AppleBundleIdDetails, { iosBundleId: game.details?.iosBundleId, ctx }),
|
|
46
|
+
/* @__PURE__ */ jsx(NextSteps, { steps })
|
|
47
|
+
] })
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export { GameIosAppStatus as default };
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { jsx } from 'react/jsx-runtime';
|
|
2
|
+
import { render } from 'ink';
|
|
3
|
+
import { Flags } from '@oclif/core';
|
|
4
|
+
import { A as App } from '../../../../App-DFPMSEZF.js';
|
|
5
|
+
import 'ink-spinner';
|
|
6
|
+
import 'crypto';
|
|
7
|
+
import 'fs';
|
|
8
|
+
import 'readline-sync';
|
|
9
|
+
import 'node:readline';
|
|
10
|
+
import 'react';
|
|
11
|
+
import 'axios';
|
|
12
|
+
import '@tanstack/react-query';
|
|
13
|
+
import { d as BaseGameCommand, h as CapabilityTypeOption } from '../../../../baseGameCommand-xrD2WDDN.js';
|
|
14
|
+
import 'luxon';
|
|
15
|
+
import 'socket.io-client';
|
|
16
|
+
import { f as fetchBundleId } from '../../../../useAppleBundleId-DCJnfNWr.js';
|
|
17
|
+
import 'isomorphic-git';
|
|
18
|
+
import 'string-length';
|
|
19
|
+
import 'strip-ansi';
|
|
20
|
+
import { R as RunWithSpinner } from '../../../../RunWithSpinner-BVXNWGD3.js';
|
|
21
|
+
import 'path';
|
|
22
|
+
import '@expo/apple-utils/build/index.js';
|
|
23
|
+
import 'ini';
|
|
24
|
+
import 'deepmerge';
|
|
25
|
+
|
|
26
|
+
class GameIosAppSync extends BaseGameCommand {
|
|
27
|
+
static args = {};
|
|
28
|
+
static description = 'Synchronies the Apple App "BundleId" with the capabilities from the local project. If --gameId is not provided it will look in the current directory.';
|
|
29
|
+
static examples = ["<%= config.bin %> <%= command.id %>"];
|
|
30
|
+
static flags = {
|
|
31
|
+
quiet: Flags.boolean({ char: "q", description: "Avoid output except for interactions and errors" }),
|
|
32
|
+
gameId: Flags.string({ char: "g", description: "The ID of the game" }),
|
|
33
|
+
force: Flags.boolean({ char: "f" })
|
|
34
|
+
// not used but don't remove or the wizard breaks
|
|
35
|
+
};
|
|
36
|
+
async run() {
|
|
37
|
+
const game = await this.getGame();
|
|
38
|
+
const authState = await this.refreshAppleAuthState();
|
|
39
|
+
const ctx = authState.context;
|
|
40
|
+
if (!game.details?.iosBundleId) return this.error("Please run `shipthis game ios app create` first");
|
|
41
|
+
const { iosBundleId } = game.details;
|
|
42
|
+
const syncCapabilities = async () => {
|
|
43
|
+
const bundleQueryResponse = await fetchBundleId({ ctx, iosBundleId });
|
|
44
|
+
const { bundleId, capabilities: existing, projectCapabilities } = bundleQueryResponse;
|
|
45
|
+
if (!bundleId) return this.error("BundleId not found");
|
|
46
|
+
if (!projectCapabilities) return this.error("Project capabilities not loaded");
|
|
47
|
+
const unRemovable = ["IN_APP_PURCHASE"];
|
|
48
|
+
const toRemove = existing.filter((c) => !projectCapabilities.includes(c) && !unRemovable.includes(c));
|
|
49
|
+
const toAdd = projectCapabilities.filter((c) => !existing.includes(c));
|
|
50
|
+
for (const capability of toRemove) {
|
|
51
|
+
await bundleId.updateBundleIdCapabilityAsync({
|
|
52
|
+
capabilityType: capability,
|
|
53
|
+
option: CapabilityTypeOption.OFF
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
for (const capability of toAdd) {
|
|
57
|
+
await bundleId.updateBundleIdCapabilityAsync({
|
|
58
|
+
capabilityType: capability,
|
|
59
|
+
option: CapabilityTypeOption.ON
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
const handleComplete = async () => {
|
|
64
|
+
await this.config.runCommand("game:ios:app:status", ["--gameId", game.id]);
|
|
65
|
+
};
|
|
66
|
+
if (this.flags.quiet) return await syncCapabilities();
|
|
67
|
+
render(
|
|
68
|
+
/* @__PURE__ */ jsx(App, { children: /* @__PURE__ */ jsx(
|
|
69
|
+
RunWithSpinner,
|
|
70
|
+
{
|
|
71
|
+
msgInProgress: "Syncing App Store BundleId capabilities",
|
|
72
|
+
msgComplete: "App Store BundleId capabilities synced",
|
|
73
|
+
executeMethod: syncCapabilities,
|
|
74
|
+
onComplete: handleComplete
|
|
75
|
+
}
|
|
76
|
+
) })
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export { GameIosAppSync as default };
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { jsx } from 'react/jsx-runtime';
|
|
2
|
+
import { render } from 'ink';
|
|
3
|
+
import { Flags } from '@oclif/core';
|
|
4
|
+
import axios from 'axios';
|
|
5
|
+
import { A as App } from '../../../../App-DFPMSEZF.js';
|
|
6
|
+
import 'ink-spinner';
|
|
7
|
+
import { d as BaseGameCommand, n as getProjectCredentials, P as Platform, C as CredentialsType, q as Certificate, r as CertificateType, g as getUserCredentials, s as Profile, t as ProfileType } from '../../../../baseGameCommand-xrD2WDDN.js';
|
|
8
|
+
import 'crypto';
|
|
9
|
+
import 'fs';
|
|
10
|
+
import 'readline-sync';
|
|
11
|
+
import 'node:readline';
|
|
12
|
+
import 'react';
|
|
13
|
+
import '@tanstack/react-query';
|
|
14
|
+
import 'luxon';
|
|
15
|
+
import 'socket.io-client';
|
|
16
|
+
import { f as fetchBundleId } from '../../../../useAppleBundleId-DCJnfNWr.js';
|
|
17
|
+
import 'isomorphic-git';
|
|
18
|
+
import 'string-length';
|
|
19
|
+
import 'strip-ansi';
|
|
20
|
+
import { R as RunWithSpinner } from '../../../../RunWithSpinner-BVXNWGD3.js';
|
|
21
|
+
import 'path';
|
|
22
|
+
import { a as uploadProjectCredentials } from '../../../../upload-CUlWmNbS.js';
|
|
23
|
+
import '@expo/apple-utils/build/index.js';
|
|
24
|
+
import 'ini';
|
|
25
|
+
import 'deepmerge';
|
|
26
|
+
|
|
27
|
+
class GameIosProfileCreate extends BaseGameCommand {
|
|
28
|
+
static args = {};
|
|
29
|
+
static description = "Creates a Mobile Provisioning Profile in the Apple Developer Portal. If --gameId is not provided it will look in the current directory.";
|
|
30
|
+
static examples = ["<%= config.bin %> <%= command.id %>"];
|
|
31
|
+
static flags = {
|
|
32
|
+
quiet: Flags.boolean({ char: "q", description: "Avoid output except for interactions and errors" }),
|
|
33
|
+
gameId: Flags.string({ char: "g", description: "The ID of the game" }),
|
|
34
|
+
force: Flags.boolean({ char: "f" })
|
|
35
|
+
};
|
|
36
|
+
async run() {
|
|
37
|
+
const game = await this.getGame();
|
|
38
|
+
const authState = await this.refreshAppleAuthState();
|
|
39
|
+
const ctx = authState.context;
|
|
40
|
+
const { flags } = this;
|
|
41
|
+
const { force } = flags;
|
|
42
|
+
const projectCredentials = await getProjectCredentials(game.id);
|
|
43
|
+
const projectAppleProfileCredentials = projectCredentials.filter(
|
|
44
|
+
(cred) => cred.platform == Platform.IOS && cred.type == CredentialsType.CERTIFICATE
|
|
45
|
+
);
|
|
46
|
+
if (projectAppleProfileCredentials.length !== 0 && !force) {
|
|
47
|
+
this.error("A Mobile Provisioning Profile already exists. Use --force to overwrite it.");
|
|
48
|
+
}
|
|
49
|
+
const createProfile = async () => {
|
|
50
|
+
if (!game.details?.iosBundleId) throw new Error("iosBundleId not found in game details");
|
|
51
|
+
const { iosBundleId } = game.details;
|
|
52
|
+
const { bundleId } = await fetchBundleId({ ctx, iosBundleId });
|
|
53
|
+
if (!bundleId) throw new Error("BundleId not found");
|
|
54
|
+
const appleCerts = await Certificate.getAsync(ctx, {
|
|
55
|
+
query: {
|
|
56
|
+
filter: {
|
|
57
|
+
certificateType: [CertificateType.DISTRIBUTION, CertificateType.IOS_DISTRIBUTION]
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
const userCerts = await getUserCredentials();
|
|
62
|
+
const validCert = userCerts.find(
|
|
63
|
+
(cred) => cred.platform === Platform.IOS && cred.type === CredentialsType.CERTIFICATE && cred.isActive == true
|
|
64
|
+
);
|
|
65
|
+
if (!validCert) throw new Error("No valid user certificates found");
|
|
66
|
+
const validAppleCert = appleCerts.find((cert) => cert.attributes.serialNumber === validCert.serialNumber);
|
|
67
|
+
if (!validAppleCert) throw new Error("No valid apple certificates found");
|
|
68
|
+
const profile = await Profile.createAsync(ctx, {
|
|
69
|
+
bundleId: bundleId.id,
|
|
70
|
+
certificates: [validAppleCert.id],
|
|
71
|
+
devices: [],
|
|
72
|
+
name: `ShipThis Profile for ${iosBundleId}`,
|
|
73
|
+
profileType: ProfileType.IOS_APP_STORE
|
|
74
|
+
});
|
|
75
|
+
const { data: contents } = await axios({
|
|
76
|
+
method: "get",
|
|
77
|
+
url: validCert.url
|
|
78
|
+
});
|
|
79
|
+
const userCertContent = contents;
|
|
80
|
+
const projectCertContent = {
|
|
81
|
+
...userCertContent,
|
|
82
|
+
mobileProvisionBase64: `${profile.attributes.profileContent}`
|
|
83
|
+
};
|
|
84
|
+
await uploadProjectCredentials(game.id, {
|
|
85
|
+
contents: projectCertContent,
|
|
86
|
+
platform: Platform.IOS,
|
|
87
|
+
type: CredentialsType.CERTIFICATE,
|
|
88
|
+
serialNumber: validCert.serialNumber,
|
|
89
|
+
identifier: iosBundleId
|
|
90
|
+
});
|
|
91
|
+
};
|
|
92
|
+
const handleComplete = async () => {
|
|
93
|
+
await this.config.runCommand("game:ios:profile:status", ["--gameId", game.id]);
|
|
94
|
+
};
|
|
95
|
+
if (this.flags.quiet) return await createProfile();
|
|
96
|
+
render(
|
|
97
|
+
/* @__PURE__ */ jsx(App, { children: /* @__PURE__ */ jsx(
|
|
98
|
+
RunWithSpinner,
|
|
99
|
+
{
|
|
100
|
+
msgInProgress: "Creating Mobile Provisioning Profile in the Apple Developer Portal",
|
|
101
|
+
msgComplete: "Mobile Provisioning Profile created",
|
|
102
|
+
executeMethod: createProfile,
|
|
103
|
+
onComplete: handleComplete
|
|
104
|
+
}
|
|
105
|
+
) })
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export { GameIosProfileCreate as default };
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { jsx } from 'react/jsx-runtime';
|
|
2
|
+
import { Args, Flags } from '@oclif/core';
|
|
3
|
+
import { render } from 'ink';
|
|
4
|
+
import * as fs from 'fs';
|
|
5
|
+
import 'path';
|
|
6
|
+
import '@expo/apple-utils/build/index.js';
|
|
7
|
+
import 'axios';
|
|
8
|
+
import { d as BaseGameCommand, n as getProjectCredentials, P as Platform, C as CredentialsType } from '../../../../baseGameCommand-xrD2WDDN.js';
|
|
9
|
+
import 'luxon';
|
|
10
|
+
import 'crypto';
|
|
11
|
+
import 'readline-sync';
|
|
12
|
+
import 'node:readline';
|
|
13
|
+
import 'react';
|
|
14
|
+
import '@tanstack/react-query';
|
|
15
|
+
import 'socket.io-client';
|
|
16
|
+
import 'isomorphic-git';
|
|
17
|
+
import { A as App } from '../../../../App-DFPMSEZF.js';
|
|
18
|
+
import 'ink-spinner';
|
|
19
|
+
import 'string-length';
|
|
20
|
+
import 'strip-ansi';
|
|
21
|
+
import { R as RunWithSpinner } from '../../../../RunWithSpinner-BVXNWGD3.js';
|
|
22
|
+
import { e as exportCredential } from '../../../../export-CujqsTR_.js';
|
|
23
|
+
import 'ini';
|
|
24
|
+
import 'deepmerge';
|
|
25
|
+
|
|
26
|
+
class GameIosProfileExport extends BaseGameCommand {
|
|
27
|
+
static args = {
|
|
28
|
+
file: Args.string({ description: "Name of the ZIP file to create", required: true })
|
|
29
|
+
};
|
|
30
|
+
static description = "Saves the current Mobile Provisioning Profile to a ZIP file";
|
|
31
|
+
static examples = ["<%= config.bin %> <%= command.id %> userProfile.zip"];
|
|
32
|
+
static flags = {
|
|
33
|
+
gameId: Flags.string({ char: "g", description: "The ID of the game" }),
|
|
34
|
+
force: Flags.boolean({ char: "f", description: "Overwrite the file if it already exists" })
|
|
35
|
+
};
|
|
36
|
+
async run() {
|
|
37
|
+
const { args, flags } = this;
|
|
38
|
+
const { file } = args;
|
|
39
|
+
const { force } = flags;
|
|
40
|
+
const game = await this.getGame();
|
|
41
|
+
const zipAlreadyExists = fs.existsSync(file);
|
|
42
|
+
if (zipAlreadyExists && !force) {
|
|
43
|
+
this.error(`The file ${file} already exists. Use --force to overwrite it.`);
|
|
44
|
+
}
|
|
45
|
+
const projectCredentials = await getProjectCredentials(game.id);
|
|
46
|
+
const userAppleProfileCredentials = projectCredentials.filter(
|
|
47
|
+
(cred) => cred.platform == Platform.IOS && cred.type == CredentialsType.CERTIFICATE
|
|
48
|
+
);
|
|
49
|
+
if (userAppleProfileCredentials.length === 0) {
|
|
50
|
+
this.error("No Mobile Provisioning Profile found which can be exported.");
|
|
51
|
+
}
|
|
52
|
+
const [profile] = userAppleProfileCredentials;
|
|
53
|
+
const handleComplete = async () => process.exit(0);
|
|
54
|
+
render(
|
|
55
|
+
/* @__PURE__ */ jsx(App, { children: /* @__PURE__ */ jsx(
|
|
56
|
+
RunWithSpinner,
|
|
57
|
+
{
|
|
58
|
+
msgInProgress: `Exporting Mobile Provisioning Profile to ${file}...`,
|
|
59
|
+
msgComplete: `Mobile Provisioning Profile exported to ${file}`,
|
|
60
|
+
executeMethod: () => exportCredential({ zipPath: file, credentialId: profile.id, projectId: game.id }),
|
|
61
|
+
onComplete: handleComplete
|
|
62
|
+
}
|
|
63
|
+
) })
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export { GameIosProfileExport as default };
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { jsx } from 'react/jsx-runtime';
|
|
2
|
+
import { Args, Flags } from '@oclif/core';
|
|
3
|
+
import { render } from 'ink';
|
|
4
|
+
import * as fs from 'fs';
|
|
5
|
+
import 'path';
|
|
6
|
+
import '@expo/apple-utils/build/index.js';
|
|
7
|
+
import 'axios';
|
|
8
|
+
import { d as BaseGameCommand, n as getProjectCredentials, P as Platform, C as CredentialsType } from '../../../../baseGameCommand-xrD2WDDN.js';
|
|
9
|
+
import 'luxon';
|
|
10
|
+
import 'crypto';
|
|
11
|
+
import 'readline-sync';
|
|
12
|
+
import 'node:readline';
|
|
13
|
+
import 'react';
|
|
14
|
+
import '@tanstack/react-query';
|
|
15
|
+
import 'socket.io-client';
|
|
16
|
+
import 'isomorphic-git';
|
|
17
|
+
import { A as App } from '../../../../App-DFPMSEZF.js';
|
|
18
|
+
import 'ink-spinner';
|
|
19
|
+
import 'string-length';
|
|
20
|
+
import 'strip-ansi';
|
|
21
|
+
import { R as RunWithSpinner } from '../../../../RunWithSpinner-BVXNWGD3.js';
|
|
22
|
+
import { i as importCredential } from '../../../../import-Q-KO61ll.js';
|
|
23
|
+
import 'ini';
|
|
24
|
+
import 'deepmerge';
|
|
25
|
+
|
|
26
|
+
class GameIosProfileImport extends BaseGameCommand {
|
|
27
|
+
static args = {
|
|
28
|
+
file: Args.string({
|
|
29
|
+
description: "Name of the ZIP file to import (must be in the same format as the export)",
|
|
30
|
+
required: true
|
|
31
|
+
})
|
|
32
|
+
};
|
|
33
|
+
static description = "Imports an Mobile Provisioning Profile to your ShipThis account";
|
|
34
|
+
static examples = ["<%= config.bin %> <%= command.id %> profile.zip"];
|
|
35
|
+
static flags = {
|
|
36
|
+
gameId: Flags.string({ char: "g", description: "The ID of the game" }),
|
|
37
|
+
force: Flags.boolean({ char: "f" })
|
|
38
|
+
};
|
|
39
|
+
async run() {
|
|
40
|
+
const { args, flags } = this;
|
|
41
|
+
const { file } = args;
|
|
42
|
+
const { force } = flags;
|
|
43
|
+
const game = await this.getGame();
|
|
44
|
+
const zipFound = fs.existsSync(file);
|
|
45
|
+
if (!zipFound) {
|
|
46
|
+
this.error(`The file ${file} does not exist.`);
|
|
47
|
+
}
|
|
48
|
+
const projectCredentials = await getProjectCredentials(game.id);
|
|
49
|
+
const projectAppleProfileCredentials = projectCredentials.filter(
|
|
50
|
+
(cred) => cred.platform == Platform.IOS && cred.type == CredentialsType.CERTIFICATE
|
|
51
|
+
);
|
|
52
|
+
if (projectAppleProfileCredentials.length !== 0 && !force) {
|
|
53
|
+
this.error("A Mobile Provisioning Profile already exists. Use --force to overwrite it.");
|
|
54
|
+
}
|
|
55
|
+
const handleComplete = async () => {
|
|
56
|
+
await this.config.runCommand(`game:ios:profile:status`, ["--noAppleAuth", "--gameId", game.id]);
|
|
57
|
+
};
|
|
58
|
+
render(
|
|
59
|
+
/* @__PURE__ */ jsx(App, { children: /* @__PURE__ */ jsx(
|
|
60
|
+
RunWithSpinner,
|
|
61
|
+
{
|
|
62
|
+
msgInProgress: `Importing Mobile Provisioning Profile from ${file}...`,
|
|
63
|
+
msgComplete: `Mobile Provisioning Profile imported from ${file}`,
|
|
64
|
+
executeMethod: () => importCredential({
|
|
65
|
+
zipPath: file,
|
|
66
|
+
type: CredentialsType.CERTIFICATE,
|
|
67
|
+
platform: Platform.IOS,
|
|
68
|
+
projectId: game.id
|
|
69
|
+
}),
|
|
70
|
+
onComplete: handleComplete
|
|
71
|
+
}
|
|
72
|
+
) })
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export { GameIosProfileImport as default };
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
2
|
+
import { Box, Text, render } from 'ink';
|
|
3
|
+
import { Flags } from '@oclif/core';
|
|
4
|
+
import { A as App } from '../../../../App-DFPMSEZF.js';
|
|
5
|
+
import Spinner from 'ink-spinner';
|
|
6
|
+
import { f as getShortDate, s as Profile, t as ProfileType, o as getAuthedHeaders, p as API_URL, I as castArrayObjectDates, P as Platform, C as CredentialsType, d as BaseGameCommand } from '../../../../baseGameCommand-xrD2WDDN.js';
|
|
7
|
+
import 'crypto';
|
|
8
|
+
import 'fs';
|
|
9
|
+
import 'readline-sync';
|
|
10
|
+
import 'node:readline';
|
|
11
|
+
import 'react';
|
|
12
|
+
import axios from 'axios';
|
|
13
|
+
import { useQuery } from '@tanstack/react-query';
|
|
14
|
+
import { DateTime } from 'luxon';
|
|
15
|
+
import 'socket.io-client';
|
|
16
|
+
import '@expo/apple-utils/build/index.js';
|
|
17
|
+
import 'isomorphic-git';
|
|
18
|
+
import { c as cacheKeys } from '../../../../cacheKeys-CShA-ZjE.js';
|
|
19
|
+
import { g as getShortUUID } from '../../../../index-DKsVctbw.js';
|
|
20
|
+
import { T as Title } from '../../../../Title-BCQtayg6.js';
|
|
21
|
+
import { T as Table } from '../../../../Table-CvM6pccN.js';
|
|
22
|
+
import 'string-length';
|
|
23
|
+
import 'strip-ansi';
|
|
24
|
+
import { N as NextSteps } from '../../../../NextSteps-CK9zHOCt.js';
|
|
25
|
+
import 'path';
|
|
26
|
+
import 'ini';
|
|
27
|
+
import 'deepmerge';
|
|
28
|
+
|
|
29
|
+
async function queryAppleProfiles({ ctx }) {
|
|
30
|
+
const appleProfiles = await Profile.getAsync(ctx, {
|
|
31
|
+
query: {
|
|
32
|
+
filter: {
|
|
33
|
+
profileType: [ProfileType.IOS_APP_STORE]
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
return appleProfiles;
|
|
38
|
+
}
|
|
39
|
+
const canAppleProfileBeUsed = (appleProfile, project, projectCredentials) => {
|
|
40
|
+
try {
|
|
41
|
+
if (!appleProfile.isValid) return false;
|
|
42
|
+
const profileBundleId = appleProfile.attributes.bundleId?.attributes.identifier;
|
|
43
|
+
const profileCertificateSerialNumber = appleProfile.attributes.certificates?.[0]?.attributes.serialNumber;
|
|
44
|
+
if (profileBundleId !== project.details?.iosBundleId) return false;
|
|
45
|
+
return projectCredentials.some(
|
|
46
|
+
(credential) => credential.isActive && credential.serialNumber === profileCertificateSerialNumber
|
|
47
|
+
);
|
|
48
|
+
} catch (e) {
|
|
49
|
+
console.log(e);
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
function getAppleProfileSummary(appleProfile, project, projectCredentials) {
|
|
54
|
+
return {
|
|
55
|
+
id: appleProfile.id,
|
|
56
|
+
name: appleProfile.attributes.name,
|
|
57
|
+
platform: appleProfile.attributes.platform,
|
|
58
|
+
expires: getShortDate(DateTime.fromISO(appleProfile.attributes.expirationDate)),
|
|
59
|
+
canBeUsed: canAppleProfileBeUsed(appleProfile, project, projectCredentials)
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
const useAppleProfiles = (props) => {
|
|
63
|
+
const queryResult = useQuery({
|
|
64
|
+
queryKey: ["appleProfiles"],
|
|
65
|
+
queryFn: () => queryAppleProfiles(props)
|
|
66
|
+
});
|
|
67
|
+
return queryResult;
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
async function queryProjectCredentials({
|
|
71
|
+
projectId,
|
|
72
|
+
...pageAndSortParams
|
|
73
|
+
}) {
|
|
74
|
+
try {
|
|
75
|
+
const headers = getAuthedHeaders();
|
|
76
|
+
const url = `${API_URL}/projects/${projectId}/credentials`;
|
|
77
|
+
const response = await axios.get(url, { headers, params: pageAndSortParams });
|
|
78
|
+
return {
|
|
79
|
+
...response.data,
|
|
80
|
+
data: castArrayObjectDates(response.data.data)
|
|
81
|
+
};
|
|
82
|
+
} catch (error) {
|
|
83
|
+
console.warn("queryProjectCredentials Error", error);
|
|
84
|
+
throw error;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
function getProjectCredentialSummary(credential) {
|
|
88
|
+
return {
|
|
89
|
+
id: getShortUUID(credential.id),
|
|
90
|
+
type: credential.type,
|
|
91
|
+
serial: credential.serialNumber,
|
|
92
|
+
isActive: credential.isActive,
|
|
93
|
+
createdAt: getShortDate(credential.createdAt)
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
const useProjectCredentials = ({
|
|
97
|
+
platform,
|
|
98
|
+
type,
|
|
99
|
+
...fetchProps
|
|
100
|
+
}) => {
|
|
101
|
+
const queryResult = useQuery({
|
|
102
|
+
queryKey: cacheKeys.projectCredentials(fetchProps),
|
|
103
|
+
queryFn: async () => queryProjectCredentials(fetchProps),
|
|
104
|
+
select: (data) => {
|
|
105
|
+
if (!(platform || type)) return data;
|
|
106
|
+
return {
|
|
107
|
+
...data,
|
|
108
|
+
data: data.data.filter((credential) => {
|
|
109
|
+
return (!platform || credential.platform === platform) && (!type || credential.type === type);
|
|
110
|
+
})
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
return queryResult;
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
const AppleProfilesTable = ({ ctx, project, ...boxProps }) => {
|
|
118
|
+
const { data: credentialsResponse } = useProjectCredentials({
|
|
119
|
+
projectId: project.id,
|
|
120
|
+
platform: Platform.IOS,
|
|
121
|
+
type: CredentialsType.CERTIFICATE
|
|
122
|
+
});
|
|
123
|
+
const { data: certs, isLoading } = useAppleProfiles({ ctx });
|
|
124
|
+
const hasUsable = certs && credentialsResponse && certs.some((cert) => canAppleProfileBeUsed(cert, project, credentialsResponse.data));
|
|
125
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginBottom: 1, ...boxProps, children: [
|
|
126
|
+
/* @__PURE__ */ jsx(Title, { children: "Mobile Provisioning Profiles in your Apple account" }),
|
|
127
|
+
isLoading && /* @__PURE__ */ jsx(Spinner, { type: "dots" }),
|
|
128
|
+
certs && credentialsResponse && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
129
|
+
/* @__PURE__ */ jsxs(Box, { marginLeft: 2, marginBottom: 1, flexDirection: "column", children: [
|
|
130
|
+
/* @__PURE__ */ jsx(Text, { children: `You have ${certs.length} Mobile Provisioning Profiles in your Apple account` }),
|
|
131
|
+
/* @__PURE__ */ jsx(Text, { children: `${hasUsable ? "One" : "None"} of these can be used by ShipThis` })
|
|
132
|
+
] }),
|
|
133
|
+
/* @__PURE__ */ jsx(Table, { data: certs.map((cert) => getAppleProfileSummary(cert, project, credentialsResponse.data)) }),
|
|
134
|
+
!hasUsable && /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(Text, { bold: true, children: "You do not have a usable Mobile Provisioning Profile. To ship an iOS game, you will need a usable Mobile Provisioning Profile." }) })
|
|
135
|
+
] })
|
|
136
|
+
] });
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
const ProjectCredentialsTable = ({ credentialTypeName, queryProps, ...boxProps }) => {
|
|
140
|
+
const { isLoading, data } = useProjectCredentials(queryProps);
|
|
141
|
+
const hasActive = data?.data.some((credential) => credential.isActive);
|
|
142
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginBottom: 1, ...boxProps, children: [
|
|
143
|
+
/* @__PURE__ */ jsx(Title, { children: `${credentialTypeName}s in your ShipThis account` }),
|
|
144
|
+
/* @__PURE__ */ jsx(Box, { marginLeft: 2, marginBottom: 1, flexDirection: "column", children: /* @__PURE__ */ jsx(Text, { children: hasActive ? `You have an active ${credentialTypeName} in your ShipThis account.` : `You DO NOT have an active ${credentialTypeName} which ShipThis can use.` }) }),
|
|
145
|
+
isLoading && /* @__PURE__ */ jsx(Spinner, { type: "dots" }),
|
|
146
|
+
data && /* @__PURE__ */ jsx(Table, { data: data.data.map(getProjectCredentialSummary) })
|
|
147
|
+
] });
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
class GameIosProfileStatus extends BaseGameCommand {
|
|
151
|
+
static args = {};
|
|
152
|
+
static description = "Shows the Game iOS Mobile Provisioning Profile Status. If --gameId is not provided it will look in the current directory.";
|
|
153
|
+
static examples = ["<%= config.bin %> <%= command.id %>"];
|
|
154
|
+
static flags = {
|
|
155
|
+
gameId: Flags.string({ char: "g", description: "The ID of the game" }),
|
|
156
|
+
noAppleAuth: Flags.boolean({ char: "f" })
|
|
157
|
+
};
|
|
158
|
+
async run() {
|
|
159
|
+
const { flags } = this;
|
|
160
|
+
const showApple = !flags.noAppleAuth;
|
|
161
|
+
const game = await this.getGame();
|
|
162
|
+
let ctx = null;
|
|
163
|
+
if (showApple) {
|
|
164
|
+
const authState = await this.refreshAppleAuthState();
|
|
165
|
+
ctx = authState.context;
|
|
166
|
+
}
|
|
167
|
+
render(
|
|
168
|
+
/* @__PURE__ */ jsxs(App, { children: [
|
|
169
|
+
/* @__PURE__ */ jsx(
|
|
170
|
+
ProjectCredentialsTable,
|
|
171
|
+
{
|
|
172
|
+
credentialTypeName: "Mobile Provisioning Profile",
|
|
173
|
+
queryProps: { platform: Platform.IOS, type: CredentialsType.CERTIFICATE, projectId: game.id }
|
|
174
|
+
}
|
|
175
|
+
),
|
|
176
|
+
showApple && /* @__PURE__ */ jsx(AppleProfilesTable, { ctx, project: game }),
|
|
177
|
+
/* @__PURE__ */ jsx(NextSteps, { steps: [] })
|
|
178
|
+
] })
|
|
179
|
+
);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
export { GameIosProfileStatus as default };
|