@ampless/admin 0.2.0-alpha.13 → 0.2.0-alpha.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. package/dist/api/index.d.ts +48 -2
  2. package/dist/api/index.js +405 -0
  3. package/dist/{chunk-C6XF22TC.js → chunk-3EDGG6ST.js} +2 -2
  4. package/dist/{chunk-XXY2GVLV.js → chunk-5VDMBDFB.js} +1 -1
  5. package/dist/{chunk-6ELFL53G.js → chunk-G7B3R6WQ.js} +2 -2
  6. package/dist/{chunk-OWYT37GC.js → chunk-I5S7J7UZ.js} +2 -2
  7. package/dist/{chunk-HP4GCYKQ.js → chunk-IJKYZNII.js} +1 -1
  8. package/dist/{chunk-MXOT7KNC.js → chunk-K4GZPMPL.js} +1 -1
  9. package/dist/{chunk-Y376EYEF.js → chunk-KAMD3SDE.js} +2 -2
  10. package/dist/{chunk-RVMHG4KN.js → chunk-LIGSQETK.js} +120 -24
  11. package/dist/{chunk-76C6OJZU.js → chunk-OYKHRBCF.js} +1 -1
  12. package/dist/chunk-Q7WU724A.js +205 -0
  13. package/dist/{chunk-NZPV2O4C.js → chunk-T3ONEJ6K.js} +2 -2
  14. package/dist/{chunk-3E7CZV6A.js → chunk-WJTZ5BNQ.js} +1 -1
  15. package/dist/{chunk-42LEQGGJ.js → chunk-XFJXMCXX.js} +1 -1
  16. package/dist/{chunk-QQ2LE36O.js → chunk-YECVXCET.js} +64 -0
  17. package/dist/components/admin-dashboard.js +3 -3
  18. package/dist/components/edit-post-view.js +5 -5
  19. package/dist/components/index.d.ts +1 -1
  20. package/dist/components/index.js +8 -8
  21. package/dist/components/login-view.js +3 -3
  22. package/dist/components/mcp-tokens-view.d.ts +5 -0
  23. package/dist/components/mcp-tokens-view.js +9 -0
  24. package/dist/components/media-view.js +5 -5
  25. package/dist/components/new-post-view.js +5 -5
  26. package/dist/components/posts-list-view.js +3 -3
  27. package/dist/components/users-list-view.js +3 -3
  28. package/dist/{i18n-OurZuBHX.d.ts → i18n-B1gZ90FD.d.ts} +97 -0
  29. package/dist/index.d.ts +2 -2
  30. package/dist/index.js +1 -1
  31. package/dist/metafile-esm.json +1 -1
  32. package/dist/pages/index.d.ts +8 -2
  33. package/dist/pages/index.js +35 -17
  34. package/package.json +5 -3
@@ -10,14 +10,14 @@ import {
10
10
  } from "./chunk-7IR4F7GA.js";
11
11
  import {
12
12
  setAdminCmsConfigClient
13
- } from "./chunk-HP4GCYKQ.js";
13
+ } from "./chunk-IJKYZNII.js";
14
14
  import {
15
15
  setAdminMediaContext
16
16
  } from "./chunk-2ITWLRYF.js";
17
17
  import {
18
18
  useLocale,
19
19
  useT
20
- } from "./chunk-MXOT7KNC.js";
20
+ } from "./chunk-K4GZPMPL.js";
21
21
 
22
22
  // src/lib/amplify-client.ts
23
23
  import { Amplify } from "aws-amplify";
