Skip to content

Commit f533988

Browse files
Update most dependencies (#1081)
Co-authored-by: me <me@kentcdodds.com> Co-authored-by: Cursor Agent <cursoragent@cursor.com>
1 parent 2abbd5b commit f533988

File tree

30 files changed

+5801
-5108
lines changed

30 files changed

+5801
-5108
lines changed

app/routes/_auth/auth.$provider/callback.test.ts

Lines changed: 13 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,11 @@ import { loader } from './callback.ts'
1919

2020
const ROUTE_PATH = '/auth/github/callback'
2121
const PARAMS = { provider: 'github' }
22+
const LOADER_ARGS_BASE = {
23+
params: PARAMS,
24+
context: {} as AppLoadContext,
25+
unstable_pattern: ROUTE_PATH,
26+
}
2227

2328
afterEach(async () => {
2429
await deleteGitHubUsers()
@@ -28,8 +33,7 @@ test('a new user goes to onboarding', async () => {
2833
const request = await setupRequest()
2934
const response = await loader({
3035
request,
31-
params: PARAMS,
32-
context: {} as AppLoadContext,
36+
...LOADER_ARGS_BASE,
3337
}).catch((e) => e)
3438
expect(response).toHaveRedirect('/onboarding/github')
3539
})
@@ -44,8 +48,7 @@ test('when auth fails, send the user to login with a toast', async () => {
4448
const request = await setupRequest()
4549
const response = await loader({
4650
request,
47-
params: PARAMS,
48-
context: {} as AppLoadContext,
51+
...LOADER_ARGS_BASE,
4952
}).catch((e) => e)
5053
invariant(response instanceof Response, 'response should be a Response')
5154
expect(response).toHaveRedirect('/login')
@@ -67,8 +70,7 @@ test('when a user is logged in, it creates the connection', async () => {
6770
})
6871
const response = await loader({
6972
request,
70-
params: PARAMS,
71-
context: {} as AppLoadContext,
73+
...LOADER_ARGS_BASE,
7274
})
7375
expect(response).toHaveRedirect('/settings/profile/connections')
7476
await expect(response).toSendToast(
@@ -107,8 +109,7 @@ test(`when a user is logged in and has already connected, it doesn't do anything
107109
})
108110
const response = await loader({
109111
request,
110-
params: PARAMS,
111-
context: {} as AppLoadContext,
112+
...LOADER_ARGS_BASE,
112113
})
113114
expect(response).toHaveRedirect('/settings/profile/connections')
114115
await expect(response).toSendToast(
@@ -126,8 +127,7 @@ test('when a user exists with the same email, create connection and make session
126127
const request = await setupRequest({ code: githubUser.code })
127128
const response = await loader({
128129
request,
129-
params: PARAMS,
130-
context: {} as AppLoadContext,
130+
...LOADER_ARGS_BASE,
131131
})
132132

133133
expect(response).toHaveRedirect('/')
@@ -174,8 +174,7 @@ test('gives an error if the account is already connected to another user', async
174174
})
175175
const response = await loader({
176176
request,
177-
params: PARAMS,
178-
context: {} as AppLoadContext,
177+
...LOADER_ARGS_BASE,
179178
})
180179
expect(response).toHaveRedirect('/settings/profile/connections')
181180
await expect(response).toSendToast(
@@ -201,8 +200,7 @@ test('if a user is not logged in, but the connection exists, make a session', as
201200
const request = await setupRequest({ code: githubUser.code })
202201
const response = await loader({
203202
request,
204-
params: PARAMS,
205-
context: {} as AppLoadContext,
203+
...LOADER_ARGS_BASE,
206204
})
207205
expect(response).toHaveRedirect('/')
208206
await expect(response).toHaveSessionForUser(userId)
@@ -229,8 +227,7 @@ test('if a user is not logged in, but the connection exists and they have enable
229227
const request = await setupRequest({ code: githubUser.code })
230228
const response = await loader({
231229
request,
232-
params: PARAMS,
233-
context: {} as AppLoadContext,
230+
...LOADER_ARGS_BASE,
234231
})
235232
const searchParams = new URLSearchParams({
236233
type: twoFAVerificationType,

app/utils/cache.server.ts

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,15 @@ const CACHE_DATABASE_PATH = process.env.CACHE_DATABASE_PATH
2424
const cacheDb = remember('cacheDb', createDatabase)
2525

2626
function createDatabase(tryAgain = true): DatabaseSync {
27-
const parentDir = path.dirname(CACHE_DATABASE_PATH)
27+
const databasePath = CACHE_DATABASE_PATH
28+
if (!databasePath) {
29+
throw new Error('CACHE_DATABASE_PATH is not set')
30+
}
31+
32+
const parentDir = path.dirname(databasePath)
2833
fs.mkdirSync(parentDir, { recursive: true })
2934

30-
const db = new DatabaseSync(CACHE_DATABASE_PATH)
35+
const db = new DatabaseSync(databasePath)
3136
const { currentIsPrimary } = getInstanceInfoSync()
3237
if (!currentIsPrimary) return db
3338

@@ -41,10 +46,21 @@ function createDatabase(tryAgain = true): DatabaseSync {
4146
)
4247
`)
4348
} catch (error: unknown) {
44-
fs.unlinkSync(CACHE_DATABASE_PATH)
49+
try {
50+
fs.rmSync(databasePath, { force: true })
51+
} catch (unlinkError) {
52+
if (
53+
typeof unlinkError !== 'object' ||
54+
unlinkError === null ||
55+
!('code' in unlinkError) ||
56+
unlinkError.code !== 'ENOENT'
57+
) {
58+
throw unlinkError
59+
}
60+
}
4561
if (tryAgain) {
4662
console.error(
47-
`Error creating cache database, deleting the file at "${CACHE_DATABASE_PATH}" and trying again...`,
63+
`Error creating cache database, deleting the file at "${databasePath}" and trying again...`,
4864
)
4965
return createDatabase(false)
5066
}

app/utils/storage.server.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ async function uploadToStorage(file: File | FileUpload, key: string) {
1414
const uploadResponse = await fetch(url, {
1515
method: 'PUT',
1616
headers,
17-
body: file instanceof File ? file : file.stream(),
17+
body: file instanceof File ? file : (file as FileUpload).stream(),
1818
})
1919

2020
if (!uploadResponse.ok) {

docs/authentication.md

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -43,13 +43,12 @@ is a precondition for a "Mock GitHub server" to be installed (with the help of
4343
[module](../tests/mocks/github.ts) for more details and pay attention to how the
4444
calls to `https://github.com/login/oauth/access_token` are being intercepted.
4545
But once deployed to an environment where `process.env.MOCKS` is not set to
46-
`'true'` (see how this is done when launching the
47-
[server](../server/index.ts) and checked in the
48-
[entrypoint](../index.ts)), or even when developing _locally_ but not setting
49-
`GITHUB_CLIENT_ID` to `MOCK_...`, the requests will actually reach the GitHub
50-
auth server. This is where you will want to have a GitHub OAuth application
51-
properly set up, otherwise the logging in with GitHub will fail and a
52-
corresponding toast will appear on the screen.
46+
`'true'` (see how this is done when launching the [server](../server/index.ts)
47+
and checked in the [entrypoint](../index.ts)), or even when developing _locally_
48+
but not setting `GITHUB_CLIENT_ID` to `MOCK_...`, the requests will actually
49+
reach the GitHub auth server. This is where you will want to have a GitHub OAuth
50+
application properly set up, otherwise the logging in with GitHub will fail and
51+
a corresponding toast will appear on the screen.
5352

5453
To set up a real OAuth application, log in to GitHub, go to
5554
`Settings -> Developer settings -> OAuth Apps`, and hit the

docs/database.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -300,7 +300,6 @@ You've got a few options:
300300
re-generating the migration after fixing the error.
301301
3. If you do care about the data and don't have a backup, you can follow these
302302
steps:
303-
304303
1. Comment out the
305304
[`exec` section from `litefs.yml` file](https://github.com/epicweb-dev/epic-stack/blob/main/other/litefs.yml#L31-L37).
306305

docs/decisions/031-imports.md

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,9 @@ and manually modify.
2828
Despite the magic of Path aliases, they are actually a standard `package.json`
2929
supported feature. Sort of.
3030
[The `"imports"` field](https://nodejs.org/api/packages.html#imports) in
31-
`package.json` allows you to configure aliases for your imports.
32-
TypeScript also uses this for its own Path aliases since version 5.4
33-
so you get autocomplete and type checking for your imports.
31+
`package.json` allows you to configure aliases for your imports. TypeScript also
32+
uses this for its own Path aliases since version 5.4 so you get autocomplete and
33+
type checking for your imports.
3434

3535
By using the `"imports"` field, you don't have to do any special configuration
3636
for `vitest` or `eslint` to be able to resolve imports. They just resolve them
@@ -44,7 +44,8 @@ again it's just a matter of familiarity. So it's no big deal.
4444

4545
## Decision
4646

47-
We're going to configure `"imports"` in the `package.json` to use path aliases for imports.
47+
We're going to configure `"imports"` in the `package.json` to use path aliases
48+
for imports.
4849

4950
We'll set it to `"#*": "./*"` which will allow us to import anything in the root
5051
of the repo with `#<dirname>/<filepath>`.

docs/decisions/039-passkeys.md

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ username/password and OAuth providers. While these methods are widely used, they
1111
come with various security challenges:
1212

1313
1. Password-based authentication:
14-
1514
- Users often reuse passwords across services
1615
- Passwords can be phished or stolen
1716
- Password management is a burden for users
@@ -39,14 +38,12 @@ using:
3938
The authentication flow works as follows:
4039

4140
1. Registration:
42-
4341
- Server generates a challenge and sends registration options
4442
- Client creates a new key pair and signs the challenge with the private key
4543
- Public key and metadata are sent to the server for storage
4644
- Private key remains securely stored in the authenticator
4745

4846
2. Authentication:
49-
5047
- Server generates a new challenge
5148
- Client signs it with the stored private key
5249
- Server verifies the signature using the stored public key
@@ -64,19 +61,16 @@ While passkeys represent the future of authentication, we maintain support for
6461
password and OAuth authentication because:
6562

6663
1. Adoption and Transition:
67-
6864
- Passkey support is still rolling out across platforms and browsers
6965
- Users need time to become comfortable with the new technology
7066
- Organizations may have existing requirements for specific auth methods
7167

7268
2. Fallback Options:
73-
7469
- Some users may not have compatible devices
7570
- Enterprise environments might restrict biometric authentication
7671
- Backup authentication methods provide reliability
7772

7873
3. User Choice:
79-
8074
- Different users have different security/convenience preferences
8175
- Some scenarios may require specific authentication types
8276
- Supporting multiple methods maximizes accessibility
@@ -112,43 +106,37 @@ We chose SimpleWebAuthn because:
112106
### Positive:
113107

114108
1. Enhanced Security for Users:
115-
116109
- Phishing-resistant authentication adds protection against common attacks
117110
- Hardware-backed security provides stronger guarantees than passwords alone
118111
- Biometric authentication reduces risk of credential sharing
119112

120113
2. Improved User Experience Options:
121-
122114
- Users can choose between password, OAuth, or passkey based on their needs
123115
- Native biometric flows provide fast and familiar authentication
124116
- Password manager integration enables seamless cross-device access
125117
- Multiple authentication methods increase accessibility
126118

127119
3. Future-Proofing Authentication:
128-
129120
- Adoption of web standard
130121
- Gradual transition path as passkey support grows
131122
- Meeting evolving security best practices
132123

133124
### Negative:
134125

135126
1. Implementation Complexity:
136-
137127
- WebAuthn is a complex specification
138128
- Need to handle various device capabilities
139129
- Must maintain backward compatibility
140130
- Need to maintain password-based auth as fallback
141131

142132
2. User Education:
143-
144133
- New technology requires user education
145134
- Some users may be hesitant to adopt
146135
- Need clear documentation and UI guidance
147136

148137
### Neutral:
149138

150139
1. Data Storage:
151-
152140
- New database model for passkeys
153141
- Additional storage requirements per user
154142
- Migration path for existing users

docs/decisions/043-pwnedpasswords.md

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,22 +22,19 @@ However, we wanted to implement this in a way that:
2222
We will integrate the HaveIBeenPwned Password API with the following approach:
2323

2424
1. **Progressive Enhancement**
25-
2625
- The password check is implemented as a non-blocking enhancement
2726
- If the check fails or times out (>1s), we allow the password
2827
- This ensures users can still set passwords even if the service is
2928
unavailable
3029

3130
2. **Development Experience**
32-
3331
- The API calls are mocked during development and testing using MSW (Mock
3432
Service Worker)
3533
- This prevents unnecessary API calls during development
3634
- Allows for consistent testing behavior
3735
- Follows our pattern of mocking external services
3836

3937
3. **Error Handling**
40-
4138
- Timeout after 1 second to prevent blocking users
4239
- Graceful fallback if the service is unavailable
4340
- Warning logs for monitoring service health

docs/decisions/044-rr-devtools.md

Lines changed: 33 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -6,34 +6,33 @@ Status: accepted
66

77
## Context
88

9-
Epic Stack uses React Router for routing. React Router is a powerful
10-
library, but it can be difficult to debug and visualize the routing
11-
in your application. This is especially true when you have a complex
12-
routing structure with nested routes, dynamic routes, and you rely
13-
on data functions like loaders and actions, which the Epic Stack does.
14-
15-
It is also hard to know which routes are currently active
16-
(which ones are rendered) and if any if the loaders are triggered
17-
when you expect them to be. This can lead to confusion and frustration
18-
and the use of console.log statements to debug the routing in your
19-
application.
20-
21-
This is where the React Router DevTools come in. The React
22-
Router DevTools are a set of tools that do all of these things for you.
23-
24-
React Router has a set of DevTools that help debug and visualize the
25-
routing in your application. The DevTools allow you to see the
26-
current route information, including the current location, the matched
27-
routes, and the route hierarchy. This can be very helpful when debugging
28-
your applications. The DevTools also hook into your server-side by
29-
wrapping loaders and actions, allowing you to get extensive
30-
information about the data being loaded and the actions being dispatched.
9+
Epic Stack uses React Router for routing. React Router is a powerful library,
10+
but it can be difficult to debug and visualize the routing in your application.
11+
This is especially true when you have a complex routing structure with nested
12+
routes, dynamic routes, and you rely on data functions like loaders and actions,
13+
which the Epic Stack does.
14+
15+
It is also hard to know which routes are currently active (which ones are
16+
rendered) and if any if the loaders are triggered when you expect them to be.
17+
This can lead to confusion and frustration and the use of console.log statements
18+
to debug the routing in your application.
19+
20+
This is where the React Router DevTools come in. The React Router DevTools are a
21+
set of tools that do all of these things for you.
22+
23+
React Router has a set of DevTools that help debug and visualize the routing in
24+
your application. The DevTools allow you to see the current route information,
25+
including the current location, the matched routes, and the route hierarchy.
26+
This can be very helpful when debugging your applications. The DevTools also
27+
hook into your server-side by wrapping loaders and actions, allowing you to get
28+
extensive information about the data being loaded and the actions being
29+
dispatched.
3130

3231
## Decision
3332

34-
We will add the React Router DevTools to the Epic Stack. The DevTools
35-
will be added to the project as a development dependency. The DevTools
36-
will be used in development mode only.
33+
We will add the React Router DevTools to the Epic Stack. The DevTools will be
34+
added to the project as a development dependency. The DevTools will be used in
35+
development mode only.
3736

3837
The DevTools will be used to enhance the following:
3938

@@ -45,19 +44,18 @@ The DevTools will be used to enhance the following:
4544
6. See cache information returned via headers from your loaders
4645
7. See which loaders/actions are triggered when you navigate to a route
4746
8. and a lot more!
48-
4947

5048
## Consequences
5149

5250
With the addition of the React Router DevTools, you will not have to rely on
53-
console.log statements to debug your routing. The DevTools will provide you
54-
with the tools to ship your applications faster and with more confidence.
51+
console.log statements to debug your routing. The DevTools will provide you with
52+
the tools to ship your applications faster and with more confidence.
5553

56-
The DevTools will also help you visualize the routing in your application,
57-
which can be very helpful in understanding routing in general, and figuring
58-
out if your routes are set up correctly.
54+
The DevTools will also help you visualize the routing in your application, which
55+
can be very helpful in understanding routing in general, and figuring out if
56+
your routes are set up correctly.
5957

60-
They are not included in the production build by default, so you will not
61-
have to worry about them being included in your production bundle.
62-
They are only included in development mode, so you can use them without
63-
any negative performance impact in production.
58+
They are not included in the production build by default, so you will not have
59+
to worry about them being included in your production bundle. They are only
60+
included in development mode, so you can use them without any negative
61+
performance impact in production.

0 commit comments

Comments
 (0)