@tpitre/story-ui 3.4.1 → 3.4.2

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.
@@ -146,7 +146,89 @@ app.get('/story-ui/frameworks/detect', detectCurrentFramework);
146
146
  app.get('/story-ui/frameworks/:type', getFrameworkDetails);
147
147
  app.post('/story-ui/frameworks/validate', validateStoryForFramework);
148
148
  app.post('/story-ui/frameworks/post-process', postProcessStoryForFramework);
149
- // Delete story from file system
149
+ // List generated stories from file system
150
+ app.get('/story-ui/stories', async (req, res) => {
151
+ try {
152
+ const storiesPath = config.generatedStoriesPath;
153
+ console.log(`📋 Listing stories from: ${storiesPath}`);
154
+ if (!fs.existsSync(storiesPath)) {
155
+ return res.json({ stories: [] });
156
+ }
157
+ const files = fs.readdirSync(storiesPath);
158
+ const stories = files
159
+ .filter(file => file.endsWith('.stories.tsx'))
160
+ .map(file => {
161
+ const filePath = path.join(storiesPath, file);
162
+ const stats = fs.statSync(filePath);
163
+ const content = fs.readFileSync(filePath, 'utf-8');
164
+ // Extract title from story file
165
+ const titleMatch = content.match(/title:\s*['"]([^'"]+)['"]/);
166
+ const title = titleMatch ? titleMatch[1].replace('Generated/', '') : file.replace('.stories.tsx', '');
167
+ return {
168
+ id: file.replace('.stories.tsx', ''),
169
+ fileName: file,
170
+ title,
171
+ lastUpdated: stats.mtime.getTime(),
172
+ code: content
173
+ };
174
+ })
175
+ .sort((a, b) => b.lastUpdated - a.lastUpdated);
176
+ console.log(`✅ Found ${stories.length} stories`);
177
+ return res.json({ stories });
178
+ }
179
+ catch (error) {
180
+ console.error('Error listing stories:', error);
181
+ return res.status(500).json({ error: 'Failed to list stories' });
182
+ }
183
+ });
184
+ // Save story to file system
185
+ app.post('/story-ui/stories', async (req, res) => {
186
+ try {
187
+ const { id, title, code } = req.body;
188
+ if (!id || !code) {
189
+ return res.status(400).json({ error: 'id and code are required' });
190
+ }
191
+ const storiesPath = config.generatedStoriesPath;
192
+ // Ensure stories directory exists
193
+ if (!fs.existsSync(storiesPath)) {
194
+ fs.mkdirSync(storiesPath, { recursive: true });
195
+ }
196
+ const fileName = `${id}.stories.tsx`;
197
+ const filePath = path.join(storiesPath, fileName);
198
+ fs.writeFileSync(filePath, code, 'utf-8');
199
+ console.log(`✅ Saved story: ${filePath}`);
200
+ return res.json({
201
+ success: true,
202
+ id,
203
+ fileName,
204
+ title
205
+ });
206
+ }
207
+ catch (error) {
208
+ console.error('Error saving story:', error);
209
+ return res.status(500).json({ error: 'Failed to save story' });
210
+ }
211
+ });
212
+ // Delete story by ID (RESTful endpoint)
213
+ app.delete('/story-ui/stories/:id', async (req, res) => {
214
+ try {
215
+ const { id } = req.params;
216
+ const storiesPath = config.generatedStoriesPath;
217
+ const fileName = id.endsWith('.stories.tsx') ? id : `${id}.stories.tsx`;
218
+ const filePath = path.join(storiesPath, fileName);
219
+ if (fs.existsSync(filePath)) {
220
+ fs.unlinkSync(filePath);
221
+ console.log(`✅ Deleted story: ${filePath}`);
222
+ return res.json({ success: true, message: 'Story deleted successfully' });
223
+ }
224
+ return res.status(404).json({ success: false, error: 'Story not found' });
225
+ }
226
+ catch (error) {
227
+ console.error('Error deleting story:', error);
228
+ return res.status(500).json({ error: 'Failed to delete story' });
229
+ }
230
+ });
231
+ // Delete story from file system (legacy POST endpoint)
150
232
  app.post('/story-ui/delete', async (req, res) => {
151
233
  try {
152
234
  const { chatId, storyId } = req.body;
@@ -1 +1 @@
1
- {"version":3,"file":"StoryUIPanel.d.ts","sourceRoot":"","sources":["../../../templates/StoryUI/StoryUIPanel.tsx"],"names":[],"mappings":"AAsSA,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,MAAM;QACd,2BAA2B,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;KACtD;CACF;AA6oCD,iBAAS,YAAY,4CA8sCpB;AAED,eAAe,YAAY,CAAC;AAC5B,OAAO,EAAE,YAAY,EAAE,CAAC"}
1
+ {"version":3,"file":"StoryUIPanel.d.ts","sourceRoot":"","sources":["../../../templates/StoryUI/StoryUIPanel.tsx"],"names":[],"mappings":"AAiTA,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,MAAM;QACd,2BAA2B,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;KACtD;CACF;AA6oCD,iBAAS,YAAY,4CA8sCpB;AAED,eAAe,YAAY,CAAC;AAC5B,OAAO,EAAE,YAAY,EAAE,CAAC"}
@@ -82,10 +82,11 @@ const StatusIcons = {
82
82
  // Priority order:
83
83
  // 1. VITE_STORY_UI_EDGE_URL - Edge Worker URL for cloud deployments
84
84
  // 2. window.__STORY_UI_EDGE_URL__ - Runtime override for edge URL
85
- // 3. VITE_STORY_UI_PORT - Custom port for localhost
86
- // 4. window.__STORY_UI_PORT__ - Legacy port override
87
- // 5. window.STORY_UI_MCP_PORT - MCP port override
88
- // 6. Default to localhost:4001
85
+ // 3. Production domains (railway.app, render.com, pages.dev) - use same origin
86
+ // 4. VITE_STORY_UI_PORT - Custom port for localhost
87
+ // 5. window.__STORY_UI_PORT__ - Legacy port override
88
+ // 6. window.STORY_UI_MCP_PORT - MCP port override
89
+ // 7. Default to localhost:4001
89
90
  const getApiBaseUrl = () => {
90
91
  // Check for Edge Worker URL (cloud deployment)
91
92
  const edgeUrl = import.meta.env?.VITE_STORY_UI_EDGE_URL;
@@ -95,6 +96,15 @@ const getApiBaseUrl = () => {
95
96
  const windowEdgeUrl = window.__STORY_UI_EDGE_URL__ || window.STORY_UI_EDGE_URL;
96
97
  if (windowEdgeUrl)
97
98
  return windowEdgeUrl.replace(/\/$/, '');
99
+ // Check if we're running on Railway production domain
100
+ // In this case, the MCP server is proxied through the same origin
101
+ if (typeof window !== 'undefined') {
102
+ const hostname = window.location.hostname;
103
+ if (hostname.includes('.railway.app')) {
104
+ // Use same-origin requests (empty string means relative URLs)
105
+ return '';
106
+ }
107
+ }
98
108
  // Check for Vite port environment variable
99
109
  const vitePort = import.meta.env?.VITE_STORY_UI_PORT;
100
110
  if (vitePort)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tpitre/story-ui",
3
- "version": "3.4.1",
3
+ "version": "3.4.2",
4
4
  "description": "AI-powered Storybook story generator with dynamic component discovery",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -249,10 +249,11 @@ interface ChatSession {
249
249
  // Priority order:
250
250
  // 1. VITE_STORY_UI_EDGE_URL - Edge Worker URL for cloud deployments
251
251
  // 2. window.__STORY_UI_EDGE_URL__ - Runtime override for edge URL
252
- // 3. VITE_STORY_UI_PORT - Custom port for localhost
253
- // 4. window.__STORY_UI_PORT__ - Legacy port override
254
- // 5. window.STORY_UI_MCP_PORT - MCP port override
255
- // 6. Default to localhost:4001
252
+ // 3. Production domains (railway.app, render.com, pages.dev) - use same origin
253
+ // 4. VITE_STORY_UI_PORT - Custom port for localhost
254
+ // 5. window.__STORY_UI_PORT__ - Legacy port override
255
+ // 6. window.STORY_UI_MCP_PORT - MCP port override
256
+ // 7. Default to localhost:4001
256
257
  const getApiBaseUrl = () => {
257
258
  // Check for Edge Worker URL (cloud deployment)
258
259
  const edgeUrl = (import.meta as any).env?.VITE_STORY_UI_EDGE_URL;
@@ -262,6 +263,16 @@ const getApiBaseUrl = () => {
262
263
  const windowEdgeUrl = (window as any).__STORY_UI_EDGE_URL__ || (window as any).STORY_UI_EDGE_URL;
263
264
  if (windowEdgeUrl) return windowEdgeUrl.replace(/\/$/, '');
264
265
 
266
+ // Check if we're running on Railway production domain
267
+ // In this case, the MCP server is proxied through the same origin
268
+ if (typeof window !== 'undefined') {
269
+ const hostname = window.location.hostname;
270
+ if (hostname.includes('.railway.app')) {
271
+ // Use same-origin requests (empty string means relative URLs)
272
+ return '';
273
+ }
274
+ }
275
+
265
276
  // Check for Vite port environment variable
266
277
  const vitePort = (import.meta as any).env?.VITE_STORY_UI_PORT;
267
278
  if (vitePort) return `http://localhost:${vitePort}`;