core-3nweb-client-lib 0.21.0 → 0.22.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/build/api-defs/files.d.ts +8 -7
  2. package/build/core/asmail/inbox/attachments/fs.d.ts +2 -2
  3. package/build/core/asmail/inbox/attachments/fs.js +3 -2
  4. package/build/core/asmail/msg/common.d.ts +2 -2
  5. package/build/core/asmail/msg/common.js +3 -2
  6. package/build/core/asmail/msg/opener.d.ts +2 -2
  7. package/build/core/asmail/msg/opener.js +3 -2
  8. package/build/core/asmail/msg/packer.d.ts +2 -2
  9. package/build/core/asmail/msg/packer.js +7 -6
  10. package/build/core/storage/index.js +2 -2
  11. package/build/core/storage/local/obj-files.js +8 -5
  12. package/build/core/storage/local/obj-status.js +4 -3
  13. package/build/core/storage/synced/obj-status.js +4 -3
  14. package/build/ipc-via-protobuf/bytes.js +1 -1
  15. package/build/lib-client/3nstorage/xsp-fs/attrs.d.ts +28 -0
  16. package/build/lib-client/3nstorage/xsp-fs/attrs.js +337 -0
  17. package/build/lib-client/3nstorage/xsp-fs/common.d.ts +1 -1
  18. package/build/lib-client/3nstorage/xsp-fs/common.js +3 -2
  19. package/build/lib-client/3nstorage/xsp-fs/file-node.d.ts +31 -18
  20. package/build/lib-client/3nstorage/xsp-fs/file-node.js +130 -118
  21. package/build/lib-client/3nstorage/xsp-fs/file.d.ts +0 -1
  22. package/build/lib-client/3nstorage/xsp-fs/file.js +14 -49
  23. package/build/lib-client/3nstorage/xsp-fs/folder-node-serialization.d.ts +1 -1
  24. package/build/lib-client/3nstorage/xsp-fs/folder-node-serialization.js +95 -91
  25. package/build/lib-client/3nstorage/xsp-fs/folder-node.d.ts +19 -24
  26. package/build/lib-client/3nstorage/xsp-fs/folder-node.js +133 -190
  27. package/build/lib-client/3nstorage/xsp-fs/fs.d.ts +3 -4
  28. package/build/lib-client/3nstorage/xsp-fs/fs.js +18 -21
  29. package/build/lib-client/3nstorage/xsp-fs/link-node.d.ts +13 -8
  30. package/build/lib-client/3nstorage/xsp-fs/link-node.js +46 -38
  31. package/build/lib-client/3nstorage/xsp-fs/node-in-fs.d.ts +17 -35
  32. package/build/lib-client/3nstorage/xsp-fs/node-in-fs.js +34 -127
  33. package/build/lib-client/3nstorage/xsp-fs/node-persistence.d.ts +57 -0
  34. package/build/lib-client/3nstorage/xsp-fs/node-persistence.js +182 -0
  35. package/build/lib-client/3nstorage/xsp-fs/xsp-payload-v1.d.ts +3 -0
  36. package/build/lib-client/3nstorage/xsp-fs/xsp-payload-v1.js +87 -0
  37. package/build/lib-client/3nstorage/xsp-fs/xsp-payload-v2.d.ts +6 -0
  38. package/build/lib-client/3nstorage/xsp-fs/xsp-payload-v2.js +1022 -0
  39. package/build/lib-client/cryptor/cryptor-wasm.js +1 -1
  40. package/build/lib-client/cryptor/cryptor.wasm +0 -0
  41. package/build/lib-client/local-files/device-fs.js +7 -3
  42. package/build/lib-client/objs-on-disk/file-writing-proc.js +3 -2
  43. package/build/lib-client/objs-on-disk/obj-on-disk.js +8 -7
  44. package/build/lib-common/big-endian.d.ts +0 -24
  45. package/build/lib-common/big-endian.js +16 -78
  46. package/build/lib-common/exceptions/file.js +5 -1
  47. package/build/lib-common/obj-streaming/sink-utils.d.ts +0 -4
  48. package/build/lib-common/obj-streaming/sink-utils.js +4 -70
  49. package/build/lib-common/objs-on-disk/file-layout.js +2 -1
  50. package/build/lib-common/objs-on-disk/obj-file.js +2 -2
  51. package/build/lib-common/objs-on-disk/utils.js +2 -1
  52. package/build/lib-common/objs-on-disk/v1-obj-file-format.js +2 -1
  53. package/package.json +2 -2
  54. package/build/lib-client/files/file-attrs.d.ts +0 -76
  55. package/build/lib-client/files/file-attrs.js +0 -549
  56. package/build/lib-client/files/file-layout.d.ts +0 -56
  57. package/build/lib-client/files/file-layout.js +0 -456
  58. package/build/lib-client/files/file-sink.d.ts +0 -33
  59. package/build/lib-client/files/file-sink.js +0 -173
  60. package/build/lib-client/files/file-source.d.ts +0 -19
  61. package/build/lib-client/files/file-source.js +0 -115
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  /*
3
- Copyright (C) 2015 - 2020 3NSoft Inc.
3
+ Copyright (C) 2015 - 2020, 2022 3NSoft Inc.
4
4
 
5
5
  This program is free software: you can redistribute it and/or modify it under
6
6
  the terms of the GNU General Public License as published by the Free Software
@@ -13,7 +13,8 @@
13
13
  See the GNU General Public License for more details.
14
14
 
15
15
  You should have received a copy of the GNU General Public License along with
16
- this program. If not, see <http://www.gnu.org/licenses/>. */
16
+ this program. If not, see <http://www.gnu.org/licenses/>.
17
+ */
17
18
  Object.defineProperty(exports, "__esModule", { value: true });
