@clerk/upgrade 2.0.0-canary-core3.v20251203181537 → 2.0.0-snapshot.v20251203203405

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.
@@ -0,0 +1,199 @@
1
+ export const fixtures = [{
2
+ name: 'ClerkProvider legacy redirect props',
3
+ source: `
4
+ import { ClerkProvider } from '@clerk/nextjs';
5
+
6
+ export function App({ children }) {
7
+ return (
8
+ <ClerkProvider
9
+ afterSignInUrl='/dashboard'
10
+ afterSignUpUrl='/welcome'
11
+ >
12
+ {children}
13
+ </ClerkProvider>
14
+ );
15
+ }
16
+ `,
17
+ output: `
18
+ import { ClerkProvider } from '@clerk/nextjs';
19
+
20
+ export function App({ children }) {
21
+ return (
22
+ <ClerkProvider
23
+ signInFallbackRedirectUrl='/dashboard'
24
+ signUpFallbackRedirectUrl='/welcome'
25
+ >
26
+ {children}
27
+ </ClerkProvider>
28
+ );
29
+ }
30
+ `
31
+ }, {
32
+ name: 'SignIn legacy props',
33
+ source: `
34
+ import { SignIn as MySignIn } from '@clerk/nextjs';
35
+
36
+ export const Page = () => (
37
+ <MySignIn
38
+ afterSignInUrl='/home'
39
+ afterSignUpUrl='/after-sign-up'
40
+ fallbackRedirectUrl='/existing'
41
+ />
42
+ );
43
+ `,
44
+ output: `
45
+ import { SignIn as MySignIn } from '@clerk/nextjs';
46
+
47
+ export const Page = () => (
48
+ <MySignIn
49
+ signUpFallbackRedirectUrl='/after-sign-up'
50
+ fallbackRedirectUrl='/existing' />
51
+ );
52
+ `
53
+ }, {
54
+ name: 'SignUp legacy props',
55
+ source: `
56
+ import { SignUp } from '@clerk/react';
57
+
58
+ export function Example() {
59
+ return (
60
+ <SignUp afterSignUpUrl='/done' afterSignInUrl='/in' />
61
+ );
62
+ }
63
+ `,
64
+ output: `
65
+ import { SignUp } from '@clerk/react';
66
+
67
+ export function Example() {
68
+ return (<SignUp fallbackRedirectUrl='/done' signInFallbackRedirectUrl='/in' />);
69
+ }
70
+ `
71
+ }, {
72
+ name: 'ClerkProvider redirectUrl only',
73
+ source: `
74
+ import { ClerkProvider } from '@clerk/react';
75
+
76
+ export const Provider = ({ children }) => (
77
+ <ClerkProvider redirectUrl='/legacy'>{children}</ClerkProvider>
78
+ );
79
+ `,
80
+ output: `
81
+ import { ClerkProvider } from '@clerk/react';
82
+
83
+ export const Provider = ({ children }) => (
84
+ <ClerkProvider signInFallbackRedirectUrl="/legacy" signUpFallbackRedirectUrl="/legacy">{children}</ClerkProvider>
85
+ );
86
+ `
87
+ }, {
88
+ name: 'SignIn redirectUrl only',
89
+ source: `
90
+ import { SignIn } from '@clerk/nextjs';
91
+
92
+ export const Page = () => <SignIn redirectUrl='/legacy' />;
93
+ `,
94
+ output: `
95
+ import { SignIn } from '@clerk/nextjs';
96
+
97
+ export const Page = () => <SignIn fallbackRedirectUrl="/legacy" />;
98
+ `
99
+ }, {
100
+ name: 'UserButton and organization props',
101
+ source: `
102
+ import { UserButton, OrganizationSwitcher, CreateOrganization } from '@clerk/react';
103
+
104
+ export const Actions = () => (
105
+ <>
106
+ <UserButton afterSignOutUrl='/bye' afterMultiSessionSingleSignOutUrl='/multi' />
107
+ <OrganizationSwitcher hideSlug afterSwitchOrganizationUrl='/org' />
108
+ <CreateOrganization hideSlug />
109
+ </>
110
+ );
111
+ `,
112
+ output: `
113
+ import { UserButton, OrganizationSwitcher, CreateOrganization } from '@clerk/react';
114
+
115
+ export const Actions = () => (
116
+ <>
117
+ <UserButton />
118
+ <OrganizationSwitcher afterSelectOrganizationUrl='/org' />
119
+ <CreateOrganization />
120
+ </>
121
+ );
122
+ `
123
+ }, {
124
+ name: 'Object literals and destructuring',
125
+ source: `
126
+ const config = {
127
+ afterSignInUrl: '/one',
128
+ afterSignUpUrl: '/two',
129
+ activeSessions,
130
+ };
131
+
132
+ const { afterSignInUrl, afterSignUpUrl: custom, activeSessions: current } = config;
133
+ `,
134
+ output: `
135
+ const config = {
136
+ signInFallbackRedirectUrl: '/one',
137
+ signUpFallbackRedirectUrl: '/two',
138
+ signedInSessions: activeSessions,
139
+ };
140
+
141
+ const { signInFallbackRedirectUrl: afterSignInUrl, signUpFallbackRedirectUrl: custom, signedInSessions: current } = config;
142
+ `
143
+ }, {
144
+ name: 'Member expressions and optional chaining',
145
+ source: `
146
+ const signInTarget = options.afterSignInUrl;
147
+ const signUpTarget = options?.afterSignUpUrl;
148
+ const fallback = options['afterSignInUrl'];
149
+ const hasSessions = client?.activeSessions?.length > 0 && client['activeSessions'];
150
+ `,
151
+ output: `
152
+ const signInTarget = options.signInFallbackRedirectUrl;
153
+ const signUpTarget = options?.signUpFallbackRedirectUrl;
154
+ const fallback = options["signInFallbackRedirectUrl"];
155
+ const hasSessions = client?.signedInSessions?.length > 0 && client["signedInSessions"];
156
+ `
157
+ }, {
158
+ name: 'setActive beforeEmit callback',
159
+ source: `
160
+ await setActive({
161
+ session: '123',
162
+ beforeEmit: handleBeforeEmit,
163
+ });
164
+ `,
165
+ output: `
166
+ await setActive({
167
+ session: '123',
168
+ navigate: params => handleBeforeEmit(params.session),
169
+ });
170
+ `
171
+ }, {
172
+ name: 'ClerkMiddlewareAuthObject type rename',
173
+ source: `
174
+ import type { ClerkMiddlewareAuthObject } from '@clerk/nextjs/server';
175
+
176
+ type Handler = (auth: ClerkMiddlewareAuthObject) => void;
177
+ `,
178
+ output: `
179
+ import type { ClerkMiddlewareSessionAuthObject } from '@clerk/nextjs/server';
180
+
181
+ type Handler = (auth: ClerkMiddlewareSessionAuthObject) => void;
182
+ `
183
+ }, {
184
+ name: 'Namespace import support',
185
+ source: `
186
+ import * as Clerk from '@clerk/nextjs';
187
+
188
+ export const Provider = ({ children }) => (
189
+ <Clerk.ClerkProvider redirectUrl='/deep' />
190
+ );
191
+ `,
192
+ output: `
193
+ import * as Clerk from '@clerk/nextjs';
194
+
195
+ export const Provider = ({ children }) => (
196
+ <Clerk.ClerkProvider signInFallbackRedirectUrl="/deep" signUpFallbackRedirectUrl="/deep" />
197
+ );
198
+ `
199
+ }];
@@ -0,0 +1,15 @@
1
+ import { applyTransform } from 'jscodeshift/dist/testUtils';
2
+ import { describe, expect, it } from 'vitest';
3
+ import transformer from '../transform-remove-deprecated-props.cjs';
4
+ import { fixtures } from './__fixtures__/transform-remove-deprecated-props.fixtures';
5
+ describe('transform-remove-deprecated-props', () => {
6
+ it.each(fixtures)('$name', ({
7
+ source,
8
+ output
9
+ }) => {
10
+ const result = applyTransform(transformer, {}, {
11
+ source
12
+ });
13
+ expect(result).toEqual(output.trim());
14
+ });
15
+ });
@@ -0,0 +1,426 @@
1
+ const CLERK_PACKAGE_PREFIX = '@clerk/';
2
+ const COMPONENTS_WITH_HIDE_SLUG = new Set(['CreateOrganization', 'OrganizationSwitcher', 'OrganizationList']);
3
+ const COMPONENT_RENAMES = new Map([['ClerkProvider', {
4
+ afterSignInUrl: 'signInFallbackRedirectUrl',
5
+ afterSignUpUrl: 'signUpFallbackRedirectUrl'
6
+ }], ['SignIn', {
7
+ afterSignInUrl: 'fallbackRedirectUrl',
8
+ afterSignUpUrl: 'signUpFallbackRedirectUrl'
9
+ }], ['SignUp', {
10
+ afterSignInUrl: 'signInFallbackRedirectUrl',
11
+ afterSignUpUrl: 'fallbackRedirectUrl'
12
+ }]]);
13
+ const COMPONENT_REDIRECT_ATTR = new Map([['ClerkProvider', {
14
+ targetAttrs: ['signInFallbackRedirectUrl', 'signUpFallbackRedirectUrl']
15
+ }], ['SignIn', {
16
+ targetAttrs: ['fallbackRedirectUrl']
17
+ }], ['SignUp', {
18
+ targetAttrs: ['fallbackRedirectUrl']
19
+ }]]);
20
+ const COMPONENTS_WITH_USER_BUTTON_REMOVALS = new Map([['UserButton', ['afterSignOutUrl', 'afterMultiSessionSingleSignOutUrl']]]);
21
+ const ORGANIZATION_SWITCHER_RENAMES = new Map([['afterSwitchOrganizationUrl', 'afterSelectOrganizationUrl']]);
22
+ module.exports = function transformDeprecatedProps({
23
+ source
24
+ }, {
25
+ jscodeshift: j
26
+ }) {
27
+ const root = j(source);
28
+ let dirty = false;
29
+ const {
30
+ namedImports,
31
+ namespaceImports
32
+ } = collectClerkImports(root, j);
33
+ root.find(j.JSXOpeningElement).forEach(path => {
34
+ const canonicalName = getCanonicalComponentName(path.node.name, namedImports, namespaceImports);
35
+ if (!canonicalName) {
36
+ return;
37
+ }
38
+ const jsxNode = path.node;
39
+ if (COMPONENTS_WITH_HIDE_SLUG.has(canonicalName)) {
40
+ if (removeJsxAttribute(j, jsxNode, 'hideSlug')) {
41
+ dirty = true;
42
+ }
43
+ }
44
+ if (COMPONENTS_WITH_USER_BUTTON_REMOVALS.has(canonicalName)) {
45
+ for (const attrName of COMPONENTS_WITH_USER_BUTTON_REMOVALS.get(canonicalName)) {
46
+ if (removeJsxAttribute(j, jsxNode, attrName)) {
47
+ dirty = true;
48
+ }
49
+ }
50
+ }
51
+ if (COMPONENT_RENAMES.has(canonicalName)) {
52
+ const renameMap = COMPONENT_RENAMES.get(canonicalName);
53
+ for (const [oldName, newName] of Object.entries(renameMap)) {
54
+ if (renameJsxAttribute(j, jsxNode, oldName, newName)) {
55
+ dirty = true;
56
+ }
57
+ }
58
+ }
59
+ if (COMPONENT_REDIRECT_ATTR.has(canonicalName)) {
60
+ if (handleRedirectAttribute(j, jsxNode, canonicalName)) {
61
+ dirty = true;
62
+ }
63
+ }
64
+ if (canonicalName === 'OrganizationSwitcher') {
65
+ for (const [oldName, newName] of ORGANIZATION_SWITCHER_RENAMES) {
66
+ if (renameJsxAttribute(j, jsxNode, oldName, newName)) {
67
+ dirty = true;
68
+ }
69
+ }
70
+ }
71
+ });
72
+ if (renameObjectProperties(root, j, 'afterSignInUrl', 'signInFallbackRedirectUrl')) {
73
+ dirty = true;
74
+ }
75
+ if (renameObjectProperties(root, j, 'afterSignUpUrl', 'signUpFallbackRedirectUrl')) {
76
+ dirty = true;
77
+ }
78
+ if (renameMemberExpressions(root, j, 'afterSignInUrl', 'signInFallbackRedirectUrl')) {
79
+ dirty = true;
80
+ }
81
+ if (renameMemberExpressions(root, j, 'afterSignUpUrl', 'signUpFallbackRedirectUrl')) {
82
+ dirty = true;
83
+ }
84
+ if (renameTSPropertySignatures(root, j, 'afterSignInUrl', 'signInFallbackRedirectUrl')) {
85
+ dirty = true;
86
+ }
87
+ if (renameTSPropertySignatures(root, j, 'afterSignUpUrl', 'signUpFallbackRedirectUrl')) {
88
+ dirty = true;
89
+ }
90
+ if (renameTSPropertySignatures(root, j, 'activeSessions', 'signedInSessions')) {
91
+ dirty = true;
92
+ }
93
+ if (renameMemberExpressions(root, j, 'activeSessions', 'signedInSessions')) {
94
+ dirty = true;
95
+ }
96
+ if (renameObjectProperties(root, j, 'activeSessions', 'signedInSessions')) {
97
+ dirty = true;
98
+ }
99
+ if (transformSetActiveBeforeEmit(root, j)) {
100
+ dirty = true;
101
+ }
102
+ if (renameTypeReferences(root, j, 'ClerkMiddlewareAuthObject', 'ClerkMiddlewareSessionAuthObject')) {
103
+ dirty = true;
104
+ }
105
+ return dirty ? root.toSource() : undefined;
106
+ };
107
+ module.exports.parser = 'tsx';
108
+ function collectClerkImports(root, j) {
109
+ const namedImports = new Map();
110
+ const namespaceImports = new Set();
111
+ root.find(j.ImportDeclaration).forEach(path => {
112
+ const sourceVal = path.node.source.value;
113
+ if (typeof sourceVal !== 'string' || !sourceVal.startsWith(CLERK_PACKAGE_PREFIX)) {
114
+ return;
115
+ }
116
+ for (const specifier of path.node.specifiers || []) {
117
+ if (j.ImportSpecifier.check(specifier)) {
118
+ const localName = specifier.local ? specifier.local.name : specifier.imported.name;
119
+ namedImports.set(localName, specifier.imported.name);
120
+ } else if (j.ImportNamespaceSpecifier.check(specifier) || j.ImportDefaultSpecifier.check(specifier)) {
121
+ namespaceImports.add(specifier.local.name);
122
+ }
123
+ }
124
+ });
125
+ return {
126
+ namedImports,
127
+ namespaceImports
128
+ };
129
+ }
130
+ function getCanonicalComponentName(nameNode, namedImports, namespaceImports) {
131
+ if (!nameNode) {
132
+ return null;
133
+ }
134
+ if (nameNode.type === 'JSXIdentifier') {
135
+ return namedImports.get(nameNode.name) || nameNode.name;
136
+ }
137
+ if (nameNode.type === 'JSXMemberExpression') {
138
+ const identifierName = getNamespaceMemberName(nameNode, namespaceImports);
139
+ if (identifierName) {
140
+ return identifierName;
141
+ }
142
+ }
143
+ return null;
144
+ }
145
+ function getNamespaceMemberName(memberNode, namespaceImports) {
146
+ if (memberNode.object.type === 'JSXIdentifier') {
147
+ return namespaceImports.has(memberNode.object.name) ? memberNode.property.name : null;
148
+ }
149
+ if (memberNode.object.type === 'JSXMemberExpression') {
150
+ const resolved = getNamespaceMemberName(memberNode.object, namespaceImports);
151
+ return resolved ? memberNode.property.name : null;
152
+ }
153
+ return null;
154
+ }
155
+ function renameJsxAttribute(j, jsxNode, oldName, newName) {
156
+ if (!jsxNode.attributes) {
157
+ return false;
158
+ }
159
+ const attrIndex = jsxNode.attributes.findIndex(attr => isJsxAttrNamed(attr, oldName));
160
+ if (attrIndex === -1) {
161
+ return false;
162
+ }
163
+ const targetExists = jsxNode.attributes.some(attr => isJsxAttrNamed(attr, newName));
164
+ if (targetExists) {
165
+ jsxNode.attributes.splice(attrIndex, 1);
166
+ return true;
167
+ }
168
+ const attribute = jsxNode.attributes[attrIndex];
169
+ attribute.name.name = newName;
170
+ return true;
171
+ }
172
+ function removeJsxAttribute(j, jsxNode, name) {
173
+ if (!jsxNode.attributes) {
174
+ return false;
175
+ }
176
+ const initialLength = jsxNode.attributes.length;
177
+ jsxNode.attributes = jsxNode.attributes.filter(attr => !isJsxAttrNamed(attr, name));
178
+ return jsxNode.attributes.length !== initialLength;
179
+ }
180
+ function isJsxAttrNamed(attribute, name) {
181
+ return attribute && attribute.type === 'JSXAttribute' && attribute.name && attribute.name.name === name;
182
+ }
183
+ function handleRedirectAttribute(j, jsxNode, canonicalName) {
184
+ if (!jsxNode.attributes) {
185
+ return false;
186
+ }
187
+ const data = COMPONENT_REDIRECT_ATTR.get(canonicalName);
188
+ const attrIndex = jsxNode.attributes.findIndex(attr => isJsxAttrNamed(attr, 'redirectUrl'));
189
+ if (attrIndex === -1) {
190
+ return false;
191
+ }
192
+ const redirectAttr = jsxNode.attributes[attrIndex];
193
+ const insertions = [];
194
+ for (const targetName of data.targetAttrs) {
195
+ if (!jsxNode.attributes.some(attr => isJsxAttrNamed(attr, targetName))) {
196
+ insertions.push(createJsxAttributeWithClonedValue(j, targetName, redirectAttr.value));
197
+ }
198
+ }
199
+ jsxNode.attributes.splice(attrIndex, 1, ...insertions);
200
+ return true;
201
+ }
202
+ function createJsxAttributeWithClonedValue(j, name, value) {
203
+ let clonedValue = null;
204
+ if (value) {
205
+ clonedValue = clone(value);
206
+ }
207
+ return j.jsxAttribute(j.jsxIdentifier(name), clonedValue);
208
+ }
209
+ function clone(node) {
210
+ return node ? JSON.parse(JSON.stringify(node)) : node;
211
+ }
212
+ function renameObjectProperties(root, j, oldName, newName) {
213
+ let changed = false;
214
+ root.find(j.ObjectProperty).forEach(path => {
215
+ if (!isPropertyKeyNamed(path.node.key, oldName)) {
216
+ return;
217
+ }
218
+ const originalLocalName = getLocalIdentifierName(path.node);
219
+ if (path.node.shorthand) {
220
+ path.node.shorthand = false;
221
+ const identifierName = originalLocalName || oldName;
222
+ path.node.value = j.identifier(identifierName);
223
+ }
224
+ if (path.node.key.type === 'Identifier') {
225
+ path.node.key.name = newName;
226
+ } else if (path.node.key.type === 'StringLiteral') {
227
+ path.node.key.value = newName;
228
+ } else if (path.node.key.type === 'Literal') {
229
+ path.node.key.value = newName;
230
+ }
231
+ changed = true;
232
+ });
233
+ return changed;
234
+ }
235
+ function getLocalIdentifierName(propertyNode) {
236
+ if (!propertyNode) {
237
+ return null;
238
+ }
239
+ if (propertyNode.value && propertyNode.value.type === 'Identifier') {
240
+ return propertyNode.value.name;
241
+ }
242
+ if (propertyNode.shorthand && propertyNode.key && propertyNode.key.type === 'Identifier') {
243
+ return propertyNode.key.name;
244
+ }
245
+ return null;
246
+ }
247
+ function isPropertyKeyNamed(keyNode, name) {
248
+ if (!keyNode) {
249
+ return false;
250
+ }
251
+ if (keyNode.type === 'Identifier') {
252
+ return keyNode.name === name;
253
+ }
254
+ if (keyNode.type === 'StringLiteral' || keyNode.type === 'Literal') {
255
+ return keyNode.value === name;
256
+ }
257
+ return false;
258
+ }
259
+ function renameMemberExpressions(root, j, oldName, newName) {
260
+ let changed = false;
261
+ root.find(j.MemberExpression, {
262
+ property: {
263
+ type: 'Identifier',
264
+ name: oldName
265
+ },
266
+ computed: false
267
+ }).forEach(path => {
268
+ path.node.property.name = newName;
269
+ changed = true;
270
+ });
271
+ root.find(j.MemberExpression, {
272
+ computed: true
273
+ }).forEach(path => {
274
+ if (path.node.property.type === 'Literal' && path.node.property.value === oldName) {
275
+ path.node.property.value = newName;
276
+ changed = true;
277
+ }
278
+ if (path.node.property.type === 'StringLiteral' && path.node.property.value === oldName) {
279
+ path.node.property.value = newName;
280
+ changed = true;
281
+ }
282
+ });
283
+ root.find(j.OptionalMemberExpression, {
284
+ property: {
285
+ type: 'Identifier',
286
+ name: oldName
287
+ },
288
+ computed: false
289
+ }).forEach(path => {
290
+ path.node.property.name = newName;
291
+ changed = true;
292
+ });
293
+ root.find(j.OptionalMemberExpression, {
294
+ computed: true
295
+ }).forEach(path => {
296
+ if (path.node.property.type === 'Literal' && path.node.property.value === oldName) {
297
+ path.node.property.value = newName;
298
+ changed = true;
299
+ }
300
+ if (path.node.property.type === 'StringLiteral' && path.node.property.value === oldName) {
301
+ path.node.property.value = newName;
302
+ changed = true;
303
+ }
304
+ });
305
+ return changed;
306
+ }
307
+ function renameTSPropertySignatures(root, j, oldName, newName) {
308
+ let changed = false;
309
+ root.find(j.TSPropertySignature).forEach(path => {
310
+ if (!isPropertyKeyNamed(path.node.key, oldName)) {
311
+ return;
312
+ }
313
+ if (path.node.key.type === 'Identifier') {
314
+ path.node.key.name = newName;
315
+ } else if (path.node.key.type === 'StringLiteral') {
316
+ path.node.key.value = newName;
317
+ }
318
+ changed = true;
319
+ });
320
+ return changed;
321
+ }
322
+ function transformSetActiveBeforeEmit(root, j) {
323
+ let changed = false;
324
+ root.find(j.CallExpression).filter(path => isSetActiveCall(path.node.callee)).forEach(path => {
325
+ const [args0] = path.node.arguments;
326
+ if (!args0 || args0.type !== 'ObjectExpression') {
327
+ return;
328
+ }
329
+ const beforeEmitIndex = args0.properties.findIndex(prop => isPropertyNamed(prop, 'beforeEmit'));
330
+ if (beforeEmitIndex === -1) {
331
+ return;
332
+ }
333
+ const beforeEmitProp = args0.properties[beforeEmitIndex];
334
+ if (!beforeEmitProp || beforeEmitProp.type !== 'ObjectProperty') {
335
+ return;
336
+ }
337
+ const originalValue = getPropertyValueExpression(beforeEmitProp.value);
338
+ if (!originalValue) {
339
+ args0.properties.splice(beforeEmitIndex, 1);
340
+ changed = true;
341
+ return;
342
+ }
343
+ const navigateProp = j.objectProperty(j.identifier('navigate'), buildNavigateArrowFunction(j, originalValue));
344
+ args0.properties.splice(beforeEmitIndex, 1, navigateProp);
345
+ changed = true;
346
+ });
347
+ return changed;
348
+ }
349
+ function isSetActiveCall(callee) {
350
+ if (!callee) {
351
+ return false;
352
+ }
353
+ if (callee.type === 'Identifier') {
354
+ return callee.name === 'setActive';
355
+ }
356
+ if (callee.type === 'MemberExpression' || callee.type === 'OptionalMemberExpression') {
357
+ const property = callee.property;
358
+ return property && property.type === 'Identifier' && property.name === 'setActive';
359
+ }
360
+ return false;
361
+ }
362
+ function isPropertyNamed(prop, name) {
363
+ return prop && prop.type === 'ObjectProperty' && isPropertyKeyNamed(prop.key, name);
364
+ }
365
+ function getPropertyValueExpression(valueNode) {
366
+ if (!valueNode) {
367
+ return null;
368
+ }
369
+ if (valueNode.type === 'JSXExpressionContainer') {
370
+ return valueNode.expression;
371
+ }
372
+ return valueNode;
373
+ }
374
+ function buildNavigateArrowFunction(j, originalExpression) {
375
+ const paramIdentifier = j.identifier('params');
376
+ const calleeExpression = clone(originalExpression);
377
+ const callExpression = j.callExpression(calleeExpression, [j.memberExpression(paramIdentifier, j.identifier('session'))]);
378
+ return j.arrowFunctionExpression([paramIdentifier], callExpression);
379
+ }
380
+ function renameTypeReferences(root, j, oldName, newName) {
381
+ let changed = false;
382
+ root.find(j.ImportSpecifier).forEach(path => {
383
+ const imported = path.node.imported;
384
+ if (imported && imported.type === 'Identifier' && imported.name === oldName) {
385
+ imported.name = newName;
386
+ if (path.node.local && path.node.local.name === oldName) {
387
+ path.node.local.name = newName;
388
+ }
389
+ changed = true;
390
+ }
391
+ });
392
+ root.find(j.TSTypeReference).forEach(path => {
393
+ if (renameEntityName(path.node.typeName, oldName, newName)) {
394
+ changed = true;
395
+ }
396
+ });
397
+ root.find(j.TSExpressionWithTypeArguments).forEach(path => {
398
+ if (renameEntityName(path.node.expression, oldName, newName)) {
399
+ changed = true;
400
+ }
401
+ });
402
+ root.find(j.TSQualifiedName).forEach(path => {
403
+ if (path.node.right.type === 'Identifier' && path.node.right.name === oldName) {
404
+ path.node.right.name = newName;
405
+ changed = true;
406
+ }
407
+ });
408
+ return changed;
409
+ }
410
+ function renameEntityName(entity, oldName, newName) {
411
+ if (!entity) {
412
+ return false;
413
+ }
414
+ if (entity.type === 'Identifier' && entity.name === oldName) {
415
+ entity.name = newName;
416
+ return true;
417
+ }
418
+ if (entity.type === 'TSQualifiedName') {
419
+ if (entity.right.type === 'Identifier' && entity.right.name === oldName) {
420
+ entity.right.name = newName;
421
+ return true;
422
+ }
423
+ return renameEntityName(entity.left, oldName, newName);
424
+ }
425
+ return false;
426
+ }
@@ -8,7 +8,10 @@ import { runCodemod } from '../codemods/index.js';
8
8
  *
