@pellux/goodvibes-sdk 0.25.7 → 0.25.8
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/_internal/contracts/artifacts/operator-contract.json +100 -4
- package/dist/_internal/contracts/generated/foundation-metadata.d.ts +2 -2
- package/dist/_internal/contracts/generated/foundation-metadata.js +2 -2
- package/dist/_internal/contracts/generated/operator-contract.d.ts.map +1 -1
- package/dist/_internal/contracts/generated/operator-contract.js +100 -4
- package/dist/_internal/contracts/generated/operator-method-ids.d.ts +1 -1
- package/dist/_internal/contracts/generated/operator-method-ids.d.ts.map +1 -1
- package/dist/_internal/contracts/generated/operator-method-ids.js +1 -0
- package/dist/_internal/daemon/context.d.ts +1 -0
- package/dist/_internal/daemon/context.d.ts.map +1 -1
- package/dist/_internal/daemon/media-route-types.d.ts +10 -0
- package/dist/_internal/daemon/media-route-types.d.ts.map +1 -1
- package/dist/_internal/daemon/media-routes.d.ts +1 -1
- package/dist/_internal/daemon/media-routes.d.ts.map +1 -1
- package/dist/_internal/daemon/media-routes.js +91 -10
- package/dist/_internal/daemon/operator.d.ts +1 -1
- package/dist/_internal/daemon/operator.d.ts.map +1 -1
- package/dist/_internal/daemon/operator.js +2 -0
- package/dist/_internal/platform/adapters/ntfy/index.js +13 -2
- package/dist/_internal/platform/adapters/types.d.ts +2 -0
- package/dist/_internal/platform/adapters/types.d.ts.map +1 -1
- package/dist/_internal/platform/batch/index.d.ts +4 -0
- package/dist/_internal/platform/batch/index.d.ts.map +1 -0
- package/dist/_internal/platform/batch/index.js +2 -0
- package/dist/_internal/platform/batch/manager.d.ts +41 -0
- package/dist/_internal/platform/batch/manager.d.ts.map +1 -0
- package/dist/_internal/platform/batch/manager.js +400 -0
- package/dist/_internal/platform/batch/types.d.ts +85 -0
- package/dist/_internal/platform/batch/types.d.ts.map +1 -0
- package/dist/_internal/platform/batch/types.js +10 -0
- package/dist/_internal/platform/channels/builtin/plugins.d.ts.map +1 -1
- package/dist/_internal/platform/channels/builtin/plugins.js +1 -0
- package/dist/_internal/platform/channels/reply-pipeline.d.ts +9 -1
- package/dist/_internal/platform/channels/reply-pipeline.d.ts.map +1 -1
- package/dist/_internal/platform/channels/reply-pipeline.js +156 -6
- package/dist/_internal/platform/config/schema-domain-core.d.ts +6 -0
- package/dist/_internal/platform/config/schema-domain-core.d.ts.map +1 -1
- package/dist/_internal/platform/config/schema-domain-core.js +30 -0
- package/dist/_internal/platform/config/schema-domain-runtime.d.ts +19 -0
- package/dist/_internal/platform/config/schema-domain-runtime.d.ts.map +1 -1
- package/dist/_internal/platform/config/schema-domain-runtime.js +118 -0
- package/dist/_internal/platform/config/schema-types.d.ts +33 -2
- package/dist/_internal/platform/config/schema-types.d.ts.map +1 -1
- package/dist/_internal/platform/config/schema.d.ts.map +1 -1
- package/dist/_internal/platform/config/schema.js +3 -0
- package/dist/_internal/platform/control-plane/method-catalog-media.d.ts.map +1 -1
- package/dist/_internal/platform/control-plane/method-catalog-media.js +17 -0
- package/dist/_internal/platform/control-plane/routes/operator.d.ts +1 -1
- package/dist/_internal/platform/control-plane/routes/operator.d.ts.map +1 -1
- package/dist/_internal/platform/control-plane/routes/operator.js +2 -0
- package/dist/_internal/platform/daemon/facade-composition.d.ts +2 -0
- package/dist/_internal/platform/daemon/facade-composition.d.ts.map +1 -1
- package/dist/_internal/platform/daemon/facade-composition.js +10 -0
- package/dist/_internal/platform/daemon/http/batch-routes.d.ts +8 -0
- package/dist/_internal/platform/daemon/http/batch-routes.d.ts.map +1 -0
- package/dist/_internal/platform/daemon/http/batch-routes.js +113 -0
- package/dist/_internal/platform/daemon/http/router-route-contexts.d.ts.map +1 -1
- package/dist/_internal/platform/daemon/http/router-route-contexts.js +1 -0
- package/dist/_internal/platform/daemon/http/router.d.ts +4 -0
- package/dist/_internal/platform/daemon/http/router.d.ts.map +1 -1
- package/dist/_internal/platform/daemon/http/router.js +15 -0
- package/dist/_internal/platform/daemon/http/runtime-route-types.d.ts +2 -0
- package/dist/_internal/platform/daemon/http/runtime-route-types.d.ts.map +1 -1
- package/dist/_internal/platform/daemon/surface-actions.d.ts +6 -0
- package/dist/_internal/platform/daemon/surface-actions.d.ts.map +1 -1
- package/dist/_internal/platform/daemon/surface-actions.js +13 -0
- package/dist/_internal/platform/daemon/surface-delivery.d.ts +3 -0
- package/dist/_internal/platform/daemon/surface-delivery.d.ts.map +1 -1
- package/dist/_internal/platform/daemon/surface-delivery.js +42 -6
- package/dist/_internal/platform/daemon/types.d.ts +2 -0
- package/dist/_internal/platform/daemon/types.d.ts.map +1 -1
- package/dist/_internal/platform/providers/anthropic.d.ts +13 -1
- package/dist/_internal/platform/providers/anthropic.d.ts.map +1 -1
- package/dist/_internal/platform/providers/anthropic.js +219 -1
- package/dist/_internal/platform/providers/interface.d.ts +48 -0
- package/dist/_internal/platform/providers/interface.d.ts.map +1 -1
- package/dist/_internal/platform/providers/openai.d.ts +13 -1
- package/dist/_internal/platform/providers/openai.d.ts.map +1 -1
- package/dist/_internal/platform/providers/openai.js +189 -1
- package/dist/_internal/platform/version.js +1 -1
- package/dist/_internal/platform/voice/index.d.ts +1 -1
- package/dist/_internal/platform/voice/index.d.ts.map +1 -1
- package/dist/_internal/platform/voice/providers/elevenlabs.d.ts.map +1 -1
- package/dist/_internal/platform/voice/providers/elevenlabs.js +150 -4
- package/dist/_internal/platform/voice/service.d.ts +2 -1
- package/dist/_internal/platform/voice/service.d.ts.map +1 -1
- package/dist/_internal/platform/voice/service.js +7 -0
- package/dist/_internal/platform/voice/types.d.ts +18 -1
- package/dist/_internal/platform/voice/types.d.ts.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/workers.d.ts +40 -0
- package/dist/workers.d.ts.map +1 -0
- package/dist/workers.js +144 -0
- package/package.json +5 -1
|
@@ -2,6 +2,9 @@ import { asRecord, buildStatus, estimateConfidenceFromAvgLogprob, inferFilename,
|
|
|
2
2
|
import { instrumentedFetch } from '../../utils/fetch-with-timeout.js';
|
|
3
3
|
const DEFAULT_ELEVENLABS_STT_MODEL = 'scribe_v2';
|
|
4
4
|
const DEFAULT_ELEVENLABS_REALTIME_MODEL = 'scribe_v2_realtime';
|
|
5
|
+
const DEFAULT_ELEVENLABS_TTS_MODEL = 'eleven_multilingual_v2';
|
|
6
|
+
const DEFAULT_ELEVENLABS_VOICE = 'pMsXgVXv3BLzUgSXRplE';
|
|
7
|
+
const DEFAULT_ELEVENLABS_OUTPUT_FORMAT = 'mp3_44100_128';
|
|
5
8
|
const ELEVENLABS_SINGLE_USE_TOKEN_TTL_MS = 15 * 60 * 1000;
|
|
6
9
|
function normalizeBooleanString(value) {
|
|
7
10
|
return typeof value === 'boolean' ? String(value) : undefined;
|
|
@@ -14,6 +17,86 @@ function asStringArray(value) {
|
|
|
14
17
|
.map((entry) => entry.trim());
|
|
15
18
|
return values.length > 0 ? values : undefined;
|
|
16
19
|
}
|
|
20
|
+
function resolveElevenLabsOutputFormat(format) {
|
|
21
|
+
const normalized = format?.trim().toLowerCase();
|
|
22
|
+
if (!normalized)
|
|
23
|
+
return DEFAULT_ELEVENLABS_OUTPUT_FORMAT;
|
|
24
|
+
if (normalized.includes('_'))
|
|
25
|
+
return normalized;
|
|
26
|
+
switch (normalized) {
|
|
27
|
+
case 'mp3':
|
|
28
|
+
return DEFAULT_ELEVENLABS_OUTPUT_FORMAT;
|
|
29
|
+
case 'pcm':
|
|
30
|
+
case 'pcm16':
|
|
31
|
+
return 'pcm_16000';
|
|
32
|
+
case 'ulaw':
|
|
33
|
+
case 'mulaw':
|
|
34
|
+
return 'ulaw_8000';
|
|
35
|
+
case 'opus':
|
|
36
|
+
case 'ogg':
|
|
37
|
+
case 'webm':
|
|
38
|
+
return 'opus_48000_32';
|
|
39
|
+
default:
|
|
40
|
+
return DEFAULT_ELEVENLABS_OUTPUT_FORMAT;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
function mimeTypeForElevenLabsOutputFormat(outputFormat) {
|
|
44
|
+
if (outputFormat.startsWith('pcm_'))
|
|
45
|
+
return 'audio/pcm';
|
|
46
|
+
if (outputFormat.startsWith('ulaw_'))
|
|
47
|
+
return 'audio/basic';
|
|
48
|
+
if (outputFormat.startsWith('opus_'))
|
|
49
|
+
return 'audio/ogg';
|
|
50
|
+
return 'audio/mpeg';
|
|
51
|
+
}
|
|
52
|
+
function artifactFormatForElevenLabsOutputFormat(outputFormat) {
|
|
53
|
+
if (outputFormat.startsWith('pcm_'))
|
|
54
|
+
return 'pcm16';
|
|
55
|
+
if (outputFormat.startsWith('ulaw_'))
|
|
56
|
+
return 'ulaw';
|
|
57
|
+
if (outputFormat.startsWith('opus_'))
|
|
58
|
+
return 'ogg';
|
|
59
|
+
return 'mp3';
|
|
60
|
+
}
|
|
61
|
+
function readVoiceSetting(metadata, camelKey, snakeKey, fallback) {
|
|
62
|
+
const value = metadata?.[camelKey] ?? metadata?.[snakeKey];
|
|
63
|
+
return typeof value === 'number' && Number.isFinite(value) ? value : fallback;
|
|
64
|
+
}
|
|
65
|
+
function readSpeakerBoost(metadata) {
|
|
66
|
+
const value = metadata?.['useSpeakerBoost'] ?? metadata?.['use_speaker_boost'];
|
|
67
|
+
return typeof value === 'boolean' ? value : true;
|
|
68
|
+
}
|
|
69
|
+
async function* streamResponseAudioChunks(response, input) {
|
|
70
|
+
const reader = response.body?.getReader();
|
|
71
|
+
if (!reader)
|
|
72
|
+
throw new Error('ElevenLabs streaming synthesis returned no response body');
|
|
73
|
+
let sequence = 0;
|
|
74
|
+
let completed = false;
|
|
75
|
+
try {
|
|
76
|
+
while (true) {
|
|
77
|
+
const { done, value } = await reader.read();
|
|
78
|
+
if (done) {
|
|
79
|
+
completed = true;
|
|
80
|
+
break;
|
|
81
|
+
}
|
|
82
|
+
if (!value || value.byteLength === 0)
|
|
83
|
+
continue;
|
|
84
|
+
sequence += 1;
|
|
85
|
+
yield {
|
|
86
|
+
data: value,
|
|
87
|
+
sequence,
|
|
88
|
+
mimeType: input.mimeType,
|
|
89
|
+
format: input.format,
|
|
90
|
+
metadata: input.metadata,
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
finally {
|
|
95
|
+
if (!completed)
|
|
96
|
+
await reader.cancel().catch(() => undefined);
|
|
97
|
+
reader.releaseLock();
|
|
98
|
+
}
|
|
99
|
+
}
|
|
17
100
|
function parseElevenLabsTranscript(payload) {
|
|
18
101
|
const text = trimToUndefined(payload.text);
|
|
19
102
|
if (!text)
|
|
@@ -60,15 +143,17 @@ export function createElevenLabsProvider() {
|
|
|
60
143
|
return {
|
|
61
144
|
id: 'elevenlabs',
|
|
62
145
|
label: 'ElevenLabs',
|
|
63
|
-
capabilities: ['tts', 'stt', 'realtime', 'voice-list'],
|
|
146
|
+
capabilities: ['tts', 'tts-stream', 'stt', 'realtime', 'voice-list'],
|
|
64
147
|
status() {
|
|
65
148
|
const configured = readFirstEnv(envVars) !== null;
|
|
66
|
-
return buildStatus('elevenlabs', 'ElevenLabs', ['tts', 'stt', 'realtime', 'voice-list'], configured, configured
|
|
149
|
+
return buildStatus('elevenlabs', 'ElevenLabs', ['tts', 'tts-stream', 'stt', 'realtime', 'voice-list'], configured, configured
|
|
67
150
|
? 'ElevenLabs speech, transcription, and realtime APIs are available.'
|
|
68
151
|
: 'Set ELEVENLABS_API_KEY or XI_API_KEY to enable ElevenLabs speech and transcription.', {
|
|
69
152
|
baseUrl: normalizeBaseUrl(readFirstEnv(baseUrlEnvVars), 'https://api.elevenlabs.io'),
|
|
153
|
+
defaultTtsModel: DEFAULT_ELEVENLABS_TTS_MODEL,
|
|
70
154
|
defaultSttModel: DEFAULT_ELEVENLABS_STT_MODEL,
|
|
71
155
|
defaultRealtimeModel: DEFAULT_ELEVENLABS_REALTIME_MODEL,
|
|
156
|
+
defaultOutputFormat: DEFAULT_ELEVENLABS_OUTPUT_FORMAT,
|
|
72
157
|
});
|
|
73
158
|
},
|
|
74
159
|
async listVoices() {
|
|
@@ -98,7 +183,7 @@ export function createElevenLabsProvider() {
|
|
|
98
183
|
if (!apiKey)
|
|
99
184
|
throw new Error('ElevenLabs API key missing');
|
|
100
185
|
const baseUrl = normalizeBaseUrl(readFirstEnv(baseUrlEnvVars), 'https://api.elevenlabs.io');
|
|
101
|
-
const voiceId = request.voiceId?.trim() ||
|
|
186
|
+
const voiceId = request.voiceId?.trim() || DEFAULT_ELEVENLABS_VOICE;
|
|
102
187
|
const response = await instrumentedFetch(`${baseUrl}/v1/text-to-speech/${voiceId}`, {
|
|
103
188
|
method: 'POST',
|
|
104
189
|
headers: {
|
|
@@ -108,7 +193,7 @@ export function createElevenLabsProvider() {
|
|
|
108
193
|
},
|
|
109
194
|
body: JSON.stringify({
|
|
110
195
|
text: request.text,
|
|
111
|
-
model_id: request.modelId?.trim() ||
|
|
196
|
+
model_id: request.modelId?.trim() || DEFAULT_ELEVENLABS_TTS_MODEL,
|
|
112
197
|
voice_settings: {
|
|
113
198
|
stability: 0.5,
|
|
114
199
|
similarity_boost: 0.75,
|
|
@@ -133,6 +218,67 @@ export function createElevenLabsProvider() {
|
|
|
133
218
|
metadata: { voiceId, baseUrl },
|
|
134
219
|
};
|
|
135
220
|
},
|
|
221
|
+
async synthesizeStream(request) {
|
|
222
|
+
const apiKey = readFirstEnv(envVars);
|
|
223
|
+
if (!apiKey)
|
|
224
|
+
throw new Error('ElevenLabs API key missing');
|
|
225
|
+
const baseUrl = normalizeBaseUrl(readFirstEnv(baseUrlEnvVars), 'https://api.elevenlabs.io');
|
|
226
|
+
const metadata = asRecord(request.metadata);
|
|
227
|
+
const voiceId = request.voiceId?.trim() || DEFAULT_ELEVENLABS_VOICE;
|
|
228
|
+
const modelId = request.modelId?.trim() || DEFAULT_ELEVENLABS_TTS_MODEL;
|
|
229
|
+
const outputFormat = resolveElevenLabsOutputFormat(request.format);
|
|
230
|
+
const mimeType = mimeTypeForElevenLabsOutputFormat(outputFormat);
|
|
231
|
+
const format = artifactFormatForElevenLabsOutputFormat(outputFormat);
|
|
232
|
+
const url = new URL(`${baseUrl}/v1/text-to-speech/${voiceId}/stream`);
|
|
233
|
+
url.searchParams.set('output_format', outputFormat);
|
|
234
|
+
if (metadata?.['enableLogging'] === false) {
|
|
235
|
+
url.searchParams.set('enable_logging', 'false');
|
|
236
|
+
}
|
|
237
|
+
const languageCode = trimToUndefined(metadata?.['languageCode']);
|
|
238
|
+
const body = {
|
|
239
|
+
text: request.text,
|
|
240
|
+
model_id: modelId,
|
|
241
|
+
voice_settings: {
|
|
242
|
+
stability: readVoiceSetting(metadata, 'stability', 'stability', 0.5),
|
|
243
|
+
similarity_boost: readVoiceSetting(metadata, 'similarityBoost', 'similarity_boost', 0.75),
|
|
244
|
+
style: readVoiceSetting(metadata, 'style', 'style', 0),
|
|
245
|
+
use_speaker_boost: readSpeakerBoost(metadata),
|
|
246
|
+
speed: request.speed ?? readVoiceSetting(metadata, 'speed', 'speed', 1),
|
|
247
|
+
},
|
|
248
|
+
...(languageCode ? { language_code: languageCode } : {}),
|
|
249
|
+
};
|
|
250
|
+
const response = await instrumentedFetch(url, {
|
|
251
|
+
method: 'POST',
|
|
252
|
+
headers: {
|
|
253
|
+
'xi-api-key': apiKey,
|
|
254
|
+
'Content-Type': 'application/json',
|
|
255
|
+
Accept: mimeType,
|
|
256
|
+
},
|
|
257
|
+
signal: request.signal,
|
|
258
|
+
body: JSON.stringify(body),
|
|
259
|
+
});
|
|
260
|
+
if (!response.ok) {
|
|
261
|
+
const errorText = await response.text().catch(() => '');
|
|
262
|
+
throw new Error(`ElevenLabs streaming synthesis failed: HTTP ${response.status}${errorText ? `: ${errorText}` : ''}`);
|
|
263
|
+
}
|
|
264
|
+
const resultMetadata = {
|
|
265
|
+
baseUrl,
|
|
266
|
+
voiceId,
|
|
267
|
+
modelId,
|
|
268
|
+
outputFormat,
|
|
269
|
+
};
|
|
270
|
+
return {
|
|
271
|
+
providerId: 'elevenlabs',
|
|
272
|
+
mimeType,
|
|
273
|
+
format,
|
|
274
|
+
chunks: streamResponseAudioChunks(response, {
|
|
275
|
+
mimeType,
|
|
276
|
+
format,
|
|
277
|
+
metadata: resultMetadata,
|
|
278
|
+
}),
|
|
279
|
+
metadata: resultMetadata,
|
|
280
|
+
};
|
|
281
|
+
},
|
|
136
282
|
async transcribe(request) {
|
|
137
283
|
const apiKey = readFirstEnv(envVars);
|
|
138
284
|
if (!apiKey)
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { VoiceProviderRegistry } from './provider-registry.js';
|
|
2
|
-
import type { VoiceDescriptor, VoiceRealtimeSession, VoiceRealtimeSessionRequest, VoiceSynthesisRequest, VoiceSynthesisResult, VoiceTranscriptionRequest, VoiceTranscriptionResult } from './types.js';
|
|
2
|
+
import type { VoiceDescriptor, VoiceRealtimeSession, VoiceRealtimeSessionRequest, VoiceSynthesisRequest, VoiceSynthesisResult, VoiceSynthesisStreamResult, VoiceTranscriptionRequest, VoiceTranscriptionResult } from './types.js';
|
|
3
3
|
export interface VoiceServiceStatus {
|
|
4
4
|
readonly enabled: boolean;
|
|
5
5
|
readonly providerCount: number;
|
|
@@ -12,6 +12,7 @@ export declare class VoiceService {
|
|
|
12
12
|
getStatus(enabled: boolean): Promise<VoiceServiceStatus>;
|
|
13
13
|
listVoices(providerId?: string): Promise<readonly VoiceDescriptor[]>;
|
|
14
14
|
synthesize(providerId: string | undefined, request: VoiceSynthesisRequest): Promise<VoiceSynthesisResult>;
|
|
15
|
+
synthesizeStream(providerId: string | undefined, request: VoiceSynthesisRequest): Promise<VoiceSynthesisStreamResult>;
|
|
15
16
|
transcribe(providerId: string | undefined, request: VoiceTranscriptionRequest): Promise<VoiceTranscriptionResult>;
|
|
16
17
|
openRealtimeSession(providerId: string | undefined, request: VoiceRealtimeSessionRequest): Promise<VoiceRealtimeSession>;
|
|
17
18
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../../../src/_internal/platform/voice/service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AAC/D,OAAO,KAAK,EACV,eAAe,EACf,oBAAoB,EACpB,2BAA2B,EAC3B,qBAAqB,EACrB,oBAAoB,EACpB,yBAAyB,EACzB,wBAAwB,EACzB,MAAM,YAAY,CAAC;AAEpB,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC,UAAU,CAAC,qBAAqB,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;IACzE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED,qBAAa,YAAY;IACX,OAAO,CAAC,QAAQ,CAAC,QAAQ;gBAAR,QAAQ,EAAE,qBAAqB;IAEtD,SAAS,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAUxD,UAAU,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,eAAe,EAAE,CAAC;IAYpE,UAAU,CAAC,UAAU,EAAE,MAAM,GAAG,SAAS,EAAE,OAAO,EAAE,qBAAqB,GAAG,OAAO,CAAC,oBAAoB,CAAC;IAQzG,UAAU,CAAC,UAAU,EAAE,MAAM,GAAG,SAAS,EAAE,OAAO,EAAE,yBAAyB,GAAG,OAAO,CAAC,wBAAwB,CAAC;IAQjH,mBAAmB,CAAC,UAAU,EAAE,MAAM,GAAG,SAAS,EAAE,OAAO,EAAE,2BAA2B,GAAG,OAAO,CAAC,oBAAoB,CAAC;CAO/H"}
|
|
1
|
+
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../../../src/_internal/platform/voice/service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AAC/D,OAAO,KAAK,EACV,eAAe,EACf,oBAAoB,EACpB,2BAA2B,EAC3B,qBAAqB,EACrB,oBAAoB,EACpB,0BAA0B,EAC1B,yBAAyB,EACzB,wBAAwB,EACzB,MAAM,YAAY,CAAC;AAEpB,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC,UAAU,CAAC,qBAAqB,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;IACzE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED,qBAAa,YAAY;IACX,OAAO,CAAC,QAAQ,CAAC,QAAQ;gBAAR,QAAQ,EAAE,qBAAqB;IAEtD,SAAS,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAUxD,UAAU,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,eAAe,EAAE,CAAC;IAYpE,UAAU,CAAC,UAAU,EAAE,MAAM,GAAG,SAAS,EAAE,OAAO,EAAE,qBAAqB,GAAG,OAAO,CAAC,oBAAoB,CAAC;IAQzG,gBAAgB,CAAC,UAAU,EAAE,MAAM,GAAG,SAAS,EAAE,OAAO,EAAE,qBAAqB,GAAG,OAAO,CAAC,0BAA0B,CAAC;IAQrH,UAAU,CAAC,UAAU,EAAE,MAAM,GAAG,SAAS,EAAE,OAAO,EAAE,yBAAyB,GAAG,OAAO,CAAC,wBAAwB,CAAC;IAQjH,mBAAmB,CAAC,UAAU,EAAE,MAAM,GAAG,SAAS,EAAE,OAAO,EAAE,2BAA2B,GAAG,OAAO,CAAC,oBAAoB,CAAC;CAO/H"}
|
|
@@ -32,6 +32,13 @@ export class VoiceService {
|
|
|
32
32
|
}
|
|
33
33
|
return provider.synthesize(request);
|
|
34
34
|
}
|
|
35
|
+
async synthesizeStream(providerId, request) {
|
|
36
|
+
const provider = this.registry.findProvider('tts-stream', providerId);
|
|
37
|
+
if (!provider?.synthesizeStream) {
|
|
38
|
+
throw new Error(providerId ? `Voice streaming TTS provider unavailable: ${providerId}` : 'No streaming voice TTS provider is registered');
|
|
39
|
+
}
|
|
40
|
+
return provider.synthesizeStream(request);
|
|
41
|
+
}
|
|
35
42
|
async transcribe(providerId, request) {
|
|
36
43
|
const provider = this.registry.findProvider('stt', providerId);
|
|
37
44
|
if (!provider?.transcribe) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/** SDK-owned platform module. This implementation is maintained in goodvibes-sdk. */
|
|
2
|
-
export type VoiceProviderCapability = 'tts' | 'stt' | 'realtime' | 'voice-list';
|
|
2
|
+
export type VoiceProviderCapability = 'tts' | 'tts-stream' | 'stt' | 'realtime' | 'voice-list';
|
|
3
3
|
export type VoiceProviderState = 'healthy' | 'degraded' | 'disabled' | 'unconfigured';
|
|
4
4
|
export type VoiceAudioFormat = 'wav' | 'mp3' | 'ogg' | 'webm' | 'pcm16' | 'flac';
|
|
5
5
|
export interface VoiceProviderStatus {
|
|
@@ -33,6 +33,7 @@ export interface VoiceSynthesisRequest {
|
|
|
33
33
|
readonly modelId?: string;
|
|
34
34
|
readonly format?: VoiceAudioFormat | string;
|
|
35
35
|
readonly speed?: number;
|
|
36
|
+
readonly signal?: AbortSignal;
|
|
36
37
|
readonly metadata?: Record<string, unknown>;
|
|
37
38
|
}
|
|
38
39
|
export interface VoiceSynthesisResult {
|
|
@@ -40,6 +41,21 @@ export interface VoiceSynthesisResult {
|
|
|
40
41
|
readonly audio: VoiceAudioArtifact;
|
|
41
42
|
readonly metadata: Record<string, unknown>;
|
|
42
43
|
}
|
|
44
|
+
export interface VoiceAudioChunk {
|
|
45
|
+
readonly data: Uint8Array;
|
|
46
|
+
readonly sequence: number;
|
|
47
|
+
readonly mimeType?: string;
|
|
48
|
+
readonly format?: VoiceAudioFormat | string;
|
|
49
|
+
readonly final?: boolean;
|
|
50
|
+
readonly metadata?: Record<string, unknown>;
|
|
51
|
+
}
|
|
52
|
+
export interface VoiceSynthesisStreamResult {
|
|
53
|
+
readonly providerId: string;
|
|
54
|
+
readonly mimeType: string;
|
|
55
|
+
readonly format: VoiceAudioFormat | string;
|
|
56
|
+
readonly chunks: AsyncIterable<VoiceAudioChunk>;
|
|
57
|
+
readonly metadata: Record<string, unknown>;
|
|
58
|
+
}
|
|
43
59
|
export interface VoiceTranscriptionRequest {
|
|
44
60
|
readonly audio: VoiceAudioArtifact;
|
|
45
61
|
readonly language?: string;
|
|
@@ -83,6 +99,7 @@ export interface VoiceProvider {
|
|
|
83
99
|
status?(): Promise<VoiceProviderStatus> | VoiceProviderStatus;
|
|
84
100
|
listVoices?(): Promise<readonly VoiceDescriptor[]> | readonly VoiceDescriptor[];
|
|
85
101
|
synthesize?(request: VoiceSynthesisRequest): Promise<VoiceSynthesisResult>;
|
|
102
|
+
synthesizeStream?(request: VoiceSynthesisRequest): Promise<VoiceSynthesisStreamResult> | VoiceSynthesisStreamResult;
|
|
86
103
|
transcribe?(request: VoiceTranscriptionRequest): Promise<VoiceTranscriptionResult>;
|
|
87
104
|
openRealtimeSession?(request: VoiceRealtimeSessionRequest): Promise<VoiceRealtimeSession>;
|
|
88
105
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/_internal/platform/voice/types.ts"],"names":[],"mappings":"AAAA,qFAAqF;AAErF,MAAM,MAAM,uBAAuB,GAAG,KAAK,GAAG,KAAK,GAAG,UAAU,GAAG,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/_internal/platform/voice/types.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -6,6 +6,8 @@ export type { BrowserGoodVibesSdkOptions } from './browser.js';
|
|
|
6
6
|
export { createBrowserGoodVibesSdk } from './browser.js';
|
|
7
7
|
export type { WebGoodVibesSdkOptions } from './web.js';
|
|
8
8
|
export { createWebGoodVibesSdk } from './web.js';
|
|
9
|
+
export type { GoodVibesCloudflareExecutionContext, GoodVibesCloudflareMessageBatch, GoodVibesCloudflareQueue, GoodVibesCloudflareQueueMessage, GoodVibesCloudflareQueuePayload, GoodVibesCloudflareWorker, GoodVibesCloudflareWorkerEnv, GoodVibesCloudflareWorkerOptions, } from './workers.js';
|
|
10
|
+
export { createGoodVibesCloudflareWorker } from './workers.js';
|
|
9
11
|
export type { ReactNativeGoodVibesRealtime, ReactNativeGoodVibesSdk, ReactNativeGoodVibesSdkOptions, } from './react-native.js';
|
|
10
12
|
export { createReactNativeGoodVibesSdk } from './react-native.js';
|
|
11
13
|
export type { ExpoGoodVibesSdkOptions } from './expo.js';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,iBAAiB,EACjB,YAAY,EACZ,wBAAwB,EACxB,mBAAmB,EACnB,kBAAkB,GACnB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACjD,YAAY,EACV,wBAAwB,EACxB,mBAAmB,EACnB,yBAAyB,EACzB,oBAAoB,EACpB,mBAAmB,EACnB,oBAAoB,EACpB,mBAAmB,GACpB,MAAM,WAAW,CAAC;AACnB,OAAO,EACL,uBAAuB,EACvB,yBAAyB,EACzB,sBAAsB,GACvB,MAAM,WAAW,CAAC;AACnB,YAAY,EAAE,0BAA0B,EAAE,MAAM,cAAc,CAAC;AAC/D,OAAO,EAAE,yBAAyB,EAAE,MAAM,cAAc,CAAC;AACzD,YAAY,EAAE,sBAAsB,EAAE,MAAM,UAAU,CAAC;AACvD,OAAO,EAAE,qBAAqB,EAAE,MAAM,UAAU,CAAC;AACjD,YAAY,EACV,4BAA4B,EAC5B,uBAAuB,EACvB,8BAA8B,GAC/B,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,6BAA6B,EAAE,MAAM,mBAAmB,CAAC;AAClE,YAAY,EAAE,uBAAuB,EAAE,MAAM,WAAW,CAAC;AACzD,OAAO,EAAE,sBAAsB,EAAE,MAAM,WAAW,CAAC;AACnD,cAAc,qBAAqB,CAAC;AACpC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,cAAc,qBAAqB,CAAC;AACpC,cAAc,uBAAuB,CAAC;AACtC,cAAc,qBAAqB,CAAC;AACpC,cAAc,yBAAyB,CAAC;AACxC,cAAc,eAAe,CAAC;AAC9B,cAAc,WAAW,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,iBAAiB,EACjB,YAAY,EACZ,wBAAwB,EACxB,mBAAmB,EACnB,kBAAkB,GACnB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACjD,YAAY,EACV,wBAAwB,EACxB,mBAAmB,EACnB,yBAAyB,EACzB,oBAAoB,EACpB,mBAAmB,EACnB,oBAAoB,EACpB,mBAAmB,GACpB,MAAM,WAAW,CAAC;AACnB,OAAO,EACL,uBAAuB,EACvB,yBAAyB,EACzB,sBAAsB,GACvB,MAAM,WAAW,CAAC;AACnB,YAAY,EAAE,0BAA0B,EAAE,MAAM,cAAc,CAAC;AAC/D,OAAO,EAAE,yBAAyB,EAAE,MAAM,cAAc,CAAC;AACzD,YAAY,EAAE,sBAAsB,EAAE,MAAM,UAAU,CAAC;AACvD,OAAO,EAAE,qBAAqB,EAAE,MAAM,UAAU,CAAC;AACjD,YAAY,EACV,mCAAmC,EACnC,+BAA+B,EAC/B,wBAAwB,EACxB,+BAA+B,EAC/B,+BAA+B,EAC/B,yBAAyB,EACzB,4BAA4B,EAC5B,gCAAgC,GACjC,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,+BAA+B,EAAE,MAAM,cAAc,CAAC;AAC/D,YAAY,EACV,4BAA4B,EAC5B,uBAAuB,EACvB,8BAA8B,GAC/B,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,6BAA6B,EAAE,MAAM,mBAAmB,CAAC;AAClE,YAAY,EAAE,uBAAuB,EAAE,MAAM,WAAW,CAAC;AACzD,OAAO,EAAE,sBAAsB,EAAE,MAAM,WAAW,CAAC;AACnD,cAAc,qBAAqB,CAAC;AACpC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,cAAc,qBAAqB,CAAC;AACpC,cAAc,uBAAuB,CAAC;AACtC,cAAc,qBAAqB,CAAC;AACpC,cAAc,yBAAyB,CAAC;AACxC,cAAc,eAAe,CAAC;AAC9B,cAAc,WAAW,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -2,6 +2,7 @@ export { createGoodVibesSdk } from './client.js';
|
|
|
2
2
|
export { createBrowserTokenStore, createGoodVibesAuthClient, createMemoryTokenStore, } from './auth.js';
|
|
3
3
|
export { createBrowserGoodVibesSdk } from './browser.js';
|
|
4
4
|
export { createWebGoodVibesSdk } from './web.js';
|
|
5
|
+
export { createGoodVibesCloudflareWorker } from './workers.js';
|
|
5
6
|
export { createReactNativeGoodVibesSdk } from './react-native.js';
|
|
6
7
|
export { createExpoGoodVibesSdk } from './expo.js';
|
|
7
8
|
export * from './observer/index.js';
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
export interface GoodVibesCloudflareQueue<Body = unknown> {
|
|
2
|
+
send(message: Body): Promise<void>;
|
|
3
|
+
}
|
|
4
|
+
export interface GoodVibesCloudflareQueueMessage<Body = unknown> {
|
|
5
|
+
readonly body: Body;
|
|
6
|
+
ack?(): void;
|
|
7
|
+
retry?(): void;
|
|
8
|
+
}
|
|
9
|
+
export interface GoodVibesCloudflareMessageBatch<Body = unknown> {
|
|
10
|
+
readonly messages: readonly GoodVibesCloudflareQueueMessage<Body>[];
|
|
11
|
+
}
|
|
12
|
+
export interface GoodVibesCloudflareExecutionContext {
|
|
13
|
+
waitUntil(promise: Promise<unknown>): void;
|
|
14
|
+
}
|
|
15
|
+
export interface GoodVibesCloudflareWorkerEnv {
|
|
16
|
+
GOODVIBES_DAEMON_URL?: string;
|
|
17
|
+
GOODVIBES_OPERATOR_TOKEN?: string;
|
|
18
|
+
GOODVIBES_BATCH_QUEUE?: GoodVibesCloudflareQueue<GoodVibesCloudflareQueuePayload>;
|
|
19
|
+
}
|
|
20
|
+
export type GoodVibesCloudflareQueuePayload = {
|
|
21
|
+
readonly type: 'batch.tick';
|
|
22
|
+
readonly force?: boolean;
|
|
23
|
+
readonly enqueuedAt?: number;
|
|
24
|
+
} | {
|
|
25
|
+
readonly type: 'batch.job.create';
|
|
26
|
+
readonly body: Record<string, unknown>;
|
|
27
|
+
readonly enqueuedAt?: number;
|
|
28
|
+
};
|
|
29
|
+
export interface GoodVibesCloudflareWorkerOptions {
|
|
30
|
+
readonly daemonUrl?: string;
|
|
31
|
+
readonly authToken?: string;
|
|
32
|
+
readonly queueJobPayloads?: boolean;
|
|
33
|
+
}
|
|
34
|
+
export interface GoodVibesCloudflareWorker {
|
|
35
|
+
fetch(request: Request, env: GoodVibesCloudflareWorkerEnv, ctx: GoodVibesCloudflareExecutionContext): Promise<Response>;
|
|
36
|
+
queue(batch: GoodVibesCloudflareMessageBatch<GoodVibesCloudflareQueuePayload>, env: GoodVibesCloudflareWorkerEnv, ctx: GoodVibesCloudflareExecutionContext): Promise<void>;
|
|
37
|
+
scheduled(event: unknown, env: GoodVibesCloudflareWorkerEnv, ctx: GoodVibesCloudflareExecutionContext): Promise<void>;
|
|
38
|
+
}
|
|
39
|
+
export declare function createGoodVibesCloudflareWorker(options?: GoodVibesCloudflareWorkerOptions): GoodVibesCloudflareWorker;
|
|
40
|
+
//# sourceMappingURL=workers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workers.d.ts","sourceRoot":"","sources":["../src/workers.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,wBAAwB,CAAC,IAAI,GAAG,OAAO;IACtD,IAAI,CAAC,OAAO,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACpC;AAED,MAAM,WAAW,+BAA+B,CAAC,IAAI,GAAG,OAAO;IAC7D,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC;IACpB,GAAG,CAAC,IAAI,IAAI,CAAC;IACb,KAAK,CAAC,IAAI,IAAI,CAAC;CAChB;AAED,MAAM,WAAW,+BAA+B,CAAC,IAAI,GAAG,OAAO;IAC7D,QAAQ,CAAC,QAAQ,EAAE,SAAS,+BAA+B,CAAC,IAAI,CAAC,EAAE,CAAC;CACrE;AAED,MAAM,WAAW,mCAAmC;IAClD,SAAS,CAAC,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC;CAC5C;AAED,MAAM,WAAW,4BAA4B;IAC3C,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,wBAAwB,CAAC,EAAE,MAAM,CAAC;IAClC,qBAAqB,CAAC,EAAE,wBAAwB,CAAC,+BAA+B,CAAC,CAAC;CACnF;AAED,MAAM,MAAM,+BAA+B,GACvC;IACE,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC;IAC5B,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;CAC9B,GACD;IACE,QAAQ,CAAC,IAAI,EAAE,kBAAkB,CAAC;IAClC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACvC,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;CAC9B,CAAC;AAEN,MAAM,WAAW,gCAAgC;IAC/C,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,gBAAgB,CAAC,EAAE,OAAO,CAAC;CACrC;AAED,MAAM,WAAW,yBAAyB;IACxC,KAAK,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,4BAA4B,EAAE,GAAG,EAAE,mCAAmC,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;IACxH,KAAK,CAAC,KAAK,EAAE,+BAA+B,CAAC,+BAA+B,CAAC,EAAE,GAAG,EAAE,4BAA4B,EAAE,GAAG,EAAE,mCAAmC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3K,SAAS,CAAC,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,4BAA4B,EAAE,GAAG,EAAE,mCAAmC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACvH;AAED,wBAAgB,+BAA+B,CAC7C,OAAO,GAAE,gCAAqC,GAC7C,yBAAyB,CAgE3B"}
|
package/dist/workers.js
ADDED
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
export function createGoodVibesCloudflareWorker(options = {}) {
|
|
2
|
+
return {
|
|
3
|
+
async fetch(request, env, _ctx) {
|
|
4
|
+
const url = new URL(request.url);
|
|
5
|
+
if (url.pathname === '/health' || url.pathname === '/batch/health') {
|
|
6
|
+
return json({ ok: true, service: 'goodvibes-cloudflare-worker' });
|
|
7
|
+
}
|
|
8
|
+
if (url.pathname === '/batch/tick/enqueue' && request.method === 'POST') {
|
|
9
|
+
const queue = env.GOODVIBES_BATCH_QUEUE;
|
|
10
|
+
if (!queue)
|
|
11
|
+
return json({ error: 'GOODVIBES_BATCH_QUEUE is not bound', code: 'QUEUE_NOT_CONFIGURED' }, 503);
|
|
12
|
+
const body = await optionalJson(request);
|
|
13
|
+
await queue.send({
|
|
14
|
+
type: 'batch.tick',
|
|
15
|
+
force: toRecord(body)['force'] === true,
|
|
16
|
+
enqueuedAt: Date.now(),
|
|
17
|
+
});
|
|
18
|
+
return json({ queued: true }, 202);
|
|
19
|
+
}
|
|
20
|
+
const daemonPath = toDaemonBatchPath(url.pathname);
|
|
21
|
+
if (!daemonPath)
|
|
22
|
+
return json({ error: 'Not found', code: 'NOT_FOUND' }, 404);
|
|
23
|
+
if (url.pathname === '/batch/jobs/enqueue' && request.method === 'POST') {
|
|
24
|
+
if (!options.queueJobPayloads) {
|
|
25
|
+
return json({
|
|
26
|
+
error: 'Queueing full batch job payloads is disabled. Post /batch/jobs to proxy directly to the daemon, or enable queueJobPayloads explicitly.',
|
|
27
|
+
code: 'QUEUE_PAYLOADS_DISABLED',
|
|
28
|
+
}, 409);
|
|
29
|
+
}
|
|
30
|
+
const queue = env.GOODVIBES_BATCH_QUEUE;
|
|
31
|
+
if (!queue)
|
|
32
|
+
return json({ error: 'GOODVIBES_BATCH_QUEUE is not bound', code: 'QUEUE_NOT_CONFIGURED' }, 503);
|
|
33
|
+
const body = await optionalJson(request);
|
|
34
|
+
await queue.send({
|
|
35
|
+
type: 'batch.job.create',
|
|
36
|
+
body: toRecord(body),
|
|
37
|
+
enqueuedAt: Date.now(),
|
|
38
|
+
});
|
|
39
|
+
return json({ queued: true }, 202);
|
|
40
|
+
}
|
|
41
|
+
return proxyDaemonBatch(request, env, options, daemonPath);
|
|
42
|
+
},
|
|
43
|
+
async queue(batch, env, _ctx) {
|
|
44
|
+
for (const message of batch.messages) {
|
|
45
|
+
try {
|
|
46
|
+
const response = await handleQueuePayload(message.body, env, options);
|
|
47
|
+
if (response.ok) {
|
|
48
|
+
message.ack?.();
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
message.retry?.();
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
message.retry?.();
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
async scheduled(_event, env) {
|
|
60
|
+
await proxyDaemonJson(env, options, '/api/batch/tick', {
|
|
61
|
+
method: 'POST',
|
|
62
|
+
body: JSON.stringify({ force: false }),
|
|
63
|
+
});
|
|
64
|
+
},
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
async function handleQueuePayload(payload, env, options) {
|
|
68
|
+
if (payload.type === 'batch.tick') {
|
|
69
|
+
return proxyDaemonJson(env, options, '/api/batch/tick', {
|
|
70
|
+
method: 'POST',
|
|
71
|
+
body: JSON.stringify({ force: payload.force === true }),
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
return proxyDaemonJson(env, options, '/api/batch/jobs', {
|
|
75
|
+
method: 'POST',
|
|
76
|
+
body: JSON.stringify({
|
|
77
|
+
...payload.body,
|
|
78
|
+
source: {
|
|
79
|
+
kind: 'cloudflare-queue',
|
|
80
|
+
id: typeof payload.body['id'] === 'string' ? payload.body['id'] : undefined,
|
|
81
|
+
},
|
|
82
|
+
}),
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
async function proxyDaemonBatch(request, env, options, daemonPath) {
|
|
86
|
+
const body = request.method === 'GET' || request.method === 'HEAD' ? undefined : await request.text();
|
|
87
|
+
return proxyDaemonJson(env, options, daemonPath, {
|
|
88
|
+
method: request.method,
|
|
89
|
+
body,
|
|
90
|
+
search: new URL(request.url).search,
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
async function proxyDaemonJson(env, options, path, init) {
|
|
94
|
+
const baseUrl = resolveDaemonUrl(env, options);
|
|
95
|
+
if (!baseUrl) {
|
|
96
|
+
return json({ error: 'GOODVIBES_DAEMON_URL is not configured', code: 'DAEMON_URL_REQUIRED' }, 503);
|
|
97
|
+
}
|
|
98
|
+
const headers = new Headers();
|
|
99
|
+
if (init.body !== undefined)
|
|
100
|
+
headers.set('Content-Type', 'application/json');
|
|
101
|
+
const token = options.authToken ?? env.GOODVIBES_OPERATOR_TOKEN ?? '';
|
|
102
|
+
if (token)
|
|
103
|
+
headers.set('Authorization', `Bearer ${token}`);
|
|
104
|
+
return fetch(`${baseUrl}${path}${init.search ?? ''}`, {
|
|
105
|
+
method: init.method,
|
|
106
|
+
headers,
|
|
107
|
+
body: init.body,
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
function toDaemonBatchPath(pathname) {
|
|
111
|
+
if (pathname.startsWith('/api/batch'))
|
|
112
|
+
return pathname;
|
|
113
|
+
if (pathname.startsWith('/batch/'))
|
|
114
|
+
return `/api${pathname}`;
|
|
115
|
+
if (pathname === '/batch')
|
|
116
|
+
return '/api/batch';
|
|
117
|
+
return null;
|
|
118
|
+
}
|
|
119
|
+
function resolveDaemonUrl(env, options) {
|
|
120
|
+
const raw = options.daemonUrl ?? env.GOODVIBES_DAEMON_URL ?? '';
|
|
121
|
+
return raw.replace(/\/+$/, '');
|
|
122
|
+
}
|
|
123
|
+
async function optionalJson(request) {
|
|
124
|
+
const text = await request.text();
|
|
125
|
+
if (!text.trim())
|
|
126
|
+
return {};
|
|
127
|
+
try {
|
|
128
|
+
return JSON.parse(text);
|
|
129
|
+
}
|
|
130
|
+
catch {
|
|
131
|
+
return {};
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
function json(body, status = 200) {
|
|
135
|
+
return new Response(JSON.stringify(body), {
|
|
136
|
+
status,
|
|
137
|
+
headers: { 'Content-Type': 'application/json' },
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
function toRecord(value) {
|
|
141
|
+
return value !== null && typeof value === 'object' && !Array.isArray(value)
|
|
142
|
+
? value
|
|
143
|
+
: {};
|
|
144
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pellux/goodvibes-sdk",
|
|
3
|
-
"version": "0.25.
|
|
3
|
+
"version": "0.25.8",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "git+https://github.com/mgd34msu/goodvibes-sdk.git"
|
|
@@ -92,6 +92,10 @@
|
|
|
92
92
|
"types": "./dist/web.d.ts",
|
|
93
93
|
"import": "./dist/web.js"
|
|
94
94
|
},
|
|
95
|
+
"./workers": {
|
|
96
|
+
"types": "./dist/workers.d.ts",
|
|
97
|
+
"import": "./dist/workers.js"
|
|
98
|
+
},
|
|
95
99
|
"./react-native": {
|
|
96
100
|
"types": "./dist/react-native.d.ts",
|
|
97
101
|
"import": "./dist/react-native.js"
|