shipthis 0.1.30 → 0.1.31

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 (78) hide show
  1. package/README.md +122 -41
  2. package/assets/markdown/create-google-play-game.md +2 -4
  3. package/assets/markdown/ship-success.md +1 -1
  4. package/dist/{AppleBundleIdDetails-Fp5COwTa.js → AppleBundleIdDetails-eoK5F8Qn.js} +4 -4
  5. package/dist/Command-DFdHXDiU.js +44 -0
  6. package/dist/{CommandGame-Z4eUQBjn.js → CommandGame-Dif-oSky.js} +2 -2
  7. package/dist/{Create-1xAdntNl.js → Create-ISdroJ3G.js} +3 -3
  8. package/dist/{Import-CzC-M4ln.js → Import-CfThJF6k.js} +4 -4
  9. package/dist/{JobLogTail-CZxoMSd5.js → JobLogTail-BWzbQBZz.js} +5 -5
  10. package/dist/{JobProgress-BjNgtIjm.js → JobProgress-DjIkuk5U.js} +20 -10
  11. package/dist/{JobStatusTable-BB-PWlwj.js → JobStatusTable-CEqWU73q.js} +4 -4
  12. package/dist/{ProjectCredentialsTable-DyZep993.js → ProjectCredentialsTable-u9ruZ9mN.js} +2 -2
  13. package/dist/{UserCredentialsTable-BraKyDWT.js → UserCredentialsTable-Q7u9M-ap.js} +3 -3
  14. package/dist/{baseAppleCommand-BHRIBtTj.js → baseAppleCommand-zhkGlKq0.js} +1 -1
  15. package/dist/{baseGameAndroidCommand-SrDRbhAG.js → baseGameAndroidCommand-DJ-cMLa_.js} +2 -2
  16. package/dist/commands/apple/apiKey/create.js +8 -8
  17. package/dist/commands/apple/apiKey/export.js +7 -7
  18. package/dist/commands/apple/apiKey/import.js +7 -7
  19. package/dist/commands/apple/apiKey/status.js +6 -6
  20. package/dist/commands/apple/certificate/create.js +8 -8
  21. package/dist/commands/apple/certificate/export.js +7 -7
  22. package/dist/commands/apple/certificate/import.js +7 -7
  23. package/dist/commands/apple/certificate/status.js +6 -6
  24. package/dist/commands/apple/login.js +3 -2
  25. package/dist/commands/apple/status.js +6 -6
  26. package/dist/commands/dashboard.js +2 -1
  27. package/dist/commands/game/android/apiKey/connect.js +9 -9
  28. package/dist/commands/game/android/apiKey/create.js +11 -11
  29. package/dist/commands/game/android/apiKey/export.js +8 -8
  30. package/dist/commands/game/android/apiKey/import.js +8 -8
  31. package/dist/commands/game/android/apiKey/invite.js +5 -4
  32. package/dist/commands/game/android/apiKey/status.js +8 -8
  33. package/dist/commands/game/android/keyStore/create.js +9 -9
  34. package/dist/commands/game/android/keyStore/export.js +7 -7
  35. package/dist/commands/game/android/keyStore/import.js +10 -10
  36. package/dist/commands/game/android/keyStore/status.js +7 -7
  37. package/dist/commands/game/android/status.js +6 -6
  38. package/dist/commands/game/build/download.js +5 -5
  39. package/dist/commands/game/build/list.js +6 -6
  40. package/dist/commands/game/create.js +3 -2
  41. package/dist/commands/game/details.js +5 -5
  42. package/dist/commands/game/export.js +2 -1
  43. package/dist/commands/game/ios/app/addTester.js +6 -6
  44. package/dist/commands/game/ios/app/create.js +5 -5
  45. package/dist/commands/game/ios/app/status.js +8 -8
  46. package/dist/commands/game/ios/app/sync.js +6 -6
  47. package/dist/commands/game/ios/profile/create.js +8 -8
  48. package/dist/commands/game/ios/profile/export.js +7 -7
  49. package/dist/commands/game/ios/profile/import.js +7 -7
  50. package/dist/commands/game/ios/profile/status.js +7 -7
  51. package/dist/commands/game/ios/status.js +9 -9
  52. package/dist/commands/game/ios/wizard.js +5 -5
  53. package/dist/commands/game/job/list.js +5 -5
  54. package/dist/commands/game/job/status.js +8 -8
  55. package/dist/commands/game/list.js +14 -8
  56. package/dist/commands/game/ship.js +11 -10
  57. package/dist/commands/game/status.js +14 -11
  58. package/dist/commands/game/wizard.js +45 -92
  59. package/dist/commands/internal/fastlane.js +2 -1
  60. package/dist/commands/internal/readme.js +2 -1
  61. package/dist/commands/login.js +3 -2
  62. package/dist/commands/status.js +8 -8
  63. package/dist/{export-BKn02-NH.js → export-DZxo2_e_.js} +1 -1
  64. package/dist/{import-CRMaNBVF.js → import-8pL1AF47.js} +1 -1
  65. package/dist/{index-OZi8bvu8.js → index-BHh0BZvD.js} +47 -13
  66. package/dist/{index-u1aj1OQW.js → index-C6aAyrXW.js} +1 -1
  67. package/dist/{index-BTAL7EB_.js → index-CyvGh-kt.js} +20 -9
  68. package/dist/{index-35Eswf6F.js → index-DJ078v-U.js} +2 -1
  69. package/dist/{index--EbYyBAZ.js → index-DKQjnJrC.js} +5 -5
  70. package/dist/{index-DxzXU9Hd.js → index-w3lHxk5O.js} +8 -1
  71. package/dist/{upload-Bw0zrS4M.js → upload-BTpxj3QP.js} +1 -1
  72. package/dist/{useAndroidServiceAccountTestResult-CJLIEYmA.js → useAndroidServiceAccountTestResult-Dy3Ag7_r.js} +1 -1
  73. package/dist/{useAppleApp-cnb8gX0x.js → useAppleApp-h1Ogi_qc.js} +1 -1
  74. package/dist/{useAppleBundleId-B0Etav8g.js → useAppleBundleId-B3TTNap0.js} +1 -1
  75. package/dist/{useProjectCredentials-DX3e_PPc.js → useProjectCredentials-DpeXZcHP.js} +3 -3
  76. package/dist/{useWebSocket-BOCa8v6o.js → useWebSocket-gyuCsore.js} +1 -1
  77. package/package.json +2 -1
  78. package/dist/Command-1p5alCz3.js +0 -28
