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
+ # These are supported funding model platforms
2
+
3
+ github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
4
+ patreon: crudjt # Replace with a single Patreon username
5
+ open_collective: # Replace with a single Open Collective username
6
+ ko_fi: # Replace with a single Ko-fi username
7
+ tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
8
+ community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
9
+ liberapay: # Replace with a single Liberapay username
10
+ issuehunt: # Replace with a single IssueHunt username
11
+ lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
12
+ polar: # Replace with a single Polar username
13
+ buy_me_a_coffee: # Replace with a single Buy Me a Coffee username
14
+ thanks_dev: # Replace with a single thanks.dev username
15
+ custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
@@ -0,0 +1,42 @@
1
+ name: Build and Test Node.js Library
2
+
3
+ on:
4
+ workflow_dispatch:
5
+
6
+ jobs:
7
+ build-and-test:
8
+ strategy:
9
+ matrix:
10
+ include:
11
+ - os: ubuntu-latest
12
+ arch: x86_64
13
+ - os: macos-latest
14
+ arch: aarch64
15
+ - os: windows-latest
16
+ arch: x86_64
17
+
18
+ runs-on: ${{ matrix.os }}
19
+
20
+ steps:
21
+ - uses: actions/checkout@v4
22
+
23
+ - name: Set up Node.js
24
+ uses: actions/setup-node@v3
25
+ with:
26
+ node-version: '20'
27
+
28
+ - name: Install dependencies
29
+ run: |
30
+ npm install
31
+ npm run cargo-build -- --release
32
+
33
+ - name: Create package 'crudjt'
34
+ run: npm pack
35
+
36
+ - name: Run Node.js test
37
+ env:
38
+ CRUDJT_AUTOTEST_ALLOWED: true
39
+ working-directory: ./test-neon-package
40
+ run: |
41
+ npm install ../crudjt-1.0.0-beta.0.tgz
42
+ node test.js
package/CHANGELOG.md ADDED
@@ -0,0 +1,12 @@
1
+ # Changelog
2
+
3
+ ## [Unreleased]
4
+ - Docker support
5
+ - Performance metrics
6
+ - Disk footprint
7
+
8
+ ## [1.0.0-beta.0] - 2026-03-18
9
+ - Initial beta release
10
+ - Fast B-tree–backed token store for stateful user sessions
11
+ - Provides authentication and authorization across multiple processes
12
+ - Optimized for vertical scaling on a single server
package/Cache.js ADDED
@@ -0,0 +1,82 @@
1
+ // This binding was generated automatically to ensure consistency across languages
2
+ // Generated using ChatGPT (GPT-5) from the canonical Ruby SDK
3
+ // API is stable and production-ready
4
+
5
+ const { LRUCache } = require('lru-cache')
6
+ const CACHE_CAPACITY = 40_000;
7
+
8
+ class Cache {
9
+ constructor(readFunc) {
10
+ this.cache = new LRUCache({
11
+ max: CACHE_CAPACITY,
12
+ updateAgeOnGet: true,
13
+ });
14
+ this.readFunc = readFunc;
15
+ }
16
+
17
+ get(token) {
18
+ let cachedValue = this.cache.get(token);
19
+
20
+ if (cachedValue) {
21
+ this.cache.set(token, cachedValue);
22
+
23
+ const output = {};
24
+ const metadata = cachedValue['metadata'] || {};
25
+
26
+ if (metadata['ttl']) {
27
+ const ttl = Math.ceil((new Date(metadata['ttl']).getTime() - Date.now()) / 1000);
28
+ if (ttl <= 0) {
29
+ this.cache.delete(token);
30
+ return;
31
+ }
32
+ output['metadata'] = { ttl };
33
+ }
34
+
35
+ let silence_read = undefined;
36
+ if (cachedValue['metadata']) {
37
+ if (cachedValue['metadata']['silence_read']) {
38
+ silence_read = cachedValue['metadata']['silence_read'];
39
+ }
40
+ }
41
+
42
+ if (silence_read) {
43
+ silence_read = (cachedValue['metadata']['silence_read'] -= 1)
44
+ output['metadata'] ||= {};
45
+ output['metadata']['silence_read'] = silence_read;
46
+
47
+ if (silence_read <= 0) {
48
+ this.cache.delete(token);
49
+ }
50
+
51
+ this.readFunc(token);
52
+ }
53
+
54
+ output['data'] = cachedValue['data'];
55
+ return output;
56
+ }
57
+ }
58
+
59
+ insert(key, token, ttl, silence_read) {
60
+ const hash = { data: token, metadata: {} };
61
+
62
+ if (ttl > 0) {
63
+ hash['metadata']['ttl'] = new Date(Date.now() + ttl * 1000).toISOString();
64
+ }
65
+
66
+ if (silence_read > 0) {
67
+ hash['metadata']['silence_read'] = silence_read;
68
+ }
69
+
70
+ this.cache.set(key, hash);
71
+ }
72
+
73
+ forceInsert(token, hash) {
74
+ this.cache.set(token, hash);
75
+ }
76
+
77
+ delete(token) {
78
+ this.cache.delete(token);
79
+ }
80
+ }
81
+
82
+ module.exports = Cache;
package/Cargo.lock ADDED
@@ -0,0 +1,176 @@
1
+ # This file is automatically @generated by Cargo.
2
+ # It is not intended for manual editing.
3
+ version = 4
4
+
5
+ [[package]]
6
+ name = "cfg-if"
7
+ version = "1.0.4"
8
+ source = "registry+https://github.com/rust-lang/crates.io-index"
9
+ checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
10
+
11
+ [[package]]
12
+ name = "crudjt"
13
+ version = "1.0.0-beta.0"
14
+ dependencies = [
15
+ "lazy_static",
16
+ "libloading",
17
+ "neon",
18
+ ]
19
+
20
+ [[package]]
21
+ name = "either"
22
+ version = "1.15.0"
23
+ source = "registry+https://github.com/rust-lang/crates.io-index"
24
+ checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
25
+
26
+ [[package]]
27
+ name = "getrandom"
28
+ version = "0.2.16"
29
+ source = "registry+https://github.com/rust-lang/crates.io-index"
30
+ checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592"
31
+ dependencies = [
32
+ "cfg-if",
33
+ "libc",
34
+ "wasi",
35
+ ]
36
+
37
+ [[package]]
38
+ name = "lazy_static"
39
+ version = "1.5.0"
40
+ source = "registry+https://github.com/rust-lang/crates.io-index"
41
+ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
42
+
43
+ [[package]]
44
+ name = "libc"
45
+ version = "0.2.177"
46
+ source = "registry+https://github.com/rust-lang/crates.io-index"
47
+ checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976"
48
+
49
+ [[package]]
50
+ name = "libloading"
51
+ version = "0.8.9"
52
+ source = "registry+https://github.com/rust-lang/crates.io-index"
53
+ checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55"
54
+ dependencies = [
55
+ "cfg-if",
56
+ "windows-link",
57
+ ]
58
+
59
+ [[package]]
60
+ name = "linkme"
61
+ version = "0.3.35"
62
+ source = "registry+https://github.com/rust-lang/crates.io-index"
63
+ checksum = "5e3283ed2d0e50c06dd8602e0ab319bb048b6325d0bba739db64ed8205179898"
64
+ dependencies = [
65
+ "linkme-impl",
66
+ ]
67
+
68
+ [[package]]
69
+ name = "linkme-impl"
70
+ version = "0.3.35"
71
+ source = "registry+https://github.com/rust-lang/crates.io-index"
72
+ checksum = "e5cec0ec4228b4853bb129c84dbf093a27e6c7a20526da046defc334a1b017f7"
73
+ dependencies = [
74
+ "proc-macro2",
75
+ "quote",
76
+ "syn",
77
+ ]
78
+
79
+ [[package]]
80
+ name = "neon"
81
+ version = "1.1.1"
82
+ source = "registry+https://github.com/rust-lang/crates.io-index"
83
+ checksum = "74c1d298c79e60a3f5a1e638ace1f9c1229d2a97bd3a9e40a63b67c8efa0f1e1"
84
+ dependencies = [
85
+ "either",
86
+ "getrandom",
87
+ "libloading",
88
+ "linkme",
89
+ "neon-macros",
90
+ "once_cell",
91
+ "semver",
92
+ "send_wrapper",
93
+ "smallvec",
94
+ ]
95
+
96
+ [[package]]
97
+ name = "neon-macros"
98
+ version = "1.1.1"
99
+ source = "registry+https://github.com/rust-lang/crates.io-index"
100
+ checksum = "c39e43767817fc963f90f400600967a2b2403602c6440685d09a6bc4e02b70b1"
101
+ dependencies = [
102
+ "proc-macro2",
103
+ "quote",
104
+ "syn",
105
+ ]
106
+
107
+ [[package]]
108
+ name = "once_cell"
109
+ version = "1.21.3"
110
+ source = "registry+https://github.com/rust-lang/crates.io-index"
111
+ checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
112
+
113
+ [[package]]
114
+ name = "proc-macro2"
115
+ version = "1.0.103"
116
+ source = "registry+https://github.com/rust-lang/crates.io-index"
117
+ checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8"
118
+ dependencies = [
119
+ "unicode-ident",
120
+ ]
121
+
122
+ [[package]]
123
+ name = "quote"
124
+ version = "1.0.41"
125
+ source = "registry+https://github.com/rust-lang/crates.io-index"
126
+ checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1"
127
+ dependencies = [
128
+ "proc-macro2",
129
+ ]
130
+
131
+ [[package]]
132
+ name = "semver"
133
+ version = "1.0.27"
134
+ source = "registry+https://github.com/rust-lang/crates.io-index"
135
+ checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2"
136
+
137
+ [[package]]
138
+ name = "send_wrapper"
139
+ version = "0.6.0"
140
+ source = "registry+https://github.com/rust-lang/crates.io-index"
141
+ checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73"
142
+
143
+ [[package]]
144
+ name = "smallvec"
145
+ version = "1.15.1"
146
+ source = "registry+https://github.com/rust-lang/crates.io-index"
147
+ checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
148
+
149
+ [[package]]
150
+ name = "syn"
151
+ version = "2.0.108"
152
+ source = "registry+https://github.com/rust-lang/crates.io-index"
153
+ checksum = "da58917d35242480a05c2897064da0a80589a2a0476c9a3f2fdc83b53502e917"
154
+ dependencies = [
155
+ "proc-macro2",
156
+ "quote",
157
+ "unicode-ident",
158
+ ]
159
+
160
+ [[package]]
161
+ name = "unicode-ident"
162
+ version = "1.0.20"
163
+ source = "registry+https://github.com/rust-lang/crates.io-index"
164
+ checksum = "462eeb75aeb73aea900253ce739c8e18a67423fadf006037cd3ff27e82748a06"
165
+
166
+ [[package]]
167
+ name = "wasi"
168
+ version = "0.11.1+wasi-snapshot-preview1"
169
+ source = "registry+https://github.com/rust-lang/crates.io-index"
170
+ checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
171
+
172
+ [[package]]
173
+ name = "windows-link"
174
+ version = "0.2.1"
175
+ source = "registry+https://github.com/rust-lang/crates.io-index"
176
+ checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
package/Cargo.toml ADDED
@@ -0,0 +1,16 @@
1
+ [package]
2
+ name = "crudjt"
3
+ version = "1.0.0-beta.0"
4
+ license = "MIT"
5
+ edition = "2021"
6
+ exclude = ["index.node"]
7
+
8
+ [lib]
9
+ crate-type = ["cdylib"]
10
+
11
+ # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
12
+
13
+ [dependencies]
14
+ lazy_static = "1.5.0"
15
+ libloading = "0.8.5"
16
+ neon = "1"
package/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2024 v_akymov
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,215 @@
1
+ <p align="center">
2
+ <picture>
3
+ <source media="(prefers-color-scheme: dark)" srcset="logos/crudjt_logo_white_on_dark.svg">
4
+ <source media="(prefers-color-scheme: light)" srcset="logos/crudjt_logo_dark_on_white.svg">
5
+ <img alt="Shows a dark logo" src="logos/crudjt_logo_dark.png">
6
+ </picture>
7
+ </br>
8
+ JavaScript SDK for the fast, file-backed, scalable JSON token engine
9
+ </p>
10
+
11
+ <p align="center">
12
+ <a href="https://www.patreon.com/crudjt">
13
+ <img src="logos/buy_me_a_coffee_orange.svg" alt="Buy Me a Coffee"/>
14
+ </a>
15
+ </p>
16
+
17
+ > ⚠️ Version 1.0.0-beta — production testing phase
18
+ > API is stable. Feedback is welcome before the final 1.0.0 release
19
+
20
+ Fast B-tree–backed token store for stateful user sessions
21
+ Provides authentication and authorization across multiple processes
22
+ Optimized for vertical scaling on a single server
23
+
24
+ # Installation
25
+
26
+ ##### NPM or (Yarn)
27
+
28
+ ```sh
29
+ npm install crudjt
30
+ ```
31
+
32
+ ## How to use
33
+
34
+ - One process starts the master
35
+ - All other processes connect to it
36
+
37
+ ## Start CRUDJT master (once)
38
+
39
+ Start the CRUDJT master when your application boots
40
+
41
+ Only **one process** should do this
42
+
43
+ The master is responsible for session state and coordination
44
+ All functions can also be used directly from it
45
+
46
+ ### Generate a new secret key (terminal)
47
+
48
+ ```sh
49
+ export CRUDJT_SECRET_KEY=$(openssl rand -base64 48)
50
+ ```
51
+
52
+ ### Start master (JavaScript)
53
+
54
+ ```javascript
55
+ const CRUDJT = require('crudjt');
56
+
57
+ await CRUDJT.Config.startMaster({
58
+ secret_key: process.env.CRUDJT_SECRET_KEY,
59
+ store_jt_path: 'path/to/local/storage', // optional
60
+ grpc_host: '127.0.0.1', // default
61
+ grpc_port: 50051 // default
62
+ });
63
+
64
+ // Use await CRUDJT.Config.shutdownServer() to shut down the gRPC server and let
65
+ // the process exit
66
+ ```
67
+
68
+ *Important: Use the same `secret_key` across all sessions. If the key changes, previously stored tokens cannot be decrypted and will return `null` or `false`*
69
+
70
+ ## Connect to an existing CRUDJT master
71
+
72
+ Use this in all other processes
73
+
74
+ Typical examples:
75
+ - multiple local processes
76
+ - background jobs
77
+ - forked processes
78
+
79
+ ```javascript
80
+ const CRUDJT = require('crudjt');
81
+
82
+ CRUDJT.Config.connectToMaster({
83
+ grpc_host: '127.0.0.1', // default
84
+ grpc_port: 50051 // default
85
+ });
86
+ ```
87
+
88
+ ### Process layout
89
+
90
+ App boot
91
+ ├─ Process A → start_master
92
+ ├─ Process B → connect_to_master
93
+ └─ Process C → connect_to_master
94
+
95
+ # C
96
+
97
+ ```javascript
98
+ const data = { user_id: 42, role: 11 }; // required
99
+ const ttl = 3600 * 24 * 30; // optional: token lifetime (seconds)
100
+
101
+ // Optional: read limit
102
+ // Each read decrements the counter
103
+ // When it reaches zero — the token is deleted
104
+ const silenceRead = 10;
105
+
106
+ const token = await CRUDJT.create(data, ttl, silenceRead);
107
+ // token === 'HBmKFXoXgJ46mCqer1WXyQ'
108
+ ```
109
+
110
+ ```javascript
111
+ // To disable token expiration or read limits, pass `null`
112
+ const token = await CRUDJT.create(
113
+ { user_id: 42, role: 11 },
114
+ null, // disable TTL
115
+ null // disable read limit
116
+ );
117
+ ```
118
+
119
+ # R
120
+
121
+ ```javascript
122
+ const result = await CRUDJT.read('HBmKFXoXgJ46mCqer1WXyQ');
123
+ // result === { metadata: { ttl: 101001, silence_read: 9 }, data: { user_id: 42, role: 11 } }
124
+ ```
125
+
126
+ ```javascript
127
+ // When expired or not found token
128
+ const result = await CRUDJT.read('HBmKFXoXgJ46mCqer1WXyQ');
129
+ // result === null
130
+ ```
131
+
132
+ # U
133
+
134
+ ```javascript
135
+ const data = { user_id: 42, role: 8 };
136
+
137
+ // `null` disables limits
138
+ const ttl = 600;
139
+ const silenceRead = 100;
140
+
141
+ const result = await CRUDJT.update('HBmKFXoXgJ46mCqer1WXyQ', data, ttl, silenceRead);
142
+ // result === true
143
+ ```
144
+
145
+ ```javascript
146
+ // When expired or not found token
147
+ const result = await CRUDJT.update('HBmKFXoXgJ46mCqer1WXyQ', { user_id: 42, role: 8 });
148
+ // result === false
149
+ ```
150
+
151
+ # D
152
+ ```javascript
153
+ const result = await CRUDJT.delete('HBmKFXoXgJ46mCqer1WXyQ');
154
+ // result === true
155
+ ```
156
+
157
+ ```javascript
158
+ // When expired or not found token
159
+ const result = await CRUDJT.delete('HBmKFXoXgJ46mCqer1WXyQ');
160
+ // result === false
161
+ ```
162
+
163
+ # Performance
164
+ > Metrics will be published after 1.0.0-beta GitHub Actions builds
165
+
166
+ # Storage (File-backed)
167
+
168
+ ## Disk footprint
169
+ > Metrics will be published after 1.0.0-beta GitHub Actions builds
170
+
171
+ ## Path Lookup Order
172
+ Stored tokens are placed in the **file system** according to the following order
173
+
174
+ 1. Explicitly set via `CRUDJT.Config.startMaster({store_jt_path: 'custom/path/to/file_system_db'});`
175
+ 2. Default system location
176
+ - **Linux**: `/var/lib/store_jt`
177
+ - **macOS**: `/usr/local/var/store_jt`
178
+ - **Windows**: `C:\Program Files\store_jt`
179
+ 3. Project root directory (fallback)
180
+
181
+ ## Storage Characteristics
182
+ * CRUDJT **automatically removing expired tokens** after start and every 24 hours without blocking the main thread
183
+ * **Storage automatically fsyncs every 500ms**, meanwhile tokens ​​are available from cache
184
+
185
+ # Multi-process Coordination
186
+ For multi-process scenarios, CRUDJT uses gRPC over an insecure local port for same-host communication only. It is not intended for inter-machine or internet-facing usage
187
+
188
+ # Limits
189
+ The library has the following limits and requirements
190
+
191
+ - **Node version:** >= 18.0.0
192
+ - **Supported platforms:** Linux, macOS, Windows (x86_64 / arm64)
193
+ - **Maximum json size per token:** 256 bytes
194
+ - **`secret_key` format:** must be Base64
195
+ - **`secret_key` size:** must be 32, 48, or 64 bytes
196
+
197
+ # Contact & Support
198
+ <p align="center">
199
+ <picture>
200
+ <source media="(prefers-color-scheme: dark)" srcset="logos/crudjt_favicon_160x160_white_on_dark.svg" width=160 height=160>
201
+ <source media="(prefers-color-scheme: light)" srcset="logos/crudjt_favicon_160x160_dark_on_white.svg" width=160 height=160>
202
+ <img alt="Shows a dark favicon in light color mode and a white one in dark color mode" src="logos/crudjt_favicon_160x160_white.png" width=160 height=160>
203
+ </picture>
204
+ </p>
205
+
206
+ - **Custom integrations / new features / collaboration**: support@crudjt.com
207
+ - **Library support & bug reports:** [open an issue](https://github.com/crudjt/crudjt-javascript/issues)
208
+
209
+
210
+ # License
211
+ CRUDJT is released under the [MIT License](LICENSE.txt)
212
+
213
+ <p align="center">
214
+ 💘 Shoot your g . ? Love me out via <a href="https://www.patreon.com/crudjt">Patreon Sponsors</a>!
215
+ </p>