@absolutejs/voice 0.0.22-beta.657 → 0.0.22-beta.659
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +125 -52
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -39835,6 +39835,11 @@ var createVoiceMonitorRunnerRoutes = (options) => {
|
|
|
39835
39835
|
};
|
|
39836
39836
|
|
|
39837
39837
|
// src/core/plugin.ts
|
|
39838
|
+
var socketIdentity = (ws) => ws.raw && typeof ws.raw === "object" ? ws.raw : ws;
|
|
39839
|
+
var socketIsOpen = (ws) => {
|
|
39840
|
+
const identity = socketIdentity(ws);
|
|
39841
|
+
return identity.readyState === undefined || identity.readyState === 1;
|
|
39842
|
+
};
|
|
39838
39843
|
var resolveQueryScenario = (query) => {
|
|
39839
39844
|
if (typeof query?.scenarioId === "string" && query.scenarioId.trim()) {
|
|
39840
39845
|
return query.scenarioId.trim();
|
|
@@ -39946,14 +39951,15 @@ var parseClientMessage = (raw) => {
|
|
|
39946
39951
|
};
|
|
39947
39952
|
var resolveSessionId3 = (runtime, ws) => {
|
|
39948
39953
|
const query = ws.data && typeof ws.data === "object" && "query" in ws.data ? ws.data.query : undefined;
|
|
39949
|
-
const
|
|
39954
|
+
const identity = socketIdentity(ws);
|
|
39955
|
+
const existing = runtime.socketSessions.get(identity);
|
|
39950
39956
|
const providedSessionId = typeof query?.sessionId === "string" && query.sessionId.trim() ? query.sessionId.trim() : existing?.sessionId ?? createId();
|
|
39951
39957
|
const scenarioId = resolveQueryScenario(query) ?? existing?.scenarioId ?? null;
|
|
39952
39958
|
const resolved = {
|
|
39953
39959
|
scenarioId,
|
|
39954
39960
|
sessionId: providedSessionId
|
|
39955
39961
|
};
|
|
39956
|
-
runtime.socketSessions.set(
|
|
39962
|
+
runtime.socketSessions.set(identity, resolved);
|
|
39957
39963
|
return resolved;
|
|
39958
39964
|
};
|
|
39959
39965
|
var resolveSocketQuery = (ws) => ws.data && typeof ws.data === "object" && ("query" in ws.data) ? ws.data.query ?? {} : {};
|
|
@@ -40158,30 +40164,55 @@ var voice = (config) => {
|
|
|
40158
40164
|
socketSessions: new WeakMap
|
|
40159
40165
|
};
|
|
40160
40166
|
const authorizedSockets = new WeakSet;
|
|
40161
|
-
const
|
|
40162
|
-
|
|
40163
|
-
|
|
40167
|
+
const closedSockets = new WeakSet;
|
|
40168
|
+
const pendingSocketAuthorizations = new WeakMap;
|
|
40169
|
+
const authorizeSocket = (ws, sessionId, scenarioId) => {
|
|
40170
|
+
const identity = socketIdentity(ws);
|
|
40171
|
+
const existing = pendingSocketAuthorizations.get(identity);
|
|
40172
|
+
if (existing)
|
|
40173
|
+
return existing;
|
|
40174
|
+
const authorization = (async () => {
|
|
40175
|
+
if (closedSockets.has(identity) || !socketIsOpen(ws))
|
|
40176
|
+
return false;
|
|
40177
|
+
if (!config.authorizeConnection) {
|
|
40178
|
+
authorizedSockets.add(identity);
|
|
40179
|
+
return true;
|
|
40180
|
+
}
|
|
40181
|
+
let authorized = false;
|
|
40182
|
+
try {
|
|
40183
|
+
authorized = await config.authorizeConnection({
|
|
40184
|
+
context: ws.data,
|
|
40185
|
+
headers: resolveSocketHeaders(ws),
|
|
40186
|
+
path: config.path,
|
|
40187
|
+
query: resolveSocketQuery(ws),
|
|
40188
|
+
scenarioId,
|
|
40189
|
+
sessionId
|
|
40190
|
+
});
|
|
40191
|
+
} catch (error) {
|
|
40192
|
+
runtime.logger.warn?.(`[voice] connection authorization failed for session "${sessionId}": ${error instanceof Error ? error.message : String(error)}`);
|
|
40193
|
+
}
|
|
40194
|
+
if (closedSockets.has(identity) || !socketIsOpen(ws))
|
|
40195
|
+
return false;
|
|
40196
|
+
if (!authorized) {
|
|
40197
|
+
ws.close(4401, "unauthorized");
|
|
40198
|
+
return false;
|
|
40199
|
+
}
|
|
40200
|
+
authorizedSockets.add(identity);
|
|
40164
40201
|
return true;
|
|
40165
|
-
}
|
|
40166
|
-
|
|
40167
|
-
|
|
40168
|
-
|
|
40169
|
-
|
|
40170
|
-
|
|
40171
|
-
|
|
40172
|
-
query: resolveSocketQuery(ws),
|
|
40173
|
-
scenarioId,
|
|
40174
|
-
sessionId
|
|
40175
|
-
});
|
|
40176
|
-
} catch (error) {
|
|
40177
|
-
runtime.logger.warn?.(`[voice] connection authorization failed for session "${sessionId}": ${error instanceof Error ? error.message : String(error)}`);
|
|
40178
|
-
}
|
|
40179
|
-
if (!authorized) {
|
|
40180
|
-
ws.close(4401, "unauthorized");
|
|
40202
|
+
})();
|
|
40203
|
+
pendingSocketAuthorizations.set(identity, authorization);
|
|
40204
|
+
return authorization;
|
|
40205
|
+
};
|
|
40206
|
+
const waitForSocketAuthorization = async (ws) => {
|
|
40207
|
+
const identity = socketIdentity(ws);
|
|
40208
|
+
if (closedSockets.has(identity) || !socketIsOpen(ws))
|
|
40181
40209
|
return false;
|
|
40182
|
-
|
|
40183
|
-
|
|
40184
|
-
|
|
40210
|
+
if (authorizedSockets.has(identity))
|
|
40211
|
+
return true;
|
|
40212
|
+
const pending = pendingSocketAuthorizations.get(identity);
|
|
40213
|
+
if (!pending)
|
|
40214
|
+
return false;
|
|
40215
|
+
return await pending && !closedSockets.has(identity) && socketIsOpen(ws);
|
|
40185
40216
|
};
|
|
40186
40217
|
const { monitor } = config;
|
|
40187
40218
|
const registerMonitorSession = (sessionId, handle) => {
|
|
@@ -40350,28 +40381,59 @@ var voice = (config) => {
|
|
|
40350
40381
|
});
|
|
40351
40382
|
};
|
|
40352
40383
|
const createAndConnectSession = async (ws, sessionId, scenarioId) => {
|
|
40384
|
+
const identity = socketIdentity(ws);
|
|
40353
40385
|
const session = await createManagedSession(ws, sessionId, scenarioId);
|
|
40354
40386
|
const typedSession = session;
|
|
40387
|
+
if (closedSockets.has(identity) || !socketIsOpen(ws) || runtime.activeSockets.get(sessionId) !== identity) {
|
|
40388
|
+
ws.close(1000, "superseded");
|
|
40389
|
+
throw new Error("Voice socket was superseded during session creation");
|
|
40390
|
+
}
|
|
40391
|
+
try {
|
|
40392
|
+
await session.connect(buildSocketAdapter(ws, sessionId));
|
|
40393
|
+
} catch (error) {
|
|
40394
|
+
runtime.logger.warn?.(`[voice] session initialization failed for "${sessionId}": ${error instanceof Error ? error.message : String(error)}`);
|
|
40395
|
+
closedSockets.add(identity);
|
|
40396
|
+
ws.close(1011, "voice session initialization failed");
|
|
40397
|
+
throw error;
|
|
40398
|
+
}
|
|
40399
|
+
if (closedSockets.has(identity) || !socketIsOpen(ws) || runtime.activeSockets.get(sessionId) !== identity) {
|
|
40400
|
+
await session.disconnect({
|
|
40401
|
+
code: 1000,
|
|
40402
|
+
reason: "superseded",
|
|
40403
|
+
recoverable: true,
|
|
40404
|
+
type: "close"
|
|
40405
|
+
});
|
|
40406
|
+
ws.close(1000, "superseded");
|
|
40407
|
+
throw new Error("Voice socket was superseded during session connection");
|
|
40408
|
+
}
|
|
40355
40409
|
runtime.activeSessions.set(sessionId, typedSession);
|
|
40356
40410
|
registerMonitorSession(sessionId, typedSession);
|
|
40357
|
-
await session.connect(buildSocketAdapter(ws, sessionId));
|
|
40358
40411
|
return typedSession;
|
|
40359
40412
|
};
|
|
40360
40413
|
const ensureManagedSession = async (ws, sessionId, scenarioId) => {
|
|
40414
|
+
const identity = socketIdentity(ws);
|
|
40415
|
+
if (closedSockets.has(identity) || !socketIsOpen(ws) || runtime.activeSockets.get(sessionId) !== identity) {
|
|
40416
|
+
throw new Error("Voice socket is no longer active");
|
|
40417
|
+
}
|
|
40361
40418
|
const active = runtime.activeSessions.get(sessionId);
|
|
40362
40419
|
if (active) {
|
|
40363
40420
|
return active;
|
|
40364
40421
|
}
|
|
40365
40422
|
const inFlight = runtime.pendingSessions.get(sessionId);
|
|
40366
|
-
if (inFlight) {
|
|
40367
|
-
return inFlight;
|
|
40423
|
+
if (inFlight?.identity === identity) {
|
|
40424
|
+
return inFlight.promise;
|
|
40368
40425
|
}
|
|
40369
40426
|
const creation = createAndConnectSession(ws, sessionId, scenarioId);
|
|
40370
|
-
runtime.pendingSessions.set(sessionId,
|
|
40427
|
+
runtime.pendingSessions.set(sessionId, {
|
|
40428
|
+
identity,
|
|
40429
|
+
promise: creation
|
|
40430
|
+
});
|
|
40371
40431
|
try {
|
|
40372
40432
|
return await creation;
|
|
40373
40433
|
} finally {
|
|
40374
|
-
runtime.pendingSessions.
|
|
40434
|
+
if (runtime.pendingSessions.get(sessionId)?.promise === creation) {
|
|
40435
|
+
runtime.pendingSessions.delete(sessionId);
|
|
40436
|
+
}
|
|
40375
40437
|
}
|
|
40376
40438
|
};
|
|
40377
40439
|
const mountSurface = (app, value, factory) => {
|
|
@@ -40491,8 +40553,10 @@ var voice = (config) => {
|
|
|
40491
40553
|
};
|
|
40492
40554
|
return new Elysia70({ name: "absolutejs-voice" }).ws(config.path, {
|
|
40493
40555
|
close: async (ws, code, reason) => {
|
|
40494
|
-
const
|
|
40495
|
-
|
|
40556
|
+
const identity = socketIdentity(ws);
|
|
40557
|
+
closedSockets.add(identity);
|
|
40558
|
+
const socketState = runtime.socketSessions.get(identity);
|
|
40559
|
+
if (!socketState || runtime.activeSockets.get(socketState.sessionId) !== identity) {
|
|
40496
40560
|
return;
|
|
40497
40561
|
}
|
|
40498
40562
|
runtime.activeSockets.delete(socketState.sessionId);
|
|
@@ -40509,7 +40573,7 @@ var voice = (config) => {
|
|
|
40509
40573
|
}
|
|
40510
40574
|
},
|
|
40511
40575
|
message: async (ws, raw) => {
|
|
40512
|
-
if (!
|
|
40576
|
+
if (!await waitForSocketAuthorization(ws)) {
|
|
40513
40577
|
ws.close(4401, "unauthorized");
|
|
40514
40578
|
return;
|
|
40515
40579
|
}
|
|
@@ -40595,8 +40659,8 @@ var voice = (config) => {
|
|
|
40595
40659
|
deregisterMonitorSession(sessionState.sessionId, "session-switch");
|
|
40596
40660
|
}
|
|
40597
40661
|
sessionState.sessionId = message.sessionId;
|
|
40598
|
-
runtime.activeSockets.set(message.sessionId, ws);
|
|
40599
|
-
runtime.socketSessions.set(ws, {
|
|
40662
|
+
runtime.activeSockets.set(message.sessionId, socketIdentity(ws));
|
|
40663
|
+
runtime.socketSessions.set(socketIdentity(ws), {
|
|
40600
40664
|
...sessionState,
|
|
40601
40665
|
sessionId: message.sessionId,
|
|
40602
40666
|
scenarioId: sessionState.scenarioId
|
|
@@ -40604,7 +40668,7 @@ var voice = (config) => {
|
|
|
40604
40668
|
}
|
|
40605
40669
|
if (message.type === "start" && message.scenarioId) {
|
|
40606
40670
|
sessionState.scenarioId = message.scenarioId;
|
|
40607
|
-
runtime.socketSessions.set(ws, {
|
|
40671
|
+
runtime.socketSessions.set(socketIdentity(ws), {
|
|
40608
40672
|
...sessionState,
|
|
40609
40673
|
scenarioId: message.scenarioId
|
|
40610
40674
|
});
|
|
@@ -40618,24 +40682,33 @@ var voice = (config) => {
|
|
|
40618
40682
|
const session = current ?? await ensureManagedSession(ws, sessionState.sessionId, sessionState.scenarioId ?? undefined);
|
|
40619
40683
|
await session.receiveAudio(audio);
|
|
40620
40684
|
},
|
|
40621
|
-
open:
|
|
40685
|
+
open: (ws) => {
|
|
40622
40686
|
const sessionState = resolveSessionId3(runtime, ws);
|
|
40623
|
-
|
|
40624
|
-
|
|
40625
|
-
|
|
40626
|
-
|
|
40627
|
-
|
|
40628
|
-
|
|
40629
|
-
|
|
40630
|
-
|
|
40631
|
-
|
|
40632
|
-
|
|
40633
|
-
|
|
40634
|
-
|
|
40635
|
-
|
|
40636
|
-
|
|
40637
|
-
|
|
40638
|
-
|
|
40687
|
+
(async () => {
|
|
40688
|
+
if (!await authorizeSocket(ws, sessionState.sessionId, sessionState.scenarioId ?? undefined)) {
|
|
40689
|
+
return;
|
|
40690
|
+
}
|
|
40691
|
+
const identity = socketIdentity(ws);
|
|
40692
|
+
if (closedSockets.has(identity) || !socketIsOpen(ws))
|
|
40693
|
+
return;
|
|
40694
|
+
const existing = runtime.activeSessions.get(sessionState.sessionId);
|
|
40695
|
+
runtime.activeSockets.set(sessionState.sessionId, identity);
|
|
40696
|
+
if (existing) {
|
|
40697
|
+
await existing.disconnect({
|
|
40698
|
+
code: 1006,
|
|
40699
|
+
reason: "superseded",
|
|
40700
|
+
recoverable: true,
|
|
40701
|
+
type: "close"
|
|
40702
|
+
});
|
|
40703
|
+
runtime.activeSessions.delete(sessionState.sessionId);
|
|
40704
|
+
deregisterMonitorSession(sessionState.sessionId, "superseded");
|
|
40705
|
+
}
|
|
40706
|
+
await ensureManagedSession(ws, sessionState.sessionId, sessionState.scenarioId ?? undefined);
|
|
40707
|
+
})().catch((error) => {
|
|
40708
|
+
if (closedSockets.has(socketIdentity(ws)))
|
|
40709
|
+
return;
|
|
40710
|
+
runtime.logger.warn?.(`[voice] session initialization failed for "${sessionState.sessionId}": ${error instanceof Error ? error.message : String(error)}`);
|
|
40711
|
+
});
|
|
40639
40712
|
}
|
|
40640
40713
|
}).use(htmxRoutes()).use(surfaceRoutes());
|
|
40641
40714
|
};
|