@juspay/neurolink 11.2.3 → 11.2.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.
Files changed (35) hide show
  1. package/CHANGELOG.md +2 -0
  2. package/dist/browser/neurolink.min.js +383 -383
  3. package/dist/core/handlerRegistry.d.ts +29 -0
  4. package/dist/core/handlerRegistry.js +61 -0
  5. package/dist/factories/providerRegistry.d.ts +4 -16
  6. package/dist/factories/providerRegistry.js +4 -56
  7. package/dist/lib/core/handlerRegistry.d.ts +29 -0
  8. package/dist/lib/core/handlerRegistry.js +62 -0
  9. package/dist/lib/factories/providerRegistry.d.ts +4 -16
  10. package/dist/lib/factories/providerRegistry.js +4 -56
  11. package/dist/lib/utils/avatarProcessor.d.ts +5 -1
  12. package/dist/lib/utils/avatarProcessor.js +13 -18
  13. package/dist/lib/utils/musicProcessor.d.ts +5 -1
  14. package/dist/lib/utils/musicProcessor.js +13 -18
  15. package/dist/lib/utils/sttProcessor.d.ts +10 -2
  16. package/dist/lib/utils/sttProcessor.js +22 -18
  17. package/dist/lib/utils/ttsProcessor.d.ts +10 -2
  18. package/dist/lib/utils/ttsProcessor.js +22 -18
  19. package/dist/lib/utils/videoProcessor.d.ts +5 -1
  20. package/dist/lib/utils/videoProcessor.js +13 -18
  21. package/dist/lib/voice/RealtimeVoiceAPI.d.ts +1 -1
  22. package/dist/lib/voice/RealtimeVoiceAPI.js +17 -28
  23. package/dist/utils/avatarProcessor.d.ts +5 -1
  24. package/dist/utils/avatarProcessor.js +13 -18
  25. package/dist/utils/musicProcessor.d.ts +5 -1
  26. package/dist/utils/musicProcessor.js +13 -18
  27. package/dist/utils/sttProcessor.d.ts +10 -2
  28. package/dist/utils/sttProcessor.js +22 -18
  29. package/dist/utils/ttsProcessor.d.ts +10 -2
  30. package/dist/utils/ttsProcessor.js +22 -18
  31. package/dist/utils/videoProcessor.d.ts +5 -1
  32. package/dist/utils/videoProcessor.js +13 -18
  33. package/dist/voice/RealtimeVoiceAPI.d.ts +1 -1
  34. package/dist/voice/RealtimeVoiceAPI.js +17 -28
  35. package/package.json +7 -1
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Generic provider-name → handler registry shared by every media-generation
3
+ * ecosystem (TTS, STT, Realtime, Video, Music, Avatar). Each ecosystem's own
4
+ * processor class composes one instance of this class instead of hand-rolling
5
+ * its own `Map<string, THandler>` plus register/supports/get/list methods.
6
+ *
7
+ * Centralizes only the behavior that was byte-identical across all six
8
+ * hand-rolled registries: input validation, name normalization (lowercase),
9
+ * the overwrite-warning log line, and the four lookup/list/clear operations.
10
+ * Registration-outcome debug logging (whose exact phrasing differs per
11
+ * ecosystem — e.g. "Registered TTS handler..." vs "Registered video
12
+ * handler...") and any ecosystem-specific extra logging (e.g. TTS/STT's
13
+ * `supports()` diagnostics) stay in the owning processor's own wrapper
14
+ * methods; this class does not attempt to unify those.
15
+ */
16
+ export declare class HandlerRegistry<THandler> {
17
+ private readonly scopeName;
18
+ private readonly handlers;
19
+ /**
20
+ * @param scopeName Log-line prefix, e.g. "TTSProcessor" — matches the
21
+ * `[ClassName]` prefix each processor already uses in its own logs.
22
+ */
23
+ constructor(scopeName: string);
24
+ register(providerName: string, handler: THandler): void;
25
+ supports(providerName: string): boolean;
26
+ get(providerName: string): THandler | undefined;
27
+ list(): string[];
28
+ clear(): void;
29
+ }
@@ -0,0 +1,61 @@
1
+ import { logger } from "../utils/logger.js";
2
+ import { sanitizeForLog } from "../utils/logSanitize.js";
3
+ /**
4
+ * Generic provider-name → handler registry shared by every media-generation
5
+ * ecosystem (TTS, STT, Realtime, Video, Music, Avatar). Each ecosystem's own
6
+ * processor class composes one instance of this class instead of hand-rolling
7
+ * its own `Map<string, THandler>` plus register/supports/get/list methods.
8
+ *
9
+ * Centralizes only the behavior that was byte-identical across all six
10
+ * hand-rolled registries: input validation, name normalization (lowercase),
11
+ * the overwrite-warning log line, and the four lookup/list/clear operations.
12
+ * Registration-outcome debug logging (whose exact phrasing differs per
13
+ * ecosystem — e.g. "Registered TTS handler..." vs "Registered video
14
+ * handler...") and any ecosystem-specific extra logging (e.g. TTS/STT's
15
+ * `supports()` diagnostics) stay in the owning processor's own wrapper
16
+ * methods; this class does not attempt to unify those.
17
+ */
18
+ export class HandlerRegistry {
19
+ scopeName;
20
+ handlers = new Map();
21
+ /**
22
+ * @param scopeName Log-line prefix, e.g. "TTSProcessor" — matches the
23
+ * `[ClassName]` prefix each processor already uses in its own logs.
24
+ */
25
+ constructor(scopeName) {
26
+ this.scopeName = scopeName;
27
+ }
28
+ register(providerName, handler) {
29
+ if (!providerName) {
30
+ throw new Error("Provider name is required");
31
+ }
32
+ if (!handler) {
33
+ throw new Error("Handler is required");
34
+ }
35
+ const key = providerName.toLowerCase();
36
+ if (this.handlers.has(key)) {
37
+ // Every caller today passes a literal provider slug, but this class is
38
+ // generic over an arbitrary string — sanitize before logging it so a
39
+ // future caller building the key from untrusted input can't leak a
40
+ // bearer token/API key through this warning.
41
+ logger.warn(`[${this.scopeName}] Overwriting existing handler for provider: ${sanitizeForLog(key)}`);
42
+ }
43
+ this.handlers.set(key, handler);
44
+ }
45
+ supports(providerName) {
46
+ if (!providerName) {
47
+ return false;
48
+ }
49
+ return this.handlers.has(providerName.toLowerCase());
50
+ }
51
+ get(providerName) {
52
+ return this.handlers.get(providerName.toLowerCase());
53
+ }
54
+ list() {
55
+ return Array.from(this.handlers.keys());
56
+ }
57
+ clear() {
58
+ this.handlers.clear();
59
+ logger.debug(`[${this.scopeName}] Cleared all handlers`);
60
+ }
61
+ }
@@ -1,14 +1,4 @@
1
1
  import type { ProviderRegistryOptions } from "../types/index.js";
