@tpitre/story-ui 3.1.0 → 3.2.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 +25 -72
- package/dist/cli/deploy.d.ts +0 -7
- package/dist/cli/deploy.d.ts.map +1 -1
- package/dist/cli/deploy.js +10 -421
- package/dist/mcp-server/index.js +7 -8
- package/dist/mcp-server/mcp-stdio-server.js +1 -2
- package/dist/mcp-server/routes/generateStory.d.ts.map +1 -1
- package/dist/mcp-server/routes/generateStory.js +3 -3
- package/dist/mcp-server/routes/generateStoryStream.d.ts.map +1 -1
- package/dist/mcp-server/routes/generateStoryStream.js +3 -3
- package/dist/mcp-server/routes/hybridStories.d.ts +6 -6
- package/dist/mcp-server/routes/hybridStories.d.ts.map +1 -1
- package/dist/mcp-server/routes/hybridStories.js +29 -27
- package/dist/mcp-server/routes/memoryStories.d.ts +7 -7
- package/dist/mcp-server/routes/memoryStories.d.ts.map +1 -1
- package/dist/mcp-server/routes/memoryStories.js +37 -26
- package/dist/story-generator/postgresStoryService.d.ts +56 -0
- package/dist/story-generator/postgresStoryService.d.ts.map +1 -0
- package/dist/story-generator/postgresStoryService.js +240 -0
- package/dist/story-generator/storyServiceFactory.d.ts +22 -0
- package/dist/story-generator/storyServiceFactory.d.ts.map +1 -0
- package/dist/story-generator/storyServiceFactory.js +97 -0
- package/dist/story-generator/storyServiceInterface.d.ts +85 -0
- package/dist/story-generator/storyServiceInterface.d.ts.map +1 -0
- package/dist/story-generator/storyServiceInterface.js +5 -0
- package/package.json +6 -6
package/README.md
CHANGED
|
@@ -66,9 +66,7 @@ Story UI will guide you through:
|
|
|
66
66
|
| **Gemini** (Google) | Gemini 3 Pro, Gemini 2.0 Flash, Gemini 1.5 Pro | Fast generation, cost efficiency |
|
|
67
67
|
|
|
68
68
|
### Production Deployment
|
|
69
|
-
- **
|
|
70
|
-
- **Cloudflare Pages**: Static frontend hosting
|
|
71
|
-
- **Railway**: Full Node.js backend (alternative)
|
|
69
|
+
- **Railway**: Node.js backend with PostgreSQL for story persistence
|
|
72
70
|
- **MCP Integration**: Connect AI clients directly to production
|
|
73
71
|
|
|
74
72
|
---
|
|
@@ -314,100 +312,55 @@ Story UI v3 can be deployed as a standalone web application accessible from anyw
|
|
|
314
312
|
|
|
315
313
|
```
|
|
316
314
|
┌─────────────────────────────────────────────────────────────┐
|
|
317
|
-
│
|
|
318
|
-
│ (Your Frontend App) │
|
|
315
|
+
│ Railway Deployment │
|
|
319
316
|
│ ┌─────────────────────────────────────────────────────────┐│
|
|
320
|
-
│ │
|
|
321
|
-
│ │ -
|
|
322
|
-
│ │ -
|
|
323
|
-
│ │ -
|
|
317
|
+
│ │ Express MCP Server (Node.js) ││
|
|
318
|
+
│ │ - Serves React frontend ││
|
|
319
|
+
│ │ - API routes for story generation ││
|
|
320
|
+
│ │ - Multi-provider LLM support ││
|
|
324
321
|
│ └─────────────────────────────────────────────────────────┘│
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
▼
|
|
328
|
-
┌─────────────────────────────────────────────────────────────┐
|
|
329
|
-
│ Cloudflare Workers Edge │
|
|
322
|
+
│ │ │
|
|
323
|
+
│ ▼ │
|
|
330
324
|
│ ┌─────────────────────────────────────────────────────────┐│
|
|
331
|
-
│ │
|
|
332
|
-
│ │ -
|
|
333
|
-
│ │ - /story-ui/openai → OpenAI API proxy ││
|
|
334
|
-
│ │ - /story-ui/gemini → Gemini API proxy ││
|
|
335
|
-
│ │ - /mcp → MCP JSON-RPC endpoint ││
|
|
325
|
+
│ │ PostgreSQL Database ││
|
|
326
|
+
│ │ - Story persistence across deployments ││
|
|
336
327
|
│ └─────────────────────────────────────────────────────────┘│
|
|
337
|
-
|
|
328
|
+
└──────────────────────────────────────────────────────────────┘
|
|
338
329
|
```
|
|
339
330
|
|
|
340
|
-
### Deploy to
|
|
341
|
-
|
|
342
|
-
**1. Deploy the Edge Worker (Backend)**
|
|
343
|
-
|
|
344
|
-
```bash
|
|
345
|
-
cd cloudflare-edge
|
|
346
|
-
wrangler deploy
|
|
331
|
+
### Deploy to Railway
|
|
347
332
|
|
|
348
|
-
|
|
349
|
-
wrangler secret put ANTHROPIC_API_KEY
|
|
350
|
-
wrangler secret put OPENAI_API_KEY # optional
|
|
351
|
-
wrangler secret put GEMINI_API_KEY # optional
|
|
352
|
-
```
|
|
333
|
+
Railway provides a complete deployment experience with PostgreSQL for story persistence.
|
|
353
334
|
|
|
354
|
-
**
|
|
335
|
+
**Quick Start:**
|
|
355
336
|
|
|
356
337
|
```bash
|
|
357
|
-
|
|
358
|
-
npm install
|
|
359
|
-
|
|
360
|
-
wrangler pages deploy dist --project-name=your-app-name
|
|
361
|
-
```
|
|
362
|
-
|
|
363
|
-
**3. Configure Environment**
|
|
364
|
-
|
|
365
|
-
Update the frontend to point to your worker URL in the configuration.
|
|
366
|
-
|
|
367
|
-
### Railway Deployment (Recommended)
|
|
338
|
+
# Install Railway CLI
|
|
339
|
+
npm install -g @railway/cli
|
|
340
|
+
railway login
|
|
368
341
|
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
- Live story generation directly in the sidebar
|
|
373
|
-
- Easy environment variable management
|
|
342
|
+
# Initialize project with PostgreSQL
|
|
343
|
+
railway init
|
|
344
|
+
railway add --plugin postgresql
|
|
374
345
|
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
```bash
|
|
378
|
-
# From your Storybook project with Story UI configured
|
|
379
|
-
npx story-ui deploy --live --platform=railway --dry-run
|
|
380
|
-
|
|
381
|
-
# Review the generated configuration, then deploy:
|
|
346
|
+
# Deploy
|
|
382
347
|
railway up
|
|
383
348
|
```
|
|
384
349
|
|
|
385
|
-
**
|
|
350
|
+
**Environment Variables (set in Railway Dashboard):**
|
|
386
351
|
- `ANTHROPIC_API_KEY` - Required for Claude models
|
|
387
352
|
- `OPENAI_API_KEY` - Optional for OpenAI models
|
|
388
353
|
- `GEMINI_API_KEY` - Optional for Gemini models
|
|
389
|
-
- `
|
|
390
|
-
|
|
391
|
-
**3. Connect External MCP Clients**
|
|
392
|
-
|
|
393
|
-
Once deployed, your Railway instance provides an MCP endpoint that AI clients can connect to:
|
|
354
|
+
- `DATABASE_URL` - Auto-set by Railway PostgreSQL plugin
|
|
394
355
|
|
|
395
|
-
|
|
396
|
-
https://your-app.up.railway.app/story-ui
|
|
397
|
-
```
|
|
356
|
+
**Connect MCP Clients:**
|
|
398
357
|
|
|
399
|
-
**For Claude Desktop/Claude Code:**
|
|
400
358
|
```bash
|
|
401
359
|
# Add your Railway deployment as an MCP server
|
|
402
360
|
claude mcp add --transport http story-ui https://your-app.up.railway.app/story-ui
|
|
403
361
|
```
|
|
404
362
|
|
|
405
|
-
|
|
406
|
-
```
|
|
407
|
-
https://your-app.up.railway.app/mcp
|
|
408
|
-
```
|
|
409
|
-
|
|
410
|
-
This allows you to generate stories from Claude Desktop, ChatGPT (with MCP support), or any other MCP-compatible AI client, and see them appear in your deployed Storybook instance.
|
|
363
|
+
See [DEPLOYMENT.md](DEPLOYMENT.md) for detailed deployment instructions, PostgreSQL setup, and troubleshooting.
|
|
411
364
|
|
|
412
365
|
---
|
|
413
366
|
|
package/dist/cli/deploy.d.ts
CHANGED
|
@@ -4,14 +4,7 @@ interface DeployOptions {
|
|
|
4
4
|
projectName?: string;
|
|
5
5
|
dryRun?: boolean;
|
|
6
6
|
backend?: boolean;
|
|
7
|
-
frontend?: boolean;
|
|
8
|
-
app?: boolean;
|
|
9
7
|
backendUrl?: string;
|
|
10
|
-
storybookDir?: string;
|
|
11
|
-
init?: boolean;
|
|
12
|
-
edge?: boolean;
|
|
13
|
-
pages?: boolean;
|
|
14
|
-
all?: boolean;
|
|
15
8
|
}
|
|
16
9
|
export declare function deployCommand(options: DeployOptions): Promise<void>;
|
|
17
10
|
export {};
|
package/dist/cli/deploy.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"deploy.d.ts","sourceRoot":"","sources":["../../cli/deploy.ts"],"names":[],"mappings":"AASA,UAAU,aAAa;IAErB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,QAAQ,CAAC,EAAE,SAAS,GAAG,KAAK,CAAC;IAC7B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,OAAO,CAAC;IAEjB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,
|
|
1
|
+
{"version":3,"file":"deploy.d.ts","sourceRoot":"","sources":["../../cli/deploy.ts"],"names":[],"mappings":"AASA,UAAU,aAAa;IAErB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,QAAQ,CAAC,EAAE,SAAS,GAAG,KAAK,CAAC;IAC7B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,OAAO,CAAC;IAEjB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AA4nBD,wBAAsB,aAAa,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CA2GzE"}
|
package/dist/cli/deploy.js
CHANGED
|
@@ -563,346 +563,10 @@ primary_region = "sjc"
|
|
|
563
563
|
return null;
|
|
564
564
|
}
|
|
565
565
|
}
|
|
566
|
-
/**
|
|
567
|
-
* Deploy Storybook frontend to Cloudflare Pages
|
|
568
|
-
*/
|
|
569
|
-
async function deployStorybook(backendUrl, storybookDir, projectName, dryRun) {
|
|
570
|
-
console.log('\n📖 Deploying Storybook to Cloudflare Pages...\n');
|
|
571
|
-
// Check wrangler auth
|
|
572
|
-
try {
|
|
573
|
-
execSync('npx wrangler whoami', { stdio: 'pipe' });
|
|
574
|
-
}
|
|
575
|
-
catch {
|
|
576
|
-
console.log('🔐 Not authenticated with Cloudflare.');
|
|
577
|
-
execSync('npx wrangler login', { stdio: 'inherit' });
|
|
578
|
-
}
|
|
579
|
-
// Validate storybook directory
|
|
580
|
-
if (!fs.existsSync(storybookDir)) {
|
|
581
|
-
console.error(`❌ Storybook directory not found: ${storybookDir}`);
|
|
582
|
-
console.log(' Make sure you have a Storybook project set up.');
|
|
583
|
-
return null;
|
|
584
|
-
}
|
|
585
|
-
const packageJsonPath = path.join(storybookDir, 'package.json');
|
|
586
|
-
if (!fs.existsSync(packageJsonPath)) {
|
|
587
|
-
console.error('❌ No package.json found in storybook directory');
|
|
588
|
-
return null;
|
|
589
|
-
}
|
|
590
|
-
if (dryRun) {
|
|
591
|
-
console.log(`[DRY RUN] Would build Storybook with VITE_STORY_UI_EDGE_URL=${backendUrl}`);
|
|
592
|
-
console.log(`[DRY RUN] Would deploy from: ${storybookDir}`);
|
|
593
|
-
return 'https://dry-run.pages.dev';
|
|
594
|
-
}
|
|
595
|
-
try {
|
|
596
|
-
// Install dependencies if needed
|
|
597
|
-
if (!fs.existsSync(path.join(storybookDir, 'node_modules'))) {
|
|
598
|
-
console.log('📦 Installing dependencies...');
|
|
599
|
-
execSync('npm install', { cwd: storybookDir, stdio: 'inherit' });
|
|
600
|
-
}
|
|
601
|
-
// Build storybook with the backend URL
|
|
602
|
-
console.log(`🔨 Building Storybook with backend URL: ${backendUrl}`);
|
|
603
|
-
execSync(`VITE_STORY_UI_EDGE_URL=${backendUrl} npm run build-storybook`, {
|
|
604
|
-
cwd: storybookDir,
|
|
605
|
-
stdio: 'inherit'
|
|
606
|
-
});
|
|
607
|
-
// Deploy to Cloudflare Pages
|
|
608
|
-
const staticDir = path.join(storybookDir, 'storybook-static');
|
|
609
|
-
if (!fs.existsSync(staticDir)) {
|
|
610
|
-
console.error('❌ storybook-static directory not found after build');
|
|
611
|
-
return null;
|
|
612
|
-
}
|
|
613
|
-
console.log('🚀 Deploying to Cloudflare Pages...');
|
|
614
|
-
const result = execSync(`npx wrangler pages deploy ${staticDir} --project-name=${projectName}-storybook 2>&1`, {
|
|
615
|
-
encoding: 'utf-8'
|
|
616
|
-
});
|
|
617
|
-
console.log(result);
|
|
618
|
-
// Extract URL from output
|
|
619
|
-
const urlMatch = result.match(/https:\/\/[^\s]+\.pages\.dev/);
|
|
620
|
-
if (urlMatch) {
|
|
621
|
-
console.log(`\n✅ Storybook deployed to: ${urlMatch[0]}`);
|
|
622
|
-
return urlMatch[0];
|
|
623
|
-
}
|
|
624
|
-
return null;
|
|
625
|
-
}
|
|
626
|
-
catch (error) {
|
|
627
|
-
console.error('❌ Storybook deployment failed:', error.message);
|
|
628
|
-
if (error.stdout)
|
|
629
|
-
console.log(error.stdout);
|
|
630
|
-
if (error.stderr)
|
|
631
|
-
console.error(error.stderr);
|
|
632
|
-
return null;
|
|
633
|
-
}
|
|
634
|
-
}
|
|
635
|
-
/**
|
|
636
|
-
* Build and deploy standalone production app
|
|
637
|
-
* This builds a React app with the user's component library bundled in
|
|
638
|
-
*/
|
|
639
|
-
async function deployProductionApp(backendUrl, projectName, dryRun) {
|
|
640
|
-
console.log('\n🚀 Building Standalone Production App...\n');
|
|
641
|
-
console.log(' This creates a standalone web app with your component library\n');
|
|
642
|
-
const pkgRoot = getPackageRoot();
|
|
643
|
-
const userCwd = process.cwd();
|
|
644
|
-
const templateDir = path.join(pkgRoot, 'templates/production-app');
|
|
645
|
-
const buildDir = path.join(userCwd, '.story-ui-build');
|
|
646
|
-
// Check for story-ui.config.js in user's project
|
|
647
|
-
const configPath = path.join(userCwd, 'story-ui.config.js');
|
|
648
|
-
if (!fs.existsSync(configPath)) {
|
|
649
|
-
console.error('❌ No story-ui.config.js found in current directory');
|
|
650
|
-
console.log(' Run "npx story-ui init" first to configure your component library');
|
|
651
|
-
return null;
|
|
652
|
-
}
|
|
653
|
-
if (dryRun) {
|
|
654
|
-
console.log(`[DRY RUN] Would build production app from: ${templateDir}`);
|
|
655
|
-
console.log(`[DRY RUN] Would bundle with components from: ${configPath}`);
|
|
656
|
-
console.log(`[DRY RUN] Backend URL would be: ${backendUrl}`);
|
|
657
|
-
return 'https://dry-run.pages.dev';
|
|
658
|
-
}
|
|
659
|
-
try {
|
|
660
|
-
// 1. Copy template to build directory
|
|
661
|
-
console.log('📁 Setting up build directory...');
|
|
662
|
-
if (fs.existsSync(buildDir)) {
|
|
663
|
-
fs.rmSync(buildDir, { recursive: true });
|
|
664
|
-
}
|
|
665
|
-
fs.mkdirSync(buildDir, { recursive: true });
|
|
666
|
-
// Copy template files
|
|
667
|
-
copyDirectory(templateDir, buildDir);
|
|
668
|
-
// 2. Load user config and discover components
|
|
669
|
-
console.log('🔍 Discovering components from your library...');
|
|
670
|
-
const { generateComponentRegistry } = await import('../story-generator/componentRegistryGenerator.js');
|
|
671
|
-
const registryOutputPath = path.join(buildDir, 'src/componentRegistry.ts');
|
|
672
|
-
// Generate the component registry in the user's project context
|
|
673
|
-
process.chdir(userCwd);
|
|
674
|
-
await generateComponentRegistry(registryOutputPath);
|
|
675
|
-
// 2.5. Load ALL design system documentation (story-ui-docs/ AND story-ui-considerations.md)
|
|
676
|
-
console.log('📚 Loading design system documentation...');
|
|
677
|
-
// First, try the full documentation directory (story-ui-docs/)
|
|
678
|
-
const { DocumentationLoader } = await import('../story-generator/documentationLoader.js');
|
|
679
|
-
const docLoader = new DocumentationLoader(userCwd);
|
|
680
|
-
let fullDocumentation = '';
|
|
681
|
-
let documentationTokens = {};
|
|
682
|
-
let documentationPatterns = {};
|
|
683
|
-
let hasFullDocs = false;
|
|
684
|
-
if (docLoader.hasDocumentation()) {
|
|
685
|
-
console.log('📂 Found story-ui-docs/ directory, loading all documentation...');
|
|
686
|
-
const docs = await docLoader.loadDocumentation();
|
|
687
|
-
fullDocumentation = docLoader.formatForPrompt(docs);
|
|
688
|
-
documentationTokens = docs.tokens;
|
|
689
|
-
documentationPatterns = docs.patterns;
|
|
690
|
-
hasFullDocs = true;
|
|
691
|
-
console.log(` ✅ Loaded ${docs.guidelines.length} guidelines, ${Object.keys(docs.tokens).length} token categories, ${Object.keys(docs.patterns).length} patterns`);
|
|
692
|
-
}
|
|
693
|
-
// Also load legacy considerations file (story-ui-considerations.md)
|
|
694
|
-
const { loadConsiderations, considerationsToPrompt } = await import('../story-generator/considerationsLoader.js');
|
|
695
|
-
const considerations = loadConsiderations(); // Auto-finds in common locations
|
|
696
|
-
const considerationsPrompt = considerations ? considerationsToPrompt(considerations) : '';
|
|
697
|
-
// Combine both sources - full docs take priority, considerations supplement
|
|
698
|
-
let combinedDocumentation = '';
|
|
699
|
-
if (fullDocumentation) {
|
|
700
|
-
combinedDocumentation = fullDocumentation;
|
|
701
|
-
if (considerationsPrompt) {
|
|
702
|
-
// Add considerations as supplementary rules
|
|
703
|
-
combinedDocumentation += '\n\n📋 ADDITIONAL DESIGN SYSTEM RULES:\n' + considerationsPrompt;
|
|
704
|
-
}
|
|
705
|
-
}
|
|
706
|
-
else if (considerationsPrompt) {
|
|
707
|
-
combinedDocumentation = considerationsPrompt;
|
|
708
|
-
}
|
|
709
|
-
const considerationsOutputPath = path.join(buildDir, 'src/considerations.ts');
|
|
710
|
-
// Write comprehensive documentation to a TypeScript file
|
|
711
|
-
const considerationsContent = `/**
|
|
712
|
-
* AI Design System Documentation - Auto-generated
|
|
713
|
-
*
|
|
714
|
-
* This file contains ALL design system documentation for the AI:
|
|
715
|
-
* - Guidelines from story-ui-docs/ directory
|
|
716
|
-
* - Design tokens (colors, spacing, typography, etc.)
|
|
717
|
-
* - Component-specific documentation
|
|
718
|
-
* - Layout patterns
|
|
719
|
-
* - Accessibility rules
|
|
720
|
-
* - Legacy considerations from story-ui-considerations.md
|
|
721
|
-
*
|
|
722
|
-
* To customize:
|
|
723
|
-
* 1. Create a story-ui-docs/ directory with markdown/JSON files
|
|
724
|
-
* 2. And/or edit story-ui-considerations.md in your project root
|
|
725
|
-
*/
|
|
726
|
-
|
|
727
|
-
export const aiConsiderations = ${JSON.stringify(combinedDocumentation, null, 2)};
|
|
728
|
-
|
|
729
|
-
export const hasConsiderations = ${(hasFullDocs || considerations) ? 'true' : 'false'};
|
|
730
|
-
|
|
731
|
-
// Design tokens for programmatic access (if needed)
|
|
732
|
-
export const designTokens = ${JSON.stringify(documentationTokens, null, 2)};
|
|
733
|
-
|
|
734
|
-
// Design patterns for programmatic access (if needed)
|
|
735
|
-
export const designPatterns = ${JSON.stringify(documentationPatterns, null, 2)};
|
|
736
|
-
|
|
737
|
-
// Source information
|
|
738
|
-
export const documentationSource = {
|
|
739
|
-
hasFullDocs: ${hasFullDocs},
|
|
740
|
-
hasLegacyConsiderations: ${considerations ? 'true' : 'false'},
|
|
741
|
-
libraryName: ${JSON.stringify(considerations?.libraryName || null)}
|
|
742
|
-
};
|
|
743
|
-
`;
|
|
744
|
-
fs.writeFileSync(considerationsOutputPath, considerationsContent);
|
|
745
|
-
if (hasFullDocs && considerations) {
|
|
746
|
-
console.log(`✅ Loaded full documentation + considerations for: ${considerations.libraryName || 'your component library'}`);
|
|
747
|
-
}
|
|
748
|
-
else if (hasFullDocs) {
|
|
749
|
-
console.log('✅ Loaded full documentation from story-ui-docs/');
|
|
750
|
-
}
|
|
751
|
-
else if (considerations) {
|
|
752
|
-
console.log(`✅ Loaded considerations for: ${considerations.libraryName || 'your component library'}`);
|
|
753
|
-
}
|
|
754
|
-
else {
|
|
755
|
-
console.log('⚠️ No documentation found - using default prompts');
|
|
756
|
-
console.log(' Create story-ui-docs/ directory or story-ui-considerations.md for better results');
|
|
757
|
-
}
|
|
758
|
-
process.chdir(buildDir);
|
|
759
|
-
// 3. Install dependencies
|
|
760
|
-
console.log('📦 Installing dependencies...');
|
|
761
|
-
// Read the user's config
|
|
762
|
-
const userConfig = await import(configPath);
|
|
763
|
-
const config = userConfig.default;
|
|
764
|
-
const componentLibraryPackage = config.importPath;
|
|
765
|
-
// Update package.json to include the component library as a dependency
|
|
766
|
-
const packageJsonPath = path.join(buildDir, 'package.json');
|
|
767
|
-
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));
|
|
768
|
-
// Add dependencies from user config (design system agnostic)
|
|
769
|
-
const packagesToAdd = config.dependencies || [componentLibraryPackage];
|
|
770
|
-
for (const pkg of packagesToAdd) {
|
|
771
|
-
packageJson.dependencies[pkg] = '*';
|
|
772
|
-
}
|
|
773
|
-
// Add any additional imports as dependencies
|
|
774
|
-
if (config.additionalImports) {
|
|
775
|
-
for (const imp of config.additionalImports) {
|
|
776
|
-
packageJson.dependencies[imp.path] = '*';
|
|
777
|
-
}
|
|
778
|
-
}
|
|
779
|
-
fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2));
|
|
780
|
-
// 3.5. Generate main.tsx with user-defined provider (design system agnostic)
|
|
781
|
-
console.log('⚙️ Configuring app providers from story-ui.config.js...');
|
|
782
|
-
const mainTsxPath = path.join(buildDir, 'src/main.tsx');
|
|
783
|
-
const mainTsxContent = generateMainTsxFromConfig(config);
|
|
784
|
-
fs.writeFileSync(mainTsxPath, mainTsxContent);
|
|
785
|
-
// Install deps using npm with link to use local versions
|
|
786
|
-
execSync('npm install', { cwd: buildDir, stdio: 'inherit' });
|
|
787
|
-
// 4. Create .env file with backend URL
|
|
788
|
-
console.log('⚙️ Configuring backend URL...');
|
|
789
|
-
fs.writeFileSync(path.join(buildDir, '.env'), `VITE_STORY_UI_SERVER=${backendUrl}\nVITE_APP_TITLE=Story UI\n`);
|
|
790
|
-
// 5. Build the app
|
|
791
|
-
console.log('🔨 Building production app...');
|
|
792
|
-
execSync('npm run build', { cwd: buildDir, stdio: 'inherit' });
|
|
793
|
-
// 6. Deploy to Cloudflare Pages
|
|
794
|
-
console.log('☁️ Deploying to Cloudflare Pages...');
|
|
795
|
-
// Check wrangler auth
|
|
796
|
-
try {
|
|
797
|
-
execSync('npx wrangler whoami', { stdio: 'pipe' });
|
|
798
|
-
}
|
|
799
|
-
catch {
|
|
800
|
-
console.log('🔐 Not authenticated with Cloudflare.');
|
|
801
|
-
execSync('npx wrangler login', { stdio: 'inherit' });
|
|
802
|
-
}
|
|
803
|
-
const distDir = path.join(buildDir, 'dist');
|
|
804
|
-
const result = execSync(`npx wrangler pages deploy ${distDir} --project-name=${projectName}-app 2>&1`, {
|
|
805
|
-
encoding: 'utf-8'
|
|
806
|
-
});
|
|
807
|
-
console.log(result);
|
|
808
|
-
// Extract URL from output
|
|
809
|
-
const urlMatch = result.match(/https:\/\/[^\s]+\.pages\.dev/);
|
|
810
|
-
if (urlMatch) {
|
|
811
|
-
console.log(`\n✅ Production app deployed to: ${urlMatch[0]}`);
|
|
812
|
-
return urlMatch[0];
|
|
813
|
-
}
|
|
814
|
-
console.log('\n⚠️ Deployment completed but URL not detected in output.');
|
|
815
|
-
return null;
|
|
816
|
-
}
|
|
817
|
-
catch (error) {
|
|
818
|
-
console.error('❌ Production app deployment failed:', error.message);
|
|
819
|
-
if (error.stdout)
|
|
820
|
-
console.log(error.stdout);
|
|
821
|
-
if (error.stderr)
|
|
822
|
-
console.error(error.stderr);
|
|
823
|
-
return null;
|
|
824
|
-
}
|
|
825
|
-
finally {
|
|
826
|
-
// Return to original directory
|
|
827
|
-
process.chdir(userCwd);
|
|
828
|
-
}
|
|
829
|
-
}
|
|
830
|
-
/**
|
|
831
|
-
* Generate main.tsx from user config (design system agnostic)
|
|
832
|
-
*
|
|
833
|
-
* User's story-ui.config.js can define provider configuration:
|
|
834
|
-
* {
|
|
835
|
-
* provider: {
|
|
836
|
-
* cssImports: ["your-library/styles.css"], // CSS files to import
|
|
837
|
-
* imports: ["import { YourProvider } from 'your-library';"], // Provider imports
|
|
838
|
-
* wrapper: "<YourProvider>{children}</YourProvider>" // JSX wrapper with {children} placeholder
|
|
839
|
-
* }
|
|
840
|
-
* }
|
|
841
|
-
*/
|
|
842
|
-
function generateMainTsxFromConfig(config) {
|
|
843
|
-
const provider = config.provider || {};
|
|
844
|
-
// CSS imports (if any)
|
|
845
|
-
const cssImports = (provider.cssImports || [])
|
|
846
|
-
.map((css) => `import '${css}';`)
|
|
847
|
-
.join('\n');
|
|
848
|
-
// Provider component imports (if any)
|
|
849
|
-
const providerImports = (provider.imports || []).join('\n');
|
|
850
|
-
// Provider wrapper - replace {children} with <App />
|
|
851
|
-
let appElement = '<App />';
|
|
852
|
-
if (provider.wrapper) {
|
|
853
|
-
appElement = provider.wrapper.replace('{children}', '<App />');
|
|
854
|
-
}
|
|
855
|
-
return `/**
|
|
856
|
-
* Production App Entry Point
|
|
857
|
-
*
|
|
858
|
-
* This is the main entry point for the Story UI production app.
|
|
859
|
-
* Provider configuration is read from story-ui.config.js
|
|
860
|
-
*/
|
|
861
|
-
|
|
862
|
-
import React from 'react';
|
|
863
|
-
import ReactDOM from 'react-dom/client';
|
|
864
|
-
${cssImports}
|
|
865
|
-
${providerImports}
|
|
866
|
-
import App from './App';
|
|
867
|
-
import './index.css';
|
|
868
|
-
|
|
869
|
-
// Mount the app
|
|
870
|
-
const rootElement = document.getElementById('root');
|
|
871
|
-
|
|
872
|
-
if (!rootElement) {
|
|
873
|
-
throw new Error('Root element not found. Make sure there is a <div id="root"></div> in your HTML.');
|
|
874
|
-
}
|
|
875
|
-
|
|
876
|
-
ReactDOM.createRoot(rootElement).render(
|
|
877
|
-
<React.StrictMode>
|
|
878
|
-
${appElement}
|
|
879
|
-
</React.StrictMode>
|
|
880
|
-
);
|
|
881
|
-
`;
|
|
882
|
-
}
|
|
883
|
-
/**
|
|
884
|
-
* Helper function to copy directory recursively
|
|
885
|
-
*/
|
|
886
|
-
function copyDirectory(src, dest) {
|
|
887
|
-
if (!fs.existsSync(dest)) {
|
|
888
|
-
fs.mkdirSync(dest, { recursive: true });
|
|
889
|
-
}
|
|
890
|
-
const entries = fs.readdirSync(src, { withFileTypes: true });
|
|
891
|
-
for (const entry of entries) {
|
|
892
|
-
const srcPath = path.join(src, entry.name);
|
|
893
|
-
const destPath = path.join(dest, entry.name);
|
|
894
|
-
if (entry.isDirectory()) {
|
|
895
|
-
copyDirectory(srcPath, destPath);
|
|
896
|
-
}
|
|
897
|
-
else {
|
|
898
|
-
fs.copyFileSync(srcPath, destPath);
|
|
899
|
-
}
|
|
900
|
-
}
|
|
901
|
-
}
|
|
902
566
|
/**
|
|
903
567
|
* Print deployment summary
|
|
904
568
|
*/
|
|
905
|
-
function printSummary(backendUrl
|
|
569
|
+
function printSummary(backendUrl) {
|
|
906
570
|
console.log('\n' + '═'.repeat(60));
|
|
907
571
|
console.log('📋 DEPLOYMENT SUMMARY');
|
|
908
572
|
console.log('═'.repeat(60));
|
|
@@ -912,54 +576,14 @@ function printSummary(backendUrl, frontendUrl, appUrl) {
|
|
|
912
576
|
console.log(` - ${backendUrl}/story-ui/providers`);
|
|
913
577
|
console.log(` - ${backendUrl}/story-ui/generate-stream`);
|
|
914
578
|
console.log(` - ${backendUrl}/story-ui/stories`);
|
|
915
|
-
|
|
916
|
-
if (appUrl) {
|
|
917
|
-
console.log(`\n🚀 Production App: ${appUrl}`);
|
|
918
|
-
console.log(' This is your standalone web app with your component library');
|
|
919
|
-
console.log(' Users can prompt and see live-rendered components!');
|
|
920
|
-
}
|
|
921
|
-
if (frontendUrl) {
|
|
922
|
-
console.log(`\n🌐 Storybook UI: ${frontendUrl}`);
|
|
923
|
-
console.log(' (Legacy Storybook-based interface)');
|
|
924
|
-
}
|
|
925
|
-
if (backendUrl && (appUrl || frontendUrl)) {
|
|
926
|
-
console.log('\n✅ Full deployment complete!');
|
|
927
|
-
console.log(' Non-developers can now access Story UI at:');
|
|
928
|
-
if (appUrl) {
|
|
929
|
-
console.log(` ${appUrl} (Recommended)`);
|
|
930
|
-
}
|
|
931
|
-
if (frontendUrl) {
|
|
932
|
-
console.log(` ${frontendUrl} (Storybook)`);
|
|
933
|
-
}
|
|
579
|
+
console.log('\n✅ Deployment complete!');
|
|
934
580
|
}
|
|
935
581
|
console.log('\n' + '═'.repeat(60));
|
|
936
582
|
}
|
|
937
|
-
/**
|
|
938
|
-
* Legacy Cloudflare Edge deployment (deprecated)
|
|
939
|
-
*/
|
|
940
|
-
async function legacyEdgeDeployment(options) {
|
|
941
|
-
console.log('\n⚠️ WARNING: The Edge Worker deployment is deprecated.');
|
|
942
|
-
console.log(' It\'s recommended to use the new approach instead:');
|
|
943
|
-
console.log(' npx story-ui deploy --backend --platform=railway');
|
|
944
|
-
console.log(' npx story-ui deploy --frontend --backend-url=<your-backend-url>\n');
|
|
945
|
-
const answer = await prompt('Continue with legacy deployment? (y/N): ');
|
|
946
|
-
if (answer.toLowerCase() !== 'y') {
|
|
947
|
-
console.log('Aborted. Use --backend and --frontend for the new approach.');
|
|
948
|
-
return;
|
|
949
|
-
}
|
|
950
|
-
// Original legacy code here...
|
|
951
|
-
console.log('Legacy deployment not implemented in new CLI.');
|
|
952
|
-
console.log('Please use the new --backend and --frontend flags.');
|
|
953
|
-
}
|
|
954
583
|
export async function deployCommand(options) {
|
|
955
584
|
console.log('\n☁️ Story UI Production Deployment');
|
|
956
585
|
console.log('═'.repeat(40) + '\n');
|
|
957
|
-
//
|
|
958
|
-
if (options.edge || options.pages || options.all || options.init) {
|
|
959
|
-
await legacyEdgeDeployment(options);
|
|
960
|
-
return;
|
|
961
|
-
}
|
|
962
|
-
// NEW RECOMMENDED: Live Storybook deployment
|
|
586
|
+
// Live Storybook deployment (recommended)
|
|
963
587
|
// Runs Storybook in dev mode with MCP server - works with ANY components
|
|
964
588
|
if (options.live) {
|
|
965
589
|
const result = await deployLiveStorybook(options);
|
|
@@ -984,11 +608,8 @@ export async function deployCommand(options) {
|
|
|
984
608
|
}
|
|
985
609
|
return;
|
|
986
610
|
}
|
|
987
|
-
//
|
|
611
|
+
// Backend-only deployment
|
|
988
612
|
let backendUrl = options.backendUrl || null;
|
|
989
|
-
let frontendUrl = null;
|
|
990
|
-
let appUrl = null;
|
|
991
|
-
// Deploy backend
|
|
992
613
|
if (options.backend) {
|
|
993
614
|
const platform = options.platform || 'railway';
|
|
994
615
|
switch (platform) {
|
|
@@ -1007,38 +628,11 @@ export async function deployCommand(options) {
|
|
|
1007
628
|
console.log('\n⚠️ Backend deployment did not return a URL.');
|
|
1008
629
|
console.log(' You may need to check the platform dashboard for the URL.');
|
|
1009
630
|
}
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
if (options.app) {
|
|
1013
|
-
if (!backendUrl) {
|
|
1014
|
-
backendUrl = await prompt('Enter your backend URL: ');
|
|
1015
|
-
if (!backendUrl) {
|
|
1016
|
-
console.error('❌ Backend URL is required for app deployment.');
|
|
1017
|
-
return;
|
|
1018
|
-
}
|
|
1019
|
-
}
|
|
1020
|
-
const projectName = options.projectName || 'story-ui';
|
|
1021
|
-
appUrl = await deployProductionApp(backendUrl, projectName, options.dryRun || false);
|
|
1022
|
-
}
|
|
1023
|
-
// Deploy frontend (legacy Storybook-based)
|
|
1024
|
-
if (options.frontend) {
|
|
1025
|
-
if (!backendUrl) {
|
|
1026
|
-
backendUrl = await prompt('Enter your backend URL: ');
|
|
1027
|
-
if (!backendUrl) {
|
|
1028
|
-
console.error('❌ Backend URL is required for frontend deployment.');
|
|
1029
|
-
return;
|
|
1030
|
-
}
|
|
1031
|
-
}
|
|
1032
|
-
const storybookDir = options.storybookDir || process.cwd();
|
|
1033
|
-
const projectName = options.projectName || 'story-ui';
|
|
1034
|
-
frontendUrl = await deployStorybook(backendUrl, storybookDir, projectName, options.dryRun || false);
|
|
1035
|
-
}
|
|
1036
|
-
// Print summary
|
|
1037
|
-
if (options.backend || options.frontend || options.app) {
|
|
1038
|
-
printSummary(backendUrl, frontendUrl, appUrl);
|
|
631
|
+
printSummary(backendUrl);
|
|
632
|
+
return;
|
|
1039
633
|
}
|
|
1040
634
|
// Show help if no flags provided
|
|
1041
|
-
if (!options.backend && !options.
|
|
635
|
+
if (!options.backend && !options.live) {
|
|
1042
636
|
console.log('Story UI Deployment - Deploy your Storybook with AI story generation\n');
|
|
1043
637
|
console.log('═'.repeat(60));
|
|
1044
638
|
console.log(' RECOMMENDED: Live Storybook Deployment');
|
|
@@ -1067,16 +661,11 @@ export async function deployCommand(options) {
|
|
|
1067
661
|
console.log(' ANTHROPIC_API_KEY - Claude API key (recommended)');
|
|
1068
662
|
console.log(' OPENAI_API_KEY - OpenAI API key (optional)');
|
|
1069
663
|
console.log(' GEMINI_API_KEY - Google Gemini API key (optional)');
|
|
1070
|
-
console.log('
|
|
1071
|
-
console.log('
|
|
664
|
+
console.log(' DATABASE_URL - PostgreSQL URL for story persistence');
|
|
665
|
+
console.log(' (Set at least one API key)\n');
|
|
666
|
+
console.log('BACKEND-ONLY DEPLOYMENT:');
|
|
1072
667
|
console.log('─'.repeat(60));
|
|
1073
668
|
console.log(' --backend Deploy only the MCP server backend');
|
|
1074
|
-
console.log(' --app Deploy standalone production app (static)');
|
|
1075
|
-
console.log(' --frontend Deploy Storybook static build');
|
|
1076
669
|
console.log(' --backend-url <url> Use existing backend URL\n');
|
|
1077
|
-
console.log('DEPRECATED:');
|
|
1078
|
-
console.log('─'.repeat(60));
|
|
1079
|
-
console.log(' --init, --edge, --pages, --all');
|
|
1080
|
-
console.log(' These Cloudflare Edge options are deprecated. Use --live instead.\n');
|
|
1081
670
|
}
|
|
1082
671
|
}
|
package/dist/mcp-server/index.js
CHANGED
|
@@ -17,7 +17,7 @@ import { clearAllStories, getMemoryStats } from './routes/memoryStories.js';
|
|
|
17
17
|
import { getAllStories, getStoryById, getStoryContent, deleteStory } from './routes/hybridStories.js';
|
|
18
18
|
import { getSyncedStories, deleteSyncedStory, clearAllSyncedStories, syncChatHistory, validateChatSession, getSyncedStoryById } from './routes/storySync.js';
|
|
19
19
|
import { setupProductionGitignore } from '../story-generator/productionGitignoreManager.js';
|
|
20
|
-
import {
|
|
20
|
+
import { getStoryService, getStorageType } from '../story-generator/storyServiceFactory.js';
|
|
21
21
|
import { loadUserConfig } from '../story-generator/configLoader.js';
|
|
22
22
|
import { loadConsiderations, considerationsToPrompt } from '../story-generator/considerationsLoader.js';
|
|
23
23
|
import { DocumentationLoader } from '../story-generator/documentationLoader.js';
|
|
@@ -177,14 +177,14 @@ app.post('/story-ui/delete', async (req, res) => {
|
|
|
177
177
|
return res.status(400).json({ error: 'chatId or storyId is required' });
|
|
178
178
|
}
|
|
179
179
|
console.log(`🗑️ Attempting to delete story: ${id}`);
|
|
180
|
-
// First try
|
|
181
|
-
const storyService =
|
|
182
|
-
const
|
|
183
|
-
if (
|
|
184
|
-
console.log(`✅ Deleted story from
|
|
180
|
+
// First try storage service deletion (production mode)
|
|
181
|
+
const storyService = await getStoryService(config);
|
|
182
|
+
const serviceDeleted = await storyService.deleteStory(id);
|
|
183
|
+
if (serviceDeleted) {
|
|
184
|
+
console.log(`✅ Deleted story from ${getStorageType()}: ${id}`);
|
|
185
185
|
return res.json({
|
|
186
186
|
success: true,
|
|
187
|
-
message:
|
|
187
|
+
message: `Story deleted successfully from ${getStorageType()}`
|
|
188
188
|
});
|
|
189
189
|
}
|
|
190
190
|
// If not found in memory, try file-system deletion (development mode)
|
|
@@ -240,7 +240,6 @@ app.get('/story-ui/redirects.js', (req, res) => {
|
|
|
240
240
|
// Set up production-ready gitignore and directory structure on startup
|
|
241
241
|
const config = loadUserConfig();
|
|
242
242
|
const gitignoreManager = setupProductionGitignore(config);
|
|
243
|
-
const storyService = getInMemoryStoryService(config);
|
|
244
243
|
// Initialize URL redirect service
|
|
245
244
|
const redirectService = new UrlRedirectService(process.cwd());
|
|
246
245
|
const PORT = parseInt(process.env.PORT || '4001', 10);
|