Repository: JoshuaKGoldberg/create-typescript-app (ts)

Issue:
🐛 Bug: Crashes if run without a logged-in gh user
### Bug Report Checklist

- [x] I have tried restarting my IDE and the issue persists.
- [x] I have pulled the latest `main` branch of the repository.
- [x] I have [searched for related issues](https://github.com/JoshuaKGoldberg/create-typescript-app/issues?q=is%3Aissue) and found none that matched my issue.

### Expected

Running `npx create-typescript-app` when the user either doesn't have `gh` installed or is logged out (`gh auth logout`) should still work. There should be a warning in Bingo about not being able to create a repo, but that's it.

### Actual

```plaintext
npx create-typescript-app --directory cta-auth-test
┌  ✨ create-typescript-app@2.4.1 ✨
│
●  Learn more on:
│    https://github.com/JoshuaKGoldberg/create-typescript-app
│
◇  Running with mode --setup using the template:
│    create-typescript-app
│
■  Error inferring default options from system:
│
■  TypeError: Cannot read properties of undefined (reading 'avatar_url')
│      at readAllContributors (file:///Users/josh/.npm/_npx/4aa729db9999bfc4/node_modules/create-typescript-app/lib/options/readAllContributors.js:16:24)
│      at runNextTicks (node:internal/process/task_queues:65:5)
│      at listOnTimeout (node:internal/timers:555:9)
│      at process.processTimers (node:internal/timers:529:7)
│      at async Promise.all (index 2)
│      at async awaitLazyProperties (file:///Users/josh/.npm/_npx/4aa729db9999bfc4/node_modules/bingo/lib/utils/awaitLazyProperties.js:21:5)
│      at async prepareOptions (file:///Users/josh/.npm/_npx/4aa729db9999bfc4/node_modules/bingo/lib/preparation/prepareOptions.js:23:12)
│      at async file:///Users/josh/.npm/_npx/4aa729db9999bfc4/node_modules/bingo/lib/cli/setup/runModeSetup.js:40:16
│      at async tryCatchError (file:///Users/josh/.npm/_npx/4aa729db9999bfc4/node_modules/bingo/lib/utils/tryCatch.js:3:16)
│      at async runSpinnerTask (file:///Users/josh/.npm/_npx/4aa729db9999bfc4/node_modules/bingo/lib/cli/display/runSpinnerTask.js:6:20)
│
●  Tip: to run again with the same input values, use: npx bingo --directory cta-auth-test --directory cta-auth-test
│
■  Error: Cannot read properties of undefined (reading 'avatar_url')
│
└  Operation cancelled. Exiting - maybe another time? 👋
```

### Additional Info

I think there'll also be an underlying bug in Bingo as well. But we can't get that far because default options inference in the CTA layer is crashing.

Reported by Nate May on Bluesky: https://bsky.app/profile/natemay.bsky.social/post/3ljqx5jklyc2b

🎁 

Pull request:
fix: don't crash reading contributors when not logged into GitHub
## PR Checklist

- [x] Addresses an existing open issue: fixes #1971
- [x] That issue was marked as [`status: accepting prs`](https://github.com/JoshuaKGoldberg/create-typescript-app/issues?q=is%3Aopen+is%3Aissue+label%3A%22status%3A+accepting+prs%22)
- [x] Steps in [CONTRIBUTING.md](https://github.com/JoshuaKGoldberg/create-typescript-app/blob/main/.github/CONTRIBUTING.md) were taken

## Overview

The `GET /user` result can be `undefined` if the user isn't logged in.

🎁 

Patch:
diff --git a/src/options/readAllContributors.ts b/src/options/readAllContributors.ts
index 2d5e037..6a6d9eb 100644
--- a/src/options/readAllContributors.ts
+++ b/src/options/readAllContributors.ts
@@ -16,15 +16,19 @@ export async function readAllContributors(take: TakeInput) {
 
 	const user = (await take(inputFromOctokit, {
 		endpoint: "GET /user",
-	})) as { avatar_url: string; blog: string; login: string; name: string };
+	})) as
+		| undefined
+		| { avatar_url: string; blog: string; login: string; name: string };
 
-	return [
-		{
-			avatar_url: user.avatar_url,
-			contributions: ownerContributions,
-			login: user.login,
-			name: user.name,
-			profile: user.blog,
-		},
-	];
+	return (
+		user && [
+			{
+				avatar_url: user.avatar_url,
+				contributions: ownerContributions,
+				login: user.login,
+				name: user.name,
+				profile: user.blog,
+			},
+		]
+	);
 }


Test patch:
diff --git a/src/options/readAllContributors.test.ts b/src/options/readAllContributors.test.ts
index 5275753..aac45a8 100644
--- a/src/options/readAllContributors.test.ts
+++ b/src/options/readAllContributors.test.ts
@@ -33,7 +33,16 @@ describe(readAllContributors, () => {
 		expect(mockInputFromOctokit).not.toHaveBeenCalled();
 	});
 
-	it("returns the current user as a contributor when .all-contributorsrc cannot be read", async () => {
+	it("returns undefined when .all-contributorsrc cannot be read and GET /user resolves undefined", async () => {
+		mockInputFromFileJSON.mockResolvedValueOnce(new Error("Oh no!"));
+		mockInputFromOctokit.mockResolvedValueOnce(undefined);
+
+		const actual = await readAllContributors(take);
+
+		expect(actual).toBeUndefined();
+	});
+
+	it("returns the current user as a contributor when .all-contributorsrc cannot be read and GET /user resolves a user", async () => {
 		mockInputFromFileJSON.mockResolvedValueOnce(new Error("Oh no!"));
 		mockInputFromOctokit.mockResolvedValueOnce({
 			avatar_url: "avatar_url",