@twin.org/core 0.9.3-next.3 → 0.9.3-next.5

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.
@@ -10,6 +10,8 @@ minimum frequency is evicted.
10
10
  The timer only runs while there are entries; it stops automatically when the cache empties.
11
11
 
12
12
  `get` and `set` increment an entry's access frequency and reset its idle timer.
13
+ `set` and `getOrSet` accept an optional hard expiry timestamp; the entry is removed once that
14
+ time is reached however recently it was used, and the TTI still applies alongside it.
13
15
  `has` and `keys` are pure peeks they evict idle entries but do not affect frequency or TTI.
14
16
  Call `destroy` when the cache is no longer needed to stop the background timer.
15
17
 
@@ -125,7 +127,7 @@ The cached value, or undefined on a miss or idle eviction.
125
127
 
126
128
  ### set() {#set}
127
129
 
128
- > **set**(`key`, `value`): `void`
130
+ > **set**(`key`, `value`, `expires?`): `void`
129
131
 
130
132
  Store a value in the cache.
131
133
  If the key already exists its value and frequency are updated.
@@ -146,6 +148,13 @@ The key to store.
146
148
 
147
149
  The value to cache.
148
150
 
151
+ ##### expires?
152
+
153
+ `number`
154
+
155
+ Hard expiry timestamp in milliseconds since the epoch. The entry is removed
156
+ once this time is reached regardless of how recently it was used. Must be an integer.
157
+
149
158
  #### Returns
150
159
 
151
160
  `void`
@@ -154,7 +163,7 @@ The value to cache.
154
163
 
155
164
  ### getOrSet() {#getorset}
156
165
 
157
- > **getOrSet**(`key`, `valueFactory`): `Promise`\<`T`\>
166
+ > **getOrSet**(`key`, `valueFactory`, `expires?`): `Promise`\<`T`\>
158
167
 
159
168
  Atomically get an existing value or create and store it once using an async factory.
160
169
  Concurrent calls for the same key are serialized via a mutex.
@@ -173,6 +182,13 @@ The key to get or create.
173
182
 
174
183
  Async callback used to build a value when the key is absent.
175
184
 
185
+ ##### expires?
186
+
187
+ `number`
188
+
189
+ Hard expiry timestamp in milliseconds since the epoch, applied to the entry
190
+ when one is created. Must be an integer.
191
+
176
192
  #### Returns
177
193
 
178
194
  `Promise`\<`T`\>
@@ -8,6 +8,8 @@ Entries are removed in two ways:
8
8
  The timer only runs while there are entries; it stops automatically when the cache empties.
9
9
 
10
10
  `get` and `set` both update an entry's LRU position and reset its idle timer.
11
+ `set` and `getOrSet` accept an optional hard expiry timestamp; the entry is removed once that
12
+ time is reached however recently it was used, and the TTI still applies alongside it.
11
13
  `has` is a pure peek it evicts idle entries but does not refresh a live entry's TTI.
12
14
  Call `destroy` when the cache is no longer needed to stop the background timer.
13
15
 
@@ -123,7 +125,7 @@ The cached value, or undefined on a miss or idle eviction.
123
125
 
124
126
  ### set() {#set}
125
127
 
126
- > **set**(`key`, `value`): `void`
128
+ > **set**(`key`, `value`, `expires?`): `void`
127
129
 
128
130
  Store a value in the cache.
129
131
  If the key already exists its value and idle timer are refreshed.
@@ -144,6 +146,13 @@ The key to store.
144
146
 
145
147
  The value to cache.
146
148
 
149
+ ##### expires?
150
+
151
+ `number`
152
+
153
+ Hard expiry timestamp in milliseconds since the epoch. The entry is removed
154
+ once this time is reached regardless of how recently it was used. Must be an integer.
155
+
147
156
  #### Returns
148
157
 
149
158
  `void`
@@ -152,7 +161,7 @@ The value to cache.
152
161
 
153
162
  ### getOrSet() {#getorset}
154
163
 
155
- > **getOrSet**(`key`, `valueFactory`): `Promise`\<`T`\>
164
+ > **getOrSet**(`key`, `valueFactory`, `expires?`): `Promise`\<`T`\>
156
165
 
157
166
  Atomically get an existing value or create and store it once using an async factory.
158
167
  Concurrent calls for the same key are serialized via a mutex.
@@ -171,6 +180,13 @@ The key to get or create.
171
180
 
172
181
  Async callback used to build a value when the key is absent.
173
182
 
183
+ ##### expires?
184
+
185
+ `number`
186
+
187
+ Hard expiry timestamp in milliseconds since the epoch, applied to the entry
188
+ when one is created. Must be an integer.
189
+
174
190
  #### Returns