@@ -317,6 +317,7 @@ import {
317
317
  Image,
318
318
  Globe,
319
319
  Users,
320
+ Key,
320
321
  LogOut,
321
322
  ExternalLink,
322
323
  Menu,
@@ -329,7 +330,8 @@ var navItems = [
329
330
  { href: "/admin/posts", key: "sidebar.posts", icon: FileText },
330
331
  { href: "/admin/media", key: "sidebar.media", icon: Image },
331
332
  { href: "/admin/sites", key: "sidebar.sites", icon: Globe },
332
- { href: "/admin/users", key: "sidebar.users", icon: Users, adminOnly: true }
333
+ { href: "/admin/users", key: "sidebar.users", icon: Users, adminOnly: true },
334
+ { href: "/admin/mcp-tokens", key: "sidebar.mcpTokens", icon: Key, adminOnly: true }
333
335
  ];
334
336
  function Sidebar({
335
337
  email,
@@ -642,7 +644,7 @@ function SiteSettingsForm({ siteId, initial, fallback }) {
642
644
  }
643
645
 
644
646
  // src/components/theme-settings-form.tsx
645
- import { useState as useState3 } from "react";
647
+ import { useEffect as useEffect2, useState as useState3 } from "react";
646
648
  import { useRouter as useRouter3 } from "next/navigation";
647
649
  import {
648
650
  setSiteSetting as setSiteSetting2,
@@ -651,7 +653,9 @@ import {
651
653
  validateThemeValue,
652
654
  resolveLocalized,
653
655
  parseLinkList,
654
- stringifyLinkList
656
+ stringifyLinkList,
657
+ parseColorPair,
658
+ formatColorPair
655
659
  } from "ampless";
656
660
  import {
657
661
  COLOR_SCHEME_SETTING_KEY,
@@ -820,11 +824,11 @@ function ThemeSettingsForm({
820
824
  /* @__PURE__ */ jsx5(
821
825
  "iframe",
822
826
  {
823
- src: `/?previewTheme=${encodeURIComponent(pendingTheme)}`,
827
+ src: `/?previewTheme=${encodeURIComponent(pendingTheme)}&previewColorScheme=${encodeURIComponent(colorScheme)}`,
824
828
  title: t("theme.previewLabel"),
825
829
  className: "h-[600px] w-full rounded-md border bg-[var(--background)]"
826
830
  },
827
- pendingTheme
831
+ `${pendingTheme}-${colorScheme}`
828
832
  ),
829
833
  /* @__PURE__ */ jsx5("p", { className: "text-xs text-muted-foreground", children: t("theme.previewHint") })
830
834
  ] }),
@@ -1098,11 +1102,79 @@ function ColorField({
1098
1102
  invalid,
1099
1103
  onChange
1100
1104
  }) {
1101
- const effective = value || field.default;
1102
- const hex = useColorAsHex(effective);
1105
+ const parsed = parseColorPair(value);
1106
+ const lightInput = parsed.dark !== null ? parsed.light : value;
1107
+ const darkInput = parsed.dark ?? "";
1108
+ const [showDark, setShowDark] = useState3(parsed.dark !== null);
1109
+ function emit(nextLight, nextDark) {
1110
+ if (!nextDark.trim()) {
1111
+ onChange(nextLight);
1112
+ return;
1113
+ }
1114
+ onChange(formatColorPair(nextLight || field.default, nextDark));
1115
+ }
1116
+ const lightEffective = lightInput || field.default;
1117
+ const darkEffective = darkInput || lightEffective;
1103
1118
  return /* @__PURE__ */ jsxs4("div", { className: "space-y-2", children: [
1104
1119
  labelEl,
1105
1120
  description,
1121
+ /* @__PURE__ */ jsx5(
1122
+ ColorRow,
1123
+ {
1124
+ id,
1125
+ label: showDark ? "Light" : void 0,
1126
+ value: lightInput,
1127
+ effective: lightEffective,
1128
+ placeholder: field.default,
1129
+ ariaLabel: `${typeof field.label === "string" ? field.label : id} (light)`,
1130
+ invalid,
1131
+ onChange: (v) => emit(v, darkInput)
1132
+ }
1133
+ ),
1134
+ showDark ? /* @__PURE__ */ jsx5(
1135
+ ColorRow,
1136
+ {
1137
+ id: `${id}-dark`,
1138
+ label: "Dark",
1139
+ value: darkInput,
1140
+ effective: darkEffective,
1141
+ placeholder: lightEffective,
1142
+ ariaLabel: `${typeof field.label === "string" ? field.label : id} (dark)`,
1143
+ invalid,
1144
+ onChange: (v) => emit(lightInput, v)
1145
+ }
1146
+ ) : null,
1147
+ /* @__PURE__ */ jsx5("div", { className: "flex items-center gap-3 text-xs", children: /* @__PURE__ */ jsx5(
1148
+ "button",
1149
+ {
1150
+ type: "button",
1151
+ className: "text-muted-foreground underline-offset-2 hover:underline",
1152
+ onClick: () => {
1153
+ if (showDark) {
1154
+ setShowDark(false);
1155
+ emit(lightInput, "");
1156
+ } else {
1157
+ setShowDark(true);
1158
+ }
1159
+ },
1160
+ children: showDark ? "\u2212 Remove dark variant" : "+ Add dark variant (optional)"
1161
+ }
1162
+ ) })
1163
+ ] });
1164
+ }
1165
+ function ColorRow({
1166
+ id,
1167
+ label,
1168
+ value,
1169
+ effective,
1170
+ placeholder,
1171
+ ariaLabel,
1172
+ invalid,
1173
+ onChange
1174
+ }) {
1175
+ const hex = useColorAsHex(effective);
1176
+ return /* @__PURE__ */ jsxs4("div", { className: "space-y-1", children: [
1177
+ label ? /* @__PURE__ */ jsx5(Label2, { htmlFor: id, className: "text-xs uppercase tracking-wide text-muted-foreground", children: label }) : null,
1106
1178
  /* @__PURE__ */ jsxs4("div", { className: "flex items-center gap-2", children: [
1107
1179
  /* @__PURE__ */ jsx5(
1108
1180
  "input",
@@ -1111,7 +1183,7 @@ function ColorField({
1111
1183
  value: hex,
1112
1184
  onChange: (e) => onChange(e.target.value),
1113
1185
  className: "h-9 w-12 cursor-pointer rounded border border-input bg-background p-0",
1114
- "aria-label": `${field.label} swatch`
1186
+ "aria-label": `${ariaLabel} swatch`
1115
1187
  }
1116
1188
  ),
1117
1189
  /* @__PURE__ */ jsx5(
@@ -1119,7 +1191,7 @@ function ColorField({
1119
1191
  {
1120
1192
  id,
1121
1193
  value,
1122
- placeholder: field.default,
1194
+ placeholder,
1123
1195
  onChange: (e) => onChange(e.target.value),
1124
1196
  "aria-invalid": invalid,
1125
1197
  className: "font-mono text-xs"
@@ -1140,19 +1212,43 @@ function ColorField({
1140
1212
  ] });
1141
1213
  }
1142
1214
  function useColorAsHex(value) {
1143
- if (typeof document === "undefined") return "#000000";
1144
- const m = /^#([0-9a-fA-F]{6})$/.exec(value);
1145
- if (m) return value.toLowerCase();
1146
- try {
1147
- const ctx = document.createElement("canvas").getContext("2d");
1148
- if (!ctx) return "#000000";
1149
- ctx.fillStyle = "#000000";
1150
- ctx.fillStyle = value;
1151
- const out = ctx.fillStyle;
1152
- return /^#[0-9a-fA-F]{6}$/.test(out) ? out : "#000000";
1153
- } catch {
1154
- return "#000000";
1155
- }
1215
+ const [hex, setHex] = useState3(() => directHex(value) ?? "#000000");
1216
+ useEffect2(() => {
1217
+ const direct = directHex(value);
1218
+ if (direct) {
1219
+ setHex(direct);
1220
+ return;
1221
+ }
1222
+ if (typeof document === "undefined") return;
1223
+ try {
1224
+ const el = document.createElement("span");
1225
+ el.style.color = value;
1226
+ el.style.display = "none";
1227
+ document.body.appendChild(el);
1228
+ const computed = getComputedStyle(el).color;
1229
+ document.body.removeChild(el);
1230
+ const next = rgbStringToHex(computed);
1231
+ if (next) setHex(next);
1232
+ } catch {
1233
+ }
1234
+ }, [value]);
1235
+ return hex;
1236
+ }
1237
+ function directHex(value) {
1238
+ const m = /^#([0-9a-fA-F]{6})$/.exec(value.trim());
1239
+ return m ? value.trim().toLowerCase() : null;
1240
+ }
1241
+ function rgbStringToHex(rgb) {
1242
+ const m = /^rgba?\(\s*(\d+)[\s,]+(\d+)[\s,]+(\d+)/.exec(rgb);
1243
+ if (!m) return null;
1244
+ const r = clampToHex(m[1]);
1245
+ const g = clampToHex(m[2]);
1246
+ const b = clampToHex(m[3]);
1247
+ return `#${r}${g}${b}`;
1248
+ }
1249
+ function clampToHex(s) {
1250
+ const n = Math.max(0, Math.min(255, parseInt(s, 10)));
1251
+ return n.toString(16).padStart(2, "0");
1156
1252
  }
1157
1253
 
1158
1254
  export {
@@ -1,7 +1,7 @@
1
1
  'use client';
2
2
  import {
3
3
  useT
4
- } from "./chunk-MXOT7KNC.js";
4
+ } from "./chunk-K4GZPMPL.js";
5
5
 
6
6
  // src/components/login-view.tsx
7
7
  import { useState } from "react";
@@ -0,0 +1,205 @@
1
+ 'use client';
2
+ import {
3
+ useT
4
+ } from "./chunk-K4GZPMPL.js";
5
+
6
+ // src/components/mcp-tokens-view.tsx
7
+ import { useEffect, useState } from "react";
8
+ import {
9
+ Button,
10
+ Input,
11
+ Label,
12
+ Table,
13
+ TableBody,
14
+ TableCell,
15
+ TableHead,
16
+ TableHeader,
17
+ TableRow
18
+ } from "@ampless/runtime/ui";
19
+ import { jsx, jsxs } from "react/jsx-runtime";
20
+ var TOKENS_URL = "/api/admin/mcp-tokens";
21
+ function McpTokensView() {
22
+ const t = useT();
23
+ const [tokens, setTokens] = useState(null);
24
+ const [loading, setLoading] = useState(true);
25
+ const [loadError, setLoadError] = useState(null);
26
+ const [label, setLabel] = useState("");
27
+ const [role, setRole] = useState("admin");
28
+ const [creating, setCreating] = useState(false);
29
+ const [createError, setCreateError] = useState(null);
30
+ const [createdPlaintext, setCreatedPlaintext] = useState(null);
31
+ const [copied, setCopied] = useState(false);
32
+ async function loadTokens() {
33
+ setLoading(true);
34
+ setLoadError(null);
35
+ try {
36
+ const res = await fetch(TOKENS_URL);
37
+ if (!res.ok) {
38
+ const body2 = await res.json().catch(() => ({}));
39
+ throw new Error(body2.error ?? `HTTP ${res.status}`);
40
+ }
41
+ const body = await res.json();
42
+ setTokens(body.tokens);
43
+ } catch (err) {
44
+ console.error("[mcp-tokens] load failed", err);
45
+ setLoadError(err instanceof Error ? err.message : String(err));
46
+ } finally {
47
+ setLoading(false);
48
+ }
49
+ }
50
+ useEffect(() => {
51
+ void loadTokens();
52
+ }, []);
53
+ async function createToken(e) {
54
+ e.preventDefault();
55
+ if (!label.trim()) return;
56
+ setCreating(true);
57
+ setCreateError(null);
58
+ try {
59
+ const res = await fetch(TOKENS_URL, {
60
+ method: "POST",
61
+ headers: { "Content-Type": "application/json" },
62
+ body: JSON.stringify({ label: label.trim(), role })
63
+ });
64
+ if (!res.ok) {
65
+ const body2 = await res.json().catch(() => ({}));
66
+ throw new Error(body2.error ?? `HTTP ${res.status}`);
67
+ }
68
+ const body = await res.json();
69
+ setCreatedPlaintext(body.token);
70
+ setLabel("");
71
+ void loadTokens();
72
+ } catch (err) {
73
+ console.error("[mcp-tokens] create failed", err);
74
+ setCreateError(err instanceof Error ? err.message : String(err));
75
+ } finally {
76
+ setCreating(false);
77
+ }
78
+ }
79
+ async function revoke(hash) {
80
+ if (!confirm(t("mcpTokens.revokeConfirm"))) return;
81
+ try {
82
+ const res = await fetch(TOKENS_URL, {
83
+ method: "DELETE",
84
+ headers: { "Content-Type": "application/json" },
85
+ body: JSON.stringify({ hash })
86
+ });
87
+ if (!res.ok) {
88
+ const body = await res.json().catch(() => ({}));
89
+ throw new Error(body.error ?? `HTTP ${res.status}`);
90
+ }
91
+ void loadTokens();
92
+ } catch (err) {
93
+ console.error("[mcp-tokens] revoke failed", err);
94
+ alert(err instanceof Error ? err.message : String(err));
95
+ }
96
+ }
97
+ async function copyToClipboard() {
98
+ if (!createdPlaintext) return;
99
+ try {
100
+ await navigator.clipboard.writeText(createdPlaintext);
101
+ setCopied(true);
102
+ setTimeout(() => setCopied(false), 1500);
103
+ } catch (err) {
104
+ console.warn("[mcp-tokens] clipboard write failed", err);
105
+ }
106
+ }
107
+ return /* @__PURE__ */ jsxs("div", { className: "mx-auto max-w-4xl space-y-8 p-4 md:p-8", children: [
108
+ /* @__PURE__ */ jsxs("div", { children: [
109
+ /* @__PURE__ */ jsx("h1", { className: "text-2xl font-bold md:text-3xl", children: t("mcpTokens.title") }),
110
+ /* @__PURE__ */ jsx("p", { className: "mt-1 text-sm text-muted-foreground", children: t("mcpTokens.description") })
111
+ ] }),
112
+ /* @__PURE__ */ jsxs("section", { className: "rounded-md border bg-card p-4 md:p-6", children: [
113
+ /* @__PURE__ */ jsx("h2", { className: "text-lg font-semibold", children: t("mcpTokens.createTitle") }),
114
+ /* @__PURE__ */ jsx("p", { className: "mt-1 text-xs text-muted-foreground", children: t("mcpTokens.createHint") }),
115
+ /* @__PURE__ */ jsxs("form", { onSubmit: createToken, className: "mt-4 space-y-3", children: [
116
+ /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
117
+ /* @__PURE__ */ jsx(Label, { htmlFor: "mcp-label", children: t("mcpTokens.labelLabel") }),
118
+ /* @__PURE__ */ jsx(
119
+ Input,
120
+ {
121
+ id: "mcp-label",
122
+ value: label,
123
+ placeholder: t("mcpTokens.labelPlaceholder"),
124
+ onChange: (e) => setLabel(e.target.value),
125
+ maxLength: 80
126
+ }
127
+ )
128
+ ] }),
129
+ /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
130
+ /* @__PURE__ */ jsx(Label, { htmlFor: "mcp-role", children: t("mcpTokens.roleLabel") }),
131
+ /* @__PURE__ */ jsxs(
132
+ "select",
133
+ {
134
+ id: "mcp-role",
135
+ className: "w-full rounded-md border bg-background px-2 py-1.5 text-sm",
136
+ value: role,
137
+ onChange: (e) => setRole(e.target.value === "editor" ? "editor" : "admin"),
138
+ children: [
139
+ /* @__PURE__ */ jsx("option", { value: "admin", children: t("mcpTokens.roleAdmin") }),
140
+ /* @__PURE__ */ jsx("option", { value: "editor", children: t("mcpTokens.roleEditor") })
141
+ ]
142
+ }
143
+ )
144
+ ] }),
145
+ createError && /* @__PURE__ */ jsx("p", { className: "text-sm text-destructive", children: createError }),
146
+ /* @__PURE__ */ jsx(Button, { type: "submit", disabled: creating || !label.trim(), children: creating ? t("mcpTokens.creating") : t("mcpTokens.createButton") })
147
+ ] })
148
+ ] }),
149
+ /* @__PURE__ */ jsxs("section", { className: "space-y-3", children: [
150
+ /* @__PURE__ */ jsx("h2", { className: "text-lg font-semibold", children: t("mcpTokens.listTitle") }),
151
+ loading ? /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: t("mcpTokens.loading") }) : loadError ? /* @__PURE__ */ jsxs("p", { className: "text-sm text-destructive", children: [
152
+ t("mcpTokens.error"),
153
+ ": ",
154
+ loadError
155
+ ] }) : !tokens || tokens.length === 0 ? /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: t("mcpTokens.listEmpty") }) : /* @__PURE__ */ jsx("div", { className: "rounded-md border", children: /* @__PURE__ */ jsxs(Table, { children: [
156
+ /* @__PURE__ */ jsx(TableHeader, { children: /* @__PURE__ */ jsxs(TableRow, { children: [
157
+ /* @__PURE__ */ jsx(TableHead, { children: t("mcpTokens.columnLabel") }),
158
+ /* @__PURE__ */ jsx(TableHead, { children: t("mcpTokens.columnRole") }),
159
+ /* @__PURE__ */ jsx(TableHead, { children: t("mcpTokens.columnCreated") }),
160
+ /* @__PURE__ */ jsx(TableHead, { children: t("mcpTokens.columnLastUsed") }),
161
+ /* @__PURE__ */ jsx(TableHead, { children: t("mcpTokens.columnActions") })
162
+ ] }) }),
163
+ /* @__PURE__ */ jsx(TableBody, { children: tokens.map((tok) => /* @__PURE__ */ jsxs(TableRow, { children: [
164
+ /* @__PURE__ */ jsx(TableCell, { className: "font-medium", children: tok.label }),
165
+ /* @__PURE__ */ jsx(TableCell, { children: tok.role === "admin" ? t("mcpTokens.roleAdmin") : t("mcpTokens.roleEditor") }),
166
+ /* @__PURE__ */ jsx(TableCell, { className: "text-xs text-muted-foreground", children: new Date(tok.createdAt).toLocaleString() }),
167
+ /* @__PURE__ */ jsx(TableCell, { className: "text-xs text-muted-foreground", children: tok.lastUsedAt ? new Date(tok.lastUsedAt).toLocaleString() : t("mcpTokens.lastUsedNever") }),
168
+ /* @__PURE__ */ jsx(TableCell, { children: /* @__PURE__ */ jsx(
169
+ Button,
170
+ {
171
+ type: "button",
172
+ variant: "outline",
173
+ size: "sm",
174
+ onClick: () => revoke(tok.hash),
175
+ children: t("mcpTokens.revoke")
176
+ }
177
+ ) })
178
+ ] }, tok.hash)) })
179
+ ] }) })
180
+ ] }),
181
+ createdPlaintext && /* @__PURE__ */ jsx("div", { className: "fixed inset-0 z-50 flex items-center justify-center bg-black/50 p-4", children: /* @__PURE__ */ jsxs("div", { className: "w-full max-w-2xl rounded-md border bg-card p-6 shadow-lg", children: [
182
+ /* @__PURE__ */ jsx("h3", { className: "text-lg font-semibold", children: t("mcpTokens.createdTitle") }),
183
+ /* @__PURE__ */ jsx("p", { className: "mt-2 text-sm text-muted-foreground", children: t("mcpTokens.createdHint") }),
184
+ /* @__PURE__ */ jsx("div", { className: "mt-4 rounded-md border bg-muted/50 p-3", children: /* @__PURE__ */ jsx("code", { className: "block break-all font-mono text-xs", children: createdPlaintext }) }),
185
+ /* @__PURE__ */ jsxs("div", { className: "mt-4 flex justify-end gap-2", children: [
186
+ /* @__PURE__ */ jsx(Button, { type: "button", variant: "outline", onClick: () => void copyToClipboard(), children: copied ? t("mcpTokens.copied") : t("mcpTokens.copy") }),
187
+ /* @__PURE__ */ jsx(
188
+ Button,
189
+ {
190
+ type: "button",
191
+ onClick: () => {
192
+ setCreatedPlaintext(null);
193
+ setCopied(false);
194
+ },
195
+ children: t("mcpTokens.close")
196
+ }
197
+ )
198
+ ] })
199
+ ] }) })
200
+ ] });
201
+ }
202
+
203
+ export {
204
+ McpTokensView
205
+ };
@@ -1,13 +1,13 @@
1
1
  'use client';
2
2
  import {
3
3
  PostForm
4
- } from "./chunk-C6XF22TC.js";
4
+ } from "./chunk-3EDGG6ST.js";
5
5
  import {
6
6
  readAdminSiteIdFromCookie
7
7
  } from "./chunk-TZWSXAHD.js";
8
8
  import {
9
9
  useT
10
- } from "./chunk-MXOT7KNC.js";
10
+ } from "./chunk-K4GZPMPL.js";
11
11
 
12
12
  // src/components/edit-post-view.tsx
13
13
  import { useEffect, useState, use } from "react";
@@ -4,7 +4,7 @@ import {
4
4
  } from "./chunk-TZWSXAHD.js";
5
5
  import {
6
6
  useT
7
- } from "./chunk-MXOT7KNC.js";
7
+ } from "./chunk-K4GZPMPL.js";
8
8
 
9
9
  // src/components/posts-list-view.tsx
10
10
  import { useEffect, useState } from "react";
@@ -1,7 +1,7 @@
1
1
  'use client';
2
2
  import {
3
3
  useT
4
- } from "./chunk-MXOT7KNC.js";
4
+ } from "./chunk-K4GZPMPL.js";
5
5
 
6
6
  // src/components/users-list-view.tsx
7
7
  import { useEffect, useState } from "react";
@@ -35,6 +35,7 @@ var en_default = {
35
35
  media: "Media",
36
36
  sites: "Sites",
37
37
  users: "Users",
38
+ mcpTokens: "MCP tokens",
38
39
  viewSite: "View site",
39
40
  signOut: "Sign out",
40
41
  site: "Site",
@@ -183,6 +184,37 @@ var en_default = {
183
184
  roleNone: "None"
184
185
  }
185
186
  },
187
+ mcpTokens: {
188
+ title: "MCP tokens",
189
+ description: "Access tokens for the MCP HTTP endpoint at /api/mcp. Use them in Claude Desktop / Cursor / any MCP-aware client to read and write this CMS over the wire.",
190
+ setupMissing: "MCP service Cognito user not configured. Set AMPLESS_MCP_SERVICE_EMAIL and AMPLESS_MCP_SERVICE_PASSWORD as Amplify Hosting environment variables and redeploy. See docs/mcp-http-setup.md.",
191
+ createTitle: "Create token",
192
+ createHint: "Pick a memorable label so you can revoke this token later. Role limits what the token can do \u2014 admin can delete posts, editor cannot.",
193
+ labelLabel: "Label",
194
+ labelPlaceholder: "Claude Desktop \u2014 laptop",
195
+ roleLabel: "Role",
196
+ roleAdmin: "Admin (all tools incl. delete)",
197
+ roleEditor: "Editor (cannot delete)",
198
+ createButton: "Generate token",
199
+ creating: "Generating...",
200
+ createdTitle: "Token created \u2014 copy it now",
201
+ createdHint: "This is the only time the plaintext token will be shown. Copy it into your MCP client config; if you lose it, revoke this token and generate a fresh one.",
202
+ copy: "Copy",
203
+ copied: "Copied!",
204
+ close: "Close",
205
+ listTitle: "Active tokens",
206
+ listEmpty: "No tokens issued yet.",
207
+ columnLabel: "Label",
208
+ columnRole: "Role",
209
+ columnCreated: "Created",
210
+ columnLastUsed: "Last used",
211
+ columnActions: "Actions",
212
+ lastUsedNever: "Never",
213
+ revoke: "Revoke",
214
+ revokeConfirm: "Revoke this token? Clients using it will start getting 401 immediately.",
215
+ loading: "Loading tokens...",
216
+ error: "Failed to load tokens"
217
+ },
186
218
  theme: {
187
219
  title: "Theme",
188
220
  activeLabel: "Active theme",
@@ -313,6 +345,7 @@ var ja_default = {
313
345
  media: "\u30E1\u30C7\u30A3\u30A2",
314
346
  sites: "\u30B5\u30A4\u30C8",
315
347
  users: "\u30E6\u30FC\u30B6\u30FC",
348
+ mcpTokens: "MCP\u30C8\u30FC\u30AF\u30F3",
316
349
  viewSite: "\u30B5\u30A4\u30C8\u3092\u8868\u793A",
317
350
  signOut: "\u30B5\u30A4\u30F3\u30A2\u30A6\u30C8",
318
351
  site: "\u30B5\u30A4\u30C8",
@@ -461,6 +494,37 @@ var ja_default = {
461
494
  roleNone: "\u306A\u3057"
462
495
  }
463
496
  },
497
+ mcpTokens: {
498
+ title: "MCP\u30C8\u30FC\u30AF\u30F3",
499
+ description: "/api/mcp \u306E HTTP MCP \u30A8\u30F3\u30C9\u30DD\u30A4\u30F3\u30C8\u3067\u4F7F\u3046\u30A2\u30AF\u30BB\u30B9\u30C8\u30FC\u30AF\u30F3\u3002Claude Desktop / Cursor \u306A\u3069\u306E MCP \u5BFE\u5FDC\u30AF\u30E9\u30A4\u30A2\u30F3\u30C8\u306B\u767B\u9332\u3059\u308B\u3068\u3001AI \u304B\u3089\u3053\u306E CMS \u3092\u8AAD\u307F\u66F8\u304D\u3067\u304D\u308B\u3088\u3046\u306B\u306A\u308A\u307E\u3059\u3002",
500
+ setupMissing: "MCP \u30B5\u30FC\u30D3\u30B9 Cognito \u30E6\u30FC\u30B6\u30FC\u304C\u672A\u8A2D\u5B9A\u3067\u3059\u3002Amplify Hosting \u306E\u74B0\u5883\u5909\u6570 AMPLESS_MCP_SERVICE_EMAIL \u3068 AMPLESS_MCP_SERVICE_PASSWORD \u3092\u8A2D\u5B9A\u3057\u3066\u518D\u30C7\u30D7\u30ED\u30A4\u3057\u3066\u304F\u3060\u3055\u3044\u3002\u8A73\u7D30\u306F docs/mcp-http-setup.md \u3092\u53C2\u7167\u3002",
501
+ createTitle: "\u30C8\u30FC\u30AF\u30F3\u4F5C\u6210",
502
+ createHint: "\u5F8C\u3067\u53D6\u308A\u6D88\u3057\u3084\u3059\u3044\u3088\u3046\u3001\u7528\u9014\u304C\u308F\u304B\u308B\u30E9\u30D9\u30EB\u3092\u4ED8\u3051\u3066\u304F\u3060\u3055\u3044\u3002\u30ED\u30FC\u30EB\u306F\u6A29\u9650\u3092\u5236\u9650\u3057\u307E\u3059 \u2014 admin \u306F\u524A\u9664\u3082\u53EF\u3001editor \u306F\u524A\u9664\u4E0D\u53EF\u3002",
503
+ labelLabel: "\u30E9\u30D9\u30EB",
504
+ labelPlaceholder: "Claude Desktop \u2014 \u30E9\u30C3\u30D7\u30C8\u30C3\u30D7",
505
+ roleLabel: "\u30ED\u30FC\u30EB",
506
+ roleAdmin: "Admin (\u524A\u9664\u3092\u542B\u3080\u5168\u30C4\u30FC\u30EB)",
507
+ roleEditor: "Editor (\u524A\u9664\u306F\u4E0D\u53EF)",
508
+ createButton: "\u30C8\u30FC\u30AF\u30F3\u751F\u6210",
509
+ creating: "\u751F\u6210\u4E2D...",
510
+ createdTitle: "\u30C8\u30FC\u30AF\u30F3\u3092\u751F\u6210\u3057\u307E\u3057\u305F \u2014 \u4ECA\u3059\u3050\u30B3\u30D4\u30FC\u3057\u3066\u304F\u3060\u3055\u3044",
511
+ createdHint: "\u5E73\u6587\u3092\u8868\u793A\u3059\u308B\u306E\u306F\u3053\u306E 1 \u56DE\u3060\u3051\u3067\u3059\u3002MCP \u30AF\u30E9\u30A4\u30A2\u30F3\u30C8\u306E\u8A2D\u5B9A\u306B\u8CBC\u308A\u4ED8\u3051\u3066\u304F\u3060\u3055\u3044\u3002\u7D1B\u5931\u3057\u305F\u5834\u5408\u306F\u53D6\u308A\u6D88\u3057\u3066\u518D\u767A\u884C\u3057\u3066\u304F\u3060\u3055\u3044\u3002",
512
+ copy: "\u30B3\u30D4\u30FC",
513
+ copied: "\u30B3\u30D4\u30FC\u3057\u307E\u3057\u305F!",
514
+ close: "\u9589\u3058\u308B",
515
+ listTitle: "\u6709\u52B9\u306A\u30C8\u30FC\u30AF\u30F3",
516
+ listEmpty: "\u307E\u3060\u30C8\u30FC\u30AF\u30F3\u3092\u767A\u884C\u3057\u3066\u3044\u307E\u305B\u3093\u3002",
517
+ columnLabel: "\u30E9\u30D9\u30EB",
518
+ columnRole: "\u30ED\u30FC\u30EB",
519
+ columnCreated: "\u4F5C\u6210\u65E5\u6642",
520
+ columnLastUsed: "\u6700\u7D42\u4F7F\u7528",
521
+ columnActions: "\u64CD\u4F5C",
522
+ lastUsedNever: "\u672A\u4F7F\u7528",
523
+ revoke: "\u53D6\u308A\u6D88\u3057",
524
+ revokeConfirm: "\u3053\u306E\u30C8\u30FC\u30AF\u30F3\u3092\u53D6\u308A\u6D88\u3057\u307E\u3059\u304B? \u4F7F\u7528\u4E2D\u306E\u30AF\u30E9\u30A4\u30A2\u30F3\u30C8\u306F\u5373\u5EA7\u306B 401 \u306B\u306A\u308A\u307E\u3059\u3002",
525
+ loading: "\u30C8\u30FC\u30AF\u30F3\u4E00\u89A7\u3092\u8AAD\u307F\u8FBC\u307F\u4E2D...",
526
+ error: "\u30C8\u30FC\u30AF\u30F3\u4E00\u89A7\u306E\u53D6\u5F97\u306B\u5931\u6557\u3057\u307E\u3057\u305F"
527
+ },
464
528
  theme: {
465
529
  title: "\u30C6\u30FC\u30DE",
466
530
  activeLabel: "\u30A2\u30AF\u30C6\u30A3\u30D6\u30C6\u30FC\u30DE",
@@ -1,9 +1,9 @@
1
1
  "use client";
2
2
  import {
3
3
  AdminDashboard
4
- } from "../chunk-XXY2GVLV.js";
5
- import "../chunk-MXOT7KNC.js";
6
- import "../chunk-QQ2LE36O.js";
4
+ } from "../chunk-5VDMBDFB.js";
5
+ import "../chunk-K4GZPMPL.js";
6
+ import "../chunk-YECVXCET.js";
7
7
  export {
8
8
  AdminDashboard
9
9
  };
@@ -1,14 +1,14 @@
1
1
  "use client";
2
2
  import {
3
3
  EditPostPage
4
- } from "../chunk-NZPV2O4C.js";
5
- import "../chunk-C6XF22TC.js";
4
+ } from "../chunk-T3ONEJ6K.js";
5
+ import "../chunk-3EDGG6ST.js";
6
6
  import "../chunk-TZWSXAHD.js";
7
7
  import "../chunk-7IR4F7GA.js";
8
- import "../chunk-HP4GCYKQ.js";
8
+ import "../chunk-IJKYZNII.js";
9
9
  import "../chunk-2ITWLRYF.js";
10
- import "../chunk-MXOT7KNC.js";
11
- import "../chunk-QQ2LE36O.js";
10
+ import "../chunk-K4GZPMPL.js";
11
+ import "../chunk-YECVXCET.js";
12
12
  export {
13
13
  EditPostPage
14
14
  };
@@ -1,5 +1,5 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
- import { L as Locale, D as Dictionary } from '../i18n-OurZuBHX.js';
2
+ import { L as Locale, D as Dictionary } from '../i18n-B1gZ90FD.js';
3
3
  import { Config, Post, ThemeManifest, LocalizedString, MediaProcessingDefaults } from 'ampless';
4
4
  import { AmplessOutputs, ColorScheme } from '@ampless/runtime';
5
5
  import { ProcessOptions } from 'ampless/media';
@@ -5,19 +5,16 @@ import {
5
5
  SiteSelector,
6
6
  SiteSettingsForm,
7
7
  ThemeSettingsForm
8
- } from "../chunk-RVMHG4KN.js";
8
+ } from "../chunk-LIGSQETK.js";
9
9
  import {
10
10
  invalidateSiteSettingsCache
11
11
  } from "../chunk-VXEVLHGL.js";
