nexus-ai-pro 1.0.0 → 1.1.0
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/API_STABILITY.md +24 -6
- package/CHANGELOG.md +21 -2
- package/README.md +66 -5
- package/ROADMAP.md +17 -1
- package/dist/core/config-builder.d.ts +3 -0
- package/dist/core/config-builder.js +5 -0
- package/dist/core/nexus.d.ts +10 -0
- package/dist/core/nexus.js +17 -0
- package/dist/images/assets.d.ts +115 -0
- package/dist/images/assets.js +343 -0
- package/dist/images/errors.d.ts +35 -0
- package/dist/images/errors.js +79 -0
- package/dist/images/index.d.ts +4 -0
- package/dist/images/index.js +2 -0
- package/dist/images/manager.d.ts +23 -0
- package/dist/images/manager.js +574 -0
- package/dist/images/mock.d.ts +17 -0
- package/dist/images/mock.js +237 -0
- package/dist/images/openai.d.ts +46 -0
- package/dist/images/openai.js +355 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +3 -0
- package/dist/testing/image-provider-conformance.d.ts +33 -0
- package/dist/testing/image-provider-conformance.js +324 -0
- package/dist/types/config.d.ts +2 -0
- package/dist/types/images.d.ts +245 -0
- package/dist/types/images.js +1 -0
- package/package.json +19 -1
package/API_STABILITY.md
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
# API Stability Policy
|
|
2
2
|
|
|
3
|
-
This policy describes compatibility guarantees for `nexus-ai-pro
|
|
3
|
+
This policy describes compatibility guarantees for `nexus-ai-pro`. The 1.x compatibility guarantees
|
|
4
|
+
apply beginning with version 1.0.0.
|
|
4
5
|
|
|
5
6
|
## Release stages
|
|
6
7
|
|
|
7
|
-
The package
|
|
8
|
+
The package follows semantic versioning. Within the 1.x line, incompatible changes to stable public
|
|
9
|
+
APIs require a major release. Minor releases may add backward-compatible features, and patch releases
|
|
10
|
+
are intended to remain backward compatible.
|
|
8
11
|
|
|
9
12
|
The following surfaces are public and covered by this policy:
|
|
10
13
|
|
|
@@ -33,11 +36,12 @@ explicit `realtime/session`, `realtime/tools`, `realtime/conversation`, `realtim
|
|
|
33
36
|
normalized event names, configuration fields, and conversation/export shapes follow the same patch
|
|
34
37
|
compatibility rules as the rest of the package.
|
|
35
38
|
|
|
36
|
-
The realtime surface
|
|
39
|
+
The realtime surface follows the 1.x compatibility rules for its normalized public API. Provider-specific
|
|
40
|
+
wire events returned by `openai-events`, values
|
|
37
41
|
under `raw`, SDP/ICE behavior, and upstream model or voice availability are controlled by the provider
|
|
38
42
|
and are not normalized compatibility guarantees. New normalized event variants or optional metrics may
|
|
39
|
-
be added in a minor release.
|
|
40
|
-
|
|
43
|
+
be added in a minor release. Incompatible normalized API changes require a major release unless an urgent
|
|
44
|
+
security fix makes preserving the old behavior unsafe.
|
|
41
45
|
|
|
42
46
|
Platform interfaces for WebRTC and WebSocket are structural so applications can inject browser, server,
|
|
43
47
|
mobile, or test adapters without a framework dependency. A documented structural member is public;
|
|
@@ -48,8 +52,22 @@ turn-oriented transcription/completion/speech workflow. `RealtimeSession` owns a
|
|
|
48
52
|
live events, interruption, and normalized realtime conversation state. Neither is a compatibility alias
|
|
49
53
|
for the other.
|
|
50
54
|
|
|
55
|
+
## Image API stage
|
|
56
|
+
|
|
57
|
+
The `nexus-ai-pro/images` family is experimental in production-readiness, but published normalized
|
|
58
|
+
types, manager methods, operation events, and explicit subpath exports still follow the 1.x semantic
|
|
59
|
+
versioning rules. The experimental label does not permit an incompatible minor or patch release.
|
|
60
|
+
|
|
61
|
+
Provider payloads under `raw`, provider-specific error metadata, temporary delivery URLs, upstream model
|
|
62
|
+
availability, and generative output are not normalized compatibility guarantees. The current local
|
|
63
|
+
operation handle is process-bound and does not promise durable recovery, distributed cancellation, or
|
|
64
|
+
exactly-once provider execution. Those capabilities will use additive adapters and contracts when added.
|
|
65
|
+
`MemoryAssetStore` is likewise process-local and does not promise cross-process durability or shared
|
|
66
|
+
tenant state.
|
|
67
|
+
|
|
51
68
|
## Deprecation process
|
|
52
69
|
|
|
53
|
-
Deprecated APIs are marked with `@deprecated` in declarations and described in the changelog.
|
|
70
|
+
Deprecated APIs are marked with `@deprecated` in declarations and described in the changelog. Removals
|
|
71
|
+
are reserved for major releases, except when an urgent security issue requires otherwise.
|
|
54
72
|
|
|
55
73
|
Report accidental compatibility regressions through the project issue tracker. Security issues should follow [SECURITY.md](./SECURITY.md).
|
package/CHANGELOG.md
CHANGED
|
@@ -1,11 +1,29 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
Notable changes to this project are recorded here. The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and releases use semantic versioning
|
|
3
|
+
Notable changes to this project are recorded here. The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and releases use semantic versioning.
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
7
|
### Added
|
|
8
8
|
|
|
9
|
+
- An experimental provider-neutral image operation family with portable asset locations,
|
|
10
|
+
`ImageManager`, generation/editing, strict capability negotiation, runtime provider registration,
|
|
11
|
+
visual-safety hooks, and cancellable local operation handles.
|
|
12
|
+
- Opt-in `images`, `images/assets`, `images/mock`, and `images/openai` subpaths with a deterministic
|
|
13
|
+
mock provider and an OpenAI Image API adapter for one-shot generation and reference-based editing.
|
|
14
|
+
- An image-provider conformance harness covering normalized assets, metadata, generation, editing, and
|
|
15
|
+
pre-aborted calls.
|
|
16
|
+
- A bounded tenant-isolated `MemoryAssetStore` with retention, defensive byte copies, computed SHA-256
|
|
17
|
+
checksums, capacity enforcement, and optional HTTP(S) signing.
|
|
18
|
+
|
|
19
|
+
### Changed
|
|
20
|
+
|
|
21
|
+
- Reconciled the changelog and API stability policy with the tagged 1.0.0 release.
|
|
22
|
+
|
|
23
|
+
## [1.0.0] - 2026-07-17
|
|
24
|
+
|
|
25
|
+
### Added
|
|
26
|
+
|
|
9
27
|
- An opt-in realtime package family with `realtime`, `realtime/session`, `realtime/tools`,
|
|
10
28
|
`realtime/conversation`, provider transport, server-helper, and deterministic mock subpaths. Realtime
|
|
11
29
|
code is not added to the root or batch voice import graph.
|
|
@@ -55,5 +73,6 @@ Notable changes to this project are recorded here. The format follows [Keep a Ch
|
|
|
55
73
|
- URL fetching rejects unsafe private-network targets and limits response reads.
|
|
56
74
|
- CLI and audit findings no longer disclose detected secret values.
|
|
57
75
|
|
|
58
|
-
[Unreleased]: https://github.com/mkhitar-abrahamyan/nexus-ai/compare/
|
|
76
|
+
[Unreleased]: https://github.com/mkhitar-abrahamyan/nexus-ai/compare/v1.0.0...HEAD
|
|
77
|
+
[1.0.0]: https://github.com/mkhitar-abrahamyan/nexus-ai/releases/tag/v1.0.0
|
|
59
78
|
[0.9.0]: https://github.com/mkhitar-abrahamyan/nexus-ai/releases/tag/v0.9.0
|
package/README.md
CHANGED
|
@@ -7,7 +7,7 @@ Use the whole pipeline for production AI features, or turn pieces off when you o
|
|
|
7
7
|
- NPM: https://www.npmjs.com/package/nexus-ai-pro
|
|
8
8
|
- GitHub: https://github.com/mkhitar-abrahamyan/nexus-ai
|
|
9
9
|
- Full technical notes and manual test cases: [NEXUS.md](./NEXUS.md)
|
|
10
|
-
-
|
|
10
|
+
- Image generation status and remaining infrastructure work: [ROADMAP.md](./ROADMAP.md)
|
|
11
11
|
|
|
12
12
|
## Install
|
|
13
13
|
|
|
@@ -307,6 +307,63 @@ const response = await ai.completeVerified(
|
|
|
307
307
|
);
|
|
308
308
|
```
|
|
309
309
|
|
|
310
|
+
## Image Generation and Editing (Experimental)
|
|
311
|
+
|
|
312
|
+
Image operations use a separate provider-neutral manager because generated assets have different
|
|
313
|
+
capabilities, delivery modes, safety checks, and lifecycles from text completions.
|
|
314
|
+
|
|
315
|
+
```ts
|
|
316
|
+
import { NexusAI } from 'nexus-ai-pro';
|
|
317
|
+
import { OpenAIImageProvider } from 'nexus-ai-pro/images/openai';
|
|
318
|
+
|
|
319
|
+
const openaiImages = new OpenAIImageProvider({
|
|
320
|
+
apiKey: process.env.OPENAI_API_KEY!,
|
|
321
|
+
});
|
|
322
|
+
|
|
323
|
+
const mediaAi = new NexusAI({
|
|
324
|
+
providers: {},
|
|
325
|
+
images: {
|
|
326
|
+
defaultProvider: 'openai',
|
|
327
|
+
providers: { openai: openaiImages },
|
|
328
|
+
},
|
|
329
|
+
});
|
|
330
|
+
|
|
331
|
+
const image = await mediaAi.images.generate({
|
|
332
|
+
model: 'auto',
|
|
333
|
+
prompt: 'A clean product photograph of a red mechanical keyboard',
|
|
334
|
+
dimensions: { width: 1536, height: 1024 },
|
|
335
|
+
quality: 'high',
|
|
336
|
+
delivery: { kind: 'bytes', format: 'png' },
|
|
337
|
+
});
|
|
338
|
+
|
|
339
|
+
console.log(image.assets[0]?.location);
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
`ImageProvider` is independent from completion providers. Explicit options are negotiated against the
|
|
343
|
+
selected provider's declared capabilities, so unsupported formats, delivery kinds, masks, seeds, or
|
|
344
|
+
dimensions fail before a provider call. The OpenAI adapter supports one-shot generation and
|
|
345
|
+
reference-based editing through byte assets. Masked OpenAI edits remain disabled until a transformer can
|
|
346
|
+
verify dimensions and convert the neutral mask contract to OpenAI's alpha-channel semantics.
|
|
347
|
+
|
|
348
|
+
Use `submit()` for a cancellable local operation handle with replayable lifecycle events:
|
|
349
|
+
|
|
350
|
+
```ts
|
|
351
|
+
const operation = mediaAi.images.submit('generate', {
|
|
352
|
+
prompt: 'A minimal blue geometric poster',
|
|
353
|
+
delivery: { kind: 'bytes', format: 'png' },
|
|
354
|
+
});
|
|
355
|
+
|
|
356
|
+
for await (const event of operation.events()) {
|
|
357
|
+
console.log(event.type);
|
|
358
|
+
}
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
For deterministic tests, register `MockImageProvider` from `nexus-ai-pro/images/mock`. The current
|
|
362
|
+
`submit()` handle is in-process; durable leases, recovery, distributed deduplication, and webhooks remain
|
|
363
|
+
future infrastructure work. `nexus-ai-pro/images/assets` includes a bounded, tenant-isolated
|
|
364
|
+
`MemoryAssetStore` for local development and single-process workloads; it computes SHA-256 checksums,
|
|
365
|
+
copies bytes at its boundaries, enforces retention and capacity, and never silently evicts live assets.
|
|
366
|
+
|
|
310
367
|
## Voice Integrations
|
|
311
368
|
|
|
312
369
|
Voice support is optional and split into small imports.
|
|
@@ -892,6 +949,10 @@ import { ContextWindowManager } from 'nexus-ai-pro/context';
|
|
|
892
949
|
import { guardrailPolicy } from 'nexus-ai-pro/security';
|
|
893
950
|
import { RedisCacheAdapter } from 'nexus-ai-pro/cache';
|
|
894
951
|
import { DeepSeekProvider } from 'nexus-ai-pro/providers/deepseek';
|
|
952
|
+
import { ImageManager } from 'nexus-ai-pro/images';
|
|
953
|
+
import { MemoryAssetStore } from 'nexus-ai-pro/images/assets';
|
|
954
|
+
import { MockImageProvider } from 'nexus-ai-pro/images/mock';
|
|
955
|
+
import { OpenAIImageProvider } from 'nexus-ai-pro/images/openai';
|
|
895
956
|
import { createRealtimeSession } from 'nexus-ai-pro/realtime/session';
|
|
896
957
|
import { OpenAIWebRTCTransport } from 'nexus-ai-pro/realtime/openai-webrtc';
|
|
897
958
|
```
|
|
@@ -946,10 +1007,10 @@ npm run test:conformance:real
|
|
|
946
1007
|
|
|
947
1008
|
## Roadmap
|
|
948
1009
|
|
|
949
|
-
The
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
1010
|
+
The experimental image foundation now includes portable asset types, `ImageManager`, provider
|
|
1011
|
+
capability negotiation, local operation handles, visual-safety hooks, deterministic conformance, and an
|
|
1012
|
+
opt-in OpenAI adapter. Durable operations, production asset storage, additional providers, and
|
|
1013
|
+
media-specific evaluations remain planned in [ROADMAP.md](./ROADMAP.md).
|
|
953
1014
|
|
|
954
1015
|
## Production Notes
|
|
955
1016
|
|
package/ROADMAP.md
CHANGED
|
@@ -36,7 +36,23 @@ Current limitations are intentional and should remain visible:
|
|
|
36
36
|
- Realtime video tracks, SIP transports, durable cost accounting beyond the configurable local estimate,
|
|
37
37
|
and a published latency benchmark methodology remain follow-on work.
|
|
38
38
|
|
|
39
|
-
##
|
|
39
|
+
## Current next-release work: first-class image generation
|
|
40
|
+
|
|
41
|
+
The experimental foundation is now implemented in the current development line:
|
|
42
|
+
|
|
43
|
+
- portable byte, URL, and stored asset locations plus image request/result, usage, safety, provenance,
|
|
44
|
+
provider-call context, and operation-handle types;
|
|
45
|
+
- a provider-neutral `ImageManager` with generation, editing, provider registration, strict capability
|
|
46
|
+
negotiation, visual-safety hooks, and cancellable in-process submissions;
|
|
47
|
+
- a deterministic network-free mock and a parallel image-provider conformance harness;
|
|
48
|
+
- an opt-in OpenAI Image API adapter for one-shot generation and reference-based editing;
|
|
49
|
+
- a bounded tenant-aware in-memory asset store with retention, defensive byte copies, computed SHA-256
|
|
50
|
+
checksums, capacity rejection, and optional signed-URL integration.
|
|
51
|
+
|
|
52
|
+
This surface remains experimental. OpenAI masks are intentionally disabled until a transformer can
|
|
53
|
+
verify dimensions and convert neutral mask polarity into provider alpha semantics. Durable operations,
|
|
54
|
+
filesystem/S3-compatible asset stores, a second cloud provider, ComfyUI, and media evaluation are still
|
|
55
|
+
required before promotion.
|
|
40
56
|
|
|
41
57
|
Image generation should be a separate operation family rather than another variation of
|
|
42
58
|
`complete()`. Text completions and generated assets have different request shapes, response
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { NexusAI } from './nexus.js';
|
|
2
2
|
import type { AnthropicProviderConfig, AuditLogConfig, AzureOpenAIProviderConfig, CacheConfig, CohereProviderConfig, CostBudgetConfig, CustomProviderConfig, DeepSeekProviderConfig, GoogleProviderConfig, GroqProviderConfig, LMStudioProviderConfig, LlamaCppProviderConfig, LoggerConfig, MistralProviderConfig, NexusAIConfig, OllamaProviderConfig, OpenAIProviderConfig, OpenRouterProviderConfig, ProvidersConfig, RateLimitConfig, ResponseFormatConfig, RetryConfig, RoutingConfig, RoutingStrategy } from '../types/config.js';
|
|
3
3
|
import type { ContextWindowConfig } from '../types/context-window.js';
|
|
4
|
+
import type { ImageConfig } from '../types/images.js';
|
|
4
5
|
import type { SecurityConfig, SecurityLevel } from '../types/security.js';
|
|
5
6
|
import type { TokenOptimizerConfig } from '../types/optimizer.js';
|
|
6
7
|
import type { PipelineConfig } from '../pipeline/types.js';
|
|
@@ -53,6 +54,8 @@ export declare class NexusConfigBuilder {
|
|
|
53
54
|
security(config: SecurityLevel | SecurityConfig): this;
|
|
54
55
|
/** Sets context-window compaction behavior. */
|
|
55
56
|
contextWindow(config: ContextWindowConfig): this;
|
|
57
|
+
/** Sets image-provider defaults and registrations. */
|
|
58
|
+
images(config: ImageConfig): this;
|
|
56
59
|
/** Sets token optimization behavior. */
|
|
57
60
|
tokenOptimizer(config: TokenOptimizerConfig): this;
|
|
58
61
|
/** Sets exact, semantic, or hybrid cache behavior. */
|
|
@@ -98,6 +98,11 @@ export class NexusConfigBuilder {
|
|
|
98
98
|
this.config.contextWindow = config;
|
|
99
99
|
return this;
|
|
100
100
|
}
|
|
101
|
+
/** Sets image-provider defaults and registrations. */
|
|
102
|
+
images(config) {
|
|
103
|
+
this.config.images = config;
|
|
104
|
+
return this;
|
|
105
|
+
}
|
|
101
106
|
/** Sets token optimization behavior. */
|
|
102
107
|
tokenOptimizer(config) {
|
|
103
108
|
this.config.tokenOptimizer = config;
|
package/dist/core/nexus.d.ts
CHANGED
|
@@ -4,10 +4,12 @@ import type { NexusPlan } from '../types/planning.js';
|
|
|
4
4
|
import type { NexusResponse, NexusStream } from '../types/response.js';
|
|
5
5
|
import type { AgentConfig, AgentResult } from '../types/agent.js';
|
|
6
6
|
import type { SpeechRequest, SpeechResponse, TranscriptionRequest, TranscriptionResponse, VoiceProvider, VoiceSessionConfig, VoiceTurnRequest, VoiceTurnResponse } from '../types/voice.js';
|
|
7
|
+
import type { ImageProvider } from '../types/images.js';
|
|
7
8
|
import type { CreateCallRequest, CreateCallResponse, TelephonyMediaStreamEvent, TelephonyOutboundAudioMessage, TelephonyProvider, TelephonyResponseRequest, TelephonyWebhookResponse, TelephonyWebhookValidationRequest } from '../types/telephony.js';
|
|
8
9
|
import type { PipelineStep } from '../pipeline/types.js';
|
|
9
10
|
import type { BaseProvider } from '../providers/base.js';
|
|
10
11
|
import { type VoiceSession } from '../voice/index.js';
|
|
12
|
+
import { ImageManager } from '../images/manager.js';
|
|
11
13
|
import { type VerificationOptions } from '../hallucination/verification.js';
|
|
12
14
|
import { type SelfConsistencyOptions } from '../hallucination/consistency.js';
|
|
13
15
|
import { type BatchOptions, type BatchItemResult } from '../jobs/batch.js';
|
|
@@ -20,6 +22,8 @@ import { type SummarizeVerifyFormatOptions, type WorkflowResult } from '../workf
|
|
|
20
22
|
* Use `new NexusAI(config)` when you want full control, or `createNexus()` for the beginner shorthand.
|
|
21
23
|
*/
|
|
22
24
|
export declare class NexusAI {
|
|
25
|
+
/** Provider-neutral image generation and editing operations. */
|
|
26
|
+
readonly images: ImageManager;
|
|
23
27
|
private config;
|
|
24
28
|
private providers;
|
|
25
29
|
private router;
|
|
@@ -112,18 +116,24 @@ export declare class NexusAI {
|
|
|
112
116
|
* Registers a custom voice provider at runtime.
|
|
113
117
|
*/
|
|
114
118
|
registerVoiceProvider(name: string, provider: VoiceProvider): this;
|
|
119
|
+
/**
|
|
120
|
+
* Registers a custom image provider at runtime.
|
|
121
|
+
*/
|
|
122
|
+
registerImageProvider(name: string, provider: ImageProvider): this;
|
|
115
123
|
/**
|
|
116
124
|
* Registers a custom telephony provider at runtime.
|
|
117
125
|
*/
|
|
118
126
|
registerTelephonyProvider(name: string, provider: TelephonyProvider): this;
|
|
119
127
|
hasProvider(name: string): boolean;
|
|
120
128
|
hasVoiceProvider(name: string): boolean;
|
|
129
|
+
hasImageProvider(name: string): boolean;
|
|
121
130
|
hasTelephonyProvider(name: string): boolean;
|
|
122
131
|
/**
|
|
123
132
|
* Lists configured text providers.
|
|
124
133
|
*/
|
|
125
134
|
listProviders(): string[];
|
|
126
135
|
listVoiceProviders(): string[];
|
|
136
|
+
listImageProviders(): string[];
|
|
127
137
|
listTelephonyProviders(): string[];
|
|
128
138
|
/**
|
|
129
139
|
* Adds a custom pipeline step.
|
package/dist/core/nexus.js
CHANGED
|
@@ -15,6 +15,7 @@ import { Logger } from '../utils/logger.js';
|
|
|
15
15
|
import { SecurityPipeline } from '../security/index.js';
|
|
16
16
|
import { ContextWindowManager } from '../context/index.js';
|
|
17
17
|
import { VoiceManager } from '../voice/index.js';
|
|
18
|
+
import { ImageManager } from '../images/manager.js';
|
|
18
19
|
import { TelephonyManager } from '../telephony/index.js';
|
|
19
20
|
import { TokenOptimizer } from '../optimizer/index.js';
|
|
20
21
|
import { AgentLoop } from '../agent/loop.js';
|
|
@@ -41,6 +42,8 @@ import { summarizeVerifyFormat } from '../workflow/chains.js';
|
|
|
41
42
|
* Use `new NexusAI(config)` when you want full control, or `createNexus()` for the beginner shorthand.
|
|
42
43
|
*/
|
|
43
44
|
export class NexusAI {
|
|
45
|
+
/** Provider-neutral image generation and editing operations. */
|
|
46
|
+
images;
|
|
44
47
|
config;
|
|
45
48
|
providers = new Map();
|
|
46
49
|
router = new Router();
|
|
@@ -73,6 +76,7 @@ export class NexusAI {
|
|
|
73
76
|
this.security = new SecurityPipeline(this.config.security || 'standard');
|
|
74
77
|
this.contextWindow = new ContextWindowManager(this.config.contextWindow || {});
|
|
75
78
|
this.voiceManager = new VoiceManager(this.config.voice || {});
|
|
79
|
+
this.images = new ImageManager(this.config.images || {});
|
|
76
80
|
this.telephonyManager = new TelephonyManager(this.config.telephony || {});
|
|
77
81
|
this.optimizer = new TokenOptimizer(this.config.tokenOptimizer || {});
|
|
78
82
|
this.cache = new MemoryCache(this.config.cache?.maxEntries || 500);
|
|
@@ -453,6 +457,13 @@ export class NexusAI {
|
|
|
453
457
|
this.voiceManager.registerProvider(name, provider);
|
|
454
458
|
return this;
|
|
455
459
|
}
|
|
460
|
+
/**
|
|
461
|
+
* Registers a custom image provider at runtime.
|
|
462
|
+
*/
|
|
463
|
+
registerImageProvider(name, provider) {
|
|
464
|
+
this.images.registerImageProvider(name, provider);
|
|
465
|
+
return this;
|
|
466
|
+
}
|
|
456
467
|
/**
|
|
457
468
|
* Registers a custom telephony provider at runtime.
|
|
458
469
|
*/
|
|
@@ -466,6 +477,9 @@ export class NexusAI {
|
|
|
466
477
|
hasVoiceProvider(name) {
|
|
467
478
|
return this.voiceManager.hasProvider(name);
|
|
468
479
|
}
|
|
480
|
+
hasImageProvider(name) {
|
|
481
|
+
return this.images.hasImageProvider(name);
|
|
482
|
+
}
|
|
469
483
|
hasTelephonyProvider(name) {
|
|
470
484
|
return this.telephonyManager.hasProvider(name);
|
|
471
485
|
}
|
|
@@ -478,6 +492,9 @@ export class NexusAI {
|
|
|
478
492
|
listVoiceProviders() {
|
|
479
493
|
return this.voiceManager.listProviders();
|
|
480
494
|
}
|
|
495
|
+
listImageProviders() {
|
|
496
|
+
return this.images.listImageProviders();
|
|
497
|
+
}
|
|
481
498
|
listTelephonyProviders() {
|
|
482
499
|
return this.telephonyManager.listProviders();
|
|
483
500
|
}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import type { AssetBytesLocation, AssetDescriptor, AssetInput, AssetProvenance } from '../types/images.js';
|
|
2
|
+
/** An asset input whose payload is already available locally as bytes. */
|
|
3
|
+
export interface ByteAssetInput extends Omit<AssetInput, 'location'> {
|
|
4
|
+
location: AssetBytesLocation;
|
|
5
|
+
}
|
|
6
|
+
/** A retrieved asset descriptor whose byte payload is available to the caller. */
|
|
7
|
+
export interface ByteAssetDescriptor extends Omit<AssetDescriptor, 'location'> {
|
|
8
|
+
location: AssetBytesLocation;
|
|
9
|
+
}
|
|
10
|
+
export interface AssetPutOptions {
|
|
11
|
+
/** Tenant that owns the asset. This value is required for every later access. */
|
|
12
|
+
tenantId: string;
|
|
13
|
+
provenance: AssetProvenance;
|
|
14
|
+
width?: number;
|
|
15
|
+
height?: number;
|
|
16
|
+
/** Relative retention period. Mutually exclusive with `expiresAt`. */
|
|
17
|
+
ttlSeconds?: number;
|
|
18
|
+
/** Absolute retention deadline. Mutually exclusive with `ttlSeconds`. */
|
|
19
|
+
expiresAt?: Date | string;
|
|
20
|
+
}
|
|
21
|
+
export interface AssetStat {
|
|
22
|
+
assetId: string;
|
|
23
|
+
tenantId: string;
|
|
24
|
+
/** Metadata-only descriptor. Its location points back to this store, not to the byte payload. */
|
|
25
|
+
descriptor: AssetDescriptor;
|
|
26
|
+
createdAt: string;
|
|
27
|
+
expiresAt?: string;
|
|
28
|
+
}
|
|
29
|
+
export interface AssetSignOptions {
|
|
30
|
+
/** Requested signed-URL lifetime. Enforcement is delegated to the configured signer. */
|
|
31
|
+
expiresInSeconds?: number;
|
|
32
|
+
}
|
|
33
|
+
export interface AssetSignerContext extends AssetStat {
|
|
34
|
+
now: string;
|
|
35
|
+
expiresInSeconds?: number;
|
|
36
|
+
}
|
|
37
|
+
export type AssetSigner = (context: AssetSignerContext) => string | URL | Promise<string | URL>;
|
|
38
|
+
export type AssetStoreResult<T> = T | Promise<T>;
|
|
39
|
+
/**
|
|
40
|
+
* Provider-neutral asset persistence contract.
|
|
41
|
+
*
|
|
42
|
+
* A store must treat a missing asset and an asset owned by another tenant identically. Implementations
|
|
43
|
+
* may complete synchronously or asynchronously so the same contract can cover memory and remote stores.
|
|
44
|
+
*/
|
|
45
|
+
export interface AssetStore {
|
|
46
|
+
put(input: ByteAssetInput, options: AssetPutOptions): AssetStoreResult<AssetStat>;
|
|
47
|
+
get(assetId: string, tenantId: string): AssetStoreResult<ByteAssetDescriptor | undefined>;
|
|
48
|
+
stat(assetId: string, tenantId: string): AssetStoreResult<AssetStat | undefined>;
|
|
49
|
+
delete(assetId: string, tenantId: string): AssetStoreResult<true | undefined>;
|
|
50
|
+
sign(assetId: string, tenantId: string, options?: AssetSignOptions): AssetStoreResult<string | undefined>;
|
|
51
|
+
purgeExpired(): AssetStoreResult<number>;
|
|
52
|
+
}
|
|
53
|
+
export interface MemoryAssetStoreOptions {
|
|
54
|
+
maxEntries?: number;
|
|
55
|
+
maxTotalBytes?: number;
|
|
56
|
+
maxAssetBytes?: number;
|
|
57
|
+
defaultTtlSeconds?: number;
|
|
58
|
+
createAssetId?: () => string;
|
|
59
|
+
now?: () => Date;
|
|
60
|
+
signer?: AssetSigner;
|
|
61
|
+
}
|
|
62
|
+
export interface MemoryAssetStoreSnapshot {
|
|
63
|
+
entries: number;
|
|
64
|
+
totalBytes: number;
|
|
65
|
+
maxEntries: number;
|
|
66
|
+
maxTotalBytes: number;
|
|
67
|
+
maxAssetBytes: number;
|
|
68
|
+
}
|
|
69
|
+
export declare class AssetStoreError extends Error {
|
|
70
|
+
readonly code: string;
|
|
71
|
+
readonly cause?: unknown | undefined;
|
|
72
|
+
constructor(message: string, code: string, cause?: unknown | undefined);
|
|
73
|
+
}
|
|
74
|
+
export declare class AssetStoreValidationError extends AssetStoreError {
|
|
75
|
+
constructor(message: string, cause?: unknown);
|
|
76
|
+
}
|
|
77
|
+
export type AssetCapacityConstraint = 'maxEntries' | 'maxTotalBytes' | 'maxAssetBytes';
|
|
78
|
+
export declare class AssetStoreCapacityError extends AssetStoreError {
|
|
79
|
+
readonly constraint: AssetCapacityConstraint;
|
|
80
|
+
readonly maximum: number;
|
|
81
|
+
readonly current: number;
|
|
82
|
+
readonly requested: number;
|
|
83
|
+
constructor(constraint: AssetCapacityConstraint, maximum: number, current: number, requested: number);
|
|
84
|
+
}
|
|
85
|
+
export declare class AssetStoreSigningError extends AssetStoreError {
|
|
86
|
+
constructor(message: string, cause?: unknown);
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Process-local, bounded asset storage. Capacity exhaustion rejects the write; live entries are never
|
|
90
|
+
* silently evicted. Expired entries are purged before capacity and access decisions.
|
|
91
|
+
*/
|
|
92
|
+
export declare class MemoryAssetStore implements AssetStore {
|
|
93
|
+
private readonly entries;
|
|
94
|
+
private readonly maxEntries;
|
|
95
|
+
private readonly maxTotalBytes;
|
|
96
|
+
private readonly maxAssetBytes;
|
|
97
|
+
private readonly defaultTtlSeconds?;
|
|
98
|
+
private readonly createAssetId;
|
|
99
|
+
private readonly clock;
|
|
100
|
+
private readonly signer?;
|
|
101
|
+
private totalBytes;
|
|
102
|
+
constructor(options?: MemoryAssetStoreOptions);
|
|
103
|
+
put(input: ByteAssetInput, options: AssetPutOptions): AssetStat;
|
|
104
|
+
get(assetId: string, tenantId: string): ByteAssetDescriptor | undefined;
|
|
105
|
+
stat(assetId: string, tenantId: string): AssetStat | undefined;
|
|
106
|
+
delete(assetId: string, tenantId: string): true | undefined;
|
|
107
|
+
sign(assetId: string, tenantId: string, options?: AssetSignOptions): Promise<string | undefined>;
|
|
108
|
+
purgeExpired(): number;
|
|
109
|
+
snapshot(): MemoryAssetStoreSnapshot;
|
|
110
|
+
private assertCapacity;
|
|
111
|
+
private ownedEntry;
|
|
112
|
+
private purgeExpiredAt;
|
|
113
|
+
private removeEntry;
|
|
114
|
+
private nowMs;
|
|
115
|
+
}
|