shipthis 0.1.31 → 0.1.33

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 (84) hide show
  1. package/dist/{AppleBundleIdDetails-eoK5F8Qn.js → AppleBundleIdDetails-BhHPCvRm.js} +17 -19
  2. package/dist/Command-BDIkuv2g.js +29 -0
  3. package/dist/CommandGame-CvBIjPZp.js +7 -0
  4. package/dist/{Create-ISdroJ3G.js → Create-Lpe0B8nT.js} +20 -20
  5. package/dist/GameStatus-5XpufIY_.js +137 -0
  6. package/dist/{Import-CfThJF6k.js → Import-DFzrAG04.js} +34 -36
  7. package/dist/{JobLogTail-BWzbQBZz.js → JobLogTail-BYcJgPcL.js} +53 -52
  8. package/dist/{JobProgress-DjIkuk5U.js → JobProgress-BcrE7CUK.js} +40 -38
  9. package/dist/{JobStatusTable-CEqWU73q.js → JobStatusTable-Bi-y8ZZT.js} +14 -13
  10. package/dist/{NextSteps-CK9zHOCt.js → NextSteps-DbJHmscQ.js} +1 -3
  11. package/dist/{ProgressSpinner-6pw1T8Iw.js → ProgressSpinner-Um6ARKlk.js} +2 -2
  12. package/dist/{ProjectCredentialsTable-u9ruZ9mN.js → ProjectCredentialsTable-B4vDJl4l.js} +11 -10
  13. package/dist/{StatusTable-Dm5St4g-.js → StatusTable-DzRWcMr4.js} +7 -9
  14. package/dist/{Table-CvM6pccN.js → Table-FaNgpyeq.js} +15 -15
  15. package/dist/{UserCredentialsTable-Q7u9M-ap.js → UserCredentialsTable-CwkZTFBD.js} +18 -19
  16. package/dist/{baseAppleCommand-zhkGlKq0.js → baseAppleCommand-BKXweb-U.js} +1 -1
  17. package/dist/{baseGameAndroidCommand-DJ-cMLa_.js → baseGameAndroidCommand-CAi-BSsH.js} +23 -23
  18. package/dist/commands/apple/apiKey/create.js +36 -36
  19. package/dist/commands/apple/apiKey/export.js +27 -27
  20. package/dist/commands/apple/apiKey/import.js +28 -28
  21. package/dist/commands/apple/apiKey/status.js +32 -32
  22. package/dist/commands/apple/certificate/create.js +40 -40
  23. package/dist/commands/apple/certificate/export.js +27 -27
  24. package/dist/commands/apple/certificate/import.js +28 -28
  25. package/dist/commands/apple/certificate/status.js +33 -33
  26. package/dist/commands/apple/login.js +15 -15
  27. package/dist/commands/apple/status.js +27 -27
  28. package/dist/commands/dashboard.js +10 -10
  29. package/dist/commands/game/android/apiKey/connect.js +28 -28
  30. package/dist/commands/game/android/apiKey/create.js +29 -29
  31. package/dist/commands/game/android/apiKey/export.js +30 -30
  32. package/dist/commands/game/android/apiKey/import.js +32 -32
  33. package/dist/commands/game/android/apiKey/invite.js +14 -14
  34. package/dist/commands/game/android/apiKey/status.js +30 -30
  35. package/dist/commands/game/android/keyStore/create.js +25 -25
  36. package/dist/commands/game/android/keyStore/export.js +29 -29
  37. package/dist/commands/game/android/keyStore/import.js +36 -36
  38. package/dist/commands/game/android/keyStore/status.js +26 -26
  39. package/dist/commands/game/android/status.js +15 -58
  40. package/dist/commands/game/build/download.js +24 -24
  41. package/dist/commands/game/build/list.js +37 -37
  42. package/dist/commands/game/create.js +15 -15
  43. package/dist/commands/game/details.js +35 -36
  44. package/dist/commands/game/export.js +12 -12
  45. package/dist/commands/game/ios/app/addTester.js +37 -32
  46. package/dist/commands/game/ios/app/create.js +24 -24
  47. package/dist/commands/game/ios/app/status.js +29 -29
  48. package/dist/commands/game/ios/app/sync.js +31 -31
  49. package/dist/commands/game/ios/profile/create.js +32 -32
  50. package/dist/commands/game/ios/profile/export.js +29 -29
  51. package/dist/commands/game/ios/profile/import.js +33 -33
  52. package/dist/commands/game/ios/profile/status.js +36 -36
  53. package/dist/commands/game/ios/status.js +46 -58
  54. package/dist/commands/game/ios/wizard.js +39 -34
  55. package/dist/commands/game/job/list.js +34 -34
  56. package/dist/commands/game/job/status.js +32 -32
  57. package/dist/commands/game/list.js +38 -40
  58. package/dist/commands/game/ship.js +81 -77
  59. package/dist/commands/game/status.js +38 -85
  60. package/dist/commands/game/wizard.js +253 -242
  61. package/dist/commands/internal/fastlane.js +15 -17
  62. package/dist/commands/internal/readme.js +38 -36
  63. package/dist/commands/login.js +14 -14
  64. package/dist/commands/status.js +32 -30
  65. package/dist/{export-DZxo2_e_.js → export-DLQrUEBK.js} +5 -5
  66. package/dist/{git-DREGq-jc.js → git-BpsfNFZ_.js} +8 -8
  67. package/dist/{import-8pL1AF47.js → import-BoY5e0uJ.js} +14 -14
  68. package/dist/{index-DJ078v-U.js → index-B27WJDxn.js} +43 -27
  69. package/dist/{index-DKQjnJrC.js → index-CisLwc7e.js} +42 -44
  70. package/dist/{index-C6aAyrXW.js → index-Crv7S0bl.js} +6 -6
  71. package/dist/{index-BHh0BZvD.js → index-DC0GJtAy.js} +50 -60
  72. package/dist/{index-CyvGh-kt.js → index-DfUg5j06.js} +93 -92
  73. package/dist/{index-w3lHxk5O.js → index-pj8JVg5X.js} +242 -225
  74. package/dist/{upload-BTpxj3QP.js → upload-C8S17EU_.js} +22 -22
  75. package/dist/{useAndroidServiceAccountTestResult-Dy3Ag7_r.js → useAndroidServiceAccountTestResult-D4e5AKAZ.js} +11 -13
  76. package/dist/{useAppleApp-h1Ogi_qc.js → useAppleApp-Dr6URQvC.js} +4 -4
  77. package/dist/{useAppleBundleId-B3TTNap0.js → useAppleBundleId-DELAwSQp.js} +6 -6
  78. package/dist/{useProjectCredentials-DpeXZcHP.js → useProjectCredentials-BjvdJdQg.js} +10 -12
  79. package/dist/{useWebSocket-gyuCsore.js → useWebSocket-CRV7V69Q.js} +1 -1
  80. package/dist/utils/help.js +4 -4
  81. package/package.json +5 -4
  82. package/dist/Command-DFdHXDiU.js +0 -44
  83. package/dist/CommandGame-Dif-oSky.js +0 -9
  84. package/dist/{RunWithSpinner-BVXNWGD3.js → RunWithSpinner-gMVA07bZ.js} +2 -2
