@twin.org/core 0.9.3-next.2 → 0.9.3-next.4

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.
package/docs/examples.md CHANGED
@@ -171,12 +171,49 @@ class SimpleHasher implements IHasher {
171
171
  }
172
172
  }
173
173
 
174
- const factory = new Factory<IHasher>('hashers');
174
+ const factory = Factory.createFactory<IHasher>('hashers');
175
175
  factory.register('simple', () => new SimpleHasher());
176
176
 
177
177
  factory.create('simple').hash('abc'); // 'abc-hash'
178
178
  ```
179
179
 
180
+ ## Factory Facades
181
+
182
+ A facade wraps the components a factory produces, so a cross cutting concern can be applied without modifying them.
183
+
184
+ ```typescript
185
+ import { ComponentFactory, FacadeFactory, Is, type IFacade } from '@twin.org/core';
186
+
187
+ class LoggingFacade implements IFacade {
188
+ public wrap(target: unknown): unknown {
189
+ return new Proxy(target as object, {
190
+ get(t, prop, receiver): unknown {
191
+ const value = Reflect.get(t, prop, receiver);
192
+
193
+ if (!Is.function(value)) {
194
+ return value;
195
+ }
196
+
197
+ return (...args: unknown[]): unknown => {
198
+ globalThis.console.log('calling', String(prop));
199
+ return value.apply(t, args);
200
+ };
201
+ }
202
+ });
203
+ }
204
+ }
205
+
206
+ FacadeFactory.register('logging', () => new LoggingFacade());
207
+
208
+ // Every component the factory produces from here on is wrapped.
209
+ ComponentFactory.useFacade('logging');
210
+
211
+ // No longer wrapped, for instances produced after this call.
212
+ ComponentFactory.unuseFacade('logging');
213
+ ```
214
+
215
+ An instance is passed through the facades in the order they were activated, so the first activated is the outermost.
216
+
180
217
  ## Encoding and Compression
181
218
 
182
219
  ```typescript
@@ -366,12 +366,75 @@ Remove all the instances and the generators.
366
366
 
367
367
  ***
368
368
 
369
+ ### useFacade() {#usefacade}
370
+
371
+ > **useFacade**(`name`): `void`
372
+
373
+ Activate a facade for this factory, so every instance it produces is wrapped by it.
374
+ An instance is passed through the facades in the order they were activated, so the facade
375
+ activated first is the outermost. Activating a facade which is already active does nothing.
376
+
377
+ #### Parameters
378
+
379
+ ##### name
380
+
381
+ `string`
382
+
383
+ The name of the facade, as registered with the facade factory.
384
+
385
+ #### Returns
386
+
387
+ `void`
388
+
389
+ #### Throws
390
+
391
+ GuardError if the parameters are invalid.
392
+
393
+ #### Throws
394
+
395
+ GeneralError if no facade is registered with the name, or the factory is the facade
396
+ factory itself.
397
+
398
+ ***
399
+
400
+ ### unuseFacade() {#unusefacade}
401
+
402
+ > **unuseFacade**(`name`): `void`
403
+
404
+ Deactivate a facade for this factory. Deactivating a facade which is not active does nothing.
405
+
406
+ #### Parameters
407
+
408
+ ##### name
409
+
410
+ `string`
411
+
412
+ The name of the facade to deactivate.
413
+
414
+ #### Returns
415
+
416
+ `void`
417
+
418
+ #### Throws
419
+
420
+ GuardError if the parameters are invalid.
421
+
422
+ ***
423
+
369
424
  ### instancesMap() {#instancesmap}
370
425
 
371
- > **instancesMap**(): `object`
426
+ > **instancesMap**(`withFacade?`): `object`
372
427
 
373
428
  Get all the instances as a map.
374
429
 
430
+ #### Parameters
431
+
432
+ ##### withFacade?
433
+
434
+ `boolean`
435
+
436
+ Return the instances with the active facades applied, defaults to false.
437
+
375
438
  #### Returns
376
439
 
377
440
  `object`
