truecanvas 0.6.0 → 0.6.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.
@@ -564,6 +564,13 @@ async function startHub(opts) {
564
564
  const store = new ProjectStore();
565
565
  const editorDir = fileURLToPath(new URL("./editor/", import.meta.url));
566
566
  const pkgDir = path5.resolve(path5.dirname(opts.cli), "..");
567
+ const version = (() => {
568
+ try {
569
+ return JSON.parse(fs5.readFileSync(path5.join(pkgDir, "package.json"), "utf8")).version;
570
+ } catch {
571
+ return "";
572
+ }
573
+ })();
567
574
  const origin = `http://localhost:${opts.port}`;
568
575
  const allowedHosts = /* @__PURE__ */ new Set([`localhost:${opts.port}`, `127.0.0.1:${opts.port}`]);
569
576
  const clients = /* @__PURE__ */ new Set();
@@ -628,6 +635,7 @@ async function startHub(opts) {
628
635
  const live = await Promise.all(running.map(async (dir) => [dir, await sessionsOf(dir)]));
629
636
  return {
630
637
  origin,
638
+ version,
631
639
  active,
632
640
  focus,
633
641
  notice: opts.notice ?? null,
package/dist/cli.js CHANGED
@@ -14,7 +14,7 @@ import {
14
14
  readPackage,
15
15
  runScript,
16
16
  startHub
17
- } from "./chunk-NAK4DQWO.js";
17
+ } from "./chunk-FJO64PGM.js";
18
18
  import {
19
19
  CHUNK,
20
20
  decodeFrame,
@@ -1659,6 +1659,9 @@ function serializePage() {
1659
1659
  ${root.outerHTML}`, css, canvases, height };
1660
1660
  }
1661
1661
 
1662
+ // src/server/app-run.ts
1663
+ var appRun = { state: "external", log: [] };
1664
+
1662
1665
  // src/server/review.ts
1663
1666
  import fs5 from "fs";
1664
1667
  import path6 from "path";
@@ -2264,7 +2267,11 @@ var Sessions = class {
2264
2267
  get(canvas) {
2265
2268
  return this.sessions.get(canvas) ?? null;
2266
2269
  }
2267
- /** Starts (or returns) the canvas's session. The canvas needs a link: share it first. */
2270
+ /**
2271
+ * Starts (or returns) the canvas's session. A canvas that has no link yet is
2272
+ * shared first through `opts.share` (invited-only on sites with sign-in), so
2273
+ * going live is one click.
2274
+ */
2268
2275
  async start(canvas, opts = {}) {
2269
2276
  const running = this.sessions.get(canvas);
2270
2277
  if (running && running.state.status !== "stopped") return running.state;
@@ -2272,12 +2279,19 @@ var Sessions = class {
2272
2279
  if (!site) throw new Error("No review site yet: connect one with `npx truecanvas share setup`, share the canvas, then start a session.");
2273
2280
  const features = await siteFeatures(site);
2274
2281
  if (!features.includes("session")) throw new Error("This review site doesn't support live sessions yet: deploy the latest review site (packages/review-worker) with LIVE_HOST_SUFFIX set.");
2275
- const res = await fetch(`${site.url}/api/shares?project=${encodeURIComponent(this.project)}&canvas=${encodeURIComponent(canvas)}`, {
2276
- headers: { authorization: `Bearer ${site.token}` },
2277
- signal: AbortSignal.timeout(2e4)
2278
- });
2279
- if (!res.ok) throw new Error(`Review site: ${res.status} ${res.statusText}`);
2280
- const { slug } = await res.json();
2282
+ const lookup = async () => {
2283
+ const res = await fetch(`${site.url}/api/shares?project=${encodeURIComponent(this.project)}&canvas=${encodeURIComponent(canvas)}`, {
2284
+ headers: { authorization: `Bearer ${site.token}` },
2285
+ signal: AbortSignal.timeout(2e4)
2286
+ });
2287
+ if (!res.ok) throw new Error(`Review site: ${res.status} ${res.statusText}`);
2288
+ return (await res.json()).slug;
2289
+ };
2290
+ let slug = await lookup();
2291
+ if (!slug && opts.share) {
2292
+ await opts.share();
2293
+ slug = await lookup();
2294
+ }
2281
2295
  if (!slug) throw new Error(`${canvas} has no link yet. Share it once (Share, or \`npx truecanvas share ${canvas}\`), then start a session.`);
2282
2296
  const session = new LiveSession(site, slug, canvas, this.appUrl, {
2283
2297
  name: opts.name ?? "Studio",
@@ -2406,6 +2420,8 @@ async function startServer(ws) {
2406
2420
  const route = `${req.method} ${url.pathname}`;
2407
2421
  const user = { kind: "user" };
2408
2422
  switch (route) {
2423
+ case "GET /api/app":
2424
+ return json(res, 200, appRun);
2409
2425
  case "GET /api/state":
2410
2426
  return json(res, 200, {
2411
2427
  appUrl: config.appUrl,
@@ -2720,7 +2736,14 @@ async function startServer(ws) {
2720
2736
  const canvas = body.canvas ?? ws.selection.canvas ?? ws.canvases()[0];
2721
2737
  if (!canvas) return json(res, 400, { error: "No canvas to share live yet." });
2722
2738
  assertCanvasName(canvas);
2723
- return json(res, 200, { session: await sessions.start(canvas, { name: body.name }) });
2739
+ const share = async () => {
2740
+ const site = reviewSite();
2741
+ if (!site) return;
2742
+ const { dir, manifest } = await createSnapshot(ws, shots, canvas, {});
2743
+ await publishSnapshot(site, dir, manifest, {});
2744
+ commentSync.forget(canvas);
2745
+ };
2746
+ return json(res, 200, { session: await sessions.start(canvas, { name: body.name, share }) });
2724
2747
  }
2725
2748
  case "POST /api/session/stop": {
2726
2749
  const { canvas } = await readJson(req);
@@ -3497,7 +3520,10 @@ async function main() {
3497
3520
  let next = null;
3498
3521
  const appUp = await reachable(config.appUrl);
3499
3522
  const devCommand = config.framework === "vite" ? "vite" : "next dev";
3500
- if (!appUp && values.next && !values["no-next"]) next = startApp(root, config.appUrl, config.framework);
3523
+ if (!appUp && values.next && !values["no-next"]) {
3524
+ next = startApp(root, config.appUrl, config.framework);
3525
+ appRun.state = "starting";
3526
+ }
3501
3527
  console.log(`
3502
3528
  ${c.accent("\u25C6")} ${c.bold("Truecanvas")} ${c.dim(`v${version}`)}
3503
3529
 
@@ -3510,7 +3536,11 @@ ${hasAgentConfig(root, config.port) ? ` ${c.dim("Agents")} connected through
3510
3536
  `);
3511
3537
  if (next) {
3512
3538
  const exited = new Promise((r) => next.once("exit", () => r("exited")));
3539
+ void exited.then(() => {
3540
+ if (appRun.state !== "ready") appRun.state = "failed";
3541
+ });
3513
3542
  const result = await Promise.race([waitFor(config.appUrl, 9e4), exited]);
3543
+ if (result === true) appRun.state = "ready";
3514
3544
  if (result === true) console.log(` ${c.green("\u2713")} App ready at ${config.appUrl}
3515
3545
  `);
3516
3546
  else if (result === "exited") console.log(` ${c.dim(`${devCommand} stopped (see above). Start your app, the editor connects as soon as it's up.`)}
@@ -3664,8 +3694,13 @@ function startApp(root, appUrl, framework) {
3664
3694
  buf += chunk.toString();
3665
3695
  const lines = buf.split(/\r?\n/);
3666
3696
  buf = lines.pop();
3667
- for (const line of lines) if (line.trim()) process.stdout.write(` ${prefix}${line}
3697
+ for (const line of lines) {
3698
+ if (!line.trim()) continue;
3699
+ process.stdout.write(` ${prefix}${line}
3668
3700
  `);
3701
+ appRun.log.push(line.replace(/\x1b\[[0-9;]*m/g, ""));
3702
+ if (appRun.log.length > 20) appRun.log.shift();
3703
+ }
3669
3704
  });
3670
3705
  }
3671
3706
  return child;