monorepotime 1.1.11 → 1.1.13
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/dist/index.js +1127 -1556
- package/package.json +2 -2
- package/public/assets/{index-CGbmb-rL.js → index-D4yOsY2s.js} +5 -3
- package/public/index.html +1 -1
package/dist/index.js
CHANGED
|
@@ -24075,11 +24075,11 @@ var require_lib3 = __commonJS({
|
|
|
24075
24075
|
var headers = [], method = req.method && req.method.toUpperCase && req.method.toUpperCase();
|
|
24076
24076
|
if (method === "OPTIONS") {
|
|
24077
24077
|
headers.push(configureOrigin(options, req));
|
|
24078
|
-
headers.push(configureCredentials(options
|
|
24079
|
-
headers.push(configureMethods(options
|
|
24078
|
+
headers.push(configureCredentials(options));
|
|
24079
|
+
headers.push(configureMethods(options));
|
|
24080
24080
|
headers.push(configureAllowedHeaders(options, req));
|
|
24081
|
-
headers.push(configureMaxAge(options
|
|
24082
|
-
headers.push(configureExposedHeaders(options
|
|
24081
|
+
headers.push(configureMaxAge(options));
|
|
24082
|
+
headers.push(configureExposedHeaders(options));
|
|
24083
24083
|
applyHeaders(headers, res);
|
|
24084
24084
|
if (options.preflightContinue) {
|
|
24085
24085
|
next();
|
|
@@ -24090,8 +24090,8 @@ var require_lib3 = __commonJS({
|
|
|
24090
24090
|
}
|
|
24091
24091
|
} else {
|
|
24092
24092
|
headers.push(configureOrigin(options, req));
|
|
24093
|
-
headers.push(configureCredentials(options
|
|
24094
|
-
headers.push(configureExposedHeaders(options
|
|
24093
|
+
headers.push(configureCredentials(options));
|
|
24094
|
+
headers.push(configureExposedHeaders(options));
|
|
24095
24095
|
applyHeaders(headers, res);
|
|
24096
24096
|
next();
|
|
24097
24097
|
}
|
|
@@ -55247,7 +55247,7 @@ __export(index_exports, {
|
|
|
55247
55247
|
io: () => io2
|
|
55248
55248
|
});
|
|
55249
55249
|
module.exports = __toCommonJS(index_exports);
|
|
55250
|
-
var
|
|
55250
|
+
var import_express25 = __toESM(require_express2());
|
|
55251
55251
|
var import_cors = __toESM(require_lib3());
|
|
55252
55252
|
var import_path19 = __toESM(require("path"));
|
|
55253
55253
|
|
|
@@ -56729,12 +56729,33 @@ var EXCLUDE_PATTERNS = {
|
|
|
56729
56729
|
"**/turbo.json": true,
|
|
56730
56730
|
"**/nodemon.json": true,
|
|
56731
56731
|
"**/temp.md": true,
|
|
56732
|
-
"
|
|
56733
|
-
"
|
|
56734
|
-
"
|
|
56735
|
-
"
|
|
56736
|
-
"
|
|
56737
|
-
"
|
|
56732
|
+
"**/postcss.config.js": true,
|
|
56733
|
+
"**/configs": true,
|
|
56734
|
+
"**/tailwind.config.js": true,
|
|
56735
|
+
"**/tsconfig.app.json": true,
|
|
56736
|
+
"**/tsconfig.json": true,
|
|
56737
|
+
"**/tsconfig.node.json": true,
|
|
56738
|
+
"**/tsconfig.spec.json": true,
|
|
56739
|
+
"**/eslint.json": true,
|
|
56740
|
+
"**/eslint.config.js": true,
|
|
56741
|
+
"**/eslint.config.mjs": true,
|
|
56742
|
+
"**/prettier.config.js": true,
|
|
56743
|
+
"**/prettier.config.mjs": true,
|
|
56744
|
+
"**/prettier.config.cjs": true,
|
|
56745
|
+
"**/vite.config.ts": true,
|
|
56746
|
+
"**/vite.config.js": true,
|
|
56747
|
+
"**/tsup.config.ts": true,
|
|
56748
|
+
"**/rollup.config.ts": true,
|
|
56749
|
+
"**/rollup.config.js": true,
|
|
56750
|
+
"**/webpack.config.js": true,
|
|
56751
|
+
"**/babel.config.js": true,
|
|
56752
|
+
"**/jest.config.js": true,
|
|
56753
|
+
"**/jest.config.ts": true,
|
|
56754
|
+
"**/next.config.js": true,
|
|
56755
|
+
"**/next.config.mjs": true,
|
|
56756
|
+
"**/postcss.config.cjs": true,
|
|
56757
|
+
"**/postcss.config.mjs": true,
|
|
56758
|
+
"**/tailwind.config.ts": true,
|
|
56738
56759
|
"_temp": true,
|
|
56739
56760
|
".gitignore": true,
|
|
56740
56761
|
".vscode": true,
|
|
@@ -57624,7 +57645,7 @@ router17.post("/stop-all", async (req, res) => {
|
|
|
57624
57645
|
var apidocker_default = router17;
|
|
57625
57646
|
|
|
57626
57647
|
// src/routes/availabletemplates.ts
|
|
57627
|
-
var
|
|
57648
|
+
var import_express22 = __toESM(require_express2());
|
|
57628
57649
|
|
|
57629
57650
|
// ../../packages/template/databases/mysql.ts
|
|
57630
57651
|
var MySQL = {
|
|
@@ -57666,6 +57687,11 @@ const EDITOR_URL = 'http://localhost/phpmyadmin'; // Change this to your preferr
|
|
|
57666
57687
|
cmd: "npm",
|
|
57667
57688
|
args: ["pkg", "set", "scripts.stop=echo 'Note: MySQL is running as a system service. Please stop it manually.'"]
|
|
57668
57689
|
},
|
|
57690
|
+
{
|
|
57691
|
+
action: "command",
|
|
57692
|
+
cmd: "npm",
|
|
57693
|
+
args: ["pkg", "set", "description=MySQL (Local)"]
|
|
57694
|
+
},
|
|
57669
57695
|
{
|
|
57670
57696
|
action: "command",
|
|
57671
57697
|
cmd: "npm",
|
|
@@ -57861,7 +57887,12 @@ process.on('SIGTERM', cleanup);`
|
|
|
57861
57887
|
{
|
|
57862
57888
|
action: "command",
|
|
57863
57889
|
cmd: "npm",
|
|
57864
|
-
args: ["pkg", "set", "
|
|
57890
|
+
args: ["pkg", "set", "description=PostgreSQL (Docker)"]
|
|
57891
|
+
},
|
|
57892
|
+
{
|
|
57893
|
+
action: "command",
|
|
57894
|
+
cmd: "npm",
|
|
57895
|
+
args: ["pkg", "set", "fontawesomeIcon=fas fa-database text-blue-500"]
|
|
57865
57896
|
}
|
|
57866
57897
|
]
|
|
57867
57898
|
};
|
|
@@ -57895,7 +57926,12 @@ var Supabase = {
|
|
|
57895
57926
|
{
|
|
57896
57927
|
action: "command",
|
|
57897
57928
|
cmd: "npm",
|
|
57898
|
-
args: ["pkg", "set", "
|
|
57929
|
+
args: ["pkg", "set", "description=Supabase (Docker)"]
|
|
57930
|
+
},
|
|
57931
|
+
{
|
|
57932
|
+
action: "command",
|
|
57933
|
+
cmd: "npm",
|
|
57934
|
+
args: ["pkg", "set", "fontawesomeIcon=fas fa-bolt text-green-500"]
|
|
57899
57935
|
}
|
|
57900
57936
|
]
|
|
57901
57937
|
};
|
|
@@ -58050,7 +58086,12 @@ process.on('SIGTERM', cleanup);`
|
|
|
58050
58086
|
{
|
|
58051
58087
|
action: "command",
|
|
58052
58088
|
cmd: "npm",
|
|
58053
|
-
args: ["pkg", "set", "
|
|
58089
|
+
args: ["pkg", "set", "description=Redis (Docker)"]
|
|
58090
|
+
},
|
|
58091
|
+
{
|
|
58092
|
+
action: "command",
|
|
58093
|
+
cmd: "npm",
|
|
58094
|
+
args: ["pkg", "set", "fontawesomeIcon=fas fa-server text-red-500"]
|
|
58054
58095
|
}
|
|
58055
58096
|
]
|
|
58056
58097
|
};
|
|
@@ -58205,6 +58246,11 @@ process.on('SIGTERM', cleanup);`
|
|
|
58205
58246
|
cmd: "npm",
|
|
58206
58247
|
args: ["pkg", "set", `scripts.stop=node -e 'const fs=require("fs"); try{const p=JSON.parse(fs.readFileSync(".runtime.json")).port; fetch("http://localhost:"+p+"/stop").catch(e=>{})}catch(e){}'`]
|
|
58207
58248
|
},
|
|
58249
|
+
{
|
|
58250
|
+
action: "command",
|
|
58251
|
+
cmd: "npm",
|
|
58252
|
+
args: ["pkg", "set", "description=MongoDB (Docker)"]
|
|
58253
|
+
},
|
|
58208
58254
|
{
|
|
58209
58255
|
action: "command",
|
|
58210
58256
|
cmd: "npm",
|
|
@@ -58362,6 +58408,11 @@ process.on('SIGTERM', cleanup);`
|
|
|
58362
58408
|
cmd: "npm",
|
|
58363
58409
|
args: ["pkg", "set", "fontawesomeIcon=fab fa-meetup text-green-500"]
|
|
58364
58410
|
},
|
|
58411
|
+
{
|
|
58412
|
+
action: "command",
|
|
58413
|
+
cmd: "npm",
|
|
58414
|
+
args: ["pkg", "set", "description=Meilisearch (Docker)"]
|
|
58415
|
+
},
|
|
58365
58416
|
{
|
|
58366
58417
|
action: "command",
|
|
58367
58418
|
cmd: "npm",
|
|
@@ -58537,6 +58588,11 @@ process.on('SIGTERM', cleanup);`
|
|
|
58537
58588
|
cmd: "npm",
|
|
58538
58589
|
args: ["pkg", "set", "fontawesomeIcon=fab fa-amazon text-blue-500"]
|
|
58539
58590
|
},
|
|
58591
|
+
{
|
|
58592
|
+
action: "command",
|
|
58593
|
+
cmd: "npm",
|
|
58594
|
+
args: ["pkg", "set", "description=MinIO (Docker)"]
|
|
58595
|
+
},
|
|
58540
58596
|
{
|
|
58541
58597
|
action: "command",
|
|
58542
58598
|
cmd: "npm",
|
|
@@ -58557,1534 +58613,297 @@ var templates = [
|
|
|
58557
58613
|
];
|
|
58558
58614
|
var database_default = templates;
|
|
58559
58615
|
|
|
58560
|
-
// ../../packages/template/demo/
|
|
58561
|
-
var
|
|
58562
|
-
|
|
58563
|
-
|
|
58564
|
-
|
|
58565
|
-
|
|
58566
|
-
|
|
58567
|
-
|
|
58568
|
-
|
|
58569
|
-
|
|
58570
|
-
|
|
58571
|
-
|
|
58572
|
-
|
|
58573
|
-
|
|
58574
|
-
|
|
58575
|
-
|
|
58576
|
-
|
|
58577
|
-
|
|
58578
|
-
|
|
58579
|
-
|
|
58580
|
-
|
|
58581
|
-
|
|
58582
|
-
|
|
58583
|
-
|
|
58584
|
-
|
|
58585
|
-
|
|
58586
|
-
|
|
58587
|
-
|
|
58588
|
-
|
|
58589
|
-
<
|
|
58590
|
-
|
|
58591
|
-
|
|
58592
|
-
|
|
58593
|
-
|
|
58594
|
-
|
|
58595
|
-
|
|
58596
|
-
|
|
58597
|
-
|
|
58598
|
-
|
|
58599
|
-
|
|
58600
|
-
|
|
58601
|
-
|
|
58602
|
-
|
|
58603
|
-
|
|
58604
|
-
|
|
58605
|
-
|
|
58606
|
-
|
|
58607
|
-
|
|
58608
|
-
|
|
58609
|
-
|
|
58610
|
-
|
|
58611
|
-
|
|
58612
|
-
|
|
58613
|
-
|
|
58614
|
-
|
|
58615
|
-
|
|
58616
|
-
|
|
58617
|
-
|
|
58618
|
-
|
|
58619
|
-
|
|
58620
|
-
|
|
58621
|
-
|
|
58622
|
-
|
|
58623
|
-
|
|
58624
|
-
|
|
58625
|
-
|
|
58626
|
-
|
|
58627
|
-
|
|
58628
|
-
|
|
58629
|
-
|
|
58630
|
-
|
|
58631
|
-
<div class="product-card">
|
|
58632
|
-
<div class="product-image">\u{1F353}</div>
|
|
58633
|
-
<div class="product-info">
|
|
58634
|
-
<h3>Fresh Strawberries</h3>
|
|
58635
|
-
<p>Hand-picked at peak ripeness for maximum flavor</p>
|
|
58636
|
-
<span class="product-price">$7.49/lb</span>
|
|
58637
|
-
</div>
|
|
58638
|
-
</div>
|
|
58639
|
-
<div class="product-card">
|
|
58640
|
-
<div class="product-image">\u{1F34C}</div>
|
|
58641
|
-
<div class="product-info">
|
|
58642
|
-
<h3>Organic Bananas</h3>
|
|
58643
|
-
<p>Naturally ripened, perfect for smoothies</p>
|
|
58644
|
-
<span class="product-price">$2.99/lb</span>
|
|
58645
|
-
</div>
|
|
58646
|
-
</div>
|
|
58647
|
-
</div>
|
|
58648
|
-
</section>
|
|
58649
|
-
|
|
58650
|
-
<!-- Chat Widget -->
|
|
58651
|
-
<div class="chat-widget">
|
|
58652
|
-
<div class="chat-window" id="chatWindow">
|
|
58653
|
-
<div class="chat-header">
|
|
58654
|
-
<div class="chat-header-avatar">\u{1F34A}</div>
|
|
58655
|
-
<div class="chat-header-info">
|
|
58656
|
-
<h4>FreshFruit Support</h4>
|
|
58657
|
-
<span>We typically reply instantly</span>
|
|
58658
|
-
</div>
|
|
58659
|
-
</div>
|
|
58660
|
-
<div class="chat-messages" id="chatMessages">
|
|
58661
|
-
<div class="message bot">
|
|
58662
|
-
Hi! \u{1F44B} Welcome to FreshFruit! How can I help you today? I can answer questions about our products, delivery, or anything else!
|
|
58663
|
-
</div>
|
|
58664
|
-
</div>
|
|
58665
|
-
<div class="chat-input-container">
|
|
58666
|
-
<input type="text" class="chat-input" id="chatInput" placeholder="Type your message..." autocomplete="off">
|
|
58667
|
-
<button class="chat-send" id="chatSend">
|
|
58668
|
-
<svg viewBox="0 0 24 24"><path d="M2.01 21L23 12 2.01 3 2 10l15 2-15 2z"/></svg>
|
|
58669
|
-
</button>
|
|
58670
|
-
</div>
|
|
58671
|
-
</div>
|
|
58672
|
-
<button class="chat-toggle" id="chatToggle">
|
|
58673
|
-
<svg viewBox="0 0 24 24"><path d="M20 2H4c-1.1 0-2 .9-2 2v18l4-4h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm0 14H6l-2 2V4h16v12z"/></svg>
|
|
58674
|
-
</button>
|
|
58675
|
-
</div>
|
|
58676
|
-
|
|
58677
|
-
<script>
|
|
58678
|
-
// Chat Widget Functionality
|
|
58679
|
-
const chatToggle = document.getElementById('chatToggle');
|
|
58680
|
-
const chatWindow = document.getElementById('chatWindow');
|
|
58681
|
-
const chatInput = document.getElementById('chatInput');
|
|
58682
|
-
const chatSend = document.getElementById('chatSend');
|
|
58683
|
-
const chatMessages = document.getElementById('chatMessages');
|
|
58684
|
-
|
|
58685
|
-
// Toggle chat window
|
|
58686
|
-
chatToggle.addEventListener('click', () => {
|
|
58687
|
-
chatWindow.classList.toggle('open');
|
|
58688
|
-
if (chatWindow.classList.contains('open')) {
|
|
58689
|
-
chatInput.focus();
|
|
58690
|
-
}
|
|
58691
|
-
});
|
|
58692
|
-
|
|
58693
|
-
// Send message function
|
|
58694
|
-
async function sendMessage() {
|
|
58695
|
-
const message = chatInput.value.trim();
|
|
58696
|
-
if (!message) return;
|
|
58697
|
-
|
|
58698
|
-
// Add user message
|
|
58699
|
-
addMessage(message, 'user');
|
|
58700
|
-
chatInput.value = '';
|
|
58701
|
-
|
|
58702
|
-
// Show typing indicator
|
|
58703
|
-
const typingEl = showTyping();
|
|
58704
|
-
|
|
58705
|
-
try {
|
|
58706
|
-
const response = await fetch('/api/chat', {
|
|
58707
|
-
method: 'POST',
|
|
58708
|
-
headers: { 'Content-Type': 'application/json' },
|
|
58709
|
-
body: JSON.stringify({ message })
|
|
58710
|
-
});
|
|
58711
|
-
|
|
58712
|
-
const data = await response.json();
|
|
58713
|
-
typingEl.remove();
|
|
58714
|
-
|
|
58715
|
-
if (data.reply) {
|
|
58716
|
-
addMessage(data.reply, 'bot');
|
|
58717
|
-
} else {
|
|
58718
|
-
addMessage('Sorry, I encountered an error. Please try again.', 'bot');
|
|
58719
|
-
}
|
|
58720
|
-
} catch (error) {
|
|
58721
|
-
typingEl.remove();
|
|
58722
|
-
addMessage('Sorry, I\\'m having trouble connecting. Please try again later.', 'bot');
|
|
58723
|
-
}
|
|
58724
|
-
}
|
|
58725
|
-
|
|
58726
|
-
// Add message to chat
|
|
58727
|
-
function addMessage(text, type) {
|
|
58728
|
-
const messageEl = document.createElement('div');
|
|
58729
|
-
messageEl.className = 'message ' + type;
|
|
58730
|
-
messageEl.textContent = text;
|
|
58731
|
-
chatMessages.appendChild(messageEl);
|
|
58732
|
-
chatMessages.scrollTop = chatMessages.scrollHeight;
|
|
58733
|
-
}
|
|
58734
|
-
|
|
58735
|
-
// Show typing indicator
|
|
58736
|
-
function showTyping() {
|
|
58737
|
-
const typingEl = document.createElement('div');
|
|
58738
|
-
typingEl.className = 'typing-indicator';
|
|
58739
|
-
typingEl.innerHTML = '<span></span><span></span><span></span>';
|
|
58740
|
-
chatMessages.appendChild(typingEl);
|
|
58741
|
-
chatMessages.scrollTop = chatMessages.scrollHeight;
|
|
58742
|
-
return typingEl;
|
|
58743
|
-
}
|
|
58744
|
-
|
|
58745
|
-
// Event listeners
|
|
58746
|
-
chatSend.addEventListener('click', sendMessage);
|
|
58747
|
-
chatInput.addEventListener('keypress', (e) => {
|
|
58748
|
-
if (e.key === 'Enter') sendMessage();
|
|
58749
|
-
});
|
|
58750
|
-
</script>
|
|
58751
|
-
</body>
|
|
58752
|
-
</html>
|
|
58753
|
-
`;
|
|
58754
|
-
|
|
58755
|
-
// ../../packages/template/demo/aichat/files/adminHtml.ts
|
|
58756
|
-
var adminHTML = `<!DOCTYPE html>
|
|
58757
|
-
<html lang="en">
|
|
58758
|
-
<head>
|
|
58759
|
-
<meta charset="UTF-8">
|
|
58760
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
58761
|
-
<title>Admin Panel - AI Chat Configuration</title>
|
|
58762
|
-
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
58763
|
-
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
58764
|
-
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap" rel="stylesheet">
|
|
58765
|
-
<link rel="stylesheet" href="/styles.css">
|
|
58766
|
-
</head>
|
|
58767
|
-
<body>
|
|
58768
|
-
<header class="header">
|
|
58769
|
-
<div class="header-content">
|
|
58770
|
-
<div class="logo">\u{1F34A} FreshFruit Admin</div>
|
|
58771
|
-
<nav>
|
|
58772
|
-
<ul class="nav-links">
|
|
58773
|
-
<li><a href="/">View Store</a></li>
|
|
58774
|
-
</ul>
|
|
58775
|
-
</nav>
|
|
58776
|
-
</div>
|
|
58777
|
-
</header>
|
|
58778
|
-
|
|
58779
|
-
<div class="admin-container">
|
|
58780
|
-
<div class="admin-header">
|
|
58781
|
-
<h1>AI Chat Configuration</h1>
|
|
58782
|
-
<p>Configure your AI provider and embed FAQ knowledge for customer support</p>
|
|
58783
|
-
</div>
|
|
58784
|
-
|
|
58785
|
-
<!-- AI Provider Configuration -->
|
|
58786
|
-
<div class="admin-card">
|
|
58787
|
-
<h2>\u{1F511} AI Provider Settings</h2>
|
|
58788
|
-
<form id="configForm">
|
|
58789
|
-
<div class="form-group">
|
|
58790
|
-
<label for="apiKey">API Key</label>
|
|
58791
|
-
<input type="password" class="form-input" id="apiKey" placeholder="sk-..." autocomplete="off">
|
|
58792
|
-
</div>
|
|
58793
|
-
<div class="form-group">
|
|
58794
|
-
<label for="providerUrl">Chat Completions URL</label>
|
|
58795
|
-
<input type="text" class="form-input" id="providerUrl" placeholder="https://api.openai.com/v1/chat/completions">
|
|
58796
|
-
</div>
|
|
58797
|
-
<div class="form-group">
|
|
58798
|
-
<label for="embeddingsUrl">Embeddings URL</label>
|
|
58799
|
-
<input type="text" class="form-input" id="embeddingsUrl" placeholder="https://api.openai.com/v1/embeddings">
|
|
58800
|
-
</div>
|
|
58801
|
-
<div class="form-group">
|
|
58802
|
-
<label for="model">Chat Model</label>
|
|
58803
|
-
<input type="text" class="form-input" id="model" placeholder="gpt-3.5-turbo">
|
|
58804
|
-
</div>
|
|
58805
|
-
<div class="form-group">
|
|
58806
|
-
<label for="embeddingsModel">Embeddings Model</label>
|
|
58807
|
-
<input type="text" class="form-input" id="embeddingsModel" placeholder="text-embedding-3-small">
|
|
58808
|
-
</div>
|
|
58809
|
-
<button type="submit" class="btn">\u{1F4BE} Save Configuration</button>
|
|
58810
|
-
</form>
|
|
58811
|
-
</div>
|
|
58812
|
-
|
|
58813
|
-
<!-- Knowledge Base Embedding -->
|
|
58814
|
-
<div class="admin-card">
|
|
58815
|
-
<h2>\u{1F4DA} Knowledge Base</h2>
|
|
58816
|
-
<p style="color: var(--text-muted); margin-bottom: 1.5rem;">
|
|
58817
|
-
Enter your FAQ content below. Each paragraph will be embedded and used to answer customer questions.
|
|
58818
|
-
</p>
|
|
58819
|
-
<form id="embedForm">
|
|
58820
|
-
<div class="form-group">
|
|
58821
|
-
<label for="faqContent">FAQ Content</label>
|
|
58822
|
-
<textarea class="form-input" id="faqContent" placeholder="Enter your FAQ content here...
|
|
58823
|
-
|
|
58824
|
-
Example:
|
|
58825
|
-
Q: What are your delivery hours?
|
|
58826
|
-
A: We deliver from 8 AM to 8 PM, Monday through Saturday.
|
|
58827
|
-
|
|
58828
|
-
Q: How do I return a product?
|
|
58829
|
-
A: You can return any product within 24 hours of delivery if you're not satisfied. Contact our support team.
|
|
58830
|
-
|
|
58831
|
-
Q: Do you offer organic certification?
|
|
58832
|
-
A: Yes, all our products are certified organic by USDA."></textarea>
|
|
58833
|
-
</div>
|
|
58834
|
-
<button type="submit" class="btn" id="embedBtn">\u{1F52E} Embed Knowledge</button>
|
|
58835
|
-
</form>
|
|
58836
|
-
<div class="status-bar">
|
|
58837
|
-
<div class="status-item">
|
|
58838
|
-
<div class="value" id="embeddingCount">0</div>
|
|
58839
|
-
<div class="label">Embeddings</div>
|
|
58840
|
-
</div>
|
|
58841
|
-
<div class="status-item">
|
|
58842
|
-
<div class="value" id="lastUpdated">Never</div>
|
|
58843
|
-
<div class="label">Last Updated</div>
|
|
58844
|
-
</div>
|
|
58845
|
-
<div class="status-item">
|
|
58846
|
-
<div class="value" id="configStatus">\u274C</div>
|
|
58847
|
-
<div class="label">API Configured</div>
|
|
58848
|
-
</div>
|
|
58849
|
-
</div>
|
|
58850
|
-
</div>
|
|
58851
|
-
|
|
58852
|
-
<!-- Clear Data -->
|
|
58853
|
-
<div class="admin-card">
|
|
58854
|
-
<h2>\u{1F5D1}\uFE0F Data Management</h2>
|
|
58855
|
-
<p style="color: var(--text-muted); margin-bottom: 1.5rem;">
|
|
58856
|
-
Clear all embeddings to start fresh or to re-embed with new content.
|
|
58857
|
-
</p>
|
|
58858
|
-
<button class="btn btn-secondary" id="clearBtn">Clear All Embeddings</button>
|
|
58859
|
-
</div>
|
|
58860
|
-
</div>
|
|
58861
|
-
|
|
58862
|
-
<div class="toast" id="toast"></div>
|
|
58863
|
-
|
|
58864
|
-
<script>
|
|
58865
|
-
// Toast notification
|
|
58866
|
-
function showToast(message, duration = 3000) {
|
|
58867
|
-
const toast = document.getElementById('toast');
|
|
58868
|
-
toast.textContent = message;
|
|
58869
|
-
toast.classList.add('show');
|
|
58870
|
-
setTimeout(() => toast.classList.remove('show'), duration);
|
|
58871
|
-
}
|
|
58872
|
-
|
|
58873
|
-
// Load configuration on page load
|
|
58874
|
-
async function loadConfig() {
|
|
58875
|
-
try {
|
|
58876
|
-
const response = await fetch('/api/config');
|
|
58877
|
-
const data = await response.json();
|
|
58878
|
-
|
|
58879
|
-
if (data.config) {
|
|
58880
|
-
document.getElementById('apiKey').value = data.config.apiKey || '';
|
|
58881
|
-
document.getElementById('providerUrl').value = data.config.providerUrl || 'https://api.openai.com/v1/chat/completions';
|
|
58882
|
-
document.getElementById('embeddingsUrl').value = data.config.embeddingsUrl || 'https://api.openai.com/v1/embeddings';
|
|
58883
|
-
document.getElementById('model').value = data.config.model || 'gpt-3.5-turbo';
|
|
58884
|
-
document.getElementById('embeddingsModel').value = data.config.embeddingsModel || 'text-embedding-3-small';
|
|
58885
|
-
}
|
|
58886
|
-
|
|
58887
|
-
document.getElementById('embeddingCount').textContent = data.embeddingCount || 0;
|
|
58888
|
-
document.getElementById('lastUpdated').textContent = data.lastUpdated || 'Never';
|
|
58889
|
-
document.getElementById('configStatus').textContent = data.config?.apiKey ? '\u2705' : '\u274C';
|
|
58890
|
-
} catch (error) {
|
|
58891
|
-
console.error('Failed to load config:', error);
|
|
58892
|
-
}
|
|
58893
|
-
}
|
|
58894
|
-
|
|
58895
|
-
// Save configuration
|
|
58896
|
-
document.getElementById('configForm').addEventListener('submit', async (e) => {
|
|
58897
|
-
e.preventDefault();
|
|
58898
|
-
|
|
58899
|
-
const config = {
|
|
58900
|
-
apiKey: document.getElementById('apiKey').value,
|
|
58901
|
-
providerUrl: document.getElementById('providerUrl').value,
|
|
58902
|
-
embeddingsUrl: document.getElementById('embeddingsUrl').value,
|
|
58903
|
-
model: document.getElementById('model').value,
|
|
58904
|
-
embeddingsModel: document.getElementById('embeddingsModel').value
|
|
58905
|
-
};
|
|
58906
|
-
|
|
58907
|
-
try {
|
|
58908
|
-
const response = await fetch('/api/config', {
|
|
58909
|
-
method: 'POST',
|
|
58910
|
-
headers: { 'Content-Type': 'application/json' },
|
|
58911
|
-
body: JSON.stringify(config)
|
|
58912
|
-
});
|
|
58913
|
-
|
|
58914
|
-
if (response.ok) {
|
|
58915
|
-
showToast('\u2705 Configuration saved successfully!');
|
|
58916
|
-
document.getElementById('configStatus').textContent = config.apiKey ? '\u2705' : '\u274C';
|
|
58917
|
-
} else {
|
|
58918
|
-
showToast('\u274C Failed to save configuration');
|
|
58919
|
-
}
|
|
58920
|
-
} catch (error) {
|
|
58921
|
-
showToast('\u274C Error saving configuration');
|
|
58922
|
-
}
|
|
58923
|
-
});
|
|
58924
|
-
|
|
58925
|
-
// Embed knowledge
|
|
58926
|
-
document.getElementById('embedForm').addEventListener('submit', async (e) => {
|
|
58927
|
-
e.preventDefault();
|
|
58928
|
-
|
|
58929
|
-
const content = document.getElementById('faqContent').value.trim();
|
|
58930
|
-
if (!content) {
|
|
58931
|
-
showToast('\u26A0\uFE0F Please enter some content to embed');
|
|
58932
|
-
return;
|
|
58933
|
-
}
|
|
58934
|
-
|
|
58935
|
-
const embedBtn = document.getElementById('embedBtn');
|
|
58936
|
-
embedBtn.disabled = true;
|
|
58937
|
-
embedBtn.textContent = '\u23F3 Embedding...';
|
|
58938
|
-
|
|
58939
|
-
try {
|
|
58940
|
-
const response = await fetch('/api/embed', {
|
|
58941
|
-
method: 'POST',
|
|
58942
|
-
headers: { 'Content-Type': 'application/json' },
|
|
58943
|
-
body: JSON.stringify({ content })
|
|
58944
|
-
});
|
|
58945
|
-
|
|
58946
|
-
const data = await response.json();
|
|
58947
|
-
|
|
58948
|
-
if (response.ok) {
|
|
58949
|
-
showToast('\u2705 ' + (data.message || 'Content embedded successfully!'));
|
|
58950
|
-
document.getElementById('embeddingCount').textContent = data.count || 0;
|
|
58951
|
-
document.getElementById('lastUpdated').textContent = new Date().toLocaleString();
|
|
58952
|
-
document.getElementById('faqContent').value = '';
|
|
58953
|
-
} else {
|
|
58954
|
-
showToast('\u274C ' + (data.error || 'Failed to embed content'));
|
|
58955
|
-
}
|
|
58956
|
-
} catch (error) {
|
|
58957
|
-
showToast('\u274C Error embedding content');
|
|
58958
|
-
} finally {
|
|
58959
|
-
embedBtn.disabled = false;
|
|
58960
|
-
embedBtn.textContent = '\u{1F52E} Embed Knowledge';
|
|
58961
|
-
}
|
|
58962
|
-
});
|
|
58963
|
-
|
|
58964
|
-
// Clear embeddings
|
|
58965
|
-
document.getElementById('clearBtn').addEventListener('click', async () => {
|
|
58966
|
-
if (!confirm('Are you sure you want to clear all embeddings?')) return;
|
|
58967
|
-
|
|
58968
|
-
try {
|
|
58969
|
-
const response = await fetch('/api/embed', {
|
|
58970
|
-
method: 'DELETE'
|
|
58971
|
-
});
|
|
58972
|
-
|
|
58973
|
-
if (response.ok) {
|
|
58974
|
-
showToast('\u2705 All embeddings cleared');
|
|
58975
|
-
document.getElementById('embeddingCount').textContent = '0';
|
|
58976
|
-
} else {
|
|
58977
|
-
showToast('\u274C Failed to clear embeddings');
|
|
58978
|
-
}
|
|
58979
|
-
} catch (error) {
|
|
58980
|
-
showToast('\u274C Error clearing embeddings');
|
|
58981
|
-
}
|
|
58982
|
-
});
|
|
58983
|
-
|
|
58984
|
-
// Load config on page load
|
|
58985
|
-
loadConfig();
|
|
58986
|
-
</script>
|
|
58987
|
-
</body>
|
|
58988
|
-
</html>
|
|
58989
|
-
`;
|
|
58990
|
-
|
|
58991
|
-
// ../../packages/template/demo/aichat/files/stylesTs.ts
|
|
58992
|
-
var stylesCSS = `/* === CSS Variables === */
|
|
58993
|
-
:root {
|
|
58994
|
-
--primary: #22c55e;
|
|
58995
|
-
--primary-dark: #16a34a;
|
|
58996
|
-
--secondary: #f97316;
|
|
58997
|
-
--bg-dark: #0f172a;
|
|
58998
|
-
--bg-card: rgba(255, 255, 255, 0.05);
|
|
58999
|
-
--text-light: #f8fafc;
|
|
59000
|
-
--text-muted: #94a3b8;
|
|
59001
|
-
--border-color: rgba(255, 255, 255, 0.1);
|
|
59002
|
-
--shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.5);
|
|
59003
|
-
--glass: rgba(255, 255, 255, 0.1);
|
|
59004
|
-
}
|
|
59005
|
-
|
|
59006
|
-
* {
|
|
59007
|
-
margin: 0;
|
|
59008
|
-
padding: 0;
|
|
59009
|
-
box-sizing: border-box;
|
|
59010
|
-
}
|
|
59011
|
-
|
|
59012
|
-
body {
|
|
59013
|
-
font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
|
|
59014
|
-
background: linear-gradient(135deg, #0f172a 0%, #1e293b 50%, #0f172a 100%);
|
|
59015
|
-
color: var(--text-light);
|
|
59016
|
-
min-height: 100vh;
|
|
59017
|
-
line-height: 1.6;
|
|
59018
|
-
}
|
|
59019
|
-
|
|
59020
|
-
/* === Header === */
|
|
59021
|
-
.header {
|
|
59022
|
-
background: var(--glass);
|
|
59023
|
-
backdrop-filter: blur(10px);
|
|
59024
|
-
border-bottom: 1px solid var(--border-color);
|
|
59025
|
-
padding: 1rem 2rem;
|
|
59026
|
-
position: fixed;
|
|
59027
|
-
top: 0;
|
|
59028
|
-
left: 0;
|
|
59029
|
-
right: 0;
|
|
59030
|
-
z-index: 100;
|
|
59031
|
-
}
|
|
59032
|
-
|
|
59033
|
-
.header-content {
|
|
59034
|
-
max-width: 1200px;
|
|
59035
|
-
margin: 0 auto;
|
|
59036
|
-
display: flex;
|
|
59037
|
-
justify-content: space-between;
|
|
59038
|
-
align-items: center;
|
|
59039
|
-
}
|
|
59040
|
-
|
|
59041
|
-
.logo {
|
|
59042
|
-
font-size: 1.5rem;
|
|
59043
|
-
font-weight: 700;
|
|
59044
|
-
background: linear-gradient(135deg, var(--primary), var(--secondary));
|
|
59045
|
-
-webkit-background-clip: text;
|
|
59046
|
-
-webkit-text-fill-color: transparent;
|
|
59047
|
-
background-clip: text;
|
|
59048
|
-
}
|
|
59049
|
-
|
|
59050
|
-
.nav-links {
|
|
59051
|
-
display: flex;
|
|
59052
|
-
gap: 2rem;
|
|
59053
|
-
list-style: none;
|
|
59054
|
-
}
|
|
59055
|
-
|
|
59056
|
-
.nav-links a {
|
|
59057
|
-
color: var(--text-muted);
|
|
59058
|
-
text-decoration: none;
|
|
59059
|
-
transition: color 0.3s;
|
|
59060
|
-
}
|
|
59061
|
-
|
|
59062
|
-
.nav-links a:hover {
|
|
59063
|
-
color: var(--primary);
|
|
59064
|
-
}
|
|
59065
|
-
|
|
59066
|
-
/* === Hero Section === */
|
|
59067
|
-
.hero {
|
|
59068
|
-
padding: 8rem 2rem 4rem;
|
|
59069
|
-
text-align: center;
|
|
59070
|
-
max-width: 900px;
|
|
59071
|
-
margin: 0 auto;
|
|
59072
|
-
}
|
|
59073
|
-
|
|
59074
|
-
.hero h1 {
|
|
59075
|
-
font-size: 3.5rem;
|
|
59076
|
-
font-weight: 800;
|
|
59077
|
-
margin-bottom: 1rem;
|
|
59078
|
-
background: linear-gradient(135deg, #fff, var(--primary));
|
|
59079
|
-
-webkit-background-clip: text;
|
|
59080
|
-
-webkit-text-fill-color: transparent;
|
|
59081
|
-
background-clip: text;
|
|
59082
|
-
}
|
|
59083
|
-
|
|
59084
|
-
.hero p {
|
|
59085
|
-
font-size: 1.25rem;
|
|
59086
|
-
color: var(--text-muted);
|
|
59087
|
-
margin-bottom: 2rem;
|
|
59088
|
-
}
|
|
59089
|
-
|
|
59090
|
-
.cta-button {
|
|
59091
|
-
background: linear-gradient(135deg, var(--primary), var(--primary-dark));
|
|
59092
|
-
color: white;
|
|
59093
|
-
padding: 1rem 2.5rem;
|
|
59094
|
-
border: none;
|
|
59095
|
-
border-radius: 50px;
|
|
59096
|
-
font-size: 1.1rem;
|
|
59097
|
-
font-weight: 600;
|
|
59098
|
-
cursor: pointer;
|
|
59099
|
-
transition: transform 0.3s, box-shadow 0.3s;
|
|
59100
|
-
}
|
|
59101
|
-
|
|
59102
|
-
.cta-button:hover {
|
|
59103
|
-
transform: translateY(-2px);
|
|
59104
|
-
box-shadow: 0 10px 30px rgba(34, 197, 94, 0.3);
|
|
59105
|
-
}
|
|
59106
|
-
|
|
59107
|
-
/* === Products Grid === */
|
|
59108
|
-
.products {
|
|
59109
|
-
max-width: 1200px;
|
|
59110
|
-
margin: 0 auto;
|
|
59111
|
-
padding: 4rem 2rem;
|
|
59112
|
-
}
|
|
59113
|
-
|
|
59114
|
-
.products h2 {
|
|
59115
|
-
text-align: center;
|
|
59116
|
-
font-size: 2.5rem;
|
|
59117
|
-
margin-bottom: 3rem;
|
|
59118
|
-
}
|
|
59119
|
-
|
|
59120
|
-
.products-grid {
|
|
59121
|
-
display: grid;
|
|
59122
|
-
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
|
|
59123
|
-
gap: 2rem;
|
|
59124
|
-
}
|
|
59125
|
-
|
|
59126
|
-
.product-card {
|
|
59127
|
-
background: var(--bg-card);
|
|
59128
|
-
border: 1px solid var(--border-color);
|
|
59129
|
-
border-radius: 20px;
|
|
59130
|
-
overflow: hidden;
|
|
59131
|
-
transition: transform 0.3s, box-shadow 0.3s;
|
|
59132
|
-
}
|
|
59133
|
-
|
|
59134
|
-
.product-card:hover {
|
|
59135
|
-
transform: translateY(-5px);
|
|
59136
|
-
box-shadow: var(--shadow);
|
|
59137
|
-
}
|
|
59138
|
-
|
|
59139
|
-
.product-image {
|
|
59140
|
-
width: 100%;
|
|
59141
|
-
height: 200px;
|
|
59142
|
-
object-fit: cover;
|
|
59143
|
-
background: linear-gradient(135deg, var(--primary), var(--secondary));
|
|
59144
|
-
display: flex;
|
|
59145
|
-
align-items: center;
|
|
59146
|
-
justify-content: center;
|
|
59147
|
-
font-size: 4rem;
|
|
59148
|
-
}
|
|
59149
|
-
|
|
59150
|
-
.product-info {
|
|
59151
|
-
padding: 1.5rem;
|
|
59152
|
-
}
|
|
59153
|
-
|
|
59154
|
-
.product-info h3 {
|
|
59155
|
-
font-size: 1.25rem;
|
|
59156
|
-
margin-bottom: 0.5rem;
|
|
59157
|
-
}
|
|
59158
|
-
|
|
59159
|
-
.product-info p {
|
|
59160
|
-
color: var(--text-muted);
|
|
59161
|
-
font-size: 0.9rem;
|
|
59162
|
-
margin-bottom: 1rem;
|
|
59163
|
-
}
|
|
59164
|
-
|
|
59165
|
-
.product-price {
|
|
59166
|
-
font-size: 1.5rem;
|
|
59167
|
-
font-weight: 700;
|
|
59168
|
-
color: var(--primary);
|
|
59169
|
-
}
|
|
59170
|
-
|
|
59171
|
-
/* === Chatbox Widget === */
|
|
59172
|
-
.chat-widget {
|
|
59173
|
-
position: fixed;
|
|
59174
|
-
bottom: 20px;
|
|
59175
|
-
right: 20px;
|
|
59176
|
-
z-index: 1000;
|
|
59177
|
-
}
|
|
59178
|
-
|
|
59179
|
-
.chat-toggle {
|
|
59180
|
-
width: 60px;
|
|
59181
|
-
height: 60px;
|
|
59182
|
-
border-radius: 50%;
|
|
59183
|
-
background: linear-gradient(135deg, var(--primary), var(--secondary));
|
|
59184
|
-
border: none;
|
|
59185
|
-
cursor: pointer;
|
|
59186
|
-
display: flex;
|
|
59187
|
-
align-items: center;
|
|
59188
|
-
justify-content: center;
|
|
59189
|
-
box-shadow: 0 5px 30px rgba(34, 197, 94, 0.4);
|
|
59190
|
-
transition: transform 0.3s;
|
|
59191
|
-
}
|
|
59192
|
-
|
|
59193
|
-
.chat-toggle:hover {
|
|
59194
|
-
transform: scale(1.1);
|
|
59195
|
-
}
|
|
59196
|
-
|
|
59197
|
-
.chat-toggle svg {
|
|
59198
|
-
width: 28px;
|
|
59199
|
-
height: 28px;
|
|
59200
|
-
fill: white;
|
|
59201
|
-
}
|
|
59202
|
-
|
|
59203
|
-
.chat-window {
|
|
59204
|
-
position: absolute;
|
|
59205
|
-
bottom: 80px;
|
|
59206
|
-
right: 0;
|
|
59207
|
-
width: 380px;
|
|
59208
|
-
height: 500px;
|
|
59209
|
-
background: var(--bg-dark);
|
|
59210
|
-
border: 1px solid var(--border-color);
|
|
59211
|
-
border-radius: 20px;
|
|
59212
|
-
box-shadow: var(--shadow);
|
|
59213
|
-
display: none;
|
|
59214
|
-
flex-direction: column;
|
|
59215
|
-
overflow: hidden;
|
|
59216
|
-
animation: slideUp 0.3s ease;
|
|
59217
|
-
}
|
|
59218
|
-
|
|
59219
|
-
.chat-window.open {
|
|
59220
|
-
display: flex;
|
|
59221
|
-
}
|
|
59222
|
-
|
|
59223
|
-
@keyframes slideUp {
|
|
59224
|
-
from {
|
|
59225
|
-
opacity: 0;
|
|
59226
|
-
transform: translateY(20px);
|
|
59227
|
-
}
|
|
59228
|
-
to {
|
|
59229
|
-
opacity: 1;
|
|
59230
|
-
transform: translateY(0);
|
|
59231
|
-
}
|
|
59232
|
-
}
|
|
59233
|
-
|
|
59234
|
-
.chat-header {
|
|
59235
|
-
background: linear-gradient(135deg, var(--primary), var(--primary-dark));
|
|
59236
|
-
padding: 1rem 1.5rem;
|
|
59237
|
-
display: flex;
|
|
59238
|
-
align-items: center;
|
|
59239
|
-
gap: 0.75rem;
|
|
59240
|
-
}
|
|
59241
|
-
|
|
59242
|
-
.chat-header-avatar {
|
|
59243
|
-
width: 40px;
|
|
59244
|
-
height: 40px;
|
|
59245
|
-
border-radius: 50%;
|
|
59246
|
-
background: rgba(255, 255, 255, 0.2);
|
|
59247
|
-
display: flex;
|
|
59248
|
-
align-items: center;
|
|
59249
|
-
justify-content: center;
|
|
59250
|
-
font-size: 1.25rem;
|
|
59251
|
-
}
|
|
59252
|
-
|
|
59253
|
-
.chat-header-info h4 {
|
|
59254
|
-
font-size: 1rem;
|
|
59255
|
-
font-weight: 600;
|
|
59256
|
-
}
|
|
59257
|
-
|
|
59258
|
-
.chat-header-info span {
|
|
59259
|
-
font-size: 0.75rem;
|
|
59260
|
-
opacity: 0.8;
|
|
59261
|
-
}
|
|
59262
|
-
|
|
59263
|
-
.chat-messages {
|
|
59264
|
-
flex: 1;
|
|
59265
|
-
overflow-y: auto;
|
|
59266
|
-
padding: 1rem;
|
|
59267
|
-
display: flex;
|
|
59268
|
-
flex-direction: column;
|
|
59269
|
-
gap: 0.75rem;
|
|
59270
|
-
}
|
|
59271
|
-
|
|
59272
|
-
.message {
|
|
59273
|
-
max-width: 80%;
|
|
59274
|
-
padding: 0.75rem 1rem;
|
|
59275
|
-
border-radius: 18px;
|
|
59276
|
-
font-size: 0.9rem;
|
|
59277
|
-
line-height: 1.4;
|
|
59278
|
-
}
|
|
59279
|
-
|
|
59280
|
-
.message.bot {
|
|
59281
|
-
background: var(--glass);
|
|
59282
|
-
border: 1px solid var(--border-color);
|
|
59283
|
-
align-self: flex-start;
|
|
59284
|
-
border-bottom-left-radius: 4px;
|
|
59285
|
-
}
|
|
59286
|
-
|
|
59287
|
-
.message.user {
|
|
59288
|
-
background: linear-gradient(135deg, var(--primary), var(--primary-dark));
|
|
59289
|
-
align-self: flex-end;
|
|
59290
|
-
border-bottom-right-radius: 4px;
|
|
59291
|
-
}
|
|
59292
|
-
|
|
59293
|
-
.typing-indicator {
|
|
59294
|
-
display: flex;
|
|
59295
|
-
gap: 4px;
|
|
59296
|
-
padding: 0.75rem 1rem;
|
|
59297
|
-
background: var(--glass);
|
|
59298
|
-
border: 1px solid var(--border-color);
|
|
59299
|
-
border-radius: 18px;
|
|
59300
|
-
align-self: flex-start;
|
|
59301
|
-
border-bottom-left-radius: 4px;
|
|
59302
|
-
}
|
|
59303
|
-
|
|
59304
|
-
.typing-indicator span {
|
|
59305
|
-
width: 8px;
|
|
59306
|
-
height: 8px;
|
|
59307
|
-
background: var(--text-muted);
|
|
59308
|
-
border-radius: 50%;
|
|
59309
|
-
animation: bounce 1.4s infinite ease-in-out;
|
|
59310
|
-
}
|
|
59311
|
-
|
|
59312
|
-
.typing-indicator span:nth-child(1) { animation-delay: -0.32s; }
|
|
59313
|
-
.typing-indicator span:nth-child(2) { animation-delay: -0.16s; }
|
|
59314
|
-
|
|
59315
|
-
@keyframes bounce {
|
|
59316
|
-
0%, 80%, 100% { transform: scale(0); }
|
|
59317
|
-
40% { transform: scale(1); }
|
|
59318
|
-
}
|
|
59319
|
-
|
|
59320
|
-
.chat-input-container {
|
|
59321
|
-
padding: 1rem;
|
|
59322
|
-
border-top: 1px solid var(--border-color);
|
|
59323
|
-
display: flex;
|
|
59324
|
-
gap: 0.5rem;
|
|
59325
|
-
}
|
|
59326
|
-
|
|
59327
|
-
.chat-input {
|
|
59328
|
-
flex: 1;
|
|
59329
|
-
background: var(--glass);
|
|
59330
|
-
border: 1px solid var(--border-color);
|
|
59331
|
-
border-radius: 25px;
|
|
59332
|
-
padding: 0.75rem 1rem;
|
|
59333
|
-
color: var(--text-light);
|
|
59334
|
-
font-size: 0.9rem;
|
|
59335
|
-
outline: none;
|
|
59336
|
-
}
|
|
59337
|
-
|
|
59338
|
-
.chat-input::placeholder {
|
|
59339
|
-
color: var(--text-muted);
|
|
59340
|
-
}
|
|
59341
|
-
|
|
59342
|
-
.chat-send {
|
|
59343
|
-
width: 44px;
|
|
59344
|
-
height: 44px;
|
|
59345
|
-
border-radius: 50%;
|
|
59346
|
-
background: linear-gradient(135deg, var(--primary), var(--primary-dark));
|
|
59347
|
-
border: none;
|
|
59348
|
-
cursor: pointer;
|
|
59349
|
-
display: flex;
|
|
59350
|
-
align-items: center;
|
|
59351
|
-
justify-content: center;
|
|
59352
|
-
transition: transform 0.2s;
|
|
59353
|
-
}
|
|
59354
|
-
|
|
59355
|
-
.chat-send:hover {
|
|
59356
|
-
transform: scale(1.05);
|
|
59357
|
-
}
|
|
59358
|
-
|
|
59359
|
-
.chat-send svg {
|
|
59360
|
-
width: 20px;
|
|
59361
|
-
height: 20px;
|
|
59362
|
-
fill: white;
|
|
59363
|
-
}
|
|
59364
|
-
|
|
59365
|
-
/* === Admin Panel Styles === */
|
|
59366
|
-
.admin-container {
|
|
59367
|
-
max-width: 900px;
|
|
59368
|
-
margin: 0 auto;
|
|
59369
|
-
padding: 6rem 2rem 4rem;
|
|
59370
|
-
}
|
|
59371
|
-
|
|
59372
|
-
.admin-header {
|
|
59373
|
-
text-align: center;
|
|
59374
|
-
margin-bottom: 3rem;
|
|
59375
|
-
}
|
|
59376
|
-
|
|
59377
|
-
.admin-header h1 {
|
|
59378
|
-
font-size: 2.5rem;
|
|
59379
|
-
margin-bottom: 0.5rem;
|
|
59380
|
-
}
|
|
59381
|
-
|
|
59382
|
-
.admin-header p {
|
|
59383
|
-
color: var(--text-muted);
|
|
59384
|
-
}
|
|
59385
|
-
|
|
59386
|
-
.admin-card {
|
|
59387
|
-
background: var(--bg-card);
|
|
59388
|
-
border: 1px solid var(--border-color);
|
|
59389
|
-
border-radius: 20px;
|
|
59390
|
-
padding: 2rem;
|
|
59391
|
-
margin-bottom: 2rem;
|
|
59392
|
-
}
|
|
59393
|
-
|
|
59394
|
-
.admin-card h2 {
|
|
59395
|
-
font-size: 1.25rem;
|
|
59396
|
-
margin-bottom: 1.5rem;
|
|
59397
|
-
display: flex;
|
|
59398
|
-
align-items: center;
|
|
59399
|
-
gap: 0.5rem;
|
|
59400
|
-
}
|
|
59401
|
-
|
|
59402
|
-
.form-group {
|
|
59403
|
-
margin-bottom: 1.5rem;
|
|
59404
|
-
}
|
|
59405
|
-
|
|
59406
|
-
.form-group label {
|
|
59407
|
-
display: block;
|
|
59408
|
-
font-size: 0.9rem;
|
|
59409
|
-
color: var(--text-muted);
|
|
59410
|
-
margin-bottom: 0.5rem;
|
|
59411
|
-
}
|
|
59412
|
-
|
|
59413
|
-
.form-input {
|
|
59414
|
-
width: 100%;
|
|
59415
|
-
background: var(--glass);
|
|
59416
|
-
border: 1px solid var(--border-color);
|
|
59417
|
-
border-radius: 10px;
|
|
59418
|
-
padding: 0.875rem 1rem;
|
|
59419
|
-
color: var(--text-light);
|
|
59420
|
-
font-size: 0.95rem;
|
|
59421
|
-
outline: none;
|
|
59422
|
-
transition: border-color 0.3s;
|
|
59423
|
-
}
|
|
59424
|
-
|
|
59425
|
-
.form-input:focus {
|
|
59426
|
-
border-color: var(--primary);
|
|
59427
|
-
}
|
|
59428
|
-
|
|
59429
|
-
.form-input::placeholder {
|
|
59430
|
-
color: var(--text-muted);
|
|
59431
|
-
}
|
|
59432
|
-
|
|
59433
|
-
textarea.form-input {
|
|
59434
|
-
min-height: 200px;
|
|
59435
|
-
resize: vertical;
|
|
59436
|
-
font-family: inherit;
|
|
59437
|
-
}
|
|
59438
|
-
|
|
59439
|
-
.btn {
|
|
59440
|
-
background: linear-gradient(135deg, var(--primary), var(--primary-dark));
|
|
59441
|
-
color: white;
|
|
59442
|
-
padding: 0.875rem 2rem;
|
|
59443
|
-
border: none;
|
|
59444
|
-
border-radius: 10px;
|
|
59445
|
-
font-size: 1rem;
|
|
59446
|
-
font-weight: 600;
|
|
59447
|
-
cursor: pointer;
|
|
59448
|
-
transition: transform 0.2s, box-shadow 0.2s;
|
|
59449
|
-
display: inline-flex;
|
|
59450
|
-
align-items: center;
|
|
59451
|
-
gap: 0.5rem;
|
|
59452
|
-
}
|
|
59453
|
-
|
|
59454
|
-
.btn:hover {
|
|
59455
|
-
transform: translateY(-2px);
|
|
59456
|
-
box-shadow: 0 10px 30px rgba(34, 197, 94, 0.3);
|
|
59457
|
-
}
|
|
59458
|
-
|
|
59459
|
-
.btn:disabled {
|
|
59460
|
-
opacity: 0.6;
|
|
59461
|
-
cursor: not-allowed;
|
|
59462
|
-
transform: none;
|
|
59463
|
-
}
|
|
59464
|
-
|
|
59465
|
-
.btn-secondary {
|
|
59466
|
-
background: var(--glass);
|
|
59467
|
-
border: 1px solid var(--border-color);
|
|
59468
|
-
}
|
|
59469
|
-
|
|
59470
|
-
.status-bar {
|
|
59471
|
-
background: var(--glass);
|
|
59472
|
-
border: 1px solid var(--border-color);
|
|
59473
|
-
border-radius: 10px;
|
|
59474
|
-
padding: 1rem 1.5rem;
|
|
59475
|
-
display: flex;
|
|
59476
|
-
justify-content: space-between;
|
|
59477
|
-
align-items: center;
|
|
59478
|
-
margin-top: 1.5rem;
|
|
59479
|
-
}
|
|
59480
|
-
|
|
59481
|
-
.status-item {
|
|
59482
|
-
text-align: center;
|
|
59483
|
-
}
|
|
59484
|
-
|
|
59485
|
-
.status-item .value {
|
|
59486
|
-
font-size: 1.5rem;
|
|
59487
|
-
font-weight: 700;
|
|
59488
|
-
color: var(--primary);
|
|
59489
|
-
}
|
|
59490
|
-
|
|
59491
|
-
.status-item .label {
|
|
59492
|
-
font-size: 0.8rem;
|
|
59493
|
-
color: var(--text-muted);
|
|
59494
|
-
}
|
|
59495
|
-
|
|
59496
|
-
.toast {
|
|
59497
|
-
position: fixed;
|
|
59498
|
-
bottom: 20px;
|
|
59499
|
-
left: 50%;
|
|
59500
|
-
transform: translateX(-50%);
|
|
59501
|
-
background: var(--primary);
|
|
59502
|
-
color: white;
|
|
59503
|
-
padding: 1rem 2rem;
|
|
59504
|
-
border-radius: 10px;
|
|
59505
|
-
box-shadow: var(--shadow);
|
|
59506
|
-
opacity: 0;
|
|
59507
|
-
transition: opacity 0.3s;
|
|
59508
|
-
z-index: 2000;
|
|
59509
|
-
}
|
|
59510
|
-
|
|
59511
|
-
.toast.show {
|
|
59512
|
-
opacity: 1;
|
|
59513
|
-
}
|
|
59514
|
-
|
|
59515
|
-
/* === Responsive === */
|
|
59516
|
-
@media (max-width: 768px) {
|
|
59517
|
-
.hero h1 {
|
|
59518
|
-
font-size: 2.5rem;
|
|
59519
|
-
}
|
|
59520
|
-
|
|
59521
|
-
.chat-window {
|
|
59522
|
-
width: calc(100vw - 40px);
|
|
59523
|
-
height: 60vh;
|
|
59524
|
-
}
|
|
59525
|
-
|
|
59526
|
-
.nav-links {
|
|
59527
|
-
display: none;
|
|
59528
|
-
}
|
|
59529
|
-
}
|
|
59530
|
-
`;
|
|
59531
|
-
|
|
59532
|
-
// ../../packages/template/demo/aichat/files/serverTs.ts
|
|
59533
|
-
var serverTs = `import express, { Request, Response } from 'express';
|
|
59534
|
-
import path from 'path';
|
|
59535
|
-
import chatRouter from './routes/chat';
|
|
59536
|
-
import embedRouter from './routes/embed';
|
|
59537
|
-
import configRouter from './routes/config';
|
|
59538
|
-
import { loadEmbeddings } from './vectorStore';
|
|
59539
|
-
import { loadConfig } from './aiClient';
|
|
59540
|
-
|
|
59541
|
-
const app = express();
|
|
59542
|
-
const port = 3500;
|
|
59543
|
-
|
|
59544
|
-
// Middleware
|
|
59545
|
-
app.use(express.static(path.join(__dirname, '../public')));
|
|
59546
|
-
app.use(express.json());
|
|
59547
|
-
|
|
59548
|
-
// Load persisted data
|
|
59549
|
-
loadEmbeddings();
|
|
59550
|
-
loadConfig();
|
|
59551
|
-
|
|
59552
|
-
// API Routes
|
|
59553
|
-
app.use('/api/chat', chatRouter);
|
|
59554
|
-
app.use('/api/embed', embedRouter);
|
|
59555
|
-
app.use('/api/config', configRouter);
|
|
59556
|
-
|
|
59557
|
-
// Serve main page
|
|
59558
|
-
app.get('/', (req: Request, res: Response) => {
|
|
59559
|
-
res.sendFile(path.join(__dirname, '../public/index.html'));
|
|
59560
|
-
});
|
|
58616
|
+
// ../../packages/template/demo/monochat.ts
|
|
58617
|
+
var MonoChat = {
|
|
58618
|
+
name: "Chat To MonoChat",
|
|
58619
|
+
description: "React Frontend, needs custom backend",
|
|
58620
|
+
notes: "Vite React + TailwindCSS + TypeScript",
|
|
58621
|
+
templating: [
|
|
58622
|
+
{
|
|
58623
|
+
action: "command",
|
|
58624
|
+
cmd: "rm -rf ./* ./.[!.]*",
|
|
58625
|
+
args: []
|
|
58626
|
+
},
|
|
58627
|
+
{
|
|
58628
|
+
action: "file",
|
|
58629
|
+
file: ".gitignore",
|
|
58630
|
+
filecontent: "# Logs\nlogs\n*.log\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\npnpm-debug.log*\nlerna-debug.log*\n\nnode_modules\ndist\ndist-ssr\n*.local\n\n# Editor directories and files\n.vscode/*\n!.vscode/extensions.json\n.idea\n.DS_Store\n*.suo\n*.ntvs*\n*.njsproj\n*.sln\n*.sw?\n"
|
|
58631
|
+
},
|
|
58632
|
+
{
|
|
58633
|
+
action: "file",
|
|
58634
|
+
file: "README.md",
|
|
58635
|
+
filecontent: "# React + TypeScript + Vite\n\nThis template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.\n\nCurrently, two official plugins are available:\n\n- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react) uses [Babel](https://babeljs.io/) (or [oxc](https://oxc.rs) when used in [rolldown-vite](https://vite.dev/guide/rolldown)) for Fast Refresh\n- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh\n\n## React Compiler\n\nThe React Compiler is not enabled on this template because of its impact on dev & build performances. To add it, see [this documentation](https://react.dev/learn/react-compiler/installation).\n\n## Expanding the ESLint configuration\n\nIf you are developing a production application, we recommend updating the configuration to enable type-aware lint rules:\n\n```js\nexport default defineConfig([\n globalIgnores(['dist']),\n {\n files: ['**/*.{ts,tsx}'],\n extends: [\n // Other configs...\n\n // Remove tseslint.configs.recommended and replace with this\n tseslint.configs.recommendedTypeChecked,\n // Alternatively, use this for stricter rules\n tseslint.configs.strictTypeChecked,\n // Optionally, add this for stylistic rules\n tseslint.configs.stylisticTypeChecked,\n\n // Other configs...\n ],\n languageOptions: {\n parserOptions: {\n project: ['./tsconfig.node.json', './tsconfig.app.json'],\n tsconfigRootDir: import.meta.dirname,\n },\n // other options...\n },\n },\n])\n```\n\nYou can also install [eslint-plugin-react-x](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-x) and [eslint-plugin-react-dom](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-dom) for React-specific lint rules:\n\n```js\n// eslint.config.js\nimport reactX from 'eslint-plugin-react-x'\nimport reactDom from 'eslint-plugin-react-dom'\n\nexport default defineConfig([\n globalIgnores(['dist']),\n {\n files: ['**/*.{ts,tsx}'],\n extends: [\n // Other configs...\n // Enable lint rules for React\n reactX.configs['recommended-typescript'],\n // Enable lint rules for React DOM\n reactDom.configs.recommended,\n ],\n languageOptions: {\n parserOptions: {\n project: ['./tsconfig.node.json', './tsconfig.app.json'],\n tsconfigRootDir: import.meta.dirname,\n },\n // other options...\n },\n },\n])\n```\n"
|
|
58636
|
+
},
|
|
58637
|
+
{
|
|
58638
|
+
action: "file",
|
|
58639
|
+
file: "eslint.config.js",
|
|
58640
|
+
filecontent: "import js from '@eslint/js'\nimport globals from 'globals'\nimport reactHooks from 'eslint-plugin-react-hooks'\nimport reactRefresh from 'eslint-plugin-react-refresh'\nimport tseslint from 'typescript-eslint'\nimport { defineConfig, globalIgnores } from 'eslint/config'\n\nexport default defineConfig([\n globalIgnores(['dist']),\n {\n files: ['**/*.{ts,tsx}'],\n extends: [\n js.configs.recommended,\n tseslint.configs.recommended,\n reactHooks.configs.flat.recommended,\n reactRefresh.configs.vite,\n ],\n languageOptions: {\n ecmaVersion: 2020,\n globals: globals.browser,\n },\n },\n])\n"
|
|
58641
|
+
},
|
|
58642
|
+
{
|
|
58643
|
+
action: "file",
|
|
58644
|
+
file: "index.html",
|
|
58645
|
+
filecontent: '<!doctype html>\n<html lang="en">\n <head>\n <meta charset="UTF-8" />\n <link rel="icon" type="image/svg+xml" href="/logo.svg" />\n <meta name="viewport" content="width=device-width, initial-scale=1.0" />\n <title>MonoChat</title>\n </head>\n <body>\n <div id="root"></div>\n <script type="module" src="/src/main.tsx"></script>\n </body>\n</html>\n'
|
|
58646
|
+
},
|
|
58647
|
+
{
|
|
58648
|
+
action: "file",
|
|
58649
|
+
file: "netlify.toml",
|
|
58650
|
+
filecontent: '[build]\n command = "npm run build"\n publish = "dist"\n\n[[redirects]]\n from = "/*"\n to = "/index.html"\n status = 200'
|
|
58651
|
+
},
|
|
58652
|
+
{
|
|
58653
|
+
action: "file",
|
|
58654
|
+
file: "package.json",
|
|
58655
|
+
filecontent: '{\n "name": "z-chat",\n "private": true,\n "version": "0.0.0",\n "type": "module",\n "scripts": {\n "dev": "vite",\n "build": "tsc -b && vite build",\n "lint": "eslint .",\n "preview": "vite preview",\n "stop": ""\n },\n "dependencies": {\n "react": "^19.2.0",\n "react-dom": "^19.2.0",\n "zustand": "^4.5.7"\n },\n "devDependencies": {\n "@eslint/js": "^9.39.1",\n "@tailwindcss/postcss": "^4.0.0",\n "@types/node": "^24.10.1",\n "@types/react": "^19.2.5",\n "@types/react-dom": "^19.2.3",\n "@vitejs/plugin-react": "^5.1.1",\n "autoprefixer": "^10.4.20",\n "eslint": "^9.39.1",\n "eslint-plugin-react-hooks": "^7.0.1",\n "eslint-plugin-react-refresh": "^0.4.24",\n "globals": "^16.5.0",\n "jiti": "^2.4.2",\n "postcss": "^8.5.1",\n "tailwindcss": "^4.0.0",\n "typescript": "~5.9.3",\n "typescript-eslint": "^8.46.4",\n "vite": "^7.2.4"\n },\n "description": "Vite React TS",\n "fontawesomeIcon": "fab fa-react text-blue-500"\n}\n'
|
|
58656
|
+
},
|
|
58657
|
+
{
|
|
58658
|
+
action: "file",
|
|
58659
|
+
file: "postcss.config.js",
|
|
58660
|
+
filecontent: 'export default {\n plugins: {\n "@tailwindcss/postcss": {},\n autoprefixer: {},\n },\n}'
|
|
58661
|
+
},
|
|
58662
|
+
{
|
|
58663
|
+
action: "file",
|
|
58664
|
+
file: "public/logo.svg",
|
|
58665
|
+
filecontent: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">\n <defs>\n <linearGradient id="grad" x1="0%" y1="0%" x2="100%" y2="100%">\n <stop offset="0%" style="stop-color:#6366f1;stop-opacity:1" />\n <stop offset="100%" style="stop-color:#a855f7;stop-opacity:1" />\n </linearGradient>\n </defs>\n <rect width="512" height="512" rx="128" fill="url(#grad)" />\n <path d="M375.3 325.7c22.1-24.9 36.7-56.3 36.7-91.7c0-79.5-72.7-144-162-144S88 154.5 88 234s72.7 144 162 144c20.3 0 39.7-3.4 57.6-9.6L368 400l-45.7-31.3c18.5-12.7 34.6-28 47-45.7v2.7z" fill="white" />\n <circle cx="178" cy="234" r="20" fill="#6366f1"/>\n <circle cx="250" cy="234" r="20" fill="#6366f1"/>\n <circle cx="322" cy="234" r="20" fill="#6366f1"/>\n</svg>\n'
|
|
58666
|
+
},
|
|
58667
|
+
{
|
|
58668
|
+
action: "file",
|
|
58669
|
+
file: "render.yaml",
|
|
58670
|
+
filecontent: "services:\n - type: web\n name: vite-react-app\n env: static\n buildCommand: npm install && npm run build\n staticPublishPath: ./dist"
|
|
58671
|
+
},
|
|
58672
|
+
{
|
|
58673
|
+
action: "file",
|
|
58674
|
+
file: "src/App.tsx",
|
|
58675
|
+
filecontent: "import Background from './components/Background';\nimport ChatContainer from './components/ChatContainer';\nimport Header from './components/Header';\n\nexport default function App() {\n return (\n <div className={`\n h-[100vh]\n w-[100vw]\n overflow-hidden\n bg-zinc-900 \n `}>\n <div className='w-full h-full'>\n <Background />\n <Header />\n <ChatContainer />\n </div>\n </div>\n );\n}"
|
|
58676
|
+
},
|
|
58677
|
+
{
|
|
58678
|
+
action: "file",
|
|
58679
|
+
file: "src/_FetchToWho.ts",
|
|
58680
|
+
filecontent: 'import type { ChatItem } from "./app/chat";\n\n//@ts-ignore\nexport default async function FetchToWho( chats: ChatItem[]) {\n // const lastChat = chats[chats.length - 1];\n // if (!lastChat) return;\n // const response = await fetch("https://api.openai.com/v1/chat/completions", {\n // method: "POST",\n // headers: {\n // "Content-Type": "application/json",\n // "Authorization": `Bearer ${process.env.OPENAI_API_KEY}`\n // },\n // body: JSON.stringify({\n // model: "gpt-3.5-turbo",\n // messages: [\n // { role: "system", content: "You are a helpful assistant." },\n // { role: "user", content: lastChat.message }\n // ]\n // })\n // });\n // const data = await response.json();\n // return data.choices[0].message.content;\n\n const lorem = "Please edit the FetchToWho function. Lorem ipsum dolor sit amet consectetur adipisicing elit. Quisquam, quod. Lorem ipsum dolor sit amet consectetur adipisicing elit. Quisquam, quod. Lorem ipsum dolor sit amet consectetur adipisicing elit. Quisquam, quod. Lorem ipsum dolor sit amet consectetur adipisicing elit. Quisquam, quod. Lorem ipsum dolor sit amet consectetur adipisicing elit. Quisquam, quod.";\n return lorem;\n}\n'
|
|
58681
|
+
},
|
|
58682
|
+
{
|
|
58683
|
+
action: "file",
|
|
58684
|
+
file: "src/app/chat.ts",
|
|
58685
|
+
filecontent: `import { create } from 'zustand';
|
|
58686
|
+
import { createSelectors } from './zustandSelector';
|
|
59561
58687
|
|
|
59562
|
-
|
|
59563
|
-
|
|
59564
|
-
|
|
59565
|
-
console.log('\u{1F34A} ====================================');
|
|
59566
|
-
console.log(' FreshFruit AI Chat Demo');
|
|
59567
|
-
console.log('====================================');
|
|
59568
|
-
console.log('');
|
|
59569
|
-
console.log('\u{1F4CD} Store: http://localhost:' + port);
|
|
59570
|
-
console.log('\u{1F527} Admin Panel: http://localhost:' + port + '/admin.html');
|
|
59571
|
-
console.log('');
|
|
59572
|
-
console.log('\u{1F4DD} Quick Start:');
|
|
59573
|
-
console.log(' 1. Open the Admin Panel');
|
|
59574
|
-
console.log(' 2. Configure your OpenAI API key');
|
|
59575
|
-
console.log(' 3. Add FAQ content and click "Embed"');
|
|
59576
|
-
console.log(' 4. Open the Store and chat with the AI!');
|
|
59577
|
-
console.log('');
|
|
59578
|
-
});
|
|
59579
|
-
`;
|
|
59580
|
-
var tsconfigJson = `{
|
|
59581
|
-
"compilerOptions": {
|
|
59582
|
-
"target": "es2016",
|
|
59583
|
-
"module": "commonjs",
|
|
59584
|
-
"outDir": "./dist",
|
|
59585
|
-
"esModuleInterop": true,
|
|
59586
|
-
"forceConsistentCasingInFileNames": true,
|
|
59587
|
-
"strict": true,
|
|
59588
|
-
"skipLibCheck": true
|
|
59589
|
-
}
|
|
59590
|
-
}`;
|
|
59591
|
-
var tsupConfig = `import { defineConfig } from 'tsup';
|
|
59592
|
-
|
|
59593
|
-
export default defineConfig({
|
|
59594
|
-
entry: ['src/index.ts'],
|
|
59595
|
-
splitting: false,
|
|
59596
|
-
sourcemap: true,
|
|
59597
|
-
clean: true,
|
|
59598
|
-
format: ['cjs'],
|
|
59599
|
-
});`;
|
|
59600
|
-
|
|
59601
|
-
// ../../packages/template/demo/aichat/files/vectorStoreTs.ts
|
|
59602
|
-
var vectorStoreTs = `import fs from 'fs';
|
|
59603
|
-
import path from 'path';
|
|
59604
|
-
|
|
59605
|
-
const EMBEDDINGS_FILE = path.join(__dirname, '../embeddings.json');
|
|
59606
|
-
|
|
59607
|
-
interface EmbeddingEntry {
|
|
59608
|
-
id: string;
|
|
59609
|
-
text: string;
|
|
59610
|
-
embedding: number[];
|
|
58688
|
+
export interface ChatItem {
|
|
58689
|
+
id: number;
|
|
58690
|
+
who: "user" | "system";
|
|
59611
58691
|
timestamp: number;
|
|
58692
|
+
message: string;
|
|
59612
58693
|
}
|
|
59613
58694
|
|
|
59614
|
-
|
|
59615
|
-
|
|
59616
|
-
|
|
59617
|
-
|
|
59618
|
-
|
|
59619
|
-
try {
|
|
59620
|
-
if (fs.existsSync(EMBEDDINGS_FILE)) {
|
|
59621
|
-
const data = fs.readFileSync(EMBEDDINGS_FILE, 'utf-8');
|
|
59622
|
-
vectorStore = JSON.parse(data);
|
|
59623
|
-
console.log('\u{1F4DA} Loaded ' + vectorStore.length + ' embeddings from file');
|
|
59624
|
-
}
|
|
59625
|
-
} catch (error) {
|
|
59626
|
-
console.error('Failed to load embeddings:', error);
|
|
59627
|
-
vectorStore = [];
|
|
59628
|
-
}
|
|
59629
|
-
}
|
|
59630
|
-
|
|
59631
|
-
// Save embeddings to file
|
|
59632
|
-
export function saveEmbeddings(): void {
|
|
59633
|
-
try {
|
|
59634
|
-
fs.writeFileSync(EMBEDDINGS_FILE, JSON.stringify(vectorStore, null, 2));
|
|
59635
|
-
} catch (error) {
|
|
59636
|
-
console.error('Failed to save embeddings:', error);
|
|
59637
|
-
}
|
|
59638
|
-
}
|
|
59639
|
-
|
|
59640
|
-
// Add embedding to store
|
|
59641
|
-
export function addEmbedding(text: string, embedding: number[]): void {
|
|
59642
|
-
const entry: EmbeddingEntry = {
|
|
59643
|
-
id: Date.now().toString(36) + Math.random().toString(36).substr(2),
|
|
59644
|
-
text,
|
|
59645
|
-
embedding,
|
|
59646
|
-
timestamp: Date.now()
|
|
59647
|
-
};
|
|
59648
|
-
vectorStore.push(entry);
|
|
59649
|
-
saveEmbeddings();
|
|
59650
|
-
}
|
|
59651
|
-
|
|
59652
|
-
// Clear all embeddings
|
|
59653
|
-
export function clearEmbeddings(): void {
|
|
59654
|
-
vectorStore = [];
|
|
59655
|
-
saveEmbeddings();
|
|
59656
|
-
}
|
|
59657
|
-
|
|
59658
|
-
// Get embedding count
|
|
59659
|
-
export function getEmbeddingCount(): number {
|
|
59660
|
-
return vectorStore.length;
|
|
59661
|
-
}
|
|
59662
|
-
|
|
59663
|
-
// Cosine similarity between two vectors
|
|
59664
|
-
function cosineSimilarity(a: number[], b: number[]): number {
|
|
59665
|
-
if (a.length !== b.length) return 0;
|
|
59666
|
-
|
|
59667
|
-
let dotProduct = 0;
|
|
59668
|
-
let normA = 0;
|
|
59669
|
-
let normB = 0;
|
|
59670
|
-
|
|
59671
|
-
for (let i = 0; i < a.length; i++) {
|
|
59672
|
-
dotProduct += a[i] * b[i];
|
|
59673
|
-
normA += a[i] * a[i];
|
|
59674
|
-
normB += b[i] * b[i];
|
|
59675
|
-
}
|
|
59676
|
-
|
|
59677
|
-
if (normA === 0 || normB === 0) return 0;
|
|
59678
|
-
return dotProduct / (Math.sqrt(normA) * Math.sqrt(normB));
|
|
58695
|
+
interface chatContext {
|
|
58696
|
+
chats: Array<ChatItem>;
|
|
58697
|
+
textinput: string;
|
|
58698
|
+
addChat: (chat: ChatItem) => void;
|
|
58699
|
+
setTextinput: (textinput: string) => void;
|
|
59679
58700
|
}
|
|
59680
58701
|
|
|
59681
|
-
|
|
59682
|
-
|
|
59683
|
-
|
|
59684
|
-
|
|
59685
|
-
|
|
59686
|
-
|
|
59687
|
-
|
|
59688
|
-
|
|
59689
|
-
|
|
59690
|
-
|
|
59691
|
-
return results;
|
|
59692
|
-
}
|
|
59693
|
-
|
|
59694
|
-
// Get last update time
|
|
59695
|
-
export function getLastUpdated(): string | null {
|
|
59696
|
-
if (vectorStore.length === 0) return null;
|
|
59697
|
-
const latest = Math.max(...vectorStore.map(e => e.timestamp));
|
|
59698
|
-
return new Date(latest).toLocaleString();
|
|
59699
|
-
}
|
|
59700
|
-
`;
|
|
59701
|
-
|
|
59702
|
-
// ../../packages/template/demo/aichat/files/aiClientTs.ts
|
|
59703
|
-
var aiClientTs = `import fs from 'fs';
|
|
59704
|
-
import path from 'path';
|
|
59705
|
-
|
|
59706
|
-
const CONFIG_FILE = path.join(__dirname, '../config.json');
|
|
59707
|
-
|
|
59708
|
-
export interface AIConfig {
|
|
59709
|
-
apiKey: string;
|
|
59710
|
-
providerUrl: string;
|
|
59711
|
-
embeddingsUrl: string;
|
|
59712
|
-
model: string;
|
|
59713
|
-
embeddingsModel: string;
|
|
59714
|
-
}
|
|
59715
|
-
|
|
59716
|
-
// Default configuration
|
|
59717
|
-
const defaultConfig: AIConfig = {
|
|
59718
|
-
apiKey: '',
|
|
59719
|
-
providerUrl: 'https://api.openai.com/v1/chat/completions',
|
|
59720
|
-
embeddingsUrl: 'https://api.openai.com/v1/embeddings',
|
|
59721
|
-
model: 'gpt-3.5-turbo',
|
|
59722
|
-
embeddingsModel: 'text-embedding-3-small'
|
|
59723
|
-
};
|
|
59724
|
-
|
|
59725
|
-
let currentConfig: AIConfig = { ...defaultConfig };
|
|
59726
|
-
|
|
59727
|
-
// Load configuration from file
|
|
59728
|
-
export function loadConfig(): void {
|
|
59729
|
-
try {
|
|
59730
|
-
if (fs.existsSync(CONFIG_FILE)) {
|
|
59731
|
-
const data = fs.readFileSync(CONFIG_FILE, 'utf-8');
|
|
59732
|
-
currentConfig = { ...defaultConfig, ...JSON.parse(data) };
|
|
59733
|
-
console.log('\u{1F511} Loaded AI configuration');
|
|
59734
|
-
}
|
|
59735
|
-
} catch (error) {
|
|
59736
|
-
console.error('Failed to load config:', error);
|
|
59737
|
-
currentConfig = { ...defaultConfig };
|
|
59738
|
-
}
|
|
59739
|
-
}
|
|
59740
|
-
|
|
59741
|
-
// Save configuration to file
|
|
59742
|
-
export function saveConfig(config: AIConfig): void {
|
|
59743
|
-
currentConfig = { ...config };
|
|
59744
|
-
try {
|
|
59745
|
-
fs.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2));
|
|
59746
|
-
} catch (error) {
|
|
59747
|
-
console.error('Failed to save config:', error);
|
|
59748
|
-
}
|
|
59749
|
-
}
|
|
59750
|
-
|
|
59751
|
-
// Get current configuration
|
|
59752
|
-
export function getConfig(): AIConfig {
|
|
59753
|
-
return currentConfig;
|
|
59754
|
-
}
|
|
59755
|
-
|
|
59756
|
-
// Call embeddings API
|
|
59757
|
-
export async function callEmbeddingsAPI(text: string): Promise<number[]> {
|
|
59758
|
-
const config = getConfig();
|
|
59759
|
-
|
|
59760
|
-
if (!config.apiKey) {
|
|
59761
|
-
throw new Error('API key not configured');
|
|
59762
|
-
}
|
|
59763
|
-
|
|
59764
|
-
const response = await fetch(config.embeddingsUrl, {
|
|
59765
|
-
method: 'POST',
|
|
59766
|
-
headers: {
|
|
59767
|
-
'Content-Type': 'application/json',
|
|
59768
|
-
'Authorization': 'Bearer ' + config.apiKey
|
|
59769
|
-
},
|
|
59770
|
-
body: JSON.stringify({
|
|
59771
|
-
model: config.embeddingsModel,
|
|
59772
|
-
input: text
|
|
59773
|
-
})
|
|
59774
|
-
});
|
|
59775
|
-
|
|
59776
|
-
if (!response.ok) {
|
|
59777
|
-
const error = await response.text();
|
|
59778
|
-
throw new Error('Embeddings API error: ' + error);
|
|
59779
|
-
}
|
|
59780
|
-
|
|
59781
|
-
const data = await response.json();
|
|
59782
|
-
return data.data[0].embedding;
|
|
59783
|
-
}
|
|
59784
|
-
|
|
59785
|
-
// Call chat completions API
|
|
59786
|
-
export async function callChatAPI(systemPrompt: string, userMessage: string): Promise<string> {
|
|
59787
|
-
const config = getConfig();
|
|
59788
|
-
|
|
59789
|
-
if (!config.apiKey) {
|
|
59790
|
-
throw new Error('API key not configured');
|
|
59791
|
-
}
|
|
59792
|
-
|
|
59793
|
-
const response = await fetch(config.providerUrl, {
|
|
59794
|
-
method: 'POST',
|
|
59795
|
-
headers: {
|
|
59796
|
-
'Content-Type': 'application/json',
|
|
59797
|
-
'Authorization': 'Bearer ' + config.apiKey
|
|
59798
|
-
},
|
|
59799
|
-
body: JSON.stringify({
|
|
59800
|
-
model: config.model,
|
|
59801
|
-
messages: [
|
|
59802
|
-
{ role: 'system', content: systemPrompt },
|
|
59803
|
-
{ role: 'user', content: userMessage }
|
|
59804
|
-
],
|
|
59805
|
-
max_tokens: 500,
|
|
59806
|
-
temperature: 0.7
|
|
59807
|
-
})
|
|
59808
|
-
});
|
|
59809
|
-
|
|
59810
|
-
if (!response.ok) {
|
|
59811
|
-
const error = await response.text();
|
|
59812
|
-
throw new Error('Chat API error: ' + error);
|
|
59813
|
-
}
|
|
59814
|
-
|
|
59815
|
-
const data = await response.json();
|
|
59816
|
-
return data.choices[0].message.content;
|
|
59817
|
-
}
|
|
59818
|
-
`;
|
|
59819
|
-
|
|
59820
|
-
// ../../packages/template/demo/aichat/files/routesTs.ts
|
|
59821
|
-
var chatRouteTs = `import { Router, Request, Response } from 'express';
|
|
59822
|
-
import { searchSimilar } from '../vectorStore';
|
|
59823
|
-
import { getConfig, callEmbeddingsAPI, callChatAPI } from '../aiClient';
|
|
59824
|
-
|
|
59825
|
-
const router = Router();
|
|
59826
|
-
|
|
59827
|
-
router.post('/', async (req: Request, res: Response) => {
|
|
59828
|
-
try {
|
|
59829
|
-
const { message } = req.body;
|
|
59830
|
-
|
|
59831
|
-
if (!message) {
|
|
59832
|
-
return res.status(400).json({ error: 'Message is required' });
|
|
59833
|
-
}
|
|
59834
|
-
|
|
59835
|
-
const config = getConfig();
|
|
59836
|
-
if (!config.apiKey) {
|
|
59837
|
-
return res.json({
|
|
59838
|
-
reply: "I'm not configured yet. Please ask the admin to set up the AI provider in the admin panel."
|
|
59839
|
-
});
|
|
59840
|
-
}
|
|
59841
|
-
|
|
59842
|
-
// Get embedding for the user's message
|
|
59843
|
-
const queryEmbedding = await callEmbeddingsAPI(message);
|
|
59844
|
-
|
|
59845
|
-
// Search for similar content in our knowledge base
|
|
59846
|
-
const similarDocs = searchSimilar(queryEmbedding, 3);
|
|
59847
|
-
|
|
59848
|
-
// Build context from similar documents
|
|
59849
|
-
let context = '';
|
|
59850
|
-
if (similarDocs.length > 0 && similarDocs[0].score > 0.3) {
|
|
59851
|
-
context = 'Relevant information from our knowledge base:\\n' +
|
|
59852
|
-
similarDocs
|
|
59853
|
-
.filter(doc => doc.score > 0.3)
|
|
59854
|
-
.map(doc => doc.text)
|
|
59855
|
-
.join('\\n\\n');
|
|
59856
|
-
}
|
|
59857
|
-
|
|
59858
|
-
// Create the chat prompt
|
|
59859
|
-
const systemPrompt = "You are a helpful customer support assistant for FreshFruit, " +
|
|
59860
|
-
"a premium organic fruit delivery service. Be friendly, helpful, and concise. " +
|
|
59861
|
-
"If you have relevant information from the knowledge base, use it to answer. " +
|
|
59862
|
-
"If you don't know something, say so politely and suggest contacting human support.\\n\\n" +
|
|
59863
|
-
(context ? 'Knowledge Base Context:\\n' + context : 'No specific knowledge base context available for this query.');
|
|
59864
|
-
|
|
59865
|
-
// Call the chat API
|
|
59866
|
-
const reply = await callChatAPI(systemPrompt, message);
|
|
59867
|
-
|
|
59868
|
-
res.json({ reply });
|
|
59869
|
-
} catch (error) {
|
|
59870
|
-
console.error('Chat error:', error);
|
|
59871
|
-
res.status(500).json({ error: 'Failed to process message' });
|
|
59872
|
-
}
|
|
59873
|
-
});
|
|
59874
|
-
|
|
59875
|
-
export default router;
|
|
59876
|
-
`;
|
|
59877
|
-
var embedRouteTs = `import { Router, Request, Response } from 'express';
|
|
59878
|
-
import { addEmbedding, clearEmbeddings, getEmbeddingCount } from '../vectorStore';
|
|
59879
|
-
import { getConfig, callEmbeddingsAPI } from '../aiClient';
|
|
59880
|
-
|
|
59881
|
-
const router = Router();
|
|
59882
|
-
|
|
59883
|
-
// Embed new content
|
|
59884
|
-
router.post('/', async (req: Request, res: Response) => {
|
|
59885
|
-
try {
|
|
59886
|
-
const { content } = req.body;
|
|
59887
|
-
|
|
59888
|
-
if (!content) {
|
|
59889
|
-
return res.status(400).json({ error: 'Content is required' });
|
|
59890
|
-
}
|
|
59891
|
-
|
|
59892
|
-
const config = getConfig();
|
|
59893
|
-
if (!config.apiKey) {
|
|
59894
|
-
return res.status(400).json({ error: 'API key not configured. Please configure in admin panel.' });
|
|
59895
|
-
}
|
|
59896
|
-
|
|
59897
|
-
// Split content into chunks (by double newline or paragraph)
|
|
59898
|
-
const chunks = content
|
|
59899
|
-
.split(/\\n\\n+/)
|
|
59900
|
-
.map((chunk: string) => chunk.trim())
|
|
59901
|
-
.filter((chunk: string) => chunk.length > 10);
|
|
59902
|
-
|
|
59903
|
-
if (chunks.length === 0) {
|
|
59904
|
-
return res.status(400).json({ error: 'No valid content chunks found' });
|
|
59905
|
-
}
|
|
59906
|
-
|
|
59907
|
-
// Embed each chunk
|
|
59908
|
-
let embedded = 0;
|
|
59909
|
-
for (const chunk of chunks) {
|
|
59910
|
-
try {
|
|
59911
|
-
const embedding = await callEmbeddingsAPI(chunk);
|
|
59912
|
-
addEmbedding(chunk, embedding);
|
|
59913
|
-
embedded++;
|
|
59914
|
-
} catch (error) {
|
|
59915
|
-
console.error('Failed to embed chunk:', error);
|
|
59916
|
-
}
|
|
59917
|
-
}
|
|
59918
|
-
|
|
59919
|
-
res.json({
|
|
59920
|
-
message: 'Successfully embedded ' + embedded + ' chunks',
|
|
59921
|
-
count: getEmbeddingCount()
|
|
59922
|
-
});
|
|
59923
|
-
} catch (error) {
|
|
59924
|
-
console.error('Embed error:', error);
|
|
59925
|
-
res.status(500).json({ error: 'Failed to embed content' });
|
|
59926
|
-
}
|
|
59927
|
-
});
|
|
59928
|
-
|
|
59929
|
-
// Clear all embeddings
|
|
59930
|
-
router.delete('/', (req: Request, res: Response) => {
|
|
59931
|
-
clearEmbeddings();
|
|
59932
|
-
res.json({ message: 'All embeddings cleared', count: 0 });
|
|
59933
|
-
});
|
|
58702
|
+
const chatstate = create<chatContext>()((set) => ({
|
|
58703
|
+
chats: [],
|
|
58704
|
+
textinput: "",
|
|
58705
|
+
addChat: (chat: ChatItem) => set((state) => ({
|
|
58706
|
+
chats: [...state.chats, chat]
|
|
58707
|
+
})),
|
|
58708
|
+
setTextinput: (textinput: string) => set(() => ({
|
|
58709
|
+
textinput: textinput
|
|
58710
|
+
}))
|
|
59934
58711
|
|
|
59935
|
-
|
|
59936
|
-
`;
|
|
59937
|
-
var configRouteTs = `import { Router, Request, Response } from 'express';
|
|
59938
|
-
import { getConfig, saveConfig, AIConfig } from '../aiClient';
|
|
59939
|
-
import { getEmbeddingCount, getLastUpdated } from '../vectorStore';
|
|
59940
|
-
|
|
59941
|
-
const router = Router();
|
|
59942
|
-
|
|
59943
|
-
// Get current config
|
|
59944
|
-
router.get('/', (req: Request, res: Response) => {
|
|
59945
|
-
const config = getConfig();
|
|
59946
|
-
// Mask the API key for security
|
|
59947
|
-
const maskedConfig = {
|
|
59948
|
-
...config,
|
|
59949
|
-
apiKey: config.apiKey ? '\u2022\u2022\u2022\u2022\u2022\u2022' + config.apiKey.slice(-4) : ''
|
|
59950
|
-
};
|
|
59951
|
-
|
|
59952
|
-
res.json({
|
|
59953
|
-
config: maskedConfig,
|
|
59954
|
-
embeddingCount: getEmbeddingCount(),
|
|
59955
|
-
lastUpdated: getLastUpdated()
|
|
59956
|
-
});
|
|
59957
|
-
});
|
|
59958
|
-
|
|
59959
|
-
// Update config
|
|
59960
|
-
router.post('/', (req: Request, res: Response) => {
|
|
59961
|
-
try {
|
|
59962
|
-
const { apiKey, providerUrl, embeddingsUrl, model, embeddingsModel } = req.body;
|
|
59963
|
-
|
|
59964
|
-
const newConfig: AIConfig = {
|
|
59965
|
-
apiKey: apiKey || '',
|
|
59966
|
-
providerUrl: providerUrl || 'https://api.openai.com/v1/chat/completions',
|
|
59967
|
-
embeddingsUrl: embeddingsUrl || 'https://api.openai.com/v1/embeddings',
|
|
59968
|
-
model: model || 'gpt-3.5-turbo',
|
|
59969
|
-
embeddingsModel: embeddingsModel || 'text-embedding-3-small'
|
|
59970
|
-
};
|
|
59971
|
-
|
|
59972
|
-
saveConfig(newConfig);
|
|
59973
|
-
res.json({ message: 'Configuration saved' });
|
|
59974
|
-
} catch (error) {
|
|
59975
|
-
console.error('Config save error:', error);
|
|
59976
|
-
res.status(500).json({ error: 'Failed to save configuration' });
|
|
59977
|
-
}
|
|
59978
|
-
});
|
|
58712
|
+
}));
|
|
59979
58713
|
|
|
59980
|
-
|
|
59981
|
-
|
|
58714
|
+
const useChatState = createSelectors(chatstate);
|
|
58715
|
+
export default useChatState;
|
|
59982
58716
|
|
|
59983
|
-
|
|
59984
|
-
var AIChat = {
|
|
59985
|
-
name: "AI Chat",
|
|
59986
|
-
description: "Fullstack AI Customer Support Chat - Chat with your FAQ/Knowledge Base",
|
|
59987
|
-
notes: "Requires Node.js, NPM, and an OpenAI-compatible API key",
|
|
59988
|
-
templating: [
|
|
59989
|
-
// Install dependencies
|
|
59990
|
-
{
|
|
59991
|
-
action: "command",
|
|
59992
|
-
cmd: "npm",
|
|
59993
|
-
args: ["init", "-y"]
|
|
58717
|
+
`
|
|
59994
58718
|
},
|
|
59995
58719
|
{
|
|
59996
|
-
action: "
|
|
59997
|
-
|
|
59998
|
-
|
|
58720
|
+
action: "file",
|
|
58721
|
+
file: "src/app/zustandSelector.ts",
|
|
58722
|
+
filecontent: "//from: https://docs.pmnd.rs/zustand/guides/auto-generating-selectors\nimport type { StoreApi, UseBoundStore } from 'zustand'\n\ntype WithSelectors<S> = S extends { getState: () => infer T }\n ? S & { use: { [K in keyof T]: () => T[K] } }\n : never\n\nexport const createSelectors = <S extends UseBoundStore<StoreApi<object>>>(\n _store: S\n) => {\n let store = _store as WithSelectors<typeof _store>\n store.use = {}\n for (let k of Object.keys(store.getState())) {\n ;(store.use as any)[k] = () => store((s) => s[k as keyof typeof s])\n }\n\n return store\n}\n"
|
|
59999
58723
|
},
|
|
60000
58724
|
{
|
|
60001
|
-
action: "
|
|
60002
|
-
|
|
60003
|
-
|
|
58725
|
+
action: "file",
|
|
58726
|
+
file: "src/components/Background.tsx",
|
|
58727
|
+
filecontent: 'export default function Background() {\n return (\n <>\n <div className="absolute -top-[25%] -left-[10%] w-[80%] h-[80%] bg-blue-800/10 rounded-full blur-[128px]"></div>\n <div className="absolute bottom-[0%] right-[0%] w-[80%] h-[40%] bg-purple-800/10 rounded-full blur-[128px]"></div>\n </>\n )\n}'
|
|
60004
58728
|
},
|
|
60005
|
-
// Public files
|
|
60006
58729
|
{
|
|
60007
58730
|
action: "file",
|
|
60008
|
-
file: "
|
|
60009
|
-
filecontent:
|
|
58731
|
+
file: "src/components/ChatContainer.tsx",
|
|
58732
|
+
filecontent: `import useChatState from '../app/chat';
|
|
58733
|
+
import TextInput from './TextInput';
|
|
58734
|
+
import ChatContents from './ChatContents';
|
|
58735
|
+
|
|
58736
|
+
export default function ChatContainer() {
|
|
58737
|
+
const chats = useChatState.use.chats();
|
|
58738
|
+
|
|
58739
|
+
return (
|
|
58740
|
+
<div className="flex flex-col h-[calc(100vh-6rem)] w-full max-w-[900px] mx-auto relative font-sans">
|
|
58741
|
+
{chats.length > 0 ? (
|
|
58742
|
+
<>
|
|
58743
|
+
<ChatContents />
|
|
58744
|
+
<TextInput />
|
|
58745
|
+
</>
|
|
58746
|
+
) : (
|
|
58747
|
+
<div className="flex flex-col items-center justify-center h-full w-full p-4">
|
|
58748
|
+
<div className="flex gap-4 items-center justify-center">
|
|
58749
|
+
<div className="w-10 h-10 mb-8">
|
|
58750
|
+
<img src="/logo.svg" alt="MonoChat Logo" className="w-full h-full object-contain" />
|
|
58751
|
+
</div>
|
|
58752
|
+
<h2 className="text-xl font-bold text-white mb-8">How can I help you today?</h2>
|
|
58753
|
+
</div>
|
|
58754
|
+
<TextInput />
|
|
58755
|
+
</div>
|
|
58756
|
+
)}
|
|
58757
|
+
</div>
|
|
58758
|
+
);
|
|
58759
|
+
}
|
|
58760
|
+
|
|
58761
|
+
`
|
|
60010
58762
|
},
|
|
60011
58763
|
{
|
|
60012
58764
|
action: "file",
|
|
60013
|
-
file: "
|
|
60014
|
-
filecontent:
|
|
58765
|
+
file: "src/components/ChatContents.tsx",
|
|
58766
|
+
filecontent: "import { useEffect, useRef } from \"react\";\nimport useChatState from \"../app/chat\";\n\nexport default function ChatContents() {\n const chats = useChatState.use.chats();\n const messagesEndRef = useRef<HTMLDivElement>(null);\n\n const scrollToBottom = () => {\n messagesEndRef.current?.scrollIntoView({ behavior: \"smooth\" });\n };\n\n useEffect(() => {\n scrollToBottom();\n }, [chats]);\n\n return (\n <div className=\"flex-1 overflow-y-auto w-full px-4 scrollbar-hide\">\n {chats.map((chat) => (\n <div\n key={chat.id}\n className={`group flex w-full ${chat.who === 'user' ? 'justify-end' : 'justify-start'}`}\n >\n <div className={`flex max-w-[85%] md:max-w-[80%] gap-4 ${chat.who === 'user' ? 'flex-row-reverse' : 'flex-row'}`}>\n <div className={`flex flex-col ${chat.who === 'user' ? 'items-end' : 'items-start'}`}>\n <div className={`flex items-center gap-2 mb-1.5 opacity-90 ${chat.who === 'user' ? 'flex-row-reverse' : 'flex-row'}`}>\n <span className=\"text-[10px] text-zinc-500\">\n {new Date(chat.timestamp).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })}\n </span>\n </div>\n <div\n className={`relative px-5 py-3 rounded-2xl text-md leading-relaxed transition-transform duration-200 ${chat.who === 'user'\n ? 'bg-zinc-800/80 text-white rounded-tr-sm border border-zinc-700/50 shadow-lg backdrop-blur-sm'\n : ' text-zinc-100'\n }`}\n >\n {chat.message}\n </div>\n </div>\n </div>\n </div>\n ))}\n <div ref={messagesEndRef} className=\"h-4\" />\n </div>\n )\n}"
|
|
60015
58767
|
},
|
|
60016
58768
|
{
|
|
60017
58769
|
action: "file",
|
|
60018
|
-
file: "
|
|
60019
|
-
filecontent:
|
|
58770
|
+
file: "src/components/Header.tsx",
|
|
58771
|
+
filecontent: '\nexport default function Header() {\n return (\n <div className="w-full h-12">\n <div className="container px-4 max-w-7xl mx-auto h-full flex items-center gap-3">\n <img src="/logo.svg" alt="MonoChat Logo" className="w-8 h-8" />\n <h1 className="font-bold text-lg tracking-wide text-white">\n MonoChat\n </h1>\n </div>\n </div>\n )\n}'
|
|
60020
58772
|
},
|
|
60021
|
-
// Source files
|
|
60022
58773
|
{
|
|
60023
58774
|
action: "file",
|
|
60024
|
-
file: "src/
|
|
60025
|
-
filecontent:
|
|
58775
|
+
file: "src/components/SendIcon.tsx",
|
|
58776
|
+
filecontent: '\nexport default function SendIcon({ className }: { className?: string }) {\n return (\n <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" className={className}>\n <path d="M3.478 2.404a.75.75 0 0 0-.926.941l2.432 7.905H13.5a.75.75 0 0 1 0 1.5H4.984l-2.432 7.905a.75.75 0 0 0 .926.94 60.519 60.519 0 0 0 18.445-8.986.75.75 0 0 0 0-1.218A60.517 60.517 0 0 0 3.478 2.404Z" />\n </svg>\n )\n}'
|
|
60026
58777
|
},
|
|
60027
58778
|
{
|
|
60028
58779
|
action: "file",
|
|
60029
|
-
file: "src/
|
|
60030
|
-
filecontent:
|
|
58780
|
+
file: "src/components/TextInput.tsx",
|
|
58781
|
+
filecontent: `import FetchToWho from "../_FetchToWho";
|
|
58782
|
+
import useChatState from "../app/chat";
|
|
58783
|
+
import SendIcon from "./SendIcon";
|
|
58784
|
+
|
|
58785
|
+
export default function TextInput() {
|
|
58786
|
+
const chats = useChatState.use.chats();
|
|
58787
|
+
const textinput = useChatState.use.textinput();
|
|
58788
|
+
const setTextinput = useChatState.use.setTextinput();
|
|
58789
|
+
const addChat = useChatState.use.addChat();
|
|
58790
|
+
|
|
58791
|
+
const handleSend = async () => {
|
|
58792
|
+
if (!textinput.trim()) return;
|
|
58793
|
+
addChat({
|
|
58794
|
+
id: Date.now(),
|
|
58795
|
+
who: "user",
|
|
58796
|
+
timestamp: Date.now(),
|
|
58797
|
+
message: textinput
|
|
58798
|
+
});
|
|
58799
|
+
setTextinput("");
|
|
58800
|
+
|
|
58801
|
+
const userChat = chats.filter((chat) => chat.who === "user");
|
|
58802
|
+
const response = await FetchToWho(userChat);
|
|
58803
|
+
addChat({
|
|
58804
|
+
id: Date.now(),
|
|
58805
|
+
who: "system",
|
|
58806
|
+
timestamp: Date.now(),
|
|
58807
|
+
message: response
|
|
58808
|
+
});
|
|
58809
|
+
};
|
|
58810
|
+
|
|
58811
|
+
const handleKeyDown = (e: React.KeyboardEvent) => {
|
|
58812
|
+
if (e.key === 'Enter' && !e.shiftKey) {
|
|
58813
|
+
e.preventDefault();
|
|
58814
|
+
handleSend();
|
|
58815
|
+
}
|
|
58816
|
+
};
|
|
58817
|
+
|
|
58818
|
+
return (
|
|
58819
|
+
<div className="p-4 w-full">
|
|
58820
|
+
<div className="w-full max-w-3xl mx-auto">
|
|
58821
|
+
<div className="relative flex items-end gap-2 bg-zinc-900/80 hover:bg-zinc-900/90 focus-within:bg-black/90 transition-all duration-300 border border-white/10 rounded-[24px] p-2 pr-2 shadow-xl backdrop-blur-xl ring-1 ring-white/5 focus-within:ring-indigo-500/30">
|
|
58822
|
+
<textarea
|
|
58823
|
+
value={textinput}
|
|
58824
|
+
onChange={(e) => setTextinput(e.target.value)}
|
|
58825
|
+
onKeyDown={handleKeyDown}
|
|
58826
|
+
placeholder="Message MonoChat..."
|
|
58827
|
+
className="w-full pl-4 py-3 bg-transparent active:bg-transparent border-none outline-none focus:outline-none text-zinc-100 placeholder:text-zinc-500 focus:ring-0 resize-none max-h-48 min-h-[44px] scrollbar-hide text-md leading-6"
|
|
58828
|
+
rows={1}
|
|
58829
|
+
style={{ height: 'auto', minHeight: '44px' }}
|
|
58830
|
+
onInput={(e) => {
|
|
58831
|
+
const target = e.target as HTMLTextAreaElement;
|
|
58832
|
+
target.style.height = 'auto';
|
|
58833
|
+
target.style.height = \`\${Math.min(target.scrollHeight, 192)}px\`;
|
|
58834
|
+
}}
|
|
58835
|
+
/>
|
|
58836
|
+
<button
|
|
58837
|
+
onClick={handleSend}
|
|
58838
|
+
disabled={!textinput.trim()}
|
|
58839
|
+
className={\`p-2 rounded-full mb-1 transition-all duration-200 flex-shrink-0 \${textinput.trim()
|
|
58840
|
+
? 'bg-indigo-600 text-white shadow-lg shadow-indigo-500/20 hover:bg-indigo-500'
|
|
58841
|
+
: 'bg-zinc-800 text-zinc-600 cursor-not-allowed'
|
|
58842
|
+
}\`}
|
|
58843
|
+
>
|
|
58844
|
+
<SendIcon className="w-5 h-5" />
|
|
58845
|
+
</button>
|
|
58846
|
+
</div>
|
|
58847
|
+
</div>
|
|
58848
|
+
</div>
|
|
58849
|
+
)
|
|
58850
|
+
}
|
|
58851
|
+
`
|
|
60031
58852
|
},
|
|
60032
58853
|
{
|
|
60033
58854
|
action: "file",
|
|
60034
|
-
file: "src/
|
|
60035
|
-
filecontent:
|
|
58855
|
+
file: "src/index.css",
|
|
58856
|
+
filecontent: '@import "tailwindcss";'
|
|
60036
58857
|
},
|
|
60037
58858
|
{
|
|
60038
58859
|
action: "file",
|
|
60039
|
-
file: "src/
|
|
60040
|
-
filecontent:
|
|
58860
|
+
file: "src/main.tsx",
|
|
58861
|
+
filecontent: "import React from 'react'\nimport ReactDOM from 'react-dom/client'\nimport App from './App'\nimport './index.css'\n\nReactDOM.createRoot(document.getElementById('root')!).render(\n <React.StrictMode>\n <App />\n </React.StrictMode>,\n)"
|
|
60041
58862
|
},
|
|
60042
58863
|
{
|
|
60043
58864
|
action: "file",
|
|
60044
|
-
file: "
|
|
60045
|
-
filecontent:
|
|
58865
|
+
file: "tailwind.config.js",
|
|
58866
|
+
filecontent: `/** @type {import('tailwindcss').Config} */
|
|
58867
|
+
export default {
|
|
58868
|
+
content: [
|
|
58869
|
+
"./index.html",
|
|
58870
|
+
"./src/**/*.{js,ts,jsx,tsx}",
|
|
58871
|
+
],
|
|
58872
|
+
theme: {
|
|
58873
|
+
extend: {},
|
|
58874
|
+
},
|
|
58875
|
+
plugins: [],
|
|
58876
|
+
};`
|
|
60046
58877
|
},
|
|
60047
58878
|
{
|
|
60048
58879
|
action: "file",
|
|
60049
|
-
file: "
|
|
60050
|
-
filecontent:
|
|
58880
|
+
file: "tsconfig.app.json",
|
|
58881
|
+
filecontent: '{\n "compilerOptions": {\n "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",\n "target": "ES2022",\n "useDefineForClassFields": true,\n "lib": ["ES2022", "DOM", "DOM.Iterable"],\n "module": "ESNext",\n "types": ["vite/client"],\n "skipLibCheck": true,\n\n /* Bundler mode */\n "moduleResolution": "bundler",\n "allowImportingTsExtensions": true,\n "verbatimModuleSyntax": true,\n "moduleDetection": "force",\n "noEmit": true,\n "jsx": "react-jsx",\n\n /* Linting */\n "strict": true,\n "noUnusedLocals": true,\n "noUnusedParameters": true,\n "erasableSyntaxOnly": true,\n "noFallthroughCasesInSwitch": true,\n "noUncheckedSideEffectImports": true\n },\n "include": ["src"]\n}\n'
|
|
60051
58882
|
},
|
|
60052
|
-
// Config files
|
|
60053
58883
|
{
|
|
60054
58884
|
action: "file",
|
|
60055
58885
|
file: "tsconfig.json",
|
|
60056
|
-
filecontent:
|
|
58886
|
+
filecontent: '{\n "files": [],\n "references": [\n { "path": "./tsconfig.app.json" },\n { "path": "./tsconfig.node.json" }\n ]\n}\n'
|
|
60057
58887
|
},
|
|
60058
58888
|
{
|
|
60059
58889
|
action: "file",
|
|
60060
|
-
file: "
|
|
60061
|
-
filecontent:
|
|
58890
|
+
file: "tsconfig.node.json",
|
|
58891
|
+
filecontent: '{\n "compilerOptions": {\n "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",\n "target": "ES2023",\n "lib": ["ES2023"],\n "module": "ESNext",\n "types": ["node"],\n "skipLibCheck": true,\n\n /* Bundler mode */\n "moduleResolution": "bundler",\n "allowImportingTsExtensions": true,\n "verbatimModuleSyntax": true,\n "moduleDetection": "force",\n "noEmit": true,\n\n /* Linting */\n "strict": true,\n "noUnusedLocals": true,\n "noUnusedParameters": true,\n "erasableSyntaxOnly": true,\n "noFallthroughCasesInSwitch": true,\n "noUncheckedSideEffectImports": true\n },\n "include": ["vite.config.ts"]\n}\n'
|
|
60062
58892
|
},
|
|
60063
|
-
// NPM scripts
|
|
60064
58893
|
{
|
|
60065
|
-
action: "
|
|
60066
|
-
|
|
60067
|
-
|
|
60068
|
-
},
|
|
60069
|
-
{
|
|
60070
|
-
action: "command",
|
|
60071
|
-
cmd: "npm",
|
|
60072
|
-
args: ["pkg", "set", "scripts.build=tsup"]
|
|
60073
|
-
},
|
|
60074
|
-
{
|
|
60075
|
-
action: "command",
|
|
60076
|
-
cmd: "npm",
|
|
60077
|
-
args: ["pkg", "set", "scripts.start=node dist/index.js"]
|
|
58894
|
+
action: "file",
|
|
58895
|
+
file: "vercel.json",
|
|
58896
|
+
filecontent: '{\n "rewrites": [\n {\n "source": "/(.*)",\n "destination": "/index.html"\n }\n ]\n}'
|
|
60078
58897
|
},
|
|
60079
58898
|
{
|
|
60080
|
-
action: "
|
|
60081
|
-
|
|
60082
|
-
|
|
58899
|
+
action: "file",
|
|
58900
|
+
file: "vite.config.ts",
|
|
58901
|
+
filecontent: "import { defineConfig } from 'vite'\nimport react from '@vitejs/plugin-react'\n\n// https://vite.dev/config/\nexport default defineConfig({\n plugins: [react()],\n})\n"
|
|
60083
58902
|
},
|
|
60084
58903
|
{
|
|
60085
58904
|
action: "command",
|
|
60086
58905
|
cmd: "npm",
|
|
60087
|
-
args: ["
|
|
58906
|
+
args: ["install"]
|
|
60088
58907
|
},
|
|
60089
58908
|
{
|
|
60090
58909
|
action: "command",
|
|
@@ -60093,16 +58912,16 @@ var AIChat = {
|
|
|
60093
58912
|
}
|
|
60094
58913
|
]
|
|
60095
58914
|
};
|
|
58915
|
+
var monochat_default = MonoChat;
|
|
60096
58916
|
|
|
60097
58917
|
// ../../packages/template/demo.ts
|
|
60098
58918
|
var templates2 = [
|
|
60099
|
-
|
|
58919
|
+
monochat_default
|
|
60100
58920
|
];
|
|
60101
58921
|
var demo_default = templates2;
|
|
60102
58922
|
|
|
60103
|
-
// ../../packages/template/projects/_viteapp.ts
|
|
60104
|
-
var file = `
|
|
60105
|
-
|
|
58923
|
+
// ../../packages/template/projects/files/_viteapp.ts
|
|
58924
|
+
var file = `
|
|
60106
58925
|
function App() {
|
|
60107
58926
|
return (
|
|
60108
58927
|
<div className="min-h-screen bg-slate-950 text-white font-sans selection:bg-indigo-500 selection:text-white">
|
|
@@ -60227,7 +59046,7 @@ var ViteReact = {
|
|
|
60227
59046
|
{
|
|
60228
59047
|
action: "command",
|
|
60229
59048
|
cmd: "npm",
|
|
60230
|
-
args: ["install", "-D", "tailwindcss", "@tailwindcss/postcss", "autoprefixer"]
|
|
59049
|
+
args: ["install", "-D", "tailwindcss", "@tailwindcss/postcss", "postcss", "autoprefixer"]
|
|
60231
59050
|
},
|
|
60232
59051
|
{
|
|
60233
59052
|
action: "file",
|
|
@@ -60235,19 +59054,9 @@ var ViteReact = {
|
|
|
60235
59054
|
filecontent: 'export default {\n plugins: {\n "@tailwindcss/postcss": {},\n autoprefixer: {},\n },\n}'
|
|
60236
59055
|
},
|
|
60237
59056
|
{
|
|
60238
|
-
action: "
|
|
60239
|
-
|
|
60240
|
-
|
|
60241
|
-
export default {
|
|
60242
|
-
content: [
|
|
60243
|
-
"./index.html",
|
|
60244
|
-
"./src/**/*.{js,ts,jsx,tsx}",
|
|
60245
|
-
],
|
|
60246
|
-
theme: {
|
|
60247
|
-
extend: {},
|
|
60248
|
-
},
|
|
60249
|
-
plugins: [],
|
|
60250
|
-
};`
|
|
59057
|
+
action: "command",
|
|
59058
|
+
cmd: "rm",
|
|
59059
|
+
args: ["src/App.css"]
|
|
60251
59060
|
},
|
|
60252
59061
|
{
|
|
60253
59062
|
action: "file",
|
|
@@ -60268,16 +59077,23 @@ ReactDOM.createRoot(document.getElementById('root')!).render(
|
|
|
60268
59077
|
</React.StrictMode>,
|
|
60269
59078
|
)`
|
|
60270
59079
|
},
|
|
60271
|
-
{
|
|
60272
|
-
action: "command",
|
|
60273
|
-
cmd: "rm",
|
|
60274
|
-
args: ["src/App.css"]
|
|
60275
|
-
},
|
|
60276
59080
|
{
|
|
60277
59081
|
action: "file",
|
|
60278
59082
|
file: "src/App.tsx",
|
|
60279
59083
|
filecontent: viteapp_default
|
|
60280
59084
|
},
|
|
59085
|
+
{
|
|
59086
|
+
action: "file",
|
|
59087
|
+
file: "vercel.json",
|
|
59088
|
+
filecontent: `{
|
|
59089
|
+
"rewrites": [
|
|
59090
|
+
{
|
|
59091
|
+
"source": "/(.*)",
|
|
59092
|
+
"destination": "/index.html"
|
|
59093
|
+
}
|
|
59094
|
+
]
|
|
59095
|
+
}`
|
|
59096
|
+
},
|
|
60281
59097
|
{
|
|
60282
59098
|
action: "command",
|
|
60283
59099
|
cmd: "npm",
|
|
@@ -60288,15 +59104,42 @@ ReactDOM.createRoot(document.getElementById('root')!).render(
|
|
|
60288
59104
|
cmd: "npm",
|
|
60289
59105
|
args: ["pkg", "set", "scripts.stop=npx -y kill-port 5173"]
|
|
60290
59106
|
},
|
|
59107
|
+
{
|
|
59108
|
+
action: "file",
|
|
59109
|
+
file: "netlify.toml",
|
|
59110
|
+
filecontent: `[build]
|
|
59111
|
+
command = "npm run build"
|
|
59112
|
+
publish = "dist"
|
|
59113
|
+
|
|
59114
|
+
[[redirects]]
|
|
59115
|
+
from = "/*"
|
|
59116
|
+
to = "/index.html"
|
|
59117
|
+
status = 200`
|
|
59118
|
+
},
|
|
59119
|
+
{
|
|
59120
|
+
action: "file",
|
|
59121
|
+
file: "render.yaml",
|
|
59122
|
+
filecontent: `services:
|
|
59123
|
+
- type: web
|
|
59124
|
+
name: vite-react-app
|
|
59125
|
+
env: static
|
|
59126
|
+
buildCommand: npm install && npm run build
|
|
59127
|
+
staticPublishPath: ./dist`
|
|
59128
|
+
},
|
|
59129
|
+
{
|
|
59130
|
+
action: "command",
|
|
59131
|
+
cmd: "npm",
|
|
59132
|
+
args: ["pkg", "set", "description=Vite React TS"]
|
|
59133
|
+
},
|
|
60291
59134
|
{
|
|
60292
59135
|
action: "command",
|
|
60293
59136
|
cmd: "npm",
|
|
60294
|
-
args: ["pkg", "set", "fontawesomeIcon=fab fa-react text-blue-
|
|
59137
|
+
args: ["pkg", "set", "fontawesomeIcon=fab fa-react text-blue-500"]
|
|
60295
59138
|
}
|
|
60296
59139
|
]
|
|
60297
59140
|
};
|
|
60298
59141
|
|
|
60299
|
-
// ../../packages/template/projects/_nextapp.ts
|
|
59142
|
+
// ../../packages/template/projects/files/_nextapp.ts
|
|
60300
59143
|
var app = `export default function Home() {
|
|
60301
59144
|
return (
|
|
60302
59145
|
<div className="min-h-screen bg-slate-950 text-white font-sans selection:bg-indigo-500 selection:text-white">
|
|
@@ -60494,11 +59337,44 @@ export default function RootLayout({
|
|
|
60494
59337
|
file: "app/page.tsx",
|
|
60495
59338
|
filecontent: nextapp_default
|
|
60496
59339
|
},
|
|
59340
|
+
{
|
|
59341
|
+
action: "file",
|
|
59342
|
+
file: "vercel.json",
|
|
59343
|
+
filecontent: '{\n "framework": "nextjs"\n}'
|
|
59344
|
+
},
|
|
60497
59345
|
{
|
|
60498
59346
|
action: "command",
|
|
60499
59347
|
cmd: "npm",
|
|
60500
59348
|
args: ["pkg", "set", "name=$(basename $PWD)"]
|
|
60501
59349
|
},
|
|
59350
|
+
{
|
|
59351
|
+
action: "file",
|
|
59352
|
+
file: "netlify.toml",
|
|
59353
|
+
filecontent: `[build]
|
|
59354
|
+
command = "npm run build"
|
|
59355
|
+
publish = ".next"`
|
|
59356
|
+
},
|
|
59357
|
+
{
|
|
59358
|
+
action: "file",
|
|
59359
|
+
file: "render.yaml",
|
|
59360
|
+
filecontent: `services:
|
|
59361
|
+
- type: web
|
|
59362
|
+
name: nextjs-app
|
|
59363
|
+
env: node
|
|
59364
|
+
plan: free
|
|
59365
|
+
buildCommand: npm install && npm run build
|
|
59366
|
+
startCommand: npm start`
|
|
59367
|
+
},
|
|
59368
|
+
{
|
|
59369
|
+
action: "file",
|
|
59370
|
+
file: "Procfile",
|
|
59371
|
+
filecontent: "web: npm start"
|
|
59372
|
+
},
|
|
59373
|
+
{
|
|
59374
|
+
action: "command",
|
|
59375
|
+
cmd: "npm",
|
|
59376
|
+
args: ["pkg", "set", "description=Next.js TS"]
|
|
59377
|
+
},
|
|
60502
59378
|
{
|
|
60503
59379
|
action: "command",
|
|
60504
59380
|
cmd: "npm",
|
|
@@ -60507,14 +59383,16 @@ export default function RootLayout({
|
|
|
60507
59383
|
]
|
|
60508
59384
|
};
|
|
60509
59385
|
|
|
60510
|
-
// ../../packages/template/projects/
|
|
59386
|
+
// ../../packages/template/projects/files/_express.ts
|
|
60511
59387
|
var expressFile = `import express, { Request, Response } from "express";
|
|
60512
59388
|
import path from "path";
|
|
59389
|
+
import cors from "cors";
|
|
60513
59390
|
import helloRouter from "./routes/hello";
|
|
60514
59391
|
|
|
60515
59392
|
const app = express();
|
|
60516
|
-
const port = 3500;
|
|
59393
|
+
const port = process.env.PORT || 3500;
|
|
60517
59394
|
|
|
59395
|
+
app.use(cors());
|
|
60518
59396
|
app.use(express.static(path.join(__dirname, "../public")));
|
|
60519
59397
|
app.use(express.json());
|
|
60520
59398
|
|
|
@@ -60604,11 +59482,21 @@ var htmlFile = `<!DOCTYPE html>
|
|
|
60604
59482
|
<div class="container">
|
|
60605
59483
|
<h1>Express Service</h1>
|
|
60606
59484
|
<p>Your backend service is up and running successfully. Ready to handle API requests.</p>
|
|
59485
|
+
<p style="margin-top: 1rem; padding: 1rem; background: rgba(255, 193, 7, 0.1); border: 1px solid rgba(255, 193, 7, 0.3); border-radius: 8px; color: #ffc107; font-size: 0.9rem;">
|
|
59486
|
+
<strong>Caution:</strong> Any origin is allowed. Update the CORS configuration in <code>src/index.ts</code> and headers in <code>vercel.json</code> to whitelist only your frontend origin to prevent unauthorized usage.
|
|
59487
|
+
</p>
|
|
60607
59488
|
<div class="status-badge">\u25CF System Online</div>
|
|
60608
59489
|
</div>
|
|
60609
59490
|
</body>
|
|
60610
59491
|
</html>
|
|
60611
59492
|
`;
|
|
59493
|
+
var express_default = {
|
|
59494
|
+
expressFile,
|
|
59495
|
+
helloRouterFile,
|
|
59496
|
+
htmlFile
|
|
59497
|
+
};
|
|
59498
|
+
|
|
59499
|
+
// ../../packages/template/projects/express.ts
|
|
60612
59500
|
var ExpressTS = {
|
|
60613
59501
|
name: "Express.js TS",
|
|
60614
59502
|
description: "Express.js TS template",
|
|
@@ -60619,15 +59507,20 @@ var ExpressTS = {
|
|
|
60619
59507
|
cmd: "npm",
|
|
60620
59508
|
args: ["init", "-y"]
|
|
60621
59509
|
},
|
|
59510
|
+
{
|
|
59511
|
+
action: "command",
|
|
59512
|
+
cmd: "node",
|
|
59513
|
+
args: ["-e", "const fs=require('fs');const p=JSON.parse(fs.readFileSync('package.json'));if(p.name==='express'){p.name='express-app';fs.writeFileSync('package.json',JSON.stringify(p,null,2))}"]
|
|
59514
|
+
},
|
|
60622
59515
|
{
|
|
60623
59516
|
action: "command",
|
|
60624
59517
|
cmd: "npm",
|
|
60625
|
-
args: ["install", "express"]
|
|
59518
|
+
args: ["install", "express", "cors"]
|
|
60626
59519
|
},
|
|
60627
59520
|
{
|
|
60628
59521
|
action: "command",
|
|
60629
59522
|
cmd: "npm",
|
|
60630
|
-
args: ["install", "-D", "nodemon", "typescript", "ts-node", "@types/node", "@types/express"]
|
|
59523
|
+
args: ["install", "-D", "nodemon", "typescript", "ts-node", "@types/node", "@types/express", "@types/cors"]
|
|
60631
59524
|
},
|
|
60632
59525
|
{
|
|
60633
59526
|
action: "command",
|
|
@@ -60637,17 +59530,17 @@ var ExpressTS = {
|
|
|
60637
59530
|
{
|
|
60638
59531
|
action: "file",
|
|
60639
59532
|
file: "public/index.html",
|
|
60640
|
-
filecontent: htmlFile
|
|
59533
|
+
filecontent: express_default.htmlFile
|
|
60641
59534
|
},
|
|
60642
59535
|
{
|
|
60643
59536
|
action: "file",
|
|
60644
59537
|
file: "src/routes/hello.ts",
|
|
60645
|
-
filecontent: helloRouterFile
|
|
59538
|
+
filecontent: express_default.helloRouterFile
|
|
60646
59539
|
},
|
|
60647
59540
|
{
|
|
60648
59541
|
action: "file",
|
|
60649
59542
|
file: "src/index.ts",
|
|
60650
|
-
filecontent: expressFile
|
|
59543
|
+
filecontent: express_default.expressFile
|
|
60651
59544
|
},
|
|
60652
59545
|
{
|
|
60653
59546
|
action: "file",
|
|
@@ -60679,6 +59572,54 @@ var ExpressTS = {
|
|
|
60679
59572
|
cmd: "npm",
|
|
60680
59573
|
args: ["pkg", "set", "scripts.stop=npx -y kill-port 3500"]
|
|
60681
59574
|
},
|
|
59575
|
+
{
|
|
59576
|
+
action: "file",
|
|
59577
|
+
file: "vercel.json",
|
|
59578
|
+
filecontent: `{
|
|
59579
|
+
"version": 2,
|
|
59580
|
+
"rewrites": [
|
|
59581
|
+
{
|
|
59582
|
+
"source": "/(.*)",
|
|
59583
|
+
"destination": "/dist/index.js"
|
|
59584
|
+
}
|
|
59585
|
+
],
|
|
59586
|
+
"headers": [
|
|
59587
|
+
{
|
|
59588
|
+
"source": "/(.*)",
|
|
59589
|
+
"headers": [
|
|
59590
|
+
{ "key": "Access-Control-Allow-Credentials", "value": "true" },
|
|
59591
|
+
{ "key": "Access-Control-Allow-Origin", "value": "*" },
|
|
59592
|
+
{ "key": "Access-Control-Allow-Methods", "value": "GET,OPTIONS,PATCH,DELETE,POST,PUT" },
|
|
59593
|
+
{ "key": "Access-Control-Allow-Headers", "value": "X-CSRF-Token, X-Requested-With, Accept, Accept-Version, Content-Length, Content-MD5, Content-Type, Date, X-Api-Version" }
|
|
59594
|
+
]
|
|
59595
|
+
}
|
|
59596
|
+
]
|
|
59597
|
+
}`
|
|
59598
|
+
},
|
|
59599
|
+
{
|
|
59600
|
+
action: "file",
|
|
59601
|
+
file: "render.yaml",
|
|
59602
|
+
filecontent: `services:
|
|
59603
|
+
- type: web
|
|
59604
|
+
name: express-service
|
|
59605
|
+
env: node
|
|
59606
|
+
plan: free
|
|
59607
|
+
buildCommand: npm install && npm run build
|
|
59608
|
+
startCommand: npm start
|
|
59609
|
+
envVars:
|
|
59610
|
+
- key: PORT
|
|
59611
|
+
value: 10000`
|
|
59612
|
+
},
|
|
59613
|
+
{
|
|
59614
|
+
action: "file",
|
|
59615
|
+
file: "Procfile",
|
|
59616
|
+
filecontent: "web: npm start"
|
|
59617
|
+
},
|
|
59618
|
+
{
|
|
59619
|
+
action: "command",
|
|
59620
|
+
cmd: "npm",
|
|
59621
|
+
args: ["pkg", "set", "description=Express.js TS"]
|
|
59622
|
+
},
|
|
60682
59623
|
{
|
|
60683
59624
|
action: "command",
|
|
60684
59625
|
cmd: "npm",
|
|
@@ -60687,6 +59628,434 @@ var ExpressTS = {
|
|
|
60687
59628
|
]
|
|
60688
59629
|
};
|
|
60689
59630
|
|
|
59631
|
+
// ../../packages/template/projects/files/_serverless.ts
|
|
59632
|
+
var htmlFile2 = `<!DOCTYPE html>
|
|
59633
|
+
<html lang="en">
|
|
59634
|
+
<head>
|
|
59635
|
+
<meta charset="UTF-8">
|
|
59636
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
59637
|
+
<title>Monorepo Time - Universal Express Service</title>
|
|
59638
|
+
<style>
|
|
59639
|
+
body {
|
|
59640
|
+
background: linear-gradient(135deg, #2d2a4e 0%, #1c1c38 100%);
|
|
59641
|
+
color: #ffffff;
|
|
59642
|
+
display: flex;
|
|
59643
|
+
justify-content: center;
|
|
59644
|
+
align-items: center;
|
|
59645
|
+
height: 100vh;
|
|
59646
|
+
margin: 0;
|
|
59647
|
+
font-family: 'Inter', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
|
|
59648
|
+
overflow: hidden;
|
|
59649
|
+
}
|
|
59650
|
+
.container {
|
|
59651
|
+
text-align: center;
|
|
59652
|
+
padding: 3rem;
|
|
59653
|
+
background: rgba(255, 255, 255, 0.08);
|
|
59654
|
+
border: 1px solid rgba(255, 255, 255, 0.15);
|
|
59655
|
+
border-radius: 20px;
|
|
59656
|
+
backdrop-filter: blur(12px);
|
|
59657
|
+
box-shadow: 0 20px 50px rgba(0, 0, 0, 0.5);
|
|
59658
|
+
max-width: 550px;
|
|
59659
|
+
width: 100%;
|
|
59660
|
+
animation: fadeIn 0.8s ease-out;
|
|
59661
|
+
}
|
|
59662
|
+
h1 {
|
|
59663
|
+
font-size: 2.5rem;
|
|
59664
|
+
margin-bottom: 0.5rem;
|
|
59665
|
+
background: linear-gradient(to right, #ff9966 0%, #ff5e62 100%);
|
|
59666
|
+
-webkit-background-clip: text;
|
|
59667
|
+
-webkit-text-fill-color: transparent;
|
|
59668
|
+
font-weight: 800;
|
|
59669
|
+
}
|
|
59670
|
+
p {
|
|
59671
|
+
font-size: 1.1rem;
|
|
59672
|
+
color: #c9d6ea;
|
|
59673
|
+
line-height: 1.6;
|
|
59674
|
+
}
|
|
59675
|
+
.status-badge {
|
|
59676
|
+
display: inline-block;
|
|
59677
|
+
margin-top: 1.5rem;
|
|
59678
|
+
padding: 0.5rem 1rem;
|
|
59679
|
+
background: rgba(255, 153, 102, 0.15);
|
|
59680
|
+
color: #ff9966;
|
|
59681
|
+
border-radius: 50px;
|
|
59682
|
+
font-weight: 600;
|
|
59683
|
+
border: 1px solid rgba(255, 153, 102, 0.25);
|
|
59684
|
+
text-transform: uppercase;
|
|
59685
|
+
font-size: 0.8rem;
|
|
59686
|
+
letter-spacing: 1px;
|
|
59687
|
+
}
|
|
59688
|
+
code {
|
|
59689
|
+
background: rgba(255, 255, 255, 0.1);
|
|
59690
|
+
padding: 2px 4px;
|
|
59691
|
+
border-radius: 4px;
|
|
59692
|
+
font-size: 0.9em;
|
|
59693
|
+
}
|
|
59694
|
+
@keyframes fadeIn {
|
|
59695
|
+
from { opacity: 0; transform: translateY(20px); }
|
|
59696
|
+
to { opacity: 1; transform: translateY(0); }
|
|
59697
|
+
}
|
|
59698
|
+
</style>
|
|
59699
|
+
</head>
|
|
59700
|
+
<body>
|
|
59701
|
+
<div class="container">
|
|
59702
|
+
<h1>Universal Express</h1>
|
|
59703
|
+
<p>Your serverless-ready service is active. Deploy to AWS, Vercel, Netlify, or Docker with zero config changes.</p>
|
|
59704
|
+
<div style="margin-top: 2rem; display: flex; justify-content: center; gap: 10px; flex-wrap: wrap;">
|
|
59705
|
+
<span class="status-badge">AWS</span>
|
|
59706
|
+
<span class="status-badge">Netlify</span>
|
|
59707
|
+
<span class="status-badge">Vercel</span>
|
|
59708
|
+
<span class="status-badge">Docker</span>
|
|
59709
|
+
</div>
|
|
59710
|
+
<p style="margin-top: 1.5rem; font-size: 0.9rem; opacity: 0.7;">
|
|
59711
|
+
Check <code>src/app.ts</code> for routing logic.
|
|
59712
|
+
</p>
|
|
59713
|
+
</div>
|
|
59714
|
+
</body>
|
|
59715
|
+
</html>
|
|
59716
|
+
`;
|
|
59717
|
+
var appFile = `import express, { Request, Response } from "express";
|
|
59718
|
+
import cors from "cors";
|
|
59719
|
+
import path from "path";
|
|
59720
|
+
import helloRouter from "./routes/hello";
|
|
59721
|
+
|
|
59722
|
+
const app = express();
|
|
59723
|
+
|
|
59724
|
+
app.use(cors());
|
|
59725
|
+
app.use(express.json());
|
|
59726
|
+
// Serve static files from the 'public' directory
|
|
59727
|
+
app.use(express.static(path.join(__dirname, "../public")));
|
|
59728
|
+
|
|
59729
|
+
const router = express.Router();
|
|
59730
|
+
router.get("/", (req: Request, res: Response) => {
|
|
59731
|
+
res.sendFile(path.join(__dirname, "../public/index.html"));
|
|
59732
|
+
});
|
|
59733
|
+
|
|
59734
|
+
router.use("/hello", helloRouter);
|
|
59735
|
+
|
|
59736
|
+
// Mount router at root and api paths to handle various gateway configurations
|
|
59737
|
+
app.use("/.netlify/functions/api", router);
|
|
59738
|
+
app.use("/api", router);
|
|
59739
|
+
app.use("/", router);
|
|
59740
|
+
|
|
59741
|
+
export default app;
|
|
59742
|
+
`;
|
|
59743
|
+
var localFile = `import app from "./app";
|
|
59744
|
+
|
|
59745
|
+
const port = process.env.PORT || 3500;
|
|
59746
|
+
|
|
59747
|
+
app.listen(port, () => {
|
|
59748
|
+
console.log("Server running locally at http://localhost:" + port);
|
|
59749
|
+
});
|
|
59750
|
+
`;
|
|
59751
|
+
var vercelApiFile = `import app from "../src/app";
|
|
59752
|
+
export default app;
|
|
59753
|
+
`;
|
|
59754
|
+
var netlifyFunctionFile = `import app from "../../src/app";
|
|
59755
|
+
import serverless from "serverless-http";
|
|
59756
|
+
export const handler = serverless(app);
|
|
59757
|
+
`;
|
|
59758
|
+
var helloRouterFile2 = `import { Router, Request, Response } from "express";
|
|
59759
|
+
|
|
59760
|
+
const router = Router();
|
|
59761
|
+
|
|
59762
|
+
router.get("/", (req: Request, res: Response) => {
|
|
59763
|
+
res.json({ message: "Hello World" });
|
|
59764
|
+
});
|
|
59765
|
+
|
|
59766
|
+
export default router;
|
|
59767
|
+
`;
|
|
59768
|
+
var lambdaFile = `import app from "./app";
|
|
59769
|
+
import serverless from "serverless-http";
|
|
59770
|
+
export const handler = serverless(app);
|
|
59771
|
+
`;
|
|
59772
|
+
var dockerFile = `# Use the official Node.js image.
|
|
59773
|
+
FROM node:18-alpine
|
|
59774
|
+
|
|
59775
|
+
# Create and change to the app directory.
|
|
59776
|
+
WORKDIR /usr/src/app
|
|
59777
|
+
|
|
59778
|
+
# Copy application dependency manifests to the container image.
|
|
59779
|
+
COPY package*.json ./
|
|
59780
|
+
|
|
59781
|
+
# Install production dependencies.
|
|
59782
|
+
# If you add a package-lock.json, speed your build by switching to 'npm ci'.
|
|
59783
|
+
RUN npm install --only=production
|
|
59784
|
+
|
|
59785
|
+
# Copy local code to the container image.
|
|
59786
|
+
COPY . .
|
|
59787
|
+
|
|
59788
|
+
# Compile TS (if you are running build inside docker)
|
|
59789
|
+
# RUN npm install typescript tsup
|
|
59790
|
+
# RUN npm run build
|
|
59791
|
+
|
|
59792
|
+
# Run the web service on container startup.
|
|
59793
|
+
CMD [ "npm", "start" ]
|
|
59794
|
+
`;
|
|
59795
|
+
var serverlessYmlFile = `service: my-express-service
|
|
59796
|
+
|
|
59797
|
+
provider:
|
|
59798
|
+
name: aws
|
|
59799
|
+
runtime: nodejs18.x
|
|
59800
|
+
region: us-east-1
|
|
59801
|
+
|
|
59802
|
+
functions:
|
|
59803
|
+
api:
|
|
59804
|
+
handler: dist/lambda.handler
|
|
59805
|
+
events:
|
|
59806
|
+
- httpApi: '*'
|
|
59807
|
+
`;
|
|
59808
|
+
var serverless_default = {
|
|
59809
|
+
htmlFile: htmlFile2,
|
|
59810
|
+
appFile,
|
|
59811
|
+
localFile,
|
|
59812
|
+
vercelApiFile,
|
|
59813
|
+
netlifyFunctionFile,
|
|
59814
|
+
helloRouterFile: helloRouterFile2,
|
|
59815
|
+
lambdaFile,
|
|
59816
|
+
dockerFile,
|
|
59817
|
+
serverlessYmlFile
|
|
59818
|
+
};
|
|
59819
|
+
|
|
59820
|
+
// ../../packages/template/projects/serverless-express.ts
|
|
59821
|
+
var ServerlessExpressTS = {
|
|
59822
|
+
name: "Serverless Express TS",
|
|
59823
|
+
description: "Serverless Express TS template optimized for Serverless (Netlify, Vercel, AWS) & Containers (Docker, Render, Fly.io)",
|
|
59824
|
+
notes: "Node.js and NPM must be installed.",
|
|
59825
|
+
templating: [
|
|
59826
|
+
{
|
|
59827
|
+
action: "command",
|
|
59828
|
+
cmd: "npm",
|
|
59829
|
+
args: ["init", "-y"]
|
|
59830
|
+
},
|
|
59831
|
+
{
|
|
59832
|
+
action: "command",
|
|
59833
|
+
cmd: "npm",
|
|
59834
|
+
args: ["install", "express", "cors", "serverless-http"]
|
|
59835
|
+
},
|
|
59836
|
+
{
|
|
59837
|
+
action: "command",
|
|
59838
|
+
cmd: "npm",
|
|
59839
|
+
args: ["install", "-D", "nodemon", "typescript", "ts-node", "tsup", "@types/node", "@types/express", "@types/cors"]
|
|
59840
|
+
},
|
|
59841
|
+
// App Files
|
|
59842
|
+
{
|
|
59843
|
+
action: "file",
|
|
59844
|
+
file: "public/index.html",
|
|
59845
|
+
filecontent: serverless_default.htmlFile
|
|
59846
|
+
},
|
|
59847
|
+
{
|
|
59848
|
+
action: "file",
|
|
59849
|
+
file: "src/app.ts",
|
|
59850
|
+
filecontent: serverless_default.appFile
|
|
59851
|
+
},
|
|
59852
|
+
{
|
|
59853
|
+
action: "file",
|
|
59854
|
+
file: "src/local.ts",
|
|
59855
|
+
filecontent: serverless_default.localFile
|
|
59856
|
+
},
|
|
59857
|
+
{
|
|
59858
|
+
action: "file",
|
|
59859
|
+
file: "src/routes/hello.ts",
|
|
59860
|
+
filecontent: serverless_default.helloRouterFile
|
|
59861
|
+
},
|
|
59862
|
+
// Serverless Entry Points
|
|
59863
|
+
{
|
|
59864
|
+
action: "file",
|
|
59865
|
+
file: "api/index.ts",
|
|
59866
|
+
filecontent: serverless_default.vercelApiFile
|
|
59867
|
+
},
|
|
59868
|
+
{
|
|
59869
|
+
action: "file",
|
|
59870
|
+
file: "netlify/functions/api.ts",
|
|
59871
|
+
filecontent: serverless_default.netlifyFunctionFile
|
|
59872
|
+
},
|
|
59873
|
+
{
|
|
59874
|
+
action: "file",
|
|
59875
|
+
file: "src/lambda.ts",
|
|
59876
|
+
filecontent: serverless_default.lambdaFile
|
|
59877
|
+
},
|
|
59878
|
+
// Container Configs
|
|
59879
|
+
{
|
|
59880
|
+
action: "file",
|
|
59881
|
+
file: "Dockerfile",
|
|
59882
|
+
filecontent: serverless_default.dockerFile
|
|
59883
|
+
},
|
|
59884
|
+
{
|
|
59885
|
+
action: "file",
|
|
59886
|
+
file: "app.yaml",
|
|
59887
|
+
filecontent: "runtime: nodejs18\nservice: default\n"
|
|
59888
|
+
},
|
|
59889
|
+
{
|
|
59890
|
+
action: "file",
|
|
59891
|
+
file: "serverless.yml",
|
|
59892
|
+
filecontent: serverless_default.serverlessYmlFile
|
|
59893
|
+
},
|
|
59894
|
+
// Config Files
|
|
59895
|
+
{
|
|
59896
|
+
action: "file",
|
|
59897
|
+
file: "tsup.config.ts",
|
|
59898
|
+
filecontent: "import { defineConfig } from 'tsup';\n\nexport default defineConfig({\n entry: ['src/local.ts', 'src/lambda.ts'],\n splitting: false,\n sourcemap: true,\n clean: true,\n format: ['cjs'],\n});"
|
|
59899
|
+
},
|
|
59900
|
+
{
|
|
59901
|
+
action: "file",
|
|
59902
|
+
file: "tsconfig.json",
|
|
59903
|
+
filecontent: '{\n "compilerOptions": {\n "target": "es2016",\n "module": "commonjs",\n "outDir": "./dist",\n "esModuleInterop": true,\n "forceConsistentCasingInFileNames": true,\n "strict": true,\n "skipLibCheck": true\n },\n "include": ["src/**/*", "api/**/*", "netlify/**/*"]\n}'
|
|
59904
|
+
},
|
|
59905
|
+
// Deployment Configs
|
|
59906
|
+
{
|
|
59907
|
+
action: "file",
|
|
59908
|
+
file: "render.yaml",
|
|
59909
|
+
filecontent: `services:
|
|
59910
|
+
- type: web
|
|
59911
|
+
name: express-serverless-service
|
|
59912
|
+
env: node
|
|
59913
|
+
plan: free
|
|
59914
|
+
buildCommand: npm install && npm run build
|
|
59915
|
+
startCommand: npm start
|
|
59916
|
+
envVars:
|
|
59917
|
+
- key: PORT
|
|
59918
|
+
value: 10000`
|
|
59919
|
+
},
|
|
59920
|
+
{
|
|
59921
|
+
action: "file",
|
|
59922
|
+
file: "Procfile",
|
|
59923
|
+
filecontent: "web: npm start"
|
|
59924
|
+
},
|
|
59925
|
+
{
|
|
59926
|
+
action: "file",
|
|
59927
|
+
file: "vercel.json",
|
|
59928
|
+
filecontent: `{
|
|
59929
|
+
"version": 2,
|
|
59930
|
+
"rewrites": [
|
|
59931
|
+
{ "source": "/(.*)", "destination": "/api/index" }
|
|
59932
|
+
]
|
|
59933
|
+
}`
|
|
59934
|
+
},
|
|
59935
|
+
{
|
|
59936
|
+
action: "file",
|
|
59937
|
+
file: "netlify.toml",
|
|
59938
|
+
filecontent: `[build]
|
|
59939
|
+
command = "npm run build"
|
|
59940
|
+
functions = "functions"
|
|
59941
|
+
|
|
59942
|
+
# Redirect all traffic to the lambda function
|
|
59943
|
+
[[redirects]]
|
|
59944
|
+
from = "/*"
|
|
59945
|
+
to = "/.netlify/functions/api"
|
|
59946
|
+
status = 200
|
|
59947
|
+
force = true`
|
|
59948
|
+
},
|
|
59949
|
+
// Scripts
|
|
59950
|
+
{
|
|
59951
|
+
action: "command",
|
|
59952
|
+
cmd: "npm",
|
|
59953
|
+
args: ["pkg", "set", "scripts.dev=nodemon --watch 'src/**/*.ts' --exec 'ts-node' src/local.ts"]
|
|
59954
|
+
},
|
|
59955
|
+
{
|
|
59956
|
+
action: "command",
|
|
59957
|
+
cmd: "npm",
|
|
59958
|
+
args: ["pkg", "set", "scripts.build=tsup"]
|
|
59959
|
+
},
|
|
59960
|
+
{
|
|
59961
|
+
action: "command",
|
|
59962
|
+
cmd: "npm",
|
|
59963
|
+
args: ["pkg", "set", "scripts.start=node dist/local.js"]
|
|
59964
|
+
},
|
|
59965
|
+
{
|
|
59966
|
+
action: "command",
|
|
59967
|
+
cmd: "npm",
|
|
59968
|
+
args: ["pkg", "set", "scripts.stop=npx -y kill-port 3500"]
|
|
59969
|
+
},
|
|
59970
|
+
{
|
|
59971
|
+
action: "command",
|
|
59972
|
+
cmd: "npm",
|
|
59973
|
+
args: ["pkg", "set", "description=Serverless Express TS"]
|
|
59974
|
+
},
|
|
59975
|
+
{
|
|
59976
|
+
action: "command",
|
|
59977
|
+
cmd: "npm",
|
|
59978
|
+
args: ["pkg", "set", "fontawesomeIcon=fab fa-aws text-orange-500"]
|
|
59979
|
+
}
|
|
59980
|
+
]
|
|
59981
|
+
};
|
|
59982
|
+
|
|
59983
|
+
// ../../packages/template/projects/files/_php.ts
|
|
59984
|
+
var phpContent = `<?php
|
|
59985
|
+
$file = 'visits.txt';
|
|
59986
|
+
if (!file_exists($file)) {
|
|
59987
|
+
file_put_contents($file, 0);
|
|
59988
|
+
}
|
|
59989
|
+
$count = (int)file_get_contents($file);
|
|
59990
|
+
$count++;
|
|
59991
|
+
file_put_contents($file, $count);
|
|
59992
|
+
?>
|
|
59993
|
+
<!DOCTYPE html>
|
|
59994
|
+
<html lang="en">
|
|
59995
|
+
<head>
|
|
59996
|
+
<meta charset="UTF-8">
|
|
59997
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
59998
|
+
<title>Welcome to Monorepo Time</title>
|
|
59999
|
+
<script src="https://cdn.tailwindcss.com"></script>
|
|
60000
|
+
<style>
|
|
60001
|
+
@import url('https://fonts.googleapis.com/css2?family=Outfit:wght@300;400;600&display=swap');
|
|
60002
|
+
body { font-family: 'Outfit', sans-serif; }
|
|
60003
|
+
</style>
|
|
60004
|
+
</head>
|
|
60005
|
+
<body class="bg-gray-900 text-white min-h-screen flex items-center justify-center relative overflow-hidden">
|
|
60006
|
+
<!-- Background Elements -->
|
|
60007
|
+
<div class="absolute top-0 left-0 w-full h-full overflow-hidden z-0">
|
|
60008
|
+
<div class="absolute top-[-10%] right-[-10%] w-96 h-96 bg-purple-600 rounded-full mix-blend-multiply filter blur-3xl opacity-20 animate-blob"></div>
|
|
60009
|
+
<div class="absolute bottom-[-10%] left-[-10%] w-96 h-96 bg-blue-600 rounded-full mix-blend-multiply filter blur-3xl opacity-20 animate-blob animation-delay-2000"></div>
|
|
60010
|
+
</div>
|
|
60011
|
+
|
|
60012
|
+
<div class="z-10 text-center p-8 bg-white/10 backdrop-blur-lg rounded-2xl border border-white/20 shadow-2xl max-w-lg w-full transform hover:scale-105 transition-transform duration-300">
|
|
60013
|
+
<div class="mb-6">
|
|
60014
|
+
<span class="text-4xl">\u{1F680}</span>
|
|
60015
|
+
</div>
|
|
60016
|
+
<h1 class="text-4xl font-bold mb-2 bg-clip-text text-transparent bg-gradient-to-r from-blue-400 to-purple-400">
|
|
60017
|
+
Monorepo Time
|
|
60018
|
+
</h1>
|
|
60019
|
+
<p class="text-gray-300 text-lg mb-6">
|
|
60020
|
+
Your PHP application is up and running.
|
|
60021
|
+
</p>
|
|
60022
|
+
|
|
60023
|
+
<div class="bg-black/30 rounded-xl p-4 mb-6">
|
|
60024
|
+
<p class="text-sm text-gray-400 uppercase tracking-widest mb-1">Total Visits</p>
|
|
60025
|
+
<p class="text-3xl font-mono font-bold text-green-400">
|
|
60026
|
+
<?php echo number_format($count); ?>
|
|
60027
|
+
</p>
|
|
60028
|
+
</div>
|
|
60029
|
+
|
|
60030
|
+
<div class="flex justify-center gap-4">
|
|
60031
|
+
<a href="#" class="px-6 py-2 bg-blue-600 hover:bg-blue-700 rounded-full font-medium transition-colors duration-200">
|
|
60032
|
+
Documentation
|
|
60033
|
+
</a>
|
|
60034
|
+
<a href="#" class="px-6 py-2 bg-transparent border border-white/30 hover:bg-white/10 rounded-full font-medium transition-colors duration-200">
|
|
60035
|
+
Learn More
|
|
60036
|
+
</a>
|
|
60037
|
+
</div>
|
|
60038
|
+
</div>
|
|
60039
|
+
|
|
60040
|
+
<!-- Animation Keyframes -->
|
|
60041
|
+
<style>
|
|
60042
|
+
@keyframes blob {
|
|
60043
|
+
0% { transform: translate(0px, 0px) scale(1); }
|
|
60044
|
+
33% { transform: translate(30px, -50px) scale(1.1); }
|
|
60045
|
+
66% { transform: translate(-20px, 20px) scale(0.9); }
|
|
60046
|
+
100% { transform: translate(0px, 0px) scale(1); }
|
|
60047
|
+
}
|
|
60048
|
+
.animate-blob {
|
|
60049
|
+
animation: blob 7s infinite;
|
|
60050
|
+
}
|
|
60051
|
+
.animation-delay-2000 {
|
|
60052
|
+
animation-delay: 2s;
|
|
60053
|
+
}
|
|
60054
|
+
</style>
|
|
60055
|
+
</body>
|
|
60056
|
+
</html>
|
|
60057
|
+
`;
|
|
60058
|
+
|
|
60690
60059
|
// ../../packages/template/projects/php.ts
|
|
60691
60060
|
var PHP = {
|
|
60692
60061
|
name: "PHP",
|
|
@@ -60696,27 +60065,27 @@ var PHP = {
|
|
|
60696
60065
|
{
|
|
60697
60066
|
action: "file",
|
|
60698
60067
|
file: "index.php",
|
|
60699
|
-
filecontent:
|
|
60068
|
+
filecontent: phpContent
|
|
60700
60069
|
},
|
|
60701
60070
|
{
|
|
60702
60071
|
action: "command",
|
|
60703
60072
|
cmd: "npm",
|
|
60704
|
-
args: ["pkg", "set", "scripts.
|
|
60073
|
+
args: ["pkg", "set", "scripts.start=php -S localhost:3000"]
|
|
60705
60074
|
},
|
|
60706
60075
|
{
|
|
60707
60076
|
action: "command",
|
|
60708
60077
|
cmd: "npm",
|
|
60709
|
-
args: ["pkg", "set", "scripts.
|
|
60078
|
+
args: ["pkg", "set", "scripts.stop=npx kill-port 3000"]
|
|
60710
60079
|
},
|
|
60711
60080
|
{
|
|
60712
60081
|
action: "command",
|
|
60713
60082
|
cmd: "npm",
|
|
60714
|
-
args: ["pkg", "set", "
|
|
60083
|
+
args: ["pkg", "set", "description=PHP"]
|
|
60715
60084
|
},
|
|
60716
60085
|
{
|
|
60717
60086
|
action: "command",
|
|
60718
60087
|
cmd: "npm",
|
|
60719
|
-
args: ["pkg", "set", "fontawesomeIcon=fab fa-php text-indigo-
|
|
60088
|
+
args: ["pkg", "set", "fontawesomeIcon=fab fa-php text-indigo-500"]
|
|
60720
60089
|
}
|
|
60721
60090
|
]
|
|
60722
60091
|
};
|
|
@@ -60757,6 +60126,11 @@ var Laravel = {
|
|
|
60757
60126
|
cmd: "npm",
|
|
60758
60127
|
args: ["pkg", "set", "scripts.stop=npx -y kill-port 8000"]
|
|
60759
60128
|
},
|
|
60129
|
+
{
|
|
60130
|
+
action: "command",
|
|
60131
|
+
cmd: "npm",
|
|
60132
|
+
args: ["pkg", "set", "description=Laravel"]
|
|
60133
|
+
},
|
|
60760
60134
|
{
|
|
60761
60135
|
action: "command",
|
|
60762
60136
|
cmd: "npm",
|
|
@@ -60765,31 +60139,171 @@ var Laravel = {
|
|
|
60765
60139
|
]
|
|
60766
60140
|
};
|
|
60767
60141
|
|
|
60768
|
-
// ../../packages/template/projects/
|
|
60769
|
-
var
|
|
60770
|
-
|
|
60771
|
-
|
|
60142
|
+
// ../../packages/template/projects/files/_python.ts
|
|
60143
|
+
var mainPy = `import http.server
|
|
60144
|
+
import socketserver
|
|
60145
|
+
import os
|
|
60146
|
+
import sys
|
|
60147
|
+
|
|
60148
|
+
# Define port, default to 3000 or use environment variable
|
|
60149
|
+
PORT = int(os.environ.get('PORT', 3000))
|
|
60150
|
+
|
|
60151
|
+
class MyHandler(http.server.SimpleHTTPRequestHandler):
|
|
60152
|
+
def do_GET(self):
|
|
60153
|
+
# Route: / -> Load index.html
|
|
60154
|
+
if self.path == '/':
|
|
60155
|
+
self.path = 'index.html'
|
|
60156
|
+
return http.server.SimpleHTTPRequestHandler.do_GET(self)
|
|
60157
|
+
|
|
60158
|
+
# Route: /test -> Return "Hello World"
|
|
60159
|
+
elif self.path == '/test':
|
|
60160
|
+
self.send_response(200)
|
|
60161
|
+
self.send_header('Content-type', 'text/plain')
|
|
60162
|
+
self.end_headers()
|
|
60163
|
+
self.wfile.write(b"Hello World")
|
|
60164
|
+
return
|
|
60165
|
+
|
|
60166
|
+
# Default: Serve static files
|
|
60167
|
+
return http.server.SimpleHTTPRequestHandler.do_GET(self)
|
|
60168
|
+
|
|
60169
|
+
# Ensure index.html exists (though template should create it)
|
|
60170
|
+
if not os.path.exists('index.html'):
|
|
60171
|
+
with open('index.html', 'w') as f:
|
|
60172
|
+
f.write("<h1>Error: index.html not found</h1>")
|
|
60173
|
+
|
|
60174
|
+
print(f"Python server is running at http://localhost:{PORT}")
|
|
60175
|
+
print("Press Ctrl+C to stop.")
|
|
60176
|
+
|
|
60177
|
+
try:
|
|
60178
|
+
# Allow address reuse to prevent "Address already in use" errors on restart
|
|
60179
|
+
socketserver.TCPServer.allow_reuse_address = True
|
|
60180
|
+
with socketserver.TCPServer(("", PORT), MyHandler) as httpd:
|
|
60181
|
+
httpd.serve_forever()
|
|
60182
|
+
except KeyboardInterrupt:
|
|
60183
|
+
print("^C received, shutting down server")
|
|
60184
|
+
sys.exit(0)
|
|
60772
60185
|
`;
|
|
60186
|
+
var indexHtml = `<!DOCTYPE html>
|
|
60187
|
+
<html lang="en">
|
|
60188
|
+
<head>
|
|
60189
|
+
<meta charset="UTF-8">
|
|
60190
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
60191
|
+
<title>Monorepo Time - Python Backend</title>
|
|
60192
|
+
<script src="https://cdn.tailwindcss.com"></script>
|
|
60193
|
+
<style>
|
|
60194
|
+
@import url('https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;700&display=swap');
|
|
60195
|
+
body { font-family: 'JetBrains Mono', monospace; }
|
|
60196
|
+
.glass {
|
|
60197
|
+
background: rgba(255, 255, 255, 0.05);
|
|
60198
|
+
backdrop-filter: blur(10px);
|
|
60199
|
+
-webkit-backdrop-filter: blur(10px);
|
|
60200
|
+
border: 1px solid rgba(255, 255, 255, 0.1);
|
|
60201
|
+
}
|
|
60202
|
+
</style>
|
|
60203
|
+
</head>
|
|
60204
|
+
<body class="bg-[#0f172a] text-gray-200 min-h-screen flex items-center justify-center relative overflow-hidden">
|
|
60205
|
+
<!-- Background Decor -->
|
|
60206
|
+
<div class="absolute top-0 left-0 w-full h-full overflow-hidden z-0 pointer-events-none">
|
|
60207
|
+
<div class="absolute top-1/4 left-1/4 w-96 h-96 bg-blue-500/20 rounded-full blur-[100px]"></div>
|
|
60208
|
+
<div class="absolute bottom-1/4 right-1/4 w-96 h-96 bg-yellow-500/10 rounded-full blur-[100px]"></div>
|
|
60209
|
+
</div>
|
|
60210
|
+
|
|
60211
|
+
<!-- Main Content -->
|
|
60212
|
+
<div class="z-10 w-full max-w-2xl px-4">
|
|
60213
|
+
<div class="glass rounded-2xl p-8 md:p-12 shadow-2xl border border-white/5 transform transition-all hover:scale-[1.01]">
|
|
60214
|
+
<div class="flex items-center justify-between mb-8">
|
|
60215
|
+
<div class="flex items-center space-x-3">
|
|
60216
|
+
<span class="text-4xl">\u{1F40D}</span>
|
|
60217
|
+
<h1 class="text-3xl font-bold bg-clip-text text-transparent bg-gradient-to-r from-blue-400 to-yellow-300">
|
|
60218
|
+
Python Backend
|
|
60219
|
+
</h1>
|
|
60220
|
+
</div>
|
|
60221
|
+
<div class="flex items-center space-x-2">
|
|
60222
|
+
<div class="w-3 h-3 bg-green-500 rounded-full animate-pulse"></div>
|
|
60223
|
+
<span class="text-xs font-mono text-green-400 uppercase tracking-widest">Online</span>
|
|
60224
|
+
</div>
|
|
60225
|
+
</div>
|
|
60226
|
+
|
|
60227
|
+
<div class="space-y-6">
|
|
60228
|
+
<p class="text-xl text-gray-300 leading-relaxed font-light">
|
|
60229
|
+
Python server is running.
|
|
60230
|
+
</p>
|
|
60231
|
+
|
|
60232
|
+
<div class="p-4 rounded-lg bg-black/30 border border-white/10 font-mono text-sm text-gray-400">
|
|
60233
|
+
<p>$ python main.py</p>
|
|
60234
|
+
<p class="text-green-400">>> Server started at http://localhost:3000</p>
|
|
60235
|
+
</div>
|
|
60236
|
+
|
|
60237
|
+
<div class="pt-4 flex flex-col sm:flex-row gap-4">
|
|
60238
|
+
<a href="/test" class="group relative px-8 py-3 bg-blue-600 hover:bg-blue-500 rounded-lg font-bold text-white transition-all shadow-[0_0_20px_rgba(37,99,235,0.3)] hover:shadow-[0_0_30px_rgba(37,99,235,0.5)] overflow-hidden">
|
|
60239
|
+
<span class="relative z-10 flex items-center justify-center gap-2">
|
|
60240
|
+
Test Endpoint
|
|
60241
|
+
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 transition-transform group-hover:translate-x-1" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
60242
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 7l5 5m0 0l-5 5m5-5H6" />
|
|
60243
|
+
</svg>
|
|
60244
|
+
</span>
|
|
60245
|
+
</a>
|
|
60246
|
+
|
|
60247
|
+
<a href="https://docs.python.org/3/library/http.server.html" target="_blank" class="px-8 py-3 bg-transparent border border-white/20 hover:bg-white/5 rounded-lg font-bold text-gray-300 transition-colors text-center">
|
|
60248
|
+
Docs
|
|
60249
|
+
</a>
|
|
60250
|
+
</div>
|
|
60251
|
+
</div>
|
|
60252
|
+
</div>
|
|
60253
|
+
|
|
60254
|
+
<div class="mt-8 text-center text-sm text-gray-500">
|
|
60255
|
+
<p>Powered by Python Standard Library & Tailwind CSS</p>
|
|
60256
|
+
</div>
|
|
60257
|
+
</div>
|
|
60258
|
+
</body>
|
|
60259
|
+
</html>
|
|
60260
|
+
`;
|
|
60261
|
+
var python_default = {
|
|
60262
|
+
mainPy,
|
|
60263
|
+
indexHtml
|
|
60264
|
+
};
|
|
60265
|
+
|
|
60266
|
+
// ../../packages/template/projects/python.ts
|
|
60773
60267
|
var PythonConsole = {
|
|
60774
|
-
name: "Python
|
|
60775
|
-
description: "Simple Python
|
|
60268
|
+
name: "Python Backend",
|
|
60269
|
+
description: "Simple Python Backend Application",
|
|
60776
60270
|
notes: "Python 3 must be installed in your system.",
|
|
60777
60271
|
templating: [
|
|
60778
60272
|
{
|
|
60779
60273
|
action: "file",
|
|
60780
60274
|
file: "main.py",
|
|
60781
|
-
filecontent:
|
|
60275
|
+
filecontent: python_default.mainPy
|
|
60276
|
+
},
|
|
60277
|
+
{
|
|
60278
|
+
action: "file",
|
|
60279
|
+
file: "index.html",
|
|
60280
|
+
filecontent: python_default.indexHtml
|
|
60782
60281
|
},
|
|
60783
60282
|
{
|
|
60784
60283
|
action: "command",
|
|
60785
60284
|
cmd: "npm",
|
|
60786
|
-
args: ["
|
|
60285
|
+
args: ["install", "-D", "nodemon"]
|
|
60286
|
+
},
|
|
60287
|
+
{
|
|
60288
|
+
action: "command",
|
|
60289
|
+
cmd: "npm",
|
|
60290
|
+
args: ["pkg", "set", "scripts.dev=nodemon --watch . --ext py --exec python3 main.py"]
|
|
60787
60291
|
},
|
|
60788
60292
|
{
|
|
60789
60293
|
action: "command",
|
|
60790
60294
|
cmd: "npm",
|
|
60791
60295
|
args: ["pkg", "set", "scripts.start=python3 main.py"]
|
|
60792
60296
|
},
|
|
60297
|
+
{
|
|
60298
|
+
action: "command",
|
|
60299
|
+
cmd: "npm",
|
|
60300
|
+
args: ["pkg", "set", "description=Python Backend"]
|
|
60301
|
+
},
|
|
60302
|
+
{
|
|
60303
|
+
action: "command",
|
|
60304
|
+
cmd: "npm",
|
|
60305
|
+
args: ["pkg", "set", "scripts.stop=npx kill-port 3000"]
|
|
60306
|
+
},
|
|
60793
60307
|
{
|
|
60794
60308
|
action: "command",
|
|
60795
60309
|
cmd: "npm",
|
|
@@ -60833,7 +60347,12 @@ var DotNetConsole = {
|
|
|
60833
60347
|
{
|
|
60834
60348
|
action: "command",
|
|
60835
60349
|
cmd: "npm",
|
|
60836
|
-
args: ["pkg", "set", "
|
|
60350
|
+
args: ["pkg", "set", "description=.NET Console"]
|
|
60351
|
+
},
|
|
60352
|
+
{
|
|
60353
|
+
action: "command",
|
|
60354
|
+
cmd: "npm",
|
|
60355
|
+
args: ["pkg", "set", "fontawesomeIcon=fab fa-windows text-blue-500"]
|
|
60837
60356
|
}
|
|
60838
60357
|
]
|
|
60839
60358
|
};
|
|
@@ -60843,6 +60362,7 @@ var templates3 = [
|
|
|
60843
60362
|
ViteReact,
|
|
60844
60363
|
NextJS,
|
|
60845
60364
|
ExpressTS,
|
|
60365
|
+
ServerlessExpressTS,
|
|
60846
60366
|
PHP,
|
|
60847
60367
|
Laravel,
|
|
60848
60368
|
PythonConsole,
|
|
@@ -60881,6 +60401,11 @@ var N8NLocal = {
|
|
|
60881
60401
|
cmd: "npm",
|
|
60882
60402
|
args: ["pkg", "set", "fontawesomeIcon=fas fa-project-diagram text-red-500"]
|
|
60883
60403
|
},
|
|
60404
|
+
{
|
|
60405
|
+
action: "command",
|
|
60406
|
+
cmd: "npm",
|
|
60407
|
+
args: ["pkg", "set", "description=N8N (Local)"]
|
|
60408
|
+
},
|
|
60884
60409
|
{
|
|
60885
60410
|
action: "command",
|
|
60886
60411
|
cmd: "npm",
|
|
@@ -61122,7 +60647,7 @@ networks:
|
|
|
61122
60647
|
driver: bridge`;
|
|
61123
60648
|
|
|
61124
60649
|
// ../../packages/template/services_list/aws/indexHtml.ts
|
|
61125
|
-
var
|
|
60650
|
+
var indexHtml2 = `<!DOCTYPE html>
|
|
61126
60651
|
<html lang="en" class="dark">
|
|
61127
60652
|
<head>
|
|
61128
60653
|
<meta charset="UTF-8">
|
|
@@ -61458,7 +60983,7 @@ spawn('docker', ['compose', 'down'], { stdio: 'inherit' });`;
|
|
|
61458
60983
|
|
|
61459
60984
|
// ../../packages/template/services_list/aws.ts
|
|
61460
60985
|
var AWSTemplate = {
|
|
61461
|
-
name: "
|
|
60986
|
+
name: "Localstack (Experimental)",
|
|
61462
60987
|
description: "AWS LocalStack Environment with Manager",
|
|
61463
60988
|
notes: "Requires Docker, Node.js, and AWS CLI installed.",
|
|
61464
60989
|
templating: [
|
|
@@ -61485,7 +61010,7 @@ var AWSTemplate = {
|
|
|
61485
61010
|
{
|
|
61486
61011
|
action: "file",
|
|
61487
61012
|
file: "index.html",
|
|
61488
|
-
filecontent:
|
|
61013
|
+
filecontent: indexHtml2
|
|
61489
61014
|
},
|
|
61490
61015
|
{
|
|
61491
61016
|
action: "command",
|
|
@@ -61515,7 +61040,12 @@ var AWSTemplate = {
|
|
|
61515
61040
|
{
|
|
61516
61041
|
action: "command",
|
|
61517
61042
|
cmd: "npm",
|
|
61518
|
-
args: ["pkg", "set", "fontawesomeIcon=fab fa-aws text-orange-
|
|
61043
|
+
args: ["pkg", "set", "fontawesomeIcon=fab fa-aws text-orange-500"]
|
|
61044
|
+
},
|
|
61045
|
+
{
|
|
61046
|
+
action: "command",
|
|
61047
|
+
cmd: "npm",
|
|
61048
|
+
args: ["pkg", "set", "description=AWS LocalStack Environment with Manager"]
|
|
61519
61049
|
},
|
|
61520
61050
|
{
|
|
61521
61051
|
action: "command",
|
|
@@ -61696,7 +61226,7 @@ const stripe = new Stripe('sk_test_mock_123', {
|
|
|
61696
61226
|
})();
|
|
61697
61227
|
`;
|
|
61698
61228
|
var StripeTemplate = {
|
|
61699
|
-
name: "Stripe Mock",
|
|
61229
|
+
name: "Stripe Mock (Experimental)",
|
|
61700
61230
|
description: "Stripe API Mock Server",
|
|
61701
61231
|
notes: "Runs the official stripe-mock image. Requires Docker.",
|
|
61702
61232
|
templating: [
|
|
@@ -61745,6 +61275,11 @@ var StripeTemplate = {
|
|
|
61745
61275
|
cmd: "npm",
|
|
61746
61276
|
args: ["pkg", "set", "fontawesomeIcon=fas fa-credit-card text-green-500"]
|
|
61747
61277
|
},
|
|
61278
|
+
{
|
|
61279
|
+
action: "command",
|
|
61280
|
+
cmd: "npm",
|
|
61281
|
+
args: ["pkg", "set", "description=Stripe Mock"]
|
|
61282
|
+
},
|
|
61748
61283
|
{
|
|
61749
61284
|
action: "command",
|
|
61750
61285
|
cmd: "npm",
|
|
@@ -61771,7 +61306,7 @@ var MonorepoTemplates = {
|
|
|
61771
61306
|
var template_default = MonorepoTemplates;
|
|
61772
61307
|
|
|
61773
61308
|
// src/routes/availabletemplates.ts
|
|
61774
|
-
var router18 =
|
|
61309
|
+
var router18 = import_express22.default.Router();
|
|
61775
61310
|
router18.get("/", (req, res) => {
|
|
61776
61311
|
try {
|
|
61777
61312
|
const stripTemplating = (templates5) => {
|
|
@@ -61792,7 +61327,7 @@ router18.get("/", (req, res) => {
|
|
|
61792
61327
|
var availabletemplates_default = router18;
|
|
61793
61328
|
|
|
61794
61329
|
// src/routes/setworkspace/index.ts
|
|
61795
|
-
var
|
|
61330
|
+
var import_express23 = __toESM(require_express2());
|
|
61796
61331
|
|
|
61797
61332
|
// src/routes/setworkspace/template.ts
|
|
61798
61333
|
var import_path17 = __toESM(require("path"));
|
|
@@ -61815,6 +61350,33 @@ async function writeFile(filePath, content) {
|
|
|
61815
61350
|
await import_fs3.promises.writeFile(filePath, content, { encoding: "utf8" });
|
|
61816
61351
|
}
|
|
61817
61352
|
var isWindows = process.platform === "win32";
|
|
61353
|
+
async function findMonorepoRoot4(startDir) {
|
|
61354
|
+
let currentDir = startDir;
|
|
61355
|
+
while (true) {
|
|
61356
|
+
const markers = ["pnpm-workspace.yaml", "turbo.json", "lerna.json", ".git"];
|
|
61357
|
+
for (const marker of markers) {
|
|
61358
|
+
try {
|
|
61359
|
+
await import_fs3.promises.stat(import_path15.default.join(currentDir, marker));
|
|
61360
|
+
return currentDir;
|
|
61361
|
+
} catch {
|
|
61362
|
+
}
|
|
61363
|
+
}
|
|
61364
|
+
try {
|
|
61365
|
+
const pkgPath = import_path15.default.join(currentDir, "package.json");
|
|
61366
|
+
const content = await import_fs3.promises.readFile(pkgPath, "utf8");
|
|
61367
|
+
const pkg = JSON.parse(content);
|
|
61368
|
+
if (pkg.workspaces) {
|
|
61369
|
+
return currentDir;
|
|
61370
|
+
}
|
|
61371
|
+
} catch {
|
|
61372
|
+
}
|
|
61373
|
+
const parentDir = import_path15.default.dirname(currentDir);
|
|
61374
|
+
if (parentDir === currentDir) {
|
|
61375
|
+
return startDir;
|
|
61376
|
+
}
|
|
61377
|
+
currentDir = parentDir;
|
|
61378
|
+
}
|
|
61379
|
+
}
|
|
61818
61380
|
|
|
61819
61381
|
// src/routes/setworkspace/command.ts
|
|
61820
61382
|
var import_path16 = __toESM(require("path"));
|
|
@@ -61912,11 +61474,17 @@ async function executeTemplate(template, workspacePath, onProgress) {
|
|
|
61912
61474
|
await ensureDirectory(workspacePath);
|
|
61913
61475
|
const progress = onProgress || ((msg) => console.log(`[Template] ${msg}`));
|
|
61914
61476
|
for (const step of template.templating) {
|
|
61915
|
-
if (step.action === "command" && step.cmd) {
|
|
61477
|
+
if ((step.action === "command" || step.action === "root-command") && step.cmd) {
|
|
61916
61478
|
const cmd = step.cmd;
|
|
61917
61479
|
let args2 = step.args || [];
|
|
61480
|
+
let cwd = workspacePath;
|
|
61481
|
+
if (step.action === "root-command") {
|
|
61482
|
+
cwd = await findMonorepoRoot4(workspacePath);
|
|
61483
|
+
}
|
|
61484
|
+
let relativePath = import_path17.default.relative(cwd, workspacePath);
|
|
61485
|
+
if (relativePath === "") relativePath = ".";
|
|
61918
61486
|
const rawFullCmd = args2.length > 0 ? `${cmd} ${args2.join(" ")}` : cmd;
|
|
61919
|
-
const processedCmd = preprocessCommand(rawFullCmd,
|
|
61487
|
+
const processedCmd = preprocessCommand(rawFullCmd, cwd);
|
|
61920
61488
|
let finalCmd = cmd;
|
|
61921
61489
|
let finalArgs = args2;
|
|
61922
61490
|
let useShell = false;
|
|
@@ -61924,13 +61492,16 @@ async function executeTemplate(template, workspacePath, onProgress) {
|
|
|
61924
61492
|
finalCmd = processedCmd;
|
|
61925
61493
|
finalArgs = [];
|
|
61926
61494
|
useShell = true;
|
|
61495
|
+
finalCmd = finalCmd.replace(/\{\{RELATIVE_PATH\}\}/g, relativePath);
|
|
61927
61496
|
} else {
|
|
61928
|
-
const dirName = import_path17.default.basename(
|
|
61929
|
-
finalArgs = finalArgs.map(
|
|
61497
|
+
const dirName = import_path17.default.basename(cwd);
|
|
61498
|
+
finalArgs = finalArgs.map(
|
|
61499
|
+
(arg) => arg.replace(/\$\(basename \$PWD\)/g, dirName).replace(/\{\{RELATIVE_PATH\}\}/g, relativePath)
|
|
61500
|
+
);
|
|
61930
61501
|
}
|
|
61931
|
-
progress(`Running: ${finalCmd} ${finalArgs.join(" ")}`);
|
|
61502
|
+
progress(`Running in ${step.action === "root-command" ? "Root" : "Workspace"}: ${finalCmd} ${finalArgs.join(" ")}`);
|
|
61932
61503
|
try {
|
|
61933
|
-
const result = await runCommand2(finalCmd, finalArgs,
|
|
61504
|
+
const result = await runCommand2(finalCmd, finalArgs, cwd, useShell, (data) => {
|
|
61934
61505
|
const trimmed = data.trim();
|
|
61935
61506
|
if (trimmed) progress(trimmed);
|
|
61936
61507
|
});
|
|
@@ -61950,7 +61521,7 @@ ${cmdErr.message}`);
|
|
|
61950
61521
|
}
|
|
61951
61522
|
|
|
61952
61523
|
// src/routes/setworkspace/index.ts
|
|
61953
|
-
var router19 =
|
|
61524
|
+
var router19 = import_express23.default.Router();
|
|
61954
61525
|
router19.post("/", async (req, res) => {
|
|
61955
61526
|
try {
|
|
61956
61527
|
const { workspace, templatename } = req.body;
|
|
@@ -62005,12 +61576,12 @@ function setWorkspaceTemplateSocket(io3) {
|
|
|
62005
61576
|
}
|
|
62006
61577
|
|
|
62007
61578
|
// src/routes/stopTerminalWorkspace.ts
|
|
62008
|
-
var
|
|
61579
|
+
var import_express24 = __toESM(require_express2());
|
|
62009
61580
|
var import_fs_extra13 = __toESM(require_lib4());
|
|
62010
61581
|
var import_path18 = __toESM(require("path"));
|
|
62011
61582
|
init_execa();
|
|
62012
61583
|
var import_tree_kill = __toESM(require_tree_kill());
|
|
62013
|
-
var router20 = (0,
|
|
61584
|
+
var router20 = (0, import_express24.Router)();
|
|
62014
61585
|
async function killProcessTree(pid, signal = "SIGKILL") {
|
|
62015
61586
|
return new Promise((resolve, reject) => {
|
|
62016
61587
|
(0, import_tree_kill.default)(pid, signal, (err) => {
|
|
@@ -62185,14 +61756,14 @@ if (command === "init") {
|
|
|
62185
61756
|
process.exit(1);
|
|
62186
61757
|
});
|
|
62187
61758
|
}
|
|
62188
|
-
var app2 = (0,
|
|
61759
|
+
var app2 = (0, import_express25.default)();
|
|
62189
61760
|
var port2 = config_default.apiPort;
|
|
62190
61761
|
app2.use((0, import_cors.default)({
|
|
62191
61762
|
origin: true,
|
|
62192
61763
|
credentials: true
|
|
62193
61764
|
}));
|
|
62194
|
-
app2.use(
|
|
62195
|
-
app2.use(
|
|
61765
|
+
app2.use(import_express25.default.static("public"));
|
|
61766
|
+
app2.use(import_express25.default.json());
|
|
62196
61767
|
app2.use("/", tester_default);
|
|
62197
61768
|
app2.use("/" + api_default.scanWorkspace, scanworkspace_default);
|
|
62198
61769
|
app2.use("/" + api_default.stopProcess, stopcmd_default);
|
|
@@ -62216,7 +61787,7 @@ app2.use("/" + api_default.docker, apidocker_default);
|
|
|
62216
61787
|
app2.use("/" + api_default.availabletemplates, availabletemplates_default);
|
|
62217
61788
|
app2.use("/" + api_default.setWorkspaceTemplate, setworkspace_default);
|
|
62218
61789
|
var frontendPath = import_path19.default.join(__dirname, "../public");
|
|
62219
|
-
app2.use(
|
|
61790
|
+
app2.use(import_express25.default.static(frontendPath));
|
|
62220
61791
|
app2.get("*", (req, res) => {
|
|
62221
61792
|
res.sendFile(import_path19.default.join(frontendPath, "index.html"));
|
|
62222
61793
|
});
|