2
- import { AIProviderName } from "../constants/enums.js";
3
- /**
4
- * Static module -> provider-ID manifest for every provider registered below.
5
- * Module names (file/dir under src/lib/providers/) intentionally differ from
6
- * their canonical IDs (e.g. amazonBedrock -> "bedrock", googleVertex ->
7
- * "vertex"); static scanners that cannot resolve the dynamic import() calls
8
- * use this mapping to confirm a module is registered. Enforced at runtime so
9
- * the registry cannot silently drift from this manifest.
10
- */
11
- export declare const PROVIDER_MODULE_TO_ID: Readonly<Record<string, AIProviderName>>;
12
2
  /**
13
3
  * Provider Registry - registers all providers with the factory
14
4
  * This is where we migrate providers one by one to the new pattern
@@ -43,12 +33,10 @@ export declare class ProviderRegistry {
43
33
  * (avoids circular dependencies; see CLAUDE.md).
44
34
  *
45
35
  * Not registered (by design): index.ts, providerTypeUtils.ts,
46
- * openaiChatCompletionsBase.ts, openaiChatCompletionsClient.ts,
47
- * anthropicImageBlocks.ts (shared base/helper modules), anthropicBaseProvider.ts
48
- * (legacy; anthropic.ts is live), googleNativeGemini3.ts (shared helpers).
49
- * Filename != provider ID (e.g. amazonBedrock -> "bedrock"); the
50
- * statically-scannable PROVIDER_MODULE_TO_ID manifest maps every registered
51
- * module to its provider ID and is enforced below (Pattern Analysis #1178/#1317).
36
+ * anthropicBaseProvider.ts (legacy; anthropic.ts is live),
37
+ * googleNativeGemini3.ts (shared helpers). Filename != provider ID
38
+ * (e.g. amazonBedrock -> "bedrock"); static scanners that miss dynamic
39
+ * imports may false-positive (Pattern Analysis #1178).
52
40
  */
