@mindexec/cli 0.2.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.
- package/README.md +275 -0
- package/codex-runtime.js +960 -0
- package/launch-bridge.cjs +162 -0
- package/package.json +61 -0
- package/port-guard.cjs +232 -0
- package/scripts/setup-tree-sitter-grammars.mjs +59 -0
- package/server.js +8422 -0
- package/start-bridge.bat +32 -0
- package/start-bridge.sh +81 -0
- package/tree-sitter-grammars/README.md +18 -0
- package/tree-sitter-grammars/tree-sitter-c_sharp.wasm +0 -0
- package/tree-sitter-grammars/tree-sitter-go.wasm +0 -0
- package/tree-sitter-grammars/tree-sitter-java.wasm +0 -0
- package/tree-sitter-grammars/tree-sitter-javascript.wasm +0 -0
- package/tree-sitter-grammars/tree-sitter-python.wasm +0 -0
- package/tree-sitter-grammars/tree-sitter-rust.wasm +0 -0
- package/tree-sitter-grammars/tree-sitter-tsx.wasm +0 -0
- package/tree-sitter-grammars/tree-sitter-typescript.wasm +0 -0
- package/wwwroot/MindExecution.Web.styles.css +3 -0
- package/wwwroot/_content/MindExecution.Plugins.Admin/css/admin-dashboard.css +546 -0
- package/wwwroot/_content/MindExecution.Plugins.Directory/MindExecution.Plugins.Directory.u7utcng611.bundle.scp.css +7 -0
- package/wwwroot/_content/MindExecution.Plugins.Directory/background.png +0 -0
- package/wwwroot/_content/MindExecution.Plugins.Directory/directory-manager.js +202 -0
- package/wwwroot/_content/MindExecution.Plugins.Directory/exampleJsInterop.js +6 -0
- package/wwwroot/_content/MindExecution.Plugins.YouTube/css/youtube-search.css +251 -0
- package/wwwroot/_content/MindExecution.Shared/MindExecution.Shared.wsano1j4wp.bundle.scp.css +4 -0
- package/wwwroot/_content/MindExecution.Shared/css/admin-dashboard.css +559 -0
- package/wwwroot/_content/MindExecution.Shared/css/app.css +1 -0
- package/wwwroot/_content/MindExecution.Shared/css/mind-map-overrides.css +2936 -0
- package/wwwroot/_content/MindExecution.Shared/fonts/NotoSansKR-Bold.ttf +0 -0
- package/wwwroot/_content/MindExecution.Shared/fonts/NotoSansKR-Regular.ttf +0 -0
- package/wwwroot/_content/MindExecution.Shared/js/agent-visualization.js +359 -0
- package/wwwroot/_content/MindExecution.Shared/js/background-themes.js +1721 -0
- package/wwwroot/_content/MindExecution.Shared/js/code-master.js +8316 -0
- package/wwwroot/_content/MindExecution.Shared/js/file-system-helper.js +639 -0
- package/wwwroot/_content/MindExecution.Shared/js/helpers/InfiniteGridHelper.js +109 -0
- package/wwwroot/_content/MindExecution.Shared/js/marked.min.js +69 -0
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-core.js +7982 -0
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-core.js.backup +1059 -0
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-css3d-manager.js +15803 -0
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-dev-guards.js +325 -0
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-dnd.js +1430 -0
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-dnd.js.bak +434 -0
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-glow-shader.js +260 -0
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-interactions.js +7640 -0
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-lod-plan-worker.js +160 -0
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-lod-renderer.js +9923 -0
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-logic-workers.js +977 -0
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-menu-manager.js +1431 -0
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-multi-select.js +1716 -0
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-node-search-worker.js +553 -0
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-nodes.js +4541 -0
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-object-manager.js +489 -0
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-object-manager.js.backup +372 -0
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-pipeline.js +2075 -0
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-text-lod-system.js +646 -0
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-text-overlay-v2.js +4323 -0
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-texture-factory.js +2260 -0
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-texture-factory.js.backup +1258 -0
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-visibility-worker.js +890 -0
- package/wwwroot/_content/MindExecution.Shared/js/mindmap-toolbar.js +594 -0
- package/wwwroot/_content/MindExecution.Shared/js/native-drop-handler.js +170 -0
- package/wwwroot/_content/MindExecution.Shared/js/plan-master.js +788 -0
- package/wwwroot/_content/MindExecution.Shared/js/renderers/CSS3DRenderer.js +50 -0
- package/wwwroot/_content/MindExecution.Shared/js/texture-worker-manager.js +188 -0
- package/wwwroot/_content/MindExecution.Shared/js/texture-worker.js +208 -0
- package/wwwroot/_content/MindExecution.Shared/js/three.min.js +6 -0
- package/wwwroot/_content/MindExecution.Shared/js/titlebar-handler.js +191 -0
- package/wwwroot/_content/MindExecution.Shared/js/token-manager.js +37 -0
- package/wwwroot/_content/MindExecution.Shared/js/token-worker.js +28 -0
- package/wwwroot/_content/MindExecution.Shared/js/troika-bundle.js +5626 -0
- package/wwwroot/_content/MindExecution.Shared/js/troika-bundle.js.map +7 -0
- package/wwwroot/_content/MindExecution.Shared/lib/font-awesome/css/all.min.css +9 -0
- package/wwwroot/_content/MindExecution.Shared/lib/font-awesome/webfonts/fa-brands-400.ttf +0 -0
- package/wwwroot/_content/MindExecution.Shared/lib/font-awesome/webfonts/fa-brands-400.woff2 +0 -0
- package/wwwroot/_content/MindExecution.Shared/lib/font-awesome/webfonts/fa-regular-400.ttf +0 -0
- package/wwwroot/_content/MindExecution.Shared/lib/font-awesome/webfonts/fa-regular-400.woff2 +0 -0
- package/wwwroot/_content/MindExecution.Shared/lib/font-awesome/webfonts/fa-solid-900.ttf +0 -0
- package/wwwroot/_content/MindExecution.Shared/lib/font-awesome/webfonts/fa-solid-900.woff2 +0 -0
- package/wwwroot/_content/MindExecution.Shared/models/all-MiniLM-L6-v2-quantized.onnx +0 -0
- package/wwwroot/_content/MindExecution.Shared/models/vocab.txt +30522 -0
- package/wwwroot/_framework/Google.Protobuf.9h59ukbel7.dll +0 -0
- package/wwwroot/_framework/Markdig.d1j7v41cl1.dll +0 -0
- package/wwwroot/_framework/MessagePack.Annotations.l6qv48kgpt.dll +0 -0
- package/wwwroot/_framework/MessagePack.eqoptzx9d5.dll +0 -0
- package/wwwroot/_framework/Microsoft.AspNetCore.Authorization.k7dsih5y5g.dll +0 -0
- package/wwwroot/_framework/Microsoft.AspNetCore.Components.6nyje9sa0g.dll +0 -0
- package/wwwroot/_framework/Microsoft.AspNetCore.Components.Authorization.iycd6unprw.dll +0 -0
- package/wwwroot/_framework/Microsoft.AspNetCore.Components.Web.487u3twia4.dll +0 -0
- package/wwwroot/_framework/Microsoft.AspNetCore.Components.WebAssembly.d0gcnmlxxz.dll +0 -0
- package/wwwroot/_framework/Microsoft.AspNetCore.Metadata.h4yevl9adi.dll +0 -0
- package/wwwroot/_framework/Microsoft.CSharp.qrvp77qmhs.dll +0 -0
- package/wwwroot/_framework/Microsoft.Data.Sqlite.jdlxgv2jtg.dll +0 -0
- package/wwwroot/_framework/Microsoft.EntityFrameworkCore.4gjazp7kjf.dll +0 -0
- package/wwwroot/_framework/Microsoft.EntityFrameworkCore.Abstractions.gocudnvz7b.dll +0 -0
- package/wwwroot/_framework/Microsoft.EntityFrameworkCore.Relational.lt4rsvinuo.dll +0 -0
- package/wwwroot/_framework/Microsoft.EntityFrameworkCore.Sqlite.69luj0fa9r.dll +0 -0
- package/wwwroot/_framework/Microsoft.Extensions.Caching.Abstractions.364t4jh3zz.dll +0 -0
- package/wwwroot/_framework/Microsoft.Extensions.Caching.Memory.izlxhpzosu.dll +0 -0
- package/wwwroot/_framework/Microsoft.Extensions.Configuration.8zq7hh41o7.dll +0 -0
- package/wwwroot/_framework/Microsoft.Extensions.Configuration.Abstractions.8if74zs6ea.dll +0 -0
- package/wwwroot/_framework/Microsoft.Extensions.Configuration.Json.duvlngw8i0.dll +0 -0
- package/wwwroot/_framework/Microsoft.Extensions.DependencyInjection.Abstractions.t2hh9kvx0o.dll +0 -0
- package/wwwroot/_framework/Microsoft.Extensions.DependencyInjection.n4tg99oy8l.dll +0 -0
- package/wwwroot/_framework/Microsoft.Extensions.DependencyModel.h0d06ixk3e.dll +0 -0
- package/wwwroot/_framework/Microsoft.Extensions.Logging.Abstractions.rl32bkx2sd.dll +0 -0
- package/wwwroot/_framework/Microsoft.Extensions.Logging.dlht1xei0t.dll +0 -0
- package/wwwroot/_framework/Microsoft.Extensions.Options.qeunebioml.dll +0 -0
- package/wwwroot/_framework/Microsoft.Extensions.Primitives.18cr6vnuuz.dll +0 -0
- package/wwwroot/_framework/Microsoft.IO.RecyclableMemoryStream.r915vovvw4.dll +0 -0
- package/wwwroot/_framework/Microsoft.IdentityModel.Abstractions.1ejljk3erv.dll +0 -0
- package/wwwroot/_framework/Microsoft.IdentityModel.JsonWebTokens.1596zr8gne.dll +0 -0
- package/wwwroot/_framework/Microsoft.IdentityModel.Logging.229uyvpgio.dll +0 -0
- package/wwwroot/_framework/Microsoft.IdentityModel.Tokens.9sibtajc9f.dll +0 -0
- package/wwwroot/_framework/Microsoft.JSInterop.17lq4j1j7g.dll +0 -0
- package/wwwroot/_framework/Microsoft.JSInterop.WebAssembly.ryia5gxiad.dll +0 -0
- package/wwwroot/_framework/Microsoft.ML.OnnxRuntime.w9deo1m5ss.dll +0 -0
- package/wwwroot/_framework/Microsoft.ML.Tokenizers.cm2vuv2z61.dll +0 -0
- package/wwwroot/_framework/Microsoft.NET.StringTools.3qbrf4v2ki.dll +0 -0
- package/wwwroot/_framework/MimeMapping.og9ys58ylm.dll +0 -0
- package/wwwroot/_framework/MindExecution.Core.1q1trifbuu.dll +0 -0
- package/wwwroot/_framework/MindExecution.Kernel.gwwc40sc45.dll +0 -0
- package/wwwroot/_framework/MindExecution.Plugins.Admin.0jgrn1sckv.dll +0 -0
- package/wwwroot/_framework/MindExecution.Plugins.Business.13mme2qcag.dll +0 -0
- package/wwwroot/_framework/MindExecution.Plugins.Concept.dfp2mdt45q.dll +0 -0
- package/wwwroot/_framework/MindExecution.Plugins.Directory.3w4t6n3se0.dll +0 -0
- package/wwwroot/_framework/MindExecution.Plugins.PlanMaster.s0qpntz420.dll +0 -0
- package/wwwroot/_framework/MindExecution.Plugins.YouTube.iu11fq8d16.dll +0 -0
- package/wwwroot/_framework/MindExecution.Shared.7j27dcqnrc.dll +0 -0
- package/wwwroot/_framework/MindExecution.Web.pq1ty8ov2v.dll +0 -0
- package/wwwroot/_framework/Newtonsoft.Json.a56zs13vug.dll +0 -0
- package/wwwroot/_framework/SQLitePCLRaw.batteries_v2.rrd1nzawpp.dll +0 -0
- package/wwwroot/_framework/SQLitePCLRaw.core.1dxloztpfz.dll +0 -0
- package/wwwroot/_framework/SQLitePCLRaw.provider.e_sqlite3.oekyzl53i1.dll +0 -0
- package/wwwroot/_framework/Supabase.Core.s1pkj4aj0l.dll +0 -0
- package/wwwroot/_framework/Supabase.Functions.qz4nu782sg.dll +0 -0
- package/wwwroot/_framework/Supabase.Gotrue.twah27pkik.dll +0 -0
- package/wwwroot/_framework/Supabase.Postgrest.gmuuv369ih.dll +0 -0
- package/wwwroot/_framework/Supabase.Realtime.ox3kchdy3w.dll +0 -0
- package/wwwroot/_framework/Supabase.Storage.fnjnepaowr.dll +0 -0
- package/wwwroot/_framework/Supabase.azmaw5pgcz.dll +0 -0
- package/wwwroot/_framework/System.Collections.Concurrent.y1zmvuyipi.dll +0 -0
- package/wwwroot/_framework/System.Collections.Immutable.ug3j698qms.dll +0 -0
- package/wwwroot/_framework/System.Collections.NonGeneric.h66hj3863h.dll +0 -0
- package/wwwroot/_framework/System.Collections.Specialized.umr3y27ntj.dll +0 -0
- package/wwwroot/_framework/System.Collections.x53e19vfsj.dll +0 -0
- package/wwwroot/_framework/System.ComponentModel.Annotations.tz6gnt4ebt.dll +0 -0
- package/wwwroot/_framework/System.ComponentModel.Primitives.j7tiphu4rg.dll +0 -0
- package/wwwroot/_framework/System.ComponentModel.TypeConverter.ujlztox1gx.dll +0 -0
- package/wwwroot/_framework/System.ComponentModel.x9xz0ojfb6.dll +0 -0
- package/wwwroot/_framework/System.Console.ijzpqmj7ne.dll +0 -0
- package/wwwroot/_framework/System.Data.Common.1r0sqffq1p.dll +0 -0
- package/wwwroot/_framework/System.Diagnostics.DiagnosticSource.9upoqwq09o.dll +0 -0
- package/wwwroot/_framework/System.Diagnostics.Process.m99azzntjm.dll +0 -0
- package/wwwroot/_framework/System.Diagnostics.TraceSource.pl7wv26myr.dll +0 -0
- package/wwwroot/_framework/System.Diagnostics.Tracing.crlhfx6tut.dll +0 -0
- package/wwwroot/_framework/System.Drawing.Primitives.22e4y9ikq9.dll +0 -0
- package/wwwroot/_framework/System.Drawing.mi7d8hwowb.dll +0 -0
- package/wwwroot/_framework/System.Formats.Asn1.jx23sjiqnn.dll +0 -0
- package/wwwroot/_framework/System.IO.Compression.6fyoii3uej.dll +0 -0
- package/wwwroot/_framework/System.IO.Pipelines.vg77t4cd4d.dll +0 -0
- package/wwwroot/_framework/System.IdentityModel.Tokens.Jwt.t67es60z5b.dll +0 -0
- package/wwwroot/_framework/System.Linq.1bkoxlqgmq.dll +0 -0
- package/wwwroot/_framework/System.Linq.Expressions.24xqiypwdt.dll +0 -0
- package/wwwroot/_framework/System.Linq.Queryable.hvd01d6rsa.dll +0 -0
- package/wwwroot/_framework/System.Memory.8dx3lwgym4.dll +0 -0
- package/wwwroot/_framework/System.Net.Http.Json.3mhdm9l1rf.dll +0 -0
- package/wwwroot/_framework/System.Net.Http.eitrz660my.dll +0 -0
- package/wwwroot/_framework/System.Net.NetworkInformation.3pkuofcv9r.dll +0 -0
- package/wwwroot/_framework/System.Net.Ping.8clj5pklrp.dll +0 -0
- package/wwwroot/_framework/System.Net.Primitives.qrp4wcjz1p.dll +0 -0
- package/wwwroot/_framework/System.Net.WebSockets.Client.2u6pv01g69.dll +0 -0
- package/wwwroot/_framework/System.Net.WebSockets.qp6u31zvm5.dll +0 -0
- package/wwwroot/_framework/System.Numerics.Tensors.0c7z4mt3on.dll +0 -0
- package/wwwroot/_framework/System.Numerics.Vectors.kc7ufp2j4l.dll +0 -0
- package/wwwroot/_framework/System.ObjectModel.qv82fot1ib.dll +0 -0
- package/wwwroot/_framework/System.Private.CoreLib.rkafq04oma.dll +0 -0
- package/wwwroot/_framework/System.Private.Uri.t9542hmr6j.dll +0 -0
- package/wwwroot/_framework/System.Private.Xml.Linq.n8n3ptrbwu.dll +0 -0
- package/wwwroot/_framework/System.Private.Xml.rxd3tytisn.dll +0 -0
- package/wwwroot/_framework/System.Reactive.t3fuon548l.dll +0 -0
- package/wwwroot/_framework/System.Reflection.Emit.9tjhp6y0j3.dll +0 -0
- package/wwwroot/_framework/System.Reflection.Emit.ILGeneration.stxyk8zoo1.dll +0 -0
- package/wwwroot/_framework/System.Reflection.Emit.Lightweight.6xrd5v8vg0.dll +0 -0
- package/wwwroot/_framework/System.Reflection.Primitives.wgn8fpwwvv.dll +0 -0
- package/wwwroot/_framework/System.Runtime.InteropServices.JavaScript.sliym526xh.dll +0 -0
- package/wwwroot/_framework/System.Runtime.InteropServices.RuntimeInformation.oji7zut14z.dll +0 -0
- package/wwwroot/_framework/System.Runtime.InteropServices.te07xr2we9.dll +0 -0
- package/wwwroot/_framework/System.Runtime.Intrinsics.507y4h8nzq.dll +0 -0
- package/wwwroot/_framework/System.Runtime.Loader.v7gk4bse0k.dll +0 -0
- package/wwwroot/_framework/System.Runtime.Numerics.eqy5xjv3nd.dll +0 -0
- package/wwwroot/_framework/System.Runtime.Serialization.Formatters.zpkrub8lab.dll +0 -0
- package/wwwroot/_framework/System.Runtime.Serialization.Primitives.vhkpnbxjip.dll +0 -0
- package/wwwroot/_framework/System.Runtime.jn319d5nyg.dll +0 -0
- package/wwwroot/_framework/System.Security.Claims.0ztig1q9vo.dll +0 -0
- package/wwwroot/_framework/System.Security.Cryptography.vttizqc9ho.dll +0 -0
- package/wwwroot/_framework/System.Text.Encoding.Extensions.utdd47ny8f.dll +0 -0
- package/wwwroot/_framework/System.Text.Encodings.Web.wah8r1zoe0.dll +0 -0
- package/wwwroot/_framework/System.Text.Json.kxlfxj0wrs.dll +0 -0
- package/wwwroot/_framework/System.Text.RegularExpressions.dbqn58klox.dll +0 -0
- package/wwwroot/_framework/System.Threading.42ao9vi047.dll +0 -0
- package/wwwroot/_framework/System.Threading.Channels.hfa7j0uv2w.dll +0 -0
- package/wwwroot/_framework/System.Threading.Thread.caul0pdqul.dll +0 -0
- package/wwwroot/_framework/System.Transactions.Local.fimi2hamzo.dll +0 -0
- package/wwwroot/_framework/System.Web.HttpUtility.gq8yz50p2e.dll +0 -0
- package/wwwroot/_framework/System.Xml.Linq.kitin4zjoj.dll +0 -0
- package/wwwroot/_framework/System.Xml.ReaderWriter.kzvw3qgxb0.dll +0 -0
- package/wwwroot/_framework/System.Xml.XDocument.c539ki6cuq.dll +0 -0
- package/wwwroot/_framework/System.m05i39uvk9.dll +0 -0
- package/wwwroot/_framework/Websocket.Client.vapounvmnl.dll +0 -0
- package/wwwroot/_framework/blazor.boot.json +305 -0
- package/wwwroot/_framework/blazor.webassembly.js +1 -0
- package/wwwroot/_framework/dotnet.js +4 -0
- package/wwwroot/_framework/dotnet.native.vz0adxojrz.wasm +0 -0
- package/wwwroot/_framework/dotnet.native.xsn1d6x2kd.js +16 -0
- package/wwwroot/_framework/dotnet.runtime.dstopyvqzi.js +4 -0
- package/wwwroot/_framework/icudt_CJK.tjcz0u77k5.dat +0 -0
- package/wwwroot/_framework/icudt_EFIGS.tptq2av103.dat +0 -0
- package/wwwroot/_framework/icudt_no_CJK.lfu7j35m59.dat +0 -0
- package/wwwroot/_framework/netstandard.0xet7jg7ky.dll +0 -0
- package/wwwroot/_headers +40 -0
- package/wwwroot/_redirects +1 -0
- package/wwwroot/appsettings.json +71 -0
- package/wwwroot/icon-192.png +0 -0
- package/wwwroot/icon-512.png +0 -0
- package/wwwroot/index.html +710 -0
- package/wwwroot/js/marketing-tool.js +180 -0
- package/wwwroot/manifest.webmanifest +22 -0
- package/wwwroot/robots.txt +4 -0
- package/wwwroot/service-worker-assets.js +857 -0
- package/wwwroot/service-worker.js +33 -0
- package/wwwroot/sitemap.xml +27 -0
|
@@ -0,0 +1,639 @@
|
|
|
1
|
+
window.fileSystemHelper = {
|
|
2
|
+
cachedFileHandle: null,
|
|
3
|
+
|
|
4
|
+
// ▼▼▼ OPFS Helpers ▼▼▼
|
|
5
|
+
_getOpfsRoot: async () => {
|
|
6
|
+
return await navigator.storage.getDirectory();
|
|
7
|
+
},
|
|
8
|
+
|
|
9
|
+
isOpfsAvailable: async () => {
|
|
10
|
+
try {
|
|
11
|
+
return !!(navigator.storage && navigator.storage.getDirectory && await navigator.storage.getDirectory());
|
|
12
|
+
} catch {
|
|
13
|
+
return false;
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
|
|
17
|
+
saveToOpfs: async (filePath, dataContent) => {
|
|
18
|
+
try {
|
|
19
|
+
const root = await window.fileSystemHelper._getOpfsRoot();
|
|
20
|
+
const parts = filePath.split('/');
|
|
21
|
+
const fileName = parts.pop();
|
|
22
|
+
let currentDir = root;
|
|
23
|
+
|
|
24
|
+
for (const part of parts) {
|
|
25
|
+
currentDir = await currentDir.getDirectoryHandle(part, { create: true });
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const fileHandle = await currentDir.getFileHandle(fileName, { create: true });
|
|
29
|
+
const writable = await fileHandle.createWritable();
|
|
30
|
+
await writable.write(dataContent);
|
|
31
|
+
await writable.close();
|
|
32
|
+
return true;
|
|
33
|
+
} catch (err) {
|
|
34
|
+
console.error(`[OPFS] Text Save Failed (${filePath}):`, err);
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
|
|
39
|
+
loadFromOpfs: async (filePath) => {
|
|
40
|
+
try {
|
|
41
|
+
const root = await window.fileSystemHelper._getOpfsRoot();
|
|
42
|
+
const parts = filePath.split('/');
|
|
43
|
+
const fileName = parts.pop();
|
|
44
|
+
let currentDir = root;
|
|
45
|
+
|
|
46
|
+
for (const part of parts) {
|
|
47
|
+
currentDir = await currentDir.getDirectoryHandle(part);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const fileHandle = await currentDir.getFileHandle(fileName);
|
|
51
|
+
const file = await fileHandle.getFile();
|
|
52
|
+
const buffer = await file.arrayBuffer();
|
|
53
|
+
return new Uint8Array(buffer);
|
|
54
|
+
} catch (err) {
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
|
|
59
|
+
loadAssetAsBlobUrl: async (filePath) => {
|
|
60
|
+
try {
|
|
61
|
+
const root = await window.fileSystemHelper._getOpfsRoot();
|
|
62
|
+
const parts = filePath.split('/');
|
|
63
|
+
const fileName = parts.pop();
|
|
64
|
+
let currentDir = root;
|
|
65
|
+
|
|
66
|
+
for (const part of parts) {
|
|
67
|
+
currentDir = await currentDir.getDirectoryHandle(part);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const fileHandle = await currentDir.getFileHandle(fileName);
|
|
71
|
+
const file = await fileHandle.getFile();
|
|
72
|
+
return URL.createObjectURL(file);
|
|
73
|
+
} catch (err) {
|
|
74
|
+
console.warn(`[OPFS] Asset not found: ${filePath}`);
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
},
|
|
78
|
+
|
|
79
|
+
existsInOpfs: async (filePath) => {
|
|
80
|
+
try {
|
|
81
|
+
const root = await window.fileSystemHelper._getOpfsRoot();
|
|
82
|
+
const parts = filePath.split('/');
|
|
83
|
+
const fileName = parts.pop();
|
|
84
|
+
let currentDir = root;
|
|
85
|
+
|
|
86
|
+
for (const part of parts) {
|
|
87
|
+
currentDir = await currentDir.getDirectoryHandle(part);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
await currentDir.getFileHandle(fileName);
|
|
91
|
+
return true;
|
|
92
|
+
} catch {
|
|
93
|
+
return false;
|
|
94
|
+
}
|
|
95
|
+
},
|
|
96
|
+
|
|
97
|
+
listOpfsDirectory: async (dirPath) => {
|
|
98
|
+
try {
|
|
99
|
+
const root = await window.fileSystemHelper._getOpfsRoot();
|
|
100
|
+
const parts = (dirPath || '').split('/').filter(Boolean);
|
|
101
|
+
let currentDir = root;
|
|
102
|
+
|
|
103
|
+
for (const part of parts) {
|
|
104
|
+
currentDir = await currentDir.getDirectoryHandle(part);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const entries = [];
|
|
108
|
+
for await (const [name, handle] of currentDir.entries()) {
|
|
109
|
+
let modified = null;
|
|
110
|
+
if (handle.kind === 'file') {
|
|
111
|
+
try {
|
|
112
|
+
const file = await handle.getFile();
|
|
113
|
+
modified = new Date(file.lastModified).toISOString();
|
|
114
|
+
} catch {
|
|
115
|
+
modified = null;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
entries.push({ name, kind: handle.kind, modified });
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
return entries;
|
|
123
|
+
} catch {
|
|
124
|
+
return [];
|
|
125
|
+
}
|
|
126
|
+
},
|
|
127
|
+
|
|
128
|
+
deleteFromOpfs: async (filePath) => {
|
|
129
|
+
try {
|
|
130
|
+
const root = await window.fileSystemHelper._getOpfsRoot();
|
|
131
|
+
const parts = filePath.split('/');
|
|
132
|
+
const fileName = parts.pop();
|
|
133
|
+
let currentDir = root;
|
|
134
|
+
|
|
135
|
+
for (const part of parts) {
|
|
136
|
+
currentDir = await currentDir.getDirectoryHandle(part);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
await currentDir.removeEntry(fileName);
|
|
140
|
+
return true;
|
|
141
|
+
} catch {
|
|
142
|
+
return false;
|
|
143
|
+
}
|
|
144
|
+
},
|
|
145
|
+
|
|
146
|
+
saveAssetFromUrlToOpfs: async (blobUrl, filePath) => {
|
|
147
|
+
try {
|
|
148
|
+
const response = await fetch(blobUrl);
|
|
149
|
+
const blob = await response.blob();
|
|
150
|
+
|
|
151
|
+
const root = await window.fileSystemHelper._getOpfsRoot();
|
|
152
|
+
const parts = filePath.split('/');
|
|
153
|
+
const fileName = parts.pop();
|
|
154
|
+
let currentDir = root;
|
|
155
|
+
|
|
156
|
+
for (const part of parts) {
|
|
157
|
+
currentDir = await currentDir.getDirectoryHandle(part, { create: true });
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
const fileHandle = await currentDir.getFileHandle(fileName, { create: true });
|
|
161
|
+
const writable = await fileHandle.createWritable();
|
|
162
|
+
await writable.write(blob);
|
|
163
|
+
await writable.close();
|
|
164
|
+
return true;
|
|
165
|
+
} catch (err) {
|
|
166
|
+
console.error('[OPFS] Asset Save Failed:', err);
|
|
167
|
+
return false;
|
|
168
|
+
}
|
|
169
|
+
},
|
|
170
|
+
|
|
171
|
+
resetOpfs: async () => {
|
|
172
|
+
try {
|
|
173
|
+
const root = await navigator.storage.getDirectory();
|
|
174
|
+
for await (const name of root.keys()) {
|
|
175
|
+
await root.removeEntry(name, { recursive: true });
|
|
176
|
+
}
|
|
177
|
+
console.log('[OPFS] All data wiped.');
|
|
178
|
+
} catch (err) {
|
|
179
|
+
console.error('[OPFS] Reset failed:', err);
|
|
180
|
+
}
|
|
181
|
+
},
|
|
182
|
+
// ▲▲▲ OPFS Helpers ▲▲▲
|
|
183
|
+
|
|
184
|
+
// ▼▼▼ [NEW] VFS <-> IndexedDB sync utilities ▼▼▼
|
|
185
|
+
_dbPromise: null,
|
|
186
|
+
_getDb: function () {
|
|
187
|
+
if (!this._dbPromise) {
|
|
188
|
+
this._dbPromise = new Promise((resolve, reject) => {
|
|
189
|
+
const request = indexedDB.open('MindMapVFS', 1);
|
|
190
|
+
request.onupgradeneeded = (e) => {
|
|
191
|
+
const db = e.target.result;
|
|
192
|
+
if (!db.objectStoreNames.contains('files')) {
|
|
193
|
+
db.createObjectStore('files');
|
|
194
|
+
}
|
|
195
|
+
};
|
|
196
|
+
request.onsuccess = (e) => resolve(e.target.result);
|
|
197
|
+
request.onerror = (e) => reject(e.target.error);
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
return this._dbPromise;
|
|
201
|
+
},
|
|
202
|
+
|
|
203
|
+
saveToIndexedDB: async (filePath, dataBytes) => {
|
|
204
|
+
try {
|
|
205
|
+
const db = await window.fileSystemHelper._getDb();
|
|
206
|
+
|
|
207
|
+
return new Promise((resolve, reject) => {
|
|
208
|
+
const tx = db.transaction('files', 'readwrite');
|
|
209
|
+
tx.objectStore('files').put(dataBytes, filePath);
|
|
210
|
+
tx.oncomplete = () => resolve(true);
|
|
211
|
+
tx.onerror = () => reject(tx.error);
|
|
212
|
+
});
|
|
213
|
+
} catch (err) {
|
|
214
|
+
console.error('[VFS] Save to IndexedDB failed:', err);
|
|
215
|
+
return false;
|
|
216
|
+
}
|
|
217
|
+
},
|
|
218
|
+
|
|
219
|
+
loadFromIndexedDB: async (filePath) => {
|
|
220
|
+
try {
|
|
221
|
+
const db = await window.fileSystemHelper._getDb();
|
|
222
|
+
return new Promise((resolve, reject) => {
|
|
223
|
+
const tx = db.transaction('files', 'readonly');
|
|
224
|
+
const store = tx.objectStore('files');
|
|
225
|
+
const request = store.get(filePath);
|
|
226
|
+
request.onsuccess = () => resolve(request.result || null);
|
|
227
|
+
request.onerror = () => reject(request.error);
|
|
228
|
+
});
|
|
229
|
+
} catch (err) {
|
|
230
|
+
console.error('[VFS] Load from IndexedDB failed:', err);
|
|
231
|
+
return null;
|
|
232
|
+
}
|
|
233
|
+
},
|
|
234
|
+
|
|
235
|
+
existsInIndexedDB: async (filePath) => {
|
|
236
|
+
try {
|
|
237
|
+
const db = await window.fileSystemHelper._getDb();
|
|
238
|
+
return new Promise((resolve) => {
|
|
239
|
+
const tx = db.transaction('files', 'readonly');
|
|
240
|
+
const store = tx.objectStore('files');
|
|
241
|
+
const request = store.count(filePath);
|
|
242
|
+
request.onsuccess = () => resolve(request.result > 0);
|
|
243
|
+
request.onerror = () => resolve(false);
|
|
244
|
+
});
|
|
245
|
+
} catch {
|
|
246
|
+
return false;
|
|
247
|
+
}
|
|
248
|
+
},
|
|
249
|
+
// ▲▲▲ [NEW] ▲▲▲
|
|
250
|
+
|
|
251
|
+
// ▼▼▼ [NEW] Save binary data to local disk ▼▼▼
|
|
252
|
+
saveDataToLocalDisk: async (dataBytes, fileName) => {
|
|
253
|
+
try {
|
|
254
|
+
// Without a cachedFileHandle (i.e., not from an explicit user gesture), we cannot prompt.
|
|
255
|
+
// For auto-save scenarios, it's correct to just skip disk writes.
|
|
256
|
+
if (!window.fileSystemHelper.cachedFileHandle) {
|
|
257
|
+
console.log("[FileSystemHelper] No cached handle for auto-export. Skipping disk write.");
|
|
258
|
+
return;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
// 1. Convert to Uint8Array (Blazor may marshal byte[] as base64 or an array; verify if needed)
|
|
262
|
+
// Usually, Blazor JS interop marshals byte[] into a Uint8Array.
|
|
263
|
+
|
|
264
|
+
const writable = await window.fileSystemHelper.cachedFileHandle.createWritable();
|
|
265
|
+
await writable.write(dataBytes);
|
|
266
|
+
await writable.close();
|
|
267
|
+
|
|
268
|
+
console.log("[FileSystemHelper] Database saved to local disk.");
|
|
269
|
+
} catch (err) {
|
|
270
|
+
console.warn("[FileSystemHelper] Disk export failed:", err);
|
|
271
|
+
}
|
|
272
|
+
},
|
|
273
|
+
// ▲▲▲ [NEW] ▲▲▲
|
|
274
|
+
|
|
275
|
+
// 1. Save the DB from OPFS to local disk (no longer used; kept for compatibility)
|
|
276
|
+
exportOpfsDatabase: async (dbName) => {
|
|
277
|
+
try {
|
|
278
|
+
// A. Read DB file from OPFS
|
|
279
|
+
const opfsRoot = await navigator.storage.getDirectory();
|
|
280
|
+
const fileHandle = await opfsRoot.getFileHandle(dbName);
|
|
281
|
+
const file = await fileHandle.getFile();
|
|
282
|
+
|
|
283
|
+
// B. Choose save location (File System Access API)
|
|
284
|
+
// If there is no cached handle, prompt the user.
|
|
285
|
+
if (!window.fileSystemHelper.cachedFileHandle) {
|
|
286
|
+
window.fileSystemHelper.cachedFileHandle = await window.showSaveFilePicker({
|
|
287
|
+
suggestedName: dbName,
|
|
288
|
+
types: [{
|
|
289
|
+
description: 'SQLite Database',
|
|
290
|
+
accept: { 'application/vnd.sqlite3': ['.db'] },
|
|
291
|
+
}],
|
|
292
|
+
});
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
// C. Write
|
|
296
|
+
const writable = await window.fileSystemHelper.cachedFileHandle.createWritable();
|
|
297
|
+
await writable.write(file);
|
|
298
|
+
await writable.close();
|
|
299
|
+
|
|
300
|
+
console.log("DB Saved to local disk successfully.");
|
|
301
|
+
} catch (err) {
|
|
302
|
+
console.error("Export failed:", err);
|
|
303
|
+
// On failure (e.g., permission denied), reset the cached handle
|
|
304
|
+
window.fileSystemHelper.cachedFileHandle = null;
|
|
305
|
+
}
|
|
306
|
+
},
|
|
307
|
+
|
|
308
|
+
// 2. Copy a local DB into OPFS (import)
|
|
309
|
+
importDatabaseToOpfs: async (dbName) => {
|
|
310
|
+
try {
|
|
311
|
+
// A. Open file
|
|
312
|
+
const [handle] = await window.showOpenFilePicker({
|
|
313
|
+
types: [{
|
|
314
|
+
description: 'SQLite Database',
|
|
315
|
+
accept: { 'application/vnd.sqlite3': ['.db'] },
|
|
316
|
+
}],
|
|
317
|
+
multiple: false
|
|
318
|
+
});
|
|
319
|
+
const file = await handle.getFile();
|
|
320
|
+
|
|
321
|
+
// B. Write into OPFS
|
|
322
|
+
const opfsRoot = await navigator.storage.getDirectory();
|
|
323
|
+
const fileHandle = await opfsRoot.getFileHandle(dbName, { create: true });
|
|
324
|
+
const writable = await fileHandle.createWritable();
|
|
325
|
+
await writable.write(file);
|
|
326
|
+
await writable.close();
|
|
327
|
+
|
|
328
|
+
console.log("DB Imported to OPFS.");
|
|
329
|
+
return true;
|
|
330
|
+
} catch (err) {
|
|
331
|
+
console.error("Import failed:", err);
|
|
332
|
+
return false;
|
|
333
|
+
}
|
|
334
|
+
},
|
|
335
|
+
|
|
336
|
+
// ▼▼▼ [UPDATED] Optimized large-file handling (use Response streams) ▼▼▼
|
|
337
|
+
createBlobUrlFromStream: async (streamRef, mimeType) => {
|
|
338
|
+
const debugTracing = Boolean(window.MindMapDebugEnabled);
|
|
339
|
+
if (debugTracing) {
|
|
340
|
+
console.debug('[FileSystemHelper] createBlobUrlFromStream start', { mimeType });
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
try {
|
|
344
|
+
// 1. Convert DotNetStreamReference into a Response object (memory-efficient)
|
|
345
|
+
const response = await streamRef.stream();
|
|
346
|
+
|
|
347
|
+
// 2. Create a Blob from the stream
|
|
348
|
+
const blob = await new Response(response).blob();
|
|
349
|
+
if (debugTracing) {
|
|
350
|
+
console.debug('[FileSystemHelper] stream converted to blob', { size: blob.size, type: blob.type });
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
// 3. Set MIME type: new Blob([blob]) may copy data; using slice only changes type and
|
|
354
|
+
// reduces memory pressure / failure risk.
|
|
355
|
+
const targetType = mimeType || blob.type || 'application/octet-stream';
|
|
356
|
+
const typedBlob = (blob.type === targetType) ? blob : blob.slice(0, blob.size, targetType);
|
|
357
|
+
const blobUrl = URL.createObjectURL(typedBlob);
|
|
358
|
+
|
|
359
|
+
if (debugTracing) {
|
|
360
|
+
console.debug('[FileSystemHelper] Blob URL created', { mimeType: targetType, blobSize: typedBlob.size });
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
return blobUrl;
|
|
364
|
+
} catch (err) {
|
|
365
|
+
console.error('[FileSystemHelper] Failed to create blob from stream:', err);
|
|
366
|
+
if (debugTracing) {
|
|
367
|
+
console.error('[FileSystemHelper] createBlobUrlFromStream error context', { mimeType });
|
|
368
|
+
}
|
|
369
|
+
return null;
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
,
|
|
373
|
+
|
|
374
|
+
// Fallback: C# byte[] -> Blob URL
|
|
375
|
+
createBlobUrlFromBytes: (dataBytes, mimeType) => {
|
|
376
|
+
const debugTracing = Boolean(window.MindMapDebugEnabled);
|
|
377
|
+
try {
|
|
378
|
+
const targetType = mimeType || 'application/octet-stream';
|
|
379
|
+
const bytes = (dataBytes instanceof Uint8Array) ? dataBytes : new Uint8Array(dataBytes);
|
|
380
|
+
if (debugTracing) {
|
|
381
|
+
console.debug('[FileSystemHelper] createBlobUrlFromBytes', { mimeType: targetType, size: bytes.byteLength });
|
|
382
|
+
}
|
|
383
|
+
const blob = new Blob([bytes], { type: targetType });
|
|
384
|
+
return URL.createObjectURL(blob);
|
|
385
|
+
} catch (err) {
|
|
386
|
+
console.error('[FileSystemHelper] Failed to create blob from bytes:', err);
|
|
387
|
+
return null;
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
// ▲▲▲ [UPDATED] ▲▲▲
|
|
391
|
+
};
|
|
392
|
+
|
|
393
|
+
(function () {
|
|
394
|
+
const DB_NAME = 'MindMapDB';
|
|
395
|
+
const STORE_NAME = 'handles';
|
|
396
|
+
const LOCAL_FILE_KEY_PREFIX = 'local-file:';
|
|
397
|
+
const LOCAL_FILE_URI_PREFIX = 'mindexec-local-file://';
|
|
398
|
+
const sessionEntries = new Map();
|
|
399
|
+
const objectUrls = new Map();
|
|
400
|
+
let dbPromise = null;
|
|
401
|
+
|
|
402
|
+
function getDb() {
|
|
403
|
+
if (!dbPromise) {
|
|
404
|
+
dbPromise = new Promise((resolve, reject) => {
|
|
405
|
+
const request = indexedDB.open(DB_NAME, 1);
|
|
406
|
+
request.onupgradeneeded = (event) => {
|
|
407
|
+
const db = event.target.result;
|
|
408
|
+
if (!db.objectStoreNames.contains(STORE_NAME)) {
|
|
409
|
+
db.createObjectStore(STORE_NAME);
|
|
410
|
+
}
|
|
411
|
+
};
|
|
412
|
+
request.onsuccess = () => resolve(request.result);
|
|
413
|
+
request.onerror = () => reject(request.error);
|
|
414
|
+
});
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
return dbPromise;
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
async function idbSet(key, value) {
|
|
421
|
+
const db = await getDb();
|
|
422
|
+
return new Promise((resolve, reject) => {
|
|
423
|
+
const tx = db.transaction(STORE_NAME, 'readwrite');
|
|
424
|
+
tx.objectStore(STORE_NAME).put(value, key);
|
|
425
|
+
tx.oncomplete = () => resolve(true);
|
|
426
|
+
tx.onerror = () => reject(tx.error);
|
|
427
|
+
});
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
async function idbGet(key) {
|
|
431
|
+
const db = await getDb();
|
|
432
|
+
return new Promise((resolve, reject) => {
|
|
433
|
+
const tx = db.transaction(STORE_NAME, 'readonly');
|
|
434
|
+
const request = tx.objectStore(STORE_NAME).get(key);
|
|
435
|
+
request.onsuccess = () => resolve(request.result || null);
|
|
436
|
+
request.onerror = () => reject(request.error);
|
|
437
|
+
});
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
function createId() {
|
|
441
|
+
if (window.crypto?.randomUUID) {
|
|
442
|
+
return window.crypto.randomUUID();
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
return `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 12)}`;
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
function createReference(id) {
|
|
449
|
+
const normalizedId = String(id || '').trim();
|
|
450
|
+
return normalizedId ? `${LOCAL_FILE_URI_PREFIX}${encodeURIComponent(normalizedId)}` : '';
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
function extractId(value) {
|
|
454
|
+
const text = String(value || '').trim();
|
|
455
|
+
if (!text) {
|
|
456
|
+
return '';
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
if (text.toLowerCase().startsWith(LOCAL_FILE_URI_PREFIX)) {
|
|
460
|
+
return decodeURIComponent(text.slice(LOCAL_FILE_URI_PREFIX.length));
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
if (text.toLowerCase().startsWith('local-file:')) {
|
|
464
|
+
return text.slice('local-file:'.length);
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
return text;
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
function isReference(value) {
|
|
471
|
+
const text = String(value || '').trim().toLowerCase();
|
|
472
|
+
return text.startsWith(LOCAL_FILE_URI_PREFIX) || text.startsWith('local-file:');
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
function rememberObjectUrl(id, objectUrl) {
|
|
476
|
+
const normalizedId = String(id || '').trim();
|
|
477
|
+
if (!normalizedId || !objectUrl) {
|
|
478
|
+
return '';
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
const previous = objectUrls.get(normalizedId);
|
|
482
|
+
if (previous && previous !== objectUrl) {
|
|
483
|
+
try { URL.revokeObjectURL(previous); } catch { }
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
objectUrls.set(normalizedId, objectUrl);
|
|
487
|
+
return objectUrl;
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
async function getDroppedFileHandle(item) {
|
|
491
|
+
if (!item || item.kind !== 'file' || typeof item.getAsFileSystemHandle !== 'function') {
|
|
492
|
+
return null;
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
try {
|
|
496
|
+
const handle = await item.getAsFileSystemHandle();
|
|
497
|
+
return handle?.kind === 'file' ? handle : null;
|
|
498
|
+
} catch (error) {
|
|
499
|
+
console.warn('[MindMapLocalFiles] Could not capture dropped file handle:', error);
|
|
500
|
+
return null;
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
async function canReadHandle(handle, requestIfNeeded = false) {
|
|
505
|
+
if (!handle) {
|
|
506
|
+
return false;
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
try {
|
|
510
|
+
if (typeof handle.queryPermission !== 'function') {
|
|
511
|
+
return true;
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
const queried = await handle.queryPermission({ mode: 'read' });
|
|
515
|
+
if (queried === 'granted') {
|
|
516
|
+
return true;
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
if (!requestIfNeeded || typeof handle.requestPermission !== 'function') {
|
|
520
|
+
return false;
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
return await handle.requestPermission({ mode: 'read' }) === 'granted';
|
|
524
|
+
} catch {
|
|
525
|
+
return false;
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
async function registerDroppedFile(file, item = null, options = {}) {
|
|
530
|
+
if (!(file instanceof File)) {
|
|
531
|
+
return null;
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
const id = String(options.id || createId()).trim();
|
|
535
|
+
const reference = createReference(id);
|
|
536
|
+
const objectUrl = rememberObjectUrl(id, URL.createObjectURL(file));
|
|
537
|
+
const handle = await getDroppedFileHandle(item);
|
|
538
|
+
let durableHandle = false;
|
|
539
|
+
|
|
540
|
+
if (handle) {
|
|
541
|
+
try {
|
|
542
|
+
await idbSet(`${LOCAL_FILE_KEY_PREFIX}${id}`, handle);
|
|
543
|
+
durableHandle = true;
|
|
544
|
+
} catch (error) {
|
|
545
|
+
console.warn('[MindMapLocalFiles] Failed to persist local file handle:', error);
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
const entry = {
|
|
550
|
+
id,
|
|
551
|
+
reference,
|
|
552
|
+
objectUrl,
|
|
553
|
+
file,
|
|
554
|
+
fileName: file.name || '',
|
|
555
|
+
size: Number(file.size || 0),
|
|
556
|
+
mime: file.type || '',
|
|
557
|
+
lastModified: Number(file.lastModified || 0),
|
|
558
|
+
durableHandle,
|
|
559
|
+
sourceKind: durableHandle ? 'local-file' : 'session-file'
|
|
560
|
+
};
|
|
561
|
+
|
|
562
|
+
sessionEntries.set(id, entry);
|
|
563
|
+
return entry;
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
async function getStoredHandle(id) {
|
|
567
|
+
const normalizedId = extractId(id);
|
|
568
|
+
if (!normalizedId) {
|
|
569
|
+
return null;
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
return await idbGet(`${LOCAL_FILE_KEY_PREFIX}${normalizedId}`);
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
async function getObjectUrl(referenceOrId, options = {}) {
|
|
576
|
+
const id = extractId(referenceOrId);
|
|
577
|
+
if (!id) {
|
|
578
|
+
return '';
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
const existingObjectUrl = objectUrls.get(id);
|
|
582
|
+
if (existingObjectUrl) {
|
|
583
|
+
return existingObjectUrl;
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
const sessionEntry = sessionEntries.get(id);
|
|
587
|
+
if (sessionEntry?.file instanceof File) {
|
|
588
|
+
return rememberObjectUrl(id, URL.createObjectURL(sessionEntry.file));
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
const handle = await getStoredHandle(id);
|
|
592
|
+
if (!handle) {
|
|
593
|
+
return '';
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
if (!(await canReadHandle(handle, options.requestPermission === true))) {
|
|
597
|
+
return '';
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
const file = await handle.getFile();
|
|
601
|
+
const objectUrl = rememberObjectUrl(id, URL.createObjectURL(file));
|
|
602
|
+
sessionEntries.set(id, {
|
|
603
|
+
id,
|
|
604
|
+
reference: createReference(id),
|
|
605
|
+
objectUrl,
|
|
606
|
+
file,
|
|
607
|
+
fileName: file.name || '',
|
|
608
|
+
size: Number(file.size || 0),
|
|
609
|
+
mime: file.type || '',
|
|
610
|
+
lastModified: Number(file.lastModified || 0),
|
|
611
|
+
durableHandle: true,
|
|
612
|
+
sourceKind: 'local-file'
|
|
613
|
+
});
|
|
614
|
+
|
|
615
|
+
return objectUrl;
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
window.MindMapLocalFiles = {
|
|
619
|
+
uriPrefix: LOCAL_FILE_URI_PREFIX,
|
|
620
|
+
isSupported: () => typeof indexedDB !== 'undefined'
|
|
621
|
+
&& typeof URL !== 'undefined'
|
|
622
|
+
&& typeof URL.createObjectURL === 'function',
|
|
623
|
+
isReference,
|
|
624
|
+
extractId,
|
|
625
|
+
createReference,
|
|
626
|
+
registerDroppedFile,
|
|
627
|
+
getObjectUrl,
|
|
628
|
+
getStoredHandle,
|
|
629
|
+
getSessionEntry: (referenceOrId) => sessionEntries.get(extractId(referenceOrId)) || null,
|
|
630
|
+
revokeObjectUrl(referenceOrId) {
|
|
631
|
+
const id = extractId(referenceOrId);
|
|
632
|
+
const objectUrl = objectUrls.get(id);
|
|
633
|
+
if (objectUrl) {
|
|
634
|
+
try { URL.revokeObjectURL(objectUrl); } catch { }
|
|
635
|
+
objectUrls.delete(id);
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
};
|
|
639
|
+
})();
|