@@ -382,10 +445,18 @@ The instances as a map.
382
445
 
383
446
  ### instancesList() {#instanceslist}
384
447
 
385
- > **instancesList**(): `T`[]
448
+ > **instancesList**(`withFacade?`): `T`[]
386
449
 
387
450
  Get all the instances as a list in the order they were registered.
388
451
 
452
+ #### Parameters
453
+
454
+ ##### withFacade?
455
+
456
+ `boolean`
457
+
458
+ Return the instances with the active facades applied, defaults to false.
459
+
389
460
  #### Returns
390
461
 
391
462
  `T`[]
@@ -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`\>
@@ -52,6 +52,7 @@
52
52
  - [IComponent](interfaces/IComponent.md)
53
53
  - [IDuration](interfaces/IDuration.md)
54
54
  - [IError](interfaces/IError.md)
55
+ - [IFacade](interfaces/IFacade.md)
55
56
  - [II18nShared](interfaces/II18nShared.md)
56
57
  - [IKeyValue](interfaces/IKeyValue.md)
57
58
  - [ILabelledValue](interfaces/ILabelledValue.md)
@@ -78,6 +79,7 @@
78
79
  ## Variables
79
80
 
80
81
  - [ComponentFactory](variables/ComponentFactory.md)
82
+ - [FacadeFactory](variables/FacadeFactory.md)
81
83
  - [CoerceType](variables/CoerceType.md)
82
84
  - [CompressionType](variables/CompressionType.md)
83
85
  - [MutexMessageTypes](variables/MutexMessageTypes.md)
@@ -0,0 +1,32 @@
1
+ # Interface: IFacade\<T\>
2
+
3
+ A facade wraps a component so a cross cutting concern can be applied to it without the
4
+ component being modified. The wrapped component is returned in place of the original.
5
+
6
+ ## Type Parameters
7
+
8
+ ### T
9
+
10
+ `T` = `unknown`
11
+
12
+ ## Methods
13
+
14
+ ### wrap() {#wrap}
15
+
16
+ > **wrap**(`target`): `T`
17
+
18
+ Wrap the target, returning a replacement.
19
+
20
+ #### Parameters
21
+
22
+ ##### target
23
+
24
+ `T`
25
+
26
+ The component to wrap.
27
+
28
+ #### Returns
29
+
30
+ `T`
31
+
32
+ The wrapped component.
@@ -0,0 +1,5 @@
1
+ # Variable: FacadeFactory
2
+
3
+ > `const` **FacadeFactory**: [`Factory`](../classes/Factory.md)\<[`IFacade`](../interfaces/IFacade.md)\<`unknown`\>\>
4
+
5
+ Factory for creating implementation of facade types.
package/locales/en.json CHANGED
@@ -91,7 +91,10 @@
91
91
  "factory": {
92
92
  "noUnregister": "There is no {typeName} registered with the name \"{name}\"",
93
93
  "noGet": "The requested {typeName} \"{name}\" does not exist in the factory",
94
- "noCreate": "The requested {typeName} \"{name}\" cannot be created by the factory, with params \"{params}\""
94
+ "noCreate": "The requested {typeName} \"{name}\" cannot be created by the factory, with params \"{params}\"",
95
+ "noFacade": "The requested facade \"{name}\" is not registered, so it cannot be applied to the {typeName} factory",
96
+ "noFacadeOnFacades": "Facades cannot be applied to the facade factory itself",
97
+ "noFacadeWrap": "The facade \"{name}\" did not return a wrapped instance for the {typeName} factory"
95
98
  },
96
99
  "bitString": {
97
100
  "outOfRange": "The index should be >= 0 and less than the length of the bit string, the index is \"{index}\" and the number of bit is \"{numberBits}\""
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@twin.org/core",
3
- "version": "0.9.3-next.2",
3
+ "version": "0.9.3-next.4",
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.2",
17
+ "@twin.org/nameof": "0.9.3-next.4",
18
18
  "intl-messageformat": "11.2.13",
19
19
  "rfc6902": "5.3.0"
20
20
  },