archyne 0.3.0-alpha.1 → 0.3.2-alpha.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.
Files changed (78) hide show
  1. package/README.md +29 -10
  2. package/THIRD-PARTY-NOTICES.md +309 -309
  3. package/dist/assets/{abnfDiagram-N423BO3Z-DIXsDC-F.js → abnfDiagram-N423BO3Z-CWxCA29s.js} +1 -1
  4. package/dist/assets/{arc-Dj16AHPP.js → arc-BPhcgyOR.js} +1 -1
  5. package/dist/assets/{architectureDiagram-T3A2C74G-BVAWUfK9.js → architectureDiagram-T3A2C74G-DbJtNiJ8.js} +1 -1
  6. package/dist/assets/{blockDiagram-VBNYF7ZC-DWGHJV3z.js → blockDiagram-VBNYF7ZC-D14dxPQ6.js} +1 -1
  7. package/dist/assets/{c4Diagram-5PPSVZJV-BQxBb-eE.js → c4Diagram-5PPSVZJV-_Ru2AQyv.js} +1 -1
  8. package/dist/assets/channel-x2nnREdF.js +1 -0
  9. package/dist/assets/{chunk-2GRJ4B5K-DrxYcIKi.js → chunk-2GRJ4B5K-B45veiLl.js} +1 -1
  10. package/dist/assets/{chunk-2Q5K7J3B-qIYVNzfi.js → chunk-2Q5K7J3B-BYEJghF5.js} +1 -1
  11. package/dist/assets/{chunk-5RXB4S5H-BSkyDD2G.js → chunk-5RXB4S5H-D6PWk-Fh.js} +1 -1
  12. package/dist/assets/{chunk-5VM5RSS4-Doshgyjn.js → chunk-5VM5RSS4-DkT1fHDH.js} +1 -1
  13. package/dist/assets/{chunk-6Q2QTUOP-DY_ARIfs.js → chunk-6Q2QTUOP-DwN_ODU0.js} +1 -1
  14. package/dist/assets/{chunk-GF5L2VYU-wHUCmL_g.js → chunk-GF5L2VYU-CfLWnAFR.js} +1 -1
  15. package/dist/assets/{chunk-JWPE2WC7-BWaI0jmn.js → chunk-JWPE2WC7-Bvoco_OT.js} +1 -1
  16. package/dist/assets/{chunk-KBJHAD2P-JqxcXows.js → chunk-KBJHAD2P-Bl8ANVAT.js} +1 -1
  17. package/dist/assets/{chunk-RYQCIY6F-Cw5xJ0a1.js → chunk-RYQCIY6F-CUFEfSAp.js} +1 -1
  18. package/dist/assets/{chunk-XXDRQBXY-DTNNhjpS.js → chunk-XXDRQBXY-CqS46WpP.js} +1 -1
  19. package/dist/assets/classDiagram-JCYQIIEL-Dcqht9zY.js +1 -0
  20. package/dist/assets/classDiagram-v2-OCEON4UE-Dcqht9zY.js +1 -0
  21. package/dist/assets/{cose-bilkent-JH36ORCC-COsgTVVE.js → cose-bilkent-JH36ORCC-0fLdUP4n.js} +1 -1
  22. package/dist/assets/{cynefin-VYW2F7L2-Cro8QprN.js → cynefin-VYW2F7L2-CB-4Q2Uq.js} +1 -1
  23. package/dist/assets/{cynefinDiagram-MW4NZA55-Otk8wE3X.js → cynefinDiagram-MW4NZA55-m6YSI3Bh.js} +1 -1
  24. package/dist/assets/{dagre-VZM6K2ZE-CvTaqqHa.js → dagre-VZM6K2ZE-BsmbvCId.js} +1 -1
  25. package/dist/assets/{diagram-7IWD3JNH-BNe8ln_N.js → diagram-7IWD3JNH-iTWBScbD.js} +1 -1
  26. package/dist/assets/{diagram-B4RE2ZJO-Brnd7Tv6.js → diagram-B4RE2ZJO-DJ95aX4N.js} +1 -1
  27. package/dist/assets/{diagram-LBJQPF4R-CrEH36Uj.js → diagram-LBJQPF4R-D4V1ejJ0.js} +1 -1
  28. package/dist/assets/{diagram-Q27KOJAE-CBK1TZN-.js → diagram-Q27KOJAE-BJ2SnmJt.js} +1 -1
  29. package/dist/assets/{diagram-UB23O5K3-JUQ78M73.js → diagram-UB23O5K3-B33ky4tq.js} +1 -1
  30. package/dist/assets/{ebnfDiagram-BXEA7PRR-BdUTSTYX.js → ebnfDiagram-BXEA7PRR-B8YZxzzx.js} +1 -1
  31. package/dist/assets/{elk-api-CnmYJVU6.js → elk-api-BEoK8cSs.js} +1 -1
  32. package/dist/assets/{elk.bundled-C1NX_935.js → elk.bundled-g5J3chN5.js} +1 -1
  33. package/dist/assets/{erDiagram-JOGREHBK-D7fhJig7.js → erDiagram-JOGREHBK-B7RkeG0t.js} +1 -1
  34. package/dist/assets/{flowDiagram-UKHOOZJN-BUuw8Sra.js → flowDiagram-UKHOOZJN-Bhg1RufJ.js} +1 -1
  35. package/dist/assets/{fromDot-m2FS_XBS.js → fromDot-CQsAmWbW.js} +1 -1
  36. package/dist/assets/{fromDrawio-d2P5s3hv.js → fromDrawio-DEgkUjY8.js} +1 -1
  37. package/dist/assets/{fromExcalidraw-gkO8wk9U.js → fromExcalidraw-BzgOaI_g.js} +1 -1
  38. package/dist/assets/{fromPlantuml-DC6Ln4Kt.js → fromPlantuml-BXgnqEO6.js} +1 -1
  39. package/dist/assets/{fromSql-fjmDwmgj.js → fromSql-CgaUND0o.js} +1 -1
  40. package/dist/assets/{fromVsdx-BNwPKIKU.js → fromVsdx-_QnAzQCc.js} +1 -1
  41. package/dist/assets/{ganttDiagram-PKOTCBZU-0pMER0ej.js → ganttDiagram-PKOTCBZU-6q1OXMFs.js} +1 -1
  42. package/dist/assets/{gitGraphDiagram-DS77QQ5N-CdqG1WOl.js → gitGraphDiagram-DS77QQ5N-DBIluxD2.js} +1 -1
  43. package/dist/assets/{index-D2iswyef.js → index-D58D9MBA.js} +63 -63
  44. package/dist/assets/index-Kkii5lY5.css +1 -0
  45. package/dist/assets/{infoDiagram-6WML65LV-DPqvV8rB.js → infoDiagram-6WML65LV-BogiGFsC.js} +1 -1
  46. package/dist/assets/{ishikawaDiagram-WSZJBQD7-CSPXAP3s.js → ishikawaDiagram-WSZJBQD7-BnuS3rDr.js} +1 -1
  47. package/dist/assets/{journeyDiagram-NVQOT4AX-DTHQtGFh.js → journeyDiagram-NVQOT4AX-C1LbH3qg.js} +1 -1
  48. package/dist/assets/{kanban-definition-27J2QSJJ-B0DJ3-Na.js → kanban-definition-27J2QSJJ-CC4tpXS8.js} +1 -1
  49. package/dist/assets/{linear-B4AE5gzn.js → linear-nPRvbK9t.js} +1 -1
  50. package/dist/assets/{mermaid.core-cnu9Hu0H.js → mermaid.core-d3X_EolB.js} +4 -4
  51. package/dist/assets/{mindmap-definition-FAOFIHXS-qGpw5nKM.js → mindmap-definition-FAOFIHXS-BKw0CExu.js} +1 -1
  52. package/dist/assets/{pegDiagram-VL7TDLO6-BGT3Nw2y.js → pegDiagram-VL7TDLO6-C0crO6aC.js} +1 -1
  53. package/dist/assets/{pieDiagram-7S7Q4E2Y-Bc8ghniT.js → pieDiagram-7S7Q4E2Y-5YsXd83r.js} +1 -1
  54. package/dist/assets/{plantumlFamilies-DOJ5Zy3V.js → plantumlFamilies-BQWcuhsm.js} +1 -1
  55. package/dist/assets/{quadrantDiagram-CIZ2JOQS-BtlM_DOc.js → quadrantDiagram-CIZ2JOQS-BWRDIcFE.js} +1 -1
  56. package/dist/assets/{railroadDiagram-AXF67PYL-LYPvIKAL.js → railroadDiagram-AXF67PYL-BeJeN8NK.js} +1 -1
  57. package/dist/assets/{requirementDiagram-LRYGKXZP-BzJkmewZ.js → requirementDiagram-LRYGKXZP-lgxjjOkj.js} +1 -1
  58. package/dist/assets/{sankeyDiagram-W5VNT64P-DETZ9w-u.js → sankeyDiagram-W5VNT64P-BdDlQIjC.js} +1 -1
  59. package/dist/assets/{sequenceDiagram-SI44F4Z6-7KPCXxWm.js → sequenceDiagram-SI44F4Z6-CftqXzOB.js} +1 -1
  60. package/dist/assets/{sizeCapture-X5ZJPWSS-BM9d5oG-.js → sizeCapture-X5ZJPWSS-DqAD3Y1J.js} +1 -1
  61. package/dist/assets/{stateDiagram-OKZ733FA-a_7Vxmm-.js → stateDiagram-OKZ733FA-CsK1tZu_.js} +1 -1
  62. package/dist/assets/stateDiagram-v2-UEYNNEHI-DoKVKwvk.js +1 -0
  63. package/dist/assets/{swimlanes-SLNWSIFB-D3qzkF1P.js → swimlanes-SLNWSIFB-y49WYIGH.js} +2 -2
  64. package/dist/assets/swimlanesDiagram-ULZ7WXOC-DdYZRZ7q.js +8 -0
  65. package/dist/assets/{timeline-definition-Z64GVDOM-CZq_A4Q0.js → timeline-definition-Z64GVDOM-dsSDjxsB.js} +1 -1
  66. package/dist/assets/{vennDiagram-T6HMQDX7-CDFzI8sR.js → vennDiagram-T6HMQDX7-D5ubu60T.js} +1 -1
  67. package/dist/assets/{wardleyDiagram-T6FBY63Y-D5fktD2X.js → wardleyDiagram-T6FBY63Y-DqlVsICK.js} +1 -1
  68. package/dist/assets/{xychartDiagram-ELKLHX3M-BSzrgaJ4.js → xychartDiagram-ELKLHX3M-Z5y_JujJ.js} +1 -1
  69. package/dist/index.html +29 -2
  70. package/dist/preview.png +0 -0
  71. package/package.json +134 -133
  72. package/desktop/main.cjs +0 -378
  73. package/dist/assets/channel-Dqh6JL_k.js +0 -1
  74. package/dist/assets/classDiagram-JCYQIIEL-BSai74_L.js +0 -1
  75. package/dist/assets/classDiagram-v2-OCEON4UE-BSai74_L.js +0 -1
  76. package/dist/assets/index-iS7lCiZ-.css +0 -1
  77. package/dist/assets/stateDiagram-v2-UEYNNEHI-DQz4hTBY.js +0 -1
  78. package/dist/assets/swimlanesDiagram-ULZ7WXOC-CuRyTLM3.js +0 -8