9
9
  * @param {Object} props
10
10
  * @param {Function} props.callback - The callback function to be called after the codemod is run.
11
- * @param {string} props.glob - The directory to scan for files in the project.
11
+ * @param {string|string[]} [props.glob] - Optional glob(s) to scan for files. When provided, the
12
+ * codemod will use this glob directly instead of prompting.
13
+ * @param {Function} [props.onGlobResolved] - Optional callback invoked with the resolved glob array
14
+ * when the user provides it via the prompt.
12
15
  * @param {string} props.sdk - The SDK name to be used in the codemod.
13
16
  * @param {string} props.transform - The transformation to be applied by the codemod.
14
17
  *
@@ -18,11 +21,21 @@ export function Codemod(props) {
18
21
  const {
19
22
  callback,
20
23
  sdk,
21
- transform
24
+ transform,
25
+ glob: initialGlob,
26
+ onGlobResolved
22
27
  } = props;
23
28
  const [error, setError] = useState();
24
- const [glob, setGlob] = useState(props.glob);
29
+ const [glob, setGlob] = useState(initialGlob);
25
30
  const [result, setResult] = useState();
31
+
32
+ // If a glob is later provided via props (e.g. from a previous codemod run),
33
+ // adopt it so we can run without re-prompting.
34
+ useEffect(() => {
35
+ if (initialGlob && !glob) {
36
+ setGlob(initialGlob);
37
+ }
38
+ }, [initialGlob, glob]);
26
39
  useEffect(() => {
27
40
  if (!glob) {
28
41
  return;
@@ -42,7 +55,11 @@ export function Codemod(props) {
42
55
  }, "(globstar syntax supported)"), glob ? /*#__PURE__*/React.createElement(Text, null, glob.toString()) : /*#__PURE__*/React.createElement(TextInput, {
43
56
  defaultValue: "**/*.(js|jsx|ts|tsx|mjs|cjs)",
44
57
  onSubmit: val => {
45
- setGlob(val.split(/[ ,]/));
58
+ const parsed = val.split(/[ ,]/).filter(Boolean);
59
+ setGlob(parsed);
60
+ if (onGlobResolved) {
61
+ onGlobResolved(parsed);
62
+ }
46
63
  }
47
64
  })), !result && !error && glob && /*#__PURE__*/React.createElement(Spinner, {
48
65
  label: `Running @clerk/${sdk} codemod... ${transform}`
@@ -32,7 +32,7 @@ export function Command({
32
32
  }).catch(err => {
33
33
  setError(err);
34
34
  });
35
- }, []);
35
+ }, [cmd]);
36
36
  return /*#__PURE__*/React.createElement(React.Fragment, null, !result && !error && /*#__PURE__*/React.createElement(Loading, {
37
37
  cmd: cmd,
38
38
  message: message
@@ -7,6 +7,11 @@ import { Codemod } from './Codemod.js';
7
7
  import { Command } from './Command.js';
8
8
  import { Header } from './Header.js';
9
9
  import { UpgradeSDK } from './UpgradeSDK.js';
10
+ const CODEMODS = {
11
+ ASYNC_REQUEST: 'transform-async-request',
12
+ CLERK_REACT_V6: 'transform-clerk-react-v6',
13
+ REMOVE_DEPRECATED_PROPS: 'transform-remove-deprecated-props'
14
+ };
10
15
  function versionNeedsUpgrade(sdk, version) {
11
16
  if (sdk === 'clerk-react' && version === 5) {
12
17
  return true;
@@ -38,10 +43,12 @@ export function SDKWorkflow(props) {
38
43
  const {
39
44
  sdk
40
45
  } = props;
46
+ const detectedVersion = getClerkSdkVersion(sdk);
41
47
  const [done, setDone] = useState(false);
42
48
  const [runCodemod, setRunCodemod] = useState(false);
43
49
  const [upgradeComplete, setUpgradeComplete] = useState(false);
44
- const [version] = useState(getClerkSdkVersion(sdk));
50
+ const [version, setVersion] = useState(detectedVersion);
51
+ const [versionConfirmed, setVersionConfirmed] = useState(Boolean(detectedVersion));
45
52
  if (!['nextjs', 'clerk-react', 'clerk-expo', 'react-router', 'tanstack-react-start'].includes(sdk)) {
46
53
  return /*#__PURE__*/React.createElement(StatusMessage, {
47
54
  variant: "error"
@@ -49,96 +56,223 @@ export function SDKWorkflow(props) {
49
56
  bold: true
50
57
  }, "@clerk/", sdk), " at the moment.");
51
58
  }
52
- if (sdk === 'nextjs') {
53
- // Right now, we only have one codemod for the `@clerk/nextjs` async request transformation
54
- return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Header, null), /*#__PURE__*/React.createElement(Text, null, "Clerk SDK used: ", /*#__PURE__*/React.createElement(Text, {
55
- color: "green"
56
- }, "@clerk/", sdk)), /*#__PURE__*/React.createElement(Text, null, "Migrating from version: ", /*#__PURE__*/React.createElement(Text, {
57
- color: "green"
58
- }, version)), runCodemod ? /*#__PURE__*/React.createElement(Text, null, "Executing codemod: ", /*#__PURE__*/React.createElement(Text, {
59
- color: "green"
60
- }, "yes")) : null, /*#__PURE__*/React.createElement(Newline, null), version === 5 && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(UpgradeSDK, {
61
- callback: setUpgradeComplete,
62
- sdk: sdk
63
- }), upgradeComplete ? /*#__PURE__*/React.createElement(Codemod, {
64
- callback: setDone,
65
- sdk: sdk,
66
- transform: "transform-async-request"
67
- }) : null), version === 6 && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(UpgradeSDK, {
68
- callback: setUpgradeComplete,
69
- sdk: sdk
70
- }), upgradeComplete ? /*#__PURE__*/React.createElement(Codemod, {
71
- callback: setDone,
72
- sdk: sdk,
73
- transform: "transform-clerk-react-v6"
74
- }) : null), version === 7 && /*#__PURE__*/React.createElement(React.Fragment, null, runCodemod ? /*#__PURE__*/React.createElement(Codemod, {
75
- sdk: sdk,
76
- callback: setDone,
77
- transform: "transform-clerk-react-v6"
78
- }) : /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Text, null, "Looks like you are already on the latest version of ", /*#__PURE__*/React.createElement(Text, {
59
+
60
+ // If we cannot automatically determine the installed version, let the user
61
+ // pick the major version they are on so we can still run the appropriate
62
+ // upgrade / codemods instead of silently doing nothing.
63
+ if (!versionConfirmed) {
64
+ return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Header, null), /*#__PURE__*/React.createElement(Text, null, "We couldn't automatically detect which major version of ", /*#__PURE__*/React.createElement(Text, {
79
65
  bold: true
80
- }, "@clerk/", sdk), ". Would you like to run the associated codemod?"), /*#__PURE__*/React.createElement(Select, {
66
+ }, "@clerk/", sdk), " you're using."), /*#__PURE__*/React.createElement(Newline, null), /*#__PURE__*/React.createElement(StatusMessage, {
67
+ variant: "warning"
68
+ }, "Please select the major version below. If you're not sure, picking v7 (Core 3) will run the latest codemods and is generally safe to re-run."), /*#__PURE__*/React.createElement(Newline, null), /*#__PURE__*/React.createElement(Text, null, "Please select your current @clerk/", sdk, " major version:"), /*#__PURE__*/React.createElement(Select, {
81
69
  options: [{
82
- label: 'yes',
83
- value: 'yes'
70
+ label: 'v5 (upgrade to v6)',
71
+ value: 5
84
72
  }, {
85
- label: 'no',
86
- value: 'no'
73
+ label: 'v6 (upgrade to v7 / Core 3)',
74
+ value: 6
75
+ }, {
76
+ label: 'v7 (already on Core 3, just run codemods)',
77
+ value: 7
87
78
  }],
88
79
  onChange: value => {
89
- if (value === 'yes') {
90
- setRunCodemod(true);
91
- } else {
92
- setDone(true);
93
- }
80
+ const numeric = typeof value === 'number' ? value : Number(value);
81
+ setVersion(Number.isNaN(numeric) ? 7 : numeric);
82
+ setVersionConfirmed(true);
94
83
  }
95
- }))), done && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(StatusMessage, {
96
- variant: "success"
97
- }, "Done upgrading ", /*#__PURE__*/React.createElement(Text, {
98
- bold: true
99
- }, "@clerk/nextjs")), /*#__PURE__*/React.createElement(Command, {
100
- cmd: 'grep -rE "import.*\\\\{.*useAuth.*\\\\}.*from.*[\'\\\\\\"]@clerk/nextjs[\'\\\\\\"]" . --exclude-dir={node_modules,dist}',
101
- message: /*#__PURE__*/React.createElement(Spinner, {
102
- label: 'Checking for `useAuth` usage in your project...'
103
- }),
104
- onError: () => null,
105
- onSuccess: () => /*#__PURE__*/React.createElement(StatusMessage, {
106
- variant: "warning"
107
- }, /*#__PURE__*/React.createElement(Text, null, "We have detected that your application might be using the ", /*#__PURE__*/React.createElement(Text, {
108
- bold: true
109
- }, "useAuth"), " hook from", ' ', /*#__PURE__*/React.createElement(Text, {
110
- bold: true
111
- }, "@clerk/nextjs"), "."), /*#__PURE__*/React.createElement(Newline, null), /*#__PURE__*/React.createElement(Text, null, "If usages of this hook are server-side rendered, you might need to add the ", /*#__PURE__*/React.createElement(Text, {
112
- bold: true
113
- }, "dynamic"), ' ', "prop to your application's root ", /*#__PURE__*/React.createElement(Text, {
114
- bold: true
115
- }, "ClerkProvider"), "."), /*#__PURE__*/React.createElement(Newline, null), /*#__PURE__*/React.createElement(Text, null, "You can find more information about this change in the Clerk documentation at", ' ', /*#__PURE__*/React.createElement(Link, {
116
- url: "https://clerk.com/docs/references/nextjs/rendering-modes"
117
- }, "https://clerk.com/docs/references/nextjs/rendering-modes"), "."))
118
- })));
84
+ }));
119
85
  }
