UNPKG

shipthis

Version:

ShipThis manages building and uploading your Godot games to the App Store and Google Play.

179 lines (173 loc) 7.47 kB
import { jsx, Fragment, jsxs } from 'react/jsx-runtime'; import { Box, Text } from 'ink'; import Spinner from 'ink-spinner'; import { useState, useRef, useEffect, useContext } from 'react'; import 'node:crypto'; import 'node:fs'; import 'node:path'; import 'node:readline'; import 'node:url'; import 'readline-sync'; import { p as getAuthedHeaders, o as API_URL, a4 as castObjectDates, H as queryClient, Q as revokePolicy, O as enforcePolicy, P as Platform, C as CredentialsType, M as getGoogleStatus, c as getShortDate } from './baseCommand-CTn3KGH3.js'; import axios from 'axios'; import 'isomorphic-git'; import '@oclif/core'; import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; import 'luxon'; import { k as cacheKeys, G as GameContext, w as useSafeInput, M as Markdown } from './baseGameCommand-8VL7xe-O.js'; import 'fast-glob'; import 'uuid'; import 'yazl'; import 'socket.io-client'; import 'fullscreen-ink'; import { u as useWebSocket } from './useWebSocket-MXDbQHcu.js'; import { u as useProjectCredentials } from './useProjectCredentials-TvlolkId.js'; import { u as useGoogleStatus } from './useGoogleStatus-WqPgHteE.js'; import 'crypto-js'; import 'string-length'; import 'strip-ansi'; import 'open'; import '@inkjs/ui'; import { P as ProgressSpinner } from './ProgressSpinner-Um6ARKlk.js'; import 'qrcode'; async function fetchStatus({ projectId }) { try { if (!projectId) throw new Error("projectId is required"); const headers = getAuthedHeaders(); const url = `${API_URL}/projects/${projectId}/credentials/android/key/status/`; const response = await axios.get(url, { headers }); return castObjectDates(response.data); } catch (error) { console.warn("fetchStatus Error", error); throw error; } } const useAndroidServiceAccountSetupStatus = (props) => useQuery({ queryFn: () => fetchStatus(props), queryKey: cacheKeys.androidSetupStatus(props), // Status changes frequently, so we want to keep it fresh refetchInterval: 1e3 * 5, staleTime: 1e3 * 5 }); const useUpdateGoogleOrgPolicy = () => useMutation({ async mutationFn(props) { if (props.action === "revoke") { return await revokePolicy(); } return await enforcePolicy(); }, async onSuccess(data) { queryClient.invalidateQueries({ queryKey: cacheKeys.googleStatus() }); } }); const ERR_NOT_AUTHENTICATED = "You must be connected to Google to create a Service Account Key"; const useHasServiceAccountKey = (projectId) => { const { data, isSuccess } = useProjectCredentials({ platform: Platform.ANDROID, projectId }); return isSuccess && data.data.some((cred) => cred.isActive && cred.platform === Platform.ANDROID && cred.type === CredentialsType.KEY); }; const useAndroidServiceAccount = ({ onComplete, onError, projectId }) => { const queryClient = useQueryClient(); const [isStarting, setIsStarting] = useState(false); const hasServiceAccountKey = useHasServiceAccountKey(projectId); const listener = { async eventHandler(pattern, data) { const key = cacheKeys.androidSetupStatus({ projectId }); queryClient.setQueryData(key, () => data); }, getPattern: () => `project.${projectId}:android-setup-status` }; useWebSocket([listener]); const { data: setupStatus } = useAndroidServiceAccountSetupStatus({ projectId }); const prevSetupStatusRef = useRef("unknown"); useEffect(() => { if (["queued", "running"].includes(prevSetupStatusRef.current)) { if (setupStatus?.status === "complete") onComplete(); if (setupStatus?.status === "error") onError(new Error(setupStatus.errorMessage)); } prevSetupStatusRef.current = setupStatus?.status || "unknown"; }, [setupStatus]); const handleStart = async () => { try { setIsStarting(true); const currentStatus = await getGoogleStatus(); if (!currentStatus.isAuthenticated) throw new Error(ERR_NOT_AUTHENTICATED); const headers = getAuthedHeaders(); const androidKeyApiBase = `${API_URL}/projects/${projectId}/credentials/android/key`; const startUrl = `${androidKeyApiBase}/setup/`; const { data: updatedStatus } = await axios.post(startUrl, {}, { headers }); queryClient.invalidateQueries({ queryKey: cacheKeys.projectCredentials({ pageNumber: 0, projectId }) }); await queryClient.setQueryData(cacheKeys.androidSetupStatus({ projectId }), (_) => updatedStatus); setIsStarting(false); return true; } catch (error) { setIsStarting(false); console.warn("useAndroidServiceAccount.handleStart Error", error); onError(error); return false; } }; const isCreating = isStarting || setupStatus?.status === "queued" || setupStatus?.status === "running"; return { handleStart, hasServiceAccountKey, isCreating, setupStatus }; }; const CreateServiceAccountKey = (props) => { const { gameId } = useContext(GameContext); return /* @__PURE__ */ jsx(Fragment, { children: gameId && /* @__PURE__ */ jsx(CreateForGame, { gameId, ...props }) }); }; const CreateForGame = ({ gameId, onComplete, onError, ...boxProps }) => { const [didStart, setDidStart] = useState(false); const startedRef = useRef(false); const { data: googleStatus } = useGoogleStatus(); const updatePolicyMutation = useUpdateGoogleOrgPolicy(); const { handleStart, isCreating, setupStatus } = useAndroidServiceAccount({ onComplete, onError, projectId: gameId }); useEffect(() => { if (startedRef.current) return; if (!googleStatus) return; if (!googleStatus.needsPolicyChange) { startedRef.current = true; handleStart().then(() => setDidStart(true)).catch((error) => onError(error)); } }, [googleStatus]); useSafeInput((input) => { if (input === "p" && googleStatus?.needsPolicyChange && !updatePolicyMutation.isPending) { updatePolicyMutation.mutate({ action: "revoke" }); } }); const needsPolicy = Boolean(googleStatus?.needsPolicyChange); const policyChanging = updatePolicyMutation.isPending || updatePolicyMutation.isSuccess && needsPolicy; const Header = () => /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [ /* @__PURE__ */ jsx(Text, { children: "Creating a Service Account and API Key..." }), isCreating && /* @__PURE__ */ jsx(Spinner, { type: "dots" }) ] }); return /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsxs(Box, { flexDirection: "column", gap: 1, ...boxProps, children: [ needsPolicy ? policyChanging ? /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [ /* @__PURE__ */ jsx(Text, { children: "Updating organization policy..." }), /* @__PURE__ */ jsx(Spinner, { type: "dots" }) ] }) : googleStatus && /* @__PURE__ */ jsx( Markdown, { filename: "service-account-policy-wizard.md.ejs", templateVars: { needsPolicyChange: Boolean(googleStatus.needsPolicyChange), orgCreatedAt: googleStatus.orgCreatedAt ? getShortDate(googleStatus.orgCreatedAt) : "Unknown", orgName: `${googleStatus.orgName}`, orgResourceName: `${googleStatus.orgResourceName}` } } ) : /* @__PURE__ */ jsx(Header, {}), didStart && /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsx(ProgressSpinner, { progress: (setupStatus?.progress || 0) * 100, spinnerType: "dots" }) }) ] }) }); }; export { CreateServiceAccountKey as C };