Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/small-dots-scream.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@clerk/upgrade': patch
---

Add entry for Sign-in Client Trust Status
68 changes: 68 additions & 0 deletions packages/upgrade/src/__tests__/integration/runner.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,9 @@ describe('runScans', () => {

it('respects ignore patterns', async () => {
const config = await loadConfig('nextjs', 6);
// Filter to only changes with matchers for this test
config.changes = config.changes.filter(change => change.matcher);

const options = {
dir: fixture.path,
ignore: ['**/src/**'],
Expand All @@ -65,4 +68,69 @@ describe('runScans', () => {

expect(results).toEqual([]);
});

it('always includes changes without matchers', async () => {
const config = await loadConfig('nextjs', 6);
// Add a change without a matcher
config.changes = [
{
title: 'Test change without matcher',
matcher: null,
packages: ['*'],
category: 'breaking',
warning: false,
docsAnchor: 'test-change',
content: 'This is a test change',
},
];

const options = {
dir: fixture.path,
ignore: [],
};

const results = await runScans(config, 'nextjs', options);

expect(results).toHaveLength(1);
expect(results[0].title).toBe('Test change without matcher');
expect(results[0].instances).toEqual([]);
});

it('includes both changes with and without matchers', async () => {
const config = await loadConfig('nextjs', 6);
// Add a change without a matcher and one with a matcher
config.changes = [
{
title: 'Change without matcher',
matcher: null,
packages: ['*'],
category: 'breaking',
warning: false,
docsAnchor: 'change-without-matcher',
content: 'This change has no matcher',
},
{
title: 'Change with matcher',
matcher: new RegExp('clerkMiddleware', 'g'),
packages: ['*'],
category: 'breaking',
warning: false,
docsAnchor: 'change-with-matcher',
content: 'This change has a matcher',
},
];

const options = {
dir: fixture.path,
ignore: [],
};

const results = await runScans(config, 'nextjs', options);

// Should include both changes
expect(results.length).toBeGreaterThanOrEqual(1);
const changeWithoutMatcher = results.find(r => r.title === 'Change without matcher');
expect(changeWithoutMatcher).toBeDefined();
expect(changeWithoutMatcher.instances).toEqual([]);
});
});
27 changes: 18 additions & 9 deletions packages/upgrade/src/runner.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,12 +59,27 @@ export async function runCodemods(config, sdk, options) {
}

export async function runScans(config, sdk, options) {
const matchers = loadMatchers(config, sdk);
const changes = loadMatchers(config, sdk);

if (matchers.length === 0) {
if (changes.length === 0) {
return [];
}

const changesWithMatchers = changes.filter(change => change.matcher);
const changesWithoutMatchers = changes.filter(change => !change.matcher);

const results = {};

// Always include changes without matchers
for (const change of changesWithoutMatchers) {
results[change.title] = { instances: [], ...change };
}

// Handle scans with matchers
if (changesWithMatchers.length === 0) {
return Object.values(results);
}

const spinner = createSpinner('Scanning files for breaking changes...');

try {
Expand All @@ -75,15 +90,13 @@ export async function runScans(config, sdk, options) {
ignore: [...GLOBBY_IGNORE, ...(options.ignore || [])],
});

const results = {};

for (let idx = 0; idx < files.length; idx++) {
const file = files[idx];
spinner.update(`Scanning ${path.basename(file)} (${idx + 1}/${files.length})`);

const content = await fs.readFile(file, 'utf8');

for (const matcher of matchers) {
for (const matcher of changesWithMatchers) {
const matches = findMatches(content, matcher.matcher);

if (matches.length === 0) {
Expand Down Expand Up @@ -127,10 +140,6 @@ function loadMatchers(config, sdk) {
}

return config.changes.filter(change => {
if (!change.matcher) {
return false;
}

const packages = change.packages || ['*'];
return packages.includes('*') || packages.includes(sdk);
});
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
---
title: 'Sign-in Client Trust status handling'
category: 'breaking'
---

We've added a new Sign-in status of `needs_client_trust` which, given the conditions listed, will need to be handled in your application.

[TODO: Documentation Link]

Prerequisites:

- [Passwords and Client Trust](https://dashboard.clerk.com/~/user-authentication/user-and-authentication?user_auth_tab=password) are enabled.
- You've opted-in to the Client Trust `needs_client_trust` [Update](https://dashboard.clerk.com/~/updates).
- Sign-in with [Email](https://dashboard.clerk.com/~/user-authentication/user-and-authentication) and/or [Phone](https://dashboard.clerk.com/~/user-authentication/user-and-authentication?user_auth_tab=phone) identifiers are enabled.
- If [Email](https://dashboard.clerk.com/~/user-authentication/user-and-authentication) or [SMS](https://dashboard.clerk.com/~/user-authentication/user-and-authentication?user_auth_tab=phone) sign-in verification aren't enabled.

While your application may differ, we've provided an example change below. Please reach out to [Support](mailto:support@clerk.dev) if you have any questions.

```diff
- const { signIn } = useSignIn()
- signIn.attemptFirstFactor({ strategy: 'password', password: '...' })
- if (signIn.status === 'complete') {/* ... */ }
+ const { signIn } = useSignIn()
+ signIn.attemptFirstFactor({ strategy: 'password', password: '...' })
+ if (signIn.status === 'needs_client_trust') { /* ... */ }
+ else if (signIn.status === 'complete') { /* ... */ }
```