├── packages ├── .gitkeep ├── cli │ ├── bin.js │ ├── src │ │ ├── utils │ │ │ ├── color.ts │ │ │ ├── files.ts │ │ │ ├── isInteractive.ts │ │ │ ├── git.ts │ │ │ └── steps.ts │ │ ├── types.ts │ │ ├── constants.ts │ │ ├── package-json.ts │ │ └── commands │ │ │ └── generate │ │ │ ├── install-packages.ts │ │ │ ├── create-directory.ts │ │ │ ├── bootstrap-plugin.ts │ │ │ ├── git-init.ts │ │ │ └── prompt-for-plugin-info.ts │ ├── template │ │ ├── rozenite.config.ts │ │ ├── vite.config.ts │ │ ├── react-native.ts │ │ ├── tsconfig.json │ │ └── package.json │ ├── tsconfig.json │ ├── tsconfig.lib.json │ ├── vite.config.ts │ └── eslint.config.mjs ├── expo-atlas-plugin │ ├── react-native.ts │ ├── src │ │ ├── css-modules.d.ts │ │ ├── base-serializer.ts │ │ └── with-expo-atlas.ts │ ├── rozenite.config.ts │ ├── tsconfig.tsbuildinfo │ ├── project.json │ ├── vite.config.ts │ ├── tsconfig.json │ └── package.json ├── redux-devtools-plugin │ ├── src │ │ ├── constants.ts │ │ ├── css-modules.d.ts │ │ ├── ui │ │ │ ├── panel.css │ │ │ └── panel.tsx │ │ ├── react-native.d.ts │ │ └── metro.ts │ ├── metro.ts │ ├── rozenite.config.ts │ ├── project.json │ ├── vite.config.ts │ ├── tsconfig.tsbuildinfo │ └── tsconfig.json ├── plugin-bridge │ ├── src │ │ ├── types.ts │ │ ├── rozenite-types.d.ts │ │ ├── errors.ts │ │ ├── channel │ │ │ ├── types.ts │ │ │ ├── device │ │ │ │ └── cdp-types.d.ts │ │ │ ├── factory.ts │ │ │ └── browser │ │ │ │ └── panel-channel.ts │ │ ├── web.ts │ │ ├── index.ts │ │ └── message.ts │ ├── tsconfig.json │ ├── tsconfig.tsbuildinfo │ ├── eslint.config.mjs │ ├── tsconfig.lib.json │ ├── vite.config.ts │ └── package.json ├── require-profiler-plugin │ ├── metro.ts │ ├── src │ │ ├── shared │ │ │ ├── index.ts │ │ │ ├── types.ts │ │ │ └── messaging.ts │ │ ├── css-modules.d.ts │ │ ├── ui │ │ │ └── components │ │ │ │ ├── LoadingState.tsx │ │ │ │ ├── index.ts │ │ │ │ ├── EmptyState.tsx │ │ │ │ ├── Legend.tsx │ │ │ │ └── InfoBar.tsx │ │ └── react-native │ │ │ └── timings.ts │ ├── postcss.config.js │ ├── rozenite.config.ts │ ├── tsconfig.tsbuildinfo │ ├── project.json │ ├── react-native.ts │ ├── tsconfig.json │ └── vite.config.ts ├── mmkv-plugin │ ├── postcss.config.js │ ├── src │ │ ├── css-modules.d.ts │ │ ├── shared │ │ │ ├── types.ts │ │ │ └── messaging.ts │ │ └── react-native │ │ │ └── is-garbled.ts │ ├── rozenite.config.ts │ ├── tsconfig.tsbuildinfo │ ├── project.json │ ├── vite.config.ts │ ├── react-native.ts │ └── tsconfig.json ├── network-activity-plugin │ ├── postcss.config.js │ ├── src │ │ ├── css-modules.d.ts │ │ ├── ui │ │ │ ├── utils │ │ │ │ ├── copyToClipboard.ts │ │ │ │ ├── assert.ts │ │ │ │ ├── cn.ts │ │ │ │ ├── checkRequestBodyBinary.ts │ │ │ │ ├── getId.ts │ │ │ │ ├── escapeShellArg.ts │ │ │ │ ├── generateMultipartBody.ts │ │ │ │ └── getStatusColor.ts │ │ │ ├── components │ │ │ │ ├── CodeBlock.tsx │ │ │ │ ├── Input.tsx │ │ │ │ ├── CodeEditor.tsx │ │ │ │ ├── Separator.tsx │ │ │ │ ├── JsonTreeCopyableItem.tsx │ │ │ │ └── Badge.tsx │ │ │ ├── App.tsx │ │ │ ├── views │ │ │ │ └── LoadingView.tsx │ │ │ ├── types.ts │ │ │ └── hooks │ │ │ │ └── useCopyToClipboard.ts │ │ ├── utils │ │ │ ├── getStringSizeInBytes.ts │ │ │ ├── safeStringify.ts │ │ │ ├── inferContentTypeFromPostData.ts │ │ │ ├── getHttpHeader.ts │ │ │ ├── getContentTypeMimeType.ts │ │ │ ├── getHttpHeaderValueAsString.ts │ │ │ ├── applyReactNativeRequestHeadersLogic.ts │ │ │ ├── typeChecks.ts │ │ │ └── applyReactNativeResponseHeadersLogic.ts │ │ ├── react-native │ │ │ ├── websocket │ │ │ │ └── websocket-interceptor.d.ts │ │ │ ├── sse │ │ │ │ ├── types.ts │ │ │ │ └── event-source.ts │ │ │ ├── utils │ │ │ │ ├── getFormDataEntries.ts │ │ │ │ └── getBlobName.ts │ │ │ ├── http │ │ │ │ ├── xml-request.d.ts │ │ │ │ └── overrides-registry.ts │ │ │ ├── utils.ts │ │ │ └── config.ts │ │ └── shared │ │ │ └── sse-events.ts │ ├── rozenite.config.ts │ ├── project.json │ ├── tsconfig.tsbuildinfo │ ├── react-native.ts │ ├── vite.config.ts │ └── tsconfig.json ├── react-navigation-plugin │ ├── postcss.config.js │ ├── src │ │ ├── css-modules.d.ts │ │ └── devtools-ui │ │ │ └── components │ │ │ ├── NavigationTree │ │ │ ├── Leaf.tsx │ │ │ └── navigationTreeColors.ts │ │ │ └── Tabs.tsx │ ├── rozenite.config.ts │ ├── project.json │ ├── react-native.ts │ ├── tsconfig.tsbuildinfo │ ├── vite.config.ts │ ├── tsconfig.json │ └── package.json ├── performance-monitor-plugin │ ├── rozenite.config.ts │ ├── src │ │ ├── react-native │ │ │ ├── helpers.ts │ │ │ ├── asserts.ts │ │ │ └── usePerformanceMonitorDevTools.ts │ │ └── ui │ │ │ ├── utils.ts │ │ │ └── components │ │ │ ├── DetailsDisplay.tsx │ │ │ ├── JsonTree.tsx │ │ │ └── MarksTable.tsx │ ├── project.json │ ├── react-native.ts │ ├── vite.config.ts │ ├── tsconfig.tsbuildinfo │ └── tsconfig.json ├── tanstack-query-plugin │ ├── rozenite.config.ts │ ├── project.json │ ├── src │ │ ├── ui │ │ │ ├── useSyncInitialData.ts │ │ │ └── tanstack-query.tsx │ │ ├── react-native │ │ │ ├── useHandleInitialData.ts │ │ │ └── useTanstackQueryDevTools.ts │ │ └── shared │ │ │ ├── useSyncOnlineStatus.ts │ │ │ └── types.ts │ ├── vite.config.ts │ ├── tsconfig.tsbuildinfo │ ├── react-native.ts │ ├── tsconfig.json │ └── package.json ├── runtime │ ├── tsconfig.json │ ├── src │ │ ├── rn-devtools │ │ │ ├── types.ts │ │ │ └── rn-devtools-frontend.ts │ │ ├── global-namespace.ts │ │ ├── manifest.ts │ │ ├── dev-mode.ts │ │ ├── create-panel.ts │ │ └── plugin-loader.ts │ ├── eslint.config.mjs │ ├── tsconfig.lib.json │ ├── package.json │ └── vite.config.ts ├── vite-plugin │ ├── tsconfig.json │ ├── tsconfig.lib.json │ ├── src │ │ ├── package-json.ts │ │ ├── utils.ts │ │ └── server-plugin.ts │ ├── eslint.config.mjs │ ├── vite.config.ts │ └── templates │ │ └── panel.ejs ├── metro │ ├── tsconfig.json │ ├── tsconfig.tsbuildinfo │ ├── tsconfig.lib.json │ ├── src │ │ └── packages.ts │ ├── eslint.config.mjs │ └── vite.config.ts ├── middleware │ ├── tsconfig.json │ ├── src │ │ ├── constants.ts │ │ ├── dev-mode.ts │ │ ├── node-modules-paths.ts │ │ ├── config.ts │ │ ├── dev-tools-url-patch.ts │ │ └── verify-react-native-version.ts │ ├── tsconfig.tsbuildinfo │ ├── tsconfig.lib.json │ ├── vite.config.ts │ └── eslint.config.mjs ├── repack │ ├── tsconfig.json │ ├── tsconfig.tsbuildinfo │ ├── eslint.config.mjs │ ├── tsconfig.lib.json │ └── vite.config.ts └── tools │ ├── src │ └── index.ts │ ├── tsconfig.lib.json │ ├── package.json │ ├── tsconfig.json │ └── vite.config.ts ├── apps └── playground │ ├── src │ ├── assets │ │ └── .gitkeep │ ├── main.tsx │ └── app │ │ ├── screens │ │ └── heavyComputationModule.ts │ │ ├── store.ts │ │ ├── navigation │ │ ├── types.ts │ │ └── SuccessiveScreensNavigator.tsx │ │ ├── store │ │ └── counterSlice.ts │ │ └── stores │ │ └── settingsStore.ts │ ├── app.json │ ├── android │ ├── app │ │ ├── debug.keystore │ │ ├── src │ │ │ ├── main │ │ │ │ ├── res │ │ │ │ │ ├── values │ │ │ │ │ │ ├── strings.xml │ │ │ │ │ │ └── styles.xml │ │ │ │ │ ├── mipmap-hdpi │ │ │ │ │ │ ├── ic_launcher.png │ │ │ │ │ │ └── ic_launcher_round.png │ │ │ │ │ ├── mipmap-mdpi │ │ │ │ │ │ ├── ic_launcher.png │ │ │ │ │ │ └── ic_launcher_round.png │ │ │ │ │ ├── mipmap-xhdpi │ │ │ │ │ │ ├── ic_launcher.png │ │ │ │ │ │ └── ic_launcher_round.png │ │ │ │ │ ├── mipmap-xxhdpi │ │ │ │ │ │ ├── ic_launcher.png │ │ │ │ │ │ └── ic_launcher_round.png │ │ │ │ │ ├── mipmap-xxxhdpi │ │ │ │ │ │ ├── ic_launcher.png │ │ │ │ │ │ └── ic_launcher_round.png │ │ │ │ │ └── xml │ │ │ │ │ │ └── network_security_config.xml │ │ │ │ └── AndroidManifest.xml │ │ │ └── debug │ │ │ │ └── AndroidManifest.xml │ │ └── proguard-rules.pro │ ├── gradle │ │ └── wrapper │ │ │ ├── gradle-wrapper.jar │ │ │ └── gradle-wrapper.properties │ ├── settings.gradle │ └── build.gradle │ ├── ios │ ├── Playground │ │ ├── Images.xcassets │ │ │ ├── Contents.json │ │ │ └── AppIcon.appiconset │ │ │ │ └── Contents.json │ │ ├── AppDelegate.h │ │ ├── main.m │ │ ├── PrivacyInfo.xcprivacy │ │ └── AppDelegate.mm │ ├── Playground.xcworkspace │ │ └── contents.xcworkspacedata │ ├── .xcode.env │ ├── PlaygroundTests │ │ └── Info.plist │ └── Podfile │ ├── tsconfig.json │ ├── tsconfig.tsbuildinfo │ ├── Gemfile │ ├── README.md │ ├── index.html │ └── .babelrc.js ├── .husky └── commit-msg ├── .nxignore ├── .prettierrc ├── website ├── src │ ├── public │ │ ├── cli.png │ │ ├── og-image.jpg │ │ ├── mmkv-plugin.png │ │ ├── expo-atlas-plugin.png │ │ ├── plugin-slideshow.webp │ │ ├── rozenite-banner.jpg │ │ ├── rozenite-loaded.png │ │ ├── redux-devtools-plugin.png │ │ ├── tanstack-query-plugin.png │ │ ├── network-activity-plugin.png │ │ ├── react-navigation-plugin.png │ │ ├── require-profiler-plugin.png │ │ ├── performance-monitor-plugin.png │ │ ├── icons │ │ │ ├── device-phone.svg │ │ │ ├── lock.svg │ │ │ ├── frame-check.svg │ │ │ ├── power.svg │ │ │ ├── loader.svg │ │ │ ├── edit-box.svg │ │ │ └── radio-signal.svg │ │ ├── notes.svg │ │ ├── logo.svg │ │ ├── arrow-bar-right.svg │ │ ├── radio-handheld.svg │ │ ├── cloud.svg │ │ ├── add-grid.svg │ │ ├── edit-box.svg │ │ ├── github.svg │ │ ├── sliders-2.svg │ │ └── repeat.svg │ ├── 404.mdx │ ├── docs │ │ ├── plugin-development │ │ │ └── _meta.json │ │ ├── _meta.json │ │ └── official-plugins │ │ │ └── _meta.json │ └── _nav.json ├── theme │ ├── fonts │ │ ├── alliance-no-2-medium.ttf │ │ └── alliance-no-2-regular.ttf │ └── styles.css ├── plugins │ └── plugin-directory │ │ ├── css-modules.d.ts │ │ ├── rspress-shared.d.ts │ │ ├── types.ts │ │ ├── repository │ │ ├── types.ts │ │ └── repository-factory.ts │ │ └── utils.ts ├── .gitignore ├── vercel.json ├── tsconfig.json ├── package.json └── rspress.config.ts ├── .vscode └── extensions.json ├── .github ├── ISSUE_TEMPLATE │ ├── config.yml │ ├── 2-feature-request.yml │ └── 3-documentation.yml └── pull_request_template.md ├── .prettierignore ├── .nx └── version-plans │ ├── version-plan-1766160851318.md │ └── version-plan-1766258458200.md ├── pnpm-workspace.yaml ├── tsconfig.base.json ├── tsconfig.json ├── commitlint.config.js ├── LICENSE └── eslint.config.mjs /packages/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /apps/playground/src/assets/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.husky/commit-msg: -------------------------------------------------------------------------------- 1 | pnpm dlx commitlint --edit $1 2 | -------------------------------------------------------------------------------- /.nxignore: -------------------------------------------------------------------------------- 1 | # Ignore template 2 | packages/cli/template/ -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true 3 | } 4 | -------------------------------------------------------------------------------- /packages/cli/bin.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | import('./dist/index.js'); 4 | -------------------------------------------------------------------------------- /packages/expo-atlas-plugin/react-native.ts: -------------------------------------------------------------------------------- 1 | export * from './src/with-expo-atlas'; 2 | -------------------------------------------------------------------------------- /packages/redux-devtools-plugin/src/constants.ts: -------------------------------------------------------------------------------- 1 | export const REDUX_DEVTOOLS_PORT = 8765; 2 | -------------------------------------------------------------------------------- /apps/playground/app.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Playground", 3 | "displayName": "Playground" 4 | } 5 | -------------------------------------------------------------------------------- /packages/cli/src/utils/color.ts: -------------------------------------------------------------------------------- 1 | import color from 'picocolors'; 2 | 3 | export { color }; 4 | -------------------------------------------------------------------------------- /packages/plugin-bridge/src/types.ts: -------------------------------------------------------------------------------- 1 | export type Subscription = { 2 | remove: () => void; 3 | }; 4 | -------------------------------------------------------------------------------- /packages/redux-devtools-plugin/metro.ts: -------------------------------------------------------------------------------- 1 | export { withRozeniteReduxDevTools } from './src/metro'; 2 | -------------------------------------------------------------------------------- /packages/cli/src/types.ts: -------------------------------------------------------------------------------- 1 | export type PluginInfo = { 2 | name: string; 3 | description: string; 4 | }; 5 | -------------------------------------------------------------------------------- /packages/require-profiler-plugin/metro.ts: -------------------------------------------------------------------------------- 1 | export { withRozeniteRequireProfiler } from './src/metro/index'; 2 | -------------------------------------------------------------------------------- /packages/require-profiler-plugin/src/shared/index.ts: -------------------------------------------------------------------------------- 1 | export * from './messaging'; 2 | export * from './types'; 3 | -------------------------------------------------------------------------------- /website/src/public/cli.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/callstackincubator/rozenite/HEAD/website/src/public/cli.png -------------------------------------------------------------------------------- /website/src/public/og-image.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/callstackincubator/rozenite/HEAD/website/src/public/og-image.jpg -------------------------------------------------------------------------------- /packages/plugin-bridge/src/rozenite-types.d.ts: -------------------------------------------------------------------------------- 1 | declare global { 2 | var __ROZENITE_PANEL__: boolean; 3 | } 4 | 5 | export {}; 6 | -------------------------------------------------------------------------------- /website/src/public/mmkv-plugin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/callstackincubator/rozenite/HEAD/website/src/public/mmkv-plugin.png -------------------------------------------------------------------------------- /website/src/404.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | pageType: custom 3 | --- 4 | 5 | import { NotFoundLayout } from '@theme'; 6 | 7 | 8 | -------------------------------------------------------------------------------- /packages/mmkv-plugin/postcss.config.js: -------------------------------------------------------------------------------- 1 | export default { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | }; 7 | -------------------------------------------------------------------------------- /website/src/public/expo-atlas-plugin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/callstackincubator/rozenite/HEAD/website/src/public/expo-atlas-plugin.png -------------------------------------------------------------------------------- /website/src/public/plugin-slideshow.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/callstackincubator/rozenite/HEAD/website/src/public/plugin-slideshow.webp -------------------------------------------------------------------------------- /website/src/public/rozenite-banner.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/callstackincubator/rozenite/HEAD/website/src/public/rozenite-banner.jpg -------------------------------------------------------------------------------- /website/src/public/rozenite-loaded.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/callstackincubator/rozenite/HEAD/website/src/public/rozenite-loaded.png -------------------------------------------------------------------------------- /apps/playground/android/app/debug.keystore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/callstackincubator/rozenite/HEAD/apps/playground/android/app/debug.keystore -------------------------------------------------------------------------------- /apps/playground/android/app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | Playground 3 | 4 | -------------------------------------------------------------------------------- /apps/playground/ios/Playground/Images.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info": { 3 | "version": 1, 4 | "author": "xcode" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /website/src/public/redux-devtools-plugin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/callstackincubator/rozenite/HEAD/website/src/public/redux-devtools-plugin.png -------------------------------------------------------------------------------- /website/src/public/tanstack-query-plugin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/callstackincubator/rozenite/HEAD/website/src/public/tanstack-query-plugin.png -------------------------------------------------------------------------------- /website/theme/fonts/alliance-no-2-medium.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/callstackincubator/rozenite/HEAD/website/theme/fonts/alliance-no-2-medium.ttf -------------------------------------------------------------------------------- /website/theme/fonts/alliance-no-2-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/callstackincubator/rozenite/HEAD/website/theme/fonts/alliance-no-2-regular.ttf -------------------------------------------------------------------------------- /packages/network-activity-plugin/postcss.config.js: -------------------------------------------------------------------------------- 1 | export default { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | }; 7 | -------------------------------------------------------------------------------- /packages/react-navigation-plugin/postcss.config.js: -------------------------------------------------------------------------------- 1 | export default { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | }; 7 | -------------------------------------------------------------------------------- /packages/require-profiler-plugin/postcss.config.js: -------------------------------------------------------------------------------- 1 | export default { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | }; 7 | -------------------------------------------------------------------------------- /website/src/public/network-activity-plugin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/callstackincubator/rozenite/HEAD/website/src/public/network-activity-plugin.png -------------------------------------------------------------------------------- /website/src/public/react-navigation-plugin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/callstackincubator/rozenite/HEAD/website/src/public/react-navigation-plugin.png -------------------------------------------------------------------------------- /website/src/public/require-profiler-plugin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/callstackincubator/rozenite/HEAD/website/src/public/require-profiler-plugin.png -------------------------------------------------------------------------------- /packages/mmkv-plugin/src/css-modules.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.module.css' { 2 | const classes: { [key: string]: string }; 3 | export default classes; 4 | } 5 | -------------------------------------------------------------------------------- /website/src/public/performance-monitor-plugin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/callstackincubator/rozenite/HEAD/website/src/public/performance-monitor-plugin.png -------------------------------------------------------------------------------- /apps/playground/ios/Playground/AppDelegate.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | 4 | @interface AppDelegate : RCTAppDelegate 5 | 6 | @end 7 | -------------------------------------------------------------------------------- /packages/expo-atlas-plugin/src/css-modules.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.module.css' { 2 | const classes: { [key: string]: string }; 3 | export default classes; 4 | } 5 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "nrwl.angular-console", 4 | "prettier.prettier-vscode", 5 | "dbaeumer.vscode-eslint" 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /packages/network-activity-plugin/src/css-modules.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.module.css' { 2 | const classes: { [key: string]: string }; 3 | export default classes; 4 | } 5 | -------------------------------------------------------------------------------- /packages/react-navigation-plugin/src/css-modules.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.module.css' { 2 | const classes: { [key: string]: string }; 3 | export default classes; 4 | } 5 | -------------------------------------------------------------------------------- /packages/redux-devtools-plugin/src/css-modules.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.module.css' { 2 | const classes: { [key: string]: string }; 3 | export default classes; 4 | } 5 | -------------------------------------------------------------------------------- /packages/require-profiler-plugin/src/css-modules.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.module.css' { 2 | const classes: { [key: string]: string }; 3 | export default classes; 4 | } 5 | -------------------------------------------------------------------------------- /website/plugins/plugin-directory/css-modules.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.module.css' { 2 | const classes: { [key: string]: string }; 3 | export default classes; 4 | } 5 | -------------------------------------------------------------------------------- /apps/playground/android/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/callstackincubator/rozenite/HEAD/apps/playground/android/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /apps/playground/src/main.tsx: -------------------------------------------------------------------------------- 1 | import { AppRegistry } from 'react-native'; 2 | import App from './app/App'; 3 | 4 | AppRegistry.registerComponent('Playground', () => App); 5 | -------------------------------------------------------------------------------- /packages/mmkv-plugin/rozenite.config.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | panels: [ 3 | { 4 | name: 'MMKV', 5 | source: './src/ui/panel.tsx', 6 | }, 7 | ], 8 | }; 9 | -------------------------------------------------------------------------------- /packages/network-activity-plugin/src/ui/utils/copyToClipboard.ts: -------------------------------------------------------------------------------- 1 | export async function copyToClipboard(text: string) { 2 | return navigator.clipboard.writeText(text); 3 | } 4 | -------------------------------------------------------------------------------- /packages/cli/src/constants.ts: -------------------------------------------------------------------------------- 1 | import { fileURLToPath } from 'node:url'; 2 | 3 | export const TEMPLATE_DIR = fileURLToPath( 4 | new URL('../template', import.meta.url) 5 | ); 6 | -------------------------------------------------------------------------------- /packages/cli/src/package-json.ts: -------------------------------------------------------------------------------- 1 | import packageJSON from '../package.json' with { type: 'json' }; 2 | 3 | export const getPackageJSON = () => { 4 | return packageJSON; 5 | }; 6 | -------------------------------------------------------------------------------- /packages/network-activity-plugin/src/utils/getStringSizeInBytes.ts: -------------------------------------------------------------------------------- 1 | export const getStringSizeInBytes = (value: string) => { 2 | return new TextEncoder().encode(value).length; 3 | }; 4 | -------------------------------------------------------------------------------- /packages/cli/template/rozenite.config.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | panels: [ 3 | { 4 | name: 'Hello world!', 5 | source: './src/hello-world.tsx', 6 | }, 7 | ], 8 | }; 9 | -------------------------------------------------------------------------------- /packages/expo-atlas-plugin/rozenite.config.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | panels: [ 3 | { 4 | name: 'Expo Atlas', 5 | source: './src/expo-atlas.tsx', 6 | }, 7 | ], 8 | }; 9 | -------------------------------------------------------------------------------- /packages/redux-devtools-plugin/rozenite.config.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | panels: [ 3 | { 4 | name: 'Redux DevTools', 5 | source: './src/ui/panel.tsx', 6 | }, 7 | ], 8 | }; 9 | -------------------------------------------------------------------------------- /apps/playground/android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/callstackincubator/rozenite/HEAD/apps/playground/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /apps/playground/android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/callstackincubator/rozenite/HEAD/apps/playground/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /apps/playground/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/callstackincubator/rozenite/HEAD/apps/playground/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /apps/playground/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/callstackincubator/rozenite/HEAD/apps/playground/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /packages/network-activity-plugin/rozenite.config.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | panels: [ 3 | { 4 | name: 'Network Activity', 5 | source: './src/ui/App.tsx', 6 | }, 7 | ], 8 | }; 9 | -------------------------------------------------------------------------------- /packages/require-profiler-plugin/rozenite.config.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | panels: [ 3 | { 4 | name: 'Require profiler', 5 | source: './src/ui/panel.tsx', 6 | }, 7 | ], 8 | }; 9 | -------------------------------------------------------------------------------- /apps/playground/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/callstackincubator/rozenite/HEAD/apps/playground/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /apps/playground/src/app/screens/heavyComputationModule.ts: -------------------------------------------------------------------------------- 1 | const startTime = Date.now(); 2 | const targetDuration = 2000; 3 | 4 | while (Date.now() - startTime < targetDuration) { 5 | // noop! 6 | } 7 | -------------------------------------------------------------------------------- /packages/performance-monitor-plugin/rozenite.config.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | panels: [ 3 | { 4 | name: 'Performance Monitor', 5 | source: './src/ui/App.tsx', 6 | }, 7 | ], 8 | }; 9 | -------------------------------------------------------------------------------- /packages/tanstack-query-plugin/rozenite.config.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | panels: [ 3 | { 4 | name: 'Tanstack Query', 5 | source: './src/ui/tanstack-query.tsx', 6 | }, 7 | ], 8 | }; 9 | -------------------------------------------------------------------------------- /apps/playground/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/callstackincubator/rozenite/HEAD/apps/playground/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /apps/playground/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/callstackincubator/rozenite/HEAD/apps/playground/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /apps/playground/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/callstackincubator/rozenite/HEAD/apps/playground/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /packages/network-activity-plugin/src/ui/utils/assert.ts: -------------------------------------------------------------------------------- 1 | export function assert(condition: boolean, message: string): asserts condition { 2 | if (!condition) { 3 | throw new Error(message); 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /packages/react-navigation-plugin/rozenite.config.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | panels: [ 3 | { 4 | name: 'React Navigation', 5 | source: './src/devtools-ui/index.tsx', 6 | }, 7 | ], 8 | }; 9 | -------------------------------------------------------------------------------- /apps/playground/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/callstackincubator/rozenite/HEAD/apps/playground/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /apps/playground/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/callstackincubator/rozenite/HEAD/apps/playground/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /packages/expo-atlas-plugin/tsconfig.tsbuildinfo: -------------------------------------------------------------------------------- 1 | {"root":["./src/css-modules.d.ts","./src/expo-atlas-without-expo.d.ts","./src/expo-atlas.tsx","./react-native.ts","./rozenite.config.ts"],"errors":true,"version":"5.8.3"} -------------------------------------------------------------------------------- /packages/cli/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "files": [], 4 | "include": [], 5 | "references": [ 6 | { 7 | "path": "./tsconfig.lib.json" 8 | } 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /packages/runtime/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "files": [], 4 | "include": [], 5 | "references": [ 6 | { 7 | "path": "./tsconfig.lib.json" 8 | } 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /packages/vite-plugin/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "files": [], 4 | "include": [], 5 | "references": [ 6 | { 7 | "path": "./tsconfig.lib.json" 8 | } 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /packages/plugin-bridge/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "files": [], 4 | "include": [], 5 | "references": [ 6 | { 7 | "path": "./tsconfig.lib.json" 8 | } 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /packages/redux-devtools-plugin/src/ui/panel.css: -------------------------------------------------------------------------------- 1 | .app { 2 | height: 100%; 3 | width: 100%; 4 | display: flex; 5 | flex-direction: column; 6 | background: rgb(42, 47, 58); 7 | margin: 0; 8 | padding: 0; 9 | } 10 | -------------------------------------------------------------------------------- /website/.gitignore: -------------------------------------------------------------------------------- 1 | # Local 2 | .DS_Store 3 | *.local 4 | *.log* 5 | 6 | # Dist 7 | node_modules 8 | dist/ 9 | doc_build/ 10 | 11 | # IDE 12 | .vscode/* 13 | !.vscode/extensions.json 14 | .idea 15 | 16 | # Vercel 17 | build/ -------------------------------------------------------------------------------- /packages/network-activity-plugin/src/ui/utils/cn.ts: -------------------------------------------------------------------------------- 1 | import { type ClassValue, clsx } from 'clsx'; 2 | import { twMerge } from 'tailwind-merge'; 3 | 4 | export function cn(...inputs: ClassValue[]) { 5 | return twMerge(clsx(inputs)); 6 | } 7 | -------------------------------------------------------------------------------- /packages/plugin-bridge/src/errors.ts: -------------------------------------------------------------------------------- 1 | export class UnsupportedPlatformError extends Error { 2 | constructor(platform: string) { 3 | super(`Unsupported platform: ${platform}`); 4 | this.name = 'UnsupportedPlatformError'; 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /website/src/public/icons/device-phone.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /website/src/public/notes.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /packages/network-activity-plugin/src/react-native/websocket/websocket-interceptor.d.ts: -------------------------------------------------------------------------------- 1 | declare module 'react-native/Libraries/WebSocket/WebSocketInterceptor' { 2 | const WebSocketInterceptor: unknown; 3 | export default WebSocketInterceptor; 4 | } 5 | -------------------------------------------------------------------------------- /packages/performance-monitor-plugin/src/react-native/helpers.ts: -------------------------------------------------------------------------------- 1 | import performance from 'react-native-performance'; 2 | 3 | export const toDateTimestamp = (origin: number, startTime: number): number => 4 | origin - performance.timeOrigin + startTime; 5 | -------------------------------------------------------------------------------- /packages/network-activity-plugin/src/utils/safeStringify.ts: -------------------------------------------------------------------------------- 1 | export function safeStringify(data: unknown): string { 2 | try { 3 | return typeof data === 'string' ? data : JSON.stringify(data); 4 | } catch { 5 | return String(data); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /website/src/public/icons/lock.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /packages/plugin-bridge/src/channel/types.ts: -------------------------------------------------------------------------------- 1 | import { Subscription } from '../types'; 2 | 3 | export type Channel = { 4 | send: (message: unknown) => void; 5 | onMessage: (listener: (message: unknown) => void) => Subscription; 6 | close: () => void; 7 | }; 8 | -------------------------------------------------------------------------------- /packages/plugin-bridge/src/web.ts: -------------------------------------------------------------------------------- 1 | export const isWeb = (): boolean => { 2 | // Checking for window.document to not depend on the 'react-native' package. 3 | return ( 4 | typeof window !== 'undefined' && typeof window.document !== 'undefined' 5 | ); 6 | }; 7 | -------------------------------------------------------------------------------- /packages/runtime/src/rn-devtools/types.ts: -------------------------------------------------------------------------------- 1 | export type DomainMessageListener = (message: JSONValue) => void; 2 | 3 | export type JSONValue = 4 | | null 5 | | string 6 | | number 7 | | boolean 8 | | { [key: string]: JSONValue } 9 | | JSONValue[]; 10 | -------------------------------------------------------------------------------- /website/plugins/plugin-directory/rspress-shared.d.ts: -------------------------------------------------------------------------------- 1 | import { PluginDirectoryPage } from './types'; 2 | 3 | declare module '@rspress/shared' { 4 | interface PageIndexInfo { 5 | pluginDirectoryPage: PluginDirectoryPage; 6 | } 7 | } 8 | 9 | export {}; 10 | -------------------------------------------------------------------------------- /packages/cli/src/utils/files.ts: -------------------------------------------------------------------------------- 1 | import fs from 'node:fs/promises'; 2 | 3 | export const fileExists = async (path: string): Promise => { 4 | try { 5 | await fs.stat(path); 6 | return true; 7 | } catch { 8 | return false; 9 | } 10 | }; 11 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | contact_links: 3 | - name: Questions & Discussions 4 | url: https://github.com/callstackincubator/rozenite/discussions 5 | about: Use GitHub discussions for message-board style questions and discussions. 6 | -------------------------------------------------------------------------------- /apps/playground/ios/Playground/main.m: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | #import "AppDelegate.h" 4 | 5 | int main(int argc, char *argv[]) 6 | { 7 | @autoreleasepool { 8 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /packages/metro/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "files": [], 4 | "include": [], 5 | "references": [ 6 | { 7 | "path": "../middleware" 8 | }, 9 | { 10 | "path": "./tsconfig.lib.json" 11 | } 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /packages/middleware/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "files": [], 4 | "include": [], 5 | "references": [ 6 | { 7 | "path": "../runtime" 8 | }, 9 | { 10 | "path": "./tsconfig.lib.json" 11 | } 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /packages/repack/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "files": [], 4 | "include": [], 5 | "references": [ 6 | { 7 | "path": "../middleware" 8 | }, 9 | { 10 | "path": "./tsconfig.lib.json" 11 | } 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /website/src/docs/plugin-development/_meta.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "type": "file", 4 | "name": "overview", 5 | "label": "Overview" 6 | }, 7 | { 8 | "type": "file", 9 | "name": "plugin-development", 10 | "label": "Plugin Development Guide" 11 | } 12 | ] -------------------------------------------------------------------------------- /packages/require-profiler-plugin/src/ui/components/LoadingState.tsx: -------------------------------------------------------------------------------- 1 | export const LoadingState = () => { 2 | return ( 3 |
4 |
5 |

