@json-to-office/core-docx 0.34.0 → 0.35.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.
@@ -12,7 +12,7 @@ import { ComponentDefinition, RenderContext } from '../types';
12
12
  import { ThemeConfig } from '../styles';
13
13
  import { type ImageOptions } from '../core/content';
14
14
  import type { VisualProps } from '@json-to-office/shared-docx';
15
- import { type PptxServiceConfig, type PptxRasterizeResult } from '@json-to-office/shared';
15
+ import { type PptxServiceConfig, type PptxRasterizeResult, type RasterizeFontFace } from '@json-to-office/shared';
16
16
  export declare const DEFAULT_RASTERIZE_SERVER_URL = "http://localhost:7802";
17
17
  /**
18
18
  * Build a single-slide pptx presentation component definition from visual props.
@@ -42,6 +42,13 @@ export declare function visualToImageProps(props: VisualProps, base64DataUri: st
42
42
  * services) the target server. Keys the per-document pre-rasterization map
43
43
  * (#153); the pre-pass and the render-time lookup MUST use this one function
44
44
  * so the two sides cannot drift.
45
+ *
46
+ * FONTS ARE DELIBERATELY NOT PART OF THIS KEY. The map is built and consumed
47
+ * inside a single `renderDocument` call, which has exactly one font set, so
48
+ * the pre-pass and the render-time lookup can never disagree about fonts.
49
+ * The load-bearing font key is the RASTERIZER's on-disk cache key, which is
50
+ * process-wide and shared across documents and users — see `fontsDigest` in
51
+ * jto-cli's pptx-rasterizer.ts.
45
52
  */
46
53
  export declare function visualRasterKey(presentation: unknown, dpi: number, serverUrl?: string): string;
47
54
  /**
@@ -61,7 +68,13 @@ export declare function effectiveVisualServerUrl(props: VisualProps, serviceConf
61
68
  * Exported for the pre-rasterization pass, whose per-visual fallback must
62
69
  * behave exactly like render-time rasterization.
63
70
  */
64
- export declare function rasterizeVisualSlide(presentation: Record<string, unknown>, dpi: number, propsServerUrl: string | undefined, serviceConfig: PptxServiceConfig | undefined, baseDir: string | undefined): Promise<PptxRasterizeResult>;
71
+ export declare function rasterizeVisualSlide(presentation: Record<string, unknown>, dpi: number, propsServerUrl: string | undefined, serviceConfig: PptxServiceConfig | undefined, baseDir: string | undefined,
72
+ /**
73
+ * Document fonts staged for the rasterizer's LibreOffice launch. Added
74
+ * conditionally below so a fontless document's request body stays exactly
75
+ * what it was before fonts existed.
76
+ */
77
+ fonts?: readonly RasterizeFontFace[]): Promise<PptxRasterizeResult>;
65
78
  /**
66
79
  * Render visual component
67
80
  */