12
- import {
13
- MediaUploader
14
- } from "../chunk-Y376EYEF.js";
15
12
  import {
16
13
  MediaPicker,
17
14
  PostForm,
18
15
  sanitizeName,
19
16
  uploadProcessedImage
20
- } from "../chunk-C6XF22TC.js";
17
+ } from "../chunk-3EDGG6ST.js";
21
18
  import {
22
19
  readAdminSiteIdFromCookie,
23
20
  setAdminCmsConfig
@@ -25,9 +22,12 @@ import {
25
22
  import {
26
23
  ADMIN_SITE_COOKIE
27
24
  } from "../chunk-7IR4F7GA.js";
25
+ import {
26
+ MediaUploader
27
+ } from "../chunk-KAMD3SDE.js";
28
28
  import {
29
29
  ImageUploadDialog
30
- } from "../chunk-HP4GCYKQ.js";
30
+ } from "../chunk-IJKYZNII.js";
31
31
  import {
32
32
  publicMediaUrl,
33
33
  setAdminMediaContext
@@ -36,8 +36,8 @@ import {
36
36
  I18nProvider,
37
37
  useLocale,
38
38
  useT
39
- } from "../chunk-MXOT7KNC.js";
40
- import "../chunk-QQ2LE36O.js";
39
+ } from "../chunk-K4GZPMPL.js";
40
+ import "../chunk-YECVXCET.js";
41
41
  export {
42
42
  ADMIN_SITE_COOKIE,
43
43
  AdminProviders,
@@ -1,9 +1,9 @@
1
1
  "use client";
2
2
  import {
3
3
  LoginPage
4
- } from "../chunk-76C6OJZU.js";
5
- import "../chunk-MXOT7KNC.js";
6
- import "../chunk-QQ2LE36O.js";
4
+ } from "../chunk-OYKHRBCF.js";
5
+ import "../chunk-K4GZPMPL.js";
6
+ import "../chunk-YECVXCET.js";
7
7
  export {
8
8
  LoginPage
9
9
  };