@getjack/jack 0.1.28 → 0.1.30

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (125) hide show
  1. package/package.json +1 -1
  2. package/src/commands/cd.ts +163 -0
  3. package/src/commands/clone.ts +112 -68
  4. package/src/commands/domain.ts +506 -0
  5. package/src/commands/domains.ts +215 -0
  6. package/src/commands/down.ts +18 -12
  7. package/src/commands/hack.ts +185 -8
  8. package/src/commands/init.ts +52 -1
  9. package/src/commands/link.ts +25 -43
  10. package/src/commands/logs.ts +2 -2
  11. package/src/commands/mcp.ts +74 -3
  12. package/src/commands/new.ts +48 -54
  13. package/src/commands/projects.ts +53 -10
  14. package/src/commands/secrets.ts +5 -1
  15. package/src/commands/services.ts +16 -4
  16. package/src/commands/shell-init.ts +43 -0
  17. package/src/commands/ship.ts +2 -11
  18. package/src/commands/skills.ts +335 -0
  19. package/src/commands/update.ts +31 -0
  20. package/src/commands/upgrade.ts +14 -0
  21. package/src/index.ts +116 -24
  22. package/src/lib/agent-integration.ts +1 -2
  23. package/src/lib/agents.ts +2 -2
  24. package/src/lib/auth/login-flow.ts +1 -1
  25. package/src/lib/clone-core.ts +252 -0
  26. package/src/lib/config.ts +22 -0
  27. package/src/lib/control-plane.ts +31 -5
  28. package/src/lib/fuzzy.ts +93 -0
  29. package/src/lib/managed-deploy.ts +4 -1
  30. package/src/lib/managed-down.ts +20 -5
  31. package/src/lib/output.ts +90 -9
  32. package/src/lib/picker.ts +406 -0
  33. package/src/lib/project-detection.ts +5 -2
  34. package/src/lib/project-list.ts +66 -5
  35. package/src/lib/project-operations.ts +68 -6
  36. package/src/lib/prompts.ts +1 -1
  37. package/src/lib/services/db-execute.ts +8 -1
  38. package/src/lib/services/db-list.ts +4 -1
  39. package/src/lib/services/domain-operations.ts +379 -0
  40. package/src/lib/services/storage-config.ts +1 -5
  41. package/src/lib/services/storage-delete.ts +1 -1
  42. package/src/lib/services/storage-info.ts +2 -4
  43. package/src/lib/services/vectorize-config.ts +1 -5
  44. package/src/lib/services/vectorize-create.ts +3 -1
  45. package/src/lib/shell-integration.ts +202 -0
  46. package/src/lib/telemetry-config.ts +50 -4
  47. package/src/lib/telemetry.ts +71 -2
  48. package/src/lib/version-check.ts +1 -3
  49. package/src/lib/wrangler-config.test.ts +2 -2
  50. package/src/lib/wrangler-config.ts +1 -1
  51. package/src/lib/zip-packager.ts +1 -3
  52. package/src/mcp/tools/index.ts +261 -7
  53. package/src/templates/index.ts +10 -1
  54. package/templates/ai-chat/.jack.json +1 -5
  55. package/templates/ai-chat/public/chat.js +130 -130
  56. package/templates/ai-chat/src/index.ts +9 -13
  57. package/templates/ai-chat/src/jack-ai.ts +6 -2
  58. package/templates/saas/.jack.json +6 -1
  59. package/templates/saas/src/auth.ts +8 -4
  60. package/templates/saas/src/client/App.tsx +22 -7
  61. package/templates/saas/src/client/components/ProtectedRoute.tsx +9 -2
  62. package/templates/saas/src/client/components/ThemeToggle.tsx +1 -6
  63. package/templates/saas/src/client/components/ui/accordion.tsx +1 -1
  64. package/templates/saas/src/client/components/ui/alert-dialog.tsx +2 -2
  65. package/templates/saas/src/client/components/ui/alert.tsx +2 -2
  66. package/templates/saas/src/client/components/ui/avatar.tsx +1 -1
  67. package/templates/saas/src/client/components/ui/badge.tsx +2 -2
  68. package/templates/saas/src/client/components/ui/breadcrumb.tsx +1 -1
  69. package/templates/saas/src/client/components/ui/button-group.tsx +2 -2
  70. package/templates/saas/src/client/components/ui/button.tsx +2 -2
  71. package/templates/saas/src/client/components/ui/card.tsx +1 -1
  72. package/templates/saas/src/client/components/ui/carousel.tsx +2 -2
  73. package/templates/saas/src/client/components/ui/checkbox.tsx +1 -1
  74. package/templates/saas/src/client/components/ui/command.tsx +2 -2
  75. package/templates/saas/src/client/components/ui/context-menu.tsx +1 -1
  76. package/templates/saas/src/client/components/ui/dialog.tsx +1 -1
  77. package/templates/saas/src/client/components/ui/drawer.tsx +1 -1
  78. package/templates/saas/src/client/components/ui/dropdown-menu.tsx +1 -1
  79. package/templates/saas/src/client/components/ui/empty.tsx +1 -1
  80. package/templates/saas/src/client/components/ui/field.tsx +2 -2
  81. package/templates/saas/src/client/components/ui/form.tsx +5 -5
  82. package/templates/saas/src/client/components/ui/hover-card.tsx +1 -1
  83. package/templates/saas/src/client/components/ui/input-group.tsx +3 -3
  84. package/templates/saas/src/client/components/ui/input-otp.tsx +1 -1
  85. package/templates/saas/src/client/components/ui/input.tsx +1 -1
  86. package/templates/saas/src/client/components/ui/item.tsx +3 -3
  87. package/templates/saas/src/client/components/ui/label.tsx +1 -1
  88. package/templates/saas/src/client/components/ui/menubar.tsx +1 -1
  89. package/templates/saas/src/client/components/ui/navigation-menu.tsx +1 -1
  90. package/templates/saas/src/client/components/ui/pagination.tsx +2 -2
  91. package/templates/saas/src/client/components/ui/popover.tsx +1 -1
  92. package/templates/saas/src/client/components/ui/progress.tsx +1 -1
  93. package/templates/saas/src/client/components/ui/radio-group.tsx +1 -1
  94. package/templates/saas/src/client/components/ui/resizable.tsx +1 -1
  95. package/templates/saas/src/client/components/ui/scroll-area.tsx +1 -1
  96. package/templates/saas/src/client/components/ui/select.tsx +1 -1
  97. package/templates/saas/src/client/components/ui/separator.tsx +1 -1
  98. package/templates/saas/src/client/components/ui/sheet.tsx +1 -1
  99. package/templates/saas/src/client/components/ui/sidebar.tsx +4 -4
  100. package/templates/saas/src/client/components/ui/slider.tsx +1 -1
  101. package/templates/saas/src/client/components/ui/switch.tsx +1 -1
  102. package/templates/saas/src/client/components/ui/table.tsx +1 -1
  103. package/templates/saas/src/client/components/ui/tabs.tsx +1 -1
  104. package/templates/saas/src/client/components/ui/textarea.tsx +1 -1
  105. package/templates/saas/src/client/components/ui/toggle-group.tsx +3 -3
  106. package/templates/saas/src/client/components/ui/toggle.tsx +2 -2
  107. package/templates/saas/src/client/components/ui/tooltip.tsx +1 -1
  108. package/templates/saas/src/client/hooks/useSubscription.ts +5 -4
  109. package/templates/saas/src/client/lib/auth-client.ts +1 -1
  110. package/templates/saas/src/client/lib/plans.ts +1 -6
  111. package/templates/saas/src/client/lib/utils.ts +1 -1
  112. package/templates/saas/src/client/main.tsx +1 -1
  113. package/templates/saas/src/client/pages/DashboardPage.tsx +41 -9
  114. package/templates/saas/src/client/pages/ForgotPasswordPage.tsx +11 -2
  115. package/templates/saas/src/client/pages/HomePage.tsx +11 -2
  116. package/templates/saas/src/client/pages/LoginPage.tsx +11 -2
  117. package/templates/saas/src/client/pages/PricingPage.tsx +20 -10
  118. package/templates/saas/src/client/pages/ResetPasswordPage.tsx +14 -11
  119. package/templates/saas/src/client/pages/SignupPage.tsx +11 -2
  120. package/templates/saas/src/index.ts +28 -19
  121. package/templates/saas/vite.config.ts +1 -1
  122. package/templates/semantic-search/.jack.json +1 -5
  123. package/templates/semantic-search/src/index.ts +8 -4
  124. package/templates/semantic-search/src/jack-ai.ts +6 -2
  125. package/templates/semantic-search/src/jack-vectorize.ts +5 -1
