datafolder 1.0.5 → 1.0.7

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 (49) hide show
  1. package/README.md +5 -0
  2. package/internal.md +119 -0
  3. package/package.json +2 -2
  4. package/sample.js +19 -19
  5. package/scripts/convertBinFiles.js +49 -0
  6. package/scripts/fastify.js +2 -2
  7. package/src/QyAcl.js +44 -44
  8. package/src/QyAclSaver_Worker.js +2 -2
  9. package/src/QyAclWriter.js +1 -1
  10. package/src/QyBatch.js +1 -3
  11. package/src/QyBinWriter.js +65 -66
  12. package/src/QyCD.js +72 -27
  13. package/src/QyCache.js +39 -33
  14. package/src/QyDB.js +4 -30
  15. package/src/QyDefaultOptions.js +2 -1
  16. package/src/QyFetch.js +4 -22
  17. package/src/QyFileLogger.js +2 -2
  18. package/src/QyKVData.js +168 -183
  19. package/src/QyKVDataCleaner_Worker.js +15 -14
  20. package/src/QyKVDataSaver_Worker.js +20 -20
  21. package/src/QyLogFileSaver.js +1 -1
  22. package/src/QyLogFileSaver_Worker.js +2 -2
  23. package/src/QyMod.js +7 -7
  24. package/src/QyOpRunner.js +19 -16
  25. package/src/QySnapshotCompactor_Worker.js +54 -52
  26. package/src/QySnapshotSaver_Worker.js +55 -53
  27. package/src/QySnapshots.js +157 -147
  28. package/src/QyUnionNode.js +2 -2
  29. package/src/rpc/evalCode.js +4 -4
  30. package/src/rpc/getFileContent.js +4 -4
  31. package/src/rpc/getSubItems.js +12 -12
  32. package/src/rpc/getTriggerFiles.js +1 -0
  33. package/src/rpc/queryFiles.js +1 -1
  34. package/src/soc_pokec.js +7 -7
  35. package/static/codemirror.bundle/editor.bundle.js +27906 -0
  36. package/static/datafolderui/QyStyledElement.js +6 -15
  37. package/static/datafolderui/QyUIFolderTree.js +130 -145
  38. package/static/datafolderui/QyUIFolderViewer.js +210 -0
  39. package/static/datafolderui/QyUIUtils.js +10 -5
  40. package/static/datafolderui/code-mirror.js +35 -0
  41. package/static/datafolderui/display-tree.js +21 -94
  42. package/static/datafolderui/explore-tree.js +66 -81
  43. package/static/datafolderui/folder-tree.js +71 -2
  44. package/static/datafolderui/index.css +7 -0
  45. package/static/datafolderui/index.html +1 -0
  46. package/static/datafolderui/json-view.js +7 -3
  47. package/static/datafolderui/main-page.js +42 -60
  48. package/static/datafolderui/query-editor.js +178 -198
  49. package/static/datafolderui/trigger-editor.js +30 -0
package/README.md CHANGED
@@ -2,6 +2,11 @@
2
2
 
3
3
  datafolder is a lightweight JSON database, featuring an AI-friendly API for simple and human maintainable code generation, millisecond data response, with full index and trigger features supported, and the unique ability to browse and manage data as a folder tree directly in your browser. It works perfectly for a wide range of scenarios, from game/application backends to embedded systems to IoT to edge computing.
4
4
 
