@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.
- package/package.json +1 -1
- package/src/commands/cd.ts +163 -0
- package/src/commands/clone.ts +112 -68
- package/src/commands/domain.ts +506 -0
- package/src/commands/domains.ts +215 -0
- package/src/commands/down.ts +18 -12
- package/src/commands/hack.ts +185 -8
- package/src/commands/init.ts +52 -1
- package/src/commands/link.ts +25 -43
- package/src/commands/logs.ts +2 -2
- package/src/commands/mcp.ts +74 -3
- package/src/commands/new.ts +48 -54
- package/src/commands/projects.ts +53 -10
- package/src/commands/secrets.ts +5 -1
- package/src/commands/services.ts +16 -4
- package/src/commands/shell-init.ts +43 -0
- package/src/commands/ship.ts +2 -11
- package/src/commands/skills.ts +335 -0
- package/src/commands/update.ts +31 -0
- package/src/commands/upgrade.ts +14 -0
- package/src/index.ts +116 -24
- package/src/lib/agent-integration.ts +1 -2
- package/src/lib/agents.ts +2 -2
- package/src/lib/auth/login-flow.ts +1 -1
- package/src/lib/clone-core.ts +252 -0
- package/src/lib/config.ts +22 -0
- package/src/lib/control-plane.ts +31 -5
- package/src/lib/fuzzy.ts +93 -0
- package/src/lib/managed-deploy.ts +4 -1
- package/src/lib/managed-down.ts +20 -5
- package/src/lib/output.ts +90 -9
- package/src/lib/picker.ts +406 -0
- package/src/lib/project-detection.ts +5 -2
- package/src/lib/project-list.ts +66 -5
- package/src/lib/project-operations.ts +68 -6
- package/src/lib/prompts.ts +1 -1
- package/src/lib/services/db-execute.ts +8 -1
- package/src/lib/services/db-list.ts +4 -1
- package/src/lib/services/domain-operations.ts +379 -0
- package/src/lib/services/storage-config.ts +1 -5
- package/src/lib/services/storage-delete.ts +1 -1
- package/src/lib/services/storage-info.ts +2 -4
- package/src/lib/services/vectorize-config.ts +1 -5
- package/src/lib/services/vectorize-create.ts +3 -1
- package/src/lib/shell-integration.ts +202 -0
- package/src/lib/telemetry-config.ts +50 -4
- package/src/lib/telemetry.ts +71 -2
- package/src/lib/version-check.ts +1 -3
- package/src/lib/wrangler-config.test.ts +2 -2
- package/src/lib/wrangler-config.ts +1 -1
- package/src/lib/zip-packager.ts +1 -3
- package/src/mcp/tools/index.ts +261 -7
- package/src/templates/index.ts +10 -1
- package/templates/ai-chat/.jack.json +1 -5
- package/templates/ai-chat/public/chat.js +130 -130
- package/templates/ai-chat/src/index.ts +9 -13
- package/templates/ai-chat/src/jack-ai.ts +6 -2
- package/templates/saas/.jack.json +6 -1
- package/templates/saas/src/auth.ts +8 -4
- package/templates/saas/src/client/App.tsx +22 -7
- package/templates/saas/src/client/components/ProtectedRoute.tsx +9 -2
- package/templates/saas/src/client/components/ThemeToggle.tsx +1 -6
- package/templates/saas/src/client/components/ui/accordion.tsx +1 -1
- package/templates/saas/src/client/components/ui/alert-dialog.tsx +2 -2
- package/templates/saas/src/client/components/ui/alert.tsx +2 -2
- package/templates/saas/src/client/components/ui/avatar.tsx +1 -1
- package/templates/saas/src/client/components/ui/badge.tsx +2 -2
- package/templates/saas/src/client/components/ui/breadcrumb.tsx +1 -1
- package/templates/saas/src/client/components/ui/button-group.tsx +2 -2
- package/templates/saas/src/client/components/ui/button.tsx +2 -2
- package/templates/saas/src/client/components/ui/card.tsx +1 -1
- package/templates/saas/src/client/components/ui/carousel.tsx +2 -2
- package/templates/saas/src/client/components/ui/checkbox.tsx +1 -1
- package/templates/saas/src/client/components/ui/command.tsx +2 -2
- package/templates/saas/src/client/components/ui/context-menu.tsx +1 -1
- package/templates/saas/src/client/components/ui/dialog.tsx +1 -1
- package/templates/saas/src/client/components/ui/drawer.tsx +1 -1
- package/templates/saas/src/client/components/ui/dropdown-menu.tsx +1 -1
- package/templates/saas/src/client/components/ui/empty.tsx +1 -1
- package/templates/saas/src/client/components/ui/field.tsx +2 -2
- package/templates/saas/src/client/components/ui/form.tsx +5 -5
- package/templates/saas/src/client/components/ui/hover-card.tsx +1 -1
- package/templates/saas/src/client/components/ui/input-group.tsx +3 -3
- package/templates/saas/src/client/components/ui/input-otp.tsx +1 -1
- package/templates/saas/src/client/components/ui/input.tsx +1 -1
- package/templates/saas/src/client/components/ui/item.tsx +3 -3
- package/templates/saas/src/client/components/ui/label.tsx +1 -1
- package/templates/saas/src/client/components/ui/menubar.tsx +1 -1
- package/templates/saas/src/client/components/ui/navigation-menu.tsx +1 -1
- package/templates/saas/src/client/components/ui/pagination.tsx +2 -2
- package/templates/saas/src/client/components/ui/popover.tsx +1 -1
- package/templates/saas/src/client/components/ui/progress.tsx +1 -1
- package/templates/saas/src/client/components/ui/radio-group.tsx +1 -1
- package/templates/saas/src/client/components/ui/resizable.tsx +1 -1
- package/templates/saas/src/client/components/ui/scroll-area.tsx +1 -1
- package/templates/saas/src/client/components/ui/select.tsx +1 -1
- package/templates/saas/src/client/components/ui/separator.tsx +1 -1
- package/templates/saas/src/client/components/ui/sheet.tsx +1 -1
- package/templates/saas/src/client/components/ui/sidebar.tsx +4 -4
- package/templates/saas/src/client/components/ui/slider.tsx +1 -1
- package/templates/saas/src/client/components/ui/switch.tsx +1 -1
- package/templates/saas/src/client/components/ui/table.tsx +1 -1
- package/templates/saas/src/client/components/ui/tabs.tsx +1 -1
- package/templates/saas/src/client/components/ui/textarea.tsx +1 -1
- package/templates/saas/src/client/components/ui/toggle-group.tsx +3 -3
- package/templates/saas/src/client/components/ui/toggle.tsx +2 -2
- package/templates/saas/src/client/components/ui/tooltip.tsx +1 -1
- package/templates/saas/src/client/hooks/useSubscription.ts +5 -4
- package/templates/saas/src/client/lib/auth-client.ts +1 -1
- package/templates/saas/src/client/lib/plans.ts +1 -6
- package/templates/saas/src/client/lib/utils.ts +1 -1
- package/templates/saas/src/client/main.tsx +1 -1
- package/templates/saas/src/client/pages/DashboardPage.tsx +41 -9
- package/templates/saas/src/client/pages/ForgotPasswordPage.tsx +11 -2
- package/templates/saas/src/client/pages/HomePage.tsx +11 -2
- package/templates/saas/src/client/pages/LoginPage.tsx +11 -2
- package/templates/saas/src/client/pages/PricingPage.tsx +20 -10
- package/templates/saas/src/client/pages/ResetPasswordPage.tsx +14 -11
- package/templates/saas/src/client/pages/SignupPage.tsx +11 -2
- package/templates/saas/src/index.ts +28 -19
- package/templates/saas/vite.config.ts +1 -1
- package/templates/semantic-search/.jack.json +1 -5
- package/templates/semantic-search/src/index.ts +8 -4
- package/templates/semantic-search/src/jack-ai.ts +6 -2
- package/templates/semantic-search/src/jack-vectorize.ts +5 -1
|
@@ -1,148 +1,148 @@
|
|
|
1
|
-
const messagesEl = document.getElementById(
|
|
2
|
-
const inputEl = document.getElementById(
|
|
3
|
-
const sendBtn = document.getElementById(
|
|
1
|
+
const messagesEl = document.getElementById("messages");
|
|
2
|
+
const inputEl = document.getElementById("input");
|
|
3
|
+
const sendBtn = document.getElementById("send");
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
const history = [];
|
|
6
6
|
let isLoading = false;
|
|
7
7
|
|
|
8
8
|
function setLoading(loading) {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
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
|
-
|
|
17
|
-
|
|
18
|
-
|
|
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
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
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
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
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(
|
|
141
|
-
inputEl.addEventListener(
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
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(
|
|
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
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
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(
|
|
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 = (
|
|
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": [
|
|
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
|
|
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(
|
|
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(
|
|
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 {
|
|
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
|
|
11
|
+
import SignupPage from "./pages/SignupPage";
|
|
12
12
|
|
|
13
|
-
type Route =
|
|
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[] = [
|
|
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 =
|
|
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,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,6 +1,6 @@
|
|
|
1
|
-
import * as React from "react";
|
|
2
1
|
import { Slot } from "@radix-ui/react-slot";
|
|
3
|
-
import {
|
|
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,8 +1,8 @@
|
|
|
1
1
|
import { Slot } from "@radix-ui/react-slot";
|
|
2
|
-
import {
|
|
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 {
|
|
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,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,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
|
|