120
- if (['clerk-react', 'clerk-expo', 'react-router', 'tanstack-react-start'].includes(sdk)) {
121
- const replacePackage = sdk === 'clerk-react' || sdk === 'clerk-expo';
122
- return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Header, null), /*#__PURE__*/React.createElement(Text, null, "Clerk SDK used: ", /*#__PURE__*/React.createElement(Text, {
123
- color: "green"
124
- }, "@clerk/", sdk)), /*#__PURE__*/React.createElement(Text, null, "Migrating from version: ", /*#__PURE__*/React.createElement(Text, {
125
- color: "green"
126
- }, version)), runCodemod ? /*#__PURE__*/React.createElement(Text, null, "Executing codemod: ", /*#__PURE__*/React.createElement(Text, {
127
- color: "green"
128
- }, "yes")) : null, /*#__PURE__*/React.createElement(Newline, null), versionNeedsUpgrade(sdk, version) && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(UpgradeSDK, {
129
- callback: setUpgradeComplete,
86
+ if (sdk === 'nextjs') {
87
+ return /*#__PURE__*/React.createElement(NextjsWorkflow, {
88
+ done: done,
89
+ runCodemod: runCodemod,
130
90
  sdk: sdk,
131
- replacePackage: replacePackage
132
- }), upgradeComplete ? /*#__PURE__*/React.createElement(Codemod, {
133
- callback: setDone,
91
+ setDone: setDone,
92
+ setRunCodemod: setRunCodemod,
93
+ setUpgradeComplete: setUpgradeComplete,
94
+ upgradeComplete: upgradeComplete,
95
+ version: version
96
+ });
97
+ }
98
+ if (['clerk-react', 'clerk-expo', 'react-router', 'tanstack-react-start'].includes(sdk)) {
99
+ return /*#__PURE__*/React.createElement(ReactSdkWorkflow, {
100
+ done: done,
101
+ runCodemod: runCodemod,
134
102
  sdk: sdk,
135
- transform: "transform-clerk-react-v6"
136
- }) : null), done && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(StatusMessage, {
137
- variant: "success"
138
- }, replacePackage ? /*#__PURE__*/React.createElement(React.Fragment, null, "Done upgrading to ", /*#__PURE__*/React.createElement(Text, {
139
- bold: true
140
- }, "@clerk/", sdk.replace('clerk-', ''))) : /*#__PURE__*/React.createElement(React.Fragment, null, "Done upgrading ", /*#__PURE__*/React.createElement(Text, {
141
- bold: true
142
- }, "@clerk/", sdk)))));
103
+ setDone: setDone,
104
+ setRunCodemod: setRunCodemod,
105
+ setUpgradeComplete: setUpgradeComplete,
106
+ upgradeComplete: upgradeComplete,
107
+ version: version
108
+ });
143
109
  }
