Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
ad896bf
feat: Deeplinks Support + Raycast Extension
Excellencedev Jan 24, 2026
a8c5a6f
logic fixes
Excellencedev Jan 24, 2026
540922e
Update apps/raycast-extension/package.json
Excellencedev Jan 24, 2026
c50550f
Update apps/desktop/src-tauri/src/lib.rs
Excellencedev Jan 24, 2026
c3f0cf7
Update apps/desktop/src-tauri/src/lib.rs
Excellencedev Jan 24, 2026
5c793f9
Update apps/raycast-extension/src/utils.ts
Excellencedev Jan 24, 2026
0c7fa42
Update apps/desktop/src-tauri/src/lib.rs
Excellencedev Jan 24, 2026
4036ae5
Update apps/raycast-extension/src/utils.ts
Excellencedev Jan 24, 2026
5380812
Update apps/desktop/src-tauri/src/lib.rs
Excellencedev Jan 24, 2026
f79d56a
Update apps/desktop/src-tauri/src/lib.rs
Excellencedev Jan 24, 2026
75d77e4
Update apps/desktop/src-tauri/src/lib.rs
Excellencedev Jan 24, 2026
8e6beb1
Update apps/desktop/src-tauri/src/lib.rs
Excellencedev Jan 24, 2026
e0c15f1
Update apps/desktop/src-tauri/src/lib.rs
Excellencedev Jan 24, 2026
3ea5202
Update apps/desktop/src-tauri/src/lib.rs
Excellencedev Jan 24, 2026
752bfa9
Update apps/desktop/src-tauri/src/lib.rs
Excellencedev Jan 24, 2026
c1c6a46
Update apps/desktop/src-tauri/src/lib.rs
Excellencedev Jan 24, 2026
d4760c3
Update apps/desktop/src-tauri/src/lib.rs
Excellencedev Jan 24, 2026
4f1d6a8
manual fixes
Excellencedev Jan 24, 2026
3ad5663
Update apps/desktop/src-tauri/src/lib.rs
Excellencedev Jan 24, 2026
7360964
Update apps/desktop/src-tauri/src/lib.rs
Excellencedev Jan 24, 2026
d44c8c3
Update apps/raycast-extension/src/start-recording.tsx
Excellencedev Jan 24, 2026
6f335ea
Update apps/desktop/src-tauri/src/deeplink_actions.rs
Excellencedev Jan 24, 2026
9a7d1f4
Update apps/desktop/src-tauri/src/lib.rs
Excellencedev Jan 24, 2026
1371856
Update apps/desktop/src-tauri/src/lib.rs
Excellencedev Jan 24, 2026
eeb2da1
Update apps/desktop/src-tauri/src/lib.rs
Excellencedev Jan 24, 2026
8a6c82e
Update apps/desktop/src-tauri/src/lib.rs
Excellencedev Jan 24, 2026
12903b9
improve manually
Excellencedev Jan 24, 2026
31af095
Update apps/desktop/src-tauri/src/deeplink_actions.rs
Excellencedev Jan 24, 2026
d5c8eea
Update apps/desktop/src-tauri/src/deeplink_actions.rs
Excellencedev Jan 24, 2026
6b37436
Update apps/desktop/src-tauri/src/lib.rs
Excellencedev Jan 24, 2026
896b791
Update apps/desktop/src-tauri/src/deeplink_actions.rs
Excellencedev Jan 24, 2026
1312514
Update apps/desktop/src-tauri/src/deeplink_actions.rs
Excellencedev Jan 24, 2026
02cd15c
Update apps/desktop/src-tauri/src/deeplink_actions.rs
Excellencedev Jan 24, 2026
4a1cc86
Update apps/raycast-extension/README.md
Excellencedev Jan 24, 2026
93dc03d
Update apps/desktop/src-tauri/src/lib.rs
Excellencedev Jan 24, 2026
53c9025
Update apps/desktop/src-tauri/src/lib.rs
Excellencedev Jan 24, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 72 additions & 0 deletions apps/desktop/src-tauri/src/deeplink_actions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,24 @@ pub enum DeepLinkAction {
capture_system_audio: bool,
mode: RecordingMode,
},
StartDefaultRecording,
StopRecording,
OpenEditor {
project_path: PathBuf,
},
OpenSettings {
page: Option<String>,
},
PauseRecording,
ResumeRecording,
SetMicrophone {
label: Option<String>,
},
SetCamera {
id: Option<DeviceOrModelID>,
},
CycleMicrophone,
CycleCamera,
}

