@dimina-kit/devtools 0.4.0-dev.20260702182435 → 0.4.0-dev.20260703051110

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 (50) hide show
  1. package/dist/main/app/app.js +5 -25
  2. package/dist/main/app/native-overview.d.ts +27 -0
  3. package/dist/main/app/native-overview.js +44 -0
  4. package/dist/main/index.bundle.js +826 -690
  5. package/dist/main/ipc/bridge-router.js +180 -141
  6. package/dist/main/ipc/project-fs.js +39 -21
  7. package/dist/main/services/automation/handlers/app.js +143 -109
  8. package/dist/main/services/mcp/tools/simulator-tools.js +118 -97
  9. package/dist/main/services/network-forward/dispatch-batch.d.ts +22 -0
  10. package/dist/main/services/network-forward/dispatch-batch.js +21 -0
  11. package/dist/main/services/network-forward/index.js +5 -20
  12. package/dist/main/services/projects/create-project-service.js +54 -34
  13. package/dist/main/services/projects/types.d.ts +1 -32
  14. package/dist/main/services/service-console/console-api.js +36 -27
  15. package/dist/main/services/simulator-temp-files/disk.js +109 -86
  16. package/dist/main/services/workbench-coi-server.js +58 -45
  17. package/dist/main/utils/logger.d.ts +5 -12
  18. package/dist/main/utils/logger.js +5 -45
  19. package/dist/preload/instrumentation/wxml-extract.js +94 -62
  20. package/dist/preload/runtime/main-api-runner.d.ts +1 -1
  21. package/dist/preload/windows/main.cjs +284 -565
  22. package/dist/preload/windows/main.cjs.map +2 -2
  23. package/dist/preload/windows/simulator.cjs +37 -39
  24. package/dist/preload/windows/simulator.cjs.map +2 -2
  25. package/dist/preload/windows/simulator.js +37 -39
  26. package/dist/render-host/render-inspect.js +63 -52
  27. package/dist/renderer/assets/index-D-ksyN1p.js +49 -0
  28. package/dist/renderer/assets/workbenchSettings-COhuFF-i.js +8 -0
  29. package/dist/renderer/entries/main/index.html +1 -1
  30. package/dist/renderer/entries/workbench-settings/index.html +1 -1
  31. package/dist/shared/appdata-accumulator.js +53 -48
  32. package/dist/shared/open-in-editor-resource-path.d.ts +56 -0
  33. package/dist/shared/open-in-editor-resource-path.js +133 -0
  34. package/dist/shared/open-in-editor.d.ts +2 -9
  35. package/dist/shared/open-in-editor.js +8 -93
  36. package/dist/shared/types.d.ts +13 -0
  37. package/dist/simulator/assets/{device-shell-CUl0ILfn.js → device-shell-CiLAPa0I.js} +2 -2
  38. package/dist/simulator/assets/simulator-Dvnxry3y.js +10 -0
  39. package/dist/simulator/simulator.html +1 -1
  40. package/dist/vscode-workbench/assets/__vite-browser-external-CXi6Kz9W.js +1 -0
  41. package/dist/vscode-workbench/assets/{dist-CS7SQP3K.js → dist-TpGpmMGi.js} +3 -3
  42. package/dist/vscode-workbench/assets/{iconv-lite-umd-D3q-1-o6.js → iconv-lite-umd-C9tiCAJa.js} +1 -1
  43. package/dist/vscode-workbench/assets/{index-zjigpZ25.js → index-DJ1HyMZ7.js} +20 -22
  44. package/dist/vscode-workbench/assets/{jschardet-Cu4ufeHq.js → jschardet-DE1jV513.js} +1 -1
  45. package/dist/vscode-workbench/index.html +1 -1
  46. package/package.json +5 -5
  47. package/dist/renderer/assets/index-B-Dqb7G0.js +0 -49
  48. package/dist/renderer/assets/workbenchSettings-Bim9ol9R.js +0 -8
  49. package/dist/simulator/assets/simulator-Dz8iGcgy.js +0 -10
  50. package/dist/vscode-workbench/assets/__vite-browser-external-B0DTNerG.js +0 -1
@@ -185,54 +185,64 @@ function notSupportedApi(apiName) {
185
185
  }
186
186
 
187
187
  // src/simulator/simulator-api-storage.ts
