@dropins/mcp 0.1.0
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/LICENSE.md +127 -0
- package/README.md +314 -0
- package/dist/common/project-reader.d.ts +55 -0
- package/dist/common/project-reader.js +173 -0
- package/dist/common/registry-loader.d.ts +101 -0
- package/dist/common/registry-loader.js +386 -0
- package/dist/common/response-handling.d.ts +12 -0
- package/dist/common/response-handling.js +21 -0
- package/dist/common/sanitize.d.ts +8 -0
- package/dist/common/sanitize.js +45 -0
- package/dist/common/synonyms.d.ts +9 -0
- package/dist/common/synonyms.js +127 -0
- package/dist/common/telemetry.d.ts +14 -0
- package/dist/common/telemetry.js +54 -0
- package/dist/common/types.d.ts +308 -0
- package/dist/common/types.js +1 -0
- package/dist/common/version.d.ts +2 -0
- package/dist/common/version.js +14 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +136 -0
- package/dist/operations/analyze-project.d.ts +13 -0
- package/dist/operations/analyze-project.js +125 -0
- package/dist/operations/check-block-health.d.ts +19 -0
- package/dist/operations/check-block-health.js +1149 -0
- package/dist/operations/check-config.d.ts +13 -0
- package/dist/operations/check-config.js +228 -0
- package/dist/operations/explain-event-flow.d.ts +16 -0
- package/dist/operations/explain-event-flow.js +218 -0
- package/dist/operations/get-upgrade-diff.d.ts +13 -0
- package/dist/operations/get-upgrade-diff.js +144 -0
- package/dist/operations/list-api-functions.d.ts +13 -0
- package/dist/operations/list-api-functions.js +53 -0
- package/dist/operations/list-containers.d.ts +13 -0
- package/dist/operations/list-containers.js +44 -0
- package/dist/operations/list-design-tokens.d.ts +13 -0
- package/dist/operations/list-design-tokens.js +47 -0
- package/dist/operations/list-events.d.ts +16 -0
- package/dist/operations/list-events.js +39 -0
- package/dist/operations/list-graphql-queries.d.ts +19 -0
- package/dist/operations/list-graphql-queries.js +84 -0
- package/dist/operations/list-i18n-keys.d.ts +19 -0
- package/dist/operations/list-i18n-keys.js +105 -0
- package/dist/operations/list-models.d.ts +16 -0
- package/dist/operations/list-models.js +80 -0
- package/dist/operations/list-slots.d.ts +16 -0
- package/dist/operations/list-slots.js +81 -0
- package/dist/operations/scaffold-block.d.ts +31 -0
- package/dist/operations/scaffold-block.js +331 -0
- package/dist/operations/scaffold-extension.d.ts +28 -0
- package/dist/operations/scaffold-extension.js +346 -0
- package/dist/operations/scaffold-slot.d.ts +22 -0
- package/dist/operations/scaffold-slot.js +189 -0
- package/dist/operations/search-commerce-docs.d.ts +16 -0
- package/dist/operations/search-commerce-docs.js +101 -0
- package/dist/operations/search-docs.d.ts +23 -0
- package/dist/operations/search-docs.js +298 -0
- package/dist/operations/suggest-event-handler.d.ts +16 -0
- package/dist/operations/suggest-event-handler.js +175 -0
- package/dist/operations/suggest-slot-implementation.d.ts +19 -0
- package/dist/operations/suggest-slot-implementation.js +183 -0
- package/dist/registry/api-functions.json +3045 -0
- package/dist/registry/block-patterns.json +78 -0
- package/dist/registry/containers.json +2003 -0
- package/dist/registry/design-tokens.json +577 -0
- package/dist/registry/docs/boilerplate.json +55 -0
- package/dist/registry/docs/dropins-all.json +97 -0
- package/dist/registry/docs/dropins-b2b.json +607 -0
- package/dist/registry/docs/dropins-cart.json +163 -0
- package/dist/registry/docs/dropins-checkout.json +193 -0
- package/dist/registry/docs/dropins-order.json +139 -0
- package/dist/registry/docs/dropins-payment-services.json +73 -0
- package/dist/registry/docs/dropins-personalization.json +67 -0
- package/dist/registry/docs/dropins-product-details.json +139 -0
- package/dist/registry/docs/dropins-product-discovery.json +85 -0
- package/dist/registry/docs/dropins-recommendations.json +67 -0
- package/dist/registry/docs/dropins-user-account.json +121 -0
- package/dist/registry/docs/dropins-user-auth.json +103 -0
- package/dist/registry/docs/dropins-wishlist.json +85 -0
- package/dist/registry/docs/get-started.json +85 -0
- package/dist/registry/docs/how-tos.json +19 -0
- package/dist/registry/docs/index.json +139 -0
- package/dist/registry/docs/licensing.json +19 -0
- package/dist/registry/docs/merchants.json +523 -0
- package/dist/registry/docs/resources.json +13 -0
- package/dist/registry/docs/sdk.json +139 -0
- package/dist/registry/docs/setup.json +145 -0
- package/dist/registry/docs/troubleshooting.json +19 -0
- package/dist/registry/events.json +2200 -0
- package/dist/registry/examples/index.json +19 -0
- package/dist/registry/examples/storefront-checkout.json +377 -0
- package/dist/registry/examples/storefront-quote-management.json +49 -0
- package/dist/registry/extensions.json +272 -0
- package/dist/registry/graphql.json +3469 -0
- package/dist/registry/i18n.json +1873 -0
- package/dist/registry/models.json +1001 -0
- package/dist/registry/sdk.json +2357 -0
- package/dist/registry/slots.json +2270 -0
- package/dist/registry/tools-components.json +595 -0
- package/dist/resources/guides.d.ts +7 -0
- package/dist/resources/guides.js +625 -0
- package/dist/resources/handlers.d.ts +31 -0
- package/dist/resources/handlers.js +322 -0
- package/package.json +47 -0
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { formatSuccessResponse, formatExceptionResponse, } from "../common/response-handling.js";
|
|
3
|
+
import { getSlotRegistry, getAllDropinNames, findModel, } from "../common/registry-loader.js";
|
|
4
|
+
import { projectDirGuard, readBlockFile, extractImportsFromBlock, } from "../common/project-reader.js";
|
|
5
|
+
import { sanitizeForComment, validateBlockName } from "../common/sanitize.js";
|
|
6
|
+
export const SuggestSlotSchema = z.object({
|
|
7
|
+
request: z
|
|
8
|
+
.string()
|
|
9
|
+
.describe('What the merchant wants (e.g. "Add loyalty points badge next to price in cart")'),
|
|
10
|
+
blockName: z.string().describe('Block name (e.g. "commerce-cart")'),
|
|
11
|
+
projectDir: z
|
|
12
|
+
.string()
|
|
13
|
+
.describe("Absolute path to the merchant storefront project root"),
|
|
14
|
+
});
|
|
15
|
+
function scoreSlotRelevance(request, slot, _container) {
|
|
16
|
+
const lowerReq = request.toLowerCase();
|
|
17
|
+
const lowerSlot = slot.name.toLowerCase();
|
|
18
|
+
const lowerDesc = (slot.description ?? "").toLowerCase();
|
|
19
|
+
let score = 0;
|
|
20
|
+
if (lowerReq.includes(lowerSlot))
|
|
21
|
+
score += 10;
|
|
22
|
+
if (lowerSlot.includes("footer") && lowerReq.includes("below"))
|
|
23
|
+
score += 3;
|
|
24
|
+
if (lowerSlot.includes("footer") && lowerReq.includes("after"))
|
|
25
|
+
score += 3;
|
|
26
|
+
if (lowerSlot.includes("heading") && lowerReq.includes("title"))
|
|
27
|
+
score += 3;
|
|
28
|
+
if (lowerSlot.includes("heading") && lowerReq.includes("header"))
|
|
29
|
+
score += 3;
|
|
30
|
+
if (lowerSlot.includes("thumbnail") && lowerReq.includes("image"))
|
|
31
|
+
score += 3;
|
|
32
|
+
if (lowerSlot.includes("thumbnail") && lowerReq.includes("photo"))
|
|
33
|
+
score += 3;
|
|
34
|
+
if (lowerSlot.includes("price") && lowerReq.includes("price"))
|
|
35
|
+
score += 5;
|
|
36
|
+
if (lowerSlot.includes("price") && lowerReq.includes("cost"))
|
|
37
|
+
score += 3;
|
|
38
|
+
if (lowerSlot.includes("content") && lowerReq.includes("content"))
|
|
39
|
+
score += 3;
|
|
40
|
+
if (lowerSlot.includes("content") && lowerReq.includes("custom"))
|
|
41
|
+
score += 2;
|
|
42
|
+
if (lowerSlot.includes("agreement") && lowerReq.includes("terms"))
|
|
43
|
+
score += 5;
|
|
44
|
+
if (lowerSlot.includes("agreement") && lowerReq.includes("checkbox"))
|
|
45
|
+
score += 3;
|
|
46
|
+
const reqWords = lowerReq.split(/\s+/);
|
|
47
|
+
for (const word of reqWords) {
|
|
48
|
+
if (word.length > 3 && lowerDesc.includes(word))
|
|
49
|
+
score += 2;
|
|
50
|
+
if (word.length > 3 && lowerSlot.includes(word))
|
|
51
|
+
score += 2;
|
|
52
|
+
}
|
|
53
|
+
return score;
|
|
54
|
+
}
|
|
55
|
+
function generateSlotCode(slot, request) {
|
|
56
|
+
const contextType = slot.contextType ?? "DefaultSlotContext";
|
|
57
|
+
const customMethods = slot.customMethods ?? [];
|
|
58
|
+
const hasAppendAgreement = customMethods.includes("appendAgreement");
|
|
59
|
+
if (hasAppendAgreement) {
|
|
60
|
+
return `${slot.name}: (ctx) => {
|
|
61
|
+
// ${sanitizeForComment(request)}
|
|
62
|
+
ctx.appendAgreement(() => ({
|
|
63
|
+
name: 'custom-agreement',
|
|
64
|
+
mode: 'manual',
|
|
65
|
+
translationId: 'Custom.Agreement.Label',
|
|
66
|
+
}));
|
|
67
|
+
},`;
|
|
68
|
+
}
|
|
69
|
+
return `${slot.name}: (ctx) => {
|
|
70
|
+
// ${sanitizeForComment(request)}
|
|
71
|
+
// Context type: ${contextType}
|
|
72
|
+
const element = document.createElement('div');
|
|
73
|
+
element.className = 'custom-${slot.name.toLowerCase()}';
|
|
74
|
+
|
|
75
|
+
// Build your custom content here
|
|
76
|
+
element.textContent = 'Custom content';
|
|
77
|
+
|
|
78
|
+
ctx.appendChild(element);
|
|
79
|
+
},`;
|
|
80
|
+
}
|
|
81
|
+
export async function suggestSlotImplementation(params) {
|
|
82
|
+
try {
|
|
83
|
+
const blockNameError = validateBlockName(params.blockName);
|
|
84
|
+
if (blockNameError) {
|
|
85
|
+
return formatSuccessResponse("Invalid block name", {
|
|
86
|
+
error: blockNameError,
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
const guard = projectDirGuard(params.projectDir);
|
|
90
|
+
if (guard)
|
|
91
|
+
return guard;
|
|
92
|
+
const blockContent = readBlockFile(params.projectDir, params.blockName);
|
|
93
|
+
let detectedDropins = [];
|
|
94
|
+
let detectedContainers = [];
|
|
95
|
+
if (blockContent) {
|
|
96
|
+
const imports = extractImportsFromBlock(blockContent);
|
|
97
|
+
detectedContainers = imports.containerImports;
|
|
98
|
+
for (const imp of imports.dropinImports) {
|
|
99
|
+
const match = imp.match(/@dropins\/(storefront-[^/]+)/);
|
|
100
|
+
if (match && !detectedDropins.includes(match[1])) {
|
|
101
|
+
detectedDropins.push(match[1]);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
else {
|
|
106
|
+
const match = params.blockName.match(/^commerce-(.+)/);
|
|
107
|
+
if (match) {
|
|
108
|
+
const hint = match[1];
|
|
109
|
+
const allDropins = getAllDropinNames();
|
|
110
|
+
detectedDropins = allDropins.filter((d) => d.includes(hint) || hint.includes(d.replace("storefront-", "")));
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
if (detectedDropins.length === 0) {
|
|
114
|
+
detectedDropins = getAllDropinNames();
|
|
115
|
+
}
|
|
116
|
+
const suggestions = [];
|
|
117
|
+
const registry = getSlotRegistry();
|
|
118
|
+
for (const dropinName of detectedDropins) {
|
|
119
|
+
const dropinData = registry.dropins[dropinName];
|
|
120
|
+
if (!dropinData)
|
|
121
|
+
continue;
|
|
122
|
+
for (const [containerName, containerData] of Object.entries(dropinData.containers)) {
|
|
123
|
+
if (detectedContainers.length > 0 &&
|
|
124
|
+
!detectedContainers.includes(containerName)) {
|
|
125
|
+
continue;
|
|
126
|
+
}
|
|
127
|
+
for (const slot of containerData.slots) {
|
|
128
|
+
const score = scoreSlotRelevance(params.request, slot, containerName);
|
|
129
|
+
if (score > 0) {
|
|
130
|
+
suggestions.push({
|
|
131
|
+
dropin: dropinName,
|
|
132
|
+
container: containerName,
|
|
133
|
+
slotName: slot.name,
|
|
134
|
+
description: slot.description,
|
|
135
|
+
contextType: slot.contextType ?? "DefaultSlotContext",
|
|
136
|
+
relevance: score >= 8 ? "high" : score >= 4 ? "medium" : "low",
|
|
137
|
+
example: slot.example ?? "",
|
|
138
|
+
codeSnippet: generateSlotCode(slot, params.request),
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
suggestions.sort((a, b) => {
|
|
145
|
+
const order = { high: 0, medium: 1, low: 2 };
|
|
146
|
+
return ((order[a.relevance] ?? 3) -
|
|
147
|
+
(order[b.relevance] ?? 3));
|
|
148
|
+
});
|
|
149
|
+
const topSuggestions = suggestions.slice(0, 5);
|
|
150
|
+
const resolvedTypes = {};
|
|
151
|
+
for (const suggestion of topSuggestions) {
|
|
152
|
+
const rawType = suggestion.contextType;
|
|
153
|
+
if (!rawType || rawType === "DefaultSlotContext")
|
|
154
|
+
continue;
|
|
155
|
+
const namedTypes = rawType.match(/\b[A-Z][A-Za-z0-9]+\b/g) ?? [];
|
|
156
|
+
for (const typeName of namedTypes) {
|
|
157
|
+
if (typeName in resolvedTypes)
|
|
158
|
+
continue;
|
|
159
|
+
const matches = findModel(typeName);
|
|
160
|
+
if (matches.length > 0) {
|
|
161
|
+
resolvedTypes[typeName] = matches[0].definition;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
return formatSuccessResponse(topSuggestions.length > 0
|
|
166
|
+
? `Found ${topSuggestions.length} slot suggestion(s) for: "${params.request}"`
|
|
167
|
+
: `No matching slots found for: "${params.request}"`, {
|
|
168
|
+
request: params.request,
|
|
169
|
+
blockName: params.blockName,
|
|
170
|
+
detectedDropins,
|
|
171
|
+
detectedContainers,
|
|
172
|
+
blockFound: !!blockContent,
|
|
173
|
+
suggestions: topSuggestions,
|
|
174
|
+
...(Object.keys(resolvedTypes).length > 0 && { resolvedTypes }),
|
|
175
|
+
hint: topSuggestions.length === 0
|
|
176
|
+
? "Try rephrasing your request, or use list_slots to browse available slots"
|
|
177
|
+
: undefined,
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
catch (error) {
|
|
181
|
+
return formatExceptionResponse(error, "suggesting slot implementation");
|
|
182
|
+
}
|
|
183
|
+
}
|