Loading require profiler data...

6 |
7 | ); 8 | }; 9 | -------------------------------------------------------------------------------- /website/src/_nav.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "text": "Docs", 4 | "link": "/docs/introduction", 5 | "activeMatch": "^/docs/" 6 | }, 7 | { 8 | "text": "Plugin Directory", 9 | "link": "/plugin-directory", 10 | "activeMatch": "^/plugin-directory" 11 | } 12 | ] 13 | -------------------------------------------------------------------------------- /website/src/public/icons/frame-check.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /website/src/public/icons/power.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /packages/network-activity-plugin/src/ui/utils/checkRequestBodyBinary.ts: -------------------------------------------------------------------------------- 1 | import { NetworkEntry } from '../state/model'; 2 | 3 | export const checkRequestBodyBinary = (request: NetworkEntry) => { 4 | return ( 5 | request.type === 'http' && request.request.body?.data.type === 'binary' 6 | ); 7 | }; 8 | -------------------------------------------------------------------------------- /website/src/public/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /website/src/public/arrow-bar-right.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | # Add files here to ignore them from prettier formatting 2 | **/dist 3 | **/coverage 4 | /.nx/cache 5 | /.nx/workspace-data 6 | /pnpm-lock.yaml 7 | 8 | # Markdown files (documentation) 9 | **/*.md 10 | 11 | # Playground (native code) 12 | 13 | apps/playground/android 14 | apps/playground/ios -------------------------------------------------------------------------------- /website/src/public/radio-handheld.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /packages/middleware/src/constants.ts: -------------------------------------------------------------------------------- 1 | import path from 'node:path'; 2 | import { fileURLToPath } from 'node:url'; 3 | 4 | export const TEMPLATE_DIR = path.resolve( 5 | fileURLToPath(new URL('../templates', import.meta.url)), 6 | './entry-point.ejs' 7 | ); 8 | 9 | export const ROZENITE_MANIFEST = 'rozenite.json'; 10 | -------------------------------------------------------------------------------- /packages/redux-devtools-plugin/src/react-native.d.ts: -------------------------------------------------------------------------------- 1 | declare module 'react-native/Libraries/Core/Devtools/getDevServer' { 2 | export type DevServerInfo = { 3 | url: string; 4 | fullBundleUrl?: string; 5 | bundleLoadedFromServer: boolean; 6 | }; 7 | export default function getDevServer(): DevServerInfo; 8 | } 9 | -------------------------------------------------------------------------------- /packages/runtime/src/global-namespace.ts: -------------------------------------------------------------------------------- 1 | declare global { 2 | var __ROZENITE__: { 3 | installedPlugins: string[]; 4 | developmentServer: boolean; 5 | destroyOnDetachPlugins: string[]; 6 | }; 7 | } 8 | 9 | export const getGlobalNamespace = (): typeof globalThis.__ROZENITE__ => 10 | globalThis.__ROZENITE__; 11 | -------------------------------------------------------------------------------- /apps/playground/android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-all.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /apps/playground/ios/Playground.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /packages/network-activity-plugin/src/utils/inferContentTypeFromPostData.ts: -------------------------------------------------------------------------------- 1 | import { RequestPostData } from '../shared/client'; 2 | 3 | export function inferContentTypeFromPostData(postData: RequestPostData) { 4 | if (postData?.type === 'form-data') { 5 | return 'multipart/form-data'; 6 | } 7 | 8 | return undefined; 9 | } 10 | -------------------------------------------------------------------------------- /.nx/version-plans/version-plan-1766160851318.md: -------------------------------------------------------------------------------- 1 | --- 2 | '@rozenite/redux-devtools-plugin': minor 3 | --- 4 | 5 | Add maxAge option to Redux DevTools plugin to configure action history size. This allows developers to control the maximum number of actions retained in DevTools; older actions are automatically removed once the limit is reached (default: 50). -------------------------------------------------------------------------------- /apps/playground/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "files": [], 4 | "include": [], 5 | "references": [ 6 | { 7 | "path": "../../packages/cli" 8 | }, 9 | { 10 | "path": "../../packages/metro" 11 | }, 12 | { 13 | "path": "./tsconfig.app.json" 14 | } 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /website/src/public/cloud.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /packages/network-activity-plugin/src/ui/utils/getId.ts: -------------------------------------------------------------------------------- 1 | const idMap = new Map(); 2 | 3 | export const getId = (namespace: string) => { 4 | if (!idMap.has(namespace)) { 5 | idMap.set(namespace, 0); 6 | } 7 | const id = idMap.get(namespace) ?? 0; 8 | idMap.set(namespace, id + 1); 9 | return `${namespace}-${id}`; 10 | }; 11 | -------------------------------------------------------------------------------- /packages/mmkv-plugin/tsconfig.tsbuildinfo: -------------------------------------------------------------------------------- 1 | {"root":["./src/css-modules.d.ts","./src/react-native/mmkv-container.ts","./src/react-native/mmkv-entry.ts","./src/react-native/usemmkvdevtools.ts","./src/shared/messaging.ts","./src/shared/types.ts","./src/ui/editable-table.tsx","./src/ui/panel.tsx","./react-native.ts","./rozenite.config.ts"],"errors":true,"version":"5.8.3"} -------------------------------------------------------------------------------- /website/vercel.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://openapi.vercel.sh/vercel.json", 3 | "buildCommand": "pnpm build", 4 | "cleanUrls": true, 5 | "framework": null, 6 | "installCommand": "pnpm install", 7 | "rewrites": [{ "source": "/(.*)", "destination": "/404.html" }], 8 | "outputDirectory": "build", 9 | "trailingSlash": false 10 | } -------------------------------------------------------------------------------- /packages/mmkv-plugin/project.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "../../node_modules/nx/schemas/project-schema.json", 3 | "name": "@rozenite/mmkv-plugin", 4 | "targets": { 5 | "build": { 6 | "cache": true, 7 | "dependsOn": ["^build"], 8 | "inputs": ["{projectRoot}/src/**/*"], 9 | "outputs": ["{projectRoot}/dist"] 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /website/src/public/icons/loader.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /apps/playground/android/app/src/main/res/xml/network_security_config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10.0.2.2 5 | localhost 6 | 7 | -------------------------------------------------------------------------------- /apps/playground/tsconfig.tsbuildinfo: -------------------------------------------------------------------------------- 1 | {"fileNames":[],"fileInfos":[],"root":[],"options":{"composite":true,"declarationMap":true,"emitDeclarationOnly":true,"importHelpers":true,"module":199,"noEmitOnError":true,"noFallthroughCasesInSwitch":true,"noImplicitOverride":true,"noImplicitReturns":true,"noUnusedLocals":true,"skipLibCheck":true,"strict":true,"target":9},"version":"5.8.3"} -------------------------------------------------------------------------------- /packages/metro/tsconfig.tsbuildinfo: -------------------------------------------------------------------------------- 1 | {"fileNames":[],"fileInfos":[],"root":[],"options":{"composite":true,"declarationMap":true,"emitDeclarationOnly":true,"importHelpers":true,"module":199,"noEmitOnError":true,"noFallthroughCasesInSwitch":true,"noImplicitOverride":true,"noImplicitReturns":true,"noUnusedLocals":true,"skipLibCheck":true,"strict":true,"target":9},"version":"5.8.3"} -------------------------------------------------------------------------------- /packages/network-activity-plugin/src/react-native/sse/types.ts: -------------------------------------------------------------------------------- 1 | import type EventSource from 'react-native-sse'; 2 | 3 | export interface EventSourceWithInternals 4 | extends EventSource { 5 | url: string; 6 | 7 | /** Used internally to mark the underlying XHR to skip it in XHR interceptor. */ 8 | _xhr?: XMLHttpRequest; 9 | } 10 | -------------------------------------------------------------------------------- /packages/repack/tsconfig.tsbuildinfo: -------------------------------------------------------------------------------- 1 | {"fileNames":[],"fileInfos":[],"root":[],"options":{"composite":true,"declarationMap":true,"emitDeclarationOnly":true,"importHelpers":true,"module":199,"noEmitOnError":true,"noFallthroughCasesInSwitch":true,"noImplicitOverride":true,"noImplicitReturns":true,"noUnusedLocals":true,"skipLibCheck":true,"strict":true,"target":9},"version":"5.8.3"} -------------------------------------------------------------------------------- /packages/require-profiler-plugin/tsconfig.tsbuildinfo: -------------------------------------------------------------------------------- 1 | {"root":["./src/css-modules.d.ts","./src/react-native/mmkv-container.ts","./src/react-native/mmkv-entry.ts","./src/react-native/usemmkvdevtools.ts","./src/shared/messaging.ts","./src/shared/types.ts","./src/ui/editable-table.tsx","./src/ui/panel.tsx","./react-native.ts","./rozenite.config.ts"],"errors":true,"version":"5.8.3"} -------------------------------------------------------------------------------- /apps/playground/android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /packages/cli/src/utils/isInteractive.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Source from https://github.com/sindresorhus/is-interactive/blob/main/index.js 3 | */ 4 | export const isInteractive = ({ stream = process.stdout } = {}) => { 5 | return Boolean( 6 | stream && 7 | stream.isTTY && 8 | process.env['TERM'] !== 'dumb' && 9 | !('CI' in process.env) 10 | ); 11 | }; 12 | -------------------------------------------------------------------------------- /packages/expo-atlas-plugin/project.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "../../node_modules/nx/schemas/project-schema.json", 3 | "name": "@rozenite/expo-atlas-plugin", 4 | "targets": { 5 | "build": { 6 | "cache": true, 7 | "dependsOn": ["^build"], 8 | "inputs": ["{projectRoot}/src/**/*"], 9 | "outputs": ["{projectRoot}/dist"] 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /packages/middleware/tsconfig.tsbuildinfo: -------------------------------------------------------------------------------- 1 | {"fileNames":[],"fileInfos":[],"root":[],"options":{"composite":true,"declarationMap":true,"emitDeclarationOnly":true,"importHelpers":true,"module":199,"noEmitOnError":true,"noFallthroughCasesInSwitch":true,"noImplicitOverride":true,"noImplicitReturns":true,"noUnusedLocals":true,"skipLibCheck":true,"strict":true,"target":9},"version":"5.8.3"} -------------------------------------------------------------------------------- /packages/plugin-bridge/tsconfig.tsbuildinfo: -------------------------------------------------------------------------------- 1 | {"fileNames":[],"fileInfos":[],"root":[],"options":{"composite":true,"declarationMap":true,"emitDeclarationOnly":true,"importHelpers":true,"module":199,"noEmitOnError":true,"noFallthroughCasesInSwitch":true,"noImplicitOverride":true,"noImplicitReturns":true,"noUnusedLocals":true,"skipLibCheck":true,"strict":true,"target":9},"version":"5.8.3"} -------------------------------------------------------------------------------- /packages/redux-devtools-plugin/project.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "../../node_modules/nx/schemas/project-schema.json", 3 | "name": "@rozenite/redux-devtools-plugin", 4 | "targets": { 5 | "build": { 6 | "cache": true, 7 | "dependsOn": ["^build"], 8 | "inputs": ["{projectRoot}/src/**/*"], 9 | "outputs": ["{projectRoot}/dist"] 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /packages/tanstack-query-plugin/project.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "../../node_modules/nx/schemas/project-schema.json", 3 | "name": "@rozenite/tanstack-query-plugin", 4 | "targets": { 5 | "build": { 6 | "cache": true, 7 | "dependsOn": ["^build"], 8 | "inputs": ["{projectRoot}/src/**/*"], 9 | "outputs": ["{projectRoot}/dist"] 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /packages/mmkv-plugin/src/shared/types.ts: -------------------------------------------------------------------------------- 1 | export type MMKVEntry = 2 | | { key: string; type: 'string'; value: string } 3 | | { key: string; type: 'number'; value: number } 4 | | { key: string; type: 'boolean'; value: boolean } 5 | | { key: string; type: 'buffer'; value: number[] }; 6 | 7 | export type MMKVEntryType = MMKVEntry['type']; 8 | export type MMKVEntryValue = MMKVEntry['value']; 9 | -------------------------------------------------------------------------------- /packages/network-activity-plugin/project.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "../../node_modules/nx/schemas/project-schema.json", 3 | "name": "@rozenite/network-activity-plugin", 4 | "targets": { 5 | "build": { 6 | "cache": true, 7 | "dependsOn": ["^build"], 8 | "inputs": ["{projectRoot}/src/**/*"], 9 | "outputs": ["{projectRoot}/dist"] 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /packages/react-navigation-plugin/project.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "../../node_modules/nx/schemas/project-schema.json", 3 | "name": "@rozenite/react-navigation-plugin", 4 | "targets": { 5 | "build": { 6 | "cache": true, 7 | "dependsOn": ["^build"], 8 | "inputs": ["{projectRoot}/src/**/*"], 9 | "outputs": ["{projectRoot}/dist"] 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /packages/require-profiler-plugin/project.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "../../node_modules/nx/schemas/project-schema.json", 3 | "name": "@rozenite/require-profiler-plugin", 4 | "targets": { 5 | "build": { 6 | "cache": true, 7 | "dependsOn": ["^build"], 8 | "inputs": ["{projectRoot}/src/**/*"], 9 | "outputs": ["{projectRoot}/dist"] 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /packages/performance-monitor-plugin/project.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "../../node_modules/nx/schemas/project-schema.json", 3 | "name": "@rozenite/performance-monitor-plugin", 4 | "targets": { 5 | "build": { 6 | "cache": true, 7 | "dependsOn": ["^build"], 8 | "inputs": ["{projectRoot}/src/**/*"], 9 | "outputs": ["{projectRoot}/dist"] 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /packages/tools/src/index.ts: -------------------------------------------------------------------------------- 1 | export { 2 | getProjectType, 3 | getAvailableBundlerTypes, 4 | type ProjectType, 5 | type BundlerType, 6 | UnknownProjectType, 7 | UnknownBundlerType, 8 | } from './project-type.js'; 9 | export { logger } from './logger.js'; 10 | export { 11 | createMetroConfigTransformer, 12 | composeMetroConfigTransformers, 13 | } from './metro-transformers.js'; 14 | -------------------------------------------------------------------------------- /apps/playground/Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | # You may use http://rbenv.org/ or https://rvm.io/ to install and use this version 4 | ruby ">= 2.6.10" 5 | 6 | # Exclude problematic versions of cocoapods and activesupport that causes build failures. 7 | gem 'cocoapods', '>= 1.13', '!= 1.15.0', '!= 1.15.1' 8 | gem 'activesupport', '>= 6.1.7.5', '!= 7.1.0' 9 | gem 'xcodeproj', '< 1.26.0' 10 | -------------------------------------------------------------------------------- /apps/playground/android/settings.gradle: -------------------------------------------------------------------------------- 1 | pluginManagement { includeBuild("../../../node_modules/@react-native/gradle-plugin") } 2 | plugins { id("com.facebook.react.settings") } 3 | extensions.configure(com.facebook.react.ReactSettingsExtension){ ex -> ex.autolinkLibrariesFromCommand() } 4 | rootProject.name = 'Playground' 5 | include ':app' 6 | includeBuild('../../../node_modules/@react-native/gradle-plugin') 7 | -------------------------------------------------------------------------------- /website/src/public/add-grid.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /website/src/public/edit-box.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /packages/plugin-bridge/src/index.ts: -------------------------------------------------------------------------------- 1 | export { useRozeniteDevToolsClient } from './useRozeniteDevToolsClient'; 2 | export type { RozeniteDevToolsClient } from './client'; 3 | export type { Subscription } from './types'; 4 | export type { UseRozeniteDevToolsClientOptions } from './useRozeniteDevToolsClient'; 5 | export { getRozeniteDevToolsClient } from './client'; 6 | export { UnsupportedPlatformError } from './errors'; 7 | -------------------------------------------------------------------------------- /website/src/public/icons/edit-box.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /website/src/public/icons/radio-signal.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /packages/runtime/src/rn-devtools/rn-devtools-frontend.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable @nx/enforce-module-boundaries */ 2 | import * as UI from '/rozenite/ui/legacy/legacy.js'; 3 | import * as SDK from '/rozenite/core/sdk/sdk.js'; 4 | import * as ReactNativeModels from '/rozenite/models/react_native/react_native.js'; 5 | 6 | export type RuntimeEvent = { 7 | data: T; 8 | }; 9 | 10 | export { UI, SDK, ReactNativeModels }; 11 | -------------------------------------------------------------------------------- /.nx/version-plans/version-plan-1766258458200.md: -------------------------------------------------------------------------------- 1 | --- 2 | '@rozenite/redux-devtools-plugin': minor 3 | '@rozenite/require-profiler-plugin': minor 4 | '@rozenite/expo-atlas-plugin': minor 5 | '@rozenite/tools': minor 6 | --- 7 | 8 | Unified Metro config mutators system where the order of mutators no longer matters. Transformers can now be composed in any sequence while preserving type safety across different Metro config export patterns. -------------------------------------------------------------------------------- /packages/runtime/src/manifest.ts: -------------------------------------------------------------------------------- 1 | export type RozeniteManifest = { 2 | name: string; 3 | version: string; 4 | description: string; 5 | panels: { 6 | name: string; 7 | source: string; 8 | }[]; 9 | }; 10 | 11 | export const getManifest = async ( 12 | baseUrl: string 13 | ): Promise => { 14 | const response = await fetch(baseUrl + '/rozenite.json'); 15 | return response.json(); 16 | }; 17 | -------------------------------------------------------------------------------- /packages/tanstack-query-plugin/src/ui/useSyncInitialData.ts: -------------------------------------------------------------------------------- 1 | import { useEffect } from 'react'; 2 | import { TanStackQueryPluginClient } from '../shared/messaging'; 3 | 4 | export const useSyncInitialData = ( 5 | client: TanStackQueryPluginClient | null 6 | ) => { 7 | useEffect(() => { 8 | if (!client) { 9 | return; 10 | } 11 | 12 | client.send('request-initial-data', {}); 13 | }, [client]); 14 | }; 15 | -------------------------------------------------------------------------------- /packages/require-profiler-plugin/src/shared/types.ts: -------------------------------------------------------------------------------- 1 | export type RequireTimingNode = { 2 | name: string; 3 | value: number; 4 | tooltip: string; 5 | children: RequireTimingNode[]; 6 | }; 7 | 8 | export type RequireChainMeta = { 9 | index: number; 10 | rootModuleId: number | string; 11 | rootModuleName: string; 12 | }; 13 | 14 | export type RequireChainData = RequireChainMeta & { 15 | tree: RequireTimingNode; 16 | }; 17 | -------------------------------------------------------------------------------- /packages/performance-monitor-plugin/react-native.ts: -------------------------------------------------------------------------------- 1 | export let usePerformanceMonitorDevTools: typeof import('./src/react-native/usePerformanceMonitorDevTools').usePerformanceMonitorDevTools; 2 | 3 | if (process.env.NODE_ENV !== 'production') { 4 | usePerformanceMonitorDevTools = 5 | require('./src/react-native/usePerformanceMonitorDevTools').usePerformanceMonitorDevTools; 6 | } else { 7 | usePerformanceMonitorDevTools = () => null; 8 | } 9 | -------------------------------------------------------------------------------- /packages/cli/src/utils/git.ts: -------------------------------------------------------------------------------- 1 | import { spawn } from './spawn.js'; 2 | 3 | export const isGitRepositoryClean = async ( 4 | projectRoot: string 5 | ): Promise => { 6 | try { 7 | const process = await spawn('git', ['status', '--porcelain'], { 8 | cwd: projectRoot, 9 | }); 10 | 11 | // No output = no changes 12 | return process.output.trim().length === 0; 13 | } catch { 14 | return false; 15 | } 16 | }; 17 | -------------------------------------------------------------------------------- /website/theme/styles.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: "Alliance No. 2"; 3 | font-style: normal; 4 | font-weight: 400; 5 | font-display: block; 6 | src: url("./fonts/alliance-no-2-regular.ttf") format("truetype"); 7 | } 8 | 9 | @font-face { 10 | font-family: "Alliance No. 2"; 11 | font-style: normal; 12 | font-weight: 500; 13 | font-display: block; 14 | src: url("./fonts/alliance-no-2-medium.ttf") format("truetype"); 15 | } 16 | -------------------------------------------------------------------------------- /packages/vite-plugin/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "baseUrl": ".", 5 | "rootDir": "src", 6 | "outDir": "dist", 7 | "tsBuildInfoFile": "dist/tsconfig.lib.tsbuildinfo", 8 | "emitDeclarationOnly": true, 9 | "forceConsistentCasingInFileNames": true, 10 | "types": ["node", "vite/client"] 11 | }, 12 | "include": ["src/**/*.ts"], 13 | "references": [] 14 | } 15 | -------------------------------------------------------------------------------- /packages/plugin-bridge/src/channel/device/cdp-types.d.ts: -------------------------------------------------------------------------------- 1 | declare global { 2 | var __FUSEBOX_REACT_DEVTOOLS_DISPATCHER__: { 3 | BINDING_NAME: string; 4 | initializeDomain: (domainName: string) => CdpDomain; 5 | onDomainInitialization: { 6 | addEventListener: (listener: (domain: CdpDomain) => void) => void; 7 | removeEventListener: (listener: (domain: CdpDomain) => void) => void; 8 | }; 9 | }; 10 | } 11 | 12 | export {}; 13 | -------------------------------------------------------------------------------- /packages/tools/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "baseUrl": ".", 5 | "rootDir": "src", 6 | "outDir": "dist", 7 | "tsBuildInfoFile": "dist/tsconfig.lib.tsbuildinfo", 8 | "emitDeclarationOnly": true, 9 | "forceConsistentCasingInFileNames": true, 10 | "types": ["node", "vite/client"], 11 | "resolveJsonModule": true 12 | }, 13 | "include": ["src/**/*.ts"] 14 | } 15 | -------------------------------------------------------------------------------- /apps/playground/android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 10 | 11 | -------------------------------------------------------------------------------- /packages/network-activity-plugin/src/ui/utils/escapeShellArg.ts: -------------------------------------------------------------------------------- 1 | // Escapes special characters in shell arguments 2 | export function escapeShellArg(arg: string): string { 3 | if (!arg) return "''"; 4 | 5 | // If the argument contains no special characters, return as is 6 | if (/^[a-zA-Z0-9_./:-]+$/.test(arg)) { 7 | return arg; 8 | } 9 | 10 | // Replace single quotes with '\'' and wrap in single quotes 11 | return `'${arg.replace(/'/g, "'\"'\"'")}'`; 12 | } 13 | -------------------------------------------------------------------------------- /website/src/public/github.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /website/src/public/sliders-2.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /packages/cli/src/utils/steps.ts: -------------------------------------------------------------------------------- 1 | import { spinner } from './prompts.js'; 2 | 3 | export type StepOptions = { 4 | start: string; 5 | stop: string; 6 | error: string; 7 | }; 8 | 9 | export const step = async ( 10 | { start, stop, error }: StepOptions, 11 | fn: () => Promise 12 | ) => { 13 | const step = spinner(); 14 | step.start(start); 15 | 16 | try { 17 | await fn(); 18 | step.stop(stop); 19 | } catch (err) { 20 | step.stop(error, 1); 21 | throw err; 22 | } 23 | }; 24 | -------------------------------------------------------------------------------- /packages/require-profiler-plugin/src/ui/components/index.ts: -------------------------------------------------------------------------------- 1 | export { Header, type HeaderProps } from './Header'; 2 | export { InfoBar, type InfoBarProps } from './InfoBar'; 3 | export { Legend } from './Legend'; 4 | export { LoadingState } from './LoadingState'; 5 | export { EmptyState, type EmptyStateProps } from './EmptyState'; 6 | export { Sidebar, type SidebarProps } from './Sidebar'; 7 | export { 8 | OptionsModal, 9 | type OptionsModalProps, 10 | type ProfilerOptions, 11 | } from './OptionsModal'; 12 | -------------------------------------------------------------------------------- /website/plugins/plugin-directory/types.ts: -------------------------------------------------------------------------------- 1 | export type PluginDirectoryReference = { 2 | npmUrl: string; 3 | githubUrl: string; 4 | }; 5 | 6 | export type RozenitePluginEntry = { 7 | packageName: string; 8 | version: string; 9 | githubUrl: string; 10 | npmUrl: string; 11 | description?: string; 12 | stars: number; 13 | isOfficial: boolean; 14 | }; 15 | 16 | export type PluginDirectoryPage = { 17 | pageNumber: number; 18 | totalPages: number; 19 | data: RozenitePluginEntry[]; 20 | }; 21 | -------------------------------------------------------------------------------- /apps/playground/android/app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /usr/local/Cellar/android-sdk/24.3.3/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | -------------------------------------------------------------------------------- /packages/vite-plugin/src/package-json.ts: -------------------------------------------------------------------------------- 1 | import path from 'node:path'; 2 | import fs from 'node:fs/promises'; 3 | 4 | export type PackageJSON = { 5 | name: string; 6 | description: string; 7 | version: string; 8 | }; 9 | 10 | export const getPackageJSON = async ( 11 | projectRoot: string 12 | ): Promise => { 13 | const packageJSONPath = path.join(projectRoot, 'package.json'); 14 | const packageJSON = await fs.readFile(packageJSONPath, 'utf8'); 15 | return JSON.parse(packageJSON); 16 | }; 17 | -------------------------------------------------------------------------------- /packages/cli/template/vite.config.ts: -------------------------------------------------------------------------------- 1 | /// 2 | import { defineConfig } from 'vite'; 3 | import { rozenitePlugin } from '@rozenite/vite-plugin'; 4 | 5 | export default defineConfig({ 6 | root: __dirname, 7 | plugins: [rozenitePlugin()], 8 | base: './', 9 | build: { 10 | outDir: './dist', 11 | emptyOutDir: false, 12 | reportCompressedSize: false, 13 | minify: true, 14 | sourcemap: false, 15 | }, 16 | server: { 17 | port: 3000, 18 | open: true, 19 | }, 20 | }); 21 | -------------------------------------------------------------------------------- /packages/mmkv-plugin/vite.config.ts: -------------------------------------------------------------------------------- 1 | /// 2 | import { defineConfig } from 'vite'; 3 | import { rozenitePlugin } from '@rozenite/vite-plugin'; 4 | 5 | export default defineConfig({ 6 | root: __dirname, 7 | plugins: [rozenitePlugin()], 8 | base: './', 9 | build: { 10 | outDir: './dist', 11 | emptyOutDir: false, 12 | reportCompressedSize: false, 13 | minify: true, 14 | sourcemap: false, 15 | }, 16 | server: { 17 | port: 3000, 18 | open: true, 19 | }, 20 | }); 21 | -------------------------------------------------------------------------------- /packages/cli/src/commands/generate/install-packages.ts: -------------------------------------------------------------------------------- 1 | import { step } from '../../utils/steps.js'; 2 | import { installDependencies } from '../../utils/packages.js'; 3 | 4 | export const installPackages = async (projectRoot: string): Promise => { 5 | await step( 6 | { 7 | start: 'Installing packages', 8 | stop: 'Packages installed successfully', 9 | error: 'Failed to install packages', 10 | }, 11 | async () => { 12 | await installDependencies(projectRoot); 13 | } 14 | ); 15 | }; 16 | -------------------------------------------------------------------------------- /packages/expo-atlas-plugin/vite.config.ts: -------------------------------------------------------------------------------- 1 | /// 2 | import { defineConfig } from 'vite'; 3 | import { rozenitePlugin } from '@rozenite/vite-plugin'; 4 | 5 | export default defineConfig({ 6 | root: __dirname, 7 | plugins: [rozenitePlugin()], 8 | base: './', 9 | build: { 10 | outDir: './dist', 11 | emptyOutDir: false, 12 | reportCompressedSize: false, 13 | minify: true, 14 | sourcemap: false, 15 | }, 16 | server: { 17 | port: 3000, 18 | open: true, 19 | }, 20 | }); 21 | -------------------------------------------------------------------------------- /packages/cli/src/commands/generate/create-directory.ts: -------------------------------------------------------------------------------- 1 | import fs from 'node:fs/promises'; 2 | import { step } from '../../utils/steps.js'; 3 | 4 | export const createProjectDirectory = async ( 5 | projectRoot: string 6 | ): Promise => { 7 | await step( 8 | { 9 | start: 'Creating plugin directory', 10 | stop: 'Plugin directory created', 11 | error: 'Failed to create plugin directory', 12 | }, 13 | async () => { 14 | await fs.mkdir(projectRoot, { recursive: true }); 15 | } 16 | ); 17 | }; 18 | -------------------------------------------------------------------------------- /packages/redux-devtools-plugin/vite.config.ts: -------------------------------------------------------------------------------- 1 | /// 2 | import { defineConfig } from 'vite'; 3 | import { rozenitePlugin } from '@rozenite/vite-plugin'; 4 | 5 | export default defineConfig({ 6 | root: __dirname, 7 | plugins: [rozenitePlugin()], 8 | base: './', 9 | build: { 10 | outDir: './dist', 11 | emptyOutDir: false, 12 | reportCompressedSize: false, 13 | minify: false, 14 | sourcemap: false, 15 | }, 16 | server: { 17 | port: 3000, 18 | open: true, 19 | }, 20 | }); 21 | -------------------------------------------------------------------------------- /packages/tanstack-query-plugin/vite.config.ts: -------------------------------------------------------------------------------- 1 | /// 2 | import { defineConfig } from 'vite'; 3 | import { rozenitePlugin } from '@rozenite/vite-plugin'; 4 | 5 | export default defineConfig({ 6 | root: __dirname, 7 | plugins: [rozenitePlugin()], 8 | base: './', 9 | build: { 10 | outDir: './dist', 11 | emptyOutDir: false, 12 | reportCompressedSize: false, 13 | minify: true, 14 | sourcemap: false, 15 | }, 16 | server: { 17 | port: 3000, 18 | open: true, 19 | }, 20 | }); 21 | -------------------------------------------------------------------------------- /packages/mmkv-plugin/react-native.ts: -------------------------------------------------------------------------------- 1 | export let useMMKVDevTools: typeof import('./src/react-native/useMMKVDevTools').useMMKVDevTools; 2 | 3 | const isWeb = 4 | typeof window !== 'undefined' && window.navigator.product !== 'ReactNative'; 5 | const isDev = process.env.NODE_ENV !== 'production'; 6 | const isServer = typeof window === 'undefined'; 7 | 8 | if (isDev && !isWeb && !isServer) { 9 | useMMKVDevTools = 10 | require('./src/react-native/useMMKVDevTools').useMMKVDevTools; 11 | } else { 12 | useMMKVDevTools = () => null; 13 | } 14 | -------------------------------------------------------------------------------- /packages/performance-monitor-plugin/vite.config.ts: -------------------------------------------------------------------------------- 1 | /// 2 | import { defineConfig } from 'vite'; 3 | import { rozenitePlugin } from '@rozenite/vite-plugin'; 4 | 5 | export default defineConfig({ 6 | root: __dirname, 7 | plugins: [rozenitePlugin()], 8 | base: './', 9 | build: { 10 | outDir: './dist', 11 | emptyOutDir: false, 12 | reportCompressedSize: false, 13 | minify: true, 14 | sourcemap: false, 15 | }, 16 | server: { 17 | port: 3000, 18 | open: true, 19 | }, 20 | }); 21 | -------------------------------------------------------------------------------- /packages/plugin-bridge/src/message.ts: -------------------------------------------------------------------------------- 1 | export type DevToolsPluginMessage = { 2 | pluginId: string; 3 | type: string; 4 | payload: unknown; 5 | }; 6 | 7 | export const getDevToolsMessage = ( 8 | message: unknown 9 | ): DevToolsPluginMessage | null => { 10 | if ( 11 | typeof message !== 'object' || 12 | message === null || 13 | !('type' in message) || 14 | !('payload' in message) || 15 | !('pluginId' in message) 16 | ) { 17 | return null; 18 | } 19 | 20 | return message as DevToolsPluginMessage; 21 | }; 22 | -------------------------------------------------------------------------------- /apps/playground/README.md: -------------------------------------------------------------------------------- 1 | # Playground 2 | 3 | This app uses React Native Community CLI, so make sure you have your [environment setup to build native apps](https://reactnative.dev/docs/environment-setup). 4 | 5 | You can then use Xcode/Android Studio/Gradle to build applications, or run `pnpm nx start playground` and `pnpm nx run-ios playground`/`pnpm nx run-android playground` to start the development server and run applications in development mode. 6 | 7 | You can also start the development server from the root workspace by executing `pnpm start:playground`. -------------------------------------------------------------------------------- /packages/cli/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "baseUrl": ".", 5 | "rootDir": "src", 6 | "outDir": "dist", 7 | "tsBuildInfoFile": "dist/tsconfig.lib.tsbuildinfo", 8 | "emitDeclarationOnly": true, 9 | "forceConsistentCasingInFileNames": true, 10 | "types": ["node", "vite/client"], 11 | "resolveJsonModule": true 12 | }, 13 | "include": ["src/**/*.ts"], 14 | "references": [ 15 | { 16 | "path": "../tools/tsconfig.lib.json" 17 | } 18 | ] 19 | } 20 | -------------------------------------------------------------------------------- /apps/playground/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | RnDevtoolsPlayground 6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /packages/network-activity-plugin/src/utils/getHttpHeader.ts: -------------------------------------------------------------------------------- 1 | import { HttpHeaders, XHRHeaders } from '../shared/client'; 2 | 3 | // Utility to get header value and actual key case-insensitively 4 | export function getHttpHeader( 5 | headers: T, 6 | name: string 7 | ) { 8 | const lowerName = name.toLowerCase(); 9 | 10 | for (const key in headers) { 11 | if (key.toLowerCase() === lowerName) { 12 | return { value: headers[key], originalKey: key }; 13 | } 14 | } 15 | 16 | return undefined; 17 | } 18 | -------------------------------------------------------------------------------- /packages/react-navigation-plugin/react-native.ts: -------------------------------------------------------------------------------- 1 | export let useReactNavigationDevTools: typeof import('./src/react-native').useReactNavigationDevTools; 2 | 3 | const isWeb = 4 | typeof window !== 'undefined' && window.navigator.product !== 'ReactNative'; 5 | const isDev = process.env.NODE_ENV !== 'production'; 6 | const isServer = typeof window === 'undefined'; 7 | 8 | if (isDev && !isWeb && !isServer) { 9 | useReactNavigationDevTools = 10 | require('./src/react-native').useReactNavigationDevTools; 11 | } else { 12 | useReactNavigationDevTools = () => null; 13 | } 14 | -------------------------------------------------------------------------------- /packages/runtime/eslint.config.mjs: -------------------------------------------------------------------------------- 1 | import baseConfig from '../../eslint.config.mjs'; 2 | 3 | export default [ 4 | ...baseConfig, 5 | { 6 | files: ['**/*.json'], 7 | rules: { 8 | '@nx/dependency-checks': [ 9 | 'error', 10 | { 11 | ignoredDependencies: ['tslib'], 12 | ignoredFiles: ['{projectRoot}/eslint.config.{js,cjs,mjs,ts,cts,mts}', '{projectRoot}/vite.config.ts'], 13 | }, 14 | ], 15 | }, 16 | languageOptions: { 17 | parser: await import('jsonc-eslint-parser'), 18 | }, 19 | }, 20 | ]; 21 | -------------------------------------------------------------------------------- /packages/plugin-bridge/eslint.config.mjs: -------------------------------------------------------------------------------- 1 | import baseConfig from '../../eslint.config.mjs'; 2 | 3 | export default [ 4 | ...baseConfig, 5 | { 6 | files: ['**/*.json'], 7 | rules: { 8 | '@nx/dependency-checks': [ 9 | 'error', 10 | { 11 | ignoredDependencies: ['tslib'], 12 | ignoredFiles: ['{projectRoot}/eslint.config.{js,cjs,mjs,ts,cts,mts}', '{projectRoot}/vite.config.ts'], 13 | }, 14 | ], 15 | }, 16 | languageOptions: { 17 | parser: await import('jsonc-eslint-parser'), 18 | }, 19 | }, 20 | ]; 21 | -------------------------------------------------------------------------------- /website/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2020", 4 | "lib": ["DOM", "ES2020"], 5 | "module": "ESNext", 6 | "jsx": "react-jsx", 7 | "noEmit": true, 8 | "strict": true, 9 | "skipLibCheck": true, 10 | "isolatedModules": true, 11 | "resolveJsonModule": true, 12 | "moduleResolution": "bundler", 13 | "useDefineForClassFields": true, 14 | "allowImportingTsExtensions": true 15 | }, 16 | "include": ["src", "plugins", "docs", "theme", "rspress.config.ts"], 17 | "mdx": { 18 | "checkMdx": true 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /packages/tanstack-query-plugin/tsconfig.tsbuildinfo: -------------------------------------------------------------------------------- 1 | {"root":["./src/react-native/usehandledevtoolsmessages.ts","./src/react-native/usehandleinitialdata.ts","./src/react-native/usesynctanstackcache.ts","./src/react-native/usetanstackquerydevtools.ts","./src/shared/dehydrate.ts","./src/shared/hydrate.ts","./src/shared/messaging.ts","./src/shared/types.ts","./src/shared/usesynconlinestatus.ts","./src/ui/tanstack-query.tsx","./src/ui/usehandlesyncmessages.ts","./src/ui/usesyncdevtoolsevents.ts","./src/ui/usesyncinitialdata.ts","./react-native.ts","./rozenite.config.ts"],"errors":true,"version":"5.8.3"} -------------------------------------------------------------------------------- /apps/playground/.babelrc.js: -------------------------------------------------------------------------------- 1 | module.exports = function (api) { 2 | api.cache(true); 3 | 4 | if ( 5 | process.env.NX_TASK_TARGET_TARGET === 'build' || 6 | process.env.NX_TASK_TARGET_TARGET?.includes('storybook') 7 | ) { 8 | return { 9 | presets: [ 10 | [ 11 | '@nx/react/babel', 12 | { 13 | runtime: 'automatic', 14 | }, 15 | ], 16 | ], 17 | }; 18 | } 19 | 20 | return { 21 | presets: [ 22 | ['module:@react-native/babel-preset', { useTransformReactJSX: true }], 23 | ], 24 | }; 25 | }; 26 | -------------------------------------------------------------------------------- /packages/performance-monitor-plugin/tsconfig.tsbuildinfo: -------------------------------------------------------------------------------- 1 | {"root":["./src/react-native/usehandledevtoolsmessages.ts","./src/react-native/usehandleinitialdata.ts","./src/react-native/usesynctanstackcache.ts","./src/react-native/usetanstackquerydevtools.ts","./src/shared/dehydrate.ts","./src/shared/hydrate.ts","./src/shared/messaging.ts","./src/shared/types.ts","./src/shared/usesynconlinestatus.ts","./src/ui/tanstack-query.tsx","./src/ui/usehandlesyncmessages.ts","./src/ui/usesyncdevtoolsevents.ts","./src/ui/usesyncinitialdata.ts","./react-native.ts","./rozenite.config.ts"],"errors":true,"version":"5.8.3"} -------------------------------------------------------------------------------- /packages/tools/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@rozenite/tools", 3 | "version": "1.1.0", 4 | "description": "Tools for Rozenite.", 5 | "type": "module", 6 | "main": "./dist/index.cjs", 7 | "module": "./dist/index.js", 8 | "types": "./dist/index.d.ts", 9 | "exports": { 10 | ".": { 11 | "types": "./dist/index.d.ts", 12 | "import": "./dist/index.js", 13 | "require": "./dist/index.cjs" 14 | } 15 | }, 16 | "devDependencies": { 17 | "metro-config": "*", 18 | "typescript": "^5.7.3", 19 | "vite": "^6.0.0" 20 | }, 21 | "license": "MIT" 22 | } 23 | -------------------------------------------------------------------------------- /website/src/docs/_meta.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "type": "file", 4 | "name": "introduction", 5 | "label": "Introduction" 6 | }, 7 | { 8 | "type": "file", 9 | "name": "prior-art", 10 | "label": "Prior Art" 11 | }, 12 | { 13 | "type": "file", 14 | "name": "getting-started", 15 | "label": "Getting started" 16 | }, 17 | { 18 | "type": "dir", 19 | "name": "plugin-development", 20 | "label": "Plugin Development" 21 | }, 22 | { 23 | "type": "dir", 24 | "name": "official-plugins", 25 | "label": "Official Plugins" 26 | } 27 | ] 28 | -------------------------------------------------------------------------------- /packages/cli/template/react-native.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * React Native DevTools Plugin Entry Point 3 | * 4 | * This file serves as the main entry point for your DevTools plugin in the React Native environment. 5 | * You have full access to all React Native APIs and can integrate with your app's functionality. 6 | * 7 | * To communicate with the DevTools panel, use the `@rozenite/plugin-bridge` package 8 | * which provides a reliable communication channel between your plugin and the DevTools interface. 9 | */ 10 | 11 | export const useDevTools = () => { 12 | // TODO: Implement your plugin! 13 | }; 14 | -------------------------------------------------------------------------------- /packages/redux-devtools-plugin/tsconfig.tsbuildinfo: -------------------------------------------------------------------------------- 1 | {"root":["./src/css-modules.d.ts","./src/react-native/network-inspector.ts","./src/react-native/network-requests-registry.ts","./src/react-native/usenetworkactivitydevtools.ts","./src/react-native/xhr-interceptor.ts","./src/react-native/xml-request.d.ts","./src/types/client.ts","./src/types/network.ts","./src/ui/components.tsx","./src/ui/network-details.tsx","./src/ui/network-list.tsx","./src/ui/network-toolbar.tsx","./src/ui/panel.tsx","./src/ui/tanstack-query.tsx","./src/ui/utils.ts","./react-native.ts","./rozenite.config.ts"],"errors":true,"version":"5.8.3"} -------------------------------------------------------------------------------- /packages/vite-plugin/eslint.config.mjs: -------------------------------------------------------------------------------- 1 | import baseConfig from '../../eslint.config.mjs'; 2 | 3 | export default [ 4 | ...baseConfig, 5 | { 6 | files: ['**/*.json'], 7 | rules: { 8 | '@nx/dependency-checks': [ 9 | 'error', 10 | { 11 | ignoredFiles: [ 12 | '{projectRoot}/eslint.config.{js,cjs,mjs,ts,cts,mts}', 13 | '{projectRoot}/vite.config.{js,ts,mjs,mts}', 14 | ], 15 | }, 16 | ], 17 | }, 18 | languageOptions: { 19 | parser: await import('jsonc-eslint-parser'), 20 | }, 21 | }, 22 | ]; 23 | -------------------------------------------------------------------------------- /packages/network-activity-plugin/tsconfig.tsbuildinfo: -------------------------------------------------------------------------------- 1 | {"root":["./src/css-modules.d.ts","./src/react-native/network-inspector.ts","./src/react-native/network-requests-registry.ts","./src/react-native/usenetworkactivitydevtools.ts","./src/react-native/xhr-interceptor.ts","./src/react-native/xml-request.d.ts","./src/types/client.ts","./src/types/network.ts","./src/ui/components.tsx","./src/ui/network-details.tsx","./src/ui/network-list.tsx","./src/ui/network-toolbar.tsx","./src/ui/panel.tsx","./src/ui/tanstack-query.tsx","./src/ui/utils.ts","./react-native.ts","./rozenite.config.ts"],"errors":true,"version":"5.8.3"} -------------------------------------------------------------------------------- /packages/react-navigation-plugin/tsconfig.tsbuildinfo: -------------------------------------------------------------------------------- 1 | {"root":["./src/css-modules.d.ts","./src/react-native/network-inspector.ts","./src/react-native/network-requests-registry.ts","./src/react-native/usenetworkactivitydevtools.ts","./src/react-native/xhr-interceptor.ts","./src/react-native/xml-request.d.ts","./src/types/client.ts","./src/types/network.ts","./src/ui/components.tsx","./src/ui/network-details.tsx","./src/ui/network-list.tsx","./src/ui/network-toolbar.tsx","./src/ui/panel.tsx","./src/ui/tanstack-query.tsx","./src/ui/utils.ts","./react-native.ts","./rozenite.config.ts"],"errors":true,"version":"5.8.3"} -------------------------------------------------------------------------------- /pnpm-workspace.yaml: -------------------------------------------------------------------------------- 1 | packages: 2 | - packages/* 3 | - libs/* 4 | - apps/* 5 | - website 6 | 7 | catalog: {} 8 | 9 | catalogs: {} 10 | 11 | onlyBuiltDependencies: 12 | - '@apollo/protobufjs' 13 | - '@swc/core' 14 | - core-js 15 | - electron 16 | - esbuild 17 | - nx 18 | - react-native-mmkv 19 | - react-native-nitro-modules 20 | - sqlite3 21 | 22 | overrides: {} 23 | 24 | patchedDependencies: {} 25 | 26 | autoInstallPeers: false 27 | publicHoistPattern: 28 | - '@react-native/*' 29 | - '@react-native-community/*' 30 | - react-native 31 | strictPeerDependencies: false 32 | -------------------------------------------------------------------------------- /apps/playground/ios/.xcode.env: -------------------------------------------------------------------------------- 1 | # This `.xcode.env` file is versioned and is used to source the environment 2 | # used when running script phases inside Xcode. 3 | # To customize your local environment, you can create an `.xcode.env.local` 4 | # file that is not versioned. 5 | 6 | # NODE_BINARY variable contains the PATH to the node executable. 7 | # 8 | # Customize the NODE_BINARY variable here. 9 | # For example, to use nvm with brew, add the following line 10 | # . "$(brew --prefix nvm)/nvm.sh" --no-use 11 | export NODE_BINARY=$(command -v node) 12 | export ENTRY_FILE="${PROJECT_DIR}/../src/main.tsx" 13 | -------------------------------------------------------------------------------- /packages/middleware/src/dev-mode.ts: -------------------------------------------------------------------------------- 1 | import path from 'node:path'; 2 | import { createRequire } from 'node:module'; 3 | 4 | const require = createRequire(import.meta.url); 5 | 6 | export const getDevModePackage = ( 7 | projectRoot: string 8 | ): { name: string; path: string } | null => { 9 | const packageName = process.env.ROZENITE_DEV_MODE; 10 | 11 | if (!packageName) { 12 | return null; 13 | } 14 | 15 | const packagePath = path.dirname( 16 | require.resolve(packageName, { paths: [projectRoot] }) 17 | ); 18 | 19 | return { 20 | name: packageName, 21 | path: packagePath, 22 | }; 23 | }; 24 | -------------------------------------------------------------------------------- /packages/repack/eslint.config.mjs: -------------------------------------------------------------------------------- 1 | import baseConfig from '../../eslint.config.mjs'; 2 | 3 | export default [ 4 | ...baseConfig, 5 | { 6 | files: ['**/*.json'], 7 | rules: { 8 | '@nx/dependency-checks': [ 9 | 'error', 10 | { 11 | ignoredDependencies: ['tslib'], 12 | ignoredFiles: [ 13 | '{projectRoot}/eslint.config.{js,cjs,mjs,ts,cts,mts}', 14 | '{projectRoot}/vite.config.ts', 15 | ], 16 | }, 17 | ], 18 | }, 19 | languageOptions: { 20 | parser: await import('jsonc-eslint-parser'), 21 | }, 22 | }, 23 | ]; 24 | -------------------------------------------------------------------------------- /tsconfig.base.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "declarationMap": true, 5 | "emitDeclarationOnly": true, 6 | "importHelpers": true, 7 | "isolatedModules": true, 8 | "lib": ["es2022"], 9 | "module": "nodenext", 10 | "moduleResolution": "nodenext", 11 | "noEmitOnError": true, 12 | "noFallthroughCasesInSwitch": true, 13 | "noImplicitOverride": true, 14 | "noImplicitReturns": true, 15 | "noUnusedLocals": true, 16 | "skipLibCheck": true, 17 | "strict": true, 18 | "target": "es2022", 19 | "customConditions": ["development"] 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /website/plugins/plugin-directory/repository/types.ts: -------------------------------------------------------------------------------- 1 | import { PluginDirectoryReference, RozenitePluginEntry } from '../types'; 2 | 3 | export interface PluginRepository { 4 | getPlugin(packageName: string): Promise; 5 | getPlugins(packageNames: string[]): Promise; 6 | refreshPlugin(plugin: PluginDirectoryReference): Promise; 7 | getPluginWithFallback( 8 | plugin: PluginDirectoryReference 9 | ): Promise; 10 | getExpiredPlugins(packageNames: string[]): Promise; 11 | cleanupExpired(): Promise; 12 | } 13 | -------------------------------------------------------------------------------- /website/src/public/repeat.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /packages/metro/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "baseUrl": ".", 5 | "rootDir": "src", 6 | "outDir": "dist", 7 | "tsBuildInfoFile": "dist/tsconfig.lib.tsbuildinfo", 8 | "emitDeclarationOnly": true, 9 | "forceConsistentCasingInFileNames": true, 10 | "types": ["node", "vite/client"], 11 | "esModuleInterop": true 12 | }, 13 | "include": ["src/**/*.ts"], 14 | "references": [ 15 | { 16 | "path": "../tools/tsconfig.lib.json" 17 | }, 18 | { 19 | "path": "../middleware/tsconfig.lib.json" 20 | } 21 | ] 22 | } 23 | -------------------------------------------------------------------------------- /packages/middleware/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "baseUrl": ".", 5 | "rootDir": "src", 6 | "outDir": "dist", 7 | "tsBuildInfoFile": "dist/tsconfig.lib.tsbuildinfo", 8 | "emitDeclarationOnly": true, 9 | "forceConsistentCasingInFileNames": true, 10 | "types": ["node", "vite/client"], 11 | "esModuleInterop": true 12 | }, 13 | "include": ["src/**/*.ts"], 14 | "references": [ 15 | { 16 | "path": "../tools/tsconfig.lib.json" 17 | }, 18 | { 19 | "path": "../runtime/tsconfig.lib.json" 20 | } 21 | ] 22 | } 23 | -------------------------------------------------------------------------------- /packages/network-activity-plugin/react-native.ts: -------------------------------------------------------------------------------- 1 | export let useNetworkActivityDevTools: typeof import('./src/react-native/useNetworkActivityDevTools').useNetworkActivityDevTools; 2 | 3 | const isWeb = 4 | typeof window !== 'undefined' && window.navigator.product !== 'ReactNative'; 5 | const isDev = process.env.NODE_ENV !== 'production'; 6 | const isServer = typeof window === 'undefined'; 7 | 8 | if (isDev && !isWeb && !isServer) { 9 | useNetworkActivityDevTools = 10 | require('./src/react-native/useNetworkActivityDevTools').useNetworkActivityDevTools; 11 | } else { 12 | useNetworkActivityDevTools = () => null; 13 | } 14 | -------------------------------------------------------------------------------- /packages/network-activity-plugin/src/utils/getContentTypeMimeType.ts: -------------------------------------------------------------------------------- 1 | import { HttpHeaders } from '../shared/client'; 2 | import { getHttpHeader } from './getHttpHeader'; 3 | 4 | export function getContentTypeMime(headers: HttpHeaders) { 5 | const contentType = getHttpHeader(headers, 'content-type'); 6 | 7 | if (!contentType) { 8 | return undefined; 9 | } 10 | 11 | const { value } = contentType; 12 | 13 | // Content-Type can't be an array, but if it does we simply get the first element. 14 | const actualValue = Array.isArray(value) ? value[0] : value; 15 | 16 | return actualValue.split(';')[0].trim(); 17 | } 18 | -------------------------------------------------------------------------------- /packages/repack/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "baseUrl": ".", 5 | "rootDir": "src", 6 | "outDir": "dist", 7 | "tsBuildInfoFile": "dist/tsconfig.lib.tsbuildinfo", 8 | "emitDeclarationOnly": true, 9 | "forceConsistentCasingInFileNames": true, 10 | "types": ["node", "vite/client"], 11 | "esModuleInterop": true 12 | }, 13 | "include": ["src/**/*.ts"], 14 | "references": [ 15 | { 16 | "path": "../tools/tsconfig.lib.json" 17 | }, 18 | { 19 | "path": "../middleware/tsconfig.lib.json" 20 | } 21 | ] 22 | } 23 | -------------------------------------------------------------------------------- /packages/require-profiler-plugin/react-native.ts: -------------------------------------------------------------------------------- 1 | export let useRequireProfilerDevTools: typeof import('./src/react-native/useRequireProfilerDevTools').useRequireProfilerDevTools; 2 | 3 | const isWeb = 4 | typeof window !== 'undefined' && window.navigator.product !== 'ReactNative'; 5 | const isDev = process.env.NODE_ENV !== 'production'; 6 | const isServer = typeof window === 'undefined'; 7 | 8 | if (isDev && !isWeb && !isServer) { 9 | useRequireProfilerDevTools = 10 | require('./src/react-native/useRequireProfilerDevTools').useRequireProfilerDevTools; 11 | } else { 12 | useRequireProfilerDevTools = () => null; 13 | } 14 | -------------------------------------------------------------------------------- /packages/network-activity-plugin/src/ui/components/CodeBlock.tsx: -------------------------------------------------------------------------------- 1 | import { HTMLProps } from 'react'; 2 | import { cn } from '../utils/cn'; 3 | 4 | export type CodeBlockProps = HTMLProps; 5 | 6 | const codeBlockClassNames = 7 | 'text-sm font-mono text-gray-300 whitespace-pre-wrap bg-gray-800 p-3 rounded-md border border-gray-700 overflow-x-auto wrap-anywhere'; 8 | 9 | export const CodeBlock = ({ 10 | children, 11 | className, 12 | ...props 13 | }: CodeBlockProps) => { 14 | return ( 15 |
16 |       {children}
17 |     
18 | ); 19 | }; 20 | -------------------------------------------------------------------------------- /packages/tanstack-query-plugin/react-native.ts: -------------------------------------------------------------------------------- 1 | export let useTanStackQueryDevTools: typeof import('./src/react-native/useTanStackQueryDevTools').useTanStackQueryDevTools; 2 | 3 | const isWeb = 4 | typeof window !== 'undefined' && window.navigator.product !== 'ReactNative'; 5 | const isDev = process.env.NODE_ENV !== 'production'; 6 | const isServer = typeof window === 'undefined'; 7 | 8 | if (isDev && !isWeb && !isServer) { 9 | useTanStackQueryDevTools = 10 | require('./src/react-native/useTanStackQueryDevTools').useTanStackQueryDevTools; 11 | } else { 12 | useTanStackQueryDevTools = () => ({ isConnected: false }); 13 | } 14 | -------------------------------------------------------------------------------- /packages/cli/vite.config.ts: -------------------------------------------------------------------------------- 1 | /// 2 | import { defineConfig } from 'vite'; 3 | 4 | export default defineConfig(() => ({ 5 | root: __dirname, 6 | cacheDir: '../../node_modules/.vite/packages/cli', 7 | build: { 8 | outDir: './dist', 9 | emptyOutDir: true, 10 | reportCompressedSize: true, 11 | commonjsOptions: { 12 | transformMixedEsModules: true, 13 | }, 14 | ssr: true, 15 | lib: { 16 | entry: 'src/index.ts', 17 | fileName: 'index', 18 | formats: ['es' as const], 19 | }, 20 | rollupOptions: { 21 | external: [], 22 | }, 23 | }, 24 | })); 25 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.base.json", 3 | "compileOnSave": false, 4 | "files": [], 5 | "references": [ 6 | { 7 | "path": "./apps/playground" 8 | }, 9 | { 10 | "path": "./packages/vite-plugin" 11 | }, 12 | { 13 | "path": "./packages/plugin-bridge" 14 | }, 15 | { 16 | "path": "./packages/cli" 17 | }, 18 | { 19 | "path": "./packages/runtime" 20 | }, 21 | { 22 | "path": "./packages/metro" 23 | }, 24 | { 25 | "path": "./packages/middleware" 26 | }, 27 | { 28 | "path": "./packages/repack" 29 | } 30 | ] 31 | } 32 | -------------------------------------------------------------------------------- /packages/plugin-bridge/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "baseUrl": ".", 5 | "rootDir": "src", 6 | "outDir": "dist", 7 | "tsBuildInfoFile": "dist/tsconfig.lib.tsbuildinfo", 8 | "emitDeclarationOnly": true, 9 | "forceConsistentCasingInFileNames": true, 10 | "types": ["node", "vite/client"], 11 | "lib": ["dom"], 12 | "jsx": "react-jsx", 13 | "paths": { 14 | "/callstack/*": ["./src/host/host-api.d.ts"] 15 | }, 16 | "module": "esnext", 17 | "moduleResolution": "bundler" 18 | }, 19 | "include": ["src/**/*.ts", "src/**/*.tsx"] 20 | } 21 | -------------------------------------------------------------------------------- /packages/network-activity-plugin/src/ui/App.tsx: -------------------------------------------------------------------------------- 1 | import { useRozeniteDevToolsClient } from '@rozenite/plugin-bridge'; 2 | import { NetworkActivityEventMap } from '../shared/client'; 3 | 4 | import { InspectorView } from './views/InspectorView'; 5 | import { LoadingView } from './views/LoadingView'; 6 | 7 | import './globals.css'; 8 | 9 | export default function NetworkActivityPanel() { 10 | const client = useRozeniteDevToolsClient({ 11 | pluginId: '@rozenite/network-activity-plugin', 12 | }); 13 | 14 | if (!client) { 15 | return ; 16 | } 17 | 18 | return ; 19 | } 20 | -------------------------------------------------------------------------------- /packages/performance-monitor-plugin/src/ui/utils.ts: -------------------------------------------------------------------------------- 1 | export const downloadFile = async (data: unknown, filename: string) => { 2 | const json = JSON.stringify(data, null, 2); 3 | const blob = new Blob([json], { type: 'application/json' }); 4 | 5 | const url = URL.createObjectURL(blob); 6 | const link = document.createElement('a'); 7 | link.href = url; 8 | link.download = filename; 9 | document.body.appendChild(link); 10 | link.click(); 11 | document.body.removeChild(link); 12 | URL.revokeObjectURL(url); 13 | }; 14 | 15 | export const formatTime = (timestamp: number): string => { 16 | return new Date(timestamp).toLocaleTimeString(); 17 | }; 18 | -------------------------------------------------------------------------------- /packages/cli/eslint.config.mjs: -------------------------------------------------------------------------------- 1 | import baseConfig from '../../eslint.config.mjs'; 2 | 3 | export default [ 4 | ...baseConfig, 5 | { 6 | ignores: [ 7 | 'template/**/*', 8 | ], 9 | }, 10 | { 11 | files: ['**/*.json'], 12 | rules: { 13 | '@nx/dependency-checks': [ 14 | 'error', 15 | { 16 | ignoredFiles: [ 17 | '{projectRoot}/eslint.config.{js,cjs,mjs,ts,cts,mts}', 18 | '{projectRoot}/vite.config.{js,ts,mjs,mts}', 19 | ], 20 | }, 21 | ], 22 | }, 23 | languageOptions: { 24 | parser: await import('jsonc-eslint-parser'), 25 | }, 26 | }, 27 | ]; 28 | -------------------------------------------------------------------------------- /packages/runtime/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "baseUrl": ".", 5 | "rootDir": "src", 6 | "outDir": "dist", 7 | "tsBuildInfoFile": "dist/tsconfig.lib.tsbuildinfo", 8 | "emitDeclarationOnly": true, 9 | "forceConsistentCasingInFileNames": true, 10 | "types": ["node", "vite/client"], 11 | "lib": ["dom"], 12 | "jsx": "react-jsx", 13 | "paths": { 14 | "/rozenite/*": ["src/rn-devtools/rn-devtools-frontend-api.d.ts"] 15 | }, 16 | "module": "esnext", 17 | "moduleResolution": "bundler" 18 | }, 19 | "include": ["src/**/*.ts", "src/**/*.tsx"] 20 | } 21 | -------------------------------------------------------------------------------- /apps/playground/android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext { 3 | buildToolsVersion = "35.0.0" 4 | minSdkVersion = 24 5 | compileSdkVersion = 35 6 | targetSdkVersion = 34 7 | ndkVersion = "26.1.10909125" 8 | kotlinVersion = "1.9.24" 9 | } 10 | repositories { 11 | google() 12 | mavenCentral() 13 | } 14 | dependencies { 15 | classpath("com.android.tools.build:gradle") 16 | classpath("com.facebook.react:react-native-gradle-plugin") 17 | classpath("org.jetbrains.kotlin:kotlin-gradle-plugin") 18 | } 19 | } 20 | 21 | apply plugin: "com.facebook.react.rootproject" 22 | -------------------------------------------------------------------------------- /apps/playground/src/app/store.ts: -------------------------------------------------------------------------------- 1 | import 'react-native-get-random-values'; 2 | 3 | import { configureStore } from '@reduxjs/toolkit'; 4 | import counterReducer from './store/counterSlice'; 5 | import { rozeniteDevToolsEnhancer } from '@rozenite/redux-devtools-plugin'; 6 | 7 | export const store = configureStore({ 8 | reducer: { 9 | counter: counterReducer, 10 | }, 11 | enhancers: (getDefaultEnhancers) => 12 | getDefaultEnhancers().concat( 13 | rozeniteDevToolsEnhancer({ 14 | maxAge: 150 15 | }) 16 | ), 17 | }); 18 | 19 | export type RootState = ReturnType; 20 | export type AppDispatch = typeof store.dispatch; 21 | -------------------------------------------------------------------------------- /packages/require-profiler-plugin/src/ui/components/EmptyState.tsx: -------------------------------------------------------------------------------- 1 | export type EmptyStateProps = { 2 | message: string; 3 | }; 4 | 5 | export const EmptyState = ({ message }: EmptyStateProps) => { 6 | return ( 7 |
8 | 15 | 16 | 17 | 18 | 19 |

