@neta-art/cohub-cli 8.4.0 → 8.4.1

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/dist/avatar.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { readFile } from "node:fs/promises";
2
- import sharp from "sharp";
2
+ const loadSharp = async () => (await import("sharp")).default;
3
3
  const AVATAR_SIZE = 1024;
4
4
  const AVATAR_QUALITY = 86;
5
5
  const detectAvatarFormat = (body) => {
@@ -25,6 +25,7 @@ export async function normalizeAvatarFile(path) {
25
25
  if (originalFormat.mimeType === "image/gif")
26
26
  return { body: original, ...originalFormat };
27
27
  try {
28
+ const sharp = await loadSharp();
28
29
  const body = await sharp(original)
29
30
  .rotate()
30
31
  .resize(AVATAR_SIZE, AVATAR_SIZE, { fit: "cover", position: "centre" })
@@ -49,6 +50,7 @@ export async function uploadAvatarAsset(input) {
49
50
  const CHAT_IMAGE_MAX_EDGE = 1984;
50
51
  const CHAT_IMAGE_QUALITY = 86;
51
52
  export async function normalizeChatImageFile(path) {
53
+ const sharp = await loadSharp();
52
54
  return sharp(path)
53
55
  .rotate()
54
56
  .resize(CHAT_IMAGE_MAX_EDGE, CHAT_IMAGE_MAX_EDGE, { fit: "inside", withoutEnlargement: true })
@@ -7,19 +7,15 @@
7
7
  * lives here: fetching the document over HTTP, pulling image bytes out of the
8
8
  * space, and locating fonts on disk.
9
9
  */
10
- import { type BoardDocument, type BoardExportRegion, type BoardItem } from "@neta-art/cohub/board";
11
- import { type BoardHeadlessExportFormat, type BoardHeadlessFont, type BoardHeadlessRenderer, type BoardHeadlessTexture } from "@neta-art/cohub/board/headless";
12
- export declare const BOARD_EXPORT_FORMATS: BoardHeadlessExportFormat[];
13
- /** Infer the output format from the file extension, defaulting to PNG. */
14
- export declare function formatFromPath(path: string): BoardHeadlessExportFormat;
10
+ import type { BoardDocument, BoardExportRegion, BoardItem } from "@neta-art/cohub/board";
11
+ import type { BoardHeadlessExportFormat, BoardHeadlessFont, BoardHeadlessRenderer, BoardHeadlessTexture } from "@neta-art/cohub/board/headless";
15
12
  /**
16
13
  * Geist, as shipped to the browser.
17
14
  *
18
15
  * The board asks for the "Geist" family; registering the exact same font files
19
16
  * the web app loads is what makes CLI output match the editor rather than
20
- * substituting whatever sans-serif the host happens to have. Resolution is
21
- * best-effort: if the font package is not installed the export still succeeds,
22
- * falling back through the font stack.
17
+ * substituting whatever sans-serif the host happens to have. A source checkout
18
+ * falls back to the dev packages.
23
19
  */
24
20
  export declare function resolveBundledFonts(): BoardHeadlessFont[];
25
21
  export type BoardExportSource = {
@@ -10,51 +10,39 @@
10
10
  import { existsSync } from "node:fs";
11
11
  import { createRequire } from "node:module";
12
12
  import { dirname, join } from "node:path";
13
- import { boardAuthoringSnapshotToDocument, boardImageKeySource, imageAssetKey, planBoardExport, selectBoardExportAssets, } from "@neta-art/cohub/board";
14
- import { createBoardHeadlessRenderer, exportBoardImageBytes, } from "@neta-art/cohub/board/headless";
13
+ import { fileURLToPath } from "node:url";
14
+ import { boardAuthoringSnapshotToDocument, boardImageKeySource, createBoardHeadlessRenderer, exportBoardImageBytes, imageAssetKey, planBoardExport, selectBoardExportAssets, } from "./board-kernel.js";
15
15
  import { resolveBoardId } from "./board-command-support.js";
16
+ import { BOARD_EXPORT_FONTS } from "./board-fonts.js";
16
17
  import { createClient } from "./client.js";
17
18
  import { downloadPublicImage } from "./safe-remote-image.js";
18
- export const BOARD_EXPORT_FORMATS = ["png", "jpeg", "webp"];
19
- /** Infer the output format from the file extension, defaulting to PNG. */
20
- export function formatFromPath(path) {
21
- const lower = path.toLowerCase();
22
- if (lower.endsWith(".jpg") || lower.endsWith(".jpeg"))
23
- return "jpeg";
24
- if (lower.endsWith(".webp"))
25
- return "webp";
26
- return "png";
27
- }
28
19
  /**
29
20
  * Geist, as shipped to the browser.
30
21
  *
31
22
  * The board asks for the "Geist" family; registering the exact same font files
32
23
  * the web app loads is what makes CLI output match the editor rather than
33
- * substituting whatever sans-serif the host happens to have. Resolution is
34
- * best-effort: if the font package is not installed the export still succeeds,
35
- * falling back through the font stack.
24
+ * substituting whatever sans-serif the host happens to have. A source checkout
25
+ * falls back to the dev packages.
36
26
  */
37
27
  export function resolveBundledFonts() {
38
28
  const require = createRequire(import.meta.url);
39
- const fonts = [];
40
- const candidates = [
41
- { pkg: "@fontsource/geist", file: "geist-latin-500-normal.woff2", family: "Geist" },
42
- { pkg: "@fontsource/geist", file: "geist-latin-400-normal.woff2", family: "Geist" },
43
- { pkg: "@fontsource/geist", file: "geist-latin-600-normal.woff2", family: "Geist" },
44
- { pkg: "@fontsource/geist-mono", file: "geist-mono-latin-400-normal.woff2", family: "Geist Mono" },
45
- ];
46
- for (const candidate of candidates) {
29
+ const bundled = fileURLToPath(new URL("./fonts/", import.meta.url));
30
+ const locate = ({ pkg, file }) => {
31
+ const copied = join(bundled, file);
32
+ if (existsSync(copied))
33
+ return copied;
47
34
  try {
48
- const root = dirname(require.resolve(`${candidate.pkg}/package.json`));
49
- const path = join(root, "files", candidate.file);
50
- if (existsSync(path))
51
- fonts.push({ path, family: candidate.family });
35
+ const path = join(dirname(require.resolve(`${pkg}/package.json`)), "files", file);
36
+ return existsSync(path) ? path : null;
52
37
  }
53
38
  catch {
54
- // Font package absent; the stack's system fallbacks cover it.
39
+ return null;
55
40
  }
56
- }
57
- return fonts;
41
+ };
42
+ return BOARD_EXPORT_FONTS.flatMap((font) => {
43
+ const path = locate(font);
44
+ return path ? [{ path, family: font.family }] : [];
45
+ });
58
46
  }
59
47
  /**
60
48
  * Load a board document by board id or by the path of its `.board` file.
@@ -0,0 +1,7 @@
1
+ /** Geist files `boards export` registers, copied into `dist/fonts` at build time. */
2
+ export type BoardExportFont = {
3
+ pkg: string;
4
+ file: string;
5
+ family: string;
6
+ };
7
+ export declare const BOARD_EXPORT_FONTS: readonly BoardExportFont[];
@@ -0,0 +1,10 @@
1
+ /** Geist files `boards export` registers, copied into `dist/fonts` at build time. */
2
+ const subset = (pkg, family, weights) => weights.map((weight) => ({
3
+ pkg,
4
+ family,
5
+ file: `${pkg.split("/").pop()}-latin-${weight}-normal.woff2`,
6
+ }));
7
+ export const BOARD_EXPORT_FONTS = [
8
+ ...subset("@fontsource/geist", "Geist", [400, 500, 600, 700]),
9
+ ...subset("@fontsource/geist-mono", "Geist Mono", [500, 600, 700]),
10
+ ];