@sentry/wizard 6.6.0 → 6.7.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/CHANGELOG.md +28 -0
- package/LICENSE +97 -8
- package/dist/bin.js +5 -0
- package/dist/bin.js.map +1 -1
- package/dist/e2e-tests/tests/help-message.test.js +5 -1
- package/dist/e2e-tests/tests/help-message.test.js.map +1 -1
- package/dist/e2e-tests/tests/nextjs-15.test.js +79 -0
- package/dist/e2e-tests/tests/nextjs-15.test.js.map +1 -1
- package/dist/e2e-tests/tests/react-router.test.d.ts +1 -0
- package/dist/e2e-tests/tests/react-router.test.js +255 -0
- package/dist/e2e-tests/tests/react-router.test.js.map +1 -0
- package/dist/e2e-tests/utils/index.d.ts +8 -2
- package/dist/e2e-tests/utils/index.js +72 -21
- package/dist/e2e-tests/utils/index.js.map +1 -1
- package/dist/lib/Constants.d.ts +1 -0
- package/dist/lib/Constants.js +5 -0
- package/dist/lib/Constants.js.map +1 -1
- package/dist/src/android/android-wizard.js +8 -1
- package/dist/src/android/android-wizard.js.map +1 -1
- package/dist/src/angular/angular-wizard.js +8 -1
- package/dist/src/angular/angular-wizard.js.map +1 -1
- package/dist/src/apple/apple-wizard.js +8 -1
- package/dist/src/apple/apple-wizard.js.map +1 -1
- package/dist/src/flutter/flutter-wizard.js +8 -1
- package/dist/src/flutter/flutter-wizard.js.map +1 -1
- package/dist/src/nextjs/nextjs-wizard.js +35 -9
- package/dist/src/nextjs/nextjs-wizard.js.map +1 -1
- package/dist/src/nextjs/templates.d.ts +3 -3
- package/dist/src/nextjs/templates.js +18 -7
- package/dist/src/nextjs/templates.js.map +1 -1
- package/dist/src/nuxt/nuxt-wizard.js +8 -1
- package/dist/src/nuxt/nuxt-wizard.js.map +1 -1
- package/dist/src/react-native/react-native-wizard.js +8 -1
- package/dist/src/react-native/react-native-wizard.js.map +1 -1
- package/dist/src/react-router/codemods/client.entry.d.ts +1 -0
- package/dist/src/react-router/codemods/client.entry.js +73 -0
- package/dist/src/react-router/codemods/client.entry.js.map +1 -0
- package/dist/src/react-router/codemods/react-router-config.d.ts +9 -0
- package/dist/src/react-router/codemods/react-router-config.js +178 -0
- package/dist/src/react-router/codemods/react-router-config.js.map +1 -0
- package/dist/src/react-router/codemods/root.d.ts +1 -0
- package/dist/src/react-router/codemods/root.js +171 -0
- package/dist/src/react-router/codemods/root.js.map +1 -0
- package/dist/src/react-router/codemods/routes-config.d.ts +1 -0
- package/dist/src/react-router/codemods/routes-config.js +106 -0
- package/dist/src/react-router/codemods/routes-config.js.map +1 -0
- package/dist/src/react-router/codemods/server-entry.d.ts +4 -0
- package/dist/src/react-router/codemods/server-entry.js +275 -0
- package/dist/src/react-router/codemods/server-entry.js.map +1 -0
- package/dist/src/react-router/codemods/utils.d.ts +2 -0
- package/dist/src/react-router/codemods/utils.js +13 -0
- package/dist/src/react-router/codemods/utils.js.map +1 -0
- package/dist/src/react-router/codemods/vite.d.ts +8 -0
- package/dist/src/react-router/codemods/vite.js +169 -0
- package/dist/src/react-router/codemods/vite.js.map +1 -0
- package/dist/src/react-router/react-router-wizard.d.ts +2 -0
- package/dist/src/react-router/react-router-wizard.js +254 -0
- package/dist/src/react-router/react-router-wizard.js.map +1 -0
- package/dist/src/react-router/sdk-example.d.ts +18 -0
- package/dist/src/react-router/sdk-example.js +306 -0
- package/dist/src/react-router/sdk-example.js.map +1 -0
- package/dist/src/react-router/sdk-setup.d.ts +17 -0
- package/dist/src/react-router/sdk-setup.js +250 -0
- package/dist/src/react-router/sdk-setup.js.map +1 -0
- package/dist/src/react-router/templates.d.ts +11 -0
- package/dist/src/react-router/templates.js +273 -0
- package/dist/src/react-router/templates.js.map +1 -0
- package/dist/src/remix/remix-wizard.js +8 -1
- package/dist/src/remix/remix-wizard.js.map +1 -1
- package/dist/src/run.d.ts +2 -1
- package/dist/src/run.js +6 -0
- package/dist/src/run.js.map +1 -1
- package/dist/src/sourcemaps/sourcemaps-wizard.js +8 -1
- package/dist/src/sourcemaps/sourcemaps-wizard.js.map +1 -1
- package/dist/src/sveltekit/sveltekit-wizard.js +8 -1
- package/dist/src/sveltekit/sveltekit-wizard.js.map +1 -1
- package/dist/src/utils/ast-utils.d.ts +30 -0
- package/dist/src/utils/ast-utils.js +71 -1
- package/dist/src/utils/ast-utils.js.map +1 -1
- package/dist/src/utils/clack/index.d.ts +5 -2
- package/dist/src/utils/clack/index.js +14 -2
- package/dist/src/utils/clack/index.js.map +1 -1
- package/dist/src/utils/types.d.ts +9 -0
- package/dist/src/utils/types.js.map +1 -1
- package/dist/src/version.d.ts +1 -1
- package/dist/src/version.js +1 -1
- package/dist/src/version.js.map +1 -1
- package/dist/test/nextjs/templates.test.js +20 -0
- package/dist/test/nextjs/templates.test.js.map +1 -1
- package/dist/test/react-router/codemods/client-entry.test.d.ts +1 -0
- package/dist/test/react-router/codemods/client-entry.test.js +168 -0
- package/dist/test/react-router/codemods/client-entry.test.js.map +1 -0
- package/dist/test/react-router/codemods/react-router-config.test.d.ts +1 -0
- package/dist/test/react-router/codemods/react-router-config.test.js +168 -0
- package/dist/test/react-router/codemods/react-router-config.test.js.map +1 -0
- package/dist/test/react-router/codemods/root.test.d.ts +1 -0
- package/dist/test/react-router/codemods/root.test.js +178 -0
- package/dist/test/react-router/codemods/root.test.js.map +1 -0
- package/dist/test/react-router/codemods/server-entry.test.d.ts +1 -0
- package/dist/test/react-router/codemods/server-entry.test.js +415 -0
- package/dist/test/react-router/codemods/server-entry.test.js.map +1 -0
- package/dist/test/react-router/codemods/vite.test.d.ts +1 -0
- package/dist/test/react-router/codemods/vite.test.js +158 -0
- package/dist/test/react-router/codemods/vite.test.js.map +1 -0
- package/dist/test/react-router/routes-config.test.d.ts +1 -0
- package/dist/test/react-router/routes-config.test.js +156 -0
- package/dist/test/react-router/routes-config.test.js.map +1 -0
- package/dist/test/react-router/sdk-setup.test.d.ts +1 -0
- package/dist/test/react-router/sdk-setup.test.js +411 -0
- package/dist/test/react-router/sdk-setup.test.js.map +1 -0
- package/dist/test/react-router/templates.test.d.ts +1 -0
- package/dist/test/react-router/templates.test.js +220 -0
- package/dist/test/react-router/templates.test.js.map +1 -0
- package/dist/test/utils/clack/index.test.js +1 -1
- package/dist/test/utils/clack/index.test.js.map +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server-entry.js","sourceRoot":"","sources":["../../../../src/react-router/codemods/server-entry.ts"],"names":[],"mappings":";AAAA,0DAA0D;AAC1D,uDAAuD;AACvD,sDAAsD;AACtD,+DAA+D;AAC/D,wDAAwD;AACxD,4DAA4D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAK5D,+CAAiC;AAGjC,+EAA+E;AAC/E,6DAAmC;AACnC,kDAA0B;AAE1B,kFAAkF;AAClF,uCAA6D;AAC7D,6CAA0C;AAC1C,qDAI+B;AAC/B,mCAAwD;AAEjD,KAAK,UAAU,qBAAqB,CACzC,eAAuB;IAEvB,MAAM,cAAc,GAAG,MAAM,IAAA,mBAAQ,EAAC,eAAe,CAAC,CAAC;IAEvD,IAAI,CAAC,IAAA,4BAAgB,EAAC,cAAc,CAAC,IAAiB,CAAC,EAAE;QACvD,cAAc,CAAC,OAAO,CAAC,IAAI,CAAC;YAC1B,IAAI,EAAE,sBAAsB;YAC5B,QAAQ,EAAE,GAAG;YACb,KAAK,EAAE,QAAQ;SAChB,CAAC,CAAC;KACJ;IAED,qBAAqB,CAAC,cAAc,CAAC,CAAC;IACtC,uBAAuB,CAAC,cAAc,CAAC,CAAC;IAExC,MAAM,IAAA,oBAAS,EAAC,cAAc,CAAC,IAAI,EAAE,eAAe,CAAC,CAAC;AACxD,CAAC;AAjBD,sDAiBC;AAED,SAAgB,uBAAuB,CACrC,sBAA4C;IAE5C,MAAM,yBAAyB,GAAG,sBAAsB,CAAC,IAAiB,CAAC;IAE3E,MAAM,wBAAwB,GAAG,yBAAyB,CAAC,IAAI,CAAC,IAAI,CAClE,CAAC,IAAI,EAAE,EAAE;QACP,OAAO,IAAI,CAAC,IAAI,KAAK,0BAA0B,CAAC;IAClD,CAAC,CACF,CAAC;IAEF,IAAI,CAAC,wBAAwB,EAAE;QAC7B,iBAAK,CAAC,GAAG,CAAC,IAAI,CACZ,2BAA2B,eAAK,CAAC,IAAI,CACnC,eAAe,CAChB,mDAAmD,CACrD,CAAC;QAEF,IAAI,uBAAuB,GAAG,KAAK,CAAC;QACpC,IAAI,iCAAiC,GAAG,KAAK,CAAC;QAC9C,IAAI,2CAA2C,GAAG,KAAK,CAAC;QAExD,sBAAsB,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE;YACrD,IAAI,IAAI,CAAC,QAAQ,KAAK,cAAc,IAAI,IAAI,CAAC,IAAI,KAAK,cAAc,EAAE;gBACpE,uBAAuB,GAAG,IAAI,CAAC;aAChC;YACD,IACE,IAAI,CAAC,QAAQ,KAAK,wBAAwB;gBAC1C,IAAI,CAAC,IAAI,KAAK,kBAAkB,EAChC;gBACA,iCAAiC,GAAG,IAAI,CAAC;aAC1C;YACD,IACE,IAAI,CAAC,QAAQ,KAAK,kCAAkC;gBACpD,IAAI,CAAC,IAAI,KAAK,oBAAoB,EAClC;gBACA,2CAA2C,GAAG,IAAI,CAAC;aACpD;QACH,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,uBAAuB,EAAE;YAC5B,sBAAsB,CAAC,OAAO,CAAC,IAAI,CAAC;gBAClC,IAAI,EAAE,cAAc;gBACpB,QAAQ,EAAE,cAAc;gBACxB,KAAK,EAAE,cAAc;aACtB,CAAC,CAAC;SACJ;QAED,IAAI,CAAC,iCAAiC,EAAE;YACtC,sBAAsB,CAAC,OAAO,CAAC,IAAI,CAAC;gBAClC,IAAI,EAAE,kBAAkB;gBACxB,QAAQ,EAAE,wBAAwB;gBAClC,KAAK,EAAE,wBAAwB;aAChC,CAAC,CAAC;SACJ;QAED,IAAI,CAAC,2CAA2C,EAAE;YAChD,sBAAsB,CAAC,OAAO,CAAC,IAAI,CAAC;gBAClC,IAAI,EAAE,oBAAoB;gBAC1B,QAAQ,EAAE,kCAAkC;gBAC5C,KAAK,EAAE,kCAAkC;aAC1C,CAAC,CAAC;SACJ;QAED,MAAM,cAAc,GAClB,MAAM,CAAC,KAAK,CAAC;;;;GAIhB,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAEjB,IAAI;YACF,yBAAyB,CAAC,IAAI,CAAC,MAAM,CACnC,IAAA,qCAA6B,EAAC,yBAAyB,CAAC,EACxD,CAAC,EACD,cAAc,CACf,CAAC;YAEF,yBAAyB,CAAC,IAAI,CAAC,IAAI,CAAC;gBAClC,IAAI,EAAE,0BAA0B;gBAChC,WAAW,EAAE;oBACX,IAAI,EAAE,YAAY;oBAClB,IAAI,EAAE,eAAe;iBACtB;aACF,CAAC,CAAC;SACJ;QAAC,OAAO,KAAK,EAAE;YACd,IAAA,aAAK,EAAC,gDAAgD,EAAE,KAAK,CAAC,CAAC;YAC/D,MAAM,IAAI,KAAK,CACb,2EAA2E,CAC5E,CAAC;SACH;KACF;SAAM,IACL,wBAAwB;QACxB,uFAAuF;QACvF,IAAA,uBAAY,EAAC,wBAAwB,CAAC,CAAC,IAAI,CAAC,QAAQ,CAClD,yBAAyB,CAC1B,EACD;QACA,IAAA,aAAK,EAAC,kEAAkE,CAAC,CAAC;QAC1E,iBAAK,CAAC,GAAG,CAAC,IAAI,CACZ,0EAA0E,CAC3E,CAAC;KACH;SAAM;QACL,IAAI,iBAAiB,GACnB,IAAI,CAAC;QACP,MAAM,kBAAkB,GAAG,yBAAyB,CAAC,IAAI,CAAC,SAAS,CACjE,CAAC,IAAI,EAAE,EAAE;YACP,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,KAAK,0BAA0B,CAAC;YAEvD,IAAI,KAAK,EAAE;gBACT,iBAAiB,GAAG,IAAI,CAAC;aAC1B;YAED,OAAO,KAAK,CAAC;QACf,CAAC,CACF,CAAC;QAEF,IAAI,kBAAkB,KAAK,CAAC,CAAC,IAAI,iBAAiB,KAAK,IAAI,EAAE;YAC3D,MAAM,CAAC,KAAK,CAAC,iBAAiB,EAAE;gBAC9B,mBAAmB,CAAC,IAAI;oBACtB,IACE,IAAA,qCAAyB,EAAC,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,MAAM,CAAC;wBACpD,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM;wBAC3B,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,YAAY;wBAC7C,IAAA,iCAAqB,EAAC,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,KAAK,MAAM,EACzD;wBACA,MAAM,OAAO,GAAG,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,cAAc,CAClD,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,gBAAgB,CACpC,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,UAAU,CAAC,QAAQ,CAAC,EAC1C,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,UAAU,CAAC,uBAAuB,CAAC,CAC1D,EACD,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAC1B,CAAC;wBAEF,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC;qBACnC;oBAED,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;gBACtB,CAAC;aACF,CAAC,CAAC;YAEH,2DAA2D;YAC3D,yBAAyB,CAAC,IAAI,CAAC,MAAM,CACnC,kBAAkB,EAClB,CAAC;YACD,qFAAqF;YACrF,iBAAiB,CAAC,WAAW,CAC9B,CAAC;YAEF,4BAA4B;YAC5B,yBAAyB,CAAC,IAAI,CAAC,IAAI,CACjC,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,wBAAwB,CAC5C,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,cAAc,CAClC,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,gBAAgB,CACpC,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,UAAU,CAAC,QAAQ,CAAC,EAC1C,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,UAAU,CAAC,yBAAyB,CAAC,CAC5D,EACD,CAAC,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,UAAU,CAAC,eAAe,CAAC,CAAC,CACpD,CACF,CACF,CAAC;SACH;KACF;AACH,CAAC;AAnKD,0DAmKC;AAED,SAAgB,qBAAqB,CACnC,sBAA4C;IAE5C,MAAM,yBAAyB,GAAG,sBAAsB,CAAC,IAAiB,CAAC;IAE3E,MAAM,yBAAyB,GAAG,yBAAyB,CAAC,IAAI,CAAC,IAAI,CACnE,CAAC,IAAI,EAAE,EAAE;QACP,OAAO,CACL,IAAI,CAAC,IAAI,KAAK,wBAAwB;YACtC,IAAI,CAAC,WAAW,EAAE,IAAI,KAAK,qBAAqB;YAChD,IAAI,CAAC,WAAW,CAAC,EAAE,EAAE,IAAI,KAAK,aAAa,CAC5C,CAAC;IACJ,CAAC,CACF,CAAC;IAEF,MAAM,4CAA4C,GAChD,yBAAyB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE;QAC3C,IACE,IAAI,CAAC,IAAI,KAAK,wBAAwB;YACtC,IAAI,CAAC,WAAW,EAAE,IAAI,KAAK,qBAAqB,EAChD;YACA,OAAO,KAAK,CAAC;SACd;QAED,MAAM,YAAY,GAAG,IAAI,CAAC,WAAW,CAAC,YAAY,CAAC;QACnD,IAAI,CAAC,YAAY,IAAI,YAAY,CAAC,MAAM,KAAK,CAAC,EAAE;YAC9C,OAAO,KAAK,CAAC;SACd;QAED,MAAM,gBAAgB,GAAG,YAAY,CAAC,CAAC,CAAC,CAAC;QACzC,IAAI,CAAC,gBAAgB,IAAI,gBAAgB,CAAC,IAAI,KAAK,oBAAoB,EAAE;YACvE,OAAO,KAAK,CAAC;SACd;QAED,MAAM,EAAE,GAAG,gBAAgB,CAAC,EAAE,CAAC;QAC/B,OAAO,EAAE,IAAI,EAAE,CAAC,IAAI,KAAK,YAAY,IAAI,EAAE,CAAC,IAAI,KAAK,aAAa,CAAC;IACrE,CAAC,CAAC,CAAC;IAEL,IACE,CAAC,yBAAyB;QAC1B,CAAC,4CAA4C,EAC7C;QACA,iBAAK,CAAC,GAAG,CAAC,IAAI,CACZ,2BAA2B,eAAK,CAAC,IAAI,CACnC,aAAa,CACd,mDAAmD,CACrD,CAAC;QAEF,MAAM,cAAc,GAClB,MAAM,CAAC,KAAK,CAAC;;GAEhB,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAEjB,yBAAyB,CAAC,IAAI,CAAC,MAAM,CACnC,IAAA,qCAA6B,EAAC,yBAAyB,CAAC,EACxD,CAAC,EACD,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,sBAAsB,CAAC,cAAc,CAAC,CAC7D,CAAC;KACH;SAAM,IACL,CAAC,yBAAyB;QACxB,uFAAuF;QACvF,IAAA,uBAAY,EAAC,yBAAyB,CAAC,CAAC,IAAI,CAAC,QAAQ,CACnD,kBAAkB,CACnB,CAAC;QACJ,CAAC,4CAA4C;YAC3C,uFAAuF;YACvF,IAAA,uBAAY,EAAC,4CAA4C,CAAC,CAAC,IAAI,CAAC,QAAQ,CACtE,kBAAkB,CACnB,CAAC,EACJ;QACA,IAAA,aAAK,EACH,qEAAqE,CACtE,CAAC;KACH;SAAM,IACL,CAAC,yBAAyB;QACxB,uFAAuF;QACvF,IAAA,uBAAY,EAAC,yBAAyB,CAAC,CAAC,IAAI,CAAC,QAAQ,CACnD,yBAAyB,CAC1B,CAAC;QACJ,CAAC,4CAA4C;YAC3C,uFAAuF;YACvF,IAAA,uBAAY,EAAC,4CAA4C,CAAC,CAAC,IAAI,CAAC,QAAQ,CACtE,yBAAyB,CAC1B,CAAC,EACJ;QACA,IAAA,aAAK,EAAC,mEAAmE,CAAC,CAAC;KAC5E;SAAM,IAAI,yBAAyB,EAAE;QACpC,4DAA4D;QAC5D,MAAM,UAAU,GAAG,MAAM,CAAC,KAAK,CAAC;;EAElC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAEhB,kFAAkF;QAClF,qFAAqF;QACrF,MAAM,WAAW,GAAG,yBAAyB,CAAC,WAAW,CAAC;QAC1D,IACE,WAAW;YACX,WAAW,CAAC,IAAI;YAChB,WAAW,CAAC,IAAI,CAAC,IAAI;YACrB,KAAK,CAAC,OAAO,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,EACpC;YACA,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;SAC3C;aAAM;YACL,IAAA,aAAK,EACH,0EAA0E,CAC3E,CAAC;SACH;KACF;SAAM,IAAI,4CAA4C,EAAE;QACvD,4DAA4D;QAC5D,MAAM,UAAU,GAAG,MAAM,CAAC,KAAK,CAAC;;EAElC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAEhB,8EAA8E;QAC9E,wFAAwF;QACxF,MAAM,iBAAiB,GACrB,4CAAmD,CAAC;QACtD,IACE,CAAC,iBAAiB,CAAC,WAAW;YAC9B,iBAAiB,CAAC,WAAW,CAAC,IAAI,KAAK,qBAAqB;YAC5D,CAAC,iBAAiB,CAAC,WAAW,CAAC,YAAY;YAC3C,iBAAiB,CAAC,WAAW,CAAC,YAAY,CAAC,MAAM,KAAK,CAAC,EACvD;YACA,IAAA,aAAK,EACH,iFAAiF,CAClF,CAAC;YACF,OAAO;SACR;QAED,MAAM,gBAAgB,GAAG,iBAAiB,CAAC,WAAW,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QACvE,IACE,CAAC,gBAAgB;YACjB,gBAAgB,CAAC,IAAI,KAAK,oBAAoB;YAC9C,CAAC,gBAAgB,CAAC,IAAI,EACtB;YACA,IAAA,aAAK,EACH,qFAAqF,CACtF,CAAC;YACF,OAAO;SACR;QAED,MAAM,iCAAiC,GAAG,gBAAgB,CAAC,IAAI,CAAC;QAChE,MAAM,cAAc,GAAG,iCAAiC,CAAC,MAAM,CAAC;QAChE,MAAM,YAAY,GAAG,iCAAiC,CAAC,IAAI,CAAC;QAE5D,MAAM,YAAY,GAAG;YACnB,GAAG,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,QAAQ,CAC/B,MAAM,EACN,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,MAAM;YACnD,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,UAAU,CAAC,SAAS,CAAC,CAC5C;YACD,SAAS,EAAE,IAAI;SAChB,CAAC;QACF,4EAA4E;QAC5E,oCAAoC;QACpC,IAAI,cAAc,CAAC,MAAM,KAAK,CAAC,EAAE;YAC/B,cAAc,CAAC,IAAI,CACjB,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,UAAU,CAAC,OAAO,CAAC,EACzC,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC,YAAY,CAAC,CAAC,CACpD,CAAC;YACF,mCAAmC;SACpC;aAAM,IAAI,cAAc,CAAC,MAAM,KAAK,CAAC,EAAE;YACtC,cAAc,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;YACzE,8DAA8D;SAC/D;aAAM,IACL,cAAc,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,eAAe;YAC1C,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,CAChC,CAAC,IAAsB,EAAE,EAAE,CACzB,IAAA,iCAAqB,EAAC,IAAI,CAAC,GAAG,CAAC,KAAK,SAAS,CAChD,EACD;YACA,cAAc,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;SACjD;QAED,2CAA2C;QAC3C,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;KACpC;AACH,CAAC;AAjLD,sDAiLC","sourcesContent":["/* eslint-disable @typescript-eslint/no-unsafe-argument */\n/* eslint-disable @typescript-eslint/no-explicit-any */\n/* eslint-disable @typescript-eslint/no-unsafe-call */\n/* eslint-disable @typescript-eslint/no-unsafe-member-access */\n/* eslint-disable @typescript-eslint/no-unsafe-return */\n/* eslint-disable @typescript-eslint/no-unsafe-assignment */\n\n// @ts-expect-error - magicast is ESM and TS complains about that. It works though\nimport type { ProxifiedModule } from 'magicast';\n\nimport * as recast from 'recast';\nimport type { namedTypes as t } from 'ast-types';\n\n// @ts-expect-error - clack is ESM and TS complains about that. It works though\nimport clack from '@clack/prompts';\nimport chalk from 'chalk';\n\n// @ts-expect-error - magicast is ESM and TS complains about that. It works though\nimport { generateCode, loadFile, writeFile } from 'magicast';\nimport { debug } from '../../utils/debug';\nimport {\n hasSentryContent,\n safeCalleeIdentifierMatch,\n safeGetIdentifierName,\n} from '../../utils/ast-utils';\nimport { getAfterImportsInsertionIndex } from './utils';\n\nexport async function instrumentServerEntry(\n serverEntryPath: string,\n): Promise<void> {\n const serverEntryAst = await loadFile(serverEntryPath);\n\n if (!hasSentryContent(serverEntryAst.$ast as t.Program)) {\n serverEntryAst.imports.$add({\n from: '@sentry/react-router',\n imported: '*',\n local: 'Sentry',\n });\n }\n\n instrumentHandleError(serverEntryAst);\n instrumentHandleRequest(serverEntryAst);\n\n await writeFile(serverEntryAst.$ast, serverEntryPath);\n}\n\nexport function instrumentHandleRequest(\n originalEntryServerMod: ProxifiedModule<any>,\n): void {\n const originalEntryServerModAST = originalEntryServerMod.$ast as t.Program;\n\n const defaultServerEntryExport = originalEntryServerModAST.body.find(\n (node) => {\n return node.type === 'ExportDefaultDeclaration';\n },\n );\n\n if (!defaultServerEntryExport) {\n clack.log.warn(\n `Could not find function ${chalk.cyan(\n 'handleRequest',\n )} in your server entry file. Creating one for you.`,\n );\n\n let foundServerRouterImport = false;\n let foundRenderToPipeableStreamImport = false;\n let foundCreateReadableStreamFromReadableImport = false;\n\n originalEntryServerMod.imports.$items.forEach((item) => {\n if (item.imported === 'ServerRouter' && item.from === 'react-router') {\n foundServerRouterImport = true;\n }\n if (\n item.imported === 'renderToPipeableStream' &&\n item.from === 'react-dom/server'\n ) {\n foundRenderToPipeableStreamImport = true;\n }\n if (\n item.imported === 'createReadableStreamFromReadable' &&\n item.from === '@react-router/node'\n ) {\n foundCreateReadableStreamFromReadableImport = true;\n }\n });\n\n if (!foundServerRouterImport) {\n originalEntryServerMod.imports.$add({\n from: 'react-router',\n imported: 'ServerRouter',\n local: 'ServerRouter',\n });\n }\n\n if (!foundRenderToPipeableStreamImport) {\n originalEntryServerMod.imports.$add({\n from: 'react-dom/server',\n imported: 'renderToPipeableStream',\n local: 'renderToPipeableStream',\n });\n }\n\n if (!foundCreateReadableStreamFromReadableImport) {\n originalEntryServerMod.imports.$add({\n from: '@react-router/node',\n imported: 'createReadableStreamFromReadable',\n local: 'createReadableStreamFromReadable',\n });\n }\n\n const implementation =\n recast.parse(`const handleRequest = Sentry.createSentryHandleRequest({\n ServerRouter,\n renderToPipeableStream,\n createReadableStreamFromReadable,\n})`).program.body[0];\n\n try {\n originalEntryServerModAST.body.splice(\n getAfterImportsInsertionIndex(originalEntryServerModAST),\n 0,\n implementation,\n );\n\n originalEntryServerModAST.body.push({\n type: 'ExportDefaultDeclaration',\n declaration: {\n type: 'Identifier',\n name: 'handleRequest',\n },\n });\n } catch (error) {\n debug('Failed to insert handleRequest implementation:', error);\n throw new Error(\n 'Could not automatically instrument handleRequest. Please add it manually.',\n );\n }\n } else if (\n defaultServerEntryExport &&\n // @ts-expect-error - StatementKind works here because the AST is proxified by magicast\n generateCode(defaultServerEntryExport).code.includes(\n 'wrapSentryHandleRequest',\n )\n ) {\n debug('wrapSentryHandleRequest is already used, skipping wrapping again');\n clack.log.info(\n 'Sentry handleRequest wrapper already detected, skipping instrumentation.',\n );\n } else {\n let defaultExportNode: recast.types.namedTypes.ExportDefaultDeclaration | null =\n null;\n const defaultExportIndex = originalEntryServerModAST.body.findIndex(\n (node) => {\n const found = node.type === 'ExportDefaultDeclaration';\n\n if (found) {\n defaultExportNode = node;\n }\n\n return found;\n },\n );\n\n if (defaultExportIndex !== -1 && defaultExportNode !== null) {\n recast.visit(defaultExportNode, {\n visitCallExpression(path) {\n if (\n safeCalleeIdentifierMatch(path.value.callee, 'pipe') &&\n path.value.arguments.length &&\n path.value.arguments[0].type === 'Identifier' &&\n safeGetIdentifierName(path.value.arguments[0]) === 'body'\n ) {\n const wrapped = recast.types.builders.callExpression(\n recast.types.builders.memberExpression(\n recast.types.builders.identifier('Sentry'),\n recast.types.builders.identifier('getMetaTagTransformer'),\n ),\n [path.value.arguments[0]],\n );\n\n path.value.arguments[0] = wrapped;\n }\n\n this.traverse(path);\n },\n });\n\n // Replace the existing default export with the wrapped one\n originalEntryServerModAST.body.splice(\n defaultExportIndex,\n 1,\n // @ts-expect-error - declaration works here because the AST is proxified by magicast\n defaultExportNode.declaration,\n );\n\n // Adding our wrapped export\n originalEntryServerModAST.body.push(\n recast.types.builders.exportDefaultDeclaration(\n recast.types.builders.callExpression(\n recast.types.builders.memberExpression(\n recast.types.builders.identifier('Sentry'),\n recast.types.builders.identifier('wrapSentryHandleRequest'),\n ),\n [recast.types.builders.identifier('handleRequest')],\n ),\n ),\n );\n }\n }\n}\n\nexport function instrumentHandleError(\n originalEntryServerMod: ProxifiedModule<any>,\n): void {\n const originalEntryServerModAST = originalEntryServerMod.$ast as t.Program;\n\n const handleErrorFunctionExport = originalEntryServerModAST.body.find(\n (node) => {\n return (\n node.type === 'ExportNamedDeclaration' &&\n node.declaration?.type === 'FunctionDeclaration' &&\n node.declaration.id?.name === 'handleError'\n );\n },\n );\n\n const handleErrorFunctionVariableDeclarationExport =\n originalEntryServerModAST.body.find((node) => {\n if (\n node.type !== 'ExportNamedDeclaration' ||\n node.declaration?.type !== 'VariableDeclaration'\n ) {\n return false;\n }\n\n const declarations = node.declaration.declarations;\n if (!declarations || declarations.length === 0) {\n return false;\n }\n\n const firstDeclaration = declarations[0];\n if (!firstDeclaration || firstDeclaration.type !== 'VariableDeclarator') {\n return false;\n }\n\n const id = firstDeclaration.id;\n return id && id.type === 'Identifier' && id.name === 'handleError';\n });\n\n if (\n !handleErrorFunctionExport &&\n !handleErrorFunctionVariableDeclarationExport\n ) {\n clack.log.warn(\n `Could not find function ${chalk.cyan(\n 'handleError',\n )} in your server entry file. Creating one for you.`,\n );\n\n const implementation =\n recast.parse(`const handleError = Sentry.createSentryHandleError({\n logErrors: false\n})`).program.body[0];\n\n originalEntryServerModAST.body.splice(\n getAfterImportsInsertionIndex(originalEntryServerModAST),\n 0,\n recast.types.builders.exportNamedDeclaration(implementation),\n );\n } else if (\n (handleErrorFunctionExport &&\n // @ts-expect-error - StatementKind works here because the AST is proxified by magicast\n generateCode(handleErrorFunctionExport).code.includes(\n 'captureException',\n )) ||\n (handleErrorFunctionVariableDeclarationExport &&\n // @ts-expect-error - StatementKind works here because the AST is proxified by magicast\n generateCode(handleErrorFunctionVariableDeclarationExport).code.includes(\n 'captureException',\n ))\n ) {\n debug(\n 'Found captureException inside handleError, skipping adding it again',\n );\n } else if (\n (handleErrorFunctionExport &&\n // @ts-expect-error - StatementKind works here because the AST is proxified by magicast\n generateCode(handleErrorFunctionExport).code.includes(\n 'createSentryHandleError',\n )) ||\n (handleErrorFunctionVariableDeclarationExport &&\n // @ts-expect-error - StatementKind works here because the AST is proxified by magicast\n generateCode(handleErrorFunctionVariableDeclarationExport).code.includes(\n 'createSentryHandleError',\n ))\n ) {\n debug('createSentryHandleError is already used, skipping adding it again');\n } else if (handleErrorFunctionExport) {\n // Create the Sentry captureException call as an IfStatement\n const sentryCall = recast.parse(`if (!request.signal.aborted) {\n Sentry.captureException(error);\n}`).program.body[0];\n\n // Safely insert the Sentry call at the beginning of the handleError function body\n // @ts-expect-error - declaration works here because the AST is proxified by magicast\n const declaration = handleErrorFunctionExport.declaration;\n if (\n declaration &&\n declaration.body &&\n declaration.body.body &&\n Array.isArray(declaration.body.body)\n ) {\n declaration.body.body.unshift(sentryCall);\n } else {\n debug(\n 'Cannot safely access handleError function body, skipping instrumentation',\n );\n }\n } else if (handleErrorFunctionVariableDeclarationExport) {\n // Create the Sentry captureException call as an IfStatement\n const sentryCall = recast.parse(`if (!request.signal.aborted) {\n Sentry.captureException(error);\n}`).program.body[0];\n\n // Safe access to existing handle error implementation with proper null checks\n // We know this is ExportNamedDeclaration with VariableDeclaration from the earlier find\n const exportDeclaration =\n handleErrorFunctionVariableDeclarationExport as any;\n if (\n !exportDeclaration.declaration ||\n exportDeclaration.declaration.type !== 'VariableDeclaration' ||\n !exportDeclaration.declaration.declarations ||\n exportDeclaration.declaration.declarations.length === 0\n ) {\n debug(\n 'Cannot safely access handleError variable declaration, skipping instrumentation',\n );\n return;\n }\n\n const firstDeclaration = exportDeclaration.declaration.declarations[0];\n if (\n !firstDeclaration ||\n firstDeclaration.type !== 'VariableDeclarator' ||\n !firstDeclaration.init\n ) {\n debug(\n 'Cannot safely access handleError variable declarator init, skipping instrumentation',\n );\n return;\n }\n\n const existingHandleErrorImplementation = firstDeclaration.init;\n const existingParams = existingHandleErrorImplementation.params;\n const existingBody = existingHandleErrorImplementation.body;\n\n const requestParam = {\n ...recast.types.builders.property(\n 'init',\n recast.types.builders.identifier('request'), // key\n recast.types.builders.identifier('request'), // value\n ),\n shorthand: true,\n };\n // Add error and {request} parameters to handleError function if not present\n // When none of the parameters exist\n if (existingParams.length === 0) {\n existingParams.push(\n recast.types.builders.identifier('error'),\n recast.types.builders.objectPattern([requestParam]),\n );\n // When only error parameter exists\n } else if (existingParams.length === 1) {\n existingParams.push(recast.types.builders.objectPattern([requestParam]));\n // When both parameters exist, but request is not destructured\n } else if (\n existingParams[1].type === 'ObjectPattern' &&\n !existingParams[1].properties.some(\n (prop: t.ObjectProperty) =>\n safeGetIdentifierName(prop.key) === 'request',\n )\n ) {\n existingParams[1].properties.push(requestParam);\n }\n\n // Add the Sentry call to the function body\n existingBody.body.push(sentryCall);\n }\n}\n"]}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getAfterImportsInsertionIndex = void 0;
|
|
4
|
+
function getAfterImportsInsertionIndex(originalEntryServerModAST) {
|
|
5
|
+
for (let x = originalEntryServerModAST.body.length - 1; x >= 0; x--) {
|
|
6
|
+
if (originalEntryServerModAST.body[x].type === 'ImportDeclaration') {
|
|
7
|
+
return x + 1;
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
return 0;
|
|
11
|
+
}
|
|
12
|
+
exports.getAfterImportsInsertionIndex = getAfterImportsInsertionIndex;
|
|
13
|
+
//# sourceMappingURL=utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../../../src/react-router/codemods/utils.ts"],"names":[],"mappings":";;;AAEA,SAAgB,6BAA6B,CAC3C,yBAAoC;IAEpC,KAAK,IAAI,CAAC,GAAG,yBAAyB,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE;QACnE,IAAI,yBAAyB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,mBAAmB,EAAE;YAClE,OAAO,CAAC,GAAG,CAAC,CAAC;SACd;KACF;IAED,OAAO,CAAC,CAAC;AACX,CAAC;AAVD,sEAUC","sourcesContent":["import type { namedTypes as t } from 'ast-types';\n\nexport function getAfterImportsInsertionIndex(\n originalEntryServerModAST: t.Program,\n): number {\n for (let x = originalEntryServerModAST.body.length - 1; x >= 0; x--) {\n if (originalEntryServerModAST.body[x].type === 'ImportDeclaration') {\n return x + 1;\n }\n }\n\n return 0;\n}\n"]}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { namedTypes as t } from 'ast-types';
|
|
2
|
+
export declare function addReactRouterPluginToViteConfig(program: t.Program, orgSlug: string, projectSlug: string): {
|
|
3
|
+
success: boolean;
|
|
4
|
+
wasConverted: boolean;
|
|
5
|
+
};
|
|
6
|
+
export declare function instrumentViteConfig(orgSlug: string, projectSlug: string): Promise<{
|
|
7
|
+
wasConverted: boolean;
|
|
8
|
+
}>;
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
26
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
27
|
+
};
|
|
28
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
|
+
exports.instrumentViteConfig = exports.addReactRouterPluginToViteConfig = void 0;
|
|
30
|
+
const recast = __importStar(require("recast"));
|
|
31
|
+
const path = __importStar(require("path"));
|
|
32
|
+
const fs = __importStar(require("fs"));
|
|
33
|
+
// @ts-expect-error - magicast is ESM and TS complains about that. It works though
|
|
34
|
+
const magicast_1 = require("magicast");
|
|
35
|
+
// @ts-expect-error - clack is ESM and TS complains about that. It works though
|
|
36
|
+
const prompts_1 = __importDefault(require("@clack/prompts"));
|
|
37
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
38
|
+
const ast_utils_1 = require("../../utils/ast-utils");
|
|
39
|
+
/**
|
|
40
|
+
* Extracts ObjectExpression from function body.
|
|
41
|
+
* Handles both arrow functions with object returns and block statements with explicit returns.
|
|
42
|
+
*
|
|
43
|
+
* - Arrow with object-return: (config) => ({ ... })
|
|
44
|
+
* - Arrow with block: (config) => { return { ... }; }
|
|
45
|
+
* - Function with block: function(config) { return { ... }; }
|
|
46
|
+
*
|
|
47
|
+
* @param body - The function body to extract from
|
|
48
|
+
* @returns The ObjectExpression if found, undefined otherwise
|
|
49
|
+
*/
|
|
50
|
+
function extractFromFunctionBody(body) {
|
|
51
|
+
if (body.type === 'ObjectExpression') {
|
|
52
|
+
return body;
|
|
53
|
+
}
|
|
54
|
+
if (body.type === 'BlockStatement') {
|
|
55
|
+
const blockBody = body;
|
|
56
|
+
const returnStatement = blockBody.body.find((stmt) => stmt.type === 'ReturnStatement');
|
|
57
|
+
return returnStatement?.argument?.type === 'ObjectExpression'
|
|
58
|
+
? returnStatement.argument
|
|
59
|
+
: undefined;
|
|
60
|
+
}
|
|
61
|
+
return undefined;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Creates the sentryReactRouter Vite plugin call expression.
|
|
65
|
+
*
|
|
66
|
+
* Generates AST for:
|
|
67
|
+
* sentryReactRouter({
|
|
68
|
+
* org: "...",
|
|
69
|
+
* project: "...",
|
|
70
|
+
* authToken: process.env.SENTRY_AUTH_TOKEN
|
|
71
|
+
* }, config)
|
|
72
|
+
*
|
|
73
|
+
* @param orgSlug - Sentry organization slug
|
|
74
|
+
* @param projectSlug - Sentry project slug
|
|
75
|
+
* @returns CallExpression node for the Sentry Vite plugin
|
|
76
|
+
*/
|
|
77
|
+
function createSentryPluginCall(orgSlug, projectSlug) {
|
|
78
|
+
const b = recast.types.builders;
|
|
79
|
+
return b.callExpression(b.identifier('sentryReactRouter'), [
|
|
80
|
+
b.objectExpression([
|
|
81
|
+
b.objectProperty(b.identifier('org'), b.stringLiteral(orgSlug)),
|
|
82
|
+
b.objectProperty(b.identifier('project'), b.stringLiteral(projectSlug)),
|
|
83
|
+
b.objectProperty(b.identifier('authToken'), b.memberExpression(b.memberExpression(b.identifier('process'), b.identifier('env')), b.identifier('SENTRY_AUTH_TOKEN'))),
|
|
84
|
+
]),
|
|
85
|
+
b.identifier('config'),
|
|
86
|
+
]);
|
|
87
|
+
}
|
|
88
|
+
function addReactRouterPluginToViteConfig(program, orgSlug, projectSlug) {
|
|
89
|
+
const b = recast.types.builders;
|
|
90
|
+
let wasConverted = false;
|
|
91
|
+
const defaultExport = program.body.find((node) => node.type === 'ExportDefaultDeclaration');
|
|
92
|
+
if (!defaultExport) {
|
|
93
|
+
return { success: false, wasConverted: false };
|
|
94
|
+
}
|
|
95
|
+
let configObj;
|
|
96
|
+
let defineConfigCall;
|
|
97
|
+
if (defaultExport.declaration.type === 'CallExpression' &&
|
|
98
|
+
defaultExport.declaration.callee.type === 'Identifier' &&
|
|
99
|
+
defaultExport.declaration.callee.name === 'defineConfig') {
|
|
100
|
+
defineConfigCall = defaultExport.declaration;
|
|
101
|
+
// Early exit if not single argument
|
|
102
|
+
if (defineConfigCall.arguments.length !== 1) {
|
|
103
|
+
return { success: false, wasConverted: false };
|
|
104
|
+
}
|
|
105
|
+
const arg = defineConfigCall.arguments[0];
|
|
106
|
+
if (arg.type === 'ObjectExpression') {
|
|
107
|
+
configObj = arg;
|
|
108
|
+
// Convert to function form
|
|
109
|
+
const arrowFunction = b.arrowFunctionExpression([b.identifier('config')], configObj);
|
|
110
|
+
defineConfigCall.arguments[0] = arrowFunction;
|
|
111
|
+
wasConverted = true;
|
|
112
|
+
}
|
|
113
|
+
else if (arg.type === 'ArrowFunctionExpression' ||
|
|
114
|
+
arg.type === 'FunctionExpression') {
|
|
115
|
+
configObj = extractFromFunctionBody(arg.body);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
if (!configObj) {
|
|
119
|
+
return { success: false, wasConverted };
|
|
120
|
+
}
|
|
121
|
+
const pluginsProp = (0, ast_utils_1.findProperty)(configObj, 'plugins');
|
|
122
|
+
const sentryPluginCall = createSentryPluginCall(orgSlug, projectSlug);
|
|
123
|
+
if (!pluginsProp) {
|
|
124
|
+
configObj.properties.push(b.objectProperty(b.identifier('plugins'), b.arrayExpression([sentryPluginCall])));
|
|
125
|
+
}
|
|
126
|
+
else if (pluginsProp.value.type === 'ArrayExpression' &&
|
|
127
|
+
pluginsProp.type === 'ObjectProperty') {
|
|
128
|
+
const arrayExpr = pluginsProp.value;
|
|
129
|
+
// Defensive: ensure elements array exists
|
|
130
|
+
if (!arrayExpr.elements) {
|
|
131
|
+
arrayExpr.elements = [];
|
|
132
|
+
}
|
|
133
|
+
arrayExpr.elements.push(sentryPluginCall);
|
|
134
|
+
}
|
|
135
|
+
else {
|
|
136
|
+
return { success: false, wasConverted };
|
|
137
|
+
}
|
|
138
|
+
return { success: true, wasConverted };
|
|
139
|
+
}
|
|
140
|
+
exports.addReactRouterPluginToViteConfig = addReactRouterPluginToViteConfig;
|
|
141
|
+
async function instrumentViteConfig(orgSlug, projectSlug) {
|
|
142
|
+
const configPath = fs.existsSync(path.join(process.cwd(), 'vite.config.ts'))
|
|
143
|
+
? path.join(process.cwd(), 'vite.config.ts')
|
|
144
|
+
: path.join(process.cwd(), 'vite.config.js');
|
|
145
|
+
if (!fs.existsSync(configPath)) {
|
|
146
|
+
throw new Error('Could not find vite.config.ts or vite.config.js');
|
|
147
|
+
}
|
|
148
|
+
const configContent = await fs.promises.readFile(configPath, 'utf-8');
|
|
149
|
+
const filename = chalk_1.default.cyan(path.basename(configPath));
|
|
150
|
+
const mod = (0, magicast_1.parseModule)(configContent);
|
|
151
|
+
if ((0, ast_utils_1.hasSentryContent)(mod.$ast)) {
|
|
152
|
+
prompts_1.default.log.info(`${filename} already contains sentryReactRouter plugin.`);
|
|
153
|
+
return { wasConverted: false };
|
|
154
|
+
}
|
|
155
|
+
mod.imports.$add({
|
|
156
|
+
from: '@sentry/react-router',
|
|
157
|
+
imported: 'sentryReactRouter',
|
|
158
|
+
local: 'sentryReactRouter',
|
|
159
|
+
});
|
|
160
|
+
const { success, wasConverted } = addReactRouterPluginToViteConfig(mod.$ast, orgSlug, projectSlug);
|
|
161
|
+
if (!success) {
|
|
162
|
+
throw new Error('Failed to modify Vite config structure');
|
|
163
|
+
}
|
|
164
|
+
const code = (0, magicast_1.generateCode)(mod.$ast).code;
|
|
165
|
+
await fs.promises.writeFile(configPath, code);
|
|
166
|
+
return { wasConverted };
|
|
167
|
+
}
|
|
168
|
+
exports.instrumentViteConfig = instrumentViteConfig;
|
|
169
|
+
//# sourceMappingURL=vite.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vite.js","sourceRoot":"","sources":["../../../../src/react-router/codemods/vite.ts"],"names":[],"mappings":"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","sourcesContent":["import type { namedTypes as t } from 'ast-types';\nimport * as recast from 'recast';\nimport * as path from 'path';\nimport * as fs from 'fs';\n\n// @ts-expect-error - magicast is ESM and TS complains about that. It works though\nimport { parseModule, generateCode } from 'magicast';\n\n// @ts-expect-error - clack is ESM and TS complains about that. It works though\nimport clack from '@clack/prompts';\nimport chalk from 'chalk';\n\nimport { hasSentryContent, findProperty } from '../../utils/ast-utils';\n\n/**\n * Extracts ObjectExpression from function body.\n * Handles both arrow functions with object returns and block statements with explicit returns.\n *\n * - Arrow with object-return: (config) => ({ ... })\n * - Arrow with block: (config) => { return { ... }; }\n * - Function with block: function(config) { return { ... }; }\n *\n * @param body - The function body to extract from\n * @returns The ObjectExpression if found, undefined otherwise\n */\nfunction extractFromFunctionBody(\n body: t.Expression | t.BlockStatement,\n): t.ObjectExpression | undefined {\n if (body.type === 'ObjectExpression') {\n return body as t.ObjectExpression;\n }\n\n if (body.type === 'BlockStatement') {\n const blockBody = body as t.BlockStatement;\n const returnStatement = blockBody.body.find(\n (stmt: t.Statement): stmt is t.ReturnStatement =>\n stmt.type === 'ReturnStatement',\n );\n\n return returnStatement?.argument?.type === 'ObjectExpression'\n ? returnStatement.argument\n : undefined;\n }\n\n return undefined;\n}\n\n/**\n * Creates the sentryReactRouter Vite plugin call expression.\n *\n * Generates AST for:\n * sentryReactRouter({\n * org: \"...\",\n * project: \"...\",\n * authToken: process.env.SENTRY_AUTH_TOKEN\n * }, config)\n *\n * @param orgSlug - Sentry organization slug\n * @param projectSlug - Sentry project slug\n * @returns CallExpression node for the Sentry Vite plugin\n */\nfunction createSentryPluginCall(\n orgSlug: string,\n projectSlug: string,\n): t.CallExpression {\n const b = recast.types.builders;\n return b.callExpression(b.identifier('sentryReactRouter'), [\n b.objectExpression([\n b.objectProperty(b.identifier('org'), b.stringLiteral(orgSlug)),\n b.objectProperty(b.identifier('project'), b.stringLiteral(projectSlug)),\n b.objectProperty(\n b.identifier('authToken'),\n b.memberExpression(\n b.memberExpression(b.identifier('process'), b.identifier('env')),\n b.identifier('SENTRY_AUTH_TOKEN'),\n ),\n ),\n ]),\n b.identifier('config'),\n ]);\n}\n\nexport function addReactRouterPluginToViteConfig(\n program: t.Program,\n orgSlug: string,\n projectSlug: string,\n): { success: boolean; wasConverted: boolean } {\n const b = recast.types.builders;\n let wasConverted = false;\n\n const defaultExport = program.body.find(\n (node) => node.type === 'ExportDefaultDeclaration',\n ) as t.ExportDefaultDeclaration | undefined;\n\n if (!defaultExport) {\n return { success: false, wasConverted: false };\n }\n\n let configObj: t.ObjectExpression | undefined;\n let defineConfigCall: t.CallExpression | undefined;\n\n if (\n defaultExport.declaration.type === 'CallExpression' &&\n defaultExport.declaration.callee.type === 'Identifier' &&\n defaultExport.declaration.callee.name === 'defineConfig'\n ) {\n defineConfigCall = defaultExport.declaration;\n\n // Early exit if not single argument\n if (defineConfigCall.arguments.length !== 1) {\n return { success: false, wasConverted: false };\n }\n\n const arg = defineConfigCall.arguments[0];\n\n if (arg.type === 'ObjectExpression') {\n configObj = arg;\n // Convert to function form\n const arrowFunction = b.arrowFunctionExpression(\n [b.identifier('config')],\n configObj,\n );\n defineConfigCall.arguments[0] = arrowFunction;\n wasConverted = true;\n } else if (\n arg.type === 'ArrowFunctionExpression' ||\n arg.type === 'FunctionExpression'\n ) {\n configObj = extractFromFunctionBody(arg.body);\n }\n }\n\n if (!configObj) {\n return { success: false, wasConverted };\n }\n\n const pluginsProp = findProperty(configObj, 'plugins');\n const sentryPluginCall = createSentryPluginCall(orgSlug, projectSlug);\n\n if (!pluginsProp) {\n configObj.properties.push(\n b.objectProperty(\n b.identifier('plugins'),\n b.arrayExpression([sentryPluginCall]),\n ),\n );\n } else if (\n pluginsProp.value.type === 'ArrayExpression' &&\n pluginsProp.type === 'ObjectProperty'\n ) {\n const arrayExpr = pluginsProp.value;\n // Defensive: ensure elements array exists\n if (!arrayExpr.elements) {\n arrayExpr.elements = [];\n }\n arrayExpr.elements.push(sentryPluginCall);\n } else {\n return { success: false, wasConverted };\n }\n\n return { success: true, wasConverted };\n}\n\nexport async function instrumentViteConfig(\n orgSlug: string,\n projectSlug: string,\n): Promise<{ wasConverted: boolean }> {\n const configPath = fs.existsSync(path.join(process.cwd(), 'vite.config.ts'))\n ? path.join(process.cwd(), 'vite.config.ts')\n : path.join(process.cwd(), 'vite.config.js');\n\n if (!fs.existsSync(configPath)) {\n throw new Error('Could not find vite.config.ts or vite.config.js');\n }\n\n const configContent = await fs.promises.readFile(configPath, 'utf-8');\n const filename = chalk.cyan(path.basename(configPath));\n\n const mod = parseModule(configContent);\n\n if (hasSentryContent(mod.$ast as t.Program)) {\n clack.log.info(`${filename} already contains sentryReactRouter plugin.`);\n return { wasConverted: false };\n }\n\n mod.imports.$add({\n from: '@sentry/react-router',\n imported: 'sentryReactRouter',\n local: 'sentryReactRouter',\n });\n\n const { success, wasConverted } = addReactRouterPluginToViteConfig(\n mod.$ast as t.Program,\n orgSlug,\n projectSlug,\n );\n\n if (!success) {\n throw new Error('Failed to modify Vite config structure');\n }\n\n const code = generateCode(mod.$ast).code;\n await fs.promises.writeFile(configPath, code);\n\n return { wasConverted };\n}\n"]}
|
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.runReactRouterWizard = void 0;
|
|
7
|
+
// @ts-expect-error - clack is ESM and TS complains about that. It works though
|
|
8
|
+
const prompts_1 = __importDefault(require("@clack/prompts"));
|
|
9
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
10
|
+
const telemetry_1 = require("../telemetry");
|
|
11
|
+
const clack_1 = require("../utils/clack");
|
|
12
|
+
const mcp_config_1 = require("../utils/clack/mcp-config");
|
|
13
|
+
const package_json_1 = require("../utils/package-json");
|
|
14
|
+
const debug_1 = require("../utils/debug");
|
|
15
|
+
const sdk_example_1 = require("./sdk-example");
|
|
16
|
+
const sdk_setup_1 = require("./sdk-setup");
|
|
17
|
+
const templates_1 = require("./templates");
|
|
18
|
+
async function runReactRouterWizard(options) {
|
|
19
|
+
return (0, telemetry_1.withTelemetry)({
|
|
20
|
+
enabled: options.telemetryEnabled,
|
|
21
|
+
integration: 'reactRouter',
|
|
22
|
+
wizardOptions: options,
|
|
23
|
+
}, () => runReactRouterWizardWithTelemetry(options));
|
|
24
|
+
}
|
|
25
|
+
exports.runReactRouterWizard = runReactRouterWizard;
|
|
26
|
+
async function runReactRouterWizardWithTelemetry(options) {
|
|
27
|
+
(0, clack_1.printWelcome)({
|
|
28
|
+
wizardName: 'Sentry React Router Wizard',
|
|
29
|
+
promoCode: options.promoCode,
|
|
30
|
+
});
|
|
31
|
+
const packageJson = await (0, clack_1.getPackageDotJson)();
|
|
32
|
+
if (!packageJson) {
|
|
33
|
+
prompts_1.default.log.error('Could not find a package.json file in the current directory');
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
const typeScriptDetected = (0, clack_1.isUsingTypeScript)();
|
|
37
|
+
if (!(0, sdk_setup_1.isReactRouterV7)(packageJson)) {
|
|
38
|
+
prompts_1.default.log.error('This wizard requires React Router v7. Please upgrade your React Router version to v7.0.0 or higher.\n\nFor upgrade instructions, visit: https://react-router.dev/upgrade/v7');
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
await (0, clack_1.confirmContinueIfNoOrDirtyGitRepo)({
|
|
42
|
+
ignoreGitChanges: options.ignoreGitChanges,
|
|
43
|
+
cwd: undefined,
|
|
44
|
+
});
|
|
45
|
+
const sentryAlreadyInstalled = (0, package_json_1.hasPackageInstalled)('@sentry/react-router', packageJson);
|
|
46
|
+
const projectData = await (0, clack_1.getOrAskForProjectData)(options, 'javascript-react-router');
|
|
47
|
+
if (projectData.spotlight) {
|
|
48
|
+
prompts_1.default.log.warn('Spotlight mode is not yet supported for React Router.');
|
|
49
|
+
prompts_1.default.log.info('Spotlight is currently only available for Next.js.');
|
|
50
|
+
await (0, clack_1.abort)('Exiting wizard', 0);
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
const { selectedProject, authToken, selfHosted, sentryUrl } = projectData;
|
|
54
|
+
await (0, clack_1.installPackage)({
|
|
55
|
+
packageName: '@sentry/react-router',
|
|
56
|
+
alreadyInstalled: sentryAlreadyInstalled,
|
|
57
|
+
});
|
|
58
|
+
const featureSelection = await (0, clack_1.featureSelectionPrompt)([
|
|
59
|
+
{
|
|
60
|
+
id: 'performance',
|
|
61
|
+
prompt: `Do you want to enable ${chalk_1.default.bold('Tracing')} to track the performance of your application?`,
|
|
62
|
+
enabledHint: 'recommended',
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
id: 'replay',
|
|
66
|
+
prompt: `Do you want to enable ${chalk_1.default.bold('Session Replay')} to get a video-like reproduction of errors during a user session?`,
|
|
67
|
+
enabledHint: 'recommended, but increases bundle size',
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
id: 'logs',
|
|
71
|
+
prompt: `Do you want to enable ${chalk_1.default.bold('Logs')} to send your application logs to Sentry?`,
|
|
72
|
+
enabledHint: 'recommended',
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
id: 'profiling',
|
|
76
|
+
prompt: `Do you want to enable ${chalk_1.default.bold('Profiling')} to track application performance in detail?`,
|
|
77
|
+
enabledHint: 'recommended for production debugging',
|
|
78
|
+
},
|
|
79
|
+
]);
|
|
80
|
+
if (featureSelection.profiling) {
|
|
81
|
+
const profilingAlreadyInstalled = (0, package_json_1.hasPackageInstalled)('@sentry/profiling-node', packageJson);
|
|
82
|
+
await (0, clack_1.installPackage)({
|
|
83
|
+
packageName: '@sentry/profiling-node',
|
|
84
|
+
alreadyInstalled: profilingAlreadyInstalled,
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
const createExamplePageSelection = await (0, clack_1.askShouldCreateExamplePage)();
|
|
88
|
+
(0, telemetry_1.traceStep)('Reveal missing entry files', () => {
|
|
89
|
+
try {
|
|
90
|
+
(0, sdk_setup_1.runReactRouterReveal)(typeScriptDetected);
|
|
91
|
+
prompts_1.default.log.success('Entry files are ready for instrumentation');
|
|
92
|
+
}
|
|
93
|
+
catch (e) {
|
|
94
|
+
prompts_1.default.log.warn(`Could not run 'npx react-router reveal'.
|
|
95
|
+
Please create your entry files manually using React Router v7 commands.`);
|
|
96
|
+
(0, debug_1.debug)(e);
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
await (0, telemetry_1.traceStep)('Initialize Sentry on client entry', async () => {
|
|
100
|
+
try {
|
|
101
|
+
await (0, sdk_setup_1.initializeSentryOnEntryClient)(selectedProject.keys[0].dsn.public, featureSelection.performance, featureSelection.replay, featureSelection.logs, typeScriptDetected);
|
|
102
|
+
}
|
|
103
|
+
catch (e) {
|
|
104
|
+
prompts_1.default.log.warn(`Could not initialize Sentry on client entry automatically.`);
|
|
105
|
+
const clientEntryFilename = `entry.client.${typeScriptDetected ? 'tsx' : 'jsx'}`;
|
|
106
|
+
const manualClientContent = (0, templates_1.getManualClientEntryContent)(selectedProject.keys[0].dsn.public, featureSelection.performance, featureSelection.replay, featureSelection.logs);
|
|
107
|
+
await (0, clack_1.showCopyPasteInstructions)({
|
|
108
|
+
filename: clientEntryFilename,
|
|
109
|
+
codeSnippet: manualClientContent,
|
|
110
|
+
hint: 'This enables error tracking and performance monitoring for your React Router app',
|
|
111
|
+
});
|
|
112
|
+
(0, debug_1.debug)(e);
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
await (0, telemetry_1.traceStep)('Instrument root route', async () => {
|
|
116
|
+
try {
|
|
117
|
+
await (0, sdk_setup_1.instrumentRootRoute)(typeScriptDetected);
|
|
118
|
+
}
|
|
119
|
+
catch (e) {
|
|
120
|
+
prompts_1.default.log.warn(`Could not instrument root route automatically.`);
|
|
121
|
+
const rootFilename = `app/root.${typeScriptDetected ? 'tsx' : 'jsx'}`;
|
|
122
|
+
const manualRootContent = (0, templates_1.getManualRootContent)(typeScriptDetected);
|
|
123
|
+
await (0, clack_1.showCopyPasteInstructions)({
|
|
124
|
+
filename: rootFilename,
|
|
125
|
+
codeSnippet: manualRootContent,
|
|
126
|
+
hint: 'This adds error boundary integration to capture exceptions in your React Router app',
|
|
127
|
+
});
|
|
128
|
+
(0, debug_1.debug)(e);
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
await (0, telemetry_1.traceStep)('Instrument server entry', async () => {
|
|
132
|
+
try {
|
|
133
|
+
await (0, sdk_setup_1.instrumentSentryOnEntryServer)(typeScriptDetected);
|
|
134
|
+
}
|
|
135
|
+
catch (e) {
|
|
136
|
+
prompts_1.default.log.warn(`Could not initialize Sentry on server entry automatically.`);
|
|
137
|
+
const serverEntryFilename = `entry.server.${typeScriptDetected ? 'tsx' : 'jsx'}`;
|
|
138
|
+
const manualServerContent = (0, templates_1.getManualServerEntryContent)();
|
|
139
|
+
await (0, clack_1.showCopyPasteInstructions)({
|
|
140
|
+
filename: serverEntryFilename,
|
|
141
|
+
codeSnippet: manualServerContent,
|
|
142
|
+
hint: 'This configures server-side request handling and error tracking',
|
|
143
|
+
});
|
|
144
|
+
(0, debug_1.debug)(e);
|
|
145
|
+
}
|
|
146
|
+
});
|
|
147
|
+
await (0, telemetry_1.traceStep)('Create server instrumentation file', async () => {
|
|
148
|
+
try {
|
|
149
|
+
(0, sdk_setup_1.createServerInstrumentationFile)(selectedProject.keys[0].dsn.public, {
|
|
150
|
+
performance: featureSelection.performance,
|
|
151
|
+
replay: featureSelection.replay,
|
|
152
|
+
logs: featureSelection.logs,
|
|
153
|
+
profiling: featureSelection.profiling,
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
catch (e) {
|
|
157
|
+
prompts_1.default.log.warn('Could not create a server instrumentation file automatically.');
|
|
158
|
+
const manualServerInstrumentContent = (0, templates_1.getManualServerInstrumentContent)(selectedProject.keys[0].dsn.public, featureSelection.performance, featureSelection.profiling, featureSelection.logs);
|
|
159
|
+
await (0, clack_1.showCopyPasteInstructions)({
|
|
160
|
+
filename: 'instrument.server.mjs',
|
|
161
|
+
codeSnippet: manualServerInstrumentContent,
|
|
162
|
+
hint: 'Create the file if it does not exist - this initializes Sentry before your application starts',
|
|
163
|
+
});
|
|
164
|
+
(0, debug_1.debug)(e);
|
|
165
|
+
}
|
|
166
|
+
});
|
|
167
|
+
await (0, telemetry_1.traceStep)('Update package.json scripts', async () => {
|
|
168
|
+
try {
|
|
169
|
+
await (0, sdk_setup_1.updatePackageJsonScripts)();
|
|
170
|
+
}
|
|
171
|
+
catch (e) {
|
|
172
|
+
prompts_1.default.log.warn('Could not update start script automatically.');
|
|
173
|
+
await (0, clack_1.showCopyPasteInstructions)({
|
|
174
|
+
filename: 'package.json',
|
|
175
|
+
codeSnippet: (0, clack_1.makeCodeSnippet)(true, (unchanged, plus, minus) => {
|
|
176
|
+
return unchanged(`{
|
|
177
|
+
scripts: {
|
|
178
|
+
${minus('"start": "react-router dev"')}
|
|
179
|
+
${plus('"start": "NODE_OPTIONS=\'--import ./instrument.server.mjs\' react-router-serve ./build/server/index.js"')}
|
|
180
|
+
${minus('"dev": "react-router dev"')}
|
|
181
|
+
${plus('"dev": "NODE_OPTIONS=\'--import ./instrument.server.mjs\' react-router dev"')}
|
|
182
|
+
},
|
|
183
|
+
// ... rest of your package.json
|
|
184
|
+
}`);
|
|
185
|
+
}),
|
|
186
|
+
});
|
|
187
|
+
(0, debug_1.debug)(e);
|
|
188
|
+
}
|
|
189
|
+
});
|
|
190
|
+
await (0, telemetry_1.traceStep)('Create build plugin env file', async () => {
|
|
191
|
+
try {
|
|
192
|
+
await (0, clack_1.addDotEnvSentryBuildPluginFile)(authToken);
|
|
193
|
+
}
|
|
194
|
+
catch (e) {
|
|
195
|
+
prompts_1.default.log.warn('Could not create .env.sentry-build-plugin file. Please create it manually.');
|
|
196
|
+
(0, debug_1.debug)(e);
|
|
197
|
+
}
|
|
198
|
+
});
|
|
199
|
+
// Validate auth token before configuring sourcemap uploads
|
|
200
|
+
if (!authToken) {
|
|
201
|
+
prompts_1.default.log.warn(`${chalk_1.default.yellow('Warning:')} No auth token found. Sourcemap uploads will not work without ${chalk_1.default.cyan('SENTRY_AUTH_TOKEN')}.\n` +
|
|
202
|
+
`Please set ${chalk_1.default.cyan('SENTRY_AUTH_TOKEN')} in your ${chalk_1.default.cyan('.env.sentry-build-plugin')} file or environment variables.`);
|
|
203
|
+
}
|
|
204
|
+
// Configure Vite plugin for sourcemap uploads
|
|
205
|
+
await (0, telemetry_1.traceStep)('Configure Vite plugin for sourcemap uploads', async () => {
|
|
206
|
+
try {
|
|
207
|
+
await (0, sdk_setup_1.configureReactRouterVitePlugin)(selectedProject.organization.slug, selectedProject.slug);
|
|
208
|
+
}
|
|
209
|
+
catch (e) {
|
|
210
|
+
prompts_1.default.log.warn(`Could not configure Vite plugin for sourcemap uploads automatically.`);
|
|
211
|
+
await (0, clack_1.showCopyPasteInstructions)({
|
|
212
|
+
filename: `vite.config.${typeScriptDetected ? 'ts' : 'js'}`,
|
|
213
|
+
codeSnippet: (0, templates_1.getManualViteConfigContent)(selectedProject.organization.slug, selectedProject.slug),
|
|
214
|
+
hint: 'This enables automatic sourcemap uploads during build for better error tracking',
|
|
215
|
+
});
|
|
216
|
+
(0, debug_1.debug)(e);
|
|
217
|
+
}
|
|
218
|
+
});
|
|
219
|
+
// Configure React Router config for build hook
|
|
220
|
+
await (0, telemetry_1.traceStep)('Configure React Router build hook', async () => {
|
|
221
|
+
try {
|
|
222
|
+
await (0, sdk_setup_1.configureReactRouterConfig)(typeScriptDetected);
|
|
223
|
+
}
|
|
224
|
+
catch (e) {
|
|
225
|
+
prompts_1.default.log.warn(`Could not configure React Router build hook automatically.`);
|
|
226
|
+
await (0, clack_1.showCopyPasteInstructions)({
|
|
227
|
+
filename: `react-router.config.${typeScriptDetected ? 'ts' : 'js'}`,
|
|
228
|
+
codeSnippet: (0, templates_1.getManualReactRouterConfigContent)(typeScriptDetected),
|
|
229
|
+
hint: 'This enables automatic sourcemap uploads at the end of the build process',
|
|
230
|
+
});
|
|
231
|
+
(0, debug_1.debug)(e);
|
|
232
|
+
}
|
|
233
|
+
});
|
|
234
|
+
// Create example page if requested
|
|
235
|
+
if (createExamplePageSelection) {
|
|
236
|
+
await (0, telemetry_1.traceStep)('Create example page', async () => {
|
|
237
|
+
await (0, sdk_example_1.createExamplePage)({
|
|
238
|
+
selfHosted,
|
|
239
|
+
orgSlug: selectedProject.organization.slug,
|
|
240
|
+
projectId: selectedProject.id,
|
|
241
|
+
url: sentryUrl,
|
|
242
|
+
isTS: typeScriptDetected,
|
|
243
|
+
projectDir: process.cwd(),
|
|
244
|
+
});
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
await (0, clack_1.runPrettierIfInstalled)({ cwd: undefined });
|
|
248
|
+
// Offer optional project-scoped MCP config for Sentry with org and project scope
|
|
249
|
+
await (0, mcp_config_1.offerProjectScopedMcpConfig)(selectedProject.organization.slug, selectedProject.slug);
|
|
250
|
+
prompts_1.default.outro(`${chalk_1.default.green('Successfully installed the Sentry React Router SDK!')}${createExamplePageSelection
|
|
251
|
+
? `\n\nYou can validate your setup by visiting ${chalk_1.default.cyan('"/sentry-example-page"')} in your application.`
|
|
252
|
+
: ''}`);
|
|
253
|
+
}
|
|
254
|
+
//# sourceMappingURL=react-router-wizard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"react-router-wizard.js","sourceRoot":"","sources":["../../../src/react-router/react-router-wizard.ts"],"names":[],"mappings":"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","sourcesContent":["// @ts-expect-error - clack is ESM and TS complains about that. It works though\nimport clack from '@clack/prompts';\nimport chalk from 'chalk';\n\nimport type { WizardOptions } from '../utils/types';\nimport { withTelemetry, traceStep } from '../telemetry';\nimport {\n abort,\n askShouldCreateExamplePage,\n confirmContinueIfNoOrDirtyGitRepo,\n featureSelectionPrompt,\n getOrAskForProjectData,\n getPackageDotJson,\n isUsingTypeScript,\n printWelcome,\n installPackage,\n addDotEnvSentryBuildPluginFile,\n showCopyPasteInstructions,\n makeCodeSnippet,\n runPrettierIfInstalled,\n} from '../utils/clack';\nimport { offerProjectScopedMcpConfig } from '../utils/clack/mcp-config';\nimport { hasPackageInstalled } from '../utils/package-json';\nimport { debug } from '../utils/debug';\nimport { createExamplePage } from './sdk-example';\nimport {\n isReactRouterV7,\n runReactRouterReveal,\n initializeSentryOnEntryClient,\n instrumentRootRoute,\n createServerInstrumentationFile,\n updatePackageJsonScripts,\n instrumentSentryOnEntryServer,\n configureReactRouterConfig,\n configureReactRouterVitePlugin,\n} from './sdk-setup';\nimport {\n getManualClientEntryContent,\n getManualServerEntryContent,\n getManualRootContent,\n getManualServerInstrumentContent,\n getManualReactRouterConfigContent,\n getManualViteConfigContent,\n} from './templates';\n\nexport async function runReactRouterWizard(\n options: WizardOptions,\n): Promise<void> {\n return withTelemetry(\n {\n enabled: options.telemetryEnabled,\n integration: 'reactRouter',\n wizardOptions: options,\n },\n () => runReactRouterWizardWithTelemetry(options),\n );\n}\n\nasync function runReactRouterWizardWithTelemetry(\n options: WizardOptions,\n): Promise<void> {\n printWelcome({\n wizardName: 'Sentry React Router Wizard',\n promoCode: options.promoCode,\n });\n\n const packageJson = await getPackageDotJson();\n\n if (!packageJson) {\n clack.log.error(\n 'Could not find a package.json file in the current directory',\n );\n return;\n }\n\n const typeScriptDetected = isUsingTypeScript();\n\n if (!isReactRouterV7(packageJson)) {\n clack.log.error(\n 'This wizard requires React Router v7. Please upgrade your React Router version to v7.0.0 or higher.\\n\\nFor upgrade instructions, visit: https://react-router.dev/upgrade/v7',\n );\n return;\n }\n\n await confirmContinueIfNoOrDirtyGitRepo({\n ignoreGitChanges: options.ignoreGitChanges,\n cwd: undefined,\n });\n\n const sentryAlreadyInstalled = hasPackageInstalled(\n '@sentry/react-router',\n packageJson,\n );\n\n const projectData = await getOrAskForProjectData(\n options,\n 'javascript-react-router',\n );\n\n if (projectData.spotlight) {\n clack.log.warn('Spotlight mode is not yet supported for React Router.');\n clack.log.info('Spotlight is currently only available for Next.js.');\n await abort('Exiting wizard', 0);\n return;\n }\n\n const { selectedProject, authToken, selfHosted, sentryUrl } = projectData;\n\n await installPackage({\n packageName: '@sentry/react-router',\n alreadyInstalled: sentryAlreadyInstalled,\n });\n\n const featureSelection = await featureSelectionPrompt([\n {\n id: 'performance',\n prompt: `Do you want to enable ${chalk.bold(\n 'Tracing',\n )} to track the performance of your application?`,\n enabledHint: 'recommended',\n },\n {\n id: 'replay',\n prompt: `Do you want to enable ${chalk.bold(\n 'Session Replay',\n )} to get a video-like reproduction of errors during a user session?`,\n enabledHint: 'recommended, but increases bundle size',\n },\n {\n id: 'logs',\n prompt: `Do you want to enable ${chalk.bold(\n 'Logs',\n )} to send your application logs to Sentry?`,\n enabledHint: 'recommended',\n },\n {\n id: 'profiling',\n prompt: `Do you want to enable ${chalk.bold(\n 'Profiling',\n )} to track application performance in detail?`,\n enabledHint: 'recommended for production debugging',\n },\n ]);\n\n if (featureSelection.profiling) {\n const profilingAlreadyInstalled = hasPackageInstalled(\n '@sentry/profiling-node',\n packageJson,\n );\n\n await installPackage({\n packageName: '@sentry/profiling-node',\n alreadyInstalled: profilingAlreadyInstalled,\n });\n }\n\n const createExamplePageSelection = await askShouldCreateExamplePage();\n\n traceStep('Reveal missing entry files', () => {\n try {\n runReactRouterReveal(typeScriptDetected);\n clack.log.success('Entry files are ready for instrumentation');\n } catch (e) {\n clack.log.warn(`Could not run 'npx react-router reveal'.\nPlease create your entry files manually using React Router v7 commands.`);\n debug(e);\n }\n });\n\n await traceStep('Initialize Sentry on client entry', async () => {\n try {\n await initializeSentryOnEntryClient(\n selectedProject.keys[0].dsn.public,\n featureSelection.performance,\n featureSelection.replay,\n featureSelection.logs,\n typeScriptDetected,\n );\n } catch (e) {\n clack.log.warn(\n `Could not initialize Sentry on client entry automatically.`,\n );\n\n const clientEntryFilename = `entry.client.${\n typeScriptDetected ? 'tsx' : 'jsx'\n }`;\n\n const manualClientContent = getManualClientEntryContent(\n selectedProject.keys[0].dsn.public,\n featureSelection.performance,\n featureSelection.replay,\n featureSelection.logs,\n );\n\n await showCopyPasteInstructions({\n filename: clientEntryFilename,\n codeSnippet: manualClientContent,\n hint: 'This enables error tracking and performance monitoring for your React Router app',\n });\n\n debug(e);\n }\n });\n\n await traceStep('Instrument root route', async () => {\n try {\n await instrumentRootRoute(typeScriptDetected);\n } catch (e) {\n clack.log.warn(`Could not instrument root route automatically.`);\n\n const rootFilename = `app/root.${typeScriptDetected ? 'tsx' : 'jsx'}`;\n const manualRootContent = getManualRootContent(typeScriptDetected);\n\n await showCopyPasteInstructions({\n filename: rootFilename,\n codeSnippet: manualRootContent,\n hint: 'This adds error boundary integration to capture exceptions in your React Router app',\n });\n\n debug(e);\n }\n });\n\n await traceStep('Instrument server entry', async () => {\n try {\n await instrumentSentryOnEntryServer(typeScriptDetected);\n } catch (e) {\n clack.log.warn(\n `Could not initialize Sentry on server entry automatically.`,\n );\n\n const serverEntryFilename = `entry.server.${\n typeScriptDetected ? 'tsx' : 'jsx'\n }`;\n const manualServerContent = getManualServerEntryContent();\n\n await showCopyPasteInstructions({\n filename: serverEntryFilename,\n codeSnippet: manualServerContent,\n hint: 'This configures server-side request handling and error tracking',\n });\n\n debug(e);\n }\n });\n\n await traceStep('Create server instrumentation file', async () => {\n try {\n createServerInstrumentationFile(selectedProject.keys[0].dsn.public, {\n performance: featureSelection.performance,\n replay: featureSelection.replay,\n logs: featureSelection.logs,\n profiling: featureSelection.profiling,\n });\n } catch (e) {\n clack.log.warn(\n 'Could not create a server instrumentation file automatically.',\n );\n\n const manualServerInstrumentContent = getManualServerInstrumentContent(\n selectedProject.keys[0].dsn.public,\n featureSelection.performance,\n featureSelection.profiling,\n featureSelection.logs,\n );\n\n await showCopyPasteInstructions({\n filename: 'instrument.server.mjs',\n codeSnippet: manualServerInstrumentContent,\n hint: 'Create the file if it does not exist - this initializes Sentry before your application starts',\n });\n\n debug(e);\n }\n });\n\n await traceStep('Update package.json scripts', async () => {\n try {\n await updatePackageJsonScripts();\n } catch (e) {\n clack.log.warn('Could not update start script automatically.');\n\n await showCopyPasteInstructions({\n filename: 'package.json',\n codeSnippet: makeCodeSnippet(true, (unchanged, plus, minus) => {\n return unchanged(`{\n scripts: {\n ${minus('\"start\": \"react-router dev\"')}\n ${plus(\n '\"start\": \"NODE_OPTIONS=\\'--import ./instrument.server.mjs\\' react-router-serve ./build/server/index.js\"',\n )}\n ${minus('\"dev\": \"react-router dev\"')}\n ${plus(\n '\"dev\": \"NODE_OPTIONS=\\'--import ./instrument.server.mjs\\' react-router dev\"',\n )}\n },\n // ... rest of your package.json\n }`);\n }),\n });\n\n debug(e);\n }\n });\n\n await traceStep('Create build plugin env file', async () => {\n try {\n await addDotEnvSentryBuildPluginFile(authToken);\n } catch (e) {\n clack.log.warn(\n 'Could not create .env.sentry-build-plugin file. Please create it manually.',\n );\n debug(e);\n }\n });\n\n // Validate auth token before configuring sourcemap uploads\n if (!authToken) {\n clack.log.warn(\n `${chalk.yellow(\n 'Warning:',\n )} No auth token found. Sourcemap uploads will not work without ${chalk.cyan(\n 'SENTRY_AUTH_TOKEN',\n )}.\\n` +\n `Please set ${chalk.cyan('SENTRY_AUTH_TOKEN')} in your ${chalk.cyan(\n '.env.sentry-build-plugin',\n )} file or environment variables.`,\n );\n }\n\n // Configure Vite plugin for sourcemap uploads\n await traceStep('Configure Vite plugin for sourcemap uploads', async () => {\n try {\n await configureReactRouterVitePlugin(\n selectedProject.organization.slug,\n selectedProject.slug,\n );\n } catch (e) {\n clack.log.warn(\n `Could not configure Vite plugin for sourcemap uploads automatically.`,\n );\n\n await showCopyPasteInstructions({\n filename: `vite.config.${typeScriptDetected ? 'ts' : 'js'}`,\n codeSnippet: getManualViteConfigContent(\n selectedProject.organization.slug,\n selectedProject.slug,\n ),\n hint: 'This enables automatic sourcemap uploads during build for better error tracking',\n });\n\n debug(e);\n }\n });\n\n // Configure React Router config for build hook\n await traceStep('Configure React Router build hook', async () => {\n try {\n await configureReactRouterConfig(typeScriptDetected);\n } catch (e) {\n clack.log.warn(\n `Could not configure React Router build hook automatically.`,\n );\n\n await showCopyPasteInstructions({\n filename: `react-router.config.${typeScriptDetected ? 'ts' : 'js'}`,\n codeSnippet: getManualReactRouterConfigContent(typeScriptDetected),\n hint: 'This enables automatic sourcemap uploads at the end of the build process',\n });\n\n debug(e);\n }\n });\n\n // Create example page if requested\n if (createExamplePageSelection) {\n await traceStep('Create example page', async () => {\n await createExamplePage({\n selfHosted,\n orgSlug: selectedProject.organization.slug,\n projectId: selectedProject.id,\n url: sentryUrl,\n isTS: typeScriptDetected,\n projectDir: process.cwd(),\n });\n });\n }\n\n await runPrettierIfInstalled({ cwd: undefined });\n\n // Offer optional project-scoped MCP config for Sentry with org and project scope\n await offerProjectScopedMcpConfig(\n selectedProject.organization.slug,\n selectedProject.slug,\n );\n\n clack.outro(\n `${chalk.green('Successfully installed the Sentry React Router SDK!')}${\n createExamplePageSelection\n ? `\\n\\nYou can validate your setup by visiting ${chalk.cyan(\n '\"/sentry-example-page\"',\n )} in your application.`\n : ''\n }`,\n );\n}\n"]}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export declare function createExamplePage(options: {
|
|
2
|
+
selfHosted: boolean;
|
|
3
|
+
orgSlug: string;
|
|
4
|
+
projectId: string;
|
|
5
|
+
url: string;
|
|
6
|
+
isTS: boolean;
|
|
7
|
+
projectDir: string;
|
|
8
|
+
}): Promise<void>;
|
|
9
|
+
export declare function getSentryExamplePageContents(options: {
|
|
10
|
+
selfHosted: boolean;
|
|
11
|
+
orgSlug: string;
|
|
12
|
+
projectId: string;
|
|
13
|
+
url: string;
|
|
14
|
+
isTS?: boolean;
|
|
15
|
+
}): string;
|
|
16
|
+
export declare function getSentryExampleApiContents(options: {
|
|
17
|
+
isTS?: boolean;
|
|
18
|
+
}): string;
|