@pixldocs/canvas-renderer 0.5.217 → 0.5.219

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.
@@ -6919,13 +6919,7 @@ function readShadowStrength(element) {
6919
6919
  return typeof raw === "number" && Number.isFinite(raw) ? Math.max(0, Math.min(100, raw)) : 100;
6920
6920
  }
6921
6921
  function resolveShadowSourceSpread(element) {
6922
- const strength = readShadowStrength(element);
6923
- const blur = Math.max(0, Number(element.textShadowBlur ?? 0) || 0);
6924
- const fontSize = Math.max(1, Number(element.fontSize ?? 16) || 16);
6925
- if (blur <= 2) return 0;
6926
- const blurRamp = Math.min(1, (blur - 2) / 4);
6927
- const t = Math.max(0, (strength - 35) / 65);
6928
- return Math.min(8, blur * 0.16, fontSize * 0.08) * t * t * blurRamp;
6922
+ return 0;
6929
6923
  }
6930
6924
  function resolveShadowAlpha(element) {
6931
6925
  const s = readShadowStrength(element);
@@ -6948,7 +6942,7 @@ function applyTextShadow(textbox, element) {
6948
6942
  }
6949
6943
  obj.__pdShadowAlpha = canonicalShadow ? resolveShadowAlpha(element) : 1;
6950
6944
  obj.__pdShadowBaseColor = canonicalShadow ? String(element.textShadowColor || "") : void 0;
6951
- obj.__pdShadowSourceSpread = canonicalShadow ? resolveShadowSourceSpread(element) : 0;
6945
+ obj.__pdShadowSourceSpread = canonicalShadow ? resolveShadowSourceSpread() : 0;
6952
6946
  textbox.set("shadow", canonicalShadow ?? null);
6953
6947
  }
6954
6948
  function applyAlphaMultiplier(c, mult) {
@@ -7232,8 +7226,6 @@ function applyTextBackground(obj, cfg) {
7232
7226
  }
7233
7227
  }
7234
7228
  const suppressShadowOnText = bg && bg.shadowAffectsText === false;