pub fn handle(app_handle: &AppHandle, urls: Vec<Url>) {
Expand Down Expand Up @@ -143,6 +154,30 @@ impl DeepLinkAction {
.await
.map(|_| ())
}
DeepLinkAction::StartDefaultRecording => {
let permissions = crate::permissions::do_permissions_check(false);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor security/UX thought: StartDefaultRecording is easy to trigger from outside the app (websites can open custom schemes). Might be worth gating recording-control deeplinks behind an opt-in setting or a lightweight confirmation when the trigger isn’t clearly user-initiated (e.g. Raycast).

if !permissions.screen_recording.permitted() {
return Err("Screen recording permission denied".to_string());
}

let displays = cap_recording::screen_capture::list_displays();
if let Some((display, _)) = displays.first() {
let state = app.state::<ArcLock<App>>();

let inputs = StartRecordingInputs {
mode: RecordingMode::Instant,
capture_target: ScreenCaptureTarget::Display { id: display.id },
capture_system_audio: false,
organization_id: None,
};

crate::recording::start_recording(app.clone(), state, inputs)
.await
.map(|_| ())
} else {
Err("No displays found".to_string())
}
}
DeepLinkAction::StopRecording => {
crate::recording::stop_recording(app.clone(), app.state()).await
}
Expand All @@ -152,6 +187,43 @@ impl DeepLinkAction {
DeepLinkAction::OpenSettings { page } => {
crate::show_window(app.clone(), ShowCapWindow::Settings { page }).await
}
DeepLinkAction::PauseRecording => {
crate::recording::pause_recording(app.clone(), app.state()).await
}
DeepLinkAction::ResumeRecording => {
crate::recording::resume_recording(app.clone(), app.state()).await
}
crate::recording::pause_recording(app.clone(), app.state()).await
}
DeepLinkAction::ResumeRecording => {
crate::recording::resume_recording(app.clone(), app.state()).await
}
Comment on lines +190 to +200
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

syntax: duplicate match arms cause compilation error. Lines 196-200 repeat the PauseRecording and ResumeRecording cases.

Suggested change
DeepLinkAction::PauseRecording => {
crate::recording::pause_recording(app.clone(), app.state()).await
}
DeepLinkAction::ResumeRecording => {
crate::recording::resume_recording(app.clone(), app.state()).await
}
crate::recording::pause_recording(app.clone(), app.state()).await
}
DeepLinkAction::ResumeRecording => {
crate::recording::resume_recording(app.clone(), app.state()).await
}
DeepLinkAction::PauseRecording => {
crate::recording::pause_recording(app.clone(), app.state()).await
}
DeepLinkAction::ResumeRecording => {
crate::recording::resume_recording(app.clone(), app.state()).await
}
DeepLinkAction::SetMicrophone { label } => {
Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/desktop/src-tauri/src/deeplink_actions.rs
Line: 190:200

Comment:
**syntax:** duplicate match arms cause compilation error. Lines 196-200 repeat the `PauseRecording` and `ResumeRecording` cases.

```suggestion
            DeepLinkAction::PauseRecording => {
                crate::recording::pause_recording(app.clone(), app.state()).await
            }
            DeepLinkAction::ResumeRecording => {
                crate::recording::resume_recording(app.clone(), app.state()).await
            }
            DeepLinkAction::SetMicrophone { label } => {
```

How can I resolve this? If you propose a fix, please make it concise.

DeepLinkAction::SetMicrophone { label } => {
let permissions = crate::permissions::do_permissions_check(false);
if !permissions.microphone.permitted() {
return Err("Microphone permission denied".to_string());
}

let state = app.state::<ArcLock<App>>();
crate::set_mic_input(state, label).await
}
DeepLinkAction::SetCamera { id } => {
let permissions = crate::permissions::do_permissions_check(false);
if !permissions.camera.permitted() {
return Err("Camera permission denied".to_string());
}

let state = app.state::<ArcLock<App>>();
crate::set_camera_input(app.clone(), state, id).await
}
DeepLinkAction::CycleMicrophone => {
let state = app.state::<ArcLock<App>>();
crate::cycle_mic_input(state).await
}
Comment on lines +219 to +222
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style: missing permissions check before cycling microphone. Other microphone operations (like SetMicrophone on line 202) check permissions first.

Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/desktop/src-tauri/src/deeplink_actions.rs
Line: 219:222

Comment:
**style:** missing permissions check before cycling microphone. Other microphone operations (like `SetMicrophone` on line 202) check permissions first.

How can I resolve this? If you propose a fix, please make it concise.

DeepLinkAction::CycleCamera => {
let state = app.state::<ArcLock<App>>();
crate::cycle_camera_input(app.clone(), state).await
}
Comment on lines +223 to +226
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style: missing permissions check before cycling camera. Other camera operations (like SetCamera on line 211) check permissions first.

Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/desktop/src-tauri/src/deeplink_actions.rs
Line: 223:226

Comment:
**style:** missing permissions check before cycling camera. Other camera operations (like `SetCamera` on line 211) check permissions first.

How can I resolve this? If you propose a fix, please make it concise.

}
}
}
84 changes: 84 additions & 0 deletions apps/desktop/src-tauri/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -588,6 +588,90 @@ async fn set_camera_input(
Ok(())
}