@@ -1,37 +1,37 @@
1
1
  import { jsx, Fragment, jsxs } from 'react/jsx-runtime';
2
2
  import { Box, Text } from 'ink';
3
- import { useState, useRef, useEffect, useContext } from 'react';
4
3
  import Spinner from 'ink-spinner';
5
- import { b as GameContext } from './index-CyvGh-kt.js';
6
- import { p as getAuthedHeaders, q as API_URL, a1 as castObjectDates, P as Platform, C as CredentialsType, Q as getGoogleStatus } from './index-w3lHxk5O.js';
7
- import axios from 'axios';
8
- import 'crypto-js';
9
- import 'uuid';
10
- import 'fs';
11
- import 'luxon';
12
- import '@inkjs/ui';
13
- import { useQuery, useQueryClient } from '@tanstack/react-query';
14
- import 'yazl';
15
- import 'crypto';
16
- import 'readline-sync';
17
- import 'node:readline';
4
+ import { useState, useRef, useEffect, useContext } from 'react';
5
+ import 'node:crypto';
6
+ import 'node:fs';
18
7
  import 'node:path';
8
+ import 'node:readline';
19
9
  import 'node:url';
10
+ import 'readline-sync';
11
+ import 'luxon';
12
+ import axios from 'axios';
20
13
  import 'isomorphic-git';
14
+ import { p as getAuthedHeaders, o as API_URL, a1 as castObjectDates, P as Platform, C as CredentialsType, Q as getGoogleStatus } from './index-pj8JVg5X.js';
21
15
  import '@oclif/core';
22
- import { c as cacheKeys } from './useAndroidServiceAccountTestResult-Dy3Ag7_r.js';
16
+ import { useQuery, useQueryClient } from '@tanstack/react-query';
17
+ import { c as cacheKeys } from './useAndroidServiceAccountTestResult-D4e5AKAZ.js';
23
18
  import 'fast-glob';
19
+ import 'uuid';
20
+ import 'yazl';
24
21
  import 'socket.io-client';
25
- import { u as useWebSocket } from './useWebSocket-gyuCsore.js';
26
- import { u as useProjectCredentials } from './useProjectCredentials-DpeXZcHP.js';
22
+ import 'fullscreen-ink';
23
+ import { u as useWebSocket } from './useWebSocket-CRV7V69Q.js';
24
+ import { u as useProjectCredentials } from './useProjectCredentials-BjvdJdQg.js';
25
+ import 'crypto-js';
26
+ import 'string-length';
27
+ import 'strip-ansi';
27
28
  import 'open';
29
+ import '@inkjs/ui';
28
30
  import 'marked';
29
31
  import 'marked-terminal';
30
- import 'path';
31
- import { P as ProgressSpinner } from './ProgressSpinner-6pw1T8Iw.js';
32
+ import { P as ProgressSpinner } from './ProgressSpinner-Um6ARKlk.js';
32
33
  import 'qrcode';
33
- import 'string-length';
34
- import 'strip-ansi';
34
+ import { G as GameContext } from './index-DfUg5j06.js';
35
35
 
