storyforge 0.1.2 → 0.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.
Files changed (2) hide show
  1. package/dist/index.js +51 -0
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  // src/commands/dev.ts
4
4
  import * as fs2 from "fs";
5
+ import * as os2 from "os";
5
6
  import * as path2 from "path";
6
7
  import * as http from "http";
7
8
  import { execFile } from "child_process";
@@ -285,6 +286,56 @@ async function devCommand(options) {
285
286
  res.end(JSON.stringify(assets));
286
287
  return;
287
288
  }
289
+ if (pathname === "/api/compositions") {
290
+ const compositionsDir = path2.join(os2.homedir(), ".forge", "compositions", meta.projectId);
291
+ fs2.mkdirSync(compositionsDir, { recursive: true });
292
+ const files = fs2.readdirSync(compositionsDir).filter((f) => f.endsWith(".tsx"));
293
+ const list = files.map((f) => ({ name: f.replace(/\.tsx$/, ""), path: path2.join(compositionsDir, f) }));
294
+ res.writeHead(200, { ...CORS_HEADERS, "Content-Type": "application/json" });
295
+ res.end(JSON.stringify(list));
296
+ return;
297
+ }
298
+ const compGetMatch = pathname.match(/^\/api\/compositions\/([^/]+)$/);
299
+ if (req.method === "GET" && compGetMatch) {
300
+ const name = compGetMatch[1].replace(/[^a-zA-Z0-9_-]/g, "");
301
+ if (!name) {
302
+ res.writeHead(400, CORS_HEADERS);
303
+ res.end("Invalid name");
304
+ return;
305
+ }
306
+ const compositionsDir = path2.join(os2.homedir(), ".forge", "compositions", meta.projectId);
307
+ const filePath = path2.join(compositionsDir, `${name}.tsx`);
308
+ if (!fs2.existsSync(filePath)) {
309
+ res.writeHead(404, CORS_HEADERS);
310
+ res.end("Not found");
311
+ return;
312
+ }
313
+ const content = fs2.readFileSync(filePath, "utf-8");
314
+ res.writeHead(200, { ...CORS_HEADERS, "Content-Type": "text/plain; charset=utf-8" });
315
+ res.end(content);
316
+ return;
317
+ }
318
+ const compPostMatch = pathname.match(/^\/api\/compositions\/([^/]+)$/);
319
+ if (req.method === "POST" && compPostMatch) {
320
+ const name = compPostMatch[1].replace(/[^a-zA-Z0-9_-]/g, "");
321
+ if (!name) {
322
+ res.writeHead(400, CORS_HEADERS);
323
+ res.end("Invalid name");
324
+ return;
325
+ }
326
+ const compositionsDir = path2.join(os2.homedir(), ".forge", "compositions", meta.projectId);
327
+ fs2.mkdirSync(compositionsDir, { recursive: true });
328
+ const filePath = path2.join(compositionsDir, `${name}.tsx`);
329
+ const chunks = [];
330
+ req.on("data", (chunk) => chunks.push(chunk));
331
+ req.on("end", () => {
332
+ const body = Buffer.concat(chunks).toString("utf-8");
333
+ fs2.writeFileSync(filePath, body, "utf-8");
334
+ res.writeHead(200, { ...CORS_HEADERS, "Content-Type": "application/json" });
335
+ res.end(JSON.stringify({ ok: true, path: filePath }));
336
+ });
337
+ return;
338
+ }
288
339
  const fileMatch = pathname.match(/^\/api\/file\/(.+)$/);
289
340
  if (fileMatch) {
290
341
  const filePath = decodeURIComponent(fileMatch[1]);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "storyforge",
3
- "version": "0.1.2",
3
+ "version": "0.2.0",
4
4
  "description": "StoryForge — local bridge for the Forge video production web app. Zero runtime dependencies.",
5
5
  "type": "module",
6
6
  "bin": {