@taloswork/ose-shared 0.1.0 → 0.1.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.
@@ -36477,7 +36477,7 @@ var require_polyfills = __commonJS({
36477
36477
  }
36478
36478
  if (platform === "win32") {
36479
36479
  fs.rename = typeof fs.rename !== "function" ? fs.rename : (function(fs$rename) {
36480
- function rename(from, to, cb) {
36480
+ function rename2(from, to, cb) {
36481
36481
  var start = Date.now();
36482
36482
  var backoff = 0;
36483
36483
  fs$rename(from, to, function CB(er) {
@@ -36497,8 +36497,8 @@ var require_polyfills = __commonJS({
36497
36497
  if (cb) cb(er);
36498
36498
  });
36499
36499
  }
36500
- if (Object.setPrototypeOf) Object.setPrototypeOf(rename, fs$rename);
36501
- return rename;
36500
+ if (Object.setPrototypeOf) Object.setPrototypeOf(rename2, fs$rename);
36501
+ return rename2;
36502
36502
  })(fs.rename);
36503
36503
  }
36504
36504
  fs.read = typeof fs.read !== "function" ? fs.read : (function(fs$read) {
@@ -72021,8 +72021,8 @@ var require_tmp = __commonJS({
72021
72021
  if (!_isUndefined(options.name)) {
72022
72022
  const name = options.name;
72023
72023
  if (path.isAbsolute(name)) throw new Error(`name option must not contain an absolute path, found "${name}".`);
72024
- const basename = path.basename(name);
72025
- if (basename === ".." || basename === "." || basename !== name) {
72024
+ const basename2 = path.basename(name);
72025
+ if (basename2 === ".." || basename2 === "." || basename2 !== name) {
72026
72026
  throw new Error(`name option must not contain a path, found "${name}".`);
72027
72027
  }
72028
72028
  }
@@ -151933,7 +151933,7 @@ var findPatchKeys = (text) => {
151933
151933
  return (_text$match = text.match(pattern)) !== null && _text$match !== void 0 ? _text$match : [];
151934
151934
  };
151935
151935
 
151936
- // packages/core/dist/fs/doc-gen.js
151936
+ // packages/core/dist/document/doc-gen.js
151937
151937
  var import_exceljs = __toESM(require_excel(), 1);
151938
151938
  var import_jszip = __toESM(require_lib3(), 1);
151939
151939
  var import_pptxgenjs = __toESM(require_pptxgen_cjs(), 1);
@@ -151941,7 +151941,7 @@ var import_pdf_lib = __toESM(require_cjs(), 1);
151941
151941
  var import_fontkit = __toESM(require_fontkit_umd(), 1);
151942
151942
  var import_node_fs = require("node:fs");
151943
151943
 
151944
- // packages/core/dist/fs/doc-theme.js
151944
+ // packages/core/dist/document/doc-theme.js
151945
151945
  var DEFAULT_THEME = {
151946
151946
  bestFor: "",
151947
151947
  fonts: { heading: "", body: "" },
@@ -152175,7 +152175,7 @@ function themeCssVars(theme) {
152175
152175
  return `:root{${lines.join(";")}}`;
152176
152176
  }
152177
152177
 
152178
- // packages/core/dist/fs/doc-palette.js
152178
+ // packages/core/dist/document/doc-palette.js
152179
152179
  var PALETTE_LIBRARY = [
152180
152180
  {
152181
152181
  name: "corporate-navy",
@@ -152413,7 +152413,7 @@ function listPalettes() {
152413
152413
  return PALETTE_LIBRARY.map(({ name, mood, dark }) => ({ name, mood, dark }));
152414
152414
  }
152415
152415
 
152416
- // packages/core/dist/fs/lucide-icons.js
152416
+ // packages/core/dist/document/lucide-icons.js
152417
152417
  var LUCIDE_ICONS = {
152418
152418
  check: '<path d="M20 6 9 17l-5-5"/>',
152419
152419
  "check-circle": '<circle cx="12" cy="12" r="10"/><path d="m9 12 2 2 4-4"/>',
@@ -152470,16 +152470,289 @@ function iconSvgDataUri(name, colorHex) {
152470
152470
  return "data:image/svg+xml;base64," + Buffer.from(svg).toString("base64");
152471
152471
  }
152472
152472
 
152473
- // packages/core/dist/fs/doc-gen.js
152473
+ // packages/core/dist/document/doc-gen.js
152474
152474
  function bareHex(c) {
152475
152475
  return c.replace("#", "").toUpperCase();
152476
152476
  }
152477
+ var DocumentSpecValidationError = class extends Error {
152478
+ code = "DOC_SPEC_INVALID";
152479
+ issues;
152480
+ constructor(issues) {
152481
+ const detail = issues.map((issue) => `${issue.path}: ${issue.message}`).join("; ");
152482
+ super(`DOC_SPEC_INVALID: ${detail}`);
152483
+ this.name = "DocumentSpecValidationError";
152484
+ this.issues = [...issues];
152485
+ }
152486
+ };
152487
+ var TEXT_DOCUMENT_KEYS = /* @__PURE__ */ new Set(["title", "paragraphs", "blocks", "allowCoverOnly", "fontPath", "theme", "topic", "palette"]);
152488
+ var XLSX_DOCUMENT_KEYS = /* @__PURE__ */ new Set(["sheets", "theme", "topic", "palette"]);
152489
+ var PPTX_DOCUMENT_KEYS = /* @__PURE__ */ new Set(["slides", "theme", "topic", "palette"]);
152490
+ var PPTX_SLIDE_KEYS = /* @__PURE__ */ new Set([
152491
+ "title",
152492
+ "cover",
152493
+ "toc",
152494
+ "ending",
152495
+ "section",
152496
+ "kpiCards",
152497
+ "cards",
152498
+ "timeline",
152499
+ "steps",
152500
+ "iconList",
152501
+ "splitImage",
152502
+ "comparison",
152503
+ "quadrant",
152504
+ "bigStat",
152505
+ "quote",
152506
+ "bullets",
152507
+ "table",
152508
+ "image",
152509
+ "chart"
152510
+ ]);
152511
+ function isJsonRecord(value) {
152512
+ return value !== null && typeof value === "object" && !Array.isArray(value);
152513
+ }
152514
+ function addUnknownPropertyIssues(record, allowed, path, issues) {
152515
+ for (const key of Object.keys(record)) {
152516
+ if (allowed.has(key))
152517
+ continue;
152518
+ const message = allowed === TEXT_DOCUMENT_KEYS && (key === "section" || key === "sections") ? `${key} is unsupported for DOCX/PDF content; use $.blocks with heading/paragraph/list/table/image blocks (section is PPTX-only)` : `unsupported property ${JSON.stringify(key)}; allowed properties: ${[...allowed].join(", ")}`;
152519
+ issues.push({ path: `${path}.${key}`, code: "UNKNOWN_PROPERTY", message });
152520
+ }
152521
+ }
152522
+ function nonBlankString(value) {
152523
+ return typeof value === "string" && value.trim().length > 0;
152524
+ }
152525
+ function validateTextBlock(value, path, issues) {
152526
+ if (!isJsonRecord(value)) {
152527
+ issues.push({ path, code: "INVALID_TYPE", message: "block must be an object" });
152528
+ return false;
152529
+ }
152530
+ if (typeof value.type !== "string") {
152531
+ issues.push({ path: `${path}.type`, code: "INVALID_TYPE", message: "block type must be a string" });
152532
+ return false;
152533
+ }
152534
+ const requireText = () => {
152535
+ if (nonBlankString(value.text))
152536
+ return true;
152537
+ issues.push({ path: `${path}.text`, code: "EMPTY_CONTENT", message: "text must be a non-empty string" });
152538
+ return false;
152539
+ };
152540
+ switch (value.type) {
152541
+ case "heading": {
152542
+ addUnknownPropertyIssues(value, /* @__PURE__ */ new Set(["type", "text", "level"]), path, issues);
152543
+ const valid = requireText();
152544
+ if (value.level !== void 0 && ![1, 2, 3, 4].includes(value.level)) {
152545
+ issues.push({ path: `${path}.level`, code: "INVALID_VALUE", message: "level must be one of 1, 2, 3, 4" });
152546
+ }
152547
+ return valid;
152548
+ }
152549
+ case "paragraph": {
152550
+ addUnknownPropertyIssues(value, /* @__PURE__ */ new Set(["type", "text", "bold", "italic"]), path, issues);
152551
+ const valid = requireText();
152552
+ for (const key of ["bold", "italic"]) {
152553
+ if (value[key] !== void 0 && typeof value[key] !== "boolean") {
152554
+ issues.push({ path: `${path}.${key}`, code: "INVALID_TYPE", message: `${key} must be a boolean` });
152555
+ }
152556
+ }
152557
+ return valid;
152558
+ }
152559
+ case "list": {
152560
+ addUnknownPropertyIssues(value, /* @__PURE__ */ new Set(["type", "items", "ordered"]), path, issues);
152561
+ if (!Array.isArray(value.items) || value.items.length === 0) {
152562
+ issues.push({ path: `${path}.items`, code: "EMPTY_CONTENT", message: "items must be a non-empty string array" });
152563
+ return false;
152564
+ }
152565
+ let valid = true;
152566
+ value.items.forEach((item, index) => {
152567
+ if (nonBlankString(item))
152568
+ return;
152569
+ valid = false;
152570
+ issues.push({ path: `${path}.items[${index}]`, code: "EMPTY_CONTENT", message: "list item must be a non-empty string" });
152571
+ });
152572
+ if (value.ordered !== void 0 && typeof value.ordered !== "boolean") {
152573
+ issues.push({ path: `${path}.ordered`, code: "INVALID_TYPE", message: "ordered must be a boolean" });
152574
+ }
152575
+ return valid;
152576
+ }
152577
+ case "table": {
152578
+ addUnknownPropertyIssues(value, /* @__PURE__ */ new Set(["type", "rows", "header", "columnWidths"]), path, issues);
152579
+ if (!Array.isArray(value.rows) || value.rows.length === 0) {
152580
+ issues.push({ path: `${path}.rows`, code: "EMPTY_CONTENT", message: "rows must be a non-empty array" });
152581
+ return false;
152582
+ }
152583
+ let hasCellContent = false;
152584
+ value.rows.forEach((row, rowIndex) => {
152585
+ if (!Array.isArray(row) || row.length === 0) {
152586
+ issues.push({ path: `${path}.rows[${rowIndex}]`, code: "INVALID_TYPE", message: "table row must be a non-empty array" });
152587
+ return;
152588
+ }
152589
+ row.forEach((cell, columnIndex) => {
152590
+ if (typeof cell !== "string" && typeof cell !== "number") {
152591
+ issues.push({ path: `${path}.rows[${rowIndex}][${columnIndex}]`, code: "INVALID_TYPE", message: "table cell must be a string or number" });
152592
+ } else if (String(cell).trim().length > 0) {
152593
+ hasCellContent = true;
152594
+ }
152595
+ });
152596
+ });
152597
+ if (!hasCellContent) {
152598
+ issues.push({ path: `${path}.rows`, code: "EMPTY_CONTENT", message: "table must contain at least one non-empty cell" });
152599
+ }
152600
+ if (value.header !== void 0 && typeof value.header !== "boolean") {
152601
+ issues.push({ path: `${path}.header`, code: "INVALID_TYPE", message: "header must be a boolean" });
152602
+ }
152603
+ if (value.columnWidths !== void 0 && (!Array.isArray(value.columnWidths) || value.columnWidths.some((width) => typeof width !== "number" || !Number.isFinite(width) || width <= 0))) {
152604
+ issues.push({ path: `${path}.columnWidths`, code: "INVALID_VALUE", message: "columnWidths must contain only positive finite numbers" });
152605
+ }
152606
+ return hasCellContent;
152607
+ }
152608
+ case "image": {
152609
+ addUnknownPropertyIssues(value, /* @__PURE__ */ new Set(["type", "data", "imageType", "width", "height"]), path, issues);
152610
+ if (!nonBlankString(value.data)) {
152611
+ issues.push({ path: `${path}.data`, code: "EMPTY_CONTENT", message: "image data must be non-empty base64" });
152612
+ return false;
152613
+ }
152614
+ if (value.imageType !== void 0 && !["png", "jpg", "gif", "bmp"].includes(String(value.imageType))) {
152615
+ issues.push({ path: `${path}.imageType`, code: "INVALID_VALUE", message: "imageType must be png, jpg, gif, or bmp" });
152616
+ }
152617
+ for (const key of ["width", "height"]) {
152618
+ if (value[key] !== void 0 && (typeof value[key] !== "number" || !Number.isFinite(value[key]) || value[key] <= 0)) {
152619
+ issues.push({ path: `${path}.${key}`, code: "INVALID_VALUE", message: `${key} must be a positive finite number` });
152620
+ }
152621
+ }
152622
+ return true;
152623
+ }
152624
+ default:
152625
+ issues.push({ path: `${path}.type`, code: "INVALID_VALUE", message: `unhandled block type: ${value.type}` });
152626
+ return false;
152627
+ }
152628
+ }
152629
+ function inspectTextDocumentSpec(spec) {
152630
+ const issues = [];
152631
+ if (!isJsonRecord(spec)) {
152632
+ issues.push({ path: "$", code: "INVALID_TYPE", message: "spec must be a JSON object" });
152633
+ return { issues, hasBody: false, hasTitle: false, allowCoverOnly: false };
152634
+ }
152635
+ addUnknownPropertyIssues(spec, TEXT_DOCUMENT_KEYS, "$", issues);
152636
+ const hasTitle = nonBlankString(spec.title);
152637
+ if (spec.title !== void 0 && !hasTitle) {
152638
+ issues.push({ path: "$.title", code: "EMPTY_CONTENT", message: "title must be a non-empty string when provided" });
152639
+ }
152640
+ if (spec.allowCoverOnly !== void 0 && typeof spec.allowCoverOnly !== "boolean") {
152641
+ issues.push({ path: "$.allowCoverOnly", code: "INVALID_TYPE", message: "allowCoverOnly must be a boolean" });
152642
+ }
152643
+ if (spec.fontPath !== void 0 && !nonBlankString(spec.fontPath)) {
152644
+ issues.push({ path: "$.fontPath", code: "INVALID_TYPE", message: "fontPath must be a non-empty string" });
152645
+ }
152646
+ let hasBody = false;
152647
+ if (spec.paragraphs !== void 0) {
152648
+ if (!Array.isArray(spec.paragraphs)) {
152649
+ issues.push({ path: "$.paragraphs", code: "INVALID_TYPE", message: "paragraphs must be a string array" });
152650
+ } else {
152651
+ spec.paragraphs.forEach((paragraph, index) => {
152652
+ if (nonBlankString(paragraph))
152653
+ hasBody = true;
152654
+ else
152655
+ issues.push({ path: `$.paragraphs[${index}]`, code: "EMPTY_CONTENT", message: "paragraph must be a non-empty string" });
152656
+ });
152657
+ }
152658
+ }
152659
+ if (spec.blocks !== void 0) {
152660
+ if (!Array.isArray(spec.blocks)) {
152661
+ issues.push({ path: "$.blocks", code: "INVALID_TYPE", message: "blocks must be an array" });
152662
+ } else {
152663
+ spec.blocks.forEach((block, index) => {
152664
+ if (validateTextBlock(block, `$.blocks[${index}]`, issues))
152665
+ hasBody = true;
152666
+ });
152667
+ }
152668
+ }
152669
+ return { issues, hasBody, hasTitle, allowCoverOnly: spec.allowCoverOnly === true };
152670
+ }
152477
152671
  function assertTextDocumentSpec(spec) {
152478
- if (!spec || typeof spec !== "object")
152672
+ const { issues } = inspectTextDocumentSpec(spec);
152673
+ if (issues.length > 0)
152674
+ throw new DocumentSpecValidationError(issues);
152675
+ }
152676
+ function validateRows(rows, path, issues) {
152677
+ if (!Array.isArray(rows) || rows.length === 0) {
152678
+ issues.push({ path, code: "EMPTY_CONTENT", message: "rows must be a non-empty array" });
152679
+ return false;
152680
+ }
152681
+ let hasContent = false;
152682
+ rows.forEach((row, rowIndex) => {
152683
+ if (!Array.isArray(row) || row.length === 0) {
152684
+ issues.push({ path: `${path}[${rowIndex}]`, code: "INVALID_TYPE", message: "row must be a non-empty array" });
152685
+ return;
152686
+ }
152687
+ row.forEach((cell, columnIndex) => {
152688
+ if (typeof cell !== "string" && typeof cell !== "number") {
152689
+ issues.push({ path: `${path}[${rowIndex}][${columnIndex}]`, code: "INVALID_TYPE", message: "cell must be a string or number" });
152690
+ } else if (String(cell).trim().length > 0) {
152691
+ hasContent = true;
152692
+ }
152693
+ });
152694
+ });
152695
+ if (!hasContent)
152696
+ issues.push({ path, code: "EMPTY_CONTENT", message: "rows must contain at least one non-empty cell" });
152697
+ return hasContent;
152698
+ }
152699
+ function assertDocumentSpec(kind, spec) {
152700
+ if (kind === "docx" || kind === "pdf") {
152701
+ const inspection = inspectTextDocumentSpec(spec);
152702
+ if (!inspection.hasBody && !(inspection.allowCoverOnly && inspection.hasTitle)) {
152703
+ inspection.issues.push({
152704
+ path: "$",
152705
+ code: "EMPTY_CONTENT",
152706
+ message: "document body is empty; provide non-empty paragraphs/blocks, or set allowCoverOnly=true with a non-empty title"
152707
+ });
152708
+ }
152709
+ if (inspection.issues.length > 0)
152710
+ throw new DocumentSpecValidationError(inspection.issues);
152479
152711
  return;
152480
- if (Object.prototype.hasOwnProperty.call(spec, "section")) {
152481
- throw new Error("unsupported document field: section (use blocks for DOCX/PDF content; section is PPTX-only)");
152482
152712
  }
152713
+ const issues = [];
152714
+ if (!isJsonRecord(spec)) {
152715
+ throw new DocumentSpecValidationError([{ path: "$", code: "INVALID_TYPE", message: "spec must be a JSON object" }]);
152716
+ }
152717
+ if (kind === "xlsx") {
152718
+ addUnknownPropertyIssues(spec, XLSX_DOCUMENT_KEYS, "$", issues);
152719
+ if (!isJsonRecord(spec.sheets) || Object.keys(spec.sheets).length === 0) {
152720
+ issues.push({ path: "$.sheets", code: "EMPTY_CONTENT", message: "sheets must be a non-empty object" });
152721
+ } else {
152722
+ for (const [name, sheet] of Object.entries(spec.sheets)) {
152723
+ const path = `$.sheets[${JSON.stringify(name)}]`;
152724
+ if (Array.isArray(sheet)) {
152725
+ validateRows(sheet, path, issues);
152726
+ } else if (isJsonRecord(sheet)) {
152727
+ addUnknownPropertyIssues(sheet, /* @__PURE__ */ new Set(["rows", "header", "columnWidths", "numFmt"]), path, issues);
152728
+ validateRows(sheet.rows, `${path}.rows`, issues);
152729
+ } else {
152730
+ issues.push({ path, code: "INVALID_TYPE", message: "sheet must be a row array or an object containing rows" });
152731
+ }
152732
+ }
152733
+ }
152734
+ } else if (kind === "pptx") {
152735
+ addUnknownPropertyIssues(spec, PPTX_DOCUMENT_KEYS, "$", issues);
152736
+ if (!Array.isArray(spec.slides) || spec.slides.length === 0) {
152737
+ issues.push({ path: "$.slides", code: "EMPTY_CONTENT", message: "slides must be a non-empty array" });
152738
+ } else {
152739
+ spec.slides.forEach((slide, index) => {
152740
+ const path = `$.slides[${index}]`;
152741
+ if (!isJsonRecord(slide)) {
152742
+ issues.push({ path, code: "INVALID_TYPE", message: "slide must be an object" });
152743
+ return;
152744
+ }
152745
+ addUnknownPropertyIssues(slide, PPTX_SLIDE_KEYS, path, issues);
152746
+ if (Object.keys(slide).length === 0) {
152747
+ issues.push({ path, code: "EMPTY_CONTENT", message: "slide must contain at least one supported field" });
152748
+ }
152749
+ });
152750
+ }
152751
+ } else {
152752
+ throw new Error(`unsupported kind: ${String(kind)}`);
152753
+ }
152754
+ if (issues.length > 0)
152755
+ throw new DocumentSpecValidationError(issues);
152483
152756
  }
152484
152757
  var HEADINGS = [HeadingLevel.HEADING_1, HeadingLevel.HEADING_2, HeadingLevel.HEADING_3, HeadingLevel.HEADING_4];
152485
152758
  var ORDERED_REF = "ol";
@@ -153741,6 +154014,7 @@ async function generatePdf(spec, themeInput) {
153741
154014
  return doc.save();
153742
154015
  }
153743
154016
  async function generateDocument(kind, spec, theme) {
154017
+ assertDocumentSpec(kind, spec);
153744
154018
  switch (kind) {
153745
154019
  case "docx":
153746
154020
  return generateDocx(spec, theme);
@@ -153755,7 +154029,7 @@ async function generateDocument(kind, spec, theme) {
153755
154029
  }
153756
154030
  }
153757
154031
 
153758
- // packages/core/dist/fs/doc-html.js
154032
+ // packages/core/dist/document/doc-html.js
153759
154033
  var FONT_STACK = 'TalosCJK, "Helvetica Neue", Helvetica, Arial, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Noto Sans CJK SC", "Source Han Sans SC", "WenQuanYi Zen Hei", sans-serif';
153760
154034
  function stackWith(font) {
153761
154035
  return font ? `"${font.replace(/"/g, "")}", ${FONT_STACK}` : FONT_STACK;
@@ -153856,8 +154130,9 @@ function themePrintOptions(themeInput, title) {
153856
154130
  // apps/admin/data/skills.lib/document/bin-src/doc-gen.mjs
153857
154131
  var import_node_path = require("node:path");
153858
154132
  var import_node_fs2 = require("node:fs");
154133
+ var import_node_crypto = require("node:crypto");
153859
154134
 
153860
- // packages/core/dist/fs/tpl-interp.js
154135
+ // packages/core/dist/document/tpl-interp.js
153861
154136
  var TAG = /\{\{\{?\s*([#/]?)\s*([^}]*?)\s*\}?\}\}/g;
153862
154137
  function parseTemplate(src) {
153863
154138
  const tokens = [];
@@ -153976,7 +154251,7 @@ function interpolate(src, data) {
153976
154251
  return render(parseTemplate(src), { ctx: data });
153977
154252
  }
153978
154253
 
153979
- // packages/core/dist/fs/html-templates.js
154254
+ // packages/core/dist/document/html-templates.js
153980
154255
  var CARD = "background:var(--card-bg);border:1px solid var(--border);border-radius:16px";
153981
154256
  var TEMPLATES = {
153982
154257
  cover: {
@@ -154130,10 +154405,10 @@ function contrastHex(hex) {
154130
154405
  return lum > 0.55 ? "#1a1a1a" : "#ffffff";
154131
154406
  }
154132
154407
 
154133
- // packages/core/dist/fs/html-pptx.js
154408
+ // packages/core/dist/document/html-pptx.js
154134
154409
  var import_jszip3 = __toESM(require_lib3(), 1);
154135
154410
 
154136
- // packages/core/dist/fs/pptx-anim.js
154411
+ // packages/core/dist/document/pptx-anim.js
154137
154412
  var import_jszip2 = __toESM(require_lib3(), 1);
154138
154413
  var FLY_SUBTYPE = { "fly-up": 4, "fly-down": 1, "fly-left": 2, "fly-right": 8 };
154139
154414
  function setVisible(id, spid) {
@@ -154210,7 +154485,7 @@ async function injectAnimations(buf, perSlide) {
154210
154485
  return await zip.generateAsync({ type: "nodebuffer", compression: "DEFLATE" });
154211
154486
  }
154212
154487
 
154213
- // packages/core/dist/fs/html-pptx.js
154488
+ // packages/core/dist/document/html-pptx.js
154214
154489
  var DEFAULT_CHART_RAMP = ["2563EB", "10B981", "F59E0B", "EF4444", "8B5CF6", "06B6D4"];
154215
154490
  var SLIDE_W_IN = 13.333;
154216
154491
  var SLIDE_H_IN = 7.5;
@@ -154596,6 +154871,21 @@ function die(msg, code = 1) {
154596
154871
  `);
154597
154872
  process.exit(code);
154598
154873
  }
154874
+ async function writeArtifactAtomically(out, bytes) {
154875
+ const temp = (0, import_node_path.join)((0, import_node_path.dirname)(out), `.${(0, import_node_path.basename)(out)}.${process.pid}.${(0, import_node_crypto.randomUUID)()}.tmp`);
154876
+ try {
154877
+ await (0, import_promises.writeFile)(temp, Buffer.from(bytes), { flag: "wx" });
154878
+ await (0, import_promises.rename)(temp, out);
154879
+ } catch (error) {
154880
+ try {
154881
+ await (0, import_promises.rm)(temp, { force: true });
154882
+ } catch (cleanupError) {
154883
+ process.stderr.write(`doc-gen: cleanup failed for ${temp}: ${cleanupError instanceof Error ? cleanupError.message : String(cleanupError)}
154884
+ `);
154885
+ }
154886
+ throw error;
154887
+ }
154888
+ }
154599
154889
  async function renderDesignHtml(spec, theme) {
154600
154890
  const { html, unsupported } = buildDeckHtml(spec, theme);
154601
154891
  if (unsupported.length) {
@@ -154698,6 +154988,11 @@ async function main() {
154698
154988
  } catch (e) {
154699
154989
  die(`bad spec: ${e.message}`, 64);
154700
154990
  }
154991
+ try {
154992
+ assertDocumentSpec(kind, spec);
154993
+ } catch (e) {
154994
+ die(e instanceof Error ? e.message : String(e), e?.code === "DOC_SPEC_INVALID" ? 65 : 64);
154995
+ }
154701
154996
  if (paletteFlag) spec.palette = paletteFlag;
154702
154997
  if (topicFlag) spec.topic = topicFlag;
154703
154998
  let rawTheme = spec.theme;
@@ -154751,8 +155046,10 @@ async function main() {
154751
155046
  if (kind === "pdf") engine = "pdf (pdf-lib)";
154752
155047
  else if (kind === "pptx" && design === "html") engine = "pptx (native fallback)";
154753
155048
  }
154754
- await (0, import_promises.writeFile)(out, Buffer.from(bytes));
155049
+ await writeArtifactAtomically(out, bytes);
154755
155050
  process.stdout.write(`wrote ${out}${kind === "pdf" || kind === "pptx" && design === "html" ? ` [${engine}]` : ""}
154756
155051
  `);
154757
155052
  }
154758
- main();
155053
+ main().catch((error) => {
155054
+ die(error instanceof Error ? error.message : String(error), 1);
155055
+ });
@@ -5,18 +5,9 @@
5
5
  var import_promises = require("node:fs/promises");
6
6
  var import_node_path2 = require("node:path");
7
7
 
8
- // packages/core/dist/fs/pdf-extract.js
8
+ // packages/core/dist/document/pdf-extract.js
9
9
  var import_node_path = require("node:path");
10
10
  var import_node_url = require("node:url");
11
-
12
- // packages/core/dist/fs/doc-scan.js
13
- var SCANNED_TEXT_CHARS = 20;
14
- var SCAN_IMAGE_COVERAGE = 0.5;
15
- function isScannedPage(s) {
16
- return s.textChars <= SCANNED_TEXT_CHARS && s.imageCoverage >= SCAN_IMAGE_COVERAGE;
17
- }
18
-
19
- // packages/core/dist/fs/pdf-extract.js
20
11
  var _mupdf = null;
21
12
  function loadMupdf() {
22
13
  if (!_mupdf) {
@@ -183,6 +174,13 @@ async function scanPdfSignals(bytes) {
183
174
  return signals;
184
175
  }
185
176
 
177
+ // packages/core/dist/document/doc-scan.js
178
+ var SCANNED_TEXT_CHARS = 20;
179
+ var SCAN_IMAGE_COVERAGE = 0.5;
180
+ function isScannedPage(s) {
181
+ return s.textChars <= SCANNED_TEXT_CHARS && s.imageCoverage >= SCAN_IMAGE_COVERAGE;
182
+ }
183
+
186
184
  // apps/admin/data/skills.lib/document/bin-src/doc-scan.mjs
187
185
  function die(msg, code = 1) {
188
186
  process.stderr.write(`doc-scan: ${msg}
@@ -5,7 +5,7 @@
5
5
  var import_promises = require("node:fs/promises");
6
6
  var import_node_path2 = require("node:path");
7
7
 
8
- // packages/core/dist/fs/pdf-extract.js
8
+ // packages/core/dist/document/pdf-extract.js
9
9
  var import_node_path = require("node:path");
10
10
  var import_node_url = require("node:url");
11
11
  var _mupdf = null;
@@ -9819,7 +9819,7 @@ var require_lib3 = __commonJS({
9819
9819
  var import_promises2 = require("node:fs/promises");
9820
9820
  var import_node_path2 = require("node:path");
9821
9821
 
9822
- // packages/core/dist/fs/doc-validate.js
9822
+ // packages/core/dist/document/doc-validate.js
9823
9823
  var import_jszip = __toESM(require_lib3(), 1);
9824
9824
  var NAME_RE = /^[A-Za-z_:][A-Za-z0-9_.:-]*/;
9825
9825
  function xmlWellFormednessErrors(xml, maxErrors = 5) {
@@ -10037,7 +10037,7 @@ async function validateOoxml(bytes) {
10037
10037
  return result(root.kind);
10038
10038
  }
10039
10039
 
10040
- // packages/core/dist/fs/doc-xsd.js
10040
+ // packages/core/dist/document/doc-xsd.js
10041
10041
  var import_node_path = require("node:path");
10042
10042
  var import_node_url = require("node:url");
10043
10043
  var import_promises = require("node:fs/promises");
@@ -10139,7 +10139,7 @@ async function validateOoxmlStrict(bytes, schemaDir) {
10139
10139
  return { ok: errors.length === 0, checked, skipped, errors };
10140
10140
  }
10141
10141
 
10142
- // packages/core/dist/fs/doc-design-lint.js
10142
+ // packages/core/dist/document/doc-design-lint.js
10143
10143
  var import_jszip3 = __toESM(require_lib3(), 1);
10144
10144
  var PLACEHOLDER_RE = /替换为|在这里写|占位|示例文本|Lorem ipsum/i;
10145
10145
  var CJK_TEXT_RE = /[぀-ヿ㐀-䶿一-鿿가-힯豈-﫿]/;
@@ -9818,12 +9818,12 @@ var require_lib3 = __commonJS({
9818
9818
  // apps/admin/data/skills.lib/document/bin-src/doc-xml.mjs
9819
9819
  var import_promises2 = require("node:fs/promises");
9820
9820
 
9821
- // packages/core/dist/fs/doc-xml.js
9821
+ // packages/core/dist/document/doc-xml.js
9822
9822
  var import_jszip = __toESM(require_lib3(), 1);
9823
9823
  var import_promises = require("node:fs/promises");
9824
9824
  var import_node_path = require("node:path");
9825
9825
 
9826
- // packages/core/dist/fs/ooxml-util.js
9826
+ // packages/core/dist/document/ooxml-util.js
9827
9827
  function escXml(s) {
9828
9828
  return s.replace(/[&<>"']/g, (c) => ({ "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;", "'": "&apos;" })[c]);
9829
9829
  }
@@ -9907,7 +9907,7 @@ function replaceTextAcrossRuns(xml, find, replacement, opts) {
9907
9907
  return { xml: rewritten, count };
9908
9908
  }
9909
9909
 
9910
- // packages/core/dist/fs/doc-xml.js
9910
+ // packages/core/dist/document/doc-xml.js
9911
9911
  function prettyXml(xml) {
9912
9912
  const tokens = xml.split(/(?<=>)(?=<)/);
9913
9913
  if (tokens.length < 2)
@@ -9818,15 +9818,15 @@ var require_lib3 = __commonJS({
9818
9818
  // apps/admin/data/skills.lib/document/bin-src/docx-annotate.mjs
9819
9819
  var import_promises = require("node:fs/promises");
9820
9820
 
9821
- // packages/core/dist/fs/docx-annotate.js
9821
+ // packages/core/dist/document/docx-annotate.js
9822
9822
  var import_jszip = __toESM(require_lib3(), 1);
9823
9823
 
9824
- // packages/core/dist/fs/ooxml-util.js
9824
+ // packages/core/dist/document/ooxml-util.js
9825
9825
  function escXml(s) {
9826
9826
  return s.replace(/[&<>"']/g, (c) => ({ "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;", "'": "&apos;" })[c]);
9827
9827
  }
9828
9828
 
9829
- // packages/core/dist/fs/docx-annotate.js
9829
+ // packages/core/dist/document/docx-annotate.js
9830
9830
  var import_node_crypto = require("node:crypto");
9831
9831
  var W_NS = "http://schemas.openxmlformats.org/wordprocessingml/2006/main";
9832
9832
  var W14_NS = "http://schemas.microsoft.com/office/word/2010/wordml";
@@ -132886,10 +132886,10 @@ var import_promises = require("node:fs/promises");
132886
132886
  var import_node_fs = require("node:fs");
132887
132887
  var import_node_path = require("node:path");
132888
132888
 
132889
- // packages/core/dist/fs/html-pptx.js
132889
+ // packages/core/dist/document/html-pptx.js
132890
132890
  var import_jszip3 = __toESM(require_lib3(), 1);
132891
132891
 
132892
- // packages/core/dist/fs/pptx-anim.js
132892
+ // packages/core/dist/document/pptx-anim.js
132893
132893
  var import_jszip = __toESM(require_lib3(), 1);
132894
132894
  var FLY_SUBTYPE = { "fly-up": 4, "fly-down": 1, "fly-left": 2, "fly-right": 8 };
132895
132895
  function setVisible(id, spid) {
@@ -146659,14 +146659,14 @@ var findPatchKeys = (text) => {
146659
146659
  return (_text$match = text.match(pattern)) !== null && _text$match !== void 0 ? _text$match : [];
146660
146660
  };
146661
146661
 
146662
- // packages/core/dist/fs/doc-gen.js
146662
+ // packages/core/dist/document/doc-gen.js
146663
146663
  var import_exceljs = __toESM(require_excel(), 1);
146664
146664
  var import_jszip2 = __toESM(require_lib3(), 1);
146665
146665
  var import_pptxgenjs = __toESM(require_pptxgen_cjs(), 1);
146666
146666
  var import_pdf_lib = __toESM(require_cjs(), 1);
146667
146667
  var import_fontkit = __toESM(require_fontkit_umd(), 1);
146668
146668
 
146669
- // packages/core/dist/fs/doc-theme.js
146669
+ // packages/core/dist/document/doc-theme.js
146670
146670
  var DEFAULT_THEME = {
146671
146671
  bestFor: "",
146672
146672
  fonts: { heading: "", body: "" },
@@ -146864,7 +146864,7 @@ function themeCssVars(theme) {
146864
146864
  return `:root{${lines.join(";")}}`;
146865
146865
  }
146866
146866
 
146867
- // packages/core/dist/fs/doc-palette.js
146867
+ // packages/core/dist/document/doc-palette.js
146868
146868
  var PALETTE_LIBRARY = [
146869
146869
  {
146870
146870
  name: "corporate-navy",
@@ -147051,7 +147051,7 @@ var PALETTE_LIBRARY = [
147051
147051
  ];
147052
147052
  var BY_NAME = new Map(PALETTE_LIBRARY.map((p) => [p.name, p]));
147053
147053
 
147054
- // packages/core/dist/fs/doc-gen.js
147054
+ // packages/core/dist/document/doc-gen.js
147055
147055
  var HEADINGS = [HeadingLevel.HEADING_1, HeadingLevel.HEADING_2, HeadingLevel.HEADING_3, HeadingLevel.HEADING_4];
147056
147056
  var SLIDE_W = 13.33;
147057
147057
  var SLIDE_LEFT = 0.6;
@@ -147128,7 +147128,7 @@ var PAGE_W = 595.28;
147128
147128
  var MARGIN = 56;
147129
147129
  var CONTENT_W = PAGE_W - MARGIN * 2;
147130
147130
 
147131
- // packages/core/dist/fs/html-pptx.js
147131
+ // packages/core/dist/document/html-pptx.js
147132
147132
  var DEFAULT_CHART_RAMP = ["2563EB", "10B981", "F59E0B", "EF4444", "8B5CF6", "06B6D4"];
147133
147133
  var SLIDE_W_IN = 13.333;
147134
147134
  var SLIDE_H_IN = 7.5;
@@ -147574,7 +147574,7 @@ async function imagesToPptx(imagesBase64Png) {
147574
147574
  return finalizePptx(new Uint8Array(buf));
147575
147575
  }
147576
147576
 
147577
- // packages/core/dist/fs/html-pptx-walker.js
147577
+ // packages/core/dist/document/html-pptx-walker.js
147578
147578
  var LAYOUT_WALKER_JS = `
147579
147579
  (() => {
147580
147580
  const sections = [...document.querySelectorAll("section.slide")];
@@ -147722,7 +147722,7 @@ var LAYOUT_WALKER_JS = `
147722
147722
  })()
147723
147723
  `;
147724
147724
 
147725
- // packages/core/dist/fs/html-pptx-headless.js
147725
+ // packages/core/dist/document/html-pptx-headless.js
147726
147726
  var sleep = (ms) => new Promise((r) => setTimeout(r, ms));
147727
147727
  var pngDataUri = (bytes) => "data:image/png;base64," + Buffer.from(bytes).toString("base64");
147728
147728
  var isolateSlide = (si) => `new Promise((done) => { const secs = document.querySelectorAll("section.slide"); secs.forEach((s, j) => { s.style.display = j === ${si} ? "" : "none"; }); window.scrollTo(0, 0); requestAnimationFrame(() => requestAnimationFrame(() => done(true))); })`;
@@ -147795,7 +147795,7 @@ async function rasterizeHeadless(page) {
147795
147795
  return shots;
147796
147796
  }
147797
147797
 
147798
- // packages/core/dist/fs/doc-images.js
147798
+ // packages/core/dist/document/doc-images.js
147799
147799
  var EXT_MIME = {
147800
147800
  png: "image/png",
147801
147801
  jpg: "image/jpeg",