@takodotid/circuit 0.34.2 → 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.
Files changed (240) hide show
  1. package/README.md +13 -14
  2. package/dist/chunks/index-20kcjxjg.js +174 -0
  3. package/dist/chunks/index-2r4bbhac.js +977 -0
  4. package/dist/chunks/index-n7w3tg5y.js +149 -0
  5. package/dist/chunks/new-w3zys5y4.js +172 -0
  6. package/dist/chunks/server-gzsf5me5.js +259 -0
  7. package/dist/cli/index.js +11347 -9018
  8. package/dist/helpers/index.js +594 -0
  9. package/dist/index.js +9 -28
  10. package/dist/types/core/{addresses.d.ts → address-space.d.ts} +23 -7
  11. package/dist/types/core/address.d.ts +44 -0
  12. package/dist/types/core/cabling.d.ts +41 -0
  13. package/dist/types/core/cross-checks.d.ts +28 -0
  14. package/dist/types/core/define.d.ts +25 -3
  15. package/dist/types/core/project-files.d.ts +12 -0
  16. package/dist/types/core/schema-docs.d.ts +13 -4
  17. package/dist/types/core/secrets.d.ts +62 -21
  18. package/dist/types/core/{graph.d.ts → topology.d.ts} +32 -12
  19. package/dist/types/core/utils.d.ts +8 -0
  20. package/dist/types/core/validator.d.ts +19 -0
  21. package/dist/types/helpers/bgp.d.ts +97 -0
  22. package/dist/types/helpers/checks.d.ts +32 -0
  23. package/dist/types/helpers/exchange.d.ts +49 -0
  24. package/dist/types/helpers/filters.d.ts +51 -0
  25. package/dist/types/helpers/index.d.ts +10 -0
  26. package/dist/types/helpers/route-server.d.ts +52 -0
  27. package/dist/types/index.d.ts +5 -3
  28. package/dist/types/integrations/librenms.d.ts +60 -0
  29. package/dist/types/integrations/netbox.d.ts +89 -0
  30. package/dist/types/integrations/peeringdb.d.ts +24 -0
  31. package/dist/types/integrations/prometheus.d.ts +24 -0
  32. package/dist/types/integrations/registries.d.ts +8 -0
  33. package/dist/types/platforms/bgp-wait.d.ts +18 -0
  34. package/dist/types/platforms/catalog.d.ts +109 -0
  35. package/dist/types/platforms/derive.d.ts +17 -0
  36. package/dist/types/platforms/fortios/firewall.d.ts +45 -0
  37. package/dist/types/platforms/fortios/index.d.ts +134 -0
  38. package/dist/types/platforms/fortios/names.d.ts +52 -0
  39. package/dist/types/platforms/fortios/plan.d.ts +104 -0
  40. package/dist/types/platforms/fortios/render.d.ts +75 -0
  41. package/dist/types/platforms/fortios/routing.d.ts +56 -0
  42. package/dist/types/platforms/fortios/tree.d.ts +37 -0
  43. package/dist/types/platforms/index.d.ts +13 -0
  44. package/dist/types/platforms/junos/bgp.d.ts +44 -0
  45. package/dist/types/platforms/junos/index.d.ts +114 -0
  46. package/dist/types/platforms/junos/render.d.ts +154 -0
  47. package/dist/types/platforms/line-diff.d.ts +67 -0
  48. package/dist/types/platforms/platform.d.ts +120 -0
  49. package/dist/types/platforms/raisecom-ros/index.d.ts +71 -0
  50. package/dist/types/platforms/raisecom-ros/render.d.ts +41 -0
  51. package/dist/types/platforms/routeros/export.d.ts +59 -0
  52. package/dist/types/platforms/routeros/index.d.ts +96 -0
  53. package/dist/types/{adapters/devices → platforms}/routeros/models.d.ts +4 -0
  54. package/dist/types/platforms/routeros/plan.d.ts +54 -0
  55. package/dist/types/platforms/routeros/render.d.ts +240 -0
  56. package/dist/types/platforms/vrp/index.d.ts +83 -0
  57. package/dist/types/platforms/vrp/render.d.ts +96 -0
  58. package/dist/types/schema/common.d.ts +12 -6
  59. package/dist/types/schema/index.d.ts +1 -0
  60. package/dist/types/schema/interfaces.d.ts +14 -6
  61. package/dist/types/schema/policy.d.ts +18 -10
  62. package/dist/types/schema/routing.d.ts +14 -1
  63. package/dist/types/schema/system.d.ts +16 -6
  64. package/dist/types/schema/time-zones.d.ts +2 -0
  65. package/dist/types/transport/console.d.ts +79 -23
  66. package/dist/types/transport/path-check.d.ts +32 -0
  67. package/dist/types/transport/ssh.d.ts +17 -15
  68. package/package.json +17 -11
  69. package/src/cli/graph-format.ts +91 -0
  70. package/src/cli/index.ts +1074 -484
  71. package/src/cli/new.ts +208 -175
  72. package/src/cli/rename.ts +97 -91
  73. package/src/core/address-space.ts +320 -0
  74. package/src/core/address.ts +202 -0
  75. package/src/core/cabling.ts +154 -0
  76. package/src/core/cross-checks.ts +364 -0
  77. package/src/core/define.ts +26 -3
  78. package/src/core/project-files.ts +35 -0
  79. package/src/core/schema-docs.ts +138 -130
  80. package/src/core/secrets.ts +170 -76
  81. package/src/core/topology.ts +656 -0
  82. package/src/core/utils.ts +37 -0
  83. package/src/core/validator.ts +407 -0
  84. package/src/helpers/bgp.ts +301 -0
  85. package/src/helpers/checks.ts +178 -0
  86. package/src/helpers/exchange.ts +117 -0
  87. package/src/helpers/filters.ts +107 -0
  88. package/src/helpers/index.ts +12 -0
  89. package/src/helpers/route-server.ts +212 -0
  90. package/src/index.ts +6 -3
  91. package/src/integrations/librenms.ts +291 -0
  92. package/src/integrations/netbox.ts +620 -0
  93. package/src/integrations/peeringdb.ts +173 -0
  94. package/src/integrations/prometheus.ts +90 -0
  95. package/src/integrations/registries.ts +25 -0
  96. package/src/platforms/bgp-wait.ts +41 -0
  97. package/src/platforms/catalog.ts +69 -0
  98. package/src/platforms/derive.ts +117 -0
  99. package/src/{adapters/devices → platforms}/fortios/TRAPS.md +6 -0
  100. package/src/platforms/fortios/firewall.ts +377 -0
  101. package/src/platforms/fortios/index.ts +1060 -0
  102. package/src/platforms/fortios/names.ts +130 -0
  103. package/src/platforms/fortios/plan.ts +929 -0
  104. package/src/platforms/fortios/render.ts +779 -0
  105. package/src/platforms/fortios/routing.ts +476 -0
  106. package/src/platforms/fortios/tree.ts +129 -0
  107. package/src/platforms/index.ts +36 -0
  108. package/src/{adapters/devices → platforms}/junos/TRAPS.md +8 -0
  109. package/src/platforms/junos/bgp.ts +293 -0
  110. package/src/platforms/junos/index.ts +1006 -0
  111. package/src/platforms/junos/render.ts +967 -0
  112. package/src/platforms/line-diff.ts +244 -0
  113. package/src/platforms/platform.ts +122 -0
  114. package/src/platforms/raisecom-ros/TRAPS.md +40 -0
  115. package/src/platforms/raisecom-ros/index.ts +731 -0
  116. package/src/platforms/raisecom-ros/render.ts +328 -0
  117. package/src/{adapters/devices → platforms}/routeros/TRAPS.md +16 -2
  118. package/src/platforms/routeros/export.ts +342 -0
  119. package/src/platforms/routeros/index.ts +636 -0
  120. package/src/{adapters/devices → platforms}/routeros/models.ts +2 -0
  121. package/src/platforms/routeros/plan.ts +444 -0
  122. package/src/platforms/routeros/render.ts +1483 -0
  123. package/src/platforms/vrp/TRAPS.md +45 -0
  124. package/src/platforms/vrp/index.ts +652 -0
  125. package/src/platforms/vrp/render.ts +615 -0
  126. package/src/schema/common.ts +15 -6
  127. package/src/schema/index.ts +1 -0
  128. package/src/schema/interfaces.ts +15 -5
  129. package/src/schema/policy.ts +22 -10
  130. package/src/schema/routing.ts +16 -1
  131. package/src/schema/system.ts +16 -6
  132. package/src/schema/time-zones.ts +482 -0
  133. package/src/studio/data.ts +172 -168
  134. package/src/studio/git.ts +95 -90
  135. package/src/studio/public/app.js +161 -150
  136. package/src/studio/public/compare.js +219 -212
  137. package/src/studio/public/diff.js +77 -75
  138. package/src/studio/public/dom.js +118 -108
  139. package/src/studio/public/evaluate.js +584 -545
  140. package/src/studio/public/export.js +120 -118
  141. package/src/studio/public/graph.js +1343 -1266
  142. package/src/studio/public/net.js +115 -109
  143. package/src/studio/public/tables.js +1135 -1083
  144. package/src/studio/public/tools.js +561 -529
  145. package/src/studio/server.ts +202 -196
  146. package/src/transport/console.ts +363 -271
  147. package/src/transport/path-check.ts +91 -0
  148. package/src/transport/ssh.ts +98 -94
  149. package/templates/colocation/checks.ts +11 -6
  150. package/templates/colocation/edge-01.ts +9 -9
  151. package/templates/colocation/routing.ts +2 -2
  152. package/templates/colocation/tenancy.ts +3 -3
  153. package/templates/colocation/tor-01.ts +3 -3
  154. package/templates/edge-router/checks.ts +4 -4
  155. package/templates/edge-router/edge-01.ts +5 -5
  156. package/templates/edge-router/routing.ts +2 -2
  157. package/templates/project/AGENTS.md +5 -1
  158. package/templates/single-site/checks.ts +2 -2
  159. package/dist/chunks/index-47debt16.js +0 -956
  160. package/dist/chunks/index-v8zgr7wm.js +0 -128
  161. package/dist/chunks/new-ny89s7y7.js +0 -166
  162. package/dist/chunks/server-tjbb3rqc.js +0 -251
  163. package/dist/presets/index.js +0 -394
  164. package/dist/types/adapters/devices/catalog.d.ts +0 -86
  165. package/dist/types/adapters/devices/derive.d.ts +0 -7
  166. package/dist/types/adapters/devices/fortios/firewall.d.ts +0 -23
  167. package/dist/types/adapters/devices/fortios/index.d.ts +0 -58
  168. package/dist/types/adapters/devices/fortios/names.d.ts +0 -48
  169. package/dist/types/adapters/devices/fortios/plan.d.ts +0 -28
  170. package/dist/types/adapters/devices/fortios/render.d.ts +0 -38
  171. package/dist/types/adapters/devices/fortios/routing.d.ts +0 -32
  172. package/dist/types/adapters/devices/fortios/tree.d.ts +0 -33
  173. package/dist/types/adapters/devices/index.d.ts +0 -3
  174. package/dist/types/adapters/devices/junos/bgp.d.ts +0 -11
  175. package/dist/types/adapters/devices/junos/index.d.ts +0 -42
  176. package/dist/types/adapters/devices/junos/render.d.ts +0 -52
  177. package/dist/types/adapters/devices/lines.d.ts +0 -56
  178. package/dist/types/adapters/devices/raisecom-ros/index.d.ts +0 -28
  179. package/dist/types/adapters/devices/routeros/export.d.ts +0 -39
  180. package/dist/types/adapters/devices/routeros/index.d.ts +0 -30
  181. package/dist/types/adapters/devices/routeros/plan.d.ts +0 -4
  182. package/dist/types/adapters/devices/routeros/render.d.ts +0 -100
  183. package/dist/types/adapters/devices/types.d.ts +0 -40
  184. package/dist/types/adapters/devices/vrp/index.d.ts +0 -27
  185. package/dist/types/adapters/registries/index.d.ts +0 -3
  186. package/dist/types/adapters/registries/librenms.d.ts +0 -15
  187. package/dist/types/adapters/registries/peeringdb.d.ts +0 -16
  188. package/dist/types/adapters/registries/prometheus.d.ts +0 -16
  189. package/dist/types/core/across.d.ts +0 -4
  190. package/dist/types/core/addr.d.ts +0 -34
  191. package/dist/types/core/files.d.ts +0 -6
  192. package/dist/types/core/merge.d.ts +0 -4
  193. package/dist/types/core/time.d.ts +0 -2
  194. package/dist/types/core/validate.d.ts +0 -2
  195. package/dist/types/presets/index.d.ts +0 -183
  196. package/src/adapters/devices/catalog.ts +0 -41
  197. package/src/adapters/devices/derive.ts +0 -59
  198. package/src/adapters/devices/fortios/firewall.ts +0 -362
  199. package/src/adapters/devices/fortios/index.ts +0 -923
  200. package/src/adapters/devices/fortios/names.ts +0 -115
  201. package/src/adapters/devices/fortios/plan.ts +0 -888
  202. package/src/adapters/devices/fortios/render.ts +0 -768
  203. package/src/adapters/devices/fortios/routing.ts +0 -444
  204. package/src/adapters/devices/fortios/tree.ts +0 -121
  205. package/src/adapters/devices/index.ts +0 -9
  206. package/src/adapters/devices/junos/bgp.ts +0 -269
  207. package/src/adapters/devices/junos/index.ts +0 -862
  208. package/src/adapters/devices/junos/render.ts +0 -872
  209. package/src/adapters/devices/lines.ts +0 -212
  210. package/src/adapters/devices/raisecom-ros/TRAPS.md +0 -25
  211. package/src/adapters/devices/raisecom-ros/index.ts +0 -693
  212. package/src/adapters/devices/routeros/export.ts +0 -321
  213. package/src/adapters/devices/routeros/index.ts +0 -346
  214. package/src/adapters/devices/routeros/plan.ts +0 -398
  215. package/src/adapters/devices/routeros/render.ts +0 -1490
  216. package/src/adapters/devices/types.ts +0 -38
  217. package/src/adapters/devices/vrp/TRAPS.md +0 -26
  218. package/src/adapters/devices/vrp/index.ts +0 -865
  219. package/src/adapters/registries/index.ts +0 -19
  220. package/src/adapters/registries/librenms.ts +0 -92
  221. package/src/adapters/registries/peeringdb.ts +0 -169
  222. package/src/adapters/registries/prometheus.ts +0 -71
  223. package/src/cli/graph.ts +0 -89
  224. package/src/core/across.ts +0 -350
  225. package/src/core/addr.ts +0 -174
  226. package/src/core/addresses.ts +0 -316
  227. package/src/core/files.ts +0 -32
  228. package/src/core/graph.ts +0 -640
  229. package/src/core/merge.ts +0 -19
  230. package/src/core/time.ts +0 -15
  231. package/src/core/validate.ts +0 -348
  232. package/src/presets/index.ts +0 -579
  233. /package/dist/types/{adapters/devices → platforms}/fortios/models.d.ts +0 -0
  234. /package/dist/types/{adapters/devices → platforms}/junos/models.d.ts +0 -0
  235. /package/dist/types/{adapters/devices → platforms}/raisecom-ros/models.d.ts +0 -0
  236. /package/dist/types/{adapters/devices → platforms}/vrp/models.d.ts +0 -0
  237. /package/src/{adapters/devices → platforms}/fortios/models.ts +0 -0
  238. /package/src/{adapters/devices → platforms}/junos/models.ts +0 -0
  239. /package/src/{adapters/devices → platforms}/raisecom-ros/models.ts +0 -0
  240. /package/src/{adapters/devices → platforms}/vrp/models.ts +0 -0
