crudjt 1.0.0-beta.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 (64) hide show
  1. package/.github/FUNDING.yml +15 -0
  2. package/.github/workflows/build.yml +42 -0
  3. package/CHANGELOG.md +12 -0
  4. package/Cache.js +82 -0
  5. package/Cargo.lock +176 -0
  6. package/Cargo.toml +16 -0
  7. package/LICENSE.txt +21 -0
  8. package/README.md +215 -0
  9. package/cargo.log +30 -0
  10. package/crudjt-1.0.0-beta.0.tgz +0 -0
  11. package/errors/internal_error.js +12 -0
  12. package/errors/invalid_state.js +12 -0
  13. package/errors.js +13 -0
  14. package/index.js +440 -0
  15. package/index.node +0 -0
  16. package/logos/buy_me_a_coffee_orange.svg +1 -0
  17. package/logos/crud_jt_logo.png +0 -0
  18. package/logos/crud_jt_logo_black.png +0 -0
  19. package/logos/crud_jt_logo_favicon_black.png +0 -0
  20. package/logos/crud_jt_logo_favicon_black_160.png +0 -0
  21. package/logos/crud_jt_logo_favicon_white.png +0 -0
  22. package/logos/crud_jt_logo_favicon_white_160.png +0 -0
  23. package/logos/crudjt_favicon_160x160_dark_on_white.svg +18 -0
  24. package/logos/crudjt_favicon_160x160_white.png +0 -0
  25. package/logos/crudjt_favicon_160x160_white_on_dark.svg +18 -0
  26. package/logos/crudjt_favicon_white_on_dark.png +0 -0
  27. package/logos/crudjt_logo_dark.png +0 -0
  28. package/logos/crudjt_logo_dark_on_white.svg +19 -0
  29. package/logos/crudjt_logo_white_on_dark.svg +26 -0
  30. package/native/linux/store_jt_arm64.so +0 -0
  31. package/native/linux/store_jt_x86_64.so +0 -0
  32. package/native/macos/store_jt_arm64.dylib +0 -0
  33. package/native/macos/store_jt_x86_64.dylib +0 -0
  34. package/native/windows/store_jt_arm64.dll +0 -0
  35. package/native/windows/store_jt_x86_64.dll +0 -0
  36. package/package/.github/workflows/build.yml +43 -0
  37. package/package/Cache.js +78 -0
  38. package/package/Cargo.lock +217 -0
  39. package/package/Cargo.toml +16 -0
  40. package/package/README.md +90 -0
  41. package/package/Validation.js +26 -0
  42. package/package/cargo.log +24 -0
  43. package/package/index.js +197 -0
  44. package/package/index.node +0 -0
  45. package/package/native/linux/store_jt_arm64.so +0 -0
  46. package/package/native/linux/store_jt_x86_64.so +0 -0
  47. package/package/native/macos/store_jt_arm64.dylib +0 -0
  48. package/package/native/macos/store_jt_x86_64.dylib +0 -0
  49. package/package/native/windows/store_jt_arm64.dll +0 -0
  50. package/package/native/windows/store_jt_x86_64.dll +0 -0
  51. package/package/package.json +26 -0
  52. package/package/src/lib.rs +190 -0
  53. package/package/test-neon-package/package-lock.json +942 -0
  54. package/package/test-neon-package/package.json +15 -0
  55. package/package/test-neon-package/test.js +178 -0
  56. package/package/test.js +202 -0
  57. package/package.json +41 -0
  58. package/src/lib.rs +288 -0
  59. package/test-neon-package/package-lock.json +1135 -0
  60. package/test-neon-package/package.json +15 -0
  61. package/test-neon-package/test.js +198 -0
  62. package/token_service.proto +47 -0
  63. package/token_service_client.js +33 -0
  64. package/validation.js +72 -0
