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.
Files changed (67) hide show
  1. package/README.md +894 -0
  2. package/bin/alias.sh +10 -0
  3. package/bin/dev.cmd +3 -0
  4. package/bin/dev.js +7 -0
  5. package/bin/dev.tsc.js +15 -0
  6. package/bin/loader.js +20 -0
  7. package/bin/run.cmd +3 -0
  8. package/bin/run.js +5 -0
  9. package/bin/run.tsc.js +15 -0
  10. package/dist/App-DFPMSEZF.js +21 -0
  11. package/dist/AppleBundleIdDetails-CuhAbVEp.js +61 -0
  12. package/dist/NextSteps-CK9zHOCt.js +18 -0
  13. package/dist/RunWithSpinner-BVXNWGD3.js +27 -0
  14. package/dist/StatusTable-CxuX_R1D.js +38 -0
  15. package/dist/Table-CvM6pccN.js +101 -0
  16. package/dist/Title-BCQtayg6.js +6 -0
  17. package/dist/UserCredentialsTable-DHeRI4h6.js +76 -0
  18. package/dist/baseAppleCommand-BXUu-026.js +10 -0
  19. package/dist/baseGameCommand-xrD2WDDN.js +599 -0
  20. package/dist/cacheKeys-CShA-ZjE.js +9 -0
  21. package/dist/commands/apple/apiKey/create.js +88 -0
  22. package/dist/commands/apple/apiKey/export.js +66 -0
  23. package/dist/commands/apple/apiKey/import.js +70 -0
  24. package/dist/commands/apple/apiKey/status.js +108 -0
  25. package/dist/commands/apple/certificate/create.js +118 -0
  26. package/dist/commands/apple/certificate/export.js +66 -0
  27. package/dist/commands/apple/certificate/import.js +70 -0
  28. package/dist/commands/apple/certificate/status.js +116 -0
  29. package/dist/commands/apple/login.js +74 -0
  30. package/dist/commands/apple/status.js +50 -0
  31. package/dist/commands/dashboard.js +32 -0
  32. package/dist/commands/game/build/download.js +78 -0
  33. package/dist/commands/game/build/list.js +83 -0
  34. package/dist/commands/game/create.js +59 -0
  35. package/dist/commands/game/details.js +89 -0
  36. package/dist/commands/game/export.js +52 -0
  37. package/dist/commands/game/ios/app/addTester.js +111 -0
  38. package/dist/commands/game/ios/app/create.js +104 -0
  39. package/dist/commands/game/ios/app/status.js +52 -0
  40. package/dist/commands/game/ios/app/sync.js +81 -0
  41. package/dist/commands/game/ios/profile/create.js +110 -0
  42. package/dist/commands/game/ios/profile/export.js +68 -0
  43. package/dist/commands/game/ios/profile/import.js +77 -0
  44. package/dist/commands/game/ios/profile/status.js +183 -0
  45. package/dist/commands/game/ios/status.js +79 -0
  46. package/dist/commands/game/job/list.js +80 -0
  47. package/dist/commands/game/job/status.js +297 -0
  48. package/dist/commands/game/list.js +69 -0
  49. package/dist/commands/game/ship.js +67 -0
  50. package/dist/commands/game/status.js +76 -0
  51. package/dist/commands/game/wizard.js +124 -0
  52. package/dist/commands/login.js +63 -0
  53. package/dist/commands/status.js +80 -0
  54. package/dist/export-CujqsTR_.js +36 -0
  55. package/dist/git-DREGq-jc.js +32 -0
  56. package/dist/import-Q-KO61ll.js +38 -0
  57. package/dist/index-DKsVctbw.js +125 -0
  58. package/dist/index.d.ts +1 -0
  59. package/dist/index.js +1 -0
  60. package/dist/run.js +3 -0
  61. package/dist/upload-CUlWmNbS.js +60 -0
  62. package/dist/useAppleApp-BmwYu7qG.js +32 -0
  63. package/dist/useAppleBundleId-DCJnfNWr.js +64 -0
  64. package/dist/useBuilds-Dh_PWwCf.js +41 -0
  65. package/dist/useJob-CCkqCMvF.js +34 -0
  66. package/oclif.manifest.json +1510 -0
  67. 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 };