@sanjibdevnath/mcp-excalidraw-local 1.0.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 (191) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +458 -0
  3. package/dist/db.d.ts +58 -0
  4. package/dist/db.d.ts.map +1 -0
  5. package/dist/db.js +379 -0
  6. package/dist/db.js.map +1 -0
  7. package/dist/frontend/assets/Assistant-Bold-gm-uSS1B.woff2 +0 -0
  8. package/dist/frontend/assets/Assistant-Medium-DrcxCXg3.woff2 +0 -0
  9. package/dist/frontend/assets/Assistant-Regular-DVxZuzxb.woff2 +0 -0
  10. package/dist/frontend/assets/Assistant-SemiBold-SCI4bEL9.woff2 +0 -0
  11. package/dist/frontend/assets/Tableau10-B-NsZVaP.js +1 -0
  12. package/dist/frontend/assets/_commonjs-dynamic-modules-TDtrdbi3.js +1 -0
  13. package/dist/frontend/assets/advancedFormat-BvOvfnfC.js +1 -0
  14. package/dist/frontend/assets/ar-SA-G6X2FPQ2-75HMOOy8.js +10 -0
  15. package/dist/frontend/assets/arc-D-322MQz.js +1 -0
  16. package/dist/frontend/assets/array-BKyUJesY.js +1 -0
  17. package/dist/frontend/assets/az-AZ-76LH7QW2-DPDwkDvh.js +1 -0
  18. package/dist/frontend/assets/band-dPffDWoQ.js +1 -0
  19. package/dist/frontend/assets/bg-BG-XCXSNQG7-DrFYc9eo.js +5 -0
  20. package/dist/frontend/assets/blockDiagram-38ab4fdb-Ch8bwO7g.js +118 -0
  21. package/dist/frontend/assets/blockDiagram-68f4deed-BVqzkDiu.js +118 -0
  22. package/dist/frontend/assets/bn-BD-2XOGV67Q-B1Y75Cvj.js +5 -0
  23. package/dist/frontend/assets/c4Diagram-15b5d702-D5U2mSdf.js +10 -0
  24. package/dist/frontend/assets/c4Diagram-3d4e48cf-eT2EEN_c.js +10 -0
  25. package/dist/frontend/assets/ca-ES-6MX7JW3Y-00BTiK3Z.js +8 -0
  26. package/dist/frontend/assets/channel-CudwHHli.js +1 -0
  27. package/dist/frontend/assets/classDiagram-70f12bd4-CcNOdQHv.js +2 -0
  28. package/dist/frontend/assets/classDiagram-d40c83e7-nRIgRTMT.js +2 -0
  29. package/dist/frontend/assets/classDiagram-v2-d5a6b087-Cfbvao44.js +2 -0
  30. package/dist/frontend/assets/classDiagram-v2-f2320105-1Sjp5Uqh.js +2 -0
  31. package/dist/frontend/assets/clone-D_tGm99B.js +1 -0
  32. package/dist/frontend/assets/createText-2e5e7dd3-Bpmkp1eZ.js +5 -0
  33. package/dist/frontend/assets/createText-d213de94-3MLB4fd8.js +5 -0
  34. package/dist/frontend/assets/cs-CZ-2BRQDIVT-R7SCWLLF.js +11 -0
  35. package/dist/frontend/assets/cytoscape-cose-bilkent-CoIxD6ON.js +331 -0
  36. package/dist/frontend/assets/da-DK-5WZEPLOC-Db1yebad.js +5 -0
  37. package/dist/frontend/assets/de-DE-XR44H4JA-HRE-6fuh.js +8 -0
  38. package/dist/frontend/assets/directory-open-01563666-DWU9wJ6I.js +1 -0
  39. package/dist/frontend/assets/directory-open-4ed118d0-BzWybGaI.js +1 -0
  40. package/dist/frontend/assets/edges-332bd1c7-DZAOA9uP.js +4 -0
  41. package/dist/frontend/assets/edges-e0da2a9e-CP-XTLb4.js +4 -0
  42. package/dist/frontend/assets/el-GR-BZB4AONW-CfNczSdx.js +10 -0
  43. package/dist/frontend/assets/elk.bundled-BZDcWavb.js +26 -0
  44. package/dist/frontend/assets/erDiagram-880f2ed8-Bk96tDga.js +51 -0
  45. package/dist/frontend/assets/erDiagram-9861fffd-BvkEkcRK.js +51 -0
  46. package/dist/frontend/assets/es-ES-U4NZUMDT-BBJZ1_wD.js +9 -0
  47. package/dist/frontend/assets/eu-ES-A7QVB2H4-CCLNmdnk.js +11 -0
  48. package/dist/frontend/assets/fa-IR-HGAKTJCU-BtKS5FOW.js +8 -0
  49. package/dist/frontend/assets/fi-FI-Z5N7JZ37-DEQi6vbL.js +6 -0
  50. package/dist/frontend/assets/file-open-002ab408-DIuFHtCF.js +1 -0
  51. package/dist/frontend/assets/file-open-7c801643-684qeFg4.js +1 -0
  52. package/dist/frontend/assets/file-save-3189631c-x92wctJd.js +1 -0
  53. package/dist/frontend/assets/file-save-745eba88-Bb9F9Kg7.js +1 -0
  54. package/dist/frontend/assets/flowDb-7c981674-JJMg1ttK.js +10 -0
  55. package/dist/frontend/assets/flowDb-956e92f1-CVVUllPW.js +10 -0
  56. package/dist/frontend/assets/flowDiagram-66a62f08-wGFuUp6y.js +4 -0
  57. package/dist/frontend/assets/flowDiagram-cbd28bf7-CXKT_tHC.js +4 -0
  58. package/dist/frontend/assets/flowDiagram-v2-96b9c2cf-CN4ht1EM.js +1 -0
  59. package/dist/frontend/assets/flowDiagram-v2-ffc7f31a-CFiBItzu.js +1 -0
  60. package/dist/frontend/assets/flowchart-elk-definition-36e2d292-Cam5JBwn.js +114 -0
  61. package/dist/frontend/assets/flowchart-elk-definition-4a651766-BoyD4myW.js +114 -0
  62. package/dist/frontend/assets/fr-FR-RHASNOE6-_AQjPuKS.js +9 -0
  63. package/dist/frontend/assets/ganttDiagram-04f9e578-DrDI9_oS.js +257 -0
  64. package/dist/frontend/assets/ganttDiagram-c361ad54-CKSyNc2k.js +257 -0
  65. package/dist/frontend/assets/gitGraphDiagram-21fc4d3e-BHBdnwSb.js +70 -0
  66. package/dist/frontend/assets/gitGraphDiagram-72cf32ee-BHN9qiXg.js +70 -0
  67. package/dist/frontend/assets/gl-ES-HMX3MZ6V-Bp2h6sBC.js +10 -0
  68. package/dist/frontend/assets/graph-CRb9j7zI.js +1 -0
  69. package/dist/frontend/assets/graph-EK5j_nPe.js +1 -0
  70. package/dist/frontend/assets/he-IL-6SHJWFNN-hsaAKZ5K.js +10 -0
  71. package/dist/frontend/assets/hi-IN-IWLTKZ5I-sgYSNzoz.js +4 -0
  72. package/dist/frontend/assets/hu-HU-A5ZG7DT2-DxYZr0yq.js +7 -0
  73. package/dist/frontend/assets/id-ID-SAP4L64H-z0RzSKPQ.js +10 -0
  74. package/dist/frontend/assets/image-blob-reduce.esm-B6b2_-a4.js +7 -0
  75. package/dist/frontend/assets/index-3862675e-CQPsxwvk.js +1 -0
  76. package/dist/frontend/assets/index-6079d271-pTR-OMc-.js +1 -0
  77. package/dist/frontend/assets/index-B9Rh8YyQ.css +1 -0
  78. package/dist/frontend/assets/index-BcHA28Dx.js +87 -0
  79. package/dist/frontend/assets/index-DGmpr33w.js +3 -0
  80. package/dist/frontend/assets/index-DPgZw9ew.js +349 -0
  81. package/dist/frontend/assets/infoDiagram-4a4f5b27-OIxyK2_N.js +7 -0
  82. package/dist/frontend/assets/infoDiagram-f8f76790-BTkoanKB.js +7 -0
  83. package/dist/frontend/assets/init-Gi6I4Gst.js +1 -0
  84. package/dist/frontend/assets/it-IT-JPQ66NNP-Cu6RM7DP.js +11 -0
  85. package/dist/frontend/assets/ja-JP-DBVTYXUO-lD7U4Zkf.js +8 -0
  86. package/dist/frontend/assets/journeyDiagram-29694f62-BS4Xl0A-.js +139 -0
  87. package/dist/frontend/assets/journeyDiagram-49397b02-BbBAwEfu.js +139 -0
  88. package/dist/frontend/assets/kaa-6HZHGXH3-DM9LwXUP.js +1 -0
  89. package/dist/frontend/assets/kab-KAB-ZGHBKWFO-BAojmp2_.js +8 -0
  90. package/dist/frontend/assets/katex-ChWnQ-fc.js +261 -0
  91. package/dist/frontend/assets/kk-KZ-P5N5QNE5-Dp0K1W81.js +1 -0
  92. package/dist/frontend/assets/km-KH-HSX4SM5Z-BzYGKbAg.js +11 -0
  93. package/dist/frontend/assets/ko-KR-MTYHY66A-DOvEMk4H.js +9 -0
  94. package/dist/frontend/assets/ku-TR-6OUDTVRD-B6l-ghqp.js +9 -0
  95. package/dist/frontend/assets/layout-CGydnLJa.js +1 -0
  96. package/dist/frontend/assets/layout-DbdMIGYe.js +1 -0
  97. package/dist/frontend/assets/line-CbImtxDK.js +1 -0
  98. package/dist/frontend/assets/linear-DvIsU3aM.js +1 -0
  99. package/dist/frontend/assets/lt-LT-XHIRWOB4-BYcRk8Uj.js +3 -0
  100. package/dist/frontend/assets/lv-LV-5QDEKY6T-DS3krNIe.js +7 -0
  101. package/dist/frontend/assets/mindmap-definition-ac74a2e8-C0Sp7ICZ.js +95 -0
  102. package/dist/frontend/assets/mindmap-definition-fc14e90a-BZrjRbkr.js +95 -0
  103. package/dist/frontend/assets/mr-IN-CRQNXWMA-BfxQL7Vh.js +13 -0
  104. package/dist/frontend/assets/my-MM-5M5IBNSE-C3EfnOvD.js +1 -0
  105. package/dist/frontend/assets/nb-NO-T6EIAALU-BIbPZokm.js +10 -0
  106. package/dist/frontend/assets/nl-NL-IS3SIHDZ-BqQloGBT.js +8 -0
  107. package/dist/frontend/assets/nn-NO-6E72VCQL-zGR8NYQf.js +8 -0
  108. package/dist/frontend/assets/oc-FR-POXYY2M6-B8-HsJFE.js +8 -0
  109. package/dist/frontend/assets/ordinal-Cboi1Yqb.js +1 -0
  110. package/dist/frontend/assets/pa-IN-N4M65BXN-B2Ta58Tu.js +4 -0
  111. package/dist/frontend/assets/path-CbwjOpE9.js +1 -0
  112. package/dist/frontend/assets/pica-DSD-O3at.js +7 -0
  113. package/dist/frontend/assets/pie-Dk_pQnuO.js +1 -0
  114. package/dist/frontend/assets/pieDiagram-421022e6-9oAq5fk_.js +35 -0
  115. package/dist/frontend/assets/pieDiagram-8a3498a8-B5SMrdDh.js +35 -0
  116. package/dist/frontend/assets/pl-PL-T2D74RX3-rZKvQ0zQ.js +9 -0
  117. package/dist/frontend/assets/pt-BR-5N22H2LF-ij6wtU6I.js +9 -0
  118. package/dist/frontend/assets/pt-PT-UZXXM6DQ-BIgtUnbW.js +9 -0
  119. package/dist/frontend/assets/quadrantDiagram-0957ecba-Cr3mj6c1.js +7 -0
  120. package/dist/frontend/assets/quadrantDiagram-120e2f19-CQnc4s0f.js +7 -0
  121. package/dist/frontend/assets/requirementDiagram-23d650b8-Bs7pP1vJ.js +52 -0
  122. package/dist/frontend/assets/requirementDiagram-deff3bca-G5e-Qxao.js +52 -0
  123. package/dist/frontend/assets/ro-RO-JPDTUUEW-DPj_79nt.js +11 -0
  124. package/dist/frontend/assets/roundRect-0PYZxl1G.js +1 -0
  125. package/dist/frontend/assets/ru-RU-B4JR7IUQ-fdYiaqbX.js +9 -0
  126. package/dist/frontend/assets/sankeyDiagram-04a897e0-CJogadkF.js +8 -0
  127. package/dist/frontend/assets/sankeyDiagram-23345273-DKUWMCrX.js +8 -0
  128. package/dist/frontend/assets/sankeyLinkHorizontal-DgqkLiUE.js +1 -0
  129. package/dist/frontend/assets/selectAll-tNeSnQY6.js +1 -0
  130. package/dist/frontend/assets/sequenceDiagram-17ac3bff-DCw9xUbw.js +122 -0
  131. package/dist/frontend/assets/sequenceDiagram-704730f1-BgClSrOI.js +122 -0
  132. package/dist/frontend/assets/si-LK-N5RQ5JYF-DfPBk-rU.js +1 -0
  133. package/dist/frontend/assets/sk-SK-C5VTKIMK-Cbj4yoD_.js +6 -0
  134. package/dist/frontend/assets/sl-SI-NN7IZMDC-C_rL7eDE.js +6 -0
  135. package/dist/frontend/assets/stateDiagram-587899a1-DuFGG-SI.js +1 -0
  136. package/dist/frontend/assets/stateDiagram-9c5f0230-Bwj38hfH.js +1 -0
  137. package/dist/frontend/assets/stateDiagram-v2-51a3dcff-3c0yKNdL.js +1 -0
  138. package/dist/frontend/assets/stateDiagram-v2-d93cdb3a-CAaqB4wm.js +1 -0
  139. package/dist/frontend/assets/styles-2ab5d517-Dxg7wKah.js +116 -0
  140. package/dist/frontend/assets/styles-5f03d8d2-DD32XMGL.js +160 -0
  141. package/dist/frontend/assets/styles-6aaf32cf-B5DxK_RW.js +207 -0
  142. package/dist/frontend/assets/styles-9a916d00-C6L6Mj2P.js +160 -0
  143. package/dist/frontend/assets/styles-c10674c1-BPM_bB3H.js +116 -0
  144. package/dist/frontend/assets/styles-edf9a4b0-CbQDxrwP.js +207 -0
  145. package/dist/frontend/assets/subset-shared.chunk-B_DQsaBC.js +84 -0
  146. package/dist/frontend/assets/subset-worker.chunk-DL6tLP7M.js +1 -0
  147. package/dist/frontend/assets/sv-SE-XGPEYMSR-BmmcOaVK.js +10 -0
  148. package/dist/frontend/assets/svgDrawCommon-08f97a94-aUx8qfJx.js +1 -0
  149. package/dist/frontend/assets/svgDrawCommon-3ba9043b-1JM8RiLc.js +1 -0
  150. package/dist/frontend/assets/ta-IN-2NMHFXQM-Kxnb_Mwk.js +9 -0
  151. package/dist/frontend/assets/th-TH-HPSO5L25-BqTLgxJz.js +2 -0
  152. package/dist/frontend/assets/timeline-definition-7e6b55e7-BbFhIPTl.js +61 -0
  153. package/dist/frontend/assets/timeline-definition-85554ec2-C1G9H6m5.js +61 -0
  154. package/dist/frontend/assets/tr-TR-DEFEU3FU-DhlYP6tL.js +7 -0
  155. package/dist/frontend/assets/uk-UA-QMV73CPH-pMrN1qBS.js +6 -0
  156. package/dist/frontend/assets/union-Cu1rbD_D.js +1 -0
  157. package/dist/frontend/assets/vi-VN-M7AON7JQ-BPMcH84R.js +5 -0
  158. package/dist/frontend/assets/xml-BOsq7VnW.js +1 -0
  159. package/dist/frontend/assets/xychartDiagram-b6496bcd-BDm9pYtk.js +7 -0
  160. package/dist/frontend/assets/xychartDiagram-e933f94c-BlrTBDHC.js +7 -0
  161. package/dist/frontend/assets/zh-CN-LNUGB5OW-B8kYYibM.js +10 -0
  162. package/dist/frontend/assets/zh-HK-E62DVLB3-CaI0gehP.js +1 -0
  163. package/dist/frontend/assets/zh-TW-RAJ6MFWO-DKCVg17j.js +9 -0
  164. package/dist/frontend/assets/zipObject-iRVIFf6r.js +1 -0
  165. package/dist/frontend/index.html +420 -0
  166. package/dist/index.d.ts +4 -0
  167. package/dist/index.d.ts.map +1 -0
  168. package/dist/index.js +2241 -0
  169. package/dist/index.js.map +1 -0
  170. package/dist/server.d.ts +6 -0
  171. package/dist/server.d.ts.map +1 -0
  172. package/dist/server.js +980 -0
  173. package/dist/server.js.map +1 -0
  174. package/dist/types.d.ts +225 -0
  175. package/dist/types.d.ts.map +1 -0
  176. package/dist/types.js +30 -0
  177. package/dist/types.js.map +1 -0
  178. package/dist/utils/logger.d.ts +4 -0
  179. package/dist/utils/logger.d.ts.map +1 -0
  180. package/dist/utils/logger.js +23 -0
  181. package/dist/utils/logger.js.map +1 -0
  182. package/package.json +108 -0
  183. package/skills/excalidraw-skill/SKILL.md +370 -0
  184. package/skills/excalidraw-skill/references/cheatsheet.md +195 -0
  185. package/skills/excalidraw-skill/scripts/clear-canvas.cjs +38 -0
  186. package/skills/excalidraw-skill/scripts/create-element.cjs +68 -0
  187. package/skills/excalidraw-skill/scripts/delete-element.cjs +48 -0
  188. package/skills/excalidraw-skill/scripts/export-elements.cjs +53 -0
  189. package/skills/excalidraw-skill/scripts/healthcheck.cjs +35 -0
  190. package/skills/excalidraw-skill/scripts/import-elements.cjs +81 -0
  191. package/skills/excalidraw-skill/scripts/update-element.cjs +70 -0