@@ -0,0 +1,15 @@
1
+ {
2
+ "name": "test-neon-package",
3
+ "version": "1.0.0",
4
+ "main": "index.js",
5
+ "scripts": {
6
+ "test": "echo \"Error: no test specified\" && exit 1"
7
+ },
8
+ "keywords": [],
9
+ "author": "",
10
+ "license": "ISC",
11
+ "description": "",
12
+ "dependencies": {
13
+ "crud_jt": "file:../crud_jt-0.1.0.tgz"
14
+ }
15
+ }
@@ -0,0 +1,178 @@
1
+ const CRUD_JT = require('crudjt');
2
+ const { performance } = require('perf_hooks');
3
+ const os = require('os');
4
+
5
+ function sortObjectByKeyRecursive(obj) {
6
+ if (typeof obj !== 'object' || obj === null) return obj;
7
+
8
+ const sorted = Object.keys(obj).sort().reduce((result, key) => {
9
+ result[key] = sortObjectByKeyRecursive(obj[key]);
10
+ return result;
11
+ }, {});
12
+
13
+ return sorted;
14
+ }
15
+
16
+ function objectToString(obj) {
17
+ return JSON.stringify(sortObjectByKeyRecursive(obj));
18
+ }
19
+
20
+ console.log(`OS: ${process.platform}`);
21
+ console.log(`CPU: ${os.arch()}`);
22
+
23
+ async function main() {
24
+ console.log('Checking without metadata...');
25
+ let data = { user_id: 42, role: 11 };
26
+ let expectedData = sortObjectByKeyRecursive({ data: { ...data } });
27
+
28
+ let edData = { user_id: 42, role: 8 };
29
+ let expectedEdData = sortObjectByKeyRecursive({ data: { ...edData } });
30
+
31
+ let token = CRUD_JT.create(data);
32
+
33
+ console.log(objectToString(CRUD_JT.read(token)) === objectToString(expectedData));
34
+ console.log(CRUD_JT.update(token, edData) === true);
35
+ console.log(objectToString(CRUD_JT.read(token)) === objectToString(expectedEdData));
36
+ console.log(CRUD_JT.delete(token) === true);
37
+ console.log(CRUD_JT.read(token) === null);
38
+
39
+ console.log('Checking ttl...');
40
+ data = { user_id: 42, role: 11 };
41
+
42
+ let ttl = 5;
43
+ let tokenWithttl = CRUD_JT.create(data, ttl);
44
+
45
+ let expectedttl = ttl;
46
+ for (let i = 0; i < ttl; i++) {
47
+ console.log(objectToString(CRUD_JT.read(tokenWithttl)) === objectToString({ metadata: { ttl: expectedttl }, data: data }));
48
+ expectedttl -= 1;
49
+
50
+ await new Promise(resolve => setTimeout(resolve, 1000)); // Затримка 1 секунда
51
+ }
52
+ console.log(CRUD_JT.read(tokenWithttl) === null);
53
+
54
+ console.log('when expired ttl');
55
+ data = { user_id: 42, role: 11 };
56
+ ttl = 1;
57
+ token = CRUD_JT.create(data, ttl);
58
+ await new Promise(resolve => setTimeout(resolve, ttl * 1000)); // Затримка на ttl секунд
59
+ console.log(CRUD_JT.read(token) === null);
60
+ console.log(CRUD_JT.update(token, data) === false);
61
+ console.log(CRUD_JT.delete(token) === false);
62
+
63
+ console.log(CRUD_JT.update(token, data) === false);
64
+ console.log(CRUD_JT.read(token) === null);
65
+
66
+ console.log("Checking silence_read...");
67
+ data = { user_id: 42, role: 11 };
68
+ let silence_read = 6;
69
+ let tokenWithsilence_read = CRUD_JT.create(data, -1, silence_read);
70
+
71
+ let expectedsilence_read = silence_read - 1;
72
+ for (let i = 0; i < silence_read; i++) {
73
+ console.log(objectToString(CRUD_JT.read(tokenWithsilence_read)) === objectToString({ metadata: { silence_read: expectedsilence_read }, data: data }));
74
+ expectedsilence_read -= 1;
75
+ }
76
+ console.log(CRUD_JT.read(tokenWithsilence_read) === null);
77
+
78
+ console.log("Checking ttl and silence_read...");
79
+ data = { user_id: 42, role: 11 };
80
+ ttl = 5;
81
+ silence_read = 5;
82
+ expectedttl = 5;
83
+ expectedsilence_read = silence_read - 1;
84
+ let tokenWithttlAndsilence_read = CRUD_JT.create(data, ttl, silence_read);
85
+
86
+ for (let i = 0; i < silence_read; i++) {
87
+ console.log(objectToString(CRUD_JT.read(tokenWithttlAndsilence_read)) === objectToString({ metadata: { ttl: expectedttl, silence_read: expectedsilence_read }, data: data }));
88
+ expectedttl -= 1;
89
+ expectedsilence_read -= 1;
90
+
91
+ await new Promise(resolve => setTimeout(resolve, 1000)); // Затримка 1 секунда
92
+ }
93
+ console.log(CRUD_JT.read(tokenWithttlAndsilence_read) === null);
94
+
95
+ const REQUESTS = 40_000;
96
+
97
+ for (let j = 0; j < 10; j++) {
98
+ let tokens = [];
99
+ data = {
100
+ user_id: 414243,
101
+ role: 11,
102
+ devices: {
103
+ ios_expired_at: "new Date().toString()",
104
+ android_expired_at: "new Date().toString()",
105
+ mobile_app_expired_at: "new Date().toString()",
106
+ external_api_integration_expired_at: "new Date().toString()",
107
+ },
108
+ a: 42
109
+ };
110
+ edData = { user_id: 42, role: 11 };
111
+
112
+ console.log('Checking scale load...');
113
+
114
+ console.log('when creates 40k tokens with Turbo Queue');
115
+ let start = performance.now();
116
+ for (let i = 0; i < REQUESTS; i++) {
117
+ tokens.push(CRUD_JT.create(data));
118
+ }
119
+ console.log(`Elapsed time: ${((performance.now() - start) / 1000).toFixed(3)}`);
120
+
121
+ console.log('when reads 40k tokens');
122
+ let index = Math.floor(Math.random() * REQUESTS);
123
+ start = performance.now();
124
+ for (let i = 0; i < REQUESTS; i++) {
125
+ CRUD_JT.read(tokens[index]);
126
+ }
127
+ console.log(`Elapsed time: ${((performance.now() - start) / 1000).toFixed(3)}`);
128
+
129
+ console.log('when updates 40k tokens');
130
+ start = performance.now();
131
+ for (let i = 0; i < REQUESTS; i++) {
132
+ CRUD_JT.update(tokens[i], edData);
133
+ }
134
+ console.log(`Elapsed time: ${((performance.now() - start) / 1000).toFixed(3)}`);
135
+
136
+ console.log('when deletes 40k tokens');
137
+ start = performance.now();
138
+ for (let i = 0; i < REQUESTS; i++) {
139
+ CRUD_JT.delete(tokens[i]);
140
+ }
141
+ console.log(`Elapsed time: ${((performance.now() - start) / 1000).toFixed(3)}`);
142
+ }
143
+
144
+ console.log('when caches after read from file system');
145
+
146
+ const ttlGH = 2;
147
+
148
+ data = {
149
+ user_id: 414243,
150
+ role: 11,
151
+ devices: {
152
+ ios_expired_at: new Date().toString(),
153
+ android_expired_at: new Date().toString(),
154
+ mobile_app_expired_at: new Date().toString(),
155
+ external_api_integration_expired_at: new Date().toString(),
156
+ },
157
+ a: 42
158
+ };
159
+
160
+ let previoustokens = [];
161
+
162
+ for (let i = 0; i < REQUESTS; i++) {
163
+ previoustokens.push(CRUD_JT.create(data));
164
+ }
165
+ for (let i = 0; i < REQUESTS; i++) {
166
+ CRUD_JT.create(data);
167
+ }
168
+
169
+ for (let i = 0; i < ttlGH; i++) {
170
+ let start = performance.now();
171
+ for (let j = 0; j < REQUESTS; j++) {
172
+ CRUD_JT.read(previoustokens[j]);
173
+ }
174
+ console.log(`Elapsed time: ${((performance.now() - start) / 1000).toFixed(3)}`);
175
+ }
176
+ }
177
+
178
+ main().catch(console.error);
@@ -0,0 +1,202 @@
1
+ const CRUD_JT = require('./index');
2
+ const { performance } = require('perf_hooks');
3
+ const os = require('os');
4
+
5
+ // Функція для рекурсивного сортування об'єктів
6
+ function sortObjectByKeyRecursive(obj) {
7
+ if (typeof obj !== 'object' || obj === null) return obj;
8
+
9
+ const sorted = Object.keys(obj).sort().reduce((result, key) => {
10
+ result[key] = sortObjectByKeyRecursive(obj[key]);
11
+ return result;
12
+ }, {});
13
+
14
+ return sorted;
15
+ }
16
+
17
+ // Функція для перетворення об'єкта на рядок
18
+ function objectToString(obj) {
19
+ return JSON.stringify(sortObjectByKeyRecursive(obj));
20
+ }
21
+
22
+ // Виводимо ОС
23
+ console.log(`OS: ${process.platform}`);
24
+ console.log(`CPU: ${os.arch()}`);
25
+
26
+ // Основна асинхронна функція
27
+ async function main() {
28
+ // Без metadata
29
+ console.log('Checking without metadata...');
30
+ let data = { user_id: 42, role: 11 };
31
+ let expectedData = sortObjectByKeyRecursive({ data: { ...data } });
32
+
33
+ let edData = { user_id: 42, role: 8 };
34
+ let expectedEdData = sortObjectByKeyRecursive({ data: { ...edData } });
35
+
36
+ let token = CRUD_JT.create(data);
37
+
38
+ console.log(objectToString(CRUD_JT.read(token)) === objectToString(expectedData));
39
+ console.log(CRUD_JT.update(token, edData) === true);
40
+ console.log(objectToString(CRUD_JT.read(token)) === objectToString(expectedEdData));
41
+ console.log(CRUD_JT.delete(token) === true);
42
+ console.log(CRUD_JT.read(token) === null);
43
+
44
+ // З metadata
45
+ console.log('Checking ttl...');
46
+ data = { user_id: 42, role: 11 };
47
+
48
+ let ttl = 5;
49
+ let tokenWithttl = CRUD_JT.create(data, ttl);
50
+
51
+ let expectedttl = ttl;
52
+ for (let i = 0; i < ttl; i++) {
53
+ console.log(objectToString(CRUD_JT.read(tokenWithttl)) === objectToString({ metadata: { ttl: expectedttl }, data: data }));
54
+ expectedttl -= 1;
55
+
56
+ await new Promise(resolve => setTimeout(resolve, 1000)); // Затримка 1 секунда
57
+ }
58
+ console.log(CRUD_JT.read(tokenWithttl) === null);
59
+
60
+ // Коли ttl закінчився
61
+ console.log('when expired ttl');
62
+ data = { user_id: 42, role: 11 };
63
+ ttl = 1;
64
+ token = CRUD_JT.create(data, ttl);
65
+ await new Promise(resolve => setTimeout(resolve, ttl * 1000)); // Затримка на ttl секунд
66
+ console.log(CRUD_JT.read(token) === null);
67
+ console.log(CRUD_JT.update(token, data) === false);
68
+ console.log(CRUD_JT.delete(token) === false);
69
+
70
+ console.log(CRUD_JT.update(token, data) === false);
71
+ console.log(CRUD_JT.read(token) === null);
72
+
73
+ // З silence_read
74
+ console.log("Checking silence_read...");
75
+ data = { user_id: 42, role: 11 };
76
+ let silence_read = 6;
77
+ let tokenWithsilence_read = CRUD_JT.create(data, -1, silence_read);
78
+
79
+ let expectedsilence_read = silence_read - 1;
80
+ for (let i = 0; i < silence_read; i++) {
81
+ console.log(objectToString(CRUD_JT.read(tokenWithsilence_read)) === objectToString({ metadata: { silence_read: expectedsilence_read }, data: data }));
82
+ expectedsilence_read -= 1;
83
+ }
84
+ console.log(CRUD_JT.read(tokenWithsilence_read) === null);
85
+
86
+ // З ttl і silence_read
87
+ console.log("Checking ttl and silence_read...");
88
+ data = { user_id: 42, role: 11 };
89
+ ttl = 5;
90
+ silence_read = 5;
91
+ expectedttl = 5;
92
+ expectedsilence_read = silence_read - 1;
93
+ let tokenWithttlAndsilence_read = CRUD_JT.create(data, ttl, silence_read);
94
+
95
+ // let expectedttlAndsilence_read = {
96
+ // ttl: expectedttl,
97
+ // silence_read: expectedsilence_read,
98
+ // };
99
+ for (let i = 0; i < silence_read; i++) {
100
+ // console.log(objectToString(CRUD_JT.read(tokenWithttlAndsilence_read)));
101
+ // console.log(objectToString({ metadata: { ttl: expectedttl, silence_read: expectedsilence_read }, data: data }));
102
+ // console.log(objectToString({ metadata: expectedttlAndsilence_read, data: data }));
103
+
104
+ console.log(objectToString(CRUD_JT.read(tokenWithttlAndsilence_read)) === objectToString({ metadata: { ttl: expectedttl, silence_read: expectedsilence_read }, data: data }));
105
+ expectedttl -= 1;
106
+ expectedsilence_read -= 1;
107
+
108
+ await new Promise(resolve => setTimeout(resolve, 1000)); // Затримка 1 секунда
109
+ }
110
+ console.log(CRUD_JT.read(tokenWithttlAndsilence_read) === null);
111
+
112
+ // З масштабним навантаженням
113
+ const REQUESTS = 40_000;
114
+
115
+ for (let j = 0; j < 10; j++) {
116
+ let tokens = [];
117
+ data = {
118
+ user_id: 414243,
119
+ role: 11,
120
+ devices: {
121
+ ios_expired_at: "new Date().toString()",
122
+ android_expired_at: "new Date().toString()",
123
+ mobile_app_expired_at: "new Date().toString()",
124
+ external_api_integration_expired_at: "new Date().toString()",
125
+ },
126
+ a: 42
127
+ };
128
+ edData = { user_id: 42, role: 11 };
129
+
130
+ console.log('Checking scale load...');
131
+
132
+ // Коли q
133
+ console.log('when creates 40k tokens with Turbo Queue');
134
+ let start = performance.now();
135
+ for (let i = 0; i < REQUESTS; i++) {
136
+ tokens.push(CRUD_JT.create(data));
137
+ }
138
+ console.log(`Elapsed time: ${((performance.now() - start) / 1000).toFixed(3)}`);
139
+
140
+ // Коли w
141
+ console.log('when reads 40k tokens');
142
+ let index = Math.floor(Math.random() * REQUESTS);
143
+ start = performance.now();
144
+ for (let i = 0; i < REQUESTS; i++) {
145
+ CRUD_JT.read(tokens[index]);
146
+ }
147
+ console.log(`Elapsed time: ${((performance.now() - start) / 1000).toFixed(3)}`);
148
+
149
+ // Коли e
150
+ console.log('when updates 40k tokens');
151
+ start = performance.now();
152
+ for (let i = 0; i < REQUESTS; i++) {
153
+ CRUD_JT.update(tokens[i], edData);
154
+ }
155
+ console.log(`Elapsed time: ${((performance.now() - start) / 1000).toFixed(3)}`);
156
+
157
+ // Коли r
158
+ console.log('when deletes 40k tokens');
159
+ start = performance.now();
160
+ for (let i = 0; i < REQUESTS; i++) {
161
+ CRUD_JT.delete(tokens[i]);
162
+ }
163
+ console.log(`Elapsed time: ${((performance.now() - start) / 1000).toFixed(3)}`);
164
+ }
165
+
166
+ // Коли кеш після w з файлової системи
167
+ console.log('when caches after read from file system');
168
+
169
+ const ttlGH = 2;
170
+
171
+ data = {
172
+ user_id: 414243,
173
+ role: 11,
174
+ devices: {
175
+ ios_expired_at: new Date().toString(),
176
+ android_expired_at: new Date().toString(),
177
+ mobile_app_expired_at: new Date().toString(),
178
+ external_api_integration_expired_at: new Date().toString(),
179
+ },
180
+ a: 42
181
+ };
182
+
183
+ let previoustokens = [];
184
+
185
+ for (let i = 0; i < REQUESTS; i++) {
186
+ previoustokens.push(CRUD_JT.create(data));
187
+ }
188
+ for (let i = 0; i < REQUESTS; i++) {
189
+ CRUD_JT.create(data);
190
+ }
191
+
192
+ for (let i = 0; i < ttlGH; i++) {
193
+ let start = performance.now();
194
+ for (let j = 0; j < REQUESTS; j++) {
195
+ CRUD_JT.read(previoustokens[j]);
196
+ }
197
+ console.log(`Elapsed time: ${((performance.now() - start) / 1000).toFixed(3)}`);
198
+ }
199
+ }
200
+
201
+ // Викликаємо основну функцію
202
+ main().catch(console.error);
package/package.json ADDED
@@ -0,0 +1,41 @@
1
+ {
2
+ "name": "crudjt",
3
+ "version": "1.0.0-beta.0",
4
+ "description": "Fast B-tree–backed token store for stateful sessions",
5
+ "main": "index.js",
6
+ "scripts": {
7
+ "test": "cargo test",
8
+ "cargo-build": "cargo build --message-format=json-render-diagnostics > cargo.log",
9
+ "cross-build": "cross build --message-format=json-render-diagnostics > cross.log",
10
+ "postcargo-build": "neon dist < cargo.log",
11
+ "postcross-build": "neon dist -m /target < cross.log",
12
+ "debug": "npm run cargo-build --",
13
+ "build": "npm run cargo-build -- --release",
14
+ "cross": "npm run cross-build -- --release"
15
+ },
16
+ "author": "Vlad Akymov (v_akymov)",
17
+ "license": "MIT",
18
+ "devDependencies": {
19
+ "@neon-rs/cli": "0.1.73"
20
+ },
21
+ "dependencies": {
22
+ "@grpc/grpc-js": "^1.14.3",
23
+ "@grpc/proto-loader": "^0.8.0",
24
+ "lru-cache": "^11.0.1",
25
+ "msgpack-lite": "^0.1.26",
26
+ "neon-cli": "^0.10.1"
27
+ },
28
+ "keywords": [
29
+ "token",
30
+ "session",
31
+ "authentication",
32
+ "authorization"
33
+ ],
34
+ "repository": {
35
+ "type": "git",
36
+ "url": "https://github.com/crudjt/crudjt-js"
37
+ },
38
+ "engines": {
39
+ "node": ">=18"
40
+ }
41
+ }