53
41
  private static _doRegister;
54
42
  /**
@@ -3,46 +3,6 @@ import { logger } from "../utils/logger.js";
3
3
  import { AIProviderName, GoogleAIModels, OpenAIModels, AnthropicModels, VertexModels, OllamaModels, LiteLLMModels, HuggingFaceModels, DeepSeekModels, NvidiaNimModels, OpenRouterModels, CohereModels, VoyageModels, JinaModels, StabilityModels, IdeogramModels, RecraftModels, ReplicateModels, } from "../constants/enums.js";
4
4
  import { PROVIDER_DESCRIPTORS_BY_NAME } from "./providerDescriptors.js";
5
5
  import { OPENAI_COMPAT_CATALOG } from "../providers/openaiCompatCatalog.js";
6
- /**
7
- * Static module -> provider-ID manifest for every provider registered below.
8
- * Module names (file/dir under src/lib/providers/) intentionally differ from
9
- * their canonical IDs (e.g. amazonBedrock -> "bedrock", googleVertex ->
10
- * "vertex"); static scanners that cannot resolve the dynamic import() calls
11
- * use this mapping to confirm a module is registered. Enforced at runtime so
12
- * the registry cannot silently drift from this manifest.
13
- */
14
- export const PROVIDER_MODULE_TO_ID = {
15
- amazonBedrock: AIProviderName.BEDROCK,
16
- amazonSagemaker: AIProviderName.SAGEMAKER,
17
- anthropic: AIProviderName.ANTHROPIC,
18
- azureOpenai: AIProviderName.AZURE,
19
- cloudflare: AIProviderName.CLOUDFLARE,
20
- cohere: AIProviderName.COHERE,
21
- deepseek: AIProviderName.DEEPSEEK,
22
- fireworks: AIProviderName.FIREWORKS,
23
- googleAiStudio: AIProviderName.GOOGLE_AI,
24
- googleVertex: AIProviderName.VERTEX,
25
- groq: AIProviderName.GROQ,
26
- huggingFace: AIProviderName.HUGGINGFACE,
27
- ideogram: AIProviderName.IDEOGRAM,
28
- jina: AIProviderName.JINA,
29
- litellm: AIProviderName.LITELLM,
30
- llamaCpp: AIProviderName.LLAMACPP,
31
- lmStudio: AIProviderName.LM_STUDIO,
32
- mistral: AIProviderName.MISTRAL,
33
- nvidiaNim: AIProviderName.NVIDIA_NIM,
34
- ollama: AIProviderName.OLLAMA,
35
- openAI: AIProviderName.OPENAI,
36
- openaiCompatible: AIProviderName.OPENAI_COMPATIBLE,
37
- openRouter: AIProviderName.OPENROUTER,
38
- perplexity: AIProviderName.PERPLEXITY,
39
- recraft: AIProviderName.RECRAFT,
40
- replicate: AIProviderName.REPLICATE,
41
- stability: AIProviderName.STABILITY,
42
- togetherAi: AIProviderName.TOGETHER_AI,
43
- voyage: AIProviderName.VOYAGE,
44
- xai: AIProviderName.XAI,
45
- };
46
6
  /**
47
7
  * Provider Registry - registers all providers with the factory
48
8
  * This is where we migrate providers one by one to the new pattern
@@ -94,12 +54,10 @@ export class ProviderRegistry {
94
54
  * (avoids circular dependencies; see CLAUDE.md).
95
55
  *
96
56
  * Not registered (by design): index.ts, providerTypeUtils.ts,
97
- * openaiChatCompletionsBase.ts, openaiChatCompletionsClient.ts,
98
- * anthropicImageBlocks.ts (shared base/helper modules), anthropicBaseProvider.ts
99
- * (legacy; anthropic.ts is live), googleNativeGemini3.ts (shared helpers).
100
- * Filename != provider ID (e.g. amazonBedrock -> "bedrock"); the
101
- * statically-scannable PROVIDER_MODULE_TO_ID manifest maps every registered
102
- * module to its provider ID and is enforced below (Pattern Analysis #1178/#1317).
57
+ * anthropicBaseProvider.ts (legacy; anthropic.ts is live),
58
+ * googleNativeGemini3.ts (shared helpers). Filename != provider ID
59
+ * (e.g. amazonBedrock -> "bedrock"); static scanners that miss dynamic
60
+ * imports may false-positive (Pattern Analysis #1178).
103
61
  */