#[tauri::command]
#[specta::specta]
#[instrument(skip(state))]
pub async fn cycle_mic_input(state: MutableState<'_, App>) -> Result<(), String> {
Comment on lines +591 to +594
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

logic: cycle_mic_input not registered in tauri_specta::collect_commands! around line 2673. Add it after set_camera_input on line 2675 so it's callable from deeplinks.

Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/desktop/src-tauri/src/lib.rs
Line: 591:594

Comment:
**logic:** `cycle_mic_input` not registered in `tauri_specta::collect_commands!` around line 2673. Add it after `set_camera_input` on line 2675 so it's callable from deeplinks.

How can I resolve this? If you propose a fix, please make it concise.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since this is annotated as a #[tauri::command] + #[specta::specta], make sure it's also included in the tauri_specta::collect_commands![] list; otherwise it won't be exposed to the frontend/typegen.

if !permissions::do_permissions_check(false)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this is used via deeplink/Raycast, returning Ok(()) on denied permissions makes failures silent. I'd return an error here so callers/logs can distinguish no-op vs success.

Suggested change
if !permissions::do_permissions_check(false)
if !permissions::do_permissions_check(false).microphone.permitted() {
return Err("Microphone permission denied".to_string());
}

.microphone
.permitted()
{
return Ok(());
}

let current_label = {
let app = state.read().await;
app.selected_mic_label.clone()
};

let mut mic_list = MicrophoneFeed::list().keys().cloned().collect::<Vec<_>>();
mic_list.sort_unstable();

if mic_list.is_empty() {
return Ok(());
}

let next_label = match current_label {
Some(label) => {
let index = mic_list.iter().position(|l| l == &label);
match index {
Some(i) => mic_list.get((i + 1) % mic_list.len()).cloned(),
None => mic_list.first().cloned(),
}
}
None => mic_list.first().cloned(),
};

set_mic_input(state, next_label).await
}

#[tauri::command]
#[specta::specta]
#[instrument(skip(app_handle, state))]
pub async fn cycle_camera_input(
Comment on lines +628 to +631
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

logic: cycle_camera_input not registered in tauri_specta::collect_commands! around line 2673. Add it after cycle_mic_input so it's callable from deeplinks.

Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/desktop/src-tauri/src/lib.rs
Line: 628:631

Comment:
**logic:** `cycle_camera_input` not registered in `tauri_specta::collect_commands!` around line 2673. Add it after `cycle_mic_input` so it's callable from deeplinks.

How can I resolve this? If you propose a fix, please make it concise.

app_handle: AppHandle,
state: MutableState<'_, App>,
) -> Result<(), String> {
if !permissions::do_permissions_check(false).camera.permitted() {
return Err("Camera permission denied".to_string());
}
if !permissions::do_permissions_check(false).camera.permitted() {
return Err("Camera permission denied".to_string());
}
}
Comment on lines +635 to +641
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

syntax: duplicate permission check and orphaned closing brace cause compilation error. Lines 638-641 repeat the check and have an extra }.

