storyforge 0.11.4 → 0.12.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 +79 -5
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -39,10 +39,26 @@ function loadCredentials() {
39
39
  return null;
40
40
  }
41
41
  }
42
+ function findEnvFilesWalkingUp(startDir) {
43
+ const found = [];
44
+ const home = os.homedir();
45
+ let dir = startDir;
46
+ for (let i = 0; i < 10; i++) {
47
+ const env = path.join(dir, ".env");
48
+ if (fs.existsSync(env)) found.push(env);
49
+ const nextEnv = path.join(dir, "apps", "web", ".env.local");
50
+ if (fs.existsSync(nextEnv)) found.push(nextEnv);
51
+ const parent = path.dirname(dir);
52
+ if (parent === dir || dir === home) break;
53
+ dir = parent;
54
+ }
55
+ return found;
56
+ }
42
57
  function loadDotEnv() {
43
58
  const loaded = [];
44
59
  const sources = [];
45
- const candidates = [path.resolve(process.cwd(), ".env"), ...FORGE_ENV_PATHS];
60
+ const walkedUp = findEnvFilesWalkingUp(path.resolve(process.cwd()));
61
+ const candidates = [...walkedUp, ...FORGE_ENV_PATHS];
46
62
  for (const file of candidates) {
47
63
  let content;
48
64
  try {
@@ -68,6 +84,52 @@ function loadDotEnv() {
68
84
  }
69
85
  return { loaded, sources };
70
86
  }
87
+ async function fetchBridgeCredentials(opts) {
88
+ const fetchImpl = opts.fetchImpl ?? fetch;
89
+ const timeoutMs = opts.timeoutMs ?? 1e4;
90
+ const url = `${opts.apiUrl.replace(/\/$/, "")}/api/cli-bridge/credentials`;
91
+ const ctrl = new AbortController();
92
+ const timer = setTimeout(() => ctrl.abort(), timeoutMs);
93
+ let resp;
94
+ try {
95
+ resp = await fetchImpl(url, {
96
+ method: "GET",
97
+ headers: {
98
+ Authorization: `Bearer ${opts.token}`,
99
+ Accept: "application/json"
100
+ },
101
+ signal: ctrl.signal
102
+ });
103
+ } catch (err) {
104
+ return { loaded: [], source: url, error: err.message };
105
+ } finally {
106
+ clearTimeout(timer);
107
+ }
108
+ if (!resp.ok) {
109
+ const text = await resp.text().catch(() => "");
110
+ return { loaded: [], source: url, error: `HTTP ${resp.status}: ${text.slice(0, 200)}` };
111
+ }
112
+ let body;
113
+ try {
114
+ body = await resp.json();
115
+ } catch (err) {
116
+ return { loaded: [], source: url, error: `parse: ${err.message}` };
117
+ }
118
+ const creds = body.credentials ?? {};
119
+ const loaded = [];
120
+ for (const [key, val] of Object.entries(creds)) {
121
+ if (typeof val !== "string" || val.length === 0) continue;
122
+ if (process.env[key] != null) continue;
123
+ process.env[key] = val;
124
+ loaded.push(key);
125
+ }
126
+ return {
127
+ loaded,
128
+ source: url,
129
+ knownCount: body.knownCount,
130
+ availableCount: body.availableCount
131
+ };
132
+ }
71
133
 
72
134
  // src/utils/script-prompt.ts
73
135
  var STYLE_GUIDES = {
@@ -839,6 +901,18 @@ async function devCommand(options) {
839
901
  if (env.loaded.length > 0) {
840
902
  log.info(`Loaded env: ${env.loaded.join(", ")} from ${env.sources.join(", ")}`);
841
903
  }
904
+ const bridgeToken = process.env.FORGE_BRIDGE_TOKEN ?? process.env.BRIDGE_TOKEN ?? "";
905
+ if (bridgeToken) {
906
+ const apiUrl = process.env.FORGE_BRIDGE_URL ?? WEB_URL;
907
+ const credResult = await fetchBridgeCredentials({ apiUrl, token: bridgeToken });
908
+ if (credResult.error) {
909
+ log.info(`Bridge cred fetch skipped: ${credResult.error}`);
910
+ } else if (credResult.loaded.length > 0) {
911
+ log.info(`Loaded ${credResult.loaded.length} cloud creds from Vercel: ${credResult.loaded.join(", ")}`);
912
+ } else if (credResult.availableCount != null) {
913
+ log.info(`Bridge cred fetch: 0 new keys (server has ${credResult.availableCount}/${credResult.knownCount ?? "?"}, all already set locally)`);
914
+ }
915
+ }
842
916
  void (async () => {
843
917
  try {
844
918
  const { gatherCliUsage, CLI_USAGE_PARSER_VERSION } = await import("./cli-usage-G762TREV.js");
@@ -1603,8 +1677,8 @@ Return ONLY the complete updated TSX. No markdown fences, no explanation.`;
1603
1677
  console.log(` POST http://localhost:${port}/api/script-gen`);
1604
1678
  }
1605
1679
  const bridgeUrl = process.env.FORGE_BRIDGE_URL ?? WEB_URL;
1606
- const bridgeToken = process.env.FORGE_BRIDGE_TOKEN ?? process.env.BRIDGE_TOKEN ?? "";
1607
- if (bridgeToken) {
1680
+ const bridgeToken2 = process.env.FORGE_BRIDGE_TOKEN ?? process.env.BRIDGE_TOKEN ?? "";
1681
+ if (bridgeToken2) {
1608
1682
  const pkgVersion = (() => {
1609
1683
  try {
1610
1684
  const here = path2.dirname(new URL(import.meta.url).pathname);
@@ -1616,7 +1690,7 @@ Return ONLY the complete updated TSX. No markdown fences, no explanation.`;
1616
1690
  })();
1617
1691
  void (async () => {
1618
1692
  const { BridgePoller } = await import("./bridge-poller-6AWMIF3V.js");
1619
- const poller = new BridgePoller({ baseUrl: bridgeUrl, token: bridgeToken, clientVersion: `storyforge ${pkgVersion}` });
1693
+ const poller = new BridgePoller({ baseUrl: bridgeUrl, token: bridgeToken2, clientVersion: `storyforge ${pkgVersion}` });
1620
1694
  poller.start();
1621
1695
  })();
1622
1696
  console.log("");
@@ -2438,7 +2512,7 @@ function resolveBridgeToken2(explicit) {
2438
2512
  // package.json
2439
2513
  var package_default = {
2440
2514
  name: "storyforge",
2441
- version: "0.11.4",
2515
+ version: "0.12.0",
2442
2516
  description: "StoryForge \u2014 local bridge for the Forge video production web app. Parallel clip-render orchestrator (Remotion 4 + Manim + HyperFrames + ffmpeg) + final video stitcher + dependency doctor.",
2443
2517
  type: "module",
2444
2518
  bin: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "storyforge",
3
- "version": "0.11.4",
3
+ "version": "0.12.0",
4
4
  "description": "StoryForge — local bridge for the Forge video production web app. Parallel clip-render orchestrator (Remotion 4 + Manim + HyperFrames + ffmpeg) + final video stitcher + dependency doctor.",
5
5
  "type": "module",
6
6
  "bin": {