diff --git a/.changeset/old-needles-study.md b/.changeset/old-needles-study.md new file mode 100644 index 0000000000..858abeae06 --- /dev/null +++ b/.changeset/old-needles-study.md @@ -0,0 +1,5 @@ +--- +"@clerk/dev-cli": patch +--- + +Introduce `clerk-dev` CLI tool diff --git a/.changeset/soft-fans-flash.md b/.changeset/soft-fans-flash.md new file mode 100644 index 0000000000..a845151cc8 --- /dev/null +++ b/.changeset/soft-fans-flash.md @@ -0,0 +1,2 @@ +--- +--- diff --git a/package-lock.json b/package-lock.json index 585bd82c9f..14cfc5420f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -764,7 +764,7 @@ }, "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": { "version": "7.22.3", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@babel/types": "^7.22.3" @@ -796,7 +796,6 @@ }, "node_modules/@babel/helper-create-class-features-plugin": { "version": "7.24.7", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-annotate-as-pure": "^7.24.7", @@ -818,7 +817,6 @@ }, "node_modules/@babel/helper-create-class-features-plugin/node_modules/semver": { "version": "6.3.1", - "dev": true, "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -826,7 +824,7 @@ }, "node_modules/@babel/helper-create-regexp-features-plugin": { "version": "7.22.1", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-annotate-as-pure": "^7.18.6", @@ -842,7 +840,7 @@ }, "node_modules/@babel/helper-create-regexp-features-plugin/node_modules/semver": { "version": "6.3.1", - "dev": true, + "devOptional": true, "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -850,7 +848,7 @@ }, "node_modules/@babel/helper-define-polyfill-provider": { "version": "0.4.2", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-compilation-targets": "^7.22.6", @@ -896,7 +894,6 @@ }, "node_modules/@babel/helper-member-expression-to-functions": { "version": "7.24.7", - "dev": true, "license": "MIT", "dependencies": { "@babel/traverse": "^7.24.7", @@ -936,7 +933,6 @@ }, "node_modules/@babel/helper-optimise-call-expression": { "version": "7.24.7", - "dev": true, "license": "MIT", "dependencies": { "@babel/types": "^7.24.7" @@ -954,7 +950,7 @@ }, "node_modules/@babel/helper-remap-async-to-generator": { "version": "7.18.9", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-annotate-as-pure": "^7.18.6", @@ -971,7 +967,6 @@ }, "node_modules/@babel/helper-replace-supers": { "version": "7.24.7", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-environment-visitor": "^7.24.7", @@ -998,7 +993,6 @@ }, "node_modules/@babel/helper-skip-transparent-expression-wrappers": { "version": "7.24.7", - "dev": true, "license": "MIT", "dependencies": { "@babel/traverse": "^7.24.7", @@ -1041,7 +1035,7 @@ }, "node_modules/@babel/helper-wrap-function": { "version": "7.20.5", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-function-name": "^7.19.0", @@ -1089,7 +1083,7 @@ }, "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { "version": "7.18.6", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.18.6" @@ -1103,7 +1097,7 @@ }, "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { "version": "7.22.3", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.21.5", @@ -1265,7 +1259,7 @@ }, "node_modules/@babel/plugin-proposal-private-property-in-object": { "version": "7.21.11", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-annotate-as-pure": "^7.18.6", @@ -1282,7 +1276,7 @@ }, "node_modules/@babel/plugin-proposal-unicode-property-regex": { "version": "7.18.6", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.18.6", @@ -1330,7 +1324,7 @@ }, "node_modules/@babel/plugin-syntax-class-static-block": { "version": "7.14.5", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.14.5" @@ -1359,7 +1353,7 @@ }, "node_modules/@babel/plugin-syntax-dynamic-import": { "version": "7.8.3", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" @@ -1385,7 +1379,7 @@ }, "node_modules/@babel/plugin-syntax-export-namespace-from": { "version": "7.8.3", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.3" @@ -1410,7 +1404,7 @@ }, "node_modules/@babel/plugin-syntax-import-assertions": { "version": "7.20.0", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.19.0" @@ -1424,7 +1418,7 @@ }, "node_modules/@babel/plugin-syntax-import-attributes": { "version": "7.22.3", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.21.5" @@ -1484,7 +1478,6 @@ }, "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { "version": "7.8.3", - "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" @@ -1528,7 +1521,6 @@ }, "node_modules/@babel/plugin-syntax-optional-chaining": { "version": "7.8.3", - "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" @@ -1539,7 +1531,7 @@ }, "node_modules/@babel/plugin-syntax-private-property-in-object": { "version": "7.14.5", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.14.5" @@ -1580,7 +1572,7 @@ }, "node_modules/@babel/plugin-syntax-unicode-sets-regex": { "version": "7.18.6", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.18.6", @@ -1595,7 +1587,7 @@ }, "node_modules/@babel/plugin-transform-arrow-functions": { "version": "7.21.5", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.21.5" @@ -1609,7 +1601,7 @@ }, "node_modules/@babel/plugin-transform-async-generator-functions": { "version": "7.22.3", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-environment-visitor": "^7.22.1", @@ -1626,7 +1618,7 @@ }, "node_modules/@babel/plugin-transform-async-to-generator": { "version": "7.20.7", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-module-imports": "^7.18.6", @@ -1642,7 +1634,7 @@ }, "node_modules/@babel/plugin-transform-block-scoped-functions": { "version": "7.18.6", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.18.6" @@ -1656,7 +1648,7 @@ }, "node_modules/@babel/plugin-transform-block-scoping": { "version": "7.21.0", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.20.2" @@ -1670,7 +1662,7 @@ }, "node_modules/@babel/plugin-transform-class-properties": { "version": "7.22.3", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-create-class-features-plugin": "^7.22.1", @@ -1685,7 +1677,7 @@ }, "node_modules/@babel/plugin-transform-class-static-block": { "version": "7.22.3", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-create-class-features-plugin": "^7.22.1", @@ -1701,7 +1693,7 @@ }, "node_modules/@babel/plugin-transform-classes": { "version": "7.21.0", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-annotate-as-pure": "^7.18.6", @@ -1723,7 +1715,7 @@ }, "node_modules/@babel/plugin-transform-computed-properties": { "version": "7.21.5", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.21.5", @@ -1738,7 +1730,7 @@ }, "node_modules/@babel/plugin-transform-destructuring": { "version": "7.21.3", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.20.2" @@ -1752,7 +1744,7 @@ }, "node_modules/@babel/plugin-transform-dotall-regex": { "version": "7.18.6", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.18.6", @@ -1767,7 +1759,7 @@ }, "node_modules/@babel/plugin-transform-duplicate-keys": { "version": "7.18.9", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.18.9" @@ -1781,7 +1773,7 @@ }, "node_modules/@babel/plugin-transform-dynamic-import": { "version": "7.22.1", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.21.5", @@ -1796,7 +1788,7 @@ }, "node_modules/@babel/plugin-transform-exponentiation-operator": { "version": "7.18.6", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-builder-binary-assignment-operator-visitor": "^7.18.6", @@ -1811,7 +1803,7 @@ }, "node_modules/@babel/plugin-transform-export-namespace-from": { "version": "7.23.4", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.22.5", @@ -1841,7 +1833,7 @@ }, "node_modules/@babel/plugin-transform-for-of": { "version": "7.21.5", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.21.5" @@ -1855,7 +1847,7 @@ }, "node_modules/@babel/plugin-transform-function-name": { "version": "7.18.9", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-compilation-targets": "^7.18.9", @@ -1871,7 +1863,7 @@ }, "node_modules/@babel/plugin-transform-json-strings": { "version": "7.22.3", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.21.5", @@ -1886,7 +1878,7 @@ }, "node_modules/@babel/plugin-transform-literals": { "version": "7.18.9", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.18.9" @@ -1900,7 +1892,7 @@ }, "node_modules/@babel/plugin-transform-logical-assignment-operators": { "version": "7.22.3", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.21.5", @@ -1915,7 +1907,7 @@ }, "node_modules/@babel/plugin-transform-member-expression-literals": { "version": "7.18.6", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.18.6" @@ -1929,7 +1921,7 @@ }, "node_modules/@babel/plugin-transform-modules-amd": { "version": "7.20.11", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-module-transforms": "^7.20.11", @@ -1944,7 +1936,7 @@ }, "node_modules/@babel/plugin-transform-modules-commonjs": { "version": "7.21.5", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-module-transforms": "^7.21.5", @@ -1960,7 +1952,7 @@ }, "node_modules/@babel/plugin-transform-modules-systemjs": { "version": "7.22.3", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-hoist-variables": "^7.18.6", @@ -1977,7 +1969,7 @@ }, "node_modules/@babel/plugin-transform-modules-umd": { "version": "7.18.6", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-module-transforms": "^7.18.6", @@ -1992,7 +1984,7 @@ }, "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { "version": "7.22.3", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.22.1", @@ -2007,7 +1999,7 @@ }, "node_modules/@babel/plugin-transform-new-target": { "version": "7.22.3", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.21.5" @@ -2021,7 +2013,7 @@ }, "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { "version": "7.22.3", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.21.5", @@ -2036,7 +2028,7 @@ }, "node_modules/@babel/plugin-transform-numeric-separator": { "version": "7.22.3", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.21.5", @@ -2051,7 +2043,7 @@ }, "node_modules/@babel/plugin-transform-object-rest-spread": { "version": "7.22.3", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@babel/compat-data": "^7.22.3", @@ -2069,7 +2061,7 @@ }, "node_modules/@babel/plugin-transform-object-super": { "version": "7.18.6", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.18.6", @@ -2084,7 +2076,7 @@ }, "node_modules/@babel/plugin-transform-optional-catch-binding": { "version": "7.22.3", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.21.5", @@ -2099,7 +2091,7 @@ }, "node_modules/@babel/plugin-transform-optional-chaining": { "version": "7.22.3", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.21.5", @@ -2115,7 +2107,7 @@ }, "node_modules/@babel/plugin-transform-parameters": { "version": "7.23.3", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.22.5" @@ -2129,7 +2121,7 @@ }, "node_modules/@babel/plugin-transform-private-methods": { "version": "7.23.3", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-create-class-features-plugin": "^7.22.15", @@ -2144,7 +2136,7 @@ }, "node_modules/@babel/plugin-transform-private-property-in-object": { "version": "7.23.4", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-annotate-as-pure": "^7.22.5", @@ -2161,7 +2153,7 @@ }, "node_modules/@babel/plugin-transform-property-literals": { "version": "7.18.6", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.18.6" @@ -2278,7 +2270,7 @@ }, "node_modules/@babel/plugin-transform-regenerator": { "version": "7.21.5", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.21.5", @@ -2293,7 +2285,7 @@ }, "node_modules/@babel/plugin-transform-reserved-words": { "version": "7.18.6", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.18.6" @@ -2334,7 +2326,7 @@ }, "node_modules/@babel/plugin-transform-shorthand-properties": { "version": "7.18.6", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.18.6" @@ -2348,7 +2340,7 @@ }, "node_modules/@babel/plugin-transform-spread": { "version": "7.20.7", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.20.2", @@ -2363,7 +2355,7 @@ }, "node_modules/@babel/plugin-transform-sticky-regex": { "version": "7.18.6", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.18.6" @@ -2377,7 +2369,7 @@ }, "node_modules/@babel/plugin-transform-template-literals": { "version": "7.18.9", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.18.9" @@ -2391,7 +2383,7 @@ }, "node_modules/@babel/plugin-transform-typeof-symbol": { "version": "7.18.9", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.18.9" @@ -2405,7 +2397,6 @@ }, "node_modules/@babel/plugin-transform-typescript": { "version": "7.24.7", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-annotate-as-pure": "^7.24.7", @@ -2422,7 +2413,7 @@ }, "node_modules/@babel/plugin-transform-unicode-escapes": { "version": "7.21.5", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.21.5" @@ -2436,7 +2427,7 @@ }, "node_modules/@babel/plugin-transform-unicode-property-regex": { "version": "7.22.3", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.22.1", @@ -2451,7 +2442,7 @@ }, "node_modules/@babel/plugin-transform-unicode-regex": { "version": "7.18.6", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.18.6", @@ -2466,7 +2457,7 @@ }, "node_modules/@babel/plugin-transform-unicode-sets-regex": { "version": "7.22.3", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.22.1", @@ -2481,7 +2472,7 @@ }, "node_modules/@babel/preset-env": { "version": "7.22.4", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@babel/compat-data": "^7.22.3", @@ -2574,7 +2565,7 @@ }, "node_modules/@babel/preset-env/node_modules/semver": { "version": "6.3.1", - "dev": true, + "devOptional": true, "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -2599,7 +2590,7 @@ }, "node_modules/@babel/preset-modules": { "version": "0.1.5", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.0.0", @@ -2792,7 +2783,7 @@ }, "node_modules/@babel/regjsgen": { "version": "0.8.0", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/@babel/runtime": { @@ -3285,6 +3276,10 @@ "resolved": "packages/sdk-node", "link": true }, + "node_modules/@clerk/dev-cli": { + "resolved": "packages/dev-cli", + "link": true + }, "node_modules/@clerk/elements": { "resolved": "packages/elements", "link": true @@ -18821,7 +18816,7 @@ }, "node_modules/babel-plugin-polyfill-corejs2": { "version": "0.4.5", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@babel/compat-data": "^7.22.6", @@ -18834,7 +18829,7 @@ }, "node_modules/babel-plugin-polyfill-corejs2/node_modules/semver": { "version": "6.3.1", - "dev": true, + "devOptional": true, "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -18842,7 +18837,7 @@ }, "node_modules/babel-plugin-polyfill-corejs3": { "version": "0.8.3", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-define-polyfill-provider": "^0.4.2", @@ -18854,7 +18849,7 @@ }, "node_modules/babel-plugin-polyfill-corejs3/node_modules/core-js-compat": { "version": "3.32.2", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "browserslist": "^4.21.10" @@ -18866,7 +18861,7 @@ }, "node_modules/babel-plugin-polyfill-regenerator": { "version": "0.5.2", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-define-polyfill-provider": "^0.4.2" @@ -20816,7 +20811,6 @@ }, "node_modules/clone-deep": { "version": "4.0.1", - "dev": true, "license": "MIT", "dependencies": { "is-plain-object": "^2.0.4", @@ -21571,7 +21565,7 @@ }, "node_modules/core-js-compat": { "version": "3.31.0", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "browserslist": "^4.21.5" @@ -24079,7 +24073,8 @@ }, "node_modules/dotenv": { "version": "16.4.5", - "license": "BSD-2-Clause", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz", + "integrity": "sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==", "engines": { "node": ">=12" }, @@ -27079,9 +27074,7 @@ }, "node_modules/flow-parser": { "version": "0.206.0", - "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=0.4.0" } @@ -31305,7 +31298,6 @@ }, "node_modules/is-plain-object": { "version": "2.0.4", - "dev": true, "license": "MIT", "dependencies": { "isobject": "^3.0.1" @@ -31622,7 +31614,6 @@ }, "node_modules/isobject": { "version": "3.0.1", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -34518,7 +34509,7 @@ }, "node_modules/lodash.debounce": { "version": "4.0.8", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/lodash.deburr": { @@ -36331,7 +36322,6 @@ }, "node_modules/mkdirp": { "version": "0.5.6", - "dev": true, "license": "MIT", "dependencies": { "minimist": "^1.2.6" @@ -36584,7 +36574,6 @@ }, "node_modules/neo-async": { "version": "2.6.2", - "dev": true, "license": "MIT" }, "node_modules/nested-error-stacks": { @@ -36689,9 +36678,7 @@ }, "node_modules/node-dir": { "version": "0.1.17", - "dev": true, "license": "MIT", - "peer": true, "dependencies": { "minimatch": "^3.0.2" }, @@ -40764,12 +40751,12 @@ }, "node_modules/regenerate": { "version": "1.4.2", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/regenerate-unicode-properties": { "version": "10.1.0", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "regenerate": "^1.4.2" @@ -40784,7 +40771,7 @@ }, "node_modules/regenerator-transform": { "version": "0.15.1", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@babel/runtime": "^7.8.4" @@ -40826,7 +40813,7 @@ }, "node_modules/regexpu-core": { "version": "5.3.2", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@babel/regjsgen": "^0.8.0", @@ -40867,7 +40854,7 @@ }, "node_modules/regjsparser": { "version": "0.9.1", - "dev": true, + "devOptional": true, "license": "BSD-2-Clause", "dependencies": { "jsesc": "~0.5.0" @@ -40878,7 +40865,7 @@ }, "node_modules/regjsparser/node_modules/jsesc": { "version": "0.5.0", - "dev": true, + "devOptional": true, "bin": { "jsesc": "bin/jsesc" } @@ -41935,7 +41922,6 @@ }, "node_modules/shallow-clone": { "version": "3.0.1", - "dev": true, "license": "MIT", "dependencies": { "kind-of": "^6.0.2" @@ -45265,7 +45251,7 @@ }, "node_modules/unicode-canonical-property-names-ecmascript": { "version": "2.0.0", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=4" @@ -45280,7 +45266,7 @@ }, "node_modules/unicode-match-property-ecmascript": { "version": "2.0.0", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "unicode-canonical-property-names-ecmascript": "^2.0.0", @@ -45292,7 +45278,7 @@ }, "node_modules/unicode-match-property-value-ecmascript": { "version": "2.1.0", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=4" @@ -45300,7 +45286,7 @@ }, "node_modules/unicode-property-aliases-ecmascript": { "version": "2.1.0", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=4" @@ -49057,6 +49043,622 @@ "url": "https://opencollective.com/webpack" } }, + "packages/dev": { + "name": "@clerk/dev", + "version": "1.0.0", + "extraneous": true, + "license": "MIT", + "dependencies": { + "commander": "^12.1.0", + "dotenv": "^16.4.5", + "glob": "^10.4.2", + "jscodeshift": "^0.16.1" + }, + "bin": { + "clerk-dev": "bin/cli.js" + }, + "devDependencies": { + "@clerk/eslint-config-custom": "*", + "@types/node": "^20.14.8", + "typescript": "*" + }, + "engines": { + "node": ">=18.17.0" + } + }, + "packages/dev-cli": { + "name": "@clerk/dev-cli", + "version": "1.0.0", + "license": "MIT", + "dependencies": { + "commander": "^12.1.0", + "dotenv": "^16.4.5", + "globby": "^14.0.2", + "jscodeshift": "^0.16.1" + }, + "bin": { + "clerk-dev": "bin/cli.js" + }, + "devDependencies": { + "@clerk/eslint-config-custom": "*", + "@types/node": "^20.14.8", + "typescript": "*" + }, + "engines": { + "node": ">=18.17.0" + } + }, + "packages/dev-cli/node_modules/@babel/helper-module-transforms": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.24.8.tgz", + "integrity": "sha512-m4vWKVqvkVAWLXfHCCfff2luJj86U+J0/x+0N3ArG/tP0Fq7zky2dYwMbtPmkc/oulkkbjdL3uWzuoBwQ8R00Q==", + "dependencies": { + "@babel/helper-environment-visitor": "^7.24.7", + "@babel/helper-module-imports": "^7.24.7", + "@babel/helper-simple-access": "^7.24.7", + "@babel/helper-split-export-declaration": "^7.24.7", + "@babel/helper-validator-identifier": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "packages/dev-cli/node_modules/@babel/helper-plugin-utils": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.8.tgz", + "integrity": "sha512-FFWx5142D8h2Mgr/iPVGH5G7w6jDn4jUSpZTyDnQO0Yn7Ks2Kuz6Pci8H6MPCoUJegd/UZQ3tAvfLCxQSnWWwg==", + "engines": { + "node": ">=6.9.0" + } + }, + "packages/dev-cli/node_modules/@babel/plugin-syntax-flow": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.24.7.tgz", + "integrity": "sha512-9G8GYT/dxn/D1IIKOUBmGX0mnmj46mGH9NnZyJLwtCpgh5f7D2VbuKodb+2s9m1Yavh1s7ASQN8lf0eqrb1LTw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "packages/dev-cli/node_modules/@babel/plugin-transform-class-properties": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.24.7.tgz", + "integrity": "sha512-vKbfawVYayKcSeSR5YYzzyXvsDFWU2mD8U5TFeXtbCPLFUqe7GyCgvO6XDHzje862ODrOwy6WCPmKeWHbCFJ4w==", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "packages/dev-cli/node_modules/@babel/plugin-transform-flow-strip-types": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.24.7.tgz", + "integrity": "sha512-cjRKJ7FobOH2eakx7Ja+KpJRj8+y+/SiB3ooYm/n2UJfxu0oEaOoxOinitkJcPqv9KxS0kxTGPUaR7L2XcXDXA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-flow": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "packages/dev-cli/node_modules/@babel/plugin-transform-modules-commonjs": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.24.8.tgz", + "integrity": "sha512-WHsk9H8XxRs3JXKWFiqtQebdh9b/pTk4EgueygFzYlTKAg0Ud985mSevdNjdXdFBATSKVJGQXP1tv6aGbssLKA==", + "dependencies": { + "@babel/helper-module-transforms": "^7.24.8", + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/helper-simple-access": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "packages/dev-cli/node_modules/@babel/plugin-transform-nullish-coalescing-operator": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.24.7.tgz", + "integrity": "sha512-Ts7xQVk1OEocqzm8rHMXHlxvsfZ0cEF2yomUqpKENHWMF4zKk175Y4q8H5knJes6PgYad50uuRmt3UJuhBw8pQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "packages/dev-cli/node_modules/@babel/plugin-transform-optional-chaining": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.24.8.tgz", + "integrity": "sha512-5cTOLSMs9eypEy8JUVvIKOu6NgvbJMnpG62VpIHrTmROdQ+L5mDAaI40g25k5vXti55JWNX5jCkq3HZxXBQANw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7", + "@babel/plugin-syntax-optional-chaining": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "packages/dev-cli/node_modules/@babel/plugin-transform-private-methods": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.24.7.tgz", + "integrity": "sha512-COTCOkG2hn4JKGEKBADkA8WNb35TGkkRbI5iT845dB+NyqgO8Hn+ajPbSnIQznneJTa3d30scb6iz/DhH8GsJQ==", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "packages/dev-cli/node_modules/@babel/preset-flow": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/preset-flow/-/preset-flow-7.24.7.tgz", + "integrity": "sha512-NL3Lo0NorCU607zU3NwRyJbpaB6E3t0xtd3LfAQKDfkeX4/ggcDXvkmkW42QWT5owUeW/jAe4hn+2qvkV1IbfQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-validator-option": "^7.24.7", + "@babel/plugin-transform-flow-strip-types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "packages/dev-cli/node_modules/@babel/preset-typescript": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.24.7.tgz", + "integrity": "sha512-SyXRe3OdWwIwalxDg5UtJnJQO+YPcTfwiIY2B0Xlddh9o7jpWLvv8X1RthIeDOxQ+O1ML5BLPCONToObyVQVuQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-validator-option": "^7.24.7", + "@babel/plugin-syntax-jsx": "^7.24.7", + "@babel/plugin-transform-modules-commonjs": "^7.24.7", + "@babel/plugin-transform-typescript": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "packages/dev-cli/node_modules/@babel/register": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/register/-/register-7.24.6.tgz", + "integrity": "sha512-WSuFCc2wCqMeXkz/i3yfAAsxwWflEgbVkZzivgAmXl/MxrXeoYFZOOPllbC8R8WTF7u61wSRQtDVZ1879cdu6w==", + "dependencies": { + "clone-deep": "^4.0.1", + "find-cache-dir": "^2.0.0", + "make-dir": "^2.1.0", + "pirates": "^4.0.6", + "source-map-support": "^0.5.16" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "packages/dev-cli/node_modules/@types/node": { + "version": "20.14.10", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.10.tgz", + "integrity": "sha512-MdiXf+nDuMvY0gJKxyfZ7/6UFsETO7mGKF54MVD/ekJS6HdFtpZFBgrh6Pseu64XTb2MLyFPlbW6hj8HYRQNOQ==", + "dev": true, + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "packages/dev-cli/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "packages/dev-cli/node_modules/ast-types": { + "version": "0.16.1", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.16.1.tgz", + "integrity": "sha512-6t10qk83GOG8p0vKmaCr8eiilZwO171AvbROMtvvNiwrTly62t+7XkA8RdIIVbpMhCASAsxgAzdRSwh6nw/5Dg==", + "dependencies": { + "tslib": "^2.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "packages/dev-cli/node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "packages/dev-cli/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "packages/dev-cli/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "packages/dev-cli/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "packages/dev-cli/node_modules/commander": { + "version": "12.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", + "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==", + "engines": { + "node": ">=18" + } + }, + "packages/dev-cli/node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "packages/dev-cli/node_modules/find-cache-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz", + "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==", + "dependencies": { + "commondir": "^1.0.1", + "make-dir": "^2.0.0", + "pkg-dir": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "packages/dev-cli/node_modules/find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dependencies": { + "locate-path": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "packages/dev-cli/node_modules/globby": { + "version": "14.0.2", + "resolved": "https://registry.npmjs.org/globby/-/globby-14.0.2.tgz", + "integrity": "sha512-s3Fq41ZVh7vbbe2PN3nrW7yC7U7MFVc5c98/iTl9c2GawNMKx/J648KQRW6WKkuU8GIbbh2IXfIRQjOZnXcTnw==", + "dependencies": { + "@sindresorhus/merge-streams": "^2.1.0", + "fast-glob": "^3.3.2", + "ignore": "^5.2.4", + "path-type": "^5.0.0", + "slash": "^5.1.0", + "unicorn-magic": "^0.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "packages/dev-cli/node_modules/jscodeshift": { + "version": "0.16.1", + "resolved": "https://registry.npmjs.org/jscodeshift/-/jscodeshift-0.16.1.tgz", + "integrity": "sha512-oMQXySazy63awNBzMpXbbVv73u3irdxTeX2L5ueRyFRxi32qb9uzdZdOY5fTBYADBG19l5M/wnGknZSV1dzCdA==", + "dependencies": { + "@babel/core": "^7.24.7", + "@babel/parser": "^7.24.7", + "@babel/plugin-transform-class-properties": "^7.24.7", + "@babel/plugin-transform-modules-commonjs": "^7.24.7", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.24.7", + "@babel/plugin-transform-optional-chaining": "^7.24.7", + "@babel/plugin-transform-private-methods": "^7.24.7", + "@babel/preset-flow": "^7.24.7", + "@babel/preset-typescript": "^7.24.7", + "@babel/register": "^7.24.6", + "chalk": "^4.1.2", + "flow-parser": "0.*", + "graceful-fs": "^4.2.4", + "micromatch": "^4.0.7", + "neo-async": "^2.5.0", + "node-dir": "^0.1.17", + "recast": "^0.23.9", + "temp": "^0.9.4", + "write-file-atomic": "^5.0.1" + }, + "bin": { + "jscodeshift": "bin/jscodeshift.js" + }, + "peerDependencies": { + "@babel/preset-env": "^7.1.6" + }, + "peerDependenciesMeta": { + "@babel/preset-env": { + "optional": true + } + } + }, + "packages/dev-cli/node_modules/locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dependencies": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "packages/dev-cli/node_modules/make-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "dependencies": { + "pify": "^4.0.1", + "semver": "^5.6.0" + }, + "engines": { + "node": ">=6" + } + }, + "packages/dev-cli/node_modules/micromatch": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz", + "integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "packages/dev-cli/node_modules/p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dependencies": { + "p-limit": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "packages/dev-cli/node_modules/path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", + "engines": { + "node": ">=4" + } + }, + "packages/dev-cli/node_modules/path-type": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-5.0.0.tgz", + "integrity": "sha512-5HviZNaZcfqP95rwpv+1HDgUamezbqdSYTyzjTvwtJSnIH+3vnbmWsItli8OFEndS984VT55M3jduxZbX351gg==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "packages/dev-cli/node_modules/pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "engines": { + "node": ">=6" + } + }, + "packages/dev-cli/node_modules/pkg-dir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", + "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", + "dependencies": { + "find-up": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "packages/dev-cli/node_modules/recast": { + "version": "0.23.9", + "resolved": "https://registry.npmjs.org/recast/-/recast-0.23.9.tgz", + "integrity": "sha512-Hx/BGIbwj+Des3+xy5uAtAbdCyqK9y9wbBcDFDYanLS9JnMqf7OeF87HQwUimE87OEc72mr6tkKUKMBBL+hF9Q==", + "dependencies": { + "ast-types": "^0.16.1", + "esprima": "~4.0.0", + "source-map": "~0.6.1", + "tiny-invariant": "^1.3.3", + "tslib": "^2.0.1" + }, + "engines": { + "node": ">= 4" + } + }, + "packages/dev-cli/node_modules/rimraf": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "packages/dev-cli/node_modules/rimraf/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "packages/dev-cli/node_modules/rimraf/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "packages/dev-cli/node_modules/rimraf/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "packages/dev-cli/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "bin": { + "semver": "bin/semver" + } + }, + "packages/dev-cli/node_modules/slash": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-5.1.0.tgz", + "integrity": "sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "packages/dev-cli/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "engines": { + "node": ">=0.10.0" + } + }, + "packages/dev-cli/node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "packages/dev-cli/node_modules/temp": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/temp/-/temp-0.9.4.tgz", + "integrity": "sha512-yYrrsWnrXMcdsnu/7YMYAofM1ktpL5By7vZhf15CrXijWWrEYZks5AXBudalfSWJLlnen/QUJUB5aoB0kqZUGA==", + "dependencies": { + "mkdirp": "^0.5.1", + "rimraf": "~2.6.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "packages/dev-cli/node_modules/write-file-atomic": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-5.0.1.tgz", + "integrity": "sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==", + "dependencies": { + "imurmurhash": "^0.1.4", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, "packages/elements": { "name": "@clerk/elements", "version": "0.10.5", diff --git a/packages/dev-cli/.eslintrc.cjs b/packages/dev-cli/.eslintrc.cjs new file mode 100644 index 0000000000..108309d83a --- /dev/null +++ b/packages/dev-cli/.eslintrc.cjs @@ -0,0 +1,8 @@ +module.exports = { + root: true, + extends: ['@clerk/custom/node', '@clerk/custom/typescript', '@clerk/custom/jest'], + rules: { + // allowList all environment variables since we don't use Turborepo for clerk-dev anyway. + 'turbo/no-undeclared-env-vars': ['error', { allowList: ['.*'] }], + }, +}; diff --git a/packages/dev-cli/README.md b/packages/dev-cli/README.md new file mode 100644 index 0000000000..66ca1af680 --- /dev/null +++ b/packages/dev-cli/README.md @@ -0,0 +1,88 @@ +# `clerk-dev` CLI + +The `clerk-dev` CLI is a tool designed to simplify the process of iterating on packages within the `clerk/javascript` repository within sample applications, such as customer reproductions. It allows for the installation of the monorepo versions of packages, and supports features such as hot module reloading for increased development velocity. + +## Installation + +```sh +npm install --global @clerk/dev-cli +``` + +If you haven't already, install `turbo` globally. + +```sh +npm install --global turbo +``` + +## First time setup + +After installing `@clerk/dev` globally, you'll need to initialise a configuration file and tell the CLI where to find your local copy of the `clerk/javascript` repository. + +1. Initialise the configuration file which will be located at `~/.config/clerk/dev.json`: + + ```shell + clerk-dev init + ``` + +2. Navigate to your local clone of `clerk/javascript` and run `set-root`: + + ```shell + clerk-dev set-root + ``` + +You're all set now to run the day-to-day commands 🎉 + +## Adding instances & changing the configuration + +During the first time setup a `~/.config/clerk/dev.json` file was created. Its object contains a `activeInstance` and `instances` key. You can add additional instances by adding a new key to the `instances` object. + +You can use the `set-instance` command to switch between `activeInstance` afterwards: + +```shell +clerk-dev set-instance yourName +``` + +## Per-Project Setup + +In each project you'd like to use with the monorepo versions of Clerk packages, `clerk-dev` can perform one-time framework setup such as installing the monorepo versions of packages and configuring the framework to use your Clerk keys. + +To perform framework setup, run: + +```sh +clerk-dev setup +``` + +If you aren't working on `@clerk/clerk-js`, and do not want to customize the `clerkJSUrl`, pass `--no-js`. + +```sh +clerk-dev setup --no-js +``` + +If you want to skip the installation of monorepo versions of packages, pass `--skip-install`. + +```sh +clerk-dev setup --skip-install +``` + +## Running + +Once your project has been configured to use the monorepo versions of your dependencies, you can start the watchers for each dependency by running: + +```sh +clerk-dev watch +``` + +This will run the `build` task for any `@clerk/*` packages in the `package.json` of the current working directory, including any of their dependencies. + +> [!NOTE] +> On macOS, this command will automatically spawn a new Terminal.app window running the dev task for `clerk-js`. On other operating systems, you will need to run the following command in a new terminal: +> +> ```sh +> clerk-dev watch --js +> ``` + +If you do not want to spawn the watcher for `@clerk/clerk-js`, you can instead pass `--no-js`. + +```sh +clerk-dev watch --no-js +``` diff --git a/packages/dev-cli/bin/cli.js b/packages/dev-cli/bin/cli.js new file mode 100755 index 0000000000..a3d1aae3d4 --- /dev/null +++ b/packages/dev-cli/bin/cli.js @@ -0,0 +1,5 @@ +#!/usr/bin/env node + +import cli from '../src/cli.js'; + +cli(); diff --git a/packages/dev-cli/jsconfig.json b/packages/dev-cli/jsconfig.json new file mode 100644 index 0000000000..f0588105fb --- /dev/null +++ b/packages/dev-cli/jsconfig.json @@ -0,0 +1,24 @@ +{ + "compilerOptions": { + "declaration": true, + "declarationMap": false, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "importHelpers": true, + "isolatedModules": true, + "moduleResolution": "NodeNext", + "module": "NodeNext", + "noImplicitReturns": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "resolveJsonModule": true, + "sourceMap": false, + "strict": true, + "target": "ES2020", + "outDir": "dist", + "types": ["jest"], + "checkJs": true + }, + "exclude": ["node_modules"], + "include": ["src/"] +} diff --git a/packages/dev-cli/package.json b/packages/dev-cli/package.json new file mode 100644 index 0000000000..8fa637cf4c --- /dev/null +++ b/packages/dev-cli/package.json @@ -0,0 +1,34 @@ +{ + "name": "@clerk/dev-cli", + "version": "0.0.0", + "license": "MIT", + "type": "module", + "author": "Clerk", + "homepage": "https://clerk.com/", + "repository": { + "type": "git", + "url": "git+https://github.com/clerk/javascript.git", + "directory": "packages/dev-cli" + }, + "main": "bin/cli.js", + "bin": { + "clerk-dev": "bin/cli.js" + }, + "engines": { + "node": ">=18.17.0" + }, + "scripts": { + "lint": "eslint src/" + }, + "dependencies": { + "commander": "^12.1.0", + "dotenv": "^16.4.5", + "globby": "^14.0.2", + "jscodeshift": "^0.16.1" + }, + "devDependencies": { + "@clerk/eslint-config-custom": "*", + "@types/node": "^20.14.8", + "typescript": "*" + } +} diff --git a/packages/dev-cli/schema.json b/packages/dev-cli/schema.json new file mode 100644 index 0000000000..1dd798fe5f --- /dev/null +++ b/packages/dev-cli/schema.json @@ -0,0 +1,47 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/Configuration", + "definitions": { + "Configuration": { + "type": "object", + "additionalProperties": false, + "properties": { + "$schema": { "type": "string" }, + "root": { + "anyOf": [{ "type": "string" }, { "type": "null" }] + }, + "activeInstance": { + "type": "string" + }, + "instances": { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/InstanceConfiguration" + } + } + }, + "required": ["root", "activeInstance", "instances"], + "title": "Configuration" + }, + "InstanceConfiguration": { + "type": "object", + "additionalProperties": false, + "properties": { + "secretKey": { + "type": "string" + }, + "publishableKey": { + "type": "string" + }, + "fapiUrl": { + "type": "string" + }, + "bapiUrl": { + "type": "string" + } + }, + "required": ["secretKey", "publishableKey", "fapiUrl", "bapiUrl"], + "title": "InstanceConfiguration" + } + } +} diff --git a/packages/dev-cli/src/cli.js b/packages/dev-cli/src/cli.js new file mode 100644 index 0000000000..a045f4f852 --- /dev/null +++ b/packages/dev-cli/src/cli.js @@ -0,0 +1,69 @@ +import { Command } from 'commander'; + +import { config } from './commands/config.js'; +import { init } from './commands/init.js'; +import { setInstance } from './commands/set-instance.js'; +import { setRoot } from './commands/set-root.js'; +import { setup } from './commands/setup.js'; +import { watch } from './commands/watch.js'; + +export default function cli() { + const program = new Command(); + + program.name('clerk-dev').description('CLI to make developing Clerk packages easier').version('0.0.0'); + + program + .command('init') + .description('Perform initial one-time machine setup') + .action(async () => { + await init(); + }); + + program + .command('config') + .description('Open the clerk-dev config file in EDITOR or VISUAL') + .action(async () => { + await config(); + }); + + program + .command('set-root') + .description( + 'Set the location of your checkout of the clerk/javascript repository to the current working directory', + ) + .action(async () => { + await setRoot(); + }); + + program + .command('set-instance') + .description('Set the active instance to the provided instance name') + .argument('', 'name of instance listed in dev.json') + .action(async instance => { + await setInstance({ instance }); + }); + + program + .command('setup') + .description( + 'Install the monorepo versions of Clerk packages listed in the package.json file and perform framework configuration for the current working directory', + ) + .option('--no-js', 'do not customize the clerkJSUrl') + .option('--skip-install', 'only perform framework configuration; do not install monorepo versions of packages') + .action(async ({ js, skipInstall }) => { + await setup({ js, skipInstall }); + }); + + program + .command('watch') + .description( + 'Start the dev tasks for all Clerk packages listed in the package.json file in the current working directory, including clerk-js (unless --no-js is specified)', + ) + .option('--js', 'only start the watcher for clerk-js') + .option('--no-js', 'do not spawn the clerk-js watcher (macOS only)') + .action(async ({ js }) => { + await watch({ js }); + }); + + program.parseAsync(); +} diff --git a/packages/dev-cli/src/codemods/index.js b/packages/dev-cli/src/codemods/index.js new file mode 100644 index 0000000000..2da3166f89 --- /dev/null +++ b/packages/dev-cli/src/codemods/index.js @@ -0,0 +1,19 @@ +import { join } from 'node:path'; + +import { run } from 'jscodeshift/src/Runner.js'; + +/** + * + * @param {string} transform + * @param {string[]} paths + */ +export async function applyCodemod(transform, paths) { + const pathToTransform = join(import.meta.dirname, 'transforms', transform); + return await run(pathToTransform, paths, { + ignorePattern: ['**/node_modules/**', '**/dist/**'], + extensions: 'tsx,ts,jsx,js', + parser: 'tsx', + silent: true, + runInBand: true, + }); +} diff --git a/packages/dev-cli/src/codemods/transforms/add-clerkjsurl-to-provider.cjs b/packages/dev-cli/src/codemods/transforms/add-clerkjsurl-to-provider.cjs new file mode 100644 index 0000000000..1613c72032 --- /dev/null +++ b/packages/dev-cli/src/codemods/transforms/add-clerkjsurl-to-provider.cjs @@ -0,0 +1,32 @@ +const CLERK_JS_URL_PROP = 'clerkJSUrl'; +const CLERK_JS_URL = 'http://localhost:4000/npm/clerk.browser.js'; + +/** + * + * @param {import('jscodeshift').FileInfo} file + * @param {import('jscodeshift').API} api + */ +module.exports = function transformer(file, api) { + const j = api.jscodeshift; + const root = j(file.source); + + const clerkProvider = root.findJSXElements('ClerkProvider'); + + if (clerkProvider.size() > 0) { + clerkProvider.forEach(clerkProviderElement => { + const attrs = clerkProviderElement.get('attributes'); + const hasClerkJSUrlProp = attrs.value.some(n => n.name.name === CLERK_JS_URL_PROP); + if (hasClerkJSUrlProp) { + for (const attr of attrs.value) { + if (attr.name.name === CLERK_JS_URL_PROP) { + attr.value = j.literal(CLERK_JS_URL); + } + } + } else { + attrs.push(j.jsxAttribute(j.jsxIdentifier(CLERK_JS_URL_PROP), j.literal(CLERK_JS_URL))); + } + }); + } + + return root.toSource(); +}; diff --git a/packages/dev-cli/src/commands/auth.js b/packages/dev-cli/src/commands/auth.js new file mode 100644 index 0000000000..888b2b1ad3 --- /dev/null +++ b/packages/dev-cli/src/commands/auth.js @@ -0,0 +1,4 @@ +/** + * TODO - authenticate to Clerk to fetch keys and persist them to the config file + */ +export async function auth() {} diff --git a/packages/dev-cli/src/commands/config.js b/packages/dev-cli/src/commands/config.js new file mode 100644 index 0000000000..8385bff122 --- /dev/null +++ b/packages/dev-cli/src/commands/config.js @@ -0,0 +1,26 @@ +import { spawn } from 'node:child_process'; + +import { CONFIG_FILE } from '../utils/getConfiguration.js'; + +/** + * Opens the clerk-dev config file in VISUAL or EDITOR. + */ +export async function config() { + if (process.env.VISUAL) { + spawn(process.env.VISUAL, [CONFIG_FILE], { + stdio: 'inherit', + env: { + ...process.env, + }, + }); + } else if (process.env.EDITOR) { + spawn(process.env.EDITOR, [CONFIG_FILE], { + stdio: 'inherit', + env: { + ...process.env, + }, + }); + } else { + console.error(`Unable to open clerk-dev config file. Make sure the EDITOR or VISUAL environment variable is set.`); + } +} diff --git a/packages/dev-cli/src/commands/init.js b/packages/dev-cli/src/commands/init.js new file mode 100644 index 0000000000..1f5440a206 --- /dev/null +++ b/packages/dev-cli/src/commands/init.js @@ -0,0 +1,50 @@ +import { spawn } from 'node:child_process'; +import { writeFile } from 'node:fs/promises'; +import { join } from 'node:path'; + +import { CONFIG_FILE } from '../utils/getConfiguration.js'; +import { getCLIRoot } from '../utils/getMonorepoRoot.js'; + +/** + * Performs one-time machine-level configuration tasks such as creating a blank config file. + */ +export async function init() { + const cliRoot = getCLIRoot(); + + /** @type import('../utils/getConfiguration.js').Configuration */ + const configuration = { + $schema: join(cliRoot, 'packages', 'dev', 'schema.json'), + root: null, + activeInstance: 'default', + instances: { + default: { + secretKey: 'sk_REPLACE_WITH_SECRET_KEY', + publishableKey: 'pk_REPLACE_WITH_PUBLISHABLE_KEY', + fapiUrl: 'REPLACE_WITH_FAPI_URL', + bapiUrl: 'https://api.clerk.com', + }, + }, + }; + + await writeFile(CONFIG_FILE, JSON.stringify(configuration, null, 2), 'utf-8'); + + if (process.env.VISUAL) { + spawn(process.env.VISUAL, [CONFIG_FILE], { + stdio: 'inherit', + env: { + ...process.env, + }, + }); + console.log(`Configuration file written to ${CONFIG_FILE}.`); + } else if (process.env.EDITOR) { + spawn(process.env.EDITOR, [CONFIG_FILE], { + stdio: 'inherit', + env: { + ...process.env, + }, + }); + console.log(`Configuration file written to ${CONFIG_FILE}.`); + } else { + console.log(`Configuration file written to ${CONFIG_FILE}. Replace with your values.`); + } +} diff --git a/packages/dev-cli/src/commands/set-instance.js b/packages/dev-cli/src/commands/set-instance.js new file mode 100644 index 0000000000..5d59e03293 --- /dev/null +++ b/packages/dev-cli/src/commands/set-instance.js @@ -0,0 +1,20 @@ +import { writeFile } from 'node:fs/promises'; + +import { CONFIG_FILE, getConfiguration } from '../utils/getConfiguration.js'; + +/** + * Sets the active instance to the provided instance name. + * @param {object} args + * @param {string} args.instance + */ +export async function setInstance({ instance }) { + const config = await getConfiguration(); + + if (!(instance in config.instances)) { + throw new Error(`Instance "${instance}" not found in dev.json.`); + } + + const newConfig = { ...config, activeInstance: instance }; + await writeFile(CONFIG_FILE, JSON.stringify(newConfig, null, 2), 'utf-8'); + console.log(`clerk-dev activeInstance set to ${instance}.`); +} diff --git a/packages/dev-cli/src/commands/set-root.js b/packages/dev-cli/src/commands/set-root.js new file mode 100644 index 0000000000..f470e1d34b --- /dev/null +++ b/packages/dev-cli/src/commands/set-root.js @@ -0,0 +1,21 @@ +import { readFile, writeFile } from 'node:fs/promises'; + +import { CONFIG_FILE, getConfiguration } from '../utils/getConfiguration.js'; + +/** + * Sets the location of the clerk/javascript monorepo to the machine-level config file. + */ +export async function setRoot() { + const config = await getConfiguration(); + const cwd = process.cwd(); + + const packageJSON = await readFile('package.json', 'utf-8'); + const pkg = JSON.parse(packageJSON); + if (pkg.name !== '@clerk/javascript') { + throw new Error('clerk-dev set-root needs to be run within a local checkout of the clerk/javascript repository.'); + } + + const newConfig = { ...config, root: process.cwd() }; + await writeFile(CONFIG_FILE, JSON.stringify(newConfig, null, 2), 'utf-8'); + console.log(`clerk-dev root set to ${cwd}.`); +} diff --git a/packages/dev-cli/src/commands/setup.js b/packages/dev-cli/src/commands/setup.js new file mode 100644 index 0000000000..72718a0bf2 --- /dev/null +++ b/packages/dev-cli/src/commands/setup.js @@ -0,0 +1,202 @@ +import { spawn } from 'node:child_process'; +import { existsSync } from 'node:fs'; +import { readFile, writeFile } from 'node:fs/promises'; +import { join } from 'node:path'; + +import { parse } from 'dotenv'; + +import { applyCodemod } from '../codemods/index.js'; +import { getClerkPackages } from '../utils/getClerkPackages.js'; +import { getConfiguration } from '../utils/getConfiguration.js'; +import { getDependencies } from '../utils/getDependencies.js'; + +/** + * Returns `true` if the cwd contains a file named `filename`, otherwise returns `false`. + * @param {string} filename + * @returns {boolean} + */ +function hasFile(filename) { + return existsSync(join(process.cwd(), filename)); +} + +/** + * Returns `true` if `packages` contains a `dependency` key, otherwise `false`. + * @param {Record | undefined} packages + * @param {string} dependency + * @returns {boolean} + */ +function hasPackage(packages, dependency) { + if (!packages) { + return false; + } + return dependency in packages; +} + +/** + * Returns a string corresponding to the framework detected in the cwd. + * @returns {Promise} + */ +async function detectFramework() { + const { dependencies, devDependencies } = await getDependencies(join(process.cwd(), 'package.json')); + + const IS_NEXT = hasFile('next.config.js') || hasFile('next.config.mjs'); + if (IS_NEXT) { + return 'nextjs'; + } + + const IS_REMIX = hasFile('remix.config.js') || hasFile('remix.config.mjs'); + if (IS_REMIX) { + return 'remix'; + } + + const IS_VITE = hasPackage(dependencies, 'vite') || hasPackage(devDependencies, 'vite'); + if (IS_VITE) { + return 'vite'; + } + + throw new Error('unable to determine framework'); +} + +/** + * Returns the active instance of the provided `configuration`. + * @param {import('../utils/getConfiguration.js').Configuration} configuration + * @returns {Promise} + */ +async function getInstanceConfiguration(configuration) { + const { activeInstance, instances } = configuration; + return instances[activeInstance]; +} + +/** + * Generates a .env file string. + * @param {Record} envConfiguration + * @returns {string} + */ +function buildEnvFile(envConfiguration) { + return ( + Object.entries(envConfiguration) + .map(([key, value]) => [key, JSON.stringify(value)].join('=')) + .join('\n') + '\n' + ); +} + +/** + * Parses the file at `filename` with dotenv. + * @param {string} filename + * @returns {Promise} + */ +async function readEnvFile(filename) { + const contents = await readFile(filename, 'utf-8'); + const envConfig = parse(contents); + return envConfig; +} + +/** + * Write the provided `config` to the .env file at `filename`, merging with any existing entries. + * @param {string} filename + * @param {Record} config + */ +async function mergeEnvFiles(filename, config) { + const envFileExists = hasFile(filename); + const existingEnv = envFileExists ? await readEnvFile(filename) : {}; + await writeFile( + join(process.cwd(), filename), + buildEnvFile({ + ...existingEnv, + ...config, + }), + ); +} + +/** + * Installs the monorepo versions of the Clerk dependencies listed in the `package.json` file of the cwd. + * @returns {Promise} + */ +async function linkDependencies() { + const { dependencies } = await getDependencies(join(process.cwd(), 'package.json')); + if (!dependencies) { + throw new Error('you have no dependencies'); + } + const clerkPackages = await getClerkPackages(); + + const dependenciesToBeInstalled = Object.keys(dependencies) + .filter(dep => dep in clerkPackages) + .map(clerkDep => clerkPackages[clerkDep]); + + const args = ['install', '--no-audit', '--no-fund', ...dependenciesToBeInstalled]; + + return new Promise((resolve, reject) => { + const child = spawn('npm', args, { + stdio: 'inherit', + env: { + ...process.env, + ADBLOCK: '1', + DISABLE_OPENCOLLECTIVE: '1', + }, + }); + + child.on('close', code => { + if (code !== 0) { + reject(); + return; + } + resolve(); + }); + }); +} + +/** + * Installs the monorepo-versions of Clerk dependencies listed in the `package.json` file of the current working + * directory, and performs framework configuration tasks necessary for local development with the monorepo packages. + * @param {object} args + * @param {boolean | undefined} args.js If `false`, do not customize the clerkJSUrl. + * @param {boolean | undefined} args.skipInstall If `true`, do not install monorepo versions of packages. + */ +export async function setup({ js = true, skipInstall = false }) { + if (!skipInstall) { + console.log('Installing monorepo versions of Clerk packages from package.json...'); + await linkDependencies(); + } + + const config = await getConfiguration(); + const instance = await getInstanceConfiguration(config); + + const framework = await detectFramework(); + switch (framework) { + case 'nextjs': { + console.log('Next.js detected, writing environment variables to .env.local...'); + await mergeEnvFiles('.env.local', { + NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY: instance.publishableKey, + CLERK_SECRET_KEY: instance.secretKey, + ...(js ? { NEXT_PUBLIC_CLERK_JS_URL: 'http://localhost:4000/npm/clerk.browser.js' } : {}), + }); + break; + } + case 'remix': { + console.log('Remix detected, writing environment variables to .env...'); + await mergeEnvFiles('.env', { + CLERK_PUBLISHABLE_KEY: instance.publishableKey, + CLERK_SECRET_KEY: instance.secretKey, + }); + break; + } + case 'vite': { + console.log('Vite detected, writing environment variables to .env...'); + await mergeEnvFiles('.env', { + VITE_CLERK_PUBLISHABLE_KEY: instance.publishableKey, + }); + + if (js) { + console.log('Adding clerkJSUrl to ClerkProvider...'); + const res = await applyCodemod('add-clerkjsurl-to-provider.cjs', [process.cwd()]); + if (res.ok === 0) { + console.warn('warning: could not find a ClerkProvider to edit. Please add clerkJSUrl manually.'); + } + } + break; + } + default: { + throw new Error('unable to determine framework'); + } + } +} diff --git a/packages/dev-cli/src/commands/watch.js b/packages/dev-cli/src/commands/watch.js new file mode 100644 index 0000000000..e5db7ef89f --- /dev/null +++ b/packages/dev-cli/src/commands/watch.js @@ -0,0 +1,77 @@ +import { spawn } from 'node:child_process'; +import { join } from 'node:path'; + +import { getClerkPackages } from '../utils/getClerkPackages.js'; +import { getDependencies } from '../utils/getDependencies.js'; +import { getMonorepoRoot } from '../utils/getMonorepoRoot.js'; + +/** + * Starts long-running watchers for Clerk dependencies. + * @param {object} args + * @param {boolean | undefined} args.js If `true`, only spawn the builder for `@clerk/clerk-js`. + * @returns {Promise} + */ +export async function watch({ js }) { + const { dependencies, devDependencies } = await getDependencies(join(process.cwd(), 'package.json')); + const clerkPackages = Object.keys(await getClerkPackages()); + + const packagesInPackageJSON = [...Object.keys(dependencies ?? {}), ...Object.keys(devDependencies ?? {})]; + const clerkPackagesInPackageJSON = packagesInPackageJSON.filter(p => clerkPackages.includes(p)); + + const filterArgs = clerkPackagesInPackageJSON.map(p => `--filter=${p}`); + + const args = ['watch', 'build', ...filterArgs]; + + const cwd = await getMonorepoRoot(); + + if (js) { + return new Promise((resolve, reject) => { + const child = spawn( + 'turbo', + ['run', 'dev', '--filter=@clerk/clerk-js', '--', '--env', 'devOrigin=http://localhost:4000'], + { + cwd, + stdio: 'inherit', + env: { ...process.env }, + }, + ); + + child.on('close', code => { + if (code !== 0) { + reject(); + return; + } + resolve(); + }); + }); + } + + if (typeof js === 'undefined') { + // On macOS, we spawn a new Terminal.app instance containing the watcher for clerk-js. This is because clerk-js is + // not declared as a dependency for any other packages, so Turborepo is unable to automatically start it. + if (process.platform === 'darwin') { + spawn('osascript', [ + '-e', + `tell app "Terminal" to do script "cd ${cwd} && turbo run dev --filter=@clerk/clerk-js -- --env devOrigin=http://localhost:4000"`, + ]); + } + } + + return new Promise((resolve, reject) => { + const child = spawn('turbo', args, { + cwd, + stdio: 'inherit', + env: { + ...process.env, + }, + }); + + child.on('close', code => { + if (code !== 0) { + reject(); + return; + } + resolve(); + }); + }); +} diff --git a/packages/dev-cli/src/utils/getClerkPackages.js b/packages/dev-cli/src/utils/getClerkPackages.js new file mode 100644 index 0000000000..6c8b69adf0 --- /dev/null +++ b/packages/dev-cli/src/utils/getClerkPackages.js @@ -0,0 +1,23 @@ +import { readFile } from 'node:fs/promises'; +import { dirname, join, posix, resolve } from 'node:path'; + +import { globby } from 'globby'; + +/** + * Generates an object with keys of package names and values of absolute paths to the package folder. + * @returns {Promise>} + */ +export async function getClerkPackages() { + const monorepoRoot = resolve(join(import.meta.dirname, '..', '..', '..', '..')); + /** @type {Record} */ + const packages = {}; + const clerkPackages = await globby([posix.join(monorepoRoot, 'packages', '*', 'package.json'), '!*node_modules*']); + for (const packageJSON of clerkPackages) { + const { name } = JSON.parse(await readFile(packageJSON, 'utf-8')); + if (name) { + packages[name] = dirname(packageJSON); + } + } + + return packages; +} diff --git a/packages/dev-cli/src/utils/getConfiguration.js b/packages/dev-cli/src/utils/getConfiguration.js new file mode 100644 index 0000000000..36d8236098 --- /dev/null +++ b/packages/dev-cli/src/utils/getConfiguration.js @@ -0,0 +1,31 @@ +import { readFile } from 'node:fs/promises'; +import { homedir } from 'node:os'; +import { join } from 'node:path'; + +/** + * @typedef {object} InstanceConfiguration + * @prop {string} secretKey + * @prop {string} publishableKey + * @prop {string} fapiUrl + * @prop {string} bapiUrl + */ + +/** + * @typedef {object} Configuration + * @prop {string} $schema + * @prop {string | null} root + * @prop {string} activeInstance + * @prop {Record} instances + */ + +export const CONFIG_FILE = join(homedir(), '.config', 'clerk', 'dev.json'); + +/** + * Gets the contents of the clerk-dev configuration file. + * @returns {Promise} + */ +export async function getConfiguration() { + const configFileJSON = await readFile(CONFIG_FILE, 'utf-8'); + const configuration = JSON.parse(configFileJSON); + return configuration; +} diff --git a/packages/dev-cli/src/utils/getDependencies.js b/packages/dev-cli/src/utils/getDependencies.js new file mode 100644 index 0000000000..8efa906d2b --- /dev/null +++ b/packages/dev-cli/src/utils/getDependencies.js @@ -0,0 +1,12 @@ +import { readFile } from 'node:fs/promises'; + +/** + * Gets the `dependencies` and `devDependencies` entries of the provided package.json. + * @param {string} pathToPackageJSON + * @returns {Promise<{ dependencies?: Record, devDependencies?: Record}>} + */ +export async function getDependencies(pathToPackageJSON) { + const packageJSON = await readFile(pathToPackageJSON, 'utf-8'); + const { dependencies, devDependencies } = JSON.parse(packageJSON); + return { dependencies, devDependencies }; +} diff --git a/packages/dev-cli/src/utils/getMonorepoRoot.js b/packages/dev-cli/src/utils/getMonorepoRoot.js new file mode 100644 index 0000000000..a34e053896 --- /dev/null +++ b/packages/dev-cli/src/utils/getMonorepoRoot.js @@ -0,0 +1,21 @@ +import { join, resolve } from 'node:path'; + +import { getConfiguration } from './getConfiguration.js'; + +export function getCLIRoot() { + return resolve(join(import.meta.dirname, '..', '..', '..', '..')); +} + +/** + * Gets the `root` property of the clerk-dev configuration file, falling back to the folder containing the source + * for the running instance of clerk-dev. + * @returns {Promise} + */ +export async function getMonorepoRoot() { + const config = await getConfiguration(); + if (config.root) { + return config.root; + } + + return getCLIRoot(); +}