{message}

20 |
21 | ); 22 | }; 23 | -------------------------------------------------------------------------------- /packages/network-activity-plugin/src/ui/utils/generateMultipartBody.ts: -------------------------------------------------------------------------------- 1 | export const generateMultipartBody = (formData: Record) => { 2 | const boundary = 'FormBoundary' + Math.random().toString(36).substr(2, 16); 3 | 4 | const parts: string[] = []; 5 | 6 | Object.entries(formData).forEach(([key, value]) => { 7 | parts.push(`--${boundary}`); 8 | parts.push(`Content-Disposition: form-data; name="${key}"`); 9 | parts.push(''); 10 | parts.push(String(value)); 11 | }); 12 | 13 | parts.push(`--${boundary}--`); 14 | 15 | return { 16 | body: parts.join('\r\n'), 17 | contentType: `multipart/form-data; boundary=${boundary}`, 18 | }; 19 | }; 20 | -------------------------------------------------------------------------------- /packages/metro/src/packages.ts: -------------------------------------------------------------------------------- 1 | import { readFileSync } from 'node:fs'; 2 | import path from 'node:path'; 3 | 4 | export const getBinaryRelativePath = ( 5 | projectRoot: string, 6 | packageName: string 7 | ): string | null => { 8 | try { 9 | const packagePath = require.resolve(`${packageName}/package.json`, { 10 | paths: [projectRoot], 11 | }); 12 | const packageJson = JSON.parse(readFileSync(packagePath, 'utf8')); 13 | const binRelativePath = packageJson.bin?.[packageName]; 14 | 15 | if (!binRelativePath) { 16 | return null; 17 | } 18 | 19 | return path.join(packageName, binRelativePath); 20 | } catch { 21 | return null; 22 | } 23 | }; 24 | -------------------------------------------------------------------------------- /packages/network-activity-plugin/src/ui/utils/getStatusColor.ts: -------------------------------------------------------------------------------- 1 | export const getStatusColor = (status: number | string): string => { 2 | if (typeof status === 'string') { 3 | // Handle WebSocket statuses 4 | if (status === 'open') return 'text-green-400'; 5 | if (status === 'connecting') return 'text-yellow-400'; 6 | if (status === 'closed' || status === 'error') return 'text-red-400'; 7 | return 'text-gray-400'; 8 | } 9 | 10 | // Handle HTTP status codes 11 | if (status >= 200 && status < 300) return 'text-green-400'; 12 | if (status >= 300 && status < 400) return 'text-yellow-400'; 13 | if (status >= 400) return 'text-red-400'; 14 | return 'text-gray-400'; 15 | }; 16 | -------------------------------------------------------------------------------- /website/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@rozenite/docs", 3 | "version": "1.0.9", 4 | "private": true, 5 | "scripts": { 6 | "build": "rspress build", 7 | "dev": "rspress dev", 8 | "preview": "rspress preview" 9 | }, 10 | "dependencies": { 11 | "@neondatabase/serverless": "^1.0.1", 12 | "@callstack/rspress-preset": "^0.4.1", 13 | "@callstack/rspress-theme": "^0.4.1", 14 | "@rspress/core": "2.0.0-beta.32", 15 | "react": "19.1.1", 16 | "react-dom": "19.1.1" 17 | }, 18 | "devDependencies": { 19 | "@rspress/shared": "2.0.0-beta.32", 20 | "@types/node": "^18.11.17", 21 | "@types/react": "^19.1.8", 22 | "p-throttle": "^7.0.0" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /packages/cli/src/commands/generate/bootstrap-plugin.ts: -------------------------------------------------------------------------------- 1 | import type { PluginInfo } from '../../types.js'; 2 | import { step } from '../../utils/steps.js'; 3 | import { renderTemplate } from '../../utils/templates.js'; 4 | import { TEMPLATE_DIR } from '../../constants.js'; 5 | 6 | export const bootstrapPlugin = async ( 7 | projectRoot: string, 8 | pluginInfo: PluginInfo 9 | ): Promise => { 10 | await step( 11 | { 12 | start: 'Bootstrapping plugin', 13 | stop: 'Plugin bootstrapped successfully', 14 | error: 'Failed to bootstrap plugin', 15 | }, 16 | async () => { 17 | await renderTemplate(TEMPLATE_DIR, projectRoot, pluginInfo); 18 | } 19 | ); 20 | }; 21 | -------------------------------------------------------------------------------- /packages/network-activity-plugin/src/utils/getHttpHeaderValueAsString.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Combines multiple HTTP header values according to RFC 7230 Section 3.2.2 3 | * 4 | * Per RFC 7230 Section 3.2.2: "A recipient MAY combine multiple header fields 5 | * with the same field name into one 'field-name: field-value' pair, without 6 | * changing the semantics of the message, by appending each subsequent field 7 | * value to the combined field value in order, separated by a comma." 8 | * 9 | * @see https://tools.ietf.org/html/rfc7230#section-3.2.2 10 | */ 11 | export function getHttpHeaderValueAsString(value: string | string[]): string { 12 | return Array.isArray(value) ? value.join(', ') : value; 13 | } 14 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | ## Description 2 | 3 | 4 | 5 | ## Related Issue 6 | 7 | 8 | 9 | 10 | 11 | 12 | ## Context 13 | 14 | 15 | 16 | 17 | ## Testing 18 | 19 | 20 | -------------------------------------------------------------------------------- /packages/cli/src/commands/generate/git-init.ts: -------------------------------------------------------------------------------- 1 | import { step } from '../../utils/steps.js'; 2 | import { spawn } from '../../utils/spawn.js'; 3 | 4 | export const createGitRepository = async ( 5 | projectRoot: string 6 | ): Promise => { 7 | await step( 8 | { 9 | start: 'Initializing Git repository', 10 | stop: 'Git repository initialized successfully', 11 | error: 'Failed to initialize Git repository', 12 | }, 13 | async () => { 14 | await spawn('git', ['init'], { cwd: projectRoot }); 15 | await spawn('git', ['add', '.'], { cwd: projectRoot }); 16 | await spawn('git', ['commit', '-m', 'Initial commit'], { 17 | cwd: projectRoot, 18 | }); 19 | } 20 | ); 21 | }; 22 | -------------------------------------------------------------------------------- /packages/plugin-bridge/vite.config.ts: -------------------------------------------------------------------------------- 1 | /// 2 | import { defineConfig } from 'vite'; 3 | import { resolve } from 'path'; 4 | import dts from 'vite-plugin-dts'; 5 | 6 | export default defineConfig({ 7 | plugins: [ 8 | dts({ 9 | tsconfigPath: './tsconfig.lib.json', 10 | }), 11 | ], 12 | root: __dirname, 13 | cacheDir: '../../node_modules/.vite/communication', 14 | base: './', 15 | build: { 16 | lib: { 17 | entry: resolve(__dirname, 'src/index.ts'), 18 | fileName: 'index', 19 | formats: ['es', 'cjs'], 20 | }, 21 | rollupOptions: { 22 | external: ['react'], 23 | }, 24 | }, 25 | server: { 26 | port: 3000, 27 | open: true, 28 | }, 29 | }); 30 | -------------------------------------------------------------------------------- /packages/tools/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2020", 4 | "lib": ["ES2020", "DOM", "DOM.Iterable"], 5 | "allowJs": true, 6 | "skipLibCheck": true, 7 | "esModuleInterop": true, 8 | "allowSyntheticDefaultImports": true, 9 | "strict": true, 10 | "forceConsistentCasingInFileNames": true, 11 | "noFallthroughCasesInSwitch": true, 12 | "module": "ESNext", 13 | "moduleResolution": "bundler", 14 | "resolveJsonModule": true, 15 | "isolatedModules": true, 16 | "noEmit": true, 17 | "jsx": "react-jsx" 18 | }, 19 | "include": ["src/**/*", "react-native.ts", "rozenite.config.ts"], 20 | "exclude": ["node_modules", "dist", "build"], 21 | "references": [] 22 | } 23 | -------------------------------------------------------------------------------- /packages/vite-plugin/src/utils.ts: -------------------------------------------------------------------------------- 1 | import fs from 'node:fs'; 2 | import path from 'node:path'; 3 | 4 | export const resolveFileWithExtensions = ( 5 | directory: string, 6 | baseName: string 7 | ): string | null => { 8 | const extensions = ['.tsx', '.ts', '.jsx', '.js']; 9 | 10 | for (const ext of extensions) { 11 | const filePath = path.join(directory, baseName + ext); 12 | 13 | if (fs.existsSync(filePath)) { 14 | return filePath; 15 | } 16 | } 17 | 18 | return null; 19 | }; 20 | 21 | export const memo = (fn: () => T): (() => T) => { 22 | let result: T | null = null; 23 | 24 | return () => { 25 | if (result === null) { 26 | result = fn(); 27 | } 28 | 29 | return result; 30 | }; 31 | }; 32 | -------------------------------------------------------------------------------- /packages/cli/template/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2020", 4 | "lib": ["ES2020", "DOM", "DOM.Iterable"], 5 | "allowJs": true, 6 | "skipLibCheck": true, 7 | "esModuleInterop": true, 8 | "allowSyntheticDefaultImports": true, 9 | "strict": true, 10 | "forceConsistentCasingInFileNames": true, 11 | "noFallthroughCasesInSwitch": true, 12 | "module": "ESNext", 13 | "moduleResolution": "bundler", 14 | "resolveJsonModule": true, 15 | "isolatedModules": true, 16 | "noEmit": true, 17 | "jsx": "react-jsx" 18 | }, 19 | "include": [ 20 | "src/**/*", 21 | "react-native.ts", 22 | "rozenite.config.ts" 23 | ], 24 | "exclude": ["node_modules", "dist", "build"] 25 | } 26 | -------------------------------------------------------------------------------- /packages/metro/eslint.config.mjs: -------------------------------------------------------------------------------- 1 | import baseConfig from '../../eslint.config.mjs'; 2 | 3 | export default [ 4 | ...baseConfig, 5 | { 6 | files: ['**/*.json'], 7 | rules: { 8 | '@nx/dependency-checks': [ 9 | 'error', 10 | { 11 | ignoredDependencies: [ 12 | 'tslib', 13 | '@react-native/metro-config', 14 | 'react', 15 | 'react-native', 16 | ], 17 | ignoredFiles: [ 18 | '{projectRoot}/eslint.config.{js,cjs,mjs,ts,cts,mts}', 19 | '{projectRoot}/vite.config.ts', 20 | ], 21 | }, 22 | ], 23 | }, 24 | languageOptions: { 25 | parser: await import('jsonc-eslint-parser'), 26 | }, 27 | }, 28 | ]; 29 | -------------------------------------------------------------------------------- /packages/middleware/vite.config.ts: -------------------------------------------------------------------------------- 1 | /// 2 | import { defineConfig } from 'vite'; 3 | import path, { resolve } from 'node:path'; 4 | import dts from 'vite-plugin-dts'; 5 | 6 | export default defineConfig({ 7 | root: __dirname, 8 | cacheDir: '../../node_modules/.vite/middleware', 9 | base: './', 10 | plugins: [ 11 | dts({ 12 | entryRoot: 'src', 13 | tsconfigPath: path.join(__dirname, 'tsconfig.lib.json'), 14 | rollupTypes: true, 15 | }), 16 | ], 17 | build: { 18 | ssr: true, 19 | lib: { 20 | entry: resolve(__dirname, 'src/index.ts'), 21 | formats: ['es' as const, 'cjs' as const], 22 | }, 23 | }, 24 | server: { 25 | port: 3000, 26 | open: true, 27 | }, 28 | }); 29 | -------------------------------------------------------------------------------- /packages/network-activity-plugin/src/ui/views/LoadingView.tsx: -------------------------------------------------------------------------------- 1 | import { Loader2 } from 'lucide-react'; 2 | 3 | export const LoadingView = () => { 4 | return ( 5 |
6 |
7 | 8 |
9 |

10 | Loading Network Inspector 11 |

12 |

13 | Initializing network monitoring... 14 |

15 |
16 |
17 |
18 | ); 19 | }; 20 | -------------------------------------------------------------------------------- /commitlint.config.js: -------------------------------------------------------------------------------- 1 | export default { 2 | extends: ['@commitlint/config-conventional'], 3 | rules: { 4 | 'scope-enum': [ 5 | 2, 6 | 'always', 7 | [ 8 | 'cli', 9 | 'expo-atlas-plugin', 10 | 'metro', 11 | 'mmkv-plugin', 12 | 'network-activity-plugin', 13 | 'plugin-bridge', 14 | 'runtime', 15 | 'tanstack-query-plugin', 16 | 'vite-plugin', 17 | 'website', 18 | 'redux-devtools-plugin', 19 | 'playground', 20 | 'middleware', 21 | 'repack', 22 | 'performance-monitor-plugin', 23 | 'tools', 24 | 'react-navigation-plugin', 25 | 'require-profiler-plugin', 26 | '', 27 | ], 28 | ], 29 | }, 30 | }; 31 | -------------------------------------------------------------------------------- /packages/middleware/src/node-modules-paths.ts: -------------------------------------------------------------------------------- 1 | import path from 'node:path'; 2 | 3 | export const getNodeModulesPaths = (): readonly string[] => { 4 | const paths: string[] = []; 5 | 6 | // Add current working directory node_modules 7 | paths.push(path.join(process.cwd(), 'node_modules')); 8 | 9 | // Add parent directories node_modules (for monorepos) 10 | let currentDir = process.cwd(); 11 | let parentDir = path.dirname(currentDir); 12 | 13 | while (parentDir !== currentDir) { 14 | const parentNodeModules = path.join(parentDir, 'node_modules'); 15 | if (parentNodeModules) { 16 | paths.push(parentNodeModules); 17 | } 18 | currentDir = parentDir; 19 | parentDir = path.dirname(currentDir); 20 | } 21 | 22 | return paths; 23 | }; 24 | -------------------------------------------------------------------------------- /packages/performance-monitor-plugin/src/ui/components/DetailsDisplay.tsx: -------------------------------------------------------------------------------- 1 | import { Box, Text, Heading } from '@radix-ui/themes'; 2 | import { ReactNode } from 'react'; 3 | import { JsonTree } from './JsonTree'; 4 | 5 | export type DetailsDisplayProps = { 6 | details?: unknown; 7 | }; 8 | 9 | export const DetailsDisplay = ({ details }: DetailsDisplayProps) => { 10 | const renderValue = (value: unknown): ReactNode => { 11 | if (value == null) { 12 | return No details provided; 13 | } 14 | 15 | return ; 16 | }; 17 | 18 | return ( 19 | 20 | 21 | Details 22 | 23 | {renderValue(details)} 24 | 25 | ); 26 | }; 27 | -------------------------------------------------------------------------------- /packages/mmkv-plugin/src/react-native/is-garbled.ts: -------------------------------------------------------------------------------- 1 | // This is a heuristic to determine if a string is garbled. 2 | export const looksLikeGarbled = (str: string): boolean => { 3 | // 1. Check for replacement character (�) 4 | if (str.includes('\uFFFD')) return true; 5 | 6 | // 2. Check for unusual control characters 7 | // eslint-disable-next-line no-control-regex 8 | const controlChars = /[\u0000-\u001F\u007F-\u009F]/; 9 | if (controlChars.test(str)) return true; 10 | 11 | // 3. Optionally, check if most chars are non-printable 12 | const printableRatio = 13 | [...str].filter((c) => c >= ' ' && c <= '~').length / str.length; 14 | if (printableRatio < 0.7) return true; // mostly non-printable → probably binary 15 | 16 | return false; // seems like valid string 17 | }; 18 | -------------------------------------------------------------------------------- /packages/redux-devtools-plugin/src/ui/panel.tsx: -------------------------------------------------------------------------------- 1 | import { NoticeBadge } from './notice-badge'; 2 | import { ReduxDevTools } from './redux-devtools'; 3 | 4 | import './panel.css'; 5 | 6 | export default function ReduxDevToolsPanel() { 7 | return ( 8 |
9 | 14 | 15 | 19 | 20 | 21 |
22 | ); 23 | } 24 | -------------------------------------------------------------------------------- /packages/tools/vite.config.ts: -------------------------------------------------------------------------------- 1 | /// 2 | import { defineConfig } from 'vite'; 3 | import path, { resolve } from 'node:path'; 4 | import dts from 'vite-plugin-dts'; 5 | 6 | export default defineConfig({ 7 | root: __dirname, 8 | cacheDir: '../../node_modules/.vite/tools', 9 | base: './', 10 | test: { 11 | environment: 'node', 12 | }, 13 | plugins: [ 14 | dts({ 15 | entryRoot: 'src', 16 | tsconfigPath: path.join(__dirname, 'tsconfig.lib.json'), 17 | rollupTypes: true, 18 | }), 19 | ], 20 | build: { 21 | ssr: true, 22 | lib: { 23 | entry: resolve(__dirname, 'src/index.ts'), 24 | formats: ['es' as const, 'cjs' as const], 25 | }, 26 | }, 27 | server: { 28 | port: 3000, 29 | open: true, 30 | }, 31 | }); 32 | -------------------------------------------------------------------------------- /packages/mmkv-plugin/src/shared/messaging.ts: -------------------------------------------------------------------------------- 1 | import { MMKVEntry } from './types'; 2 | 3 | export type MMKVSnapshotEvent = { 4 | type: 'snapshot'; 5 | id: string; 6 | entries: MMKVEntry[]; 7 | }; 8 | 9 | export type MMKVSetEntryEvent = { 10 | type: 'set-entry'; 11 | id: string; 12 | entry: MMKVEntry; 13 | }; 14 | 15 | export type MMKVDeleteEntryEvent = { 16 | type: 'delete-entry'; 17 | id: string; 18 | key: string; 19 | }; 20 | 21 | export type MMKVGetSnapshotEvent = { 22 | type: 'get-snapshot'; 23 | id: string | 'all'; 24 | }; 25 | 26 | export type MMKVEvent = 27 | | MMKVSnapshotEvent 28 | | MMKVSetEntryEvent 29 | | MMKVDeleteEntryEvent 30 | | MMKVGetSnapshotEvent; 31 | 32 | export type MMKVEventMap = { 33 | [K in MMKVEvent['type']]: Extract; 34 | }; 35 | -------------------------------------------------------------------------------- /packages/network-activity-plugin/src/ui/types.ts: -------------------------------------------------------------------------------- 1 | import { 2 | RequestId, 3 | Request, 4 | Response, 5 | Initiator, 6 | ResourceType, 7 | HttpHeaders, 8 | } from '../shared/client'; 9 | 10 | export type NetworkEntry = { 11 | requestId: RequestId; 12 | url: string; 13 | method: string; 14 | headers: HttpHeaders; 15 | body?: { 16 | type: string; 17 | data: string; 18 | }; 19 | status: 'pending' | 'loading' | 'finished' | 'failed'; 20 | startTime: number; 21 | endTime?: number; 22 | duration?: number; 23 | ttfb?: number; 24 | type?: ResourceType; 25 | initiator?: Initiator; 26 | request?: Request; 27 | response?: Response; 28 | responseBody?: { 29 | body: string | null; 30 | }; 31 | error?: string; 32 | canceled?: boolean; 33 | size?: number; 34 | }; 35 | -------------------------------------------------------------------------------- /website/plugins/plugin-directory/utils.ts: -------------------------------------------------------------------------------- 1 | export function extractPackageNameFromNpmUrl(npmUrl: string): string | null { 2 | try { 3 | const url = new URL(npmUrl); 4 | const pathParts = url.pathname.split('/').filter(Boolean); 5 | 6 | if (pathParts[0] === 'package' && pathParts.length >= 2) { 7 | if (pathParts[1].startsWith('@') && pathParts.length >= 3) { 8 | return `${pathParts[1]}/${pathParts[2]}`; 9 | } 10 | return pathParts[1]; 11 | } 12 | 13 | return null; 14 | } catch (error) { 15 | return null; 16 | } 17 | } 18 | 19 | export function getPackageNamesFromReferences( 20 | references: Array<{ npmUrl: string }> 21 | ): string[] { 22 | return references 23 | .map((ref) => extractPackageNameFromNpmUrl(ref.npmUrl)) 24 | .filter(Boolean) as string[]; 25 | } 26 | -------------------------------------------------------------------------------- /packages/redux-devtools-plugin/src/metro.ts: -------------------------------------------------------------------------------- 1 | import type { ConfigT as MetroConfig } from 'metro-config'; 2 | import { createMetroConfigTransformer } from '@rozenite/tools'; 3 | import { REDUX_DEVTOOLS_PORT } from './constants'; 4 | 5 | export const withRozeniteReduxDevTools = createMetroConfigTransformer( 6 | async (config: MetroConfig): Promise => { 7 | // This is ESM only, so we need to import it dynamically in case of CJS 8 | const { default: setupWebSocketRelay } = await import( 9 | '@redux-devtools/cli' 10 | ); 11 | setupWebSocketRelay({ 12 | hostname: 'localhost', 13 | port: REDUX_DEVTOOLS_PORT, 14 | // This environment variable is set by Rozenite middleware. 15 | logLevel: process.env.ROZENITE_LOG_LEVEL, 16 | }); 17 | 18 | return config; 19 | }, 20 | ); 21 | -------------------------------------------------------------------------------- /apps/playground/src/app/navigation/types.ts: -------------------------------------------------------------------------------- 1 | import { NativeStackNavigationProp } from '@react-navigation/native-stack'; 2 | 3 | export type RootStackParamList = { 4 | Landing: undefined; 5 | MMKVPlugin: undefined; 6 | NetworkTest: undefined; 7 | RequestBodyTest: undefined; 8 | ReduxTest: undefined; 9 | PerformanceMonitor: undefined; 10 | RequireProfilerTest: undefined; 11 | Config: undefined; 12 | BottomTabs: undefined; 13 | ParameterDisplay: { 14 | title: string; 15 | message: string; 16 | color: string; 17 | source: string; 18 | }; 19 | SuccessiveScreensStack: undefined; 20 | }; 21 | 22 | export type BottomTabParamList = { 23 | Home: undefined; 24 | Profile: undefined; 25 | Settings: undefined; 26 | }; 27 | 28 | export type NavigationProp = NativeStackNavigationProp; 29 | -------------------------------------------------------------------------------- /packages/middleware/eslint.config.mjs: -------------------------------------------------------------------------------- 1 | import baseConfig from '../../eslint.config.mjs'; 2 | 3 | export default [ 4 | ...baseConfig, 5 | { 6 | files: ['**/*.json'], 7 | rules: { 8 | '@nx/dependency-checks': [ 9 | 'error', 10 | { 11 | ignoredDependencies: [ 12 | 'tslib', 13 | '@react-native/debugger-frontend', 14 | 'react-native', 15 | '@react-native/community-cli-plugin', 16 | '@react-native/dev-middleware', 17 | ], 18 | ignoredFiles: [ 19 | '{projectRoot}/eslint.config.{js,cjs,mjs,ts,cts,mts}', 20 | '{projectRoot}/vite.config.ts', 21 | ], 22 | }, 23 | ], 24 | }, 25 | languageOptions: { 26 | parser: await import('jsonc-eslint-parser'), 27 | }, 28 | }, 29 | ]; 30 | -------------------------------------------------------------------------------- /packages/tanstack-query-plugin/src/react-native/useHandleInitialData.ts: -------------------------------------------------------------------------------- 1 | import { useEffect } from 'react'; 2 | import { TanStackQueryPluginClient } from '../shared/messaging'; 3 | import { QueryClient } from '@tanstack/react-query'; 4 | import { dehydrateQueryClient } from '../shared/dehydrate'; 5 | 6 | export const useHandleInitialData = ( 7 | queryClient: QueryClient, 8 | client: TanStackQueryPluginClient | null 9 | ) => { 10 | useEffect(() => { 11 | if (!client) { 12 | return; 13 | } 14 | 15 | const subscription = client.onMessage('request-initial-data', () => { 16 | const dehydratedState = dehydrateQueryClient(queryClient); 17 | client.send('sync-data', { data: dehydratedState }); 18 | }); 19 | 20 | return () => { 21 | subscription.remove(); 22 | }; 23 | }, [client, queryClient]); 24 | }; 25 | -------------------------------------------------------------------------------- /packages/vite-plugin/src/server-plugin.ts: -------------------------------------------------------------------------------- 1 | import type { Plugin } from 'vite'; 2 | import process from 'node:process'; 3 | import path from 'node:path'; 4 | 5 | export const rozeniteServerPlugin = (): Plugin => { 6 | return { 7 | name: 'rozenite-server-plugin', 8 | 9 | config(config) { 10 | const projectRoot = config.root ?? process.cwd(); 11 | 12 | config.build ??= {}; 13 | config.build.lib = { 14 | entry: path.resolve(projectRoot, 'metro.ts'), 15 | formats: ['es' as const, 'cjs' as const], 16 | fileName: (format) => `metro.${format === 'es' ? 'js' : 'cjs'}`, 17 | }; 18 | config.build.ssr = true; 19 | config.build.rollupOptions = { 20 | output: { 21 | exports: 'named', 22 | interop: 'auto', 23 | }, 24 | }; 25 | }, 26 | }; 27 | }; 28 | -------------------------------------------------------------------------------- /website/plugins/plugin-directory/repository/repository-factory.ts: -------------------------------------------------------------------------------- 1 | import { PluginRepository } from './types'; 2 | 3 | let repository: Promise | PluginRepository | null = null; 4 | 5 | export const getRepository = async (): Promise => { 6 | if (repository) { 7 | return repository; 8 | } 9 | 10 | if (process.env.NODE_ENV === 'production' && process.env.USE_DATABASE) { 11 | repository = import('./neon-repository').then( 12 | ({ PostgresPluginRepository }) => new PostgresPluginRepository() 13 | ); 14 | console.log('Using Neon repository'); 15 | return repository; 16 | } 17 | 18 | repository = import('./mock-repository').then( 19 | ({ MockPluginRepository }) => new MockPluginRepository() 20 | ); 21 | console.log('Using mock repository'); 22 | return repository; 23 | }; 24 | -------------------------------------------------------------------------------- /apps/playground/src/app/store/counterSlice.ts: -------------------------------------------------------------------------------- 1 | import { createSlice, PayloadAction } from '@reduxjs/toolkit'; 2 | 3 | interface CounterState { 4 | value: number; 5 | } 6 | 7 | const initialState: CounterState = { 8 | value: 0, 9 | }; 10 | 11 | export const counterSlice = createSlice({ 12 | name: 'counter', 13 | initialState, 14 | reducers: { 15 | increment: (state) => { 16 | state.value += 1; 17 | }, 18 | decrement: (state) => { 19 | state.value -= 1; 20 | }, 21 | reset: (state) => { 22 | state.value = 0; 23 | }, 24 | incrementByAmount: (state, action: PayloadAction) => { 25 | state.value += action.payload; 26 | }, 27 | }, 28 | }); 29 | 30 | export const { increment, decrement, reset, incrementByAmount } = 31 | counterSlice.actions; 32 | export default counterSlice.reducer; 33 | -------------------------------------------------------------------------------- /packages/runtime/src/dev-mode.ts: -------------------------------------------------------------------------------- 1 | import { getManifest } from './manifest'; 2 | import { loadPluginFromUrl } from './plugin-loader'; 3 | 4 | const DEV_SERVER_URL = 'http://localhost:8888'; 5 | 6 | const isDevServerAvailable = async (): Promise => { 7 | try { 8 | await getManifest(DEV_SERVER_URL); 9 | return true; 10 | } catch { 11 | return false; 12 | } 13 | }; 14 | 15 | export const setupDevMode = async (): Promise => { 16 | const isAvailable = await isDevServerAvailable(); 17 | 18 | if (!isAvailable) { 19 | return; 20 | } 21 | 22 | console.group('🔧 Rozenite Dev Mode'); 23 | console.log('We detected that you are developing a plugin.'); 24 | console.log('This plugin will be automatically loaded with hot reload.'); 25 | console.groupEnd(); 26 | 27 | await loadPluginFromUrl(DEV_SERVER_URL); 28 | }; 29 | -------------------------------------------------------------------------------- /apps/playground/ios/PlaygroundTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /packages/network-activity-plugin/src/react-native/sse/event-source.ts: -------------------------------------------------------------------------------- 1 | import type EventSource from 'react-native-sse'; 2 | 3 | const NOOP = () => { 4 | // noop 5 | }; 6 | 7 | const MOCK_EVENT_SOURCE = class { 8 | open = NOOP; 9 | close = NOOP; 10 | addEventListener = NOOP; 11 | removeEventListener = NOOP; 12 | dispatch = NOOP; 13 | removeAllEventListeners = NOOP; 14 | }; 15 | 16 | export const getEventSource = (): typeof EventSource => { 17 | try { 18 | const { default: EventSource } = require('react-native-sse'); 19 | return EventSource; 20 | } catch { 21 | // This is a workaround for the fact that Vite doesn't support require() calls for in-project dependencies. 22 | // We are going to return a mock object, so the code will work fine, but it will not be able to intercept SSE requests. 23 | return MOCK_EVENT_SOURCE; 24 | } 25 | }; 26 | -------------------------------------------------------------------------------- /packages/network-activity-plugin/src/react-native/utils/getFormDataEntries.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Extracts form data parts from a FormData object. 3 | * Handles both the standard FormData API and the React Native FormData format. 4 | * 5 | * ``` 6 | * // node_modules/react-native/Libraries/Network/FormData.js 7 | * 8 | * class FormData { 9 | * _parts: Array; 10 | * 11 | * constructor() { 12 | * this._parts = []; 13 | * } 14 | * 15 | * ... 16 | * ``` 17 | */ 18 | export function getFormDataEntries(formData: any): [string, unknown][] { 19 | if (!formData || typeof formData !== 'object') { 20 | return []; 21 | } 22 | 23 | if (typeof formData.entries === 'function') { 24 | return formData.entries(); 25 | } 26 | 27 | if (Array.isArray(formData._parts)) { 28 | return formData._parts; 29 | } 30 | 31 | return []; 32 | } 33 | -------------------------------------------------------------------------------- /packages/network-activity-plugin/vite.config.ts: -------------------------------------------------------------------------------- 1 | /// 2 | import { defineConfig } from 'vite'; 3 | import { rozenitePlugin } from '@rozenite/vite-plugin'; 4 | 5 | export default defineConfig({ 6 | root: __dirname, 7 | plugins: [rozenitePlugin()], 8 | base: './', 9 | build: { 10 | outDir: './dist', 11 | emptyOutDir: false, 12 | reportCompressedSize: false, 13 | minify: false, 14 | sourcemap: false, 15 | rollupOptions: { 16 | output: { 17 | manualChunks: (id) => { 18 | // Mitigate https://github.com/facebook/metro/issues/836 19 | if (id.includes('event-source.ts')) { 20 | return 'event-source'; 21 | } 22 | 23 | return undefined; 24 | }, 25 | }, 26 | }, 27 | }, 28 | server: { 29 | port: 3000, 30 | open: true, 31 | }, 32 | }); 33 | -------------------------------------------------------------------------------- /packages/react-navigation-plugin/vite.config.ts: -------------------------------------------------------------------------------- 1 | /// 2 | import { defineConfig } from 'vite'; 3 | import { rozenitePlugin } from '@rozenite/vite-plugin'; 4 | 5 | export default defineConfig({ 6 | root: __dirname, 7 | plugins: [rozenitePlugin()], 8 | base: './', 9 | build: { 10 | outDir: './dist', 11 | emptyOutDir: false, 12 | reportCompressedSize: false, 13 | minify: false, 14 | sourcemap: false, 15 | rollupOptions: { 16 | output: { 17 | manualChunks: (id) => { 18 | // Mitigate https://github.com/facebook/metro/issues/836 19 | if (id.includes('event-source.ts')) { 20 | return 'event-source'; 21 | } 22 | 23 | return undefined; 24 | }, 25 | }, 26 | }, 27 | }, 28 | server: { 29 | port: 3000, 30 | open: true, 31 | }, 32 | }); 33 | -------------------------------------------------------------------------------- /packages/network-activity-plugin/src/ui/hooks/useCopyToClipboard.ts: -------------------------------------------------------------------------------- 1 | import { useState, useRef, useEffect, useCallback } from 'react'; 2 | 3 | import { copyToClipboard } from '../utils/copyToClipboard'; 4 | 5 | export function useCopyToClipboard() { 6 | const [isCopied, setIsCopied] = useState(false); 7 | 8 | const timeoutRef = useRef(); 9 | 10 | useEffect(() => { 11 | return () => clearTimeout(timeoutRef.current); 12 | }, []); 13 | 14 | const copy = useCallback(async (value: string) => { 15 | try { 16 | await copyToClipboard(value); 17 | 18 | setIsCopied(true); 19 | 20 | clearTimeout(timeoutRef.current); 21 | timeoutRef.current = setTimeout(() => setIsCopied(false), 1000); 22 | } catch (error) { 23 | console.error('Failed to copy:', error); 24 | } 25 | }, []); 26 | 27 | return { isCopied, copy }; 28 | } 29 | -------------------------------------------------------------------------------- /packages/vite-plugin/vite.config.ts: -------------------------------------------------------------------------------- 1 | /// 2 | import { defineConfig } from 'vite'; 3 | import dts from 'vite-plugin-dts'; 4 | import * as path from 'path'; 5 | 6 | export default defineConfig({ 7 | root: __dirname, 8 | cacheDir: '../../node_modules/.vite/packages/vite-plugin', 9 | plugins: [ 10 | dts({ 11 | entryRoot: 'src', 12 | tsconfigPath: path.join(__dirname, 'tsconfig.lib.json'), 13 | }), 14 | ], 15 | build: { 16 | outDir: './dist', 17 | emptyOutDir: true, 18 | reportCompressedSize: true, 19 | commonjsOptions: { 20 | transformMixedEsModules: true, 21 | }, 22 | ssr: true, 23 | lib: { 24 | entry: 'src/index.ts', 25 | fileName: 'index', 26 | formats: ['es' as const, 'cjs' as const], 27 | }, 28 | rollupOptions: { 29 | external: [], 30 | }, 31 | }, 32 | }); 33 | -------------------------------------------------------------------------------- /packages/tanstack-query-plugin/src/shared/useSyncOnlineStatus.ts: -------------------------------------------------------------------------------- 1 | import { useEffect } from 'react'; 2 | import { onlineManager } from '@tanstack/react-query'; 3 | import { TanStackQueryPluginClient } from './messaging'; 4 | 5 | export const useSyncOnlineStatus = ( 6 | client: TanStackQueryPluginClient | null 7 | ) => { 8 | useEffect(() => { 9 | if (!client) { 10 | return; 11 | } 12 | 13 | const onlineManagerSubscription = onlineManager.subscribe((online) => { 14 | client.send('online-status-changed', { online }); 15 | }); 16 | 17 | const onlineMessageSubscription = client.onMessage( 18 | 'online-status-changed', 19 | ({ online }) => { 20 | onlineManager.setOnline(online); 21 | } 22 | ); 23 | 24 | return () => { 25 | onlineManagerSubscription(); 26 | onlineMessageSubscription.remove(); 27 | }; 28 | }, [client]); 29 | }; 30 | -------------------------------------------------------------------------------- /packages/performance-monitor-plugin/src/react-native/asserts.ts: -------------------------------------------------------------------------------- 1 | import type { 2 | PerformanceMark, 3 | PerformanceMeasure, 4 | PerformanceMetric, 5 | } from 'react-native-performance'; 6 | 7 | export function assertPerformanceMark( 8 | entry: PerformanceEntry 9 | ): asserts entry is PerformanceMark { 10 | if (entry.entryType !== 'mark') { 11 | throw new Error('Entry is not a PerformanceMark'); 12 | } 13 | } 14 | 15 | export function assertPerformanceMeasure( 16 | entry: PerformanceEntry 17 | ): asserts entry is PerformanceMeasure { 18 | if (entry.entryType !== 'measure') { 19 | throw new Error('Entry is not a PerformanceMeasure'); 20 | } 21 | } 22 | 23 | export function assertPerformanceMetric( 24 | entry: PerformanceEntry 25 | ): asserts entry is PerformanceMetric { 26 | if (entry.entryType !== 'metric') { 27 | throw new Error('Entry is not a PerformanceMetric'); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /packages/plugin-bridge/src/channel/factory.ts: -------------------------------------------------------------------------------- 1 | import { getCdpChannel } from './device/cdp-channel'; 2 | import { getPanelChannel } from './browser/panel-channel'; 3 | import { Channel } from './types'; 4 | 5 | let channel: Promise | Channel | null = null; 6 | 7 | export const getChannel = async (): Promise => { 8 | // Channel can be safely reused, because it's not scoped to the plugin. 9 | 10 | if (channel) { 11 | return channel; 12 | } 13 | 14 | const isPanel = '__ROZENITE_PANEL__' in window; 15 | const channelPromise = isPanel ? getPanelChannel() : getCdpChannel(); 16 | channel = channelPromise; 17 | 18 | try { 19 | const instance = await channelPromise; 20 | channel = instance; 21 | return instance; 22 | } catch (error) { 23 | // Clear the cached promise on error so subsequent calls can retry 24 | channel = null; 25 | throw error; 26 | } 27 | }; 28 | -------------------------------------------------------------------------------- /packages/mmkv-plugin/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2020", 4 | "lib": ["ES2020", "DOM", "DOM.Iterable"], 5 | "allowJs": true, 6 | "skipLibCheck": true, 7 | "esModuleInterop": true, 8 | "allowSyntheticDefaultImports": true, 9 | "strict": true, 10 | "forceConsistentCasingInFileNames": true, 11 | "noFallthroughCasesInSwitch": true, 12 | "module": "ESNext", 13 | "moduleResolution": "bundler", 14 | "resolveJsonModule": true, 15 | "isolatedModules": true, 16 | "noEmit": true, 17 | "jsx": "react-jsx" 18 | }, 19 | "include": ["src/**/*", "react-native.ts", "rozenite.config.ts"], 20 | "exclude": ["node_modules", "dist", "build"], 21 | "references": [ 22 | { 23 | "path": "../plugin-bridge" 24 | }, 25 | { 26 | "path": "../cli" 27 | }, 28 | { 29 | "path": "../vite-plugin" 30 | } 31 | ] 32 | } 33 | -------------------------------------------------------------------------------- /packages/redux-devtools-plugin/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2020", 4 | "lib": ["ES2020", "DOM", "DOM.Iterable"], 5 | "allowJs": true, 6 | "skipLibCheck": true, 7 | "esModuleInterop": true, 8 | "allowSyntheticDefaultImports": true, 9 | "strict": true, 10 | "forceConsistentCasingInFileNames": true, 11 | "noFallthroughCasesInSwitch": true, 12 | "module": "ESNext", 13 | "moduleResolution": "bundler", 14 | "resolveJsonModule": true, 15 | "isolatedModules": true, 16 | "noEmit": true, 17 | "jsx": "react-jsx" 18 | }, 19 | "include": ["src/**/*", "react-native.ts", "metro.ts"], 20 | "exclude": ["node_modules", "dist", "build"], 21 | "references": [ 22 | { 23 | "path": "../plugin-bridge" 24 | }, 25 | { 26 | "path": "../cli" 27 | }, 28 | { 29 | "path": "../vite-plugin" 30 | } 31 | ] 32 | } 33 | -------------------------------------------------------------------------------- /packages/expo-atlas-plugin/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2020", 4 | "lib": ["ES2020", "DOM", "DOM.Iterable"], 5 | "allowJs": true, 6 | "skipLibCheck": true, 7 | "esModuleInterop": true, 8 | "allowSyntheticDefaultImports": true, 9 | "strict": true, 10 | "forceConsistentCasingInFileNames": true, 11 | "noFallthroughCasesInSwitch": true, 12 | "module": "ESNext", 13 | "moduleResolution": "bundler", 14 | "resolveJsonModule": true, 15 | "isolatedModules": true, 16 | "noEmit": true, 17 | "jsx": "react-jsx" 18 | }, 19 | "include": ["src/**/*", "react-native.ts", "rozenite.config.ts"], 20 | "exclude": ["node_modules", "dist", "build"], 21 | "references": [ 22 | { 23 | "path": "../plugin-bridge" 24 | }, 25 | { 26 | "path": "../cli" 27 | }, 28 | { 29 | "path": "../vite-plugin" 30 | } 31 | ] 32 | } 33 | -------------------------------------------------------------------------------- /packages/network-activity-plugin/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2020", 4 | "lib": ["ES2020", "DOM", "DOM.Iterable"], 5 | "allowJs": true, 6 | "skipLibCheck": true, 7 | "esModuleInterop": true, 8 | "allowSyntheticDefaultImports": true, 9 | "strict": true, 10 | "forceConsistentCasingInFileNames": true, 11 | "noFallthroughCasesInSwitch": true, 12 | "module": "ESNext", 13 | "moduleResolution": "bundler", 14 | "resolveJsonModule": true, 15 | "isolatedModules": true, 16 | "noEmit": true, 17 | "jsx": "react-jsx" 18 | }, 19 | "include": ["src/**/*", "react-native.ts", "rozenite.config.ts"], 20 | "exclude": ["node_modules", "dist", "build"], 21 | "references": [ 22 | { 23 | "path": "../plugin-bridge" 24 | }, 25 | { 26 | "path": "../cli" 27 | }, 28 | { 29 | "path": "../vite-plugin" 30 | } 31 | ] 32 | } 33 | -------------------------------------------------------------------------------- /packages/react-navigation-plugin/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2020", 4 | "lib": ["ES2020", "DOM", "DOM.Iterable"], 5 | "allowJs": true, 6 | "skipLibCheck": true, 7 | "esModuleInterop": true, 8 | "allowSyntheticDefaultImports": true, 9 | "strict": true, 10 | "forceConsistentCasingInFileNames": true, 11 | "noFallthroughCasesInSwitch": true, 12 | "module": "ESNext", 13 | "moduleResolution": "bundler", 14 | "resolveJsonModule": true, 15 | "isolatedModules": true, 16 | "noEmit": true, 17 | "jsx": "react-jsx" 18 | }, 19 | "include": ["src/**/*", "react-native.ts", "rozenite.config.ts"], 20 | "exclude": ["node_modules", "dist", "build"], 21 | "references": [ 22 | { 23 | "path": "../plugin-bridge" 24 | }, 25 | { 26 | "path": "../cli" 27 | }, 28 | { 29 | "path": "../vite-plugin" 30 | } 31 | ] 32 | } 33 | -------------------------------------------------------------------------------- /packages/require-profiler-plugin/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2020", 4 | "lib": ["ES2020", "DOM", "DOM.Iterable"], 5 | "allowJs": true, 6 | "skipLibCheck": true, 7 | "esModuleInterop": true, 8 | "allowSyntheticDefaultImports": true, 9 | "strict": true, 10 | "forceConsistentCasingInFileNames": true, 11 | "noFallthroughCasesInSwitch": true, 12 | "module": "ESNext", 13 | "moduleResolution": "bundler", 14 | "resolveJsonModule": true, 15 | "isolatedModules": true, 16 | "noEmit": true, 17 | "jsx": "react-jsx" 18 | }, 19 | "include": ["src/**/*", "react-native.ts", "rozenite.config.ts"], 20 | "exclude": ["node_modules", "dist", "build"], 21 | "references": [ 22 | { 23 | "path": "../plugin-bridge" 24 | }, 25 | { 26 | "path": "../cli" 27 | }, 28 | { 29 | "path": "../vite-plugin" 30 | } 31 | ] 32 | } 33 | -------------------------------------------------------------------------------- /packages/tanstack-query-plugin/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2020", 4 | "lib": ["ES2020", "DOM", "DOM.Iterable"], 5 | "allowJs": true, 6 | "skipLibCheck": true, 7 | "esModuleInterop": true, 8 | "allowSyntheticDefaultImports": true, 9 | "strict": true, 10 | "forceConsistentCasingInFileNames": true, 11 | "noFallthroughCasesInSwitch": true, 12 | "module": "ESNext", 13 | "moduleResolution": "bundler", 14 | "resolveJsonModule": true, 15 | "isolatedModules": true, 16 | "noEmit": true, 17 | "jsx": "react-jsx" 18 | }, 19 | "include": ["src/**/*", "react-native.ts", "rozenite.config.ts"], 20 | "exclude": ["node_modules", "dist", "build"], 21 | "references": [ 22 | { 23 | "path": "../plugin-bridge" 24 | }, 25 | { 26 | "path": "../cli" 27 | }, 28 | { 29 | "path": "../vite-plugin" 30 | } 31 | ] 32 | } 33 | -------------------------------------------------------------------------------- /apps/playground/src/app/navigation/SuccessiveScreensNavigator.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | createNativeStackNavigator, 3 | NativeStackNavigationProp, 4 | } from '@react-navigation/native-stack'; 5 | import { SuccessiveScreens } from '../screens/SuccessiveScreens'; 6 | 7 | export type SuccessiveScreensStackParamList = { 8 | SuccessiveScreens: undefined; 9 | }; 10 | 11 | export type SuccessiveScreensNavigationProp = 12 | NativeStackNavigationProp; 13 | 14 | const Stack = createNativeStackNavigator(); 15 | 16 | export const SuccessiveScreensNavigator = () => { 17 | return ( 18 | 24 | 25 | 26 | ); 27 | }; 28 | -------------------------------------------------------------------------------- /packages/cli/template/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "<%- name %>", 3 | "version": "0.0.1", 4 | "description": "<%- description %>", 5 | "type": "module", 6 | "main": "./dist/react-native.cjs", 7 | "module": "./dist/react-native.js", 8 | "types": "./dist/react-native.d.ts", 9 | "scripts": { 10 | "build": "rozenite build", 11 | "dev": "rozenite dev" 12 | }, 13 | "dependencies": { 14 | "@rozenite/plugin-bridge": "1.0.0-alpha.3" 15 | }, 16 | "devDependencies": { 17 | "vite": "^6.0.0", 18 | "@rozenite/vite-plugin": "1.0.0-alpha.3", 19 | "typescript": "^5.7.3", 20 | "rozenite": "1.0.0-alpha.3", 21 | "react-native-web": "0.21.0", 22 | "react": "18.3.1", 23 | "react-dom": "18.3.0", 24 | "react-native": "0.76.0", 25 | "@types/react": "~18.3.12" 26 | }, 27 | "peerDependencies": { 28 | "react": "*", 29 | "react-native": "*" 30 | }, 31 | "license": "MIT" 32 | } 33 | -------------------------------------------------------------------------------- /packages/expo-atlas-plugin/src/base-serializer.ts: -------------------------------------------------------------------------------- 1 | const createSerializer = () => { 2 | const baseJSBundle = require('metro/src/DeltaBundler/Serializers/baseJSBundle'); 3 | const bundleToString = require('metro/src/lib/bundleToString'); 4 | 5 | return ( 6 | entryPoint: unknown, 7 | prepend: unknown, 8 | graph: unknown, 9 | bundleOptions: unknown 10 | ) => bundleToString(baseJSBundle(entryPoint, prepend, graph, bundleOptions)); 11 | }; 12 | 13 | export const getBaseSerializer = () => { 14 | try { 15 | return createSerializer(); 16 | } catch (error) { 17 | if ( 18 | error instanceof Error && 19 | 'code' in error && 20 | error.code === 'MODULE_NOT_FOUND' 21 | ) { 22 | throw new Error( 23 | 'Cannot find required internals of Metro. Please make sure you have installed the correct version of Metro.' 24 | ); 25 | } 26 | 27 | throw error; 28 | } 29 | }; 30 | -------------------------------------------------------------------------------- /packages/performance-monitor-plugin/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2020", 4 | "lib": ["ES2020", "DOM", "DOM.Iterable"], 5 | "allowJs": true, 6 | "skipLibCheck": true, 7 | "esModuleInterop": true, 8 | "allowSyntheticDefaultImports": true, 9 | "strict": true, 10 | "forceConsistentCasingInFileNames": true, 11 | "noFallthroughCasesInSwitch": true, 12 | "module": "ESNext", 13 | "moduleResolution": "bundler", 14 | "resolveJsonModule": true, 15 | "isolatedModules": true, 16 | "noEmit": true, 17 | "jsx": "react-jsx" 18 | }, 19 | "include": ["src/**/*", "react-native.ts", "rozenite.config.ts"], 20 | "exclude": ["node_modules", "dist", "build"], 21 | "references": [ 22 | { 23 | "path": "../plugin-bridge" 24 | }, 25 | { 26 | "path": "../cli" 27 | }, 28 | { 29 | "path": "../vite-plugin" 30 | } 31 | ] 32 | } 33 | -------------------------------------------------------------------------------- /packages/middleware/src/config.ts: -------------------------------------------------------------------------------- 1 | import { type ProjectType } from '@rozenite/tools'; 2 | import { RozeniteLogLevel } from './logger.js'; 3 | 4 | export type RozeniteConfig = { 5 | projectRoot: string; 6 | include?: string[]; 7 | exclude?: string[]; 8 | 9 | /** 10 | * Plugin identifiers that should NOT maintain their UI state when not active. 11 | * These panels will be destroyed instead of hidden when switching between panels. 12 | * If not provided (default), all plugins will persist their state. 13 | */ 14 | destroyOnDetachPlugins?: string[]; 15 | 16 | /** 17 | * Project type of the project. If not provided, Rozenite will try to guess it based on the project root. 18 | * Useful if built-in heuristics fail to detect the project type. 19 | */ 20 | projectType?: ProjectType; 21 | 22 | /** 23 | * The log level to use. 24 | * @default 'info' 25 | */ 26 | logLevel?: RozeniteLogLevel; 27 | }; 28 | -------------------------------------------------------------------------------- /packages/network-activity-plugin/src/ui/components/Input.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | 3 | import { cn } from '../utils/cn'; 4 | 5 | const Input = React.forwardRef>( 6 | ({ className, type, ...props }, ref) => { 7 | return ( 8 | 17 | ); 18 | } 19 | ); 20 | Input.displayName = 'Input'; 21 | 22 | export { Input }; 23 | -------------------------------------------------------------------------------- /packages/react-navigation-plugin/src/devtools-ui/components/NavigationTree/Leaf.tsx: -------------------------------------------------------------------------------- 1 | export const Leaf = ({ 2 | title, 3 | isSelectedTab, 4 | color, 5 | subtitle, 6 | }: { 7 | title: string; 8 | isSelectedTab?: boolean; 9 | color: string; 10 | subtitle?: string; 11 | }) => { 12 | return ( 13 |
20 | 31 |
32 | ); 33 | }; 34 | -------------------------------------------------------------------------------- /packages/network-activity-plugin/src/ui/components/CodeEditor.tsx: -------------------------------------------------------------------------------- 1 | import { forwardRef } from 'react'; 2 | 3 | export type CodeEditorProps = { 4 | data: string | undefined; 5 | onInput?: (event: React.FormEvent) => void; 6 | }; 7 | 8 | export const CodeEditor = forwardRef( 9 | ({ data, onInput }, ref) => { 10 | return ( 11 |
20 |         {data}
21 |       
22 | ); 23 | } 24 | ); 25 | 26 | CodeEditor.displayName = 'CodeEditor'; 27 | -------------------------------------------------------------------------------- /packages/require-profiler-plugin/vite.config.ts: -------------------------------------------------------------------------------- 1 | /// 2 | import { defineConfig } from 'vite'; 3 | import { rozenitePlugin } from '@rozenite/vite-plugin'; 4 | import fs from 'node:fs'; 5 | import path from 'node:path'; 6 | 7 | export default defineConfig({ 8 | root: __dirname, 9 | plugins: [rozenitePlugin()], 10 | base: './', 11 | build: { 12 | outDir: './dist', 13 | emptyOutDir: false, 14 | reportCompressedSize: false, 15 | minify: true, 16 | sourcemap: false, 17 | rollupOptions: { 18 | plugins: [ 19 | { 20 | name: 'copy-files', 21 | writeBundle() { 22 | fs.cpSync( 23 | path.resolve(__dirname, 'src/metro/setup.js'), 24 | path.resolve(__dirname, 'dist/setup.js'), 25 | ); 26 | }, 27 | }, 28 | ], 29 | }, 30 | }, 31 | server: { 32 | port: 3000, 33 | open: true, 34 | }, 35 | }); 36 | -------------------------------------------------------------------------------- /packages/metro/vite.config.ts: -------------------------------------------------------------------------------- 1 | /// 2 | import { defineConfig } from 'vite'; 3 | import path, { resolve } from 'node:path'; 4 | import dts from 'vite-plugin-dts'; 5 | import packageJson from './package.json' assert { type: 'json' }; 6 | 7 | const dependencies = Object.keys(packageJson.dependencies || {}); 8 | 9 | export default defineConfig({ 10 | root: __dirname, 11 | cacheDir: '../../node_modules/.vite/metro', 12 | base: './', 13 | plugins: [ 14 | dts({ 15 | entryRoot: 'src', 16 | tsconfigPath: path.join(__dirname, 'tsconfig.lib.json'), 17 | rollupTypes: true, 18 | }), 19 | ], 20 | build: { 21 | ssr: true, 22 | lib: { 23 | entry: resolve(__dirname, 'src/index.ts'), 24 | formats: ['es' as const, 'cjs' as const], 25 | }, 26 | rollupOptions: { 27 | external: dependencies, 28 | }, 29 | }, 30 | server: { 31 | port: 3000, 32 | open: true, 33 | }, 34 | }); 35 | -------------------------------------------------------------------------------- /packages/network-activity-plugin/src/ui/components/Separator.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | 3 | import * as React from 'react'; 4 | import * as SeparatorPrimitive from '@radix-ui/react-separator'; 5 | 6 | import { cn } from '../utils/cn'; 7 | 8 | const Separator = React.forwardRef< 9 | React.ElementRef, 10 | React.ComponentPropsWithoutRef 11 | >( 12 | ( 13 | { className, orientation = 'horizontal', decorative = true, ...props }, 14 | ref 15 | ) => ( 16 | 27 | ) 28 | ); 29 | Separator.displayName = SeparatorPrimitive.Root.displayName; 30 | 31 | export { Separator }; 32 | -------------------------------------------------------------------------------- /packages/repack/vite.config.ts: -------------------------------------------------------------------------------- 1 | /// 2 | import { defineConfig } from 'vite'; 3 | import path, { resolve } from 'node:path'; 4 | import dts from 'vite-plugin-dts'; 5 | import packageJson from './package.json' assert { type: 'json' }; 6 | 7 | const dependencies = Object.keys(packageJson.dependencies || {}); 8 | 9 | export default defineConfig({ 10 | root: __dirname, 11 | cacheDir: '../../node_modules/.vite/repack', 12 | base: './', 13 | plugins: [ 14 | dts({ 15 | entryRoot: 'src', 16 | tsconfigPath: path.join(__dirname, 'tsconfig.lib.json'), 17 | rollupTypes: true, 18 | }), 19 | ], 20 | build: { 21 | ssr: true, 22 | lib: { 23 | entry: resolve(__dirname, 'src/index.ts'), 24 | formats: ['es' as const, 'cjs' as const], 25 | }, 26 | rollupOptions: { 27 | external: dependencies, 28 | }, 29 | }, 30 | server: { 31 | port: 3000, 32 | open: true, 33 | }, 34 | }); 35 | -------------------------------------------------------------------------------- /packages/tanstack-query-plugin/src/react-native/useTanstackQueryDevTools.ts: -------------------------------------------------------------------------------- 1 | import { QueryClient } from '@tanstack/react-query'; 2 | import { useRozeniteDevToolsClient } from '@rozenite/plugin-bridge'; 3 | import { TanStackQueryPluginEventMap } from '../shared/messaging'; 4 | import { useSyncOnlineStatus } from '../shared/useSyncOnlineStatus'; 5 | import { useHandleDevToolsMessages } from './useHandleDevToolsMessages'; 6 | import { useSyncTanStackCache } from './useSyncTanStackCache'; 7 | import { useHandleInitialData } from './useHandleInitialData'; 8 | 9 | export const useTanStackQueryDevTools = (queryClient: QueryClient) => { 10 | const client = useRozeniteDevToolsClient({ 11 | pluginId: '@rozenite/tanstack-query-plugin', 12 | }); 13 | 14 | useSyncOnlineStatus(client); 15 | 16 | useHandleDevToolsMessages(queryClient, client); 17 | 18 | useSyncTanStackCache(queryClient, client); 19 | 20 | useHandleInitialData(queryClient, client); 21 | }; 22 | -------------------------------------------------------------------------------- /packages/plugin-bridge/src/channel/browser/panel-channel.ts: -------------------------------------------------------------------------------- 1 | import { Channel } from '../types'; 2 | 3 | export const getPanelChannel = async (): Promise => { 4 | const listeners = new Set<(message: unknown) => void>(); 5 | 6 | const handleMessage = (event: MessageEvent) => { 7 | listeners.forEach((listener) => { 8 | listener(event.data); 9 | }); 10 | }; 11 | 12 | window.addEventListener('message', handleMessage); 13 | 14 | return { 15 | send: (message: unknown) => { 16 | window.parent.postMessage( 17 | { type: 'rozenite-message', payload: message }, 18 | '*' 19 | ); 20 | }, 21 | onMessage: (listener: (message: unknown) => void) => { 22 | listeners.add(listener); 23 | 24 | return { 25 | remove: () => { 26 | listeners.delete(listener); 27 | }, 28 | }; 29 | }, 30 | close: () => { 31 | listeners.clear(); 32 | window.removeEventListener('message', handleMessage); 33 | }, 34 | }; 35 | }; 36 | -------------------------------------------------------------------------------- /packages/network-activity-plugin/src/react-native/http/xml-request.d.ts: -------------------------------------------------------------------------------- 1 | declare type BlobData = { 2 | blobId: string; 3 | lastModified?: number; 4 | name?: string; 5 | offset: number; 6 | size: number; 7 | type?: string; 8 | }; 9 | 10 | declare global { 11 | interface XMLHttpRequest { 12 | _rozeniteRequestId: string; 13 | _requestId?: number; 14 | _subscriptions: Array; 15 | _aborted: boolean; 16 | _cachedResponse: Response; 17 | _hasError: boolean; 18 | _headers: { [key: string]: string }; 19 | _lowerCaseResponseHeaders: { [key: string]: string }; 20 | _method?: string | null; 21 | _perfKey?: string | null; 22 | _responseType: ResponseType; 23 | _response: string | BlobData; 24 | _sent: boolean; 25 | _url?: string | null; 26 | _timedOut: boolean; 27 | _trackingName?: string; 28 | _incrementalEvents: boolean; 29 | _startTime?: number | null; 30 | responseHeaders?: { [key: string]: string }; 31 | } 32 | } 33 | 34 | export {}; 35 | -------------------------------------------------------------------------------- /website/src/docs/official-plugins/_meta.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "type": "file", 4 | "name": "overview", 5 | "label": "Overview" 6 | }, 7 | { 8 | "type": "file", 9 | "name": "expo-atlas", 10 | "label": "Expo Atlas" 11 | }, 12 | { 13 | "type": "file", 14 | "name": "tanstack-query", 15 | "label": "TanStack Query" 16 | }, 17 | { 18 | "type": "file", 19 | "name": "react-navigation", 20 | "label": "React Navigation" 21 | }, 22 | { 23 | "type": "file", 24 | "name": "network-activity", 25 | "label": "Network Activity" 26 | }, 27 | { 28 | "type": "file", 29 | "name": "redux-devtools", 30 | "label": "Redux DevTools" 31 | }, 32 | { 33 | "type": "file", 34 | "name": "performance-monitor", 35 | "label": "Performance Monitor" 36 | }, 37 | { 38 | "type": "file", 39 | "name": "mmkv", 40 | "label": "MMKV" 41 | }, 42 | { 43 | "type": "file", 44 | "name": "require-profiler", 45 | "label": "Require Profiler" 46 | } 47 | ] 48 | -------------------------------------------------------------------------------- /packages/network-activity-plugin/src/react-native/http/overrides-registry.ts: -------------------------------------------------------------------------------- 1 | import { RequestOverride } from '../../shared/client'; 2 | 3 | export type OverridesRegistry = { 4 | setOverrides: (newOverrides: [string, RequestOverride][]) => void; 5 | getOverrideForUrl: (url: string) => RequestOverride | undefined; 6 | }; 7 | 8 | const createOverridesRegistry = (): OverridesRegistry => { 9 | let overrides = new Map(); 10 | 11 | const setOverrides = (newOverrides: [string, RequestOverride][]) => { 12 | overrides = new Map(newOverrides); 13 | }; 14 | 15 | const getOverrideForUrl = (url: string) => { 16 | return overrides.get(url); 17 | }; 18 | 19 | return { 20 | setOverrides, 21 | getOverrideForUrl, 22 | }; 23 | }; 24 | 25 | let registryInstance: OverridesRegistry | null = null; 26 | 27 | export const getOverridesRegistry = (): OverridesRegistry => { 28 | if (!registryInstance) { 29 | registryInstance = createOverridesRegistry(); 30 | } 31 | return registryInstance; 32 | }; 33 | -------------------------------------------------------------------------------- /packages/performance-monitor-plugin/src/react-native/usePerformanceMonitorDevTools.ts: -------------------------------------------------------------------------------- 1 | import { useRozeniteDevToolsClient } from '@rozenite/plugin-bridge'; 2 | import { useEffect } from 'react'; 3 | import { getPerformanceMonitor } from './performance-monitor'; 4 | import { PerformanceMonitorEventMap } from '../shared/types'; 5 | 6 | export const usePerformanceMonitorDevTools = () => { 7 | const client = useRozeniteDevToolsClient({ 8 | pluginId: '@rozenite/performance-monitor-plugin', 9 | }); 10 | 11 | useEffect(() => { 12 | if (!client) { 13 | return; 14 | } 15 | 16 | const performanceMonitor = getPerformanceMonitor(client); 17 | 18 | const subscription = client.onMessage('setEnabled', ({ enabled }) => { 19 | if (enabled) { 20 | performanceMonitor.enable(); 21 | } else { 22 | performanceMonitor.disable(); 23 | } 24 | }); 25 | 26 | return () => { 27 | subscription.remove(); 28 | performanceMonitor.dispose(); 29 | }; 30 | }, [client]); 31 | }; 32 | -------------------------------------------------------------------------------- /packages/runtime/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@rozenite/runtime", 3 | "version": "1.1.0", 4 | "description": "Rozenite runtime for React Native DevTools.", 5 | "type": "module", 6 | "files": [ 7 | "dist" 8 | ], 9 | "keywords": [ 10 | "react-native", 11 | "devtools", 12 | "framework", 13 | "plugin", 14 | "orchestration" 15 | ], 16 | "homepage": "https://github.com/callstackincubator/rozenite#readme", 17 | "bugs": { 18 | "url": "https://github.com/callstackincubator/rozenite/issues" 19 | }, 20 | "repository": { 21 | "type": "git", 22 | "url": "https://github.com/callstackincubator/rozenite.git" 23 | }, 24 | "author": "Szymon Chmal ", 25 | "license": "MIT", 26 | "exports": { 27 | ".": { 28 | "types": "./dist/host.d.ts", 29 | "import": "./dist/host.js", 30 | "require": "./dist/host.cjs" 31 | } 32 | }, 33 | "dependencies": { 34 | "tslib": "^2.3.0" 35 | }, 36 | "devDependencies": {}, 37 | "engines": { 38 | "node": ">=20" 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/2-feature-request.yml: -------------------------------------------------------------------------------- 1 | name: "\U0001F5E3 Feature request" 2 | description: Propose a new feature to be added to Rozenite 3 | type: feature 4 | body: 5 | - type: markdown 6 | attributes: 7 | value: Thanks for your interest in the project and taking the time to fill out this feature report! 8 | - type: textarea 9 | id: feature-description 10 | attributes: 11 | label: Description 12 | description: 'Clear and concise description of the problem.' 13 | validations: 14 | required: true 15 | - type: textarea 16 | id: suggested-solution 17 | attributes: 18 | label: Suggested solution 19 | description: 'Describe the solution you have in mind. If you want to submit a PR for this issue, tell us in the description!' 20 | placeholder: 'In module X we could provide following implementation...' 21 | - type: textarea 22 | id: additional-context 23 | attributes: 24 | label: Additional context 25 | description: Any other context or screenshots about the feature request here. 26 | -------------------------------------------------------------------------------- /packages/runtime/src/create-panel.ts: -------------------------------------------------------------------------------- 1 | import { getPluginView } from './rn-devtools/plugin-view.js'; 2 | import { UI } from './rn-devtools/rn-devtools-frontend.js'; 3 | 4 | const toExtendedKebabCase = (input: string): string => { 5 | return input 6 | .toLowerCase() 7 | .replace(/[^a-z0-9]/g, ' ') 8 | .trim() 9 | .replace(/\s+/g, ' ') 10 | .replace(/\s/g, '.') 11 | .replace(/\.+/g, '.') 12 | .replace(/^\.+|\.+$/g, ''); 13 | }; 14 | 15 | export const createPanel = (pluginId: string, name: string, url: string) => { 16 | try { 17 | const pluginIdKebab = toExtendedKebabCase(pluginId); 18 | const nameKebab = toExtendedKebabCase(name); 19 | const panelId = `${pluginIdKebab}.${nameKebab}`; 20 | 21 | if (UI.InspectorView.InspectorView.instance().hasPanel(panelId)) { 22 | return; 23 | } 24 | 25 | const panelView = getPluginView(pluginId, panelId, name, url); 26 | 27 | UI.InspectorView.InspectorView.instance().addPanel(panelView); 28 | } catch (err) { 29 | console.error(err); 30 | throw err; 31 | } 32 | }; 33 | -------------------------------------------------------------------------------- /packages/runtime/src/plugin-loader.ts: -------------------------------------------------------------------------------- 1 | import { createPanel } from './create-panel'; 2 | import { getManifest } from './manifest'; 3 | 4 | const getPluginUrl = (pluginId: string) => { 5 | const url = new URL(location.href); 6 | url.search = ''; 7 | url.pathname = '/rozenite/plugins/' + pluginId.replace('/', '_'); 8 | return url.toString(); 9 | }; 10 | 11 | export const loadPluginFromUrl = async (url: string): Promise => { 12 | const manifest = await getManifest(url); 13 | manifest.panels.forEach((panel) => { 14 | const panelUrl = url + panel.source; 15 | createPanel(manifest.name, panel.name, panelUrl); 16 | }); 17 | 18 | console.groupCollapsed(`📦 Plugin: ${manifest.name}`); 19 | console.log('Version:', manifest.version); 20 | console.log('Description:', manifest.description); 21 | console.log('Panels:', manifest.panels.map((panel) => panel.name).join(', ')); 22 | console.groupEnd(); 23 | }; 24 | 25 | export const loadPlugin = async (pluginId: string): Promise => { 26 | await loadPluginFromUrl(getPluginUrl(pluginId)); 27 | }; 28 | -------------------------------------------------------------------------------- /packages/expo-atlas-plugin/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@rozenite/expo-atlas-plugin", 3 | "version": "1.1.0", 4 | "description": "Expo Atlas for Rozenite.", 5 | "type": "module", 6 | "main": "./dist/react-native.cjs", 7 | "module": "./dist/react-native.js", 8 | "types": "./dist/react-native.d.ts", 9 | "scripts": { 10 | "build": "rozenite build", 11 | "dev": "rozenite dev" 12 | }, 13 | "dependencies": { 14 | "@rozenite/plugin-bridge": "workspace:*", 15 | "connect": "^3.7.0", 16 | "expo-atlas": "^0.4.0" 17 | }, 18 | "devDependencies": { 19 | "vite": "^6.0.0", 20 | "@rozenite/vite-plugin": "workspace:*", 21 | "typescript": "^5.7.3", 22 | "rozenite": "workspace:*", 23 | "react-native-web": "0.21.0", 24 | "react": "18.3.1", 25 | "react-dom": "18.3.0", 26 | "react-native": "0.76.0", 27 | "@types/react": "~18.3.12", 28 | "metro-config": "^0.82.5", 29 | "@types/connect": "^3.4.38" 30 | }, 31 | "peerDependencies": { 32 | "react": "*", 33 | "react-native": "*" 34 | }, 35 | "license": "MIT" 36 | } 37 | -------------------------------------------------------------------------------- /packages/cli/src/commands/generate/prompt-for-plugin-info.ts: -------------------------------------------------------------------------------- 1 | import { promptGroup, promptText } from '../../utils/prompts.js'; 2 | import validateNpmPackage from 'validate-npm-package-name'; 3 | import type { PluginInfo } from '../../types.js'; 4 | 5 | export const promptForPluginInfo = async (): Promise => { 6 | return await promptGroup({ 7 | name: () => 8 | promptText({ 9 | message: 'What is the name of the plugin?', 10 | validate: (input: string) => { 11 | if (validateNpmPackage(input).validForNewPackages) { 12 | return undefined; 13 | } 14 | 15 | return 'The name must be a valid NPM package name'; 16 | }, 17 | }), 18 | description: () => 19 | promptText({ 20 | message: 'What is the description of the plugin?', 21 | validate: (input: string) => { 22 | if (input.length > 0) { 23 | return undefined; 24 | } 25 | 26 | return 'The description must be at least 1 character long'; 27 | }, 28 | }), 29 | }); 30 | }; 31 | -------------------------------------------------------------------------------- /packages/network-activity-plugin/src/utils/applyReactNativeRequestHeadersLogic.ts: -------------------------------------------------------------------------------- 1 | import { HttpHeaders, RequestPostData } from '../shared/client'; 2 | import { getHttpHeader } from './getHttpHeader'; 3 | import { inferContentTypeFromPostData } from './inferContentTypeFromPostData'; 4 | 5 | /** 6 | * Partially emulates React Native's behavior for setting HTTP headers. 7 | * 8 | * @see https://github.com/facebook/react-native/blob/de5093c88771977b58f7bec3f3ffa64a9595334e/packages/react-native/Libraries/Network/RCTNetworking.mm#L345-L349 9 | */ 10 | export function applyReactNativeRequestHeadersLogic( 11 | headers: HttpHeaders, 12 | postData?: RequestPostData 13 | ): HttpHeaders { 14 | const existingContentType = getHttpHeader(headers, 'content-type'); 15 | 16 | if (existingContentType) { 17 | return headers; 18 | } 19 | 20 | const inferredContentType = inferContentTypeFromPostData(postData); 21 | 22 | if (!inferredContentType) { 23 | return headers; 24 | } 25 | 26 | return { 27 | ...headers, 28 | 'Content-Type': inferredContentType, 29 | }; 30 | } 31 | -------------------------------------------------------------------------------- /packages/runtime/vite.config.ts: -------------------------------------------------------------------------------- 1 | /// 2 | import { defineConfig } from 'vite'; 3 | import { resolve } from 'path'; 4 | import dts from 'vite-plugin-dts'; 5 | 6 | export default defineConfig({ 7 | plugins: [ 8 | dts({ 9 | rollupTypes: true, 10 | tsconfigPath: resolve(__dirname, 'tsconfig.lib.json'), 11 | }), 12 | ], 13 | root: __dirname, 14 | cacheDir: '../../node_modules/.vite/runtime', 15 | base: './', 16 | build: { 17 | lib: { 18 | entry: resolve(__dirname, 'src/index.ts'), 19 | formats: ['es' as const, 'cjs' as const], 20 | fileName: (format) => `host.${format === 'es' ? 'js' : 'cjs'}`, 21 | }, 22 | rollupOptions: { 23 | external: [ 24 | '/rozenite/ui/legacy/legacy.js', 25 | '/rozenite/core/sdk/sdk.js', 26 | '/rozenite/models/react_native/react_native.js', 27 | ], 28 | output: { 29 | inlineDynamicImports: true, 30 | }, 31 | }, 32 | emptyOutDir: true, 33 | }, 34 | server: { 35 | port: 3000, 36 | open: true, 37 | }, 38 | }); 39 | -------------------------------------------------------------------------------- /packages/network-activity-plugin/src/utils/typeChecks.ts: -------------------------------------------------------------------------------- 1 | export const isBlob = (value: unknown): value is Blob => value instanceof Blob; 2 | 3 | export const isArrayBuffer = ( 4 | value: unknown 5 | ): value is ArrayBuffer | ArrayBufferView => 6 | value instanceof ArrayBuffer || ArrayBuffer.isView(value); 7 | 8 | export const isFormData = (value: unknown): value is FormData => 9 | value instanceof FormData; 10 | 11 | export const isNullOrUndefined = (value: unknown): value is null | undefined => 12 | value === null || value === undefined; 13 | 14 | export const isString = (value: unknown): value is string => 15 | typeof value === 'string'; 16 | 17 | export const isNumber = (value: unknown): value is number => 18 | typeof value === 'number' && !isNaN(value); 19 | 20 | export const isBoolean = (value: unknown): value is boolean => 21 | typeof value === 'boolean'; 22 | 23 | export const isObject = (value: unknown): value is object => 24 | typeof value === 'object' && value !== null; 25 | 26 | export const isArray = (value: unknown): value is unknown[] => 27 | Array.isArray(value); 28 | -------------------------------------------------------------------------------- /apps/playground/src/app/stores/settingsStore.ts: -------------------------------------------------------------------------------- 1 | import { create } from 'zustand'; 2 | 3 | export type PluginSettings = { 4 | tanstackQuery: { 5 | throttleMs: number; 6 | }; 7 | // Example of how easy it is to add new plugin settings: 8 | // networkActivity: { 9 | // enabled: boolean; 10 | // maxRequests: number; 11 | // autoRefresh: boolean; 12 | // }; 13 | // mmkv: { 14 | // enabled: boolean; 15 | // maxEntries: number; 16 | // showTimestamps: boolean; 17 | // }; 18 | }; 19 | 20 | export type SettingsStore = { 21 | settings: PluginSettings; 22 | updateSettings: ( 23 | plugin: K, 24 | settings: Partial 25 | ) => void; 26 | }; 27 | 28 | export const useSettingsStore = create((set) => ({ 29 | settings: { 30 | tanstackQuery: { 31 | throttleMs: 0, 32 | }, 33 | }, 34 | updateSettings: (plugin, settings) => 35 | set((state) => ({ 36 | settings: { 37 | ...state.settings, 38 | [plugin]: { ...state.settings[plugin], ...settings }, 39 | }, 40 | })), 41 | })); 42 | -------------------------------------------------------------------------------- /packages/vite-plugin/templates/panel.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | <%= panelName %> Panel 7 | 22 | 25 | 26 | 27 |
28 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /apps/playground/ios/Playground/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images": [ 3 | { 4 | "idiom": "iphone", 5 | "scale": "2x", 6 | "size": "20x20" 7 | }, 8 | { 9 | "idiom": "iphone", 10 | "scale": "3x", 11 | "size": "20x20" 12 | }, 13 | { 14 | "idiom": "iphone", 15 | "scale": "2x", 16 | "size": "29x29" 17 | }, 18 | { 19 | "idiom": "iphone", 20 | "scale": "3x", 21 | "size": "29x29" 22 | }, 23 | { 24 | "idiom": "iphone", 25 | "scale": "2x", 26 | "size": "40x40" 27 | }, 28 | { 29 | "idiom": "iphone", 30 | "scale": "3x", 31 | "size": "40x40" 32 | }, 33 | { 34 | "idiom": "iphone", 35 | "scale": "2x", 36 | "size": "60x60" 37 | }, 38 | { 39 | "idiom": "iphone", 40 | "scale": "3x", 41 | "size": "60x60" 42 | }, 43 | { 44 | "idiom": "ios-marketing", 45 | "scale": "1x", 46 | "size": "1024x1024" 47 | } 48 | ], 49 | "info": { 50 | "author": "xcode", 51 | "version": 1 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /packages/performance-monitor-plugin/src/ui/components/JsonTree.tsx: -------------------------------------------------------------------------------- 1 | import { JSONTree } from 'react-json-tree'; 2 | 3 | const THEME = { 4 | base00: 'transparent', 5 | base01: '#f3f4f6', // bg-gray-100 6 | base02: '#e5e7eb', // bg-gray-200 7 | base03: '#d1d5db', // text-gray-300 8 | base04: '#9ca3af', // text-gray-400 9 | base05: '#6b7280', // text-gray-500 10 | base06: '#374151', // text-gray-700 11 | base07: '#1f2937', // text-gray-800 12 | base08: '#ef4444', // text-red-500 13 | base09: '#f59e0b', // text-yellow-500 14 | base0A: '#10b981', // text-green-500 15 | base0B: '#3b82f6', // text-blue-500 16 | base0C: '#06b6d4', // text-cyan-500 17 | base0D: '#8b5cf6', // text-purple-500 18 | base0E: '#ec4899', // text-pink-500 19 | base0F: '#f97316', // text-orange-500 20 | }; 21 | 22 | export type JsonTreeProps = { 23 | data: unknown; 24 | }; 25 | 26 | export const JsonTree = ({ data }: JsonTreeProps) => { 27 | return ( 28 | true} 33 | /> 34 | ); 35 | }; 36 | -------------------------------------------------------------------------------- /packages/require-profiler-plugin/src/shared/messaging.ts: -------------------------------------------------------------------------------- 1 | import { RequireChainMeta, RequireChainData } from './types'; 2 | 3 | export type RequireProfilerRequestChainsListEvent = Record; 4 | 5 | export type RequireProfilerChainsListResponseEvent = { 6 | chains: RequireChainMeta[]; 7 | }; 8 | 9 | export type RequireProfilerRequestChainDataEvent = { 10 | chainIndex: number; 11 | }; 12 | 13 | export type RequireProfilerChainDataResponseEvent = { 14 | data: RequireChainData | null; 15 | }; 16 | 17 | export type RequireProfilerReloadAndProfileEvent = Record; 18 | 19 | export type RequireProfilerNewChainEvent = { 20 | chain: RequireChainMeta; 21 | }; 22 | 23 | export type RequireProfilerEventMap = { 24 | 'request-chains-list': RequireProfilerRequestChainsListEvent; 25 | 'chains-list-response': RequireProfilerChainsListResponseEvent; 26 | 'request-chain-data': RequireProfilerRequestChainDataEvent; 27 | 'chain-data-response': RequireProfilerChainDataResponseEvent; 28 | 'reload-and-profile': RequireProfilerReloadAndProfileEvent; 29 | 'new-chain': RequireProfilerNewChainEvent; 30 | }; 31 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 Szymon Chmal 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. -------------------------------------------------------------------------------- /packages/tanstack-query-plugin/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@rozenite/tanstack-query-plugin", 3 | "version": "1.1.0", 4 | "description": "TanStack Query for Rozenite.", 5 | "type": "module", 6 | "main": "./dist/react-native.cjs", 7 | "module": "./dist/react-native.js", 8 | "types": "./dist/react-native.d.ts", 9 | "scripts": { 10 | "build": "rozenite build", 11 | "dev": "rozenite dev" 12 | }, 13 | "dependencies": { 14 | "@rozenite/plugin-bridge": "workspace:*", 15 | "fast-deep-equal": "^3.1.3" 16 | }, 17 | "devDependencies": { 18 | "@rozenite/vite-plugin": "workspace:*", 19 | "@tanstack/react-query": "^5.0.0", 20 | "@tanstack/react-query-devtools": "^5.0.0", 21 | "@types/react": "~18.3.12", 22 | "react": "18.3.1", 23 | "react-dom": "18.3.0", 24 | "react-native": "0.76.0", 25 | "react-native-web": "0.21.0", 26 | "rozenite": "workspace:*", 27 | "typescript": "^5.7.3", 28 | "vite": "^6.0.0" 29 | }, 30 | "peerDependencies": { 31 | "@tanstack/react-query": "^5.0.0", 32 | "react": "*", 33 | "react-native": "*" 34 | }, 35 | "license": "MIT" 36 | } 37 | -------------------------------------------------------------------------------- /packages/middleware/src/dev-tools-url-patch.ts: -------------------------------------------------------------------------------- 1 | import path from 'node:path'; 2 | import { createRequire } from 'node:module'; 3 | import { getDevMiddlewarePath } from './resolve.js'; 4 | import { RozeniteConfig } from './index.js'; 5 | 6 | const require = createRequire(import.meta.url); 7 | 8 | export const patchDevtoolsFrontendUrl = (options: RozeniteConfig): void => { 9 | const getDevToolsFrontendUrlModulePath = path.dirname( 10 | getDevMiddlewarePath(options) 11 | ); 12 | const getDevToolsFrontendUrlModule = require(path.join( 13 | getDevToolsFrontendUrlModulePath, 14 | '/utils/getDevToolsFrontendUrl' 15 | )); 16 | const getDevToolsFrontendUrl = getDevToolsFrontendUrlModule.default; 17 | getDevToolsFrontendUrlModule.default = ( 18 | experiments: unknown, 19 | webSocketDebuggerUrl: string, 20 | devServerUrl: string, 21 | options: unknown 22 | ) => { 23 | const originalUrl = getDevToolsFrontendUrl( 24 | experiments, 25 | webSocketDebuggerUrl, 26 | devServerUrl, 27 | options 28 | ); 29 | return originalUrl.replace('/debugger-frontend/', '/rozenite/'); 30 | }; 31 | }; 32 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/3-documentation.yml: -------------------------------------------------------------------------------- 1 | name: "\U0001F4DA Documentation" 2 | description: 'Suggest a change or new page to be added to rozenite.dev' 3 | type: task 4 | body: 5 | - type: markdown 6 | attributes: 7 | value: Thanks for taking the time to fill out this issue! 8 | - type: checkboxes 9 | id: documentation_is 10 | attributes: 11 | label: Documentation is 12 | options: 13 | - label: Missing 14 | - label: Outdated 15 | - label: Confusing 16 | - label: Not sure? 17 | - type: textarea 18 | id: description 19 | attributes: 20 | label: Explain in Detail 21 | description: A clear and concise description of your suggestion. 22 | placeholder: The description of ... page is not clear. I thought it meant ... but it wasn't. 23 | validations: 24 | required: true 25 | - type: textarea 26 | id: suggestion 27 | attributes: 28 | label: Your Suggestion for Changes 29 | description: 'Describe the changes you have in mind. If you want to submit a PR for this issue, tell us in the description!' 30 | validations: 31 | required: true 32 | -------------------------------------------------------------------------------- /packages/middleware/src/verify-react-native-version.ts: -------------------------------------------------------------------------------- 1 | import fs from 'node:fs'; 2 | import path from 'node:path'; 3 | import semver from 'semver'; 4 | import { logger } from './logger.js'; 5 | import { getReactNativePackagePath } from './resolve.js'; 6 | 7 | const REQUIRED_REACT_NATIVE_VERSION = '0.76.0'; 8 | 9 | export const verifyReactNativeVersion = (projectRoot: string): void => { 10 | const reactNativePath = getReactNativePackagePath(projectRoot); 11 | const packageJsonPath = path.join(reactNativePath, 'package.json'); 12 | const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8')); 13 | const reactNativeVersion = packageJson.version; 14 | 15 | if ( 16 | semver.satisfies(reactNativeVersion, `>=${REQUIRED_REACT_NATIVE_VERSION}`, { 17 | includePrerelease: true, 18 | }) 19 | ) { 20 | return; 21 | } 22 | 23 | logger.error( 24 | `React Native DevTools requires React Native ${REQUIRED_REACT_NATIVE_VERSION} or higher.\n` + 25 | ` Current version: ${reactNativeVersion}\n` + 26 | ` Please upgrade your React Native version to continue using Rozenite.` 27 | ); 28 | process.exit(1); 29 | }; 30 | -------------------------------------------------------------------------------- /website/rspress.config.ts: -------------------------------------------------------------------------------- 1 | import { withCallstackPreset } from '@callstack/rspress-preset'; 2 | import { pluginDirectoryPlugin } from './plugins/plugin-directory'; 3 | 4 | const EDIT_ROOT_URL = `https://github.com/callstackincubator/rozenite/tree/main/website/src`; 5 | 6 | export default withCallstackPreset( 7 | { 8 | context: __dirname, 9 | docs: { 10 | description: 11 | 'Build powerful debugging tools and custom panels for React Native DevTools with type-safe, isomorphic communication', 12 | icon: '/logo.svg', 13 | logoDark: '/logo-dark.svg', 14 | logoLight: '/logo-light.svg', 15 | ogImage: '/og-image.jpg', 16 | rootDir: 'src', 17 | rootUrl: 'https://rozenite.dev', 18 | socials: { 19 | github: 'https://github.com/callstackincubator/rozenite', 20 | discord: 'https://discord.gg/xgGt7KAjxv', 21 | }, 22 | title: 'Rozenite', 23 | editUrl: EDIT_ROOT_URL, 24 | }, 25 | }, 26 | { 27 | outDir: 'build', 28 | builderConfig: {}, 29 | themeConfig: { 30 | enableScrollToTop: true, 31 | }, 32 | plugins: [pluginDirectoryPlugin()], 33 | } 34 | ); 35 | -------------------------------------------------------------------------------- /packages/network-activity-plugin/src/shared/sse-events.ts: -------------------------------------------------------------------------------- 1 | import type { Response } from './client'; 2 | 3 | export type SSEConnectionStatus = 'connecting' | 'open' | 'closed'; 4 | export type SSERequestId = string; 5 | 6 | export type SSEOpenEvent = { 7 | type: 'sse-open'; 8 | requestId: SSERequestId; 9 | timestamp: number; 10 | response: Response; 11 | }; 12 | 13 | export type SSEMessageEvent = { 14 | type: 'sse-message'; 15 | requestId: SSERequestId; 16 | timestamp: number; 17 | payload: { 18 | type: string; 19 | data: string; 20 | }; 21 | }; 22 | 23 | export type SSEErrorEvent = { 24 | type: 'sse-error'; 25 | requestId: SSERequestId; 26 | timestamp: number; 27 | error: { 28 | type: 'error' | 'timeout' | 'exception'; 29 | message: string; 30 | }; 31 | }; 32 | 33 | export type SSECloseEvent = { 34 | type: 'sse-close'; 35 | requestId: SSERequestId; 36 | timestamp: number; 37 | }; 38 | 39 | export type SSEEvent = 40 | | SSEOpenEvent 41 | | SSEMessageEvent 42 | | SSEErrorEvent 43 | | SSECloseEvent; 44 | 45 | export type SSEEventMap = { 46 | [K in SSEEvent['type']]: Extract; 47 | }; 48 | -------------------------------------------------------------------------------- /apps/playground/ios/Playground/PrivacyInfo.xcprivacy: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | NSPrivacyAccessedAPITypes 6 | 7 | 8 | NSPrivacyAccessedAPIType 9 | NSPrivacyAccessedAPICategoryFileTimestamp 10 | NSPrivacyAccessedAPITypeReasons 11 | 12 | C617.1 13 | 14 | 15 | 16 | NSPrivacyAccessedAPIType 17 | NSPrivacyAccessedAPICategoryUserDefaults 18 | NSPrivacyAccessedAPITypeReasons 19 | 20 | CA92.1 21 | 22 | 23 | 24 | NSPrivacyAccessedAPIType 25 | NSPrivacyAccessedAPICategorySystemBootTime 26 | NSPrivacyAccessedAPITypeReasons 27 | 28 | 35F9.1 29 | 30 | 31 | 32 | NSPrivacyCollectedDataTypes 33 | 34 | NSPrivacyTracking 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /packages/network-activity-plugin/src/react-native/utils/getBlobName.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Utility function to get the name of a blob. Handles both the direct name property and the data object. 3 | * 4 | * ``` 5 | * // node_modules/react-native/Libraries/Blob/Blob.js 6 | * 7 | * export type BlobData = { 8 | * blobId: string, 9 | * offset: number, 10 | * size: number, 11 | * name?: string, 12 | * type?: string, 13 | * lastModified?: number, 14 | * __collector?: ?BlobCollector, 15 | * ... 16 | * }; 17 | * 18 | * get data(): BlobData { 19 | * if (!this._data) { 20 | * throw new Error('Blob has been closed and is no longer available'); 21 | * } 22 | * 23 | * return this._data; 24 | * } 25 | * 26 | * get size(): number { 27 | * return this.data.size; 28 | * } 29 | * 30 | * get type(): string { 31 | * return this.data.type || ''; 32 | * } 33 | * ``` 34 | */ 35 | export function getBlobName(blob: any): string | undefined { 36 | if (typeof blob?.name === 'string') { 37 | return blob.name; 38 | } 39 | 40 | if (blob?.data && typeof blob.data.name === 'string') { 41 | return blob.data.name; 42 | } 43 | 44 | return undefined; 45 | } 46 | -------------------------------------------------------------------------------- /packages/react-navigation-plugin/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@rozenite/react-navigation-plugin", 3 | "version": "1.1.0", 4 | "description": "React Navigation for Rozenite.", 5 | "type": "module", 6 | "main": "./dist/react-native.cjs", 7 | "module": "./dist/react-native.js", 8 | "types": "./dist/react-native.d.ts", 9 | "scripts": { 10 | "build": "rozenite build", 11 | "dev": "rozenite dev" 12 | }, 13 | "dependencies": { 14 | "@rozenite/plugin-bridge": "workspace:*", 15 | "fast-deep-equal": "^3.1.3" 16 | }, 17 | "devDependencies": { 18 | "@react-navigation/core": "^7.12.1", 19 | "@rozenite/vite-plugin": "workspace:*", 20 | "@types/react": "~18.3.23", 21 | "@types/react-dom": "~18.3.1", 22 | "autoprefixer": "^10.4.21", 23 | "postcss": "^8.5.6", 24 | "react": "*", 25 | "react-json-tree": "^0.20.0", 26 | "rozenite": "workspace:*", 27 | "tailwind-merge": "^3.3.1", 28 | "tailwindcss": "^3.4.17", 29 | "tailwindcss-animate": "^1.0.7", 30 | "typescript": "^5.7.3", 31 | "vite": "^6.0.0" 32 | }, 33 | "peerDependencies": { 34 | "@react-navigation/core": "^7.12.1" 35 | }, 36 | "license": "MIT" 37 | } 38 | -------------------------------------------------------------------------------- /packages/network-activity-plugin/src/utils/applyReactNativeResponseHeadersLogic.ts: -------------------------------------------------------------------------------- 1 | import { HttpHeaders, XHRHeaders } from '../shared/client'; 2 | import { splitSetCookieHeaderByComma } from './cookieParser'; 3 | import { getHttpHeader } from './getHttpHeader'; 4 | 5 | /** 6 | * Applies React Native specific logic to response headers. 7 | * React Native concatenates multiple header values into single strings, 8 | * this function parses them back into arrays where appropriate. 9 | * 10 | * @see https://github.com/facebook/react-native/blob/588f0c5ce6c283f116228456da2170d2adc3cbf4/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java#L637 11 | */ 12 | export const applyReactNativeResponseHeadersLogic = ( 13 | headers: XHRHeaders 14 | ): HttpHeaders => { 15 | const parsedHeaders: HttpHeaders = { ...headers }; 16 | 17 | const setCookieHeader = getHttpHeader(headers, 'set-cookie'); 18 | 19 | if (setCookieHeader) { 20 | const { value, originalKey } = setCookieHeader; 21 | 22 | const cookies = splitSetCookieHeaderByComma(value); 23 | 24 | parsedHeaders[originalKey] = cookies.length > 0 ? cookies : value; 25 | } 26 | 27 | return parsedHeaders; 28 | }; 29 | -------------------------------------------------------------------------------- /packages/tanstack-query-plugin/src/shared/types.ts: -------------------------------------------------------------------------------- 1 | import type { 2 | QueryKey, 3 | MutationState, 4 | QueryState, 5 | QueryObserverOptions, 6 | InfiniteQueryObserverOptions, 7 | MutationOptions, 8 | } from '@tanstack/react-query'; 9 | 10 | export type SerializableQuery = { 11 | queryHash: string; 12 | state: QueryState; 13 | queryKey: QueryKey; 14 | observers: SerializableObserver[]; 15 | }; 16 | 17 | export type PartialQueryState = { 18 | queryHash: string; 19 | state: Partial; 20 | }; 21 | 22 | export type SerializableMutation = { 23 | mutationId: number; 24 | options: MutationOptions; 25 | state: MutationState; 26 | }; 27 | 28 | export type SerializableObserver = { 29 | queryHash: string; 30 | options: QueryObserverOptions | InfiniteQueryObserverOptions; 31 | }; 32 | 33 | export type SerializableQueryClient = { 34 | queries: SerializableQuery[]; 35 | mutations: SerializableMutation[]; 36 | }; 37 | 38 | export type DevToolsActionType = 39 | | 'REFETCH' 40 | | 'INVALIDATE' 41 | | 'RESET' 42 | | 'REMOVE' 43 | | 'TRIGGER_ERROR' 44 | | 'RESTORE_ERROR' 45 | | 'TRIGGER_LOADING' 46 | | 'RESTORE_LOADING' 47 | | 'CLEAR_MUTATION_CACHE' 48 | | 'CLEAR_QUERY_CACHE'; 49 | -------------------------------------------------------------------------------- /packages/network-activity-plugin/src/ui/components/JsonTreeCopyableItem.tsx: -------------------------------------------------------------------------------- 1 | import { Check, Copy } from 'lucide-react'; 2 | import { MouseEvent, PropsWithChildren } from 'react'; 3 | import { useCopyToClipboard } from '../hooks/useCopyToClipboard'; 4 | import { cn } from '../utils/cn'; 5 | 6 | type JsonTreeCopyableItemProps = PropsWithChildren<{ 7 | getCopyableValue: () => string; 8 | className?: string; 9 | }>; 10 | 11 | export const JsonTreeCopyableItem = ({ 12 | children, 13 | getCopyableValue, 14 | className, 15 | }: JsonTreeCopyableItemProps) => { 16 | const { isCopied, copy } = useCopyToClipboard(); 17 | 18 | const handleCopy = (event: MouseEvent) => { 19 | event.stopPropagation(); 20 | 21 | copy(getCopyableValue()); 22 | }; 23 | 24 | const Icon = isCopied ? Check : Copy; 25 | 26 | return ( 27 | 28 | {children} 29 |
33 | 34 |
35 |
36 | ); 37 | }; 38 | -------------------------------------------------------------------------------- /packages/require-profiler-plugin/src/ui/components/Legend.tsx: -------------------------------------------------------------------------------- 1 | export const Legend = () => { 2 | return ( 3 |
4 |
5 |
6 | Expensive init ({'>'}70%) 7 |
8 |
9 |
10 | Moderate init (40-70%) 11 |
12 |
13 |
14 | Light init (20-40%) 15 |
16 |
17 |
18 | Minimal init ({'<'}20%) 19 |
20 |
21 |
22 | No own time (0ms) 23 |
24 |
25 | ); 26 | }; 27 | -------------------------------------------------------------------------------- /eslint.config.mjs: -------------------------------------------------------------------------------- 1 | import nx from '@nx/eslint-plugin'; 2 | 3 | export default [ 4 | ...nx.configs['flat/base'], 5 | ...nx.configs['flat/typescript'], 6 | ...nx.configs['flat/javascript'], 7 | { 8 | ignores: [ 9 | '**/dist', 10 | '**/vite.config.*.timestamp*', 11 | '**/vitest.config.*.timestamp*', 12 | '**/build', 13 | ], 14 | }, 15 | { 16 | files: ['**/*.ts', '**/*.tsx', '**/*.js', '**/*.jsx'], 17 | rules: { 18 | '@nx/enforce-module-boundaries': [ 19 | 'error', 20 | { 21 | enforceBuildableLibDependency: true, 22 | allow: [ 23 | '^.*/eslint(\\.base)?\\.config\\.[cm]?[jt]s$', 24 | '^@rozenite/.*-plugin$', 25 | ], 26 | depConstraints: [ 27 | { 28 | sourceTag: '*', 29 | onlyDependOnLibsWithTags: ['*'], 30 | }, 31 | ], 32 | }, 33 | ], 34 | }, 35 | }, 36 | { 37 | files: [ 38 | '**/*.ts', 39 | '**/*.tsx', 40 | '**/*.cts', 41 | '**/*.mts', 42 | '**/*.js', 43 | '**/*.jsx', 44 | '**/*.cjs', 45 | '**/*.mjs', 46 | ], 47 | // Override or add rules here 48 | rules: {}, 49 | }, 50 | ]; 51 | -------------------------------------------------------------------------------- /packages/require-profiler-plugin/src/ui/components/InfoBar.tsx: -------------------------------------------------------------------------------- 1 | import { formatTime } from '../transformations'; 2 | 3 | export type InfoBarProps = { 4 | totalTime: number; 5 | totalModules: number; 6 | entryName: string | undefined; 7 | }; 8 | 9 | export const InfoBar = ({ 10 | totalTime, 11 | totalModules, 12 | entryName, 13 | }: InfoBarProps) => { 14 | return ( 15 |
16 |
17 |
18 | Total Time: 19 | {formatTime(totalTime)} 20 |
21 |
22 | Modules: 23 | 24 | {totalModules.toLocaleString()} 25 | 26 |
27 |
28 | Entry: 29 | {entryName ?? 'N/A'} 30 |
31 |
32 |
33 | 34 | Click to zoom in, Esc to reset 35 | 36 |
37 |
38 | ); 39 | }; 40 | -------------------------------------------------------------------------------- /packages/network-activity-plugin/src/react-native/utils.ts: -------------------------------------------------------------------------------- 1 | import { getContentTypeMime } from '../utils/getContentTypeMimeType'; 2 | 3 | type UnionToIntersection = ( 4 | U extends unknown ? (k: U) => void : never 5 | ) extends (k: infer I) => void 6 | ? I 7 | : never; 8 | 9 | type LastOf = UnionToIntersection< 10 | T extends unknown ? () => T : never 11 | > extends () => infer R 12 | ? R 13 | : never; 14 | 15 | type Push = [...T, V]; 16 | 17 | export type UnionToTuple> = [T] extends [never] 18 | ? [] 19 | : Push>, L>; 20 | 21 | export const getContentType = (request: XMLHttpRequest): string => { 22 | const responseHeaders = request.responseHeaders; 23 | const responseType = request.responseType; 24 | 25 | const contentType = getContentTypeMime(responseHeaders || {}); 26 | 27 | if (contentType) { 28 | return contentType; 29 | } 30 | 31 | switch (responseType) { 32 | case 'arraybuffer': 33 | case 'blob': 34 | return 'application/octet-stream'; 35 | case 'text': 36 | case '': 37 | return 'text/plain'; 38 | case 'json': 39 | return 'application/json'; 40 | case 'document': 41 | return 'text/html'; 42 | } 43 | }; 44 | -------------------------------------------------------------------------------- /apps/playground/ios/Playground/AppDelegate.mm: -------------------------------------------------------------------------------- 1 | #import "AppDelegate.h" 2 | 3 | #import 4 | #import 5 | 6 | @implementation AppDelegate 7 | 8 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 9 | { 10 | self.moduleName = @"Playground"; 11 | // You can add your custom initial props in the dictionary below. 12 | // They will be passed down to the ViewController used by React Native. 13 | self.initialProps = @{}; 14 | 15 | return [super application:application didFinishLaunchingWithOptions:launchOptions]; 16 | } 17 | 18 | - (NSURL *)sourceURLForBridge:(RCTBridge *)bridge 19 | { 20 | return [self bundleURL]; 21 | } 22 | 23 | - (NSURL *)bundleURL 24 | { 25 | #if DEBUG 26 | return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"src/main"]; 27 | #else 28 | return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"]; 29 | #endif 30 | } 31 | 32 | - (BOOL)application:(UIApplication *)application 33 | openURL:(NSURL *)url 34 | options:(NSDictionary *)options 35 | { 36 | return [RCTLinkingManager application:application openURL:url options:options]; 37 | } 38 | 39 | @end 40 | -------------------------------------------------------------------------------- /packages/expo-atlas-plugin/src/with-expo-atlas.ts: -------------------------------------------------------------------------------- 1 | import { createExpoAtlasMiddleware } from 'expo-atlas/cli'; 2 | import connect from 'connect'; 3 | import type { ConfigT as MetroConfig } from 'metro-config'; 4 | import { createMetroConfigTransformer } from '@rozenite/tools'; 5 | import { getBaseSerializer } from './base-serializer'; 6 | 7 | export const withRozeniteExpoAtlasPlugin = createMetroConfigTransformer( 8 | async (config: MetroConfig): Promise => { 9 | const basicConfig = { 10 | ...config, 11 | serializer: { 12 | ...config.serializer, 13 | customSerializer: 14 | config?.serializer?.customSerializer ?? getBaseSerializer(), 15 | }, 16 | }; 17 | const instance = createExpoAtlasMiddleware(basicConfig); 18 | 19 | return { 20 | ...basicConfig, 21 | server: { 22 | ...basicConfig.server, 23 | enhanceMiddleware: (middleware, server) => { 24 | const prevMiddleware = 25 | basicConfig.server?.enhanceMiddleware?.(middleware, server) ?? 26 | middleware; 27 | 28 | return connect() 29 | .use(prevMiddleware) 30 | .use('/_expo/atlas', instance.middleware); 31 | }, 32 | }, 33 | }; 34 | }, 35 | ); 36 | -------------------------------------------------------------------------------- /packages/plugin-bridge/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@rozenite/plugin-bridge", 3 | "version": "1.1.0", 4 | "description": "Communication layer for React Native DevTools plugins across React Native and web environments", 5 | "type": "module", 6 | "main": "./dist/index.cjs", 7 | "module": "./dist/index.js", 8 | "types": "./dist/index.d.ts", 9 | "files": [ 10 | "dist" 11 | ], 12 | "keywords": [ 13 | "react-native", 14 | "devtools", 15 | "plugin", 16 | "bridge", 17 | "isomorphic" 18 | ], 19 | "homepage": "https://github.com/callstackincubator/rozenite#readme", 20 | "bugs": { 21 | "url": "https://github.com/callstackincubator/rozenite/issues" 22 | }, 23 | "repository": { 24 | "type": "git", 25 | "url": "https://github.com/callstackincubator/rozenite.git" 26 | }, 27 | "author": "Szymon Chmal ", 28 | "license": "MIT", 29 | "exports": { 30 | ".": { 31 | "types": "./dist/index.d.ts", 32 | "import": "./dist/index.js", 33 | "require": "./dist/index.cjs" 34 | } 35 | }, 36 | "dependencies": { 37 | "tslib": "^2.3.0" 38 | }, 39 | "devDependencies": {}, 40 | "peerDependencies": { 41 | "react": ">=17" 42 | }, 43 | "engines": { 44 | "node": ">=20" 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /packages/require-profiler-plugin/src/react-native/timings.ts: -------------------------------------------------------------------------------- 1 | import { RequireChainMeta, RequireChainData } from '../shared'; 2 | 3 | export const getRequireChainsList = (): RequireChainMeta[] => { 4 | if ( 5 | !('getRequireChainsList' in global) || 6 | typeof global.getRequireChainsList !== 'function' 7 | ) { 8 | return []; 9 | } 10 | 11 | return global.getRequireChainsList(); 12 | }; 13 | 14 | export const getRequireChainData = (index: number): RequireChainData | null => { 15 | if ( 16 | !('getRequireChainData' in global) || 17 | typeof global.getRequireChainData !== 'function' 18 | ) { 19 | return null; 20 | } 21 | 22 | return global.getRequireChainData(index); 23 | }; 24 | 25 | export const onRequireChainComplete = ( 26 | callback: (chain: RequireChainMeta) => void, 27 | ): (() => void) => { 28 | if ( 29 | !('__onRequireChainComplete' in global) || 30 | typeof (global as Record).__onRequireChainComplete !== 31 | 'function' 32 | ) { 33 | return () => { 34 | // Return no-op unsubscribe if not available 35 | }; 36 | } 37 | 38 | return ( 39 | global.__onRequireChainComplete as ( 40 | callback: (chain: RequireChainMeta) => void, 41 | ) => () => void 42 | )(callback) as () => void; 43 | }; 44 | -------------------------------------------------------------------------------- /packages/tanstack-query-plugin/src/ui/tanstack-query.tsx: -------------------------------------------------------------------------------- 1 | import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; 2 | import { ReactQueryDevtoolsPanel } from '@tanstack/react-query-devtools/production'; 3 | import { useRozeniteDevToolsClient } from '@rozenite/plugin-bridge'; 4 | import { TanStackQueryPluginEventMap } from '../shared/messaging'; 5 | import { useSyncInitialData } from './useSyncInitialData'; 6 | import { useSyncDevToolsEvents } from './useSyncDevToolsEvents'; 7 | import { useSyncOnlineStatus } from '../shared/useSyncOnlineStatus'; 8 | import { useHandleSyncMessages } from './useHandleSyncMessages'; 9 | 10 | const App = () => { 11 | const client = useRozeniteDevToolsClient({ 12 | pluginId: '@rozenite/tanstack-query-plugin', 13 | }); 14 | 15 | useSyncInitialData(client); 16 | 17 | useSyncDevToolsEvents(client); 18 | 19 | useSyncOnlineStatus(client); 20 | 21 | useHandleSyncMessages(client); 22 | 23 | return ; 24 | }; 25 | 26 | const queryClient = new QueryClient(); 27 | 28 | export default function TanStackQueryPanel() { 29 | return ( 30 | 31 | 32 | 33 | ); 34 | } 35 | -------------------------------------------------------------------------------- /apps/playground/ios/Podfile: -------------------------------------------------------------------------------- 1 | # Resolve react_native_pods.rb with node to allow for hoisting 2 | require Pod::Executable.execute_command('node', ['-p', 3 | 'require.resolve( 4 | "react-native/scripts/react_native_pods.rb", 5 | {paths: [process.argv[1]]}, 6 | )', __dir__]).strip 7 | 8 | platform :ios, min_ios_version_supported 9 | prepare_react_native_project! 10 | 11 | linkage = ENV['USE_FRAMEWORKS'] 12 | if linkage != nil 13 | Pod::UI.puts "Configuring Pod with #{linkage}ally linked Frameworks".green 14 | use_frameworks! :linkage => linkage.to_sym 15 | end 16 | 17 | target 'Playground' do 18 | config = use_native_modules! 19 | 20 | use_react_native!( 21 | :path => config[:reactNativePath], 22 | # An absolute path to your application root. 23 | :app_path => "#{Pod::Config.instance.installation_root}/.." 24 | ) 25 | 26 | target 'PlaygroundTests' do 27 | inherit! :complete 28 | # Pods for testing 29 | end 30 | 31 | post_install do |installer| 32 | # https://github.com/facebook/react-native/blob/main/packages/react-native/scripts/react_native_pods.rb#L197-L202 33 | react_native_post_install( 34 | installer, 35 | config[:reactNativePath], 36 | :mac_catalyst_enabled => false, 37 | # :ccache_enabled => true 38 | ) 39 | end 40 | end 41 | -------------------------------------------------------------------------------- /packages/react-navigation-plugin/src/devtools-ui/components/Tabs.tsx: -------------------------------------------------------------------------------- 1 | import { ReactNode } from 'react'; 2 | 3 | export type Tab = { 4 | id: string; 5 | label: string; 6 | content: ReactNode; 7 | }; 8 | 9 | export type TabsProps = { 10 | tabs: Tab[]; 11 | activeTabId: string; 12 | onTabChange: (tabId: string) => void; 13 | }; 14 | 15 | export const Tabs = ({ tabs, activeTabId, onTabChange }: TabsProps) => { 16 | return ( 17 |
18 | {/* Tab Headers */} 19 |
20 | {tabs.map((tab) => ( 21 | 32 | ))} 33 |
34 | 35 | {/* Tab Content */} 36 |
37 | {tabs.find((tab) => tab.id === activeTabId)?.content} 38 |
39 |
40 | ); 41 | }; 42 | -------------------------------------------------------------------------------- /packages/performance-monitor-plugin/src/ui/components/MarksTable.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { ColumnDef } from '@tanstack/react-table'; 3 | import { Text } from '@radix-ui/themes'; 4 | import { SerializedPerformanceMark } from '../../shared/types'; 5 | import { DataTable } from './DataTable'; 6 | import { formatTime } from '../utils'; 7 | 8 | export type MarksTableProps = { 9 | marks: SerializedPerformanceMark[]; 10 | onRowClick?: (mark: SerializedPerformanceMark) => void; 11 | }; 12 | 13 | const columns: ColumnDef[] = [ 14 | { 15 | accessorKey: 'name', 16 | header: 'Name', 17 | cell: ({ row }) => {row.getValue('name')}, 18 | }, 19 | { 20 | accessorKey: 'startTime', 21 | header: 'Recorded at', 22 | cell: ({ row }) => { 23 | const startTime = row.getValue('startTime') as number; 24 | return ( 25 | 26 | {formatTime(startTime)} 27 | 28 | ); 29 | }, 30 | }, 31 | ]; 32 | 33 | export const MarksTable = ({ marks, onRowClick }: MarksTableProps) => { 34 | return ( 35 | 41 | ); 42 | }; 43 | -------------------------------------------------------------------------------- /apps/playground/android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /packages/network-activity-plugin/src/react-native/config.ts: -------------------------------------------------------------------------------- 1 | export type InspectorType = 'http' | 'websocket' | 'sse'; 2 | 3 | export type NetworkActivityDevToolsConfig = { 4 | /** 5 | * Specifies which network inspectors are enabled. 6 | * Set to `false` to disable monitoring for a specific type of network traffic. 7 | * @default { http: true, websocket: true, sse: true } 8 | */ 9 | inspectors?: { 10 | [key in InspectorType]?: boolean; 11 | }; 12 | clientUISettings?: { 13 | /** 14 | * If true, display the entire relative URL as the request name in the UI instead of only the last path segment. 15 | * @default false 16 | */ 17 | showUrlAsName?: boolean; 18 | }; 19 | }; 20 | 21 | export const DEFAULT_CONFIG: NetworkActivityDevToolsConfig = { 22 | inspectors: { 23 | http: true, 24 | websocket: true, 25 | sse: true, 26 | }, 27 | clientUISettings: { 28 | showUrlAsName: false, 29 | } 30 | }; 31 | 32 | export const validateConfig = (config: NetworkActivityDevToolsConfig): void => { 33 | const inspectors = config.inspectors; 34 | 35 | if (!inspectors) { 36 | return; 37 | } 38 | 39 | // For SSE, HTTP must be enabled 40 | if (inspectors.sse && !inspectors.http) { 41 | throw new Error('SSE inspector requires HTTP inspector to be enabled.'); 42 | } 43 | }; 44 | -------------------------------------------------------------------------------- /packages/network-activity-plugin/src/ui/components/Badge.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { cva, type VariantProps } from 'class-variance-authority'; 3 | 4 | import { cn } from '../utils/cn'; 5 | 6 | const badgeVariants = cva( 7 | 'inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2', 8 | { 9 | variants: { 10 | variant: { 11 | default: 12 | 'border-transparent bg-primary text-primary-foreground hover:bg-primary/80', 13 | secondary: 14 | 'border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80', 15 | destructive: 16 | 'border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80', 17 | outline: 'text-foreground', 18 | }, 19 | }, 20 | defaultVariants: { 21 | variant: 'default', 22 | }, 23 | } 24 | ); 25 | 26 | export interface BadgeProps 27 | extends React.HTMLAttributes, 28 | VariantProps {} 29 | 30 | function Badge({ className, variant, ...props }: BadgeProps) { 31 | return ( 32 |
33 | ); 34 | } 35 | 36 | export { Badge, badgeVariants }; 37 | -------------------------------------------------------------------------------- /packages/react-navigation-plugin/src/devtools-ui/components/NavigationTree/navigationTreeColors.ts: -------------------------------------------------------------------------------- 1 | const colorMap: Record = {}; 2 | let currentIndex = 0; 3 | 4 | export const colorList = [ 5 | 'red', 6 | 'orange', 7 | 'amber', 8 | 'yellow', 9 | 'lime', 10 | 'green', 11 | 'emerald', 12 | 'teal', 13 | 'cyan', 14 | 'sky', 15 | 'blue', 16 | 'indigo', 17 | 'violet', 18 | 'purple', 19 | 'fuchsia', 20 | 'pink', 21 | 'rose', 22 | ] as const; 23 | 24 | type NavigationTreeColors = (typeof colorList)[number]; 25 | 26 | export const getNavigationTreeColor = (color: NavigationTreeColors): string => { 27 | return `text-${color}-600`; 28 | }; 29 | 30 | export const getNavigationTreeBorderColor = ( 31 | color: NavigationTreeColors 32 | ): string => { 33 | return `border-${color}-600`; 34 | }; 35 | 36 | export const getNavigationTreeBackgroundColor = ( 37 | color: NavigationTreeColors 38 | ): string => { 39 | return `bg-${color}-600`; 40 | }; 41 | 42 | export const generateColor = (key: string): NavigationTreeColors => { 43 | if (colorMap[key]) { 44 | return colorMap[key]; 45 | } 46 | 47 | currentIndex = (currentIndex + 1) % colorList.length; 48 | const newColor = colorList[currentIndex]; 49 | 50 | colorMap[key] = newColor; 51 | 52 | return newColor; 53 | }; 54 | --------------------------------------------------------------------------------