@clerk/upgrade 1.1.0-snapshot.vfbd7c17 → 1.1.0

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.
package/dist/app.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { MultiSelect, Select, TextInput } from '@inkjs/ui';
2
- import { Newline, Text } from 'ink';
3
- import React, { useState } from 'react';
2
+ import { Newline, Text, useApp } from 'ink';
3
+ import React, { useEffect, useState } from 'react';
4
4
  import { Header } from './components/Header.js';
5
5
  import { Scan } from './components/Scan.js';
6
6
  import { SDKWorkflow } from './components/SDKWorkflow.js';
@@ -28,20 +28,19 @@ export default function App(props) {
28
28
  noWarnings = false,
29
29
  disableTelemetry = false
30
30
  } = props;
31
+ const {
32
+ exit
33
+ } = useApp();
31
34
  const [yolo, setYolo] = useState(props.yolo ?? false);
32
35
  const [sdks, setSdks] = useState(props.sdk ? [props.sdk] : []);
33
36
  const [sdkGuesses, setSdkGuesses] = useState([]);
34
37
  const [sdkGuessConfirmed, setSdkGuessConfirmed] = useState(false);
35
38
  const [sdkGuessAttempted, setSdkGuessAttempted] = useState(false);
36
- // See comments below, can be enabled on next major
37
-
38
- // eslint-disable-next-line no-unused-vars
39
39
  const [fromVersion, setFromVersion] = useState(props.fromVersion);
40
40
  const [fromVersionGuessAttempted, setFromVersionGuessAttempted] = useState(false);
41
- // eslint-disable-next-line no-unused-vars
42
41
  const [toVersion, setToVersion] = useState(props.toVersion);
43
42
  const [dir, setDir] = useState(props.dir);
44
- const [ignore, setIgnore] = useState(props.ignore);
43
+ const [ignore, setIgnore] = useState(props.ignore ?? []);
45
44
  const [configComplete, setConfigComplete] = useState(false);
46
45
  const [configVerified, setConfigVerified] = useState(false);
47
46
  const [uuid, setUuid] = useState();
@@ -50,9 +49,19 @@ export default function App(props) {
50
49
  setSdks(SDKS.map(s => s.value));
51
50
  setYolo(false);
52
51
  }
52
+ useEffect(() => {
53
+ if (toVersion === 'core-2') {
54
+ setFromVersion('core-1');
55
+ }
56
+ }, [toVersion]);
57
+ useEffect(() => {
58
+ if (fromVersion === 'core-1') {
59
+ setToVersion('core-2');
60
+ }
61
+ }, [fromVersion]);
53
62
 
54
63
  // Handle the individual SDK upgrade