Suggested change
if !permissions::do_permissions_check(false).camera.permitted() {
return Err("Camera permission denied".to_string());
}
if !permissions::do_permissions_check(false).camera.permitted() {
return Err("Camera permission denied".to_string());
}
}
if !permissions::do_permissions_check(false).camera.permitted() {
return Err("Camera permission denied".to_string());
}
let current_id = {
Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/desktop/src-tauri/src/lib.rs
Line: 635:641

Comment:
**syntax:** duplicate permission check and orphaned closing brace cause compilation error. Lines 638-641 repeat the check and have an extra `}`.

```suggestion
    if !permissions::do_permissions_check(false).camera.permitted() {
        return Err("Camera permission denied".to_string());
    }

    let current_id = {
```

How can I resolve this? If you propose a fix, please make it concise.


let current_id = {
let app = state.read().await;
app.selected_camera_id.clone()
};

let camera_list = cap_camera::list_cameras().collect::<Vec<_>>();

if camera_list.is_empty() {
return Ok(());
}

let current_index = match current_id {
Some(id) => camera_list.iter().position(|c| match &id {
DeviceOrModelID::DeviceID(dev_id) => c.device_id() == dev_id,
DeviceOrModelID::ModelID(mod_id) => c.model_id().is_some_and(|m| m == mod_id),
}),
None => None,
};

let next_camera = match current_index {
Some(i) => camera_list.get((i + 1) % camera_list.len()),
None => camera_list.first(),
};

let next_id = next_camera.map(|c| DeviceOrModelID::DeviceID(c.device_id().to_string()));
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor: using DeviceOrModelID::from_info here preserves ModelID when available (which is usually the more stable identifier).

Suggested change
let next_id = next_camera.map(|c| DeviceOrModelID::DeviceID(c.device_id().to_string()));
let next_id = next_camera.map(DeviceOrModelID::from_info);

let next_id = next_camera.map(|c| match c.model_id() {
Some(model_id) => DeviceOrModelID::ModelID(model_id.to_string()),
None => DeviceOrModelID::DeviceID(c.device_id().to_string()),
});
Comment on lines +667 to +671
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

syntax: next_id is computed twice with different logic - the second assignment overwrites the first. The second one (lines 668-671) is the correct implementation as it prefers ModelID.

Suggested change
let next_id = next_camera.map(|c| DeviceOrModelID::DeviceID(c.device_id().to_string()));
let next_id = next_camera.map(|c| match c.model_id() {
Some(model_id) => DeviceOrModelID::ModelID(model_id.to_string()),
None => DeviceOrModelID::DeviceID(c.device_id().to_string()),
});
let next_id = next_camera.map(|c| match c.model_id() {
Some(model_id) => DeviceOrModelID::ModelID(model_id.to_string()),
None => DeviceOrModelID::DeviceID(c.device_id().to_string()),
});
Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/desktop/src-tauri/src/lib.rs
Line: 667:671

Comment:
**syntax:** `next_id` is computed twice with different logic - the second assignment overwrites the first. The second one (lines 668-671) is the correct implementation as it prefers ModelID.

```suggestion
    let next_id = next_camera.map(|c| match c.model_id() {
        Some(model_id) => DeviceOrModelID::ModelID(model_id.to_string()),
        None => DeviceOrModelID::DeviceID(c.device_id().to_string()),
    });
```

How can I resolve this? If you propose a fix, please make it concise.

set_camera_input(app_handle, state, next_id).await
}

