fastmode-mcp 1.0.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/README.md +561 -0
- package/bin/run.js +50 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +802 -0
- package/dist/lib/api-client.d.ts +81 -0
- package/dist/lib/api-client.d.ts.map +1 -0
- package/dist/lib/api-client.js +237 -0
- package/dist/lib/auth-state.d.ts +13 -0
- package/dist/lib/auth-state.d.ts.map +1 -0
- package/dist/lib/auth-state.js +24 -0
- package/dist/lib/context-fetcher.d.ts +67 -0
- package/dist/lib/context-fetcher.d.ts.map +1 -0
- package/dist/lib/context-fetcher.js +190 -0
- package/dist/lib/credentials.d.ts +52 -0
- package/dist/lib/credentials.d.ts.map +1 -0
- package/dist/lib/credentials.js +196 -0
- package/dist/lib/device-flow.d.ts +14 -0
- package/dist/lib/device-flow.d.ts.map +1 -0
- package/dist/lib/device-flow.js +244 -0
- package/dist/tools/cms-items.d.ts +56 -0
- package/dist/tools/cms-items.d.ts.map +1 -0
- package/dist/tools/cms-items.js +376 -0
- package/dist/tools/create-site.d.ts +9 -0
- package/dist/tools/create-site.d.ts.map +1 -0
- package/dist/tools/create-site.js +202 -0
- package/dist/tools/deploy-package.d.ts +9 -0
- package/dist/tools/deploy-package.d.ts.map +1 -0
- package/dist/tools/deploy-package.js +434 -0
- package/dist/tools/generate-samples.d.ts +19 -0
- package/dist/tools/generate-samples.d.ts.map +1 -0
- package/dist/tools/generate-samples.js +272 -0
- package/dist/tools/get-conversion-guide.d.ts +7 -0
- package/dist/tools/get-conversion-guide.d.ts.map +1 -0
- package/dist/tools/get-conversion-guide.js +1323 -0
- package/dist/tools/get-example.d.ts +7 -0
- package/dist/tools/get-example.d.ts.map +1 -0
- package/dist/tools/get-example.js +1568 -0
- package/dist/tools/get-field-types.d.ts +30 -0
- package/dist/tools/get-field-types.d.ts.map +1 -0
- package/dist/tools/get-field-types.js +154 -0
- package/dist/tools/get-schema.d.ts +5 -0
- package/dist/tools/get-schema.d.ts.map +1 -0
- package/dist/tools/get-schema.js +320 -0
- package/dist/tools/get-started.d.ts +21 -0
- package/dist/tools/get-started.d.ts.map +1 -0
- package/dist/tools/get-started.js +624 -0
- package/dist/tools/get-tenant-schema.d.ts +18 -0
- package/dist/tools/get-tenant-schema.d.ts.map +1 -0
- package/dist/tools/get-tenant-schema.js +158 -0
- package/dist/tools/list-projects.d.ts +5 -0
- package/dist/tools/list-projects.d.ts.map +1 -0
- package/dist/tools/list-projects.js +101 -0
- package/dist/tools/sync-schema.d.ts +41 -0
- package/dist/tools/sync-schema.d.ts.map +1 -0
- package/dist/tools/sync-schema.js +483 -0
- package/dist/tools/validate-manifest.d.ts +5 -0
- package/dist/tools/validate-manifest.d.ts.map +1 -0
- package/dist/tools/validate-manifest.js +311 -0
- package/dist/tools/validate-package.d.ts +5 -0
- package/dist/tools/validate-package.d.ts.map +1 -0
- package/dist/tools/validate-package.js +337 -0
- package/dist/tools/validate-template.d.ts +12 -0
- package/dist/tools/validate-template.d.ts.map +1 -0
- package/dist/tools/validate-template.js +790 -0
- package/package.json +54 -0
- package/scripts/postinstall.js +129 -0
|
@@ -0,0 +1,434 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.deployPackage = deployPackage;
|
|
40
|
+
const fs = __importStar(require("fs"));
|
|
41
|
+
const path = __importStar(require("path"));
|
|
42
|
+
const adm_zip_1 = __importDefault(require("adm-zip"));
|
|
43
|
+
const api_client_1 = require("../lib/api-client");
|
|
44
|
+
const device_flow_1 = require("../lib/device-flow");
|
|
45
|
+
const credentials_1 = require("../lib/credentials");
|
|
46
|
+
const validate_package_1 = require("./validate-package");
|
|
47
|
+
/**
|
|
48
|
+
* List existing projects for the authenticated user
|
|
49
|
+
*/
|
|
50
|
+
async function listExistingProjects() {
|
|
51
|
+
const response = await (0, api_client_1.apiRequest)('/api/tenants');
|
|
52
|
+
if ((0, api_client_1.isApiError)(response)) {
|
|
53
|
+
return [];
|
|
54
|
+
}
|
|
55
|
+
return response.data;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Check if a project has GitHub connected
|
|
59
|
+
*/
|
|
60
|
+
async function checkGitHubConnection(tenantId) {
|
|
61
|
+
const response = await (0, api_client_1.apiRequest)('/api/github/site-connection', { tenantId });
|
|
62
|
+
if ((0, api_client_1.isApiError)(response)) {
|
|
63
|
+
// If we can't check, assume not connected (fail open for better UX)
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
66
|
+
return response.data;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Format the GitHub blocking message
|
|
70
|
+
*/
|
|
71
|
+
function formatGitHubBlockMessage(repo, branch, subdomain) {
|
|
72
|
+
return `# ⚠️ GitHub Sync Detected
|
|
73
|
+
|
|
74
|
+
This project has GitHub connected and will auto-deploy from:
|
|
75
|
+
- **Repository:** ${repo}
|
|
76
|
+
- **Branch:** ${branch}
|
|
77
|
+
|
|
78
|
+
## Why This Matters
|
|
79
|
+
|
|
80
|
+
Deploying via MCP while GitHub is connected can cause conflicts:
|
|
81
|
+
- Your MCP changes could be overwritten on the next GitHub push
|
|
82
|
+
- Or this deploy could overwrite changes from GitHub
|
|
83
|
+
|
|
84
|
+
## Options
|
|
85
|
+
|
|
86
|
+
### Option 1: Push to GitHub Instead (Recommended)
|
|
87
|
+
Push your changes to the connected repository and let GitHub handle the deploy:
|
|
88
|
+
\`\`\`bash
|
|
89
|
+
git push origin ${branch}
|
|
90
|
+
\`\`\`
|
|
91
|
+
|
|
92
|
+
### Option 2: Disconnect GitHub First
|
|
93
|
+
Go to **app.fastmode.ai** → Settings → GitHub and disconnect the repository.
|
|
94
|
+
|
|
95
|
+
### Option 3: Force Deploy Anyway
|
|
96
|
+
If you understand the risks and want to proceed:
|
|
97
|
+
\`\`\`
|
|
98
|
+
deploy_package(
|
|
99
|
+
packagePath: "./your-site.zip",
|
|
100
|
+
projectId: "...",
|
|
101
|
+
force: true
|
|
102
|
+
)
|
|
103
|
+
\`\`\`
|
|
104
|
+
|
|
105
|
+
---
|
|
106
|
+
|
|
107
|
+
**Dashboard:** https://app.fastmode.ai
|
|
108
|
+
**Site:** https://${subdomain}.fastmode.ai
|
|
109
|
+
`;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Upload a package to a specific tenant
|
|
113
|
+
*/
|
|
114
|
+
async function uploadPackage(tenantId, zipBuffer) {
|
|
115
|
+
const credentials = await (0, credentials_1.getValidCredentials)();
|
|
116
|
+
if (!credentials) {
|
|
117
|
+
return { error: 'Not authenticated' };
|
|
118
|
+
}
|
|
119
|
+
const apiUrl = (0, api_client_1.getApiUrl)();
|
|
120
|
+
const url = `${apiUrl}/api/upload/package`;
|
|
121
|
+
// Generate a unique boundary for multipart form data
|
|
122
|
+
const boundary = `----FormBoundary${Date.now().toString(16)}`;
|
|
123
|
+
// Build multipart form data manually
|
|
124
|
+
const header = Buffer.from(`--${boundary}\r\n` +
|
|
125
|
+
`Content-Disposition: form-data; name="package"; filename="package.zip"\r\n` +
|
|
126
|
+
`Content-Type: application/zip\r\n\r\n`);
|
|
127
|
+
const footer = Buffer.from(`\r\n--${boundary}--\r\n`);
|
|
128
|
+
const body = Buffer.concat([header, zipBuffer, footer]);
|
|
129
|
+
try {
|
|
130
|
+
const response = await fetch(url, {
|
|
131
|
+
method: 'POST',
|
|
132
|
+
headers: {
|
|
133
|
+
'Authorization': `Bearer ${credentials.accessToken}`,
|
|
134
|
+
'X-Tenant-Id': tenantId,
|
|
135
|
+
'Content-Type': `multipart/form-data; boundary=${boundary}`,
|
|
136
|
+
},
|
|
137
|
+
body: body,
|
|
138
|
+
});
|
|
139
|
+
const data = await response.json();
|
|
140
|
+
if (!response.ok) {
|
|
141
|
+
return { error: data.error || `Upload failed with status ${response.status}` };
|
|
142
|
+
}
|
|
143
|
+
return data.data;
|
|
144
|
+
}
|
|
145
|
+
catch (error) {
|
|
146
|
+
return { error: error instanceof Error ? error.message : 'Upload failed' };
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Read a package from path (zip file or directory)
|
|
151
|
+
*/
|
|
152
|
+
async function readPackage(packagePath) {
|
|
153
|
+
const absolutePath = path.resolve(packagePath);
|
|
154
|
+
// Check if path exists
|
|
155
|
+
if (!fs.existsSync(absolutePath)) {
|
|
156
|
+
return { error: `Path not found: ${absolutePath}` };
|
|
157
|
+
}
|
|
158
|
+
const stats = fs.statSync(absolutePath);
|
|
159
|
+
if (stats.isFile()) {
|
|
160
|
+
// It's a file - check if it's a zip
|
|
161
|
+
if (!absolutePath.endsWith('.zip')) {
|
|
162
|
+
return { error: 'File must be a .zip archive' };
|
|
163
|
+
}
|
|
164
|
+
return fs.readFileSync(absolutePath);
|
|
165
|
+
}
|
|
166
|
+
// It's a directory - we need to zip it
|
|
167
|
+
// For now, require a zip file
|
|
168
|
+
return { error: 'Please provide a .zip file. Directory upload is not yet supported.' };
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Format project list for user selection
|
|
172
|
+
*/
|
|
173
|
+
function formatProjectChoice(projects, packagePath) {
|
|
174
|
+
let output = `# Project Required
|
|
175
|
+
|
|
176
|
+
You need to specify which project to deploy to.
|
|
177
|
+
|
|
178
|
+
## Your Projects
|
|
179
|
+
|
|
180
|
+
`;
|
|
181
|
+
if (projects.length > 0) {
|
|
182
|
+
projects.forEach((project, index) => {
|
|
183
|
+
const url = project.customDomain || `${project.subdomain}.fastmode.ai`;
|
|
184
|
+
output += `${index + 1}. **${project.name}**
|
|
185
|
+
- ID: \`${project.id}\`
|
|
186
|
+
- URL: ${url}
|
|
187
|
+
- Status: ${project.site?.status || 'pending'}
|
|
188
|
+
|
|
189
|
+
`;
|
|
190
|
+
});
|
|
191
|
+
output += `---
|
|
192
|
+
|
|
193
|
+
## ACTION REQUIRED
|
|
194
|
+
|
|
195
|
+
**Ask the user:** "Which project should I deploy to? You can choose from the list above, or I can create a new project for you."
|
|
196
|
+
|
|
197
|
+
### To deploy to an existing project:
|
|
198
|
+
\`\`\`
|
|
199
|
+
deploy_package(
|
|
200
|
+
packagePath: "${packagePath}",
|
|
201
|
+
projectId: "${projects[0]?.id || 'project-id-here'}"
|
|
202
|
+
)
|
|
203
|
+
\`\`\`
|
|
204
|
+
|
|
205
|
+
### To create a NEW project first:
|
|
206
|
+
\`\`\`
|
|
207
|
+
create_site(name: "Project Name")
|
|
208
|
+
\`\`\`
|
|
209
|
+
Then deploy with the returned project ID.
|
|
210
|
+
`;
|
|
211
|
+
}
|
|
212
|
+
else {
|
|
213
|
+
output += `You don't have any projects yet.
|
|
214
|
+
|
|
215
|
+
---
|
|
216
|
+
|
|
217
|
+
## ACTION REQUIRED
|
|
218
|
+
|
|
219
|
+
**Ask the user:** "What would you like to name your new project?"
|
|
220
|
+
|
|
221
|
+
Then create the project:
|
|
222
|
+
\`\`\`
|
|
223
|
+
create_site(name: "User's Project Name")
|
|
224
|
+
\`\`\`
|
|
225
|
+
|
|
226
|
+
And deploy with the returned project ID:
|
|
227
|
+
\`\`\`
|
|
228
|
+
deploy_package(
|
|
229
|
+
packagePath: "${packagePath}",
|
|
230
|
+
projectId: "returned-project-id"
|
|
231
|
+
)
|
|
232
|
+
\`\`\`
|
|
233
|
+
`;
|
|
234
|
+
}
|
|
235
|
+
return output;
|
|
236
|
+
}
|
|
237
|
+
/**
|
|
238
|
+
* Deploy a website package to Fast Mode
|
|
239
|
+
*
|
|
240
|
+
* @param packagePath - Path to the zip file
|
|
241
|
+
* @param projectId - Project ID to deploy to (use list_projects to find, or create_site to create new)
|
|
242
|
+
* @param force - Optional: Skip GitHub connection check and deploy anyway
|
|
243
|
+
*/
|
|
244
|
+
async function deployPackage(packagePath, projectId, force) {
|
|
245
|
+
// Check authentication
|
|
246
|
+
if (await (0, api_client_1.needsAuthentication)()) {
|
|
247
|
+
const authResult = await (0, device_flow_1.ensureAuthenticated)();
|
|
248
|
+
if (!authResult.authenticated) {
|
|
249
|
+
return authResult.message;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
// If no projectId specified, list projects and prompt for selection
|
|
253
|
+
if (!projectId) {
|
|
254
|
+
const projects = await listExistingProjects();
|
|
255
|
+
return formatProjectChoice(projects, packagePath);
|
|
256
|
+
}
|
|
257
|
+
// Read the package first
|
|
258
|
+
const packageResult = await readPackage(packagePath);
|
|
259
|
+
if ('error' in packageResult) {
|
|
260
|
+
return `# Package Error
|
|
261
|
+
|
|
262
|
+
${packageResult.error}
|
|
263
|
+
|
|
264
|
+
Please provide a valid .zip file path.
|
|
265
|
+
`;
|
|
266
|
+
}
|
|
267
|
+
const zipBuffer = packageResult;
|
|
268
|
+
// Get subdomain for the project
|
|
269
|
+
const projects = await listExistingProjects();
|
|
270
|
+
const project = projects.find(p => p.id === projectId);
|
|
271
|
+
const subdomain = project?.subdomain || '';
|
|
272
|
+
if (!project) {
|
|
273
|
+
return `# Project Not Found
|
|
274
|
+
|
|
275
|
+
Could not find project with ID: \`${projectId}\`
|
|
276
|
+
|
|
277
|
+
Use \`list_projects\` to see available projects, or \`create_site\` to create a new one.
|
|
278
|
+
`;
|
|
279
|
+
}
|
|
280
|
+
// Check for GitHub connection (unless force is true)
|
|
281
|
+
if (!force) {
|
|
282
|
+
const githubStatus = await checkGitHubConnection(projectId);
|
|
283
|
+
if (githubStatus?.connected && githubStatus.repo) {
|
|
284
|
+
// GitHub is connected - block deployment
|
|
285
|
+
return formatGitHubBlockMessage(githubStatus.repo, githubStatus.branch || 'main', subdomain);
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
// ============ PRE-DEPLOY VALIDATION GATE ============
|
|
289
|
+
// Validate the package BEFORE uploading to catch errors early
|
|
290
|
+
try {
|
|
291
|
+
const zip = new adm_zip_1.default(zipBuffer);
|
|
292
|
+
const entries = zip.getEntries();
|
|
293
|
+
// Build file list from zip
|
|
294
|
+
const fileList = entries.map(e => e.entryName);
|
|
295
|
+
// Find and read manifest.json
|
|
296
|
+
const manifestEntry = entries.find(e => e.entryName === 'manifest.json' ||
|
|
297
|
+
e.entryName.endsWith('/manifest.json'));
|
|
298
|
+
if (!manifestEntry) {
|
|
299
|
+
return `# DEPLOYMENT BLOCKED
|
|
300
|
+
|
|
301
|
+
**Reason:** Missing manifest.json
|
|
302
|
+
|
|
303
|
+
Every Fast Mode package requires a manifest.json at the root.
|
|
304
|
+
|
|
305
|
+
Run \`get_example("manifest_basic")\` to see the required format.
|
|
306
|
+
|
|
307
|
+
## Expected Package Structure
|
|
308
|
+
|
|
309
|
+
\`\`\`
|
|
310
|
+
your-site.zip
|
|
311
|
+
├── manifest.json <- REQUIRED
|
|
312
|
+
├── pages/
|
|
313
|
+
│ ├── index.html
|
|
314
|
+
│ └── ...
|
|
315
|
+
├── public/
|
|
316
|
+
│ └── css/, js/, images/
|
|
317
|
+
└── templates/ (optional, for CMS)
|
|
318
|
+
\`\`\`
|
|
319
|
+
`;
|
|
320
|
+
}
|
|
321
|
+
const manifestContent = manifestEntry.getData().toString('utf8');
|
|
322
|
+
// Collect template contents for validation
|
|
323
|
+
const templateContents = {};
|
|
324
|
+
for (const entry of entries) {
|
|
325
|
+
if (entry.entryName.endsWith('.html') && !entry.isDirectory) {
|
|
326
|
+
try {
|
|
327
|
+
templateContents[entry.entryName] = entry.getData().toString('utf8');
|
|
328
|
+
}
|
|
329
|
+
catch {
|
|
330
|
+
// Skip files that can't be read
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
// Run full package validation
|
|
335
|
+
const validationResult = await (0, validate_package_1.validatePackage)(fileList, manifestContent, templateContents);
|
|
336
|
+
// Only block on actual ERRORS, not warnings
|
|
337
|
+
if (validationResult.includes('HAS ERRORS') || validationResult.includes('INVALID')) {
|
|
338
|
+
return `# DEPLOYMENT BLOCKED
|
|
339
|
+
|
|
340
|
+
Your package has validation errors that must be fixed before deployment.
|
|
341
|
+
|
|
342
|
+
---
|
|
343
|
+
|
|
344
|
+
${validationResult}
|
|
345
|
+
|
|
346
|
+
---
|
|
347
|
+
|
|
348
|
+
## Next Steps
|
|
349
|
+
|
|
350
|
+
1. Fix the errors listed above
|
|
351
|
+
2. Rebuild your .zip package
|
|
352
|
+
3. Run \`deploy_package\` again
|
|
353
|
+
|
|
354
|
+
Use \`validate_template\` and \`validate_manifest\` to check individual files.
|
|
355
|
+
`;
|
|
356
|
+
}
|
|
357
|
+
// Validation passed - include summary in success response later
|
|
358
|
+
console.error('Pre-deploy validation passed');
|
|
359
|
+
}
|
|
360
|
+
catch (validationError) {
|
|
361
|
+
// If validation itself fails (e.g., corrupt zip), log but continue
|
|
362
|
+
// The upload will fail with a more specific error if the package is truly broken
|
|
363
|
+
console.error('Pre-deploy validation error:', validationError);
|
|
364
|
+
}
|
|
365
|
+
// Upload the package
|
|
366
|
+
console.error(`Deploying to ${subdomain}.fastmode.ai...`);
|
|
367
|
+
const uploadResult = await uploadPackage(projectId, zipBuffer);
|
|
368
|
+
if ('error' in uploadResult) {
|
|
369
|
+
// Check if it's an auth error
|
|
370
|
+
if ((0, api_client_1.needsAuthError)({ success: false, error: uploadResult.error, statusCode: 401 })) {
|
|
371
|
+
const authResult = await (0, device_flow_1.ensureAuthenticated)();
|
|
372
|
+
if (!authResult.authenticated) {
|
|
373
|
+
return authResult.message;
|
|
374
|
+
}
|
|
375
|
+
// Retry upload
|
|
376
|
+
const retryResult = await uploadPackage(projectId, zipBuffer);
|
|
377
|
+
if ('error' in retryResult) {
|
|
378
|
+
return `# Upload Failed
|
|
379
|
+
|
|
380
|
+
${retryResult.error}
|
|
381
|
+
|
|
382
|
+
Please check:
|
|
383
|
+
1. The package is a valid .zip file
|
|
384
|
+
2. It contains manifest.json, pages/, and public/ folders
|
|
385
|
+
3. Try again or upload manually at app.fastmode.ai
|
|
386
|
+
`;
|
|
387
|
+
}
|
|
388
|
+
return formatSuccess(subdomain, retryResult);
|
|
389
|
+
}
|
|
390
|
+
return `# Upload Failed
|
|
391
|
+
|
|
392
|
+
${uploadResult.error}
|
|
393
|
+
|
|
394
|
+
Please check:
|
|
395
|
+
1. The package is a valid .zip file
|
|
396
|
+
2. It contains manifest.json, pages/, and public/ folders
|
|
397
|
+
3. Try again or upload manually at app.fastmode.ai
|
|
398
|
+
`;
|
|
399
|
+
}
|
|
400
|
+
return formatSuccess(subdomain, uploadResult);
|
|
401
|
+
}
|
|
402
|
+
/**
|
|
403
|
+
* Format success message
|
|
404
|
+
*/
|
|
405
|
+
function formatSuccess(subdomain, result) {
|
|
406
|
+
return `# Deployment Successful!
|
|
407
|
+
|
|
408
|
+
**Package deployed!**
|
|
409
|
+
|
|
410
|
+
## Live Site
|
|
411
|
+
|
|
412
|
+
**URL:** https://${subdomain}.fastmode.ai
|
|
413
|
+
|
|
414
|
+
## Details
|
|
415
|
+
|
|
416
|
+
- **Files Uploaded:** ${result.filesUploaded}
|
|
417
|
+
- **Pages:** ${result.pages}
|
|
418
|
+
- **Version:** ${result.site.packageVersion}
|
|
419
|
+
- **Status:** ${result.site.status}
|
|
420
|
+
|
|
421
|
+
## Next Steps
|
|
422
|
+
|
|
423
|
+
1. **View your site:** https://${subdomain}.fastmode.ai
|
|
424
|
+
2. **Edit content:** Go to app.fastmode.ai to manage your CMS
|
|
425
|
+
3. **Connect GitHub:** For automatic deploys on push
|
|
426
|
+
|
|
427
|
+
---
|
|
428
|
+
|
|
429
|
+
To update this site later:
|
|
430
|
+
\`\`\`
|
|
431
|
+
deploy_package(packagePath: "./updated-site.zip", projectId: "${result.site.id}")
|
|
432
|
+
\`\`\`
|
|
433
|
+
`;
|
|
434
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generate Sample Items Tool
|
|
3
|
+
*
|
|
4
|
+
* Generates sample items for collections with automatic dependency ordering.
|
|
5
|
+
* Handles relation fields by generating parent collections first.
|
|
6
|
+
* Requires authentication.
|
|
7
|
+
*/
|
|
8
|
+
interface GenerateSamplesInput {
|
|
9
|
+
projectId: string;
|
|
10
|
+
collectionSlugs?: string[];
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Generate sample items for collections
|
|
14
|
+
*
|
|
15
|
+
* @param input - The input with projectId and optional collectionSlugs
|
|
16
|
+
*/
|
|
17
|
+
export declare function generateSampleItems(input: GenerateSamplesInput): Promise<string>;
|
|
18
|
+
export {};
|
|
19
|
+
//# sourceMappingURL=generate-samples.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generate-samples.d.ts","sourceRoot":"","sources":["../../src/tools/generate-samples.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAgCH,UAAU,oBAAoB;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;CAC5B;AAmID;;;;GAIG;AACH,wBAAsB,mBAAmB,CAAC,KAAK,EAAE,oBAAoB,GAAG,OAAO,CAAC,MAAM,CAAC,CAoLtF"}
|