@ampless/mcp-server 1.0.0-beta.59 → 1.0.0-beta.60
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 +47 -15
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -452,7 +452,23 @@ var uploadMediaSchema = {
|
|
|
452
452
|
}
|
|
453
453
|
}
|
|
454
454
|
};
|
|
455
|
+
var MIME_TYPE_RE = /^[a-z0-9][a-z0-9!#$&^_.+-]{0,126}\/[a-z0-9][a-z0-9!#$&^_.+-]{0,126}$/i;
|
|
456
|
+
var BLOCKED_MIME_TYPES = /* @__PURE__ */ new Set([
|
|
457
|
+
"text/html",
|
|
458
|
+
"application/xhtml+xml",
|
|
459
|
+
"application/javascript",
|
|
460
|
+
"text/javascript"
|
|
461
|
+
]);
|
|
462
|
+
function assertSafeMimeType(mimeType) {
|
|
463
|
+
if (!MIME_TYPE_RE.test(mimeType)) {
|
|
464
|
+
throw new Error(`upload_media: invalid mimeType: ${JSON.stringify(mimeType)}`);
|
|
465
|
+
}
|
|
466
|
+
if (BLOCKED_MIME_TYPES.has(mimeType.toLowerCase())) {
|
|
467
|
+
throw new Error(`upload_media: mimeType not allowed for public media: ${mimeType}`);
|
|
468
|
+
}
|
|
469
|
+
}
|
|
455
470
|
async function uploadMedia(graphql, storage, args) {
|
|
471
|
+
assertSafeMimeType(args.mimeType);
|
|
456
472
|
const body = Buffer.from(args.base64Data, "base64");
|
|
457
473
|
const key = buildMediaKey(args.filename);
|
|
458
474
|
const putResult = await storage.putObject(key, body, args.mimeType);
|
|
@@ -645,13 +661,16 @@ var GET_BY_ID2 = (
|
|
|
645
661
|
}
|
|
646
662
|
`
|
|
647
663
|
);
|
|
648
|
-
var
|
|
664
|
+
var FIND_BY_SRC = (
|
|
649
665
|
/* GraphQL */
|
|
650
666
|
`
|
|
651
|
-
query
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
667
|
+
query FindMediaBySrc($filter: ModelMediaFilterInput!, $nextToken: String) {
|
|
668
|
+
listMedia(filter: $filter, limit: 100, nextToken: $nextToken) {
|
|
669
|
+
items {
|
|
670
|
+
mediaId
|
|
671
|
+
src
|
|
672
|
+
}
|
|
673
|
+
nextToken
|
|
655
674
|
}
|
|
656
675
|
}
|
|
657
676
|
`
|
|
@@ -720,12 +739,18 @@ async function deleteMedia(graphql, storage, args) {
|
|
|
720
739
|
assertMediaPrefix(src);
|
|
721
740
|
}
|
|
722
741
|
} else {
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
742
|
+
let cursor;
|
|
743
|
+
do {
|
|
744
|
+
const data = await graphql.query(FIND_BY_SRC, { filter: { src: { eq: args.src } }, nextToken: cursor });
|
|
745
|
+
const row = data.listMedia.items[0];
|
|
746
|
+
if (row) {
|
|
747
|
+
mediaId = row.mediaId;
|
|
748
|
+
src = row.src;
|
|
749
|
+
assertMediaPrefix(src);
|
|
750
|
+
break;
|
|
751
|
+
}
|
|
752
|
+
cursor = data.listMedia.nextToken ?? void 0;
|
|
753
|
+
} while (cursor);
|
|
729
754
|
}
|
|
730
755
|
if (!mediaId) {
|
|
731
756
|
if (args.src) {
|
|
@@ -782,7 +807,12 @@ function getSchema() {
|
|
|
782
807
|
slug: { type: "string", required: true, description: "URL slug, unique" },
|
|
783
808
|
title: { type: "string", required: true },
|
|
784
809
|
excerpt: { type: "string" },
|
|
785
|
-
format: {
|
|
810
|
+
format: {
|
|
811
|
+
type: "enum",
|
|
812
|
+
values: ["tiptap", "markdown", "html", "static"],
|
|
813
|
+
required: true,
|
|
814
|
+
description: "`static` is read-only here \u2014 get_post / list_posts can return it, but it is created/edited only via the static-bundle tools (upload_static_bundle, upload_static_file, delete_static_file, commit_static_post), NOT create_post / update_post. See notes.staticFormat."
|
|
815
|
+
},
|
|
786
816
|
body: {
|
|
787
817
|
type: "json",
|
|
788
818
|
description: "tiptap node JSON when format=tiptap; markdown source string when format=markdown; raw HTML string when format=html"
|
|
@@ -821,7 +851,7 @@ function getSchema() {
|
|
|
821
851
|
}
|
|
822
852
|
}
|
|
823
853
|
],
|
|
824
|
-
formats: ["tiptap", "markdown", "html"],
|
|
854
|
+
formats: ["tiptap", "markdown", "html", "static"],
|
|
825
855
|
notes: {
|
|
826
856
|
editorTrust: 'editor stores arbitrary HTML/JS verbatim \u2014 same trust shape as WordPress unfiltered_html capability. See docs/architecture/04-access-layer-mcp.md \xA7"editor \u306E\u4FE1\u983C\u30E2\u30C7\u30EB".',
|
|
827
857
|
tiptapBody: 'When format=tiptap, body is the tiptap document JSON: { type: "doc", content: [...] }. The renderer expects this shape.',
|
|
@@ -1493,8 +1523,10 @@ async function uploadStaticBundle(graphql, storage, args) {
|
|
|
1493
1523
|
}
|
|
1494
1524
|
const prefix = bundlePrefix(slug);
|
|
1495
1525
|
const existing = await storage.listObjects(prefix).catch((err2) => {
|
|
1496
|
-
console.error("[upload_static_bundle] listObjects failed
|
|
1497
|
-
|
|
1526
|
+
console.error("[upload_static_bundle] listObjects failed", err2);
|
|
1527
|
+
throw new Error(
|
|
1528
|
+
`upload_static_bundle: failed to list existing bundle objects for full-prefix wipe: ${err2 instanceof Error ? err2.message : String(err2)}`
|
|
1529
|
+
);
|
|
1498
1530
|
});
|
|
1499
1531
|
for (const obj of existing) {
|
|
1500
1532
|
await storage.deleteObject(obj.key);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ampless/mcp-server",
|
|
3
|
-
"version": "1.0.0-beta.
|
|
3
|
+
"version": "1.0.0-beta.60",
|
|
4
4
|
"description": "MCP tool registry shared by @ampless/backend mcp-handler Lambda. Installed transitively via @ampless/admin / @ampless/backend; no direct install needed.",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
"bugs": "https://github.com/heavymoons/ampless/issues",
|
|
27
27
|
"dependencies": {
|
|
28
28
|
"fflate": "^0.8.3",
|
|
29
|
-
"ampless": "1.0.0-beta.
|
|
29
|
+
"ampless": "1.0.0-beta.54"
|
|
30
30
|
},
|
|
31
31
|
"keywords": [
|
|
32
32
|
"ampless",
|