fn spawn_mic_error_handler(app_handle: AppHandle, error_rx: flume::Receiver<StreamError>) {
tokio::spawn(async move {
let state = app_handle.state::<ArcLock<App>>();
Expand Down
20 changes: 20 additions & 0 deletions apps/raycast-extension/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Cap Control Raycast Extension

Control the Cap desktop app from Raycast.

## Commands

- **Start Recording**: Starts a new recording (defaults to first display).
- **Stop Recording**: Stops the current recording.
- **Pause Recording**: Pauses the current recording.
- **Resume Recording**: Resumes the current recording.
- **Switch Camera**: Cycles through available cameras.
- **Switch Microphone**: Cycles through available microphones.

## Installation

1. `cd apps/raycast-extension`
2. `pnpm install`
3. `pnpm build`
3. `npm run build`
Comment on lines +18 to +19
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

syntax: duplicate build step with conflicting commands. Line 18 says pnpm build but line 19 says npm run build.

Suggested change
3. `pnpm build`
3. `npm run build`
3. `npm run build`
Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/raycast-extension/README.md
Line: 18:19

Comment:
**syntax:** duplicate build step with conflicting commands. Line 18 says `pnpm build` but line 19 says `npm run build`.

```suggestion
3. `npm run build`
```

How can I resolve this? If you propose a fix, please make it concise.

4. Import into Raycast via "Import Extension".
Binary file added apps/raycast-extension/assets/command-icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
73 changes: 73 additions & 0 deletions apps/raycast-extension/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
{
"$schema": "https://www.raycast.com/schemas/extension.json",
"name": "cap-control",
"version": "0.0.0",
"private": true,
"title": "Cap Control",
"description": "Control Cap desktop app",
"icon": "command-icon.png",
"author": "CapSoftware",
"categories": [
"Productivity",
"Media"
],
"license": "MIT",
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This repo isn't MIT-licensed overall (see root LICENSE), so MIT here is probably misleading. I'd drop the field unless you intend to license this extension differently.

Suggested change
"license": "MIT",
"categories": [
"Productivity",
"Media"
],
"commands": [

"commands": [
{
"name": "start-recording",
"title": "Start Recording",
"description": "Start a new recording",
"mode": "no-view"
},
{
"name": "stop-recording",
"title": "Stop Recording",
"description": "Stop current recording",
"mode": "no-view"
},
{
"name": "pause-recording",
"title": "Pause Recording",
"description": "Pause current recording",
"mode": "no-view"
},
{
"name": "resume-recording",
"title": "Resume Recording",
"description": "Resume current recording",
"mode": "no-view"
},
{
"name": "switch-camera",
"title": "Switch Camera",
"description": "Cycle through available cameras",
"mode": "no-view"
},
{
"name": "switch-microphone",
"title": "Switch Microphone",
"description": "Cycle through available microphones",
"mode": "no-view"
}
],
"dependencies": {
"@raycast/api": "^1.69.0",
"@raycast/utils": "^1.13.0"
},
"devDependencies": {
"@raycast/eslint-config": "^1.0.6",
"@types/node": "20.8.10",
"@types/react": "18.2.27",
"eslint": "^8.51.0",
"prettier": "^3.0.3",
"typescript": "^5.2.2"
},
"scripts": {
"build": "ray build -e dist",
"dev": "ray develop",
"fix-lint": "ray lint --fix",
"lint": "ray lint",
"prepublishOnly": "echo \"\\n\\nIt seems like you are trying to publish the Raycast extension to npm.\\n\\nIf you did intend to publish it to npm, remove the \\`prepublishOnly\\` script and rerun \\`npm publish\\` again.\\nIf you wanted to publish it to the Raycast Store instead, use \\`npm run publish\\` instead.\\n\\n\" && exit 1",
"publish": "npx @raycast/api@latest publish"
}
}
5 changes: 5 additions & 0 deletions apps/raycast-extension/src/pause-recording.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { sendCapCommand } from "./utils";

export default async function Command() {
await sendCapCommand("pause_recording", "Recording Paused");
}
5 changes: 5 additions & 0 deletions apps/raycast-extension/src/resume-recording.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { sendCapCommand } from "./utils";

export default async function Command() {
await sendCapCommand("resume_recording", "Recording Resumed");
}
5 changes: 5 additions & 0 deletions apps/raycast-extension/src/start-recording.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { sendCapCommand } from "./utils";

export default async function Command() {
await sendCapCommand("start_default_recording", "Recording Started");
}
5 changes: 5 additions & 0 deletions apps/raycast-extension/src/stop-recording.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { sendCapCommand } from "./utils";

export default async function Command() {
await sendCapCommand("stop_recording", "Recording Stopped");
}
5 changes: 5 additions & 0 deletions apps/raycast-extension/src/switch-camera.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { sendCapCommand } from "./utils";

export default async function Command() {
await sendCapCommand("cycle_camera", "Switching Camera...");
}
5 changes: 5 additions & 0 deletions apps/raycast-extension/src/switch-microphone.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { sendCapCommand } from "./utils";

export default async function Command() {
await sendCapCommand("cycle_microphone", "Switching Microphone...");
}
15 changes: 15 additions & 0 deletions apps/raycast-extension/src/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { closeMainWindow, open, showHUD } from "@raycast/api";

type CapAction = string | Record<string, unknown>;

export async function sendCapCommand(action: CapAction, hudMessage: string): Promise<void> {
try {
await closeMainWindow();
const url = `cap-desktop://action?value=${encodeURIComponent(JSON.stringify(action))}`;
await open(url);
await showHUD(hudMessage);
} catch (error) {
console.error(error);
await showHUD("Failed to connect to Cap");
}
}
20 changes: 20 additions & 0 deletions apps/raycast-extension/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"compilerOptions": {
"lib": [
"ES2023"
],
"module": "commonjs",
"target": "ES2023",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"sourceMap": true,
"jsx": "react",
"moduleResolution": "Node",
"resolveJsonModule": true
},
"include": [
"src/**/*"
]
}