55
- if (sdks.length === 1) {
64
+ if (!fromVersion && !toVersion && sdks[0] === 'nextjs') {
56
65
  return /*#__PURE__*/React.createElement(SDKWorkflow, {
57
66
  packageManager: props.packageManager,
58
67
  sdk: sdks[0]
@@ -68,7 +77,6 @@ export default function App(props) {
68
77
  guesses,
69
78
  _uuid
70
79
  } = guessFrameworks(dir, disableTelemetry);
71
- // console.log({ guesses, _uuid });
72
80
  setUuid(_uuid);
73
81
  setSdkGuesses(guesses);
74
82
  setSdkGuessAttempted(true);
@@ -97,7 +105,9 @@ export default function App(props) {
97
105
  color: "blue"
98
106
  }, "Hello friend!"), " We're excited to help you upgrade Clerk modules. Before we get started, a couple questions..."), /*#__PURE__*/React.createElement(Newline, null)), isEmpty(sdks) && !isEmpty(sdkGuesses) && !sdkGuessConfirmed && /*#__PURE__*/React.createElement(React.Fragment, null, sdkGuesses.length > 1 ? /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Text, null, "It looks like you are using the following Clerk SDKs in your project:"), sdkGuesses.map(guess => /*#__PURE__*/React.createElement(Text, {
99
107
  key: guess.value
100
- }, ' ', "- ", guess.label)), /*#__PURE__*/React.createElement(Text, null, "Is that right?")) : /*#__PURE__*/React.createElement(Text, null, "It looks like you are using the \"", sdkGuesses[0].label, "\" Clerk SDK in your project. Is that right?"), /*#__PURE__*/React.createElement(Select, {
108
+ }, ' ', "- ", guess.label)), /*#__PURE__*/React.createElement(Text, null, "Is that right?")) : /*#__PURE__*/React.createElement(Text, null, "It looks like you are using the ", /*#__PURE__*/React.createElement(Text, {
109
+ bold: true
110
+ }, sdkGuesses[0].label), " Clerk SDK in your project. Is that right?"), /*#__PURE__*/React.createElement(Select, {
101
111
  options: [{
102
112
  label: 'yes',
103
113
  value: 'yes'
@@ -110,6 +120,8 @@ export default function App(props) {
110
120
  // if true, we were right so we set the sdk
111
121
  if (item === 'yes') {
112
122
  setSdks(sdkGuesses.map(guess => guess.value));
123
+ } else {
124
+ setSdkGuesses([]);
113
125
  }
114
126
  }
115
127
  })), isEmpty(sdks) && isEmpty(sdkGuesses) && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Text, null, "Please select which Clerk SDK(s) you're using for your app:"), /*#__PURE__*/React.createElement(Text, {
@@ -145,14 +157,14 @@ export default function App(props) {
145
157
  }, " ", ignore.join(', ')))), /*#__PURE__*/React.createElement(Newline, null), /*#__PURE__*/React.createElement(Text, null, "Does this look right?"), /*#__PURE__*/React.createElement(Select, {
146
158
  options: [{
147
159
  label: 'yes',
148
- value: true
160
+ value: 'yes'
149
161
  }, {
150
- label: 'no - exit, and i will try again',
151
- value: false
162
+ label: 'no - exit, and I will try again',
163
+ value: 'no'
152
164
  }],
153
165
  onChange: value => {
154
- if (!value) {
155
- process.exit();
166
+ if (!value || value === 'no') {
167
+ exit();
156
168
  } else {
157
169
  setConfigVerified(true);
158
170
  }
package/dist/cli.js CHANGED
@@ -21,16 +21,15 @@ const cli = meow(`
21
21
  Examples
22
22
  $ clerk-upgrade --sdk=nextjs --dir=src/**
23
23
  $ clerk-upgrade --ignore=**/public/** --ignore=**/dist/**
24
+ $ clerk-upgrade --from=core-1 --to=core-2
24
25
  `, {
25
26
  importMeta: import.meta,
26
27
  flags: {
27
28
  from: {
28
- type: 'string',
29
- default: 'core-1'
29
+ type: 'string'
30
30
  },
31
31
  to: {
32
- type: 'string',
33
- default: 'core-2'
32
+ type: 'string'
34
33
  },
35
34
  sdk: {
36
35
  type: 'string',
@@ -178,6 +178,30 @@ export default clerkMiddleware(
178
178
  },
179
179
  );
180
180
  `
181
+ }, {
182
+ name: 'Complex clerkMiddleware() without protect()',
183
+ source: `
184
+ import { clerkMiddleware } from '@clerk/nextjs/server';
185
+
186
+ export default clerkMiddleware(
187
+ (auth, req) => {
188
+ const { redirectToSignIn } = auth();
189
+
190
+ redirectToSignIn();
191
+ },
192
+ );
193
+ `,
194
+ output: `
195
+ import { clerkMiddleware } from '@clerk/nextjs/server';
196
+
197
+ export default clerkMiddleware(
198
+ async (auth, req) => {
199
+ const { redirectToSignIn } = await auth();
200
+
201
+ redirectToSignIn();
202
+ },
203
+ );
204
+ `
181
205
  }, {
182
206
  name: 'Does not transform other imports',
183
207
  source: `
@@ -0,0 +1,45 @@
1
+ export const fixtures = [{
2
+ name: 'Basic await transform',
3
+ source: `
4
+ import { ClerkProvider } from '@clerk/nextjs'
5
+
6
+ export default function RootLayout({ children }) {
7
+ return (
8
+ <ClerkProvider>
9
+ <html>
10
+ <body>{children}</body>
11
+ </html>
12
+ </ClerkProvider>
13
+ );
14
+ }
15
+ `,
16
+ output: `
17
+ import { ClerkProvider } from '@clerk/nextjs'
18
+
19
+ export default function RootLayout({ children }) {
20
+ return (
21
+ (<ClerkProvider dynamic>
22
+ <html>
23
+ <body>{children}</body>
24
+ </html>
25
+ </ClerkProvider>)
26
+ );
27
+ }
28
+ `
29
+ }, {
30
+ name: 'Does not transform if ClerkProvider is already dynamic',
31
+ source: `
32
+ import { ClerkProvider } from '@clerk/nextjs'
33
+
34
+ export default function RootLayout({ children }) {
35
+ return (
36
+ <ClerkProvider dynamic>
37
+ <html>
38
+ <body>{children}</body>
39
+ </html>
40
+ </ClerkProvider>
41
+ )
42
+ }
43
+ `,
44
+ output: ''
45
+ }];
@@ -0,0 +1,15 @@
1
+ import { applyTransform } from 'jscodeshift/dist/testUtils';
2
+ import { describe, expect, it } from 'vitest';
3
+ import transformer from '../transform-clerk-provider-dynamic.cjs';
4
+ import { fixtures } from './__fixtures__/transform-clerk-provider-dynamic.fixtures';
5
+ describe('transform-clerk-provider-dynamic', () => {
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
+ });
@@ -3,7 +3,10 @@ import { fileURLToPath } from 'node:url';
3
3
  import { globby } from 'globby';
4
4
  import { run } from 'jscodeshift/src/Runner.js';
5
5
  const __dirname = dirname(fileURLToPath(import.meta.url));
6
- export async function runCodemod(transform = 'transform-async-request', glob, options) {
6
+ export async function runCodemod(transform, glob, options) {
7
+ if (!transform) {
8
+ throw new Error('No transform provided');
9
+ }
7
10
  const resolvedPath = resolve(__dirname, `${transform}.cjs`);
8
11
  const paths = await globby(glob, {
9
12
  ignore: ['**/*.md', 'node_modules/**', '**/node_modules/**', '.git/**', '**/*.json', 'package.json', '**/package.json', 'package-lock.json', '**/package-lock.json', 'yarn.lock', '**/yarn.lock', 'pnpm-lock.yaml', '**/pnpm-lock.yaml', 'yalc.lock', '**/*.(ico|png|webp|svg|gif|jpg|jpeg)+',
@@ -116,12 +116,6 @@ module.exports = function transformAsyncRequest({
116
116
  }
117
117
  }
118
118
  });
119
- if (dirtyFlag) {
120
- if (process.env.NODE_ENV !== 'test') {
121
- console.log(`changed: ${path}`);
122
- }
123
- return root.toSource();
124
- }
125
- return undefined;
119
+ return dirtyFlag ? root.toSource() : undefined;
126
120
  };
127
121
  module.exports.parser = 'tsx';
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Transforms the source code by adding the dynamic prop to the ClerkProvider
3
+ *
4
+ * @param {import('jscodeshift').FileInfo} FileInfo - The parameters object
5
+ * @param {import('jscodeshift').API} api - The API object provided by jscodeshift
6
+ * @param {Object} _options - Additional options (unused)
7
+ * @returns {string|undefined} - The transformed source code if modifications were made, otherwise undefined
8
+ */
9
+ module.exports = function transformClerkProviderDynamic({
10
+ _path,
11
+ source
12
+ }, {
13
+ jscodeshift: j
14
+ }, _options) {
15
+ const root = j(source);
16
+ let dirtyFlag = false;
17
+
18
+ // Short-circuit if the import from '@clerk/nextjs' is not found
19
+ if (root.find(j.ImportDeclaration, {
20
+ source: {
21
+ value: '@clerk/nextjs'
22
+ }
23
+ }).size() === 0) {
24
+ return undefined;
25
+ }
26
+
27
+ // Find all JSXElements with the name ClerkProvider
28
+ root.find(j.JSXElement, {
29
+ openingElement: {
30
+ name: {
31
+ name: 'ClerkProvider'
32
+ }
33
+ }
34
+ }).forEach(path => {
35
+ const openingElement = path.node.openingElement;
36
+
37
+ // Check if the dynamic attribute is already present
38
+ const hasDynamicAttribute = openingElement.attributes.some(attr => {
39
+ return j.JSXAttribute.check(attr) && attr.name.name === 'dynamic';
40
+ });
41
+
42
+ // If dynamic attribute is not present, add it
43
+ if (!hasDynamicAttribute) {
44
+ openingElement.attributes.push(j.jsxAttribute(j.jsxIdentifier('dynamic')));
45
+ dirtyFlag = true;
46
+ }
47
+ });
48
+ return dirtyFlag ? root.toSource() : undefined;
49
+ };
50
+ module.exports.parser = 'tsx';
@@ -1,4 +1,4 @@
1
- import { TextInput } from '@inkjs/ui';
1
+ import { Spinner, StatusMessage, TextInput } from '@inkjs/ui';
2
2
  import { Newline, Text } from 'ink';
3
3
  import React, { useEffect, useState } from 'react';
4
4
  import { runCodemod } from '../codemods/index.js';
@@ -6,9 +6,9 @@ import { runCodemod } from '../codemods/index.js';
6
6
  /**
7
7
  * Codemod component that allows users to run a codemod transformation on their project files.
8
8
  *
9
- * @param {Object} props - The properties object.
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.dir] - The directory to scan for files in the project.
11
+ * @param {string} props.glob - The directory to scan for files in the project.
12
12
  * @param {string} props.sdk - The SDK name to be used in the codemod.
13
13
  * @param {string} props.transform - The transformation to be applied by the codemod.
14
14
  *
@@ -21,8 +21,8 @@ export function Codemod(props) {
21
21
  transform
22
22
  } = props;
23
23
  const [error, setError] = useState();
24
- const [result, setResult] = useState(null);
25
24
  const [glob, setGlob] = useState(props.glob);
25
+ const [result, setResult] = useState();
26
26
  useEffect(() => {
27
27
  if (!glob) {
28
28
  return;
@@ -35,20 +35,24 @@ export function Codemod(props) {
35
35
  callback(true);
36
36
  });
37
37
  }, [glob]);
38
- return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Text, null, "Where would you like for us to scan for files in your project?"), /*#__PURE__*/React.createElement(Text, {
38
+ return /*#__PURE__*/React.createElement(React.Fragment, null, glob ? /*#__PURE__*/React.createElement(StatusMessage, {
39
+ variant: "success"
40
+ }, "Scanning for files in your project... ", glob.toString()) : /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Text, null, "Where would you like for us to scan for files in your project?"), /*#__PURE__*/React.createElement(Text, {
39
41
  color: "gray"
40
42
  }, "(globstar syntax supported)"), glob ? /*#__PURE__*/React.createElement(Text, null, glob.toString()) : /*#__PURE__*/React.createElement(TextInput, {
41
43
  defaultValue: "**/*",
42
44
  onSubmit: val => {
43
45
  setGlob(val.split(/[ ,]/));
44
46
  }
45
- })), !result && !error && glob && /*#__PURE__*/React.createElement(Text, null, "Running ", /*#__PURE__*/React.createElement(Text, {
46
- bold: true
47
- }, "@clerk/", sdk), " codemod... ", transform), result && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Text, null, "Running ", /*#__PURE__*/React.createElement(Text, {
47
+ })), !result && !error && glob && /*#__PURE__*/React.createElement(Spinner, {
48
+ label: `Running @clerk/${sdk}</Text> codemod... ${transform}`
49
+ }), result && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(StatusMessage, {
50
+ variant: "success"
51
+ }, "Running ", /*#__PURE__*/React.createElement(Text, {
48
52
  bold: true
49
53
  }, "@clerk/", sdk), " codemod... ", transform, " complete!"), /*#__PURE__*/React.createElement(Newline, null), /*#__PURE__*/React.createElement(Text, {
50
54
  bold: true
51
- }, "Results:"), /*#__PURE__*/React.createElement(Text, {
55
+ }, "Codemod results:"), /*#__PURE__*/React.createElement(Text, {
52
56
  color: "red"
53
57
  }, result.error ?? 0, " errors"), /*#__PURE__*/React.createElement(Text, {
54
58
  color: "green"
@@ -56,7 +60,7 @@ export function Codemod(props) {
56
60
  color: "yellow"
57
61
  }, result.skip ?? 0, " skipped"), /*#__PURE__*/React.createElement(Text, {
58
62
  color: "gray"
59
- }, result.nochange ?? 0, " unmodified"), result.timeElapsed && /*#__PURE__*/React.createElement(Text, null, "Time elapsed: ", result.timeElapsed)), error && /*#__PURE__*/React.createElement(Text, {
63
+ }, result.nochange ?? 0, " unmodified"), result.timeElapsed && /*#__PURE__*/React.createElement(Text, null, "Time elapsed: ", result.timeElapsed), /*#__PURE__*/React.createElement(Newline, null)), error && /*#__PURE__*/React.createElement(Text, {
60
64
  color: "red"
61
65
  }, error.message));
62
66
  }
@@ -0,0 +1,56 @@
1
+ import { Spinner, StatusMessage } from '@inkjs/ui';
2
+ import { execa } from 'execa';
3
+ import { Text } from 'ink';
4
+ import React, { useEffect, useState } from 'react';
5
+
6
+ /**
7
+ * Component that runs a command and handles the result.
8
+ *
9
+ * @component
10
+ * @param {Object} props
11
+ * @param {Function} props.callback - The callback function to be called after the command execution.
12
+ * @param {string} props.cmd - The command to execute.
13
+ * @param {string} props.message - The message to display while the command is running.
14
+ * @returns {JSX.Element} The rendered component.
15
+ *
16
+ * @example
17
+ * <Command cmd="echo 'hello world'" />
18
+ */
19
+ export function Command({
20
+ cmd,
21
+ message,
22
+ onError,
23
+ onSuccess
24
+ }) {
25
+ const [error, setError] = useState();
26
+ const [result, setResult] = useState();
27
+ useEffect(() => {
28
+ execa({
29
+ shell: true
30
+ })`${cmd}`.then(res => {
31
+ setResult(res);
32
+ }).catch(err => {
33
+ setError(err);
34
+ });
35
+ }, []);
36
+ return /*#__PURE__*/React.createElement(React.Fragment, null, !result && !error && /*#__PURE__*/React.createElement(Loading, {
37
+ cmd: cmd,
38
+ message: message
39
+ }), result ? onSuccess ? onSuccess() : /*#__PURE__*/React.createElement(StatusMessage, {
40
+ variant: "success"
41
+ }, "Successfully ran: ", /*#__PURE__*/React.createElement(Text, {
42
+ bold: true
43
+ }, cmd)) : null, error ? onError ? onError() : /*#__PURE__*/React.createElement(StatusMessage, {
44
+ variant: "error"
45
+ }, "Failed running: ", /*#__PURE__*/React.createElement(Text, {
46
+ bold: true
47
+ }, cmd)) : null);
48
+ }
49
+ function Loading({
50
+ cmd,
51
+ message
52
+ }) {
53
+ return message ? message : /*#__PURE__*/React.createElement(Spinner, {
54
+ label: `Running command: ${cmd}`
55
+ });
56
+ }
@@ -1,11 +1,25 @@
1
- import { Select } from '@inkjs/ui';
2
- import { execa } from 'execa';
1
+ import { Select, Spinner, StatusMessage } from '@inkjs/ui';
3
2
  import { Newline, Text } from 'ink';
4
- import React, { useEffect, useState } from 'react';
5
- import { getUpgradeCommand } from '../util/detect-package-manager.js';
3
+ import Link from 'ink-link';
4
+ import React, { useState } from 'react';
6
5
  import { getClerkSdkVersion } from '../util/get-clerk-version.js';
7
6
  import { Codemod } from './Codemod.js';
7
+ import { Command } from './Command.js';
8
8
  import { Header } from './Header.js';
9
+ import { UpgradeSDK } from './UpgradeSDK.js';
10
+
11
+ /**
12
+ * SDKWorkflow component handles the upgrade process for a given SDK.
13
+ * It checks the current version of the SDK and provides the necessary steps
14
+ * to upgrade or run codemods based on the version.
15
+ *
16
+ * @component
17
+ * @param {Object} props
18
+ * @param {string} props.packageManager - The package manager to use for the upgrade, if needed.
19
+ * @param {string} props.sdk - The SDK to be upgraded.
20
+ *
21
+ * @returns {JSX.Element} The rendered component.
22
+ */
9
23
  export function SDKWorkflow(props) {
10
24
  const {
11
25
  packageManager,
@@ -14,7 +28,16 @@ export function SDKWorkflow(props) {
14
28
  const [done, setDone] = useState(false);
15
29
  const [upgradeComplete, setUpgradeComplete] = useState(false);
16
30
  const version = getClerkSdkVersion(sdk);
17
- return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Header, null), version === 5 && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(UpgradeCommand, {
31
+ if (sdk !== 'nextjs') {
32
+ return /*#__PURE__*/React.createElement(StatusMessage, {
33
+ variant: "error"
34
+ }, "The SDK upgrade functionality is only available for ", /*#__PURE__*/React.createElement(Text, {
35
+ bold: true
36
+ }, "@clerk/nextjs"), " at the moment.");
37
+ }
38
+
39
+ // Right now, we only have one codemod for the `@clerk/nextjs` async request transformation
40
+ return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Header, null), version === 5 && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(UpgradeSDK, {
18
41
  callback: setUpgradeComplete,
19
42
  packageManager: packageManager,
20
43
  sdk: sdk
@@ -42,28 +65,28 @@ export function SDKWorkflow(props) {
42
65
  setDone(true);
43
66
  }
44
67
  }
45
- })), done && /*#__PURE__*/React.createElement(Text, null, "You are done!"));
46
- }
47
- function UpgradeCommand({
48
- sdk,
49
- callback
50
- }) {
51
- const [result, setResult] = useState();
52
- const [error, setError] = useState();
53
- const command = getUpgradeCommand(sdk);
54
- useEffect(() => {
55
- execa({
56
- shell: true
57
- })`${command}`.then(res => {
58
- setResult(res);
59
- callback(true);
60
- }).catch(err => {
61
- setError(err);
62
- });
63
- }, [command]);
64
- return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Text, null, "Running upgrade command: ", command), result && /*#__PURE__*/React.createElement(Text, {
65
- color: "green"
66
- }, "Upgrade complete!"), error && /*#__PURE__*/React.createElement(Text, {
67
- color: "red"
68
- }, "Upgrade failed!"), /*#__PURE__*/React.createElement(Newline, null));
68
+ })), done && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(StatusMessage, {
69
+ variant: "success"
70
+ }, "Done upgrading ", /*#__PURE__*/React.createElement(Text, {
71
+ bold: true
72
+ }, "@clerk/nextjs")), /*#__PURE__*/React.createElement(Command, {
73
+ cmd: 'grep -rE "import.*\\\\{.*useAuth.*\\\\}.*from.*[\'\\\\\\"]@clerk/nextjs[\'\\\\\\"]" . --exclude-dir={node_modules,dist}',
74
+ message: /*#__PURE__*/React.createElement(Spinner, {
75
+ label: 'Checking for `useAuth` usage in your project...'
76
+ }),
77
+ onError: () => null,
78
+ onSuccess: () => /*#__PURE__*/React.createElement(StatusMessage, {
79
+ variant: "warning"
80
+ }, /*#__PURE__*/React.createElement(Text, null, "We have detected that your application might be using the ", /*#__PURE__*/React.createElement(Text, {
81
+ bold: true
82
+ }, "useAuth"), " hook from", ' ', /*#__PURE__*/React.createElement(Text, {
83
+ bold: true
84
+ }, "@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, {
85
+ bold: true
86
+ }, "dynamic"), ' ', "prop to your application's root ", /*#__PURE__*/React.createElement(Text, {
87
+ bold: true
88
+ }, "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, {
89
+ url: "https://clerk.com/docs/nextjs/rendering-modes"
90
+ }, "https://clerk.com/docs/nextjs/rendering-modes"), "."))
91
+ })));
69
92
  }
