executable-stories-formatters 1.21.0 → 1.21.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/cli.js CHANGED
@@ -11626,9 +11626,12 @@ import * as fs13 from "fs";
11626
11626
  import * as path19 from "path";
11627
11627
  import { parseArgs as parseArgs2 } from "util";
11628
11628
  import { canonicalizeRun as canonicalizeRun5 } from "executable-stories-core/converters/acl/canonicalize";
11629
- import { collectReportAssets, rewriteReportAssets } from "executable-stories-core/report-assets";
11630
11629
  import { toStoryReport as toStoryReport8 } from "executable-stories-core/converters/story-report";
11631
11630
  import { synthesizeStories as synthesizeStories3 } from "executable-stories-core/converters/synthesize";
11631
+ import {
11632
+ collectReportAssets,
11633
+ rewriteReportAssets
11634
+ } from "executable-stories-core/report-assets";
11632
11635
  var EXIT_SUCCESS2 = 0;
11633
11636
  var EXIT_SHARE_FAILED = 1;
11634
11637
  var EXIT_USAGE2 = 4;
@@ -11733,13 +11736,20 @@ function loadReport(filePath, deps) {
11733
11736
  const text2 = deps.readFile(filePath);
11734
11737
  if (filePath.endsWith(".html")) {
11735
11738
  const match = HTML_REPORT_DATA.exec(text2);
11736
- if (!match?.[1]) throw new Error(`${filePath} is an HTML page with no report embedded in it`);
11737
- return asStoryReport(JSON.parse(match[1]), filePath);
11739
+ if (!match?.[1])
11740
+ throw new Error(
11741
+ `${filePath} is an HTML page with no report embedded in it`
11742
+ );
11743
+ return asStoryReport(
11744
+ JSON.parse(match[1]),
11745
+ filePath
11746
+ );
11738
11747
  }
11739
11748
  return asStoryReport(JSON.parse(text2), filePath);
11740
11749
  }
11741
11750
  function asStoryReport(data, filePath) {
11742
- if (typeof data.schemaVersion === "string") return data;
11751
+ if (typeof data.schemaVersion === "string")
11752
+ return data;
11743
11753
  try {
11744
11754
  return toStoryReport8(canonicalizeRun5(synthesizeStories3(data)));
11745
11755
  } catch (err) {
@@ -11775,7 +11785,12 @@ function planAssets(report, reportDir, deps) {
11775
11785
  missing.push(assetPath);
11776
11786
  continue;
11777
11787
  }
11778
- assets.push({ path: key, localPath, contentType: contentTypeFor(key), bytes });
11788
+ assets.push({
11789
+ path: key,
11790
+ localPath,
11791
+ contentType: contentTypeFor(key),
11792
+ bytes
11793
+ });
11779
11794
  }
11780
11795
  return { assets, missing, keyByPath };
11781
11796
  }