18
19
  exports.FolderNode = void 0;
19
20
  /**
@@ -31,7 +32,8 @@ const json_utils_1 = require("../../../lib-common/json-utils");
31
32
  const xsp_files_1 = require("xsp-files");
32
33
  const random = require("../../../lib-common/random-node");
33
34
  const folder_node_serialization_1 = require("./folder-node-serialization");
34
- const file_attrs_1 = require("../../files/file-attrs");
35
+ const attrs_1 = require("./attrs");
36
+ const node_persistence_1 = require("./node-persistence");
35
37
  function jsonToInfoAndAttrs(json) {
36
38
  const folderInfo = {
37
39
  nodes: json_utils_1.copy(json.nodes)
@@ -40,50 +42,30 @@ function jsonToInfoAndAttrs(json) {
40
42
  node.key = buffer_utils_1.base64.open(node.key);
41
43
  }
42
44
  checkFolderInfo(folderInfo);
43
- if (json.attrs) {
44
- const attrs = file_attrs_1.AttrsHolder.fromJSONReadonly(json.attrs);
45
- return { attrs, folderInfo };
46
- }
47
- else {
48
- return { folderInfo };
49
- }
45
+ const attrs = new attrs_1.CommonAttrs(json.ctime, json.ctime);
46
+ return { attrs, folderInfo };
50
47
  }
51
- class FolderCrypto extends node_in_fs_1.NodeCrypto {
48
+ class FolderPersistance extends node_persistence_1.NodePersistance {
52
49
  constructor(zNonce, key, cryptor) {
53
50
  super(zNonce, key, cryptor);
54
51
  Object.seal(this);
55
52
  }
56
- async pack(folderInfo, version, attrs) {
57
- return this.saveBytes(folder_node_serialization_1.serializeFolderInfo(folderInfo), version, attrs);
53
+ async write(folderInfo, version, attrs, xattrs) {
54
+ const bytes = folder_node_serialization_1.serializeFolderInfo(folderInfo);
55
+ return this.writeWhole(bytes, version, attrs, xattrs);
58
56
  }
59
- async open(src) {
60
- try {
61
- const { attrs, content } = await this.readBytes(src);
62
- const folderInfo = folder_node_serialization_1.deserializeFolderInfo(content);
63
- if (attrs) {
64
- return {
65
- folderInfo,
66
- attrs: file_attrs_1.AttrsHolder.fromBytesReadonly(attrs)
67
- };
68
- }
69
- else {
70
- return { folderInfo };
71
- }
72
- }
73
- catch (err) {
74
- throw error_1.errWithCause(err, `Cannot open folder object`);
75
- }
57
+ async read(src) {
58
+ const { content, xattrs, attrs } = await this.readAll(src);
59
+ const folderInfo = folder_node_serialization_1.parseFolderInfo(content);
60
+ return { folderInfo, xattrs, attrs: attrs_1.CommonAttrs.fromAttrs(attrs) };
76
61
  }
77
62
  }
78
- Object.freeze(FolderCrypto.prototype);
79
- Object.freeze(FolderCrypto);
63
+ Object.freeze(FolderPersistance.prototype);
64
+ Object.freeze(FolderPersistance);
80
65
  class FolderNode extends node_in_fs_1.NodeInFS {
81
66
  constructor(storage, name, objId, zNonce, version, parentId, key, setNewAttrs) {
82
67
  super(storage, 'folder', name, objId, version, parentId);
83
68
  this.currentState = { nodes: {} };
84
- this.transitionState = undefined;
85
- this.transitionVersion = undefined;
86
- this.transitionSaved = false;
87
69
  if (!name && (objId || parentId)) {
88
70
  throw new Error("Root folder must " +
89
71
  "have both objId and parent as nulls.");
@@ -97,9 +79,9 @@ class FolderNode extends node_in_fs_1.NodeInFS {
97
79
  }
98
80
  zNonce = xsp_files_1.idToHeaderNonce(objId);
99
81
  }
100
- this.crypto = new FolderCrypto(zNonce, key, storage.cryptor);
82
+ this.crypto = new FolderPersistance(zNonce, key, storage.cryptor);
101
83
  if (setNewAttrs) {
102
- this.attrs = file_attrs_1.AttrsHolder.makeReadonlyForFolder(Date.now());
84
+ this.attrs = attrs_1.CommonAttrs.makeForTimeNow();
103
85
  }
104
86
  Object.seal(this);
105
87
  }
@@ -107,7 +89,7 @@ class FolderNode extends node_in_fs_1.NodeInFS {
107
89
  const zNonce = await random.bytes(xsp_files_1.NONCE_LENGTH);
108
90
  const rf = new FolderNode(storage, undefined, null, zNonce, 0, undefined, key, true);
109
91
  rf.storage.nodes.set(rf);
110
- await rf.saveFirstVersion();
92
+ await rf.saveFirstVersion(undefined);
111
93
  return rf;
112
94
  }
113
95
  static async rootFromObjBytes(storage, name, objId, src, key) {
@@ -122,9 +104,9 @@ class FolderNode extends node_in_fs_1.NodeInFS {
122
104
  }
123
105
  static async readNodeFromObjBytes(storage, name, objId, zNonce, src, key) {
124
106
  const rf = new FolderNode(storage, name, objId, zNonce, src.version, undefined, key, false);
125
- const { folderInfo, attrs } = await rf.crypto.open(src);
107
+ const { folderInfo, attrs, xattrs } = await rf.crypto.read(src);
126
108
  rf.currentState = folderInfo;
127
- rf.attrs = (attrs ? attrs : file_attrs_1.AttrsHolder.makeReadonlyForFolder(0));
109
+ rf.setUpdatedParams(src.version, attrs, xattrs);
128
110
  return rf;
129
111
  }
130
112
  static async rootFromLinkParams(storage, params) {
@@ -145,9 +127,9 @@ class FolderNode extends node_in_fs_1.NodeInFS {
145
127
  }
146
128
  static rootFromJSON(storage, name, folderJson) {
147
129
  const rf = new FolderNode(storage, name, 'readonly-root', EMPTY_ARR, 0, undefined, undefined, false);
148
- const { folderInfo, attrs } = jsonToInfoAndAttrs(folderJson);
130
+ const { folderInfo, attrs, xattrs } = jsonToInfoAndAttrs(folderJson);
149
131
  rf.currentState = folderInfo;
150
- rf.attrs = (attrs ? attrs : file_attrs_1.AttrsHolder.makeReadonlyForFolder(0));
132
+ rf.setUpdatedParams(0, attrs, xattrs);
151
133
  return rf;
152
134
  }
153
135
  list() {
@@ -267,15 +249,15 @@ class FolderNode extends node_in_fs_1.NodeInFS {
267
249
  return this.getNode('link', name, undefOnMissing);
268
250
  }
269
251
  async fixMissingChildAndThrow(exc, childInfo) {
270
- await this.doTransition(true, async () => {
271
- delete this.transitionState.nodes[childInfo.name];
252
+ await this.doTransition(async (state, version) => {
253
+ delete state.nodes[childInfo.name];
272
254
  const event = {
273
255
  type: 'entry-removal',
274
256
  path: this.name,
275
257
  name: childInfo.name,
276
- newVersion: this.transitionVersion
258
+ newVersion: version
277
259
  };
278
- this.broadcastEvent(event);
260
+ return event;
279
261
  }).catch(noop);
280
262
  const fileExc = file_1.makeFileException(file_1.Code.notFound, childInfo.name, exc);
281
263
  fileExc.inconsistentStateOfFS = true;
@@ -283,117 +265,59 @@ class FolderNode extends node_in_fs_1.NodeInFS {
283
265
  }
284
266
  /**
285
267
  * This method prepares a transition state, runs given action, and completes
286
- * transition to a new version. Returned promise resolves to whatever given
287
- * action returns (promise is unwrapped).
268
+ * transition to a new version.
288
269
  * Note that if there is already an ongoing change, this transition will
289
270
  * wait. Such behaviour is generally needed for folder as different processes
290
271
  * may be sharing same elements in a file tree. In contrast, file
291
272
  * operations should more often follow a throw instead wait approach.
292
- * @param autoSave true value turns on saving in of transition by this call,
293
- * while false value indicates that saving will be done within a given action
294
- * @param action is a function that is run when transition is started
273
+ * @param change is a function that is run when transition is started
295
274
  */