7235
- const dropShadowSpread = Math.max(0, Number(this.__pdShadowSourceSpread) || 0);
7236
- const dropShadowActive = dropShadowSpread > 0 && !!this.shadow && !suppressShadowOnText && !blockShadowActive && !lineShadowActive;
7237
7229
  if (suppressShadowOnText) {
7238
7230
  ctx.save();
7239
7231
  ctx.shadowColor = "transparent";
@@ -7242,44 +7234,6 @@ function applyTextBackground(obj, cfg) {
7242
7234
  ctx.shadowOffsetY = 0;
7243
7235
  originalRender(ctx);
7244
7236
  ctx.restore();
7245
- } else if (dropShadowActive) {
7246
- const self = this;
7247
- const shadow = self.shadow;
7248
- const shadowColor = String((shadow == null ? void 0 : shadow.color) || this.__pdShadowBaseColor || "rgba(0,0,0,1)");
7249
- const shadowBlur = Math.max(0, Number((shadow == null ? void 0 : shadow.blur) ?? 0) || 0);
7250
- const shadowOffsetX = Number((shadow == null ? void 0 : shadow.offsetX) ?? 0) || 0;
7251
- const shadowOffsetY = Number((shadow == null ? void 0 : shadow.offsetY) ?? 0) || 0;
7252
- const origFill = self.fill;
7253
- const origStroke = self.stroke;
7254
- const origStrokeWidth = self.strokeWidth;
7255
- const origStyles = self.styles;
7256
- const origShadow = self.shadow;
7257
- try {
7258
- ctx.save();
7259
- self.shadow = null;
7260
- self.fill = shadowColor;
7261
- self.styles = {};
7262
- self.stroke = shadowColor;
7263
- self.strokeWidth = dropShadowSpread;
7264
- ctx.translate(shadowOffsetX, shadowOffsetY);
7265
- if (shadowBlur > 0) ctx.filter = `blur(${shadowBlur / 2}px)`;
7266
- ctx.lineJoin = "round";
7267
- ctx.lineCap = "round";
7268
- originalRender(ctx);
7269
- ctx.restore();
7270
- self.fill = origFill;
7271
- self.stroke = origStroke;
7272
- self.strokeWidth = origStrokeWidth;
7273
- self.styles = origStyles;
7274
- self.shadow = null;
7275
- originalRender(ctx);
7276
- } finally {
7277
- self.fill = origFill;
7278
- self.stroke = origStroke;
7279
- self.strokeWidth = origStrokeWidth;
7280
- self.styles = origStyles;
7281
- self.shadow = origShadow;
7282
- }
7283
7237
  } else {
7284
7238
  originalRender(ctx);
7285
7239
  }
@@ -7361,7 +7315,7 @@ function applyTextBackground(obj, cfg) {
7361
7315
  const oy = Number(shadow.offsetY ?? 0) || 0;
7362
7316
  const blur = Math.max(0, Number(shadow.blur ?? 0));
7363
7317
  const shadowColor = String(shadow.color);
7364
- const sourceSpread = Math.max(0, Number(this.__pdShadowSourceSpread) || 0);
7318
+ const sourceSpread = 0;
7365
7319
  const pad = Math.max(16, Math.ceil((blur + sourceSpread) * 4) + Math.ceil(Math.max(Math.abs(ox), Math.abs(oy))) + 8);
7366
7320
  const shadowBounds = unionBounds([
7367
7321
  ...rects,
@@ -17412,7 +17366,14 @@ function buildRepeatablePagesInputForApply(schema, sectionState) {
17412
17366
  const minEntries = page.minEntries != null ? Math.max(0, page.minEntries) : 1;
17413
17367
  let entryCount;
17414
17368
  if (Array.isArray(entries)) {
17415
- entryCount = minEntries === 0 ? entries.length : Math.max(1, entries.length);
17369
+ const realEntries = entries.filter((entry) => {
17370
+ if (!isRecord(entry)) return false;
17371
+ return Object.keys(entry).some(
17372
+ (k) => k !== ENTRY_ID_KEY && k !== ENTRY_NAME_KEY
17373
+ );
17374
+ });
17375
+ const count = minEntries === 0 ? realEntries.length : Math.max(1, realEntries.length);
17376
+ entryCount = count;
17416
17377
  } else {
17417
17378
  entryCount = minEntries === 0 ? 0 : minEntries;
17418
17379
  }
@@ -17423,6 +17384,25 @@ function buildRepeatablePagesInputForApply(schema, sectionState) {
17423
17384
  };
17424
17385
  });
17425
17386
  }
17387
+ function sanitizeSectionStateAgainstSchema(state, schema) {
17388
+ if (!state) return {};
17389
+ if (!schema) return { ...state };
17390
+ const known = /* @__PURE__ */ new Set();
17391
+ for (const s of schema.sections ?? []) known.add(s.id);
17392
+ for (const p of schema.repeatablePages ?? []) known.add(p.id);
17393
+ const out = {};
17394
+ for (const [key, value] of Object.entries(state)) {
17395
+ if (known.has(key)) {
17396
+ out[key] = value;
17397
+ continue;
17398
+ }
17399
+ const compositeMatch = /^(.+?)_(\d+)_(.+)$/.exec(key);
17400
+ if (compositeMatch && known.has(compositeMatch[1]) && known.has(compositeMatch[3])) {
17401
+ out[key] = value;
17402
+ }
17403
+ }
17404
+ return out;
17405
+ }
17426
17406
  async function fetchRow(supabaseUrl, anonKey, table, id) {
17427
17407
  const url = `${supabaseUrl}/rest/v1/${table}?id=eq.${id}&select=*`;
17428
17408
  const res = await fetch(url, {
@@ -17655,7 +17635,8 @@ async function resolveFromForm(options) {
17655
17635
  let mergedSectionState = { ...sectionState };
17656
17636
  const templateDefaultData = templateRow.default_data;
17657
17637
  if (templateDefaultData && isDefaultDataV2(templateDefaultData)) {
17658
- const defaults = templateDefaultData.sectionState;
17638
+ const rawDefaults = templateDefaultData.sectionState;
17639
+ const defaults = sanitizeSectionStateAgainstSchema(rawDefaults, formSchema);
17659
17640
  for (const key of Object.keys(defaults)) {
17660
17641
  if (!(key in mergedSectionState)) {
17661
17642
  mergedSectionState[key] = defaults[key];
@@ -17664,6 +17645,7 @@ async function resolveFromForm(options) {
17664
17645
  }
17665
17646
  mergedSectionState = mergeRepeatableEntryMeta(mergedSectionState, templateDefaultMetaSectionState, inferredSections);
17666
17647
  mergedSectionState = mergeRepeatableEntryMeta(mergedSectionState, defaultFormMetaSectionState, inferredSections);
17648
+ mergedSectionState = sanitizeSectionStateAgainstSchema(mergedSectionState, formSchema);
17667
17649
  const flatFormData = flattenSectionStateToFormData(mergedSectionState, inferredSections);
17668
17650
  const dynamicFields = templateConfig.dynamicFields || [];
17669
17651
  const mappings = [];
@@ -19103,9 +19085,9 @@ function captureFabricCanvasSvgForPdf(fabricInstance, canvasWidth, canvasHeight)
19103
19085
  }
19104
19086
  return svgString;
19105
19087
  }
19106
- const resolvedPackageVersion = "0.5.217";
19088
+ const resolvedPackageVersion = "0.5.219";
19107
19089
  const PACKAGE_VERSION = resolvedPackageVersion;
19108
- const DEPLOYMENT_VERSION_MARKER = "__PIXLDOCS_CANVAS_RENDERER_VERSION__:0.5.217";
19090
+ const DEPLOYMENT_VERSION_MARKER = "__PIXLDOCS_CANVAS_RENDERER_VERSION__:0.5.219";
19109
19091
  const roundParityValue = (value) => {
19110
19092
  if (typeof value !== "number") return value;
19111
19093
  return Number.isFinite(value) ? Number(value.toFixed(3)) : value;
@@ -19666,6 +19648,58 @@ class PixldocsRenderer {
19666
19648
  compressionQuality
19667
19649
  });
19668
19650
  }
19651
+ /**
19652
+ * Render the template AND deliver the resulting PDF to the user — currently
19653
+ * via email (SendGrid). The PDF is rendered server-side on EC2, uploaded to
19654
+ * S3 (returned as `pdfUrl` for download fallback), and emailed with the PDF
19655
+ * attached.
19656
+ *
19657
+ * Every delivery is logged in the `delivery_log` table for audit + admin
19658
+ * resend. The same `pdfUrl` is returned to the caller so the host app can
19659
+ * also offer a "Download" button on the success screen.
19660
+ *
19661
+ * ```ts
19662
+ * const result = await renderer.renderAndDeliver({
19663
+ * templateId, formSchemaId, sectionState,
19664
+ * project: 'biomaker',
19665
+ * recipient: { email: 'user@example.com', name: 'Anya' },
19666
+ * });
19667
+ * // → { jobId, pdfUrl, deliveries: [{ channel: 'email', status: 'sent' }] }
19668
+ * ```
19669
+ *
19670
+ * Requires `RendererConfig.deliveryServerUrl` to be set.
19671
+ */
19672
+ async renderAndDeliver(options) {
19673
+ var _a;
19674
+ const base = (_a = this.config.deliveryServerUrl) == null ? void 0 : _a.replace(/\/+$/, "");
19675
+ if (!base) {
19676
+ throw new Error("renderAndDeliver: RendererConfig.deliveryServerUrl is required");
19677
+ }
19678
+ const { templateId, formSchemaId, sectionState, themeId, watermark, project, recipient, channels, scale } = options;
19679
+ if (!project) throw new Error('renderAndDeliver: project is required (e.g. "biomaker", "pixldocs")');
19680
+ if (!(recipient == null ? void 0 : recipient.email)) throw new Error("renderAndDeliver: recipient.email is required");
19681
+ const body = {
19682
+ template_id: templateId,
19683
+ form_schema_id: formSchemaId,
19684
+ data: { version: 2, sectionState },
19685
+ project,
19686
+ recipient,
19687
+ channels: channels || ["email"]
19688
+ };
19689
+ if (themeId) body.theme = themeId;
19690
+ if (typeof watermark === "boolean") body.watermark = watermark;
19691
+ if (typeof scale === "number") body.scale = scale;
19692
+ const res = await fetch(`${base}/v1/render-and-deliver`, {
19693
+ method: "POST",
19694
+ headers: { "Content-Type": "application/json" },
19695
+ body: JSON.stringify(body)
19696
+ });
19697
+ if (!res.ok) {
19698
+ const errText = await res.text().catch(() => "");
19699
+ throw new Error(`renderAndDeliver failed: ${res.status} ${errText.slice(0, 300)}`);
19700
+ }
19701
+ return await res.json();
19702
+ }
19669
19703
  async renderById(templateId, formData, options) {
19670
19704
  const resolved = await resolveTemplateData({
19671
19705
  templateId,
@@ -19797,7 +19831,7 @@ class PixldocsRenderer {
19797
19831
  await this.waitForCanvasScene(container, cloned, i);
19798
19832
  }
19799
19833
  console.log(`[canvas-renderer][pdf-unified] mounted ${cloned.pages.length} page(s), handing off to client exportMultiPagePdf`);
19800
- const { exportMultiPagePdf, preparePagesForExport } = await Promise.resolve().then(() => require("./vectorPdfExport-B8uqWQoW.cjs"));
19834
+ const { exportMultiPagePdf, preparePagesForExport } = await Promise.resolve().then(() => require("./vectorPdfExport-CwyiHDGD.cjs"));
19801
19835
  const prepared = preparePagesForExport(
19802
19836
  cloned.pages,
19803
19837
  canvasWidth,
@@ -21739,7 +21773,7 @@ async function rasterizeShadowMarkers(svg) {
21739
21773
  const by = parseFloat(marker.getAttribute("data-by") || "0");
21740
21774
  const bw = parseFloat(marker.getAttribute("data-bw") || "0");
21741
21775
  const bh = parseFloat(marker.getAttribute("data-bh") || "0");
21742
- const spread = parseFloat(marker.getAttribute("data-spread") || "0");
21776
+ const spread = 0;
21743
21777
  const alphaRaw = parseFloat(marker.getAttribute("data-alpha") || "1");
21744
21778
  const shadowAlpha = Number.isFinite(alphaRaw) ? Math.max(0, Math.min(1, alphaRaw)) : 1;
21745
21779
  if (!Number.isFinite(bw) || !Number.isFinite(bh) || bw <= 0 || bh <= 0) {
@@ -21987,7 +22021,7 @@ async function prepareLiveCanvasSvgForPdf(rawSvg, pageWidth, pageHeight, pageKey
21987
22021
  if (options == null ? void 0 : options.stripPageBackground) stripRootPageBackgroundFromSvg(svgToDraw);
21988
22022
  sanitizeSvgTreeForPdf(svgToDraw);
21989
22023
  try {
21990
- const { bakeTextAnchorPositionsFromLiveSvg, logTextMeasurementDiagnostic } = await Promise.resolve().then(() => require("./vectorPdfExport-B8uqWQoW.cjs"));
22024
+ const { bakeTextAnchorPositionsFromLiveSvg, logTextMeasurementDiagnostic } = await Promise.resolve().then(() => require("./vectorPdfExport-CwyiHDGD.cjs"));
21991
22025
  try {
21992
22026
  await logTextMeasurementDiagnostic(svgToDraw);
21993
22027
  } catch {
@@ -22384,4 +22418,4 @@ exports.setAutoShrinkDebug = setAutoShrinkDebug;
22384
22418
  exports.setBundledAssetPrefixes = setBundledAssetPrefixes;
22385
22419
  exports.warmResolvedTemplateForPreview = warmResolvedTemplateForPreview;
22386
22420
  exports.warmTemplateFromForm = warmTemplateFromForm;
22387
- //# sourceMappingURL=index-CDrMSTDa.cjs.map
22421
+ //# sourceMappingURL=index-CBB2UdwF.cjs.map