110
+ }
111
+ function NextjsWorkflow({
112
+ done,
113
+ runCodemod,
114
+ sdk,
115
+ setDone,
116
+ setRunCodemod,
117
+ setUpgradeComplete,
118
+ upgradeComplete,
119
+ version
120
+ }) {
121
+ const [v6CodemodComplete, setV6CodemodComplete] = useState(false);
122
+ const [glob, setGlob] = useState();
123
+ return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Header, null), /*#__PURE__*/React.createElement(Text, null, "Clerk SDK used: ", /*#__PURE__*/React.createElement(Text, {
124
+ color: "green"
125
+ }, "@clerk/", sdk)), /*#__PURE__*/React.createElement(Text, null, "Migrating from version: ", /*#__PURE__*/React.createElement(Text, {
126
+ color: "green"
127
+ }, version)), runCodemod ? /*#__PURE__*/React.createElement(Text, null, "Executing codemod: ", /*#__PURE__*/React.createElement(Text, {
128
+ color: "green"
129
+ }, "yes")) : null, /*#__PURE__*/React.createElement(Newline, null), version === 5 && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(UpgradeSDK, {
130
+ callback: setUpgradeComplete,
131
+ sdk: sdk
132
+ }), upgradeComplete ? /*#__PURE__*/React.createElement(Codemod, {
133
+ callback: setV6CodemodComplete,
134
+ sdk: sdk,
135
+ transform: CODEMODS.ASYNC_REQUEST,
136
+ onGlobResolved: setGlob
137
+ }) : null, v6CodemodComplete ? /*#__PURE__*/React.createElement(Codemod, {
138
+ callback: setDone,
139
+ sdk: sdk,
140
+ transform: CODEMODS.REMOVE_DEPRECATED_PROPS,
141
+ glob: glob
142
+ }) : null), version === 6 && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(UpgradeSDK, {
143
+ callback: setUpgradeComplete,
144
+ sdk: sdk
145
+ }), upgradeComplete ? /*#__PURE__*/React.createElement(Codemod, {
146
+ callback: setV6CodemodComplete,
147
+ sdk: sdk,
148
+ transform: CODEMODS.CLERK_REACT_V6,
149
+ onGlobResolved: setGlob
150
+ }) : null, v6CodemodComplete ? /*#__PURE__*/React.createElement(Codemod, {
151
+ callback: setDone,
152
+ sdk: sdk,
153
+ transform: CODEMODS.REMOVE_DEPRECATED_PROPS,
154
+ glob: glob
155
+ }) : null), version === 7 && /*#__PURE__*/React.createElement(React.Fragment, null, runCodemod ? /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Codemod, {
156
+ callback: setV6CodemodComplete,
157
+ sdk: sdk,
158
+ transform: CODEMODS.CLERK_REACT_V6,
159
+ onGlobResolved: setGlob
160
+ }), v6CodemodComplete ? /*#__PURE__*/React.createElement(Codemod, {
161
+ callback: setDone,
162
+ sdk: sdk,
163
+ transform: CODEMODS.REMOVE_DEPRECATED_PROPS,
164
+ glob: glob
165
+ }) : null) : /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Text, null, "Looks like you are already on the latest version of ", /*#__PURE__*/React.createElement(Text, {
166
+ bold: true
167
+ }, "@clerk/", sdk), ". Would you like to run the associated codemods?"), /*#__PURE__*/React.createElement(Select, {
168
+ onChange: value => {
169
+ if (value === 'yes') {
170
+ setRunCodemod(true);
171
+ } else {
172
+ setDone(true);
173
+ }
174
+ },
175
+ options: [{
176
+ label: 'yes',
177
+ value: 'yes'
178
+ }, {
179
+ label: 'no',
180
+ value: 'no'
181
+ }]
182
+ }))), done && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(StatusMessage, {
183
+ variant: "success"
184
+ }, "Done upgrading ", /*#__PURE__*/React.createElement(Text, {
185
+ bold: true
186
+ }, "@clerk/nextjs")), /*#__PURE__*/React.createElement(Command, {
187
+ cmd: 'grep -rE "import.*\\\\{.*useAuth.*\\\\}.*from.*[\'\\\\\\"]@clerk/nextjs[\'\\\\\\"]" . --exclude-dir={node_modules,dist}',
188
+ message: /*#__PURE__*/React.createElement(Spinner, {
189
+ label: 'Checking for `useAuth` usage in your project...'
190
+ }),
191
+ onError: () => null,
192
+ onSuccess: NextjsUseAuthWarning
193
+ })));
194
+ }
195
+ function NextjsUseAuthWarning() {
196
+ return /*#__PURE__*/React.createElement(StatusMessage, {
197
+ variant: "warning"
198
+ }, /*#__PURE__*/React.createElement(Text, null, "We have detected that your application might be using the ", /*#__PURE__*/React.createElement(Text, {
199
+ bold: true
200
+ }, "useAuth"), " hook from", ' ', /*#__PURE__*/React.createElement(Text, {
201
+ bold: true
202
+ }, "@clerk/nextjs"), "."), /*#__PURE__*/React.createElement(Newline, null), /*#__PURE__*/React.createElement(Text, null, "If usages of this hook are server-side rendered, you might need to add the ", /*#__PURE__*/React.createElement(Text, {
203
+ bold: true
204
+ }, "dynamic"), " prop to your application's root ", /*#__PURE__*/React.createElement(Text, {
205
+ bold: true
206
+ }, "ClerkProvider"), "."), /*#__PURE__*/React.createElement(Newline, null), /*#__PURE__*/React.createElement(Text, null, "You can find more information about this change in the Clerk documentation at", ' ', /*#__PURE__*/React.createElement(Link, {
207
+ url: "https://clerk.com/docs/references/nextjs/rendering-modes"
208
+ }, "https://clerk.com/docs/references/nextjs/rendering-modes"), "."));
209
+ }
210
+ function ReactSdkWorkflow({
211
+ done,
212
+ runCodemod,
213
+ sdk,
214
+ setDone,
215
+ setRunCodemod,
216
+ setUpgradeComplete,
217
+ upgradeComplete,
218
+ version
219
+ }) {
220
+ const [v6CodemodComplete, setV6CodemodComplete] = useState(false);
221
+ const [glob, setGlob] = useState();
222
+ const replacePackage = sdk === 'clerk-react' || sdk === 'clerk-expo';
223
+ const needsUpgrade = versionNeedsUpgrade(sdk, version);
224
+ return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Header, null), /*#__PURE__*/React.createElement(Text, null, "Clerk SDK used: ", /*#__PURE__*/React.createElement(Text, {
225
+ color: "green"
226
+ }, "@clerk/", sdk)), /*#__PURE__*/React.createElement(Text, null, "Migrating from version: ", /*#__PURE__*/React.createElement(Text, {
227
+ color: "green"
228
+ }, version)), runCodemod ? /*#__PURE__*/React.createElement(Text, null, "Executing codemod: ", /*#__PURE__*/React.createElement(Text, {
229
+ color: "green"
230
+ }, "yes")) : null, /*#__PURE__*/React.createElement(Newline, null), needsUpgrade && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(UpgradeSDK, {
231
+ callback: setUpgradeComplete,
232
+ replacePackage: replacePackage,
233
+ sdk: sdk
234
+ }), upgradeComplete ? /*#__PURE__*/React.createElement(Codemod, {
235
+ callback: setV6CodemodComplete,
236
+ sdk: sdk,
237
+ transform: CODEMODS.CLERK_REACT_V6,
238
+ onGlobResolved: setGlob
239
+ }) : null, v6CodemodComplete ? /*#__PURE__*/React.createElement(Codemod, {
240
+ callback: setDone,
241
+ sdk: sdk,
242
+ transform: CODEMODS.REMOVE_DEPRECATED_PROPS,
243
+ glob: glob
244
+ }) : null), !needsUpgrade && /*#__PURE__*/React.createElement(React.Fragment, null, runCodemod ? /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Codemod, {
245
+ callback: setV6CodemodComplete,
246
+ sdk: sdk,
247
+ transform: CODEMODS.CLERK_REACT_V6,
248
+ onGlobResolved: setGlob
249
+ }), v6CodemodComplete ? /*#__PURE__*/React.createElement(Codemod, {
250
+ callback: setDone,
251
+ sdk: sdk,
252
+ transform: CODEMODS.REMOVE_DEPRECATED_PROPS,
253
+ glob: glob
254
+ }) : null) : /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Text, null, "Looks like you are already on the latest version of ", /*#__PURE__*/React.createElement(Text, {
255
+ bold: true
256
+ }, "@clerk/", sdk), ". Would you like to run the associated codemods?"), /*#__PURE__*/React.createElement(Select, {
257
+ onChange: value => {
258
+ if (value === 'yes') {
259
+ setRunCodemod(true);
260
+ } else {
261
+ setDone(true);
262
+ }
263
+ },
264
+ options: [{
265
+ label: 'yes',
266
+ value: 'yes'
267
+ }, {
268
+ label: 'no',
269
+ value: 'no'
270
+ }]
271
+ }))), done && /*#__PURE__*/React.createElement(StatusMessage, {
272
+ variant: "success"
273
+ }, replacePackage ? /*#__PURE__*/React.createElement(React.Fragment, null, "Done upgrading to ", /*#__PURE__*/React.createElement(Text, {
274
+ bold: true
275
+ }, "@clerk/", sdk.replace('clerk-', ''))) : /*#__PURE__*/React.createElement(React.Fragment, null, "Done upgrading ", /*#__PURE__*/React.createElement(Text, {
276
+ bold: true
277
+ }, "@clerk/", sdk))));
144
278
  }
