webcake-storefront-mcp 1.1.1 → 1.1.2
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/README.md +1 -1
- package/README.vi.md +1 -1
- package/dist/config.js +1 -1
- package/dist/db.js +48 -61
- package/dist/legal.js +2 -2
- package/dist/tools/context.js +2 -2
- package/dist/tools/images.js +3 -3
- package/dist/web-guide.js +35 -46
- package/package.json +1 -3
package/README.md
CHANGED
|
@@ -150,7 +150,7 @@ Base URLs come from a **named environment** — set `WEBCAKE_ENV` (or `--env`) a
|
|
|
150
150
|
|
|
151
151
|
Override a preset with `WEBCAKE_API_URL` / `WEBCAKE_APP_URL`. Optional, configured server-side:
|
|
152
152
|
`PEXELS_API_KEY` (search_images), `MONGO_URI` (image-alt cache). Token / session / site can also be set
|
|
153
|
-
in chat via `update_auth` and `switch_site` — saved to a local
|
|
153
|
+
in chat via `update_auth` and `switch_site` — saved to a local config file at `~/.webcake-storefront-mcp/`.
|
|
154
154
|
|
|
155
155
|
<details>
|
|
156
156
|
<summary><b>How to get your token + session</b></summary>
|
package/README.vi.md
CHANGED
|
@@ -149,7 +149,7 @@ URL gốc lấy theo **môi trường có tên** — đặt `WEBCAKE_ENV` (hoặ
|
|
|
149
149
|
|
|
150
150
|
Override bằng `WEBCAKE_API_URL` / `WEBCAKE_APP_URL`. Tuỳ chọn, đặt phía server:
|
|
151
151
|
`PEXELS_API_KEY` (search_images), `MONGO_URI` (cache alt ảnh). Token / session / site cũng có thể đặt
|
|
152
|
-
trong chat bằng `update_auth` và `switch_site` — lưu vào
|
|
152
|
+
trong chat bằng `update_auth` và `switch_site` — lưu vào file cấu hình tại `~/.webcake-storefront-mcp/`.
|
|
153
153
|
|
|
154
154
|
<details>
|
|
155
155
|
<summary><b>Cách lấy token + session</b></summary>
|
package/dist/config.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// Central resolution of connection settings for every entry path (stdio, install,
|
|
2
2
|
// login, remote HTTP). Precedence: explicit overrides > environment variables >
|
|
3
|
-
// saved config in the local
|
|
3
|
+
// saved config in the local config file.
|
|
4
4
|
import { WebcakeCmsApi } from "./api.js";
|
|
5
5
|
import { getSavedConfig } from "./tools/context.js";
|
|
6
6
|
// Per-environment endpoints so you can switch with `--env <name>` / WEBCAKE_ENV
|
package/dist/db.js
CHANGED
|
@@ -1,96 +1,83 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
// Tiny JSON-file persistence (no native deps) for: (1) the saved connection config
|
|
2
|
+
// (token / session / site / api_url / confirm_mode) and (2) the image-alt cache.
|
|
3
|
+
//
|
|
4
|
+
// Stored under a stable home dir so it survives `npx` (ephemeral package cache) and
|
|
5
|
+
// container restarts. Two flat JSON files instead of SQLite — keeps the package light
|
|
6
|
+
// and works in any runtime (Alpine, Docker `--ignore-scripts`, serverless) with no
|
|
7
|
+
// native binding to build. The API is synchronous to match the call sites.
|
|
8
|
+
import { mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
3
9
|
import { homedir } from "node:os";
|
|
4
10
|
import { join } from "node:path";
|
|
5
|
-
// Persist in a stable home directory so saved config survives `npx` (where the
|
|
6
|
-
// package lives in an ephemeral cache dir) and rebuilds.
|
|
7
11
|
const CONFIG_DIR = process.env.WEBCAKE_CONFIG_DIR || join(homedir(), ".webcake-storefront-mcp");
|
|
8
12
|
mkdirSync(CONFIG_DIR, { recursive: true });
|
|
9
|
-
const
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
13
|
+
const CONFIG_FILE = join(CONFIG_DIR, "config.json");
|
|
14
|
+
const ALT_FILE = join(CONFIG_DIR, "image-alt-cache.json");
|
|
15
|
+
function readJson(file, fallback) {
|
|
16
|
+
try {
|
|
17
|
+
return JSON.parse(readFileSync(file, "utf-8"));
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
return fallback;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
function writeJson(file, data) {
|
|
24
|
+
try {
|
|
25
|
+
writeFileSync(file, JSON.stringify(data), "utf-8");
|
|
26
|
+
}
|
|
27
|
+
catch (e) {
|
|
28
|
+
console.error("[db] write failed:", e?.message ?? e);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
// ── Config (key/value) ───────────────────────────────────────────────────────
|
|
32
|
+
const config = readJson(CONFIG_FILE, {});
|
|
25
33
|
export function getConfig(key) {
|
|
26
|
-
|
|
27
|
-
return row ? row.value : null;
|
|
34
|
+
return key in config ? config[key] : null;
|
|
28
35
|
}
|
|
29
36
|
export function setConfig(key, value) {
|
|
30
|
-
|
|
37
|
+
config[key] = String(value);
|
|
38
|
+
writeJson(CONFIG_FILE, config);
|
|
31
39
|
}
|
|
32
40
|
export function delConfig(key) {
|
|
33
|
-
|
|
41
|
+
delete config[key];
|
|
42
|
+
writeJson(CONFIG_FILE, config);
|
|
34
43
|
}
|
|
35
44
|
export function getAllConfig() {
|
|
36
|
-
|
|
37
|
-
const result = {};
|
|
38
|
-
for (const row of rows)
|
|
39
|
-
result[row.key] = row.value;
|
|
40
|
-
return result;
|
|
45
|
+
return { ...config };
|
|
41
46
|
}
|
|
42
|
-
|
|
43
|
-
db.exec(`
|
|
44
|
-
CREATE TABLE IF NOT EXISTS image_alt_cache (
|
|
45
|
-
url_key TEXT PRIMARY KEY,
|
|
46
|
-
url TEXT NOT NULL,
|
|
47
|
-
alt TEXT NOT NULL,
|
|
48
|
-
source TEXT,
|
|
49
|
-
updated_at INTEGER NOT NULL
|
|
50
|
-
);
|
|
51
|
-
`);
|
|
52
|
-
const stmtAltGet = db.prepare("SELECT url_key, url, alt, source, updated_at FROM image_alt_cache WHERE url_key = ?");
|
|
53
|
-
const stmtAltSet = db.prepare(`
|
|
54
|
-
INSERT INTO image_alt_cache (url_key, url, alt, source, updated_at)
|
|
55
|
-
VALUES (@url_key, @url, @alt, @source, @updated_at)
|
|
56
|
-
ON CONFLICT(url_key) DO UPDATE SET
|
|
57
|
-
url = excluded.url,
|
|
58
|
-
alt = excluded.alt,
|
|
59
|
-
source = excluded.source,
|
|
60
|
-
updated_at = excluded.updated_at
|
|
61
|
-
`);
|
|
62
|
-
const stmtAltList = db.prepare("SELECT url_key, url, alt, source, updated_at FROM image_alt_cache ORDER BY updated_at DESC LIMIT ? OFFSET ?");
|
|
63
|
-
const stmtAltCount = db.prepare("SELECT COUNT(*) AS n FROM image_alt_cache");
|
|
47
|
+
const altCache = readJson(ALT_FILE, {});
|
|
64
48
|
export function getImageAlt(urlKey) {
|
|
65
|
-
return
|
|
49
|
+
return altCache[urlKey] || null;
|
|
66
50
|
}
|
|
67
51
|
export function getImageAlts(urlKeys) {
|
|
68
52
|
const out = new Map();
|
|
69
53
|
for (const k of urlKeys) {
|
|
70
|
-
const row =
|
|
54
|
+
const row = altCache[k];
|
|
71
55
|
if (row)
|
|
72
56
|
out.set(k, row);
|
|
73
57
|
}
|
|
74
58
|
return out;
|
|
75
59
|
}
|
|
76
60
|
export function setImageAlt({ url_key, url, alt, source = "ai" }) {
|
|
77
|
-
|
|
61
|
+
altCache[url_key] = { url_key, url, alt, source, updated_at: Date.now() };
|
|
62
|
+
writeJson(ALT_FILE, altCache);
|
|
78
63
|
}
|
|
79
|
-
export
|
|
64
|
+
export function setImageAlts(items) {
|
|
80
65
|
for (const it of items) {
|
|
81
|
-
|
|
66
|
+
altCache[it.url_key] = {
|
|
82
67
|
url_key: it.url_key,
|
|
83
68
|
url: it.url,
|
|
84
69
|
alt: it.alt,
|
|
85
70
|
source: it.source || "ai",
|
|
86
71
|
updated_at: Date.now(),
|
|
87
|
-
}
|
|
72
|
+
};
|
|
88
73
|
}
|
|
89
|
-
|
|
74
|
+
writeJson(ALT_FILE, altCache);
|
|
75
|
+
}
|
|
90
76
|
export function listImageAlts(limit = 100, offset = 0) {
|
|
91
|
-
return
|
|
77
|
+
return Object.values(altCache)
|
|
78
|
+
.sort((a, b) => b.updated_at - a.updated_at)
|
|
79
|
+
.slice(offset, offset + limit);
|
|
92
80
|
}
|
|
93
81
|
export function countImageAlts() {
|
|
94
|
-
return
|
|
82
|
+
return Object.keys(altCache).length;
|
|
95
83
|
}
|
|
96
|
-
export default db;
|
package/dist/legal.js
CHANGED
|
@@ -18,7 +18,7 @@ function page(title, bodyHtml) {
|
|
|
18
18
|
h1{font-size:1.9rem;margin:0 0 4px}
|
|
19
19
|
h2{font-size:1.2rem;margin:32px 0 8px}
|
|
20
20
|
.meta{color:#64748b;font-size:.9rem;margin-bottom:28px}
|
|
21
|
-
a{color:#
|
|
21
|
+
a{color:#108B67}
|
|
22
22
|
code{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;background:rgba(127,127,127,.15);padding:1px 5px;border-radius:4px}
|
|
23
23
|
ul{padding-left:22px}
|
|
24
24
|
footer{margin-top:48px;padding-top:20px;border-top:1px solid rgba(127,127,127,.25);color:#64748b;font-size:.85rem}
|
|
@@ -55,7 +55,7 @@ handles, why, who receives it, and how long it is kept.</p>
|
|
|
55
55
|
tokens are never written to disk by the connector. Access tokens expire automatically after ~1 hour, refresh
|
|
56
56
|
tokens after ~30 days. A server restart clears all tokens.</li>
|
|
57
57
|
<li><strong>Local CLI config (stdio mode).</strong> When you run <code>npx webcake-storefront-mcp login</code>,
|
|
58
|
-
your token and session ID are saved to a local
|
|
58
|
+
your token and session ID are saved to a local file on <em>your own machine</em> (at
|
|
59
59
|
<code>~/.webcake-storefront-mcp.db</code> or similar). This file stays on your device and is not transmitted
|
|
60
60
|
anywhere by the connector.</li>
|
|
61
61
|
<li>The connector does <strong>not</strong> run an analytics database, does <strong>not</strong> sell or share
|
package/dist/tools/context.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { getConfig, setConfig } from "../db.js";
|
|
3
|
-
/** Read all saved credentials from
|
|
3
|
+
/** Read all saved credentials from the local config file for startup */
|
|
4
4
|
export function getSavedConfig() {
|
|
5
5
|
return {
|
|
6
6
|
token: getConfig("token") || "",
|
|
@@ -118,7 +118,7 @@ Get token and session_id from browser DevTools → Network tab → copy from any
|
|
|
118
118
|
api.baseUrl = oldBaseUrl;
|
|
119
119
|
throw new Error("Authentication failed — credentials were NOT changed. Make sure token and session_id are both correct.");
|
|
120
120
|
}
|
|
121
|
-
// Persist all to
|
|
121
|
+
// Persist all to the local config file
|
|
122
122
|
if (token)
|
|
123
123
|
setConfig("token", token);
|
|
124
124
|
if (session_id)
|
package/dist/tools/images.js
CHANGED
|
@@ -606,7 +606,7 @@ If alt_path is omitted, it is auto-detected via the same probe used by list_imag
|
|
|
606
606
|
}));
|
|
607
607
|
// ── Alt cache tools ──
|
|
608
608
|
server.tool("get_cached_image_alts", `Look up cached alt descriptions for image URLs. URLs are matched by normalized form (query string stripped, lowercase). Use BEFORE running read_image/OCR — skip already-described URLs.
|
|
609
|
-
When MONGO_URI is set, misses are then checked against MongoDB and successful hits are backfilled into the local
|
|
609
|
+
When MONGO_URI is set, misses are then checked against MongoDB and successful hits are backfilled into the local cache for fast re-lookup.`, {
|
|
610
610
|
urls: z.array(z.string()).min(1).describe("Image URLs to look up"),
|
|
611
611
|
}, ({ urls }) => handle(async () => {
|
|
612
612
|
const hits = [];
|
|
@@ -693,7 +693,7 @@ When MONGO_URI is set, misses are then checked against MongoDB and successful hi
|
|
|
693
693
|
return { total, count: rows.length, entries: rows };
|
|
694
694
|
}));
|
|
695
695
|
// ── Mongo sync (active when MONGO_URI is set) ──
|
|
696
|
-
server.tool("sync_image_alts_to_mongo", `Push local
|
|
696
|
+
server.tool("sync_image_alts_to_mongo", `Push local alt cache entries up to MongoDB. Bulk upsert keyed by url_key. Use when you want to back up local-only entries to the shared central store, or after a session of heavy AI describes.
|
|
697
697
|
Requires MONGO_URI env var.`, {
|
|
698
698
|
limit: z.number().default(1000).describe("Max entries to push per call"),
|
|
699
699
|
offset: z.number().default(0).describe("Offset into local cache"),
|
|
@@ -706,7 +706,7 @@ Requires MONGO_URI env var.`, {
|
|
|
706
706
|
const res = await mongoUpsertAlts(rows.map((r) => ({ url_key: r.url_key, url: r.url, alt: r.alt, source: r.source })));
|
|
707
707
|
return { pushed: rows.length, ...res, total_local: countImageAlts() };
|
|
708
708
|
}));
|
|
709
|
-
server.tool("sync_image_alts_from_mongo", `Pull MongoDB alt entries down into local
|
|
709
|
+
server.tool("sync_image_alts_from_mongo", `Pull MongoDB alt entries down into local cache. Useful when starting on a new machine/site to warm the local cache from the central store.
|
|
710
710
|
Requires MONGO_URI env var.`, {
|
|
711
711
|
limit: z.number().default(1000).describe("Max entries to pull"),
|
|
712
712
|
offset: z.number().default(0).describe("Offset into Mongo collection"),
|
package/dist/web-guide.js
CHANGED
|
@@ -24,8 +24,8 @@ const DOCS_URL = `${GITHUB_URL}#readme`;
|
|
|
24
24
|
const ICON_SVG = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
|
|
25
25
|
<rect width="32" height="32" rx="7" fill="url(#sg)"/>
|
|
26
26
|
<defs><linearGradient id="sg" x1="0" y1="0" x2="1" y2="1">
|
|
27
|
-
<stop offset="0%" stop-color="#
|
|
28
|
-
<stop offset="100%" stop-color="#
|
|
27
|
+
<stop offset="0%" stop-color="#108B67"/>
|
|
28
|
+
<stop offset="100%" stop-color="#14a87c"/>
|
|
29
29
|
</linearGradient></defs>
|
|
30
30
|
<text x="16" y="22" text-anchor="middle" font-family="system-ui,sans-serif" font-weight="700" font-size="17" fill="white">S</text>
|
|
31
31
|
<circle cx="24" cy="9" r="4" fill="#FFD591"/>
|
|
@@ -518,7 +518,7 @@ export function guideHtml(origin, lang = "vi") {
|
|
|
518
518
|
<meta name="keywords" content="${m.keywords}">
|
|
519
519
|
<meta name="author" content="WebCake">
|
|
520
520
|
<meta name="robots" content="index,follow">
|
|
521
|
-
<meta name="theme-color" content="#
|
|
521
|
+
<meta name="theme-color" content="#108B67">
|
|
522
522
|
<link rel="canonical" href="${canonical}">
|
|
523
523
|
<link rel="alternate" hreflang="vi" href="${origin}/">
|
|
524
524
|
<link rel="alternate" hreflang="en" href="${origin}/?lang=en">
|
|
@@ -543,13 +543,13 @@ export function guideHtml(origin, lang = "vi") {
|
|
|
543
543
|
<meta name="twitter:image:alt" content="${m.title}">
|
|
544
544
|
<script type="application/ld+json">${jsonLdScript}</script>
|
|
545
545
|
<style>
|
|
546
|
-
:root{--g:#
|
|
546
|
+
:root{--g:#108B67;--g7:#0c6f52;--ink:#11121e;--mut:#5e5f7a;--bg:#f6f5ff;--card:#ffffff;
|
|
547
547
|
--line:rgba(16,14,40,.09);--shadow:0 1px 2px rgba(16,14,40,.05),0 6px 20px -12px rgba(16,14,40,.18);--code:#0e0d1a;
|
|
548
|
-
--ic-fg:#
|
|
548
|
+
--ic-fg:#0c6f52;--btn-hover:#0c6f52;--navbg:rgba(246,245,255,.82)}
|
|
549
549
|
@media(prefers-color-scheme:dark){:root:not([data-theme="light"]){--ink:#e8e6ff;--mut:#9a98b8;--bg:#0c0b14;--card:#141320;
|
|
550
|
-
--line:rgba(255,255,255,.07);--shadow:0 1px 2px rgba(0,0,0,.3),0 8px 24px -14px rgba(0,0,0,.7);--code:#07060f;--g7:#
|
|
550
|
+
--line:rgba(255,255,255,.07);--shadow:0 1px 2px rgba(0,0,0,.3),0 8px 24px -14px rgba(0,0,0,.7);--code:#07060f;--g7:#5fe0b3;--ic-fg:#8aecc9;--btn-hover:#16a07a;--navbg:rgba(12,11,20,.82)}}
|
|
551
551
|
:root[data-theme="dark"]{--ink:#e8e6ff;--mut:#9a98b8;--bg:#0c0b14;--card:#141320;
|
|
552
|
-
--line:rgba(255,255,255,.07);--shadow:0 1px 2px rgba(0,0,0,.3),0 8px 24px -14px rgba(0,0,0,.7);--code:#07060f;--g7:#
|
|
552
|
+
--line:rgba(255,255,255,.07);--shadow:0 1px 2px rgba(0,0,0,.3),0 8px 24px -14px rgba(0,0,0,.7);--code:#07060f;--g7:#5fe0b3;--ic-fg:#8aecc9;--btn-hover:#16a07a;--navbg:rgba(12,11,20,.82)}
|
|
553
553
|
*{box-sizing:border-box}
|
|
554
554
|
html{scroll-behavior:auto}
|
|
555
555
|
html.smooth{scroll-behavior:smooth}
|
|
@@ -557,8 +557,8 @@ export function guideHtml(origin, lang = "vi") {
|
|
|
557
557
|
background:var(--bg);line-height:1.62;overflow-x:hidden}
|
|
558
558
|
.blobs{position:fixed;inset:0;z-index:-1;overflow:hidden;pointer-events:none}
|
|
559
559
|
.blobs b{position:absolute;border-radius:50%;filter:blur(90px);opacity:.16;will-change:transform}
|
|
560
|
-
.blobs b:nth-child(1){width:560px;height:560px;right:-160px;top:-180px;background:radial-gradient(circle,#
|
|
561
|
-
.blobs b:nth-child(2){width:440px;height:440px;left:-160px;bottom:-160px;background:radial-gradient(circle,#
|
|
560
|
+
.blobs b:nth-child(1){width:560px;height:560px;right:-160px;top:-180px;background:radial-gradient(circle,#108B67,transparent 70%);animation:drift1 40s ease-in-out infinite}
|
|
561
|
+
.blobs b:nth-child(2){width:440px;height:440px;left:-160px;bottom:-160px;background:radial-gradient(circle,#14a87c,transparent 70%);animation:drift2 48s ease-in-out infinite}
|
|
562
562
|
@keyframes drift1{50%{transform:translate(-50px,60px)}}
|
|
563
563
|
@keyframes drift2{50%{transform:translate(40px,-50px)}}
|
|
564
564
|
.wrap{max-width:900px;margin:0 auto;padding:48px 20px 72px}
|
|
@@ -568,7 +568,7 @@ export function guideHtml(origin, lang = "vi") {
|
|
|
568
568
|
transition:box-shadow .2s ease,border-color .2s ease}
|
|
569
569
|
header{display:flex;align-items:center;gap:14px;margin-bottom:14px}
|
|
570
570
|
header .logo{width:50px;height:50px;border-radius:14px;overflow:hidden;flex:0 0 auto;
|
|
571
|
-
box-shadow:0 6px 16px -4px rgba(
|
|
571
|
+
box-shadow:0 6px 16px -4px rgba(16,139,103,.4)}
|
|
572
572
|
header .logo svg{width:100%;height:100%;display:block}
|
|
573
573
|
.hgrow{flex:1 1 auto;min-width:0}
|
|
574
574
|
.controls{margin-left:auto;flex:0 0 auto;display:flex;align-items:center;gap:8px}
|
|
@@ -583,16 +583,16 @@ export function guideHtml(origin, lang = "vi") {
|
|
|
583
583
|
.sub{color:var(--mut);margin:3px 0 0;font-size:.98rem}
|
|
584
584
|
.lead{font-size:1.16rem;margin:20px 0 18px;max-width:60ch}
|
|
585
585
|
.lead b{color:var(--ink)}
|
|
586
|
-
.grad{background:linear-gradient(95deg,#
|
|
586
|
+
.grad{background:linear-gradient(95deg,#108B67,#14a87c 60%,#3fcf9e);-webkit-background-clip:text;background-clip:text;color:transparent;
|
|
587
587
|
background-size:200% auto;animation:shim 7s linear infinite}
|
|
588
588
|
@keyframes shim{to{background-position:200% center}}
|
|
589
589
|
.pill{display:inline-flex;align-items:center;gap:8px;padding:6px 14px;border-radius:999px;font-size:.82rem;font-weight:600;
|
|
590
|
-
color:var(--g7);background:rgba(
|
|
591
|
-
.dot{width:8px;height:8px;border-radius:50%;background:var(--g);box-shadow:0 0 0 0 rgba(
|
|
592
|
-
@keyframes pulse{70%{box-shadow:0 0 0 7px rgba(
|
|
590
|
+
color:var(--g7);background:rgba(16,139,103,.10);border:1px solid var(--line)}
|
|
591
|
+
.dot{width:8px;height:8px;border-radius:50%;background:var(--g);box-shadow:0 0 0 0 rgba(16,139,103,.5);animation:pulse 2s infinite}
|
|
592
|
+
@keyframes pulse{70%{box-shadow:0 0 0 7px rgba(16,139,103,0)}100%{box-shadow:0 0 0 0 rgba(16,139,103,0)}}
|
|
593
593
|
h2{font-size:1.32rem;margin:46px 0 16px;font-weight:800;letter-spacing:-.01em;scroll-margin-top:72px}
|
|
594
594
|
.ic{width:42px;height:42px;border-radius:12px;display:grid;place-items:center;flex:0 0 auto;color:var(--ic-fg);
|
|
595
|
-
background:rgba(
|
|
595
|
+
background:rgba(16,139,103,.11);border:1px solid var(--line);transition:transform .2s ease}
|
|
596
596
|
.ic .i{width:22px;height:22px}
|
|
597
597
|
.grid{display:grid;gap:16px;grid-template-columns:1fr 1fr}
|
|
598
598
|
.grid-3{display:grid;gap:16px;grid-template-columns:1fr 1fr 1fr}
|
|
@@ -614,7 +614,7 @@ export function guideHtml(origin, lang = "vi") {
|
|
|
614
614
|
transition:background .15s ease,color .15s ease,border-color .15s ease}
|
|
615
615
|
.copy:hover{background:rgba(255,255,255,.13);color:#fff}
|
|
616
616
|
.copy svg{width:15px;height:15px}
|
|
617
|
-
.copy.done{color:#
|
|
617
|
+
.copy.done{color:#5fe0b3;border-color:rgba(95,224,179,.55)}
|
|
618
618
|
.feat{list-style:none;padding:0;margin:0;display:grid;gap:12px}
|
|
619
619
|
.feat li{display:flex;gap:13px;align-items:center;font-size:.97rem;padding:13px 16px}
|
|
620
620
|
.feat li b{color:var(--ink)}
|
|
@@ -626,9 +626,9 @@ export function guideHtml(origin, lang = "vi") {
|
|
|
626
626
|
.flow .node b{font-size:.93rem}
|
|
627
627
|
.flow .node span{font-size:.75rem;color:var(--mut)}
|
|
628
628
|
.flow .wire{flex:1 1 auto;min-width:30px;position:relative;height:2px;margin-top:27px;
|
|
629
|
-
background:linear-gradient(90deg,var(--line),rgba(
|
|
629
|
+
background:linear-gradient(90deg,var(--line),rgba(16,139,103,.45),var(--line))}
|
|
630
630
|
.flow .wire .pkt{position:absolute;top:50%;left:0;width:9px;height:9px;margin:-5px 0 0 -4px;border-radius:50%;
|
|
631
|
-
background:var(--g);box-shadow:0 0 9px 1px rgba(
|
|
631
|
+
background:var(--g);box-shadow:0 0 9px 1px rgba(16,139,103,.7)}
|
|
632
632
|
.flow .wire::after{content:"";position:absolute;right:-1px;top:50%;width:7px;height:7px;margin-top:-4px;
|
|
633
633
|
border-top:2px solid var(--g7);border-right:2px solid var(--g7);transform:rotate(45deg)}
|
|
634
634
|
.flow-cap{color:var(--mut);font-size:.9rem;margin:2px 2px 0;max-width:68ch}
|
|
@@ -638,10 +638,10 @@ export function guideHtml(origin, lang = "vi") {
|
|
|
638
638
|
.flow .node .ic{animation:nodepop 2.4s ease-in-out infinite}
|
|
639
639
|
}
|
|
640
640
|
@media(prefers-reduced-motion:reduce){.flow .wire .pkt{display:none}}
|
|
641
|
-
@keyframes nodepop{0%,100%{box-shadow:none}50%{box-shadow:0 0 0 4px rgba(
|
|
641
|
+
@keyframes nodepop{0%,100%{box-shadow:none}50%{box-shadow:0 0 0 4px rgba(16,139,103,.12)}}
|
|
642
642
|
.btn{display:inline-flex;align-items:center;gap:9px;padding:11px 19px;border-radius:11px;cursor:pointer;
|
|
643
643
|
background:var(--g);color:#fff;text-decoration:none;font-weight:700;font-size:.93rem;
|
|
644
|
-
box-shadow:0 4px 12px -4px rgba(
|
|
644
|
+
box-shadow:0 4px 12px -4px rgba(16,139,103,.5);transition:transform .15s ease,background .15s ease}
|
|
645
645
|
.btn .i{width:18px;height:18px}
|
|
646
646
|
.btn:hover{transform:translateY(-1px);background:var(--btn-hover)}
|
|
647
647
|
.btn.ghost{background:var(--card);color:var(--ink);border:1px solid var(--line);box-shadow:none}
|
|
@@ -652,17 +652,17 @@ export function guideHtml(origin, lang = "vi") {
|
|
|
652
652
|
.nav::-webkit-scrollbar{display:none}
|
|
653
653
|
.nav a{flex:0 0 auto;font-size:.84rem;font-weight:600;color:var(--mut);text-decoration:none;
|
|
654
654
|
padding:7px 13px;border-radius:999px;white-space:nowrap;transition:color .15s ease,background .15s ease}
|
|
655
|
-
.nav a:hover{color:var(--g7);background:rgba(
|
|
656
|
-
.nav a.active{color:var(--g7);background:rgba(
|
|
655
|
+
.nav a:hover{color:var(--g7);background:rgba(16,139,103,.10)}
|
|
656
|
+
.nav a.active{color:var(--g7);background:rgba(16,139,103,.13)}
|
|
657
657
|
.uses{display:grid;gap:14px;grid-template-columns:1fr 1fr;padding:0;margin:0;list-style:none}
|
|
658
658
|
@media(max-width:640px){.uses{grid-template-columns:1fr}}
|
|
659
659
|
.uses li{display:flex;gap:13px;padding:16px 18px;align-items:flex-start;transition:transform .2s ease,border-color .2s ease,box-shadow .2s ease}
|
|
660
|
-
.uses li:hover{transform:translateY(-3px);border-color:rgba(
|
|
660
|
+
.uses li:hover{transform:translateY(-3px);border-color:rgba(16,139,103,.4);box-shadow:0 10px 26px -14px rgba(16,14,40,.4)}
|
|
661
661
|
.uses b{display:block;font-size:.96rem;margin-bottom:2px}
|
|
662
662
|
.uses span{color:var(--mut);font-size:.88rem}
|
|
663
663
|
.card{transition:transform .2s ease,border-color .2s ease,box-shadow .2s ease}
|
|
664
664
|
.card:hover{transform:translateY(-3px);box-shadow:0 10px 26px -14px rgba(16,14,40,.4)}
|
|
665
|
-
.card:hover,.method:hover{border-color:rgba(
|
|
665
|
+
.card:hover,.method:hover{border-color:rgba(16,139,103,.32)}
|
|
666
666
|
.method{margin-bottom:16px;padding:24px}
|
|
667
667
|
.method>.tag{margin-bottom:4px}
|
|
668
668
|
.msub{color:var(--mut);font-size:.92rem;margin:.5rem 0 1.2rem}
|
|
@@ -670,16 +670,16 @@ export function guideHtml(origin, lang = "vi") {
|
|
|
670
670
|
.steps li{display:flex;gap:14px;align-items:flex-start;position:relative}
|
|
671
671
|
.steps li:not(:last-child)::after{content:"";position:absolute;left:13px;top:30px;bottom:-18px;width:2px;background:var(--line)}
|
|
672
672
|
.steps .n{flex:0 0 auto;width:28px;height:28px;border-radius:50%;color:var(--ic-fg);
|
|
673
|
-
background:rgba(
|
|
673
|
+
background:rgba(16,139,103,.12);border:1px solid var(--line);
|
|
674
674
|
font:800 .85rem/1 system-ui;display:flex;align-items:center;justify-content:center}
|
|
675
675
|
.steps .body{flex:1;min-width:0;font-size:.95rem}
|
|
676
676
|
.steps .body pre{margin-top:9px}
|
|
677
677
|
.steps .body .btn{display:flex;width:fit-content;margin-top:10px}
|
|
678
|
-
code.inl{background:rgba(
|
|
678
|
+
code.inl{background:rgba(16,139,103,.13);color:var(--g7);padding:1px 6px;border-radius:6px;font-size:.85em;font-weight:600;
|
|
679
679
|
overflow-wrap:anywhere;word-break:break-word}
|
|
680
680
|
.note{font-size:.86rem;color:var(--mut);margin-top:10px}
|
|
681
681
|
.note + pre,.note + .codewrap{margin-top:9px}
|
|
682
|
-
.tip{margin-top:16px;background:rgba(
|
|
682
|
+
.tip{margin-top:16px;background:rgba(16,139,103,.06);border:1px solid var(--line);border-radius:12px;padding:13px 15px}
|
|
683
683
|
.tip .note{margin:0}
|
|
684
684
|
details{padding:2px 18px;margin-bottom:11px}
|
|
685
685
|
details summary{cursor:pointer;font-weight:600;padding:15px 0;list-style:none;display:flex;align-items:center;gap:10px}
|
|
@@ -690,7 +690,7 @@ export function guideHtml(origin, lang = "vi") {
|
|
|
690
690
|
details p{color:var(--mut);font-size:.92rem;margin:0 0 16px;padding-left:0}
|
|
691
691
|
.star{margin-top:48px;text-align:center;padding:38px 24px;overflow:hidden;position:relative}
|
|
692
692
|
.star::before{content:"";position:absolute;inset:-40% 0 auto;height:70%;
|
|
693
|
-
background:radial-gradient(closest-side,rgba(
|
|
693
|
+
background:radial-gradient(closest-side,rgba(16,139,103,.10),transparent);pointer-events:none}
|
|
694
694
|
.star h2{margin:0 0 6px;position:relative;display:inline-flex;align-items:center;gap:9px;justify-content:center}
|
|
695
695
|
.star h2 .i{color:var(--g7)}
|
|
696
696
|
.star p{color:var(--mut);max-width:48ch;margin:0 auto 18px;position:relative}
|
|
@@ -699,8 +699,6 @@ export function guideHtml(origin, lang = "vi") {
|
|
|
699
699
|
display:flex;gap:18px;flex-wrap:wrap;align-items:center}
|
|
700
700
|
footer a{color:var(--g7);font-weight:600;text-decoration:none;display:inline-flex;align-items:center;gap:6px}
|
|
701
701
|
footer a:hover{text-decoration:underline}
|
|
702
|
-
.badges{display:flex;gap:8px;flex-wrap:wrap;margin:14px 0 4px}
|
|
703
|
-
.badges img{height:20px;border-radius:4px}
|
|
704
702
|
@media(max-width:640px){
|
|
705
703
|
.wrap{padding:30px 15px 56px}
|
|
706
704
|
header{flex-wrap:wrap;gap:12px}
|
|
@@ -757,13 +755,6 @@ export function guideHtml(origin, lang = "vi") {
|
|
|
757
755
|
<a class="btn ghost" href="${GITHUB_URL}">${icon("star")} ${t.ctaStar}</a>
|
|
758
756
|
</div>
|
|
759
757
|
|
|
760
|
-
<div class="badges hero-in">
|
|
761
|
-
<a href="${NPM_URL}" target="_blank" rel="noopener"><img src="https://img.shields.io/npm/v/webcake-storefront-mcp?label=npm&color=6d5efc" alt="npm version"></a>
|
|
762
|
-
<a href="${NPM_URL}" target="_blank" rel="noopener"><img src="https://img.shields.io/npm/dm/webcake-storefront-mcp?color=8b5cf6" alt="npm downloads"></a>
|
|
763
|
-
<a href="${GITHUB_URL}/blob/main/LICENSE" target="_blank" rel="noopener"><img src="https://img.shields.io/badge/license-MIT-blue" alt="MIT license"></a>
|
|
764
|
-
<a href="https://modelcontextprotocol.io" target="_blank" rel="noopener"><img src="https://img.shields.io/badge/Model_Context_Protocol-server-6E56CF" alt="MCP server"></a>
|
|
765
|
-
</div>
|
|
766
|
-
|
|
767
758
|
<nav class="nav" aria-label="${L === "en" ? "Sections" : "Mục lục"}">
|
|
768
759
|
${t.nav.map((n) => `<a href="${n.href}">${n.label}</a>`).join("\n ")}
|
|
769
760
|
</nav>
|
|
@@ -845,8 +836,6 @@ export function guideHtml(origin, lang = "vi") {
|
|
|
845
836
|
<span>Endpoint: <code class="inl">${endpoint}</code></span>
|
|
846
837
|
<a href="${DOCS_URL}">${icon("book")} ${t.footGuide}</a>
|
|
847
838
|
<a href="${GITHUB_URL}">${icon("github")} GitHub</a>
|
|
848
|
-
<a href="${NPM_URL}">${icon("package")} npm</a>
|
|
849
|
-
<a href="${selfPath === "/" ? "/health" : "/health"}">Health</a>
|
|
850
839
|
<a href="/privacy">Privacy</a>
|
|
851
840
|
<a href="/terms">Terms</a>
|
|
852
841
|
</footer>
|
|
@@ -924,7 +913,7 @@ export function ogImageSvg() {
|
|
|
924
913
|
<stop stop-color="#0c0b14"/><stop offset="1" stop-color="#16122a"/>
|
|
925
914
|
</linearGradient>
|
|
926
915
|
<radialGradient id="glow" cx="0" cy="0" r="1" gradientTransform="translate(960 70) rotate(130) scale(620)" gradientUnits="userSpaceOnUse">
|
|
927
|
-
<stop stop-color="#
|
|
916
|
+
<stop stop-color="#108B67" stop-opacity="0.40"/><stop offset="1" stop-color="#108B67" stop-opacity="0"/>
|
|
928
917
|
</radialGradient>
|
|
929
918
|
</defs>
|
|
930
919
|
<rect width="1200" height="630" fill="url(#bg)"/>
|
|
@@ -933,22 +922,22 @@ export function ogImageSvg() {
|
|
|
933
922
|
<svg x="0" y="0" width="80" height="80" viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg">
|
|
934
923
|
<rect width="32" height="32" rx="7" fill="url(#sg2)"/>
|
|
935
924
|
<defs><linearGradient id="sg2" x1="0" y1="0" x2="1" y2="1">
|
|
936
|
-
<stop offset="0%" stop-color="#
|
|
937
|
-
<stop offset="100%" stop-color="#
|
|
925
|
+
<stop offset="0%" stop-color="#108B67"/>
|
|
926
|
+
<stop offset="100%" stop-color="#14a87c"/>
|
|
938
927
|
</linearGradient></defs>
|
|
939
928
|
<text x="16" y="22" text-anchor="middle" font-family="system-ui,sans-serif" font-weight="700" font-size="17" fill="white">S</text>
|
|
940
929
|
<circle cx="24" cy="9" r="4" fill="#FFD591"/>
|
|
941
930
|
</svg>
|
|
942
931
|
<text x="100" y="42" fill="#ffffff" font-size="40" font-weight="800" letter-spacing="-1">WebCake Storefront MCP</text>
|
|
943
|
-
<text x="100" y="74" fill="#
|
|
932
|
+
<text x="100" y="74" fill="#5fe0b3" font-size="22" font-weight="600">Tạo website bán hàng chỉ bằng cách trò chuyện · Build your store just by chatting</text>
|
|
944
933
|
</g>
|
|
945
934
|
<text x="90" y="300" fill="#ffffff" font-size="64" font-weight="800" letter-spacing="-2">Bạn nói điều mình muốn —</text>
|
|
946
935
|
<text x="90" y="380" fill="#ffffff" font-size="64" font-weight="800" letter-spacing="-2">AI dựng trang, kiểm tra,</text>
|
|
947
|
-
<text x="90" y="460" fill="#
|
|
936
|
+
<text x="90" y="460" fill="#108B67" font-size="64" font-weight="800" letter-spacing="-2">đăng lên là xong.</text>
|
|
948
937
|
<text x="90" y="534" fill="#9a98b8" font-size="28" font-weight="500">Không cần kéo-thả · Không cần biết lập trình · Luôn xem trước khi lưu</text>
|
|
949
938
|
<g transform="translate(90 560)">
|
|
950
|
-
<rect width="540" height="52" rx="12" fill="#
|
|
951
|
-
<text x="270" y="34" fill="#ffffff" font-size="22" font-weight="700" text-anchor="middle">
|
|
939
|
+
<rect width="540" height="52" rx="12" fill="#108B67"/>
|
|
940
|
+
<text x="270" y="34" fill="#ffffff" font-size="22" font-weight="700" text-anchor="middle">store.toolvn.io.vn</text>
|
|
952
941
|
</g>
|
|
953
942
|
<text x="1110" y="600" fill="#5b5a7a" font-size="22" font-weight="600" text-anchor="end">github.com/vuluu2k/webcake-storefront-mcp</text>
|
|
954
943
|
</svg>`;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "webcake-storefront-mcp",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.2",
|
|
4
4
|
"description": "MCP server for the WebCake/StoreCake storefront builder — page CRUD, page authoring, products, orders, and more",
|
|
5
5
|
"mcpName": "io.github.vuluu2k/webcake-storefront-mcp",
|
|
6
6
|
"license": "MIT",
|
|
@@ -35,14 +35,12 @@
|
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
37
|
"@modelcontextprotocol/sdk": "^1.12.1",
|
|
38
|
-
"better-sqlite3": "^12.8.0",
|
|
39
38
|
"mongodb": "^6.21.0",
|
|
40
39
|
"node-html-parser": "^8.0.2",
|
|
41
40
|
"sharp": "^0.34.5",
|
|
42
41
|
"zod": "^3.25.0"
|
|
43
42
|
},
|
|
44
43
|
"devDependencies": {
|
|
45
|
-
"@types/better-sqlite3": "^7.6.13",
|
|
46
44
|
"@types/node": "^26.0.0",
|
|
47
45
|
"typescript": "^6.0.3"
|
|
48
46
|
},
|