36
36
  async function fetchStatus({ projectId }) {
37
37
  try {
@@ -45,37 +45,35 @@ async function fetchStatus({ projectId }) {
45
45
  throw error;
46
46
  }
47
47
  }
48
- const useAndroidServiceAccountSetupStatus = (props) => {
49
- return useQuery({
50
- queryKey: cacheKeys.androidSetupStatus(props),
51
- queryFn: () => fetchStatus(props),
52
- // Status changes frequently, so we want to keep it fresh
53
- refetchInterval: 1e3 * 5,
54
- staleTime: 1e3 * 5
55
- });
56
- };
48
+ const useAndroidServiceAccountSetupStatus = (props) => useQuery({
49
+ queryFn: () => fetchStatus(props),
50
+ queryKey: cacheKeys.androidSetupStatus(props),
51
+ // Status changes frequently, so we want to keep it fresh
52
+ refetchInterval: 1e3 * 5,
53
+ staleTime: 1e3 * 5
54
+ });
57
55
 
58
56
  const ERR_NOT_AUTHENTICATED = "You must be connected to Google to create a Service Account Key";
59
57
  const useHasServiceAccountKey = (projectId) => {
60
- const { data, isSuccess } = useProjectCredentials({ projectId, platform: Platform.ANDROID });
61
- return isSuccess && data.data.some((cred) => cred.isActive && cred.platform === Platform.ANDROID && cred.type == CredentialsType.KEY);
58
+ const { data, isSuccess } = useProjectCredentials({ platform: Platform.ANDROID, projectId });
59
+ return isSuccess && data.data.some((cred) => cred.isActive && cred.platform === Platform.ANDROID && cred.type === CredentialsType.KEY);
62
60
  };
63
- const useAndroidServiceAccount = ({ projectId, onError, onComplete }) => {
61
+ const useAndroidServiceAccount = ({ onComplete, onError, projectId }) => {
64
62
  const queryClient = useQueryClient();
65
63
  const [isStarting, setIsStarting] = useState(false);
66
64
  const hasServiceAccountKey = useHasServiceAccountKey(projectId);
67
65
  const listener = {
68
- getPattern: () => `project.${projectId}:android-setup-status`,
69
- eventHandler: async (pattern, data) => {
66
+ async eventHandler(pattern, data) {
70
67
  const key = cacheKeys.androidSetupStatus({ projectId });
71
68
  queryClient.setQueryData(key, () => data);
72
- }
69
+ },
70
+ getPattern: () => `project.${projectId}:android-setup-status`
73
71
  };
74
72
  useWebSocket([listener]);
75
73
  const { data: setupStatus } = useAndroidServiceAccountSetupStatus({ projectId });
76
74
  const prevSetupStatusRef = useRef("unknown");
77
75
  useEffect(() => {
78
- if (["running", "queued"].includes(prevSetupStatusRef.current)) {
76
+ if (["queued", "running"].includes(prevSetupStatusRef.current)) {
79
77
  if (setupStatus?.status === "complete") onComplete();
80
78
  if (setupStatus?.status === "error") onError(new Error(setupStatus.errorMessage));
81
79
  }
@@ -91,7 +89,7 @@ const useAndroidServiceAccount = ({ projectId, onError, onComplete }) => {
91
89
  const startUrl = `${androidKeyApiBase}/setup/`;
92
90
  const { data: updatedStatus } = await axios.post(startUrl, {}, { headers });
93
91
  queryClient.invalidateQueries({
94
- queryKey: cacheKeys.projectCredentials({ projectId, pageNumber: 0 })
92
+ queryKey: cacheKeys.projectCredentials({ pageNumber: 0, projectId })
95
93
  });
96
94
  await queryClient.setQueryData(cacheKeys.androidSetupStatus({ projectId }), (_) => updatedStatus);
97
95
  setIsStarting(false);
@@ -106,9 +104,9 @@ const useAndroidServiceAccount = ({ projectId, onError, onComplete }) => {
106
104
  const isCreating = isStarting || setupStatus?.status === "queued" || setupStatus?.status === "running";
107
105
  return {
108
106
  handleStart,
109
- setupStatus,
107
+ hasServiceAccountKey,
110
108
  isCreating,
111
- hasServiceAccountKey
109
+ setupStatus
112
110
  };
113
111
  };
114
112
 
@@ -116,12 +114,12 @@ const CreateServiceAccountKey = (props) => {
116
114
  const { gameId } = useContext(GameContext);
117
115
  return /* @__PURE__ */ jsx(Fragment, { children: gameId && /* @__PURE__ */ jsx(CreateForGame, { gameId, ...props }) });
118
116
  };
119
- const CreateForGame = ({ onComplete, onError, gameId, ...boxProps }) => {
117
+ const CreateForGame = ({ gameId, onComplete, onError, ...boxProps }) => {
120
118
  const [didStart, setDidStart] = useState(false);
121
- const { handleStart, setupStatus, isCreating } = useAndroidServiceAccount({
122
- projectId: gameId,
119
+ const { handleStart, isCreating, setupStatus } = useAndroidServiceAccount({
120
+ onComplete,
123
121
  onError,
124
- onComplete
122
+ projectId: gameId
125
123
  });
126
124
  useEffect(() => {
127
125
  handleStart().then(() => setDidStart(true));
@@ -1,22 +1,22 @@
1
1
  import axios from 'axios';
2
- import { p as getAuthedHeaders, q as API_URL, I as castArrayObjectDates } from './index-w3lHxk5O.js';
3
- import 'fs';
2
+ import { o as API_URL, p as getAuthedHeaders, I as castArrayObjectDates } from './index-pj8JVg5X.js';
3
+ import 'node:fs';
4
4
 
5
5
  async function getUserCredentials(pageSize = 100) {
6
6
  const headers = getAuthedHeaders();
7
7
  const { data } = await axios({
8
+ headers,
8
9
  method: "get",
9
- url: `${API_URL}/credentials?pageSize=${pageSize}`,
10
- headers
10
+ url: `${API_URL}/credentials?pageSize=${pageSize}`
11
11
  });
12
12
  return castArrayObjectDates(data.data);
13
13
  }
14
14
  async function getProjectCredentials(projectId, pageSize = 100) {
15
15
  const headers = getAuthedHeaders();
16
16
  const { data } = await axios({
17
+ headers,
17
18
  method: "get",
18
- url: `${API_URL}/projects/${projectId}/credentials?pageSize=${pageSize}`,
19
- headers
19
+ url: `${API_URL}/projects/${projectId}/credentials?pageSize=${pageSize}`
20
20
  });
21
21
  return castArrayObjectDates(data.data);
22
22
  }
@@ -1,17 +1,18 @@
1
1
  import { jsx, Fragment, jsxs } from 'react/jsx-runtime';
2
- import { Text, useInput, Box } from 'ink';
2
+ import { Text, Box } from 'ink';
3
3
  import open from 'open';
4
4
  import { useState, useEffect, useContext } from 'react';
5
- import { Q as getGoogleStatus, a2 as getShortAuthRequiredUrl, a8 as getGoogleAuthUrl, W as WEB_URL } from './index-w3lHxk5O.js';
6
- import 'crypto';
7
- import 'fs';
8
- import 'readline-sync';
9
- import 'node:readline';
5
+ import 'ink-spinner';
6
+ import 'node:crypto';
7
+ import 'node:fs';
10
8
  import 'node:path';
9
+ import 'node:readline';
11
10
  import 'node:url';
11
+ import 'readline-sync';
12
12
  import 'luxon';
13
13
  import 'axios';
14
14
  import 'isomorphic-git';
15
+ import { Q as getGoogleStatus, a2 as getShortAuthRequiredUrl, a3 as getGoogleAuthUrl, W as WEB_URL } from './index-pj8JVg5X.js';
15
16
  import '@oclif/core';
16
17
  import { useQuery } from '@tanstack/react-query';
17
18
  import 'crypto-js';
@@ -19,70 +20,52 @@ import 'uuid';
19
20
  import 'fast-glob';
20
21
  import 'yazl';
21
22
  import 'socket.io-client';
22
- import { u as useWebSocket } from './useWebSocket-gyuCsore.js';
23
- import { c as cacheKeys } from './useAndroidServiceAccountTestResult-Dy3Ag7_r.js';
24
- import { u as useScreenSize } from './Command-DFdHXDiU.js';
25
- import { b as GameContext, M as Markdown } from './index-CyvGh-kt.js';
26
- import 'ink-spinner';
27
- import '@inkjs/ui';
23
+ import { c as cacheKeys } from './useAndroidServiceAccountTestResult-D4e5AKAZ.js';
24
+ import { u as useWebSocket } from './useWebSocket-CRV7V69Q.js';
25
+ import 'fullscreen-ink';
26
+ import { G as GameContext, e as useSafeInput, M as Markdown } from './index-DfUg5j06.js';
28
27
  import 'string-length';
29
28
  import 'strip-ansi';
29
+ import '@inkjs/ui';
30
30
  import 'marked';
31
31
  import 'marked-terminal';
32
- import 'path';
33
32
  import qrcode from 'qrcode';
34
33
 
35
- const useGoogleStatus = () => {
36
- return useQuery({
37
- queryKey: cacheKeys.googleStatus(),
38
- queryFn: getGoogleStatus
39
- });
40
- };
34
+ const useGoogleStatus = () => useQuery({
35
+ queryFn: getGoogleStatus,
36
+ queryKey: cacheKeys.googleStatus()
37
+ });
41
38
 
42
39
  function useGoogleStatusWatching({
43
- projectId,
44
40
  isWatching,
45
- onGoogleStatusUpdate
41
+ onGoogleStatusUpdate,
42
+ projectId
46
43
  }) {
47
44
  const [wsGoogleStatus, setWsGoogleStatus] = useState(null);
48
45
  const listener = {
49
- getPattern: () => `project.${projectId}:google-status`,
50
- eventHandler: async (pattern, data2) => {
46
+ async eventHandler(pattern, data2) {
51
47
  setWsGoogleStatus(data2);
52
48
  if (onGoogleStatusUpdate) onGoogleStatusUpdate(data2);
53
- }
49
+ },
50
+ getPattern: () => `project.${projectId}:google-status`
54
51
  };
55
52
  useWebSocket([listener] );
56
- const { isLoading, data: googleStatus } = useGoogleStatus();
53
+ const { data: googleStatus, isLoading } = useGoogleStatus();
57
54
  useEffect(() => {
58
55
  setWsGoogleStatus(null);
59
56
  }, [projectId, isWatching, googleStatus]);
60
57
  const fetchedGoogleStatus = googleStatus ? googleStatus : null;
61
58
  const data = wsGoogleStatus ? wsGoogleStatus : fetchedGoogleStatus;
62
59
  return {
63
- isLoading,
64
- data
65
- };
66
- }
67
-
68
- const WIDE_BREAKPOINT = 100;
69
- const TALL_BREAKPOINT = 35;
70
- function useResponsive() {
71
- const { width, height } = useScreenSize();
72
- const isWide = width >= WIDE_BREAKPOINT;
73
- const isTall = height >= TALL_BREAKPOINT;
74
- return {
75
- width,
76
- height,
77
- isWide,
78
- isTall
60
+ data,
61
+ isLoading
79
62
  };
80
63
  }
81
64
 
82
65
  const QRCodeTerminal = ({ url }) => {
83
66
  const [code, setCode] = useState(null);
84
67
  const handleLoad = async () => {
85
- const codeString = await qrcode.toString(url, { type: "terminal", errorCorrectionLevel: "L", small: true });
68
+ const codeString = await qrcode.toString(url, { errorCorrectionLevel: "L", small: true, type: "terminal" });
86
69
  setCode(codeString);
87
70
  };
88
71
  useEffect(() => {
@@ -112,31 +95,38 @@ const ConnectGoogle = (props) => {
112
95
  const { gameId } = useContext(GameContext);
113
96
  return /* @__PURE__ */ jsx(Fragment, { children: gameId && /* @__PURE__ */ jsx(ConnectForGame, { gameId, ...props }) });
114
97
  };
115
- const ConnectForGame = ({ onComplete, onError, helpPage, gameId, ...boxProps }) => {
116
- const { isTall } = useResponsive();
117
- const [showQRCode, setShowQRCode] = useState(isTall);
98
+ const ConnectForGame = ({ gameId, helpPage, onComplete, onError, ...boxProps }) => {
99
+ const [showQRCode, setShowQRCode] = useState(false);
100
+ const [connectUrl, setConnectUrl] = useState(null);
101
+ useEffect(() => {
102
+ const fetchConnectUrl = async () => {
103
+ const url = await getConnectUrl(gameId, Boolean(helpPage));
104
+ setConnectUrl(url);
105
+ };
106
+ if (!connectUrl) fetchConnectUrl();
107
+ }, []);
118
108
  useGoogleStatusWatching({
119
- projectId: gameId,
120
109
  isWatching: true,
121
- onGoogleStatusUpdate: (status) => {
110
+ onGoogleStatusUpdate(status) {
122
111
  if (status.isAuthenticated) return onComplete();
123
- }
112
+ },
113
+ projectId: gameId
124
114
  });
125
- useInput(async (input) => {
115
+ useSafeInput(async (input) => {
126
116
  switch (input) {
127
- case "q":
117
+ case "q": {
128
118
  setShowQRCode(true);
129
119
  return;
130
- case "x":
120
+ }
121
+ case "x": {
131
122
  setShowQRCode(false);
132
123
  return;
133
- case "b":
124
+ }
125
+ case "b": {
134
126
  if (!gameId) return;
135
- const url = await getConnectUrl(gameId, true);
136
- await open(url);
137
- return;
138
- default:
139
- return;
127
+ if (!connectUrl) return;
128
+ await open(connectUrl);
129
+ }
140
130
  }
141
131
  });
142
132
  const templateVars = {
@@ -145,15 +135,15 @@ const ConnectForGame = ({ onComplete, onError, helpPage, gameId, ...boxProps })
145
135
  return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", gap: 1, ...boxProps, children: [
146
136
  !showQRCode && /* @__PURE__ */ jsxs(Box, { flexDirection: "column", gap: 1, children: [
147
137
  /* @__PURE__ */ jsx(Markdown, { filename: "privacy-notification.md", templateVars }),
148
- /* @__PURE__ */ jsx(Text, { bold: true, color: "#4CE64C", children: "Press B to open your browser and connect your Google account to ShipThis" }),
138
+ connectUrl && /* @__PURE__ */ jsx(Text, { bold: true, color: "#4CE64C", children: `Press B to open ${connectUrl} in your browser and connect your Google account to ShipThis` }),
149
139
  /* @__PURE__ */ jsx(Text, { bold: true, color: "#4CE64C", children: "Press Q to show a QR-code to connect using your mobile phone" })
150
140
  ] }),
151
141
  showQRCode && /* @__PURE__ */ jsxs(Box, { flexDirection: "column", gap: 1, children: [
152
142
  /* @__PURE__ */ jsx(Text, { children: "Scan the QR code below to connect your Google account to ShipThis:" }),
153
- gameId && /* @__PURE__ */ jsx(GoogleAuthQRCode, { gameId, helpPage: !!helpPage }),
143
+ gameId && /* @__PURE__ */ jsx(GoogleAuthQRCode, { gameId, helpPage: Boolean(helpPage) }),
154
144
  /* @__PURE__ */ jsx(Text, { bold: true, color: "#4CE64C", children: "Press X to hide the QR code" })
155
145
  ] })
156
146
  ] });
157
147
  };
158
148
 
159
- export { ConnectGoogle as C, useResponsive as u };
149
+ export { ConnectGoogle as C };
@@ -1,26 +1,27 @@
1
1
  import { jsx, Fragment, jsxs } from 'react/jsx-runtime';
2
- import { Text, useInput, Box } from 'ink';
3
- import React, { useState, useEffect, useContext, useRef } from 'react';
2
+ import { useStdin, useInput, Text, Box } from 'ink';
4
3
  import Spinner from 'ink-spinner';
5
4
  import open from 'open';
6
- import { g as getShortUUID, h as getPlatformName, s as scriptDir } from './index-DJ078v-U.js';
7
- import { c as cacheKeys, u as useAndroidServiceAccountTestResult, K as KeyTestStatus, a as KeyTestError } from './useAndroidServiceAccountTestResult-Dy3Ag7_r.js';
8
- import { p as getAuthedHeaders, q as API_URL, I as castArrayObjectDates, P as Platform, a5 as getShortDateTime, J as JobStatus, a6 as getShortTimeDelta, E as getJob, F as getProject, a2 as getShortAuthRequiredUrl, _ as queryClient, a7 as BuildType, W as WEB_URL } from './index-w3lHxk5O.js';
9
- import '@inkjs/ui';
10
- import axios from 'axios';
5
+ import React, { useState, useEffect, useContext, useRef } from 'react';
6
+ import { p as getAuthedHeaders, o as API_URL, I as castArrayObjectDates, P as Platform, a6 as getShortDateTime, J as JobStatus, a7 as getShortTimeDelta, z as getJob, E as getProject, a2 as getShortAuthRequiredUrl, K as queryClient, a8 as BuildType, W as WEB_URL } from './index-pj8JVg5X.js';
7
+ import { h as getPlatformName, g as getShortUUID, s as scriptDir } from './index-B27WJDxn.js';
11
8
  import { useQuery } from '@tanstack/react-query';
12
- import fs__default from 'fs';
9
+ import axios from 'axios';
10
+ import { c as cacheKeys, u as useAndroidServiceAccountTestResult, K as KeyTestStatus, a as KeyTestError } from './useAndroidServiceAccountTestResult-D4e5AKAZ.js';
11
+ import 'luxon';
12
+ import fs__default from 'node:fs';
13
+ import 'fast-glob';
13
14
  import 'uuid';
14
15
  import 'yazl';
16
+ import 'socket.io-client';
17
+ import 'fullscreen-ink';
18
+ import 'string-length';
19
+ import 'strip-ansi';
20
+ import '@inkjs/ui';
21
+ import path from 'node:path';
15
22
  import { setOptions, parse } from 'marked';
16
23
  import TerminalRenderer from 'marked-terminal';
17
- import path from 'path';
18
24
  import 'qrcode';
19
- import 'string-length';
20
- import 'strip-ansi';
21
- import 'luxon';
22
- import 'fast-glob';
23
- import 'socket.io-client';
24
25
 
25
26
  async function queryBuilds({ projectId, ...pageAndSortParams }) {
26
27
  try {
@@ -37,21 +38,21 @@ async function queryBuilds({ projectId, ...pageAndSortParams }) {
37
38
  }
38
39
  }
39
40
  function getBuildSummary(build) {
40
- const ext = build.buildType || (build.platform == Platform.IOS ? "IPA" : "AAB");
41
+ const ext = build.buildType || (build.platform === Platform.IOS ? "IPA" : "AAB");
41
42
  const filename = `game.${ext.toLowerCase()}`;
42
43
  return {
43
44
  id: getShortUUID(build.id),
44
45
  jobId: getShortUUID(build.jobId),
45
46
  ...getJobDetailsSummary(build.jobDetails),
46
- type: `${getPlatformName(build.platform)} ${build.buildType || ""}`.trim(),
47
+ cmd: `shipthis game build download ${getShortUUID(build.id)} ${filename}`,
47
48
  createdAt: getShortDateTime(build.createdAt),
48
- cmd: `shipthis game build download ${getShortUUID(build.id)} ${filename}`
49
+ type: `${getPlatformName(build.platform)} ${build.buildType || ""}`.trim()
49
50
  };
50
51
  }
51
52
  const useBuilds = (props) => {
52
53
  const queryResult = useQuery({
53
- queryKey: cacheKeys.builds(props),
54
- queryFn: async () => queryBuilds(props)
54
+ queryFn: async () => queryBuilds(props),
55
+ queryKey: cacheKeys.builds(props)
55
56
  });
56
57
  return queryResult;
57
58
  };
@@ -62,8 +63,8 @@ function getJobDetailsSummary(jobDetails) {
62
63
  const gitCommit = jobDetails?.gitCommitHash ? getShortUUID(jobDetails?.gitCommitHash) : "";
63
64
  const gitBranch = jobDetails?.gitBranch || "";
64
65
  return {
65
- version: `${semanticVersion} (${buildNumber})`,
66
- gitInfo: gitCommit ? `${gitCommit} (${gitBranch})` : ""
66
+ gitInfo: gitCommit ? `${gitCommit} (${gitBranch})` : "",
67
+ version: `${semanticVersion} (${buildNumber})`
67
68
  };
68
69
  }
69
70
  function getJobSummary(job, timeNow) {
@@ -71,65 +72,34 @@ function getJobSummary(job, timeNow) {
71
72
  return {
72
73
  id: getShortUUID(job.id),
73
74
  ...getJobDetailsSummary(job.details),
74
- platform: getPlatformName(job.type),
75
- status: job.status,
76
75
  createdAt: getShortDateTime(job.createdAt),
77
- runtime: getShortTimeDelta(job.createdAt, inProgress ? timeNow : job.updatedAt)
76
+ platform: getPlatformName(job.type),
77
+ runtime: getShortTimeDelta(job.createdAt, inProgress ? timeNow : job.updatedAt),
78
+ status: job.status
78
79
  };
79
80
  }
80
- const useJob = (props) => {
81
- return useQuery({
82
- queryKey: cacheKeys.job(props),
83
- queryFn: () => getJob(props.jobId, props.projectId)
84
- });
85
- };
86
-
87
- const CommandContext = React.createContext({
88
- command: null,
89
- setCommand: (command) => {
90
- }
81
+ const useJob = (props) => useQuery({
82
+ queryFn: () => getJob(props.jobId, props.projectId),
83
+ queryKey: cacheKeys.job(props)
91
84
  });
92
- const CommandProvider = (props) => {
93
- const [command, setCommand] = useState(props.command || null);
94
- return /* @__PURE__ */ jsx(CommandContext.Provider, { value: { command, setCommand }, children: props.children });
95
- };
96
85
 
97
- const GameContext = React.createContext({
98
- gameId: null,
99
- game: null,
100
- setGameId: (gameId) => {
101
- }
102
- });
103
- const GameProvider = ({ children }) => {
104
- const [gameId, setGameId] = useState(null);
105
- const [game, setGame] = useState(null);
106
- const { command } = React.useContext(CommandContext);
107
- const handleLoad = async () => {
108
- if (command) {
109
- const commandGameId = await command.getGameId();
110
- if (commandGameId) setGameId(commandGameId);
111
- }
112
- };
113
- const handleGameIdChange = async () => {
114
- if (!gameId) {
115
- setGame(null);
116
- return;
117
- }
118
- const game2 = await getProject(gameId);
119
- setGame(game2);
120
- };
121
- useEffect(() => {
122
- handleGameIdChange();
123
- }, [gameId]);
124
- useEffect(() => {
125
- handleLoad();
126
- }, [command]);
127
- return /* @__PURE__ */ jsx(GameContext.Provider, { value: { gameId, game, setGameId }, children });
86
+ const useSafeInput = (handler, options = { isActive: true }) => {
87
+ const { isRawModeSupported } = useStdin();
88
+ const isActive = isRawModeSupported === true && options.isActive !== false;
89
+ useInput(
90
+ (input, key) => {
91
+ const lowerInput = input.toLowerCase();
92
+ return handler(lowerInput, key);
93
+ },
94
+ { isActive }
95
+ );
128
96
  };
129
97
 
130
- const cleanHyperlinks = (input) => {
131
- return input.replace(/\x1b]8;;[^\x07]*\x07/g, "").replace(/\x1b]8;;\x07/g, "");
132
- };
98
+ const cleanHyperlinks = (input) => (
99
+ // When we run in a <ScrollArea> the links break
100
+ // Remove OSC 8 hyperlink wrappers but preserve the styled content inside
101
+ input.replaceAll(/\u001B]8;;[^\u0007]*\u0007/g, "").replaceAll("\x1B]8;;\x07", "")
102
+ );
133
103
  const getRenderedMarkdown = ({ filename, templateVars, ...options }) => {
134
104
  setOptions({
135
105
  renderer: new TerminalRenderer({
@@ -142,10 +112,8 @@ const getRenderedMarkdown = ({ filename, templateVars, ...options }) => {
142
112
  const mdTemplate = fs__default.readFileSync(mdPath, "utf8").trim();
143
113
  let markdown = mdTemplate;
144
114
  if (templateVars) {
145
- markdown = markdown.replace(/\${if (.*?)\}([\s\S]*?)\${endif}/g, (_, key, content) => {
146
- return templateVars[key.trim()] ? content : "";
147
- });
148
- markdown = markdown.replace(/\${(.*?)}/g, (_, key) => {
115
+ markdown = markdown.replaceAll(/\${if (.*?)}([\S\s]*?)\${endif}/g, (_, key, content) => templateVars[key.trim()] ? content : "");
116
+ markdown = markdown.replaceAll(/\${(.*?)}/g, (_, key) => {
149
117
  const trimmed = key.trim();
150
118
  return templateVars[trimmed] ? String(templateVars[trimmed]) : "";
151
119
  });
@@ -163,6 +131,40 @@ const Markdown = ({ filename, templateVars, ...options }) => {
163
131
  return /* @__PURE__ */ jsx(Text, { children: text });
164
132
  };
165
133
 
134
+ const CommandContext = React.createContext({
135
+ command: null,
136
+ setCommand(command) {
137
+ }
138
+ });
139
+ const CommandProvider = (props) => {
140
+ const [command, setCommand] = useState(props.command || null);
141
+ return /* @__PURE__ */ jsx(CommandContext.Provider, { value: { command, setCommand }, children: props.children });
142
+ };
143
+
144
+ const GameContext = React.createContext({
145
+ game: null,
146
+ gameId: null,
147
+ setGameId(gameId) {
148
+ }
149
+ });
150
+ const GameProvider = ({ children }) => {
151
+ const { command } = React.useContext(CommandContext);
152
+ const [gameId, setGameId] = useState(command?.getGameId() || null);
153
+ const [game, setGame] = useState(null);
154
+ const handleGameIdChange = async () => {
155
+ if (!gameId) {
156
+ setGame(null);
157
+ return;
158
+ }
159
+ const game2 = await getProject(gameId);
160
+ setGame(game2);
161
+ };
162
+ useEffect(() => {
163
+ handleGameIdChange();
164
+ }, [gameId]);
165
+ return /* @__PURE__ */ jsx(GameContext.Provider, { value: { game, gameId, setGameId }, children });
166
+ };
167
+
166
168
  scriptDir(import.meta);
167
169
  const getIsAppFound = (result) => {
168
170
  const isFound = result?.status === KeyTestStatus.SUCCESS || result?.status === KeyTestStatus.ERROR && result?.error === KeyTestError.NOT_INVITED;
@@ -172,9 +174,9 @@ const CreateGooglePlayGame = (props) => {
172
174
  const { gameId } = useContext(GameContext);
173
175
  return /* @__PURE__ */ jsx(Fragment, { children: gameId && /* @__PURE__ */ jsx(Create, { gameId, ...props }) });
174
176
  };
175
- const Create = ({ onComplete, onError, gameId, ...boxProps }) => {
177
+ const Create = ({ gameId, onComplete, onError, ...boxProps }) => {
176
178
  const { data: result, isFetching } = useAndroidServiceAccountTestResult({ projectId: gameId });
177
- const { data: builds } = useBuilds({ projectId: gameId, pageNumber: 0 });
179
+ const { data: builds } = useBuilds({ pageNumber: 0, projectId: gameId });
178
180
  const previousIsFound = useRef(false);
179
181
  useEffect(() => {
180
182
  const isFound = getIsAppFound(result);
@@ -183,30 +185,29 @@ const Create = ({ onComplete, onError, gameId, ...boxProps }) => {
183
185
  }
184
186
  previousIsFound.current = isFound;
185
187
  }, [result]);
186
- useInput(async (input) => {
188
+ useSafeInput(async (input) => {
187
189
  if (!gameId) return;
188
190
  switch (input) {
189
- case "r":
191
+ case "r": {
190
192
  queryClient.invalidateQueries({
191
193
  queryKey: cacheKeys.androidKeyTestResult({ projectId: gameId })
192
194
  });
193
195
  break;
194
- case "d":
196
+ }
197
+ case "d": {
195
198
  const dashUrl = await getShortAuthRequiredUrl(`/games/${getShortUUID(gameId)}/builds`);
196
199
  await open(dashUrl);
200
+ break;
201
+ }
197
202
  }
198
- if (input !== "r") return;
199
- queryClient.invalidateQueries({
200
- queryKey: cacheKeys.androidKeyTestResult({ projectId: gameId })
201
- });
202
- });
203
- const initialBuild = builds?.data.find((build) => {
204
- return build.platform === Platform.ANDROID && build.buildType === BuildType.AAB;
205
203
  });
204
+ const initialBuild = builds?.data.find(
205
+ (build) => build.platform === Platform.ANDROID && build.buildType === BuildType.AAB
206
+ );
206
207
  const downloadCmd = initialBuild ? `${getBuildSummary(initialBuild).cmd}` : "Initial AAB build not found!";
207
208
  const templateVars = {
208
- downloadCmd,
209
- dashboardURL: new URL(`/games/${getShortUUID(gameId)}/builds`, WEB_URL).toString()
209
+ dashboardURL: new URL(`/games/${getShortUUID(gameId)}/builds`, WEB_URL).toString(),
210
+ downloadCmd
210
211
  };
211
212
  return /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsxs(Box, { flexDirection: "column", gap: 1, ...boxProps, children: [
212
213
  /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
@@ -217,4 +218,4 @@ const Create = ({ onComplete, onError, gameId, ...boxProps }) => {
217
218
  ] }) });
218
219
  };
219
220
 
220
- export { CommandProvider as C, GameProvider as G, Markdown as M, getJobSummary as a, GameContext as b, getBuildSummary as c, CommandContext as d, useJob as e, CreateGooglePlayGame as f, getRenderedMarkdown as g, queryBuilds as q, useBuilds as u };
221
+ export { CommandContext as C, GameContext as G, Markdown as M, getJobSummary as a, CommandProvider as b, GameProvider as c, getBuildSummary as d, useSafeInput as e, useJob as f, getRenderedMarkdown as g, CreateGooglePlayGame as h, queryBuilds as q, useBuilds as u };