@azure-net/kit 6.0.0-next.8 → 6.0.0-next.9

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/README.md CHANGED
@@ -342,8 +342,8 @@ URLs; external navigation should use browser location APIs.
342
342
  ## CompositionRoot
343
343
 
344
344
  `CreateServiceContainer` remains unchanged. `CompositionRoot` is a lazy class
345
- facade over it, with a unique internal container name. It can be created at module
346
- scope; `resolveContainer()` resolves against the current SSR request or browser
345
+ facade over it, with a unique symbol as its internal container identity. It can be created at module
346
+ scope; `resolve()` resolves against the current SSR request or browser
347
347
  cache, never a request captured by the constructor.
348
348
 
349
349
  ```ts
@@ -361,7 +361,7 @@ export const Identity = new CompositionRoot({
361
361
  });
362
362
 
363
363
  // Inside a presenter factory or an active request:
364
- const { Account } = Identity.resolveContainer();
364
+ const { Account } = Identity.resolve();
365
365
  ```
366
366
 
367
367
  Dependencies accept both other `CompositionRoot` instances and existing
@@ -370,3 +370,6 @@ Only registration metadata is wrapped; there is no extra proxy around services
370
370
  and no new caching layer. Repeated resolution preserves existing container/service
371
371
  identity. If explicit cleanup is needed, use `await cleanupProvider(Identity.name)`.
372
372
  Declare roots once, rather than creating new roots per component render.
373
+ `name` is now a symbol, not a serializable string. Its description is for diagnostics
374
+ only; equal descriptions never share a cache. Existing string keys passed directly
375
+ to `CreateServiceContainer` and `cleanupProvider` remain supported.
@@ -1,12 +1,12 @@
1
1
  import { type ProviderSettings, type ProviderWithType } from './Provider.js';
2
2
  type Services = Record<string, () => unknown>;
3
3
  type Dependency = ProviderWithType<Services> | {
4
- readonly resolveContainer: ProviderWithType<Services>;
4
+ readonly resolve: ProviderWithType<Services>;
5
5
  };
6
6
  type Dependencies = Record<string, Dependency>;
7
7
  type Providers<D extends Dependencies> = {
8
8
  [K in keyof D]: D[K] extends {
9
- readonly resolveContainer: infer P extends ProviderWithType<Services>;
9
+ readonly resolve: infer P extends ProviderWithType<Services>;
10
10
  } ? P : D[K] extends ProviderWithType<Services> ? D[K] : never;
11
11
  };
12
12
  export type CompositionRootSettings<T extends Services, D extends Dependencies = Record<never, never>> = Omit<ProviderSettings<T, Providers<D>>, 'dependsOn'> & {
@@ -14,8 +14,8 @@ export type CompositionRootSettings<T extends Services, D extends Dependencies =
14
14
  };
15
15
  /** Holds registration metadata only. Resolving always uses the current request's container. */
16
16
  export declare class CompositionRoot<T extends Services, D extends Dependencies = Record<never, never>> {
17
- readonly name: string;
18
- readonly resolveContainer: ProviderWithType<T>;
17
+ readonly name: symbol;
18
+ readonly resolve: ProviderWithType<T>;
19
19
  constructor(settings: CompositionRootSettings<T, D>);
20
20
  }
21
21
  export {};
@@ -1,11 +1,11 @@
1
1
  import { CreateServiceContainer } from './Provider.js';
2
- const toProvider = (dependency) => typeof dependency === 'function' ? dependency : dependency.resolveContainer;
2
+ const toProvider = (dependency) => typeof dependency === 'function' ? dependency : dependency.resolve;
3
3
  /** Holds registration metadata only. Resolving always uses the current request's container. */
4
4
  export class CompositionRoot {
5
- name = `@azure-net/kit:CompositionRoot:${crypto.randomUUID()}`;
6
- resolveContainer;
5
+ name = Symbol('@azure-net/kit:CompositionRoot');
6
+ resolve;
7
7
  constructor(settings) {
8
8
  const dependsOn = Object.fromEntries(Object.entries(settings.dependsOn ?? {}).map(([key, dependency]) => [key, toProvider(dependency)]));
9
- this.resolveContainer = CreateServiceContainer(this.name, { ...settings, dependsOn });
9
+ this.resolve = CreateServiceContainer(this.name, { ...settings, dependsOn });
10
10
  }
11
11
  }
@@ -1,3 +1,4 @@
1
+ export type ProviderKey = string | symbol;
1
2
  type ServiceFactory<T> = () => T;
2
3
  type ServiceMap = Record<string, ServiceFactory<unknown>>;
3
4
  type ResolvedServices<T extends ServiceMap> = {
@@ -16,6 +17,6 @@ export interface ProviderSettings<T extends ServiceMap, D extends Record<string,
16
17
  boot?: (services: ResolvedServices<T>) => undefined;
17
18
  register: ProviderFactory<T, D>;
18
19
  }
19
- export declare const CreateServiceContainer: <T extends ServiceMap, D extends Record<string, ProviderWithType<ServiceMap>>>(name: string, settings: ProviderSettings<T, D>) => ProviderWithType<T>;
20
- export declare function cleanupProvider(name: string): Promise<void>;
20
+ export declare const CreateServiceContainer: <T extends ServiceMap, D extends Record<string, ProviderWithType<ServiceMap>>>(name: ProviderKey, settings: ProviderSettings<T, D>) => ProviderWithType<T>;
21
+ export declare function cleanupProvider(name: ProviderKey): Promise<void>;
21
22
  export {};
