@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/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
- // Use factory to create the instance with the new context parameter
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;
@@ -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
@@ -2,5 +2,6 @@ export * from './Coordinate';
2
2
  export * from './Instance';
3
3
  export * from './Registry';
4
4
  export * from './RegistryHub';
5
+ export * from './RegistryStats';
5
6
  export * from './types';
6
7
  export * from './errors';
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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VzIjpbXSwic291cmNlc0NvbnRlbnQiOltdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7OyJ9
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
- - 📱 **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
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>🏔️ Fjell Registry - TypeScript Registry Library</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