@@ -11790,6 +11805,10 @@ async function describeFailure(response) {
11790
11805
  if (error?.type === "SHARE_TOO_LARGE") {
11791
11806
  return `the report and its assets are over the ${error.maxBytes ?? 0} byte limit for a share.`;
11792
11807
  }
11808
+ if (error?.type === "STORAGE_LIMIT") {
11809
+ const mb = (bytes) => `${Math.round(bytes / 1024 / 1024)} MB`;
11810
+ return `stored evidence is at the plan's ${mb(error.limit ?? 0)} (${mb(error.used ?? 0)} used). Delete a share or an attachment in your cloud settings, or upgrade.`;
11811
+ }
11793
11812
  if (error?.message) return error.message;
11794
11813
  if (error?.type) return error.type;
11795
11814
  } catch {
@@ -11824,7 +11843,9 @@ async function runShare(rawArgs, depsOverride = {}) {
11824
11843
  }
11825
11844
  const inputPath = parsed.positionals[0];
11826
11845
  if (!inputPath) {
11827
- deps.error("share needs a report: executable-stories share <reports-dir|report.html|report.json>");
11846
+ deps.error(
11847
+ "share needs a report: executable-stories share <reports-dir|report.html|report.json>"
11848
+ );
11828
11849
  deps.error(HELP2);
11829
11850
  return EXIT_USAGE2;
11830
11851
  }
@@ -11838,7 +11859,9 @@ async function runShare(rawArgs, depsOverride = {}) {
11838
11859
  const expiresRaw = parsed.values["expires-days"];
11839
11860
  const expiresInDays = expiresRaw === void 0 ? 30 : Number(expiresRaw);
11840
11861
  if (!Number.isInteger(expiresInDays) || expiresInDays < 0) {
11841
- deps.error(`--expires-days takes a whole number of days (0 never expires), not "${expiresRaw}".`);
11862
+ deps.error(
11863
+ `--expires-days takes a whole number of days (0 never expires), not "${expiresRaw}".`
11864
+ );
11842
11865
  return EXIT_USAGE2;
11843
11866
  }
11844
11867
  let reportPath;
@@ -11846,16 +11869,23 @@ async function runShare(rawArgs, depsOverride = {}) {
11846
11869
  try {
11847
11870
  ({ path: reportPath, report } = resolveReport(inputPath, deps));
11848
11871
  } catch (err) {
11849
- deps.error(`Could not read ${inputPath}: ${err instanceof Error ? err.message : String(err)}`);
11872
+ deps.error(
11873
+ `Could not read ${inputPath}: ${err instanceof Error ? err.message : String(err)}`
11874
+ );
11850
11875
  return EXIT_USAGE2;
11851
11876
  }
11852
11877
  const reportDir = path19.dirname(reportPath);
11853
11878
  const { assets, missing, keyByPath } = planAssets(report, reportDir, deps);
11854
11879
  for (const assetPath of missing) {
11855
- deps.error(`Warning: ${assetPath} is missing, so it will not be in the share.`);
11880
+ deps.error(
11881
+ `Warning: ${assetPath} is missing, so it will not be in the share.`
11882
+ );
11856
11883
  }
11857
11884
  const shareReport = {
11858
- ...rewriteReportAssets(report, (assetPath) => keyByPath.get(assetPath) ?? assetPath),
11885
+ ...rewriteReportAssets(
11886
+ report,
11887
+ (assetPath) => keyByPath.get(assetPath) ?? assetPath
11888
+ ),
11859
11889
  projectRoot: ""
11860
11890
  };
11861
11891
  const emails = (parsed.values.emails ?? "").split(",").map((email) => email.trim()).filter(Boolean);
@@ -11864,7 +11894,10 @@ async function runShare(rawArgs, depsOverride = {}) {
11864
11894
  try {
11865
11895
  const response = await deps.fetchFn(new URL("/api/v1/shares", baseUrl), {
11866
11896
  method: "POST",
11867
- headers: { "Content-Type": "application/json", Authorization: `Bearer ${key}` },
11897
+ headers: {
11898
+ "Content-Type": "application/json",
11899
+ Authorization: `Bearer ${key}`
11900
+ },
11868
11901
  body: JSON.stringify({
11869
11902
  title: parsed.values.title,
11870
11903
  report: shareReport,
@@ -11884,21 +11917,32 @@ async function runShare(rawArgs, depsOverride = {}) {
11884
11917
  }
11885
11918
  created = await response.json();
11886
11919
  } catch (err) {
11887
- deps.error(`Could not reach ${baseUrl}: ${err instanceof Error ? err.message : String(err)}`);
11920
+ deps.error(
11921
+ `Could not reach ${baseUrl}: ${err instanceof Error ? err.message : String(err)}`
11922
+ );
11888
11923
  return EXIT_SHARE_FAILED;
11889
11924
  }
11890
- const localByKey = new Map(assets.map((asset) => [asset.path, asset.localPath]));
11925
+ const localByKey = new Map(
11926
+ assets.map((asset) => [asset.path, asset.localPath])
11927
+ );
11891
11928
  for (const upload of created.uploads ?? []) {
11892
11929
  const filePath = localByKey.get(upload.path);
11893
11930
  if (filePath === void 0) {
11894
- deps.error(`Share asked for a file this report did not offer: ${upload.path}`);
11931
+ deps.error(
11932
+ `Share asked for a file this report did not offer: ${upload.path}`
11933
+ );
11895
11934
  return EXIT_SHARE_FAILED;
11896
11935
  }
11897
11936
  try {
11898
11937
  const response = await deps.fetchFn(upload.url, {
11899
11938
  method: "PUT",
11900
- headers: { "Content-Type": contentTypeFor(upload.path), ...upload.headers },
11901
- body: new Blob([deps.readBinary(filePath)], { type: contentTypeFor(upload.path) })
11939
+ headers: {
11940
+ "Content-Type": contentTypeFor(upload.path),
11941
+ ...upload.headers
11942
+ },
11943
+ body: new Blob([deps.readBinary(filePath)], {
11944
+ type: contentTypeFor(upload.path)
11945
+ })
11902
11946
  });
11903
11947
  if (!response.ok) {
11904
11948
  deps.error(`Upload of ${upload.path} failed: HTTP ${response.status}`);
@@ -11912,12 +11956,17 @@ async function runShare(rawArgs, depsOverride = {}) {
11912
11956
  }
11913
11957
  }
11914
11958
  try {
11915
- const response = await deps.fetchFn(new URL(`/api/v1/shares/${created.id}/complete`, baseUrl), {
11916
- method: "POST",
11917
- headers: { Authorization: `Bearer ${key}` }
11918
- });
11959
+ const response = await deps.fetchFn(
11960
+ new URL(`/api/v1/shares/${created.id}/complete`, baseUrl),
11961
+ {
11962
+ method: "POST",
11963
+ headers: { Authorization: `Bearer ${key}` }
11964
+ }
11965
+ );
11919
11966
  if (!response.ok) {
11920
- deps.error(`Share could not be published: ${await describeFailure(response)}`);
11967
+ deps.error(
11968
+ `Share could not be published: ${await describeFailure(response)}`
11969
+ );
11921
11970
  return EXIT_SHARE_FAILED;
11922
11971
  }
11923
11972
  } catch (err) {
@@ -11926,8 +11975,15 @@ async function runShare(rawArgs, depsOverride = {}) {
11926
11975
  );
11927
11976
  return EXIT_SHARE_FAILED;
11928
11977
  }
11978
+ const notStored = created.notStored ?? [];
11929
11979
  if (parsed.values.json) {
11930
- deps.log(JSON.stringify({ id: created.id, url: created.url, assets: assets.length }, null, 2));
11980
+ deps.log(
11981
+ JSON.stringify(
11982
+ { id: created.id, url: created.url, assets: assets.length, notStored },
11983
+ null,
11984
+ 2
11985
+ )
11986
+ );
11931
11987
  return EXIT_SUCCESS2;
11932
11988
  }
11933
11989
  const withAssets = assets.length === 1 ? "1 asset" : `${assets.length} assets`;
@@ -11936,6 +11992,9 @@ async function runShare(rawArgs, depsOverride = {}) {
11936
11992
  deps.log(
11937
11993
  emails.length > 0 ? ` Only ${emails.join(", ")} can open it, after signing in.` : " Anyone with the link can open it."
11938
11994
  );
11995
+ for (const skipped of notStored) {
11996
+ deps.log(` Not stored: ${skipped.path} (${skipped.reason})`);
11997
+ }
11939
11998
  return EXIT_SUCCESS2;
11940
11999
  }
11941
12000