package/package.json CHANGED
@@ -1,133 +1,134 @@
1
- {
2
- "name": "archyne",
3
- "version": "0.3.0-alpha.1",
4
- "license": "MIT",
5
- "type": "module",
6
- "bin": {
7
- "archyne": "bin/archyne.mjs"
8
- },
9
- "files": [
10
- "bin",
11
- "dist",
12
- "LICENSE",
13
- "NOTICE",
14
- "README.md",
15
- "THIRD-PARTY-NOTICES.md"
16
- ],
17
- "engines": {
18
- "node": ">=22"
19
- },
20
- "repository": {
21
- "type": "git",
22
- "url": "git+https://github.com/dariodd/archyne.git"
23
- },
24
- "bugs": {
25
- "url": "https://github.com/dariodd/archyne/issues"
26
- },
27
- "homepage": "https://dariodd.github.io/archyne/",
28
- "keywords": [
29
- "mermaid",
30
- "diagram",
31
- "diagram-editor",
32
- "flowchart",
33
- "uml",
34
- "erd",
35
- "c4-model",
36
- "sequence-diagram",
37
- "architecture-diagram",
38
- "local-first",
39
- "mcp",
40
- "editor"
41
- ],
42
- "scripts": {
43
- "dev": "vite",
44
- "build": "npm run typecheck && vite build",
45
- "preview": "vite preview",
46
- "test": "vitest run",
47
- "typecheck": "tsc -p tsconfig.json && tsc -p tsconfig.node.json",
48
- "lint": "eslint .",
49
- "lint:fix": "eslint . --fix",
50
- "format": "prettier --write .",
51
- "format:check": "prettier --check .",
52
- "size": "node scripts/check-bundle-size.mjs",
53
- "icons:azure": "node scripts/build-azure-icons.mjs",
54
- "icons:index": "node scripts/build-icon-index.mjs",
55
- "audit": "node scripts/audit-gate.mjs",
56
- "sbom": "node scripts/sbom.mjs",
57
- "notices:check": "node scripts/sbom.mjs && node scripts/check-notices.mjs",
58
- "notices:update": "node scripts/sbom.mjs && node scripts/update-notices.mjs",
59
- "mcp": "tsx mcp/server.ts",
60
- "mcp:smoke": "tsx mcp/smoke.ts",
61
- "test:e2e:export": "tsx tests/e2e-export.mts",
62
- "test:e2e:i18n": "tsx tests/e2e-i18n-export.mts",
63
- "test:e2e:a11y": "tsx tests/e2e-a11y.mts",
64
- "test:e2e:rtl": "tsx tests/e2e-rtl.mts",
65
- "test:e2e:csp": "tsx tests/e2e-csp.mts",
66
- "test:e2e:drag": "tsx tests/e2e-drag.mts",
67
- "test:e2e:waypoints": "tsx tests/e2e-waypoints.mts",
68
- "test:e2e:resize": "tsx tests/e2e-resize.mts",
69
- "test:e2e:watch": "tsx tests/e2e-watch.mts",
70
- "test:e2e:panel": "tsx tests/e2e-panel.mts",
71
- "test:e2e:icons": "tsx tests/e2e-icons.mts",
72
- "test:e2e:import": "tsx tests/e2e-import.mts",
73
- "start": "node bin/archyne.mjs",
74
- "prepublishOnly": "npm run build",
75
- "desktop": "electron .",
76
- "desktop:build": "npm run build && electron-builder --win"
77
- },
78
- "dependencies": {
79
- "@codemirror/theme-one-dark": "^6.1.3",
80
- "@iconify-json/carbon": "^1.2.24",
81
- "@iconify-json/devicon": "^1.2.62",
82
- "@iconify-json/logos": "^1.2.11",
83
- "@iconify-json/simple-icons": "^1.2.92",
84
- "@iconify-json/tabler": "^1.2.38",
85
- "@iconify/utils": "^3.1.4",
86
- "@modelcontextprotocol/sdk": "^1.30.0",
87
- "@xyflow/react": "^12.8.0",
88
- "codemirror": "^6.0.2",
89
- "codemirror-lang-mermaid": "^0.5.0",
90
- "elkjs": "^0.12.0",
91
- "fflate": "^0.8.3",
92
- "html-to-image": "^1.11.13",
93
- "mermaid": "^11.9.0",
94
- "react": "^19.1.0",
95
- "react-dom": "^19.1.0",
96
- "tsx": "^4.23.1",
97
- "zod": "^4.4.3",
98
- "zustand": "^5.0.0"
99
- },
100
- "devDependencies": {
101
- "@eslint/js": "^9.39.5",
102
- "@testing-library/react": "^16.3.2",
103
- "@testing-library/user-event": "^14.6.1",
104
- "@types/jsdom": "^28.0.3",
105
- "@types/node": "^26.1.2",
106
- "@types/react": "^19.1.0",
107
- "@types/react-dom": "^19.1.0",
108
- "@vitejs/plugin-react": "^4.5.0",
109
- "axe-core": "^4.12.1",
110
- "electron": "^43.2.0",
111
- "electron-builder": "^26.15.3",
112
- "eslint": "^9.39.5",
113
- "eslint-config-prettier": "^10.1.8",
114
- "eslint-plugin-jsx-a11y": "^6.10.2",
115
- "eslint-plugin-react-hooks": "^7.1.1",
116
- "eslint-plugin-react-refresh": "^0.5.3",
117
- "globals": "^17.8.0",
118
- "jsdom": "^30.0.1",
119
- "playwright": "^1.62.1",
120
- "prettier": "^3.9.6",
121
- "typescript": "~5.8.0",
122
- "typescript-eslint": "^8.65.0",
123
- "vite": "^6.3.0",
124
- "vitest": "^4.1.10"
125
- },
126
- "main": "desktop/main.cjs",
127
- "description": "A visual editor for Mermaid diagrams — draw, and get Mermaid code",
128
- "author": {
129
- "name": "dariodd",
130
- "email": "57635667+dariodd@users.noreply.github.com",
131
- "url": "https://github.com/dariodd"
132
- }
133
- }
1
+ {
2
+ "name": "archyne",
3
+ "version": "0.3.2-alpha.1",
4
+ "license": "MIT",
5
+ "type": "module",
6
+ "bin": {
7
+ "archyne": "bin/archyne.mjs"
8
+ },
9
+ "files": [
10
+ "bin",
11
+ "dist",
12
+ "LICENSE",
13
+ "NOTICE",
14
+ "README.md",
15
+ "THIRD-PARTY-NOTICES.md"
16
+ ],
17
+ "engines": {
18
+ "node": ">=22"
19
+ },
20
+ "repository": {
21
+ "type": "git",
22
+ "url": "git+https://github.com/dariodd/archyne.git"
23
+ },
24
+ "bugs": {
25
+ "url": "https://github.com/dariodd/archyne/issues"
26
+ },
27
+ "homepage": "https://dariodd.github.io/archyne/",
28
+ "keywords": [
29
+ "mermaid",
30
+ "diagram",
31
+ "diagram-editor",
32
+ "flowchart",
33
+ "uml",
34
+ "erd",
35
+ "c4-model",
36
+ "sequence-diagram",
37
+ "architecture-diagram",
38
+ "local-first",
39
+ "mcp",
40
+ "editor"
41
+ ],
42
+ "scripts": {
43
+ "dev": "vite",
44
+ "build": "npm run typecheck && vite build",
45
+ "preview": "vite preview",
46
+ "test": "vitest run",
47
+ "typecheck": "tsc -p tsconfig.json && tsc -p tsconfig.node.json",
48
+ "lint": "eslint .",
49
+ "lint:fix": "eslint . --fix",
50
+ "format": "prettier --write .",
51
+ "format:check": "prettier --check .",
52
+ "size": "node scripts/check-bundle-size.mjs",
53
+ "icons:azure": "node scripts/build-azure-icons.mjs",
54
+ "icons:index": "node scripts/build-icon-index.mjs",
55
+ "audit": "node scripts/audit-gate.mjs",
56
+ "sbom": "node scripts/sbom.mjs",
57
+ "notices:check": "node scripts/sbom.mjs && node scripts/check-notices.mjs",
58
+ "notices:update": "node scripts/sbom.mjs && node scripts/update-notices.mjs",
59
+ "mcp": "tsx mcp/server.ts",
60
+ "mcp:smoke": "tsx mcp/smoke.ts",
61
+ "test:e2e:export": "tsx tests/e2e-export.mts",
62
+ "test:e2e:i18n": "tsx tests/e2e-i18n-export.mts",
63
+ "test:e2e:a11y": "tsx tests/e2e-a11y.mts",
64
+ "test:e2e:rtl": "tsx tests/e2e-rtl.mts",
65
+ "test:e2e:csp": "tsx tests/e2e-csp.mts",
66
+ "test:e2e:drag": "tsx tests/e2e-drag.mts",
67
+ "test:e2e:waypoints": "tsx tests/e2e-waypoints.mts",
68
+ "test:e2e:sequence": "tsx tests/e2e-sequence.mts",
69
+ "test:e2e:architecture": "tsx tests/e2e-architecture.mts",
70
+ "test:e2e:resize": "tsx tests/e2e-resize.mts",
71
+ "test:e2e:watch": "tsx tests/e2e-watch.mts",
72
+ "test:e2e:panel": "tsx tests/e2e-panel.mts",
73
+ "test:e2e:icons": "tsx tests/e2e-icons.mts",
74
+ "test:e2e:import": "tsx tests/e2e-import.mts",
75
+ "start": "node bin/archyne.mjs",
76
+ "prepublishOnly": "npm run build",
77
+ "desktop": "electron desktop/main.cjs",
78
+ "desktop:build": "npm run build && electron-builder --win"
79
+ },
80
+ "dependencies": {
81
+ "@codemirror/theme-one-dark": "^6.1.3",
82
+ "@iconify-json/carbon": "^1.2.24",
83
+ "@iconify-json/devicon": "^1.2.62",
84
+ "@iconify-json/logos": "^1.2.11",
85
+ "@iconify-json/simple-icons": "^1.2.92",
86
+ "@iconify-json/tabler": "^1.2.38",
87
+ "@iconify/utils": "^3.1.4",
88
+ "@modelcontextprotocol/sdk": "^1.30.0",
89
+ "@xyflow/react": "^12.8.0",
90
+ "codemirror": "^6.0.2",
91
+ "codemirror-lang-mermaid": "^0.5.0",
92
+ "elkjs": "^0.12.0",
93
+ "fflate": "^0.8.3",
94
+ "html-to-image": "^1.11.13",
95
+ "mermaid": "^11.9.0",
96
+ "react": "^19.1.0",
97
+ "react-dom": "^19.1.0",
98
+ "tsx": "^4.23.1",
99
+ "zod": "^4.4.3",
100
+ "zustand": "^5.0.0"
101
+ },
102
+ "devDependencies": {
103
+ "@eslint/js": "^9.39.5",
104
+ "@testing-library/react": "^16.3.2",
105
+ "@testing-library/user-event": "^14.6.1",
106
+ "@types/jsdom": "^28.0.3",
107
+ "@types/node": "^26.1.2",
108
+ "@types/react": "^19.1.0",
109
+ "@types/react-dom": "^19.1.0",
110
+ "@vitejs/plugin-react": "^4.5.0",
111
+ "axe-core": "^4.12.1",
112
+ "electron": "^43.2.0",
113
+ "electron-builder": "^26.15.3",
114
+ "eslint": "^9.39.5",
115
+ "eslint-config-prettier": "^10.1.8",
116
+ "eslint-plugin-jsx-a11y": "^6.10.2",
117
+ "eslint-plugin-react-hooks": "^7.1.1",
118
+ "eslint-plugin-react-refresh": "^0.5.3",
119
+ "globals": "^17.8.0",
120
+ "jsdom": "^30.0.1",
121
+ "playwright": "^1.62.1",
122
+ "prettier": "^3.9.6",
123
+ "typescript": "~5.8.0",
124
+ "typescript-eslint": "^8.65.0",
125
+ "vite": "^6.3.0",
126
+ "vitest": "^4.1.10"
127
+ },
128
+ "description": "A visual editor for Mermaid diagrams — draw, and get Mermaid code",
129
+ "author": {
130
+ "name": "dariodd",
131
+ "email": "57635667+dariodd@users.noreply.github.com",
132
+ "url": "https://github.com/dariodd"
133
+ }
134
+ }
package/desktop/main.cjs DELETED
@@ -1,378 +0,0 @@
1
- /**
2
- * Archyne desktop shell: a thin Electron window around the static build.
3
- *
4
- * Everything still runs locally in the renderer — no backend. The shell
5
- * reaches the network in exactly one place, `archyne:fetch-icons`, and only
6
- * because a link the user pasted asked it to; see the notes there.
7
- */
8
- const { app, BrowserWindow, dialog, ipcMain, nativeTheme, shell } = require("electron");
9
- const path = require("node:path");
10
- const fs = require("node:fs");
11
- const fsp = require("node:fs/promises");
12
- const { unzipSync } = require("fflate");
13
-
14
- /**
15
- * .mmd file passed on the command line (double-click / "open with").
16
- * @param {string[]} argv
17
- * @returns {string | undefined}
18
- */
19
- function fileArg(argv) {
20
- // `.xml` is deliberately not here: the installer associates `.mmd`, and
21
- // picking up any stray XML on the command line would be a surprise. A
22
- // draw.io file named `.xml` can still be opened from the dialog.
23
- const openable =
24
- /\.(mmd|mermaid|drawio|vsdx|dot|gv|sql|ddl|excalidraw|puml|plantuml|iuml|wsd)$/i;
25
- return argv.find((a) => openable.test(a) && fs.existsSync(a));
26
- }
27
-
28
- /**
29
- * File the app was launched with, handed to the renderer over IPC once it
30
- * asks. Passing it through the URL — as this used to — broke on large
31
- * diagrams and lost the path, so saving could never write back to it.
32
- * @type {string | undefined}
33
- */
34
- let pendingFile;
35
-
36
- const FILTERS = [
37
- { name: "Mermaid diagram", extensions: ["mmd", "mermaid"] },
38
- { name: "All files", extensions: ["*"] },
39
- ];
40
-
41
- const IMPORTABLE = [
42
- "drawio",
43
- "xml",
44
- "vsdx",
45
- "dot",
46
- "gv",
47
- "sql",
48
- "ddl",
49
- "excalidraw",
50
- "puml",
51
- "plantuml",
52
- "iuml",
53
- "wsd",
54
- ];
55
-
56
- /**
57
- * What **Import** offers. Open shows `FILTERS` instead: opening a file means
58
- * editing it and saving it back, and none of these is ever written back — the
59
- * renderer converts it and unbinds it from its source, so Save always writes
60
- * Mermaid.
61
- */
62
- const IMPORT_FILTERS = [
63
- { name: "Any importable drawing", extensions: IMPORTABLE },
64
- { name: "draw.io diagram", extensions: ["drawio", "xml"] },
65
- { name: "Visio drawing", extensions: ["vsdx"] },
66
- { name: "Graphviz DOT", extensions: ["dot", "gv"] },
67
- { name: "SQL schema", extensions: ["sql", "ddl"] },
68
- { name: "PlantUML sequence", extensions: ["puml", "plantuml", "iuml", "wsd"] },
69
- { name: "Excalidraw scene", extensions: ["excalidraw"] },
70
- { name: "All files", extensions: ["*"] },
71
- ];
72
-
73
- /** @param {string} [openFile] */
74
- function createWindow(openFile) {
75
- if (openFile) pendingFile = openFile;
76
-
77
- const win = new BrowserWindow({
78
- width: 1440,
79
- height: 920,
80
- // The layout now collapses the palette and side panel into drawers below
81
- // 900px, so the window no longer has to stay that wide to be usable.
82
- minWidth: 680,
83
- minHeight: 520,
84
- backgroundColor: "#12141a",
85
- autoHideMenuBar: true,
86
- icon: path.join(__dirname, "..", "build", "icon.png"),
87
- webPreferences: {
88
- contextIsolation: true,
89
- nodeIntegration: false,
90
- sandbox: true,
91
- preload: path.join(__dirname, "preload.cjs"),
92
- },
93
- });
94
-
95
- // External links open in the default browser, not in the app.
96
- win.webContents.setWindowOpenHandler(({ url }) => {
97
- void shell.openExternal(url);
98
- return { action: "deny" };
99
- });
100
-
101
- void win.loadFile(path.join(__dirname, "..", "dist", "index.html"));
102
- return win;
103
- }
104
-
105
- /**
106
- * Read a file for the renderer; a failure surfaces as a rejected invoke.
107
- * @param {string} filePath
108
- */
109
- async function readFile(filePath) {
110
- const buffer = await fsp.readFile(filePath);
111
- // A Visio drawing is a zip, and decoding one as UTF-8 destroys it. Anything
112
- // that opens with the zip signature crosses to the renderer as base64
113
- // instead, and only the importers ever look at it.
114
- const zip =
115
- buffer.length > 3 &&
116
- buffer[0] === 0x50 &&
117
- buffer[1] === 0x4b &&
118
- buffer[2] === 0x03 &&
119
- buffer[3] === 0x04;
120
- if (zip) return { path: filePath, content: "", base64: buffer.toString("base64") };
121
- return { path: filePath, content: buffer.toString("utf8") };
122
- }
123
-
124
- /**
125
- * Downloading icons — the shell's one outward call, and the reason it exists
126
- * here rather than in the page.
127
- *
128
- * A browser cannot fetch a vendor's icon pack: the file is a `.zip`, and the
129
- * host does not permit cross-origin reads. The shell is under neither
130
- * restriction, so this is where "paste the link to the Azure pack" actually
131
- * works. That capability is worth fencing:
132
- *
133
- * - https only, and never at the machine or the network it is running on. A
134
- * renderer bug that reached this handler must not be able to use the shell
135
- * as a probe for whatever is on the user's LAN.
136
- * - What comes back is bytes, not trust. The renderer sanitises every SVG
137
- * before it is stored or drawn, exactly as it does for a file from disk.
138
- * - Sizes are capped at every step, because a zip is an invitation to send
139
- * far more than was asked for.
140
- */
141
- const MAX_DOWNLOAD_BYTES = 64_000_000;
142
- const MAX_ICON_BYTES = 512_000;
143
- const MAX_ICONS = 800;
144
- const MAX_LINKS = 200;
145
-
146
- /**
147
- * Whether a hostname points at this machine or the network it sits on.
148
- *
149
- * Not a complete defence — a name that resolves to a private address passes
150
- * this, and only the operating system knows for certain — but it refuses the
151
- * forms anyone would actually reach for.
152
- * @param {string} hostname
153
- */
154
- function reachesLocalNetwork(hostname) {
155
- const host = hostname.toLowerCase().replace(/^\[|\]$/g, "");
156
- if (host.includes(":")) {
157
- // IPv6: loopback, link-local, and the unique-local block.
158
- return host === "::1" || host.startsWith("fe80:") || /^f[cd]/.test(host);
159
- }
160
- return (
161
- host === "localhost" ||
162
- host.endsWith(".localhost") ||
163
- host.endsWith(".local") ||
164
- host.endsWith(".internal") ||
165
- host === "0.0.0.0" ||
166
- /^127\./.test(host) ||
167
- /^10\./.test(host) ||
168
- /^192\.168\./.test(host) ||
169
- /^169\.254\./.test(host) ||
170
- /^172\.(1[6-9]|2\d|3[01])\./.test(host)
171
- );
172
- }
173
-
174
- /**
175
- * Fetch a URL, refusing to hold more than the cap.
176
- *
177
- * Read in chunks rather than in one `arrayBuffer()`: a server that declares
178
- * no length, or lies about it, would otherwise decide how much memory this
179
- * process uses.
180
- * @param {URL} url
181
- * @returns {Promise<Buffer | null>}
182
- */
183
- async function download(url) {
184
- const res = await fetch(url, { redirect: "follow" });
185
- if (!res.ok || !res.body) return null;
186
-
187
- const declared = Number(res.headers.get("content-length"));
188
- if (Number.isFinite(declared) && declared > MAX_DOWNLOAD_BYTES) return null;
189
-
190
- const reader = res.body.getReader();
191
- const chunks = [];
192
- let total = 0;
193
- for (;;) {
194
- const { done, value } = await reader.read();
195
- if (done) break;
196
- total += value.length;
197
- if (total > MAX_DOWNLOAD_BYTES) {
198
- // Stop the transfer rather than draining it politely.
199
- await reader.cancel();
200
- return null;
201
- }
202
- chunks.push(value);
203
- }
204
- return Buffer.concat(chunks);
205
- }
206
-
207
- /**
208
- * A zip begins `PK`; a vendor's pack is one, a single icon is not.
209
- * @param {Buffer} buffer
210
- */
211
- function looksZipped(buffer) {
212
- return buffer.length > 4 && buffer[0] === 0x50 && buffer[1] === 0x4b;
213
- }
214
-
215
- /**
216
- * Every SVG in a zip, keeping the folders it arrived in.
217
- *
218
- * The path is not decoration: the renderer reads the vendor off it, so
219
- * `Azure_Public_Service_Icons/Icons/networking/…` is filed under Azure and
220
- * not into one undifferentiated heap. It reduces the path to a name itself.
221
- * @param {Buffer} buffer
222
- */
223
- function iconsFromZip(buffer) {
224
- let taken = 0;
225
- const files = unzipSync(buffer, {
226
- // Decided before decompression, so an entry that claims to be enormous
227
- // is never expanded.
228
- filter: (file) => {
229
- if (taken >= MAX_ICONS) return false;
230
- if (!file.name.toLowerCase().endsWith(".svg")) return false;
231
- if (file.originalSize > MAX_ICON_BYTES) return false;
232
- taken++;
233
- return true;
234
- },
235
- });
236
- return Object.entries(files).map(([name, bytes]) => ({
237
- name,
238
- svg: Buffer.from(bytes).toString("utf8"),
239
- }));
240
- }
241
-
242
- function registerIpc() {
243
- // The renderer's theme is CSS, which reaches only what the page paints. The
244
- // widgets Chromium draws itself — the option list a <select> pops up, the
245
- // native dialogs, the scrollbars — follow the *app's* theme, and that
246
- // defaults to whatever Windows is set to. A dark Archyne on a light Windows
247
- // therefore opened a white option list. Told here, they match the app.
248
- ipcMain.on("archyne:set-theme", (_event, theme) => {
249
- nativeTheme.themeSource = theme === "light" ? "light" : "dark";
250
- });
251
-
252
- ipcMain.handle("archyne:opened-file", async () => {
253
- if (!pendingFile) return null;
254
- const filePath = pendingFile;
255
- pendingFile = undefined; // hand it over exactly once
256
- return readFile(filePath);
257
- });
258
-
259
- ipcMain.handle("archyne:show-open", async (event, arg) => {
260
- // The sender's window can already be gone if the user closed it mid-call;
261
- // fall back to an app-modal dialog rather than crashing.
262
- const win = BrowserWindow.fromWebContents(event.sender);
263
- // Import offers the foreign formats; Open offers only what Save writes.
264
- const filters = arg && arg.mode === "import" ? IMPORT_FILTERS : FILTERS;
265
- /** @type {import("electron").OpenDialogOptions} */
266
- const options = { properties: ["openFile"], filters };
267
- const { canceled, filePaths } = win
268
- ? await dialog.showOpenDialog(win, options)
269
- : await dialog.showOpenDialog(options);
270
- if (canceled || filePaths.length === 0) return null;
271
- return readFile(filePaths[0]);
272
- });
273
-
274
- ipcMain.handle("archyne:show-save", async (event, { defaultPath, content }) => {
275
- const win = BrowserWindow.fromWebContents(event.sender);
276
- const options = { defaultPath, filters: FILTERS };
277
- const { canceled, filePath } = win
278
- ? await dialog.showSaveDialog(win, options)
279
- : await dialog.showSaveDialog(options);
280
- if (canceled || !filePath) return null;
281
- await fsp.writeFile(filePath, content, "utf8");
282
- return filePath;
283
- });
284
-
285
- // Reading a file the renderer already holds a path for: no dialog, and no
286
- // new capability — the path can only have come from an open or save the
287
- // user went through.
288
- ipcMain.handle("archyne:stat-file", async (_event, { path: filePath }) => {
289
- try {
290
- const stat = await fsp.stat(filePath);
291
- return { mtimeMs: stat.mtimeMs };
292
- } catch {
293
- return null; // moved, deleted, or being written to
294
- }
295
- });
296
-
297
- ipcMain.handle("archyne:read-file", async (_event, { path: filePath }) => {
298
- try {
299
- return await fsp.readFile(filePath, "utf8");
300
- } catch {
301
- return null;
302
- }
303
- });
304
-
305
- ipcMain.handle("archyne:write-file", async (_event, { path: filePath, content }) => {
306
- await fsp.writeFile(filePath, content, "utf8");
307
- });
308
-
309
- // Icons from pasted links: one `.svg`, or a vendor's whole `.zip`. See the
310
- // notes above `MAX_DOWNLOAD_BYTES` for what this is allowed to reach.
311
- ipcMain.handle("archyne:fetch-icons", async (_event, { urls }) => {
312
- const icons = [];
313
- const failed = [];
314
-
315
- for (const link of (Array.isArray(urls) ? urls : []).slice(0, MAX_LINKS)) {
316
- try {
317
- const url = new URL(String(link));
318
- if (url.protocol !== "https:" || reachesLocalNetwork(url.hostname)) {
319
- failed.push(link);
320
- continue;
321
- }
322
-
323
- const body = await download(url);
324
- if (!body) {
325
- failed.push(link);
326
- continue;
327
- }
328
-
329
- const got = looksZipped(body)
330
- ? iconsFromZip(body)
331
- : [{ name: decodeURIComponent(url.pathname), svg: body.toString("utf8") }];
332
- if (got.length === 0) failed.push(link);
333
- else icons.push(...got);
334
- } catch {
335
- // Unreachable, malformed, not a zip after all: the renderer only
336
- // needs to know which links produced nothing.
337
- failed.push(link);
338
- }
339
- if (icons.length >= MAX_ICONS) break;
340
- }
341
-
342
- return { icons: icons.slice(0, MAX_ICONS), failed };
343
- });
344
- }
345
-
346
- const gotLock = app.requestSingleInstanceLock();
347
- if (!gotLock) {
348
- app.quit();
349
- } else {
350
- app.on("second-instance", (_e, argv) => {
351
- const file = fileArg(argv.slice(1));
352
- const [existing] = BrowserWindow.getAllWindows();
353
- if (existing) {
354
- // Reuse the running window rather than stacking another one up.
355
- if (existing.isMinimized()) existing.restore();
356
- existing.focus();
357
- if (file) {
358
- void readFile(file).then((payload) =>
359
- existing.webContents.send("archyne:open-file", payload),
360
- );
361
- }
362
- return;
363
- }
364
- createWindow(file);
365
- });
366
-
367
- void app.whenReady().then(() => {
368
- registerIpc();
369
- createWindow(fileArg(process.argv.slice(1)));
370
- app.on("activate", () => {
371
- if (BrowserWindow.getAllWindows().length === 0) createWindow();
372
- });
373
- });
374
-
375
- app.on("window-all-closed", () => {
376
- if (process.platform !== "darwin") app.quit();
377
- });
378
- }
@@ -1 +0,0 @@
1
- import{U as a,D as n}from"./mermaid.core-cnu9Hu0H.js";const t=(r,o)=>a.lang.round(n.parse(r)[o]);export{t as c};
@@ -1 +0,0 @@
1
- import{s as a,c as s,a as e,C as t}from"./chunk-GF5L2VYU-wHUCmL_g.js";import{_ as i}from"./mermaid.core-cnu9Hu0H.js";import"./index-D2iswyef.js";import"./chunk-5VM5RSS4-Doshgyjn.js";import"./chunk-XXDRQBXY-DTNNhjpS.js";import"./chunk-KBJHAD2P-JqxcXows.js";import"./chunk-2GRJ4B5K-DrxYcIKi.js";var n={parser:e,get db(){return new t},renderer:s,styles:a,init:i(r=>{r.class||(r.class={}),r.class.arrowMarkerAbsolute=r.arrowMarkerAbsolute},"init")};export{n as diagram};
@@ -1 +0,0 @@
1
- import{s as a,c as s,a as e,C as t}from"./chunk-GF5L2VYU-wHUCmL_g.js";import{_ as i}from"./mermaid.core-cnu9Hu0H.js";import"./index-D2iswyef.js";import"./chunk-5VM5RSS4-Doshgyjn.js";import"./chunk-XXDRQBXY-DTNNhjpS.js";import"./chunk-KBJHAD2P-JqxcXows.js";import"./chunk-2GRJ4B5K-DrxYcIKi.js";var n={parser:e,get db(){return new t},renderer:s,styles:a,init:i(r=>{r.class||(r.class={}),r.class.arrowMarkerAbsolute=r.arrowMarkerAbsolute},"init")};export{n as diagram};