@@ -2,127 +2,129 @@
2
2
  /// <reference lib="dom" />
3
3
  // Saving what Studio shows: a table as CSV, and the graph as SVG or PNG, drawn the way it looks on screen.
4
4
 
5
- /** The properties that make the drawing look as it does, copied onto each element, since a saved SVG has no stylesheet. */
6
- const DRAWN = [
7
- "fill",
8
- "stroke",
9
- "stroke-width",
10
- "stroke-dasharray",
11
- "stroke-linejoin",
12
- "paint-order",
13
- "opacity",
14
- "font-family",
15
- "font-size",
16
- "font-weight",
17
- "text-anchor",
18
- "dominant-baseline",
19
- "display",
20
- ];
21
-
22
- /**
23
- * Hand the browser a file to save.
24
- *
25
- * @param {string} name
26
- * @param {Blob} blob
27
- */
28
- export function save(name, blob) {
29
- const url = URL.createObjectURL(blob);
30
- const anchor = document.createElement("a");
31
- anchor.href = url;
32
- anchor.download = name;
33
- anchor.click();
34
- setTimeout(() => URL.revokeObjectURL(url), 1000);
35
- }
36
-
37
- /**
38
- * A table as CSV: its header, then each row, every cell as the text it shows.
39
- *
40
- * @param {HTMLTableElement} table
41
- */
42
- export function csvOf(table) {
43
- /** @param {string} text */
44
- const field = (text) => (/[",\n]/.test(text) ? `"${text.replace(/"/g, '""')}"` : text);
45
- const rows = [...table.querySelectorAll(":scope > thead > tr, :scope > tbody > tr")];
46
-
47
- return rows.map((row) => [...row.children].map((cell) => field(cell.textContent?.trim() ?? "")).join(",")).join("\n") + "\n";
48
- }
49
-
50
- /**
51
- * The drawing as an SVG file of its own: the drawn parts, framed around what is drawn, with each element's look written onto it.
52
- *
53
- * @param {SVGElement} svg
54
- * @param {SVGGraphicsElement} viewport
55
- * @returns {{ text: string, width: number, height: number }}
56
- */
57
- export function svgOf(svg, viewport) {
58
- const box = viewport.getBBox();
59
- const margin = 24;
60
- const width = Math.ceil(box.width + margin * 2);
61
- const height = Math.ceil(box.height + margin * 2);
62
-
63
- const copy = /** @type {SVGElement} */ (svg.cloneNode(true));
64
- const originals = [svg, ...svg.querySelectorAll("*")];
65
- const copies = [copy, ...copy.querySelectorAll("*")];
66
-
67
- // The dots travelling the cables are left out: a still image would show each one stopped at the drawing's corner.
68
- const moving = [];
69
-
70
- for (const [index, original] of originals.entries()) {
71
- const target = copies[index];
72
- if (!(target instanceof SVGElement)) continue;
73
- if (original.classList.contains("signal")) moving.push(target);
74
-
75
- const look = getComputedStyle(original);
76
- target.setAttribute("style", DRAWN.map((name) => `${name}:${look.getPropertyValue(name)}`).join(";"));
77
- target.removeAttribute("class");
5
+ export class Export {
6
+ /** The properties that make the drawing look as it does, copied onto each element, since a saved SVG has no stylesheet. */
7
+ static #DRAWN = [
8
+ "fill",
9
+ "stroke",
10
+ "stroke-width",
11
+ "stroke-dasharray",
12
+ "stroke-linejoin",
13
+ "paint-order",
14
+ "opacity",
15
+ "font-family",
16
+ "font-size",
17
+ "font-weight",
18
+ "text-anchor",
19
+ "dominant-baseline",
20
+ "display",
21
+ ];
22
+
23
+ /**
24
+ * Hand the browser a file to save.
25
+ *
26
+ * @param {string} name
27
+ * @param {Blob} blob
28
+ */
29
+ static save(name, blob) {
30
+ const url = URL.createObjectURL(blob);
31
+ const anchor = document.createElement("a");
32
+ anchor.href = url;
33
+ anchor.download = name;
34
+ anchor.click();
35
+ setTimeout(() => URL.revokeObjectURL(url), 1000);
78
36
  }
79
37
 
80
- for (const dot of moving) dot.remove();
81
-
82
- // The drawing's own place on screen is left out: the file is framed around what is drawn.
83
- copy.querySelector("#viewport")?.removeAttribute("transform");
84
- copy.setAttribute("xmlns", "http://www.w3.org/2000/svg");
85
- copy.setAttribute("viewBox", `${box.x - margin} ${box.y - margin} ${width} ${height}`);
86
- copy.setAttribute("width", String(width));
87
- copy.setAttribute("height", String(height));
88
-
89
- const background = document.createElementNS("http://www.w3.org/2000/svg", "rect");
90
- background.setAttribute("x", String(box.x - margin));
91
- background.setAttribute("y", String(box.y - margin));
92
- background.setAttribute("width", String(width));
93
- background.setAttribute("height", String(height));
94
- background.setAttribute("fill", getComputedStyle(document.body).backgroundColor);
95
- copy.prepend(background);
38
+ /**
39
+ * A table as CSV: its header, then each row, every cell as the text it shows.
40
+ *
41
+ * @param {HTMLTableElement} table
42
+ */
43
+ static csv(table) {
44
+ /** @param {string} text */
45
+ const field = (text) => (/[",\n]/.test(text) ? `"${text.replace(/"/g, '""')}"` : text);
46
+ const rows = [...table.querySelectorAll(":scope > thead > tr, :scope > tbody > tr")];
47
+
48
+ return rows.map((row) => [...row.children].map((cell) => field(cell.textContent?.trim() ?? "")).join(",")).join("\n") + "\n";
49
+ }
96
50
 
97
- return { text: new XMLSerializer().serializeToString(copy), width, height };
98
- }
51
+ /**
52
+ * The drawing as an SVG file of its own: the drawn parts, framed around what is drawn, with each element's look written onto it.
53
+ *
54
+ * @param {SVGElement} svg
55
+ * @param {SVGGraphicsElement} viewport
56
+ * @returns {{ text: string, width: number, height: number }}
57
+ */
58
+ static svg(svg, viewport) {
59
+ const box = viewport.getBBox();
60
+ const margin = 24;
61
+ const width = Math.ceil(box.width + margin * 2);
62
+ const height = Math.ceil(box.height + margin * 2);
63
+
64
+ const copy = /** @type {SVGElement} */ (svg.cloneNode(true));
65
+ const originals = [svg, ...svg.querySelectorAll("*")];
66
+ const copies = [copy, ...copy.querySelectorAll("*")];
67
+
68
+ // The dots travelling the cables are left out: a still image would show each one stopped at the drawing's corner.
69
+ const moving = [];
70
+
71
+ for (const [index, original] of originals.entries()) {
72
+ const target = copies[index];
73
+ if (!(target instanceof SVGElement)) continue;
74
+ if (original.classList.contains("signal")) moving.push(target);
75
+
76
+ const look = getComputedStyle(original);
77
+ target.setAttribute("style", Export.#DRAWN.map((name) => `${name}:${look.getPropertyValue(name)}`).join(";"));
78
+ target.removeAttribute("class");
79
+ }
80
+
81
+ for (const dot of moving) dot.remove();
82
+
83
+ // The drawing's own place on screen is left out: the file is framed around what is drawn.
84
+ copy.querySelector("#viewport")?.removeAttribute("transform");
85
+ copy.setAttribute("xmlns", "http://www.w3.org/2000/svg");
86
+ copy.setAttribute("viewBox", `${box.x - margin} ${box.y - margin} ${width} ${height}`);
87
+ copy.setAttribute("width", String(width));
88
+ copy.setAttribute("height", String(height));
89
+
90
+ const background = document.createElementNS("http://www.w3.org/2000/svg", "rect");
91
+ background.setAttribute("x", String(box.x - margin));
92
+ background.setAttribute("y", String(box.y - margin));
93
+ background.setAttribute("width", String(width));
94
+ background.setAttribute("height", String(height));
95
+ background.setAttribute("fill", getComputedStyle(document.body).backgroundColor);
96
+ copy.prepend(background);
97
+
98
+ return { text: new XMLSerializer().serializeToString(copy), width, height };
99
+ }
99
100
 
100
- /**
101
- * An SVG drawn into a PNG, at twice its size so it stays sharp.
102
- *
103
- * @param {{ text: string, width: number, height: number }} drawing
104
- * @returns {Promise<Blob>}
105
- */
106
- export function pngOf(drawing) {
107
- const scale = 2;
108
- const image = new Image();
109
- const url = URL.createObjectURL(new Blob([drawing.text], { type: "image/svg+xml" }));
110
-
111
- return new Promise((done, fail) => {
112
- image.addEventListener("load", () => {
113
- const canvas = document.createElement("canvas");
114
- canvas.width = drawing.width * scale;
115
- canvas.height = drawing.height * scale;
116
-
117
- const context = canvas.getContext("2d");
118
- if (!context) return fail(new Error("this browser cannot draw a PNG"));
119
-
120
- context.scale(scale, scale);
121
- context.drawImage(image, 0, 0);
122
- URL.revokeObjectURL(url);
123
- canvas.toBlob((blob) => (blob ? done(blob) : fail(new Error("the PNG could not be made"))), "image/png");
101
+ /**
102
+ * An SVG drawn into a PNG, at twice its size so it stays sharp.
103
+ *
104
+ * @param {{ text: string, width: number, height: number }} drawing
105
+ * @returns {Promise<Blob>}
106
+ */
107
+ static png(drawing) {
108
+ const scale = 2;
109
+ const image = new Image();
110
+ const url = URL.createObjectURL(new Blob([drawing.text], { type: "image/svg+xml" }));
111
+
112
+ return new Promise((done, fail) => {
113
+ image.addEventListener("load", () => {
114
+ const canvas = document.createElement("canvas");
115
+ canvas.width = drawing.width * scale;
116
+ canvas.height = drawing.height * scale;
117
+
118
+ const context = canvas.getContext("2d");
119
+ if (!context) return fail(new Error("this browser cannot draw a PNG"));
120
+
121
+ context.scale(scale, scale);
122
+ context.drawImage(image, 0, 0);
123
+ URL.revokeObjectURL(url);
124
+ canvas.toBlob((blob) => (blob ? done(blob) : fail(new Error("the PNG could not be made"))), "image/png");
125
+ });
126
+ image.addEventListener("error", () => fail(new Error("the drawing could not be read back")));
127
+ image.src = url;
124
128
  });
125
- image.addEventListener("error", () => fail(new Error("the drawing could not be read back")));
126
- image.src = url;
127
- });
129
+ }
128
130
  }