@@ -6,16 +6,17 @@ import { Newline, Text } from 'ink';
6
6
  import path from 'path';
7
7
  import React, { useEffect, useState } from 'react';
8
8
  import ExpandableList from '../util/expandable-list.js';
9
- export function Scan({
10
- fromVersion,
11
- toVersion,
12
- sdks,
13
- dir,
14
- ignore,
15
- noWarnings,
16
- uuid,
17
- disableTelemetry
18
- }) {
9
+ export function Scan(props) {
10
+ const {
11
+ fromVersion,
12
+ toVersion,
13
+ sdks,
14
+ dir,
15
+ ignore,
16
+ noWarnings,
17
+ uuid,
18
+ disableTelemetry
19
+ } = props;
19
20
  // NOTE: if the difference between fromVersion and toVersion is greater than 1
20
21
  // we need to do a little extra work here and import two matchers,
21
22
  // sequence them after each other, and clearly mark which version migration
@@ -36,7 +37,7 @@ export function Scan({
36
37
  // { sdkName: [{ title: 'x', matcher: /x/, slug: 'x', ... }] }
37
38
  useEffect(() => {
38
39
  setStatus(`Loading data for ${toVersion} migration`);
39
- import(`./versions/${toVersion}/index.js`).then(version => {
40
+ import(`../versions/${toVersion}/index.js`).then(version => {
40
41
  setMatchers(sdks.reduce((m, sdk) => {
41
42
  m[sdk] = version.default[sdk];
42
43
  return m;
@@ -49,12 +50,9 @@ export function Scan({
49
50
  // result = `files` set to format: ['/filename', '/other/filename']
50
51
  useEffect(() => {
51
52
  setStatus('Collecting files to scan');
52
- ignore.push('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)+',
53
- // common image files
54
- '**/*.(mp4|mkv|wmv|m4v|mov|avi|flv|webm|flac|mka|m4a|aac|ogg)+' // common video files
55
- );
56
- globby(convertPathToPattern(path.resolve(dir)), {
57
- ignore: ignore.filter(Boolean)
53
+ const pattern = convertPathToPattern(path.resolve(dir));
54
+ globby(pattern, {
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)
58
56
  }).then(files => {
59
57
  setFiles(files);
60
58
  });
@@ -0,0 +1,70 @@
1
+ import { Spinner, StatusMessage } from '@inkjs/ui';
2
+ import { execa } from 'execa';
3
+ import { existsSync } from 'fs';
4
+ import { Text } from 'ink';
5
+ import React, { useEffect, useState } from 'react';
6
+ function detectPackageManager() {
7
+ if (existsSync('package-lock.json')) {
8
+ return 'npm';
9
+ } else if (existsSync('yarn.lock')) {
10
+ return 'yarn';
11
+ } else if (existsSync('pnpm-lock.yaml')) {
12
+ return 'pnpm';
13
+ } else {
14
+ return 'npm';
15
+ }
16
+ }
17
+ function upgradeCommand(sdk, packageManager) {
18
+ switch (packageManager || detectPackageManager()) {
19
+ case 'yarn':
20
+ return `yarn add @clerk/${sdk}@latest`;
21
+ case 'pnpm':
22
+ return `pnpm add @clerk/${sdk}@latest`;
23
+ default:
24
+ return `npm install @clerk/${sdk}@latest`;
25
+ }
26
+ }
27
+
28
+ /**
29
+ * Component that runs an upgrade command for a given SDK and handles the result.
30
+ *
31
+ * @component
32
+ * @param {Object} props
33
+ * @param {Function} props.callback - The callback function to be called after the command execution.
34
+ * @param {string} props.packageManager - The package manager used in the project in case we cannot detect it automatically.
35
+ * @param {string} props.sdk - The SDK for which the upgrade command is run.
36
+ * @returns {JSX.Element} The rendered component.
37
+ *
38
+ * @example
39
+ * <UpgradeCommand sdk="example-sdk" callback={handleUpgrade} />
40
+ */
41
+ export function UpgradeSDK({
42
+ callback,
43
+ packageManager,
44
+ sdk
45
+ }) {
46
+ const [error, setError] = useState();
47
+ const [result, setResult] = useState();
48
+ const command = upgradeCommand(sdk, packageManager);
49
+ useEffect(() => {
50
+ execa({
51
+ shell: true
52
+ })`${command}`.then(res => {
53
+ setResult(res);
54
+ callback(true);
55
+ }).catch(err => {
56
+ setError(err);
57
+ });
58
+ }, [command]);
59
+ return /*#__PURE__*/React.createElement(React.Fragment, null, !result && !error && /*#__PURE__*/React.createElement(Spinner, {
60
+ label: `Running upgrade command: ${command}`
61
+ }), result && /*#__PURE__*/React.createElement(StatusMessage, {
62
+ variant: "success"
63
+ }, /*#__PURE__*/React.createElement(Text, {
64
+ bold: true
65
+ }, "@clerk/", sdk), " upgraded successfully to ", /*#__PURE__*/React.createElement(Text, {
66
+ bold: true
67
+ }, "latest!")), error && /*#__PURE__*/React.createElement(StatusMessage, {
68
+ variant: "error"
69
+ }, "Upgrade failed!"));
70
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@clerk/upgrade",
3
- "version": "1.1.0-snapshot.vfbd7c17",
3
+ "version": "1.1.0",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/clerk/javascript.git",
@@ -1,22 +0,0 @@
1
- import { existsSync } from 'fs';
2
- export function detectPackageManager() {
3
- if (existsSync('package-lock.json')) {
4
- return 'npm';
5
- } else if (existsSync('yarn.lock')) {
6
- return 'yarn';
7
- } else if (existsSync('pnpm-lock.yaml')) {
8
- return 'pnpm';
9
- } else {
10
- return 'npm';
11
- }
12
- }
13
- export function getUpgradeCommand(sdk, packageManager) {
14
- switch (packageManager || detectPackageManager()) {
15
- case 'yarn':
16
- return `yarn add @clerk/${sdk}@latest`;
17
- case 'pnpm':
18
- return `pnpm add @clerk/${sdk}@latest`;
19
- default:
20
- return `npm install @clerk/${sdk}@latest`;
21
- }
22
- }