@fjell/registry 4.4.10 → 4.4.11
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/dist/Registry.cjs +36 -3
- package/dist/Registry.js +36 -3
- package/dist/RegistryStats.cjs +200 -0
- package/dist/RegistryStats.d.ts +103 -0
- package/dist/RegistryStats.js +196 -0
- package/dist/index.cjs +229 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +2 -1
- package/dist/types.d.ts +7 -0
- package/docs/README.md +5 -5
- package/docs/index.html +1 -1
- package/docs/memory-data/scaling-10-instances.json +206 -206
- package/docs/memory-data/scaling-100-instances.json +206 -206
- package/docs/memory-data/scaling-1000-instances.json +108 -108
- package/docs/memory-data/scaling-10000-instances.json +49 -49
- package/docs/memory-data/scaling-20-instances.json +208 -208
- package/docs/memory-data/scaling-200-instances.json +206 -206
- package/docs/memory-data/scaling-2000-instances.json +109 -109
- package/docs/memory-data/scaling-50-instances.json +206 -206
- package/docs/memory-data/scaling-500-instances.json +108 -108
- package/docs/memory-data/scaling-5000-instances.json +49 -49
- package/docs/memory-overhead.svg +16 -16
- package/docs/memory.md +122 -122
- package/docs/public/package.json +65 -0
- package/docs/src/App.css +84 -22
- package/docs/src/App.tsx +39 -16
- package/docs/src/index.css +1 -7
- package/docs/timing-range.svg +38 -40
- package/docs/timing.md +122 -122
- package/examples/README.md +19 -0
- package/examples/registry-statistics-example.ts +264 -0
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -45,6 +45,200 @@ const isInstance = (instance)=>{
|
|
|
45
45
|
return instance !== null && instance !== undefined && instance.coordinate !== undefined && instance.registry !== undefined;
|
|
46
46
|
};
|
|
47
47
|
|
|
48
|
+
/**
|
|
49
|
+
* Represents a service client (another service making the request)
|
|
50
|
+
*/ function _define_property$4(obj, key, value) {
|
|
51
|
+
if (key in obj) {
|
|
52
|
+
Object.defineProperty(obj, key, {
|
|
53
|
+
value: value,
|
|
54
|
+
enumerable: true,
|
|
55
|
+
configurable: true,
|
|
56
|
+
writable: true
|
|
57
|
+
});
|
|
58
|
+
} else {
|
|
59
|
+
obj[key] = value;
|
|
60
|
+
}
|
|
61
|
+
return obj;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Internal class for tracking Registry statistics with complex coordinate combinations and client tracking
|
|
65
|
+
*/ class RegistryStats {
|
|
66
|
+
/**
|
|
67
|
+
* Records a get() call for the specified coordinate and client
|
|
68
|
+
*/ recordGetCall(kta, scopes, client) {
|
|
69
|
+
this.totalCalls++;
|
|
70
|
+
const ktaKey = kta.join('.');
|
|
71
|
+
const scopeKey = this.createScopeKey(scopes || []);
|
|
72
|
+
const clientKey = this.createClientKey(client);
|
|
73
|
+
if (!this.coordinateCalls.has(ktaKey)) {
|
|
74
|
+
this.coordinateCalls.set(ktaKey, new Map());
|
|
75
|
+
}
|
|
76
|
+
const scopeMap = this.coordinateCalls.get(ktaKey);
|
|
77
|
+
if (!scopeMap.has(scopeKey)) {
|
|
78
|
+
scopeMap.set(scopeKey, new Map());
|
|
79
|
+
}
|
|
80
|
+
const clientMap = scopeMap.get(scopeKey);
|
|
81
|
+
const currentCount = clientMap.get(clientKey) || 0;
|
|
82
|
+
clientMap.set(clientKey, currentCount + 1);
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Gets the current statistics snapshot
|
|
86
|
+
*/ getStatistics() {
|
|
87
|
+
const coordinateCallRecords = [];
|
|
88
|
+
let serviceCalls = 0;
|
|
89
|
+
let applicationCalls = 0;
|
|
90
|
+
let unidentifiedCalls = 0;
|
|
91
|
+
for (const [ktaKey, scopeMap] of this.coordinateCalls){
|
|
92
|
+
for (const [scopeKey, clientMap] of scopeMap){
|
|
93
|
+
const clientCalls = [];
|
|
94
|
+
let totalCount = 0;
|
|
95
|
+
for (const [clientKey, count] of clientMap){
|
|
96
|
+
const client = this.parseClientKey(clientKey);
|
|
97
|
+
if (client !== null) {
|
|
98
|
+
clientCalls.push({
|
|
99
|
+
client,
|
|
100
|
+
count
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
totalCount += count;
|
|
104
|
+
// Update client summary
|
|
105
|
+
if (clientKey === '__no_client__') {
|
|
106
|
+
unidentifiedCalls += count;
|
|
107
|
+
} else if (typeof client === 'string') {
|
|
108
|
+
applicationCalls += count;
|
|
109
|
+
} else if (client !== null) {
|
|
110
|
+
serviceCalls += count;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
coordinateCallRecords.push({
|
|
114
|
+
kta: ktaKey.split('.'),
|
|
115
|
+
scopes: this.parseScopeKey(scopeKey),
|
|
116
|
+
count: totalCount,
|
|
117
|
+
clientCalls: [
|
|
118
|
+
...clientCalls
|
|
119
|
+
] // Return a copy
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
return {
|
|
124
|
+
totalGetCalls: this.totalCalls,
|
|
125
|
+
coordinateCallRecords: [
|
|
126
|
+
...coordinateCallRecords
|
|
127
|
+
],
|
|
128
|
+
clientSummary: {
|
|
129
|
+
serviceCalls,
|
|
130
|
+
applicationCalls,
|
|
131
|
+
unidentifiedCalls
|
|
132
|
+
}
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Gets call count for a specific coordinate combination
|
|
137
|
+
*/ getCallCount(kta, scopes) {
|
|
138
|
+
const ktaKey = kta.join('.');
|
|
139
|
+
const scopeKey = this.createScopeKey(scopes || []);
|
|
140
|
+
const scopeMap = this.coordinateCalls.get(ktaKey);
|
|
141
|
+
if (!scopeMap) return 0;
|
|
142
|
+
const clientMap = scopeMap.get(scopeKey);
|
|
143
|
+
if (!clientMap) return 0;
|
|
144
|
+
let total = 0;
|
|
145
|
+
for (const count of clientMap.values()){
|
|
146
|
+
total += count;
|
|
147
|
+
}
|
|
148
|
+
return total;
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Gets call count for a specific coordinate combination from a specific client
|
|
152
|
+
*/ getCallCountByClient(kta, scopes, client) {
|
|
153
|
+
const ktaKey = kta.join('.');
|
|
154
|
+
const scopeKey = this.createScopeKey(scopes || []);
|
|
155
|
+
const clientKey = this.createClientKey(client);
|
|
156
|
+
const scopeMap = this.coordinateCalls.get(ktaKey);
|
|
157
|
+
if (!scopeMap) return 0;
|
|
158
|
+
const clientMap = scopeMap.get(scopeKey);
|
|
159
|
+
if (!clientMap) return 0;
|
|
160
|
+
return clientMap.get(clientKey) || 0;
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Gets total calls for a specific kta (across all scopes)
|
|
164
|
+
*/ getTotalCallsForKta(kta) {
|
|
165
|
+
const ktaKey = kta.join('.');
|
|
166
|
+
const scopeMap = this.coordinateCalls.get(ktaKey);
|
|
167
|
+
if (!scopeMap) return 0;
|
|
168
|
+
let total = 0;
|
|
169
|
+
for (const clientMap of scopeMap.values()){
|
|
170
|
+
for (const count of clientMap.values()){
|
|
171
|
+
total += count;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
return total;
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Gets all unique kta paths that have been called
|
|
178
|
+
*/ getCalledKtaPaths() {
|
|
179
|
+
const ktaPaths = [];
|
|
180
|
+
for (const ktaKey of this.coordinateCalls.keys()){
|
|
181
|
+
ktaPaths.push(ktaKey.split('.'));
|
|
182
|
+
}
|
|
183
|
+
return ktaPaths;
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Creates a normalized scope key from scopes array
|
|
187
|
+
*/ createScopeKey(scopes) {
|
|
188
|
+
if (scopes.length === 0) return '__no_scopes__';
|
|
189
|
+
return [
|
|
190
|
+
...scopes
|
|
191
|
+
].sort().join(',');
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Parses a scope key back to scopes array
|
|
195
|
+
*/ parseScopeKey(scopeKey) {
|
|
196
|
+
if (scopeKey === '__no_scopes__') return [];
|
|
197
|
+
return scopeKey.split(',');
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Creates a normalized client key from client identifier
|
|
201
|
+
*/ createClientKey(client) {
|
|
202
|
+
if (!client) return '__no_client__';
|
|
203
|
+
if (typeof client === 'string') {
|
|
204
|
+
return `app:${client}`;
|
|
205
|
+
}
|
|
206
|
+
// Service client
|
|
207
|
+
const coordKey = `${client.coordinate.kta.join('.')};${this.createScopeKey(client.coordinate.scopes)}`;
|
|
208
|
+
return `service:${client.registryType}:${coordKey}`;
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Parses a client key back to client identifier
|
|
212
|
+
*/ parseClientKey(clientKey) {
|
|
213
|
+
if (clientKey === '__no_client__') return null;
|
|
214
|
+
if (clientKey.startsWith('app:')) {
|
|
215
|
+
return clientKey.substring(4);
|
|
216
|
+
}
|
|
217
|
+
if (clientKey.startsWith('service:')) {
|
|
218
|
+
const parts = clientKey.substring(8).split(':');
|
|
219
|
+
if (parts.length !== 2) return null;
|
|
220
|
+
const registryType = parts[0];
|
|
221
|
+
const coordParts = parts[1].split(';');
|
|
222
|
+
if (coordParts.length !== 2) return null;
|
|
223
|
+
const kta = coordParts[0].split('.');
|
|
224
|
+
const scopes = this.parseScopeKey(coordParts[1]);
|
|
225
|
+
return {
|
|
226
|
+
registryType,
|
|
227
|
+
coordinate: {
|
|
228
|
+
kta,
|
|
229
|
+
scopes
|
|
230
|
+
}
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
return null;
|
|
234
|
+
}
|
|
235
|
+
constructor(){
|
|
236
|
+
_define_property$4(this, "totalCalls", 0);
|
|
237
|
+
// Map structure: ktaKey -> scopeKey -> clientKey -> count
|
|
238
|
+
_define_property$4(this, "coordinateCalls", new Map());
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
48
242
|
const logger$1 = LibLogger.get("Registry");
|
|
49
243
|
const findScopedInstance = (scopedInstances, requestedScopes)=>{
|
|
50
244
|
if (!requestedScopes || requestedScopes.length === 0) {
|
|
@@ -68,13 +262,39 @@ const findScopedInstance = (scopedInstances, requestedScopes)=>{
|
|
|
68
262
|
};
|
|
69
263
|
const createRegistry = (type, registryHub)=>{
|
|
70
264
|
const instanceTree = {};
|
|
265
|
+
// Statistics tracking
|
|
266
|
+
const registryStats = new RegistryStats();
|
|
267
|
+
/**
|
|
268
|
+
* Creates a proxied Registry that automatically injects client information for service-to-service calls
|
|
269
|
+
*/ const createProxiedRegistry = (callingCoordinate)=>{
|
|
270
|
+
const serviceClient = {
|
|
271
|
+
registryType: type,
|
|
272
|
+
coordinate: {
|
|
273
|
+
kta: callingCoordinate.kta,
|
|
274
|
+
scopes: callingCoordinate.scopes
|
|
275
|
+
}
|
|
276
|
+
};
|
|
277
|
+
return {
|
|
278
|
+
...registry,
|
|
279
|
+
get: (kta, options)=>{
|
|
280
|
+
// Automatically inject the calling service as the client if no client is specified
|
|
281
|
+
const clientToUse = (options === null || options === void 0 ? void 0 : options.client) || serviceClient;
|
|
282
|
+
return registry.get(kta, {
|
|
283
|
+
...options,
|
|
284
|
+
client: clientToUse
|
|
285
|
+
});
|
|
286
|
+
}
|
|
287
|
+
};
|
|
288
|
+
};
|
|
71
289
|
const createInstance = (kta, scopes, factory)=>{
|
|
72
290
|
logger$1.debug(`Creating and registering instance for key path and scopes`, kta, scopes, `in registry type: ${type}`);
|
|
73
291
|
// Create coordinate for the instance
|
|
74
292
|
const coordinate = createCoordinate(kta, scopes);
|
|
75
|
-
//
|
|
293
|
+
// Create a proxied registry that automatically tracks this service as the client
|
|
294
|
+
const proxiedRegistry = createProxiedRegistry(coordinate);
|
|
295
|
+
// Use factory to create the instance with the proxied registry
|
|
76
296
|
const instance = factory(coordinate, {
|
|
77
|
-
registry,
|
|
297
|
+
registry: proxiedRegistry,
|
|
78
298
|
registryHub
|
|
79
299
|
});
|
|
80
300
|
// Validate the created instance
|
|
@@ -126,6 +346,8 @@ const createRegistry = (type, registryHub)=>{
|
|
|
126
346
|
registerInternal(kta, instance, options);
|
|
127
347
|
};
|
|
128
348
|
const get = (kta, options)=>{
|
|
349
|
+
// Track statistics with kta, scopes, and client
|
|
350
|
+
registryStats.recordGetCall(kta, options === null || options === void 0 ? void 0 : options.scopes, options === null || options === void 0 ? void 0 : options.client);
|
|
129
351
|
const keyPath = [
|
|
130
352
|
...kta
|
|
131
353
|
].reverse();
|
|
@@ -172,6 +394,9 @@ const createRegistry = (type, registryHub)=>{
|
|
|
172
394
|
traverseTree(instanceTree);
|
|
173
395
|
return coordinates;
|
|
174
396
|
};
|
|
397
|
+
const getStatistics = ()=>{
|
|
398
|
+
return registryStats.getStatistics();
|
|
399
|
+
};
|
|
175
400
|
const registry = {
|
|
176
401
|
type,
|
|
177
402
|
registryHub,
|
|
@@ -179,6 +404,7 @@ const createRegistry = (type, registryHub)=>{
|
|
|
179
404
|
register,
|
|
180
405
|
get,
|
|
181
406
|
getCoordinates,
|
|
407
|
+
getStatistics,
|
|
182
408
|
instanceTree
|
|
183
409
|
};
|
|
184
410
|
return registry;
|
|
@@ -586,6 +812,7 @@ exports.RegistryCreationError = RegistryCreationError;
|
|
|
586
812
|
exports.RegistryError = RegistryError;
|
|
587
813
|
exports.RegistryFactoryError = RegistryFactoryError;
|
|
588
814
|
exports.RegistryHubError = RegistryHubError;
|
|
815
|
+
exports.RegistryStats = RegistryStats;
|
|
589
816
|
exports.RegistryTypeNotFoundError = RegistryTypeNotFoundError;
|
|
590
817
|
exports.ScopeNotFoundError = ScopeNotFoundError;
|
|
591
818
|
exports.createCoordinate = createCoordinate;
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.cjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -2,8 +2,9 @@ export { createCoordinate } from './Coordinate.js';
|
|
|
2
2
|
export { createInstance, isInstance } from './Instance.js';
|
|
3
3
|
export { createRegistry } from './Registry.js';
|
|
4
4
|
export { createRegistryHub } from './RegistryHub.js';
|
|
5
|
+
export { RegistryStats } from './RegistryStats.js';
|
|
5
6
|
export { InvalidFactoryResultError, InvalidInstanceRegistrationError, RegistryCreationError, RegistryError } from './errors/RegistryError.js';
|
|
6
7
|
export { InstanceError, InstanceNotFoundError, NoChildrenAvailableError, NoInstancesAvailableError, NoInstancesRegisteredError, ScopeNotFoundError } from './errors/InstanceError.js';
|
|
7
8
|
export { CoordinateError, InvalidCoordinateError, InvalidKTAError, InvalidScopesError } from './errors/CoordinateError.js';
|
|
8
9
|
export { DuplicateRegistryTypeError, InvalidRegistryFactoryResultError, RegistryFactoryError, RegistryHubError, RegistryTypeNotFoundError } from './errors/RegistryHubError.js';
|
|
9
|
-
//# sourceMappingURL=data:application/json;charset=utf-8;base64,
|
|
10
|
+
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VzIjpbXSwic291cmNlc0NvbnRlbnQiOltdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7OzsifQ==
|
package/dist/types.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Instance } from './Instance';
|
|
2
2
|
import { Coordinate } from './Coordinate';
|
|
3
|
+
import { ClientIdentifier, RegistryStatistics } from './RegistryStats';
|
|
3
4
|
/**
|
|
4
5
|
* Represents a coordinate along with information about which registry contains it.
|
|
5
6
|
*/
|
|
@@ -24,6 +25,7 @@ export interface RegistryHub {
|
|
|
24
25
|
*/
|
|
25
26
|
readonly get: (type: string, kta: string[], options?: {
|
|
26
27
|
scopes?: string[];
|
|
28
|
+
client?: ClientIdentifier;
|
|
27
29
|
}) => Instance<any, any | never, any | never, any | never, any | never, any | never> | null;
|
|
28
30
|
/**
|
|
29
31
|
* Retrieves a registry instance by its type key.
|
|
@@ -95,6 +97,7 @@ export interface Registry {
|
|
|
95
97
|
*/
|
|
96
98
|
get: (kta: string[], options?: {
|
|
97
99
|
scopes?: string[];
|
|
100
|
+
client?: ClientIdentifier;
|
|
98
101
|
}) => Instance<any, any | never, any | never, any | never, any | never, any | never> | null;
|
|
99
102
|
/** The tree structure representing the hierarchy of instances */
|
|
100
103
|
instanceTree: InstanceTree;
|
|
@@ -102,4 +105,8 @@ export interface Registry {
|
|
|
102
105
|
* Retrieves all coordinates currently registered in the registry.
|
|
103
106
|
*/
|
|
104
107
|
getCoordinates: () => Coordinate<any, any | never, any | never, any | never, any | never, any | never>[];
|
|
108
|
+
/**
|
|
109
|
+
* Retrieves statistics about get() method calls, including total calls and per-coordinate call counts.
|
|
110
|
+
*/
|
|
111
|
+
getStatistics: () => RegistryStatistics;
|
|
105
112
|
}
|
package/docs/README.md
CHANGED
|
@@ -4,11 +4,11 @@ This is a React-based documentation site for the Fjell Registry package. It prov
|
|
|
4
4
|
|
|
5
5
|
## Features
|
|
6
6
|
|
|
7
|
-
-
|
|
8
|
-
-
|
|
9
|
-
-
|
|
10
|
-
-
|
|
11
|
-
-
|
|
7
|
+
- **Responsive Design** - Works on desktop, tablet, and mobile
|
|
8
|
+
- **Modern UI** - Clean, modern interface with Fjell branding
|
|
9
|
+
- **Syntax Highlighting** - Code blocks with proper syntax highlighting
|
|
10
|
+
- **Markdown Support** - Full GitHub Flavored Markdown support
|
|
11
|
+
- **Fast Loading** - Built with Vite for optimal performance
|
|
12
12
|
|
|
13
13
|
## Development
|
|
14
14
|
|
package/docs/index.html
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
<meta charset="UTF-8" />
|
|
6
6
|
<link rel="icon" type="image/svg+xml" href="/fjell-icon.svg" />
|
|
7
7
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
8
|
-
<title
|
|
8
|
+
<title>Fjell Registry - TypeScript Registry Library</title>
|
|
9
9
|
<meta name="description" content="Common Registry for Fjell - A powerful TypeScript registry system">
|
|
10
10
|
</head>
|
|
11
11
|
|