@@ -37,7 +37,7 @@ export function Scan(props) {
37
37
  // { sdkName: [{ title: 'x', matcher: /x/, slug: 'x', ... }] }
38
38
  useEffect(() => {
39
39
  setStatus(`Loading data for ${toVersion} migration`);
40
- import(`../versions/${toVersion}/index.js`).then(version => {
40
+ void import(`../versions/${toVersion}/index.js`).then(version => {
41
41
  setMatchers(sdks.reduce((m, sdk) => {
42
42
  m[sdk] = version.default[sdk];
43
43
  return m;
@@ -51,7 +51,7 @@ export function Scan(props) {
51
51
  useEffect(() => {
52
52
  setStatus('Collecting files to scan');
53
53
  const pattern = convertPathToPattern(path.resolve(dir));
54
- globby(pattern, {
54
+ void globby(pattern, {
55
55
  ignore: ['node_modules/**', '**/node_modules/**', '.git/**', 'package.json', '**/package.json', 'package-lock.json', '**/package-lock.json', 'yarn.lock', '**/yarn.lock', 'pnpm-lock.yaml', '**/pnpm-lock.yaml', '**/*.(png|webp|svg|gif|jpg|jpeg)+', '**/*.(mp4|mkv|wmv|m4v|mov|avi|flv|webm|flac|mka|m4a|aac|ogg)+', ...ignore].filter(Boolean)
56
56
  }).then(files => {
57
57
  setFiles(files);
@@ -66,7 +66,7 @@ export function Scan(props) {
66
66
  return;
67
67
  }
68
68
  const allResults = {};
69
- Promise.all(
69
+ void Promise.all(
70
70
  // first we read all the files
71
71
  files.map(async (file, idx) => {
72
72
  const content = await fs.readFile(file, 'utf8');
@@ -124,8 +124,8 @@ export function Scan(props) {
124
124
  setStatus(`Scanning ${file}`);
125
125
  setProgress(Math.ceil(idx / files.length * 100));
126
126
  })).then(() => {
127
- const newResults = [...results, ...Object.keys(allResults).map(k => allResults[k])];
128
- setResults(newResults);
127
+ const aggregatedResults = Object.keys(allResults).map(k => allResults[k]);
128
+ setResults(prevResults => [...prevResults, ...aggregatedResults]);
129
129
 
130
130
  // Anonymously track how many instances of each breaking change item were encountered.
131
131
  // This only tracks the name of the breaking change found, and how many instances of it
@@ -133,14 +133,14 @@ export function Scan(props) {
133
133
  // It is used internally to help us understand what the most common sticking points are
134
134
  // for our users so we can appropriate prioritize support/guidance/docs around them.
135
135
  if (!disableTelemetry) {
136
- fetch('https://api.segment.io/v1/batch', {
136
+ void fetch('https://api.segment.io/v1/batch', {
137
137
  method: 'POST',
138
138
  headers: {
139
139
  Authorization: `Basic ${Buffer.from('5TkC1SM87VX2JRJcIGBBmL7sHLRWaIvc:').toString('base64')}`,
140
140
  'Content-Type': 'application/json'
141
141
  },
142
142
  body: JSON.stringify({
143
- batch: newResults.map(item => {
143
+ batch: aggregatedResults.map(item => {
144
144
  return {
145
145
  type: 'track',
146
146
  userId: 'clerk-upgrade-tool',
@@ -169,7 +169,7 @@ export function Scan(props) {
169
169
  }).catch(err => {
170
170
  console.error(err);
171
171
  });
172
- }, [matchers, files, noWarnings, disableTelemetry]);
172
+ }, [matchers, files, noWarnings, disableTelemetry, fromVersion, toVersion, uuid]);
173
173
  return complete ? /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Text, {
174
174
  color: "green"
175
175
  }, "\u2713 ", status), /*#__PURE__*/React.createElement(Newline, null), !!results.length && /*#__PURE__*/React.createElement(ExpandableList, {
@@ -80,7 +80,7 @@ export function UpgradeSDK({
80
80
  }).finally(() => {
81
81
  callback(true);
82
82
  });
83
- }, [command, packageManager, sdk]);
83
+ }, [callback, command, packageManager, replacePackage, sdk]);
84
84
  return /*#__PURE__*/React.createElement(React.Fragment, null, packageManager ? null : /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Text, null, "We could not detect the package manager used in your project. Please select the package manager you are using"), /*#__PURE__*/React.createElement(Select, {
85
85
  options: [{
86
86
  label: 'npm',
@@ -19,4 +19,4 @@ async function generate() {
19
19
  packageName
20
20
  }), markdown('cli'), '## Breaking Changes', singleItem('authenticaterequest-params-change'), singleItem('clockskewinseconds'), markdown('import-paths'), accordionForCategory('import-paths'), singleItem('httpoptions-removed'), markdown('orgs-claim'), markdown('pagination-args'), accordionForCategory('pagination-args'), markdown('pagination-return'), accordionForCategory('pagination-return'), markdown('image-url'), accordionForCategory(['image-url', 'image-url-backend']), deprecationRemovalsAndHousekeeping()]);
21
21
  }
22
- generate().then(writeToFile(cwd));
22
+ void generate().then(writeToFile(cwd));
@@ -21,4 +21,4 @@ async function generate() {
21
21
  packageName
22
22
  }), markdown('image-url'), accordionForCategory('image-url'), deprecationRemovalsAndHousekeeping(['hof-removal', 'pagination-return', 'pagination-args', 'error-imports'])]);
23
23
  }
24
- generate().then(writeToFile(cwd));
24
+ void generate().then(writeToFile(cwd));
@@ -22,4 +22,4 @@ async function generate() {
22
22
  packageName
23
23
  }), markdown('image-url'), accordionForCategory('image-url'), deprecationRemovalsAndHousekeeping(['hof-removal', 'pagination-return', 'pagination-args', 'error-imports'])]);
24
24
  }
25
- generate().then(writeToFile(cwd));
25
+ void generate().then(writeToFile(cwd));
@@ -20,4 +20,4 @@ async function generate() {
20
20
  packageName
21
21
  }), markdown('cli'), '## Breaking Changes', markdown('orgs-claim'), markdown('image-url'), accordionForCategory('image-url'), deprecationRemovalsAndHousekeeping(['hof-removal', 'pagination-return', 'pagination-args', 'error-imports'])]);
22
22
  }
23
- generate().then(writeToFile(cwd));
23
+ void generate().then(writeToFile(cwd));
@@ -25,4 +25,4 @@ async function generate() {
25
25
  // attemptweb3wallet?
26
26
  deprecationRemovalsAndHousekeeping(['error-imports'])]);
27
27
  }
28
- generate().then(writeToFile(cwd));
28
+ void generate().then(writeToFile(cwd));
@@ -22,4 +22,4 @@ async function generate() {
22
22
  packageName
23
23
  }), markdown('image-url'), accordionForCategory('image-url'), deprecationRemovalsAndHousekeeping(['hof-removal', 'pagination-return', 'pagination-args', 'error-imports'])]);
24
24
  }
25
- generate().then(writeToFile(cwd));
25
+ void generate().then(writeToFile(cwd));
@@ -20,4 +20,4 @@ async function generate() {
20
20
  packageName
21
21
  }), markdown('cli'), '## Breaking Changes', singleItem('cjs-esm-instance'), markdown('node-setters-removals'), markdown('orgs-claim'), markdown('image-url'), accordionForCategory('image-url'), deprecationRemovalsAndHousekeeping(['pagination-return', 'pagination-args', 'error-imports'])]);
22
22
  }
23
- generate().then(writeToFile(cwd));
23
+ void generate().then(writeToFile(cwd));
@@ -1,7 +1,7 @@
1
1
  import { assembleContent, frontmatter, markdown, writeToFile } from '../../text-generation.js';
2
2
  const cwd = 'core-2/overview';
3
3
  async function generate() {
4
- return assembleContent({
4
+ return await assembleContent({
5
5
  data: {},
6
6
  cwd
7
7
  }, [frontmatter({
@@ -9,4 +9,4 @@ async function generate() {
9
9
  description: `Learn how to upgrade to the latest version of Clerk's SDKs`
10
10
  }), markdown('intro')]);
11
11
  }
12
- generate().then(writeToFile(cwd));
12
+ void generate().then(writeToFile(cwd));
@@ -22,4 +22,4 @@ async function generate() {
22
22
  packageName
23
23
  }), markdown('image-url'), accordionForCategory('image-url'), deprecationRemovalsAndHousekeeping(['hof-removal', 'pagination-return', 'pagination-args', 'error-imports'])]);
24
24
  }
25
- generate().then(writeToFile(cwd));
25
+ void generate().then(writeToFile(cwd));
@@ -22,4 +22,4 @@ async function generate() {
22
22
  packageName
23
23
  }), markdown('image-url'), accordionForCategory('image-url'), deprecationRemovalsAndHousekeeping()]);
24
24
  }
25
- generate().then(writeToFile(cwd));
25
+ void generate().then(writeToFile(cwd));
@@ -20,4 +20,4 @@ async function generate() {
20
20
  additionalItems: [defaultsChangeItem]
21
21
  }), '## Localization Changes', accordionForCategory('localization')]);
22
22
  }
23
- generate().then(writeToFile(cwd));
23
+ void generate().then(writeToFile(cwd));
@@ -24,7 +24,7 @@ ${entry.content}
24
24
  }
25
25
  return output;
26
26
  }
27
- generate().then(console.log);
27
+ void generate().then(console.log);
28
28
  function getSdkName(val) {
29
29
  return SDKS.find(sdk => val === sdk.value).label;
30
30
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@clerk/upgrade",
3
- "version": "2.0.0-canary-core3.v20251203181537",
3
+ "version": "2.0.0-snapshot.v20251203203405",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/clerk/javascript.git",