296
- doTransition(autoSave, action) {
297
- return this.doChange(true, this.wrapInTransition(autoSave, action));
298
- }
299
- wrapInTransition(autoSave, action) {
300
- return async () => {
301
- // start transition and prepare transition state
302
- // Note on copy: byte arrays are not cloned
303
- this.transitionState = json_utils_1.copy(this.currentState);
304
- this.transitionVersion = this.version + 1;
305
- try {
306
- // do action within transition state
307
- const result = await action();
308
- // return fast, if transaction was canceled
309
- if (!this.transitionState) {
310
- return result;
311
- }
312
- // save transition state, if saving hasn't been done inside of action
313
- if (autoSave) {
314
- await this.saveTransitionState();
315
- }
316
- // complete transition
317
- if (!this.transitionSaved) {
318
- throw new Error(`Transition state has not been saved`);
319
- }
320
- this.currentState = this.transitionState;
321
- this.setCurrentVersion(this.transitionVersion);
322
- return result;
323
- }
324
- finally {
325
- // cleanup after both completion and fail
326
- this.clearTransitionState();
327
- }
328
- };
329
- }
330
- clearTransitionState() {
331
- this.transitionState = undefined;
332
- this.transitionVersion = undefined;
333
- this.transitionSaved = false;
334
- }
335
- async saveTransitionState() {
336
- if (!this.transitionState || !this.transitionVersion) {
337
- throw new Error(`Transition is not set correctly`);
338
- }
339
- if (this.transitionSaved) {
340
- throw new Error(`Transition has already been saved.`);
341
- }
342
- const attrs = this.attrs.modifiableCopy();
343
- const encSub = await this.crypto.pack(this.transitionState, this.transitionVersion, attrs);
344
- await this.storage.saveObj(this.objId, this.transitionVersion, encSub);
345
- this.transitionSaved = true;
346
- attrs.setReadonly();
275
+ async doTransition(change) {
276
+ await this.doChange(true, () => this.performTransition(change));
277
+ }
278
+ async performTransition(change) {
279
+ // start transition and prepare transition state
280
+ // Note on copy: byte arrays are not cloned
281
+ const state = json_utils_1.copy(this.currentState);
282
+ const version = this.version + 1;
283
+ const attrs = this.attrs.copy();
284
+ // do action within transition state
285
+ const event = await change(state, version);
286
+ // save transition state
287
+ const encSub = await this.crypto.write(state, version, attrs, this.xattrs);
288
+ await this.storage.saveObj(this.objId, version, encSub);
289
+ // complete transition
290
+ this.currentState = state;
291
+ this.setCurrentVersion(version);
347
292
  this.attrs = attrs;
348
- }
349
- addToTransitionState(f, key) {
350
- const nodeInfo = {
351
- name: f.name,
352
- objId: f.objId,
353
- key
354
- };
355
- if (f.type === 'folder') {
356
- nodeInfo.isFolder = true;
357
- }
358
- else if (f.type === 'file') {
359
- nodeInfo.isFile = true;
360
- }
361
- else if (f.type === 'link') {
362
- nodeInfo.isLink = true;
363
- }
364
- else {
365
- throw new Error(`Unknown type of file system entity: ${f.type}`);
366
- }
367
- this.transitionState.nodes[nodeInfo.name] = nodeInfo;
293
+ this.broadcastEvent(event);
368
294
  }
369
295
  /**
370
296
  * This function only creates folder node, but it doesn't insert it anywhere.
371
297
  * @param name
372
298
  */
373
- async makeAndSaveNewChildFolderNode(name) {
299
+ async makeAndSaveNewChildFolderNode(name, changes) {
374
300
  const key = await random.bytes(xsp_files_1.KEY_LENGTH);
375
301
  const childObjId = await this.storage.generateNewObjId();
376
302
  const node = new FolderNode(this.storage, name, childObjId, undefined, 0, this.objId, key, true);
377
- await node.saveFirstVersion().catch((exc) => {
303
+ await node.saveFirstVersion(changes).catch((exc) => {
378
304
  if (!exc.objExists) {
379
305
  throw exc;
380
306
  }
381
307
  // call this method recursively, if obj id is already used in storage
382
- return this.makeAndSaveNewChildFolderNode(name);
308
+ return this.makeAndSaveNewChildFolderNode(name, changes);
383
309
  });
384
310
  return { node, key };
385
311
  }
386
- async saveFirstVersion() {
312
+ async saveFirstVersion(changes) {
387
313
  await this.doChange(false, async () => {
388
314
  if (this.version > 0) {
389
315
  throw new Error(`Can call this function only for zeroth version, not ${this.version}`);
390
316
  }
391
- this.setCurrentVersion(1);
392
- const attrs = this.attrs.modifiableCopy();
393
- const encSub = await this.crypto.pack(this.currentState, this.version, attrs);
394
- await this.storage.saveObj(this.objId, this.version, encSub);
395
- attrs.setReadonly();
396
- this.attrs = attrs;
317
+ const { attrs, xattrs, newVersion } = super.getParamsForUpdate(changes);
318
+ const encSub = await this.crypto.write(this.currentState, newVersion, attrs, xattrs);
319
+ await this.storage.saveObj(this.objId, newVersion, encSub);
320
+ super.setUpdatedParams(newVersion, attrs, xattrs);
397
321
  });
398
322
  }
399
323
  /**
@@ -420,7 +344,7 @@ class FolderNode extends node_in_fs_1.NodeInFS {
420
344
  async makeAndSaveNewChildLinkNode(name, params) {
421
345
  const key = await random.bytes(xsp_files_1.KEY_LENGTH);
422
346
  const node = await link_node_1.LinkNode.makeForNew(this.storage, this.objId, name, key);
423
- await node.setLinkParams(params).catch((exc) => {
347
+ await node.save(params).catch((exc) => {
424
348
  if (!exc.objExists) {
425
349
  throw exc;
426
350
  }
@@ -429,19 +353,17 @@ class FolderNode extends node_in_fs_1.NodeInFS {
429
353
  });
430
354
  return { node, key };
431
355
  }
432
- create(type, name, exclusive, linkParams) {
433
- return this.doTransition(false, async () => {
356
+ create(type, name, exclusive, changes, linkParams) {
357
+ return this.doChange(true, async () => {
434
358
  // do check for concurrent creation of a node
435
359
  if (this.getNodeInfo(name, true)) {
436
360
  if (exclusive) {
437
361
  throw file_1.makeFileException(file_1.Code.alreadyExists, name);
438
362
  }
439
363
  else if (type === 'folder') {
440
- this.clearTransitionState();
441
364
  return (await this.getNode('folder', name));
442
365
  }
443
366
  else if (type === 'file') {
444
- this.clearTransitionState();
445
367
  return (await this.getNode('file', name));
446
368
  }
447
369
  else if (type === 'link') {
@@ -451,62 +373,63 @@ class FolderNode extends node_in_fs_1.NodeInFS {
451
373
  throw new Error(`Unknown type of node: ${type}`);
452
374
  }
453
375
  }
454
- // create new node
455
- let node;
456
- let key;
457
- if (type === 'file') {
458
- ({ node, key } = await this.makeAndSaveNewChildFileNode(name));
459
- }
460
- else if (type === 'folder') {
461
- ({ node, key } = await this.makeAndSaveNewChildFolderNode(name));
462
- }
463
- else if (type === 'link') {
464
- ({ node, key } = await this.makeAndSaveNewChildLinkNode(name, linkParams));
465
- }
466
- else {
467
- throw new Error(`Unknown type of node: ${type}`);
468
- }
469
- this.addToTransitionState(node, key);
470
- await this.saveTransitionState(); // manual save
471
- this.storage.nodes.set(node);
472
- const event = {
473
- type: 'entry-addition',
474
- path: this.name,
475
- newVersion: this.transitionVersion,
476
- entry: {
477
- name: node.name,
478
- isFile: (node.type === 'file'),
479
- isFolder: (node.type === 'folder'),
480
- isLink: (node.type === 'link')
376
+ let node = undefined;
377
+ await this.performTransition(async (state, version) => {
378
+ // create new node
379
+ let key;
380
+ if (type === 'file') {
381
+ ({ node, key } = await this.makeAndSaveNewChildFileNode(name));
481
382
  }
482
- };
483
- this.broadcastEvent(event);
383
+ else if (type === 'folder') {
384
+ ({ node, key } = await this.makeAndSaveNewChildFolderNode(name, changes));
385
+ }
386
+ else if (type === 'link') {
387
+ ({ node, key } = await this.makeAndSaveNewChildLinkNode(name, linkParams));
388
+ }
389
+ else {
390
+ throw new Error(`Unknown type of node: ${type}`);
391
+ }
392
+ addToTransitionState(state, node, key);
393
+ this.storage.nodes.set(node);
394
+ const event = {
395
+ type: 'entry-addition',
396
+ path: this.name,
397
+ newVersion: version,
398
+ entry: {
399
+ name: node.name,
400
+ isFile: (node.type === 'file'),
401
+ isFolder: (node.type === 'folder'),
402
+ isLink: (node.type === 'link')
403
+ }
404
+ };
405
+ return event;
406
+ });
484
407
  return node;
485
408
  });
486
409
  }
487
- createFolder(name, exclusive) {
488
- return this.create('folder', name, exclusive);
410
+ createFolder(name, exclusive, changes) {
411
+ return this.create('folder', name, exclusive, changes);
489
412
  }
490
413
  createFile(name, exclusive) {
491
414
  return this.create('file', name, exclusive);
492
415
  }
493
416
  async createLink(name, params) {
494
- await this.create('link', name, true, params);
417
+ await this.create('link', name, true, undefined, params);
495
418
  }
496
419
  async removeChild(f) {
497
- await this.doTransition(true, async () => {
498
- const childJSON = this.transitionState.nodes[f.name];
420
+ await this.doTransition(async (state, version) => {
421
+ const childJSON = state.nodes[f.name];
499
422
  if (!childJSON || (childJSON.objId !== f.objId)) {
500
423
  throw new Error(`Not a child given: name==${f.name}, objId==${f.objId}, parentId==${f.parentId}, this folder objId==${this.objId}`);
501
424
  }
502
- delete this.transitionState.nodes[f.name];
425
+ delete state.nodes[f.name];
503
426
  const event = {
504
427
  type: 'entry-removal',
505
428
  path: this.name,
506
429
  name: f.name,
507
- newVersion: this.transitionVersion
430
+ newVersion: version
508
431
  };
509
- this.broadcastEvent(event);
432
+ return event;
510
433
  });
511
434
  // explicitly do not wait on a result of child's delete, cause if it fails
512
435
  // we just get traceable garbage, yet, the rest of a live/non-deleted tree
@@ -514,10 +437,10 @@ class FolderNode extends node_in_fs_1.NodeInFS {
514
437
  f.localDelete();
515
438
  }
516
439
  changeChildName(initName, newName) {
517
- return this.doTransition(true, async () => {
518
- const child = this.transitionState.nodes[initName];
519
- delete this.transitionState.nodes[child.name];
520
- this.transitionState.nodes[newName] = child;
440
+ return this.doTransition(async (state, version) => {
441
+ const child = state.nodes[initName];
442
+ delete state.nodes[child.name];
443
+ state.nodes[newName] = child;
521
444
  child.name = newName;
522
445
  const childNode = this.storage.nodes.get(child.objId);
523
446
  if (childNode) {
@@ -528,9 +451,9 @@ class FolderNode extends node_in_fs_1.NodeInFS {
528
451
  path: this.name,
529
452
  newName,
530
453
  oldName: initName,
531
- newVersion: this.transitionVersion
454
+ newVersion: version
532
455
  };
533
- this.broadcastEvent(event);
456
+ return event;
534
457
  });
535
458
  }
536
459
  async moveChildTo(childName, dst, nameInDst) {
@@ -549,22 +472,22 @@ class FolderNode extends node_in_fs_1.NodeInFS {
549
472
  ]);
550
473
  }
551
474
  async moveChildOut(name) {
552
- await this.doTransition(true, async () => {
553
- delete this.transitionState.nodes[name];
475
+ await this.doTransition(async (state, version) => {
476
+ delete state.nodes[name];
554
477
  const event = {
555
478
  type: 'entry-removal',
556
479
  path: this.name,
557
480
  name,
558
- newVersion: this.transitionVersion
481
+ newVersion: version
559
482
  };
560
- this.broadcastEvent(event);
483
+ return event;
561
484
  });
562
485
  }
563
486
  async moveChildIn(newName, child) {
564
487
  child = json_utils_1.copy(child);
565
- await this.doTransition(true, async () => {
488
+ await this.doTransition(async (state, version) => {
566
489
  child.name = newName;
567
- this.transitionState.nodes[child.name] = child;
490
+ state.nodes[child.name] = child;
568
491
  const event = {
569
492
  type: 'entry-addition',
570
493
  path: this.name,
@@ -574,9 +497,9 @@ class FolderNode extends node_in_fs_1.NodeInFS {
574
497
  isFolder: child.isFolder,
575
498
  isLink: child.isLink
576
499
  },
577
- newVersion: this.transitionVersion
500
+ newVersion: version
578
501
  };
579
- this.broadcastEvent(event);
502
+ return event;
580
503
  });
581
504
  }
582
505
  async getFolderInThisSubTree(path, createIfMissing = false, exclusiveCreate = false) {
@@ -604,7 +527,7 @@ class FolderNode extends node_in_fs_1.NodeInFS {
604
527
  throw err;
605
528
  }
606
529
  try {
607
- f = await this.createFolder(path[0], exclusiveCreate);
530
+ f = await this.createFolder(path[0], exclusiveCreate, undefined);
608
531
  }
609
532
  catch (exc) {
610
533
  if (exc.alreadyExists && !exclusiveCreate) {
@@ -704,7 +627,7 @@ class FolderNode extends node_in_fs_1.NodeInFS {
704
627
  if (newVersion <= this.version) {
705
628
  return;
706
629
  }
707
- const { folderInfo, attrs } = await this.crypto.open(src);
630
+ const { folderInfo, attrs } = await this.crypto.read(src);
708
631
  const initState = this.currentState;
709
632
  this.currentState = checkFolderInfo(folderInfo);
710
633
  this.setCurrentVersion(newVersion);
@@ -765,4 +688,24 @@ function checkFolderInfo(folderJson) {
765
688
  // TODO throw if folderJson is not ok
766
689
  return folderJson;
767
690
  }
691
+ function addToTransitionState(state, f, key) {
692
+ const nodeInfo = {
693
+ name: f.name,
694
+ objId: f.objId,
695
+ key
696
+ };
697
+ if (f.type === 'folder') {
698
+ nodeInfo.isFolder = true;
699
+ }
700
+ else if (f.type === 'file') {
701
+ nodeInfo.isFile = true;
702
+ }
703
+ else if (f.type === 'link') {
704
+ nodeInfo.isLink = true;
705
+ }
706
+ else {
707
+ throw new Error(`Unknown type of file system entity: ${f.type}`);
708
+ }
709
+ state.nodes[nodeInfo.name] = nodeInfo;
710
+ }
768
711
  Object.freeze(exports);
@@ -1,9 +1,8 @@
1
- import { FolderNode, FolderLinkParams, FolderInfoWithAttrs } from './folder-node';
1
+ import { FolderNode, FolderLinkParams, FolderInJSON } from './folder-node';
2
2
  import { FileNode } from './file-node';
3
3
  import { Storage } from './common';
4
4
  import { LinkParameters } from '../../files';
5
5
  import { NodeInFS } from './node-in-fs';
6
- import { EntityAttrs } from '../../files/file-attrs';
7
6
  declare type Stats = web3n.files.Stats;
8
7
  declare type FS = web3n.files.FS;
9
8
  declare type WritableFS = web3n.files.WritableFS;
@@ -46,7 +45,7 @@ export declare class XspFS implements WritableFS {
46
45
  * @param key is a file key of a root object
47
46
  */
48
47
  static fromExistingRoot(storage: Storage, key: Uint8Array): Promise<WritableFS>;
49
- static fromASMailMsgRootFromJSON(storage: Storage, folderJson: FolderInfoWithAttrs, rootName?: string): ReadonlyFS;
48
+ static fromASMailMsgRootFromJSON(storage: Storage, folderJson: FolderInJSON, rootName?: string): ReadonlyFS;
50
49
  /**
51
50
  * Note that this method doesn't close storage.
52
51
  */
@@ -97,7 +96,7 @@ declare class V implements WritableFSVersionedAPI {
97
96
  root: FolderNode;
98
97
  constructor();
99
98
  getOrCreateFile(path: string, flags: FileFlags): Promise<FileNode>;
100
- get(path: string): Promise<NodeInFS<any, EntityAttrs>>;
99
+ get(path: string): Promise<NodeInFS<any>>;
101
100
  updateXAttrs(path: string, changes: XAttrsChanges): Promise<number>;
102
101
  getXAttr(path: string, xaName: string): Promise<{
103
102
  attr: any;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  /*
3
- Copyright (C) 2015 - 2020 3NSoft Inc.
3
+ Copyright (C) 2015 - 2020, 2022 3NSoft Inc.
4
4
 
5
5
  This program is free software: you can redistribute it and/or modify it under
6
6
  the terms of the GNU General Public License as published by the Free Software
@@ -36,7 +36,8 @@ function splitPathIntoParts(path) {
36
36
  }
37
37
  function setExcPath(path) {
38
38
  return (exc) => {
39
- if (exc.notFound || exc.notDirectory || exc.alreadyExists || exc.notFile) {
39
+ if (exc.notFound || exc.notDirectory || exc.alreadyExists
40
+ || exc.notFile) {
40
41
  exc.path = path;
41
42
  }
42
43
  throw exc;
@@ -189,27 +190,25 @@ class XspFS {
189
190
  }
190
191
  async stat(path) {
191
192
  const node = await this.v.get(path);
193
+ const attrs = node.getAttrs();
194
+ const stats = {
195
+ ctime: new Date(attrs.ctime),
196
+ mtime: new Date(attrs.mtime),
197
+ version: node.version,
198
+ writable: this.writable,
199
+ };
192
200
  if (node.type === 'file') {
193
- const { src, version } = await node.readSrc();
194
- return {
195
- isFile: true,
196
- writable: this.writable,
197
- size: await src.getSize(),
198
- version
199
- };
201
+ stats.size = node.size;
202
+ stats.isFile = true;
203
+ return stats;
200
204
  }
201
205
  else if (node.type === 'folder') {
202
- return {
203
- isFolder: true,
204
- writable: this.writable,
205
- version: node.version
206
- };
206
+ stats.isFolder = true;
207
+ return stats;
207
208
  }
208
209
  else if (node.type === 'link') {
209
- return {
210
- writable: false,
211
- isLink: true
212
- };
210
+ stats.isLink = true;
211
+ return stats;
213
212
  }
214
213
  else {
215
214
  throw new Error(`Unknown type of fs node`);
@@ -515,9 +514,7 @@ class V {
515
514
  }
516
515
  async readBytes(path, start, end) {
517
516
  const file = await this.getOrCreateFile(path, {});
518
- const { src, version } = await file.readSrc();
519
- const bytes = await file_2.readBytesFrom(src, start, end);
520
- return { bytes, version };
517
+ return await file.readBytes(start, end);
521
518
  }
522
519
  writeTxtFile(path, txt, flags = WRITE_NONEXCL_FLAGS) {
523
520
  const bytes = buffer_utils_1.utf8.pack(txt);