@@ -1 +1 @@
1
- {"version":3,"file":"visual.d.ts","sourceRoot":"","sources":["../../src/components/visual.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,MAAM,CAAC;AACxC,OAAO,EACL,mBAAmB,EACnB,aAAa,EAEd,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAe,KAAK,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAKjE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAC;AAC/D,OAAO,EAGL,KAAK,iBAAiB,EACtB,KAAK,mBAAmB,EACzB,MAAM,wBAAwB,CAAC;AAEhC,eAAO,MAAM,4BAA4B,0BAA0B,CAAC;AAIpE;;;;GAIG;AACH,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,WAAW,GACjB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAuBzB;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,WAAW,GAAG,MAAM,CAE/D;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,WAAW,GAAG,YAAY,CAWrE;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,WAAW,EAClB,aAAa,EAAE,MAAM,GACpB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAMzB;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAC7B,YAAY,EAAE,OAAO,EACrB,GAAG,EAAE,MAAM,EACX,SAAS,CAAC,EAAE,MAAM,GACjB,MAAM,CAIR;AAED;;;;;;;;;GASG;AACH,wBAAgB,wBAAwB,CACtC,KAAK,EAAE,WAAW,EAClB,aAAa,EAAE,iBAAiB,GAAG,SAAS,GAC3C,MAAM,GAAG,SAAS,CAGpB;AAED;;;;;GAKG;AACH,wBAAsB,oBAAoB,CACxC,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACrC,GAAG,EAAE,MAAM,EACX,cAAc,EAAE,MAAM,GAAG,SAAS,EAClC,aAAa,EAAE,iBAAiB,GAAG,SAAS,EAC5C,OAAO,EAAE,MAAM,GAAG,SAAS,GAC1B,OAAO,CAAC,mBAAmB,CAAC,CA6C9B;AAED;;GAEG;AACH,wBAAsB,qBAAqB,CACzC,SAAS,EAAE,mBAAmB,EAC9B,KAAK,EAAE,WAAW,EAClB,SAAS,CAAC,EAAE,MAAM,EAClB,OAAO,CAAC,EAAE,aAAa,GACtB,OAAO,CAAC,CAAC,SAAS,GAAG,KAAK,CAAC,EAAE,CAAC,CAkDhC"}
1
+ {"version":3,"file":"visual.d.ts","sourceRoot":"","sources":["../../src/components/visual.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,MAAM,CAAC;AACxC,OAAO,EACL,mBAAmB,EACnB,aAAa,EAEd,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAe,KAAK,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAKjE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAC;AAC/D,OAAO,EAGL,KAAK,iBAAiB,EACtB,KAAK,mBAAmB,EACxB,KAAK,iBAAiB,EACvB,MAAM,wBAAwB,CAAC;AAEhC,eAAO,MAAM,4BAA4B,0BAA0B,CAAC;AAIpE;;;;GAIG;AACH,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,WAAW,GACjB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAuBzB;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,WAAW,GAAG,MAAM,CAE/D;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,WAAW,GAAG,YAAY,CAWrE;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,WAAW,EAClB,aAAa,EAAE,MAAM,GACpB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAMzB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,eAAe,CAC7B,YAAY,EAAE,OAAO,EACrB,GAAG,EAAE,MAAM,EACX,SAAS,CAAC,EAAE,MAAM,GACjB,MAAM,CAIR;AAED;;;;;;;;;GASG;AACH,wBAAgB,wBAAwB,CACtC,KAAK,EAAE,WAAW,EAClB,aAAa,EAAE,iBAAiB,GAAG,SAAS,GAC3C,MAAM,GAAG,SAAS,CAGpB;AAED;;;;;GAKG;AACH,wBAAsB,oBAAoB,CACxC,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACrC,GAAG,EAAE,MAAM,EACX,cAAc,EAAE,MAAM,GAAG,SAAS,EAClC,aAAa,EAAE,iBAAiB,GAAG,SAAS,EAC5C,OAAO,EAAE,MAAM,GAAG,SAAS;AAC3B;;;;GAIG;AACH,KAAK,CAAC,EAAE,SAAS,iBAAiB,EAAE,GACnC,OAAO,CAAC,mBAAmB,CAAC,CAuD9B;AAED;;GAEG;AACH,wBAAsB,qBAAqB,CACzC,SAAS,EAAE,mBAAmB,EAC9B,KAAK,EAAE,WAAW,EAClB,SAAS,CAAC,EAAE,MAAM,EAClB,OAAO,CAAC,EAAE,aAAa,GACtB,OAAO,CAAC,CAAC,SAAS,GAAG,KAAK,CAAC,EAAE,CAAC,CAmDhC"}
@@ -13,7 +13,7 @@
13
13
  * just `children`: section `props.header`/`props.footer`, and table
14
14
  * `props.columns[].cells[].content` / `props.columns[].header.content`.
15
15
  */
16
- import { type PptxRasterizer, type PptxBatchRasterizer } from '@json-to-office/shared';
16
+ import { type PptxRasterizer, type PptxBatchRasterizer, type RasterizeFontFace } from '@json-to-office/shared';
17
17
  export interface FlattenVisualsOptions {
18
18
  /** Rasterizer that turns a single-slide pptx presentation into a PNG. */
19
19
  rasterize: PptxRasterizer;
@@ -32,6 +32,13 @@ export interface FlattenVisualsOptions {
32
32
  * the document's own directory. Absent → the rasterizer's cwd (#142).
33
33
  */
34
34
  baseDir?: string;
35
+ /**
36
+ * Font faces staged for each visual's LibreOffice render. Without these a
37
+ * flattened document bakes in fontless PNGs permanently — the flatten
38
+ * output is a portable, service-free `.docx.json`, so there is no second
39
+ * chance to re-rasterize with the right fonts.
40
+ */
41
+ fonts?: readonly RasterizeFontFace[];
35
42
  }
36
43
  /**
37
44
  * Return a deep copy of `doc` with every `visual` node replaced by the `image`
@@ -1 +1 @@
1
- {"version":3,"file":"flattenVisuals.d.ts","sourceRoot":"","sources":["../../src/core/flattenVisuals.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAGL,KAAK,cAAc,EACnB,KAAK,mBAAmB,EACzB,MAAM,wBAAwB,CAAC;AAYhC,MAAM,WAAW,qBAAqB;IACpC,yEAAyE;IACzE,SAAS,EAAE,cAAc,CAAC;IAC1B;;;;OAIG;IACH,cAAc,CAAC,EAAE,mBAAmB,CAAC;IACrC,8EAA8E;IAC9E,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,iDAAiD;IACjD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AASD;;;;;;;;GAQG;AACH,wBAAsB,cAAc,CAAC,CAAC,GAAG,OAAO,EAC9C,GAAG,EAAE,CAAC,EACN,OAAO,EAAE,qBAAqB,GAC7B,OAAO,CAAC,CAAC,CAAC,CA0CZ"}
1
+ {"version":3,"file":"flattenVisuals.d.ts","sourceRoot":"","sources":["../../src/core/flattenVisuals.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAGL,KAAK,cAAc,EACnB,KAAK,mBAAmB,EACxB,KAAK,iBAAiB,EACvB,MAAM,wBAAwB,CAAC;AAYhC,MAAM,WAAW,qBAAqB;IACpC,yEAAyE;IACzE,SAAS,EAAE,cAAc,CAAC;IAC1B;;;;OAIG;IACH,cAAc,CAAC,EAAE,mBAAmB,CAAC;IACrC,8EAA8E;IAC9E,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,iDAAiD;IACjD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;;OAKG;IACH,KAAK,CAAC,EAAE,SAAS,iBAAiB,EAAE,CAAC;CACtC;AAUD;;;;;;;;GAQG;AACH,wBAAsB,cAAc,CAAC,CAAC,GAAG,OAAO,EAC9C,GAAG,EAAE,CAAC,EACN,OAAO,EAAE,qBAAqB,GAC7B,OAAO,CAAC,CAAC,CAAC,CA+CZ"}
@@ -7,9 +7,23 @@
7
7
  * Keeping it in one place ensures the two paths behave identically around
8
8
  * validation, SAFE_FONTS awareness, Google Fonts materialization, and the
9
9
  * `onResolved` side-channel consumed by the LibreOffice preview font stager.
10
+ *
11
+ * Materialization has two triggers: an `onResolved` listener, or the
12
+ * caller's `forceMaterialize` flag (set when the document contains a
13
+ * `visual`, whose PNG is produced by an out-of-process LibreOffice that
14
+ * needs real font files). Both entry paths return the resolved fonts so the
15
+ * caller can forward them to the rasterizer.
10
16
  */
11
17
  import type { FontRuntimeOpts, ResolvedFont, GenerationWarning } from '@json-to-office/shared';
12
18
  import type { ThemeConfig } from '../styles';
13
19
  import type { ReportComponentDefinition } from '../types';
14
- export declare function resolveDocumentFonts(document: ReportComponentDefinition, theme: ThemeConfig, fonts?: FontRuntimeOpts, warnings?: GenerationWarning[]): Promise<ResolvedFont[]>;
20
+ export declare function resolveDocumentFonts(document: ReportComponentDefinition, theme: ThemeConfig, fonts?: FontRuntimeOpts, warnings?: GenerationWarning[],
21
+ /**
22
+ * Materialize font bytes even when no `onResolved` listener is registered.
23
+ * Set by the callers when the document contains at least one `visual`,
24
+ * whose PNG is rendered by an out-of-process LibreOffice that needs the
25
+ * actual font files — there is no listener on the plain CLI path, so
26
+ * without this a visual-bearing build silently renders with fallbacks.
27
+ */
28
+ forceMaterialize?: boolean): Promise<ResolvedFont[]>;
15
29
  //# sourceMappingURL=fontResolution.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"fontResolution.d.ts","sourceRoot":"","sources":["../../src/core/fontResolution.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EACV,eAAe,EACf,YAAY,EACZ,iBAAiB,EAClB,MAAM,wBAAwB,CAAC;AAWhC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,UAAU,CAAC;AAE1D,wBAAsB,oBAAoB,CACxC,QAAQ,EAAE,yBAAyB,EACnC,KAAK,EAAE,WAAW,EAClB,KAAK,CAAC,EAAE,eAAe,EACvB,QAAQ,CAAC,EAAE,iBAAiB,EAAE,GAC7B,OAAO,CAAC,YAAY,EAAE,CAAC,CAmEzB"}
1
+ {"version":3,"file":"fontResolution.d.ts","sourceRoot":"","sources":["../../src/core/fontResolution.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EACV,eAAe,EACf,YAAY,EACZ,iBAAiB,EAClB,MAAM,wBAAwB,CAAC;AAchC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,UAAU,CAAC;AAE1D,wBAAsB,oBAAoB,CACxC,QAAQ,EAAE,yBAAyB,EACnC,KAAK,EAAE,WAAW,EAClB,KAAK,CAAC,EAAE,eAAe,EACvB,QAAQ,CAAC,EAAE,iBAAiB,EAAE;AAC9B;;;;;;GAMG;AACH,gBAAgB,UAAQ,GACvB,OAAO,CAAC,YAAY,EAAE,CAAC,CAkFzB"}
@@ -1 +1 @@
1
- {"version":3,"file":"generator.d.ts","sourceRoot":"","sources":["../../src/core/generator.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"generator.d.ts","sourceRoot":"","sources":["../../src/core/generator.ts"],"names":[],"mappings":"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"}
@@ -15,13 +15,20 @@
15
15
  * wastes a little work, under-collection and every failure mode degrade to
16
16
  * the sequential status quo, never to a broken render.
17
17
  */
18
- import { type PptxServiceConfig, type PptxRasterizeBatchSlideResult } from '@json-to-office/shared';
18
+ import { type PptxServiceConfig, type PptxRasterizeBatchSlideResult, type RasterizeFontFace } from '@json-to-office/shared';
19
19
  import type { VisualProps } from '@json-to-office/shared-docx';
20
20
  export interface PrerasterizeOptions {
21
21
  /** Directory relative asset paths resolve against (#142). */
22
22
  baseDir?: string;
23
23
  /** Max concurrent per-visual fallback rasterizations (default 4). */
24
24
  concurrency?: number;
25
+ /**
26
+ * Font faces staged for every slide's LibreOffice render. Request-level,
27
+ * like `baseDir` — never per-slide: the batch schema validates each slide
28
+ * object with `additionalProperties: false`, and a uniform slide shape is
29
+ * what lets the server share one disk-cache key with the single path.
30
+ */
31
+ fonts?: readonly RasterizeFontFace[];
25
32
  }
26
33
  /** Cumulative pre-pass counters for cache observability (#156). */
27
34
  export interface VisualPrepassStats {
@@ -1 +1 @@
1
- {"version":3,"file":"prerasterizeVisuals.d.ts","sourceRoot":"","sources":["../../src/core/prerasterizeVisuals.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EAIL,KAAK,iBAAiB,EAEtB,KAAK,6BAA6B,EACnC,MAAM,wBAAwB,CAAC;AAChC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAC;AAkB/D,MAAM,WAAW,mBAAmB;IAClC,6DAA6D;IAC7D,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,qEAAqE;IACrE,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,mEAAmE;AACnE,MAAM,WAAW,kBAAkB;IACjC,oEAAoE;IACpE,SAAS,EAAE,MAAM,CAAC;IAClB,wDAAwD;IACxD,SAAS,EAAE,MAAM,CAAC;IAClB,uEAAuE;IACvE,MAAM,EAAE,MAAM,CAAC;CAChB;AAQD;;;;GAIG;AACH,wBAAgB,qBAAqB,IAAI,kBAAkB,CAE1D;AAED,wBAAgB,uBAAuB,IAAI,IAAI,CAI9C;AASD;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,OAAO,GAAG,WAAW,EAAE,CA4B/D;AAsDD;;;;;GAKG;AACH,wBAAsB,mBAAmB,CACvC,IAAI,EAAE,OAAO,EACb,aAAa,EAAE,iBAAiB,GAAG,SAAS,EAC5C,OAAO,GAAE,mBAAwB,GAChC,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,6BAA6B,CAAC,CAAC,CAuJrD"}
1
+ {"version":3,"file":"prerasterizeVisuals.d.ts","sourceRoot":"","sources":["../../src/core/prerasterizeVisuals.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EAIL,KAAK,iBAAiB,EAEtB,KAAK,6BAA6B,EAClC,KAAK,iBAAiB,EACvB,MAAM,wBAAwB,CAAC;AAChC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAC;AAkB/D,MAAM,WAAW,mBAAmB;IAClC,6DAA6D;IAC7D,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,qEAAqE;IACrE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;;OAKG;IACH,KAAK,CAAC,EAAE,SAAS,iBAAiB,EAAE,CAAC;CACtC;AAED,mEAAmE;AACnE,MAAM,WAAW,kBAAkB;IACjC,oEAAoE;IACpE,SAAS,EAAE,MAAM,CAAC;IAClB,wDAAwD;IACxD,SAAS,EAAE,MAAM,CAAC;IAClB,uEAAuE;IACvE,MAAM,EAAE,MAAM,CAAC;CAChB;AAQD;;;;GAIG;AACH,wBAAgB,qBAAqB,IAAI,kBAAkB,CAE1D;AAED,wBAAgB,uBAAuB,IAAI,IAAI,CAI9C;AAkBD;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,OAAO,GAAG,WAAW,EAAE,CA4B/D;AA6ED;;;;;GAKG;AACH,wBAAsB,mBAAmB,CACvC,IAAI,EAAE,OAAO,EACb,aAAa,EAAE,iBAAiB,GAAG,SAAS,EAC5C,OAAO,GAAE,mBAAwB,GAChC,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,6BAA6B,CAAC,CAAC,CAiOrD"}
@@ -8,7 +8,7 @@ import { ThemeConfig } from '../styles';
8
8
  import { ProcessedDocument } from './structure';
9
9
  import { LayoutPlan, SectionLayout } from './layout';
10
10
  import { MemoryCache } from '../cache';
11
- import type { ServicesConfig } from '@json-to-office/shared';
11
+ import type { ServicesConfig, RasterizeFontFace } from '@json-to-office/shared';
12
12
  interface RenderDocumentOptions {
13
13
  cache?: MemoryCache;
14
14
  bypassCache?: boolean;
@@ -18,6 +18,13 @@ interface RenderDocumentOptions {
18
18
  * against. Defaults to `process.cwd()` when absent (#142).
19
19
  */
20
20
  baseDir?: string;
21
+ /**
22
+ * Font faces (base64) shipped with every `visual` rasterization so the
23
+ * out-of-process LibreOffice renders the slide with the document's real
24
+ * fonts instead of a system fallback. Produced by the caller from
25
+ * `resolveDocumentFonts` via `toRasterizeFontFaces`.
26
+ */
27
+ visualFonts?: RasterizeFontFace[];
21
28
  }
22
29
  /**
23
30
  * Render a complete document from structure and layout
@@ -1 +1 @@
1
- {"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../../src/core/render.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EACL,QAAQ,EACR,SAAS,EACT,KAAK,EACL,eAAe,EAEf,eAAe,EAKf,OAAO,EACR,MAAM,MAAM,CAAC;AAcd,OAAO,EACL,mBAAmB,EACnB,aAAa,EAed,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAIxC,OAAO,EAEL,iBAAiB,EAElB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAKrD,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AACvC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAoC7D,UAAU,qBAAqB;IAC7B,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,QAAQ,CAAC,EAAE,cAAc,CAAC;IAC1B;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AA8DD;;GAEG;AACH,wBAAsB,cAAc,CAClC,SAAS,EAAE,iBAAiB,EAC5B,MAAM,EAAE,UAAU,EAClB,OAAO,CAAC,EAAE,qBAAqB,GAC9B,OAAO,CAAC,QAAQ,CAAC,CAwBnB;AAiZD;;GAEG;AACH,wBAAsB,aAAa,CACjC,OAAO,EAAE,aAAa,EACtB,KAAK,EAAE,WAAW,EAClB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,aAAa,EACtB,cAAc,CAAC,EAAE,MAAM,EACvB,aAAa,CAAC,EAAE,OAAO,EACvB,WAAW,UAAQ,GAClB,OAAO,CAAC,eAAe,CAAC,CAkH1B;AAED;;GAEG;AACH,wBAAsB,eAAe,CACnC,SAAS,EAAE,mBAAmB,EAC9B,KAAK,EAAE,WAAW,EAClB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,aAAa,GACrB,OAAO,CAAC,CAAC,SAAS,GAAG,KAAK,GAAG,eAAe,GAAG,OAAO,CAAC,EAAE,CAAC,CAmC5D"}
1
+ {"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../../src/core/render.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EACL,QAAQ,EACR,SAAS,EACT,KAAK,EACL,eAAe,EAEf,eAAe,EAKf,OAAO,EACR,MAAM,MAAM,CAAC;AAcd,OAAO,EACL,mBAAmB,EACnB,aAAa,EAed,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAIxC,OAAO,EAEL,iBAAiB,EAElB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAKrD,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AACvC,OAAO,KAAK,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAoChF,UAAU,qBAAqB;IAC7B,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,QAAQ,CAAC,EAAE,cAAc,CAAC;IAC1B;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;;OAKG;IACH,WAAW,CAAC,EAAE,iBAAiB,EAAE,CAAC;CACnC;AA8DD;;GAEG;AACH,wBAAsB,cAAc,CAClC,SAAS,EAAE,iBAAiB,EAC5B,MAAM,EAAE,UAAU,EAClB,OAAO,CAAC,EAAE,qBAAqB,GAC9B,OAAO,CAAC,QAAQ,CAAC,CAwBnB;AAkZD;;GAEG;AACH,wBAAsB,aAAa,CACjC,OAAO,EAAE,aAAa,EACtB,KAAK,EAAE,WAAW,EAClB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,aAAa,EACtB,cAAc,CAAC,EAAE,MAAM,EACvB,aAAa,CAAC,EAAE,OAAO,EACvB,WAAW,UAAQ,GAClB,OAAO,CAAC,eAAe,CAAC,CAkH1B;AAED;;GAEG;AACH,wBAAsB,eAAe,CACnC,SAAS,EAAE,mBAAmB,EAC9B,KAAK,EAAE,WAAW,EAClB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,aAAa,GACrB,OAAO,CAAC,CAAC,SAAS,GAAG,KAAK,GAAG,eAAe,GAAG,OAAO,CAAC,EAAE,CAAC,CAmC5D"}
package/dist/index.js CHANGED
@@ -7610,14 +7610,19 @@ function effectiveVisualServerUrl(props, serviceConfig) {
7610
7610
  if (serviceConfig?.render) return void 0;
7611
7611
  return props.serverUrl;
7612
7612
  }
7613
- async function rasterizeVisualSlide(presentation, dpi, propsServerUrl, serviceConfig, baseDir) {
7613
+ async function rasterizeVisualSlide(presentation, dpi, propsServerUrl, serviceConfig, baseDir, fonts) {
7614
7614
  if (!isNodeEnvironment()) {
7615
7615
  throw new Error(
7616
7616
  "Visual rasterization requires a Node.js environment. It is not available in browser environments."
7617
7617
  );
7618
7618
  }
7619
7619
  if (serviceConfig?.render) {
7620
- return serviceConfig.render({ presentation, dpi, baseDir });
7620
+ return serviceConfig.render({
7621
+ presentation,
7622
+ dpi,
7623
+ baseDir,
7624
+ ...fonts?.length ? { fonts: [...fonts] } : {}
7625
+ });
7621
7626
  }
7622
7627
  const serverUrl = resolveServiceUrl(
7623
7628
  propsServerUrl,
@@ -7627,7 +7632,12 @@ async function rasterizeVisualSlide(presentation, dpi, propsServerUrl, serviceCo
7627
7632
  const response = await postJsonToService({
7628
7633
  url: serverUrl,
7629
7634
  path: "/rasterize",
7630
- body: { presentation, dpi, ...baseDir !== void 0 && { baseDir } },
7635
+ body: {
7636
+ presentation,
7637
+ dpi,
7638
+ ...baseDir !== void 0 && { baseDir },
7639
+ ...fonts?.length ? { fonts } : {}
7640
+ },
7631
7641
  headers: serviceConfig?.headers,
7632
7642
  serviceLabel: "PPTX rasterization service",
7633
7643
  onUnreachable: (url, cause) => `PPTX rasterization service is not reachable at ${url}. Configure services.pptx with a \`render\` callback or a running \`serverUrl\`.
@@ -7673,7 +7683,8 @@ async function renderVisualComponent(component, theme, themeName, context) {
7673
7683
  dpi,
7674
7684
  props.serverUrl,
7675
7685
  serviceConfig,
7676
- getBaseDir()
7686
+ getBaseDir(),
7687
+ context?.visualFonts
7677
7688
  );
7678
7689
  }
7679
7690
  return await createImage(
@@ -7807,6 +7818,11 @@ function collectVisualProps(root) {
7807
7818
  function toErrorMessage(error) {
7808
7819
  return error instanceof Error ? error.message : String(error);
7809
7820
  }
7821
+ var HTTP_STATUS_IN_MESSAGE = /\breturned (\d{3})\b/;
7822
+ function isSchemaRejection(error) {
7823
+ const match = HTTP_STATUS_IN_MESSAGE.exec(toErrorMessage(error));
7824
+ return match !== null && match[1] === "400";
7825
+ }
7810
7826
  function* chunksOf(items, size) {
7811
7827
  for (let i = 0; i < items.length; i += size) yield items.slice(i, i + size);
7812
7828
  }
@@ -7865,22 +7881,38 @@ async function prerasterizeVisuals(root, serviceConfig, options = {}) {
7865
7881
  const limit = createLimiter(
7866
7882
  Math.max(1, options.concurrency ?? DEFAULT_FALLBACK_CONCURRENCY)
7867
7883
  );
7884
+ let fontsRejected = false;
7885
+ const requestFonts = () => fontsRejected || !options.fonts?.length ? void 0 : options.fonts;
7886
+ const rasterizeOne = async (target) => {
7887
+ const fonts = requestFonts();
7888
+ const call = (withFonts) => rasterizeVisualSlide(
7889
+ target.presentation,
7890
+ target.dpi,
7891
+ void 0,
7892
+ serviceConfig,
7893
+ options.baseDir,
7894
+ withFonts
7895
+ );
7896
+ try {
7897
+ return { ok: true, ...await call(fonts) };
7898
+ } catch (error) {
7899
+ if (!fonts || !isSchemaRejection(error)) {
7900
+ return { ok: false, error: toErrorMessage(error) };
7901
+ }
7902
+ try {
7903
+ const result = await call(void 0);
7904
+ fontsRejected = true;
7905
+ return { ok: true, ...result };
7906
+ } catch {
7907
+ return { ok: false, error: toErrorMessage(error) };
7908
+ }
7909
+ }
7910
+ };
7868
7911
  const rasterizeIndividually = async (chunk) => {
7869
7912
  await Promise.all(
7870
7913
  chunk.map(
7871
7914
  (target) => limit(async () => {
7872
- try {
7873
- const result = await rasterizeVisualSlide(
7874
- target.presentation,
7875
- target.dpi,
7876
- void 0,
7877
- serviceConfig,
7878
- options.baseDir
7879
- );
7880
- map.set(target.key, { ok: true, ...result });
7881
- } catch (error) {
7882
- map.set(target.key, { ok: false, error: toErrorMessage(error) });
7883
- }
7915
+ map.set(target.key, await rasterizeOne(target));
7884
7916
  })
7885
7917
  )
7886
7918
  );
@@ -7893,7 +7925,8 @@ async function prerasterizeVisuals(root, serviceConfig, options = {}) {
7893
7925
  presentation: target.presentation,
7894
7926
  dpi: target.dpi
7895
7927
  })),
7896
- ...options.baseDir !== void 0 && { baseDir: options.baseDir }
7928
+ ...options.baseDir !== void 0 && { baseDir: options.baseDir },
7929
+ ...options.fonts?.length ? { fonts: [...options.fonts] } : {}
7897
7930
  });
7898
7931
  if (!applyBatchResponse(chunk, response, map)) {
7899
7932
  throw new Error(
@@ -7922,10 +7955,10 @@ async function prerasterizeVisuals(root, serviceConfig, options = {}) {
7922
7955
  serviceConfig?.serverUrl,
7923
7956
  DEFAULT_RASTERIZE_SERVER_URL
7924
7957
  );
7925
- for (const chunk of chunksOf(unique, MAX_RASTERIZE_BATCH_SLIDES)) {
7926
- let applied = false;
7958
+ const postBatch = async (chunk, fonts) => {
7959
+ let response;
7927
7960
  try {
7928
- const response = await postJsonToService({
7961
+ response = await postJsonToService({
7929
7962
  url: serverUrl,
7930
7963
  path: "/rasterize/batch",
7931
7964
  body: {
@@ -7933,18 +7966,36 @@ async function prerasterizeVisuals(root, serviceConfig, options = {}) {
7933
7966
  presentation: target.presentation,
7934
7967
  dpi: target.dpi
7935
7968
  })),
7936
- ...options.baseDir !== void 0 && { baseDir: options.baseDir }
7969
+ ...options.baseDir !== void 0 && { baseDir: options.baseDir },
7970
+ ...fonts?.length ? { fonts } : {}
7937
7971
  },
7938
7972
  headers: serviceConfig?.headers,
7939
7973
  timeoutMs: BATCH_TIMEOUT_BASE_MS + BATCH_TIMEOUT_PER_SLIDE_MS * chunk.length,
7940
7974
  serviceLabel: "PPTX batch rasterization service",
7941
7975
  onUnreachable: (url, cause) => `PPTX rasterization service is not reachable at ${url}. Cause: ${cause}`
7942
7976
  });
7943
- applied = applyBatchResponse(chunk, await response.json(), map);
7977
+ } catch (error) {
7978
+ return { applied: false, schemaRejected: isSchemaRejection(error) };
7979
+ }
7980
+ try {
7981
+ if (applyBatchResponse(chunk, await response.json(), map)) {
7982
+ return { applied: true };
7983
+ }
7944
7984
  } catch {
7945
- applied = false;
7946
7985
  }
7947
- if (!applied) await rasterizeIndividually(chunk);
7986
+ return { applied: false, schemaRejected: false };
7987
+ };
7988
+ for (const chunk of chunksOf(unique, MAX_RASTERIZE_BATCH_SLIDES)) {
7989
+ const fonts = requestFonts();
7990
+ let outcome = await postBatch(chunk, fonts);
7991
+ if (!outcome.applied && fonts && outcome.schemaRejected) {
7992
+ const retry = await postBatch(chunk, void 0);
7993
+ if (retry.applied) {
7994
+ fontsRejected = true;
7995
+ outcome = retry;
7996
+ }
7997
+ }
7998
+ if (!outcome.applied) await rasterizeIndividually(chunk);
7948
7999
  }
7949
8000
  return map;
7950
8001
  }
@@ -8094,11 +8145,12 @@ async function renderDocumentScoped(structure, layout, options) {
8094
8145
  structure.themeName
8095
8146
  );
8096
8147
  context.services = options?.services;
8148
+ context.visualFonts = options?.visualFonts;
8097
8149
  try {
8098
8150
  const visualRasterResults = await prerasterizeVisuals(
8099
8151
  layout.sections,
8100
8152
  options?.services?.pptx,
8101
- { baseDir: getBaseDir() }
8153
+ { baseDir: getBaseDir(), fonts: options?.visualFonts }
8102
8154
  );
8103
8155
  if (visualRasterResults.size > 0) {
8104
8156
  context.visualRasterResults = visualRasterResults;
@@ -8468,14 +8520,17 @@ async function renderComponent(component, theme, themeName, context) {
8468
8520
  import {
8469
8521
  collectFontNamesFromDocx,
8470
8522
  validateFontReferences,
8471
- FontRegistry
8523
+ FontRegistry,
8524
+ documentFontRegistry,
8525
+ themeFontRegistry,
8526
+ mergeFontRegistries
8472
8527
  } from "@json-to-office/shared";
8473
8528
  import {
8474
8529
  loadFileFontSource,
8475
8530
  FontDiskCache,
8476
8531
  fetchVariableFontSource
8477
8532
  } from "@json-to-office/shared/fonts/node";
8478
- async function resolveDocumentFonts(document, theme, fonts, warnings) {
8533
+ async function resolveDocumentFonts(document, theme, fonts, warnings, forceMaterialize = false) {
8479
8534
  const emit = (code, message) => {
8480
8535
  if (warnings) {
8481
8536
  warnings.push({
@@ -8492,9 +8547,14 @@ async function resolveDocumentFonts(document, theme, fonts, warnings) {
8492
8547
  for (const n of collectFontNamesFromDocx(document)) names.add(n);
8493
8548
  for (const n of collectFontNamesFromDocx(theme)) names.add(n);
8494
8549
  if (names.size === 0) return [];
8550
+ const registryEntries = mergeFontRegistries(
8551
+ themeFontRegistry(theme),
8552
+ documentFontRegistry(document),
8553
+ fonts?.extraEntries
8554
+ );
8495
8555
  const validation = validateFontReferences({
8496
8556
  referencedNames: names,
8497
- registeredEntries: fonts?.extraEntries
8557
+ registeredEntries: registryEntries
8498
8558
  });
8499
8559
  if (validation.warnings.length > 0) {
8500
8560
  if (fonts?.strict) {
@@ -8507,9 +8567,11 @@ async function resolveDocumentFonts(document, theme, fonts, warnings) {
8507
8567
  emit(w.code, w.message);
8508
8568
  }
8509
8569
  }
8510
- if (!fonts?.onResolved) return [];
8570
+ if (!fonts?.onResolved && !forceMaterialize) return [];
8511
8571
  const registry = new FontRegistry({
8512
- opts: fonts,
8572
+ // Spread keeps baseDir/googleFonts/mode/substitution intact for
8573
+ // materializeSource; extraEntries carries the merged registry.
8574
+ opts: { ...fonts, extraEntries: registryEntries },
8513
8575
  fileLoader: loadFileFontSource,
8514
8576
  variableLoader: fetchVariableFontSource,
8515
8577
  diskCache: fonts?.googleFonts?.cacheDir ? new FontDiskCache(fonts.googleFonts.cacheDir) : void 0
@@ -8520,10 +8582,13 @@ async function resolveDocumentFonts(document, theme, fonts, warnings) {
8520
8582
  emit("FONT_UNRESOLVED", msg);
8521
8583
  }
8522
8584
  }
8523
- fonts.onResolved(resolved);
8585
+ fonts?.onResolved?.(resolved);
8524
8586
  return resolved;
8525
8587
  }
8526
8588
 
8589
+ // src/core/generator.ts
8590
+ import { toRasterizeFontFaces } from "@json-to-office/shared/fonts/node";
8591
+
8527
8592
  // src/utils/packageDocument.ts
8528
8593
  import AdmZip2 from "adm-zip";
8529
8594
  import { Packer } from "docx";
@@ -8783,7 +8848,15 @@ async function generateDocumentWithCustomThemes(documentIn, customThemes, servic
8783
8848
  fonts,
8784
8849
  warnings
8785
8850
  });
8786
- await resolveDocumentFonts(document, theme, fonts, warnings);
8851
+ const hasVisual = collectVisualProps(document).length > 0;
8852
+ const resolvedFonts = await resolveDocumentFonts(
8853
+ document,
8854
+ theme,
8855
+ fonts,
8856
+ warnings,
8857
+ hasVisual
8858
+ );
8859
+ const visualFonts = hasVisual ? toRasterizeFontFaces(resolvedFonts, warnings) : [];
8787
8860
  const structure = await processDocument(
8788
8861
  document,
8789
8862
  theme,
@@ -8794,7 +8867,8 @@ async function generateDocumentWithCustomThemes(documentIn, customThemes, servic
8794
8867
  const renderedDocument = await renderDocument(structure, layout, {
8795
8868
  bypassCache: false,
8796
8869
  services,
8797
- baseDir
8870
+ baseDir,
8871
+ ...visualFonts.length > 0 && { visualFonts }
8798
8872
  });
8799
8873
  return renderedDocument;
8800
8874
  }
@@ -8908,7 +8982,11 @@ async function flattenVisuals(doc, options) {
8908
8982
  renderBatch: options.rasterizeBatch,
8909
8983
  dpi: options.dpi
8910
8984
  },
8911
- { baseDir: options.baseDir, concurrency: options.concurrency }
8985
+ {
8986
+ baseDir: options.baseDir,
8987
+ concurrency: options.concurrency,
8988
+ fonts: options.fonts
8989
+ }
8912
8990
  ).catch(() => /* @__PURE__ */ new Map());
8913
8991
  rasterize = async (request) => {
8914
8992
  const hit = preRasterized.get(
@@ -8929,6 +9007,7 @@ async function flattenVisuals(doc, options) {
8929
9007
  rasterize,
8930
9008
  dpi: options.dpi,
8931
9009
  baseDir: options.baseDir,
9010
+ fonts: options.fonts,
8932
9011
  limit: createLimiter(
8933
9012
  Math.max(1, options.concurrency ?? DEFAULT_CONCURRENCY)
8934
9013
  )
@@ -8942,7 +9021,8 @@ async function rasterizeVisual(obj, ctx) {
8942
9021
  () => ctx.rasterize({
8943
9022
  presentation: buildVisualPresentation(props),
8944
9023
  dpi,
8945
- baseDir: ctx.baseDir
9024
+ baseDir: ctx.baseDir,
9025
+ ...ctx.fonts?.length ? { fonts: [...ctx.fonts] } : {}
8946
9026
  })
8947
9027
  );
8948
9028
  const image = {
@@ -9218,6 +9298,7 @@ async function runExample(example, options = {}) {
9218
9298
 
9219
9299
  // src/plugin/createDocumentGenerator.ts
9220
9300
  init_themes();
9301
+ import { toRasterizeFontFaces as toRasterizeFontFaces2 } from "@json-to-office/shared/fonts/node";
9221
9302
 
9222
9303
  // src/plugin/version-resolver.ts
9223
9304
  import { resolveComponentVersion } from "@json-to-office/shared/plugin";
@@ -9745,7 +9826,15 @@ function createBuilderImpl(state) {
9745
9826
  warnings,
9746
9827
  preserveSet
9747
9828
  } = await expandDocument(document, options);
9748
- await resolveDocumentFonts(modedDoc, modedTheme, state.fonts, warnings);
9829
+ const hasVisual = collectVisualProps(modedDoc).length > 0;
9830
+ const resolvedFonts = await resolveDocumentFonts(
9831
+ modedDoc,
9832
+ modedTheme,
9833
+ state.fonts,
9834
+ warnings,
9835
+ hasVisual
9836
+ );
9837
+ const visualFonts = hasVisual ? toRasterizeFontFaces2(resolvedFonts, warnings) : [];
9749
9838
  const packageOptions = {
9750
9839
  deterministic: options?.deterministic ?? state.deterministic,
9751
9840
  generatedAt: options?.generatedAt ?? state.generatedAt
@@ -9760,7 +9849,8 @@ function createBuilderImpl(state) {
9760
9849
  const generatedDocument = await renderDocument(structure, layout, {
9761
9850
  services: state.services,
9762
9851
  bypassCache: !state.enableCache,
9763
- baseDir: options?.baseDir ?? state.baseDir
9852
+ baseDir: options?.baseDir ?? state.baseDir,
9853
+ ...visualFonts.length > 0 && { visualFonts }
9764
9854
  });
9765
9855
  const preservedDefinition = preserveSet ? {
9766
9856
  ...modedRoot,