@@ -67,19 +67,20 @@ const getConstructionStack = () => {
67
67
  const context = RequestContext.current();
68
68
  return (getContextInternals(context).boundaryProviderConstructionStack ??= []);
69
69
  };
70
- const runWithCycleGuard = (key, callback) => {
70
+ const runWithCycleGuard = (provider, member, callback) => {
71
71
  const stack = getConstructionStack();
72
- if (stack.includes(key)) {
73
- const cycleStart = stack.indexOf(key);
74
- const cyclePath = [...stack.slice(cycleStart), key].join(' -> ');
72
+ const cycleStart = stack.findIndex((entry) => entry.provider === provider && entry.member === member);
73
+ const entry = { provider, member };
74
+ if (cycleStart !== -1) {
75
+ const cyclePath = [...stack.slice(cycleStart), entry].map(({ provider, member }) => `${String(provider)}.${member}`).join(' -> ');
75
76
  throw new AzureNetKitInternalError(`[BoundaryProvider] Circular provider dependency detected: ${cyclePath}`);
76
77
  }
77
- stack.push(key);
78
+ stack.push(entry);
78
79
  try {
79
80
  return callback();
80
81
  }
81
82
  finally {
82
- const idx = stack.lastIndexOf(key);
83
+ const idx = stack.lastIndexOf(entry);
83
84
  if (idx !== -1)
84
85
  stack.splice(idx, 1);
85
86
  }
@@ -109,7 +110,7 @@ export const CreateServiceContainer = (name, settings) => {
109
110
  }
110
111
  });
111
112
  }
112
- factories = runWithCycleGuard(`${name}.register`, () => register(deps));
113
+ factories = runWithCycleGuard(name, 'register', () => register(deps));
113
114
  return factories;
114
115
  };
115
116
  const providerProxy = new Proxy({}, {
@@ -125,15 +126,15 @@ export const CreateServiceContainer = (name, settings) => {
125
126
  return undefined;
126
127
  if (Reflect.has(target, key))
127
128
  return Reflect.get(target, key, receiver);
128
- throw new AzureNetKitInternalError(`[BoundaryProvider] Service '${key}' not found in provider '${name}'`);
129
+ throw new AzureNetKitInternalError(`[BoundaryProvider] Service '${key}' not found in provider '${String(name)}'`);
129
130
  }
130
131
  const factory = factories[key];
131
132
  if (typeof factory !== 'function') {
132
133
  throw new AzureNetKitInternalError('[BoundaryProvider] Factory must be a function');
133
134
  }
134
- const instance = runWithCycleGuard(`${name}.${key}`, () => factory());
135
+ const instance = runWithCycleGuard(name, key, () => factory());
135
136
  if (instance && typeof instance?.then === 'function') {
136
- throw new AzureNetKitInternalError(`[BoundaryProvider] Service '${key}' in provider '${name}' returned Promise.`);
137
+ throw new AzureNetKitInternalError(`[BoundaryProvider] Service '${key}' in provider '${String(name)}' returned Promise.`);
137
138
  }
138
139
  cache.set(key, instance);
139
140
  return instance;
@@ -172,7 +173,7 @@ export const CreateServiceContainer = (name, settings) => {
172
173
  const bootResult = boot(providerProxy);
173
174
  if (bootResult && typeof bootResult.then === 'function') {
174
175
  void Promise.resolve(bootResult).catch(() => undefined);
175
- throw new AzureNetKitInternalError(`[BoundaryProvider] Boot for provider '${name}' must be synchronous.`);
176
+ throw new AzureNetKitInternalError(`[BoundaryProvider] Boot for provider '${String(name)}' must be synchronous.`);
176
177
  }
177
178
  setBootFlag(name, true);
178
179
  }
@@ -192,10 +193,10 @@ export async function cleanupProvider(name) {
192
193
  if (service && typeof service === 'object' && 'dispose' in service) {
193
194
  try {
194
195
  const disposeResult = service.dispose();
195
- promises.push(Promise.resolve(disposeResult).catch((err) => console.error(`Error disposing ${name}.${key}:`, err)));
196
+ promises.push(Promise.resolve(disposeResult).catch((err) => console.error(`Error disposing ${String(name)}.${key}:`, err)));
196
197
  }
197
198
  catch (err) {
198
- console.error(`Error disposing ${name}.${key}:`, err);
199
+ console.error(`Error disposing ${String(name)}.${key}:`, err);
199
200
  }
200
201
  }
201
202
  }
@@ -1,7 +1,7 @@
1
1
  export { UniversalCookie, UniversalCookieInstance, UniversalNamedCookieInstance, type CookieOptions } from './cookie/index.js';
2
2
  export { BackgroundTask } from './background-task/index.js';
3
3
  export { ClassMirror } from './class-mirror/index.js';
4
- export { CreateServiceContainer, cleanupProvider, type ProviderSettings } from './boundary-provider/index.js';
4
+ export { CreateServiceContainer, cleanupProvider, type ProviderSettings, type ProviderKey } from './boundary-provider/index.js';
5
5
  export { CompositionRoot, type CompositionRootSettings } from './boundary-provider/index.js';
6
6
  export * from './app/index.js';
7
7
  export { useLogger, LoggerErrors, type ILoggerError, type ILoggerSettings } from './logger/index.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@azure-net/kit",
3
- "version": "6.0.0-next.8",
3
+ "version": "6.0.0-next.9",
4
4
  "license": "MIT",
5
5
  "author": "Pixel1917",
6
6
  "description": "Universal toolkit and library collection, developed as part of the Azure-net ecosystem",