104
62
  // eslint-disable-next-line max-lines-per-function
105
63
  static async _doRegister() {
@@ -270,16 +228,6 @@ export class ProviderRegistry {
270
228
  const { RecraftProvider } = await import("../providers/recraft.js");
271
229
  return new RecraftProvider(modelName, sdk, undefined, recraftCreds);
272
230
  }, process.env.RECRAFT_MODEL || RecraftModels.RECRAFT_V3, ["recraft"], PROVIDER_DESCRIPTORS_BY_NAME.get(AIProviderName.RECRAFT));
273
- const unregistered = Object.entries(PROVIDER_MODULE_TO_ID).filter(([module, id]) => {
274
- if (!ProviderFactory.hasProvider(id)) {
275
- logger.error(`[ProviderRegistry] drift: module "${module}" not registered as "${id}"`);
276
- return true;
277
- }
278
- return false;
279
- });
280
- if (unregistered.length > 0) {
281
- throw new Error(`ProviderRegistry drift: ${unregistered.length} module(s) in PROVIDER_MODULE_TO_ID are not registered`);
282
- }
283
231
  logger.debug("All AI providers registered successfully");
284
232
  // ===== TTS HANDLER REGISTRATION =====
285
233
  try {
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Generic provider-name → handler registry shared by every media-generation
3
+ * ecosystem (TTS, STT, Realtime, Video, Music, Avatar). Each ecosystem's own
4
+ * processor class composes one instance of this class instead of hand-rolling
5
+ * its own `Map<string, THandler>` plus register/supports/get/list methods.
6
+ *
7
+ * Centralizes only the behavior that was byte-identical across all six
8
+ * hand-rolled registries: input validation, name normalization (lowercase),
9
+ * the overwrite-warning log line, and the four lookup/list/clear operations.
10
+ * Registration-outcome debug logging (whose exact phrasing differs per
11
+ * ecosystem — e.g. "Registered TTS handler..." vs "Registered video
12
+ * handler...") and any ecosystem-specific extra logging (e.g. TTS/STT's
13
+ * `supports()` diagnostics) stay in the owning processor's own wrapper
14
+ * methods; this class does not attempt to unify those.
15
+ */
16
+ export declare class HandlerRegistry<THandler> {
17
+ private readonly scopeName;
18
+ private readonly handlers;
19
+ /**
20
+ * @param scopeName Log-line prefix, e.g. "TTSProcessor" — matches the
21
+ * `[ClassName]` prefix each processor already uses in its own logs.
22
+ */
23
+ constructor(scopeName: string);
24
+ register(providerName: string, handler: THandler): void;
25
+ supports(providerName: string): boolean;
26
+ get(providerName: string): THandler | undefined;
27
+ list(): string[];
28
+ clear(): void;
29
+ }
@@ -0,0 +1,62 @@
1
+ import { logger } from "../utils/logger.js";
2
+ import { sanitizeForLog } from "../utils/logSanitize.js";
3
+ /**
4
+ * Generic provider-name → handler registry shared by every media-generation
5
+ * ecosystem (TTS, STT, Realtime, Video, Music, Avatar). Each ecosystem's own
6
+ * processor class composes one instance of this class instead of hand-rolling
7
+ * its own `Map<string, THandler>` plus register/supports/get/list methods.
8
+ *
9
+ * Centralizes only the behavior that was byte-identical across all six
10
+ * hand-rolled registries: input validation, name normalization (lowercase),
11
+ * the overwrite-warning log line, and the four lookup/list/clear operations.
12
+ * Registration-outcome debug logging (whose exact phrasing differs per
13
+ * ecosystem — e.g. "Registered TTS handler..." vs "Registered video
14
+ * handler...") and any ecosystem-specific extra logging (e.g. TTS/STT's
15
+ * `supports()` diagnostics) stay in the owning processor's own wrapper
16
+ * methods; this class does not attempt to unify those.
17
+ */
18
+ export class HandlerRegistry {
19
+ scopeName;
20
+ handlers = new Map();
21
+ /**
22
+ * @param scopeName Log-line prefix, e.g. "TTSProcessor" — matches the
23
+ * `[ClassName]` prefix each processor already uses in its own logs.
24
+ */
25
+ constructor(scopeName) {
26
+ this.scopeName = scopeName;
27
+ }
28
+ register(providerName, handler) {
29
+ if (!providerName) {
30
+ throw new Error("Provider name is required");
31
+ }
32
+ if (!handler) {
33
+ throw new Error("Handler is required");
34
+ }
35
+ const key = providerName.toLowerCase();
36
+ if (this.handlers.has(key)) {
37
+ // Every caller today passes a literal provider slug, but this class is
38
+ // generic over an arbitrary string — sanitize before logging it so a
39
+ // future caller building the key from untrusted input can't leak a
40
+ // bearer token/API key through this warning.
41
+ logger.warn(`[${this.scopeName}] Overwriting existing handler for provider: ${sanitizeForLog(key)}`);
42
+ }
43
+ this.handlers.set(key, handler);
44
+ }
45
+ supports(providerName) {
46
+ if (!providerName) {
47
+ return false;
48
+ }
49
+ return this.handlers.has(providerName.toLowerCase());
50
+ }
51
+ get(providerName) {
52
+ return this.handlers.get(providerName.toLowerCase());
53
+ }
54
+ list() {
55
+ return Array.from(this.handlers.keys());
56
+ }
57
+ clear() {
58
+ this.handlers.clear();
59
+ logger.debug(`[${this.scopeName}] Cleared all handlers`);
60
+ }
61
+ }
62
+ //# sourceMappingURL=handlerRegistry.js.map
@@ -1,14 +1,4 @@
1
1
  import type { ProviderRegistryOptions } from "../types/index.js";
2
- import { AIProviderName } from "../constants/enums.js";
3
- /**
4
- * Static module -> provider-ID manifest for every provider registered below.
5
- * Module names (file/dir under src/lib/providers/) intentionally differ from
6
- * their canonical IDs (e.g. amazonBedrock -> "bedrock", googleVertex ->
7
- * "vertex"); static scanners that cannot resolve the dynamic import() calls
8
- * use this mapping to confirm a module is registered. Enforced at runtime so
9
- * the registry cannot silently drift from this manifest.
10
- */
11
- export declare const PROVIDER_MODULE_TO_ID: Readonly<Record<string, AIProviderName>>;
12
2
  /**
13
3
  * Provider Registry - registers all providers with the factory
14
4
  * This is where we migrate providers one by one to the new pattern
@@ -43,12 +33,10 @@ export declare class ProviderRegistry {
43
33
  * (avoids circular dependencies; see CLAUDE.md).
44
34
  *
45
35
  * Not registered (by design): index.ts, providerTypeUtils.ts,
46
- * openaiChatCompletionsBase.ts, openaiChatCompletionsClient.ts,
47
- * anthropicImageBlocks.ts (shared base/helper modules), anthropicBaseProvider.ts
48
- * (legacy; anthropic.ts is live), googleNativeGemini3.ts (shared helpers).
49
- * Filename != provider ID (e.g. amazonBedrock -> "bedrock"); the
50
- * statically-scannable PROVIDER_MODULE_TO_ID manifest maps every registered
51
- * module to its provider ID and is enforced below (Pattern Analysis #1178/#1317).
36
+ * anthropicBaseProvider.ts (legacy; anthropic.ts is live),
37
+ * googleNativeGemini3.ts (shared helpers). Filename != provider ID
38
+ * (e.g. amazonBedrock -> "bedrock"); static scanners that miss dynamic
39
+ * imports may false-positive (Pattern Analysis #1178).
52
40
  */
53
41
  private static _doRegister;
54
42
  /**
@@ -3,46 +3,6 @@ import { logger } from "../utils/logger.js";
3
3
  import { AIProviderName, GoogleAIModels, OpenAIModels, AnthropicModels, VertexModels, OllamaModels, LiteLLMModels, HuggingFaceModels, DeepSeekModels, NvidiaNimModels, OpenRouterModels, CohereModels, VoyageModels, JinaModels, StabilityModels, IdeogramModels, RecraftModels, ReplicateModels, } from "../constants/enums.js";
4
4
  import { PROVIDER_DESCRIPTORS_BY_NAME } from "./providerDescriptors.js";
5
5
  import { OPENAI_COMPAT_CATALOG } from "../providers/openaiCompatCatalog.js";
6
- /**
7
- * Static module -> provider-ID manifest for every provider registered below.
8
- * Module names (file/dir under src/lib/providers/) intentionally differ from
9
- * their canonical IDs (e.g. amazonBedrock -> "bedrock", googleVertex ->
10
- * "vertex"); static scanners that cannot resolve the dynamic import() calls
11
- * use this mapping to confirm a module is registered. Enforced at runtime so
12
- * the registry cannot silently drift from this manifest.
13
- */
14
- export const PROVIDER_MODULE_TO_ID = {
15
- amazonBedrock: AIProviderName.BEDROCK,
16
- amazonSagemaker: AIProviderName.SAGEMAKER,
17
- anthropic: AIProviderName.ANTHROPIC,
18
- azureOpenai: AIProviderName.AZURE,
19
- cloudflare: AIProviderName.CLOUDFLARE,
20
- cohere: AIProviderName.COHERE,
21
- deepseek: AIProviderName.DEEPSEEK,
22
- fireworks: AIProviderName.FIREWORKS,
23
- googleAiStudio: AIProviderName.GOOGLE_AI,
24
- googleVertex: AIProviderName.VERTEX,
25
- groq: AIProviderName.GROQ,
26
- huggingFace: AIProviderName.HUGGINGFACE,
27
- ideogram: AIProviderName.IDEOGRAM,
28
- jina: AIProviderName.JINA,
29
- litellm: AIProviderName.LITELLM,
30
- llamaCpp: AIProviderName.LLAMACPP,
31
- lmStudio: AIProviderName.LM_STUDIO,
32
- mistral: AIProviderName.MISTRAL,
33
- nvidiaNim: AIProviderName.NVIDIA_NIM,
34
- ollama: AIProviderName.OLLAMA,
35
- openAI: AIProviderName.OPENAI,
36
- openaiCompatible: AIProviderName.OPENAI_COMPATIBLE,
37
- openRouter: AIProviderName.OPENROUTER,
38
- perplexity: AIProviderName.PERPLEXITY,
39
- recraft: AIProviderName.RECRAFT,
40
- replicate: AIProviderName.REPLICATE,
41
- stability: AIProviderName.STABILITY,
42
- togetherAi: AIProviderName.TOGETHER_AI,
43
- voyage: AIProviderName.VOYAGE,
44
- xai: AIProviderName.XAI,
45
- };
46
6
  /**
47
7
  * Provider Registry - registers all providers with the factory
48
8
  * This is where we migrate providers one by one to the new pattern
@@ -94,12 +54,10 @@ export class ProviderRegistry {
94
54
  * (avoids circular dependencies; see CLAUDE.md).
95
55
  *
96
56
  * Not registered (by design): index.ts, providerTypeUtils.ts,
97
- * openaiChatCompletionsBase.ts, openaiChatCompletionsClient.ts,
98
- * anthropicImageBlocks.ts (shared base/helper modules), anthropicBaseProvider.ts
99
- * (legacy; anthropic.ts is live), googleNativeGemini3.ts (shared helpers).
100
- * Filename != provider ID (e.g. amazonBedrock -> "bedrock"); the
101
- * statically-scannable PROVIDER_MODULE_TO_ID manifest maps every registered
102
- * module to its provider ID and is enforced below (Pattern Analysis #1178/#1317).
57
+ * anthropicBaseProvider.ts (legacy; anthropic.ts is live),
58
+ * googleNativeGemini3.ts (shared helpers). Filename != provider ID
59
+ * (e.g. amazonBedrock -> "bedrock"); static scanners that miss dynamic
60
+ * imports may false-positive (Pattern Analysis #1178).
103
61
  */
104
62
  // eslint-disable-next-line max-lines-per-function
105
63
  static async _doRegister() {
@@ -270,16 +228,6 @@ export class ProviderRegistry {
270
228
  const { RecraftProvider } = await import("../providers/recraft.js");
271
229
  return new RecraftProvider(modelName, sdk, undefined, recraftCreds);
272
230
  }, process.env.RECRAFT_MODEL || RecraftModels.RECRAFT_V3, ["recraft"], PROVIDER_DESCRIPTORS_BY_NAME.get(AIProviderName.RECRAFT));
273
- const unregistered = Object.entries(PROVIDER_MODULE_TO_ID).filter(([module, id]) => {
274
- if (!ProviderFactory.hasProvider(id)) {
275
- logger.error(`[ProviderRegistry] drift: module "${module}" not registered as "${id}"`);
276
- return true;
277
- }
278
- return false;
279
- });
280
- if (unregistered.length > 0) {
281
- throw new Error(`ProviderRegistry drift: ${unregistered.length} module(s) in PROVIDER_MODULE_TO_ID are not registered`);
282
- }
283
231
  logger.debug("All AI providers registered successfully");
284
232
  // ===== TTS HANDLER REGISTRATION =====
285
233
  try {
@@ -43,7 +43,7 @@ export declare class AvatarError extends NeuroLinkError {
43
43
  * Static processor managing the avatar handler registry.
44
44
  */
45
45
  export declare class AvatarProcessor {
46
- private static readonly handlers;
46
+ private static readonly registry;
47
47
  /**
48
48
  * Register an avatar handler for a specific provider.
49
49
  */
@@ -63,6 +63,10 @@ export declare class AvatarProcessor {
63
63
  * already-registered primary handler when backfilling its aliases.
64
64
  */
65
65
  static getHandler(providerName: string): AvatarHandler | undefined;
66
+ /**
67
+ * Clear all registered handlers (for testing).
68
+ */
69
+ static clearHandlers(): void;
66
70
  private static buildSpanAttributes;
67
71
  /**
68
72
  * Generate an avatar video via the registered handler.
@@ -13,6 +13,7 @@ import { ErrorCategory, ErrorSeverity } from "../constants/enums.js";
13
13
  import { SpanSerializer, SpanStatus, SpanType, getMetricsAggregator, } from "../observability/index.js";
14
14
  import { NeuroLinkError } from "./errorHandling.js";
15
15
  import { logger } from "./logger.js";
16
+ import { HandlerRegistry } from "../core/handlerRegistry.js";
16
17
  /**
17
18
  * Avatar-specific error codes.
18
19
  */
@@ -47,38 +48,26 @@ export class AvatarError extends NeuroLinkError {
47
48
  * Static processor managing the avatar handler registry.
48
49
  */
49
50
  export class AvatarProcessor {
50
- static handlers = new Map();
51
+ static registry = new HandlerRegistry("AvatarProcessor");
51
52
  /**
52
53
  * Register an avatar handler for a specific provider.
53
54
  */
54
55
  static registerHandler(providerName, handler) {
55
- if (!providerName) {
56
- throw new Error("Provider name is required");
57
- }
58
- if (!handler) {
59
- throw new Error("Handler is required");
60
- }
61
- const key = providerName.toLowerCase();
62
- if (this.handlers.has(key)) {
63
- logger.warn(`[AvatarProcessor] Overwriting existing handler for provider: ${key}`);
64
- }
65
- this.handlers.set(key, handler);
56
+ const key = providerName ? providerName.toLowerCase() : providerName;
57
+ this.registry.register(providerName, handler);
66
58
  logger.debug(`[AvatarProcessor] Registered avatar handler: ${key}`);
67
59
  }
68
60
  /**
69
61
  * Check if a provider has a registered avatar handler.
70
62
  */
71
63
  static supports(providerName) {
72
- if (!providerName) {
73
- return false;
74
- }
75
- return this.handlers.has(providerName.toLowerCase());
64
+ return this.registry.supports(providerName);
76
65
  }
77
66
  /**
78
67
  * List the names of all registered providers.
79
68
  */
80
69
  static listProviders() {
81
- return Array.from(this.handlers.keys());
70
+ return this.registry.list();
82
71
  }
83
72
  /**
84
73
  * Get a registered avatar handler by provider name.
@@ -87,7 +76,13 @@ export class AvatarProcessor {
87
76
  * already-registered primary handler when backfilling its aliases.
88
77
  */
89
78
  static getHandler(providerName) {
90
- return this.handlers.get(providerName.toLowerCase());
79
+ return this.registry.get(providerName);
80
+ }
81
+ /**
82
+ * Clear all registered handlers (for testing).
83
+ */
84
+ static clearHandlers() {
85
+ this.registry.clear();
91
86
  }
92
87
  static buildSpanAttributes(provider, options) {
93
88
  return {
@@ -42,7 +42,7 @@ export declare class MusicError extends NeuroLinkError {
42
42
  * Static processor managing the music handler registry.
43
43
  */
44
44
  export declare class MusicProcessor {
45
- private static readonly handlers;
45
+ private static readonly registry;
46
46
  /**
47
47
  * Register a music handler for a specific provider.
48
48
  */
@@ -62,6 +62,10 @@ export declare class MusicProcessor {
62
62
  * already-registered primary handler when backfilling its aliases.
63
63
  */
64
64
  static getHandler(providerName: string): MusicHandler | undefined;
65
+ /**
66
+ * Clear all registered handlers (for testing).
67
+ */
68
+ static clearHandlers(): void;
65
69
  private static buildSpanAttributes;
66
70
  /**
67
71
  * Generate a music track via the registered handler.
@@ -13,6 +13,7 @@ import { ErrorCategory, ErrorSeverity } from "../constants/enums.js";
13
13
  import { SpanSerializer, SpanStatus, SpanType, getMetricsAggregator, } from "../observability/index.js";
14
14
  import { NeuroLinkError } from "./errorHandling.js";
15
15
  import { logger } from "./logger.js";
16
+ import { HandlerRegistry } from "../core/handlerRegistry.js";
16
17
  /**
17
18
  * Music-specific error codes.
18
19
  */
@@ -46,38 +47,26 @@ export class MusicError extends NeuroLinkError {
46
47
  * Static processor managing the music handler registry.
47
48
  */
48
49
  export class MusicProcessor {
49
- static handlers = new Map();
50
+ static registry = new HandlerRegistry("MusicProcessor");
50
51
  /**
51
52
  * Register a music handler for a specific provider.
52
53
  */
53
54
  static registerHandler(providerName, handler) {
54
- if (!providerName) {
55
- throw new Error("Provider name is required");
56
- }
57
- if (!handler) {
58
- throw new Error("Handler is required");
59
- }
60
- const key = providerName.toLowerCase();
61
- if (this.handlers.has(key)) {
62
- logger.warn(`[MusicProcessor] Overwriting existing handler for provider: ${key}`);
63
- }
64
- this.handlers.set(key, handler);
55
+ const key = providerName ? providerName.toLowerCase() : providerName;
56
+ this.registry.register(providerName, handler);
65
57
  logger.debug(`[MusicProcessor] Registered music handler: ${key}`);
66
58
  }
67
59
  /**
68
60
  * Check if a provider has a registered music handler.
69
61
  */
70
62
  static supports(providerName) {
71
- if (!providerName) {
72
- return false;
73
- }
74
- return this.handlers.has(providerName.toLowerCase());
63
+ return this.registry.supports(providerName);
75
64
  }
76
65
  /**
77
66
  * List the names of all registered providers.
78
67
  */
79
68
  static listProviders() {
80
- return Array.from(this.handlers.keys());
69
+ return this.registry.list();
81
70
  }
82
71
  /**
83
72
  * Get a registered music handler by provider name.
@@ -86,7 +75,13 @@ export class MusicProcessor {
86
75
  * already-registered primary handler when backfilling its aliases.
87
76
  */
88
77
  static getHandler(providerName) {
89
- return this.handlers.get(providerName.toLowerCase());
78
+ return this.registry.get(providerName);
79
+ }
80
+ /**
81
+ * Clear all registered handlers (for testing).
82
+ */
83
+ static clearHandlers() {
84
+ this.registry.clear();
90
85
  }
91
86
  static buildSpanAttributes(provider, options) {
92
87
  return {
@@ -27,11 +27,10 @@ import type { STTOptions, STTResult, STTHandler } from "../types/index.js";
27
27
  export declare class STTProcessor {
28
28
  /**
29
29
  * Handler registry mapping provider names to STT handlers
30
- * Uses Map for O(1) lookups and better type safety
31
30
  *
32
31
  * @private
33
32
  */
34
- private static readonly handlers;
33
+ private static readonly registry;
35
34
  /**
36
35
  * Default maximum audio duration for STT transcription (in seconds)
37
36
  *
@@ -72,6 +71,15 @@ export declare class STTProcessor {
72
71
  * @returns Handler instance or undefined if not registered
73
72
  */
74
73
  static getHandler(providerName: string): STTHandler | undefined;
74
+ /**
75
+ * List the names of all registered providers.
76
+ */
77
+ static listProviders(): string[];
78
+ /**
79
+ * Removes every registered STT handler. Primarily for test isolation —
80
+ * production code should not need to call this.
81
+ */
82
+ static clearHandlers(): void;
75
83
  /**
76
84
  * Check if a provider is supported (has a registered STT handler)
77
85
  *