@@ -1,148 +1,148 @@
1
- const messagesEl = document.getElementById('messages');
2
- const inputEl = document.getElementById('input');
3
- const sendBtn = document.getElementById('send');
1
+ const messagesEl = document.getElementById("messages");
2
+ const inputEl = document.getElementById("input");
3
+ const sendBtn = document.getElementById("send");
4
4
 
5
- let history = [];
5
+ const history = [];
6
6
  let isLoading = false;
7
7
 
8
8
  function setLoading(loading) {
9
- isLoading = loading;
10
- inputEl.disabled = loading;
11
- sendBtn.disabled = loading;
12
- sendBtn.textContent = loading ? '...' : 'Send';
9
+ isLoading = loading;
10
+ inputEl.disabled = loading;
11
+ sendBtn.disabled = loading;
12
+ sendBtn.textContent = loading ? "..." : "Send";
13
13
  }
14
14
 
15
15
  function clearEmptyState() {
16
- const emptyState = messagesEl.querySelector('.empty-state');
17
- if (emptyState) {
18
- emptyState.remove();
19
- }
16
+ const emptyState = messagesEl.querySelector(".empty-state");
17
+ if (emptyState) {
18
+ emptyState.remove();
19
+ }
20
20
  }
21
21
 
22
- function appendMessage(role, content, className = '') {
23
- clearEmptyState();
24
- const el = document.createElement('div');
25
- el.className = `message ${role} ${className}`.trim();
26
- el.textContent = content;
27
- messagesEl.appendChild(el);
28
- messagesEl.scrollTop = messagesEl.scrollHeight;
29
- return el;
22
+ function appendMessage(role, content, className = "") {
23
+ clearEmptyState();
24
+ const el = document.createElement("div");
25
+ el.className = `message ${role} ${className}`.trim();
26
+ el.textContent = content;
27
+ messagesEl.appendChild(el);
28
+ messagesEl.scrollTop = messagesEl.scrollHeight;
29
+ return el;
30
30
  }
31
31
 
32
32
  async function sendMessage() {
33
- const content = inputEl.value.trim();
34
- if (!content || isLoading) return;
35
-
36
- // Add user message to history and display
37
- history.push({ role: 'user', content });
38
- appendMessage('user', content);
39
- inputEl.value = '';
40
-
41
- // Create assistant message placeholder
42
- const assistantEl = appendMessage('assistant', '', 'typing');
43
- setLoading(true);
44
-
45
- try {
46
- const response = await fetch('/api/chat', {
47
- method: 'POST',
48
- headers: { 'Content-Type': 'application/json' },
49
- body: JSON.stringify({ messages: history }),
50
- });
51
-
52
- if (!response.ok) {
53
- let errorMessage = 'Something went wrong. Please try again.';
54
- try {
55
- const err = await response.json();
56
- if (err.error) {
57
- errorMessage = err.error;
58
- }
59
- } catch {
60
- // Use default error message
61
- }
62
- assistantEl.textContent = errorMessage;
63
- assistantEl.className = 'message assistant error';
64
- setLoading(false);
65
- return;
66
- }
67
-
68
- // Stream response
69
- const reader = response.body.getReader();
70
- const decoder = new TextDecoder();
71
- let assistantContent = '';
72
- let buffer = '';
73
-
74
- while (true) {
75
- const { done, value } = await reader.read();
76
- if (done) break;
77
-
78
- buffer += decoder.decode(value, { stream: true });
79
-
80
- // Process complete SSE messages
81
- const lines = buffer.split('\n');
82
- // Keep the last potentially incomplete line in the buffer
83
- buffer = lines.pop() || '';
84
-
85
- for (const line of lines) {
86
- if (line.startsWith('data: ')) {
87
- const data = line.slice(6).trim();
88
- if (data === '[DONE]') continue;
89
-
90
- try {
91
- const parsed = JSON.parse(data);
92
- if (parsed.response) {
93
- assistantContent += parsed.response;
94
- assistantEl.textContent = assistantContent;
95
- assistantEl.className = 'message assistant';
96
- messagesEl.scrollTop = messagesEl.scrollHeight;
97
- }
98
- } catch {
99
- // Skip malformed JSON chunks
100
- }
101
- }
102
- }
103
- }
104
-
105
- // Process any remaining buffer content
106
- if (buffer.startsWith('data: ')) {
107
- const data = buffer.slice(6).trim();
108
- if (data && data !== '[DONE]') {
109
- try {
110
- const parsed = JSON.parse(data);
111
- if (parsed.response) {
112
- assistantContent += parsed.response;
113
- assistantEl.textContent = assistantContent;
114
- assistantEl.className = 'message assistant';
115
- }
116
- } catch {
117
- // Skip malformed JSON
118
- }
119
- }
120
- }
121
-
122
- // Save to history if we got content
123
- if (assistantContent) {
124
- history.push({ role: 'assistant', content: assistantContent });
125
- } else {
126
- assistantEl.textContent = 'No response received. Please try again.';
127
- assistantEl.className = 'message assistant error';
128
- }
129
- } catch (err) {
130
- console.error('Chat error:', err);
131
- assistantEl.textContent = 'Connection error. Please check your network and try again.';
132
- assistantEl.className = 'message assistant error';
133
- }
134
-
135
- setLoading(false);
136
- inputEl.focus();
33
+ const content = inputEl.value.trim();
34
+ if (!content || isLoading) return;
35
+
36
+ // Add user message to history and display
37
+ history.push({ role: "user", content });
38
+ appendMessage("user", content);
39
+ inputEl.value = "";
40
+
41
+ // Create assistant message placeholder
42
+ const assistantEl = appendMessage("assistant", "", "typing");
43
+ setLoading(true);
44
+
45
+ try {
46
+ const response = await fetch("/api/chat", {
47
+ method: "POST",
48
+ headers: { "Content-Type": "application/json" },
49
+ body: JSON.stringify({ messages: history }),
50
+ });
51
+
52
+ if (!response.ok) {
53
+ let errorMessage = "Something went wrong. Please try again.";
54
+ try {
55
+ const err = await response.json();
56
+ if (err.error) {
57
+ errorMessage = err.error;
58
+ }
59
+ } catch {
60
+ // Use default error message
61
+ }
62
+ assistantEl.textContent = errorMessage;
63
+ assistantEl.className = "message assistant error";
64
+ setLoading(false);
65
+ return;
66
+ }
67
+
68
+ // Stream response
69
+ const reader = response.body.getReader();
70
+ const decoder = new TextDecoder();
71
+ let assistantContent = "";
72
+ let buffer = "";
73
+
74
+ while (true) {
75
+ const { done, value } = await reader.read();
76
+ if (done) break;
77
+
78
+ buffer += decoder.decode(value, { stream: true });
79
+
80
+ // Process complete SSE messages
81
+ const lines = buffer.split("\n");
82
+ // Keep the last potentially incomplete line in the buffer
83
+ buffer = lines.pop() || "";
84
+
85
+ for (const line of lines) {
86
+ if (line.startsWith("data: ")) {
87
+ const data = line.slice(6).trim();
88
+ if (data === "[DONE]") continue;
89
+
90
+ try {
91
+ const parsed = JSON.parse(data);
92
+ if (parsed.response) {
93
+ assistantContent += parsed.response;
94
+ assistantEl.textContent = assistantContent;
95
+ assistantEl.className = "message assistant";
96
+ messagesEl.scrollTop = messagesEl.scrollHeight;
97
+ }
98
+ } catch {
99
+ // Skip malformed JSON chunks
100
+ }
101
+ }
102
+ }
103
+ }
104
+
105
+ // Process any remaining buffer content
106
+ if (buffer.startsWith("data: ")) {
107
+ const data = buffer.slice(6).trim();
108
+ if (data && data !== "[DONE]") {
109
+ try {
110
+ const parsed = JSON.parse(data);
111
+ if (parsed.response) {
112
+ assistantContent += parsed.response;
113
+ assistantEl.textContent = assistantContent;
114
+ assistantEl.className = "message assistant";
115
+ }
116
+ } catch {
117
+ // Skip malformed JSON
118
+ }
119
+ }
120
+ }
121
+
122
+ // Save to history if we got content
123
+ if (assistantContent) {
124
+ history.push({ role: "assistant", content: assistantContent });
125
+ } else {
126
+ assistantEl.textContent = "No response received. Please try again.";
127
+ assistantEl.className = "message assistant error";
128
+ }
129
+ } catch (err) {
130
+ console.error("Chat error:", err);
131
+ assistantEl.textContent = "Connection error. Please check your network and try again.";
132
+ assistantEl.className = "message assistant error";
133
+ }
134
+
135
+ setLoading(false);
136
+ inputEl.focus();
137
137
  }
138
138
 
139
139
  // Event listeners
140
- sendBtn.addEventListener('click', sendMessage);
141
- inputEl.addEventListener('keypress', (e) => {
142
- if (e.key === 'Enter' && !e.shiftKey) {
143
- e.preventDefault();
144
- sendMessage();
145
- }
140
+ sendBtn.addEventListener("click", sendMessage);
141
+ inputEl.addEventListener("keypress", (e) => {
142
+ if (e.key === "Enter" && !e.shiftKey) {
143
+ e.preventDefault();
144
+ sendMessage();
145
+ }
146
146
  });
147
147
 
148
148
  // Focus input on load
@@ -14,7 +14,9 @@ interface Env {
14
14
  function getAI(env: Env) {
15
15
  // Prefer jack cloud proxy if available (for metering)
16
16
  if (env.__AI_PROXY && env.__JACK_PROJECT_ID && env.__JACK_ORG_ID) {
17
- return createJackAI(env as Required<Pick<Env, "__AI_PROXY" | "__JACK_PROJECT_ID" | "__JACK_ORG_ID">>);
17
+ return createJackAI(
18
+ env as Required<Pick<Env, "__AI_PROXY" | "__JACK_PROJECT_ID" | "__JACK_ORG_ID">>,
19
+ );
18
20
  }
19
21
  // Fallback to direct binding for local dev
20
22
  if (env.AI) {
@@ -115,14 +117,11 @@ export default {
115
117
  // Stream response using Llama 3.2 1B - cheapest model with good quality
116
118
  // See: https://developers.cloudflare.com/workers-ai/models/
117
119
  const ai = getAI(env);
118
- const stream = await ai.run(
119
- "@cf/meta/llama-3.2-1b-instruct",
120
- {
121
- messages,
122
- stream: true,
123
- max_tokens: 1024,
124
- },
125
- );
120
+ const stream = await ai.run("@cf/meta/llama-3.2-1b-instruct", {
121
+ messages,
122
+ stream: true,
123
+ max_tokens: 1024,
124
+ });
126
125
 
127
126
  return new Response(stream, {
128
127
  headers: {
@@ -133,10 +132,7 @@ export default {
133
132
  });
134
133
  } catch (err) {
135
134
  console.error("Chat error:", err);
136
- return Response.json(
137
- { error: "Something went wrong. Please try again." },
138
- { status: 500 },
139
- );
135
+ return Response.json({ error: "Something went wrong. Please try again." }, { status: 500 });
140
136
  }
141
137
  }
142
138
 
@@ -65,9 +65,13 @@ export function createJackAI(env: JackAIEnv): {
65
65
  // Handle quota exceeded
66
66
  if (response.status === 429) {
67
67
  const error = await response.json();
68
- const quotaError = new Error((error as { message?: string }).message || "AI quota exceeded");
68
+ const quotaError = new Error(
69
+ (error as { message?: string }).message || "AI quota exceeded",
70
+ );
69
71
  (quotaError as Error & { code: string }).code = "AI_QUOTA_EXCEEDED";
70
- (quotaError as Error & { resetIn?: number }).resetIn = (error as { resetIn?: number }).resetIn;
72
+ (quotaError as Error & { resetIn?: number }).resetIn = (
73
+ error as { resetIn?: number }
74
+ ).resetIn;
71
75
  throw quotaError;
72
76
  }
73
77
 
@@ -1,7 +1,12 @@
1
1
  {
2
2
  "name": "saas",
3
3
  "description": "SaaS starter (Auth + Payments + React)",
4
- "secrets": ["STRIPE_SECRET_KEY", "BETTER_AUTH_SECRET", "STRIPE_PRO_PRICE_ID", "STRIPE_ENTERPRISE_PRICE_ID"],
4
+ "secrets": [
5
+ "STRIPE_SECRET_KEY",
6
+ "BETTER_AUTH_SECRET",
7
+ "STRIPE_PRO_PRICE_ID",
8
+ "STRIPE_ENTERPRISE_PRICE_ID"
9
+ ],
5
10
  "capabilities": ["db"],
6
11
  "requires": ["DB"],
7
12
  "intent": {
@@ -1,8 +1,8 @@
1
- import { betterAuth } from "better-auth";
2
1
  import { stripe } from "@better-auth/stripe";
3
- import Stripe from "stripe";
2
+ import { betterAuth } from "better-auth";
4
3
  import { Kysely } from "kysely";
5
4
  import { D1Dialect } from "kysely-d1";
5
+ import Stripe from "stripe";
6
6
 
7
7
  // Env type is defined in index.ts and passed from the worker
8
8
  type Env = {
@@ -29,7 +29,9 @@ export function createAuth(env: Env) {
29
29
 
30
30
  if (missingConfig.length > 0) {
31
31
  console.error(`[Stripe] Missing required config: ${missingConfig.join(", ")}`);
32
- console.error("[Stripe] Subscriptions will not work correctly. Set these secrets via: jack secrets set <KEY> <value>");
32
+ console.error(
33
+ "[Stripe] Subscriptions will not work correctly. Set these secrets via: jack secrets set <KEY> <value>",
34
+ );
33
35
  }
34
36
 
35
37
  // Only enable Stripe plugin if we have the minimum required config
@@ -49,7 +51,9 @@ export function createAuth(env: Env) {
49
51
  }),
50
52
  );
51
53
  } else {
52
- console.error("[Stripe] Plugin DISABLED - STRIPE_WEBHOOK_SECRET is required for reliable subscription sync");
54
+ console.error(
55
+ "[Stripe] Plugin DISABLED - STRIPE_WEBHOOK_SECRET is required for reliable subscription sync",
56
+ );
53
57
  }
54
58
  }
55
59
 
@@ -1,20 +1,35 @@
1
- import { useState, useEffect } from "react";
1
+ import { useEffect, useState } from "react";
2
2
 
3
+ import { ProtectedRoute } from "./components/ProtectedRoute";
4
+ import DashboardPage from "./pages/DashboardPage";
5
+ import ForgotPasswordPage from "./pages/ForgotPasswordPage";
3
6
  // Page imports
4
7
  import HomePage from "./pages/HomePage";
5
8
  import LoginPage from "./pages/LoginPage";
6
- import SignupPage from "./pages/SignupPage";
7
9
  import PricingPage from "./pages/PricingPage";
8
- import DashboardPage from "./pages/DashboardPage";
9
- import ForgotPasswordPage from "./pages/ForgotPasswordPage";
10
10
  import ResetPasswordPage from "./pages/ResetPasswordPage";
11
- import { ProtectedRoute } from "./components/ProtectedRoute";
11
+ import SignupPage from "./pages/SignupPage";
12
12
 
13
- type Route = "/" | "/login" | "/signup" | "/pricing" | "/dashboard" | "/forgot-password" | "/reset-password";
13
+ type Route =
14
+ | "/"
15
+ | "/login"
16
+ | "/signup"
17
+ | "/pricing"
18
+ | "/dashboard"
19
+ | "/forgot-password"
20
+ | "/reset-password";
14
21
 
15
22
  function getRouteFromHash(): Route {
16
23
  const hash = window.location.hash.split("?")[0].slice(1) || "/";
17
- const validRoutes: Route[] = ["/", "/login", "/signup", "/pricing", "/dashboard", "/forgot-password", "/reset-password"];
24
+ const validRoutes: Route[] = [
25
+ "/",
26
+ "/login",
27
+ "/signup",
28
+ "/pricing",
29
+ "/dashboard",
30
+ "/forgot-password",
31
+ "/reset-password",
32
+ ];
18
33
  return validRoutes.includes(hash as Route) ? (hash as Route) : "/";
19
34
  }
20
35
 
@@ -1,7 +1,14 @@
1
- import { ReactNode, useEffect } from "react";
1
+ import { type ReactNode, useEffect } from "react";
2
2
  import { authClient } from "../lib/auth-client";
3
3
 
4
- type Route = "/" | "/login" | "/signup" | "/pricing" | "/dashboard" | "/forgot-password" | "/reset-password";
4
+ type Route =
5
+ | "/"
6
+ | "/login"
7
+ | "/signup"
8
+ | "/pricing"
9
+ | "/dashboard"
10
+ | "/forgot-password"
11
+ | "/reset-password";
5
12
 
6
13
  interface ProtectedRouteProps {
7
14
  children: ReactNode;
@@ -18,12 +18,7 @@ export function ThemeToggle() {
18
18
  };
19
19
 
20
20
  return (
21
- <Button
22
- variant="ghost"
23
- size="icon"
24
- className="h-9 w-9"
25
- onClick={toggleTheme}
26
- >
21
+ <Button variant="ghost" size="icon" className="h-9 w-9" onClick={toggleTheme}>
27
22
  <Sun className="h-4 w-4 rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0" />
28
23
  <Moon className="absolute h-4 w-4 rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100" />
29
24
  <span className="sr-only">Toggle theme</span>
@@ -1,6 +1,6 @@
1
- import * as React from "react";
2
1
  import * as AccordionPrimitive from "@radix-ui/react-accordion";
3
2
  import { ChevronDownIcon } from "lucide-react";
3
+ import type * as React from "react";
4
4
 
5
5
  import { cn } from "@/lib/utils";
6
6
 
@@ -1,8 +1,8 @@
1
- import * as React from "react";
2
1
  import * as AlertDialogPrimitive from "@radix-ui/react-alert-dialog";
2
+ import type * as React from "react";
3
3
 
4
- import { cn } from "@/lib/utils";
5
4
  import { buttonVariants } from "@/components/ui/button";
5
+ import { cn } from "@/lib/utils";
6
6
 
7
7
  function AlertDialog({ ...props }: React.ComponentProps<typeof AlertDialogPrimitive.Root>) {
8
8
  return <AlertDialogPrimitive.Root data-slot="alert-dialog" {...props} />;
@@ -1,5 +1,5 @@
1
- import * as React from "react";
2
- import { cva, type VariantProps } from "class-variance-authority";
1
+ import { type VariantProps, cva } from "class-variance-authority";
2
+ import type * as React from "react";
3
3
 
4
4
  import { cn } from "@/lib/utils";
5
5
 
@@ -1,5 +1,5 @@
1
- import * as React from "react";
2
1
  import * as AvatarPrimitive from "@radix-ui/react-avatar";
2
+ import type * as React from "react";
3
3
 
4
4
  import { cn } from "@/lib/utils";
5
5
 
@@ -1,6 +1,6 @@
1
- import * as React from "react";
2
1
  import { Slot } from "@radix-ui/react-slot";
3
- import { cva, type VariantProps } from "class-variance-authority";
2
+ import { type VariantProps, cva } from "class-variance-authority";
3
+ import type * as React from "react";
4
4
 
5
5
  import { cn } from "@/lib/utils";
6
6
 
@@ -1,6 +1,6 @@
1
- import * as React from "react";
2
1
  import { Slot } from "@radix-ui/react-slot";
3
2
  import { ChevronRight, MoreHorizontal } from "lucide-react";
3
+ import type * as React from "react";
4
4
 
5
5
  import { cn } from "@/lib/utils";
6
6
 
@@ -1,8 +1,8 @@
1
1
  import { Slot } from "@radix-ui/react-slot";
2
- import { cva, type VariantProps } from "class-variance-authority";
2
+ import { type VariantProps, cva } from "class-variance-authority";
3
3
 
4
- import { cn } from "@/lib/utils";
5
4
  import { Separator } from "@/components/ui/separator";
5
+ import { cn } from "@/lib/utils";
6
6
 
7
7
  const buttonGroupVariants = cva(
8
8
  "flex w-fit items-stretch [&>*]:focus-visible:z-10 [&>*]:focus-visible:relative [&>[data-slot=select-trigger]:not([class*='w-'])]:w-fit [&>input]:flex-1 has-[select[aria-hidden=true]:last-child]:[&>[data-slot=select-trigger]:last-of-type]:rounded-r-md has-[>[data-slot=button-group]]:gap-2",
@@ -1,6 +1,6 @@
1
- import * as React from "react";
2
1
  import { Slot } from "@radix-ui/react-slot";
3
- import { cva, type VariantProps } from "class-variance-authority";
2
+ import { type VariantProps, cva } from "class-variance-authority";
3
+ import type * as React from "react";
4
4
 
5
5
  import { cn } from "@/lib/utils";
6
6
 
@@ -1,4 +1,4 @@
1
- import * as React from "react";
1
+ import type * as React from "react";
2
2
 
3
3
  import { cn } from "@/lib/utils";
4
4
 
@@ -1,9 +1,9 @@
1
- import * as React from "react";
2
1
  import useEmblaCarousel, { type UseEmblaCarouselType } from "embla-carousel-react";
3
2
  import { ArrowLeft, ArrowRight } from "lucide-react";
3
+ import * as React from "react";
4
4
 
5
- import { cn } from "@/lib/utils";
6
5
  import { Button } from "@/components/ui/button";
6
+ import { cn } from "@/lib/utils";
7
7
 
8
8
  type CarouselApi = UseEmblaCarouselType[1];
9
9
  type UseCarouselParameters = Parameters<typeof useEmblaCarousel>;
@@ -1,8 +1,8 @@
1
1
  "use client";
2
2
 
3
- import * as React from "react";
4
3
  import * as CheckboxPrimitive from "@radix-ui/react-checkbox";
5
4
  import { CheckIcon } from "lucide-react";
5
+ import type * as React from "react";
6
6
 
7
7
  import { cn } from "@/lib/utils";
8
8
 
@@ -1,8 +1,7 @@
1
- import * as React from "react";
2
1
  import { Command as CommandPrimitive } from "cmdk";
3
2
  import { SearchIcon } from "lucide-react";
3
+ import type * as React from "react";
4
4
 
5
- import { cn } from "@/lib/utils";
6
5
  import {
7
6
  Dialog,
8
7
  DialogContent,
@@ -10,6 +9,7 @@ import {
10
9
  DialogHeader,
11
10
  DialogTitle,
12
11
  } from "@/components/ui/dialog";
12
+ import { cn } from "@/lib/utils";
13
13
 
14
14
  function Command({ className, ...props }: React.ComponentProps<typeof CommandPrimitive>) {
15
15
  return (
@@ -1,8 +1,8 @@
1
1
  "use client";
2
2
 
3
- import * as React from "react";
4
3
  import * as ContextMenuPrimitive from "@radix-ui/react-context-menu";
5
4
  import { CheckIcon, ChevronRightIcon, CircleIcon } from "lucide-react";
5
+ import type * as React from "react";
6
6
 
7
7
  import { cn } from "@/lib/utils";
8
8
 
@@ -1,6 +1,6 @@
1
- import * as React from "react";
2
1
  import * as DialogPrimitive from "@radix-ui/react-dialog";
3
2
  import { XIcon } from "lucide-react";
3
+ import type * as React from "react";
4
4
 
5
5
  import { cn } from "@/lib/utils";
6
6
 
@@ -1,6 +1,6 @@
1
1
  "use client";
2
2
 
3
- import * as React from "react";
3
+ import type * as React from "react";
4
4
  import { Drawer as DrawerPrimitive } from "vaul";
5
5
 
6
6
  import { cn } from "@/lib/utils";
@@ -1,6 +1,6 @@
1
- import * as React from "react";
2
1
  import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu";
3
2
  import { CheckIcon, ChevronRightIcon, CircleIcon } from "lucide-react";
3
+ import type * as React from "react";
4
4
 
5
5
  import { cn } from "@/lib/utils";
6
6
 
@@ -1,4 +1,4 @@
1
- import { cva, type VariantProps } from "class-variance-authority";
1
+ import { type VariantProps, cva } from "class-variance-authority";
2
2
 
3
3
  import { cn } from "@/lib/utils";
4
4