175
191
 
176
192
  `Promise`\<`T`\>
@@ -12,6 +12,13 @@ the shared buffer with the main thread on first use of each key, then caches it
12
12
  The main thread must call Mutex.handleWorkerMessage(msg) from its worker message handler
13
13
  before that worker first calls Mutex.lock().
14
14
 
15
+ Callers on the same thread are served in the order they arrived. Each key has a FIFO
16
+ queue of waiters, unlock() hands the lock directly to the waiter at the front, and a new
17
+ caller only takes the lock outright when that queue is empty. Without this a caller that
18
+ arrives while a waiter is being woken can take the lock first, which lets a busy key
19
+ starve a waiter until its timeout elapses. Threads still contend with each other for the
20
+ shared lock, so the ordering guarantee is per thread rather than global.
21
+
15
22
  The lock is not re-entrant: a thread that already holds a key and calls lock() again on
16
23
  the same key will block until the timeout elapses.
17
24
 
@@ -81,6 +88,8 @@ Acquires a lock for the given key without blocking the event loop. If the lock i
81
88
  held, it suspends the current async task until the lock is released or the timeout is reached.
82
89
  Use this in async single-threaded contexts (e.g. the main thread or a Fastify route handler)
83
90
  where calling the synchronous lock() would freeze the event loop and deadlock.
91
+ Callers on the same thread are served in the order they arrived, so a contended key
92
+ cannot starve an earlier caller.
84
93
  The lock is not re-entrant: if the same context holds the key and calls lockAsync() again on
85
94
  the same key, it will suspend until the timeout elapses.
86
95
 
@@ -59,6 +59,7 @@
59
59
  - [ILocale](interfaces/ILocale.md)
60
60
  - [ILocaleDictionary](interfaces/ILocaleDictionary.md)
61
61
  - [ILocalesIndex](interfaces/ILocalesIndex.md)
62
+ - [IMutexWaiter](interfaces/IMutexWaiter.md)
62
63
  - [IMutexWorkerMessage](interfaces/IMutexWorkerMessage.md)
63
64
  - [IPatchOperation](interfaces/IPatchOperation.md)
64
65
  - [ISharedObjectBufferOptions](interfaces/ISharedObjectBufferOptions.md)
@@ -0,0 +1,37 @@
1
+ # Interface: IMutexWaiter
2
+
3
+ A caller queued on a mutex key, waiting to be handed the lock.
4
+
5
+ ## Properties
6
+
7
+ ### settled {#settled}
8
+
9
+ > **settled**: `boolean`
10
+
11
+ Has the waiter already been granted the lock or given up waiting.
12
+
13
+ ***
14
+
15
+ ### resolve? {#resolve}
16
+
17
+ > `optional` **resolve?**: (`granted`) => `void`
18
+
19
+ Resolves the queued caller, true when it now owns the lock.
20
+
21
+ #### Parameters
22
+
23
+ ##### granted
24
+
25
+ `boolean`
26
+
27
+ #### Returns
28
+
29
+ `void`
30
+
31
+ ***
32
+
33
+ ### timer? {#timer}
34
+
35
+ > `optional` **timer?**: `Timeout`
36
+
37
+ Timer which enforces the waiter's deadline.
package/locales/en.json CHANGED
@@ -114,7 +114,7 @@
114
114
  "mutex": {
115
115
  "lockNotFound": "The key \"{key}\" has no active lock",
116
116
  "lockAlreadyReleased": "The key \"{key}\" is not currently locked",
117
- "lockTimeout": "Failed to acquire lock for key \"{key}\" within the timeout of {timeout} milliseconds",
117
+ "lockTimeout": "Failed to acquire lock for key \"{key}\" within the timeout of {timeoutMs} milliseconds",
118
118
  "bufferFetchFailed": "Failed to retrieve shared buffer for key \"{key}\" from the main thread",
119
119
  "invalidTimeout": "The timeout value \"{timeoutMs}\" is invalid, it must be a non-negative integer"
120
120
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@twin.org/core",
3
- "version": "0.9.3-next.3",
3
+ "version": "0.9.3-next.5",
4
4
  "description": "Helper methods/classes for data type checking/validation/guarding/error handling",
5
5
  "repository": {
6
6
  "type": "git",
@@ -14,7 +14,7 @@
14
14
  "node": ">=24.0.0"
15
15
  },
16
16
  "dependencies": {
17
- "@twin.org/nameof": "0.9.3-next.3",
17
+ "@twin.org/nameof": "0.9.3-next.5",
18
18
  "intl-messageformat": "11.2.13",
19
19
  "rfc6902": "5.3.0"
20
20
  },