@json-to-office/core-docx 5.3.0 → 5.4.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.
@@ -5771,7 +5771,10 @@ import {
5771
5771
  import {
5772
5772
  clampVisualDpi,
5773
5773
  DEFAULT_VISUAL_DPI,
5774
- MAX_RASTERIZE_BATCH_SLIDES
5774
+ MAX_RASTERIZE_BATCH_SLIDES,
5775
+ createLimiter,
5776
+ resolveServiceUrl as resolveServiceUrl2,
5777
+ postJsonToService as postJsonToService2
5775
5778
  } from "@json-to-office/shared";
5776
5779
  import {
5777
5780
  isNativeVisualProps
@@ -5785,54 +5788,8 @@ function isNodeEnvironment() {
5785
5788
  return typeof process !== "undefined" && process.versions != null && process.versions.node != null && typeof process.versions.node === "string";
5786
5789
  }
5787
5790
 
5788
- // src/utils/serviceClient.ts
5789
- var DEFAULT_TIMEOUT_MS = 3e4;
5790
- function resolveServiceUrl(propsUrl, servicesUrl, defaultUrl) {
5791
- const raw = (propsUrl || servicesUrl || defaultUrl).trim();
5792
- const withScheme = /^https?:\/\//i.test(raw) ? raw : `http://${raw}`;
5793
- return withScheme.replace(/\/+$/, "");
5794
- }
5795
- var SERVICE_UNAVAILABLE_CODE = "SERVICE_UNAVAILABLE";
5796
- function serviceUnavailable(message) {
5797
- return Object.assign(new Error(message), { code: SERVICE_UNAVAILABLE_CODE });
5798
- }
5799
- async function postJsonToService(opts) {
5800
- const resolvedHeaders = typeof opts.headers === "function" ? await opts.headers(opts.body) : opts.headers;
5801
- const headers = {
5802
- "Content-Type": "application/json",
5803
- ...resolvedHeaders
5804
- };
5805
- const timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS;
5806
- const controller = new AbortController();
5807
- const timer = setTimeout(() => controller.abort(), timeoutMs);
5808
- let response;
5809
- try {
5810
- response = await fetch(`${opts.url}${opts.path}`, {
5811
- method: "POST",
5812
- headers,
5813
- body: JSON.stringify(opts.body),
5814
- signal: controller.signal
5815
- });
5816
- } catch (error) {
5817
- if (error?.name === "AbortError") {
5818
- throw serviceUnavailable(
5819
- `${opts.serviceLabel} timed out after ${timeoutMs}ms at ${opts.url}.`
5820
- );
5821
- }
5822
- const cause = error instanceof Error ? error.message : String(error);
5823
- throw serviceUnavailable(opts.onUnreachable(opts.url, cause));
5824
- } finally {
5825
- clearTimeout(timer);
5826
- }
5827
- if (!response.ok) {
5828
- throw new Error(
5829
- `${opts.serviceLabel} returned ${response.status}: ${response.statusText}`
5830
- );
5831
- }
5832
- return response;
5833
- }
5834
-
5835
5791
  // src/components/visual.ts
5792
+ import { resolveServiceUrl, postJsonToService } from "@json-to-office/shared";
5836
5793
  var DEFAULT_RASTERIZE_SERVER_URL = "http://localhost:7802";
5837
5794
  var PIXELS_PER_INCH = 96;
5838
5795
  function buildVisualPresentation(props) {
@@ -5934,26 +5891,6 @@ Cause: ${cause}`
5934
5891
  return result;
5935
5892
  }
5936
5893
 
5937
- // src/utils/promiseLimiter.ts
5938
- function createLimiter(max) {
5939
- let active = 0;
5940
- const queue = [];
5941
- const release = () => {
5942
- active--;
5943
- queue.shift()?.();
5944
- };
5945
- return async function limit(fn) {
5946
- while (active >= max)
5947
- await new Promise((resolve2) => queue.push(resolve2));
5948
- active++;
5949
- try {
5950
- return await fn();
5951
- } finally {
5952
- release();
5953
- }
5954
- };
5955
- }
5956
-
5957
5894
  // src/core/prerasterizeVisuals.ts
5958
5895
  var DEFAULT_FALLBACK_CONCURRENCY = 4;
5959
5896
  var BATCH_TIMEOUT_BASE_MS = 3e4;
@@ -6122,7 +6059,7 @@ async function prerasterizeVisuals(root, serviceConfig, options = {}) {
6122
6059
  await rasterizeIndividually(unique);
6123
6060
  return map;
6124
6061
  }
6125
- const serverUrl = resolveServiceUrl(
6062
+ const serverUrl = resolveServiceUrl2(
6126
6063
  void 0,
6127
6064
  serviceConfig?.serverUrl,
6128
6065
  DEFAULT_RASTERIZE_SERVER_URL
@@ -6130,7 +6067,7 @@ async function prerasterizeVisuals(root, serviceConfig, options = {}) {
6130
6067
  const postBatch = async (chunk, fonts) => {
6131
6068
  let response;
6132
6069
  try {
6133
- response = await postJsonToService({
6070
+ response = await postJsonToService2({
6134
6071
  url: serverUrl,
6135
6072
  path: "/rasterize/batch",
6136
6073
  body: {
@@ -6256,7 +6193,8 @@ function containsComponent(root, name) {
6256
6193
  // src/core/desugarExternals.ts
6257
6194
  import {
6258
6195
  clampVisualDpi as clampVisualDpi2,
6259
- DEFAULT_VISUAL_DPI as DEFAULT_VISUAL_DPI2
6196
+ DEFAULT_VISUAL_DPI as DEFAULT_VISUAL_DPI2,
6197
+ limitChartRequest
6260
6198
  } from "@json-to-office/shared";
6261
6199
  import {
6262
6200
  isNativeVisualProps as isNativeVisualProps2
@@ -6272,30 +6210,42 @@ import {
6272
6210
  chartPointsPerPixel,
6273
6211
  POINTS_PER_PIXEL_96DPI,
6274
6212
  withChartFontFaceCss,
6275
- withChartTypography
6213
+ withChartTypography,
6214
+ resolveServiceUrl as resolveServiceUrl3,
6215
+ postJsonToService as postJsonToService3,
6216
+ chartRequestKey,
6217
+ dedupeChartRequest,
6218
+ recordChartRetry
6276
6219
  } from "@json-to-office/shared";
6277
6220
  var DEFAULT_EXPORT_SERVER_URL = "http://localhost:7801";
6221
+ function effectiveChartServerUrl(props, servicesConfig) {
6222
+ return resolveServiceUrl3(
6223
+ props.serverUrl,
6224
+ servicesConfig?.serverUrl,
6225
+ DEFAULT_EXPORT_SERVER_URL
6226
+ );
6227
+ }
6278
6228
  function assertExportServerAllowed(serverUrl, servicesConfig, warnings) {
6279
6229
  const notice = remoteExportNotice(serverUrl, servicesConfig?.allowRemote);
6280
- if (notice)
6281
- warnings?.push({
6282
- component: "highcharts",
6283
- severity: "warning",
6284
- message: notice,
6285
- context: { code: REMOTE_EXPORT_WARNING, serverUrl }
6286
- });
6230
+ if (!notice || !warnings) return;
6231
+ const alreadySaid = warnings.some(
6232
+ (warning) => warning.context?.code === REMOTE_EXPORT_WARNING && warning.context?.serverUrl === serverUrl
6233
+ );
6234
+ if (alreadySaid) return;
6235
+ warnings.push({
6236
+ component: "highcharts",
6237
+ severity: "warning",
6238
+ message: notice,
6239
+ context: { code: REMOTE_EXPORT_WARNING, serverUrl }
6240
+ });
6287
6241
  }
6288
- async function generateChart(config, servicesConfig, warnings) {
6242
+ async function generateChart(config, servicesConfig, warnings, cache) {
6289
6243
  if (!isNodeEnvironment()) {
6290
6244
  throw new Error(
6291
6245
  "Highcharts export server requires a Node.js environment. Chart generation is not available in browser environments."
6292
6246
  );
6293
6247
  }
6294
- const serverUrl = resolveServiceUrl(
6295
- config.serverUrl,
6296
- servicesConfig?.serverUrl,
6297
- DEFAULT_EXPORT_SERVER_URL
6298
- );
6248
+ const serverUrl = effectiveChartServerUrl(config, servicesConfig);
6299
6249
  assertExportServerAllowed(serverUrl, servicesConfig, warnings);
6300
6250
  const requestBody = {
6301
6251
  infile: config.options,
@@ -6306,11 +6256,21 @@ async function generateChart(config, servicesConfig, warnings) {
6306
6256
  // byte-identical to before for callers that omit it.
6307
6257
  ...config.resources ? { resources: config.resources } : {}
6308
6258
  };
6309
- const response = await postJsonToService({
6259
+ return dedupeChartRequest(
6260
+ cache,
6261
+ chartRequestKey(serverUrl, requestBody),
6262
+ () => postChart(serverUrl, requestBody, config, servicesConfig)
6263
+ );
6264
+ }
6265
+ async function postChart(serverUrl, requestBody, config, servicesConfig) {
6266
+ const response = await postJsonToService3({
6310
6267
  url: serverUrl,
6311
6268
  path: "/export",
6312
6269
  body: requestBody,
6313
6270
  headers: servicesConfig?.headers,
6271
+ timeoutMs: servicesConfig?.timeoutMs,
6272
+ retries: servicesConfig?.retries,
6273
+ onRetry: recordChartRetry,
6314
6274
  serviceLabel: "Highcharts export server",
6315
6275
  onUnreachable: (url, cause) => `Highcharts Export Server is not running at ${url}. Start it with: npx highcharts-export-server --enableServer true
6316
6276
  Cause: ${cause}`
@@ -6409,13 +6369,13 @@ function withChartFontFaces(config, theme, faces) {
6409
6369
  theme.fonts.heading.family
6410
6370
  ]);
6411
6371
  }
6412
- async function renderChartToImageProps(props, theme, servicesConfig, chartFonts, warnings) {
6372
+ async function renderChartToImageProps(props, theme, servicesConfig, chartFonts, warnings, cache) {
6413
6373
  const config = withChartFontFaces(
6414
6374
  withThemeTypography(withThemeColors(props, theme), theme),
6415
6375
  theme,
6416
6376
  chartFonts
6417
6377
  );
6418
- const chart = await generateChart(config, servicesConfig, warnings);
6378
+ const chart = await generateChart(config, servicesConfig, warnings, cache);
6419
6379
  const hasConfigDimensions = config.width !== void 0 || config.height !== void 0;
6420
6380
  return {
6421
6381
  base64: chart.base64DataUri,
@@ -6435,6 +6395,7 @@ async function desugarExternals(document, options) {
6435
6395
  ...options.visualFonts ? { fonts: options.visualFonts } : {}
6436
6396
  }
6437
6397
  ).catch(() => /* @__PURE__ */ new Map());
6398
+ const chartCache = /* @__PURE__ */ new Map();
6438
6399
  return transformComponents(document, async (node) => {
6439
6400
  if (node.enabled === false) return void 0;
6440
6401
  if (node.name === "visual") {
@@ -6449,14 +6410,21 @@ async function desugarExternals(document, options) {
6449
6410
  });
6450
6411
  }
6451
6412
  if (node.name === "highcharts") {
6413
+ const props = node.props;
6414
+ const chartConfig = options.services?.highcharts;
6452
6415
  return withNodeIdentity(node, {
6453
6416
  name: "image",
6454
- props: await renderChartToImageProps(
6455
- node.props,
6456
- options.theme,
6457
- options.services?.highcharts,
6458
- options.chartFonts,
6459
- options.warnings
6417
+ props: await limitChartRequest(
6418
+ effectiveChartServerUrl(props, chartConfig),
6419
+ chartConfig?.concurrency,
6420
+ () => renderChartToImageProps(
6421
+ props,
6422
+ options.theme,
6423
+ chartConfig,
6424
+ options.chartFonts,
6425
+ options.warnings,
6426
+ chartCache
6427
+ )
6460
6428
  )
6461
6429
  });
6462
6430
  }