package/README.md CHANGED
@@ -14,7 +14,7 @@
14
14
  <b>ShipThis</b> is a <b>command line tool</b> for building and uploading your <a href="https://godotengine.org/">Godot</a> mobile games to the <b>Apple App Store</b> and <b>Google Play</b>.
15
15
  </p>
16
16
  <p align="center">
17
- ShipThis compiles your game on managed cloud servers no local build tools needed. Use it manually or add it into your CI when you're ready to ship.
17
+ ShipThis compiles your game on managed cloud servers. You do not need Xcode, Android Studio, or SDK installations. You can run it manually or from CI.
18
18
  </p>
19
19
 
20
20
  <p align="center">
@@ -29,45 +29,22 @@
29
29
 
30
30
  ---
31
31
 
32
+ ## Why use ShipThis?
32
33
 
33
- <details>
34
- <summary><strong>Watch: Set up ShipThis for iOS</strong></summary>
34
+ - **Always a free tier** - Enough build minutes for most solo devs
35
+ - **One-command setup** - Use the interactive [`wizard`](https://shipth.is/docs/reference/game/wizard) to configure your game
36
+ - **No additional tools** - No Xcode, Android Studio, or SDK installation required
37
+ - **Simplified provisioning** - We handle iOS certificates, Android keystores, app signing, and API keys
38
+ - **One-command deployment** - Publish to TestFlight or Google Play with a single command
35
39
 
36
- <p align="center">
37
- <a href="https://www.youtube.com/watch?v=ijTUFVk1duw" target="_blank">
38
- <img src="https://img.youtube.com/vi/ijTUFVk1duw/0.jpg" alt="Watch the iOS setup video" width="640" height="480">
39
- </a>
40
- </p>
40
+ ## Quick start
41
41
 
42
- </details>
43
- <details>
44
- <summary><strong>Watch: Set up ShipThis for Android</strong></summary>
45
-
46
- <p align="center">
47
- <picture>
48
- <img height="431" width="672" alt="ShipThis Command - Android Wizard - published game" src="docs/assets/wizard-android-existingx0.5.gif">
49
- </picture>
50
- </p>
51
-
52
- </details>
53
-
54
-
55
- ## ❓ Why use ShipThis?
56
-
57
- - **✅ Always a free tier** – Enough usage for most solo devs.
58
- - **✨ One-command setup** – Our interactive [`wizard`](https://shipth.is/docs/reference/game/wizard) guides you through configuration.
59
- - **⏩ Skip the build tools** – No Xcode, Android Studio, or SDK installation required.
60
- - **🔐 Simplify provisioning** – We handle iOS certificates, Android keystores, app signing, and API keys.
61
- - **🚀 One-command deployment** – Publish to TestFlight or Google Play with a single CLI command.
62
-
63
- ## ⚡️ Quick start
64
-
65
- ### What you'll need
42
+ ### Requirements
66
43
 
67
44
  - A Godot 3.6 or 4.X game
68
45
  - [Node.js](https://nodejs.org/en/download/) version 18.0 or above
69
- - **If you are building an iOS game** an [Apple Developer account](https://developer.apple.com)
70
- - **If you are building an Android game** a [Play Console developer account](https://play.google.com/apps/publish/signup)
46
+ - **To publish an Android game** - a [Play Console developer account](https://play.google.com/apps/publish/signup) (not required for building an APK/AAB)
47
+ - **To build an iOS game** - an [Apple Developer account](https://developer.apple.com)
71
48
 
72
49
  ### 1. Install ShipThis
73
50
 
@@ -81,7 +58,7 @@ npm install -g shipthis
81
58
 
82
59
  Set up an account with ShipThis by logging in for the first time using the [`shipthis login`](https://shipth.is/docs/reference/login) command.
83
60
 
84
- > 🛠 All builds run on managed cloud servers no need to install Xcode or Android Studio locally.
61
+ > 🛠 All builds run on managed cloud servers - no need to install Xcode or Android Studio locally.
85
62
 
86
63
  ```bash
87
64
  shipthis login
@@ -89,20 +66,42 @@ shipthis login
89
66
 
90
67
  ### 3. Set up your game
91
68
 
92
- Next, run the [wizard command](https://shipth.is/docs/reference/game/wizard) to configure your game on ShipThis. The command takes a platform parameter this can be either **android** or **ios**. Run this command from within a Godot game directory (with a **project.godot** file):
69
+ Run the [wizard command](https://shipth.is/docs/reference/game/wizard) to configure your game on ShipThis. The command takes a platform parameter - this can be either **android** or **ios**. Run this command from within a Godot game directory (with a **project.godot** file):
93
70
 
94
- ### Set up an Android game
71
+ #### Set up an Android game
95
72
 
96
73
  ```bash
97
74
  shipthis game wizard android
98
75
  ```
99
76
 
100
- ### Set up an iOS game
77
+ <details>
78
+ <summary><strong>Watch: Set up ShipThis for Android</strong></summary>
79
+
80
+ <p align="center">
81
+ <picture>
82
+ <img height="431" width="672" alt="ShipThis Command - Android Wizard - published game" src="docs/assets/wizard-android-existingx0.5.gif">
83
+ </picture>
84
+ </p>
85
+
86
+ </details>
87
+
88
+ #### Set up an iOS game
101
89
 
102
90
  ```bash
103
91
  shipthis game wizard ios
104
92
  ```
105
93
 
94
+ <details>
95
+ <summary><strong>Watch: Set up ShipThis for iOS</strong></summary>
96
+
97
+ <p align="center">
98
+ <a href="https://www.youtube.com/watch?v=ijTUFVk1duw" target="_blank">
99
+ <img src="https://img.youtube.com/vi/ijTUFVk1duw/0.jpg" alt="Watch the iOS setup video" width="640" height="480">
100
+ </a>
101
+ </p>
102
+
103
+ </details>
104
+
106
105
  ### 4. Ship
107
106
 
108
107
  Now you can publish new versions of your game to TestFlight or Google Play with the [`shipthis game ship`](https://shipth.is/docs/reference/game/ship) command:
@@ -111,8 +110,90 @@ Now you can publish new versions of your game to TestFlight or Google Play with
111
110
  shipthis game ship
112
111
  ```
113
112
 
114
- - 💡 Having issues? Check the [Troubleshooting](https://shipth.is/docs/troubleshooting) or [join our Discord](https://discord.gg/gPjn3S99k4)
115
- - 📚 For detailed documentation, visit [shipth.is/docs](https://shipth.is/docs)
113
+ - Having issues? Check the [Troubleshooting](https://shipth.is/docs/troubleshooting) or [join our Discord](https://discord.gg/gPjn3S99k4)
114
+ - For detailed documentation, visit [shipth.is/docs](https://shipth.is/docs)
115
+
116
+
117
+ ## FAQ
118
+
119
+ <details>
120
+ <summary><strong>Can I build my game as APK without a Google Play account?</strong></summary>
121
+
122
+ ---
123
+
124
+ Yes.
125
+
126
+ Running the wizard command will create a Service Account Key for automatic publishing, you might not need this when initially building your game.
127
+
128
+ You can run the steps below to create a ShipThis account, create the game, create a keystore, and then run the ship command. Later, when you need to setup publishing you can re-run the wizard command.
129
+
130
+
131
+ ```bash
132
+ # Create or login to your shipthis account (OTP based login)
133
+ shipthis login --email me@email.com
134
+
135
+ # Create a ShipThis game - run this in a dir with a project.godot file
136
+ shipthis game create --name "My Game" --androidPackageName "com.my.game"
137
+
138
+ # Create a keystore for signing the APK
139
+ shipthis game android keyStore create
140
+
141
+ # Run the build, skip the publish step, and download as game.apk
142
+ shipthis game ship --follow --platform android --skipPublish --downloadAPK game.apk
143
+ ```
144
+
145
+
146
+ </details>
147
+
148
+
149
+ <details>
150
+ <summary><strong>Do I need a Mac to build for iOS?</strong></summary>
151
+
152
+ ---
153
+
154
+ No, you do not need a Mac, but you will need an Apple Developer Account.
155
+
156
+ ShipThis handles iOS builds on managed macOS cloud servers. The command-line tool communicates with the Apple Developer Portal to configure everything on your behalf.
157
+
158
+ </details>
159
+
160
+ <details>
161
+ <summary><strong>Which versions of Godot are supported?</strong></summary>
162
+
163
+ ---
164
+
165
+ We support **all stable Godot versions since 3.6**, including:
166
+
167
+ | 3.6 | 4.0 | 4.1 | 4.2 | 4.3 | 4.4 |
168
+ |---------|----------|----------|--------|-----|--------|
169
+ | 3.6.1 | 4.0.1 | 4.1.1 | 4.2.1 | | 4.4.1 |
170
+ | | 4.0.2 | 4.1.2 | 4.2.2 | | |
171
+ | | 4.0.3 | 4.1.3 | | | |
172
+ | | 4.0.4 | 4.1.4 | | | |
173
+
174
+ You can read more in our [Godot versioning guide](https://shipth.is/docs/guides/godot-versioning).
175
+
176
+ </details>
177
+
178
+ <details>
179
+ <summary><strong>Do I need to create an export_presets.cfg file?</strong></summary>
180
+
181
+ ---
182
+
183
+ No, the ShipThis build server will generate a valid **export_presets.cfg** for your game.
184
+
185
+ If you provide an **export_presets.cfg** file, the desired preset values will be merged with the generated file.
186
+
187
+ </details>
188
+
189
+ <details>
190
+ <summary><strong>How much does it cost to use ShipThis?</strong></summary>
191
+
192
+ ---
193
+
194
+ ShipThis is currently in open-beta as so it is completely free to use. You can see our planned pricing on the [pricing page](https://shipth.is/pricing).
195
+
196
+ </details>
116
197
 
117
198
  ## 📖 Command Reference
118
199
 
@@ -132,4 +213,4 @@ shipthis game ship
132
213
 
133
214
  - 💬 [Join us on Discord](https://discord.gg/gPjn3S99k4)
134
215
  - 🐛 [Report an issue](https://github.com/shipth-is/cli/issues)
135
- - 📣 Feature ideas? Feedback? We’d love to hear from you – email support@shipth.is
216
+ - 📣 Feature ideas? Feedback? We’d love to hear from you – email support@shipth.is
@@ -1,14 +1,12 @@
1
1
  # Create the game in Google Play
2
2
 
3
- You will need to manually create an "app" in Google Play. This will involve entering the name, agreeing to Google Play's TOS and uploading an initial build (created in the previous step).
4
-
5
- Broadly, the steps are:
3
+ You will need to manually create an "app" in Google Play.
6
4
 
7
5
  1. Log into the **Google Play Console** with your Google account. [https://play.google.com/console](https://play.google.com/console)
8
6
  1. Create a developer account and payments profile if prompted.
9
7
  1. Click **"Create app"** on the Console dashboard.
10
8
  1. Enter the app name, default language, and accept terms.
11
- 1. Go to **"Internal testing"** and create a new release.
9
+ 1. Go to **"Test and release"** > **"Testing"** > **"Internal testing"** and create a new release.
12
10
  1. Upload the initial build **AAB file** of your game from the previous step
13
11
 
14
12
  To download the AAB file from the previous step, please run:
@@ -1,6 +1,6 @@
1
1
  # 🚀 Shipped
2
2
 
3
- **Your game has been successfully built and published.**
3
+ **Your game has been successfully built${if wasPublished} and published${endif}.**
4
4
 
5
5
  ## Next Steps
6
6
 
@@ -1,7 +1,7 @@
1
1
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
2
2
  import { Box, Text } from 'ink';
3
3
  import Spinner from 'ink-spinner';
4
- import './index-DxzXU9Hd.js';
4
+ import './index-w3lHxk5O.js';
5
5
  import 'axios';
6
6
  import '@tanstack/react-query';
7
7
  import 'crypto';
@@ -17,11 +17,11 @@ import 'react';
17
17
  import 'crypto-js';
18
18
  import 'uuid';
19
19
  import 'socket.io-client';
20
- import { u as useAppleApp } from './useAppleApp-cnb8gX0x.js';
20
+ import { u as useAppleApp } from './useAppleApp-h1Ogi_qc.js';
21
21
  import 'fast-glob';
22
22
  import 'yazl';
23
23
  import '@inkjs/ui';
24
- import './index-BTAL7EB_.js';
24
+ import './index-CyvGh-kt.js';
25
25
  import 'open';
26
26
  import { T as Table } from './Table-CvM6pccN.js';
27
27
  import { T as Title } from './Title-BCQtayg6.js';
@@ -31,7 +31,7 @@ import 'marked';
31
31
  import 'marked-terminal';
32
32
  import 'path';
33
33
  import 'qrcode';
34
- import { u as useAppleBundleId } from './useAppleBundleId-B0Etav8g.js';
34
+ import { u as useAppleBundleId } from './useAppleBundleId-B3TTNap0.js';
35
35
 
36
36
  const AppleAppDetails = (props) => {
37
37
  const { data, isLoading } = useAppleApp(props);
@@ -0,0 +1,44 @@
1
+ import { jsx } from 'react/jsx-runtime';
2
+ import { useStdout, Box } from 'ink';
3
+ import { QueryClientProvider } from '@tanstack/react-query';
4
+ import { _ as queryClient } from './index-w3lHxk5O.js';
5
+ import 'axios';
6
+ import 'crypto';
7
+ import 'fs';
8
+ import 'readline-sync';
9
+ import 'node:readline';
10
+ import 'node:path';
11
+ import 'node:url';
12
+ import 'luxon';
13
+ import 'isomorphic-git';
14
+ import '@oclif/core';
15
+ import { useCallback, useState, useEffect } from 'react';
16
+ import 'crypto-js';
17
+ import 'uuid';
18
+ import 'socket.io-client';
19
+ import 'fast-glob';
20
+ import 'yazl';
21
+ import { C as CommandProvider } from './index-CyvGh-kt.js';
22
+
23
+ function useScreenSize() {
24
+ const { stdout } = useStdout();
25
+ const getSize = useCallback(() => ({ height: stdout.rows, width: stdout.columns }), [stdout]);
26
+ const [size, setSize] = useState(getSize);
27
+ useEffect(() => {
28
+ function onResize() {
29
+ setSize(getSize());
30
+ }
31
+ stdout.on("resize", onResize);
32
+ return () => {
33
+ stdout.off("resize", onResize);
34
+ };
35
+ }, [stdout, getSize]);
36
+ return size;
37
+ }
38
+
39
+ const Command = ({ children, command }) => {
40
+ const { width } = useScreenSize();
41
+ return /* @__PURE__ */ jsx(QueryClientProvider, { client: queryClient, children: /* @__PURE__ */ jsx(CommandProvider, { command, children: /* @__PURE__ */ jsx(Box, { width, flexDirection: "column", children }) }) });
42
+ };
43
+
44
+ export { Command as C, useScreenSize as u };
@@ -1,6 +1,6 @@
1
1
  import { jsx } from 'react/jsx-runtime';
2
- import { G as GameProvider } from './index-BTAL7EB_.js';
3
- import { C as Command } from './Command-1p5alCz3.js';
2
+ import { G as GameProvider } from './index-CyvGh-kt.js';
3
+ import { C as Command } from './Command-DFdHXDiU.js';
4
4
 
5
5
  const CommandGame = ({ children, command }) => {
6
6
  return /* @__PURE__ */ jsx(Command, { command, children: /* @__PURE__ */ jsx(GameProvider, { children }) });
@@ -3,9 +3,9 @@ import { Box } from 'ink';
3
3
  import axios from 'axios';
4
4
  import { useContext } from 'react';
5
5
  import { useQueryClient } from '@tanstack/react-query';
6
- import { p as getAuthedHeaders, q as API_URL } from './index-DxzXU9Hd.js';
7
- import { c as cacheKeys } from './useAndroidServiceAccountTestResult-CJLIEYmA.js';
8
- import { b as GameContext } from './index-BTAL7EB_.js';
6
+ import { p as getAuthedHeaders, q as API_URL } from './index-w3lHxk5O.js';
7
+ import { c as cacheKeys } from './useAndroidServiceAccountTestResult-Dy3Ag7_r.js';
8
+ import { b as GameContext } from './index-CyvGh-kt.js';
9
9
  import 'ink-spinner';
10
10
  import '@inkjs/ui';
11
11
  import 'fs';
@@ -2,8 +2,8 @@ import { jsxs, jsx } from 'react/jsx-runtime';
2
2
  import { useContext, useState, useEffect } from 'react';
3
3
  import { Box, Text } from 'ink';
4
4
  import Spinner from 'ink-spinner';
5
- import { b as GameContext } from './index-BTAL7EB_.js';
6
- import { K as queryClient, P as Platform, C as CredentialsType } from './index-DxzXU9Hd.js';
5
+ import { b as GameContext } from './index-CyvGh-kt.js';
6
+ import { _ as queryClient, P as Platform, C as CredentialsType } from './index-w3lHxk5O.js';
7
7
  import 'axios';
8
8
  import 'crypto-js';
9
9
  import { v4 } from 'uuid';
@@ -12,8 +12,8 @@ import 'luxon';
12
12
  import '@inkjs/ui';
13
13
  import { useMutation } from '@tanstack/react-query';
14
14
  import yazl from 'yazl';
15
- import { c as cacheKeys } from './useAndroidServiceAccountTestResult-CJLIEYmA.js';
16
- import { i as importCredential } from './import-CRMaNBVF.js';
15
+ import { c as cacheKeys } from './useAndroidServiceAccountTestResult-Dy3Ag7_r.js';
16
+ import { i as importCredential } from './import-8pL1AF47.js';
17
17
  import 'crypto';
18
18
  import 'readline-sync';
19
19
  import 'node:readline';
@@ -1,11 +1,11 @@
1
1
  import { jsx, jsxs } from 'react/jsx-runtime';
2
2
  import { measureElement, Box, Text } from 'ink';
3
3
  import Spinner from 'ink-spinner';
4
- import { d as getStageColor, j as getMessageColor } from './index-35Eswf6F.js';
4
+ import { d as getStageColor, j as getMessageColor } from './index-DJ078v-U.js';
5
5
  import { useState, useRef, useEffect } from 'react';
6
6
  import axios from 'axios';
7
7
  import { useInfiniteQuery } from '@tanstack/react-query';
8
- import { p as getAuthedHeaders, q as API_URL, I as castArrayObjectDates, J as JobStatus, a4 as castJobDates, a1 as castObjectDates, a5 as getShortTime } from './index-DxzXU9Hd.js';
8
+ import { p as getAuthedHeaders, q as API_URL, I as castArrayObjectDates, J as JobStatus, a3 as castJobDates, a1 as castObjectDates, a4 as getShortTime } from './index-w3lHxk5O.js';
9
9
  import 'crypto-js';
10
10
  import 'uuid';
11
11
  import 'fs';
@@ -20,9 +20,9 @@ import 'node:path';
20
20
  import 'node:url';
21
21
  import 'isomorphic-git';
22
22
  import '@oclif/core';
23
- import { c as cacheKeys } from './useAndroidServiceAccountTestResult-CJLIEYmA.js';
24
- import { e as useJob } from './index-BTAL7EB_.js';
25
- import { u as useWebSocket } from './useWebSocket-BOCa8v6o.js';
23
+ import { c as cacheKeys } from './useAndroidServiceAccountTestResult-Dy3Ag7_r.js';
24
+ import { e as useJob } from './index-CyvGh-kt.js';
25
+ import { u as useWebSocket } from './useWebSocket-gyuCsore.js';
26
26
  import { T as Title } from './Title-BCQtayg6.js';
27
27
  import stringLength from 'string-length';
28
28
  import stripAnsi from 'strip-ansi';
@@ -4,14 +4,14 @@ import fg from 'fast-glob';
4
4
  import fs__default from 'fs';
5
5
  import yazl from 'yazl';
6
6
  import { useMutation } from '@tanstack/react-query';
7
- import { c as cacheKeys } from './useAndroidServiceAccountTestResult-CJLIEYmA.js';
8
- import { K as queryClient, x as DEFAULT_SHIPPED_FILES_GLOBS, w as DEFAULT_IGNORED_FILES_GLOBS, $ as getNewUploadTicket, a0 as startJobsFromUpload } from './index-DxzXU9Hd.js';
9
- import { f as getFileHash, h as getPlatformName } from './index-35Eswf6F.js';
7
+ import { c as cacheKeys } from './useAndroidServiceAccountTestResult-Dy3Ag7_r.js';
8
+ import { _ as queryClient, x as DEFAULT_SHIPPED_FILES_GLOBS, w as DEFAULT_IGNORED_FILES_GLOBS, $ as getNewUploadTicket, a0 as startJobsFromUpload } from './index-w3lHxk5O.js';
9
+ import { f as getFileHash, h as getPlatformName } from './index-DJ078v-U.js';
10
10
  import { g as getCWDGitInfo } from './git-DREGq-jc.js';
11
11
  import { jsx, Fragment } from 'react/jsx-runtime';
12
12
  import 'react';
13
13
  import 'ink';
14
- import './index-BTAL7EB_.js';
14
+ import './index-CyvGh-kt.js';
15
15
  import 'ink-spinner';
16
16
  import 'crypto-js';
17
17
  import 'luxon';
@@ -25,13 +25,20 @@ import 'qrcode';
25
25
  import 'string-length';
26
26
  import 'strip-ansi';
27
27
  import 'socket.io-client';
28
- import { u as useJobWatching } from './JobLogTail-CZxoMSd5.js';
28
+ import { u as useJobWatching } from './JobLogTail-BWzbQBZz.js';
29
29
 
30
30
  async function ship({ command, log = () => {
31
- } }) {
32
- log("Fetching project config...");
31
+ }, shipFlags }) {
32
+ log("Fetching game config...");
33
33
  const projectConfig = await command.getProjectConfig();
34
34
  if (!projectConfig.project) throw new Error("No project found in project config");
35
+ const hasConfiguredIos = !!projectConfig.project.details?.iosBundleId;
36
+ const hasConfiguredAndroid = !!projectConfig.project.details?.androidPackageName;
37
+ if (!hasConfiguredAndroid && !hasConfiguredIos) {
38
+ throw new Error(
39
+ "No Android or iOS configuration found. Please run `shipthis game wizard android` or `shipthis game wizard ios` to configure your game."
40
+ );
41
+ }
35
42
  log("Retrieving file globs...");
36
43
  const shippedFilesGlobs = projectConfig.shippedFilesGlobs || DEFAULT_SHIPPED_FILES_GLOBS;
37
44
  const ignoredFilesGlobs = projectConfig.ignoredFilesGlobs || DEFAULT_IGNORED_FILES_GLOBS;
@@ -71,16 +78,19 @@ async function ship({ command, log = () => {
71
78
  zipFileMd5
72
79
  };
73
80
  log("Starting jobs from upload...");
74
- const commandFlags = command.getFlags();
81
+ const finalFlags = shipFlags || command.getFlags();
75
82
  const startJobsOptions = {
76
83
  ...uploadDetails,
77
- skipPublish: commandFlags.skipPublish,
78
- platform: commandFlags.platform?.toUpperCase()
84
+ skipPublish: finalFlags.skipPublish,
85
+ platform: finalFlags.platform?.toUpperCase()
79
86
  };
80
87
  const jobs = await startJobsFromUpload(uploadTicket.id, startJobsOptions);
81
88
  log("Cleaning up temporary zip file...");
82
89
  fs__default.unlinkSync(tmpZipFile);
83
90
  log("Job submission complete.");
91
+ if (jobs.length === 0) {
92
+ throw new Error("No jobs were created. Please check your game configuration and try again.");
93
+ }
84
94
  return jobs;
85
95
  }
86
96
  const useShip = () => {
@@ -3,18 +3,18 @@ import { useState, useEffect } from 'react';
3
3
  import { Box, Text } from 'ink';
4
4
  import { DateTime } from 'luxon';
5
5
  import Spinner from 'ink-spinner';
6
- import { d as getStageColor, c as getJobStatusColor } from './index-35Eswf6F.js';
7
- import { J as JobStatus } from './index-DxzXU9Hd.js';
6
+ import { d as getStageColor, c as getJobStatusColor } from './index-DJ078v-U.js';
7
+ import { J as JobStatus } from './index-w3lHxk5O.js';
8
8
  import 'axios';
9
9
  import '@tanstack/react-query';
10
10
  import 'crypto-js';
11
11
  import 'uuid';
12
12
  import 'fs';
13
- import { a as getJobSummary } from './index-BTAL7EB_.js';
13
+ import { a as getJobSummary } from './index-CyvGh-kt.js';
14
14
  import 'fast-glob';
15
15
  import 'yazl';
16
16
  import 'socket.io-client';
17
- import { u as useJobWatching } from './JobLogTail-CZxoMSd5.js';
17
+ import { u as useJobWatching } from './JobLogTail-BWzbQBZz.js';
18
18
  import { T as Title } from './Title-BCQtayg6.js';
19
19
  import { a as StatusRow, b as StatusRowLabel } from './StatusTable-Dm5St4g-.js';
20
20
 
@@ -10,13 +10,13 @@ import 'node:url';
10
10
  import 'luxon';
11
11
  import 'axios';
12
12
  import 'isomorphic-git';
13
- import './index-DxzXU9Hd.js';
13
+ import './index-w3lHxk5O.js';
14
14
  import '@oclif/core';
15
15
  import 'react';
16
16
  import '@tanstack/react-query';
17
17
  import 'crypto-js';
18
18
  import 'uuid';
19
- import { u as useProjectCredentials, g as getProjectCredentialSummary } from './useProjectCredentials-DX3e_PPc.js';
19
+ import { u as useProjectCredentials, g as getProjectCredentialSummary } from './useProjectCredentials-DpeXZcHP.js';
20
20
  import 'fast-glob';
21
21
  import 'yazl';
22
22
  import 'socket.io-client';
@@ -10,7 +10,7 @@ import 'node:url';
10
10
  import 'luxon';
11
11
  import axios from 'axios';
12
12
  import 'isomorphic-git';
13
- import { b as getShortDate, p as getAuthedHeaders, q as API_URL, I as castArrayObjectDates } from './index-DxzXU9Hd.js';
13
+ import { b as getShortDate, p as getAuthedHeaders, q as API_URL, I as castArrayObjectDates } from './index-w3lHxk5O.js';
14
14
  import '@oclif/core';
15
15
  import 'react';
16
16
  import { useQuery } from '@tanstack/react-query';
@@ -18,8 +18,8 @@ import 'crypto-js';
18
18
  import 'uuid';
19
19
  import 'fast-glob';
20
20
  import 'yazl';
21
- import { c as cacheKeys } from './useAndroidServiceAccountTestResult-CJLIEYmA.js';
22
- import { g as getShortUUID } from './index-35Eswf6F.js';
21
+ import { c as cacheKeys } from './useAndroidServiceAccountTestResult-Dy3Ag7_r.js';
22
+ import { g as getShortUUID } from './index-DJ078v-U.js';
23
23
  import 'socket.io-client';
24
24
  import { T as Table } from './Table-CvM6pccN.js';
25
25
  import { T as Title } from './Title-BCQtayg6.js';
@@ -1,4 +1,4 @@
1
- import { B as BaseAuthenticatedCommand } from './index-DxzXU9Hd.js';
1
+ import { B as BaseAuthenticatedCommand } from './index-w3lHxk5O.js';
2
2
 
3
3
  class BaseAppleCommand extends BaseAuthenticatedCommand {
4
4
  async init() {
@@ -1,5 +1,5 @@
1
- import { c as BaseGameCommand, Q as getGodotAndroidPackageName, R as getGoogleStatus } from './index-DxzXU9Hd.js';
2
- import { b as generatePackageName, a as getInput } from './index-35Eswf6F.js';
1
+ import { c as BaseGameCommand, O as getGodotAndroidPackageName, Q as getGoogleStatus } from './index-w3lHxk5O.js';
2
+ import { b as generatePackageName, a as getInput } from './index-DJ078v-U.js';
3
3
 
4
4
  class BaseGameAndroidCommand extends BaseGameCommand {
5
5
  async init() {
@@ -1,10 +1,10 @@
1
1
  import { jsx } from 'react/jsx-runtime';
2
2
  import { Flags } from '@oclif/core';
3
3
  import { render } from 'ink';
4
- import { P as Platform, C as CredentialsType, A as ApiKey, a as ApiKeyType, U as UserRole } from '../../../index-DxzXU9Hd.js';
5
- import { g as getUserCredentials } from '../../../index-u1aj1OQW.js';
4
+ import { P as Platform, C as CredentialsType, A as ApiKey, a as ApiKeyType, U as UserRole } from '../../../index-w3lHxk5O.js';
5
+ import { g as getUserCredentials } from '../../../index-C6aAyrXW.js';
6
6
  import 'react';
7
- import '../../../index-BTAL7EB_.js';
7
+ import '../../../index-CyvGh-kt.js';
8
8
  import 'ink-spinner';
9
9
  import 'axios';
10
10
  import 'crypto-js';
@@ -30,14 +30,14 @@ import 'qrcode';
30
30
  import { R as RunWithSpinner } from '../../../RunWithSpinner-BVXNWGD3.js';
31
31
  import 'string-length';
32
32
  import 'strip-ansi';
33
- import { C as Command } from '../../../Command-1p5alCz3.js';
34
- import { B as BaseAppleCommand } from '../../../baseAppleCommand-BHRIBtTj.js';
35
- import { u as uploadUserCredentials } from '../../../upload-Bw0zrS4M.js';
33
+ import { C as Command } from '../../../Command-DFdHXDiU.js';
34
+ import { B as BaseAppleCommand } from '../../../baseAppleCommand-zhkGlKq0.js';
35
+ import { u as uploadUserCredentials } from '../../../upload-BTpxj3QP.js';
36
36
  import '@expo/apple-utils/build/index.js';
37
37
  import 'ini';
38
38
  import 'deepmerge';
39
- import '../../../index-35Eswf6F.js';
40
- import '../../../useAndroidServiceAccountTestResult-CJLIEYmA.js';
39
+ import '../../../index-DJ078v-U.js';
40
+ import '../../../useAndroidServiceAccountTestResult-Dy3Ag7_r.js';
41
41
 
42
42
  class AppleApiKeyCreate extends BaseAppleCommand {
43
43
  static args = {};
@@ -2,10 +2,10 @@ import { jsx } from 'react/jsx-runtime';
2
2
  import { Args, Flags } from '@oclif/core';
3
3
  import { render } from 'ink';
4
4
  import * as fs from 'fs';
5
- import { B as BaseAuthenticatedCommand, P as Platform, C as CredentialsType } from '../../../index-DxzXU9Hd.js';
6
- import { g as getUserCredentials } from '../../../index-u1aj1OQW.js';
5
+ import { B as BaseAuthenticatedCommand, P as Platform, C as CredentialsType } from '../../../index-w3lHxk5O.js';
6
+ import { g as getUserCredentials } from '../../../index-C6aAyrXW.js';
7
7
  import 'react';
8
- import '../../../index-BTAL7EB_.js';
8
+ import '../../../index-CyvGh-kt.js';
9
9
  import 'ink-spinner';
10
10
  import 'axios';
11
11
  import 'crypto-js';
@@ -30,13 +30,13 @@ import 'qrcode';
30
30
  import { R as RunWithSpinner } from '../../../RunWithSpinner-BVXNWGD3.js';
31
31
  import 'string-length';
32
32
  import 'strip-ansi';
33
- import { C as Command } from '../../../Command-1p5alCz3.js';
34
- import { e as exportCredential } from '../../../export-BKn02-NH.js';
33
+ import { C as Command } from '../../../Command-DFdHXDiU.js';
34
+ import { e as exportCredential } from '../../../export-DZxo2_e_.js';
35
35
  import '@expo/apple-utils/build/index.js';
36
36
  import 'ini';
37
37
  import 'deepmerge';
38
- import '../../../index-35Eswf6F.js';
39
- import '../../../useAndroidServiceAccountTestResult-CJLIEYmA.js';
38
+ import '../../../index-DJ078v-U.js';
39
+ import '../../../useAndroidServiceAccountTestResult-Dy3Ag7_r.js';
40
40
 
41
41
  class AppleApiKeyExport extends BaseAuthenticatedCommand {
42
42
  static args = {
@@ -2,10 +2,10 @@ import { jsx } from 'react/jsx-runtime';
2
2
  import { Args, Flags } from '@oclif/core';
3
3
  import { render } from 'ink';
4
4
  import * as fs from 'fs';
5
- import { B as BaseAuthenticatedCommand, P as Platform, C as CredentialsType } from '../../../index-DxzXU9Hd.js';
6
- import { g as getUserCredentials } from '../../../index-u1aj1OQW.js';
5
+ import { B as BaseAuthenticatedCommand, P as Platform, C as CredentialsType } from '../../../index-w3lHxk5O.js';
6
+ import { g as getUserCredentials } from '../../../index-C6aAyrXW.js';
7
7
  import 'react';
8
- import '../../../index-BTAL7EB_.js';
8
+ import '../../../index-CyvGh-kt.js';
9
9
  import 'ink-spinner';
10
10
  import 'axios';
11
11
  import 'crypto-js';
@@ -30,13 +30,13 @@ import 'qrcode';
30
30
  import { R as RunWithSpinner } from '../../../RunWithSpinner-BVXNWGD3.js';
31
31
  import 'string-length';
32
32
  import 'strip-ansi';
33
- import { C as Command } from '../../../Command-1p5alCz3.js';
34
- import { i as importCredential } from '../../../import-CRMaNBVF.js';
33
+ import { C as Command } from '../../../Command-DFdHXDiU.js';
34
+ import { i as importCredential } from '../../../import-8pL1AF47.js';
35
35
  import '@expo/apple-utils/build/index.js';
36
36
  import 'ini';
37
37
  import 'deepmerge';
38
- import '../../../index-35Eswf6F.js';
39
- import '../../../useAndroidServiceAccountTestResult-CJLIEYmA.js';
38
+ import '../../../index-DJ078v-U.js';
39
+ import '../../../useAndroidServiceAccountTestResult-Dy3Ag7_r.js';
40
40
 
41
41
  class AppleApiKeyImport extends BaseAuthenticatedCommand {
42
42
  static args = {