@@ -0,0 +1,48 @@
1
+ #!/usr/bin/env node
2
+ /* eslint-disable no-console */
3
+
4
+ const DEFAULT_URL = process.env.EXPRESS_SERVER_URL || "http://localhost:3000";
5
+
6
+ function usage() {
7
+ console.error("Usage: node scripts/delete-element.cjs --id <id> [--url <canvasUrl>]");
8
+ process.exit(2);
9
+ }
10
+
11
+ function parseArgs(argv) {
12
+ const out = { url: DEFAULT_URL, id: null };
13
+ for (let i = 0; i < argv.length; i++) {
14
+ const a = argv[i];
15
+ if (a === "--url") out.url = argv[++i];
16
+ else if (a === "--id") out.id = argv[++i];
17
+ }
18
+ return out;
19
+ }
20
+
21
+ async function main() {
22
+ if (typeof fetch !== "function") {
23
+ throw new Error("This script requires Node 18+ (global fetch).");
24
+ }
25
+
26
+ const args = parseArgs(process.argv.slice(2));
27
+ if (!args.id) usage();
28
+
29
+ const baseUrl = args.url.replace(/\/$/, "");
30
+ const res = await fetch(`${baseUrl}/api/elements/${encodeURIComponent(args.id)}`, {
31
+ method: "DELETE",
32
+ });
33
+
34
+ const json = await res.json().catch(() => null);
35
+ if (!res.ok || !json || json.success !== true) {
36
+ throw new Error(
37
+ `Failed to delete element: ${res.status} ${res.statusText} ${json?.error ? `- ${json.error}` : ""}`,
38
+ );
39
+ }
40
+
41
+ console.log(`Deleted ${args.id}`);
42
+ }
43
+
44
+ main().catch((err) => {
45
+ console.error(err?.stack || String(err));
46
+ process.exit(1);
47
+ });
48
+
@@ -0,0 +1,53 @@
1
+ #!/usr/bin/env node
2
+ /* eslint-disable no-console */
3
+
4
+ const fs = require("node:fs");
5
+ const path = require("node:path");
6
+
7
+ const DEFAULT_URL = process.env.EXPRESS_SERVER_URL || "http://localhost:3000";
8
+
9
+ function parseArgs(argv) {
10
+ const out = { url: DEFAULT_URL, outFile: null };
11
+ for (let i = 0; i < argv.length; i++) {
12
+ const a = argv[i];
13
+ if (a === "--url") out.url = argv[++i];
14
+ else if (a === "--out") out.outFile = argv[++i];
15
+ else if (a === "-o") out.outFile = argv[++i];
16
+ }
17
+ return out;
18
+ }
19
+
20
+ async function main() {
21
+ if (typeof fetch !== "function") {
22
+ throw new Error("This script requires Node 18+ (global fetch).");
23
+ }
24
+
25
+ const { url, outFile } = parseArgs(process.argv.slice(2));
26
+ const res = await fetch(`${url.replace(/\/$/, "")}/api/elements`);
27
+ const json = await res.json();
28
+
29
+ if (!res.ok || !json || json.success !== true) {
30
+ throw new Error(`Failed to export elements: ${res.status} ${res.statusText}`);
31
+ }
32
+
33
+ const payload = {
34
+ exportedAt: new Date().toISOString(),
35
+ expressServerUrl: url,
36
+ elements: json.elements || [],
37
+ };
38
+
39
+ const text = JSON.stringify(payload, null, 2);
40
+ if (!outFile) {
41
+ process.stdout.write(text + "\n");
42
+ return;
43
+ }
44
+
45
+ fs.mkdirSync(path.dirname(outFile), { recursive: true });
46
+ fs.writeFileSync(outFile, text + "\n");
47
+ console.log(`Wrote ${payload.elements.length} elements to ${outFile}`);
48
+ }
49
+
50
+ main().catch((err) => {
51
+ console.error(err?.stack || String(err));
52
+ process.exit(1);
53
+ });
@@ -0,0 +1,35 @@
1
+ #!/usr/bin/env node
2
+ /* eslint-disable no-console */
3
+
4
+ const DEFAULT_URL = process.env.EXPRESS_SERVER_URL || "http://localhost:3000";
5
+
6
+ function parseArgs(argv) {
7
+ const out = { url: DEFAULT_URL };
8
+ for (let i = 0; i < argv.length; i++) {
9
+ const a = argv[i];
10
+ if (a === "--url") out.url = argv[++i];
11
+ }
12
+ return out;
13
+ }
14
+
15
+ async function main() {
16
+ if (typeof fetch !== "function") {
17
+ throw new Error("This script requires Node 18+ (global fetch).");
18
+ }
19
+
20
+ const { url } = parseArgs(process.argv.slice(2));
21
+ const res = await fetch(`${url.replace(/\/$/, "")}/health`);
22
+ const text = await res.text();
23
+
24
+ if (!res.ok) {
25
+ console.error(text);
26
+ process.exit(1);
27
+ }
28
+
29
+ console.log(text);
30
+ }
31
+
32
+ main().catch((err) => {
33
+ console.error(err?.stack || String(err));
34
+ process.exit(1);
35
+ });
@@ -0,0 +1,81 @@
1
+ #!/usr/bin/env node
2
+ /* eslint-disable no-console */
3
+
4
+ const fs = require("node:fs");
5
+
6
+ const DEFAULT_URL = process.env.EXPRESS_SERVER_URL || "http://localhost:3000";
7
+
8
+ function usage() {
9
+ console.error(
10
+ [
11
+ "Usage:",
12
+ " node scripts/import-elements.cjs --in <file> [--mode batch|sync] [--url <canvasUrl>]",
13
+ "",
14
+ "Modes:",
15
+ " batch POST /api/elements/batch (append; creates elements)",
16
+ " sync POST /api/elements/sync (overwrite; clears then writes)",
17
+ ].join("\n"),
18
+ );
19
+ process.exit(2);
20
+ }
21
+
22
+ function parseArgs(argv) {
23
+ const out = { url: DEFAULT_URL, inFile: null, mode: "batch" };
24
+ for (let i = 0; i < argv.length; i++) {
25
+ const a = argv[i];
26
+ if (a === "--url") out.url = argv[++i];
27
+ else if (a === "--in") out.inFile = argv[++i];
28
+ else if (a === "--mode") out.mode = argv[++i];
29
+ }
30
+ return out;
31
+ }
32
+
33
+ function readElementsFromFile(inFile) {
34
+ const raw = fs.readFileSync(inFile, "utf8");
35
+ const data = JSON.parse(raw);
36
+ if (Array.isArray(data)) return data;
37
+ if (data && Array.isArray(data.elements)) return data.elements;
38
+ throw new Error('Input file must be an array, or an object with an "elements" array');
39
+ }
40
+
41
+ async function main() {
42
+ if (typeof fetch !== "function") {
43
+ throw new Error("This script requires Node 18+ (global fetch).");
44
+ }
45
+
46
+ const { url, inFile, mode } = parseArgs(process.argv.slice(2));
47
+ if (!inFile) usage();
48
+ if (mode !== "batch" && mode !== "sync") usage();
49
+
50
+ const elements = readElementsFromFile(inFile);
51
+ const baseUrl = url.replace(/\/$/, "");
52
+
53
+ let endpoint;
54
+ let body;
55
+ if (mode === "batch") {
56
+ endpoint = `${baseUrl}/api/elements/batch`;
57
+ body = { elements };
58
+ } else {
59
+ endpoint = `${baseUrl}/api/elements/sync`;
60
+ body = { elements, timestamp: new Date().toISOString() };
61
+ }
62
+
63
+ const res = await fetch(endpoint, {
64
+ method: "POST",
65
+ headers: { "Content-Type": "application/json" },
66
+ body: JSON.stringify(body),
67
+ });
68
+
69
+ const json = await res.json().catch(() => null);
70
+ if (!res.ok || !json || json.success !== true) {
71
+ throw new Error(`Failed to import elements: ${res.status} ${res.statusText} ${json?.error ? `- ${json.error}` : ""}`);
72
+ }
73
+
74
+ const count = json.count ?? json.elements?.length ?? elements.length;
75
+ console.log(`Imported ${count} elements (${mode})`);
76
+ }
77
+
78
+ main().catch((err) => {
79
+ console.error(err?.stack || String(err));
80
+ process.exit(1);
81
+ });
@@ -0,0 +1,70 @@
1
+ #!/usr/bin/env node
2
+ /* eslint-disable no-console */
3
+
4
+ const fs = require("node:fs");
5
+
6
+ const DEFAULT_URL = process.env.EXPRESS_SERVER_URL || "http://localhost:3000";
7
+
8
+ function usage() {
9
+ console.error(
10
+ [
11
+ "Usage:",
12
+ " node scripts/update-element.cjs --id <id> (--data <json> | --file <path>) [--url <canvasUrl>]",
13
+ "",
14
+ "Examples:",
15
+ ' node scripts/update-element.cjs --id abc --data \'{"x":200,"y":250,"backgroundColor":"#ffeeee"}\'',
16
+ " node scripts/update-element.cjs --id abc --file updates.json",
17
+ ].join("\n"),
18
+ );
19
+ process.exit(2);
20
+ }
21
+
22
+ function parseArgs(argv) {
23
+ const out = { url: DEFAULT_URL, id: null, data: null, file: null };
24
+ for (let i = 0; i < argv.length; i++) {
25
+ const a = argv[i];
26
+ if (a === "--url") out.url = argv[++i];
27
+ else if (a === "--id") out.id = argv[++i];
28
+ else if (a === "--data") out.data = argv[++i];
29
+ else if (a === "--file") out.file = argv[++i];
30
+ }
31
+ return out;
32
+ }
33
+
34
+ function readJson({ data, file }) {
35
+ if (data) return JSON.parse(data);
36
+ if (file) return JSON.parse(fs.readFileSync(file, "utf8"));
37
+ usage();
38
+ }
39
+
40
+ async function main() {
41
+ if (typeof fetch !== "function") {
42
+ throw new Error("This script requires Node 18+ (global fetch).");
43
+ }
44
+
45
+ const args = parseArgs(process.argv.slice(2));
46
+ if (!args.id) usage();
47
+ const payload = readJson(args);
48
+
49
+ const baseUrl = args.url.replace(/\/$/, "");
50
+ const res = await fetch(`${baseUrl}/api/elements/${encodeURIComponent(args.id)}`, {
51
+ method: "PUT",
52
+ headers: { "Content-Type": "application/json" },
53
+ body: JSON.stringify(payload),
54
+ });
55
+
56
+ const json = await res.json().catch(() => null);
57
+ if (!res.ok || !json || json.success !== true) {
58
+ throw new Error(
59
+ `Failed to update element: ${res.status} ${res.statusText} ${json?.error ? `- ${json.error}` : ""}`,
60
+ );
61
+ }
62
+
63
+ process.stdout.write(JSON.stringify(json.element, null, 2) + "\n");
64
+ }
65
+
66
+ main().catch((err) => {
67
+ console.error(err?.stack || String(err));
68
+ process.exit(1);
69
+ });
70
+