188
- function setStorageSync({ key, data }) {
189
- const storageKey = `${this.appId}_${key}`;
188
+ function storageKeyOf(appId, key) {
189
+ return `${appId}_${key}`;
190
+ }
191
+ function collectAppKeys(appId) {
192
+ const prefix = `${appId}_`;
193
+ const keys = [];
194
+ for (let i = 0; i < localStorage.length; i++) {
195
+ const k = localStorage.key(i);
196
+ if (k && k.startsWith(prefix)) keys.push(k);
197
+ }
198
+ return keys;
199
+ }
200
+ function writeEntry(appId, key, data) {
190
201
  const dataString = typeof data === "object" ? JSON.stringify(data) : String(data);
191
- localStorage.setItem(storageKey, dataString);
202
+ localStorage.setItem(storageKeyOf(appId, key), dataString);
192
203
  }
193
- function getStorageSync({ key }) {
194
- const storageKey = `${this.appId}_${key}`;
195
- const raw = localStorage.getItem(storageKey);
196
- if (raw === null) return { data: "" };
204
+ function readEntry(appId, key) {
205
+ const raw = localStorage.getItem(storageKeyOf(appId, key));
206
+ if (raw === null) return void 0;
197
207
  try {
198
208
  return { data: JSON.parse(raw) };
199
209
  } catch {
200
210
  return { data: raw };
201
211
  }
202
212
  }
203
- function removeStorageSync({ key }) {
204
- const storageKey = `${this.appId}_${key}`;
205
- localStorage.removeItem(storageKey);
213
+ function clearAppKeys(appId) {
214
+ collectAppKeys(appId).forEach((k) => localStorage.removeItem(k));
206
215
  }
207
- function clearStorageSync() {
208
- const prefix = `${this.appId}_`;
209
- const keysToRemove = [];
210
- for (let i = 0; i < localStorage.length; i++) {
211
- const k = localStorage.key(i);
212
- if (k && k.startsWith(prefix)) keysToRemove.push(k);
213
- }
214
- keysToRemove.forEach((k) => localStorage.removeItem(k));
215
- }
216
- function getStorageInfoSync() {
217
- const prefix = `${this.appId}_`;
216
+ function storageInfoOf(appId) {
217
+ const prefix = `${appId}_`;
218
218
  const keys = [];
219
219
  let currentSize = 0;
220
- for (let i = 0; i < localStorage.length; i++) {
221
- const fullKey = localStorage.key(i);
222
- if (fullKey && fullKey.startsWith(prefix)) {
223
- keys.push(fullKey.substring(prefix.length));
224
- const item = localStorage.getItem(fullKey);
225
- currentSize += item ? item.length * 2 : 0;
226
- }
220
+ for (const fullKey of collectAppKeys(appId)) {
221
+ keys.push(fullKey.slice(prefix.length));
222
+ const item = localStorage.getItem(fullKey);
223
+ currentSize += item ? item.length * 2 : 0;
227
224
  }
228
225
  return { keys, currentSize, limitSize: 10 * 1024 * 1024 };
229
226
  }
227
+ function setStorageSync({ key, data }) {
228
+ writeEntry(this.appId, key, data);
229
+ }
230
+ function getStorageSync({ key }) {
231
+ return readEntry(this.appId, key) ?? { data: "" };
232
+ }
233
+ function removeStorageSync({ key }) {
234
+ localStorage.removeItem(storageKeyOf(this.appId, key));
235
+ }
236
+ function clearStorageSync() {
237
+ clearAppKeys(this.appId);
238
+ }
239
+ function getStorageInfoSync() {
240
+ return storageInfoOf(this.appId);
241
+ }
230
242
  function setStorage({ key, data, success, fail, complete }) {
231
243
  const { onSuccess, onFail, onComplete } = bindCallbacks(this, { success, fail, complete });
232
244
  try {
233
- const storageKey = `${this.appId}_${key}`;
234
- const dataString = typeof data === "object" ? JSON.stringify(data) : String(data);
235
- localStorage.setItem(storageKey, dataString);
245
+ writeEntry(this.appId, key, data);
236
246
  onSuccess?.({ errMsg: "setStorage:ok" });
237
247
  } catch (e) {
238
248
  onFail?.({ errMsg: `setStorage:fail ${e.message}` });
@@ -241,26 +251,18 @@ function setStorage({ key, data, success, fail, complete }) {
241
251
  }
242
252
  function getStorage({ key, success, fail, complete }) {
243
253
  const { onSuccess, onFail, onComplete } = bindCallbacks(this, { success, fail, complete });
244
- const storageKey = `${this.appId}_${key}`;
245
- const raw = localStorage.getItem(storageKey);
246
- if (raw === null) {
254
+ const entry = readEntry(this.appId, key);
255
+ if (!entry) {
247
256
  onFail?.({ errMsg: "getStorage:fail data not found" });
248
257
  } else {
249
- let data;
250
- try {
251
- data = JSON.parse(raw);
252
- } catch {
253
- data = raw;
254
- }
255
- onSuccess?.({ data, errMsg: "getStorage:ok" });
258
+ onSuccess?.({ data: entry.data, errMsg: "getStorage:ok" });
256
259
  }
257
260
  onComplete?.();
258
261
  }
259
262
  function removeStorage({ key, success, fail, complete }) {
260
263
  const { onSuccess, onFail, onComplete } = bindCallbacks(this, { success, fail, complete });
261
264
  try {
262
- const storageKey = `${this.appId}_${key}`;
263
- localStorage.removeItem(storageKey);
265
+ localStorage.removeItem(storageKeyOf(this.appId, key));
264
266
  onSuccess?.({ errMsg: "removeStorage:ok" });
265
267
  } catch (e) {
266
268
  onFail?.({ errMsg: `removeStorage:fail ${e.message}` });
@@ -269,30 +271,14 @@ function removeStorage({ key, success, fail, complete }) {
269
271
  }
270
272
  function clearStorage({ success, complete } = {}) {
271
273
  const { onSuccess, onComplete } = bindCallbacks(this, { success, complete });
272
- const prefix = `${this.appId}_`;
273
- const keysToRemove = [];
274
- for (let i = 0; i < localStorage.length; i++) {
275
- const k = localStorage.key(i);
276
- if (k && k.startsWith(prefix)) keysToRemove.push(k);
277
- }
278
- keysToRemove.forEach((k) => localStorage.removeItem(k));
274
+ clearAppKeys(this.appId);
279
275
  onSuccess?.({ errMsg: "clearStorage:ok" });
280
276
  onComplete?.();
281
277
  }
282
278
  function getStorageInfo({ success, complete } = {}) {
283
279
  const { onSuccess, onComplete } = bindCallbacks(this, { success, complete });
284
- const prefix = `${this.appId}_`;
285
- const keys = [];
286
- let currentSize = 0;
287
- for (let i = 0; i < localStorage.length; i++) {
288
- const fullKey = localStorage.key(i);
289
- if (fullKey && fullKey.startsWith(prefix)) {
290
- keys.push(fullKey.substring(prefix.length));
291
- const item = localStorage.getItem(fullKey);
292
- currentSize += item ? item.length * 2 : 0;
293
- }
294
- }
295
- onSuccess?.({ keys, currentSize, limitSize: 10 * 1024 * 1024, errMsg: "getStorageInfo:ok" });
280
+ const info = storageInfoOf(this.appId);
281
+ onSuccess?.({ ...info, errMsg: "getStorageInfo:ok" });
296
282
  onComplete?.();
297
283
  }
298
284
 
@@ -457,35 +443,50 @@ function getTempFileName(path2, blob, fallback = "file") {
457
443
  }
458
444
 
459
445
  // src/simulator/simulator-api-media.ts
460
- function chooseImage({ count = 9, sourceType, camera, success, fail, complete }) {
461
- const { onSuccess, onFail, onComplete } = bindCallbacks(this, { success, fail, complete });
462
- const normalizedCount = normalizeChooseMediaCount(count);
463
- const normalizedSourceType = normalizeStringArray(sourceType, ["album", "camera"]);
446
+ function captureAttrFor(sourceType, camera) {
447
+ if (sourceType.length !== 1 || sourceType[0] !== "camera") return void 0;
448
+ return camera === "front" ? "user" : "environment";
449
+ }
450
+ function createFilePicker(apiName, config, cbs, onPick) {
464
451
  const input = document.createElement("input");
465
452
  input.type = "file";
466
- input.accept = "image/*";
467
- input.multiple = normalizedCount > 1;
468
- if (normalizedSourceType.length === 1 && normalizedSourceType[0] === "camera") {
469
- input.setAttribute("capture", camera === "front" ? "user" : "environment");
470
- }
453
+ input.accept = config.accept;
454
+ input.multiple = config.multiple;
455
+ if (config.capture) input.setAttribute("capture", config.capture);
471
456
  input.style.display = "none";
472
457
  document.body.appendChild(input);
458
+ const removeInput = () => input.remove();
473
459
  input.addEventListener("change", () => {
474
- const files = Array.from(input.files || []).slice(0, normalizedCount);
460
+ const files = Array.from(input.files || []);
475
461
  if (files.length === 0) {
476
- onFail?.({ errMsg: "chooseImage:fail cancel" });
477
- onComplete?.();
478
- input.remove();
462
+ cbs.onFail?.({ errMsg: `${apiName}:fail cancel` });
463
+ cbs.onComplete?.();
464
+ removeInput();
479
465
  return;
480
466
  }
481
- const tempFilePaths = files.map((f) => createTempFilePath(f));
482
- const tempFiles2 = files.map((f, i) => ({ path: tempFilePaths[i], size: f.size }));
483
- onSuccess?.({ tempFilePaths, tempFiles: tempFiles2, errMsg: "chooseImage:ok" });
484
- onComplete?.();
485
- input.remove();
467
+ void onPick(files, removeInput);
486
468
  });
487
469
  input.click();
488
470
  }
471
+ function chooseImage({ count = 9, sourceType, camera, success, fail, complete }) {
472
+ const cbs = bindCallbacks(this, { success, fail, complete });
473
+ const { onSuccess, onComplete } = cbs;
474
+ const normalizedCount = normalizeChooseMediaCount(count);
475
+ const normalizedSourceType = normalizeStringArray(sourceType, ["album", "camera"]);
476
+ createFilePicker(
477
+ "chooseImage",
478
+ { accept: "image/*", multiple: normalizedCount > 1, capture: captureAttrFor(normalizedSourceType, camera) },
479
+ cbs,
480
+ (rawFiles, removeInput) => {
481
+ const files = rawFiles.slice(0, normalizedCount);
482
+ const tempFilePaths = files.map((f) => createTempFilePath(f));
483
+ const tempFiles2 = files.map((f, i) => ({ path: tempFilePaths[i], size: f.size }));
484
+ onSuccess?.({ tempFilePaths, tempFiles: tempFiles2, errMsg: "chooseImage:ok" });
485
+ onComplete?.();
486
+ removeInput();
487
+ }
488
+ );
489
+ }
489
490
  function previewImage({ urls, current, success, complete }) {
490
491
  const { onSuccess, onComplete } = bindCallbacks(this, { success, complete });
491
492
  if (!urls || urls.length === 0) {
@@ -726,78 +727,62 @@ async function buildChooseMediaTempFile(file) {
726
727
  };
727
728
  }
728
729
  function chooseMedia({ count = 9, mediaType = ["image", "video"], sourceType = ["album", "camera"], camera = "back", success, fail, complete }) {
729
- const { onSuccess, onFail, onComplete } = bindCallbacks(this, { success, fail, complete });
730
+ const cbs = bindCallbacks(this, { success, fail, complete });
731
+ const { onSuccess, onFail, onComplete } = cbs;
730
732
  const normalizedCount = normalizeChooseMediaCount(count);
731
733
  const normalizedMediaType = normalizeStringArray(mediaType, ["image", "video"]);
732
734
  const normalizedSourceType = normalizeStringArray(sourceType, ["album", "camera"]);
733
- const input = document.createElement("input");
734
- input.type = "file";
735
- input.accept = getChooseMediaAccept(normalizedMediaType);
736
- input.multiple = normalizedCount > 1;
737
- if (normalizedSourceType.length === 1 && normalizedSourceType[0] === "camera") {
738
- input.setAttribute("capture", camera === "front" ? "user" : "environment");
739
- }
740
- input.style.display = "none";
741
- document.body.appendChild(input);
742
- input.addEventListener("change", async () => {
743
- const files = Array.from(input.files || []).slice(0, normalizedCount);
744
- if (files.length === 0) {
745
- onFail?.({ errMsg: "chooseMedia:fail cancel" });
746
- onComplete?.();
747
- input.remove();
748
- return;
749
- }
750
- try {
751
- const tempFiles2 = await Promise.all(files.map(buildChooseMediaTempFile));
752
- onSuccess?.({
753
- tempFiles: tempFiles2,
754
- type: getChooseMediaResultType(tempFiles2),
755
- failedCount: 0,
756
- errMsg: "chooseMedia:ok"
757
- });
758
- } catch (error) {
759
- onFail?.({ errMsg: `chooseMedia:fail ${error.message}` });
760
- } finally {
761
- onComplete?.();
762
- input.remove();
735
+ createFilePicker(
736
+ "chooseMedia",
737
+ {
738
+ accept: getChooseMediaAccept(normalizedMediaType),
739
+ multiple: normalizedCount > 1,
740
+ capture: captureAttrFor(normalizedSourceType, camera)
741
+ },
742
+ cbs,
743
+ async (rawFiles, removeInput) => {
744
+ const files = rawFiles.slice(0, normalizedCount);
745
+ try {
746
+ const tempFiles2 = await Promise.all(files.map(buildChooseMediaTempFile));
747
+ onSuccess?.({
748
+ tempFiles: tempFiles2,
749
+ type: getChooseMediaResultType(tempFiles2),
750
+ failedCount: 0,
751
+ errMsg: "chooseMedia:ok"
752
+ });
753
+ } catch (error) {
754
+ onFail?.({ errMsg: `chooseMedia:fail ${error.message}` });
755
+ } finally {
756
+ onComplete?.();
757
+ removeInput();
758
+ }
763
759
  }
764
- });
765
- input.click();
760
+ );
766
761
  }
767
762
  function chooseVideo({ sourceType, camera, success, fail, complete }) {
768
- const { onSuccess, onFail, onComplete } = bindCallbacks(this, { success, fail, complete });
763
+ const cbs = bindCallbacks(this, { success, fail, complete });
764
+ const { onSuccess, onComplete } = cbs;
769
765
  const normalizedSourceType = normalizeStringArray(sourceType, ["album", "camera"]);
770
- const input = document.createElement("input");
771
- input.type = "file";
772
- input.accept = "video/*";
773
- if (normalizedSourceType.length === 1 && normalizedSourceType[0] === "camera") {
774
- input.setAttribute("capture", camera === "front" ? "user" : "environment");
775
- }
776
- input.style.display = "none";
777
- document.body.appendChild(input);
778
- input.addEventListener("change", async () => {
779
- const files = Array.from(input.files || []);
780
- if (files.length === 0) {
781
- onFail?.({ errMsg: "chooseVideo:fail cancel" });
766
+ createFilePicker(
767
+ "chooseVideo",
768
+ { accept: "video/*", multiple: false, capture: captureAttrFor(normalizedSourceType, camera) },
769
+ cbs,
770
+ async (files, removeInput) => {
771
+ const file = files[0];
772
+ const tempFilePath = createTempFilePath(file);
773
+ const metadata = await readVideoMetadata(tempFilePath);
774
+ onSuccess?.({
775
+ tempFilePath,
776
+ duration: metadata.duration,
777
+ size: file.size,
778
+ width: metadata.width,
779
+ height: metadata.height,
780
+ errMsg: "chooseVideo:ok"
781
+ });
782
782
  onComplete?.();
783
- input.remove();
784
- return;
783
+ removeInput();
785
784
  }
786
- const file = files[0];
787
- const tempFilePath = createTempFilePath(file);
788
- const metadata = await readVideoMetadata(tempFilePath);
789
- onSuccess?.({
790
- tempFilePath,
791
- duration: metadata.duration,
792
- size: file.size,
793
- width: metadata.width,
794
- height: metadata.height,
795
- errMsg: "chooseVideo:ok"
796
- });
797
- onComplete?.();
798
- input.remove();
799
- });
800
- input.click();
785
+ );
801
786
  }
802
787
  var AUDIO_EVENT_MAP = {
803
788
  play: "play",
@@ -966,39 +951,64 @@ async function _tmpBytes(url) {
966
951
  var _fs = typeof require !== "undefined" ? require("fs") : null;
967
952
  var _path = typeof require !== "undefined" ? require("path") : null;
968
953
  var _crypto = typeof require !== "undefined" ? require("crypto") : null;
969
- function _fsResolveOrFail(p, apiName, onFail) {
954
+ function guardFsAvailable(apiName, cbs) {
955
+ if (_fs) return false;
956
+ cbs.onFail?.({ errMsg: `${apiName}:fail not available in browser context` });
957
+ cbs.onComplete?.();
958
+ return true;
959
+ }
960
+ function resolveOrBail(p, apiName, cbs) {
970
961
  const v = resolveVPath(p);
971
- if (!v) {
972
- onFail?.({ errMsg: `${apiName}:fail invalid or unsafe path` });
973
- return null;
974
- }
975
- return v;
962
+ if (v) return v;
963
+ cbs.onFail?.({ errMsg: `${apiName}:fail invalid or unsafe path` });
964
+ cbs.onComplete?.();
965
+ return void 0;
966
+ }
967
+ function ensureWritable(v, apiName, cbs) {
968
+ if (v.writable && v.realPath) return true;
969
+ cbs.onFail?.({ errMsg: `${apiName}:fail permission denied` });
970
+ cbs.onComplete?.();
971
+ return false;
972
+ }
973
+ function tmpFailHandler(apiName, cbs) {
974
+ return (err) => {
975
+ cbs.onFail?.({ errMsg: `${apiName}:fail ${err.message}` });
976
+ cbs.onComplete?.();
977
+ };
976
978
  }
977
- function _denyWrite(apiName, onFail) {
978
- onFail?.({ errMsg: `${apiName}:fail permission denied` });
979
+ function nodeComplete(apiName, cbs, buildOk) {
980
+ return (err, ...args) => {
981
+ if (err) {
982
+ cbs.onFail?.({ errMsg: `${apiName}:fail ${err.message}` });
983
+ } else {
984
+ cbs.onSuccess?.({ ...buildOk ? buildOk(...args) : void 0, errMsg: `${apiName}:ok` });
985
+ }
986
+ cbs.onComplete?.();
987
+ };
988
+ }
989
+ function mkdirpThenWrite(destReal, apiName, cbs, writeFn, okExtra) {
990
+ _fs.mkdir(_path.dirname(destReal), { recursive: true }, (mkdirErr) => {
991
+ if (mkdirErr) {
992
+ cbs.onFail?.({ errMsg: `${apiName}:fail ${mkdirErr.message}` });
993
+ cbs.onComplete?.();
994
+ return;
995
+ }
996
+ writeFn(nodeComplete(apiName, cbs, () => okExtra));
997
+ });
979
998
  }
980
999
  function fsAccess({ path: path2, success, fail, complete }) {
981
- const { onSuccess, onFail, onComplete } = bindCallbacks(this, { success, fail, complete });
982
- if (!_fs) {
983
- onFail?.({ errMsg: "fsAccess:fail not available in browser context" });
984
- onComplete?.();
985
- return;
986
- }
987
- const v = _fsResolveOrFail(path2, "fsAccess", onFail);
988
- if (!v) {
989
- onComplete?.();
990
- return;
991
- }
1000
+ const cbs = bindCallbacks(this, { success, fail, complete });
1001
+ const { onSuccess, onFail, onComplete } = cbs;
1002
+ if (guardFsAvailable("fsAccess", cbs)) return;
1003
+ const v = resolveOrBail(path2, "fsAccess", cbs);
1004
+ if (!v) return;
992
1005
  if (v.kind === "tmp") {
993
1006
  _tmpBytes(path2).then(
994
1007
  () => {
995
1008
  onSuccess?.({ errMsg: "fsAccess:ok" });
996
1009
  onComplete?.();
997
1010
  },
998
- (err) => {
999
- onFail?.({ errMsg: `fsAccess:fail ${err.message}` });
1000
- onComplete?.();
1001
- }
1011
+ tmpFailHandler("fsAccess", cbs)
1002
1012
  );
1003
1013
  return;
1004
1014
  }
@@ -1007,27 +1017,14 @@ function fsAccess({ path: path2, success, fail, complete }) {
1007
1017
  onComplete?.();
1008
1018
  return;
1009
1019
  }
1010
- _fs.access(v.realPath, _fs.constants.F_OK, (err) => {
1011
- if (err) {
1012
- onFail?.({ errMsg: `fsAccess:fail ${err.message}` });
1013
- } else {
1014
- onSuccess?.({ errMsg: "fsAccess:ok" });
1015
- }
1016
- onComplete?.();
1017
- });
1020
+ _fs.access(v.realPath, _fs.constants.F_OK, nodeComplete("fsAccess", cbs));
1018
1021
  }
1019
1022
  function fsStat({ path: path2, recursive = false, success, fail, complete }) {
1020
- const { onSuccess, onFail, onComplete } = bindCallbacks(this, { success, fail, complete });
1021
- if (!_fs) {
1022
- onFail?.({ errMsg: "fsStat:fail not available in browser context" });
1023
- onComplete?.();
1024
- return;
1025
- }
1026
- const v = _fsResolveOrFail(path2, "fsStat", onFail);
1027
- if (!v) {
1028
- onComplete?.();
1029
- return;
1030
- }
1023
+ const cbs = bindCallbacks(this, { success, fail, complete });
1024
+ const { onSuccess, onFail, onComplete } = cbs;
1025
+ if (guardFsAvailable("fsStat", cbs)) return;
1026
+ const v = resolveOrBail(path2, "fsStat", cbs);
1027
+ if (!v) return;
1031
1028
  if (v.kind === "tmp") {
1032
1029
  _tmpBytes(path2).then(
1033
1030
  (buf) => {
@@ -1044,10 +1041,7 @@ function fsStat({ path: path2, recursive = false, success, fail, complete }) {
1044
1041
  });
1045
1042
  onComplete?.();
1046
1043
  },
1047
- (err) => {
1048
- onFail?.({ errMsg: `fsStat:fail ${err.message}` });
1049
- onComplete?.();
1050
- }
1044
+ tmpFailHandler("fsStat", cbs)
1051
1045
  );
1052
1046
  return;
1053
1047
  }
@@ -1103,38 +1097,24 @@ function fsStat({ path: path2, recursive = false, success, fail, complete }) {
1103
1097
  onComplete?.();
1104
1098
  });
1105
1099
  } else {
1106
- _fs.stat(resolved, (err, s) => {
1107
- if (err) {
1108
- onFail?.({ errMsg: `fsStat:fail ${err.message}` });
1109
- } else {
1110
- onSuccess?.({
1111
- stats: {
1112
- size: s.size,
1113
- mode: s.mode,
1114
- lastAccessedTime: s.atimeMs,
1115
- lastModifiedTime: s.mtimeMs,
1116
- isFile: s.isFile(),
1117
- isDirectory: s.isDirectory()
1118
- },
1119
- errMsg: "fsStat:ok"
1120
- });
1100
+ _fs.stat(resolved, nodeComplete("fsStat", cbs, (s) => ({
1101
+ stats: {
1102
+ size: s.size,
1103
+ mode: s.mode,
1104
+ lastAccessedTime: s.atimeMs,
1105
+ lastModifiedTime: s.mtimeMs,
1106
+ isFile: s.isFile(),
1107
+ isDirectory: s.isDirectory()
1121
1108
  }
1122
- onComplete?.();
1123
- });
1109
+ })));
1124
1110
  }
1125
1111
  }
1126
1112
  function fsReadFile({ filePath, encoding, success, fail, complete }) {
1127
- const { onSuccess, onFail, onComplete } = bindCallbacks(this, { success, fail, complete });
1128
- if (!_fs) {
1129
- onFail?.({ errMsg: "fsReadFile:fail not available in browser context" });
1130
- onComplete?.();
1131
- return;
1132
- }
1133
- const v = _fsResolveOrFail(filePath, "fsReadFile", onFail);
1134
- if (!v) {
1135
- onComplete?.();
1136
- return;
1137
- }
1113
+ const cbs = bindCallbacks(this, { success, fail, complete });
1114
+ const { onSuccess, onFail, onComplete } = cbs;
1115
+ if (guardFsAvailable("fsReadFile", cbs)) return;
1116
+ const v = resolveOrBail(filePath, "fsReadFile", cbs);
1117
+ if (!v) return;
1138
1118
  if (v.kind === "tmp") {
1139
1119
  _tmpBytes(filePath).then(
1140
1120
  (buf) => {
@@ -1142,10 +1122,7 @@ function fsReadFile({ filePath, encoding, success, fail, complete }) {
1142
1122
  onSuccess?.({ data, errMsg: "fsReadFile:ok" });
1143
1123
  onComplete?.();
1144
1124
  },
1145
- (err) => {
1146
- onFail?.({ errMsg: `fsReadFile:fail ${err.message}` });
1147
- onComplete?.();
1148
- }
1125
+ tmpFailHandler("fsReadFile", cbs)
1149
1126
  );
1150
1127
  return;
1151
1128
  }
@@ -1154,116 +1131,37 @@ function fsReadFile({ filePath, encoding, success, fail, complete }) {
1154
1131
  onComplete?.();
1155
1132
  return;
1156
1133
  }
1157
- _fs.readFile(v.realPath, encoding || null, (err, data) => {
1158
- if (err) {
1159
- onFail?.({ errMsg: `fsReadFile:fail ${err.message}` });
1160
- } else {
1161
- onSuccess?.({ data, errMsg: "fsReadFile:ok" });
1162
- }
1163
- onComplete?.();
1164
- });
1134
+ _fs.readFile(v.realPath, encoding || null, nodeComplete("fsReadFile", cbs, (data) => ({ data })));
1165
1135
  }
1166
1136
  function fsWriteFile({ filePath, data, encoding = "utf8", success, fail, complete }) {
1167
- const { onSuccess, onFail, onComplete } = bindCallbacks(this, { success, fail, complete });
1168
- if (!_fs) {
1169
- onFail?.({ errMsg: "fsWriteFile:fail not available in browser context" });
1170
- onComplete?.();
1171
- return;
1172
- }
1173
- const v = _fsResolveOrFail(filePath, "fsWriteFile", onFail);
1174
- if (!v) {
1175
- onComplete?.();
1176
- return;
1177
- }
1178
- if (!v.writable || !v.realPath) {
1179
- _denyWrite("fsWriteFile", onFail);
1180
- onComplete?.();
1181
- return;
1182
- }
1183
- _fs.mkdir(_path.dirname(v.realPath), { recursive: true }, (mkdirErr) => {
1184
- if (mkdirErr) {
1185
- onFail?.({ errMsg: `fsWriteFile:fail ${mkdirErr.message}` });
1186
- onComplete?.();
1187
- return;
1188
- }
1189
- _fs.writeFile(v.realPath, data, { encoding }, (err) => {
1190
- if (err) {
1191
- onFail?.({ errMsg: `fsWriteFile:fail ${err.message}` });
1192
- } else {
1193
- onSuccess?.({ errMsg: "fsWriteFile:ok" });
1194
- }
1195
- onComplete?.();
1196
- });
1197
- });
1137
+ const cbs = bindCallbacks(this, { success, fail, complete });
1138
+ if (guardFsAvailable("fsWriteFile", cbs)) return;
1139
+ const v = resolveOrBail(filePath, "fsWriteFile", cbs);
1140
+ if (!v) return;
1141
+ if (!ensureWritable(v, "fsWriteFile", cbs)) return;
1142
+ mkdirpThenWrite(v.realPath, "fsWriteFile", cbs, (done) => _fs.writeFile(v.realPath, data, { encoding }, done));
1198
1143
  }
1199
1144
  function fsAppendFile({ filePath, data, encoding = "utf8", success, fail, complete }) {
1200
- const { onSuccess, onFail, onComplete } = bindCallbacks(this, { success, fail, complete });
1201
- if (!_fs) {
1202
- onFail?.({ errMsg: "fsAppendFile:fail not available in browser context" });
1203
- onComplete?.();
1204
- return;
1205
- }
1206
- const v = _fsResolveOrFail(filePath, "fsAppendFile", onFail);
1207
- if (!v) {
1208
- onComplete?.();
1209
- return;
1210
- }
1211
- if (!v.writable || !v.realPath) {
1212
- _denyWrite("fsAppendFile", onFail);
1213
- onComplete?.();
1214
- return;
1215
- }
1216
- _fs.appendFile(v.realPath, data, { encoding }, (err) => {
1217
- if (err) {
1218
- onFail?.({ errMsg: `fsAppendFile:fail ${err.message}` });
1219
- } else {
1220
- onSuccess?.({ errMsg: "fsAppendFile:ok" });
1221
- }
1222
- onComplete?.();
1223
- });
1145
+ const cbs = bindCallbacks(this, { success, fail, complete });
1146
+ if (guardFsAvailable("fsAppendFile", cbs)) return;
1147
+ const v = resolveOrBail(filePath, "fsAppendFile", cbs);
1148
+ if (!v) return;
1149
+ if (!ensureWritable(v, "fsAppendFile", cbs)) return;
1150
+ _fs.appendFile(v.realPath, data, { encoding }, nodeComplete("fsAppendFile", cbs));
1224
1151
  }
1225
1152
  function fsCopyFile({ srcPath, destPath, success, fail, complete }) {
1226
- const { onSuccess, onFail, onComplete } = bindCallbacks(this, { success, fail, complete });
1227
- if (!_fs) {
1228
- onFail?.({ errMsg: "fsCopyFile:fail not available in browser context" });
1229
- onComplete?.();
1230
- return;
1231
- }
1232
- const vSrc = _fsResolveOrFail(srcPath, "fsCopyFile", onFail);
1233
- if (!vSrc) {
1234
- onComplete?.();
1235
- return;
1236
- }
1237
- const vDest = _fsResolveOrFail(destPath, "fsCopyFile", onFail);
1238
- if (!vDest) {
1239
- onComplete?.();
1240
- return;
1241
- }
1242
- if (!vDest.writable || !vDest.realPath) {
1243
- _denyWrite("fsCopyFile", onFail);
1244
- onComplete?.();
1245
- return;
1246
- }
1153
+ const cbs = bindCallbacks(this, { success, fail, complete });
1154
+ const { onFail, onComplete } = cbs;
1155
+ if (guardFsAvailable("fsCopyFile", cbs)) return;
1156
+ const vSrc = resolveOrBail(srcPath, "fsCopyFile", cbs);
1157
+ if (!vSrc) return;
1158
+ const vDest = resolveOrBail(destPath, "fsCopyFile", cbs);
1159
+ if (!vDest) return;
1160
+ if (!ensureWritable(vDest, "fsCopyFile", cbs)) return;
1247
1161
  if (vSrc.kind === "tmp") {
1248
1162
  _tmpBytes(srcPath).then(
1249
- (buf) => {
1250
- _fs.mkdir(_path.dirname(vDest.realPath), { recursive: true }, (mkdirErr) => {
1251
- if (mkdirErr) {
1252
- onFail?.({ errMsg: `fsCopyFile:fail ${mkdirErr.message}` });
1253
- onComplete?.();
1254
- return;
1255
- }
1256
- _fs.writeFile(vDest.realPath, buf, (err) => {
1257
- if (err) onFail?.({ errMsg: `fsCopyFile:fail ${err.message}` });
1258
- else onSuccess?.({ errMsg: "fsCopyFile:ok" });
1259
- onComplete?.();
1260
- });
1261
- });
1262
- },
1263
- (err) => {
1264
- onFail?.({ errMsg: `fsCopyFile:fail ${err.message}` });
1265
- onComplete?.();
1266
- }
1163
+ (buf) => mkdirpThenWrite(vDest.realPath, "fsCopyFile", cbs, (done) => _fs.writeFile(vDest.realPath, buf, done)),
1164
+ tmpFailHandler("fsCopyFile", cbs)
1267
1165
  );
1268
1166
  return;
1269
1167
  }
@@ -1272,142 +1170,50 @@ function fsCopyFile({ srcPath, destPath, success, fail, complete }) {
1272
1170
  onComplete?.();
1273
1171
  return;
1274
1172
  }
1275
- _fs.copyFile(vSrc.realPath, vDest.realPath, (err) => {
1276
- if (err) {
1277
- onFail?.({ errMsg: `fsCopyFile:fail ${err.message}` });
1278
- } else {
1279
- onSuccess?.({ errMsg: "fsCopyFile:ok" });
1280
- }
1281
- onComplete?.();
1282
- });
1173
+ _fs.copyFile(vSrc.realPath, vDest.realPath, nodeComplete("fsCopyFile", cbs));
1283
1174
  }
1284
1175
  function fsRename({ oldPath, newPath, success, fail, complete }) {
1285
- const { onSuccess, onFail, onComplete } = bindCallbacks(this, { success, fail, complete });
1286
- if (!_fs) {
1287
- onFail?.({ errMsg: "fsRename:fail not available in browser context" });
1288
- onComplete?.();
1289
- return;
1290
- }
1291
- const vOld = _fsResolveOrFail(oldPath, "fsRename", onFail);
1292
- if (!vOld) {
1293
- onComplete?.();
1294
- return;
1295
- }
1296
- const vNew = _fsResolveOrFail(newPath, "fsRename", onFail);
1297
- if (!vNew) {
1298
- onComplete?.();
1299
- return;
1300
- }
1301
- if (!vOld.writable || !vOld.realPath) {
1302
- _denyWrite("fsRename", onFail);
1303
- onComplete?.();
1304
- return;
1305
- }
1306
- if (!vNew.writable || !vNew.realPath) {
1307
- _denyWrite("fsRename", onFail);
1308
- onComplete?.();
1309
- return;
1310
- }
1311
- _fs.rename(vOld.realPath, vNew.realPath, (err) => {
1312
- if (err) {
1313
- onFail?.({ errMsg: `fsRename:fail ${err.message}` });
1314
- } else {
1315
- onSuccess?.({ errMsg: "fsRename:ok" });
1316
- }
1317
- onComplete?.();
1318
- });
1176
+ const cbs = bindCallbacks(this, { success, fail, complete });
1177
+ if (guardFsAvailable("fsRename", cbs)) return;
1178
+ const vOld = resolveOrBail(oldPath, "fsRename", cbs);
1179
+ if (!vOld) return;
1180
+ const vNew = resolveOrBail(newPath, "fsRename", cbs);
1181
+ if (!vNew) return;
1182
+ if (!ensureWritable(vOld, "fsRename", cbs)) return;
1183
+ if (!ensureWritable(vNew, "fsRename", cbs)) return;
1184
+ _fs.rename(vOld.realPath, vNew.realPath, nodeComplete("fsRename", cbs));
1319
1185
  }
1320
1186
  function fsUnlink({ filePath, success, fail, complete }) {
1321
- const { onSuccess, onFail, onComplete } = bindCallbacks(this, { success, fail, complete });
1322
- if (!_fs) {
1323
- onFail?.({ errMsg: "fsUnlink:fail not available in browser context" });
1324
- onComplete?.();
1325
- return;
1326
- }
1327
- const v = _fsResolveOrFail(filePath, "fsUnlink", onFail);
1328
- if (!v) {
1329
- onComplete?.();
1330
- return;
1331
- }
1332
- if (!v.writable || !v.realPath) {
1333
- _denyWrite("fsUnlink", onFail);
1334
- onComplete?.();
1335
- return;
1336
- }
1337
- _fs.unlink(v.realPath, (err) => {
1338
- if (err) {
1339
- onFail?.({ errMsg: `fsUnlink:fail ${err.message}` });
1340
- } else {
1341
- onSuccess?.({ errMsg: "fsUnlink:ok" });
1342
- }
1343
- onComplete?.();
1344
- });
1187
+ const cbs = bindCallbacks(this, { success, fail, complete });
1188
+ if (guardFsAvailable("fsUnlink", cbs)) return;
1189
+ const v = resolveOrBail(filePath, "fsUnlink", cbs);
1190
+ if (!v) return;
1191
+ if (!ensureWritable(v, "fsUnlink", cbs)) return;
1192
+ _fs.unlink(v.realPath, nodeComplete("fsUnlink", cbs));
1345
1193
  }
1346
1194
  function fsMkdir({ dirPath, recursive = false, success, fail, complete }) {
1347
- const { onSuccess, onFail, onComplete } = bindCallbacks(this, { success, fail, complete });
1348
- if (!_fs) {
1349
- onFail?.({ errMsg: "fsMkdir:fail not available in browser context" });
1350
- onComplete?.();
1351
- return;
1352
- }
1353
- const v = _fsResolveOrFail(dirPath, "fsMkdir", onFail);
1354
- if (!v) {
1355
- onComplete?.();
1356
- return;
1357
- }
1358
- if (!v.writable || !v.realPath) {
1359
- _denyWrite("fsMkdir", onFail);
1360
- onComplete?.();
1361
- return;
1362
- }
1363
- _fs.mkdir(v.realPath, { recursive }, (err) => {
1364
- if (err) {
1365
- onFail?.({ errMsg: `fsMkdir:fail ${err.message}` });
1366
- } else {
1367
- onSuccess?.({ errMsg: "fsMkdir:ok" });
1368
- }
1369
- onComplete?.();
1370
- });
1195
+ const cbs = bindCallbacks(this, { success, fail, complete });
1196
+ if (guardFsAvailable("fsMkdir", cbs)) return;
1197
+ const v = resolveOrBail(dirPath, "fsMkdir", cbs);
1198
+ if (!v) return;
1199
+ if (!ensureWritable(v, "fsMkdir", cbs)) return;
1200
+ _fs.mkdir(v.realPath, { recursive }, nodeComplete("fsMkdir", cbs));
1371
1201
  }
1372
1202
  function fsRmdir({ dirPath, recursive = false, success, fail, complete }) {
1373
- const { onSuccess, onFail, onComplete } = bindCallbacks(this, { success, fail, complete });
1374
- if (!_fs) {
1375
- onFail?.({ errMsg: "fsRmdir:fail not available in browser context" });
1376
- onComplete?.();
1377
- return;
1378
- }
1379
- const v = _fsResolveOrFail(dirPath, "fsRmdir", onFail);
1380
- if (!v) {
1381
- onComplete?.();
1382
- return;
1383
- }
1384
- if (!v.writable || !v.realPath) {
1385
- _denyWrite("fsRmdir", onFail);
1386
- onComplete?.();
1387
- return;
1388
- }
1203
+ const cbs = bindCallbacks(this, { success, fail, complete });
1204
+ if (guardFsAvailable("fsRmdir", cbs)) return;
1205
+ const v = resolveOrBail(dirPath, "fsRmdir", cbs);
1206
+ if (!v) return;
1207
+ if (!ensureWritable(v, "fsRmdir", cbs)) return;
1389
1208
  const rmFn = _fs.rm ?? _fs.rmdir;
1390
- rmFn(v.realPath, { recursive }, (err) => {
1391
- if (err) {
1392
- onFail?.({ errMsg: `fsRmdir:fail ${err.message}` });
1393
- } else {
1394
- onSuccess?.({ errMsg: "fsRmdir:ok" });
1395
- }
1396
- onComplete?.();
1397
- });
1209
+ rmFn(v.realPath, { recursive }, nodeComplete("fsRmdir", cbs));
1398
1210
  }
1399
1211
  function fsReaddir({ dirPath, success, fail, complete }) {
1400
- const { onSuccess, onFail, onComplete } = bindCallbacks(this, { success, fail, complete });
1401
- if (!_fs) {
1402
- onFail?.({ errMsg: "fsReaddir:fail not available in browser context" });
1403
- onComplete?.();
1404
- return;
1405
- }
1406
- const v = _fsResolveOrFail(dirPath, "fsReaddir", onFail);
1407
- if (!v) {
1408
- onComplete?.();
1409
- return;
1410
- }
1212
+ const cbs = bindCallbacks(this, { success, fail, complete });
1213
+ const { onFail, onComplete } = cbs;
1214
+ if (guardFsAvailable("fsReaddir", cbs)) return;
1215
+ const v = resolveOrBail(dirPath, "fsReaddir", cbs);
1216
+ if (!v) return;
1411
1217
  if (v.kind === "tmp" || v.kind === "store") {
1412
1218
  onFail?.({ errMsg: `fsReaddir:fail ${v.kind} is a flat namespace (no dir tree)` });
1413
1219
  onComplete?.();
@@ -1418,27 +1224,14 @@ function fsReaddir({ dirPath, success, fail, complete }) {
1418
1224
  onComplete?.();
1419
1225
  return;
1420
1226
  }
1421
- _fs.readdir(v.realPath, (err, files) => {
1422
- if (err) {
1423
- onFail?.({ errMsg: `fsReaddir:fail ${err.message}` });
1424
- } else {
1425
- onSuccess?.({ files, errMsg: "fsReaddir:ok" });
1426
- }
1427
- onComplete?.();
1428
- });
1227
+ _fs.readdir(v.realPath, nodeComplete("fsReaddir", cbs, (files) => ({ files })));
1429
1228
  }
1430
1229
  function fsGetFileInfo({ filePath, digestAlgorithm, success, fail, complete }) {
1431
- const { onSuccess, onFail, onComplete } = bindCallbacks(this, { success, fail, complete });
1432
- if (!_fs) {
1433
- onFail?.({ errMsg: "fsGetFileInfo:fail not available in browser context" });
1434
- onComplete?.();
1435
- return;
1436
- }
1437
- const v = _fsResolveOrFail(filePath, "fsGetFileInfo", onFail);
1438
- if (!v) {
1439
- onComplete?.();
1440
- return;
1441
- }
1230
+ const cbs = bindCallbacks(this, { success, fail, complete });
1231
+ const { onSuccess, onFail, onComplete } = cbs;
1232
+ if (guardFsAvailable("fsGetFileInfo", cbs)) return;
1233
+ const v = resolveOrBail(filePath, "fsGetFileInfo", cbs);
1234
+ if (!v) return;
1442
1235
  if (v.kind === "tmp") {
1443
1236
  _tmpBytes(filePath).then(
1444
1237
  (buf) => {
@@ -1454,10 +1247,7 @@ function fsGetFileInfo({ filePath, digestAlgorithm, success, fail, complete }) {
1454
1247
  onSuccess?.(result);
1455
1248
  onComplete?.();
1456
1249
  },
1457
- (err) => {
1458
- onFail?.({ errMsg: `fsGetFileInfo:fail ${err.message}` });
1459
- onComplete?.();
1460
- }
1250
+ tmpFailHandler("fsGetFileInfo", cbs)
1461
1251
  );
1462
1252
  return;
1463
1253
  }
@@ -1498,17 +1288,11 @@ function fsGetFileInfo({ filePath, digestAlgorithm, success, fail, complete }) {
1498
1288
  }
1499
1289
  function fsSaveFile({ tempFilePath, filePath: _filePath, success, fail, complete }) {
1500
1290
  void _filePath;
1501
- const { onSuccess, onFail, onComplete } = bindCallbacks(this, { success, fail, complete });
1502
- if (!_fs) {
1503
- onFail?.({ errMsg: "fsSaveFile:fail not available in browser context" });
1504
- onComplete?.();
1505
- return;
1506
- }
1507
- const src = _fsResolveOrFail(tempFilePath, "fsSaveFile", onFail);
1508
- if (!src) {
1509
- onComplete?.();
1510
- return;
1511
- }
1291
+ const cbs = bindCallbacks(this, { success, fail, complete });
1292
+ const { onFail, onComplete } = cbs;
1293
+ if (guardFsAvailable("fsSaveFile", cbs)) return;
1294
+ const src = resolveOrBail(tempFilePath, "fsSaveFile", cbs);
1295
+ if (!src) return;
1512
1296
  const ext = _path.extname(tempFilePath) || "";
1513
1297
  const id = _crypto.randomUUID() + ext;
1514
1298
  const savedFilePath = `difile://_store/${id}`;
@@ -1519,27 +1303,10 @@ function fsSaveFile({ tempFilePath, filePath: _filePath, success, fail, complete
1519
1303
  return;
1520
1304
  }
1521
1305
  const destReal = destResolved.realPath;
1522
- function writeBytesToStore(bytes) {
1523
- _fs.mkdir(_path.dirname(destReal), { recursive: true }, (mkdirErr) => {
1524
- if (mkdirErr) {
1525
- onFail?.({ errMsg: `fsSaveFile:fail ${mkdirErr.message}` });
1526
- onComplete?.();
1527
- return;
1528
- }
1529
- _fs.writeFile(destReal, bytes, (err) => {
1530
- if (err) onFail?.({ errMsg: `fsSaveFile:fail ${err.message}` });
1531
- else onSuccess?.({ savedFilePath, errMsg: "fsSaveFile:ok" });
1532
- onComplete?.();
1533
- });
1534
- });
1535
- }
1536
1306
  if (src.kind === "tmp") {
1537
1307
  _tmpBytes(tempFilePath).then(
1538
- writeBytesToStore,
1539
- (err) => {
1540
- onFail?.({ errMsg: `fsSaveFile:fail ${err.message}` });
1541
- onComplete?.();
1542
- }
1308
+ (bytes) => mkdirpThenWrite(destReal, "fsSaveFile", cbs, (done) => _fs.writeFile(destReal, bytes, done), { savedFilePath }),
1309
+ tmpFailHandler("fsSaveFile", cbs)
1543
1310
  );
1544
1311
  return;
1545
1312
  }
@@ -1548,29 +1315,12 @@ function fsSaveFile({ tempFilePath, filePath: _filePath, success, fail, complete
1548
1315
  onComplete?.();
1549
1316
  return;
1550
1317
  }
1551
- _fs.mkdir(_path.dirname(destReal), { recursive: true }, (mkdirErr) => {
1552
- if (mkdirErr) {
1553
- onFail?.({ errMsg: `fsSaveFile:fail ${mkdirErr.message}` });
1554
- onComplete?.();
1555
- return;
1556
- }
1557
- _fs.copyFile(src.realPath, destReal, (err) => {
1558
- if (err) {
1559
- onFail?.({ errMsg: `fsSaveFile:fail ${err.message}` });
1560
- } else {
1561
- onSuccess?.({ savedFilePath, errMsg: "fsSaveFile:ok" });
1562
- }
1563
- onComplete?.();
1564
- });
1565
- });
1318
+ mkdirpThenWrite(destReal, "fsSaveFile", cbs, (done) => _fs.copyFile(src.realPath, destReal, done), { savedFilePath });
1566
1319
  }
1567
1320
  function fsGetSavedFileList({ success, fail, complete } = {}) {
1568
- const { onSuccess, onFail, onComplete } = bindCallbacks(this, { success, fail, complete });
1569
- if (!_fs) {
1570
- onFail?.({ errMsg: "fsGetSavedFileList:fail not available in browser context" });
1571
- onComplete?.();
1572
- return;
1573
- }
1321
+ const cbs = bindCallbacks(this, { success, fail, complete });
1322
+ const { onSuccess, onComplete } = cbs;
1323
+ if (guardFsAvailable("fsGetSavedFileList", cbs)) return;
1574
1324
  const storeVpath = resolveVPath("difile://_store/");
1575
1325
  const storeDir = storeVpath?.realPath;
1576
1326
  if (!storeDir) {
@@ -1610,56 +1360,25 @@ function fsGetSavedFileList({ success, fail, complete } = {}) {
1610
1360
  });
1611
1361
  }
1612
1362
  function fsRemoveSavedFile({ filePath, success, fail, complete }) {
1613
- const { onSuccess, onFail, onComplete } = bindCallbacks(this, { success, fail, complete });
1614
- if (!_fs) {
1615
- onFail?.({ errMsg: "fsRemoveSavedFile:fail not available in browser context" });
1616
- onComplete?.();
1617
- return;
1618
- }
1619
- const v = _fsResolveOrFail(filePath, "fsRemoveSavedFile", onFail);
1620
- if (!v) {
1621
- onComplete?.();
1622
- return;
1623
- }
1363
+ const cbs = bindCallbacks(this, { success, fail, complete });
1364
+ const { onFail, onComplete } = cbs;
1365
+ if (guardFsAvailable("fsRemoveSavedFile", cbs)) return;
1366
+ const v = resolveOrBail(filePath, "fsRemoveSavedFile", cbs);
1367
+ if (!v) return;
1624
1368
  if (v.kind !== "store" || !v.realPath) {
1625
1369
  onFail?.({ errMsg: "fsRemoveSavedFile:fail only _store/ entries may be removed" });
1626
1370
  onComplete?.();
1627
1371
  return;
1628
1372
  }
1629
- _fs.unlink(v.realPath, (err) => {
1630
- if (err) {
1631
- onFail?.({ errMsg: `fsRemoveSavedFile:fail ${err.message}` });
1632
- } else {
1633
- onSuccess?.({ errMsg: "fsRemoveSavedFile:ok" });
1634
- }
1635
- onComplete?.();
1636
- });
1373
+ _fs.unlink(v.realPath, nodeComplete("fsRemoveSavedFile", cbs));
1637
1374
  }
1638
1375
  function fsTruncate({ filePath, length = 0, success, fail, complete }) {
1639
- const { onSuccess, onFail, onComplete } = bindCallbacks(this, { success, fail, complete });
1640
- if (!_fs) {
1641
- onFail?.({ errMsg: "fsTruncate:fail not available in browser context" });
1642
- onComplete?.();
1643
- return;
1644
- }
1645
- const v = _fsResolveOrFail(filePath, "fsTruncate", onFail);
1646
- if (!v) {
1647
- onComplete?.();
1648
- return;
1649
- }
1650
- if (!v.writable || !v.realPath) {
1651
- _denyWrite("fsTruncate", onFail);
1652
- onComplete?.();
1653
- return;
1654
- }
1655
- _fs.truncate(v.realPath, length, (err) => {
1656
- if (err) {
1657
- onFail?.({ errMsg: `fsTruncate:fail ${err.message}` });
1658
- } else {
1659
- onSuccess?.({ errMsg: "fsTruncate:ok" });
1660
- }
1661
- onComplete?.();
1662
- });
1376
+ const cbs = bindCallbacks(this, { success, fail, complete });
1377
+ if (guardFsAvailable("fsTruncate", cbs)) return;
1378
+ const v = resolveOrBail(filePath, "fsTruncate", cbs);
1379
+ if (!v) return;
1380
+ if (!ensureWritable(v, "fsTruncate", cbs)) return;
1381
+ _fs.truncate(v.realPath, length, nodeComplete("fsTruncate", cbs));
1663
1382
  }
1664
1383
  var fsUnzip = notSupportedApi("fsUnzip");
1665
1384