5
+ ### Changelog
6
+
7
+ 1.0.7 Added trigger editor and [internal.md](https://github.com/datafolderdev/datafolder/wiki/Internals-of-datafolder)
8
+ 1.0.6 Added code mirror as the query editor.
9
+
5
10
  ## Installation
6
11
 
7
12
  ```javascript
package/internal.md ADDED
@@ -0,0 +1,119 @@
1
+ ## Internals of datafolder
2
+
3
+ The best mechanism to index and partition data is **by the nature of data**. Instead of forcing data to transform, it should seamlessly embrace and fully cater to the **uniqueness** of each and every data to accomplish nature-level efficiency, **mentally and mechanically**. Whatever data is, it follows like fluid.
4
+
5
+ This is the **design philosophy** behind datafolder, a lightweight schemaless JSON database, featuring an AI-friendly API for simple and human maintainable code generation, millisecond data response, with full index and trigger features supported, and the unique ability to browse and manage data as a folder tree directly in your browser. It works perfectly for a wide range of scenarios, from game/application backends to embedded systems to IoT to edge computing.
6
+
7
+ ### User Level Data Layout
8
+
9
+ Data can be organized naturally into folders, sub folders and files. For example, Orders can be stored in
10
+
11
+ ```
12
+ orders/{year}/{month}/{day}/{order_id}
13
+ ```
14
+
15
+ Flights can be stored as
16
+
17
+ ```
18
+ flights/{from}/{to}/{flight_id}
19
+ ```
20
+
21
+ Airports can be stored as
22
+
23
+ ```
24
+ airports/{country}/{state}/{airport_id}
25
+ ```
26
+
27
+ When you conceive the data model, you don't need to think about tables, schemas, indexes etc. All you need to know is the nature of the data and then goes with the most comfortable one for your mental mind.
28
+
29
+ ### In-memory Tree Structure
30
+
31
+ datafolder uses a tree structure to store the folder/file relationship in memory. Each node has a subdir map and a file map. subdir map stores subdir nodes, which in turn has its subdir map. file map stores the files that are inside this folder. JSON data is stored as file content within each file node. They are all normal Javascript Objects themselves. Thanks to V8 engine's highly optimized object [property](https://v8.dev/blog/fast-properties) [access](https://v8.dev/docs/hidden-classes), getting the dir/file node by path and getting properties from JSON data are extremely fast. These dir/file node and file content can be loaded beforehand, or loaded on demand. And will be released according to visiting time/count to reduce runtime memory usage.
32
+
33
+ ### Lock Free, Always Sync, Immediate Programming Mode
34
+
35
+ When dealing with datafolder, you write your Node.js code in a lock free, always sync, immediate programming mode.
36
+
37
+ - The data are just normal Javascript objects and live within the same memory space of your code. No network traffic, no serialization/deserialization, no overhead. You code directly manipulates the data.
38
+ - No need to worry about whether data is modified by others during your changes. No need to guard data corruption with a transaction.
39
+ - You get the needed data, exam them, make your decisions and changes, and store them back. That is it.
40
+ - datafolder's underlying mechanism guarantees the correctness of running your code in this mode.
41
+ - start() and stop() are the only two APIs that need be called with await. All other APIs are called synchronously.
42
+
43
+ ### Accumulated Change List
44
+
45
+ datafolder make changes immediately in memory. It calculates deltas of such changes and store these deltas in a log file called acl file. Since only storing deltas, these changes are compact. datafolder utilize Node.js's processes and offload the actual acl storing work to separate process. In fact, this change stream is also sent out to other processes to create snapshots, read-only replicas and to compress snapshots etc.
46
+ These deltas can be of the following types:
47
+
48
+ 1. Adding a subdir or file to a dir.
49
+ 2. Deleting a subdir or file from a dir.
50
+ 3. Delete a dir or a file itself.
51
+ 4. Merging JSON changes.
52
+
53
+ JSON changes are further separated into the following:
54
+
55
+ 1. Deleting a property
56
+ 2. Adding a property with value.
57
+ 3. Changing a property to new value.
58
+
59
+ These deltas are appended to the acl log file in sequence. Once the log file reaches a certain size a new log file will be created and appended to. Storing these acl1, acl2, ...,acln files keep the change history of the whole database. The whole data can be reconstructed by replying these acl files in sequence.
60
+
61
+ ### Snapshots
62
+
63
+ The whole data changes are stored as acl1, acl2, acl3,..., acln files. But the reconstruct process takes time to read and apply all these acl files. In order to reduce reconstruction time snapshots are introduced. They store the exact shapes and contents of the items changed after a certain acl file. For example,
64
+
65
+ ```
66
+ acl1, snapshot1, acl2, snapshot2, acl3, snapshot3, acl4, acl5, snapshot5, ...
67
+ ```
68
+
69
+ snapshot1 will store the whole data afte applying acl1. It will shadow acl1.
70
+
71
+ snapshot2 will store the whole changes that are introduced by applying acl2 and will shadow acl2. That is, if a dir/file is changed during acl2, it will be stored as whole in snapshot2 and will shadow the one in snapshot1. If a dir/file is not changed during acl2, it will remain intact in snapshot1.
72
+
73
+ The same as snapshot3, snapshot5 etc. They only contain changed items after the last snapshots. This way the whole data is constructed by various snapshots and the following acls. Since snapshots are holding the whole items, they don't need reconstruction but only need to be able to read a certain dir/file and content out.
74
+
75
+ ### Snapshot Indexes
76
+
77
+ Each Snapshot is a big key value pair map. It is stored in two files: posMap file and valueList file.
78
+
79
+ - posMap file is storing the [start, length] of the content of each key in the valueList file.
80
+ - valueList file is storing the values of this snapshot.
81
+
82
+ For example,
83
+ posMap file contains
84
+
85
+ ```
86
+ key1 [0, 28]
87
+ key2 [28, 128]
88
+ key3 ...
89
+ ```
90
+
91
+ valueList file contains
92
+
93
+ ```
94
+ content1 (from 0, length 28)
95
+ content2 (from 28, length 128)
96
+ content3 (...)
97
+ ```
98
+
99
+ In this format, when posMap is loaded we can read arbitrary key content from valueList file. But if posMap is big, itself will be indexed using prefixPM file.
100
+ prefixPM file is storing the [start, length] of each prefix (like the first 2 characthers of keys) to the posMap file.
101
+
102
+ ```
103
+ prefix1 [0, 38]
104
+ prefix2 [38, 120]
105
+ ```
106
+
107
+ This way we only need to load prefixPM files in memory. Corresponding posmap content and valueList content can be loaded on-demand.
108
+
109
+ For example, we can store 20 years of [Hacker](https://news.ycombinator.com/item?id=46435308) [News](https://github.com/DOSAYGO-STUDIO/HackerBook) which is 22GB into datafolder in the layout of
110
+
111
+ ```
112
+ hackernews/{year}/{month}/{day}/{id}
113
+ ```
114
+
115
+ And each file contains the full story and the nested comments in a Javascript object. Even with 22GB contents, since they are partitioned naturally and each folder only contains a few thousands files they can be read via datafolder UI directly within the browser.
116
+
117
+ ### Snapshot Shadowing and Compaction
118
+
119
+ The same key with updated values will be stored in multiple snapshots and the latest one shadows all previous ones. At some point, thes redundant key/values will take up too much disc space. datafolder can automatically detect the threshold, and save the snapshots into new compacted ones with these redundances removed. These compactions are done in different processes and won't use the main process's time.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "datafolder",
3
- "version": "1.0.5",
3
+ "version": "1.0.7",
4
4
  "author": {
5
5
  "name": "lysh",
6
6
  "email": "datafolderdev@outlook.com"
@@ -11,7 +11,7 @@
11
11
  "type": "git",
12
12
  "url": "git+https://github.com/datafolderdev/datafolder"
13
13
  },
14
- "homepage": "https://github.com/datafolderdev/datafolder",
14
+ "homepage": "https://github.com/datafolderdev/datafolder/wiki/Internals-of-datafolder",
15
15
  "bugs": {
16
16
  "url": "https://github.com/datafolderdev/datafolder/issues",
17
17
  "email": "datafolderdev@outlook.com"
package/sample.js CHANGED
@@ -5,33 +5,33 @@ run();
5
5
 
6
6
  async function run() {
7
7
  await dataFolder.start();
8
- dataFolder.insert("users/2026/user_0001", {
8
+ dataFolder.insert("traindata/2026/1/20/chat_0001", {
9
9
  userid: "user_0001",
10
10
  email: "a@b.com",
11
- password: "123",
12
- score: 5,
11
+ feedbackScore: 5,
13
12
  address: { city: "a", zipcode: 123 },
14
13
  });
15
- dataFolder.insert("users/2026/user_0002", {
16
- userid: "user_0002",
17
- email: "c@b.com",
18
- password: "333",
19
- score: 3,
20
- address: { city: "b", zipcode: 321 },
21
- });
22
- const { email, password, address, score } = dataFolder.view("users/2026/user_0002");
23
- logger.log(email, password, score, address);
14
+ dataFolder.insert("traindata/2026/1/20/chat_0001/prompt", "What is async/await?");
15
+ dataFolder.insert("traindata/2026/1/20/chat_0001/answer", "async/await is ...");
16
+ const { userid, email, address, feedbackScore } = dataFolder.view("traindata/2026/1/20/chat_0001");
17
+ logger.log(userid, email, feedbackScore, address);
24
18
  address.zipcode = 678;
25
- dataFolder.insert("users/2026/user_0002", { score: score + 1, address });
26
- logger.log(dataFolder.view("users/2026/user_0002", ["score", "address"]));
19
+ dataFolder.insert("traindata/2026/1/20/chat_0001", { feedbackScore: feedbackScore + 1, address });
20
+ logger.log(dataFolder.view("traindata/2026/1/20/chat_0001", ["feedbackScore", "address"]));
21
+ logger.log(dataFolder.view("traindata/2026/1/20/chat_0001/prompt"));
22
+ logger.log(dataFolder.view("traindata/2026/1/20/chat_0001/answer"));
27
23
  await dataFolder.stop();
28
24
  await dataFolder.start();
29
25
  {
30
- const file = dataFolder.file("users/2026/user_0002");
31
- const { email, password, score } = file.view();
32
- logger.log(email, password, score);
33
- dataFolder.insert(file, { score: score + 1 });
34
- logger.log(file.view());
26
+ const file = dataFolder.file("traindata/2026/1/20/chat_0001");
27
+ const { email, feedbackScore } = file.view();
28
+ logger.log(email, feedbackScore);
29
+ dataFolder.insert(file, { feedbackScore: feedbackScore + 1 });
30
+ logger.log(
31
+ file.view(),
32
+ dataFolder.view("traindata/2026/1/20/chat_0001/prompt"),
33
+ dataFolder.view("traindata/2026/1/20/chat_0001/answer"),
34
+ );
35
35
  }
36
36
  await dataFolder.stop();
37
37
  }
@@ -0,0 +1,49 @@
1
+ import { join, basename } from "node:path";
2
+ import { readFile, readdir, writeFile } from "node:fs/promises";
3
+
4
+ import { iterPMBuffer, loadPrefixPMFile } from "../src/QySnapshots.js";
5
+ import { ensureDir, folderOrFileExists } from "../src/QyUtils.js";
6
+
7
+ logger.level = "info";
8
+
9
+ run();
10
+
11
+ async function loadPosMapFile(posMapFilePath) {
12
+ const buffer = await readFile(posMapFilePath);
13
+ const posMap = {};
14
+ iterPMBuffer(buffer, (key, nums) => (posMap[key] = nums));
15
+ return posMap;
16
+ }
17
+
18
+ async function run() {
19
+ const folderPath = process.argv[2];
20
+ let destFolderPath = process.argv[3];
21
+ if (!folderPath || !destFolderPath) {
22
+ console.log(`Usage: node ${basename(import.meta.filename)} folder/to/convert folder/to/save or inplace`);
23
+ } else {
24
+ if (destFolderPath == "inplace") destFolderPath = folderPath;
25
+ await convertFolder(folderPath, destFolderPath);
26
+ }
27
+ }
28
+
29
+ async function convertFolder(folder, destFolder) {
30
+ const promises = [];
31
+ for (const item of await readdir(folder, { withFileTypes: true })) {
32
+ const { name } = item;
33
+ if (item.isDirectory()) {
34
+ promises.push(convertFolder(join(folder, name), join(destFolder, name)));
35
+ } else {
36
+ const match = /^[0-9]+_(pM|prefixPM)\.txt/.exec(name);
37
+ if (match) {
38
+ const filePath = join(folder, name);
39
+ const destFilePath = join(destFolder, "dump_" + name + ".json");
40
+ if (await folderOrFileExists(destFilePath)) continue;
41
+ await ensureDir(destFolder);
42
+ console.log(`Converting ${filePath} -> ${destFilePath}`);
43
+ const map = await (match[1] == "pM" ? loadPosMapFile(filePath) : loadPrefixPMFile(filePath));
44
+ promises.push(writeFile(destFilePath, JSON.stringify(map, null, 2)));
45
+ }
46
+ }
47
+ }
48
+ await Promise.all(promises);
49
+ }
@@ -16,7 +16,7 @@ const { port, staticRoot } = config;
16
16
 
17
17
  const fastify = Fastify({ logger: false, forceCloseConnections: true });
18
18
 
19
- const qyDB = new QyDB();
19
+ const qyDB = new QyDB(join(__dirname, "../tmp/QyTrigger/1"));
20
20
 
21
21
  let sigintReceived = false;
22
22
 
@@ -45,7 +45,7 @@ async function insertRpcs() {
45
45
 
46
46
  async function handleGet(request, reply) {
47
47
  const { query, params } = request;
48
- const result = await qyDB.callRpc(params.funName, JSON.parse(query.args));
48
+ const result = await qyDB.callRpc(params.funName, query && query.args ? JSON.parse(query.args) : undefined);
49
49
  if (Error.isError(result)) {
50
50
  logger.warn(result.message);
51
51
  }
package/src/QyAcl.js CHANGED
@@ -2,13 +2,13 @@ import u from "node:fs/promises";
2
2
 
3
3
  import {
4
4
  mergeContent as m,
5
- mergeContentChanges as s,
5
+ mergeContentChanges as n,
6
6
  setValByNamePath as a
7
7
  } from "./QyFileContentUtils.js";
8
8
 
9
9
  import {
10
10
  isEmptyObj as g,
11
- arrayLast as n
11
+ arrayLast as s
12
12
  } from "./QyUtils.js";
13
13
 
14
14
  import {
@@ -20,14 +20,14 @@ function r(r, e) {
20
20
  A: r,
21
21
  R: t,
22
22
  M: a,
23
- D: n
23
+ D: s
24
24
  } = r;
25
- n && delete n[e], e.startsWith("c") ? a && delete a[e] : (r && delete r[e],
25
+ s && delete s[e], e.startsWith("c") ? a && delete a[e] : (r && delete r[e],
26
26
  t && delete t[e]);
27
27
  }
28
28
 
29
29
  function e(r, e) {
30
- var t, a, n, s, {
30
+ var t, a, s, n, {
31
31
  D: e,
32
32
  A: i,
33
33
  R: o,
@@ -38,27 +38,27 @@ function e(r, e) {
38
38
  var c, l = r[a] || (r[a] = {});
39
39
  for (c of i[a]) l[c] = 1;
40
40
  }
41
- for (n in o) {
42
- var u = r[n];
41
+ for (s in o) {
42
+ var u = r[s];
43
43
  if (u) {
44
- var d = o[n];
44
+ var d = o[s];
45
45
  if (d) {
46
46
  for (var h of d) delete u[h];
47
- g(u) && (r[n] = void 0);
47
+ g(u) && (r[s] = void 0);
48
48
  }
49
49
  }
50
50
  }
51
- for (s in f) r[s] = m(r[s], f[s]);
51
+ for (n in f) r[n] = m(r[n], f[n]);
52
52
  }
53
53
 
54
54
  function t(r, e) {
55
55
  var t, {
56
56
  D: r,
57
57
  A: a,
58
- R: n,
59
- M: s
58
+ R: s,
59
+ M: n
60
60
  } = r;
61
- for (t of [ r, a, n, s ]) for (var i in t) e(i);
61
+ for (t of [ r, a, s, n ]) for (var i in t) e(i);
62
62
  }
63
63
 
64
64
  class i {
@@ -85,10 +85,10 @@ class i {
85
85
 
86
86
  case "M":
87
87
  {
88
- var n = this.cmdArgAsMapObj;
89
- let r = n.M;
90
- n = (r = null == r ? n.M = {} : r)[e];
91
- r[e] = null != n ? s(n, t) : t;
88
+ var s = this.cmdArgAsMapObj;
89
+ let r = s.M;
90
+ s = (r = null == r ? s.M = {} : r)[e];
91
+ r[e] = null != s ? n(s, t) : t;
92
92
  break;
93
93
  }
94
94
 
@@ -100,15 +100,15 @@ class i {
100
100
  if (r) {
101
101
  ++this.batchSize;
102
102
  var e, t, a, {
103
- D: n,
104
- M: s
103
+ D: s,
104
+ M: n
105
105
  } = r;
106
- for (e in n) this.pushCmd("D", e);
106
+ for (e in s) this.pushCmd("D", e);
107
107
  for (t of [ "A", "R" ]) {
108
108
  var i, o = r[t];
109
109
  for (i in o) for (var f of o[i]) this.pushCmd(t, i, f);
110
110
  }
111
- for (a in s) this.pushCmd("M", a, s[a]);
111
+ for (a in n) this.pushCmd("M", a, n[a]);
112
112
  }
113
113
  return this;
114
114
  }
@@ -122,20 +122,20 @@ class i {
122
122
  for (r of [ "A", "R" ]) {
123
123
  var t, a = e[r];
124
124
  for (t in a) {
125
- var n = Object.keys(a[t]);
126
- 0 < n.length ? a[t] = n : delete a[t];
125
+ var s = Object.keys(a[t]);
126
+ 0 < s.length ? a[t] = s : delete a[t];
127
127
  }
128
128
  g(a) && delete e[r];
129
129
  }
130
130
  var {
131
- D: s,
131
+ D: n,
132
132
  M: i
133
133
  } = e;
134
- return s && g(s) && delete e.D, i && g(i) && delete e.M, e;
134
+ return n && g(n) && delete e.D, i && g(i) && delete e.M, e;
135
135
  }
136
136
  toAclBuffer(r) {
137
137
  var e, t = this.batchSize;
138
- if (0 < t) return r = r, t = t, e = this.takeCmdArgAsListObj(), e = Buffer.from(JSON.stringify(e) + "\n"),
138
+ if (0 < t) return r = r, t = t, e = this.takeCmdArgAsListObj(), e = Buffer.from(JSON.stringify(e)),
139
139
  Buffer.concat([ l([ r, t, e.length ]), e ]);
140
140
  }
141
141
  }
@@ -148,7 +148,7 @@ function f(r, e) {
148
148
  let t = r.cmdArgAsMapObj;
149
149
  if (t && e && !(e.length <= 1)) {
150
150
  for (let r = 0; r < e.length - 1; ++r) if (null == (t = t[e[r]])) return;
151
- delete t[n(e)];
151
+ delete t[s(e)];
152
152
  }
153
153
  }
154
154
 
@@ -163,19 +163,19 @@ async function c(e, r = !1, t = 0) {
163
163
  let A = [ 1, 2, 4, 8 ];
164
164
 
165
165
  function l(e) {
166
- var t = e.length, a = new Array(t), n = new Array(t);
167
- let s = t << 6, i = 1;
166
+ var t = e.length, a = new Array(t), s = new Array(t);
167
+ let n = t << 6, i = 1;
168
168
  for (let r = 0; r < t; ++r) {
169
- var o = a[r] = (o = e[r]) <= 255 ? 0 : o <= 65535 ? 1 : o <= 4294967295 ? 2 : 3, o = (s |= o << (r << 1),
170
- n[r] = A[o]);
169
+ var o = a[r] = (o = e[r]) <= 255 ? 0 : o <= 65535 ? 1 : o <= 4294967295 ? 2 : 3, o = (n |= o << (r << 1),
170
+ s[r] = A[o]);
171
171
  i += o;
172
172
  }
173
173
  var f = Buffer.allocUnsafe(i);
174
- f.writeUInt8(s);
174
+ f.writeUInt8(n);
175
175
  let c = 1;
176
176
  for (let r = 0; r < t; ++r) {
177
177
  h = d = u = l = void 0;
178
- var [ l, u, d, h = 0 ] = [ f, e[r], n[r], c ];
178
+ var [ l, u, d, h = 0 ] = [ f, e[r], s[r], c ];
179
179
  switch (d) {
180
180
  case 1:
181
181
  l.writeUInt8(u, h);
@@ -192,15 +192,15 @@ function l(e) {
192
192
  default:
193
193
  l.writeBigUInt64BE(BigInt(u), h);
194
194
  }
195
- c += n[r];
195
+ c += s[r];
196
196
  }
197
197
  return f;
198
198
  }
199
199
 
200
200
  function h(e, t, a) {
201
- var n = e.readUInt8(t), s = (++t, n >> 6 & 3);
202
- for (let r = 0; r < s; ++r) {
203
- var i = A[n >> (r << 1) & 3];
201
+ var s = e.readUInt8(t), n = (++t, s >> 6 & 3);
202
+ for (let r = 0; r < n; ++r) {
203
+ var i = A[s >> (r << 1) & 3];
204
204
  a[r] = ((r, e, t = 0) => {
205
205
  switch (e) {
206
206
  case 1:
@@ -220,25 +220,25 @@ function h(e, t, a) {
220
220
  return t;
221
221
  }
222
222
 
223
- async function v(t, r, a, n) {
224
- var s = [];
223
+ async function v(t, r, a, s) {
224
+ var n = [];
225
225
  for (let e = 0; e < r.length; ) {
226
226
  var i = [], o = h(r, e, i), [ i, f, c ] = i;
227
- if (i <= n) d.warn(`changeId ${i} <= currentChangeId ${n} at ${t}:${e}. Ignored.`),
227
+ if (i <= s) d.warn(`changeId ${i} <= currentChangeId ${s} at ${t}:${e}. Ignored.`),
228
228
  e = o + c; else {
229
- n + f != i && d.warn(`currentChangeId ${n} + batchSize ${f} != changeId ` + i);
229
+ s + f != i && d.warn(`currentChangeId ${s} + batchSize ${f} != changeId ` + i);
230
230
  try {
231
231
  var l = JSON.parse(r.subarray(o, o + c));
232
- s.push([ i, l ]), n = i, e = o + c;
232
+ n.push([ i, l ]), s = i, e = o + c;
233
233
  } catch (r) {
234
234
  if (d.error(`Parse ${t} failed at ${e}:`, r), a) return d.warn(`Autorepair by truncating ${t} to ` + e),
235
235
  null == (f = await u.truncate(t, e)) ? d.log("truncate success") : d.error("truncate failed:", f),
236
- s;
236
+ n;
237
237
  throw r;
238
238
  }
239
239
  }
240
240
  }
241
- return s;
241
+ return n;
242
242
  }
243
243
 
244
244
  export {
@@ -15,10 +15,10 @@ class r extends t {
15
15
  })
16
16
  });
17
17
  }
18
- async start(t) {
18
+ async _op_start(t) {
19
19
  await this.qyAclWriter.start(t);
20
20
  }
21
- async stop() {
21
+ async _op_stop() {
22
22
  await this.qyAclWriter.stop();
23
23
  }
24
24
  switch(t) {
@@ -17,7 +17,7 @@ class t extends r {
17
17
  ...r
18
18
  }, t), this.qyAclCmdGenerator = new e();
19
19
  }
20
- _getBinData(r, t) {
20
+ getBinData(r, t) {
21
21
  var e, s = this.qyAclCmdGenerator;
22
22
  for (e of r) s.pushCmdArgAsListObj(e);
23
23
  return s.toAclBuffer(t);
package/src/QyBatch.js CHANGED
@@ -235,9 +235,7 @@ ${r}
235
235
  modCode: t
236
236
  } = e, r = this._action_insert({
237
237
  item: e,
238
- content: {
239
- modCode: t
240
- }
238
+ content: t
241
239
  });
242
240
  return r && this.qyCache.insertRpc(e.name, t), r;
243
241
  }